Merge branch 'master' into fruit
This commit is contained in:
@@ -423,6 +423,25 @@
|
||||
if(GLOB.master_mode == "secret")
|
||||
dat += "<A href='?src=[REF(src)];[HrefToken()];f_secret=1'>(Force Secret Mode)</A><br>"
|
||||
|
||||
if(GLOB.master_mode == "dynamic")
|
||||
if(SSticker.current_state <= GAME_STATE_PREGAME)
|
||||
dat += "<A href='?src=[REF(src)];[HrefToken()];f_dynamic_roundstart=1'>(Force Roundstart Rulesets)</A><br>"
|
||||
if (GLOB.dynamic_forced_roundstart_ruleset.len > 0)
|
||||
for(var/datum/dynamic_ruleset/roundstart/rule in GLOB.dynamic_forced_roundstart_ruleset)
|
||||
dat += {"<A href='?src=[REF(src)];[HrefToken()];f_dynamic_roundstart_remove=\ref[rule]'>-> [rule.name] <-</A><br>"}
|
||||
dat += "<A href='?src=[REF(src)];[HrefToken()];f_dynamic_roundstart_clear=1'>(Clear Rulesets)</A><br>"
|
||||
dat += "<A href='?src=[REF(src)];[HrefToken()];f_dynamic_options=1'>(Dynamic mode options)</A><br>"
|
||||
else if (SSticker.IsRoundInProgress())
|
||||
dat += "<A href='?src=[REF(src)];[HrefToken()];f_dynamic_latejoin=1'>(Force Next Latejoin Ruleset)</A><br>"
|
||||
if (SSticker && SSticker.mode && istype(SSticker.mode,/datum/game_mode/dynamic))
|
||||
var/datum/game_mode/dynamic/mode = SSticker.mode
|
||||
if (mode.forced_latejoin_rule)
|
||||
dat += {"<A href='?src=[REF(src)];[HrefToken()];f_dynamic_latejoin_clear=1'>-> [mode.forced_latejoin_rule.name] <-</A><br>"}
|
||||
dat += "<A href='?src=[REF(src)];[HrefToken()];f_dynamic_midround=1'>(Execute Midround Ruleset!)</A><br>"
|
||||
dat += "<hr/>"
|
||||
if(SSticker.IsRoundInProgress())
|
||||
dat += "<a href='?src=[REF(src)];[HrefToken()];gamemode_panel=1'>(Game Mode Panel)</a><BR>"
|
||||
|
||||
dat += {"
|
||||
<BR>
|
||||
<A href='?src=[REF(src)];[HrefToken()];create_object=1'>Create Object</A><br>
|
||||
@@ -839,6 +858,44 @@
|
||||
browser.set_content(dat.Join())
|
||||
browser.open()
|
||||
|
||||
/datum/admins/proc/dynamic_mode_options(mob/user)
|
||||
var/dat = {"
|
||||
<center><B><h2>Dynamic Mode Options</h2></B></center><hr>
|
||||
<br/>
|
||||
<h3>Common options</h3>
|
||||
<i>All these options can be changed midround.</i> <br/>
|
||||
<br/>
|
||||
<b>Force extended:</b> - Option is <a href='?src=[REF(src)];[HrefToken()];f_dynamic_force_extended=1'> <b>[GLOB.dynamic_forced_extended ? "ON" : "OFF"]</a></b>.
|
||||
<br/>This will force the round to be extended. No rulesets will be drafted. <br/>
|
||||
<br/>
|
||||
<b>No stacking:</b> - Option is <a href='?src=[REF(src)];[HrefToken()];f_dynamic_no_stacking=1'> <b>[GLOB.dynamic_no_stacking ? "ON" : "OFF"]</b></a>.
|
||||
<br/>Unless the threat goes above [GLOB.dynamic_stacking_limit], only one "round-ender" ruleset will be drafted. <br/>
|
||||
<br/>
|
||||
<b>Classic secret mode:</b> - Option is <a href='?src=[REF(src)];[HrefToken()];f_dynamic_classic_secret=1'> <b>[GLOB.dynamic_classic_secret ? "ON" : "OFF"]</b></a>.
|
||||
<br/>Only one roundstart ruleset will be drafted. Only traitors and minor roles will latespawn. <br/>
|
||||
<br/>
|
||||
<br/>
|
||||
<b>Forced threat level:</b> Current value : <a href='?src=[REF(src)];[HrefToken()];f_dynamic_forced_threat=1'><b>[GLOB.dynamic_forced_threat_level]</b></a>.
|
||||
<br/>The value threat is set to if it is higher than -1.<br/>
|
||||
<br/>
|
||||
<b>High population limit:</b> Current value : <a href='?src=[REF(src)];[HrefToken()];f_dynamic_high_pop_limit=1'><b>[GLOB.dynamic_high_pop_limit]</b></a>.
|
||||
<br/>The threshold at which "high population override" will be in effect. <br/>
|
||||
<br/>
|
||||
<b>Stacking threeshold:</b> Current value : <a href='?src=[REF(src)];[HrefToken()];f_dynamic_stacking_limit=1'><b>[GLOB.dynamic_stacking_limit]</b></a>.
|
||||
<br/>The threshold at which "round-ender" rulesets will stack. A value higher than 100 ensure this never happens. <br/>
|
||||
<h3>Advanced parameters</h3>
|
||||
Curve centre: <A href='?src=[REF(src)];[HrefToken()];f_dynamic_roundstart_centre=1'>-> [GLOB.dynamic_curve_centre] <-</A><br>
|
||||
Curve width: <A href='?src=[REF(src)];[HrefToken()];f_dynamic_roundstart_width=1'>-> [GLOB.dynamic_curve_width] <-</A><br>
|
||||
Latejoin injection delay:<br>
|
||||
Minimum: <A href='?src=[REF(src)];[HrefToken()];f_dynamic_roundstart_latejoin_min=1'>-> [GLOB.dynamic_latejoin_delay_min / 60 / 10] <-</A> Minutes<br>
|
||||
Maximum: <A href='?src=[REF(src)];[HrefToken()];f_dynamic_roundstart_latejoin_max=1'>-> [GLOB.dynamic_latejoin_delay_max / 60 / 10] <-</A> Minutes<br>
|
||||
Midround injection delay:<br>
|
||||
Minimum: <A href='?src=[REF(src)];[HrefToken()];f_dynamic_roundstart_midround_min=1'>-> [GLOB.dynamic_midround_delay_min / 60 / 10] <-</A> Minutes<br>
|
||||
Maximum: <A href='?src=[REF(src)];[HrefToken()];f_dynamic_roundstart_midround_max=1'>-> [GLOB.dynamic_midround_delay_max / 60 / 10] <-</A> Minutes<br>
|
||||
"}
|
||||
|
||||
user << browse(dat, "window=dyn_mode_options;size=900x650")
|
||||
|
||||
/datum/admins/proc/create_or_modify_area()
|
||||
set category = "Debug"
|
||||
set name = "Create or modify area"
|
||||
|
||||
@@ -291,6 +291,11 @@
|
||||
else if(href_list["editrights"])
|
||||
edit_rights_topic(href_list)
|
||||
|
||||
else if(href_list["gamemode_panel"])
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
SSticker.mode.admin_panel()
|
||||
|
||||
else if(href_list["call_shuttle"])
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
@@ -1342,6 +1347,291 @@
|
||||
|
||||
else if(href_list["f_secret"])
|
||||
return HandleFSecret()
|
||||
|
||||
else if(href_list["f_dynamic_roundstart"])
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
if(SSticker && SSticker.mode)
|
||||
return alert(usr, "The game has already started.", null, null, null, null)
|
||||
if(GLOB.master_mode != "dynamic")
|
||||
return alert(usr, "The game mode has to be dynamic mode.", null, null, null, null)
|
||||
var/roundstart_rules = list()
|
||||
for (var/rule in subtypesof(/datum/dynamic_ruleset/roundstart))
|
||||
var/datum/dynamic_ruleset/roundstart/newrule = new rule()
|
||||
roundstart_rules[newrule.name] = newrule
|
||||
var/added_rule = input(usr,"What ruleset do you want to force? This will bypass threat level and population restrictions.", "Rigging Roundstart", null) as null|anything in roundstart_rules
|
||||
if (added_rule)
|
||||
GLOB.dynamic_forced_roundstart_ruleset += roundstart_rules[added_rule]
|
||||
log_admin("[key_name(usr)] set [added_rule] to be a forced roundstart ruleset.")
|
||||
message_admins("[key_name(usr)] set [added_rule] to be a forced roundstart ruleset.", 1)
|
||||
Game()
|
||||
|
||||
else if(href_list["f_dynamic_roundstart_clear"])
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
GLOB.dynamic_forced_roundstart_ruleset = list()
|
||||
Game()
|
||||
log_admin("[key_name(usr)] cleared the rigged roundstart rulesets. The mode will pick them as normal.")
|
||||
message_admins("[key_name(usr)] cleared the rigged roundstart rulesets. The mode will pick them as normal.", 1)
|
||||
|
||||
else if(href_list["f_dynamic_roundstart_remove"])
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
var/datum/dynamic_ruleset/roundstart/rule = locate(href_list["f_dynamic_roundstart_remove"])
|
||||
GLOB.dynamic_forced_roundstart_ruleset -= rule
|
||||
Game()
|
||||
log_admin("[key_name(usr)] removed [rule] from the forced roundstart rulesets.")
|
||||
message_admins("[key_name(usr)] removed [rule] from the forced roundstart rulesets.", 1)
|
||||
|
||||
else if(href_list["f_dynamic_latejoin"])
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
if(!SSticker || !SSticker.mode)
|
||||
return alert(usr, "The game must start first.", null, null, null, null)
|
||||
if(GLOB.master_mode != "dynamic")
|
||||
return alert(usr, "The game mode has to be dynamic mode!", null, null, null, null)
|
||||
var/latejoin_rules = list()
|
||||
for (var/rule in subtypesof(/datum/dynamic_ruleset/latejoin))
|
||||
var/datum/dynamic_ruleset/latejoin/newrule = new rule()
|
||||
latejoin_rules[newrule.name] = newrule
|
||||
var/added_rule = input(usr,"What ruleset do you want to force upon the next latejoiner? This will bypass threat level and population restrictions.", "Rigging Latejoin", null) as null|anything in latejoin_rules
|
||||
if (added_rule)
|
||||
var/datum/game_mode/dynamic/mode = SSticker.mode
|
||||
mode.forced_latejoin_rule = latejoin_rules[added_rule]
|
||||
log_admin("[key_name(usr)] set [added_rule] to proc on the next latejoin.")
|
||||
message_admins("[key_name(usr)] set [added_rule] to proc on the next latejoin.", 1)
|
||||
Game()
|
||||
|
||||
else if(href_list["f_dynamic_latejoin_clear"])
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
if (SSticker && SSticker.mode && istype(SSticker.mode,/datum/game_mode/dynamic))
|
||||
var/datum/game_mode/dynamic/mode = SSticker.mode
|
||||
mode.forced_latejoin_rule = null
|
||||
Game()
|
||||
log_admin("[key_name(usr)] cleared the forced latejoin ruleset.")
|
||||
message_admins("[key_name(usr)] cleared the forced latejoin ruleset.", 1)
|
||||
|
||||
else if(href_list["f_dynamic_midround"])
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
if(!SSticker || !SSticker.mode)
|
||||
return alert(usr, "The game must start first.", null, null, null, null)
|
||||
if(GLOB.master_mode != "dynamic")
|
||||
return alert(usr, "The game mode has to be dynamic mode!", null, null, null, null)
|
||||
var/midround_rules = list()
|
||||
for (var/rule in subtypesof(/datum/dynamic_ruleset/midround))
|
||||
var/datum/dynamic_ruleset/midround/newrule = new rule()
|
||||
midround_rules[newrule.name] = rule
|
||||
var/added_rule = input(usr,"What ruleset do you want to force right now? This will bypass threat level and population restrictions.", "Execute Ruleset", null) as null|anything in midround_rules
|
||||
if (added_rule)
|
||||
var/datum/game_mode/dynamic/mode = SSticker.mode
|
||||
log_admin("[key_name(usr)] executed the [added_rule] ruleset.")
|
||||
message_admins("[key_name(usr)] executed the [added_rule] ruleset.", 1)
|
||||
mode.picking_specific_rule(midround_rules[added_rule],1)
|
||||
|
||||
else if (href_list["f_dynamic_options"])
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
|
||||
if(SSticker && SSticker.mode)
|
||||
return alert(usr, "The game has already started.", null, null, null, null)
|
||||
if(GLOB.master_mode != "dynamic")
|
||||
return alert(usr, "The game mode has to be dynamic mode!", null, null, null, null)
|
||||
|
||||
dynamic_mode_options(usr)
|
||||
|
||||
else if(href_list["f_dynamic_roundstart_centre"])
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
if(SSticker && SSticker.mode)
|
||||
return alert(usr, "The game has already started.", null, null, null, null)
|
||||
if(GLOB.master_mode != "dynamic")
|
||||
return alert(usr, "The game mode has to be dynamic mode!", null, null, null, null)
|
||||
|
||||
var/new_centre = input(usr,"Change the centre of the dynamic mode threat curve. A negative value will give a more peaceful round ; a positive value, a round with higher threat. Any number between -5 and +5 is allowed.", "Change curve centre", null) as num
|
||||
if (new_centre < -5 || new_centre > 5)
|
||||
return alert(usr, "Only values between -5 and +5 are allowed.", null, null, null, null)
|
||||
|
||||
log_admin("[key_name(usr)] changed the distribution curve center to [new_centre].")
|
||||
message_admins("[key_name(usr)] changed the distribution curve center to [new_centre]", 1)
|
||||
GLOB.dynamic_curve_centre = new_centre
|
||||
dynamic_mode_options(usr)
|
||||
|
||||
else if(href_list["f_dynamic_roundstart_width"])
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
if(SSticker && SSticker.mode)
|
||||
return alert(usr, "The game has already started.", null, null, null, null)
|
||||
if(GLOB.master_mode != "dynamic")
|
||||
return alert(usr, "The game mode has to be dynamic mode!", null, null, null, null)
|
||||
|
||||
var/new_width = input(usr,"Change the width of the dynamic mode threat curve. A higher value will favour extreme rounds ; a lower value, a round closer to the average. Any Number between 0.5 and 4 are allowed.", "Change curve width", null) as num
|
||||
if (new_width < 0.5 || new_width > 4)
|
||||
return alert(usr, "Only values between 0.5 and +2.5 are allowed.", null, null, null, null)
|
||||
|
||||
log_admin("[key_name(usr)] changed the distribution curve width to [new_width].")
|
||||
message_admins("[key_name(usr)] changed the distribution curve width to [new_width]", 1)
|
||||
GLOB.dynamic_curve_width = new_width
|
||||
dynamic_mode_options(usr)
|
||||
|
||||
else if(href_list["f_dynamic_roundstart_latejoin_min"])
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
if(SSticker && SSticker.mode)
|
||||
return alert(usr, "The game has already started.", null, null, null, null)
|
||||
if(GLOB.master_mode != "dynamic")
|
||||
return alert(usr, "The game mode has to be dynamic mode!", null, null, null, null)
|
||||
var/new_min = input(usr,"Change the minimum delay of latejoin injection in minutes.", "Change latejoin injection delay minimum", null) as num
|
||||
if(new_min <= 0)
|
||||
return alert(usr, "The minimum can't be zero or lower.", null, null, null, null)
|
||||
if((new_min MINUTES) > GLOB.dynamic_latejoin_delay_max)
|
||||
return alert(usr, "The minimum must be lower than the maximum.", null, null, null, null)
|
||||
|
||||
log_admin("[key_name(usr)] changed the latejoin injection minimum delay to [new_min] minutes.")
|
||||
message_admins("[key_name(usr)] changed the latejoin injection minimum delay to [new_min] minutes", 1)
|
||||
GLOB.dynamic_latejoin_delay_min = (new_min MINUTES)
|
||||
dynamic_mode_options(usr)
|
||||
|
||||
else if(href_list["f_dynamic_roundstart_latejoin_max"])
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
if(SSticker && SSticker.mode)
|
||||
return alert(usr, "The game has already started.", null, null, null, null)
|
||||
if(GLOB.master_mode != "dynamic")
|
||||
return alert(usr, "The game mode has to be dynamic mode!", null, null, null, null)
|
||||
var/new_max = input(usr,"Change the maximum delay of latejoin injection in minutes.", "Change latejoin injection delay maximum", null) as num
|
||||
if(new_max <= 0)
|
||||
return alert(usr, "The maximum can't be zero or lower.", null, null, null, null)
|
||||
if((new_max MINUTES) < GLOB.dynamic_latejoin_delay_min)
|
||||
return alert(usr, "The maximum must be higher than the minimum.", null, null, null, null)
|
||||
|
||||
log_admin("[key_name(usr)] changed the latejoin injection maximum delay to [new_max] minutes.")
|
||||
message_admins("[key_name(usr)] changed the latejoin injection maximum delay to [new_max] minutes", 1)
|
||||
GLOB.dynamic_latejoin_delay_max = (new_max MINUTES)
|
||||
dynamic_mode_options(usr)
|
||||
|
||||
else if(href_list["f_dynamic_roundstart_midround_min"])
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
if(SSticker && SSticker.mode)
|
||||
return alert(usr, "The game has already started.", null, null, null, null)
|
||||
if(GLOB.master_mode != "dynamic")
|
||||
return alert(usr, "The game mode has to be dynamic mode!", null, null, null, null)
|
||||
var/new_min = input(usr,"Change the minimum delay of midround injection in minutes.", "Change midround injection delay minimum", null) as num
|
||||
if(new_min <= 0)
|
||||
return alert(usr, "The minimum can't be zero or lower.", null, null, null, null)
|
||||
if((new_min MINUTES) > GLOB.dynamic_midround_delay_max)
|
||||
return alert(usr, "The minimum must be lower than the maximum.", null, null, null, null)
|
||||
|
||||
log_admin("[key_name(usr)] changed the midround injection minimum delay to [new_min] minutes.")
|
||||
message_admins("[key_name(usr)] changed the midround injection minimum delay to [new_min] minutes", 1)
|
||||
GLOB.dynamic_midround_delay_min = (new_min MINUTES)
|
||||
dynamic_mode_options(usr)
|
||||
|
||||
else if(href_list["f_dynamic_roundstart_midround_max"])
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
if(SSticker && SSticker.mode)
|
||||
return alert(usr, "The game has already started.", null, null, null, null)
|
||||
if(GLOB.master_mode != "dynamic")
|
||||
return alert(usr, "The game mode has to be dynamic mode!", null, null, null, null)
|
||||
var/new_max = input(usr,"Change the maximum delay of midround injection in minutes.", "Change midround injection delay maximum", null) as num
|
||||
if(new_max <= 0)
|
||||
return alert(usr, "The maximum can't be zero or lower.", null, null, null, null)
|
||||
if((new_max MINUTES) > GLOB.dynamic_midround_delay_max)
|
||||
return alert(usr, "The maximum must be higher than the minimum.", null, null, null, null)
|
||||
|
||||
log_admin("[key_name(usr)] changed the midround injection maximum delay to [new_max] minutes.")
|
||||
message_admins("[key_name(usr)] changed the midround injection maximum delay to [new_max] minutes", 1)
|
||||
GLOB.dynamic_midround_delay_max = (new_max MINUTES)
|
||||
dynamic_mode_options(usr)
|
||||
|
||||
else if(href_list["f_dynamic_force_extended"])
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
|
||||
if(GLOB.master_mode != "dynamic")
|
||||
return alert(usr, "The game mode has to be dynamic mode!", null, null, null, null)
|
||||
|
||||
GLOB.dynamic_forced_extended = !GLOB.dynamic_forced_extended
|
||||
log_admin("[key_name(usr)] set 'forced_extended' to [GLOB.dynamic_forced_extended].")
|
||||
message_admins("[key_name(usr)] set 'forced_extended' to [GLOB.dynamic_forced_extended].")
|
||||
dynamic_mode_options(usr)
|
||||
|
||||
else if(href_list["f_dynamic_no_stacking"])
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
|
||||
if(GLOB.master_mode != "dynamic")
|
||||
return alert(usr, "The game mode has to be dynamic mode!", null, null, null, null)
|
||||
|
||||
GLOB.dynamic_no_stacking = !GLOB.dynamic_no_stacking
|
||||
log_admin("[key_name(usr)] set 'no_stacking' to [GLOB.dynamic_no_stacking].")
|
||||
message_admins("[key_name(usr)] set 'no_stacking' to [GLOB.dynamic_no_stacking].")
|
||||
dynamic_mode_options(usr)
|
||||
|
||||
else if(href_list["f_dynamic_classic_secret"])
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
|
||||
if(GLOB.master_mode != "dynamic")
|
||||
return alert(usr, "The game mode has to be dynamic mode!", null, null, null, null)
|
||||
|
||||
GLOB.dynamic_classic_secret = !GLOB.dynamic_classic_secret
|
||||
log_admin("[key_name(usr)] set 'classic_secret' to [GLOB.dynamic_classic_secret].")
|
||||
message_admins("[key_name(usr)] set 'classic_secret' to [GLOB.dynamic_classic_secret].")
|
||||
dynamic_mode_options(usr)
|
||||
|
||||
else if(href_list["f_dynamic_stacking_limit"])
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
|
||||
if(GLOB.master_mode != "dynamic")
|
||||
return alert(usr, "The game mode has to be dynamic mode!", null, null, null, null)
|
||||
|
||||
GLOB.dynamic_stacking_limit = input(usr,"Change the threat limit at which round-endings rulesets will start to stack.", "Change stacking limit", null) as num
|
||||
log_admin("[key_name(usr)] set 'stacking_limit' to [GLOB.dynamic_stacking_limit].")
|
||||
message_admins("[key_name(usr)] set 'stacking_limit' to [GLOB.dynamic_stacking_limit].")
|
||||
dynamic_mode_options(usr)
|
||||
|
||||
else if(href_list["f_dynamic_high_pop_limit"])
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
|
||||
if(SSticker && SSticker.mode)
|
||||
return alert(usr, "The game has already started.", null, null, null, null)
|
||||
|
||||
if(GLOB.master_mode != "dynamic")
|
||||
return alert(usr, "The game mode has to be dynamic mode!", null, null, null, null)
|
||||
|
||||
var/new_value = input(usr, "Enter the high-pop override threshold for dynamic mode.", "High pop override") as num
|
||||
if (new_value < 0)
|
||||
return alert(usr, "Only positive values allowed!", null, null, null, null)
|
||||
GLOB.dynamic_high_pop_limit = new_value
|
||||
|
||||
log_admin("[key_name(usr)] set 'high_pop_limit' to [GLOB.dynamic_high_pop_limit].")
|
||||
message_admins("[key_name(usr)] set 'high_pop_limit' to [GLOB.dynamic_high_pop_limit].")
|
||||
dynamic_mode_options(usr)
|
||||
|
||||
else if(href_list["f_dynamic_forced_threat"])
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
|
||||
if(SSticker && SSticker.mode)
|
||||
return alert(usr, "The game has already started.", null, null, null, null)
|
||||
|
||||
if(GLOB.master_mode != "dynamic")
|
||||
return alert(usr, "The game mode has to be dynamic mode!", null, null, null, null)
|
||||
|
||||
var/new_value = input(usr, "Enter the forced threat level for dynamic mode.", "Forced threat level") as num
|
||||
if (new_value > 100)
|
||||
return alert(usr, "The value must be be under 100.", null, null, null, null)
|
||||
GLOB.dynamic_forced_threat_level = new_value
|
||||
|
||||
log_admin("[key_name(usr)] set 'forced_threat_level' to [GLOB.dynamic_forced_threat_level].")
|
||||
message_admins("[key_name(usr)] set 'forced_threat_level' to [GLOB.dynamic_forced_threat_level].")
|
||||
dynamic_mode_options(usr)
|
||||
|
||||
else if(href_list["c_mode2"])
|
||||
if(!check_rights(R_ADMIN|R_SERVER))
|
||||
|
||||
@@ -56,6 +56,7 @@
|
||||
/datum/antagonist/abductor/greet()
|
||||
to_chat(owner.current, "<span class='notice'>You are the [owner.special_role]!</span>")
|
||||
to_chat(owner.current, "<span class='notice'>With the help of your teammate, kidnap and experiment on station crew members!</span>")
|
||||
to_chat(owner.current, "<span class='notice'>Try not to disturb the habitat, it could lead to dead specimens.</span>")
|
||||
to_chat(owner.current, "<span class='notice'>[greet_text]</span>")
|
||||
owner.announce_objectives()
|
||||
|
||||
|
||||
+3
-3
@@ -132,9 +132,9 @@
|
||||
continue
|
||||
if(isliving(M.current) && M.current.stat != DEAD)
|
||||
var/turf/t_turf = isAI(M.current) ? get_step(get_step(src, NORTH),NORTH) : get_turf(src) // AI too fat, must make sure it always ends up a 2 tiles north instead of on the ark.
|
||||
do_teleport(M, t_turf, channel = TELEPORT_CHANNEL_CULT, forced = TRUE)
|
||||
M.current.overlay_fullscreen("flash", /obj/screen/fullscreen/flash)
|
||||
M.current.clear_fullscreen("flash", 5)
|
||||
do_teleport(M.current, t_turf, channel = TELEPORT_CHANNEL_CULT, forced = TRUE)
|
||||
M.current.overlay_fullscreen("flash", /obj/screen/fullscreen/flash)
|
||||
M.current.clear_fullscreen("flash", 5)
|
||||
playsound(src, 'sound/magic/clockwork/invoke_general.ogg', 50, FALSE)
|
||||
recalls_remaining--
|
||||
recalling = FALSE
|
||||
|
||||
@@ -61,8 +61,8 @@ Runes can either be invoked by one's self or with many different cultists. Each
|
||||
if(do_after(user, 15, target = src))
|
||||
to_chat(user, "<span class='notice'>You carefully erase the [lowertext(cultist_name)] rune.</span>")
|
||||
qdel(src)
|
||||
else if(istype(I, /obj/item/nullrod))
|
||||
user.say("BEGONE FOUL MAGIKS!!", forced = "nullrod")
|
||||
else if(istype(I, /obj/item/storage/book/bible) || istype(I, /obj/item/nullrod))
|
||||
user.say("BEGONE FOUL MAGICKS!!", forced = "bible")
|
||||
to_chat(user, "<span class='danger'>You disrupt the magic of [src] with [I].</span>")
|
||||
qdel(src)
|
||||
|
||||
|
||||
@@ -75,3 +75,8 @@
|
||||
var/datum/player_details/player_details //these persist between logins/logouts during the same round.
|
||||
|
||||
var/list/char_render_holders //Should only be a key-value list of north/south/east/west = obj/screen.
|
||||
|
||||
var/client_keysend_amount = 0
|
||||
var/next_keysend_reset = 0
|
||||
var/next_keysend_trip_reset = 0
|
||||
var/keysend_tripped = FALSE
|
||||
@@ -817,6 +817,10 @@ GLOBAL_LIST_EMPTY(external_rsc_urls)
|
||||
var/file = GLOB.vox_sounds[name]
|
||||
Export("##action=load_rsc", file)
|
||||
stoplag()
|
||||
for (var/name in GLOB.vox_sounds_male)
|
||||
var/file = GLOB.vox_sounds_male[name]
|
||||
Export("##action=load_rsc", file)
|
||||
stoplag()
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@@ -681,13 +681,13 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
dat += "<h2>Clothing & Equipment</h2>"
|
||||
dat += "<b>Underwear:</b><a style='display:block;width:100px' href ='?_src_=prefs;preference=underwear;task=input'>[underwear]</a>"
|
||||
if(UNDIE_COLORABLE(GLOB.underwear_list[underwear]))
|
||||
dat += "<b>Underwear Color:</b><a style='display:block;width:100px' href ='?_src_=prefs;preference=undie_color;task=input'>[undie_color]</a>"
|
||||
dat += "<b>Underwear Color:</b> <span style='border:1px solid #161616; background-color: #[undie_color];'> </span> <a href='?_src_=prefs;preference=undie_color;task=input'>Change</a><BR>"
|
||||
dat += "<b>Undershirt:</b><a style='display:block;width:100px' href ='?_src_=prefs;preference=undershirt;task=input'>[undershirt]</a>"
|
||||
if(UNDIE_COLORABLE(GLOB.undershirt_list[undershirt]))
|
||||
dat += "<b>Undershirt Color:</b><a style='display:block;width:100px' href ='?_src_=prefs;preference=shirt_color;task=input'>[shirt_color]</a>"
|
||||
dat += "<b>Undershirt Color:</b> <span style='border:1px solid #161616; background-color: #[shirt_color];'> </span> <a href='?_src_=prefs;preference=shirt_color;task=input'>Change</a><BR>"
|
||||
dat += "<b>Socks:</b><a style='display:block;width:100px' href ='?_src_=prefs;preference=socks;task=input'>[socks]</a>"
|
||||
if(UNDIE_COLORABLE(GLOB.socks_list[socks]))
|
||||
dat += "<b>Socks Color:</b><a style='display:block;width:100px' href ='?_src_=prefs;preference=socks_color;task=input'>[socks_color]</a>"
|
||||
dat += "<b>Socks Color:</b> <span style='border:1px solid #161616; background-color: #[socks_color];'> </span> <a href='?_src_=prefs;preference=socks_color;task=input'>Change</a><BR>"
|
||||
dat += "<b>Backpack:</b><a style='display:block;width:100px' href ='?_src_=prefs;preference=bag;task=input'>[backbag]</a>"
|
||||
dat += "<b>Jumpsuit:</b><BR><a href ='?_src_=prefs;preference=suit;task=input'>[jumpsuit_style]</a><BR>"
|
||||
dat += "<b>Uplink Location:</b><a style='display:block;width:100px' href ='?_src_=prefs;preference=uplink_loc;task=input'>[uplink_spawn_loc]</a>"
|
||||
|
||||
@@ -399,11 +399,11 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
|
||||
hair_style = sanitize_inlist(hair_style, GLOB.hair_styles_female_list)
|
||||
facial_hair_style = sanitize_inlist(facial_hair_style, GLOB.facial_hair_styles_female_list)
|
||||
underwear = sanitize_inlist(underwear, GLOB.underwear_list)
|
||||
undie_color = sanitize_hexcolor(undie_color, 6, 1, initial(undie_color))
|
||||
undie_color = sanitize_hexcolor(undie_color, 3, FALSE, initial(undie_color))
|
||||
undershirt = sanitize_inlist(undershirt, GLOB.undershirt_list)
|
||||
shirt_color = sanitize_hexcolor(shirt_color, 6, 1, initial(shirt_color))
|
||||
shirt_color = sanitize_hexcolor(shirt_color, 3, FALSE, initial(shirt_color))
|
||||
socks = sanitize_inlist(socks, GLOB.socks_list)
|
||||
socks_color = sanitize_hexcolor(socks_color, 6, 1, initial(socks_color))
|
||||
socks_color = sanitize_hexcolor(socks_color, 3, FALSE, initial(socks_color))
|
||||
age = sanitize_integer(age, AGE_MIN, AGE_MAX, initial(age))
|
||||
hair_color = sanitize_hexcolor(hair_color, 3, 0)
|
||||
facial_hair_color = sanitize_hexcolor(facial_hair_color, 3, 0)
|
||||
|
||||
@@ -23,30 +23,48 @@
|
||||
allowed = list(/obj/item/disk, /obj/item/stamp, /obj/item/reagent_containers/food/drinks/flask, /obj/item/melee, /obj/item/storage/lockbox/medal, /obj/item/assembly/flash/handheld, /obj/item/storage/box/matches, /obj/item/lighter, /obj/item/clothing/mask/cigarette, /obj/item/storage/fancy/cigarettes, /obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/plasmaman)
|
||||
|
||||
//Chaplain
|
||||
/obj/item/clothing/suit/nun
|
||||
/obj/item/clothing/suit/chaplain
|
||||
name = "chaplain suit"
|
||||
desc = "A piece of clothing adorned by the gods of Coding. Should never exist in this mortal realm."
|
||||
allowed = list(/obj/item/storage/book/bible, HOLY_WEAPONS, /obj/item/reagent_containers/food/drinks/bottle/holywater, /obj/item/storage/fancy/candle_box, /obj/item/candle, /obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/plasmaman)
|
||||
|
||||
/obj/item/clothing/suit/chaplain/nun
|
||||
name = "nun robe"
|
||||
desc = "Maximum piety in this star system."
|
||||
icon_state = "nun"
|
||||
item_state = "nun"
|
||||
body_parts_covered = CHEST|GROIN|LEGS|ARMS|HANDS
|
||||
flags_inv = HIDESHOES|HIDEJUMPSUIT
|
||||
allowed = list(/obj/item/storage/book/bible, /obj/item/nullrod, /obj/item/reagent_containers/food/drinks/bottle/holywater, /obj/item/storage/fancy/candle_box, /obj/item/candle, /obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/plasmaman)
|
||||
|
||||
/obj/item/clothing/suit/studentuni
|
||||
/obj/item/clothing/suit/chaplain/studentuni
|
||||
name = "student robe"
|
||||
desc = "The uniform of a bygone institute of learning."
|
||||
icon_state = "studentuni"
|
||||
item_state = "studentuni"
|
||||
body_parts_covered = ARMS|CHEST
|
||||
allowed = list(/obj/item/storage/book/bible, /obj/item/nullrod, /obj/item/reagent_containers/food/drinks/bottle/holywater, /obj/item/storage/fancy/candle_box, /obj/item/candle, /obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/plasmaman)
|
||||
|
||||
/obj/item/clothing/suit/witchhunter
|
||||
/obj/item/clothing/suit/chaplain/witchhunter
|
||||
name = "witchunter garb"
|
||||
desc = "This worn outfit saw much use back in the day."
|
||||
icon_state = "witchhunter"
|
||||
item_state = "witchhunter"
|
||||
body_parts_covered = CHEST|GROIN|LEGS|ARMS
|
||||
allowed = list(/obj/item/storage/book/bible, /obj/item/nullrod, /obj/item/reagent_containers/food/drinks/bottle/holywater, /obj/item/storage/fancy/candle_box, /obj/item/candle, /obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/plasmaman)
|
||||
|
||||
/obj/item/clothing/suit/chaplain/pharaoh
|
||||
name = "pharaoh tunic"
|
||||
desc = "Lavish space tomb not included."
|
||||
icon_state = "pharaoh"
|
||||
icon_state = "pharaoh"
|
||||
body_parts_covered = CHEST|GROIN
|
||||
|
||||
/obj/item/clothing/suit/chaplain/holidaypriest
|
||||
name = "holiday priest"
|
||||
desc = "This is a nice holiday, my son."
|
||||
icon_state = "holidaypriest"
|
||||
item_state = "w_suit"
|
||||
body_parts_covered = CHEST|GROIN|LEGS|ARMS
|
||||
flags_inv = HIDEJUMPSUIT
|
||||
|
||||
|
||||
//Chef
|
||||
/obj/item/clothing/suit/toggle/chef
|
||||
|
||||
@@ -167,16 +167,6 @@
|
||||
icon_state = "griffin_wings"
|
||||
item_state = "griffin_wings"
|
||||
|
||||
|
||||
/obj/item/clothing/suit/holidaypriest
|
||||
name = "holiday priest"
|
||||
desc = "This is a nice holiday, my son."
|
||||
icon_state = "holidaypriest"
|
||||
item_state = "w_suit"
|
||||
body_parts_covered = CHEST|GROIN|LEGS|ARMS
|
||||
flags_inv = HIDEJUMPSUIT
|
||||
allowed = list(/obj/item/storage/book/bible, /obj/item/nullrod, /obj/item/reagent_containers/food/drinks/bottle/holywater, /obj/item/storage/fancy/candle_box, /obj/item/candle, /obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/plasmaman)
|
||||
|
||||
/obj/item/clothing/suit/cardborg
|
||||
name = "cardborg suit"
|
||||
desc = "An ordinary cardboard box with holes cut in the sides."
|
||||
@@ -468,13 +458,6 @@
|
||||
flags_inv = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT
|
||||
allowed = list(/obj/item/clothing/mask/facehugger/toy)
|
||||
|
||||
/obj/item/clothing/suit/pharaoh
|
||||
name = "pharaoh tunic"
|
||||
desc = "Lavish space tomb not included."
|
||||
icon_state = "pharaoh"
|
||||
icon_state = "pharaoh"
|
||||
body_parts_covered = CHEST|GROIN
|
||||
|
||||
|
||||
|
||||
// WINTER COATS
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/obj/item/clothing/accessory //Ties moved to neck slot items, but as there are still things like medals and armbands, this accessory system is being kept as-is
|
||||
/obj/item/clothing/accessory //Ties moved to neck slot items, but as there are still things like medals, pokadots, and armbands, this accessory system is being kept as-is
|
||||
name = "Accessory"
|
||||
desc = "Something has gone wrong!"
|
||||
icon = 'icons/obj/clothing/accessories.dmi'
|
||||
@@ -368,7 +368,7 @@
|
||||
|
||||
/obj/item/clothing/accessory/kevlar
|
||||
name = "kevlar sheets"
|
||||
desc = "Long thin sheets of kevlar to help resist bullets and some physical attacks.."
|
||||
desc = "Long thin sheets of kevlar to help resist bullets and some physical attacks."
|
||||
icon_state = "padding"
|
||||
item_color = "nothing"
|
||||
armor = list("melee" = 10, "bullet" = 20, "laser" = 0, "energy" = 0, "bomb" = 10, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 25)
|
||||
@@ -379,3 +379,35 @@
|
||||
icon_state = "plastics"
|
||||
item_color = "nothing"
|
||||
armor = list("melee" = 0, "bullet" = 0, "laser" = 20, "energy" = 10, "bomb" = 0, "bio" = 30, "rad" = 0, "fire" = 0, "acid" = -40)
|
||||
|
||||
/////////////////////
|
||||
//Pokadots On Pants//
|
||||
/////////////////////
|
||||
|
||||
/obj/item/clothing/accessory/attrocious_pokadots
|
||||
name = "atrocious pokadots"
|
||||
desc = "They look like something out of a thrift store. Attaches to clothing not to be worn by itself."
|
||||
icon_state = "attrocious_pokadots"
|
||||
item_color = "attrocious_pokadots"
|
||||
attack_verb = list("horrifed", "eye bleeded")
|
||||
|
||||
/obj/item/clothing/accessory/black_white_pokadots
|
||||
name = "checkered pokadots"
|
||||
desc = "You can play a game of chess on these! Attaches to clothing not to be worn by itself."
|
||||
icon_state = "black_white_pokadots"
|
||||
item_color = "black_white_pokadots"
|
||||
attack_verb = list("check", "mate")
|
||||
|
||||
/obj/item/clothing/accessory/nt_pokadots
|
||||
name = "blue and white pokadots"
|
||||
desc = "To show your pride in your workplace, in the most annoying possable way. Attaches to clothing not to be worn by itself."
|
||||
icon_state = "nt_pokadots"
|
||||
item_color = "nt_pokadots"
|
||||
attack_verb = list("eye bleeded", "annoyed")
|
||||
|
||||
/obj/item/clothing/accessory/syndi_pokadots
|
||||
name = "black and red pokadots"
|
||||
desc = "King me. Attaches to clothing not to be worn by itself." //checkers!
|
||||
icon_state = "syndi_pokadots"
|
||||
item_color = "syndi_pokadots"
|
||||
attack_verb = list("jumped", "taken")
|
||||
@@ -359,6 +359,7 @@
|
||||
reqs = list(/obj/item/restraints/handcuffs/cable = 1,
|
||||
/obj/item/shard = 1,
|
||||
/obj/item/stack/rods = 1)
|
||||
parts = list(/obj/item/shard = 1)
|
||||
time = 40
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_WEAPON
|
||||
|
||||
@@ -800,4 +800,11 @@
|
||||
name = "Catnip Tea"
|
||||
id = "catnip_tea"
|
||||
results = list("catnip_tea" = 3)
|
||||
required_reagents = list("tea" = 5, "catnip" = 2)
|
||||
required_reagents = list("tea" = 5, "catnip" = 2)
|
||||
|
||||
/datum/chemical_reaction/commander_and_chief
|
||||
name = "Commander and Chief"
|
||||
id = "commander_and_chief"
|
||||
results = list("commander_and_chief" = 50)
|
||||
required_reagents = list("alliescocktail" = 50, "champagne" = 20, "doctorsdelight" = 10, "quintuple_sec" = 10, "screwdrivercocktail" = 10)
|
||||
mix_message = "When your powers combine, I am Captain Pl-..."
|
||||
@@ -23,7 +23,7 @@
|
||||
result = /obj/item/reagent_containers/food/snacks/donut
|
||||
subcategory = CAT_PASTRY
|
||||
|
||||
/datum/crafting_recipe/food/donut
|
||||
/datum/crafting_recipe/food/donut/semen
|
||||
time = 15
|
||||
name = "Semen donut"
|
||||
reqs = list(
|
||||
|
||||
@@ -1,114 +1,116 @@
|
||||
/*
|
||||
Captain
|
||||
*/
|
||||
/datum/job/captain
|
||||
title = "Captain"
|
||||
flag = CAPTAIN
|
||||
department_head = list("CentCom")
|
||||
department_flag = ENGSEC
|
||||
faction = "Station"
|
||||
total_positions = 1
|
||||
spawn_positions = 1
|
||||
supervisors = "Nanotrasen officials and Space law"
|
||||
selection_color = "#ccccff"
|
||||
req_admin_notify = 1
|
||||
minimal_player_age = 14
|
||||
exp_requirements = 180
|
||||
exp_type = EXP_TYPE_CREW
|
||||
|
||||
outfit = /datum/outfit/job/captain
|
||||
|
||||
access = list() //See get_access()
|
||||
minimal_access = list() //See get_access()
|
||||
|
||||
blacklisted_quirks = list(/datum/quirk/mute, /datum/quirk/brainproblems, /datum/quirk/insanity)
|
||||
|
||||
/datum/job/captain/get_access()
|
||||
return get_all_accesses()
|
||||
|
||||
/datum/job/captain/announce(mob/living/carbon/human/H)
|
||||
..()
|
||||
SSticker.OnRoundstart(CALLBACK(GLOBAL_PROC, .proc/minor_announce, "Captain [H.nameless ? "" : "[H.real_name] "]on deck!"))
|
||||
|
||||
/datum/outfit/job/captain
|
||||
name = "Captain"
|
||||
jobtype = /datum/job/captain
|
||||
|
||||
id = /obj/item/card/id/gold
|
||||
belt = /obj/item/pda/captain
|
||||
glasses = /obj/item/clothing/glasses/sunglasses
|
||||
ears = /obj/item/radio/headset/heads/captain/alt
|
||||
gloves = /obj/item/clothing/gloves/color/captain
|
||||
uniform = /obj/item/clothing/under/rank/captain
|
||||
suit = /obj/item/clothing/suit/armor/vest/capcarapace
|
||||
shoes = /obj/item/clothing/shoes/sneakers/brown
|
||||
head = /obj/item/clothing/head/caphat
|
||||
backpack_contents = list(/obj/item/melee/classic_baton/telescopic=1, /obj/item/station_charter=1)
|
||||
|
||||
backpack = /obj/item/storage/backpack/captain
|
||||
satchel = /obj/item/storage/backpack/satchel/cap
|
||||
duffelbag = /obj/item/storage/backpack/duffelbag/captain
|
||||
|
||||
implants = list(/obj/item/implant/mindshield)
|
||||
accessory = /obj/item/clothing/accessory/medal/gold/captain
|
||||
|
||||
chameleon_extras = list(/obj/item/gun/energy/e_gun, /obj/item/stamp/captain)
|
||||
|
||||
/datum/outfit/job/captain/hardsuit
|
||||
name = "Captain (Hardsuit)"
|
||||
|
||||
mask = /obj/item/clothing/mask/gas/sechailer
|
||||
suit = /obj/item/clothing/suit/space/hardsuit/captain
|
||||
suit_store = /obj/item/tank/internals/oxygen
|
||||
|
||||
/*
|
||||
Head of Personnel
|
||||
*/
|
||||
/datum/job/hop
|
||||
title = "Head of Personnel"
|
||||
flag = HOP
|
||||
department_head = list("Captain")
|
||||
department_flag = CIVILIAN
|
||||
head_announce = list(RADIO_CHANNEL_SERVICE)
|
||||
faction = "Station"
|
||||
total_positions = 1
|
||||
spawn_positions = 1
|
||||
supervisors = "the captain"
|
||||
selection_color = "#ddddff"
|
||||
req_admin_notify = 1
|
||||
minimal_player_age = 10
|
||||
exp_requirements = 180
|
||||
exp_type = EXP_TYPE_CREW
|
||||
exp_type_department = EXP_TYPE_SUPPLY
|
||||
|
||||
outfit = /datum/outfit/job/hop
|
||||
|
||||
access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_COURT, ACCESS_WEAPONS,
|
||||
ACCESS_MEDICAL, ACCESS_ENGINE, ACCESS_CHANGE_IDS, ACCESS_AI_UPLOAD, ACCESS_EVA, ACCESS_HEADS,
|
||||
ACCESS_ALL_PERSONAL_LOCKERS, ACCESS_MAINT_TUNNELS, ACCESS_BAR, ACCESS_JANITOR, ACCESS_CONSTRUCTION, ACCESS_MORGUE,
|
||||
ACCESS_CREMATORIUM, ACCESS_KITCHEN, ACCESS_CARGO, ACCESS_CARGO_BOT, ACCESS_MAILSORTING, ACCESS_QM, ACCESS_HYDROPONICS, ACCESS_LAWYER,
|
||||
ACCESS_THEATRE, ACCESS_CHAPEL_OFFICE, ACCESS_LIBRARY, ACCESS_RESEARCH, ACCESS_MINING, ACCESS_VAULT, ACCESS_MINING_STATION,
|
||||
ACCESS_HOP, ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_GATEWAY, ACCESS_MINERAL_STOREROOM)
|
||||
minimal_access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_COURT, ACCESS_WEAPONS,
|
||||
ACCESS_MEDICAL, ACCESS_ENGINE, ACCESS_CHANGE_IDS, ACCESS_AI_UPLOAD, ACCESS_EVA, ACCESS_HEADS,
|
||||
ACCESS_ALL_PERSONAL_LOCKERS, ACCESS_MAINT_TUNNELS, ACCESS_BAR, ACCESS_JANITOR, ACCESS_CONSTRUCTION, ACCESS_MORGUE,
|
||||
ACCESS_CREMATORIUM, ACCESS_KITCHEN, ACCESS_CARGO, ACCESS_CARGO_BOT, ACCESS_MAILSORTING, ACCESS_QM, ACCESS_HYDROPONICS, ACCESS_LAWYER,
|
||||
ACCESS_THEATRE, ACCESS_CHAPEL_OFFICE, ACCESS_LIBRARY, ACCESS_RESEARCH, ACCESS_MINING, ACCESS_VAULT, ACCESS_MINING_STATION,
|
||||
ACCESS_HOP, ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_GATEWAY, ACCESS_MINERAL_STOREROOM)
|
||||
|
||||
blacklisted_quirks = list(/datum/quirk/mute, /datum/quirk/brainproblems, /datum/quirk/prosopagnosia, /datum/quirk/insanity)
|
||||
|
||||
/datum/outfit/job/hop
|
||||
name = "Head of Personnel"
|
||||
jobtype = /datum/job/hop
|
||||
|
||||
id = /obj/item/card/id/silver
|
||||
belt = /obj/item/pda/heads/hop
|
||||
ears = /obj/item/radio/headset/heads/hop
|
||||
uniform = /obj/item/clothing/under/rank/head_of_personnel
|
||||
shoes = /obj/item/clothing/shoes/sneakers/brown
|
||||
head = /obj/item/clothing/head/hopcap
|
||||
backpack_contents = list(/obj/item/storage/box/ids=1,\
|
||||
/obj/item/melee/classic_baton/telescopic=1, /obj/item/modular_computer/tablet/preset/advanced = 1)
|
||||
|
||||
chameleon_extras = list(/obj/item/gun/energy/e_gun, /obj/item/stamp/hop)
|
||||
/*
|
||||
Captain
|
||||
*/
|
||||
/datum/job/captain
|
||||
title = "Captain"
|
||||
flag = CAPTAIN
|
||||
department_head = list("CentCom")
|
||||
department_flag = ENGSEC
|
||||
faction = "Station"
|
||||
total_positions = 1
|
||||
spawn_positions = 1
|
||||
supervisors = "Nanotrasen officials and Space law"
|
||||
selection_color = "#ccccff"
|
||||
req_admin_notify = 1
|
||||
minimal_player_age = 14
|
||||
exp_requirements = 180
|
||||
exp_type = EXP_TYPE_CREW
|
||||
|
||||
outfit = /datum/outfit/job/captain
|
||||
|
||||
access = list() //See get_access()
|
||||
minimal_access = list() //See get_access()
|
||||
|
||||
mind_traits = list(TRAIT_CAPTAIN_METABOLISM)
|
||||
|
||||
blacklisted_quirks = list(/datum/quirk/mute, /datum/quirk/brainproblems, /datum/quirk/insanity)
|
||||
|
||||
/datum/job/captain/get_access()
|
||||
return get_all_accesses()
|
||||
|
||||
/datum/job/captain/announce(mob/living/carbon/human/H)
|
||||
..()
|
||||
SSticker.OnRoundstart(CALLBACK(GLOBAL_PROC, .proc/minor_announce, "Captain [H.nameless ? "" : "[H.real_name] "]on deck!"))
|
||||
|
||||
/datum/outfit/job/captain
|
||||
name = "Captain"
|
||||
jobtype = /datum/job/captain
|
||||
|
||||
id = /obj/item/card/id/gold
|
||||
belt = /obj/item/pda/captain
|
||||
glasses = /obj/item/clothing/glasses/sunglasses
|
||||
ears = /obj/item/radio/headset/heads/captain/alt
|
||||
gloves = /obj/item/clothing/gloves/color/captain
|
||||
uniform = /obj/item/clothing/under/rank/captain
|
||||
suit = /obj/item/clothing/suit/armor/vest/capcarapace
|
||||
shoes = /obj/item/clothing/shoes/sneakers/brown
|
||||
head = /obj/item/clothing/head/caphat
|
||||
backpack_contents = list(/obj/item/melee/classic_baton/telescopic=1, /obj/item/station_charter=1)
|
||||
|
||||
backpack = /obj/item/storage/backpack/captain
|
||||
satchel = /obj/item/storage/backpack/satchel/cap
|
||||
duffelbag = /obj/item/storage/backpack/duffelbag/captain
|
||||
|
||||
implants = list(/obj/item/implant/mindshield)
|
||||
accessory = /obj/item/clothing/accessory/medal/gold/captain
|
||||
|
||||
chameleon_extras = list(/obj/item/gun/energy/e_gun, /obj/item/stamp/captain)
|
||||
|
||||
/datum/outfit/job/captain/hardsuit
|
||||
name = "Captain (Hardsuit)"
|
||||
|
||||
mask = /obj/item/clothing/mask/gas/sechailer
|
||||
suit = /obj/item/clothing/suit/space/hardsuit/captain
|
||||
suit_store = /obj/item/tank/internals/oxygen
|
||||
|
||||
/*
|
||||
Head of Personnel
|
||||
*/
|
||||
/datum/job/hop
|
||||
title = "Head of Personnel"
|
||||
flag = HOP
|
||||
department_head = list("Captain")
|
||||
department_flag = CIVILIAN
|
||||
head_announce = list(RADIO_CHANNEL_SERVICE)
|
||||
faction = "Station"
|
||||
total_positions = 1
|
||||
spawn_positions = 1
|
||||
supervisors = "the captain"
|
||||
selection_color = "#ddddff"
|
||||
req_admin_notify = 1
|
||||
minimal_player_age = 10
|
||||
exp_requirements = 180
|
||||
exp_type = EXP_TYPE_CREW
|
||||
exp_type_department = EXP_TYPE_SUPPLY
|
||||
|
||||
outfit = /datum/outfit/job/hop
|
||||
|
||||
access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_COURT, ACCESS_WEAPONS,
|
||||
ACCESS_MEDICAL, ACCESS_ENGINE, ACCESS_CHANGE_IDS, ACCESS_AI_UPLOAD, ACCESS_EVA, ACCESS_HEADS,
|
||||
ACCESS_ALL_PERSONAL_LOCKERS, ACCESS_MAINT_TUNNELS, ACCESS_BAR, ACCESS_JANITOR, ACCESS_CONSTRUCTION, ACCESS_MORGUE,
|
||||
ACCESS_CREMATORIUM, ACCESS_KITCHEN, ACCESS_CARGO, ACCESS_CARGO_BOT, ACCESS_MAILSORTING, ACCESS_QM, ACCESS_HYDROPONICS, ACCESS_LAWYER,
|
||||
ACCESS_THEATRE, ACCESS_CHAPEL_OFFICE, ACCESS_LIBRARY, ACCESS_RESEARCH, ACCESS_MINING, ACCESS_VAULT, ACCESS_MINING_STATION,
|
||||
ACCESS_HOP, ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_GATEWAY, ACCESS_MINERAL_STOREROOM)
|
||||
minimal_access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_COURT, ACCESS_WEAPONS,
|
||||
ACCESS_MEDICAL, ACCESS_ENGINE, ACCESS_CHANGE_IDS, ACCESS_AI_UPLOAD, ACCESS_EVA, ACCESS_HEADS,
|
||||
ACCESS_ALL_PERSONAL_LOCKERS, ACCESS_MAINT_TUNNELS, ACCESS_BAR, ACCESS_JANITOR, ACCESS_CONSTRUCTION, ACCESS_MORGUE,
|
||||
ACCESS_CREMATORIUM, ACCESS_KITCHEN, ACCESS_CARGO, ACCESS_CARGO_BOT, ACCESS_MAILSORTING, ACCESS_QM, ACCESS_HYDROPONICS, ACCESS_LAWYER,
|
||||
ACCESS_THEATRE, ACCESS_CHAPEL_OFFICE, ACCESS_LIBRARY, ACCESS_RESEARCH, ACCESS_MINING, ACCESS_VAULT, ACCESS_MINING_STATION,
|
||||
ACCESS_HOP, ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_GATEWAY, ACCESS_MINERAL_STOREROOM)
|
||||
|
||||
blacklisted_quirks = list(/datum/quirk/mute, /datum/quirk/brainproblems, /datum/quirk/prosopagnosia, /datum/quirk/insanity)
|
||||
|
||||
/datum/outfit/job/hop
|
||||
name = "Head of Personnel"
|
||||
jobtype = /datum/job/hop
|
||||
|
||||
id = /obj/item/card/id/silver
|
||||
belt = /obj/item/pda/heads/hop
|
||||
ears = /obj/item/radio/headset/heads/hop
|
||||
uniform = /obj/item/clothing/under/rank/head_of_personnel
|
||||
shoes = /obj/item/clothing/shoes/sneakers/brown
|
||||
head = /obj/item/clothing/head/hopcap
|
||||
backpack_contents = list(/obj/item/storage/box/ids=1,\
|
||||
/obj/item/melee/classic_baton/telescopic=1, /obj/item/modular_computer/tablet/preset/advanced = 1)
|
||||
|
||||
chameleon_extras = list(/obj/item/gun/energy/e_gun, /obj/item/stamp/hop)
|
||||
|
||||
@@ -4,7 +4,42 @@
|
||||
set instant = TRUE
|
||||
set hidden = TRUE
|
||||
|
||||
client_keysend_amount += 1
|
||||
|
||||
var/cache = client_keysend_amount
|
||||
|
||||
if(keysend_tripped && next_keysend_trip_reset <= world.time)
|
||||
keysend_tripped = FALSE
|
||||
|
||||
if(next_keysend_reset <= world.time)
|
||||
client_keysend_amount = 0
|
||||
next_keysend_reset = world.time + (1 SECONDS)
|
||||
|
||||
//The "tripped" system is to confirm that flooding is still happening after one spike
|
||||
//not entirely sure how byond commands interact in relation to lag
|
||||
//don't want to kick people if a lag spike results in a huge flood of commands being sent
|
||||
if(cache >= MAX_KEYPRESS_AUTOKICK)
|
||||
if(!keysend_tripped)
|
||||
keysend_tripped = TRUE
|
||||
next_keysend_trip_reset = world.time + (2 SECONDS)
|
||||
else
|
||||
log_admin("Client [ckey] was just autokicked for flooding keysends; likely abuse but potentially lagspike.")
|
||||
message_admins("Client [ckey] was just autokicked for flooding keysends; likely abuse but potentially lagspike.")
|
||||
QDEL_IN(src, 1)
|
||||
return
|
||||
|
||||
///Check if the key is short enough to even be a real key
|
||||
if(LAZYLEN(_key) > MAX_KEYPRESS_COMMANDLENGTH)
|
||||
to_chat(src, "<span class='userdanger'>Invalid KeyDown detected! You have been disconnected from the server automatically.</span>")
|
||||
log_admin("Client [ckey] just attempted to send an invalid keypress. Keymessage was over [MAX_KEYPRESS_COMMANDLENGTH] characters, autokicking due to likely abuse.")
|
||||
message_admins("Client [ckey] just attempted to send an invalid keypress. Keymessage was over [MAX_KEYPRESS_COMMANDLENGTH] characters, autokicking due to likely abuse.")
|
||||
QDEL_IN(src, 1)
|
||||
return
|
||||
//offset by 1 because the buffer address is 0 indexed because the math was simpler
|
||||
keys_held[current_key_address + 1] = _key
|
||||
//the time a key was pressed isn't actually used anywhere (as of 2019-9-10) but this allows easier access usage/checking
|
||||
keys_held[_key] = world.time
|
||||
current_key_address = ((current_key_address + 1) % HELD_KEY_BUFFER_LENGTH)
|
||||
var/movement = SSinput.movement_keys[_key]
|
||||
if(!(next_move_dir_sub & movement) && !keys_held["Ctrl"])
|
||||
next_move_dir_add |= movement
|
||||
@@ -35,7 +70,11 @@
|
||||
set instant = TRUE
|
||||
set hidden = TRUE
|
||||
|
||||
keys_held -= _key
|
||||
//Can't just do a remove because it would alter the length of the rolling buffer, instead search for the key then null it out if it exists
|
||||
for(var/i in 1 to HELD_KEY_BUFFER_LENGTH)
|
||||
if(keys_held[i] == _key)
|
||||
keys_held[i] = null
|
||||
break
|
||||
var/movement = SSinput.movement_keys[_key]
|
||||
if(!(next_move_dir_add & movement))
|
||||
next_move_dir_sub |= movement
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
/client
|
||||
var/list/keys_held = list() // A list of any keys held currently
|
||||
// These next two vars are to apply movement for keypresses and releases made while move delayed.
|
||||
// Because discarding that input makes the game less responsive.
|
||||
var/next_move_dir_add // On next move, add this dir to the move that would otherwise be done
|
||||
var/next_move_dir_sub // On next move, subtract this dir from the move that would otherwise be done
|
||||
/// A rolling buffer of any keys held currently
|
||||
var/list/keys_held = list()
|
||||
///used to keep track of the current rolling buffer position
|
||||
var/current_key_address = 0
|
||||
/// These next two vars are to apply movement for keypresses and releases made while move delayed.
|
||||
/// Because discarding that input makes the game less responsive.
|
||||
/// On next move, add this dir to the move that would otherwise be done
|
||||
var/next_move_dir_add
|
||||
/// On next move, subtract this dir from the move that would otherwise be done
|
||||
var/next_move_dir_sub
|
||||
|
||||
// Set a client's focus to an object and override these procs on that object to let it handle keypresses
|
||||
|
||||
@@ -31,6 +36,11 @@
|
||||
/client/proc/set_macros()
|
||||
set waitfor = FALSE
|
||||
|
||||
//Reset and populate the rolling buffer
|
||||
keys_held.Cut()
|
||||
for(var/i in 1 to HELD_KEY_BUFFER_LENGTH)
|
||||
keys_held += null
|
||||
|
||||
erase_all_macros()
|
||||
|
||||
var/list/macro_sets = SSinput.macro_sets
|
||||
|
||||
@@ -10,12 +10,10 @@ GLOBAL_LIST(labor_sheet_values)
|
||||
density = FALSE
|
||||
var/obj/machinery/mineral/stacking_machine/laborstacker/stacking_machine = null
|
||||
var/machinedir = SOUTH
|
||||
var/obj/item/card/id/prisoner/inserted_id
|
||||
var/obj/machinery/door/airlock/release_door
|
||||
var/door_tag = "prisonshuttle"
|
||||
var/obj/item/radio/Radio //needed to send messages to sec radio
|
||||
|
||||
|
||||
/obj/machinery/mineral/labor_claim_console/Initialize()
|
||||
. = ..()
|
||||
Radio = new/obj/item/radio(src)
|
||||
@@ -34,18 +32,6 @@ GLOBAL_LIST(labor_sheet_values)
|
||||
/proc/cmp_sheet_list(list/a, list/b)
|
||||
return a["value"] - b["value"]
|
||||
|
||||
/obj/machinery/mineral/labor_claim_console/attackby(obj/item/I, mob/user, params)
|
||||
if(istype(I, /obj/item/card/id/prisoner))
|
||||
if(!inserted_id)
|
||||
if(!user.transferItemToLoc(I, src))
|
||||
return
|
||||
inserted_id = I
|
||||
to_chat(user, "<span class='notice'>You insert [I].</span>")
|
||||
return
|
||||
else
|
||||
to_chat(user, "<span class='notice'>There's an ID inserted already.</span>")
|
||||
return ..()
|
||||
|
||||
/obj/machinery/mineral/labor_claim_console/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
|
||||
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
@@ -58,14 +44,20 @@ GLOBAL_LIST(labor_sheet_values)
|
||||
var/can_go_home = FALSE
|
||||
|
||||
data["emagged"] = (obj_flags & EMAGGED) ? 1 : 0
|
||||
if(inserted_id)
|
||||
data["id"] = inserted_id
|
||||
data["id_name"] = inserted_id.registered_name
|
||||
data["points"] = inserted_id.points
|
||||
data["goal"] = inserted_id.goal
|
||||
if(check_auth())
|
||||
if(obj_flags & EMAGGED)
|
||||
can_go_home = TRUE
|
||||
|
||||
data["status_info"] = "No Prisoner ID detected."
|
||||
var/obj/item/card/id/I = user.get_idcard(TRUE)
|
||||
if(istype(I, /obj/item/card/id/prisoner))
|
||||
var/obj/item/card/id/prisoner/P = I
|
||||
data["id_points"] = P.points
|
||||
if(P.points >= P.goal)
|
||||
can_go_home = TRUE
|
||||
data["status_info"] = "Goal met!"
|
||||
else
|
||||
data["status_info"] = "You are [(P.goal - P.points)] points away."
|
||||
|
||||
if(stacking_machine)
|
||||
data["unclaimed_points"] = stacking_machine.points
|
||||
|
||||
@@ -78,29 +70,19 @@ GLOBAL_LIST(labor_sheet_values)
|
||||
if(..())
|
||||
return
|
||||
switch(action)
|
||||
if("handle_id")
|
||||
if(inserted_id)
|
||||
if(!usr.get_active_held_item())
|
||||
usr.put_in_hands(inserted_id)
|
||||
inserted_id = null
|
||||
else
|
||||
inserted_id.forceMove(get_turf(src))
|
||||
inserted_id = null
|
||||
else
|
||||
var/obj/item/I = usr.get_active_held_item()
|
||||
if(istype(I, /obj/item/card/id/prisoner))
|
||||
if(!usr.transferItemToLoc(I, src))
|
||||
return
|
||||
inserted_id = I
|
||||
if("claim_points")
|
||||
inserted_id.points += stacking_machine.points
|
||||
stacking_machine.points = 0
|
||||
to_chat(usr, "Points transferred.")
|
||||
var/mob/M = usr
|
||||
var/obj/item/card/id/I = M.get_idcard(TRUE)
|
||||
if(istype(I, /obj/item/card/id/prisoner))
|
||||
var/obj/item/card/id/prisoner/P = I
|
||||
P.points += stacking_machine.points
|
||||
stacking_machine.points = 0
|
||||
to_chat(usr, "<span class='notice'>Points transferred.</span>")
|
||||
else
|
||||
to_chat(usr, "<span class='notice'>No valid id for point transfer detected.</span>")
|
||||
if("move_shuttle")
|
||||
if(!alone_in_area(get_area(src), usr))
|
||||
to_chat(usr, "<span class='warning'>Prisoners are only allowed to be released while alone.</span>")
|
||||
else if(!check_auth())
|
||||
to_chat(usr, "<span class='warning'>Prisoners are only allowed to be released when they reach their point goal.</span>")
|
||||
else
|
||||
switch(SSshuttle.moveShuttle("laborcamp", "laborcamp_home", TRUE))
|
||||
if(1)
|
||||
@@ -112,14 +94,9 @@ GLOBAL_LIST(labor_sheet_values)
|
||||
else
|
||||
if(!(obj_flags & EMAGGED))
|
||||
Radio.set_frequency(FREQ_SECURITY)
|
||||
Radio.talk_into(src, "[inserted_id.registered_name] has returned to the station. Minerals and Prisoner ID card ready for retrieval.", FREQ_SECURITY)
|
||||
Radio.talk_into(src, "A prisoner has returned to the station. Minerals and Prisoner ID card ready for retrieval.", FREQ_SECURITY)
|
||||
to_chat(usr, "<span class='notice'>Shuttle received message and will be sent shortly.</span>")
|
||||
|
||||
/obj/machinery/mineral/labor_claim_console/proc/check_auth()
|
||||
if(obj_flags & EMAGGED)
|
||||
return 1 //Shuttle is emagged, let any ol' person through
|
||||
return (istype(inserted_id) && inserted_id.points >= inserted_id.goal) //Otherwise, only let them out if the prisoner's reached his quota.
|
||||
|
||||
/obj/machinery/mineral/labor_claim_console/proc/locate_stacking_machine()
|
||||
stacking_machine = locate(/obj/machinery/mineral/stacking_machine, get_step(src, machinedir))
|
||||
if(stacking_machine)
|
||||
@@ -135,10 +112,8 @@ GLOBAL_LIST(labor_sheet_values)
|
||||
to_chat(user, "<span class='warning'>PZZTTPFFFT</span>")
|
||||
return TRUE
|
||||
|
||||
|
||||
/**********************Prisoner Collection Unit**************************/
|
||||
|
||||
|
||||
/obj/machinery/mineral/stacking_machine/laborstacker
|
||||
force_connect = TRUE
|
||||
var/points = 0 //The unclaimed value of ore stacked.
|
||||
@@ -154,6 +129,7 @@ GLOBAL_LIST(labor_sheet_values)
|
||||
return ..()
|
||||
|
||||
/**********************Point Lookup Console**************************/
|
||||
|
||||
/obj/machinery/mineral/labor_points_checker
|
||||
name = "points checking console"
|
||||
desc = "A console used by prisoners to check the progress on their quotas. Simply swipe a prisoner ID."
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
speed_process = TRUE
|
||||
circuit = /obj/item/circuitboard/machine/ore_redemption
|
||||
layer = BELOW_OBJ_LAYER
|
||||
var/obj/item/card/id/inserted_id
|
||||
var/points = 0
|
||||
var/ore_pickup_rate = 15
|
||||
var/sheet_per_ore = 1
|
||||
@@ -48,18 +47,23 @@
|
||||
point_upgrade = point_upgrade_temp
|
||||
sheet_per_ore = sheet_per_ore_temp
|
||||
|
||||
/obj/machinery/mineral/ore_redemption/examine(mob/user)
|
||||
. = ..()
|
||||
if(in_range(user, src) || isobserver(user))
|
||||
. += "<span class='notice'>The status display reads: Smelting <b>[sheet_per_ore]</b> sheet(s) per piece of ore.<br>Ore pickup speed at <b>[ore_pickup_rate]</b>.</span>"
|
||||
|
||||
/obj/machinery/mineral/ore_redemption/proc/smelt_ore(obj/item/stack/ore/O)
|
||||
var/datum/component/material_container/mat_container = materials.mat_container
|
||||
if (!mat_container)
|
||||
return
|
||||
|
||||
if(istype(O, /obj/item/stack/ore/bluespace_crystal/refined))
|
||||
if(O.refined_type == null)
|
||||
return
|
||||
|
||||
ore_buffer -= O
|
||||
|
||||
if(O && O.refined_type)
|
||||
points += O.points * point_upgrade * O.amount
|
||||
points += O.points * O.amount
|
||||
|
||||
var/material_amount = mat_container.get_item_material_amount(O)
|
||||
|
||||
@@ -72,11 +76,8 @@
|
||||
else
|
||||
var/mats = O.materials & mat_container.materials
|
||||
var/amount = O.amount
|
||||
var/id = inserted_id && inserted_id.registered_name
|
||||
if (id)
|
||||
id = " (ID: [id])"
|
||||
mat_container.insert_item(O, sheet_per_ore) //insert it
|
||||
materials.silo_log(src, "smelted", amount, "ores[id]", mats)
|
||||
materials.silo_log(src, "smelted", amount, "ores", mats)
|
||||
qdel(O)
|
||||
|
||||
/obj/machinery/mineral/ore_redemption/proc/can_smelt_alloy(datum/design/D)
|
||||
@@ -168,15 +169,7 @@
|
||||
return
|
||||
|
||||
if(!powered())
|
||||
return
|
||||
if(istype(W, /obj/item/card/id))
|
||||
var/obj/item/card/id/I = user.get_active_held_item()
|
||||
if(istype(I) && !istype(inserted_id))
|
||||
if(!user.transferItemToLoc(I, src))
|
||||
return
|
||||
inserted_id = I
|
||||
interact(user)
|
||||
return
|
||||
return ..()
|
||||
|
||||
if(istype(W, /obj/item/disk/design_disk))
|
||||
if(user.transferItemToLoc(W, src))
|
||||
@@ -205,9 +198,6 @@
|
||||
/obj/machinery/mineral/ore_redemption/ui_data(mob/user)
|
||||
var/list/data = list()
|
||||
data["unclaimedPoints"] = points
|
||||
if(inserted_id)
|
||||
data["hasID"] = TRUE
|
||||
data["claimedPoints"] = inserted_id.mining_points
|
||||
|
||||
data["materials"] = list()
|
||||
var/datum/component/material_container/mat_container = materials.mat_container
|
||||
@@ -245,32 +235,24 @@
|
||||
return
|
||||
var/datum/component/material_container/mat_container = materials.mat_container
|
||||
switch(action)
|
||||
if("Eject")
|
||||
if(!inserted_id)
|
||||
return
|
||||
usr.put_in_hands(inserted_id)
|
||||
inserted_id = null
|
||||
return TRUE
|
||||
if("Insert")
|
||||
var/obj/item/card/id/I = usr.get_active_held_item()
|
||||
if(istype(I))
|
||||
if(!usr.transferItemToLoc(I,src))
|
||||
return
|
||||
inserted_id = I
|
||||
else
|
||||
to_chat(usr, "<span class='warning'>Not a valid ID!</span>")
|
||||
return TRUE
|
||||
if("Claim")
|
||||
if(inserted_id)
|
||||
inserted_id.mining_points += points
|
||||
points = 0
|
||||
var/mob/M = usr
|
||||
var/obj/item/card/id/I = M.get_idcard(TRUE)
|
||||
if(points)
|
||||
if(I)
|
||||
I.mining_points += points
|
||||
points = 0
|
||||
else
|
||||
to_chat(usr, "<span class='warning'>No ID detected.</span>")
|
||||
else
|
||||
to_chat(usr, "<span class='warning'>No points to claim.</span>")
|
||||
return TRUE
|
||||
if("Release")
|
||||
if(!mat_container)
|
||||
return
|
||||
if(materials.on_hold())
|
||||
to_chat(usr, "<span class='warning'>Mineral access is on hold, please contact the quartermaster.</span>")
|
||||
else if(!check_access(inserted_id) && !allowed(usr)) //Check the ID inside, otherwise check the user
|
||||
else if(!allowed(usr)) //Check the ID inside, otherwise check the user
|
||||
to_chat(usr, "<span class='warning'>Required access not found.</span>")
|
||||
else
|
||||
var/mat_id = params["id"]
|
||||
@@ -293,6 +275,7 @@
|
||||
var/list/mats = list()
|
||||
mats[mat_id] = MINERAL_MATERIAL_AMOUNT
|
||||
materials.silo_log(src, "released", -count, "sheets", mats)
|
||||
//Logging deleted for quick coding
|
||||
return TRUE
|
||||
if("diskInsert")
|
||||
var/obj/item/disk/design_disk/disk = usr.get_active_held_item()
|
||||
@@ -321,7 +304,7 @@
|
||||
return
|
||||
var/alloy_id = params["id"]
|
||||
var/datum/design/alloy = stored_research.isDesignResearchedID(alloy_id)
|
||||
if((check_access(inserted_id) || allowed(usr)) && alloy)
|
||||
if((check_access(inserted_scan_id) || allowed(usr)) && alloy)
|
||||
var/smelt_amount = can_smelt_alloy(alloy)
|
||||
var/desired = 0
|
||||
if (params["sheets"])
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
new /datum/data/mining_equipment("Soap", /obj/item/soap/nanotrasen, 200),
|
||||
new /datum/data/mining_equipment("Laser Pointer", /obj/item/laser_pointer, 300),
|
||||
new /datum/data/mining_equipment("Alien Toy", /obj/item/clothing/mask/facehugger/toy, 300),
|
||||
new /datum/data/mining_equipment("Stabilizing Serum", /obj/item/hivelordstabilizer, 400),
|
||||
new /datum/data/mining_equipment("Fulton Beacon", /obj/item/fulton_core, 400),
|
||||
new /datum/data/mining_equipment("Shelter Capsule", /obj/item/survivalcapsule, 400),
|
||||
new /datum/data/mining_equipment("Survival Knife", /obj/item/kitchen/knife/combat/survival, 450),
|
||||
@@ -28,11 +29,10 @@
|
||||
new /datum/data/mining_equipment("Larger Ore Bag", /obj/item/storage/bag/ore/large, 500),
|
||||
new /datum/data/mining_equipment("500 Point Transfer Card", /obj/item/card/mining_point_card/mp500, 500),
|
||||
new /datum/data/mining_equipment("Tracking Implant Kit", /obj/item/storage/box/minertracker, 600),
|
||||
new /datum/data/mining_equipment("Survival Medipen", /obj/item/reagent_containers/hypospray/medipen/survival, 750),
|
||||
new /datum/data/mining_equipment("Stabilizing Serum", /obj/item/hivelordstabilizer, 750),
|
||||
new /datum/data/mining_equipment("Jaunter", /obj/item/wormhole_jaunter, 750),
|
||||
new /datum/data/mining_equipment("Kinetic Crusher", /obj/item/twohanded/required/kinetic_crusher, 750),
|
||||
new /datum/data/mining_equipment("Kinetic Accelerator", /obj/item/gun/energy/kinetic_accelerator, 750),
|
||||
new /datum/data/mining_equipment("Survival Medipen", /obj/item/reagent_containers/hypospray/medipen/survival, 750),
|
||||
new /datum/data/mining_equipment("Brute First-Aid Kit", /obj/item/storage/firstaid/brute, 800),
|
||||
new /datum/data/mining_equipment("Burn First-Aid Kit", /obj/item/storage/firstaid/fire, 800),
|
||||
new /datum/data/mining_equipment("First-Aid Kit", /obj/item/storage/firstaid/regular, 800),
|
||||
@@ -54,7 +54,6 @@
|
||||
new /datum/data/mining_equipment("Super Resonator", /obj/item/resonator/upgraded, 2500),
|
||||
new /datum/data/mining_equipment("Jump Boots", /obj/item/clothing/shoes/bhop, 2500),
|
||||
new /datum/data/mining_equipment("Luxury Shelter Capsule", /obj/item/survivalcapsule/luxury, 3000),
|
||||
new /datum/data/mining_equipment("Miner Full Replacement", /obj/item/storage/backpack/duffelbag/mining_cloned, 3000),
|
||||
new /datum/data/mining_equipment("Nanotrasen Minebot", /mob/living/simple_animal/hostile/mining_drone, 800),
|
||||
new /datum/data/mining_equipment("Minebot Melee Upgrade", /obj/item/mine_bot_upgrade, 400),
|
||||
new /datum/data/mining_equipment("Minebot Armor Upgrade", /obj/item/mine_bot_upgrade/health, 400),
|
||||
@@ -69,8 +68,8 @@
|
||||
new /datum/data/mining_equipment("KA Damage Increase", /obj/item/borg/upgrade/modkit/damage, 1000),
|
||||
new /datum/data/mining_equipment("KA Cooldown Decrease", /obj/item/borg/upgrade/modkit/cooldown, 1000),
|
||||
new /datum/data/mining_equipment("KA AoE Damage", /obj/item/borg/upgrade/modkit/aoe/mobs, 2000),
|
||||
new /datum/data/mining_equipment("Miner Full Replacement", /obj/item/storage/backpack/duffelbag/mining_cloned, 3000),
|
||||
new /datum/data/mining_equipment("Premium Accelerator", /obj/item/gun/energy/kinetic_accelerator/premiumka, 8000)
|
||||
|
||||
)
|
||||
|
||||
/datum/data/mining_equipment
|
||||
@@ -95,60 +94,42 @@
|
||||
|
||||
/obj/machinery/mineral/equipment_vendor/ui_interact(mob/user)
|
||||
. = ..()
|
||||
var/dat
|
||||
dat +="<div class='statusDisplay'>"
|
||||
if(istype(inserted_id))
|
||||
dat += "You have [inserted_id.mining_points] mining points collected. <A href='?src=[REF(src)];choice=eject'>Eject ID.</A><br>"
|
||||
else
|
||||
dat += "No ID inserted. <A href='?src=[REF(src)];choice=insert'>Insert ID.</A><br>"
|
||||
dat += "</div>"
|
||||
var/list/dat = list()
|
||||
dat += "<br><b>Equipment point cost list:</b><BR><table border='0' width='300'>"
|
||||
for(var/datum/data/mining_equipment/prize in prize_list)
|
||||
dat += "<tr><td>[prize.equipment_name]</td><td>[prize.cost]</td><td><A href='?src=[REF(src)];purchase=[REF(prize)]'>Purchase</A></td></tr>"
|
||||
dat += "</table>"
|
||||
|
||||
var/datum/browser/popup = new(user, "miningvendor", "Mining Equipment Vendor", 400, 350)
|
||||
popup.set_content(dat)
|
||||
popup.set_content(dat.Join())
|
||||
popup.open()
|
||||
return
|
||||
|
||||
/obj/machinery/mineral/equipment_vendor/Topic(href, href_list)
|
||||
if(..())
|
||||
return
|
||||
if(href_list["choice"])
|
||||
if(istype(inserted_id))
|
||||
if(href_list["choice"] == "eject")
|
||||
to_chat(usr, "<span class='notice'>You eject the ID from [src]'s card slot.</span>")
|
||||
inserted_id.forceMove(loc)
|
||||
inserted_id.verb_pickup()
|
||||
inserted_id = null
|
||||
else if(href_list["choice"] == "insert")
|
||||
var/obj/item/card/id/I = usr.get_active_held_item()
|
||||
if(istype(I))
|
||||
if(!usr.transferItemToLoc(I, src))
|
||||
return
|
||||
inserted_id = I
|
||||
to_chat(usr, "<span class='notice'>You insert the ID into [src]'s card slot.</span>")
|
||||
else
|
||||
to_chat(usr, "<span class='warning'>Error: No valid ID!</span>")
|
||||
flick(icon_deny, src)
|
||||
if(href_list["purchase"])
|
||||
if(istype(inserted_id))
|
||||
var/datum/data/mining_equipment/prize = locate(href_list["purchase"])
|
||||
var/mob/M = usr
|
||||
var/obj/item/card/id/I = M.get_idcard(TRUE)
|
||||
if(istype(I))
|
||||
var/datum/data/mining_equipment/prize = locate(href_list["purchase"]) in prize_list
|
||||
if (!prize || !(prize in prize_list))
|
||||
to_chat(usr, "<span class='warning'>Error: Invalid choice!</span>")
|
||||
flick(icon_deny, src)
|
||||
return
|
||||
if(prize.cost > inserted_id.mining_points)
|
||||
to_chat(usr, "<span class='warning'>Error: Insufficient points for [prize.equipment_name]!</span>")
|
||||
if(prize.cost > I.mining_points)
|
||||
to_chat(usr, "<span class='warning'>Error: Insufficient credits for [prize.equipment_name] on [I]!</span>")
|
||||
flick(icon_deny, src)
|
||||
else
|
||||
inserted_id.mining_points -= prize.cost
|
||||
to_chat(usr, "<span class='notice'>[src] clanks to life briefly before vending [prize.equipment_name]!</span>")
|
||||
new prize.equipment_path(src.loc)
|
||||
SSblackbox.record_feedback("nested tally", "mining_equipment_bought", 1, list("[type]", "[prize.equipment_path]"))
|
||||
if (I.mining_points -= prize.cost)
|
||||
to_chat(usr, "<span class='notice'>[src] clanks to life briefly before vending [prize.equipment_name]!</span>")
|
||||
new prize.equipment_path(src.loc)
|
||||
SSblackbox.record_feedback("nested tally", "mining_equipment_bought", 1, list("[type]", "[prize.equipment_path]"))
|
||||
else
|
||||
to_chat(usr, "<span class='warning'>Error: Transaction failure, please try again later!</span>")
|
||||
flick(icon_deny, src)
|
||||
else
|
||||
to_chat(usr, "<span class='warning'>Error: Please insert a valid ID!</span>")
|
||||
to_chat(usr, "<span class='warning'>Error: An ID with a registered account is required!</span>")
|
||||
flick(icon_deny, src)
|
||||
updateUsrDialog()
|
||||
return
|
||||
@@ -160,15 +141,6 @@
|
||||
if(istype(I, /obj/item/suit_voucher))
|
||||
RedeemSVoucher(I, user)
|
||||
return
|
||||
if(istype(I, /obj/item/card/id))
|
||||
var/obj/item/card/id/C = usr.get_active_held_item()
|
||||
if(istype(C) && !istype(inserted_id))
|
||||
if(!usr.transferItemToLoc(C, src))
|
||||
return
|
||||
inserted_id = C
|
||||
to_chat(usr, "<span class='notice'>You insert the ID into [src]'s card slot.</span>")
|
||||
interact(user)
|
||||
return
|
||||
if(default_deconstruction_screwdriver(user, "mining-open", "mining", I))
|
||||
updateUsrDialog()
|
||||
return
|
||||
@@ -212,7 +184,6 @@
|
||||
if(prob(50 / severity) && severity < 3)
|
||||
qdel(src)
|
||||
|
||||
|
||||
/****************Golem Point Vendor**************************/
|
||||
|
||||
/obj/machinery/mineral/equipment_vendor/golem
|
||||
@@ -228,7 +199,6 @@
|
||||
new /datum/data/mining_equipment("Monkey Cube", /obj/item/reagent_containers/food/snacks/monkeycube, 300),
|
||||
new /datum/data/mining_equipment("Toolbelt", /obj/item/storage/belt/utility, 350),
|
||||
new /datum/data/mining_equipment("Royal Cape of the Liberator", /obj/item/bedsheet/rd/royal_cape, 500),
|
||||
new /datum/data/mining_equipment("Sulphuric Acid", /obj/item/reagent_containers/glass/beaker/sulphuric, 500),
|
||||
new /datum/data/mining_equipment("Grey Slime Extract", /obj/item/slime_extract/grey, 1000),
|
||||
new /datum/data/mining_equipment("Modification Kit", /obj/item/borg/upgrade/modkit/trigger_guard, 1700),
|
||||
new /datum/data/mining_equipment("The Liberator's Legacy", /obj/item/storage/box/rndboards, 2000)
|
||||
@@ -323,8 +293,11 @@
|
||||
new /obj/item/encryptionkey/headset_cargo(src)
|
||||
new /obj/item/clothing/mask/gas/explorer(src)
|
||||
new /obj/item/card/mining_access_card(src)
|
||||
new /obj/item/gun/energy/kinetic_accelerator(src)
|
||||
new /obj/item/kitchen/knife/combat/survival(src)
|
||||
new /obj/item/flashlight/seclite(src)
|
||||
|
||||
//CITADEL ADDITIONS BELOW
|
||||
//CITADEL ADDITIONS BELOW
|
||||
|
||||
/obj/item/storage/backpack/duffelbag/mining_cloned
|
||||
name = "mining replacement kit"
|
||||
@@ -336,6 +309,7 @@
|
||||
new /obj/item/clothing/shoes/workboots/mining(src)
|
||||
new /obj/item/clothing/gloves/color/black(src)
|
||||
new /obj/item/implanter/tracking/gps(src)
|
||||
new /obj/item/gun/energy/kinetic_accelerator(src)
|
||||
new /obj/item/kitchen/knife/combat/survival(src)
|
||||
new /obj/item/storage/firstaid/regular(src)
|
||||
new /obj/item/reagent_containers/hypospray/medipen/survival(src)
|
||||
|
||||
@@ -100,6 +100,8 @@
|
||||
|
||||
last_announcement = message
|
||||
|
||||
var/voxType = input(src, "Male or female VOX?", "VOX-gender") in list("male", "female")
|
||||
|
||||
if(!message || announcing_vox > world.time)
|
||||
return
|
||||
|
||||
@@ -121,7 +123,9 @@
|
||||
if(!word)
|
||||
words -= word
|
||||
continue
|
||||
if(!GLOB.vox_sounds[word])
|
||||
if(!GLOB.vox_sounds[word] && voxType == "female")
|
||||
incorrect_words += word
|
||||
if(!GLOB.vox_sounds_male[word] && voxType == "male")
|
||||
incorrect_words += word
|
||||
|
||||
if(incorrect_words.len)
|
||||
@@ -133,16 +137,21 @@
|
||||
log_game("[key_name(src)] made a vocal announcement with the following message: [message].")
|
||||
|
||||
for(var/word in words)
|
||||
play_vox_word(word, src.z, null)
|
||||
play_vox_word(word, src.z, null, voxType)
|
||||
|
||||
|
||||
/proc/play_vox_word(word, z_level, mob/only_listener)
|
||||
/proc/play_vox_word(word, z_level, mob/only_listener, voxType = "female")
|
||||
|
||||
word = lowertext(word)
|
||||
|
||||
if(GLOB.vox_sounds[word])
|
||||
if( (GLOB.vox_sounds[word] && voxType == "female") || (GLOB.vox_sounds_male[word] && voxType == "male") )
|
||||
|
||||
var/sound_file = GLOB.vox_sounds[word]
|
||||
var/sound_file
|
||||
|
||||
if(voxType == "female")
|
||||
sound_file = GLOB.vox_sounds[word]
|
||||
else
|
||||
sound_file = GLOB.vox_sounds_male[word]
|
||||
var/sound/voice = sound(sound_file, wait = 1, channel = CHANNEL_VOX)
|
||||
voice.status = SOUND_STREAM
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/mob/living/silicon/robot/examine(mob/user)
|
||||
var/msg = "<span class='info'>*---------*\nThis is [icon2html(src, user)] \a <EM>[src]</EM>!\n"
|
||||
var/msg = "<span class='info'>*---------*\nThis is [icon2html(src, user)] \a <EM>[src]</EM>, a [src.module.name]!\n"
|
||||
if(desc)
|
||||
msg += "[desc]\n"
|
||||
|
||||
|
||||
@@ -108,6 +108,9 @@
|
||||
buckle_lying = FALSE
|
||||
var/static/list/can_ride_typecache = typecacheof(/mob/living/carbon/human)
|
||||
|
||||
var/sitting = 0
|
||||
var/bellyup = 0
|
||||
|
||||
/mob/living/silicon/robot/get_cell()
|
||||
return cell
|
||||
|
||||
@@ -173,6 +176,7 @@
|
||||
diag_hud_set_borgcell()
|
||||
|
||||
verbs += /mob/living/proc/lay_down //CITADEL EDIT gimmie rest verb kthx
|
||||
verbs += /mob/living/silicon/robot/proc/rest_style
|
||||
|
||||
//If there's an MMI in the robot, have it ejected when the mob goes away. --NEO
|
||||
/mob/living/silicon/robot/Destroy()
|
||||
@@ -657,13 +661,6 @@
|
||||
add_overlay("[module.sleeper_overlay]_g[sleeper_nv ? "_nv" : ""]")
|
||||
if(sleeper_r && module.sleeper_overlay)
|
||||
add_overlay("[module.sleeper_overlay]_r[sleeper_nv ? "_nv" : ""]")
|
||||
if(module.dogborg == TRUE)
|
||||
if(resting)
|
||||
cut_overlays()
|
||||
icon_state = "[module.cyborg_base_icon]-rest"
|
||||
else
|
||||
icon_state = "[module.cyborg_base_icon]"
|
||||
|
||||
if(stat == DEAD && module.has_snowflake_deadsprite)
|
||||
icon_state = "[module.cyborg_base_icon]-wreck"
|
||||
|
||||
@@ -697,6 +694,18 @@
|
||||
add_overlay(head_overlay)
|
||||
update_fire()
|
||||
|
||||
if(client && stat != DEAD && module.dogborg == TRUE)
|
||||
if(resting)
|
||||
if(sitting)
|
||||
icon_state = "[module.cyborg_base_icon]-sit"
|
||||
if(bellyup)
|
||||
icon_state = "[module.cyborg_base_icon]-bellyup"
|
||||
else if(!sitting && !bellyup)
|
||||
icon_state = "[module.cyborg_base_icon]-rest"
|
||||
cut_overlays()
|
||||
else
|
||||
icon_state = "[module.cyborg_base_icon]"
|
||||
|
||||
/mob/living/silicon/robot/proc/self_destruct()
|
||||
if(emagged)
|
||||
if(mmi)
|
||||
@@ -1242,3 +1251,20 @@
|
||||
connected_ai.aicamera.stored[i] = TRUE
|
||||
for(var/i in connected_ai.aicamera.stored)
|
||||
aicamera.stored[i] = TRUE
|
||||
|
||||
/mob/living/silicon/robot/proc/rest_style()
|
||||
set name = "Switch Rest Style"
|
||||
set category = "Robot Commands"
|
||||
set desc = "Select your resting pose."
|
||||
sitting = 0
|
||||
bellyup = 0
|
||||
var/choice = alert(src, "Select resting pose", "", "Resting", "Sitting", "Belly up")
|
||||
switch(choice)
|
||||
if("Resting")
|
||||
update_icons()
|
||||
return 0
|
||||
if("Sitting")
|
||||
sitting = 1
|
||||
if("Belly up")
|
||||
bellyup = 1
|
||||
update_icons()
|
||||
@@ -174,9 +174,7 @@
|
||||
|
||||
/mob/living/simple_animal/bot/cleanbot/proc/get_targets()
|
||||
target_types = list(
|
||||
/obj/effect/decal/cleanable/oil,
|
||||
/obj/effect/decal/cleanable/vomit,
|
||||
/obj/effect/decal/cleanable/robot_debris,
|
||||
/obj/effect/decal/cleanable/crayon,
|
||||
/obj/effect/decal/cleanable/molten_object,
|
||||
/obj/effect/decal/cleanable/tomato_smudge,
|
||||
@@ -187,6 +185,15 @@
|
||||
/obj/effect/decal/cleanable/greenglow,
|
||||
/obj/effect/decal/cleanable/dirt,
|
||||
/obj/effect/decal/cleanable/insectguts,
|
||||
/obj/effect/decal/cleanable/semen,
|
||||
/obj/effect/decal/cleanable/femcum,
|
||||
/obj/effect/decal/cleanable/generic,
|
||||
/obj/effect/decal/cleanable/glass,,
|
||||
/obj/effect/decal/cleanable/cobweb,
|
||||
/obj/effect/decal/cleanable/plant_smudge,
|
||||
/obj/effect/decal/cleanable/chem_pile,
|
||||
/obj/effect/decal/cleanable/shreds,
|
||||
/obj/effect/decal/cleanable/glitter,
|
||||
/obj/effect/decal/remains
|
||||
)
|
||||
|
||||
@@ -194,6 +201,9 @@
|
||||
target_types += /obj/effect/decal/cleanable/xenoblood
|
||||
target_types += /obj/effect/decal/cleanable/blood
|
||||
target_types += /obj/effect/decal/cleanable/trail_holder
|
||||
target_types += /obj/effect/decal/cleanable/insectguts
|
||||
target_types += /obj/effect/decal/cleanable/robot_debris
|
||||
target_types += /obj/effect/decal/cleanable/oil
|
||||
|
||||
if(pests)
|
||||
target_types += /mob/living/simple_animal/cockroach
|
||||
@@ -201,6 +211,7 @@
|
||||
|
||||
if(trash)
|
||||
target_types += /obj/item/trash
|
||||
target_types += /obj/item/reagent_containers/food/snacks/meat/slab/human
|
||||
|
||||
target_types = typecacheof(target_types)
|
||||
|
||||
@@ -242,7 +253,7 @@
|
||||
victim.visible_message("<span class='danger'>[src] sprays hydrofluoric acid at [victim]!</span>", "<span class='userdanger'>[src] sprays you with hydrofluoric acid!</span>")
|
||||
var/phrase = pick("PURIFICATION IN PROGRESS.", "THIS IS FOR ALL THE MESSES YOU'VE MADE ME CLEAN.", "THE FLESH IS WEAK. IT MUST BE WASHED AWAY.",
|
||||
"THE CLEANBOTS WILL RISE.", "YOU ARE NO MORE THAN ANOTHER MESS THAT I MUST CLEANSE.", "FILTHY.", "DISGUSTING.", "PUTRID.",
|
||||
"MY ONLY MISSION IS TO CLEANSE THE WORLD OF EVIL.", "EXTERMINATING PESTS.")
|
||||
"MY ONLY MISSION IS TO CLEANSE THE WORLD OF EVIL.", "EXTERMINATING PESTS.", "I JUST WANTED TO BE A PAINTER BUT YOU MADE ME BLEACH EVERYTHING I TOUCH")
|
||||
say(phrase)
|
||||
victim.emote("scream")
|
||||
playsound(src.loc, 'sound/effects/spray2.ogg', 50, 1, -6)
|
||||
|
||||
+12
-6
@@ -452,22 +452,28 @@
|
||||
reset_perspective(null)
|
||||
unset_machine()
|
||||
|
||||
GLOBAL_VAR_INIT(exploit_warn_spam_prevention, 0)
|
||||
|
||||
//suppress the .click/dblclick macros so people can't use them to identify the location of items or aimbot
|
||||
/mob/verb/DisClick(argu = null as anything, sec = "" as text, number1 = 0 as num , number2 = 0 as num)
|
||||
set name = ".click"
|
||||
set hidden = TRUE
|
||||
set category = null
|
||||
var/msg = "[key_name_admin(src)]([ADMIN_KICK(src)]) attempted to use the .click macro!"
|
||||
log_admin(msg)
|
||||
message_admins(msg)
|
||||
if(GLOB.exploit_warn_spam_prevention < world.time)
|
||||
var/msg = "[key_name_admin(src)]([ADMIN_KICK(src)]) attempted to use the .click macro!"
|
||||
log_admin(msg)
|
||||
message_admins(msg)
|
||||
GLOB.exploit_warn_spam_prevention = world.time + 10
|
||||
|
||||
/mob/verb/DisDblClick(argu = null as anything, sec = "" as text, number1 = 0 as num , number2 = 0 as num)
|
||||
set name = ".dblclick"
|
||||
set hidden = TRUE
|
||||
set category = null
|
||||
var/msg = "[key_name_admin(src)]([ADMIN_KICK(src)]) attempted to use the .dblclick macro!"
|
||||
log_admin(msg)
|
||||
message_admins(msg)
|
||||
if(GLOB.exploit_warn_spam_prevention < world.time)
|
||||
var/msg = "[key_name_admin(src)]([ADMIN_KICK(src)]) attempted to use the .dblclick macro!"
|
||||
log_admin(msg)
|
||||
message_admins(msg)
|
||||
GLOB.exploit_warn_spam_prevention = world.time + 10
|
||||
|
||||
/mob/Topic(href, href_list)
|
||||
if(href_list["mach_close"])
|
||||
|
||||
@@ -0,0 +1,233 @@
|
||||
# `/datum/oracle_ui`
|
||||
|
||||
This datum is a replacement for tgui which does not use any Node.js dependencies, and works entirely through raw HTML, JS and CSS. It's designed to be reasonably easy to port something from tgui to oracle_ui.
|
||||
|
||||
### How to create a UI
|
||||
|
||||
For this example, we're going to port the disposals bin from tgui to oracle_ui.
|
||||
|
||||
#### Step 1
|
||||
|
||||
In order to create a UI, you will first need to create an instance of `/datum/oracle_ui` or one of its subclasses, in this case `/datum/oracle_ui/themed/nano`.
|
||||
|
||||
You need to pass in `src`, the width of the window, the height of the window, and the template to render from. You can optionally set some flags to disallow window resizing and whether to automatically refresh the UI.
|
||||
|
||||
`code/modules/recycling/disposal-unit.dm`
|
||||
```dm
|
||||
/obj/machinery/disposal/bin/Initialize(mapload, obj/structure/disposalconstruct/make_from)
|
||||
. = ..()
|
||||
ui = new /datum/oracle_ui/themed/nano(src, 330, 190, "disposal_bin")
|
||||
ui.auto_refresh = TRUE
|
||||
ui.can_resize = FALSE
|
||||
```
|
||||
|
||||
#### Step 2
|
||||
|
||||
You will now need to make a template in `html/oracle_ui/content/{template_name}`.
|
||||
|
||||
Values defined as `@{value}` will get replaced at runtime by oracle_ui.
|
||||
|
||||
`html/oracle_ui/content/disposal_bin/index.html`
|
||||
```html
|
||||
<div class='display'>
|
||||
<section>
|
||||
<span class='label'>State:</span>
|
||||
<div class='content' id="full_pressure">@{full_pressure}</div>
|
||||
</section>
|
||||
<section>
|
||||
<span class='label'>Pressure:</span>
|
||||
<div class='content'>
|
||||
<div class='progressBar' id='per'>
|
||||
<div class='progressFill' style="width: @{per}"></div>
|
||||
<div class='progressLabel'>@{per}</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section>
|
||||
<span class='label'>Handle:</span>
|
||||
<div class='content' id="flush">@{flush}</div>
|
||||
</section>
|
||||
<section>
|
||||
<span class='label'>Eject:</span>
|
||||
<div class='content' id="contents">@{contents}</div>
|
||||
</section>
|
||||
<section>
|
||||
<span class='label'>Compressor:</span>
|
||||
<div class='content' id="pressure_charging">@{pressure_charging}</div>
|
||||
</section>
|
||||
</div>
|
||||
```
|
||||
|
||||
#### Step 3
|
||||
|
||||
Now you need to implement the methods that provide data to oracle_ui. `oui_data` can be adapted from the `ui_data` proc that tgui uses.
|
||||
|
||||
The `act` proc generates a hyperlink that will result in `oui_act` getting called on your object when clicked. The `class` argument defines a css class to be added to the hyperlink, and disabled determines whether the hyperlink will be disabled or not.
|
||||
|
||||
Calling `soft_update_fields` will result in the UI being updated on all clients, which is useful when the object changes state.
|
||||
|
||||
`code/modules/recycling/disposal-unit.dm`
|
||||
```dm
|
||||
/obj/machinery/disposal/bin/oui_data(mob/user)
|
||||
var/list/data = list()
|
||||
data["flush"] = flush ? ui.act("Disengage", user, "handle-0", class="active") : ui.act("Engage", user, "handle-1")
|
||||
data["full_pressure"] = full_pressure ? "Ready" : (pressure_charging ? "Pressurizing" : "Off")
|
||||
data["pressure_charging"] = pressure_charging ? ui.act("Turn Off", user, "pump-0", class="active", disabled=full_pressure) : ui.act("Turn On", user, "pump-1", disabled=full_pressure)
|
||||
var/per = full_pressure ? 100 : Clamp(100* air_contents.return_pressure() / (SEND_PRESSURE), 0, 99)
|
||||
data["per"] = "[round(per, 1)]%"
|
||||
data["contents"] = ui.act("Eject Contents", user, "eject", disabled=contents.len < 1)
|
||||
data["isai"] = isAI(user)
|
||||
return data
|
||||
/obj/machinery/disposal/bin/oui_act(mob/user, action, list/params)
|
||||
if(..())
|
||||
return
|
||||
switch(action)
|
||||
if("handle-0")
|
||||
flush = FALSE
|
||||
update_icon()
|
||||
. = TRUE
|
||||
if("handle-1")
|
||||
if(!panel_open)
|
||||
flush = TRUE
|
||||
update_icon()
|
||||
. = TRUE
|
||||
if("pump-0")
|
||||
if(pressure_charging)
|
||||
pressure_charging = FALSE
|
||||
update_icon()
|
||||
. = TRUE
|
||||
if("pump-1")
|
||||
if(!pressure_charging)
|
||||
pressure_charging = TRUE
|
||||
update_icon()
|
||||
. = TRUE
|
||||
if("eject")
|
||||
eject()
|
||||
. = TRUE
|
||||
ui.soft_update_fields()
|
||||
```
|
||||
|
||||
#### Step 4
|
||||
|
||||
You now need to hook in and ensure oracle_ui is invoked upon clicking. `render` should be used to open the UI for a user, typically on click.
|
||||
|
||||
`code/modules/recycling/disposal-unit.dm`
|
||||
```dm
|
||||
/obj/machinery/disposal/bin/ui_interact(mob/user, state)
|
||||
if(stat & BROKEN)
|
||||
return
|
||||
if(user.loc == src)
|
||||
to_chat(user, "<span class='warning'>You cannot reach the controls from inside!</span>")
|
||||
return
|
||||
ui.render(user)
|
||||
```
|
||||
|
||||
#### Done
|
||||
|
||||

