Merge remote-tracking branch 'citadel/master' into shield_refactor
This commit is contained in:
@@ -639,15 +639,13 @@
|
||||
var/almcam = CONFIG_GET(flag/allow_ai_multicam)
|
||||
CONFIG_SET(flag/allow_ai_multicam, !almcam)
|
||||
if (almcam)
|
||||
to_chat(world, "<B>The AI no longer has multicam.</B>")
|
||||
for(var/i in GLOB.ai_list)
|
||||
var/mob/living/silicon/ai/aiPlayer = i
|
||||
if(aiPlayer.multicam_on)
|
||||
aiPlayer.end_multicam()
|
||||
else
|
||||
to_chat(world, "<B>The AI now has multicam.</B>")
|
||||
log_admin("[key_name(usr)] toggled AI multicam.")
|
||||
world.update_status()
|
||||
to_chat(GLOB.ai_list | GLOB.admins, "<B>The AI [almcam ? "no longer" : "now"] has multicam.</B>")
|
||||
SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle Multicam", "[!almcam ? "Disabled" : "Enabled"]")) //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/datum/admins/proc/toggleaban()
|
||||
|
||||
@@ -1732,7 +1732,7 @@
|
||||
var/mob/M = locate(href_list["makeeligible"])
|
||||
if(!ismob(M))
|
||||
to_chat(usr, "this can only be used on instances of type /mob.")
|
||||
var/datum/element/ghost_role_eligibility/eli = SSdcs.GetElement(/datum/element/ghost_role_eligibility)
|
||||
var/datum/element/ghost_role_eligibility/eli = SSdcs.GetElement(list(/datum/element/ghost_role_eligibility))
|
||||
if(M.ckey in eli.timeouts)
|
||||
eli.timeouts -= M.ckey
|
||||
|
||||
|
||||
@@ -1315,15 +1315,15 @@ GLOBAL_LIST_EMPTY(custom_outfits) //Admin created outfits
|
||||
var/obj/item/reagent_containers/food/snacks/pie/cream/nostun/creamy = new(get_turf(target))
|
||||
creamy.splat(target)
|
||||
if (ADMIN_PUNISHMENT_CUSTOM_PIE)
|
||||
var/obj/item/reagent_containers/food/snacks/pie/cream/nostun/A = new(get_turf(target))
|
||||
var/obj/item/reagent_containers/food/snacks/pie/cream/nostun/A = new()
|
||||
if(!A.reagents)
|
||||
var/amount = input(usr, "Specify the reagent size of [A]", "Set Reagent Size", 50) as num
|
||||
var/amount = input(usr, "Specify the reagent size of [A]", "Set Reagent Size", 50) as num|null
|
||||
if(amount)
|
||||
A.create_reagents(amount)
|
||||
if(A.reagents)
|
||||
var/chosen_id = choose_reagent_id(usr)
|
||||
if(chosen_id)
|
||||
var/amount = input(usr, "Choose the amount to add.", "Choose the amount.", A.reagents.maximum_volume) as num
|
||||
var/amount = input(usr, "Choose the amount to add.", "Choose the amount.", A.reagents.maximum_volume) as num|null
|
||||
if(amount)
|
||||
A.reagents.add_reagent(chosen_id, amount)
|
||||
A.splat(target)
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
|
||||
// EXPLANATION
|
||||
/datum/objective/bloodsucker/lair/update_explanation_text()
|
||||
explanation_text = "Create a lair by claiming a coffin, and protect it until the end of the shift"// Make sure to keep it safe!"
|
||||
explanation_text = "Create a lair by claiming a coffin, and protect it until the end of the shift."// Make sure to keep it safe!"
|
||||
|
||||
// WIN CONDITIONS?
|
||||
/datum/objective/bloodsucker/lair/check_completion()
|
||||
@@ -228,7 +228,7 @@
|
||||
if (SC && SC.lastgen > 0 && SC.connected_panels.len > 0 && SC.connected_tracker)
|
||||
return FALSE
|
||||
return TRUE
|
||||
*/
|
||||
*/
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -250,15 +250,15 @@
|
||||
// WIN CONDITIONS?
|
||||
/datum/objective/bloodsucker/heartthief/check_completion()
|
||||
// -Must have a body.
|
||||
if (!owner.current)
|
||||
if(!owner.current)
|
||||
return FALSE
|
||||
// Taken from /steal in objective.dm
|
||||
var/list/all_items = owner.current.GetAllContents() // Includes items inside other items.
|
||||
var/itemcount = FALSE
|
||||
for(var/obj/I in all_items) //Check for items
|
||||
if(I == /obj/item/organ/heart)
|
||||
itemcount ++
|
||||
if (itemcount >= target_amount) // Got the right amount?
|
||||
if(istype(I, /obj/item/organ/heart/))
|
||||
itemcount++
|
||||
if(itemcount >= target_amount) // Got the right amount?
|
||||
return TRUE
|
||||
|
||||
return FALSE
|
||||
|
||||
@@ -120,7 +120,7 @@
|
||||
|
||||
/datum/antagonist/traitor/internal_affairs/reinstate_escape_objective()
|
||||
..()
|
||||
var/objtype = traitor_kind == TRAITOR_HUMAN ? /datum/objective/escape : /datum/objective/survive
|
||||
var/objtype = !istype(traitor_kind,TRAITOR_AI) ? /datum/objective/escape : /datum/objective/survive
|
||||
var/datum/objective/escape_objective = new objtype
|
||||
escape_objective.owner = owner
|
||||
add_objective(escape_objective)
|
||||
@@ -215,20 +215,12 @@
|
||||
kill_objective.target = target_mind
|
||||
kill_objective.update_explanation_text()
|
||||
add_objective(kill_objective)
|
||||
|
||||
//Optional traitor objective
|
||||
if(prob(PROB_ACTUAL_TRAITOR))
|
||||
employer = "The Syndicate"
|
||||
owner.special_role = TRAITOR_AGENT_ROLE
|
||||
special_role = TRAITOR_AGENT_ROLE
|
||||
syndicate = TRUE
|
||||
forge_single_objective()
|
||||
return
|
||||
|
||||
/datum/antagonist/traitor/internal_affairs/forge_traitor_objectives()
|
||||
forge_iaa_objectives()
|
||||
|
||||
var/objtype = traitor_kind == TRAITOR_HUMAN ? /datum/objective/escape : /datum/objective/survive
|
||||
var/objtype = !istype(traitor_kind,TRAITOR_AI) ? /datum/objective/escape : /datum/objective/survive
|
||||
var/datum/objective/escape_objective = new objtype
|
||||
escape_objective.owner = owner
|
||||
add_objective(escape_objective)
|
||||
|
||||
68
code/modules/antagonists/traitor/classes/ai.dm
Normal file
68
code/modules/antagonists/traitor/classes/ai.dm
Normal file
@@ -0,0 +1,68 @@
|
||||
/datum/traitor_class/ai // this one is special, so has no weight
|
||||
name = "Malfunctioning AI"
|
||||
|
||||
/datum/traitor_class/ai/forge_objectives(datum/antagonist/traitor/T)
|
||||
var/objective_count = 0
|
||||
|
||||
if(prob(30))
|
||||
objective_count += forge_single_objective()
|
||||
|
||||
for(var/i = objective_count, i < CONFIG_GET(number/traitor_objectives_amount), i++)
|
||||
var/datum/objective/assassinate/kill_objective = new
|
||||
kill_objective.owner = T.owner
|
||||
kill_objective.find_target()
|
||||
T.add_objective(kill_objective)
|
||||
|
||||
var/datum/objective/survive/exist/exist_objective = new
|
||||
exist_objective.owner = T.owner
|
||||
T.add_objective(exist_objective)
|
||||
|
||||
/datum/traitor_class/ai/forge_single_objective(datum/antagonist/traitor/T)
|
||||
.=1
|
||||
var/special_pick = rand(1,4)
|
||||
switch(special_pick)
|
||||
if(1)
|
||||
var/datum/objective/block/block_objective = new
|
||||
block_objective.owner = T.owner
|
||||
T.add_objective(block_objective)
|
||||
if(2)
|
||||
var/datum/objective/purge/purge_objective = new
|
||||
purge_objective.owner = T.owner
|
||||
T.add_objective(purge_objective)
|
||||
if(3)
|
||||
var/datum/objective/robot_army/robot_objective = new
|
||||
robot_objective.owner = T.owner
|
||||
T.add_objective(robot_objective)
|
||||
if(4) //Protect and strand a target
|
||||
var/datum/objective/protect/yandere_one = new
|
||||
yandere_one.owner = T.owner
|
||||
T.add_objective(yandere_one)
|
||||
yandere_one.find_target()
|
||||
var/datum/objective/maroon/yandere_two = new
|
||||
yandere_two.owner = T.owner
|
||||
yandere_two.target = yandere_one.target
|
||||
yandere_two.update_explanation_text() // normally called in find_target()
|
||||
T.add_objective(yandere_two)
|
||||
.=2
|
||||
|
||||
/datum/traitor_class/ai/on_removal(datum/antagonist/traitor/T)
|
||||
var/mob/living/silicon/ai/A = T.owner.current
|
||||
A.set_zeroth_law("")
|
||||
A.verbs -= /mob/living/silicon/ai/proc/choose_modules
|
||||
A.malf_picker.remove_malf_verbs(A)
|
||||
qdel(A.malf_picker)
|
||||
|
||||
|
||||
/datum/traitor_class/ai/apply_innate_effects(mob/living/M)
|
||||
var/mob/living/silicon/ai/A = M
|
||||
A.hack_software = TRUE
|
||||
|
||||
/datum/traitor_class/ai/remove_innate_effects(mob/living/M)
|
||||
var/mob/living/silicon/ai/A = M
|
||||
A.hack_software = FALSE
|
||||
|
||||
/datum/traitor_class/ai/finalize_traitor(datum/antagonist/traitor/T)
|
||||
T.add_law_zero()
|
||||
T.owner.current.playsound_local(get_turf(T.owner.current), 'sound/ambience/antag/malf.ogg', 100, FALSE, pressure_affected = FALSE)
|
||||
T.owner.current.grant_language(/datum/language/codespeak)
|
||||
return FALSE
|
||||
37
code/modules/antagonists/traitor/classes/assassin.dm
Normal file
37
code/modules/antagonists/traitor/classes/assassin.dm
Normal file
@@ -0,0 +1,37 @@
|
||||
/datum/traitor_class/human/assassin
|
||||
name = "Donk Co Operative"
|
||||
employer = "Donk Corporation"
|
||||
weight = 0
|
||||
chaos = 1
|
||||
cost = 2
|
||||
|
||||
/datum/traitor_class/human/assassin/forge_single_objective(datum/antagonist/traitor/T)
|
||||
.=1
|
||||
var/permakill_prob = 20
|
||||
var/is_dynamic = FALSE
|
||||
var/datum/game_mode/dynamic/mode
|
||||
if(istype(SSticker.mode,/datum/game_mode/dynamic))
|
||||
mode = SSticker.mode
|
||||
is_dynamic = TRUE
|
||||
permakill_prob = max(0,mode.threat_level-50)
|
||||
var/list/active_ais = active_ais()
|
||||
if(active_ais.len && prob(100/GLOB.joined_player_list.len))
|
||||
var/datum/objective/destroy/destroy_objective = new
|
||||
destroy_objective.owner = T.owner
|
||||
destroy_objective.find_target()
|
||||
T.add_objective(destroy_objective)
|
||||
else if(prob(30) || (is_dynamic && (mode.storyteller.flags & NO_ASSASSIN)))
|
||||
var/datum/objective/maroon/maroon_objective = new
|
||||
maroon_objective.owner = T.owner
|
||||
maroon_objective.find_target()
|
||||
T.add_objective(maroon_objective)
|
||||
else if(prob(permakill_prob))
|
||||
var/datum/objective/assassinate/kill_objective = new
|
||||
kill_objective.owner = T.owner
|
||||
kill_objective.find_target()
|
||||
T.add_objective(kill_objective)
|
||||
else
|
||||
var/datum/objective/assassinate/once/kill_objective = new
|
||||
kill_objective.owner = T.owner
|
||||
kill_objective.find_target()
|
||||
T.add_objective(kill_objective)
|
||||
12
code/modules/antagonists/traitor/classes/freeform.dm
Normal file
12
code/modules/antagonists/traitor/classes/freeform.dm
Normal file
@@ -0,0 +1,12 @@
|
||||
/datum/traitor_class/human/freeform
|
||||
name = "Waffle Co Agent"
|
||||
employer = "Waffle Company"
|
||||
weight = 16
|
||||
chaos = 0
|
||||
|
||||
/datum/traitor_class/human/freeform/forge_objectives(datum/antagonist/traitor/T)
|
||||
var/datum/objective/escape/O = new
|
||||
O.explanation_text = "You have no goals! Whatever you can do do antagonize Nanotrasen, do it! The gimmickier, the better! Make sure to escape alive, though!"
|
||||
O.owner = T.owner
|
||||
T.add_objective(O)
|
||||
return
|
||||
18
code/modules/antagonists/traitor/classes/hijack.dm
Normal file
18
code/modules/antagonists/traitor/classes/hijack.dm
Normal file
@@ -0,0 +1,18 @@
|
||||
/datum/traitor_class/human/hijack
|
||||
name = "Gorlex Marauder"
|
||||
employer = "The Gorlex Marauders"
|
||||
weight = 3
|
||||
chaos = 5
|
||||
cost = 5
|
||||
uplink_filters = list(/datum/uplink_item/stealthy_weapons/romerol_kit)
|
||||
|
||||
/datum/traitor_class/human/hijack/forge_objectives(datum/antagonist/traitor/T)
|
||||
var/datum/objective/hijack/O = new
|
||||
O.explanation_text = "The Gorlex Marauders are letting you do what you want, with one condition: the shuttle must be hijacked by hacking its navigational protocols through the control console (alt click emergency shuttle console)."
|
||||
O.owner = T.owner
|
||||
T.add_objective(O)
|
||||
return
|
||||
|
||||
/datum/traitor_class/human/hijack/finalize_traitor(datum/antagonist/traitor/T)
|
||||
T.hijack_speed=1
|
||||
return TRUE
|
||||
82
code/modules/antagonists/traitor/classes/human.dm
Normal file
82
code/modules/antagonists/traitor/classes/human.dm
Normal file
@@ -0,0 +1,82 @@
|
||||
/datum/traitor_class/human
|
||||
name = "Syndicate Agent"
|
||||
chaos = 0
|
||||
|
||||
/datum/traitor_class/human/forge_objectives(datum/antagonist/traitor/T)
|
||||
var/objective_count = 0 //Hijacking counts towards number of objectives
|
||||
if(!SSticker.mode.exchange_blue && SSticker.mode.traitors.len >= 8) //Set up an exchange if there are enough traitors
|
||||
if(!SSticker.mode.exchange_red)
|
||||
SSticker.mode.exchange_red = T.owner
|
||||
else
|
||||
SSticker.mode.exchange_blue = T.owner
|
||||
T.assign_exchange_role(SSticker.mode.exchange_red)
|
||||
T.assign_exchange_role(SSticker.mode.exchange_blue)
|
||||
objective_count += 1 //Exchange counts towards number of objectives
|
||||
var/toa = CONFIG_GET(number/traitor_objectives_amount)
|
||||
for(var/i = objective_count, i < toa, i++)
|
||||
forge_single_objective(T)
|
||||
if(!(locate(/datum/objective/escape) in T.objectives))
|
||||
var/datum/objective/escape/escape_objective = new
|
||||
escape_objective.owner = T.owner
|
||||
T.add_objective(escape_objective)
|
||||
return
|
||||
|
||||
/datum/traitor_class/human/forge_single_objective(datum/antagonist/traitor/T)
|
||||
.=1
|
||||
var/assassin_prob = 50
|
||||
var/is_dynamic = FALSE
|
||||
var/datum/game_mode/dynamic/mode
|
||||
if(istype(SSticker.mode,/datum/game_mode/dynamic))
|
||||
mode = SSticker.mode
|
||||
is_dynamic = TRUE
|
||||
assassin_prob = max(0,mode.threat_level-20)
|
||||
if(prob(assassin_prob))
|
||||
if(is_dynamic)
|
||||
var/threat_spent = CONFIG_GET(number/dynamic_assassinate_cost)
|
||||
mode.spend_threat(threat_spent)
|
||||
mode.log_threat("[T.owner.name] spent [threat_spent] on an assassination target.")
|
||||
var/list/active_ais = active_ais()
|
||||
if(active_ais.len && prob(100/GLOB.joined_player_list.len))
|
||||
var/datum/objective/destroy/destroy_objective = new
|
||||
destroy_objective.owner = T.owner
|
||||
destroy_objective.find_target()
|
||||
T.add_objective(destroy_objective)
|
||||
else if(prob(30) || (is_dynamic && (mode.storyteller.flags & NO_ASSASSIN)))
|
||||
var/datum/objective/maroon/maroon_objective = new
|
||||
maroon_objective.owner = T.owner
|
||||
maroon_objective.find_target()
|
||||
T.add_objective(maroon_objective)
|
||||
else if(prob(max(0,assassin_prob-20)))
|
||||
var/datum/objective/assassinate/kill_objective = new
|
||||
kill_objective.owner = T.owner
|
||||
kill_objective.find_target()
|
||||
T.add_objective(kill_objective)
|
||||
else
|
||||
var/datum/objective/assassinate/once/kill_objective = new
|
||||
kill_objective.owner = T.owner
|
||||
kill_objective.find_target()
|
||||
T.add_objective(kill_objective)
|
||||
else
|
||||
if(prob(15) && !(locate(/datum/objective/download) in T.objectives) && !(T.owner.assigned_role in list("Research Director", "Scientist", "Roboticist")))
|
||||
var/datum/objective/download/download_objective = new
|
||||
download_objective.owner = T.owner
|
||||
download_objective.gen_amount_goal()
|
||||
T.add_objective(download_objective)
|
||||
else if(prob(40)) // cum. not counting download: 40%.
|
||||
var/datum/objective/steal/steal_objective = new
|
||||
steal_objective.owner = T.owner
|
||||
steal_objective.find_target()
|
||||
T.add_objective(steal_objective)
|
||||
else if(prob(100/3)) // cum. not counting download: 20%.
|
||||
var/datum/objective/sabotage/sabotage_objective = new
|
||||
sabotage_objective.owner = T.owner
|
||||
sabotage_objective.find_target()
|
||||
T.add_objective(sabotage_objective)
|
||||
else // cum. not counting download: 40%
|
||||
var/datum/objective/flavor/traitor/flavor_objective = new
|
||||
flavor_objective.owner = T.owner
|
||||
flavor_objective.forge_objective()
|
||||
T.add_objective(flavor_objective)
|
||||
|
||||
/datum/traitor_class/human/greet(datum/antagonist/traitor/T)
|
||||
to_chat(T.owner.current, "<B><font size=2 color=red>You are under contract with [employer]. They have given you your objectives.</font></B>")
|
||||
14
code/modules/antagonists/traitor/classes/martyr.dm
Normal file
14
code/modules/antagonists/traitor/classes/martyr.dm
Normal file
@@ -0,0 +1,14 @@
|
||||
/datum/traitor_class/human/martyr
|
||||
name = "Tiger Cooperator"
|
||||
employer = "The Tiger Cooperative"
|
||||
weight = 2
|
||||
chaos = 5
|
||||
cost = 5
|
||||
uplink_filters = list(/datum/uplink_item/stealthy_weapons/romerol_kit,/datum/uplink_item/bundles_TC/contract_kit)
|
||||
|
||||
/datum/traitor_class/human/martyr/forge_objectives(datum/antagonist/traitor/T)
|
||||
var/datum/objective/martyr/O = new
|
||||
O.explanation_text = "The tiger cooperative have given you free reign. You may do as you wish, as long as you die a glorious death!"
|
||||
O.owner = T.owner
|
||||
T.add_objective(O)
|
||||
return
|
||||
40
code/modules/antagonists/traitor/classes/subterfuge.dm
Normal file
40
code/modules/antagonists/traitor/classes/subterfuge.dm
Normal file
@@ -0,0 +1,40 @@
|
||||
/datum/traitor_class/human/subterfuge
|
||||
name = "MI13 Operative"
|
||||
employer = "MI13"
|
||||
weight = 20
|
||||
chaos = -5
|
||||
|
||||
/datum/traitor_class/human/subterfuge/forge_single_objective(datum/antagonist/traitor/T)
|
||||
.=1
|
||||
var/assassin_prob = 30
|
||||
var/datum/game_mode/dynamic/mode
|
||||
if(istype(SSticker.mode,/datum/game_mode/dynamic))
|
||||
mode = SSticker.mode
|
||||
assassin_prob = max(0,mode.threat_level-40)
|
||||
if(prob(assassin_prob))
|
||||
if(prob(assassin_prob))
|
||||
var/datum/objective/assassinate/once/kill_objective = new
|
||||
kill_objective.owner = T.owner
|
||||
kill_objective.find_target()
|
||||
T.add_objective(kill_objective)
|
||||
else
|
||||
var/datum/objective/maroon/maroon_objective = new
|
||||
maroon_objective.owner = T.owner
|
||||
maroon_objective.find_target()
|
||||
T.add_objective(maroon_objective)
|
||||
else
|
||||
if(prob(15) && !(locate(/datum/objective/download) in T.objectives) && !(T.owner.assigned_role in list("Research Director", "Scientist", "Roboticist")))
|
||||
var/datum/objective/download/download_objective = new
|
||||
download_objective.owner = T.owner
|
||||
download_objective.gen_amount_goal()
|
||||
T.add_objective(download_objective)
|
||||
else if(prob(70)) // cum. not counting download: 40%.
|
||||
var/datum/objective/steal/steal_objective = new
|
||||
steal_objective.owner = T.owner
|
||||
steal_objective.find_target()
|
||||
T.add_objective(steal_objective)
|
||||
else
|
||||
var/datum/objective/sabotage/sabotage_objective = new
|
||||
sabotage_objective.owner = T.owner
|
||||
sabotage_objective.find_target()
|
||||
T.add_objective(sabotage_objective)
|
||||
40
code/modules/antagonists/traitor/classes/traitor_class.dm
Normal file
40
code/modules/antagonists/traitor/classes/traitor_class.dm
Normal file
@@ -0,0 +1,40 @@
|
||||
GLOBAL_LIST_EMPTY(traitor_classes)
|
||||
|
||||
/datum/traitor_class
|
||||
var/name = "Bad Coders Ltd."
|
||||
var/employer = "The Syndicate"
|
||||
var/weight = 0
|
||||
var/chaos = 0
|
||||
var/cost = 0
|
||||
var/TC = 20
|
||||
var/list/uplink_filters
|
||||
|
||||
/datum/traitor_class/New()
|
||||
..()
|
||||
if(src.type in GLOB.traitor_classes)
|
||||
qdel(src)
|
||||
else
|
||||
GLOB.traitor_classes += src.type
|
||||
GLOB.traitor_classes[src.type] = src
|
||||
|
||||
/datum/traitor_class/proc/forge_objectives(datum/antagonist/traitor/T)
|
||||
// Like the old forge_human_objectives. Makes all the objectives for this traitor class.
|
||||
|
||||
/datum/traitor_class/proc/forge_single_objective(datum/antagonist/traitor/T)
|
||||
// As forge_single_objective.
|
||||
|
||||
/datum/traitor_class/proc/on_removal(datum/antagonist/traitor/T)
|
||||
// What this does to the antag datum on removal. Called before proper removal, obviously.
|
||||
|
||||
/datum/traitor_class/proc/apply_innate_effects(mob/living/M)
|
||||
// What innate effects it should have. See: AI.
|
||||
|
||||
/datum/traitor_class/proc/remove_innate_effects(mob/living/M)
|
||||
// Cleaning up the innate effects.
|
||||
|
||||
/datum/traitor_class/proc/greet(datum/antagonist/traitor/T)
|
||||
// Message upon creation. Not necessary, but can be useful.
|
||||
|
||||
/datum/traitor_class/proc/finalize_traitor(datum/antagonist/traitor/T)
|
||||
// Finalization. Return TRUE if should play standard traitor sound/equip, return FALSE if both are special case
|
||||
return TRUE
|
||||
@@ -1,6 +1,3 @@
|
||||
#define TRAITOR_HUMAN "human"
|
||||
#define TRAITOR_AI "AI"
|
||||
|
||||
/datum/antagonist/traitor
|
||||
name = "Traitor"
|
||||
roundend_category = "traitors"
|
||||
@@ -12,43 +9,52 @@
|
||||
var/give_objectives = TRUE
|
||||
var/should_give_codewords = TRUE
|
||||
var/should_equip = TRUE
|
||||
var/traitor_kind = TRAITOR_HUMAN //Set on initial assignment
|
||||
var/datum/traitor_class/traitor_kind
|
||||
var/datum/contractor_hub/contractor_hub
|
||||
hijack_speed = 0.5 //10 seconds per hijack stage by default
|
||||
|
||||
/datum/antagonist/traitor/New()
|
||||
..()
|
||||
if(!GLOB.traitor_classes.len)//Only need to fill the list when it's needed.
|
||||
for(var/I in subtypesof(/datum/traitor_class))
|
||||
new I
|
||||
|
||||
/datum/antagonist/traitor/proc/set_traitor_kind(var/kind)
|
||||
traitor_kind = GLOB.traitor_classes[kind]
|
||||
if(istype(SSticker.mode, /datum/game_mode/dynamic))
|
||||
var/datum/game_mode/dynamic/mode = SSticker.mode
|
||||
if(traitor_kind.cost)
|
||||
mode.spend_threat(traitor_kind.cost)
|
||||
mode.log_threat("[traitor_kind.cost] was spent due to [owner.name] being a [traitor_kind.name].")
|
||||
|
||||
/datum/antagonist/traitor/on_gain()
|
||||
if(owner.current && isAI(owner.current))
|
||||
traitor_kind = TRAITOR_AI
|
||||
|
||||
set_traitor_kind(TRAITOR_AI)
|
||||
else
|
||||
var/chaos_weight = 0
|
||||
if(istype(SSticker.mode,/datum/game_mode/dynamic))
|
||||
var/datum/game_mode/dynamic/mode = SSticker.mode
|
||||
chaos_weight = (mode.threat - 50)/50
|
||||
var/list/weights = list()
|
||||
for(var/C in GLOB.traitor_classes)
|
||||
var/datum/traitor_class/class = GLOB.traitor_classes[C]
|
||||
var/weight = (1.5*class.weight)/(0.5+NUM_E**(-chaos_weight*class.chaos)) // just a logistic function
|
||||
weights[C] = weight
|
||||
var/choice = pickweightAllowZero(weights)
|
||||
if(!choice)
|
||||
choice = GLOB.traitor_classes[TRAITOR_HUMAN]
|
||||
set_traitor_kind(pickweightAllowZero(weights))
|
||||
traitor_kind.weight *= 0.8 // less likely this round
|
||||
SSticker.mode.traitors += owner
|
||||
owner.special_role = special_role
|
||||
if(give_objectives)
|
||||
forge_traitor_objectives()
|
||||
traitor_kind.forge_objectives(src)
|
||||
finalize_traitor()
|
||||
..()
|
||||
|
||||
/datum/antagonist/traitor/apply_innate_effects()
|
||||
if(owner.assigned_role == "Clown")
|
||||
var/mob/living/carbon/human/traitor_mob = owner.current
|
||||
if(traitor_mob && istype(traitor_mob))
|
||||
if(!silent)
|
||||
to_chat(traitor_mob, "Your training has allowed you to overcome your clownish nature, allowing you to wield weapons without harming yourself.")
|
||||
traitor_mob.dna.remove_mutation(CLOWNMUT)
|
||||
|
||||
/datum/antagonist/traitor/remove_innate_effects()
|
||||
if(owner.assigned_role == "Clown")
|
||||
var/mob/living/carbon/human/traitor_mob = owner.current
|
||||
if(traitor_mob && istype(traitor_mob))
|
||||
traitor_mob.dna.add_mutation(CLOWNMUT)
|
||||
|
||||
/datum/antagonist/traitor/on_removal()
|
||||
//Remove malf powers.
|
||||
if(traitor_kind == TRAITOR_AI && owner.current && isAI(owner.current))
|
||||
var/mob/living/silicon/ai/A = owner.current
|
||||
A.set_zeroth_law("")
|
||||
A.verbs -= /mob/living/silicon/ai/proc/choose_modules
|
||||
A.malf_picker.remove_malf_verbs(A)
|
||||
qdel(A.malf_picker)
|
||||
traitor_kind.on_removal(src)
|
||||
SSticker.mode.traitors -= owner
|
||||
if(!silent && owner.current)
|
||||
to_chat(owner.current,"<span class='userdanger'> You are no longer the [special_role]! </span>")
|
||||
@@ -69,192 +75,11 @@
|
||||
objectives -= O
|
||||
|
||||
/datum/antagonist/traitor/proc/forge_traitor_objectives()
|
||||
switch(traitor_kind)
|
||||
if(TRAITOR_AI)
|
||||
forge_ai_objectives()
|
||||
else
|
||||
forge_human_objectives()
|
||||
|
||||
/datum/antagonist/traitor/proc/forge_human_objectives()
|
||||
var/is_hijacker = FALSE
|
||||
var/datum/game_mode/dynamic/mode
|
||||
var/is_dynamic = FALSE
|
||||
var/hijack_prob = 0
|
||||
if(istype(SSticker.mode,/datum/game_mode/dynamic))
|
||||
mode = SSticker.mode
|
||||
is_dynamic = TRUE
|
||||
if(mode.threat >= CONFIG_GET(number/dynamic_hijack_cost))
|
||||
hijack_prob = CLAMP(mode.threat_level-50,0,20)
|
||||
if(GLOB.joined_player_list.len>=GLOB.dynamic_high_pop_limit)
|
||||
is_hijacker = (prob(hijack_prob) && mode.threat_level > CONFIG_GET(number/dynamic_hijack_high_population_requirement))
|
||||
else
|
||||
var/indice_pop = min(10,round(GLOB.joined_player_list.len/mode.pop_per_requirement)+1)
|
||||
is_hijacker = (prob(hijack_prob) && (mode.threat_level >= CONFIG_GET(number_list/dynamic_hijack_requirements)[indice_pop]))
|
||||
if(mode.storyteller.flags & NO_ASSASSIN)
|
||||
is_hijacker = FALSE
|
||||
else if (GLOB.joined_player_list.len >= 30) // Less murderboning on lowpop thanks
|
||||
hijack_prob = 10
|
||||
is_hijacker = prob(10)
|
||||
var/martyr_chance = prob(hijack_prob*2)
|
||||
var/objective_count = is_hijacker //Hijacking counts towards number of objectives
|
||||
if(!SSticker.mode.exchange_blue && SSticker.mode.traitors.len >= 8) //Set up an exchange if there are enough traitors
|
||||
if(!SSticker.mode.exchange_red)
|
||||
SSticker.mode.exchange_red = owner
|
||||
else
|
||||
SSticker.mode.exchange_blue = owner
|
||||
assign_exchange_role(SSticker.mode.exchange_red)
|
||||
assign_exchange_role(SSticker.mode.exchange_blue)
|
||||
objective_count += 1 //Exchange counts towards number of objectives
|
||||
var/toa = CONFIG_GET(number/traitor_objectives_amount)
|
||||
for(var/i = objective_count, i < toa, i++)
|
||||
forge_single_objective()
|
||||
|
||||
if(is_hijacker && objective_count <= toa) //Don't assign hijack if it would exceed the number of objectives set in config.traitor_objectives_amount
|
||||
if (!(locate(/datum/objective/hijack) in objectives))
|
||||
var/datum/objective/hijack/hijack_objective = new
|
||||
hijack_objective.owner = owner
|
||||
add_objective(hijack_objective)
|
||||
if(is_dynamic)
|
||||
var/threat_spent = CONFIG_GET(number/dynamic_hijack_cost)
|
||||
mode.spend_threat(threat_spent)
|
||||
mode.log_threat("[owner.name] spent [threat_spent] on hijack.")
|
||||
return
|
||||
|
||||
|
||||
var/martyr_compatibility = 1 //You can't succeed in stealing if you're dead.
|
||||
for(var/datum/objective/O in objectives)
|
||||
if(!O.martyr_compatible)
|
||||
martyr_compatibility = 0
|
||||
break
|
||||
|
||||
if(martyr_compatibility && martyr_chance)
|
||||
var/datum/objective/martyr/martyr_objective = new
|
||||
martyr_objective.owner = owner
|
||||
add_objective(martyr_objective)
|
||||
if(is_dynamic)
|
||||
var/threat_spent = CONFIG_GET(number/dynamic_hijack_cost)
|
||||
mode.spend_threat(threat_spent)
|
||||
mode.log_threat("[owner.name] spent [threat_spent] on glorious death.")
|
||||
return
|
||||
|
||||
else
|
||||
if(!(locate(/datum/objective/escape) in objectives))
|
||||
var/datum/objective/escape/escape_objective = new
|
||||
escape_objective.owner = owner
|
||||
add_objective(escape_objective)
|
||||
return
|
||||
|
||||
/datum/antagonist/traitor/proc/forge_ai_objectives()
|
||||
var/objective_count = 0
|
||||
|
||||
if(prob(30))
|
||||
objective_count += forge_single_objective()
|
||||
|
||||
for(var/i = objective_count, i < CONFIG_GET(number/traitor_objectives_amount), i++)
|
||||
var/datum/objective/assassinate/kill_objective = new
|
||||
kill_objective.owner = owner
|
||||
kill_objective.find_target()
|
||||
add_objective(kill_objective)
|
||||
|
||||
var/datum/objective/survive/exist/exist_objective = new
|
||||
exist_objective.owner = owner
|
||||
add_objective(exist_objective)
|
||||
|
||||
|
||||
/datum/antagonist/traitor/proc/forge_single_objective()
|
||||
switch(traitor_kind)
|
||||
if(TRAITOR_AI)
|
||||
return forge_single_AI_objective()
|
||||
else
|
||||
return forge_single_human_objective()
|
||||
|
||||
/datum/antagonist/traitor/proc/forge_single_human_objective() //Returns how many objectives are added
|
||||
.=1
|
||||
var/assassin_prob = 50
|
||||
var/is_dynamic = FALSE
|
||||
var/datum/game_mode/dynamic/mode
|
||||
if(istype(SSticker.mode,/datum/game_mode/dynamic))
|
||||
mode = SSticker.mode
|
||||
is_dynamic = TRUE
|
||||
assassin_prob = max(0,mode.threat_level-20)
|
||||
if(prob(assassin_prob))
|
||||
if(is_dynamic)
|
||||
var/threat_spent = CONFIG_GET(number/dynamic_assassinate_cost)
|
||||
mode.spend_threat(threat_spent)
|
||||
mode.log_threat("[owner.name] spent [threat_spent] on an assassination target.")
|
||||
var/list/active_ais = active_ais()
|
||||
if(active_ais.len && prob(100/GLOB.joined_player_list.len))
|
||||
var/datum/objective/destroy/destroy_objective = new
|
||||
destroy_objective.owner = owner
|
||||
destroy_objective.find_target()
|
||||
add_objective(destroy_objective)
|
||||
else if(prob(30) || (is_dynamic && (mode.storyteller.flags & NO_ASSASSIN)))
|
||||
var/datum/objective/maroon/maroon_objective = new
|
||||
maroon_objective.owner = owner
|
||||
maroon_objective.find_target()
|
||||
add_objective(maroon_objective)
|
||||
else if(prob(max(0,assassin_prob-20)))
|
||||
var/datum/objective/assassinate/kill_objective = new
|
||||
kill_objective.owner = owner
|
||||
kill_objective.find_target()
|
||||
add_objective(kill_objective)
|
||||
else
|
||||
var/datum/objective/assassinate/once/kill_objective = new
|
||||
kill_objective.owner = owner
|
||||
kill_objective.find_target()
|
||||
add_objective(kill_objective)
|
||||
else
|
||||
if(prob(15) && !(locate(/datum/objective/download) in objectives) && !(owner.assigned_role in list("Research Director", "Scientist", "Roboticist")))
|
||||
var/datum/objective/download/download_objective = new
|
||||
download_objective.owner = owner
|
||||
download_objective.gen_amount_goal()
|
||||
add_objective(download_objective)
|
||||
else if(prob(40)) // cum. not counting download: 40%.
|
||||
var/datum/objective/steal/steal_objective = new
|
||||
steal_objective.owner = owner
|
||||
steal_objective.find_target()
|
||||
add_objective(steal_objective)
|
||||
else if(prob(100/3)) // cum. not counting download: 20%.
|
||||
var/datum/objective/sabotage/sabotage_objective = new
|
||||
sabotage_objective.owner = owner
|
||||
sabotage_objective.find_target()
|
||||
add_objective(sabotage_objective)
|
||||
else // cum. not counting download: 40%
|
||||
var/datum/objective/flavor/traitor/flavor_objective = new
|
||||
flavor_objective.owner = owner
|
||||
flavor_objective.forge_objective()
|
||||
add_objective(flavor_objective)
|
||||
|
||||
/datum/antagonist/traitor/proc/forge_single_AI_objective()
|
||||
.=1
|
||||
var/special_pick = rand(1,4)
|
||||
switch(special_pick)
|
||||
if(1)
|
||||
var/datum/objective/block/block_objective = new
|
||||
block_objective.owner = owner
|
||||
add_objective(block_objective)
|
||||
if(2)
|
||||
var/datum/objective/purge/purge_objective = new
|
||||
purge_objective.owner = owner
|
||||
add_objective(purge_objective)
|
||||
if(3)
|
||||
var/datum/objective/robot_army/robot_objective = new
|
||||
robot_objective.owner = owner
|
||||
add_objective(robot_objective)
|
||||
if(4) //Protect and strand a target
|
||||
var/datum/objective/protect/yandere_one = new
|
||||
yandere_one.owner = owner
|
||||
add_objective(yandere_one)
|
||||
yandere_one.find_target()
|
||||
var/datum/objective/maroon/yandere_two = new
|
||||
yandere_two.owner = owner
|
||||
yandere_two.target = yandere_one.target
|
||||
yandere_two.update_explanation_text() // normally called in find_target()
|
||||
add_objective(yandere_two)
|
||||
.=2
|
||||
traitor_kind.forge_objectives(src)
|
||||
|
||||
/datum/antagonist/traitor/greet()
|
||||
to_chat(owner.current, "<B><font size=3 color=red>You are the [owner.special_role].</font></B>")
|
||||
traitor_kind.greet(src)
|
||||
owner.announce_objectives()
|
||||
if(should_give_codewords)
|
||||
give_codewords()
|
||||
@@ -270,32 +95,33 @@
|
||||
set_antag_hud(owner.current, null)
|
||||
|
||||
/datum/antagonist/traitor/proc/finalize_traitor()
|
||||
switch(traitor_kind)
|
||||
if(TRAITOR_AI)
|
||||
add_law_zero()
|
||||
owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/malf.ogg', 100, FALSE, pressure_affected = FALSE)
|
||||
owner.current.grant_language(/datum/language/codespeak)
|
||||
if(TRAITOR_HUMAN)
|
||||
if(should_equip)
|
||||
equip(silent)
|
||||
owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/tatoralert.ogg', 100, FALSE, pressure_affected = FALSE)
|
||||
if(traitor_kind.finalize_traitor(src))
|
||||
if(should_equip)
|
||||
equip(silent)
|
||||
owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/tatoralert.ogg', 100, FALSE, pressure_affected = FALSE)
|
||||
|
||||
/datum/antagonist/traitor/apply_innate_effects(mob/living/mob_override)
|
||||
. = ..()
|
||||
update_traitor_icons_added()
|
||||
var/mob/M = mob_override || owner.current
|
||||
if(isAI(M) && traitor_kind == TRAITOR_AI)
|
||||
var/mob/living/silicon/ai/A = M
|
||||
A.hack_software = TRUE
|
||||
traitor_kind.apply_innate_effects(M)
|
||||
if(owner.assigned_role == "Clown")
|
||||
var/mob/living/carbon/human/H = M
|
||||
if(istype(H))
|
||||
if(!silent)
|
||||
to_chat(H, "Your training has allowed you to overcome your clownish nature, allowing you to wield weapons without harming yourself.")
|
||||
H.dna.remove_mutation(CLOWNMUT)
|
||||
RegisterSignal(M, COMSIG_MOVABLE_HEAR, .proc/handle_hearing)
|
||||
|
||||
/datum/antagonist/traitor/remove_innate_effects(mob/living/mob_override)
|
||||
. = ..()
|
||||
update_traitor_icons_removed()
|
||||
var/mob/M = mob_override || owner.current
|
||||
if(isAI(M) && traitor_kind == TRAITOR_AI)
|
||||
var/mob/living/silicon/ai/A = M
|
||||
A.hack_software = FALSE
|
||||
traitor_kind.remove_innate_effects(M)
|
||||
if(owner.assigned_role == "Clown")
|
||||
var/mob/living/carbon/human/H = M
|
||||
if(istype(H))
|
||||
H.dna.add_mutation(CLOWNMUT)
|
||||
UnregisterSignal(M, COMSIG_MOVABLE_HEAR)
|
||||
|
||||
/datum/antagonist/traitor/proc/give_codewords()
|
||||
@@ -326,8 +152,7 @@
|
||||
killer.add_malf_picker()
|
||||
|
||||
/datum/antagonist/traitor/proc/equip(var/silent = FALSE)
|
||||
if(traitor_kind == TRAITOR_HUMAN)
|
||||
owner.equip_traitor(employer, silent, src)
|
||||
owner.equip_traitor(traitor_kind, silent, src)
|
||||
|
||||
/datum/antagonist/traitor/proc/assign_exchange_role()
|
||||
//set faction
|
||||
|
||||
@@ -89,32 +89,17 @@
|
||||
|
||||
/datum/supply_pack/misc/paper_work
|
||||
name = "Freelance Paper work"
|
||||
desc = "The Nanotrasen Primary Bureaucratic Database Intelligence (PDBI) reports that the station has not completed its funding and grant paperwork this solar cycle. In order to gain further funding, your station is required to fill out (20) ten of these forms or no additional capital will be disbursed. We have sent you ten copies of the following form and we expect every one to be up to Nanotrasen Standards." // Disbursement. It's not a typo, look it up.
|
||||
cost = 700 // Net of 0 credits but makes (120 x 20 = 2400)
|
||||
desc = "The Nanotrasen Primary Bureaucratic Database Intelligence (PDBI) reports that the station has not completed its funding and grant paperwork this solar cycle. In order to gain further funding, your station is required to fill out (10) ten of these forms or no additional capital will be disbursed. We have sent you ten copies of the following form and we expect every one to be up to Nanotrasen Standards." // Disbursement. It's not a typo, look it up.
|
||||
cost = 700 // Net of 0 credits but makes (120 x 10 = 1200)
|
||||
contains = list(/obj/item/folder/paperwork,
|
||||
/obj/item/folder/paperwork,
|
||||
/obj/item/folder/paperwork,
|
||||
/obj/item/folder/paperwork,
|
||||
/obj/item/folder/paperwork,
|
||||
/obj/item/folder/paperwork,
|
||||
/obj/item/folder/paperwork,
|
||||
/obj/item/folder/paperwork,
|
||||
/obj/item/folder/paperwork,
|
||||
/obj/item/folder/paperwork,
|
||||
/obj/item/folder/paperwork,
|
||||
/obj/item/folder/paperwork,
|
||||
/obj/item/folder/paperwork,
|
||||
/obj/item/folder/paperwork,
|
||||
/obj/item/folder/paperwork,
|
||||
/obj/item/folder/paperwork,
|
||||
/obj/item/folder/paperwork,
|
||||
/obj/item/folder/paperwork,
|
||||
/obj/item/folder/paperwork,
|
||||
/obj/item/folder/paperwork,
|
||||
/obj/item/pen/fountain
|
||||
)
|
||||
crate_name = "Paperwork"
|
||||
|
||||
/datum/supply_pack/misc/paper_work/generate()
|
||||
. = ..()
|
||||
for(var/i in 1 to 9)
|
||||
new /obj/item/folder/paperwork(.)
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////// Entertainment ///////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
@@ -123,16 +108,14 @@
|
||||
name = "Bedsheet Crate (R)"
|
||||
desc = "Snuggle up in some sweet sheets with this assorted bedsheet crate. Each set comes with eight random bedsheets for your slumbering pleasure!"
|
||||
cost = 2000
|
||||
contains = list(/obj/item/bedsheet/random,
|
||||
/obj/item/bedsheet/random,
|
||||
/obj/item/bedsheet/random,
|
||||
/obj/item/bedsheet/random,
|
||||
/obj/item/bedsheet/random,
|
||||
/obj/item/bedsheet/random,
|
||||
/obj/item/bedsheet/random,
|
||||
/obj/item/bedsheet/random) //I'm lazy, and I copy paste stuff.
|
||||
contains = list(/obj/item/bedsheet/random)
|
||||
crate_name = "random bedsheet crate"
|
||||
|
||||
/datum/supply_pack/misc/randombedsheets/generate()
|
||||
. = ..()
|
||||
for(var/i in 1 to 7)
|
||||
new /obj/item/bedsheet/random(.)
|
||||
|
||||
/datum/supply_pack/misc/coloredsheets
|
||||
name = "Bedsheet Crate (C)"
|
||||
desc = "Give your night life a splash of color with this crate filled with bedsheets! Contains a total of nine different-colored sheets."
|
||||
@@ -208,13 +191,14 @@
|
||||
name = "Dueling Pistols"
|
||||
desc = "Resolve all your quarrels with some nonlethal fun."
|
||||
cost = 2000
|
||||
contains = list(/obj/item/storage/lockbox/dueling/hugbox/stamina,
|
||||
/obj/item/storage/lockbox/dueling/hugbox/stamina,
|
||||
/obj/item/storage/lockbox/dueling/hugbox/stamina,
|
||||
/obj/item/storage/lockbox/dueling/hugbox/stamina,
|
||||
/obj/item/storage/lockbox/dueling/hugbox/stamina)
|
||||
contains = list(/obj/item/storage/lockbox/dueling/hugbox/stamina)
|
||||
crate_name = "dueling pistols"
|
||||
|
||||
/datum/supply_pack/misc/dueling_stam/generate()
|
||||
. = ..()
|
||||
for(var/i in 1 to 3)
|
||||
new /obj/item/storage/lockbox/dueling/hugbox/stamina(.)
|
||||
|
||||
/datum/supply_pack/misc/dueling_lethal
|
||||
name = "Lethal Dueling Pistols"
|
||||
desc = "Settle your differences the true spaceman way."
|
||||
@@ -240,12 +224,7 @@
|
||||
cost = 12000
|
||||
var/num_contained = 3
|
||||
contains = list(/obj/item/ammo_box/a357,
|
||||
/obj/item/ammo_box/a357,
|
||||
/obj/item/ammo_box/a357,
|
||||
/obj/item/ammo_box/magazine/pistolm9mm,
|
||||
/obj/item/ammo_box/magazine/pistolm9mm,
|
||||
/obj/item/ammo_box/magazine/pistolm9mm,
|
||||
/obj/item/ammo_box/magazine/m45/kitchengun,
|
||||
/obj/item/ammo_box/magazine/m45/kitchengun)
|
||||
crate_name = "crate"
|
||||
|
||||
|
||||
@@ -44,8 +44,8 @@
|
||||
if(ishuman(hit_atom))
|
||||
var/mob/living/carbon/human/H = hit_atom
|
||||
var/mutable_appearance/creamoverlay = mutable_appearance('icons/effects/creampie.dmi')
|
||||
if(H.dna.species.limbs_id == "lizard")
|
||||
creamoverlay.icon_state = "creampie_lizard"
|
||||
if((("mam_snouts" in H.dna.species.default_features) && H.dna.features["mam_snouts"] != "None") || (("snout" in H.dna.species.default_features) && H.dna.features["snout"] != "None"))
|
||||
creamoverlay.icon_state = "creampie_snout"
|
||||
else
|
||||
creamoverlay.icon_state = "creampie_human"
|
||||
if(stunning)
|
||||
@@ -53,7 +53,7 @@
|
||||
H.adjust_blurriness(1)
|
||||
H.visible_message("<span class='warning'>[H] is creamed by [src]!</span>", "<span class='userdanger'>You've been creamed by [src]!</span>")
|
||||
playsound(H, "desceration", 50, TRUE)
|
||||
if(!H.is_mouth_covered())
|
||||
if(!H.is_mouth_covered())
|
||||
reagents.trans_to(H,15) //Cream pie combat
|
||||
if(!H.creamed) // one layer at a time
|
||||
H.add_overlay(creamoverlay)
|
||||
|
||||
@@ -139,6 +139,9 @@
|
||||
icon = 'icons/obj/lavaland/survival_pod.dmi'
|
||||
icon_state = "sleeper"
|
||||
|
||||
/obj/machinery/sleeper/survival_pod/update_icon_state()
|
||||
return
|
||||
|
||||
/obj/machinery/sleeper/survival_pod/update_overlays()
|
||||
. = ..()
|
||||
if(!state_open)
|
||||
@@ -189,7 +192,7 @@
|
||||
flags_1 = NODECONSTRUCT_1
|
||||
var/empty = FALSE
|
||||
|
||||
/obj/machinery/stasis/survival_pod/ComponentInitialize()
|
||||
/obj/machinery/smartfridge/survival_pod/ComponentInitialize()
|
||||
. = ..()
|
||||
AddElement(/datum/element/update_icon_blocker)
|
||||
|
||||
|
||||
@@ -261,11 +261,11 @@
|
||||
jitteriness += 1000 //High numbers for violent convulsions
|
||||
do_jitter_animation(jitteriness)
|
||||
stuttering += 2
|
||||
if((!(flags & SHOCK_TESLA) || siemens_coeff > 0.5) && (flags & SHOCK_NOSTUN))
|
||||
if((!(flags & SHOCK_TESLA) || siemens_coeff > 0.5) && !(flags & SHOCK_NOSTUN))
|
||||
Stun(40)
|
||||
spawn(20)
|
||||
jitteriness = max(jitteriness - 990, 10) //Still jittery, but vastly less
|
||||
if((!(flags & SHOCK_TESLA) || siemens_coeff > 0.5) && (flags & SHOCK_NOSTUN))
|
||||
if((!(flags & SHOCK_TESLA) || siemens_coeff > 0.5) && !(flags & SHOCK_NOSTUN))
|
||||
DefaultCombatKnockdown(60)
|
||||
return shock_damage
|
||||
|
||||
|
||||
@@ -242,6 +242,12 @@
|
||||
return
|
||||
|
||||
if(href_list["pockets"])
|
||||
var/strip_mod = 1
|
||||
var/strip_silence = FALSE
|
||||
var/obj/item/clothing/gloves/g = gloves
|
||||
if (istype(g))
|
||||
strip_mod = g.strip_mod
|
||||
strip_silence = g.strip_silence
|
||||
var/pocket_side = href_list["pockets"]
|
||||
var/pocket_id = (pocket_side == "right" ? SLOT_R_STORE : SLOT_L_STORE)
|
||||
var/obj/item/pocket_item = (pocket_id == SLOT_R_STORE ? r_store : l_store)
|
||||
@@ -258,7 +264,7 @@
|
||||
else
|
||||
return
|
||||
|
||||
if(do_mob(usr, src, POCKET_STRIP_DELAY/delay_denominator, ignorehelditem = TRUE)) //placing an item into the pocket is 4 times faster
|
||||
if(do_mob(usr, src, max(round(POCKET_STRIP_DELAY/(delay_denominator*strip_mod)),1), ignorehelditem = TRUE)) //placing an item into the pocket is 4 times faster (and the strip_mod too)
|
||||
if(pocket_item)
|
||||
if(pocket_item == (pocket_id == SLOT_R_STORE ? r_store : l_store)) //item still in the pocket we search
|
||||
dropItemToGround(pocket_item)
|
||||
@@ -276,7 +282,8 @@
|
||||
show_inv(usr)
|
||||
else
|
||||
// Display a warning if the user mocks up
|
||||
to_chat(src, "<span class='warning'>You feel your [pocket_side] pocket being fumbled with!</span>")
|
||||
if (!strip_silence)
|
||||
to_chat(src, "<span class='warning'>You feel your [pocket_side] pocket being fumbled with!</span>")
|
||||
|
||||
..() //CITADEL CHANGE - removes a tab from behind this ..() so that flavortext can actually be examined
|
||||
|
||||
|
||||
@@ -397,7 +397,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
if(I.flags_inv & HIDEFACIALHAIR)
|
||||
facialhair_hidden = TRUE
|
||||
|
||||
if(H.wear_mask)
|
||||
if(H.wear_mask && istype(H.wear_mask))
|
||||
var/obj/item/clothing/mask/M = H.wear_mask
|
||||
dynamic_fhair_suffix = M.dynamic_fhair_suffix //mask > head in terms of facial hair
|
||||
if(M.flags_inv & HIDEFACIALHAIR)
|
||||
@@ -451,7 +451,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
if(I.flags_inv & HIDEHAIR)
|
||||
hair_hidden = TRUE
|
||||
|
||||
if(H.wear_mask)
|
||||
if(H.wear_mask && istype(H.wear_mask))
|
||||
var/obj/item/clothing/mask/M = H.wear_mask
|
||||
if(!dynamic_hair_suffix) //head > mask in terms of head hair
|
||||
dynamic_hair_suffix = M.dynamic_hair_suffix
|
||||
|
||||
@@ -821,7 +821,6 @@
|
||||
/obj/item/gps/cyborg,
|
||||
/obj/item/weapon/gripper/mining,
|
||||
/obj/item/cyborg_clamp,
|
||||
/obj/item/card/id/miningborg,
|
||||
/obj/item/stack/marker_beacon,
|
||||
/obj/item/destTagger,
|
||||
/obj/item/stack/packageWrap)
|
||||
@@ -1023,4 +1022,4 @@
|
||||
/datum/robot_energy_storage/wrapping_paper
|
||||
max_energy = 30
|
||||
recharge_rate = 1
|
||||
name = "Wrapping Paper Storage"
|
||||
name = "Wrapping Paper Storage"
|
||||
|
||||
@@ -363,10 +363,8 @@
|
||||
icon_dead = "old_corgi_dead"
|
||||
desc = "At a ripe old age of [record_age] Ian's not as spry as he used to be, but he'll always be the HoP's beloved corgi." //RIP
|
||||
turns_per_move = 20
|
||||
var/datum/element/mob_holder/ele = SSdcs.GetElement(/datum/element/mob_holder, held_icon)
|
||||
if(ele)
|
||||
ele.Detach(src)
|
||||
AddElement(/datum/element/mob_holder, "old_corgi")
|
||||
RemoveElement(/datum/element/mob_holder, held_icon)
|
||||
AddElement(/datum/element/mob_holder, "old_corgi")
|
||||
|
||||
/mob/living/simple_animal/pet/dog/corgi/Ian/Life()
|
||||
if(!stat && SSticker.current_state == GAME_STATE_FINISHED && !memory_saved)
|
||||
@@ -447,7 +445,7 @@
|
||||
sleep(3)
|
||||
step_to(src,movement_target,1)
|
||||
|
||||
if(movement_target) //Not redundant due to sleeps, Item can be gone in 6 decisecomds
|
||||
if(movement_target?.loc) //Not redundant due to sleeps, Item can be gone in 6 decisecomds
|
||||
if (movement_target.loc.x < src.x)
|
||||
setDir(WEST)
|
||||
else if (movement_target.loc.x > src.x)
|
||||
|
||||
@@ -64,7 +64,7 @@
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/mouse/handle_automated_action()
|
||||
if(isbelly(loc))
|
||||
if(!isturf(loc))
|
||||
return
|
||||
|
||||
if(prob(chew_probability))
|
||||
@@ -76,7 +76,7 @@
|
||||
visible_message("<span class='warning'>[src] chews through the [C]. It's toast!</span>")
|
||||
playsound(src, 'sound/effects/sparks2.ogg', 100, 1)
|
||||
C.deconstruct()
|
||||
death(toast=1)
|
||||
death(toast=TRUE)
|
||||
else
|
||||
C.deconstruct()
|
||||
visible_message("<span class='warning'>[src] chews through the [C].</span>")
|
||||
|
||||
@@ -19,9 +19,15 @@
|
||||
/mob/proc/set_dizziness(amount)
|
||||
dizziness = max(amount, 0)
|
||||
|
||||
///Blind a mobs eyes by amount
|
||||
/**
|
||||
* Sets a mob's blindness to an amount if it was not above it already, similar to how status effects work
|
||||
*/
|
||||
/mob/proc/blind_eyes(amount)
|
||||
adjust_blindness(amount)
|
||||
var/old_blind = eye_blind || HAS_TRAIT(src, TRAIT_BLIND)
|
||||
eye_blind = max(eye_blind, amount)
|
||||
var/new_blind = eye_blind || HAS_TRAIT(src, TRAIT_BLIND)
|
||||
if(old_blind != new_blind)
|
||||
update_blindness()
|
||||
|
||||
/**
|
||||
* Adjust a mobs blindness by an amount
|
||||
|
||||
@@ -12,6 +12,10 @@
|
||||
battery = new battery_type(src)
|
||||
..()
|
||||
|
||||
/obj/item/computer_hardware/battery/Destroy()
|
||||
. = ..()
|
||||
QDEL_NULL(battery)
|
||||
|
||||
/obj/item/computer_hardware/battery/try_insert(obj/item/I, mob/living/user = null)
|
||||
if(!holder)
|
||||
return FALSE
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
var/mob/current_user = null
|
||||
var/list/obj/effect/projectile/tracer/current_tracers
|
||||
|
||||
var/structure_piercing = 1
|
||||
var/structure_piercing = 0
|
||||
var/structure_bleed_coeff = 0.7
|
||||
var/wall_pierce_amount = 0
|
||||
var/wall_devastate = 0
|
||||
@@ -60,7 +60,7 @@
|
||||
var/impact_structure_damage = 75
|
||||
var/projectile_damage = 40
|
||||
var/projectile_stun = 0
|
||||
var/projectile_setting_pierce = TRUE
|
||||
var/projectile_setting_pierce = FALSE
|
||||
var/delay = 30
|
||||
var/lastfire = 0
|
||||
|
||||
@@ -160,6 +160,9 @@
|
||||
add_overlay(drained_overlay)
|
||||
|
||||
/obj/item/gun/energy/beam_rifle/attack_self(mob/user)
|
||||
if(!structure_piercing)
|
||||
projectile_setting_pierce = FALSE
|
||||
return
|
||||
projectile_setting_pierce = !projectile_setting_pierce
|
||||
to_chat(user, "<span class='boldnotice'>You set \the [src] to [projectile_setting_pierce? "pierce":"impact"] mode.</span>")
|
||||
aiming_beam()
|
||||
@@ -402,7 +405,7 @@
|
||||
/obj/item/ammo_casing/energy/beam_rifle/hitscan
|
||||
projectile_type = /obj/item/projectile/beam/beam_rifle/hitscan
|
||||
select_name = "beam"
|
||||
e_cost = 5000
|
||||
e_cost = 10000
|
||||
fire_sound = 'sound/weapons/beam_sniper.ogg'
|
||||
|
||||
/obj/item/projectile/beam/beam_rifle
|
||||
@@ -557,9 +560,4 @@
|
||||
hitscan_light_color_override = "#99ff99"
|
||||
|
||||
/obj/item/projectile/beam/beam_rifle/hitscan/aiming_beam/prehit(atom/target)
|
||||
qdel(src)
|
||||
return FALSE
|
||||
|
||||
/obj/item/projectile/beam/beam_rifle/hitscan/aiming_beam/on_hit()
|
||||
qdel(src)
|
||||
return BULLET_ACT_HIT
|
||||
|
||||
@@ -28,7 +28,7 @@ Borg Hypospray
|
||||
|
||||
var/list/datum/reagents/reagent_list = list()
|
||||
var/list/reagent_ids = list(/datum/reagent/medicine/dexalin, /datum/reagent/medicine/kelotane, /datum/reagent/medicine/bicaridine, /datum/reagent/medicine/antitoxin,
|
||||
/datum/reagent/medicine/epinephrine, /datum/reagent/medicine/spaceacillin, /datum/reagent/medicine/salglu_solution, /datum/reagent/medicine/insulin)
|
||||
/datum/reagent/medicine/epinephrine, /datum/reagent/medicine/spaceacillin, /datum/reagent/medicine/salglu_solution, /datum/reagent/medicine/insulin, /datum/reagent/medicine/potass_iodide)
|
||||
var/accepts_reagent_upgrades = TRUE //If upgrades can increase number of reagents dispensed.
|
||||
var/list/modes = list() //Basically the inverse of reagent_ids. Instead of having numbers as "keys" and strings as values it has strings as keys and numbers as values.
|
||||
//Used as list for input() in shakers.
|
||||
@@ -164,7 +164,7 @@ Borg Hypospray
|
||||
icon_state = "borghypo_s"
|
||||
charge_cost = 20
|
||||
recharge_time = 2
|
||||
reagent_ids = list(/datum/reagent/medicine/syndicate_nanites, /datum/reagent/medicine/potass_iodide, /datum/reagent/medicine/morphine, /datum/reagent/medicine/insulin)
|
||||
reagent_ids = list(/datum/reagent/medicine/syndicate_nanites, /datum/reagent/medicine/prussian_blue, /datum/reagent/medicine/morphine, /datum/reagent/medicine/insulin)
|
||||
bypass_protection = 1
|
||||
accepts_reagent_upgrades = FALSE
|
||||
|
||||
@@ -261,5 +261,5 @@ Borg Shaker
|
||||
/obj/item/reagent_containers/borghypo/epi
|
||||
name = "Stabilizer injector"
|
||||
desc = "An advanced chemical synthesizer and injection system, designed to stabilize patients."
|
||||
reagent_ids = list(/datum/reagent/medicine/epinephrine, /datum/reagent/medicine/insulin)
|
||||
reagent_ids = list(/datum/reagent/medicine/epinephrine, /datum/reagent/medicine/insulin, /datum/reagent/medicine/potass_iodide)
|
||||
accepts_reagent_upgrades = FALSE
|
||||
|
||||
@@ -35,6 +35,17 @@
|
||||
dangerous_construction = TRUE
|
||||
departmental_flags = DEPARTMENTAL_FLAG_SCIENCE
|
||||
|
||||
/datum/design/duffelbag_holding
|
||||
name = "Duffel Bag of Holding"
|
||||
desc = "A duffel bag that opens into a localized pocket of bluespace."
|
||||
id = "duffelbag_holding"
|
||||
build_type = PROTOLATHE
|
||||
materials = list(/datum/material/gold = 3000, /datum/material/diamond = 1500, /datum/material/uranium = 250, /datum/material/bluespace = 2000)
|
||||
build_path = /obj/item/storage/backpack/holding/duffel
|
||||
category = list("Bluespace Designs")
|
||||
dangerous_construction = TRUE
|
||||
departmental_flags = DEPARTMENTAL_FLAG_SCIENCE
|
||||
|
||||
/datum/design/biobag_holding
|
||||
name = "Bio Bag of Holding"
|
||||
desc = "A chemical holding thingy. Mostly used for xenobiology."
|
||||
|
||||
@@ -633,15 +633,6 @@
|
||||
construction_time = 120
|
||||
category = list("Cyborg Upgrade Modules")
|
||||
|
||||
/datum/design/borg_upgrade_premiumka
|
||||
name = "Cyborg Upgrade (Premium Kinetic Accelerator)"
|
||||
id = "borg_upgrade_premiumka"
|
||||
build_type = MECHFAB
|
||||
build_path = /obj/item/borg/upgrade/premiumka
|
||||
materials = list(/datum/material/iron=8000, /datum/material/glass=4000, /datum/material/titanium=2000)
|
||||
construction_time = 120
|
||||
category = list("Cyborg Upgrade Modules")
|
||||
|
||||
/datum/design/borg_upgrade_lavaproof
|
||||
name = "Cyborg Upgrade (Lavaproof Tracks)"
|
||||
id = "borg_upgrade_lavaproof"
|
||||
|
||||
@@ -278,7 +278,7 @@
|
||||
display_name = "Bluespace Pockets"
|
||||
description = "Studies into the mysterious alternate dimension known as bluespace and how to place items in the threads of reality."
|
||||
prereq_ids = list("adv_power", "adv_bluespace", "adv_biotech", "adv_plasma")
|
||||
design_ids = list( "bluespacebodybag","bag_holding", "bluespace_pod", "borg_upgrade_trashofholding", "blutrash", "satchel_holding", "bsblood_bag")
|
||||
design_ids = list( "bluespacebodybag","bag_holding", "bluespace_pod", "borg_upgrade_trashofholding", "blutrash", "satchel_holding", "bsblood_bag", "duffelbag_holding")
|
||||
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 5500)
|
||||
|
||||
/datum/techweb_node/bluespace_portal
|
||||
@@ -336,7 +336,7 @@
|
||||
display_name = "Advanced Robotics Research"
|
||||
description = "It can even do the dishes!"
|
||||
prereq_ids = list("robotics")
|
||||
design_ids = list("borg_upgrade_diamonddrill", "borg_upgrade_advancedmop", "borg_upgrade_advcutter", "borg_upgrade_premiumka")
|
||||
design_ids = list("borg_upgrade_diamonddrill", "borg_upgrade_advancedmop", "borg_upgrade_advcutter")
|
||||
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 3000)
|
||||
|
||||
/datum/techweb_node/neural_programming
|
||||
|
||||
@@ -319,6 +319,8 @@
|
||||
on_mob.forceMove(scanning)
|
||||
for(var/i in 1 to light_beam_distance)
|
||||
scanning = get_step(scanning, scandir)
|
||||
if(!scanning)
|
||||
break
|
||||
if(scanning.opacity || scanning.has_opaque_atom)
|
||||
stop = TRUE
|
||||
var/obj/effect/abstract/eye_lighting/L = LAZYACCESS(eye_lighting, i)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/proc/get_uplink_items(datum/game_mode/gamemode, allow_sales = TRUE, allow_restricted = TRUE)
|
||||
/proc/get_uplink_items(datum/game_mode/gamemode, allow_sales = TRUE, allow_restricted = TRUE, other_filter = list())
|
||||
var/list/filtered_uplink_items = GLOB.uplink_categories.Copy() // list of uplink categories without associated values.
|
||||
var/list/sale_items = list()
|
||||
|
||||
@@ -18,7 +18,8 @@
|
||||
continue
|
||||
if (I.restricted && !allow_restricted)
|
||||
continue
|
||||
|
||||
if (I.type in other_filter)
|
||||
continue
|
||||
LAZYSET(filtered_uplink_items[I.category], I.name, I)
|
||||
|
||||
if(I.limited_stock < 0 && !I.cant_discount && I.item && I.cost > 1)
|
||||
|
||||
Reference in New Issue
Block a user