diff --git a/code/controllers/subsystem/mobs.dm b/code/controllers/subsystem/mobs.dm index 9bae03b30a4..41d9d3fb05c 100644 --- a/code/controllers/subsystem/mobs.dm +++ b/code/controllers/subsystem/mobs.dm @@ -19,4 +19,5 @@ var/datum/subsystem/mobs/SSmob if(thing) thing:Life(seconds) continue + WARNING("Found a null in the mob list. Removing.") mob_list.Remove(thing) \ No newline at end of file diff --git a/code/datums/spells/wizard.dm b/code/datums/spells/wizard.dm index 20323fc1f8a..a32bae29911 100644 --- a/code/datums/spells/wizard.dm +++ b/code/datums/spells/wizard.dm @@ -157,6 +157,20 @@ cast_sound = "sound/magic/ForceWall.ogg" +/obj/effect/proc_holder/spell/aoe_turf/conjure/timestop + name = "Stop Time" + desc = "This spell stops time for everyone except for you, allowing you to move freely while your enemies and even projectiles are frozen." + charge_max = 300 + clothes_req = 1 + invocation = "TOKI WO TOMARE" + invocation_type = "shout" + range = 0 + cooldown_min = 90 + summon_amt = 1 + action_icon_state = "time" + + summon_type = list(/obj/effect/timestop/wizard) + /obj/effect/proc_holder/spell/aoe_turf/conjure/carp name = "Summon Carp" desc = "This spell conjures a simple carp." @@ -319,4 +333,4 @@ var/mob/living/M = AM M.Weaken(2) M << "You're thrown back by a mystical force!" - spawn(0) AM.throw_at(throwtarget, ((Clamp((maxthrow - (Clamp(distfromcaster - 2, 0, distfromcaster))), 3, maxthrow))), 1,user)//So stuff gets tossed around at the same time. \ No newline at end of file + spawn(0) AM.throw_at(throwtarget, ((Clamp((maxthrow - (Clamp(distfromcaster - 2, 0, distfromcaster))), 3, maxthrow))), 1,user)//So stuff gets tossed around at the same time. diff --git a/code/datums/uplink_item.dm b/code/datums/uplink_item.dm index bf0d8a5f190..bf1edc9c372 100644 --- a/code/datums/uplink_item.dm +++ b/code/datums/uplink_item.dm @@ -303,10 +303,10 @@ var/list/uplink_items = list() cost = 2 gamemodes = list(/datum/game_mode/nuclear) -/datum/uplink_item/ammo/bulltoxin - name = "Drum Magazine - 12g Bioterror" - desc = "An alternative 8-round toxic magazine for use in the Bulldog shotgun. Contains debilitating toxins to make your target die an excruciatingly rapid death." - item = /obj/item/ammo_box/magazine/m12g/bioterror +/datum/uplink_item/ammo/bioterror + name = "Box of Bioterror Syringes" + desc = "A box full of preloaded syringes, containing various chemicals that seize up the victim's motor and broca system , making it impossible for them to move or speak while in their system." + item = /obj/item/weapon/storage/box/syndie_kit/bioterror cost = 6 gamemodes = list(/datum/game_mode/nuclear) @@ -353,12 +353,6 @@ var/list/uplink_items = list() cost = 6 excludefrom = list(/datum/game_mode/nuclear) -/datum/uplink_item/stealthy_weapons/edagger - name = "Energy Dagger" - desc = "A dagger made of energy that looks and functions as a pen when off." - item = /obj/item/weapon/pen/edagger - cost = 3 - /datum/uplink_item/stealthy_weapons/foampistol name = "Toy Gun (with Stun Darts)" desc = "An innocent-looking toy pistol designed to fire foam darts. Comes loaded with riot-grade darts, to incapacitate a target." diff --git a/code/game/gamemodes/changeling/changeling.dm b/code/game/gamemodes/changeling/changeling.dm index d93712c1831..47ca5efc699 100644 --- a/code/game/gamemodes/changeling/changeling.dm +++ b/code/game/gamemodes/changeling/changeling.dm @@ -82,8 +82,10 @@ var/list/slot2type = list("head" = /obj/item/clothing/head/changeling, "wear_mas //And then set it up to be handed out in forge_changeling_objectives var/list/team_objectives = typesof(/datum/objective/changeling_team_objective) - /datum/objective/changeling_team_objective var/list/possible_team_objectives = list() - for(var/datum/objective/changeling_team_objective/T in team_objectives) - if(changelings.len >= initial(T.min_lings)) + for(var/T in team_objectives) + var/datum/objective/changeling_team_objective/CTO = T + + if(changelings.len >= initial(CTO.min_lings)) possible_team_objectives += T if(possible_team_objectives.len && prob(20*changelings.len)) @@ -114,6 +116,14 @@ var/list/slot2type = list("head" = /obj/item/clothing/head/changeling, "wear_mas //No escape alone because changelings aren't suited for it and it'd probably just lead to rampant robusting //If it seems like they'd be able to do it in play, add a 10% chance to have to escape alone + var/escape_objective_possible = TRUE + + //if there's a team objective, check if it's compatible with escape objectives + for(var/datum/objective/changeling_team_objective/CTO in changeling.objectives) + if(!CTO.escape_objective_compatible) + escape_objective_possible = FALSE + break + var/datum/objective/absorb/absorb_objective = new absorb_objective.owner = changeling absorb_objective.gen_amount_goal(6, 8) @@ -149,14 +159,15 @@ var/list/slot2type = list("head" = /obj/item/clothing/head/changeling, "wear_mas maroon_objective.find_target() changeling.objectives += maroon_objective - if (!(locate(/datum/objective/escape) in changeling.objectives)) + if (!(locate(/datum/objective/escape) in changeling.objectives) && escape_objective_possible) var/datum/objective/escape/escape_with_identity/identity_theft = new identity_theft.owner = changeling identity_theft.target = maroon_objective.target identity_theft.update_explanation_text() changeling.objectives += identity_theft + escape_objective_possible = FALSE - if (!(locate(/datum/objective/escape) in changeling.objectives)) + if (!(locate(/datum/objective/escape) in changeling.objectives) && escape_objective_possible) if(prob(50)) var/datum/objective/escape/escape_objective = new escape_objective.owner = changeling @@ -164,8 +175,12 @@ var/list/slot2type = list("head" = /obj/item/clothing/head/changeling, "wear_mas else var/datum/objective/escape/escape_with_identity/identity_theft = new identity_theft.owner = changeling - identity_theft.find_target() + if(team_mode) + identity_theft.find_target_by_role(role = "Changeling", role_type = 1, invert = 1) + else + identity_theft.find_target() changeling.objectives += identity_theft + escape_objective_possible = FALSE @@ -265,7 +280,7 @@ var/list/slot2type = list("head" = /obj/item/clothing/head/changeling, "wear_mas //var/list/absorbed_dna = list() //var/list/protected_dna = list() //dna that is not lost when capacity is otherwise full var/dna_max = 6 //How many extra DNA strands the changeling can store for transformation. - var/absorbedcount = 1 //We would require at least 1 sample of compatible DNA to have taken on the form of a human. + var/absorbedcount = 0 var/chem_charges = 20 var/chem_storage = 75 var/chem_recharge_rate = 1 @@ -349,7 +364,7 @@ var/list/slot2type = list("head" = /obj/item/clothing/head/changeling, "wear_mas prof.dna = new_dna prof.name = H.real_name prof.protected = protect - + var/list/slots = list("head", "wear_mask", "back", "wear_suit", "w_uniform", "shoes", "belt", "gloves", "glasses", "ears", "wear_id", "s_store") for(var/slot in slots) var/obj/item/I = H.vars[slot] @@ -363,6 +378,7 @@ var/list/slot2type = list("head" = /obj/item/clothing/head/changeling, "wear_mas prof.exists_list[slot] = 1 stored_profiles += prof + absorbedcount++ return prof @@ -425,7 +441,7 @@ var/list/slot2type = list("head" = /obj/item/clothing/head/changeling, "wear_mas /datum/changelingprofile var/name = "a bug" - + var/protected = 0 var/datum/dna/dna = null @@ -435,6 +451,6 @@ var/list/slot2type = list("head" = /obj/item/clothing/head/changeling, "wear_mas var/list/exists_list = list() var/list/item_color_list = list() var/list/item_state_list = list() - + /datum/changelingprofile/Destroy() qdel(dna) diff --git a/code/game/gamemodes/objective.dm b/code/game/gamemodes/objective.dm index 17f812ccf89..fa97aea7600 100644 --- a/code/game/gamemodes/objective.dm +++ b/code/game/gamemodes/objective.dm @@ -68,7 +68,7 @@ /datum/objective/assassinate/find_target_by_role(role, role_type=0, invert=0) if(!invert) target_role_type = role_type - ..(role, role_type) + ..() return target /datum/objective/assassinate/check_completion() @@ -93,7 +93,7 @@ /datum/objective/mutiny/find_target_by_role(role, role_type=0,invert=0) if(!invert) target_role_type = role_type - ..(role, role_type) + ..() return target /datum/objective/mutiny/check_completion() @@ -123,7 +123,7 @@ /datum/objective/maroon/find_target_by_role(role, role_type=0, invert=0) if(!invert) target_role_type = role_type - ..(role, role_type) + ..() return target /datum/objective/maroon/check_completion() @@ -149,7 +149,7 @@ /datum/objective/debrain/find_target_by_role(role, role_type=0, invert=0) if(!invert) target_role_type = role_type - ..(role, role_type) + ..() return target /datum/objective/debrain/check_completion() @@ -183,7 +183,7 @@ /datum/objective/protect/find_target_by_role(role, role_type=0, invert=0) if(!invert) target_role_type = role_type - ..(role, role_type) + ..() return target /datum/objective/protect/check_completion() @@ -668,7 +668,7 @@ var/global/list/possible_items_special = list() martyr_compatible = 0 //Suicide is not teamwork! explanation_text = "Changeling Friendship!" var/min_lings = 3 //Minimum amount of lings for this team objective to be possible - + var/escape_objective_compatible = FALSE //Impersonate department @@ -701,13 +701,18 @@ var/global/list/possible_items_special = list() var/ling_count = ticker.mode.changelings for(var/datum/mind/M in ticker.minds) - if(department_head in M.assigned_job.department_head) + if(M in ticker.mode.changelings) + continue + if(department_head in get_department_heads(M.assigned_role)) if(ling_count) ling_count-- department_minds += M department_real_names += M.current.real_name + else + break if(!department_minds.len) + log_game("[type] has failed to find department staff, and has removed itself. the round will continue normally") owner.objectives -= src qdel(src) return @@ -724,16 +729,19 @@ var/global/list/possible_items_special = list() var/needed_heads = rand(min_lings,command_positions.len) needed_heads = min(ticker.mode.changelings.len,needed_heads) - for(var/datum/mind/possible_head in ticker.minds) - if(possible_head in ticker.mode.changelings) //Looking at you HoP. + var/list/heads = ticker.mode.get_living_heads() + for(var/datum/mind/head in heads) + if(head in ticker.mode.changelings) //Looking at you HoP. continue - if(possible_head.assigned_job.title in command_positions) - if(needed_heads) - department_minds += possible_head - department_real_names += possible_head.current.real_name - needed_heads-- + if(needed_heads) + department_minds += head + department_real_names += head.current.real_name + needed_heads-- + else + break if(!department_minds.len) + log_game("[type] has failed to find department heads, and has removed itself. the round will continue normally") owner.objectives -= src qdel(src) return @@ -783,6 +791,9 @@ var/global/list/possible_items_special = list() //Check each department member's mind to see if any of them made it to centcomm alive, if they did it's an automatic fail for(var/datum/mind/M in department_minds) + if(M in ticker.mode.changelings) //Lings aren't picked for this, but let's be safe + continue + if(M.current) var/turf/mloc = get_turf(M.current) if(mloc.onCentcom() && (M.current.stat != DEAD)) diff --git a/code/game/gamemodes/wizard/spellbook.dm b/code/game/gamemodes/wizard/spellbook.dm index eec319a8fba..4ae18618855 100644 --- a/code/game/gamemodes/wizard/spellbook.dm +++ b/code/game/gamemodes/wizard/spellbook.dm @@ -119,6 +119,11 @@ spell_type = /obj/effect/proc_holder/spell/aoe_turf/repulse log_name = "RP" +/datum/spellbook_entry/timestop + name = "Time Stop" + spell_type = /obj/effect/proc_holder/spell/aoe_turf/conjure/timestop + log_name = "TS" + /datum/spellbook_entry/smoke name = "Smoke" spell_type = /obj/effect/proc_holder/spell/targeted/smoke diff --git a/code/game/jobs/jobs.dm b/code/game/jobs/jobs.dm index 9bcc58643d7..e47d66df179 100644 --- a/code/game/jobs/jobs.dm +++ b/code/game/jobs/jobs.dm @@ -125,3 +125,15 @@ var/list/nonhuman_positions = list( /proc/guest_jobbans(job) return ((job in command_positions) || (job in nonhuman_positions) || (job in security_positions)) + + + +//this is necessary because antags happen before job datums are handed out, but NOT before they come into existence +//so I can't simply use job datum.department_head straight from the mind datum, laaaaame. +/proc/get_department_heads(var/job_title) + if(!job_title) + return list() + + for(var/datum/job/J in SSjob.occupations) + if(J.title == job_title) + return J.department_head //this is a list \ No newline at end of file diff --git a/code/game/objects/items/weapons/storage/uplink_kits.dm b/code/game/objects/items/weapons/storage/uplink_kits.dm index 6b41ed26f70..dc3d34b95f4 100644 --- a/code/game/objects/items/weapons/storage/uplink_kits.dm +++ b/code/game/objects/items/weapons/storage/uplink_kits.dm @@ -137,6 +137,20 @@ O.update_icon() return +/obj/item/weapon/storage/box/syndie_kit/bioterror + name = "bioterror syringe box" + +/obj/item/weapon/storage/box/syndie_kit/bioterror/New() + ..() + new /obj/item/weapon/reagent_containers/syringe/bioterror(src) + new /obj/item/weapon/reagent_containers/syringe/bioterror(src) + new /obj/item/weapon/reagent_containers/syringe/bioterror(src) + new /obj/item/weapon/reagent_containers/syringe/bioterror(src) + new /obj/item/weapon/reagent_containers/syringe/bioterror(src) + new /obj/item/weapon/reagent_containers/syringe/bioterror(src) + new /obj/item/weapon/reagent_containers/syringe/bioterror(src) + return + /obj/item/weapon/storage/box/syndie_kit/imp_adrenal name = "boxed adrenal implant (with injector)" diff --git a/code/modules/paperwork/pen.dm b/code/modules/paperwork/pen.dm index 9ba8bec513b..e1e38fc0ecf 100644 --- a/code/modules/paperwork/pen.dm +++ b/code/modules/paperwork/pen.dm @@ -80,7 +80,7 @@ reagents.add_reagent("morphine", 20) reagents.add_reagent("mutetoxin", 15) reagents.add_reagent("tirizene", 10) - ..() + ..() /* * (Alan) Edaggers @@ -119,4 +119,4 @@ item_state = "edagger" else icon_state = initial(icon_state) //looks like a normal pen when off. - item_state = initial(item_state) + item_state = initial(item_state) diff --git a/code/modules/projectiles/projectile/magic.dm b/code/modules/projectiles/projectile/magic.dm index bbe10e02af3..5c891b9fae0 100644 --- a/code/modules/projectiles/projectile/magic.dm +++ b/code/modules/projectiles/projectile/magic.dm @@ -243,7 +243,7 @@ new_mob << "Your form morphs into that of a [randomize]." - del(M) + qdel(M) return new_mob /obj/item/projectile/magic/animate diff --git a/code/modules/reagents/Chemistry-Recipes/Slime_extracts.dm b/code/modules/reagents/Chemistry-Recipes/Slime_extracts.dm index a0b76e0bad4..cd4da1f60d6 100644 --- a/code/modules/reagents/Chemistry-Recipes/Slime_extracts.dm +++ b/code/modules/reagents/Chemistry-Recipes/Slime_extracts.dm @@ -579,7 +579,7 @@ var/mob/mob = get_mob_by_key(holder.my_atom.fingerprintslast) var/obj/effect/timestop/T = new /obj/effect/timestop T.loc = get_turf(holder.my_atom) - T.immune = mob + T.immune += mob T.timestop() diff --git a/code/modules/reagents/reagent_containers/syringes.dm b/code/modules/reagents/reagent_containers/syringes.dm index 46b77827093..3bac3f14830 100644 --- a/code/modules/reagents/reagent_containers/syringes.dm +++ b/code/modules/reagents/reagent_containers/syringes.dm @@ -221,6 +221,11 @@ desc = "Contains antiviral agents." list_reagents = list("spaceacillin" = 15) +/obj/item/weapon/reagent_containers/syringe/bioterror + name = "bioterror syringe" + desc = "Contains several paralyzing reagents." + list_reagents = list("neurotoxin" = 5, "mutetoxin" = 5, "sodium_thiopental" = 5) + /obj/item/weapon/reagent_containers/syringe/stimulants name = "Stimpack" desc = "Contains stimulants." diff --git a/code/modules/research/xenobiology/xenobiology.dm b/code/modules/research/xenobiology/xenobiology.dm index 63ea9a0a6d3..68d65f28023 100644 --- a/code/modules/research/xenobiology/xenobiology.dm +++ b/code/modules/research/xenobiology/xenobiology.dm @@ -410,7 +410,7 @@ var/mob/living/carbon/human/G = new /mob/living/carbon/human if(prob(50)) G.gender = "female" hardset_dna(G, null, null, null, null, /datum/species/golem/adamantine) - + G.set_cloned_appearance() G.real_name = text("Adamantine Golem ([rand(1, 1000)])") G.dna.species.auto_equip(G) @@ -436,13 +436,16 @@ pixel_x = -64 pixel_y = -64 unacidable = 1 - var/mob/living/immune = null // the one who creates the timestop is immune + var/mob/living/immune = list() // the one who creates the timestop is immune var/freezerange = 2 var/duration = 140 alpha = 125 /obj/effect/timestop/New() ..() + for(var/mob/living/M in player_list) + for(var/obj/effect/proc_holder/spell/aoe_turf/conjure/timestop/T in M.mind.spell_list) //People who can stop time are immune to timestop + immune |= M timestop() @@ -451,7 +454,7 @@ while(loc) if(duration) for(var/mob/living/M in orange (freezerange, src.loc)) - if(M == immune) + if(M in immune) continue M.stunned = 10 M.anchored = 1 @@ -478,6 +481,9 @@ sleep(1) +/obj/effect/timestop/wizard + duration = 90 + /obj/item/stack/tile/bluespace name = "bluespace floor tile" diff --git a/html/changelog.html b/html/changelog.html index 65158d9c7e1..a38639667d7 100644 --- a/html/changelog.html +++ b/html/changelog.html @@ -59,6 +59,8 @@