Merge remote-tracking branch 'origin/master' into TGUI-3.0
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
#define VV_HTML_ENCODE(thing) ( sanitize ? html_encode(thing) : thing )
|
||||
/// Get displayed variable in VV variable list
|
||||
/proc/debug_variable(name, value, level, datum/D, sanitize = TRUE) //if D is a list, name will be index, and value will be assoc value.
|
||||
var/header
|
||||
if(D)
|
||||
@@ -35,6 +36,19 @@
|
||||
else if (isfile(value))
|
||||
item = "[VV_HTML_ENCODE(name)] = <span class='value'>'[value]'</span>"
|
||||
|
||||
else if(istype(value, /matrix)) // Needs to be before datum
|
||||
var/matrix/M = value
|
||||
item = {"[VV_HTML_ENCODE(name)] = <span class='value'>
|
||||
<table class='matrixbrak'><tbody><tr>
|
||||
<td class='lbrak'> </td>
|
||||
<td><table class='matrix'><tbody>
|
||||
<tr><td>[M.a]</td><td>[M.d]</td><td>0</td></tr>
|
||||
<tr><td>[M.b]</td><td>[M.e]</td><td>0</td></tr>
|
||||
<tr><td>[M.c]</td><td>[M.f]</td><td>1</td></tr>
|
||||
</tbody></table></td>
|
||||
<td class='rbrak'> </td>
|
||||
</tr></tbody></table></span>"} //TODO link to modify_transform wrapper for all matrices
|
||||
|
||||
else if (istype(value, /datum))
|
||||
var/datum/DV = value
|
||||
if ("[DV]" != "[DV.type]") //if the thing as a name var, lets use it.
|
||||
|
||||
@@ -96,16 +96,7 @@
|
||||
<head>
|
||||
<meta http-equiv='Content-Type' content='text/html; charset=UTF-8'>
|
||||
<title>[title]</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: Verdana, sans-serif;
|
||||
font-size: 9pt;
|
||||
}
|
||||
.value {
|
||||
font-family: "Courier New", monospace;
|
||||
font-size: 8pt;
|
||||
}
|
||||
</style>
|
||||
<link rel="stylesheet" type="text/css" href="view_variables.css">
|
||||
</head>
|
||||
<body onload='selectTextField()' onkeydown='return handle_keydown()' onkeyup='handle_keyup()'>
|
||||
<script type="text/javascript">
|
||||
|
||||
@@ -91,6 +91,7 @@
|
||||
B.organ_flags |= ORGAN_VITAL
|
||||
B.decoy_override = FALSE
|
||||
remove_changeling_powers()
|
||||
owner.special_role = null
|
||||
. = ..()
|
||||
|
||||
/datum/antagonist/changeling/proc/remove_clownmut()
|
||||
|
||||
@@ -1,21 +1,31 @@
|
||||
//horrifying power drain proc made for clockcult's power drain in lieu of six istypes or six for(x in view) loops
|
||||
/atom/movable/proc/power_drain(clockcult_user)
|
||||
/atom/movable/proc/power_drain(clockcult_user, drain_weapons = FALSE) //This proc as of now is only in use for void volt
|
||||
var/obj/item/stock_parts/cell/cell = get_cell()
|
||||
if(cell)
|
||||
return cell.power_drain(clockcult_user)
|
||||
return 0
|
||||
return 0 //Returns 0 instead of FALSE to symbolise it returning the power amount in other cases, not TRUE aka 1
|
||||
|
||||
/obj/item/melee/baton/power_drain(clockcult_user) //balance memes
|
||||
return 0
|
||||
/obj/item/melee/baton/power_drain(clockcult_user, drain_weapons = FALSE) //balance memes
|
||||
if(!drain_weapons)
|
||||
return 0
|
||||
return ..()
|
||||
|
||||
/obj/item/gun/power_drain(clockcult_user) //balance memes
|
||||
return 0
|
||||
/obj/item/gun/power_drain(clockcult_user, drain_weapons = FALSE) //balance memes
|
||||
if(!drain_weapons)
|
||||
return 0
|
||||
var/obj/item/stock_parts/cell/cell = get_cell()
|
||||
if(!cell)
|
||||
return 0
|
||||
if(cell.charge)
|
||||
. = min(cell.charge, MIN_CLOCKCULT_POWER*4) //Done snowflakey because guns have far smaller cells than batons / other equipment
|
||||
cell.use(.)
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/power/apc/power_drain(clockcult_user)
|
||||
/obj/machinery/power/apc/power_drain(clockcult_user, drain_weapons = FALSE)
|
||||
if(cell && cell.charge)
|
||||
playsound(src, "sparks", 50, 1)
|
||||
flick("apc-spark", src)
|
||||
. = min(cell.charge, MIN_CLOCKCULT_POWER*3)
|
||||
. = min(cell.charge, MIN_CLOCKCULT_POWER*4)
|
||||
cell.use(.) //Better than a power sink!
|
||||
if(!cell.charge && !shorted)
|
||||
shorted = 1
|
||||
@@ -23,9 +33,9 @@
|
||||
update()
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/power/smes/power_drain(clockcult_user)
|
||||
/obj/machinery/power/smes/power_drain(clockcult_user, drain_weapons = FALSE)
|
||||
if(charge)
|
||||
. = min(charge, MIN_CLOCKCULT_POWER*3)
|
||||
. = min(charge, MIN_CLOCKCULT_POWER*4)
|
||||
charge -= . * 50
|
||||
if(!charge && !panel_open)
|
||||
panel_open = TRUE
|
||||
@@ -34,19 +44,19 @@
|
||||
visible_message("<span class='warning'>[src]'s panel flies open with a flurry of sparks!</span>")
|
||||
update_icon()
|
||||
|
||||
/obj/item/stock_parts/cell/power_drain(clockcult_user)
|
||||
/obj/item/stock_parts/cell/power_drain(clockcult_user, drain_weapons = FALSE)
|
||||
if(charge)
|
||||
. = min(charge, MIN_CLOCKCULT_POWER*3)
|
||||
charge = use(.)
|
||||
. = min(charge, MIN_CLOCKCULT_POWER * 4) //Done like this because normal cells are usually quite a bit bigger than the ones used in guns / APCs
|
||||
use(min(charge, . * 10)) //Usually cell-powered equipment that is not a gun has at least ten times the capacity of a gun / 5 times the amount of an APC. This adjusts the drain to account for that.
|
||||
update_icon()
|
||||
|
||||
/mob/living/silicon/robot/power_drain(clockcult_user)
|
||||
/mob/living/silicon/robot/power_drain(clockcult_user, drain_weapons = FALSE)
|
||||
if((!clockcult_user || !is_servant_of_ratvar(src)) && cell && cell.charge)
|
||||
. = min(cell.charge, MIN_CLOCKCULT_POWER*4)
|
||||
cell.use(.)
|
||||
spark_system.start()
|
||||
|
||||
/obj/mecha/power_drain(clockcult_user)
|
||||
/obj/mecha/power_drain(clockcult_user, drain_weapons = FALSE)
|
||||
if((!clockcult_user || (occupant && !is_servant_of_ratvar(occupant))) && cell && cell.charge)
|
||||
. = min(cell.charge, MIN_CLOCKCULT_POWER*4)
|
||||
cell.use(.)
|
||||
|
||||
@@ -135,6 +135,29 @@
|
||||
|
||||
return TRUE
|
||||
|
||||
//For the Volt Void scripture, fires a ray of energy at a target location
|
||||
/obj/effect/proc_holder/slab/volt
|
||||
ranged_mousepointer = 'icons/effects/volt_target.dmi'
|
||||
|
||||
/obj/effect/proc_holder/slab/volt/InterceptClickOn(mob/living/caller, params, atom/target)
|
||||
if(target == slab || ..()) //we can't cancel
|
||||
return TRUE
|
||||
|
||||
var/turf/T = ranged_ability_user.loc
|
||||
if(!isturf(T))
|
||||
return TRUE
|
||||
|
||||
if(target in view(7, get_turf(ranged_ability_user)))
|
||||
successful = TRUE
|
||||
ranged_ability_user.visible_message("<span class='warning'>[ranged_ability_user] fires a ray of energy at [target]!</span>", "<span class='nzcrentr'>You fire a volt ray at [target].</span>")
|
||||
playsound(ranged_ability_user, 'sound/effects/light_flicker.ogg', 50, 1)
|
||||
T = get_turf(target)
|
||||
new/obj/effect/temp_visual/ratvar/volt_hit(T, ranged_ability_user)
|
||||
log_combat(ranged_ability_user, T, "fired a volt ray")
|
||||
remove_ranged_ability()
|
||||
|
||||
return TRUE
|
||||
|
||||
//For the Kindle scripture; stuns and mutes a target non-servant.
|
||||
/obj/effect/proc_holder/slab/kindle
|
||||
ranged_mousepointer = 'icons/effects/volt_target.dmi'
|
||||
|
||||
@@ -203,6 +203,10 @@ Applications: 8 servants, 3 caches, and 100 CV
|
||||
if(!do_after(invoker, chant_interval, target = invoker, extra_checks = CALLBACK(src, .proc/can_recite)))
|
||||
break
|
||||
clockwork_say(invoker, text2ratvar(pick(chant_invocations)), whispered)
|
||||
if(multiple_invokers_used)
|
||||
for(var/mob/living/L in range(1, get_turf(invoker)))
|
||||
if(can_recite_scripture(L) && L != invoker)
|
||||
clockwork_say(L, text2ratvar(pick(chant_invocations)), whispered)
|
||||
if(!chant_effects(i))
|
||||
break
|
||||
if(invoker && slab)
|
||||
|
||||
@@ -115,7 +115,7 @@
|
||||
tier = SCRIPTURE_SCRIPT
|
||||
space_allowed = TRUE
|
||||
primary_component = VANGUARD_COGWHEEL
|
||||
sort_priority = 5
|
||||
sort_priority = 6
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Creates a Ratvarian shield, which can absorb energy from attacks for use in powerful bashes."
|
||||
|
||||
@@ -131,7 +131,7 @@
|
||||
usage_tip = "Throwing the spear at a mob will do massive damage and knock them down, but break the spear. You will need to wait for 30 seconds before resummoning it."
|
||||
tier = SCRIPTURE_SCRIPT
|
||||
primary_component = VANGUARD_COGWHEEL
|
||||
sort_priority = 6
|
||||
sort_priority = 7
|
||||
important = TRUE
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Permanently binds clockwork armor and a Ratvarian spear to you."
|
||||
@@ -231,7 +231,7 @@
|
||||
usage_tip = "This gateway is strictly one-way and will only allow things through the invoker's portal."
|
||||
tier = SCRIPTURE_SCRIPT
|
||||
primary_component = GEIS_CAPACITOR
|
||||
sort_priority = 7
|
||||
sort_priority = 9
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Allows you to create a one-way Spatial Gateway to a living Servant or Clockwork Obelisk."
|
||||
|
||||
@@ -263,3 +263,227 @@
|
||||
duration = max(duration, 100)
|
||||
return slab.procure_gateway(invoker, duration, portal_uses)
|
||||
|
||||
|
||||
//Mending Mantra: Channeled for up to ten times over twenty seconds to repair structures and heal allies
|
||||
/datum/clockwork_scripture/channeled/mending_mantra
|
||||
descname = "Channeled, Area Healing and Repair"
|
||||
name = "Mending Mantra"
|
||||
desc = "Repairs nearby structures and constructs. Servants wearing clockwork armor will also be healed. Channeled every two seconds for a maximum of twenty seconds."
|
||||
chant_invocations = list("Mend our dents!", "Heal our scratches!", "Repair our gears!")
|
||||
chant_amount = 10
|
||||
chant_interval = 20
|
||||
power_cost = 400
|
||||
usage_tip = "This is a very effective way to rapidly reinforce a base after an attack."
|
||||
tier = SCRIPTURE_SCRIPT
|
||||
primary_component = VANGUARD_COGWHEEL
|
||||
sort_priority = 8
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Repairs nearby structures and constructs. Servants wearing clockwork armor will also be healed.<br><b>Maximum 10 chants.</b>"
|
||||
var/heal_attempts = 4
|
||||
var/heal_amount = 2.5
|
||||
var/static/list/damage_heal_order = list(BRUTE, BURN, OXY)
|
||||
var/static/list/heal_finish_messages = list("There, all mended!", "Try not to get too damaged.", "No more dents and scratches for you!", "Champions never die.", "All patched up.", \
|
||||
"Ah, child, it's okay now.", "Pain is temporary.", "What you do for the Justiciar is eternal.", "Bear this for me.", "Be strong, child.", "Please, be careful!", \
|
||||
"If you die, you will be remembered.")
|
||||
var/static/list/heal_target_typecache = typecacheof(list(
|
||||
/obj/structure/destructible/clockwork,
|
||||
/obj/machinery/door/airlock/clockwork,
|
||||
/obj/machinery/door/window/clockwork,
|
||||
/obj/structure/window/reinforced/clockwork,
|
||||
/obj/structure/table/reinforced/brass))
|
||||
var/static/list/ratvarian_armor_typecache = typecacheof(list(
|
||||
/obj/item/clothing/suit/armor/clockwork,
|
||||
/obj/item/clothing/head/helmet/clockwork,
|
||||
/obj/item/clothing/gloves/clockwork,
|
||||
/obj/item/clothing/shoes/clockwork))
|
||||
|
||||
/datum/clockwork_scripture/channeled/mending_mantra/chant_effects(chant_number)
|
||||
var/turf/T
|
||||
for(var/atom/movable/M in range(7, invoker))
|
||||
if(isliving(M))
|
||||
if(isclockmob(M) || istype(M, /mob/living/simple_animal/drone/cogscarab))
|
||||
var/mob/living/simple_animal/S = M
|
||||
if(S.health == S.maxHealth || S.stat == DEAD)
|
||||
continue
|
||||
T = get_turf(M)
|
||||
for(var/i in 1 to heal_attempts)
|
||||
if(S.health < S.maxHealth)
|
||||
S.adjustHealth(-heal_amount)
|
||||
new /obj/effect/temp_visual/heal(T, "#1E8CE1")
|
||||
if(i == heal_attempts && S.health >= S.maxHealth) //we finished healing on the last tick, give them the message
|
||||
to_chat(S, "<span class='inathneq'>\"[text2ratvar(pick(heal_finish_messages))]\"</span>")
|
||||
break
|
||||
else
|
||||
to_chat(S, "<span class='inathneq'>\"[text2ratvar(pick(heal_finish_messages))]\"</span>")
|
||||
break
|
||||
else if(issilicon(M))
|
||||
var/mob/living/silicon/S = M
|
||||
if(S.health == S.maxHealth || S.stat == DEAD || !is_servant_of_ratvar(S))
|
||||
continue
|
||||
T = get_turf(M)
|
||||
for(var/i in 1 to heal_attempts)
|
||||
if(S.health < S.maxHealth)
|
||||
S.heal_ordered_damage(heal_amount, damage_heal_order)
|
||||
new /obj/effect/temp_visual/heal(T, "#1E8CE1")
|
||||
if(i == heal_attempts && S.health >= S.maxHealth)
|
||||
to_chat(S, "<span class='inathneq'>\"[text2ratvar(pick(heal_finish_messages))]\"</span>")
|
||||
break
|
||||
else
|
||||
to_chat(S, "<span class='inathneq'>\"[text2ratvar(pick(heal_finish_messages))]\"</span>")
|
||||
break
|
||||
else if(ishuman(M))
|
||||
var/mob/living/carbon/human/H = M
|
||||
if(H.health == H.maxHealth || H.stat == DEAD || !is_servant_of_ratvar(H))
|
||||
continue
|
||||
T = get_turf(M)
|
||||
var/heal_ticks = 0 //one heal tick for each piece of ratvarian armor worn
|
||||
var/obj/item/I = H.get_item_by_slot(SLOT_WEAR_SUIT)
|
||||
if(is_type_in_typecache(I, ratvarian_armor_typecache))
|
||||
heal_ticks++
|
||||
I = H.get_item_by_slot(SLOT_HEAD)
|
||||
if(is_type_in_typecache(I, ratvarian_armor_typecache))
|
||||
heal_ticks++
|
||||
I = H.get_item_by_slot(SLOT_GLOVES)
|
||||
if(is_type_in_typecache(I, ratvarian_armor_typecache))
|
||||
heal_ticks++
|
||||
I = H.get_item_by_slot(SLOT_SHOES)
|
||||
if(is_type_in_typecache(I, ratvarian_armor_typecache))
|
||||
heal_ticks++
|
||||
if(heal_ticks)
|
||||
for(var/i in 1 to heal_ticks)
|
||||
if(H.health < H.maxHealth)
|
||||
H.heal_ordered_damage(heal_amount, damage_heal_order)
|
||||
new /obj/effect/temp_visual/heal(T, "#1E8CE1")
|
||||
if(i == heal_ticks && H.health >= H.maxHealth)
|
||||
to_chat(H, "<span class='inathneq'>\"[text2ratvar(pick(heal_finish_messages))]\"</span>")
|
||||
break
|
||||
else
|
||||
to_chat(H, "<span class='inathneq'>\"[text2ratvar(pick(heal_finish_messages))]\"</span>")
|
||||
break
|
||||
else if(is_type_in_typecache(M, heal_target_typecache))
|
||||
var/obj/structure/destructible/clockwork/C = M
|
||||
if(C.obj_integrity == C.max_integrity || (istype(C) && !C.can_be_repaired))
|
||||
continue
|
||||
T = get_turf(M)
|
||||
for(var/i in 1 to heal_attempts)
|
||||
if(C.obj_integrity < C.max_integrity)
|
||||
C.obj_integrity = min(C.obj_integrity + 5, C.max_integrity)
|
||||
C.update_icon()
|
||||
new /obj/effect/temp_visual/heal(T, "#1E8CE1")
|
||||
else
|
||||
break
|
||||
new /obj/effect/temp_visual/ratvar/mending_mantra(get_turf(invoker))
|
||||
return TRUE
|
||||
|
||||
//Volt Blaster: Channeled for up to five times over ten seconds to fire up to five rays of energy at target locations.
|
||||
/datum/clockwork_scripture/channeled/volt_blaster
|
||||
descname = "Channeled, Targeted Energy Blasts"
|
||||
name = "Volt Blaster"
|
||||
desc = "Allows you to fire five energy rays at target locations. Channeled every fourth of a second for a maximum of ten seconds."
|
||||
channel_time = 30
|
||||
invocations = list("Amperage...", "...grant me your power!")
|
||||
chant_invocations = list("Use charge to kill!", "Slay with power!", "Hunt with energy!")
|
||||
chant_amount = 5
|
||||
chant_interval = 4
|
||||
power_cost = 500
|
||||
usage_tip = "Though it requires you to stand still, this scripture can do massive damage."
|
||||
tier = SCRIPTURE_SCRIPT
|
||||
primary_component = BELLIGERENT_EYE
|
||||
sort_priority = 5
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Allows you to fire energy rays at target locations.<br><b>Maximum 5 chants.</b>"
|
||||
var/static/list/nzcrentr_insults = list("You're not very good at aiming.", "You hunt badly.", "What a waste of energy.", "Almost funny to watch.",
|
||||
"Boss says </span><span class='heavy_brass'>\"Click something, you idiot!\"</span><span class='nzcrentr'>.", "Stop wasting power if you can't aim.")
|
||||
|
||||
/datum/clockwork_scripture/channeled/volt_blaster/chant_effects(chant_number)
|
||||
slab.busy = null
|
||||
var/datum/clockwork_scripture/ranged_ability/volt_ray/ray = new
|
||||
ray.slab = slab
|
||||
ray.invoker = invoker
|
||||
var/turf/T = get_turf(invoker)
|
||||
if(!ray.run_scripture() && slab && invoker)
|
||||
if(can_recite() && T == get_turf(invoker))
|
||||
to_chat(invoker, "<span class='nzcrentr'>\"[text2ratvar(pick(nzcrentr_insults))]\"</span>")
|
||||
else
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/obj/effect/ebeam/volt_ray
|
||||
name = "volt_ray"
|
||||
layer = LYING_MOB_LAYER
|
||||
|
||||
/datum/clockwork_scripture/ranged_ability/volt_ray
|
||||
name = "Volt Ray"
|
||||
slab_overlay = "volt"
|
||||
allow_mobility = FALSE
|
||||
ranged_type = /obj/effect/proc_holder/slab/volt
|
||||
ranged_message = "<span class='nzcrentr_small'><i>You charge the clockwork slab with shocking might.</i>\n\
|
||||
<b>Left-click a target to fire, quickly!</b></span>"
|
||||
timeout_time = 20
|
||||
|
||||
/datum/clockwork_scripture/channeled/void_volt
|
||||
descname = "Channeled, Power Drain"
|
||||
name = "Void Volt"
|
||||
desc = "A channeled spell that quickly drains any powercells in a radius of eight tiles, but burns the invoker. \
|
||||
Can be channeled with more cultists to increase range and split the caused damage evenly over all invokers. \
|
||||
Also charges clockwork power by a small percentage of the drained power amount, which can help offset this scriptures powercost."
|
||||
invocations = list("Channel their energy through my body... ", "... so it may fuel Engine!")
|
||||
chant_invocations = list("Make their lights fall dark!", "They shall be powerless!", "Rob them of their power!")
|
||||
chant_amount = 20
|
||||
chant_interval = 10 //100KW drain per pulse for guns / APCs / 1MW for other cells = 10 chants / 100ds / 10s to drain a charged weapon or a baton with a nonupgraded cell
|
||||
channel_time = 50
|
||||
power_cost = 300
|
||||
multiple_invokers_used = TRUE
|
||||
multiple_invokers_optional = TRUE
|
||||
usage_tip = "It may be useful to end channelling early if the burning becomes too much to handle.."
|
||||
tier = SCRIPTURE_SCRIPT
|
||||
primary_component = GEIS_CAPACITOR
|
||||
sort_priority = 10
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Quickly drains power in an area around the invoker, causing burns proportional to the amount of energy drained.<br><b>Maximum of 20 chants.</b>"
|
||||
|
||||
/datum/clockwork_scripture/channeled/void_volt/scripture_effects()
|
||||
invoker.visible_message("<span class='warning'>[invoker] glows in a brilliant golden light!</span>")
|
||||
invoker.add_atom_colour("#FFD700", ADMIN_COLOUR_PRIORITY)
|
||||
invoker.light_power = 2
|
||||
invoker.light_range = 4
|
||||
invoker.light_color = LIGHT_COLOR_FIRE
|
||||
invoker.update_light()
|
||||
return ..()
|
||||
|
||||
|
||||
/datum/clockwork_scripture/channeled/void_volt/chant_effects(chant_number)
|
||||
var/power_drained = 0
|
||||
var/power_mod = 0.005 //Amount of power drained (generally) is multiplied with this, and subsequently dealt in damage to the invoker, then 15 times that is added to the clockwork cult's power reserves.
|
||||
var/drain_range = 8
|
||||
var/additional_chanters = 0
|
||||
var/list/chanters = list()
|
||||
chanters += invoker
|
||||
for(var/mob/living/L in range(1, invoker))
|
||||
if(!L.stat && is_servant_of_ratvar(L))
|
||||
additional_chanters++
|
||||
chanters += L
|
||||
drain_range = min(drain_range + 2 * additional_chanters, drain_range * 2) //s u c c
|
||||
for(var/t in spiral_range_turfs(drain_range, invoker))
|
||||
var/turf/T = t
|
||||
for(var/M in T)
|
||||
var/atom/movable/A = M
|
||||
power_drained += A.power_drain(TRUE, TRUE) //Yes, this absolutely does drain weaponry. 10 pulses to drain guns / batons, though of course they can just be recharged.
|
||||
new /obj/effect/temp_visual/ratvar/sigil/transgression(invoker.loc, 1 + (power_drained * power_mod))
|
||||
var/datum/effect_system/spark_spread/S = new
|
||||
S.set_up(round(1 + (power_drained * power_mod), 1), 0, get_turf(invoker))
|
||||
S.start()
|
||||
adjust_clockwork_power(power_drained * power_mod * 15)
|
||||
for(var/mob/living/L in chanters)
|
||||
L.adjustFireLoss(round(clamp(power_drained * power_mod / (1 + additional_chanters), 0, 20), 0.1)) //No you won't just immediately melt if you do this in a very power-rich area
|
||||
|
||||
|
||||
return TRUE
|
||||
|
||||
/datum/clockwork_scripture/channeled/void_volt/chant_end_effects()
|
||||
invoker.visible_message("<span class='warning'>[invoker] stops glowing...</span>")
|
||||
invoker.remove_atom_colour(ADMIN_COLOUR_PRIORITY)
|
||||
invoker.light_power = 0
|
||||
invoker.light_range = 0
|
||||
invoker.update_light()
|
||||
return ..()
|
||||
|
||||
@@ -343,7 +343,7 @@
|
||||
icon = 'icons/obj/items_and_weapons.dmi'
|
||||
icon_state = "disintegrate"
|
||||
item_state = null
|
||||
item_flags = NEEDS_PERMIT | ABSTRACT | DROPDEL | NO_ATTACK_CHAIN_SOFT_STAMCRIT
|
||||
item_flags = NEEDS_PERMIT | ABSTRACT | DROPDEL
|
||||
|
||||
w_class = WEIGHT_CLASS_HUGE
|
||||
throwforce = 0
|
||||
|
||||
@@ -118,22 +118,10 @@
|
||||
|
||||
|
||||
/mob/living/carbon/true_devil/attacked_by(obj/item/I, mob/living/user, def_zone)
|
||||
var/weakness = check_weakness(I, user)
|
||||
apply_damage(I.force * weakness, I.damtype, def_zone)
|
||||
var/message_verb = ""
|
||||
if(I.attack_verb && I.attack_verb.len)
|
||||
message_verb = "[pick(I.attack_verb)]"
|
||||
else if(I.force)
|
||||
message_verb = "attacked"
|
||||
|
||||
var/attack_message = "[src] has been [message_verb] with [I]."
|
||||
if(user)
|
||||
user.do_attack_animation(src)
|
||||
if(user in viewers(src, null))
|
||||
attack_message = "[user] has [message_verb] [src] with [I]!"
|
||||
if(message_verb)
|
||||
visible_message("<span class='danger'>[attack_message]</span>",
|
||||
"<span class='userdanger'>[attack_message]</span>", null, COMBAT_MESSAGE_RANGE)
|
||||
var/totitemdamage = pre_attacked_by(I, user)
|
||||
totitemdamage *= check_weakness(I, user)
|
||||
apply_damage(totitemdamage, I.damtype, def_zone)
|
||||
send_item_attack_message(I, user, null, totitemdamage)
|
||||
return TRUE
|
||||
|
||||
/mob/living/carbon/true_devil/singularity_act()
|
||||
|
||||
@@ -171,10 +171,10 @@
|
||||
var/worth = 10
|
||||
var/gases = C.air_contents.gases
|
||||
|
||||
worth += gases[/datum/gas/bz]*4
|
||||
worth += gases[/datum/gas/bz]*3
|
||||
worth += gases[/datum/gas/stimulum]*25
|
||||
worth += gases[/datum/gas/hypernoblium]*1000
|
||||
worth += gases[/datum/gas/miasma]*4
|
||||
worth += gases[/datum/gas/miasma]*2
|
||||
worth += gases[/datum/gas/tritium]*7
|
||||
worth += gases[/datum/gas/pluoxium]*6
|
||||
worth += gases[/datum/gas/nitryl]*30
|
||||
|
||||
@@ -66,6 +66,16 @@
|
||||
crate_name = "shaft miner starter kit"
|
||||
crate_type = /obj/structure/closet/crate/secure
|
||||
|
||||
/datum/supply_pack/service/snowmobile
|
||||
name = "Snowmobile kit"
|
||||
desc = "trapped on a frigid wasteland? need to get around fast? purchase a refurbished snowmobile, with a FREE 10 microsecond warranty!"
|
||||
cost = 1500 // 1000 points cheaper than ATV
|
||||
contains = list(/obj/vehicle/ridden/atv/snowmobile = 1,
|
||||
/obj/item/key = 1,
|
||||
/obj/item/clothing/mask/gas/explorer = 1)
|
||||
crate_name = "Snowmobile kit"
|
||||
crate_type = /obj/structure/closet/crate/large
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////// Chef, Botanist, Bartender ////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -0,0 +1,751 @@
|
||||
/*
|
||||
Asset cache quick users guide:
|
||||
|
||||
Make a datum at the bottom of this file with your assets for your thing.
|
||||
The simple subsystem will most like be of use for most cases.
|
||||
Then call get_asset_datum() with the type of the datum you created and store the return
|
||||
Then call .send(client) on that stored return value.
|
||||
|
||||
You can set verify to TRUE if you want send() to sleep until the client has the assets.
|
||||
*/
|
||||
|
||||
|
||||
// Amount of time(ds) MAX to send per asset, if this get exceeded we cancel the sleeping.
|
||||
// This is doubled for the first asset, then added per asset after
|
||||
#define ASSET_CACHE_SEND_TIMEOUT 7
|
||||
|
||||
//When sending mutiple assets, how many before we give the client a quaint little sending resources message
|
||||
#define ASSET_CACHE_TELL_CLIENT_AMOUNT 8
|
||||
|
||||
//When passively preloading assets, how many to send at once? Too high creates noticable lag where as too low can flood the client's cache with "verify" files
|
||||
#define ASSET_CACHE_PRELOAD_CONCURRENT 3
|
||||
|
||||
/client
|
||||
var/list/cache = list() // List of all assets sent to this client by the asset cache.
|
||||
var/list/completed_asset_jobs = list() // List of all completed jobs, awaiting acknowledgement.
|
||||
var/list/sending = list()
|
||||
var/last_asset_job = 0 // Last job done.
|
||||
|
||||
//This proc sends the asset to the client, but only if it needs it.
|
||||
//This proc blocks(sleeps) unless verify is set to false
|
||||
/proc/send_asset(client/client, asset_name, verify = TRUE)
|
||||
if(!istype(client))
|
||||
if(ismob(client))
|
||||
var/mob/M = client
|
||||
if(M.client)
|
||||
client = M.client
|
||||
|
||||
else
|
||||
return 0
|
||||
|
||||
else
|
||||
return 0
|
||||
|
||||
if(client.cache.Find(asset_name) || client.sending.Find(asset_name))
|
||||
return 0
|
||||
|
||||
client << browse_rsc(SSassets.cache[asset_name], asset_name)
|
||||
if(!verify)
|
||||
client.cache += asset_name
|
||||
return 1
|
||||
|
||||
client.sending |= asset_name
|
||||
var/job = ++client.last_asset_job
|
||||
|
||||
client << browse({"
|
||||
<script>
|
||||
window.location.href="?asset_cache_confirm_arrival=[job]"
|
||||
</script>
|
||||
"}, "window=asset_cache_browser")
|
||||
|
||||
var/t = 0
|
||||
var/timeout_time = (ASSET_CACHE_SEND_TIMEOUT * client.sending.len) + ASSET_CACHE_SEND_TIMEOUT
|
||||
while(client && !client.completed_asset_jobs.Find(job) && t < timeout_time) // Reception is handled in Topic()
|
||||
stoplag(1) // Lock up the caller until this is received.
|
||||
t++
|
||||
|
||||
if(client)
|
||||
client.sending -= asset_name
|
||||
client.cache |= asset_name
|
||||
client.completed_asset_jobs -= job
|
||||
|
||||
return 1
|
||||
|
||||
//This proc blocks(sleeps) unless verify is set to false
|
||||
/proc/send_asset_list(client/client, list/asset_list, verify = TRUE)
|
||||
if(!istype(client))
|
||||
if(ismob(client))
|
||||
var/mob/M = client
|
||||
if(M.client)
|
||||
client = M.client
|
||||
|
||||
else
|
||||
return 0
|
||||
|
||||
else
|
||||
return 0
|
||||
|
||||
var/list/unreceived = asset_list - (client.cache + client.sending)
|
||||
if(!unreceived || !unreceived.len)
|
||||
return 0
|
||||
if (unreceived.len >= ASSET_CACHE_TELL_CLIENT_AMOUNT)
|
||||
to_chat(client, "Sending Resources...")
|
||||
for(var/asset in unreceived)
|
||||
if (asset in SSassets.cache)
|
||||
client << browse_rsc(SSassets.cache[asset], asset)
|
||||
|
||||
if(!verify) // Can't access the asset cache browser, rip.
|
||||
client.cache += unreceived
|
||||
return 1
|
||||
|
||||
client.sending |= unreceived
|
||||
var/job = ++client.last_asset_job
|
||||
|
||||
client << browse({"
|
||||
<script>
|
||||
window.location.href="?asset_cache_confirm_arrival=[job]"
|
||||
</script>
|
||||
"}, "window=asset_cache_browser")
|
||||
|
||||
var/t = 0
|
||||
var/timeout_time = ASSET_CACHE_SEND_TIMEOUT * client.sending.len
|
||||
while(client && !client.completed_asset_jobs.Find(job) && t < timeout_time) // Reception is handled in Topic()
|
||||
stoplag(1) // Lock up the caller until this is received.
|
||||
t++
|
||||
|
||||
if(client)
|
||||
client.sending -= unreceived
|
||||
client.cache |= unreceived
|
||||
client.completed_asset_jobs -= job
|
||||
|
||||
return 1
|
||||
|
||||
//This proc will download the files without clogging up the browse() queue, used for passively sending files on connection start.
|
||||
//The proc calls procs that sleep for long times.
|
||||
/proc/getFilesSlow(client/client, list/files, register_asset = TRUE)
|
||||
var/concurrent_tracker = 1
|
||||
for(var/file in files)
|
||||
if (!client)
|
||||
break
|
||||
if (register_asset)
|
||||
register_asset(file, files[file])
|
||||
if (concurrent_tracker >= ASSET_CACHE_PRELOAD_CONCURRENT)
|
||||
concurrent_tracker = 1
|
||||
send_asset(client, file)
|
||||
else
|
||||
concurrent_tracker++
|
||||
send_asset(client, file, verify=FALSE)
|
||||
|
||||
stoplag(0) //queuing calls like this too quickly can cause issues in some client versions
|
||||
|
||||
//This proc "registers" an asset, it adds it to the cache for further use, you cannot touch it from this point on or you'll fuck things up.
|
||||
//if it's an icon or something be careful, you'll have to copy it before further use.
|
||||
/proc/register_asset(asset_name, asset)
|
||||
SSassets.cache[asset_name] = asset
|
||||
|
||||
//Generated names do not include file extention.
|
||||
//Used mainly for code that deals with assets in a generic way
|
||||
//The same asset will always lead to the same asset name
|
||||
/proc/generate_asset_name(file)
|
||||
return "asset.[md5(fcopy_rsc(file))]"
|
||||
|
||||
|
||||
//These datums are used to populate the asset cache, the proc "register()" does this.
|
||||
|
||||
//all of our asset datums, used for referring to these later
|
||||
GLOBAL_LIST_EMPTY(asset_datums)
|
||||
|
||||
//get an assetdatum or make a new one
|
||||
/proc/get_asset_datum(type)
|
||||
return GLOB.asset_datums[type] || new type()
|
||||
|
||||
/datum/asset
|
||||
var/_abstract = /datum/asset
|
||||
|
||||
/datum/asset/New()
|
||||
GLOB.asset_datums[type] = src
|
||||
register()
|
||||
|
||||
/datum/asset/proc/register()
|
||||
return
|
||||
|
||||
/datum/asset/proc/send(client)
|
||||
return
|
||||
|
||||
|
||||
//If you don't need anything complicated.
|
||||
/datum/asset/simple
|
||||
_abstract = /datum/asset/simple
|
||||
var/assets = list()
|
||||
var/verify = FALSE
|
||||
|
||||
/datum/asset/simple/register()
|
||||
for(var/asset_name in assets)
|
||||
register_asset(asset_name, assets[asset_name])
|
||||
|
||||
/datum/asset/simple/send(client)
|
||||
send_asset_list(client,assets,verify)
|
||||
|
||||
|
||||
// For registering or sending multiple others at once
|
||||
/datum/asset/group
|
||||
_abstract = /datum/asset/group
|
||||
var/list/children
|
||||
|
||||
/datum/asset/group/register()
|
||||
for(var/type in children)
|
||||
get_asset_datum(type)
|
||||
|
||||
/datum/asset/group/send(client/C)
|
||||
for(var/type in children)
|
||||
var/datum/asset/A = get_asset_datum(type)
|
||||
A.send(C)
|
||||
|
||||
|
||||
// spritesheet implementation - coalesces various icons into a single .png file
|
||||
// and uses CSS to select icons out of that file - saves on transferring some
|
||||
// 1400-odd individual PNG files
|
||||
#define SPR_SIZE 1
|
||||
#define SPR_IDX 2
|
||||
#define SPRSZ_COUNT 1
|
||||
#define SPRSZ_ICON 2
|
||||
#define SPRSZ_STRIPPED 3
|
||||
|
||||
/datum/asset/spritesheet
|
||||
_abstract = /datum/asset/spritesheet
|
||||
var/name
|
||||
var/list/sizes = list() // "32x32" -> list(10, icon/normal, icon/stripped)
|
||||
var/list/sprites = list() // "foo_bar" -> list("32x32", 5)
|
||||
var/verify = FALSE
|
||||
|
||||
/datum/asset/spritesheet/register()
|
||||
if (!name)
|
||||
CRASH("spritesheet [type] cannot register without a name")
|
||||
ensure_stripped()
|
||||
|
||||
var/res_name = "spritesheet_[name].css"
|
||||
var/fname = "data/spritesheets/[res_name]"
|
||||
fdel(fname)
|
||||
text2file(generate_css(), fname)
|
||||
register_asset(res_name, fcopy_rsc(fname))
|
||||
fdel(fname)
|
||||
|
||||
for(var/size_id in sizes)
|
||||
var/size = sizes[size_id]
|
||||
register_asset("[name]_[size_id].png", size[SPRSZ_STRIPPED])
|
||||
|
||||
/datum/asset/spritesheet/send(client/C)
|
||||
if (!name)
|
||||
return
|
||||
var/all = list("spritesheet_[name].css")
|
||||
for(var/size_id in sizes)
|
||||
all += "[name]_[size_id].png"
|
||||
send_asset_list(C, all, verify)
|
||||
|
||||
/datum/asset/spritesheet/proc/ensure_stripped(sizes_to_strip = sizes)
|
||||
for(var/size_id in sizes_to_strip)
|
||||
var/size = sizes[size_id]
|
||||
if (size[SPRSZ_STRIPPED])
|
||||
continue
|
||||
|
||||
// save flattened version
|
||||
var/fname = "data/spritesheets/[name]_[size_id].png"
|
||||
fcopy(size[SPRSZ_ICON], fname)
|
||||
var/error = rustg_dmi_strip_metadata(fname)
|
||||
if(length(error))
|
||||
stack_trace("Failed to strip [name]_[size_id].png: [error]")
|
||||
size[SPRSZ_STRIPPED] = icon(fname)
|
||||
fdel(fname)
|
||||
|
||||
/datum/asset/spritesheet/proc/generate_css()
|
||||
var/list/out = list()
|
||||
|
||||
for (var/size_id in sizes)
|
||||
var/size = sizes[size_id]
|
||||
var/icon/tiny = size[SPRSZ_ICON]
|
||||
out += ".[name][size_id]{display:inline-block;width:[tiny.Width()]px;height:[tiny.Height()]px;background:url('[name]_[size_id].png') no-repeat;}"
|
||||
|
||||
for (var/sprite_id in sprites)
|
||||
var/sprite = sprites[sprite_id]
|
||||
var/size_id = sprite[SPR_SIZE]
|
||||
var/idx = sprite[SPR_IDX]
|
||||
var/size = sizes[size_id]
|
||||
|
||||
var/icon/tiny = size[SPRSZ_ICON]
|
||||
var/icon/big = size[SPRSZ_STRIPPED]
|
||||
var/per_line = big.Width() / tiny.Width()
|
||||
var/x = (idx % per_line) * tiny.Width()
|
||||
var/y = round(idx / per_line) * tiny.Height()
|
||||
|
||||
out += ".[name][size_id].[sprite_id]{background-position:-[x]px -[y]px;}"
|
||||
|
||||
return out.Join("\n")
|
||||
|
||||
/datum/asset/spritesheet/proc/Insert(sprite_name, icon/I, icon_state="", dir=SOUTH, frame=1, moving=FALSE)
|
||||
I = icon(I, icon_state=icon_state, dir=dir, frame=frame, moving=moving)
|
||||
if (!I || !length(icon_states(I))) // that direction or state doesn't exist
|
||||
return
|
||||
var/size_id = "[I.Width()]x[I.Height()]"
|
||||
var/size = sizes[size_id]
|
||||
|
||||
if (sprites[sprite_name])
|
||||
CRASH("duplicate sprite \"[sprite_name]\" in sheet [name] ([type])")
|
||||
|
||||
if (size)
|
||||
var/position = size[SPRSZ_COUNT]++
|
||||
var/icon/sheet = size[SPRSZ_ICON]
|
||||
size[SPRSZ_STRIPPED] = null
|
||||
sheet.Insert(I, icon_state=sprite_name)
|
||||
sprites[sprite_name] = list(size_id, position)
|
||||
else
|
||||
sizes[size_id] = size = list(1, I, null)
|
||||
sprites[sprite_name] = list(size_id, 0)
|
||||
|
||||
/datum/asset/spritesheet/proc/InsertAll(prefix, icon/I, list/directions)
|
||||
if (length(prefix))
|
||||
prefix = "[prefix]-"
|
||||
|
||||
if (!directions)
|
||||
directions = list(SOUTH)
|
||||
|
||||
for (var/icon_state_name in icon_states(I))
|
||||
for (var/direction in directions)
|
||||
var/prefix2 = (directions.len > 1) ? "[dir2text(direction)]-" : ""
|
||||
Insert("[prefix][prefix2][icon_state_name]", I, icon_state=icon_state_name, dir=direction)
|
||||
|
||||
/datum/asset/spritesheet/proc/css_tag()
|
||||
return {"<link rel="stylesheet" href="spritesheet_[name].css" />"}
|
||||
|
||||
/datum/asset/spritesheet/proc/icon_tag(sprite_name)
|
||||
var/sprite = sprites[sprite_name]
|
||||
if (!sprite)
|
||||
return null
|
||||
var/size_id = sprite[SPR_SIZE]
|
||||
return {"<span class="[name][size_id] [sprite_name]"></span>"}
|
||||
|
||||
/datum/asset/spritesheet/proc/icon_class_name(sprite_name)
|
||||
var/sprite = sprites[sprite_name]
|
||||
if (!sprite)
|
||||
return null
|
||||
var/size_id = sprite[SPR_SIZE]
|
||||
return {"[name][size_id] [sprite_name]"}
|
||||
|
||||
#undef SPR_SIZE
|
||||
#undef SPR_IDX
|
||||
#undef SPRSZ_COUNT
|
||||
#undef SPRSZ_ICON
|
||||
#undef SPRSZ_STRIPPED
|
||||
|
||||
|
||||
/datum/asset/spritesheet/simple
|
||||
_abstract = /datum/asset/spritesheet/simple
|
||||
var/list/assets
|
||||
|
||||
/datum/asset/spritesheet/simple/register()
|
||||
for (var/key in assets)
|
||||
Insert(key, assets[key])
|
||||
..()
|
||||
|
||||
//Generates assets based on iconstates of a single icon
|
||||
/datum/asset/simple/icon_states
|
||||
_abstract = /datum/asset/simple/icon_states
|
||||
var/icon
|
||||
var/list/directions = list(SOUTH)
|
||||
var/frame = 1
|
||||
var/movement_states = FALSE
|
||||
|
||||
var/prefix = "default" //asset_name = "[prefix].[icon_state_name].png"
|
||||
var/generic_icon_names = FALSE //generate icon filenames using generate_asset_name() instead the above format
|
||||
|
||||
verify = FALSE
|
||||
|
||||
/datum/asset/simple/icon_states/register(_icon = icon)
|
||||
for(var/icon_state_name in icon_states(_icon))
|
||||
for(var/direction in directions)
|
||||
var/asset = icon(_icon, icon_state_name, direction, frame, movement_states)
|
||||
if (!asset)
|
||||
continue
|
||||
asset = fcopy_rsc(asset) //dedupe
|
||||
var/prefix2 = (directions.len > 1) ? "[dir2text(direction)]." : ""
|
||||
var/asset_name = sanitize_filename("[prefix].[prefix2][icon_state_name].png")
|
||||
if (generic_icon_names)
|
||||
asset_name = "[generate_asset_name(asset)].png"
|
||||
|
||||
register_asset(asset_name, asset)
|
||||
|
||||
/datum/asset/simple/icon_states/multiple_icons
|
||||
_abstract = /datum/asset/simple/icon_states/multiple_icons
|
||||
var/list/icons
|
||||
|
||||
/datum/asset/simple/icon_states/multiple_icons/register()
|
||||
for(var/i in icons)
|
||||
..(i)
|
||||
|
||||
|
||||
//DEFINITIONS FOR ASSET DATUMS START HERE.
|
||||
|
||||
/datum/asset/simple/tgui
|
||||
assets = list(
|
||||
// tgui
|
||||
"tgui.css" = 'tgui/assets/tgui.css',
|
||||
"tgui.js" = 'tgui/assets/tgui.js',
|
||||
// tgui-next
|
||||
"tgui-main.html" = 'tgui-next/packages/tgui/public/tgui-main.html',
|
||||
"tgui-fallback.html" = 'tgui-next/packages/tgui/public/tgui-fallback.html',
|
||||
"tgui.bundle.js" = 'tgui-next/packages/tgui/public/tgui.bundle.js',
|
||||
"tgui.bundle.css" = 'tgui-next/packages/tgui/public/tgui.bundle.css',
|
||||
"shim-html5shiv.js" = 'tgui-next/packages/tgui/public/shim-html5shiv.js',
|
||||
"shim-ie8.js" = 'tgui-next/packages/tgui/public/shim-ie8.js',
|
||||
"shim-dom4.js" = 'tgui-next/packages/tgui/public/shim-dom4.js',
|
||||
"shim-css-om.js" = 'tgui-next/packages/tgui/public/shim-css-om.js',
|
||||
)
|
||||
|
||||
/datum/asset/group/tgui
|
||||
children = list(
|
||||
/datum/asset/simple/tgui,
|
||||
/datum/asset/simple/fontawesome
|
||||
)
|
||||
|
||||
/datum/asset/simple/headers
|
||||
assets = list(
|
||||
"alarm_green.gif" = 'icons/program_icons/alarm_green.gif',
|
||||
"alarm_red.gif" = 'icons/program_icons/alarm_red.gif',
|
||||
"batt_5.gif" = 'icons/program_icons/batt_5.gif',
|
||||
"batt_20.gif" = 'icons/program_icons/batt_20.gif',
|
||||
"batt_40.gif" = 'icons/program_icons/batt_40.gif',
|
||||
"batt_60.gif" = 'icons/program_icons/batt_60.gif',
|
||||
"batt_80.gif" = 'icons/program_icons/batt_80.gif',
|
||||
"batt_100.gif" = 'icons/program_icons/batt_100.gif',
|
||||
"charging.gif" = 'icons/program_icons/charging.gif',
|
||||
"downloader_finished.gif" = 'icons/program_icons/downloader_finished.gif',
|
||||
"downloader_running.gif" = 'icons/program_icons/downloader_running.gif',
|
||||
"ntnrc_idle.gif" = 'icons/program_icons/ntnrc_idle.gif',
|
||||
"ntnrc_new.gif" = 'icons/program_icons/ntnrc_new.gif',
|
||||
"power_norm.gif" = 'icons/program_icons/power_norm.gif',
|
||||
"power_warn.gif" = 'icons/program_icons/power_warn.gif',
|
||||
"sig_high.gif" = 'icons/program_icons/sig_high.gif',
|
||||
"sig_low.gif" = 'icons/program_icons/sig_low.gif',
|
||||
"sig_lan.gif" = 'icons/program_icons/sig_lan.gif',
|
||||
"sig_none.gif" = 'icons/program_icons/sig_none.gif',
|
||||
"smmon_0.gif" = 'icons/program_icons/smmon_0.gif',
|
||||
"smmon_1.gif" = 'icons/program_icons/smmon_1.gif',
|
||||
"smmon_2.gif" = 'icons/program_icons/smmon_2.gif',
|
||||
"smmon_3.gif" = 'icons/program_icons/smmon_3.gif',
|
||||
"smmon_4.gif" = 'icons/program_icons/smmon_4.gif',
|
||||
"smmon_5.gif" = 'icons/program_icons/smmon_5.gif',
|
||||
"smmon_6.gif" = 'icons/program_icons/smmon_6.gif'
|
||||
)
|
||||
|
||||
/datum/asset/spritesheet/simple/pda
|
||||
name = "pda"
|
||||
assets = list(
|
||||
"atmos" = 'icons/pda_icons/pda_atmos.png',
|
||||
"back" = 'icons/pda_icons/pda_back.png',
|
||||
"bell" = 'icons/pda_icons/pda_bell.png',
|
||||
"blank" = 'icons/pda_icons/pda_blank.png',
|
||||
"boom" = 'icons/pda_icons/pda_boom.png',
|
||||
"bucket" = 'icons/pda_icons/pda_bucket.png',
|
||||
"medbot" = 'icons/pda_icons/pda_medbot.png',
|
||||
"floorbot" = 'icons/pda_icons/pda_floorbot.png',
|
||||
"cleanbot" = 'icons/pda_icons/pda_cleanbot.png',
|
||||
"crate" = 'icons/pda_icons/pda_crate.png',
|
||||
"cuffs" = 'icons/pda_icons/pda_cuffs.png',
|
||||
"eject" = 'icons/pda_icons/pda_eject.png',
|
||||
"flashlight" = 'icons/pda_icons/pda_flashlight.png',
|
||||
"honk" = 'icons/pda_icons/pda_honk.png',
|
||||
"mail" = 'icons/pda_icons/pda_mail.png',
|
||||
"medical" = 'icons/pda_icons/pda_medical.png',
|
||||
"menu" = 'icons/pda_icons/pda_menu.png',
|
||||
"mule" = 'icons/pda_icons/pda_mule.png',
|
||||
"notes" = 'icons/pda_icons/pda_notes.png',
|
||||
"power" = 'icons/pda_icons/pda_power.png',
|
||||
"rdoor" = 'icons/pda_icons/pda_rdoor.png',
|
||||
"reagent" = 'icons/pda_icons/pda_reagent.png',
|
||||
"refresh" = 'icons/pda_icons/pda_refresh.png',
|
||||
"scanner" = 'icons/pda_icons/pda_scanner.png',
|
||||
"signaler" = 'icons/pda_icons/pda_signaler.png',
|
||||
"status" = 'icons/pda_icons/pda_status.png',
|
||||
"dronephone" = 'icons/pda_icons/pda_dronephone.png',
|
||||
"emoji" = 'icons/pda_icons/pda_emoji.png'
|
||||
)
|
||||
|
||||
/datum/asset/spritesheet/simple/paper
|
||||
name = "paper"
|
||||
assets = list(
|
||||
"stamp-clown" = 'icons/stamp_icons/large_stamp-clown.png',
|
||||
"stamp-deny" = 'icons/stamp_icons/large_stamp-deny.png',
|
||||
"stamp-ok" = 'icons/stamp_icons/large_stamp-ok.png',
|
||||
"stamp-hop" = 'icons/stamp_icons/large_stamp-hop.png',
|
||||
"stamp-cmo" = 'icons/stamp_icons/large_stamp-cmo.png',
|
||||
"stamp-ce" = 'icons/stamp_icons/large_stamp-ce.png',
|
||||
"stamp-hos" = 'icons/stamp_icons/large_stamp-hos.png',
|
||||
"stamp-rd" = 'icons/stamp_icons/large_stamp-rd.png',
|
||||
"stamp-cap" = 'icons/stamp_icons/large_stamp-cap.png',
|
||||
"stamp-qm" = 'icons/stamp_icons/large_stamp-qm.png',
|
||||
"stamp-law" = 'icons/stamp_icons/large_stamp-law.png'
|
||||
)
|
||||
|
||||
/datum/asset/spritesheet/simple/minesweeper
|
||||
name = "minesweeper"
|
||||
assets = list(
|
||||
"1" = 'icons/UI_Icons/minesweeper_tiles/one.png',
|
||||
"2" = 'icons/UI_Icons/minesweeper_tiles/two.png',
|
||||
"3" = 'icons/UI_Icons/minesweeper_tiles/three.png',
|
||||
"4" = 'icons/UI_Icons/minesweeper_tiles/four.png',
|
||||
"5" = 'icons/UI_Icons/minesweeper_tiles/five.png',
|
||||
"6" = 'icons/UI_Icons/minesweeper_tiles/six.png',
|
||||
"7" = 'icons/UI_Icons/minesweeper_tiles/seven.png',
|
||||
"8" = 'icons/UI_Icons/minesweeper_tiles/eight.png',
|
||||
"empty" = 'icons/UI_Icons/minesweeper_tiles/empty.png',
|
||||
"flag" = 'icons/UI_Icons/minesweeper_tiles/flag.png',
|
||||
"hidden" = 'icons/UI_Icons/minesweeper_tiles/hidden.png',
|
||||
"mine" = 'icons/UI_Icons/minesweeper_tiles/mine.png',
|
||||
"minehit" = 'icons/UI_Icons/minesweeper_tiles/minehit.png'
|
||||
)
|
||||
|
||||
/datum/asset/spritesheet/simple/pills
|
||||
name = "pills"
|
||||
assets = list(
|
||||
"pill1" = 'icons/UI_Icons/Pills/pill1.png',
|
||||
"pill2" = 'icons/UI_Icons/Pills/pill2.png',
|
||||
"pill3" = 'icons/UI_Icons/Pills/pill3.png',
|
||||
"pill4" = 'icons/UI_Icons/Pills/pill4.png',
|
||||
"pill5" = 'icons/UI_Icons/Pills/pill5.png',
|
||||
"pill6" = 'icons/UI_Icons/Pills/pill6.png',
|
||||
"pill7" = 'icons/UI_Icons/Pills/pill7.png',
|
||||
"pill8" = 'icons/UI_Icons/Pills/pill8.png',
|
||||
"pill9" = 'icons/UI_Icons/Pills/pill9.png',
|
||||
"pill10" = 'icons/UI_Icons/Pills/pill10.png',
|
||||
"pill11" = 'icons/UI_Icons/Pills/pill11.png',
|
||||
"pill12" = 'icons/UI_Icons/Pills/pill12.png',
|
||||
"pill13" = 'icons/UI_Icons/Pills/pill13.png',
|
||||
"pill14" = 'icons/UI_Icons/Pills/pill14.png',
|
||||
"pill15" = 'icons/UI_Icons/Pills/pill15.png',
|
||||
"pill16" = 'icons/UI_Icons/Pills/pill16.png',
|
||||
"pill17" = 'icons/UI_Icons/Pills/pill17.png',
|
||||
"pill18" = 'icons/UI_Icons/Pills/pill18.png',
|
||||
"pill19" = 'icons/UI_Icons/Pills/pill19.png',
|
||||
"pill20" = 'icons/UI_Icons/Pills/pill20.png',
|
||||
"pill21" = 'icons/UI_Icons/Pills/pill21.png',
|
||||
"pill22" = 'icons/UI_Icons/Pills/pill22.png',
|
||||
)
|
||||
|
||||
/datum/asset/simple/IRV
|
||||
assets = list(
|
||||
"jquery-ui.custom-core-widgit-mouse-sortable-min.js" = 'html/IRV/jquery-ui.custom-core-widgit-mouse-sortable-min.js',
|
||||
)
|
||||
|
||||
/datum/asset/group/IRV
|
||||
children = list(
|
||||
/datum/asset/simple/jquery,
|
||||
/datum/asset/simple/IRV
|
||||
)
|
||||
|
||||
/datum/asset/simple/changelog
|
||||
assets = list(
|
||||
"88x31.png" = 'html/88x31.png',
|
||||
"bug-minus.png" = 'html/bug-minus.png',
|
||||
"cross-circle.png" = 'html/cross-circle.png',
|
||||
"hard-hat-exclamation.png" = 'html/hard-hat-exclamation.png',
|
||||
"image-minus.png" = 'html/image-minus.png',
|
||||
"image-plus.png" = 'html/image-plus.png',
|
||||
"music-minus.png" = 'html/music-minus.png',
|
||||
"music-plus.png" = 'html/music-plus.png',
|
||||
"tick-circle.png" = 'html/tick-circle.png',
|
||||
"wrench-screwdriver.png" = 'html/wrench-screwdriver.png',
|
||||
"spell-check.png" = 'html/spell-check.png',
|
||||
"burn-exclamation.png" = 'html/burn-exclamation.png',
|
||||
"chevron.png" = 'html/chevron.png',
|
||||
"chevron-expand.png" = 'html/chevron-expand.png',
|
||||
"scales.png" = 'html/scales.png',
|
||||
"coding.png" = 'html/coding.png',
|
||||
"ban.png" = 'html/ban.png',
|
||||
"chrome-wrench.png" = 'html/chrome-wrench.png',
|
||||
"changelog.css" = 'html/changelog.css'
|
||||
)
|
||||
|
||||
/datum/asset/group/goonchat
|
||||
children = list(
|
||||
/datum/asset/simple/jquery,
|
||||
/datum/asset/simple/goonchat,
|
||||
/datum/asset/spritesheet/goonchat,
|
||||
/datum/asset/simple/fontawesome
|
||||
)
|
||||
|
||||
/datum/asset/simple/jquery
|
||||
verify = FALSE
|
||||
assets = list(
|
||||
"jquery.min.js" = 'code/modules/goonchat/browserassets/js/jquery.min.js',
|
||||
)
|
||||
|
||||
/datum/asset/simple/goonchat
|
||||
verify = FALSE
|
||||
assets = list(
|
||||
"json2.min.js" = 'code/modules/goonchat/browserassets/js/json2.min.js',
|
||||
"browserOutput.js" = 'code/modules/goonchat/browserassets/js/browserOutput.js',
|
||||
"browserOutput.css" = 'code/modules/goonchat/browserassets/css/browserOutput.css',
|
||||
"browserOutput_dark.css" = 'code/modules/goonchat/browserassets/css/browserOutput_dark.css',
|
||||
"browserOutput_light.css" = 'code/modules/goonchat/browserassets/css/browserOutput_light.css'
|
||||
)
|
||||
|
||||
/datum/asset/simple/fontawesome
|
||||
verify = FALSE
|
||||
assets = list(
|
||||
"fa-regular-400.eot" = 'html/font-awesome/webfonts/fa-regular-400.eot',
|
||||
"fa-regular-400.woff" = 'html/font-awesome/webfonts/fa-regular-400.woff',
|
||||
"fa-solid-900.eot" = 'html/font-awesome/webfonts/fa-solid-900.eot',
|
||||
"fa-solid-900.woff" = 'html/font-awesome/webfonts/fa-solid-900.woff',
|
||||
"font-awesome.css" = 'html/font-awesome/css/all.min.css',
|
||||
"v4shim.css" = 'html/font-awesome/css/v4-shims.min.css'
|
||||
)
|
||||
|
||||
/datum/asset/spritesheet/goonchat
|
||||
name = "chat"
|
||||
|
||||
/datum/asset/spritesheet/goonchat/register()
|
||||
InsertAll("emoji", 'icons/emoji.dmi')
|
||||
|
||||
// pre-loading all lanugage icons also helps to avoid meta
|
||||
InsertAll("language", 'icons/misc/language.dmi')
|
||||
// catch languages which are pulling icons from another file
|
||||
for(var/path in typesof(/datum/language))
|
||||
var/datum/language/L = path
|
||||
var/icon = initial(L.icon)
|
||||
if (icon != 'icons/misc/language.dmi')
|
||||
var/icon_state = initial(L.icon_state)
|
||||
Insert("language-[icon_state]", icon, icon_state=icon_state)
|
||||
|
||||
..()
|
||||
|
||||
/datum/asset/simple/permissions
|
||||
assets = list(
|
||||
"padlock.png" = 'html/padlock.png'
|
||||
)
|
||||
|
||||
/datum/asset/simple/notes
|
||||
assets = list(
|
||||
"high_button.png" = 'html/high_button.png',
|
||||
"medium_button.png" = 'html/medium_button.png',
|
||||
"minor_button.png" = 'html/minor_button.png',
|
||||
"none_button.png" = 'html/none_button.png',
|
||||
)
|
||||
|
||||
//this exists purely to avoid meta by pre-loading all language icons.
|
||||
/datum/asset/language/register()
|
||||
for(var/path in typesof(/datum/language))
|
||||
set waitfor = FALSE
|
||||
var/datum/language/L = new path ()
|
||||
L.get_icon()
|
||||
|
||||
/datum/asset/spritesheet/pipes
|
||||
name = "pipes"
|
||||
|
||||
/datum/asset/spritesheet/pipes/register()
|
||||
for (var/each in list('icons/obj/atmospherics/pipes/pipe_item.dmi', 'icons/obj/atmospherics/pipes/disposal.dmi', 'icons/obj/atmospherics/pipes/transit_tube.dmi'))
|
||||
InsertAll("", each, GLOB.alldirs)
|
||||
..()
|
||||
|
||||
// Representative icons for each research design
|
||||
/datum/asset/spritesheet/research_designs
|
||||
name = "design"
|
||||
|
||||
/datum/asset/spritesheet/research_designs/register()
|
||||
for (var/path in subtypesof(/datum/design))
|
||||
var/datum/design/D = path
|
||||
|
||||
var/icon_file
|
||||
var/icon_state
|
||||
var/icon/I
|
||||
|
||||
if(initial(D.research_icon) && initial(D.research_icon_state)) //If the design has an icon replacement skip the rest
|
||||
icon_file = initial(D.research_icon)
|
||||
icon_state = initial(D.research_icon_state)
|
||||
if(!(icon_state in icon_states(icon_file)))
|
||||
warning("design [D] with icon '[icon_file]' missing state '[icon_state]'")
|
||||
continue
|
||||
I = icon(icon_file, icon_state, SOUTH)
|
||||
|
||||
else
|
||||
// construct the icon and slap it into the resource cache
|
||||
var/atom/item = initial(D.build_path)
|
||||
if (!ispath(item, /atom))
|
||||
// biogenerator outputs to beakers by default
|
||||
if (initial(D.build_type) & BIOGENERATOR)
|
||||
item = /obj/item/reagent_containers/glass/beaker/large
|
||||
else
|
||||
continue // shouldn't happen, but just in case
|
||||
|
||||
// circuit boards become their resulting machines or computers
|
||||
if (ispath(item, /obj/item/circuitboard))
|
||||
var/obj/item/circuitboard/C = item
|
||||
var/machine = initial(C.build_path)
|
||||
if (machine)
|
||||
item = machine
|
||||
|
||||
icon_file = initial(item.icon)
|
||||
icon_state = initial(item.icon_state)
|
||||
|
||||
if(!(icon_state in icon_states(icon_file)))
|
||||
warning("design [D] with icon '[icon_file]' missing state '[icon_state]'")
|
||||
continue
|
||||
I = icon(icon_file, icon_state, SOUTH)
|
||||
|
||||
// computers (and snowflakes) get their screen and keyboard sprites
|
||||
if (ispath(item, /obj/machinery/computer) || ispath(item, /obj/machinery/power/solar_control))
|
||||
var/obj/machinery/computer/C = item
|
||||
var/screen = initial(C.icon_screen)
|
||||
var/keyboard = initial(C.icon_keyboard)
|
||||
var/all_states = icon_states(icon_file)
|
||||
if (screen && (screen in all_states))
|
||||
I.Blend(icon(icon_file, screen, SOUTH), ICON_OVERLAY)
|
||||
if (keyboard && (keyboard in all_states))
|
||||
I.Blend(icon(icon_file, keyboard, SOUTH), ICON_OVERLAY)
|
||||
|
||||
Insert(initial(D.id), I)
|
||||
return ..()
|
||||
|
||||
/datum/asset/spritesheet/vending
|
||||
name = "vending"
|
||||
|
||||
/datum/asset/spritesheet/vending/register()
|
||||
for(var/k in GLOB.vending_products)
|
||||
var/atom/item = k
|
||||
if(!ispath(item, /atom))
|
||||
continue
|
||||
|
||||
var/icon_file = initial(item.icon)
|
||||
var/icon_state = initial(item.icon_state)
|
||||
var/icon/I
|
||||
|
||||
var/icon_states_list = icon_states(icon_file)
|
||||
if(icon_state in icon_states_list)
|
||||
I = icon(icon_file, icon_state, SOUTH)
|
||||
var/c = initial(item.color)
|
||||
if(!isnull(c) && c != "#FFFFFF")
|
||||
I.Blend(c, ICON_MULTIPLY)
|
||||
else
|
||||
var/icon_states_string
|
||||
for(var/an_icon_state in icon_states_list)
|
||||
if(!icon_states_string)
|
||||
icon_states_string = "[json_encode(an_icon_state)](\ref[an_icon_state])"
|
||||
else
|
||||
icon_states_string += ", [json_encode(an_icon_state)](\ref[an_icon_state])"
|
||||
stack_trace("[item] does not have a valid icon state, icon=[icon_file], icon_state=[json_encode(icon_state)](\ref[icon_state]), icon_states=[icon_states_string]")
|
||||
I = icon('icons/turf/floors.dmi', "", SOUTH)
|
||||
|
||||
var/imgid = replacetext(replacetext("[item]", "/obj/item/", ""), "/", "-")
|
||||
|
||||
Insert(imgid, I)
|
||||
return ..()
|
||||
|
||||
/datum/asset/simple/genetics
|
||||
assets = list(
|
||||
"dna_discovered.gif" = 'html/dna_discovered.gif',
|
||||
"dna_undiscovered.gif" = 'html/dna_undiscovered.gif',
|
||||
"dna_extra.gif" = 'html/dna_extra.gif'
|
||||
)
|
||||
|
||||
/datum/asset/simple/vv
|
||||
assets = list(
|
||||
"view_variables.css" = 'html/admin/view_variables.css'
|
||||
)
|
||||
@@ -50,6 +50,8 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
|
||||
/// Custom Keybindings
|
||||
var/list/key_bindings = list()
|
||||
/// List with a key string associated to a list of keybindings. Unlike key_bindings, this one operates on raw key, allowing for binding a key that triggers regardless of if a modifier is depressed as long as the raw key is sent.
|
||||
var/list/modless_key_bindings = list()
|
||||
|
||||
|
||||
var/tgui_fancy = TRUE
|
||||
@@ -154,6 +156,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
"ipc_screen" = "Sunburst",
|
||||
"ipc_antenna" = "None",
|
||||
"flavor_text" = "",
|
||||
"silicon_flavor_text" = "",
|
||||
"ooc_notes" = "",
|
||||
"meat_type" = "Mammalian",
|
||||
"body_model" = MALE,
|
||||
@@ -367,6 +370,15 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
dat += "[features["flavor_text"]]"
|
||||
else
|
||||
dat += "[TextPreview(features["flavor_text"])]...<BR>"
|
||||
dat += "<h2>Silicon Flavor Text</h2>"
|
||||
dat += "<a href='?_src_=prefs;preference=silicon_flavor_text;task=input'><b>Set Silicon Examine Text</b></a><br>"
|
||||
if(length(features["silicon_flavor_text"]) <= 40)
|
||||
if(!length(features["silicon_flavor_text"]))
|
||||
dat += "\[...\]"
|
||||
else
|
||||
dat += "[features["silicon_flavor_text"]]"
|
||||
else
|
||||
dat += "[TextPreview(features["silicon_flavor_text"])]...<BR>"
|
||||
dat += "<h2>OOC notes</h2>"
|
||||
dat += "<a href='?_src_=prefs;preference=ooc_notes;task=input'><b>Set OOC notes</b></a><br>"
|
||||
var/ooc_notes_len = length(features["ooc_notes"])
|
||||
@@ -1088,11 +1100,16 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
Input mode is the closest thing to the old input system.<br>\
|
||||
<b>IMPORTANT:</b> While in input mode's non hotkey setting (tab toggled), Ctrl + KEY will send KEY to the keybind system as the key itself, not as Ctrl + KEY. This means Ctrl + T/W/A/S/D/all your familiar stuff still works, but you \
|
||||
won't be able to access any regular Ctrl binds.<br>"
|
||||
dat += "<br><b>Modifier-Independent binding</b> - This is a singular bind that works regardless of if Ctrl/Shift/Alt are held down. For example, if combat mode is bound to C in modifier-independent binds, it'll trigger regardless of if you are \
|
||||
holding down shift for sprint. <b>Each keybind can only have one independent binding, and each key can only have one keybind independently bound to it.</b>"
|
||||
// Create an inverted list of keybindings -> key
|
||||
var/list/user_binds = list()
|
||||
var/list/user_modless_binds = list()
|
||||
for (var/key in key_bindings)
|
||||
for(var/kb_name in key_bindings[key])
|
||||
user_binds[kb_name] += list(key)
|
||||
for (var/key in modless_key_bindings)
|
||||
user_modless_binds[modless_key_bindings[key]] = key
|
||||
|
||||
var/list/kb_categories = list()
|
||||
// Group keybinds by category
|
||||
@@ -1100,21 +1117,29 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
var/datum/keybinding/kb = GLOB.keybindings_by_name[name]
|
||||
kb_categories[kb.category] += list(kb)
|
||||
|
||||
dat += "<style>label { display: inline-block; width: 200px; }</style><body>"
|
||||
dat += {"
|
||||
<style>
|
||||
span.bindname { display: inline-block; position: absolute; width: 20% ; left: 5px; padding: 5px; } \
|
||||
span.bindings { display: inline-block; position: relative; width: auto; left: 20%; width: auto; right: 20%; padding: 5px; } \
|
||||
span.independent { display: inline-block; position: absolute; width: 20%; right: 5px; padding: 5px; } \
|
||||
</style><body>
|
||||
"}
|
||||
|
||||
for (var/category in kb_categories)
|
||||
dat += "<h3>[category]</h3>"
|
||||
for (var/i in kb_categories[category])
|
||||
var/datum/keybinding/kb = i
|
||||
var/current_independent_binding = user_modless_binds[kb.name] || "Unbound"
|
||||
if(!length(user_binds[kb.name]))
|
||||
dat += "<label>[kb.full_name]</label> <a href ='?_src_=prefs;preference=keybindings_capture;keybinding=[kb.name];old_key=["Unbound"]'>Unbound</a>"
|
||||
dat += "<span class='bindname'>[kb.full_name]</span><span class='bindings'><a href ='?_src_=prefs;preference=keybindings_capture;keybinding=[kb.name];old_key=["Unbound"]'>Unbound</a>"
|
||||
var/list/default_keys = hotkeys ? kb.hotkey_keys : kb.classic_keys
|
||||
if(LAZYLEN(default_keys))
|
||||
dat += "| Default: [default_keys.Join(", ")]"
|
||||
dat += "</span><span class='independent'>Independent Binding: <a href='?_src_=prefs;preference=keybindings_capture;keybinding=[kb.name];old_key=[current_independent_binding];independent=1'>[current_independent_binding]</a></span>"
|
||||
dat += "<br>"
|
||||
else
|
||||
var/bound_key = user_binds[kb.name][1]
|
||||
dat += "<label>[kb.full_name]</label> <a href ='?_src_=prefs;preference=keybindings_capture;keybinding=[kb.name];old_key=[bound_key]'>[bound_key]</a>"
|
||||
dat += "<span class='bindname'l>[kb.full_name]</span><span class='bindings'><a href ='?_src_=prefs;preference=keybindings_capture;keybinding=[kb.name];old_key=[bound_key]'>[bound_key]</a>"
|
||||
for(var/bound_key_index in 2 to length(user_binds[kb.name]))
|
||||
bound_key = user_binds[kb.name][bound_key_index]
|
||||
dat += " | <a href ='?_src_=prefs;preference=keybindings_capture;keybinding=[kb.name];old_key=[bound_key]'>[bound_key]</a>"
|
||||
@@ -1123,6 +1148,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
var/list/default_keys = hotkeys ? kb.classic_keys : kb.hotkey_keys
|
||||
if(LAZYLEN(default_keys))
|
||||
dat += "| Default: [default_keys.Join(", ")]"
|
||||
dat += "</span><span class='independent'>Independent Binding: <a href='?_src_=prefs;preference=keybindings_capture;keybinding=[kb.name];old_key=[current_independent_binding];independent=1'>[current_independent_binding]</a></span>"
|
||||
dat += "<br>"
|
||||
|
||||
dat += "<br><br>"
|
||||
@@ -1148,7 +1174,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
#undef APPEARANCE_CATEGORY_COLUMN
|
||||
#undef MAX_MUTANT_ROWS
|
||||
|
||||
/datum/preferences/proc/CaptureKeybinding(mob/user, datum/keybinding/kb, var/old_key)
|
||||
/datum/preferences/proc/CaptureKeybinding(mob/user, datum/keybinding/kb, old_key, independent = FALSE)
|
||||
var/HTML = {"
|
||||
<div id='focus' style="outline: 0;" tabindex=0>Keybinding: [kb.full_name]<br>[kb.description]<br><br><b>Press any key to change<br>Press ESC to clear</b></div>
|
||||
<script>
|
||||
@@ -1160,7 +1186,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
var shift = e.shiftKey ? 1 : 0;
|
||||
var numpad = (95 < e.keyCode && e.keyCode < 112) ? 1 : 0;
|
||||
var escPressed = e.keyCode == 27 ? 1 : 0;
|
||||
var url = 'byond://?_src_=prefs;preference=keybindings_set;keybinding=[kb.name];old_key=[old_key];clear_key='+escPressed+';key='+e.key+';alt='+alt+';ctrl='+ctrl+';shift='+shift+';numpad='+numpad+';key_code='+e.keyCode;
|
||||
var url = 'byond://?_src_=prefs;preference=keybindings_set;keybinding=[kb.name];old_key=[old_key];[independent?"independent=1":""];clear_key='+escPressed+';key='+e.key+';alt='+alt+';ctrl='+ctrl+';shift='+shift+';numpad='+numpad+';key_code='+e.keyCode;
|
||||
window.location=url;
|
||||
deedDone = true;
|
||||
}
|
||||
@@ -1616,6 +1642,11 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
if(!isnull(msg))
|
||||
features["flavor_text"] = html_decode(msg)
|
||||
|
||||
if("silicon_flavor_text")
|
||||
var/msg = stripped_multiline_input(usr, "Set the silicon flavor text in your 'examine' verb. This can also be used for OOC notes and preferences!", "Silicon Flavor Text", features["silicon_flavor_text"], MAX_FLAVOR_LEN, TRUE)
|
||||
if(!isnull(msg))
|
||||
features["silicon_flavor_text"] = html_decode(msg)
|
||||
|
||||
if("ooc_notes")
|
||||
var/msg = stripped_multiline_input(usr, "Set always-visible OOC notes related to content preferences. THIS IS NOT FOR CHARACTER DESCRIPTIONS!", "OOC notes", features["ooc_notes"], MAX_FLAVOR_LEN, TRUE)
|
||||
if(!isnull(msg))
|
||||
@@ -2357,8 +2388,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
|
||||
if("keybindings_capture")
|
||||
var/datum/keybinding/kb = GLOB.keybindings_by_name[href_list["keybinding"]]
|
||||
var/old_key = href_list["old_key"]
|
||||
CaptureKeybinding(user, kb, old_key)
|
||||
CaptureKeybinding(user, kb, href_list["old_key"], text2num(href_list["independent"]))
|
||||
return
|
||||
|
||||
if("keybindings_set")
|
||||
@@ -2368,13 +2398,18 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
ShowChoices(user)
|
||||
return
|
||||
|
||||
var/independent = href_list["independent"]
|
||||
|
||||
var/clear_key = text2num(href_list["clear_key"])
|
||||
var/old_key = href_list["old_key"]
|
||||
if(clear_key)
|
||||
if(key_bindings[old_key])
|
||||
key_bindings[old_key] -= kb_name
|
||||
if(!length(key_bindings[old_key]))
|
||||
key_bindings -= old_key
|
||||
if(independent)
|
||||
modless_key_bindings -= old_key
|
||||
else
|
||||
if(key_bindings[old_key])
|
||||
key_bindings[old_key] -= kb_name
|
||||
if(!length(key_bindings[old_key]))
|
||||
key_bindings -= old_key
|
||||
user << browse(null, "window=capturekeypress")
|
||||
save_preferences()
|
||||
ShowChoices(user)
|
||||
@@ -2400,15 +2435,18 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
full_key = "[AltMod][CtrlMod][new_key]"
|
||||
else
|
||||
full_key = "[AltMod][CtrlMod][ShiftMod][numpad][new_key]"
|
||||
if(key_bindings[old_key])
|
||||
key_bindings[old_key] -= kb_name
|
||||
if(!length(key_bindings[old_key]))
|
||||
key_bindings -= old_key
|
||||
key_bindings[full_key] += list(kb_name)
|
||||
key_bindings[full_key] = sortList(key_bindings[full_key])
|
||||
|
||||
user << browse(null, "window=capturekeypress")
|
||||
if(independent)
|
||||
modless_key_bindings -= old_key
|
||||
modless_key_bindings[full_key] = kb_name
|
||||
else
|
||||
if(key_bindings[old_key])
|
||||
key_bindings[old_key] -= kb_name
|
||||
if(!length(key_bindings[old_key]))
|
||||
key_bindings -= old_key
|
||||
key_bindings[full_key] += list(kb_name)
|
||||
key_bindings[full_key] = sortList(key_bindings[full_key])
|
||||
user.client.update_movement_keys()
|
||||
user << browse(null, "window=capturekeypress")
|
||||
save_preferences()
|
||||
|
||||
if("keybindings_reset")
|
||||
@@ -2418,6 +2456,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
return
|
||||
hotkeys = (choice == "Hotkey")
|
||||
key_bindings = (hotkeys) ? deepCopyList(GLOB.hotkey_keybinding_list_by_key) : deepCopyList(GLOB.classic_keybinding_list_by_key)
|
||||
modless_key_bindings = list()
|
||||
user.client.update_movement_keys()
|
||||
|
||||
if("chat_on_map")
|
||||
@@ -2572,8 +2611,8 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
current_tab = text2num(href_list["tab"])
|
||||
if(href_list["preference"] == "gear")
|
||||
if(href_list["clear_loadout"])
|
||||
LAZYCLEARLIST(chosen_gear)
|
||||
gear_points = initial(gear_points)
|
||||
chosen_gear = list()
|
||||
gear_points = CONFIG_GET(number/initial_gear_points)
|
||||
save_preferences()
|
||||
if(href_list["select_category"])
|
||||
for(var/i in GLOB.loadout_items)
|
||||
@@ -2585,7 +2624,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
return
|
||||
var/toggle = text2num(href_list["toggle_gear"])
|
||||
if(!toggle && (G.type in chosen_gear))//toggling off and the item effectively is in chosen gear)
|
||||
LAZYREMOVE(chosen_gear, G.type)
|
||||
chosen_gear -= G.type
|
||||
gear_points += initial(G.cost)
|
||||
else if(toggle && (!(is_type_in_ref_list(G, chosen_gear))))
|
||||
if(!is_loadout_slot_available(G.category))
|
||||
@@ -2595,7 +2634,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
to_chat(user, "<span class='danger'>This is an item intended for donator use only. You are not authorized to use this item.</span>")
|
||||
return
|
||||
if(gear_points >= initial(G.cost))
|
||||
LAZYADD(chosen_gear, G.type)
|
||||
chosen_gear += G.type
|
||||
gear_points -= initial(G.cost)
|
||||
|
||||
ShowChoices(user)
|
||||
|
||||
@@ -262,6 +262,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
|
||||
|
||||
// Custom hotkeys
|
||||
S["key_bindings"] >> key_bindings
|
||||
S["modless_key_bindings"] >> modless_key_bindings
|
||||
|
||||
//citadel code
|
||||
S["arousable"] >> arousable
|
||||
@@ -315,7 +316,8 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
|
||||
cit_toggles = sanitize_integer(cit_toggles, 0, 16777215, initial(cit_toggles))
|
||||
auto_ooc = sanitize_integer(auto_ooc, 0, 1, initial(auto_ooc))
|
||||
no_tetris_storage = sanitize_integer(no_tetris_storage, 0, 1, initial(no_tetris_storage))
|
||||
key_bindings = sanitize_islist(key_bindings, list())
|
||||
key_bindings = sanitize_islist(key_bindings, list())
|
||||
modless_key_bindings = sanitize_islist(modless_key_bindings, list())
|
||||
|
||||
verify_keybindings_valid() // one of these days this will runtime and you'll be glad that i put it in a different proc so no one gets their saves wiped
|
||||
|
||||
@@ -333,6 +335,11 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
|
||||
if(!length(binds))
|
||||
key_bindings -= key
|
||||
// End
|
||||
// I hate copypaste but let's do it again but for modless ones
|
||||
for(var/key in modless_key_bindings)
|
||||
var/bindname = modless_key_bindings[key]
|
||||
if(!GLOB.keybindings_by_name[bindname])
|
||||
modless_key_bindings -= key
|
||||
|
||||
/datum/preferences/proc/save_preferences()
|
||||
if(!path)
|
||||
@@ -387,6 +394,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
|
||||
WRITE_FILE(S["pda_color"], pda_color)
|
||||
WRITE_FILE(S["pda_skin"], pda_skin)
|
||||
WRITE_FILE(S["key_bindings"], key_bindings)
|
||||
WRITE_FILE(S["modless_key_bindings"], modless_key_bindings)
|
||||
|
||||
//citadel code
|
||||
WRITE_FILE(S["screenshake"], screenshake)
|
||||
@@ -553,7 +561,11 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
|
||||
else //We have no old flavortext, default to new
|
||||
S["feature_flavor_text"] >> features["flavor_text"]
|
||||
|
||||
|
||||
S["silicon_feature_flavor_text"] >> features["silicon_flavor_text"]
|
||||
|
||||
S["feature_ooc_notes"] >> features["ooc_notes"]
|
||||
S["silicon_flavor_text"] >> features["silicon_flavor_text"]
|
||||
|
||||
S["vore_flags"] >> vore_flags
|
||||
S["vore_taste"] >> vore_taste
|
||||
@@ -678,6 +690,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
|
||||
|
||||
|
||||
features["flavor_text"] = copytext(features["flavor_text"], 1, MAX_FLAVOR_LEN)
|
||||
features["silicon_flavor_text"] = copytext(features["silicon_flavor_text"], 1, MAX_FLAVOR_LEN)
|
||||
features["ooc_notes"] = copytext(features["ooc_notes"], 1, MAX_FLAVOR_LEN)
|
||||
|
||||
joblessrole = sanitize_integer(joblessrole, 1, 3, initial(joblessrole))
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
/obj/item/clothing/head/hunter
|
||||
name = "hunter"
|
||||
desc = "A basic hat for hunting things."
|
||||
icon = 'modular_citadel/icons/obj/clothing/cit_hats.dmi'
|
||||
icon_state = "hunter"
|
||||
item_state = "hunter_worn"
|
||||
@@ -375,12 +375,6 @@
|
||||
icon_state = "telegram"
|
||||
dog_fashion = /datum/dog_fashion/head/telegram
|
||||
|
||||
/obj/item/clothing/head/colour
|
||||
name = "Singer cap"
|
||||
desc = "A light white hat that has bands of color. Just makes you want to sing and dance!"
|
||||
icon_state = "colour"
|
||||
dog_fashion = /datum/dog_fashion/head/colour
|
||||
|
||||
/obj/item/clothing/head/christmashat
|
||||
name = "red santa hat"
|
||||
desc = "A red Christmas Hat! How festive!"
|
||||
@@ -434,3 +428,4 @@
|
||||
desc = "A symbol of discipline, honor, and lots and lots of removal of some type of skewered food."
|
||||
icon_state = "russobluecamohat"
|
||||
item_state = "russobluecamohat"
|
||||
dynamic_hair_suffix = ""
|
||||
|
||||
@@ -114,6 +114,7 @@
|
||||
desc = "A jack o' lantern! Believed to ward off evil spirits."
|
||||
icon_state = "hardhat0_pumpkin"
|
||||
item_state = "hardhat0_pumpkin"
|
||||
hat_type = "pumpkin"
|
||||
flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDEFACIALHAIR|HIDESNOUT
|
||||
armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 0)
|
||||
brightness_on = 2 //luminosity when on
|
||||
@@ -150,6 +151,7 @@
|
||||
desc = "Some fake antlers and a very fake red nose."
|
||||
icon_state = "hardhat0_reindeer"
|
||||
item_state = "hardhat0_reindeer"
|
||||
hat_type = "reindeer"
|
||||
flags_inv = 0
|
||||
armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 0)
|
||||
brightness_on = 1 //luminosity when on
|
||||
|
||||
@@ -134,7 +134,7 @@
|
||||
name = "baseball cap"
|
||||
desc = "It's a robust baseball hat, this one belongs to syndicate major league team."
|
||||
icon_state = "baseballsoft"
|
||||
soft_type = "baseballsoft"
|
||||
soft_type = "baseball"
|
||||
item_state = "baseballsoft"
|
||||
flags_inv = HIDEEYES|HIDEFACE
|
||||
armor = list("melee" = 35, "bullet" = 35, "laser" = 25, "energy" = 10, "bomb" = 25, "bio" = 0, "rad" = 0, "fire" = 20, "acid" = 90)
|
||||
|
||||
@@ -97,6 +97,48 @@
|
||||
icon_state = "trek_ds9_medsci"
|
||||
item_state = "b_suit"
|
||||
|
||||
//Orvilike (Orville-inspired clothing with TOS-like color code)
|
||||
/obj/item/clothing/under/trek/command/orv
|
||||
desc = "An uniform worn by command officers since 2420s."
|
||||
icon_state = "orv_com"
|
||||
|
||||
/obj/item/clothing/under/trek/engsec/orv
|
||||
desc = "An uniform worn by operations officers since 2420s."
|
||||
icon_state = "orv_ops"
|
||||
|
||||
/obj/item/clothing/under/trek/medsci/orv
|
||||
desc = "An uniform worn by medsci officers since 2420s."
|
||||
icon_state = "orv_medsci"
|
||||
|
||||
//Orvilike Extra (Ditto, but expands it for Civilian department with SS13 colors and gives specified command uniform)
|
||||
//honestly no idea why i added specified comm. uniforms but w/e
|
||||
/obj/item/clothing/under/trek/command/orv/captain
|
||||
name = "captain uniform"
|
||||
desc = "An uniform worn by captains since 2550s."
|
||||
icon_state = "orv_com_capt"
|
||||
|
||||
/obj/item/clothing/under/trek/command/orv/engsec
|
||||
name = "operations command uniform"
|
||||
desc = "An uniform worn by operations command officers since 2550s."
|
||||
icon_state = "orv_com_ops"
|
||||
|
||||
/obj/item/clothing/under/trek/command/orv/medsci
|
||||
name = "medsci command uniform"
|
||||
desc = "An uniform worn by medsci command officers since 2550s."
|
||||
icon_state = "orv_com_medsci"
|
||||
|
||||
/obj/item/clothing/under/trek/orv
|
||||
name = "adjutant uniform"
|
||||
desc = "An uniform worn by adjutants <i>(assistants)</i> since 2550s."
|
||||
icon_state = "orv_ass"
|
||||
item_state = "gy_suit"
|
||||
|
||||
/obj/item/clothing/under/trek/orv/service
|
||||
name = "service uniform"
|
||||
desc = "An uniform worn by service officers since 2550s."
|
||||
icon_state = "orv_srv"
|
||||
item_state = "g_suit"
|
||||
|
||||
//The Motion Picture
|
||||
/obj/item/clothing/under/trek/fedutil
|
||||
name = "federation utility uniform"
|
||||
|
||||
@@ -383,6 +383,7 @@
|
||||
/datum/spacevine_controller/New(turf/location, list/muts, potency, production, datum/round_event/event = null)
|
||||
vines = list()
|
||||
growth_queue = list()
|
||||
spawn_spacevine_piece(location, null, muts)
|
||||
START_PROCESSING(SSobj, src)
|
||||
vine_mutations_list = list()
|
||||
init_subtypes(/datum/spacevine_mutation/, vine_mutations_list)
|
||||
|
||||
@@ -412,6 +412,15 @@
|
||||
begin_month = JUNE
|
||||
begin_weekday = SUNDAY
|
||||
|
||||
/datum/holiday/pride
|
||||
name = PRIDE_MONTH
|
||||
begin_day = 1
|
||||
begin_month = JUNE
|
||||
end_day = 30
|
||||
|
||||
/datum/holiday/pride/getStationPrefix()
|
||||
return pick("Pride", "Gay", "Bi", "Trans", "Lesbian", "Ace", "Aro", "Agender", pick("Enby", "Enbie"), "Pan", "Intersex", "Demi", "Poly", "Closeted", "Genderfluid")
|
||||
|
||||
/datum/holiday/moth
|
||||
name = "Moth Week"
|
||||
|
||||
|
||||
@@ -40,9 +40,6 @@
|
||||
return ..()
|
||||
return ..()
|
||||
|
||||
/obj/item/holo/esword/attack(target as mob, mob/user as mob)
|
||||
..()
|
||||
|
||||
/obj/item/holo/esword/Initialize()
|
||||
. = ..()
|
||||
saber_color = pick("red","blue","green","purple")
|
||||
|
||||
@@ -205,6 +205,11 @@
|
||||
popup.set_content(dat)
|
||||
popup.open()
|
||||
|
||||
/obj/machinery/biogenerator/AltClick(mob/living/user)
|
||||
. = ..()
|
||||
if(istype(user) && user.canUseTopic(src, BE_CLOSE, FALSE, NO_TK))
|
||||
detach(user)
|
||||
|
||||
/obj/machinery/biogenerator/proc/activate()
|
||||
if (usr.stat != CONSCIOUS)
|
||||
return
|
||||
@@ -293,9 +298,9 @@
|
||||
update_icon()
|
||||
return .
|
||||
|
||||
/obj/machinery/biogenerator/proc/detach()
|
||||
/obj/machinery/biogenerator/proc/detach(mob/living/user)
|
||||
if(beaker)
|
||||
beaker.forceMove(drop_location())
|
||||
user.put_in_hands(beaker)
|
||||
beaker = null
|
||||
update_icon()
|
||||
|
||||
@@ -310,7 +315,7 @@
|
||||
updateUsrDialog()
|
||||
|
||||
else if(href_list["detach"])
|
||||
detach()
|
||||
detach(usr)
|
||||
updateUsrDialog()
|
||||
|
||||
else if(href_list["create"])
|
||||
|
||||
@@ -69,7 +69,7 @@
|
||||
/obj/item/instrument/dropped(mob/user)
|
||||
. = ..()
|
||||
if((loc != user) && (user.machine == src))
|
||||
user.set_machine(null)
|
||||
user.unset_machine()
|
||||
|
||||
/obj/item/instrument/interact(mob/user)
|
||||
ui_interact(user)
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
|
||||
/obj/structure/musician/ui_interact(mob/user)
|
||||
. = ..()
|
||||
user.set_machine(src)
|
||||
song.ui_interact(user)
|
||||
|
||||
/obj/structure/musician/wrench_act(mob/living/user, obj/item/I)
|
||||
|
||||
@@ -223,8 +223,6 @@
|
||||
|
||||
/// Updates the window for our user. Override in subtypes.
|
||||
/datum/song/proc/updateDialog(mob/user = usr)
|
||||
if(user.machine != src)
|
||||
return
|
||||
ui_interact(user)
|
||||
|
||||
/datum/song/process(wait)
|
||||
|
||||
@@ -35,12 +35,9 @@ Assistant
|
||||
..()
|
||||
var/suited = !preference_source || preference_source.prefs.jumpsuit_style == PREF_SUIT
|
||||
if (CONFIG_GET(flag/grey_assistants))
|
||||
if(suited)
|
||||
uniform = /obj/item/clothing/under/color/grey
|
||||
else
|
||||
uniform = /obj/item/clothing/under/color/jumpskirt/grey
|
||||
uniform = suited ? /obj/item/clothing/under/color/grey : /obj/item/clothing/under/color/jumpskirt/grey
|
||||
else
|
||||
if(suited)
|
||||
uniform = /obj/item/clothing/under/color/random
|
||||
if(SSevents.holidays && SSevents.holidays[PRIDE_MONTH])
|
||||
uniform = suited ? /obj/item/clothing/under/color/rainbow : /obj/item/clothing/under/color/jumpskirt/rainbow
|
||||
else
|
||||
uniform = /obj/item/clothing/under/color/jumpskirt/random
|
||||
uniform = suited ? /obj/item/clothing/under/color/random : /obj/item/clothing/under/color/jumpskirt/random
|
||||
|
||||
@@ -59,6 +59,11 @@
|
||||
else
|
||||
full_key = "[AltMod][CtrlMod][ShiftMod][_key]"
|
||||
var/keycount = 0
|
||||
if(prefs.modless_key_bindings[_key])
|
||||
var/datum/keybinding/kb = GLOB.keybindings_by_name[prefs.modless_key_bindings[_key]]
|
||||
if(kb.can_use(src))
|
||||
kb.down(src)
|
||||
keycount++
|
||||
for(var/kb_name in prefs.key_bindings[full_key])
|
||||
keycount++
|
||||
var/datum/keybinding/kb = GLOB.keybindings_by_name[kb_name]
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
var/turf/pixel_turf // The turf the top_atom appears to over.
|
||||
var/light_power // Intensity of the emitter light.
|
||||
var/light_range // The range of the emitted light.
|
||||
var/light_color // The colour of the light, string, decomposed by parse_light_color()
|
||||
var/light_color // The colour of the light, string, decomposed by PARSE_LIGHT_COLOR()
|
||||
|
||||
// Variables for keeping track of the colour.
|
||||
var/lum_r
|
||||
@@ -48,12 +48,10 @@
|
||||
light_range = source_atom.light_range
|
||||
light_color = source_atom.light_color
|
||||
|
||||
parse_light_color()
|
||||
PARSE_LIGHT_COLOR(src)
|
||||
|
||||
update()
|
||||
|
||||
return ..()
|
||||
|
||||
/datum/light_source/Destroy(force)
|
||||
remove_lum()
|
||||
if (source_atom)
|
||||
@@ -99,17 +97,6 @@
|
||||
/datum/light_source/proc/vis_update()
|
||||
EFFECT_UPDATE(LIGHTING_VIS_UPDATE)
|
||||
|
||||
// Decompile the hexadecimal colour into lumcounts of each perspective.
|
||||
/datum/light_source/proc/parse_light_color()
|
||||
if (light_color)
|
||||
lum_r = GetRedPart (light_color) / 255
|
||||
lum_g = GetGreenPart (light_color) / 255
|
||||
lum_b = GetBluePart (light_color) / 255
|
||||
else
|
||||
lum_r = 1
|
||||
lum_g = 1
|
||||
lum_b = 1
|
||||
|
||||
// Macro that applies light to a new corner.
|
||||
// It is a macro in the interest of speed, yet not having to copy paste it.
|
||||
// If you're wondering what's with the backslashes, the backslashes cause BYOND to not automatically end the line.
|
||||
@@ -224,7 +211,7 @@
|
||||
|
||||
if (source_atom.light_color != light_color)
|
||||
light_color = source_atom.light_color
|
||||
parse_light_color()
|
||||
PARSE_LIGHT_COLOR(src)
|
||||
update = TRUE
|
||||
|
||||
else if (applied_lum_r != lum_r || applied_lum_g != lum_g || applied_lum_b != lum_b)
|
||||
@@ -241,17 +228,16 @@
|
||||
var/list/turf/turfs = list()
|
||||
var/thing
|
||||
var/turf/T
|
||||
|
||||
if (source_turf)
|
||||
var/oldlum = source_turf.luminosity
|
||||
source_turf.luminosity = CEILING(light_range, 1)
|
||||
for(T in view(CEILING(light_range, 1), source_turf))
|
||||
turfs += T
|
||||
if(!IS_DYNAMIC_LIGHTING(T) && !T.light_sources)
|
||||
if((!IS_DYNAMIC_LIGHTING(T) && !T.light_sources) || T.has_opaque_atom )
|
||||
continue
|
||||
if(!T.lighting_corners_initialised)
|
||||
T.generate_missing_corners()
|
||||
if(T.has_opaque_atom)
|
||||
continue
|
||||
corners[T.lc_topright] = 0
|
||||
corners[T.lc_bottomright] = 0
|
||||
corners[T.lc_bottomleft] = 0
|
||||
|
||||
@@ -189,6 +189,26 @@
|
||||
name = "Coffee House"
|
||||
icon_state = "hair_coffeehouse"
|
||||
|
||||
/datum/sprite_accessory/hair/cornrows1
|
||||
name = "Cornrows"
|
||||
icon_state = "hair_cornrows"
|
||||
|
||||
/datum/sprite_accessory/hair/cornrows2
|
||||
name = "Cornrows 2"
|
||||
icon_state = "hair_cornrows2"
|
||||
|
||||
/datum/sprite_accessory/hair/cornrowbun
|
||||
name = "Cornrow Bun"
|
||||
icon_state = "hair_cornrowbun"
|
||||
|
||||
/datum/sprite_accessory/hair/cornrowbraid
|
||||
name = "Cornrow Braid"
|
||||
icon_state = "hair_cornrowbraid"
|
||||
|
||||
/datum/sprite_accessory/hair/cornrowdualtail
|
||||
name = "Cornrow Tail"
|
||||
icon_state = "hair_cornrowtail"
|
||||
|
||||
/datum/sprite_accessory/hair/country
|
||||
name = "Country"
|
||||
icon_state = "hair_country"
|
||||
|
||||
@@ -280,25 +280,15 @@
|
||||
. = ..()
|
||||
C.faction |= "plants"
|
||||
C.faction |= "vines"
|
||||
C.AddElement(/datum/element/photosynthesis)
|
||||
|
||||
/datum/species/golem/wood/on_species_loss(mob/living/carbon/C)
|
||||
. = ..()
|
||||
C.faction -= "plants"
|
||||
C.faction -= "vines"
|
||||
C.RemoveElement(/datum/element/photosynthesis)
|
||||
|
||||
/datum/species/golem/wood/spec_life(mob/living/carbon/human/H)
|
||||
if(H.stat == DEAD)
|
||||
return
|
||||
var/light_amount = 0 //how much light there is in the place, affects receiving nutrition and healing
|
||||
if(isturf(H.loc)) //else, there's considered to be no light
|
||||
var/turf/T = H.loc
|
||||
light_amount = min(1,T.get_lumcount()) - 0.5
|
||||
H.adjust_nutrition(light_amount * 4, NUTRITION_LEVEL_FULL)
|
||||
if(light_amount > 0.2) //if there's enough light, heal
|
||||
H.heal_overall_damage(1,1)
|
||||
H.adjustToxLoss(-1)
|
||||
H.adjustOxyLoss(-1)
|
||||
|
||||
if(H.nutrition < NUTRITION_LEVEL_STARVING + 50)
|
||||
H.take_overall_damage(2,0)
|
||||
|
||||
|
||||
@@ -14,34 +14,24 @@
|
||||
liked_food = VEGETABLES | FRUIT | GRAIN
|
||||
species_language_holder = /datum/language_holder/sylvan
|
||||
var/light_nutrition_gain_factor = 4
|
||||
var/light_toxheal = 1
|
||||
var/light_oxyheal = 1
|
||||
var/light_burnheal = 1
|
||||
var/light_bruteheal = 1
|
||||
var/light_toxheal = -1
|
||||
var/light_oxyheal = -1
|
||||
var/light_burnheal = -1
|
||||
var/light_bruteheal = -1
|
||||
|
||||
/datum/species/pod/on_species_gain(mob/living/carbon/C, datum/species/old_species)
|
||||
. = ..()
|
||||
C.faction |= "plants"
|
||||
C.faction |= "vines"
|
||||
C.AddElement(/datum/element/photosynthesis, light_bruteheal, light_burnheal, light_toxheal, light_oxyheal, light_nutrition_gain_factor)
|
||||
|
||||
/datum/species/pod/on_species_loss(mob/living/carbon/C)
|
||||
. = ..()
|
||||
C.faction -= "plants"
|
||||
C.faction -= "vines"
|
||||
C.RemoveElement(/datum/element/photosynthesis, light_bruteheal, light_burnheal, light_toxheal, light_oxyheal, light_nutrition_gain_factor)
|
||||
|
||||
/datum/species/pod/spec_life(mob/living/carbon/human/H)
|
||||
if(H.stat == DEAD)
|
||||
return
|
||||
var/light_amount = 0 //how much light there is in the place, affects receiving nutrition and healing
|
||||
if(isturf(H.loc)) //else, there's considered to be no light
|
||||
var/turf/T = H.loc
|
||||
light_amount = min(1,T.get_lumcount()) - 0.5
|
||||
H.adjust_nutrition(light_amount * light_nutrition_gain_factor, NUTRITION_LEVEL_FULL)
|
||||
if(light_amount > 0.2) //if there's enough light, heal
|
||||
H.heal_overall_damage(light_bruteheal, light_burnheal)
|
||||
H.adjustToxLoss(-light_toxheal)
|
||||
H.adjustOxyLoss(-light_oxyheal)
|
||||
|
||||
if(H.nutrition < NUTRITION_LEVEL_STARVING + 50)
|
||||
H.take_overall_damage(2,0)
|
||||
|
||||
@@ -77,9 +67,9 @@
|
||||
mutant_bodyparts = list("mcolor" = "FFF","mcolor2" = "FFF","mcolor3" = "FFF", "mam_snouts" = "Husky", "mam_tail" = "Husky", "mam_ears" = "Husky", "mam_body_markings" = "Husky", "taur" = "None", "legs" = "Normal Legs")
|
||||
limbs_id = "pod"
|
||||
light_nutrition_gain_factor = 3
|
||||
light_bruteheal = 0.2
|
||||
light_burnheal = 0.2
|
||||
light_toxheal = 0.7
|
||||
light_bruteheal = -0.2
|
||||
light_burnheal = -0.2
|
||||
light_toxheal = -0.7
|
||||
|
||||
/datum/species/pod/pseudo_weak/spec_death(gibbed, mob/living/carbon/human/H)
|
||||
if(H)
|
||||
|
||||
@@ -15,16 +15,13 @@
|
||||
dangerous_existence = 1
|
||||
mutanteyes = /obj/item/organ/eyes/night_vision
|
||||
|
||||
/datum/species/shadow/on_species_gain(mob/living/carbon/C, datum/species/old_species)
|
||||
. = ..()
|
||||
C.AddElement(/datum/element/photosynthesis, 1, 1, 0, 0, 0, 0, SHADOW_SPECIES_LIGHT_THRESHOLD, SHADOW_SPECIES_LIGHT_THRESHOLD)
|
||||
|
||||
/datum/species/shadow/spec_life(mob/living/carbon/human/H)
|
||||
var/turf/T = H.loc
|
||||
if(istype(T))
|
||||
var/light_amount = T.get_lumcount()
|
||||
|
||||
if(light_amount > SHADOW_SPECIES_LIGHT_THRESHOLD) //if there's enough light, start dying
|
||||
H.take_overall_damage(1,1)
|
||||
else if (light_amount < SHADOW_SPECIES_LIGHT_THRESHOLD) //heal in the dark
|
||||
H.heal_overall_damage(1,1)
|
||||
/datum/species/shadow/on_species_loss(mob/living/carbon/C)
|
||||
. = ..()
|
||||
C.RemoveElement(/datum/element/photosynthesis, 1, 1, 0, 0, 0, 0, SHADOW_SPECIES_LIGHT_THRESHOLD, SHADOW_SPECIES_LIGHT_THRESHOLD)
|
||||
|
||||
/datum/species/shadow/check_roundstart_eligible()
|
||||
if(SSevents.holidays && SSevents.holidays[HALLOWEEN])
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
|
||||
typing_indicator_enabled = TRUE
|
||||
|
||||
var/last_click_move = 0 // Stores the previous next_move value.
|
||||
|
||||
var/resize = 1 //Badminnery resize
|
||||
var/lastattacker = null
|
||||
var/lastattackerckey = null
|
||||
|
||||
@@ -285,8 +285,6 @@
|
||||
. = ..()
|
||||
var/turf/ai = get_turf(src)
|
||||
var/turf/target = get_turf(A)
|
||||
if (.)
|
||||
return
|
||||
|
||||
if(!target)
|
||||
return
|
||||
|
||||
@@ -93,6 +93,7 @@
|
||||
return new storage_type(src)
|
||||
|
||||
/obj/item/robot_module/proc/add_module(obj/item/I, nonstandard, requires_rebuild)
|
||||
rad_flags |= RAD_NO_CONTAMINATE
|
||||
if(istype(I, /obj/item/stack))
|
||||
var/obj/item/stack/S = I
|
||||
|
||||
|
||||
@@ -56,6 +56,12 @@
|
||||
diag_hud_set_status()
|
||||
diag_hud_set_health()
|
||||
|
||||
/mob/living/silicon/ComponentInitialize()
|
||||
. = ..()
|
||||
AddElement(/datum/element/flavor_text, _name = "Silicon Flavor Text", _save_key = "silicon_flavor_text")
|
||||
AddElement(/datum/element/flavor_text, "", "Temporary Flavor Text", "This should be used only for things pertaining to the current round!")
|
||||
AddElement(/datum/element/flavor_text, _name = "OOC Notes", _addendum = "Put information on ERP/vore/lewd-related preferences here. THIS SHOULD NOT CONTAIN REGULAR FLAVORTEXT!!", _always_show = TRUE, _save_key = "ooc_notes", _examine_no_preview = TRUE)
|
||||
|
||||
/mob/living/silicon/med_hud_set_health()
|
||||
return //we use a different hud
|
||||
|
||||
|
||||
@@ -2,15 +2,16 @@
|
||||
name = "A Perfectly Generic Boss Placeholder"
|
||||
desc = ""
|
||||
threat = 10
|
||||
robust_searching = 1
|
||||
robust_searching = TRUE
|
||||
stat_attack = UNCONSCIOUS
|
||||
status_flags = 0
|
||||
status_flags = NONE
|
||||
a_intent = INTENT_HARM
|
||||
gender = NEUTER
|
||||
has_field_of_vision = FALSE //You are a frikkin boss
|
||||
var/list/boss_abilities = list() //list of /datum/action/boss
|
||||
var/datum/boss_active_timed_battle/atb
|
||||
var/point_regen_delay = 1
|
||||
var/point_regen_delay = 20
|
||||
var/point_regen_amount = 1
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/boss/Initialize()
|
||||
@@ -18,6 +19,7 @@
|
||||
|
||||
atb = new()
|
||||
atb.point_regen_delay = point_regen_delay
|
||||
atb.point_regen_amount = point_regen_amount
|
||||
atb.boss = src
|
||||
|
||||
for(var/ab in boss_abilities)
|
||||
@@ -40,6 +42,7 @@
|
||||
required_mobility_flags = NONE
|
||||
var/boss_cost = 100 //Cost of usage for the boss' AI 1-100
|
||||
var/usage_probability = 100
|
||||
var/list/req_statuses //If set, will only trigger if the mob AI status is present in this list.
|
||||
var/mob/living/simple_animal/hostile/boss/boss
|
||||
var/boss_type = /mob/living/simple_animal/hostile/boss
|
||||
var/needs_target = TRUE //Does the boss need to have a target? (Only matters for the AI)
|
||||
@@ -57,7 +60,7 @@
|
||||
. = ..()
|
||||
boss = null
|
||||
|
||||
/datum/action/boss/Trigger()
|
||||
/datum/action/boss/IsAvailable(silent = FALSE)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
@@ -69,6 +72,11 @@
|
||||
return FALSE
|
||||
if(!boss.client && needs_target && !boss.target)
|
||||
return FALSE
|
||||
|
||||
/datum/action/boss/Trigger()
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
if(!boss.atb.spend(boss_cost))
|
||||
return FALSE
|
||||
if(say_when_triggered)
|
||||
@@ -85,7 +93,8 @@
|
||||
//Designed for boss mobs only
|
||||
/datum/boss_active_timed_battle
|
||||
var/list/abilities //a list of /datum/action/boss owned by a boss mob
|
||||
var/point_regen_delay = 5
|
||||
var/point_regen_delay = 20
|
||||
var/point_regen_amount = 1
|
||||
var/max_points = 100
|
||||
var/points = 50 //start with 50 so we can use some abilities but not insta-buttfug somebody
|
||||
var/next_point_time = 0
|
||||
@@ -93,48 +102,45 @@
|
||||
var/highest_cost = 0
|
||||
var/mob/living/simple_animal/hostile/boss/boss
|
||||
|
||||
|
||||
/datum/boss_active_timed_battle/New()
|
||||
..()
|
||||
START_PROCESSING(SSobj, src)
|
||||
|
||||
|
||||
/datum/boss_active_timed_battle/proc/assign_abilities(list/L)
|
||||
if(!L)
|
||||
return 0
|
||||
return FALSE
|
||||
abilities = L
|
||||
for(var/ab in abilities)
|
||||
var/datum/action/boss/AB = ab
|
||||
if(AB.boss_cost > highest_cost)
|
||||
highest_cost = AB.boss_cost
|
||||
|
||||
|
||||
/datum/boss_active_timed_battle/proc/spend(cost)
|
||||
if(cost <= points)
|
||||
points = max(0,points-cost)
|
||||
points -= cost
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
|
||||
/datum/boss_active_timed_battle/proc/refund(cost)
|
||||
points = min(points+cost, max_points)
|
||||
|
||||
|
||||
/datum/boss_active_timed_battle/process()
|
||||
if(world.time >= next_point_time && points < max_points)
|
||||
next_point_time = world.time + point_regen_delay
|
||||
points = min(max_points, ++points) //has to be out of 100
|
||||
points = min(max_points, points + point_regen_amount)
|
||||
|
||||
if(abilities)
|
||||
chance_to_hold_onto_points = highest_cost*0.5
|
||||
if(points != max_points && prob(chance_to_hold_onto_points))
|
||||
return //Let's save our points for a better ability (unless we're at max points, in which case we can't save anymore!)
|
||||
if(!boss.client)
|
||||
abilities = shuffle(abilities)
|
||||
for(var/ab in abilities)
|
||||
var/datum/action/boss/AB = ab
|
||||
if(prob(AB.usage_probability) && AB.Trigger())
|
||||
break
|
||||
if(!abilities)
|
||||
return
|
||||
chance_to_hold_onto_points = highest_cost*0.5
|
||||
if(points != max_points && prob(chance_to_hold_onto_points))
|
||||
return //Let's save our points for a better ability (unless we're at max points, in which case we can't save anymore!)
|
||||
if(!boss.client)
|
||||
abilities = shuffle(abilities)
|
||||
for(var/ab in abilities)
|
||||
var/datum/action/boss/AB = ab
|
||||
if(!boss.client && (!AB.req_statuses || (boss.AIStatus in AB.req_statuses)) && prob(AB.usage_probability) && AB.Trigger())
|
||||
break
|
||||
AB.UpdateButtonIcon(TRUE)
|
||||
|
||||
|
||||
/datum/boss_active_timed_battle/Destroy()
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
boss_cost = 30
|
||||
boss_type = /mob/living/simple_animal/hostile/boss/paper_wizard
|
||||
needs_target = FALSE
|
||||
req_statuses = list(AI_ON)
|
||||
say_when_triggered = "Rise, my creations! Jump off your pages and into this realm!"
|
||||
var/list/summoned_minions = list()
|
||||
var/maximum_stickmen = 6
|
||||
@@ -85,6 +86,7 @@
|
||||
usage_probability = 30
|
||||
boss_cost = 40
|
||||
boss_type = /mob/living/simple_animal/hostile/boss/paper_wizard
|
||||
req_statuses = list(AI_ON)
|
||||
say_when_triggered = ""
|
||||
|
||||
/datum/action/boss/wizard_mimic/Trigger()
|
||||
|
||||
@@ -105,6 +105,7 @@ IGNORE_PROC_IF_NOT_TARGET(attack_slime)
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/curseblob/attacked_by(obj/item/I, mob/living/L)
|
||||
if(L != set_target)
|
||||
L.changeNext_move(I.click_delay) //pre_attacked_by not called
|
||||
return
|
||||
return ..()
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
throw_speed = 3
|
||||
throw_range = 5
|
||||
force = 5
|
||||
item_flags = NEEDS_PERMIT | NO_ATTACK_CHAIN_SOFT_STAMCRIT
|
||||
item_flags = NEEDS_PERMIT
|
||||
attack_verb = list("struck", "hit", "bashed")
|
||||
|
||||
var/fire_sound = "gunshot"
|
||||
@@ -140,12 +140,13 @@
|
||||
to_chat(user, "<span class='danger'>*click*</span>")
|
||||
playsound(src, "gun_dry_fire", 30, 1)
|
||||
|
||||
/obj/item/gun/proc/shoot_live_shot(mob/living/user as mob|obj, pointblank = 0, mob/pbtarget = null, message = 1)
|
||||
/obj/item/gun/proc/shoot_live_shot(mob/living/user, pointblank = FALSE, mob/pbtarget, message = 1, stam_cost = 0)
|
||||
if(recoil)
|
||||
shake_camera(user, recoil + 1, recoil)
|
||||
|
||||
if(isliving(user)) //CIT CHANGE - makes gun recoil cause staminaloss
|
||||
user.adjustStaminaLossBuffered(getstamcost(user)*(firing && burst_size >= 2 ? 1/burst_size : 1)) //CIT CHANGE - ditto
|
||||
if(stam_cost) //CIT CHANGE - makes gun recoil cause staminaloss
|
||||
var/safe_cost = clamp(stam_cost, 0, STAMINA_NEAR_CRIT - user.getStaminaLoss())*(firing && burst_size >= 2 ? 1/burst_size : 1)
|
||||
user.adjustStaminaLossBuffered(safe_cost) //CIT CHANGE - ditto
|
||||
|
||||
if(suppressed)
|
||||
playsound(user, fire_sound, 10, 1)
|
||||
@@ -172,9 +173,10 @@
|
||||
return
|
||||
if(firing)
|
||||
return
|
||||
if(IS_STAMCRIT(user)) //respect stamina softcrit
|
||||
to_chat(user, "<span class='warning'>You are too exhausted to fire [src]!</span>")
|
||||
return
|
||||
var/stamloss = user.getStaminaLoss()
|
||||
if(stamloss >= STAMINA_NEAR_SOFTCRIT) //The more tired you are, the less damage you do.
|
||||
var/penalty = (stamloss - STAMINA_NEAR_SOFTCRIT)/(STAMINA_NEAR_CRIT - STAMINA_NEAR_SOFTCRIT)*STAM_CRIT_GUN_DELAY
|
||||
user.changeNext_move(CLICK_CD_RANGE+(CLICK_CD_RANGE*penalty))
|
||||
if(flag) //It's adjacent, is the user, or is on the user's person
|
||||
if(target in user.contents) //can't shoot stuff inside us.
|
||||
return
|
||||
@@ -216,7 +218,7 @@
|
||||
var/loop_counter = 0
|
||||
|
||||
if(user)
|
||||
bonus_spread += getinaccuracy(user) //CIT CHANGE - adds bonus spread while not aiming
|
||||
bonus_spread = getinaccuracy(user, bonus_spread, stamloss) //CIT CHANGE - adds bonus spread while not aiming
|
||||
if(ishuman(user) && user.a_intent == INTENT_HARM && weapon_weight <= WEAPON_LIGHT)
|
||||
var/mob/living/carbon/human/H = user
|
||||
for(var/obj/item/gun/G in H.held_items)
|
||||
@@ -225,9 +227,11 @@
|
||||
else if(G.can_trigger_gun(user))
|
||||
bonus_spread += 24 * G.weapon_weight * G.dualwield_spread_mult
|
||||
loop_counter++
|
||||
addtimer(CALLBACK(G, /obj/item/gun.proc/process_fire, target, user, TRUE, params, null, bonus_spread), loop_counter)
|
||||
var/stam_cost = G.getstamcost(user)
|
||||
addtimer(CALLBACK(G, /obj/item/gun.proc/process_fire, target, user, TRUE, params, null, bonus_spread, stam_cost), loop_counter)
|
||||
|
||||
process_fire(target, user, TRUE, params, null, bonus_spread)
|
||||
var/stam_cost = getstamcost(user)
|
||||
process_fire(target, user, TRUE, params, null, bonus_spread, stam_cost)
|
||||
|
||||
/obj/item/gun/can_trigger_gun(mob/living/user)
|
||||
. = ..()
|
||||
@@ -258,21 +262,21 @@
|
||||
/obj/item/gun/proc/on_cooldown()
|
||||
return busy_action || firing || ((last_fire + fire_delay) > world.time)
|
||||
|
||||
/obj/item/gun/proc/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0)
|
||||
/obj/item/gun/proc/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0, stam_cost = 0)
|
||||
add_fingerprint(user)
|
||||
|
||||
if(on_cooldown())
|
||||
return
|
||||
firing = TRUE
|
||||
. = do_fire(target, user, message, params, zone_override, bonus_spread)
|
||||
. = do_fire(target, user, message, params, zone_override, bonus_spread, stam_cost)
|
||||
firing = FALSE
|
||||
last_fire = world.time
|
||||
|
||||
if(user)
|
||||
user.update_inv_hands()
|
||||
SEND_SIGNAL(user, COMSIG_LIVING_GUN_PROCESS_FIRE, target, params, zone_override)
|
||||
SEND_SIGNAL(user, COMSIG_LIVING_GUN_PROCESS_FIRE, target, params, zone_override, bonus_spread, stam_cost)
|
||||
|
||||
/obj/item/gun/proc/do_fire(atom/target, mob/living/user, message = TRUE, params, zone_override = "", bonus_spread = 0)
|
||||
/obj/item/gun/proc/do_fire(atom/target, mob/living/user, message = TRUE, params, zone_override = "", bonus_spread = 0, stam_cost = 0)
|
||||
var/sprd = 0
|
||||
var/randomized_gun_spread = 0
|
||||
var/rand_spr = rand()
|
||||
@@ -290,7 +294,7 @@
|
||||
sleep(burst_shot_delay)
|
||||
if(QDELETED(src))
|
||||
break
|
||||
do_burst_shot(user, target, message, params, zone_override, sprd, randomized_gun_spread, randomized_bonus_spread, rand_spr, i)
|
||||
do_burst_shot(user, target, message, params, zone_override, sprd, randomized_gun_spread, randomized_bonus_spread, rand_spr, i, stam_cost)
|
||||
else
|
||||
if(chambered)
|
||||
sprd = round((rand() - 0.5) * DUALWIELD_PENALTY_EXTRA_MULTIPLIER * (randomized_gun_spread + randomized_bonus_spread))
|
||||
@@ -300,9 +304,9 @@
|
||||
return
|
||||
else
|
||||
if(get_dist(user, target) <= 1) //Making sure whether the target is in vicinity for the pointblank shot
|
||||
shoot_live_shot(user, 1, target, message)
|
||||
shoot_live_shot(user, 1, target, message, stam_cost)
|
||||
else
|
||||
shoot_live_shot(user, 0, target, message)
|
||||
shoot_live_shot(user, 0, target, message, stam_cost)
|
||||
else
|
||||
shoot_with_empty_chamber(user)
|
||||
return
|
||||
@@ -312,7 +316,7 @@
|
||||
SSblackbox.record_feedback("tally", "gun_fired", 1, type)
|
||||
return TRUE
|
||||
|
||||
/obj/item/gun/proc/do_burst_shot(mob/living/user, atom/target, message = TRUE, params=null, zone_override = "", sprd = 0, randomized_gun_spread = 0, randomized_bonus_spread = 0, rand_spr = 0, iteration = 0)
|
||||
/obj/item/gun/proc/do_burst_shot(mob/living/user, atom/target, message = TRUE, params=null, zone_override = "", sprd = 0, randomized_gun_spread = 0, randomized_bonus_spread = 0, rand_spr = 0, iteration = 0, stam_cost = 0)
|
||||
if(!user || !firing)
|
||||
firing = FALSE
|
||||
return FALSE
|
||||
@@ -336,9 +340,9 @@
|
||||
return FALSE
|
||||
else
|
||||
if(get_dist(user, target) <= 1) //Making sure whether the target is in vicinity for the pointblank shot
|
||||
shoot_live_shot(user, 1, target, message)
|
||||
shoot_live_shot(user, 1, target, message, stam_cost)
|
||||
else
|
||||
shoot_live_shot(user, 0, target, message)
|
||||
shoot_live_shot(user, 0, target, message, stam_cost)
|
||||
if (iteration >= burst_size)
|
||||
firing = FALSE
|
||||
else
|
||||
@@ -349,20 +353,21 @@
|
||||
update_icon()
|
||||
return TRUE
|
||||
|
||||
/obj/item/gun/attack(mob/M as mob, mob/user)
|
||||
/obj/item/gun/attack(mob/living/M, mob/user)
|
||||
if(user.a_intent == INTENT_HARM) //Flogging
|
||||
if(bayonet)
|
||||
M.attackby(bayonet, user)
|
||||
attack_delay_done = TRUE
|
||||
return
|
||||
else
|
||||
return ..()
|
||||
return
|
||||
attack_delay_done = TRUE //we are firing the gun, not bashing people with its butt.
|
||||
|
||||
/obj/item/gun/attack_obj(obj/O, mob/user)
|
||||
if(user.a_intent == INTENT_HARM)
|
||||
if(bayonet)
|
||||
O.attackby(bayonet, user)
|
||||
return
|
||||
return TRUE
|
||||
return ..()
|
||||
|
||||
/obj/item/gun/attackby(obj/item/I, mob/user, params)
|
||||
@@ -498,7 +503,7 @@
|
||||
if(chambered && chambered.BB)
|
||||
chambered.BB.damage *= 5
|
||||
|
||||
process_fire(target, user, TRUE, params)
|
||||
process_fire(target, user, TRUE, params, stam_cost = getstamcost(user))
|
||||
|
||||
/obj/item/gun/proc/unlock() //used in summon guns and as a convience for admins
|
||||
if(pin)
|
||||
@@ -566,7 +571,25 @@
|
||||
chambered = null
|
||||
update_icon()
|
||||
|
||||
/obj/item/gun/proc/getinaccuracy(mob/user)
|
||||
if(SEND_SIGNAL(user, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_INACTIVE))
|
||||
return ((weapon_weight * 25) * inaccuracy_modifier)
|
||||
return 0
|
||||
/obj/item/gun/proc/getinaccuracy(mob/living/user, bonus_spread, stamloss)
|
||||
if(inaccuracy_modifier == 0)
|
||||
return bonus_spread
|
||||
var/base_inaccuracy = weapon_weight * 25 * inaccuracy_modifier
|
||||
var/aiming_delay = 0 //Otherwise aiming would be meaningless for slower guns such as sniper rifles and launchers.
|
||||
if(fire_delay)
|
||||
var/penalty = (last_fire + GUN_AIMING_TIME + fire_delay) - world.time
|
||||
if(penalty > 0) //Yet we only penalize users firing it multiple times in a haste. fire_delay isn't necessarily cumbersomeness.
|
||||
aiming_delay = penalty
|
||||
if(SEND_SIGNAL(user, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_ACTIVE)) //To be removed in favor of something less tactless later.
|
||||
base_inaccuracy /= 1.5
|
||||
if(stamloss > STAMINA_NEAR_SOFTCRIT) //This can null out the above bonus.
|
||||
base_inaccuracy *= 1 + (stamloss - STAMINA_NEAR_SOFTCRIT)/(STAMINA_NEAR_CRIT - STAMINA_NEAR_SOFTCRIT)*0.5
|
||||
var/mult = max((GUN_AIMING_TIME + aiming_delay + user.last_click_move - world.time)/GUN_AIMING_TIME, -0.5) //Yes, there is a bonus for taking time aiming.
|
||||
if(mult < 0) //accurate weapons should provide a proper bonus with negative inaccuracy. the opposite is true too.
|
||||
mult *= 1/inaccuracy_modifier
|
||||
return max(bonus_spread + (base_inaccuracy * mult), 0) //no negative spread.
|
||||
|
||||
/obj/item/gun/proc/getstamcost(mob/living/carbon/user)
|
||||
. = recoil
|
||||
if(user && !user.has_gravity())
|
||||
. = recoil*5
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
else
|
||||
icon_state = "[initial(icon_state)][suppressed ? "-suppressed" : ""][sawn_off ? "-sawn" : ""]"
|
||||
|
||||
/obj/item/gun/ballistic/process_chamber(empty_chamber = 1)
|
||||
/obj/item/gun/ballistic/process_chamber(mob/living/user, empty_chamber = 1)
|
||||
var/obj/item/ammo_casing/AC = chambered //Find chambered round
|
||||
if(istype(AC)) //there's a chambered round
|
||||
if(casing_ejector)
|
||||
|
||||
@@ -365,7 +365,7 @@
|
||||
can_unsuppress = TRUE
|
||||
can_suppress = TRUE
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
inaccuracy_modifier = 0
|
||||
inaccuracy_modifier = 0.5
|
||||
zoomable = TRUE
|
||||
zoom_amt = 10 //Long range, enough to see in front of you, but no tiles behind you.
|
||||
zoom_out_amt = 13
|
||||
|
||||
@@ -130,7 +130,7 @@
|
||||
else
|
||||
qdel(src)
|
||||
|
||||
/obj/item/gun/ballistic/minigun/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0)
|
||||
/obj/item/gun/ballistic/minigun/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0, stam_cost = 0)
|
||||
if(ammo_pack)
|
||||
if(ammo_pack.overheat < ammo_pack.overheat_max)
|
||||
ammo_pack.overheat += burst_size
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
name = "grenade launcher"
|
||||
icon_state = "dshotgun-sawn"
|
||||
item_state = "gun"
|
||||
inaccuracy_modifier = 0
|
||||
inaccuracy_modifier = 0.5
|
||||
mag_type = /obj/item/ammo_box/magazine/internal/grenadelauncher
|
||||
fire_sound = 'sound/weapons/grenadelaunch.ogg'
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
@@ -87,7 +87,7 @@
|
||||
pin = /obj/item/firing_pin/implant/pindicate
|
||||
burst_size = 1
|
||||
fire_delay = 0
|
||||
inaccuracy_modifier = 0
|
||||
inaccuracy_modifier = 0.25
|
||||
casing_ejector = FALSE
|
||||
weapon_weight = WEAPON_HEAVY
|
||||
magazine_wording = "rocket"
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
spread = 0
|
||||
recoil = 0.1
|
||||
casing_ejector = FALSE
|
||||
inaccuracy_modifier = 0
|
||||
inaccuracy_modifier = 0.15
|
||||
dualwield_spread_mult = 1.4
|
||||
weapon_weight = WEAPON_MEDIUM
|
||||
w_class = WEIGHT_CLASS_BULKY
|
||||
@@ -46,7 +46,7 @@
|
||||
return 0
|
||||
. = ..()
|
||||
|
||||
/obj/item/gun/ballistic/automatic/magrifle/shoot_live_shot()
|
||||
/obj/item/gun/ballistic/automatic/magrifle/shoot_live_shot(mob/living/user, pointblank = FALSE, mob/pbtarget, message = 1, stam_cost = 0)
|
||||
var/obj/item/ammo_casing/caseless/magnetic/shot = chambered
|
||||
cell.use(shot.energy_cost)
|
||||
. = ..()
|
||||
|
||||
@@ -102,7 +102,7 @@
|
||||
. = ..()
|
||||
safe_calibers = magazine.caliber
|
||||
|
||||
/obj/item/gun/ballistic/revolver/detective/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0)
|
||||
/obj/item/gun/ballistic/revolver/detective/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0, stam_cost = 0)
|
||||
if(chambered && !(chambered.caliber in safe_calibers))
|
||||
if(prob(70 - (magazine.ammo_count() * 10))) //minimum probability of 10, maximum of 60
|
||||
playsound(user, fire_sound, 50, 1)
|
||||
@@ -242,7 +242,7 @@
|
||||
user.visible_message("<span class='danger'>*click*</span>")
|
||||
playsound(src, "gun_dry_fire", 30, 1)
|
||||
|
||||
/obj/item/gun/ballistic/revolver/russian/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0)
|
||||
/obj/item/gun/ballistic/revolver/russian/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0, stam_cost = 0)
|
||||
add_fingerprint(user)
|
||||
playsound(src, "gun_dry_fire", 30, TRUE)
|
||||
user.visible_message("<span class='danger'>[user.name] tries to fire \the [src] at the same time, but only succeeds at looking like an idiot.</span>", "<span class='danger'>\The [src]'s anti-combat mechanism prevents you from firing it at the same time!</span>")
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
A.update_icon()
|
||||
update_icon()
|
||||
|
||||
/obj/item/gun/ballistic/shotgun/process_chamber(empty_chamber = 0)
|
||||
/obj/item/gun/ballistic/shotgun/process_chamber(mob/living/user, empty_chamber = 0)
|
||||
return ..() //changed argument value
|
||||
|
||||
/obj/item/gun/ballistic/shotgun/chamber_round()
|
||||
@@ -116,7 +116,7 @@
|
||||
icon_state = "moistnugget"
|
||||
item_state = "moistnugget"
|
||||
slot_flags = 0 //no ITEM_SLOT_BACK sprite, alas
|
||||
inaccuracy_modifier = 0
|
||||
inaccuracy_modifier = 0.5
|
||||
mag_type = /obj/item/ammo_box/magazine/internal/boltaction
|
||||
var/bolt_open = FALSE
|
||||
can_bayonet = TRUE
|
||||
@@ -191,7 +191,7 @@
|
||||
/obj/item/gun/ballistic/shotgun/boltaction/enchanted/attack_self()
|
||||
return
|
||||
|
||||
/obj/item/gun/ballistic/shotgun/boltaction/enchanted/shoot_live_shot(mob/living/user as mob|obj, pointblank = 0, mob/pbtarget = null, message = 1)
|
||||
/obj/item/gun/ballistic/shotgun/boltaction/enchanted/shoot_live_shot(mob/living/user, pointblank = FALSE, mob/pbtarget, message = 1, stam_cost = 0)
|
||||
..()
|
||||
if(guns_left)
|
||||
var/obj/item/gun/ballistic/shotgun/boltaction/enchanted/GUN = new gun_type
|
||||
@@ -205,7 +205,7 @@
|
||||
|
||||
// Automatic Shotguns//
|
||||
|
||||
/obj/item/gun/ballistic/shotgun/automatic/shoot_live_shot(mob/living/user as mob|obj)
|
||||
/obj/item/gun/ballistic/shotgun/automatic/shoot_live_shot(mob/living/user, pointblank = FALSE, mob/pbtarget, message = 1, stam_cost = 0)
|
||||
..()
|
||||
src.pump(user)
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
casing_ejector = FALSE
|
||||
can_suppress = FALSE
|
||||
|
||||
/obj/item/gun/ballistic/shotgun/toy/process_chamber(empty_chamber = 0)
|
||||
/obj/item/gun/ballistic/shotgun/toy/process_chamber(mob/living/user, empty_chamber = 0)
|
||||
..()
|
||||
if(chambered && !chambered.BB)
|
||||
qdel(chambered)
|
||||
|
||||
@@ -127,12 +127,12 @@
|
||||
chambered = null //either way, released the prepared shot
|
||||
recharge_newshot() //try to charge a new shot
|
||||
|
||||
/obj/item/gun/energy/do_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0)
|
||||
/obj/item/gun/energy/do_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0, stam_cost = 0)
|
||||
if(!chambered && can_shoot())
|
||||
process_chamber() // If the gun was drained and then recharged, load a new shot.
|
||||
return ..()
|
||||
|
||||
/obj/item/gun/energy/do_burst_shot(mob/living/user, atom/target, message = TRUE, params = null, zone_override="", sprd = 0, randomized_gun_spread = 0, randomized_bonus_spread = 0, rand_spr = 0, iteration = 0)
|
||||
/obj/item/gun/energy/do_burst_shot(mob/living/user, atom/target, message = TRUE, params = null, zone_override="", sprd = 0, randomized_gun_spread = 0, randomized_bonus_spread = 0, rand_spr = 0, iteration = 0, stam_cost = 0)
|
||||
if(!chambered && can_shoot())
|
||||
process_chamber() // Ditto.
|
||||
return ..()
|
||||
|
||||
@@ -237,7 +237,7 @@
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/obj/item/gun/energy/dueling/process_fire(atom/target, mob/living/user, message, params, zone_override, bonus_spread)
|
||||
/obj/item/gun/energy/dueling/process_fire(atom/target, mob/living/user, message, params, zone_override, bonus_spread = 0, stam_cost = 0)
|
||||
if(duel.state == DUEL_READY)
|
||||
duel.confirmations[src] = TRUE
|
||||
to_chat(user,"<span class='notice'>You confirm your readiness.</span>")
|
||||
|
||||
@@ -110,7 +110,7 @@
|
||||
fail_tick--
|
||||
..()
|
||||
|
||||
/obj/item/gun/energy/e_gun/nuclear/shoot_live_shot()
|
||||
/obj/item/gun/energy/e_gun/nuclear/shoot_live_shot(mob/living/user, pointblank = FALSE, mob/pbtarget, message = 1, stam_cost = 0)
|
||||
failcheck()
|
||||
update_icon()
|
||||
..()
|
||||
|
||||
@@ -60,6 +60,12 @@
|
||||
else
|
||||
cut_overlays()
|
||||
|
||||
/obj/item/gun/energy/kinetic_accelerator/getinaccuracy(mob/living/user, bonus_spread, stamloss)
|
||||
var/old_fire_delay = fire_delay //It's pretty irrelevant tbh but whatever.
|
||||
fire_delay = overheat_time
|
||||
. = ..()
|
||||
fire_delay = old_fire_delay
|
||||
|
||||
/obj/item/gun/energy/kinetic_accelerator/examine(mob/user)
|
||||
. = ..()
|
||||
if(max_mod_capacity)
|
||||
@@ -128,7 +134,7 @@
|
||||
if(!holds_charge)
|
||||
empty()
|
||||
|
||||
/obj/item/gun/energy/kinetic_accelerator/shoot_live_shot()
|
||||
/obj/item/gun/energy/kinetic_accelerator/shoot_live_shot(mob/living/user, pointblank = FALSE, mob/pbtarget, message = 1, stam_cost = 0)
|
||||
. = ..()
|
||||
attempt_reload()
|
||||
|
||||
@@ -207,6 +213,12 @@
|
||||
var/obj/item/gun/energy/kinetic_accelerator/KA = loc
|
||||
KA.modify_projectile(BB)
|
||||
|
||||
/obj/item/gun/energy/kinetic_accelerator/getstamcost(mob/living/carbon/user)
|
||||
if(user && !lavaland_equipment_pressure_check(get_turf(user)))
|
||||
return 0
|
||||
else
|
||||
return ..()
|
||||
|
||||
//Projectiles
|
||||
/obj/item/projectile/kinetic
|
||||
name = "kinetic force"
|
||||
|
||||
@@ -62,7 +62,7 @@
|
||||
slot_flags = ITEM_SLOT_BACK
|
||||
w_class = WEIGHT_CLASS_BULKY
|
||||
weapon_weight = WEAPON_MEDIUM
|
||||
inaccuracy_modifier = 0.5
|
||||
inaccuracy_modifier = 0.7
|
||||
force = 10
|
||||
throwforce = 10
|
||||
cell_type = /obj/item/stock_parts/cell/lascarbine
|
||||
|
||||
@@ -89,7 +89,7 @@
|
||||
suppressed = TRUE
|
||||
ammo_type = list(/obj/item/ammo_casing/energy/bolt)
|
||||
weapon_weight = WEAPON_LIGHT
|
||||
inaccuracy_modifier = 0
|
||||
inaccuracy_modifier = 0.25
|
||||
obj_flags = 0
|
||||
overheat_time = 20
|
||||
holds_charge = TRUE
|
||||
@@ -126,7 +126,7 @@
|
||||
attack_verb = list("attacked", "slashed", "cut", "sliced")
|
||||
force = 12
|
||||
sharpness = IS_SHARP
|
||||
inaccuracy_modifier = 0
|
||||
inaccuracy_modifier = 0.25
|
||||
can_charge = 0
|
||||
|
||||
heat = 3800
|
||||
@@ -182,7 +182,7 @@
|
||||
item_state = null
|
||||
icon_state = "wormhole_projector"
|
||||
pin = null
|
||||
inaccuracy_modifier = 0
|
||||
inaccuracy_modifier = 0.25
|
||||
var/obj/effect/portal/p_blue
|
||||
var/obj/effect/portal/p_orange
|
||||
var/atmos_link = FALSE
|
||||
@@ -318,7 +318,7 @@
|
||||
icon_state = "emitter_carbine"
|
||||
force = 12
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
inaccuracy_modifier = 0
|
||||
inaccuracy_modifier = 0.25
|
||||
cell_type = /obj/item/stock_parts/cell/super
|
||||
ammo_type = list(/obj/item/ammo_casing/energy/emitter)
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
/obj/item/projectile/magic/death, /obj/item/projectile/magic/teleport, /obj/item/projectile/magic/door, /obj/item/projectile/magic/aoe/fireball,
|
||||
/obj/item/projectile/magic/spellblade, /obj/item/projectile/magic/arcane_barrage, /obj/item/projectile/magic/locker)
|
||||
|
||||
/obj/item/gun/magic/staff/chaos/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0)
|
||||
/obj/item/gun/magic/staff/chaos/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0, stam_cost = 0)
|
||||
chambered.projectile_type = pick(allowed_projectile_types)
|
||||
. = ..()
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
throw_speed = 3
|
||||
throw_range = 7
|
||||
force = 4
|
||||
inaccuracy_modifier = 0
|
||||
inaccuracy_modifier = 0.25
|
||||
custom_materials = list(/datum/material/iron=2000)
|
||||
clumsy_check = FALSE
|
||||
fire_sound = 'sound/items/syringeproj.ogg'
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
/obj/item/gun/grenadelauncher/can_shoot()
|
||||
return grenades.len
|
||||
|
||||
/obj/item/gun/grenadelauncher/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0)
|
||||
/obj/item/gun/grenadelauncher/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0, stam_cost = 0)
|
||||
user.visible_message("<span class='danger'>[user] fired a grenade!</span>", \
|
||||
"<span class='danger'>You fire the grenade launcher!</span>")
|
||||
var/obj/item/grenade/F = grenades[1] //Now with less copypasta!
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
on_beam_release(current_target)
|
||||
current_target = null
|
||||
|
||||
/obj/item/gun/medbeam/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0)
|
||||
/obj/item/gun/medbeam/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0, stam_cost = 0)
|
||||
if(isliving(user))
|
||||
add_fingerprint(user)
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
throw_speed = 3
|
||||
throw_range = 7
|
||||
force = 4
|
||||
inaccuracy_modifier = 0
|
||||
inaccuracy_modifier = 0.25
|
||||
custom_materials = list(/datum/material/iron=2000)
|
||||
clumsy_check = 0
|
||||
fire_sound = 'sound/items/syringeproj.ogg'
|
||||
@@ -160,7 +160,7 @@
|
||||
item_state = "blowgun"
|
||||
fire_sound = 'sound/items/syringeproj.ogg'
|
||||
|
||||
/obj/item/gun/syringe/blowgun/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0)
|
||||
/obj/item/gun/syringe/blowgun/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0, stam_cost = 0)
|
||||
visible_message("<span class='danger'>[user] starts aiming with a blowgun!</span>")
|
||||
if(do_after(user, 25, target = src))
|
||||
user.adjustStaminaLoss(20)
|
||||
|
||||
@@ -272,7 +272,7 @@
|
||||
return TRUE
|
||||
|
||||
var/distance = get_dist(T, starting) // Get the distance between the turf shot from and the mob we hit and use that for the calculations.
|
||||
if(check_zone(def_zone) != BODY_ZONE_CHEST)
|
||||
if(def_zone && check_zone(def_zone) != BODY_ZONE_CHEST)
|
||||
def_zone = ran_zone(def_zone, max(100-(7*distance), 5) * zone_accuracy_factor) //Lower accurancy/longer range tradeoff. 7 is a balanced number to use.
|
||||
|
||||
if(isturf(A) && hitsound_wall)
|
||||
@@ -548,7 +548,7 @@
|
||||
var/safety = CEILING(pixel_increment_amount / world.icon_size, 1) * 2 + 1
|
||||
while(T != loc)
|
||||
if(!--safety)
|
||||
CRASH("Projectile took more than pixel incrememnt speed times 2 to get to its location, this is probably something seriously scuffed going on.")
|
||||
CRASH("[type] took too long (allowed: [CEILING(pixel_increment_amount/world.icon_size,1)*2] moves) to get to its location.")
|
||||
step_towards(src, T)
|
||||
if(QDELETED(src))
|
||||
return
|
||||
|
||||
@@ -326,19 +326,18 @@
|
||||
var/datum/reagent/R = addiction
|
||||
if(C && R)
|
||||
R.addiction_stage++
|
||||
switch(R.addiction_stage)
|
||||
if(1 to R.addiction_stage1_end)
|
||||
need_mob_update += R.addiction_act_stage1(C)
|
||||
if(R.addiction_stage1_end to R.addiction_stage2_end)
|
||||
need_mob_update += R.addiction_act_stage2(C)
|
||||
if(R.addiction_stage2_end to R.addiction_stage3_end)
|
||||
need_mob_update += R.addiction_act_stage3(C)
|
||||
if(R.addiction_stage3_end to R.addiction_stage4_end)
|
||||
need_mob_update += R.addiction_act_stage4(C)
|
||||
if(R.addiction_stage4_end to INFINITY)
|
||||
remove_addiction(R)
|
||||
else
|
||||
SEND_SIGNAL(C, COMSIG_CLEAR_MOOD_EVENT, "[R.type]_overdose")
|
||||
if(1 <= R.addiction_stage && R.addiction_stage <= R.addiction_stage1_end)
|
||||
need_mob_update += R.addiction_act_stage1(C)
|
||||
else if(R.addiction_stage1_end < R.addiction_stage && R.addiction_stage <= R.addiction_stage2_end)
|
||||
need_mob_update += R.addiction_act_stage2(C)
|
||||
else if(R.addiction_stage2_end < R.addiction_stage && R.addiction_stage <= R.addiction_stage3_end)
|
||||
need_mob_update += R.addiction_act_stage3(C)
|
||||
else if(R.addiction_stage3_end < R.addiction_stage && R.addiction_stage <= R.addiction_stage4_end)
|
||||
need_mob_update += R.addiction_act_stage4(C)
|
||||
else if(R.addiction_stage4_end < R.addiction_stage)
|
||||
remove_addiction(R)
|
||||
else
|
||||
SEND_SIGNAL(C, COMSIG_CLEAR_MOOD_EVENT, "[R.type]_overdose")
|
||||
addiction_tick++
|
||||
if(C && need_mob_update) //some of the metabolized reagents had effects on the mob that requires some updates.
|
||||
C.updatehealth()
|
||||
|
||||
@@ -213,6 +213,11 @@
|
||||
for(var/datum/reagent/R in beaker.reagents.reagent_list)
|
||||
. += "<span class='notice'>- [R.volume] units of [R.name].</span>"
|
||||
|
||||
/obj/machinery/reagentgrinder/AltClick(mob/user)
|
||||
. = ..()
|
||||
if(istype(user) && user.canUseTopic(src, BE_CLOSE, FALSE, NO_TK))
|
||||
replace_beaker(user)
|
||||
|
||||
/obj/machinery/reagentgrinder/proc/eject(mob/user)
|
||||
for(var/i in holdingitems)
|
||||
var/obj/item/O = i
|
||||
|
||||
@@ -25,14 +25,8 @@
|
||||
/obj/item/reagent_containers/pill/attack_self(mob/user)
|
||||
return
|
||||
|
||||
/obj/item/reagent_containers/pill/get_w_volume()
|
||||
switch(reagents.total_volume)
|
||||
if(0 to 9.5)
|
||||
return 1
|
||||
if(9.5 to 25)
|
||||
return DEFAULT_VOLUME_TINY
|
||||
else
|
||||
return DEFAULT_VOLUME_SMALL
|
||||
/obj/item/reagent_containers/pill/get_w_volume() // DEFAULT_VOLUME_TINY at 25u, DEFAULT_VOLUME_SMALL at 50u
|
||||
return DEFAULT_VOLUME_TINY/2 + reagents.total_volume / reagents.maximum_volume * DEFAULT_VOLUME_TINY
|
||||
|
||||
/obj/item/reagent_containers/pill/attack(mob/M, mob/user, def_zone)
|
||||
if(!canconsume(M, user))
|
||||
|
||||
@@ -707,3 +707,57 @@
|
||||
build_path = /obj/item/clothing/gloves/tackler/rocket
|
||||
category = list("Equipment")
|
||||
departmental_flags = DEPARTMENTAL_FLAG_SECURITY
|
||||
|
||||
/////////////////////////////////////////
|
||||
/////////////Internal Tanks//////////////
|
||||
/////////////////////////////////////////
|
||||
|
||||
/datum/design/oxygen_tank
|
||||
name = "Oxygen Tank"
|
||||
desc = "An empty oxygen tank."
|
||||
id = "oxygen_tank"
|
||||
build_type = PROTOLATHE
|
||||
materials = list(/datum/material/iron = 2000)
|
||||
build_path = /obj/item/tank/internals/oxygen/empty
|
||||
category = list("Equipment")
|
||||
departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING
|
||||
|
||||
/datum/design/plasma_tank
|
||||
name = "Plasma Tank"
|
||||
desc = "An empty plasma tank."
|
||||
id = "plasma_tank"
|
||||
build_type = PROTOLATHE
|
||||
materials = list(/datum/material/iron = 2000)
|
||||
build_path = /obj/item/tank/internals/plasma/empty
|
||||
category = list("Equipment")
|
||||
departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING
|
||||
|
||||
/datum/design/emergency_oxygen
|
||||
name = "Emergency Oxygen Tank"
|
||||
desc = "A small emergency oxygen tank."
|
||||
id = "emergency_oxygen"
|
||||
build_type = PROTOLATHE
|
||||
materials = list(/datum/material/iron = 1000)
|
||||
build_path = /obj/item/tank/internals/emergency_oxygen/empty
|
||||
category = list("Equipment")
|
||||
departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING
|
||||
|
||||
/datum/design/plasma_belt_tank
|
||||
name = "Plasmaman Belt Tank"
|
||||
desc = "A small tank of plasma for plasmamen."
|
||||
id = "plasmaman_tank_belt"
|
||||
build_type = PROTOLATHE
|
||||
materials = list(/datum/material/iron = 1000)
|
||||
build_path = /obj/item/tank/internals/plasmaman/belt/empty
|
||||
category = list("Equipment")
|
||||
departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING
|
||||
|
||||
/datum/design/emergency_oxygen_engi
|
||||
name = "Engineering Emergency Oxygen Tank"
|
||||
desc = "An emergency oxygen tank for engineers."
|
||||
id = "emergency_oxygen_engi"
|
||||
build_type = PROTOLATHE
|
||||
materials = list(/datum/material/iron = 1000)
|
||||
build_path = /obj/item/tank/internals/emergency_oxygen/engi/empty
|
||||
category = list("Equipment")
|
||||
departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING
|
||||
@@ -7,7 +7,8 @@
|
||||
prereq_ids = list("base")
|
||||
design_ids = list("solarcontrol", "recharger", "powermonitor", "rped", "pacman", "adv_capacitor", "adv_scanning", "emitter", "high_cell", "adv_matter_bin",
|
||||
"atmosalerts", "atmos_control", "recycler", "autolathe", "autolathe_secure", "high_micro_laser", "nano_mani", "mesons", "thermomachine", "rad_collector", "tesla_coil", "grounding_rod",
|
||||
"apc_control", "power control", "airlock_board", "firelock_board", "airalarm_electronics", "firealarm_electronics", "cell_charger", "stack_console", "stack_machine", "rcd_ammo")
|
||||
"apc_control", "power control", "airlock_board", "firelock_board", "airalarm_electronics", "firealarm_electronics", "cell_charger", "stack_console", "stack_machine", "rcd_ammo","oxygen_tank",
|
||||
"plasma_tank", "emergency_oxygen", "emergency_oxygen_engi", "plasmaman_tank_belt")
|
||||
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 6000)
|
||||
|
||||
/datum/techweb_node/adv_engi
|
||||
|
||||
@@ -23,6 +23,7 @@ GLOBAL_DATUM_INIT(keycard_events, /datum/events, new)
|
||||
var/event = ""
|
||||
var/obj/machinery/keycard_auth/event_source
|
||||
var/mob/triggerer = null
|
||||
var/obj/item/card/id/first_id = null
|
||||
var/waiting = 0
|
||||
|
||||
/obj/machinery/keycard_auth/Initialize()
|
||||
@@ -59,32 +60,37 @@ GLOBAL_DATUM_INIT(keycard_events, /datum/events, new)
|
||||
return ..()
|
||||
|
||||
/obj/machinery/keycard_auth/ui_act(action, params)
|
||||
if(..() || waiting || !allowed(usr))
|
||||
if(..() || waiting)
|
||||
return
|
||||
var/obj/item/card/id/ID = usr.get_idcard(TRUE)
|
||||
if(!ID || !istype(ID))
|
||||
return
|
||||
if(!check_access(ID))
|
||||
return
|
||||
switch(action)
|
||||
if("red_alert")
|
||||
if(!event_source)
|
||||
sendEvent(KEYCARD_RED_ALERT)
|
||||
sendEvent(KEYCARD_RED_ALERT, ID)
|
||||
. = TRUE
|
||||
if("emergency_maint")
|
||||
if(!event_source)
|
||||
sendEvent(KEYCARD_EMERGENCY_MAINTENANCE_ACCESS)
|
||||
sendEvent(KEYCARD_EMERGENCY_MAINTENANCE_ACCESS, ID)
|
||||
. = TRUE
|
||||
if("auth_swipe")
|
||||
if(event_source)
|
||||
if(event_source && ID != first_id && first_id)
|
||||
event_source.trigger_event(usr)
|
||||
event_source = null
|
||||
. = TRUE
|
||||
if("bsa_unlock")
|
||||
if(!event_source)
|
||||
sendEvent(KEYCARD_BSA_UNLOCK)
|
||||
sendEvent(KEYCARD_BSA_UNLOCK, ID)
|
||||
. = TRUE
|
||||
|
||||
/obj/machinery/keycard_auth/proc/sendEvent(event_type)
|
||||
/obj/machinery/keycard_auth/proc/sendEvent(event_type, trigger_id)
|
||||
triggerer = usr
|
||||
event = event_type
|
||||
waiting = 1
|
||||
GLOB.keycard_events.fireEvent("triggerEvent", src)
|
||||
GLOB.keycard_events.fireEvent("triggerEvent", src, trigger_id)
|
||||
addtimer(CALLBACK(src, .proc/eventSent), 20)
|
||||
|
||||
/obj/machinery/keycard_auth/proc/eventSent()
|
||||
@@ -92,14 +98,16 @@ GLOBAL_DATUM_INIT(keycard_events, /datum/events, new)
|
||||
event = ""
|
||||
waiting = 0
|
||||
|
||||
/obj/machinery/keycard_auth/proc/triggerEvent(source)
|
||||
/obj/machinery/keycard_auth/proc/triggerEvent(source, trigger_id)
|
||||
icon_state = "auth_on"
|
||||
first_id = trigger_id
|
||||
event_source = source
|
||||
addtimer(CALLBACK(src, .proc/eventTriggered), 20)
|
||||
|
||||
/obj/machinery/keycard_auth/proc/eventTriggered()
|
||||
icon_state = "auth_off"
|
||||
event_source = null
|
||||
first_id = null
|
||||
|
||||
/obj/machinery/keycard_auth/proc/trigger_event(confirmer)
|
||||
log_game("[key_name(triggerer)] triggered and [key_name(confirmer)] confirmed event [event]")
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
/obj/machinery/computer/shuttle/snow_taxi
|
||||
name = "snow taxi console"
|
||||
desc = "Used to direct the snow taxi."
|
||||
circuit = /obj/item/circuitboard/computer/snow_taxi
|
||||
shuttleId = "snow_taxi"
|
||||
possible_destinations = "snaxi_nw;snaxi_ne;snaxi_s"
|
||||
no_destination_swap = TRUE
|
||||
@@ -285,7 +285,7 @@
|
||||
if(status == BODYPART_ORGANIC)
|
||||
icon = base_bp_icon || DEFAULT_BODYPART_ICON_ORGANIC
|
||||
else if(status == BODYPART_ROBOTIC)
|
||||
icon = base_bp_icon || DEFAULT_BODYPART_ICON_ROBOTIC
|
||||
icon = DEFAULT_BODYPART_ICON_ROBOTIC
|
||||
|
||||
if(owner)
|
||||
owner.updatehealth()
|
||||
|
||||
@@ -66,7 +66,6 @@
|
||||
toolspeed = 0.5
|
||||
attack_verb = list("attacked", "pinched")
|
||||
|
||||
|
||||
/obj/item/cautery
|
||||
name = "cautery"
|
||||
desc = "This stops bleeding."
|
||||
@@ -91,7 +90,6 @@
|
||||
toolspeed = 0.5
|
||||
attack_verb = list("burnt")
|
||||
|
||||
|
||||
/obj/item/surgicaldrill
|
||||
name = "surgical drill"
|
||||
desc = "You can drill using this item. You dig?"
|
||||
@@ -148,7 +146,6 @@
|
||||
toolspeed = 0.5
|
||||
attack_verb = list("drilled")
|
||||
|
||||
|
||||
/obj/item/scalpel
|
||||
name = "scalpel"
|
||||
desc = "Cut, cut, and once more cut."
|
||||
@@ -229,7 +226,6 @@
|
||||
user.visible_message("<span class='suicide'>[user] is slitting [user.p_their()] [pick("wrists", "throat", "stomach")] with [src]! It looks like [user.p_theyre()] trying to commit suicide!</span>")
|
||||
return (BRUTELOSS)
|
||||
|
||||
|
||||
/obj/item/circular_saw
|
||||
name = "circular saw"
|
||||
desc = "For heavy duty cutting."
|
||||
|
||||
@@ -60,3 +60,23 @@
|
||||
turret.pixel_x = 12
|
||||
turret.pixel_y = 4
|
||||
turret.layer = OBJ_LAYER
|
||||
|
||||
/obj/vehicle/ridden/atv/snowmobile
|
||||
name = "snowmobile"
|
||||
desc = "a tracked vehicle designed for use in the snow, it looks like it would have difficulty moving elsewhere, however."
|
||||
icon_state = "snowmobile"
|
||||
|
||||
/obj/vehicle/ridden/atv/snowmobile/Moved()
|
||||
. = ..()
|
||||
var/static/list/snow_typecache = typecacheof(list(/turf/open/floor/plating/asteroid/snow/icemoon, /turf/open/floor/plating/snowed/smoothed/icemoon))
|
||||
var/datum/component/riding/E = LoadComponent(/datum/component/riding)
|
||||
if(snow_typecache[loc.type])
|
||||
E.vehicle_move_delay = 1
|
||||
else
|
||||
E.vehicle_move_delay = 2
|
||||
|
||||
/obj/vehicle/ridden/atv/snowmobile/snowcurity
|
||||
name = "security snowmobile"
|
||||
desc = "for when you want to look like even more of a tool than riding a secway."
|
||||
icon_state = "snowcurity"
|
||||
key_type = /obj/item/key/security
|
||||
|
||||
@@ -51,10 +51,10 @@
|
||||
|
||||
/obj/vehicle/sealed/car/attacked_by(obj/item/I, mob/living/user)
|
||||
if(!I.force)
|
||||
return
|
||||
return FALSE
|
||||
if(occupants[user])
|
||||
to_chat(user, "<span class='notice'>Your attack bounces off of the car's padded interior.</span>")
|
||||
return
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/obj/vehicle/sealed/car/attack_hand(mob/living/user)
|
||||
|
||||
Reference in New Issue
Block a user