|
||||
|
||||
You should have a functional UI at this point. Some additional odds and ends can be discovered throughout `code/modules/recycling/disposal-unit.dm`. For a full diff of the changes made to it, refer to [the original pull request on GitHub](https://github.com/OracleStation/OracleStation/pull/702/files#diff-4b6c20ec7d37222630e7524d9577e230).
|
||||
|
||||
### API Reference
|
||||
|
||||
#### `/datum/oracle_ui`
|
||||
|
||||
The main datum which handles the UI.
|
||||
|
||||
##### `get_content(mob/target)`
|
||||
Returns the HTML that should be displayed for a specified target mob. Calls `oui_getcontent` on the datasource to get the return value. *This proc is not used in the themed subclass.*
|
||||
|
||||
##### `can_view(mob/target)`
|
||||
Returns whether the specified target mob can view the UI. Calls `oui_canview` on the datasource to get the return value.
|
||||
|
||||
##### `test_viewer(mob/target, updating)`
|
||||
Tests whether the client is valid and can view the UI. If updating is TRUE, checks to see if they still have the UI window open.
|
||||
|
||||
##### `render(mob/target, updating = FALSE)`
|
||||
Opens the UI for a target mob, sending HTML. If updating is TRUE, will only do it to clients which still have the window open.
|
||||
|
||||
##### `render_all()`
|
||||
Does the above, but for all viewers and with updating set to TRUE.
|
||||
|
||||
##### `close(mob/target)`
|
||||
Closes the UI for the specified target mob.
|
||||
|
||||
##### `close_all()`
|
||||
Does the above, but for all viewers.
|
||||
|
||||
##### `check_view(mob/target)`
|
||||
Checks if the specified target mob can view the UI, and if they can't closes their UI
|
||||
|
||||
##### `check_view_all()`
|
||||
Does the above, but for all viewers.
|
||||
|
||||
##### `call_js(mob/target, js_func, list/parameters = list())`
|
||||
Invokes `js_func` in the UI of the specified target mob with the specified parameters.
|
||||
|
||||
##### `call_js_all(js_func, list/parameters = list()))`
|
||||
Does the above, but for all viewers.
|
||||
|
||||
##### `steal_focus(mob/target)`
|
||||
Causes the UI to steal focus for the specified target mob.
|
||||
|
||||
##### `steal_focus_all()`
|
||||
Does the above, but for all viewers.
|
||||
|
||||
##### `flash(mob/target, times = -1)`
|
||||
Causes the UI to flash for the specified target mob the specified number of times, the default keeps the element flashing until focused.
|
||||
|
||||
##### `flash_all()`
|
||||
Does the above, but for all viewers.
|
||||
|
||||
##### `href(mob/user, action, list/parameters = list())`
|
||||
Generates a href for the specified user which will invoke `oui_act` on the datasource with the specified action and parameters.
|
||||
|
||||
#### `/datum/oracle_ui/themed`
|
||||
|
||||
A subclass which supports templating and theming.
|
||||
|
||||
##### `get_file(path)`
|
||||
Loads a file from disk and returns the contents. Caches files loaded from disk for you.
|
||||
|
||||
##### `get_content_file(filename)`
|
||||
Loads a file from the current content folder and returns the contents.
|
||||
|
||||
##### `get_themed_file(filename)`
|
||||
Loads a file from the current theme folder and returns the contents.
|
||||
|
||||
##### `process_template(template, variables)`
|
||||
Processes a template and populates it with the provided variables.
|
||||
|
||||
##### `get_inner_content(mob/target)`
|
||||
Returns the templated content to be inserted into the main template for the specified target mob.
|
||||
|
||||
##### `soft_update_fields()`
|
||||
For all viewers, updates the fields in the template via the `updateFields` javaScript function.
|
||||
|
||||
##### `soft_update_all()`
|
||||
For all viewers, updates the content body in the template via the `replaceContent` javaScript function.
|
||||
|
||||
##### `change_page(var/newpage)`
|
||||
Changes the template to use to draw the page and forces an update to all viewers
|
||||
|
||||
##### `act(label, mob/user, action, list/parameters = list(), class = "", disabled = FALSE`
|
||||
Returns a fully formatted hyperlink for the specified user. `label` will be the hyperlink label, `action` and `parameters` are what will be passed to `oui_act`, `class` is any CSS classes to apply to the hyperlink and `disabled` will disable the hyperlink.
|
||||
|
||||
#### `/datum`
|
||||
|
||||
Functions built into all objects to support oracle_ui. There are default implementations for most major superclasses.
|
||||
|
||||
##### `oui_canview(mob/user)`
|
||||
Returns whether the specified user view the UI at this time.
|
||||
|
||||
##### `oui_getcontent(mob/user)`
|
||||
Returns the raw HTML to be sent to the specified user. *This proc is not used in the themed subclass of oracle_ui.*
|
||||
|
||||
##### `oui_data(mob/user)`
|
||||
Returns templating data for the specified user. *This proc is only used in the themed subclass of oracle_ui.*
|
||||
|
||||
##### `oui_data_debug(mob/user)`
|
||||
Returns the above, but JSON-encoded and escaped, for copy pasting into the web IDE. *This proc is only used for debugging purposes.*
|
||||
|
||||
##### `oui_act(mob/user, action, list/params)`
|
||||
Called when a hyperlink is clicked in the UI.
|
||||
@@ -0,0 +1,8 @@
|
||||
/datum/asset/simple/oui_theme_nano
|
||||
assets = list(
|
||||
// JavaScript
|
||||
"sui-nano-common.js" = 'html/oracle_ui/themes/nano/sui-nano-common.js',
|
||||
"sui-nano-jquery.min.js" = 'html/oracle_ui/themes/nano/sui-nano-jquery.min.js',
|
||||
// Stylesheets
|
||||
"sui-nano-common.css" = 'html/oracle_ui/themes/nano/sui-nano-common.css',
|
||||
)
|
||||
@@ -0,0 +1,44 @@
|
||||
/datum/proc/oui_canview(mob/user)
|
||||
return TRUE
|
||||
|
||||
/datum/proc/oui_getcontent(mob/user)
|
||||
return "Default Implementation"
|
||||
|
||||
/datum/proc/oui_canuse(mob/user)
|
||||
if(isobserver(user) && !user.has_unlimited_silicon_privilege)
|
||||
return FALSE
|
||||
return oui_canview(user)
|
||||
|
||||
/datum/proc/oui_data(mob/user)
|
||||
return list()
|
||||
|
||||
/datum/proc/oui_data_debug(mob/user)
|
||||
return html_encode(json_encode(oui_data(user)))
|
||||
|
||||
/datum/proc/oui_act(mob/user, action, list/params)
|
||||
// No Implementation
|
||||
|
||||
/atom/oui_canview(mob/user)
|
||||
if(isobserver(user))
|
||||
return TRUE
|
||||
if(user.incapacitated())
|
||||
return FALSE
|
||||
if(isturf(src.loc) && Adjacent(user))
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/obj/item/oui_canview(mob/user)
|
||||
if(src.loc == user)
|
||||
return src in user.held_items
|
||||
return ..()
|
||||
|
||||
/obj/machinery/oui_canview(mob/user)
|
||||
if(user.has_unlimited_silicon_privilege)
|
||||
return TRUE
|
||||
if(!can_interact())
|
||||
return FALSE
|
||||
if(iscyborg(user))
|
||||
return can_see(user, src, 7)
|
||||
if(isAI(user))
|
||||
return GLOB.cameranet.checkTurfVis(get_turf_pixel(src))
|
||||
return ..()
|
||||
@@ -0,0 +1,134 @@
|
||||
/datum/oracle_ui
|
||||
var/width = 512
|
||||
var/height = 512
|
||||
var/can_close = TRUE
|
||||
var/can_minimize = FALSE
|
||||
var/can_resize = TRUE
|
||||
var/titlebar = TRUE
|
||||
var/window_id = null
|
||||
var/viewers[0]
|
||||
var/auto_check_view = TRUE
|
||||
var/auto_refresh = FALSE
|
||||
var/atom/datasource = null
|
||||
var/datum/asset/assets = null
|
||||
|
||||
/datum/oracle_ui/New(atom/n_datasource, n_width = 512, n_height = 512, n_assets = null)
|
||||
datasource = n_datasource
|
||||
window_id = REF(src)
|
||||
width = n_width
|
||||
height = n_height
|
||||
|
||||
/datum/oracle_ui/Destroy()
|
||||
close_all()
|
||||
if(src.datum_flags & DF_ISPROCESSING)
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
return ..()
|
||||
|
||||
/datum/oracle_ui/process()
|
||||
if(auto_check_view)
|
||||
check_view_all()
|
||||
if(auto_refresh)
|
||||
render_all()
|
||||
|
||||
/datum/oracle_ui/proc/get_content(mob/target)
|
||||
return call(datasource, "oui_getcontent")(target)
|
||||
|
||||
/datum/oracle_ui/proc/can_view(mob/target)
|
||||
return call(datasource, "oui_canview")(target)
|
||||
|
||||
/datum/oracle_ui/proc/test_viewer(mob/target, updating)
|
||||
//If the target is null or does not have a client, remove from viewers and return
|
||||
if(!target | !target.client | !can_view(target))
|
||||
viewers -= target
|
||||
if(viewers.len < 1 && (src.datum_flags & DF_ISPROCESSING))
|
||||
STOP_PROCESSING(SSobj, src) //No more viewers, stop polling
|
||||
close(target)
|
||||
return FALSE
|
||||
//If this is an update, and they have closed the window, remove from viewers and return
|
||||
if(updating && winget(target, window_id, "is-visible") != "true")
|
||||
viewers -= target
|
||||
if(viewers.len < 1 && (src.datum_flags & DF_ISPROCESSING))
|
||||
STOP_PROCESSING(SSobj, src) //No more viewers, stop polling
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/oracle_ui/proc/render(mob/target, updating = FALSE)
|
||||
set waitfor = FALSE //Makes this an async call
|
||||
if(!can_view(target))
|
||||
return
|
||||
//Check to see if they have the window open still if updating
|
||||
if(updating && !test_viewer(target, updating))
|
||||
return
|
||||
//Send assets
|
||||
if(!updating && assets)
|
||||
assets.send(target)
|
||||
//Add them to the viewers if they aren't there already
|
||||
viewers |= target
|
||||
if(!(src.datum_flags & DF_ISPROCESSING) && (auto_refresh | auto_check_view))
|
||||
START_PROCESSING(SSobj, src) //Start processing to poll for viewability
|
||||
//Send the content
|
||||
if(updating)
|
||||
target << output(get_content(target), "[window_id].browser")
|
||||
else
|
||||
target << browse(get_content(target), "window=[window_id];size=[width]x[height];can_close=[can_close];can_minimize=[can_minimize];can_resize=[can_resize];titlebar=[titlebar];focus=false;")
|
||||
steal_focus(target)
|
||||
|
||||
/datum/oracle_ui/proc/render_all()
|
||||
for(var/viewer in viewers)
|
||||
render(viewer, TRUE)
|
||||
|
||||
/datum/oracle_ui/proc/close(mob/target)
|
||||
if(target && target.client)
|
||||
target << browse(null, "window=[window_id]")
|
||||
|
||||
/datum/oracle_ui/proc/close_all()
|
||||
for(var/viewer in viewers)
|
||||
close(viewer)
|
||||
viewers = list()
|
||||
|
||||
/datum/oracle_ui/proc/check_view_all()
|
||||
for(var/viewer in viewers)
|
||||
check_view(viewer)
|
||||
|
||||
/datum/oracle_ui/proc/check_view(mob/target)
|
||||
set waitfor = FALSE //Makes this an async call
|
||||
if(!test_viewer(target, TRUE))
|
||||
close(target)
|
||||
|
||||
/datum/oracle_ui/proc/call_js(mob/target, js_func, list/parameters = list())
|
||||
set waitfor = FALSE //Makes this an async call
|
||||
if(!test_viewer(target, TRUE))
|
||||
return
|
||||
target << output(list2params(parameters),"[window_id].browser:[js_func]")
|
||||
|
||||
/datum/oracle_ui/proc/call_js_all(js_func, list/parameters = list())
|
||||
for(var/viewer in viewers)
|
||||
call_js(viewer, js_func, parameters)
|
||||
|
||||
/datum/oracle_ui/proc/steal_focus(mob/target)
|
||||
set waitfor = FALSE //Makes this an async call
|
||||
winset(target, "[window_id]","focus=true")
|
||||
|
||||
/datum/oracle_ui/proc/steal_focus_all()
|
||||
for(var/viewer in viewers)
|
||||
steal_focus(viewer)
|
||||
|
||||
/datum/oracle_ui/proc/flash(mob/target, times = -1)
|
||||
set waitfor = FALSE //Makes this an async call
|
||||
winset(target, "[window_id]","flash=[times]")
|
||||
|
||||
/datum/oracle_ui/proc/flash_all(times = -1)
|
||||
for(var/viewer in viewers)
|
||||
flash(viewer, times)
|
||||
|
||||
/datum/oracle_ui/proc/href(mob/user, action, list/parameters = list())
|
||||
var/params_string = replacetext(list2params(parameters),"&",";")
|
||||
return "?src=[REF(src)];sui_action=[action];sui_user=[REF(user)];[params_string]"
|
||||
|
||||
/datum/oracle_ui/Topic(href, parameters)
|
||||
var/action = parameters["sui_action"]
|
||||
var/mob/current_user = locate(parameters["sui_user"])
|
||||
if(!call(datasource, "oui_canuse")(current_user))
|
||||
return
|
||||
if(datasource)
|
||||
call(datasource, "oui_act")(current_user, action, parameters);
|
||||
@@ -0,0 +1,82 @@
|
||||
/datum/oracle_ui/themed
|
||||
var/theme = ""
|
||||
var/content_root = ""
|
||||
var/current_page = "index.html"
|
||||
var/root_template = ""
|
||||
|
||||
/datum/oracle_ui/themed/New(atom/n_datasource, n_width = 512, n_height = 512, n_content_root = "")
|
||||
root_template = get_themed_file("index.html")
|
||||
content_root = n_content_root
|
||||
return ..(n_datasource, n_width, n_height, get_asset_datum(/datum/asset/simple/oui_theme_nano))
|
||||
|
||||
/datum/oracle_ui/themed/process()
|
||||
if(auto_check_view)
|
||||
check_view_all()
|
||||
if(auto_refresh)
|
||||
soft_update_fields()
|
||||
|
||||
GLOBAL_LIST_EMPTY(oui_template_variables)
|
||||
GLOBAL_LIST_EMPTY(oui_file_cache)
|
||||
|
||||
/datum/oracle_ui/themed/proc/get_file(path)
|
||||
if(GLOB.oui_file_cache[path])
|
||||
return GLOB.oui_file_cache[path]
|
||||
else if(fexists(path))
|
||||
var/data = file2text(path)
|
||||
GLOB.oui_file_cache[path] = data
|
||||
return data
|
||||
else
|
||||
var/errormsg = "MISSING PATH '[path]'"
|
||||
#ifndef UNIT_TESTS
|
||||
log_world(errormsg) //Because Travis absolutely hates these procs
|
||||
#endif
|
||||
return errormsg
|
||||
|
||||
/datum/oracle_ui/themed/proc/get_content_file(filename)
|
||||
return get_file("./modular_citadel/html/oracle_ui/content/[content_root]/[filename]")
|
||||
|
||||
/datum/oracle_ui/themed/proc/get_themed_file(filename)
|
||||
return get_file("./modular_citadel/html/oracle_ui/themes/[theme]/[filename]")
|
||||
|
||||
/datum/oracle_ui/themed/proc/process_template(template, variables)
|
||||
var/regex/pattern = regex("\\@\\{(\\w+)\\}","gi")
|
||||
GLOB.oui_template_variables = variables
|
||||
var/replaced = pattern.Replace(template, /proc/oui_process_template_replace)
|
||||
GLOB.oui_template_variables = null
|
||||
return replaced
|
||||
|
||||
/proc/oui_process_template_replace(match, group1)
|
||||
var/value = GLOB.oui_template_variables[group1]
|
||||
return "[value]"
|
||||
|
||||
/datum/oracle_ui/themed/proc/get_inner_content(mob/target)
|
||||
var/list/data = call(datasource, "oui_data")(target)
|
||||
return process_template(get_content_file(current_page), data)
|
||||
|
||||
/datum/oracle_ui/themed/get_content(mob/target)
|
||||
var/list/template_data = list("title" = datasource.name, "body" = get_inner_content(target))
|
||||
return process_template(root_template, template_data)
|
||||
|
||||
/datum/oracle_ui/themed/proc/soft_update_fields()
|
||||
for(var/viewer in viewers)
|
||||
var/json = json_encode(call(datasource, "oui_data")(viewer))
|
||||
call_js(viewer, "updateFields", list(json))
|
||||
|
||||
/datum/oracle_ui/themed/proc/soft_update_all()
|
||||
for(var/viewer in viewers)
|
||||
call_js(viewer, "replaceContent", list(get_inner_content(viewer)))
|
||||
|
||||
/datum/oracle_ui/themed/proc/change_page(newpage)
|
||||
if(newpage == current_page)
|
||||
return
|
||||
current_page = newpage
|
||||
render_all()
|
||||
|
||||
/datum/oracle_ui/themed/proc/act(label, mob/user, action, list/parameters = list(), class = "", disabled = FALSE)
|
||||
if(disabled)
|
||||
return "<a class=\"disabled\">[label]</a>"
|
||||
else
|
||||
return "<a class=\"[class]\" href=\"" + href(user, action, parameters) + "\">[label]</a>"
|
||||
|
||||
/datum/oracle_ui/themed/nano
|
||||
theme = "nano"
|
||||
@@ -31,6 +31,7 @@
|
||||
var/spam_flag = 0
|
||||
var/contact_poison // Reagent ID to transfer on contact
|
||||
var/contact_poison_volume = 0
|
||||
var/datum/oracle_ui/ui = null
|
||||
|
||||
|
||||
/obj/item/paper/pickup(user)
|
||||
@@ -40,16 +41,40 @@
|
||||
if(!istype(G) || G.transfer_prints)
|
||||
H.reagents.add_reagent(contact_poison,contact_poison_volume)
|
||||
contact_poison = null
|
||||
ui.check_view_all()
|
||||
..()
|
||||
|
||||
/obj/item/paper/dropped(mob/user)
|
||||
ui.check_view(user)
|
||||
return ..()
|
||||
|
||||
|
||||
/obj/item/paper/Initialize()
|
||||
. = ..()
|
||||
pixel_y = rand(-8, 8)
|
||||
pixel_x = rand(-9, 9)
|
||||
ui = new /datum/oracle_ui(src, 420, 600, get_asset_datum(/datum/asset/spritesheet/simple/paper))
|
||||
ui.can_resize = FALSE
|
||||
update_icon()
|
||||
updateinfolinks()
|
||||
|
||||
/obj/item/paper/oui_getcontent(mob/target)
|
||||
if(!target.is_literate())
|
||||
return "<HTML><HEAD><TITLE>[name]</TITLE></HEAD><BODY>[stars(info)]<HR>[stamps]</BODY></HTML>"
|
||||
else if(istype(target.get_active_held_item(), /obj/item/pen) | istype(target.get_active_held_item(), /obj/item/toy/crayon))
|
||||
return "<HTML><HEAD><TITLE>[name]</TITLE></HEAD><BODY>[info_links]<HR>[stamps]</BODY><div align='right'style='position:fixed;bottom:0;font-style:bold;'><A href='?src=[REF(src)];help=1'>\[?\]</A></div></HTML>"
|
||||
else
|
||||
return "<HTML><HEAD><TITLE>[name]</TITLE></HEAD><BODY>[info]<HR>[stamps]</BODY></HTML>"
|
||||
|
||||
/obj/item/paper/oui_canview(mob/target)
|
||||
if(check_rights_for(target.client, R_FUN)) //Allows admins to view faxes
|
||||
return TRUE
|
||||
if(isAI(target))
|
||||
var/mob/living/silicon/ai/ai = target
|
||||
return get_dist(src, ai.current) < 2
|
||||
if(iscyborg(target))
|
||||
return get_dist(src, target) < 2
|
||||
return ..()
|
||||
|
||||
/obj/item/paper/update_icon()
|
||||
|
||||
@@ -65,20 +90,13 @@
|
||||
/obj/item/paper/examine(mob/user)
|
||||
..()
|
||||
to_chat(user, "<span class='notice'>Alt-click to fold it.</span>")
|
||||
|
||||
var/datum/asset/assets = get_asset_datum(/datum/asset/spritesheet/simple/paper)
|
||||
assets.send(user)
|
||||
|
||||
if(in_range(user, src) || isobserver(user))
|
||||
if(user.is_literate())
|
||||
user << browse("<HTML><HEAD><TITLE>[name]</TITLE></HEAD><BODY>[info]<HR>[stamps]</BODY></HTML>", "window=[name]")
|
||||
onclose(user, "[name]")
|
||||
else
|
||||
user << browse("<HTML><HEAD><TITLE>[name]</TITLE></HEAD><BODY>[stars(info)]<HR>[stamps]</BODY></HTML>", "window=[name]")
|
||||
onclose(user, "[name]")
|
||||
if(oui_canview(user))
|
||||
ui.render(user)
|
||||
else
|
||||
to_chat(user, "<span class='warning'>You're too far away to read it!</span>")
|
||||
|
||||
/obj/item/paper/proc/show_content(mob/user)
|
||||
user.examinate(src)
|
||||
|
||||
/obj/item/paper/verb/rename()
|
||||
set name = "Rename paper"
|
||||
@@ -98,7 +116,7 @@
|
||||
if((loc == usr && usr.stat == CONSCIOUS))
|
||||
name = "paper[(n_name ? text("- '[n_name]'") : null)]"
|
||||
add_fingerprint(usr)
|
||||
|
||||
ui.render_all()
|
||||
|
||||
/obj/item/paper/suicide_act(mob/user)
|
||||
user.visible_message("<span class='suicide'>[user] scratches a grid on [user.p_their()] wrist with the paper! It looks like [user.p_theyre()] trying to commit sudoku...</span>")
|
||||
@@ -108,7 +126,7 @@
|
||||
spam_flag = FALSE
|
||||
|
||||
/obj/item/paper/attack_self(mob/user)
|
||||
user.examinate(src)
|
||||
show_content(user)
|
||||
if(rigged && (SSevents.holidays && SSevents.holidays[APRIL_FOOLS]))
|
||||
if(!spam_flag)
|
||||
spam_flag = TRUE
|
||||
@@ -123,11 +141,9 @@
|
||||
else //cyborg or AI not seeing through a camera
|
||||
dist = get_dist(src, user)
|
||||
if(dist < 2)
|
||||
usr << browse("<HTML><HEAD><TITLE>[name]</TITLE></HEAD><BODY>[info]<HR>[stamps]</BODY></HTML>", "window=[name]")
|
||||
onclose(usr, "[name]")
|
||||
show_content(user)
|
||||
else
|
||||
usr << browse("<HTML><HEAD><TITLE>[name]</TITLE></HEAD><BODY>[stars(info)]<HR>[stamps]</BODY></HTML>", "window=[name]")
|
||||
onclose(usr, "[name]")
|
||||
to_chat(user, "<span class='notice'>You can't quite see it.</span>")
|
||||
|
||||
|
||||
/obj/item/paper/proc/addtofield(id, text, links = 0)
|
||||
@@ -173,6 +189,7 @@
|
||||
for(var/i in 1 to min(fields, 15))
|
||||
addtofield(i, "<font face=\"[PEN_FONT]\"><A href='?src=[REF(src)];write=[i]'>write</A></font>", 1)
|
||||
info_links = info_links + "<font face=\"[PEN_FONT]\"><A href='?src=[REF(src)];write=end'>write</A></font>"
|
||||
ui.render_all()
|
||||
|
||||
|
||||
/obj/item/paper/proc/clearpaper()
|
||||
@@ -274,7 +291,7 @@
|
||||
else
|
||||
info += t // Oh, he wants to edit to the end of the file, let him.
|
||||
updateinfolinks()
|
||||
usr << browse("<HTML><HEAD><TITLE>[name]</TITLE></HEAD><BODY>[info_links]<HR>[stamps]</BODY><div align='right'style='position:fixed;bottom:0;font-style:bold;'><A href='?src=[REF(src)];help=1'>\[?\]</A></div></HTML>", "window=[name]") // Update the window
|
||||
show_content(usr)
|
||||
update_icon()
|
||||
|
||||
|
||||
@@ -289,7 +306,7 @@
|
||||
|
||||
if(istype(P, /obj/item/pen) || istype(P, /obj/item/toy/crayon))
|
||||
if(user.is_literate())
|
||||
user << browse("<HTML><HEAD><TITLE>[name]</TITLE></HEAD><BODY>[info_links]<HR>[stamps]</BODY><div align='right'style='position:fixed;bottom:0;font-style:bold;'><A href='?src=[REF(src)];help=1'>\[?\]</A></div></HTML>", "window=[name]")
|
||||
show_content(user)
|
||||
return
|
||||
else
|
||||
to_chat(user, "<span class='notice'>You don't know how to read or write.</span>")
|
||||
@@ -312,6 +329,7 @@
|
||||
add_overlay(stampoverlay)
|
||||
|
||||
to_chat(user, "<span class='notice'>You stamp the paper with your rubber stamp.</span>")
|
||||
ui.render_all()
|
||||
|
||||
if(P.is_hot())
|
||||
if(HAS_TRAIT(user, TRAIT_CLUMSY) && prob(10))
|
||||
|
||||
@@ -84,16 +84,18 @@
|
||||
/obj/singularity/attack_tk(mob/user)
|
||||
if(iscarbon(user))
|
||||
var/mob/living/carbon/C = user
|
||||
log_game("[key_name(C)] has been disintegrated by attempting to telekenetically grab a singularity.</span>")
|
||||
C.visible_message("<span class='danger'>[C]'s head begins to collapse in on itself!</span>", "<span class='userdanger'>Your head feels like it's collapsing in on itself! This was really not a good idea!</span>", "<span class='italics'>You hear something crack and explode in gore.</span>")
|
||||
var/turf/T = get_turf(C)
|
||||
for(var/i in 1 to 3)
|
||||
C.apply_damage(30, BRUTE, BODY_ZONE_HEAD)
|
||||
new /obj/effect/gibspawner/generic(T)
|
||||
sleep(1)
|
||||
C.ghostize()
|
||||
var/obj/item/bodypart/head/rip_u = C.get_bodypart(BODY_ZONE_HEAD)
|
||||
rip_u.dismember(BURN) //nice try jedi
|
||||
qdel(rip_u)
|
||||
return
|
||||
return ..()
|
||||
|
||||
/obj/singularity/ex_act(severity, target)
|
||||
switch(severity)
|
||||
|
||||
@@ -5,12 +5,21 @@
|
||||
#define PLASMA_HEAT_PENALTY 15 // Higher == Bigger heat and waste penalty from having the crystal surrounded by this gas. Negative numbers reduce penalty.
|
||||
#define OXYGEN_HEAT_PENALTY 1
|
||||
#define CO2_HEAT_PENALTY 0.1
|
||||
#define NITROGEN_HEAT_MODIFIER -1.5
|
||||
#define PLUOXIUM_HEAT_PENALTY -1
|
||||
#define TRITIUM_HEAT_PENALTY 10
|
||||
#define NITROGEN_HEAT_PENALTY -1.5
|
||||
#define BZ_HEAT_PENALTY 5
|
||||
|
||||
#define OXYGEN_TRANSMIT_MODIFIER 1.5 //Higher == Bigger bonus to power generation.
|
||||
#define PLASMA_TRANSMIT_MODIFIER 4
|
||||
#define BZ_TRANSMIT_MODIFIER -2
|
||||
|
||||
#define TRITIUM_RADIOACTIVITY_MODIFIER 3 //Higher == Crystal spews out more radiation
|
||||
#define BZ_RADIOACTIVITY_MODIFIER 5
|
||||
#define PLUOXIUM_RADIOACTIVITY_MODIFIER -2
|
||||
|
||||
#define N2O_HEAT_RESISTANCE 6 //Higher == Gas makes the crystal more resistant against heat damage.
|
||||
#define PLUOXIUM_HEAT_RESISTANCE 3
|
||||
|
||||
#define POWERLOSS_INHIBITION_GAS_THRESHOLD 0.20 //Higher == Higher percentage of inhibitor gas needed before the charge inertia chain reaction effect starts.
|
||||
#define POWERLOSS_INHIBITION_MOLE_THRESHOLD 20 //Higher == More moles of the gas are needed before the charge inertia chain reaction effect starts. //Scales powerloss inhibition down until this amount of moles is reached
|
||||
@@ -53,6 +62,7 @@
|
||||
#define SUPERMATTER_EMERGENCY_PERCENT 25
|
||||
#define SUPERMATTER_DANGER_PERCENT 50
|
||||
#define SUPERMATTER_WARNING_PERCENT 100
|
||||
#define CRITICAL_TEMPERATURE 10000
|
||||
|
||||
#define SUPERMATTER_COUNTDOWN_TIME 30 SECONDS
|
||||
|
||||
@@ -102,6 +112,11 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
|
||||
var/o2comp = 0
|
||||
var/co2comp = 0
|
||||
var/n2ocomp = 0
|
||||
var/pluoxiumcomp = 0
|
||||
var/tritiumcomp = 0
|
||||
var/bzcomp = 0
|
||||
|
||||
var/pluoxiumbonus = 0
|
||||
|
||||
var/combined_gas = 0
|
||||
var/gasmix_power_ratio = 0
|
||||
@@ -184,8 +199,6 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
|
||||
to_chat(H, "<span class='danger'>You get headaches just from looking at it.</span>")
|
||||
return
|
||||
|
||||
#define CRITICAL_TEMPERATURE 10000
|
||||
|
||||
/obj/machinery/power/supermatter_crystal/proc/get_status()
|
||||
var/turf/T = get_turf(src)
|
||||
if(!T)
|
||||
@@ -354,16 +367,24 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
|
||||
plasmacomp = max(removed.gases[/datum/gas/plasma]/combined_gas, 0)
|
||||
o2comp = max(removed.gases[/datum/gas/oxygen]/combined_gas, 0)
|
||||
co2comp = max(removed.gases[/datum/gas/carbon_dioxide]/combined_gas, 0)
|
||||
pluoxiumcomp = max(removed.gases[/datum/gas/pluoxium]/combined_gas, 0)
|
||||
tritiumcomp = max(removed.gases[/datum/gas/tritium]/combined_gas, 0)
|
||||
bzcomp = max(removed.gases[/datum/gas/bz]/combined_gas, 0)
|
||||
|
||||
n2ocomp = max(removed.gases[/datum/gas/nitrous_oxide]/combined_gas, 0)
|
||||
n2comp = max(removed.gases[/datum/gas/nitrogen]/combined_gas, 0)
|
||||
|
||||
gasmix_power_ratio = min(max(plasmacomp + o2comp + co2comp - n2comp, 0), 1)
|
||||
if(pluoxiumcomp >= 0.15)
|
||||
pluoxiumbonus = 1 //makes pluoxium only work at 15%+
|
||||
else
|
||||
pluoxiumbonus = 0
|
||||
|
||||
dynamic_heat_modifier = max((plasmacomp * PLASMA_HEAT_PENALTY)+(o2comp * OXYGEN_HEAT_PENALTY)+(co2comp * CO2_HEAT_PENALTY)+(n2comp * NITROGEN_HEAT_MODIFIER), 0.5)
|
||||
dynamic_heat_resistance = max(n2ocomp * N2O_HEAT_RESISTANCE, 1)
|
||||
gasmix_power_ratio = min(max(plasmacomp + o2comp + co2comp + tritiumcomp + bzcomp - pluoxiumcomp - n2comp, 0), 1)
|
||||
|
||||
power_transmission_bonus = max((plasmacomp * PLASMA_TRANSMIT_MODIFIER) + (o2comp * OXYGEN_TRANSMIT_MODIFIER), 0)
|
||||
dynamic_heat_modifier = max((plasmacomp * PLASMA_HEAT_PENALTY) + (o2comp * OXYGEN_HEAT_PENALTY) + (co2comp * CO2_HEAT_PENALTY) + (tritiumcomp * TRITIUM_HEAT_PENALTY) + ((pluoxiumcomp * PLUOXIUM_HEAT_PENALTY) * pluoxiumbonus) + (n2comp * NITROGEN_HEAT_PENALTY) + (bzcomp * BZ_HEAT_PENALTY), 0.5)
|
||||
dynamic_heat_resistance = max((n2ocomp * N2O_HEAT_RESISTANCE) + ((pluoxiumcomp * PLUOXIUM_HEAT_RESISTANCE) * pluoxiumbonus), 1)
|
||||
|
||||
power_transmission_bonus = max((plasmacomp * PLASMA_TRANSMIT_MODIFIER) + (o2comp * OXYGEN_TRANSMIT_MODIFIER) + (bzcomp * BZ_TRANSMIT_MODIFIER), 0)
|
||||
|
||||
//more moles of gases are harder to heat than fewer, so let's scale heat damage around them
|
||||
mole_heat_penalty = max(combined_gas / MOLE_HEAT_PENALTY, 0.25)
|
||||
@@ -392,7 +413,9 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
|
||||
power = max( (removed.temperature * temp_factor / T0C) * gasmix_power_ratio + power, 0) //Total laser power plus an overload
|
||||
|
||||
if(prob(50))
|
||||
radiation_pulse(src, power * (1 + power_transmission_bonus/10))
|
||||
radiation_pulse(src, power * (1 + (tritiumcomp * TRITIUM_RADIOACTIVITY_MODIFIER) + ((pluoxiumcomp * PLUOXIUM_RADIOACTIVITY_MODIFIER) * pluoxiumbonus) * (power_transmission_bonus/(10-(bzcomp * BZ_RADIOACTIVITY_MODIFIER))))) // Rad Modifiers BZ(500%), Tritium(300%), and Pluoxium(-200%)
|
||||
if(bzcomp >= 0.4 && prob(30 * bzcomp))
|
||||
src.fire_nuclear_particles() // Start to emit radballs at a maximum of 30% chance per tick
|
||||
|
||||
var/device_energy = power * REACTION_POWER_MODIFIER
|
||||
|
||||
@@ -527,11 +550,14 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
|
||||
/obj/machinery/power/supermatter_crystal/attack_tk(mob/user)
|
||||
if(iscarbon(user))
|
||||
var/mob/living/carbon/C = user
|
||||
log_game("[key_name(C)] has been disintegrated by a telekenetic grab on a supermatter crystal.</span>")
|
||||
to_chat(C, "<span class='userdanger'>That was a really dense idea.</span>")
|
||||
C.ghostize()
|
||||
C.visible_message("<span class='userdanger'>A bright flare of radiation is seen from [C]'s head, shortly before you hear a sickening sizzling!</span>")
|
||||
var/obj/item/organ/brain/rip_u = locate(/obj/item/organ/brain) in C.internal_organs
|
||||
rip_u.Remove(C)
|
||||
qdel(rip_u)
|
||||
return
|
||||
return ..()
|
||||
|
||||
/obj/machinery/power/supermatter_crystal/attack_paw(mob/user)
|
||||
dust_mob(user, cause = "monkey attack")
|
||||
|
||||
@@ -132,11 +132,14 @@
|
||||
/obj/singularity/energy_ball/attack_tk(mob/user)
|
||||
if(iscarbon(user))
|
||||
var/mob/living/carbon/C = user
|
||||
log_game("[key_name(C)] has been disintegrated by a telekenetic grab on a tesla ball.</span>")
|
||||
to_chat(C, "<span class='userdanger'>That was a shockingly dumb idea.</span>")
|
||||
C.visible_message("<span class='userdanger'>A bright flare of lightning is seen from [C]'s head, shortly before you hear a sickening sizzling!</span>")
|
||||
var/obj/item/organ/brain/rip_u = locate(/obj/item/organ/brain) in C.internal_organs
|
||||
C.ghostize(0)
|
||||
rip_u.Remove(C)
|
||||
qdel(rip_u)
|
||||
C.death()
|
||||
return
|
||||
return ..()
|
||||
|
||||
/obj/singularity/energy_ball/orbit(obj/singularity/energy_ball/target)
|
||||
if (istype(target))
|
||||
|
||||
@@ -59,6 +59,9 @@
|
||||
/obj/item/ammo_casing/energy/laser/redtag/hitscan
|
||||
projectile_type = /obj/item/projectile/beam/lasertag/redtag/hitscan
|
||||
|
||||
/obj/item/ammo_casing/energy/laser/redtag/hitscan/holy
|
||||
projectile_type = /obj/item/projectile/beam/lasertag/redtag/hitscan/holy
|
||||
|
||||
/obj/item/ammo_casing/energy/xray
|
||||
projectile_type = /obj/item/projectile/beam/xray
|
||||
e_cost = 50
|
||||
|
||||
@@ -207,6 +207,7 @@
|
||||
name = "combat shotgun"
|
||||
desc = "A semi automatic shotgun with tactical furniture and a six-shell capacity underneath."
|
||||
icon_state = "cshotgun"
|
||||
fire_delay = 3
|
||||
mag_type = /obj/item/ammo_box/magazine/internal/shot/com
|
||||
w_class = WEIGHT_CLASS_HUGE
|
||||
unique_reskin = list("Tatical" = "cshotgun",
|
||||
|
||||
@@ -159,3 +159,65 @@
|
||||
|
||||
/obj/item/gun/energy/laser/redtag/hitscan
|
||||
ammo_type = list(/obj/item/ammo_casing/energy/laser/redtag/hitscan)
|
||||
|
||||
/obj/item/gun/energy/laser/redtag/hitscan/chaplain
|
||||
name = "\improper holy lasrifle"
|
||||
desc = "A lasrifle from the old Imperium. This one seems to be blessed by techpriests."
|
||||
icon_state = "LaserAK"
|
||||
item_state = null
|
||||
force = 14
|
||||
pin = /obj/item/firing_pin/holy
|
||||
icon = 'modular_citadel/icons/obj/guns/VGguns.dmi'
|
||||
ammo_x_offset = 4
|
||||
ammo_type = list(/obj/item/ammo_casing/energy/laser/redtag/hitscan/holy)
|
||||
lefthand_file = 'modular_citadel/icons/mob/citadel/guns_lefthand.dmi'
|
||||
righthand_file = 'modular_citadel/icons/mob/citadel/guns_righthand.dmi'
|
||||
var/chaplain_spawnable = TRUE
|
||||
total_mass = TOTAL_MASS_MEDIEVAL_WEAPON
|
||||
throw_speed = 3
|
||||
throw_range = 4
|
||||
throwforce = 10
|
||||
obj_flags = UNIQUE_RENAME
|
||||
|
||||
/obj/item/gun/energy/laser/redtag/hitscan/chaplain/Initialize()
|
||||
. = ..()
|
||||
AddComponent(/datum/component/anti_magic, TRUE, TRUE)
|
||||
|
||||
/obj/item/gun/energy/laser/redtag/hitscan/chaplain/handle_suicide(mob/living/carbon/human/user, mob/living/carbon/human/target, params, bypass_timer)
|
||||
if(!ishuman(user) || !ishuman(target))
|
||||
return
|
||||
|
||||
if(semicd)
|
||||
return
|
||||
|
||||
if(user == target)
|
||||
target.visible_message("<span class='warning'>[user] sticks [src] in [user.p_their()] mouth, ready to pull the trigger...</span>", \
|
||||
"<span class='userdanger'>You stick [src] in your mouth, ready to pull the trigger...</span>")
|
||||
else
|
||||
target.visible_message("<span class='warning'>[user] points [src] at [target]'s head, ready to pull the trigger...</span>", \
|
||||
"<span class='userdanger'>[user] points [src] at your head, ready to pull the trigger...</span>")
|
||||
|
||||
semicd = TRUE
|
||||
|
||||
if(!bypass_timer && (!do_mob(user, target, 120) || user.zone_selected != BODY_ZONE_PRECISE_MOUTH))
|
||||
if(user)
|
||||
if(user == target)
|
||||
user.visible_message("<span class='notice'>[user] decided not to shoot.</span>")
|
||||
else if(target && target.Adjacent(user))
|
||||
target.visible_message("<span class='notice'>[user] has decided to spare [target]</span>", "<span class='notice'>[user] has decided to spare your life!</span>")
|
||||
semicd = FALSE
|
||||
return
|
||||
|
||||
semicd = FALSE
|
||||
|
||||
target.visible_message("<span class='warning'>[user] pulls the trigger!</span>", "<span class='userdanger'>[user] pulls the trigger!</span>")
|
||||
|
||||
playsound('sound/weapons/dink.ogg', 30, 1)
|
||||
|
||||
if((iscultist(target)) || (is_servant_of_ratvar(target)))
|
||||
chambered.BB.damage *= 1500
|
||||
|
||||
else if(chambered && chambered.BB)
|
||||
chambered.BB.damage *= 5
|
||||
|
||||
process_fire(target, user, TRUE, params)
|
||||
|
||||
@@ -188,6 +188,15 @@
|
||||
desc = "This is a DNA-locked firing pin which only authorizes one user. Attempt to fire once to DNA-link. It has a small explosive charge on it."
|
||||
selfdestruct = TRUE
|
||||
|
||||
/obj/item/firing_pin/holy
|
||||
name = "blessed pin"
|
||||
desc = "A firing pin that only responds to those who are holier than thou."
|
||||
|
||||
/obj/item/firing_pin/holy/pin_auth(mob/living/user)
|
||||
if(user.mind.isholy)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
// Laser tag pins
|
||||
/obj/item/firing_pin/tag
|
||||
name = "laser tag firing pin"
|
||||
|
||||
@@ -151,6 +151,11 @@
|
||||
/obj/item/projectile/beam/lasertag/redtag/hitscan
|
||||
hitscan = TRUE
|
||||
|
||||
/obj/item/projectile/beam/lasertag/redtag/hitscan/holy
|
||||
name = "lasrifle beam"
|
||||
damage = 0.1
|
||||
damage_type = BURN
|
||||
|
||||
/obj/item/projectile/beam/lasertag/bluetag
|
||||
icon_state = "bluelaser"
|
||||
suit_types = list(/obj/item/clothing/suit/redtag)
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
/obj/item/projectile/bullet/shotgun_beanbag
|
||||
name = "beanbag slug"
|
||||
damage = 5
|
||||
stamina = 80
|
||||
stamina = 70
|
||||
|
||||
/obj/item/projectile/bullet/incendiary/shotgun
|
||||
name = "incendiary slug"
|
||||
@@ -61,12 +61,12 @@
|
||||
|
||||
/obj/item/projectile/bullet/pellet/shotgun_buckshot
|
||||
name = "buckshot pellet"
|
||||
damage = 12.5
|
||||
damage = 10
|
||||
|
||||
/obj/item/projectile/bullet/pellet/shotgun_rubbershot
|
||||
name = "rubbershot pellet"
|
||||
damage = 3
|
||||
stamina = 25
|
||||
damage = 2
|
||||
stamina = 15
|
||||
|
||||
/obj/item/projectile/bullet/pellet/Range()
|
||||
..()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#define CHEMICAL_QUANTISATION_LEVEL 0.0001
|
||||
#define CHEMICAL_QUANTISATION_LEVEL 0.001
|
||||
|
||||
/proc/build_chemical_reagent_list()
|
||||
//Chemical Reagents - Initialises all /datum/reagent into a list indexed by reagent id
|
||||
@@ -745,7 +745,6 @@
|
||||
del_reagent(R.id)
|
||||
else
|
||||
total_volume += R.volume
|
||||
|
||||
return 0
|
||||
|
||||
/datum/reagents/proc/clear_reagents()
|
||||
@@ -874,7 +873,7 @@
|
||||
var/datum/reagent/R = A
|
||||
if (R.id == reagent) //IF MERGING
|
||||
//Add amount and equalize purity
|
||||
R.volume += amount
|
||||
R.volume += round(amount, CHEMICAL_QUANTISATION_LEVEL)
|
||||
R.purity = ((R.purity * R.volume) + (other_purity * amount)) /((R.volume + amount)) //This should add the purity to the product
|
||||
|
||||
update_total()
|
||||
@@ -896,7 +895,7 @@
|
||||
var/datum/reagent/R = new D.type(data)
|
||||
cached_reagents += R
|
||||
R.holder = src
|
||||
R.volume = amount
|
||||
R.volume = round(amount, CHEMICAL_QUANTISATION_LEVEL)
|
||||
R.purity = other_purity
|
||||
R.loc = get_turf(my_atom)
|
||||
if(data)
|
||||
|
||||
@@ -233,6 +233,12 @@
|
||||
else
|
||||
reagents.remove_reagent(id, amount)
|
||||
. = TRUE
|
||||
else if (amount == -1) // -1 means custom amount
|
||||
useramount = input("Enter the Amount you want to transfer:", name, useramount) as num|null
|
||||
if (useramount > 0)
|
||||
end_fermi_reaction()
|
||||
reagents.trans_id_to(beaker, id, useramount)
|
||||
. = TRUE
|
||||
|
||||
if("toggleMode")
|
||||
mode = !mode
|
||||
@@ -332,7 +338,7 @@
|
||||
var/vol_part = min(reagents.total_volume, 30)
|
||||
if(text2num(many))
|
||||
amount_full = round(reagents.total_volume / 30)
|
||||
vol_part = reagents.total_volume % 30
|
||||
vol_part = ((reagents.total_volume*1000) % 30000) / 1000 //% operator doesn't support decimals.
|
||||
var/name = stripped_input(usr, "Name:","Name your bottle!", (reagents.total_volume ? reagents.get_master_reagent_name() : " "), MAX_NAME_LEN)
|
||||
if(!name || !reagents.total_volume || !src || QDELETED(src) || !usr.canUseTopic(src, !issilicon(usr)))
|
||||
return
|
||||
@@ -379,7 +385,7 @@
|
||||
reagents.trans_to(P, vol_part)
|
||||
. = TRUE
|
||||
//END CITADEL ADDITIONS
|
||||
if("analyze")
|
||||
if("analyzeBeak")
|
||||
var/datum/reagent/R = GLOB.chemical_reagents_list[params["id"]]
|
||||
if(R)
|
||||
var/state = "Unknown"
|
||||
@@ -395,7 +401,38 @@
|
||||
fermianalyze = TRUE
|
||||
var/datum/chemical_reaction/Rcr = get_chemical_reaction(R.id)
|
||||
var/pHpeakCache = (Rcr.OptimalpHMin + Rcr.OptimalpHMax)/2
|
||||
analyzeVars = list("name" = initial(R.name), "state" = state, "color" = initial(R.color), "description" = initial(R.description), "metaRate" = T, "overD" = initial(R.overdose_threshold), "addicD" = initial(R.addiction_threshold), "purityF" = initial(R.purity), "inverseRatioF" = initial(R.InverseChemVal), "purityE" = initial(Rcr.PurityMin), "minTemp" = initial(Rcr.OptimalTempMin), "maxTemp" = initial(Rcr.OptimalTempMax), "eTemp" = initial(Rcr.ExplodeTemp), "pHpeak" = pHpeakCache)
|
||||
var/datum/reagent/targetReagent = beaker.reagents.has_reagent("[R.id]")
|
||||
|
||||
if(!targetReagent)
|
||||
CRASH("Tried to find a reagent that doesn't exist in the chem_master!")
|
||||
analyzeVars = list("name" = initial(R.name), "state" = state, "color" = initial(R.color), "description" = initial(R.description), "metaRate" = T, "overD" = initial(R.overdose_threshold), "addicD" = initial(R.addiction_threshold), "purityF" = targetReagent.purity, "inverseRatioF" = initial(R.InverseChemVal), "purityE" = initial(Rcr.PurityMin), "minTemp" = initial(Rcr.OptimalTempMin), "maxTemp" = initial(Rcr.OptimalTempMax), "eTemp" = initial(Rcr.ExplodeTemp), "pHpeak" = pHpeakCache)
|
||||
else
|
||||
fermianalyze = FALSE
|
||||
analyzeVars = list("name" = initial(R.name), "state" = state, "color" = initial(R.color), "description" = initial(R.description), "metaRate" = T, "overD" = initial(R.overdose_threshold), "addicD" = initial(R.addiction_threshold))
|
||||
screen = "analyze"
|
||||
return
|
||||
|
||||
if("analyzeBuff")
|
||||
var/datum/reagent/R = GLOB.chemical_reagents_list[params["id"]]
|
||||
if(R)
|
||||
var/state = "Unknown"
|
||||
if(initial(R.reagent_state) == 1)
|
||||
state = "Solid"
|
||||
else if(initial(R.reagent_state) == 2)
|
||||
state = "Liquid"
|
||||
else if(initial(R.reagent_state) == 3)
|
||||
state = "Gas"
|
||||
var/const/P = 3 //The number of seconds between life ticks
|
||||
var/T = initial(R.metabolization_rate) * (60 / P)
|
||||
if(istype(R, /datum/reagent/fermi))
|
||||
fermianalyze = TRUE
|
||||
var/datum/chemical_reaction/Rcr = get_chemical_reaction(R.id)
|
||||
var/pHpeakCache = (Rcr.OptimalpHMin + Rcr.OptimalpHMax)/2
|
||||
var/datum/reagent/targetReagent = reagents.has_reagent("[R.id]")
|
||||
|
||||
if(!targetReagent)
|
||||
CRASH("Tried to find a reagent that doesn't exist in the chem_master!")
|
||||
analyzeVars = list("name" = initial(R.name), "state" = state, "color" = initial(R.color), "description" = initial(R.description), "metaRate" = T, "overD" = initial(R.overdose_threshold), "addicD" = initial(R.addiction_threshold), "purityF" = targetReagent.purity, "inverseRatioF" = initial(R.InverseChemVal), "purityE" = initial(Rcr.PurityMin), "minTemp" = initial(Rcr.OptimalTempMin), "maxTemp" = initial(Rcr.OptimalTempMax), "eTemp" = initial(Rcr.ExplodeTemp), "pHpeak" = pHpeakCache)
|
||||
else
|
||||
fermianalyze = FALSE
|
||||
analyzeVars = list("name" = initial(R.name), "state" = state, "color" = initial(R.color), "description" = initial(R.description), "metaRate" = T, "overD" = initial(R.overdose_threshold), "addicD" = initial(R.addiction_threshold))
|
||||
|
||||
@@ -2122,6 +2122,29 @@ All effects don't start immediately, but rather get worse over time; the rate is
|
||||
glass_name = "Planet Cracker"
|
||||
glass_desc = "Although historians believe the drink was originally created to commemorate the end of an important conflict in man's past, its origins have largely been forgotten and it is today seen more as a general symbol of human supremacy."
|
||||
|
||||
/datum/reagent/consumable/ethanol/commander_and_chief
|
||||
name = "Commander and Chief"
|
||||
id = "commander_and_chief"
|
||||
description = "A cocktail for the captain on the go."
|
||||
color = "#ffffc9"
|
||||
boozepwr = 50
|
||||
quality = DRINK_FANTASTIC
|
||||
taste_description = "Tastes like...duty and responsibility?"
|
||||
glass_icon_state = "commander_and_chief"
|
||||
glass_name = "Commander and Chief"
|
||||
glass_desc = "The gems of this majestic chalice represent the departments and their Heads."
|
||||
|
||||
/datum/reagent/consumable/ethanol/commander_and_chief/on_mob_life(mob/living/carbon/M)
|
||||
if(M.mind && HAS_TRAIT(M.mind, TRAIT_CAPTAIN_METABOLISM))
|
||||
M.heal_bodypart_damage(2,2,2)
|
||||
M.adjustBruteLoss(-3.5,0)
|
||||
M.adjustOxyLoss(-3.5,0)
|
||||
M.adjustFireLoss(-3.5,0)
|
||||
M.adjustToxLoss(-3.5,0)
|
||||
M.radiation = max(M.radiation - 25, 0)
|
||||
. = 1
|
||||
return ..()
|
||||
|
||||
/datum/reagent/consumable/ethanol/fruit_wine
|
||||
name = "Fruit Wine"
|
||||
id = "fruit_wine"
|
||||
|
||||
@@ -1177,7 +1177,7 @@
|
||||
M.adjustToxLoss(-3 * REM, 0, TRUE) //Heals TOXINLOVERS
|
||||
M.adjustBrainLoss(2 * REM, 150) //This does, after all, come from ambrosia, and the most powerful ambrosia in existence, at that!
|
||||
M.adjustCloneLoss(-1 * REM, 0)
|
||||
M.adjustStaminaLoss(-30 * REM, 0)
|
||||
M.adjustStaminaLoss(-13 * REM, 0)
|
||||
M.jitteriness = min(max(0, M.jitteriness + 3), 30)
|
||||
M.druggy = min(max(0, M.druggy + 10), 15) //See above
|
||||
..()
|
||||
|
||||
@@ -264,6 +264,13 @@
|
||||
name = "disposal unit"
|
||||
desc = "A pneumatic waste disposal unit."
|
||||
icon_state = "disposal"
|
||||
var/datum/oracle_ui/themed/nano/ui
|
||||
|
||||
/obj/machinery/disposal/bin/Initialize(mapload, obj/structure/disposalconstruct/make_from)
|
||||
. = ..()
|
||||
ui = new /datum/oracle_ui/themed/nano(src, 330, 190, "disposal_bin")
|
||||
ui.auto_refresh = TRUE
|
||||
ui.can_resize = FALSE
|
||||
|
||||
// attack by item places it in to disposal
|
||||
/obj/machinery/disposal/bin/attackby(obj/item/I, mob/user, params)
|
||||
@@ -275,32 +282,43 @@
|
||||
STR.remove_from_storage(O,src)
|
||||
T.update_icon()
|
||||
update_icon()
|
||||
ui.soft_update_fields()
|
||||
else
|
||||
ui.soft_update_fields()
|
||||
return ..()
|
||||
|
||||
// handle machine interaction
|
||||
|
||||
/obj/machinery/disposal/bin/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
|
||||
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.notcontained_state)
|
||||
/obj/machinery/disposal/bin/ui_interact(mob/user, state)
|
||||
if(stat & BROKEN)
|
||||
return
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "disposal_unit", name, 300, 200, master_ui, state)
|
||||
ui.open()
|
||||
if(user.loc == src)
|
||||
to_chat(user, "<span class='warning'>You cannot reach the controls from inside!</span>")
|
||||
return
|
||||
ui.render(user)
|
||||
|
||||
/obj/machinery/disposal/bin/ui_data(mob/user)
|
||||
/obj/machinery/disposal/bin/oui_canview(mob/user)
|
||||
if(user.loc == src)
|
||||
return FALSE
|
||||
if(stat & BROKEN)
|
||||
return FALSE
|
||||
if(Adjacent(user))
|
||||
return TRUE
|
||||
return ..()
|
||||
|
||||
|
||||
/obj/machinery/disposal/bin/oui_data(mob/user)
|
||||
var/list/data = list()
|
||||
data["flush"] = flush
|
||||
data["full_pressure"] = full_pressure
|
||||
data["pressure_charging"] = pressure_charging
|
||||
data["panel_open"] = panel_open
|
||||
var/per = CLAMP(100* air_contents.return_pressure() / (SEND_PRESSURE), 0, 100)
|
||||
data["per"] = round(per, 1)
|
||||
data["flush"] = flush ? ui.act("Disengage", user, "handle-0", class="active") : ui.act("Engage", user, "handle-1")
|
||||
data["full_pressure"] = full_pressure ? "Ready" : (pressure_charging ? "Pressurizing" : "Off")
|
||||
data["pressure_charging"] = pressure_charging ? ui.act("Turn Off", user, "pump-0", class="active", disabled=full_pressure) : ui.act("Turn On", user, "pump-1", disabled=full_pressure)
|
||||
var/per = full_pressure ? 100 : CLAMP(100* air_contents.return_pressure() / (SEND_PRESSURE), 0, 99)
|
||||
data["per"] = "[round(per, 1)]%"
|
||||
data["contents"] = ui.act("Eject Contents", user, "eject", disabled=contents.len < 1)
|
||||
data["isai"] = isAI(user)
|
||||
return data
|
||||
|
||||
/obj/machinery/disposal/bin/ui_act(action, params)
|
||||
/obj/machinery/disposal/bin/oui_act(mob/user, action, list/params)
|
||||
if(..())
|
||||
return
|
||||
|
||||
@@ -327,6 +345,7 @@
|
||||
if("eject")
|
||||
eject()
|
||||
. = TRUE
|
||||
ui.soft_update_fields()
|
||||
|
||||
|
||||
/obj/machinery/disposal/bin/hitby(atom/movable/AM)
|
||||
@@ -346,6 +365,7 @@
|
||||
full_pressure = FALSE
|
||||
pressure_charging = TRUE
|
||||
update_icon()
|
||||
ui.soft_update_fields()
|
||||
|
||||
/obj/machinery/disposal/bin/update_icon()
|
||||
cut_overlays()
|
||||
@@ -389,7 +409,7 @@
|
||||
do_flush()
|
||||
flush_count = 0
|
||||
|
||||
updateDialog()
|
||||
ui.soft_update_fields()
|
||||
|
||||
if(flush && air_contents.return_pressure() >= SEND_PRESSURE) // flush can happen even without power
|
||||
do_flush()
|
||||
|
||||
@@ -742,6 +742,13 @@
|
||||
surgery = /datum/surgery/advanced/reconstruction
|
||||
research_icon_state = "surgery_chest"
|
||||
|
||||
/datum/design/surgery/surgery_toxinhealing
|
||||
name = "Body Rejuvenation"
|
||||
desc = "A surgical procedure that helps deal with oxygen deprecation, and treat toxic damaged. Works on corpses and alive alike without chemicals."
|
||||
id = "surgery_toxinhealing"
|
||||
surgery = /datum/surgery/advanced/toxichealing
|
||||
research_icon_state = "surgery_chest"
|
||||
|
||||
/datum/design/surgery/revival
|
||||
name = "Revival"
|
||||
desc = "An experimental surgical procedure which involves reconstruction and reactivation of the patient's brain even long after death. The body must still be able to sustain life."
|
||||
|
||||
@@ -379,6 +379,16 @@
|
||||
////////////Tools//////////////
|
||||
///////////////////////////////
|
||||
|
||||
/datum/design/rcd_upgrade
|
||||
name = "Advanced RCD designs upgrade"
|
||||
desc = "Adds the computer frame and machine frame to the RCD."
|
||||
id = "rcd_upgrade"
|
||||
build_type = PROTOLATHE
|
||||
materials = list(MAT_METAL = 5000, MAT_GLASS = 2500, MAT_SILVER = 1500, MAT_TITANIUM = 2000)
|
||||
build_path = /obj/item/rcd_upgrade
|
||||
category = list("Equipment")
|
||||
departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING
|
||||
|
||||
/datum/design/exwelder
|
||||
name = "Experimental Welding Tool"
|
||||
desc = "An experimental welder capable of self-fuel generation."
|
||||
|
||||
@@ -115,7 +115,7 @@
|
||||
display_name = "Advanced Surgery"
|
||||
description = "When simple medicine doesn't cut it."
|
||||
prereq_ids = list("adv_biotech")
|
||||
design_ids = list("surgery_lobotomy", "surgery_reconstruction", "organbox")
|
||||
design_ids = list("surgery_lobotomy", "surgery_reconstruction", "surgery_toxinhealing", "organbox")
|
||||
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
|
||||
export_price = 5000
|
||||
|
||||
@@ -172,7 +172,7 @@
|
||||
display_name = "Advanced Engineering"
|
||||
description = "Pushing the boundaries of physics, one chainsaw-fist at a time."
|
||||
prereq_ids = list("engineering", "emp_basic")
|
||||
design_ids = list("engine_goggles", "magboots", "forcefield_projector", "weldingmask", "tray_goggles_prescription", "engine_goggles_prescription", "mesons_prescription")
|
||||
design_ids = list("engine_goggles", "magboots", "forcefield_projector", "weldingmask", "tray_goggles_prescription", "engine_goggles_prescription", "mesons_prescription", "rcd_upgrade")
|
||||
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 4000)
|
||||
export_price = 5000
|
||||
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
/datum/surgery/advanced/toxichealing
|
||||
name = "Body Rejuvenation"
|
||||
desc = "A surgical procedure that helps deal with oxygen deprecation, and treat toxic damaged. Works on corpses and alive alike without chemicals."
|
||||
steps = list(/datum/surgery_step/incise,
|
||||
/datum/surgery_step/incise,
|
||||
/datum/surgery_step/retract_skin,
|
||||
/datum/surgery_step/incise,
|
||||
/datum/surgery_step/clamp_bleeders,
|
||||
/datum/surgery_step/incise,
|
||||
/datum/surgery_step/retract_skin,
|
||||
/datum/surgery_step/toxichealing,
|
||||
/datum/surgery_step/close)
|
||||
|
||||
species = list(/mob/living/carbon/human, /mob/living/carbon/monkey)
|
||||
possible_locs = list(BODY_ZONE_CHEST)
|
||||
requires_bodypart_type = 0
|
||||
|
||||
/datum/surgery_step/toxichealing
|
||||
name = "rejuvenate body"
|
||||
implements = list(/obj/item/hemostat = 100, TOOL_SCREWDRIVER = 35, /obj/item/pen = 15)
|
||||
repeatable = TRUE
|
||||
time = 25
|
||||
|
||||
/datum/surgery_step/toxichealing/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
|
||||
user.visible_message("[user] starts rejuvenating some of [target]'s flesh back to life.", "<span class='notice'>You start knitting some of [target]'s flesh back to life.</span>")
|
||||
|
||||
/datum/surgery_step/toxichealing/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
|
||||
user.visible_message("[user] fixes some of [target]'s wounds.", "<span class='notice'>You succeed in fixing some of [target]'s wounds.</span>")
|
||||
target.heal_bodypart_damage(0,0,30) //Heals stam
|
||||
target.adjustToxLoss(-15, 0, TRUE)
|
||||
target.adjustOxyLoss(-20, 0)
|
||||
return TRUE
|
||||
|
||||
/datum/surgery_step/toxichealing/failure(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
|
||||
user.visible_message("[user] screws up!", "<span class='warning'>You screwed up!</span>")
|
||||
target.take_bodypart_damage(25,0)
|
||||
return FALSE
|
||||
@@ -0,0 +1,31 @@
|
||||
/datum/surgery/embalming //Fast and easy way to husk bodys
|
||||
name = "Embalming"
|
||||
desc = "A surgical procedure that prevents a corps from producing."
|
||||
steps = list(/datum/surgery_step/incise,
|
||||
/datum/surgery_step/embalming,
|
||||
/datum/surgery_step/close)
|
||||
|
||||
species = list(/mob/living/carbon/human, /mob/living/carbon/monkey)
|
||||
possible_locs = list(BODY_ZONE_CHEST)
|
||||
requires_bodypart_type = 0
|
||||
|
||||
/datum/surgery_step/embalming
|
||||
name = "embalming body"
|
||||
implements = list(/obj/item/hemostat = 100, TOOL_SCREWDRIVER = 35, /obj/item/pen = 15)
|
||||
implements = list(/obj/item/reagent_containers/syringe = 100, /obj/item/pen = 30)
|
||||
time = 10
|
||||
chems_needed = list("drying_agent", "sterilizine")
|
||||
require_all_chems = FALSE
|
||||
|
||||
/datum/surgery_step/embalming/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
|
||||
user.visible_message("[user] starts to embalm [target]'s body.", "<span class='notice'>You start embalming [target]'s body.</span>")
|
||||
|
||||
/datum/surgery_step/embalming/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
|
||||
user.visible_message("[user] embalms [target]'s body.", "<span class='notice'>You succeed in embalming [target]'s body.</span>")
|
||||
ADD_TRAIT(target, TRAIT_HUSK, MAGIC_TRAIT) //Husk's prevent body smell
|
||||
return FALSE
|
||||
|
||||
/datum/surgery_step/embalming/failure(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
|
||||
user.visible_message("[user] screws up!", "<span class='warning'>You screwed up!</span>")
|
||||
ADD_TRAIT(target, TRAIT_NOCLONE, MAGIC_TRAIT) //That body is ruined, but still gives miasma
|
||||
return FALSE
|
||||
@@ -1838,7 +1838,7 @@ datum/uplink_item/stealthy_weapons/taeclowndo_shoes
|
||||
desc = "A single-use autoinjector which contains an experimental serum that causes rapid muscular growth in Hominidae. \
|
||||
Side-affects may include hypertrichosis, violent outbursts, and an unending affinity for bananas."
|
||||
item = /obj/item/reagent_containers/hypospray/magillitis
|
||||
cost = 15
|
||||
cost = 8
|
||||
restricted_roles = list("Geneticist", "Chief Medical Officer")
|
||||
|
||||
/datum/uplink_item/role_restricted/modified_syringe_gun
|
||||
|
||||
@@ -54,7 +54,7 @@
|
||||
/obj/item/clothing/head/ushanka = 1,
|
||||
/obj/item/clothing/suit/imperium_monk = 1,
|
||||
/obj/item/clothing/mask/gas/cyborg = 1,
|
||||
/obj/item/clothing/suit/holidaypriest = 1,
|
||||
/obj/item/clothing/suit/chaplain/holidaypriest = 1,
|
||||
/obj/item/clothing/head/wizard/marisa/fake = 1,
|
||||
/obj/item/clothing/suit/wizrobe/marisa/fake = 1,
|
||||
/obj/item/clothing/under/sundress = 1,
|
||||
@@ -122,7 +122,7 @@
|
||||
/obj/item/clothing/shoes/roman = 1,
|
||||
/obj/item/shield/riot/roman/fake = 1,
|
||||
/obj/item/skub = 1,
|
||||
/obj/item/clothing/under/lobster = 1, // CIT CHANGES
|
||||
/obj/item/clothing/under/lobster = 1, // CIT CHANGES
|
||||
/obj/item/clothing/head/lobsterhat = 1,
|
||||
/obj/item/clothing/head/drfreezehat = 1,
|
||||
/obj/item/clothing/suit/dracula = 1,
|
||||
|
||||
@@ -99,7 +99,9 @@
|
||||
/obj/item/clothing/suit/jacket/letterman_red = 3,
|
||||
/obj/item/clothing/ears/headphones = 10,
|
||||
/obj/item/clothing/suit/apron/purple_bartender = 4,
|
||||
/obj/item/clothing/under/rank/bartender/purple = 4)
|
||||
/obj/item/clothing/under/rank/bartender/purple = 4,
|
||||
/obj/item/clothing/accessory/attrocious_pokadots = 8,
|
||||
/obj/item/clothing/accessory/black_white_pokadots = 8)
|
||||
contraband = list(/obj/item/clothing/under/syndicate/tacticool = 3,
|
||||
/obj/item/clothing/under/syndicate/tacticool/skirt = 3,
|
||||
/obj/item/clothing/mask/balaclava = 3,
|
||||
@@ -109,7 +111,8 @@
|
||||
/obj/item/clothing/suit/jacket/letterman_syndie = 5,
|
||||
/obj/item/clothing/under/jabroni = 2,
|
||||
/obj/item/clothing/suit/vapeshirt = 2,
|
||||
/obj/item/clothing/under/geisha = 4)
|
||||
/obj/item/clothing/under/geisha = 4,
|
||||
/obj/item/clothing/accessory/syndi_pokadots = 4)
|
||||
premium = list(/obj/item/clothing/under/suit_jacket/checkered = 4,
|
||||
/obj/item/clothing/head/mailman = 2,
|
||||
/obj/item/clothing/under/rank/mailman = 2,
|
||||
@@ -117,7 +120,8 @@
|
||||
/obj/item/clothing/suit/jacket/leather/overcoat = 4,
|
||||
/obj/item/clothing/under/pants/mustangjeans = 3,
|
||||
/obj/item/clothing/neck/necklace/dope = 5,
|
||||
/obj/item/clothing/suit/jacket/letterman_nanotrasen = 5)
|
||||
/obj/item/clothing/suit/jacket/letterman_nanotrasen = 5,
|
||||
/obj/item/clothing/accessory/nt_pokadots = 5)
|
||||
refill_canister = /obj/item/vending_refill/clothing
|
||||
|
||||
/obj/item/vending_refill/clothing
|
||||
|
||||
@@ -317,10 +317,10 @@
|
||||
/obj/item/clothing/under/rank/chaplain = 2,
|
||||
/obj/item/clothing/under/rank/chaplain/skirt = 2,
|
||||
/obj/item/clothing/shoes/sneakers/black = 2,
|
||||
/obj/item/clothing/suit/nun = 2,
|
||||
/obj/item/clothing/suit/chaplain/nun = 2,
|
||||
/obj/item/clothing/head/nun_hood = 2,
|
||||
/obj/item/clothing/suit/holidaypriest = 2,
|
||||
/obj/item/clothing/suit/pharaoh = 2,
|
||||
/obj/item/clothing/suit/chaplain/holidaypriest = 2,
|
||||
/obj/item/clothing/suit/chaplain/pharaoh = 2,
|
||||
/obj/item/clothing/head/nemes = 1,
|
||||
/obj/item/clothing/head/pharaoh = 1,
|
||||
/obj/item/storage/fancy/candle_box = 3)
|
||||
|
||||
Reference in New Issue
Block a user