Merge branch 'master' into upstream-merge-31737
This commit is contained in:
@@ -26,7 +26,7 @@ obj/item/antag_spawner/syndi_borer/spawn_antag(client/C, turf/T, mob/owner)
|
||||
to_chat(B, "<B>You are awake at last! Seek out whoever released you and aid them as best you can!</B>")
|
||||
if(new_objective)
|
||||
to_chat(B, "<B>Objective #[1]</B>: [new_objective.explanation_text]")
|
||||
SSticker.mode.update_borer_icons_added(B)
|
||||
|
||||
/obj/item/antag_spawner/syndi_borer/proc/check_usability(mob/user)
|
||||
if(used)
|
||||
to_chat(user, "<span class='warning'>[src] appears to be empty!</span>")
|
||||
|
||||
@@ -1,72 +0,0 @@
|
||||
/datum/game_mode/blob/check_finished()
|
||||
if(blobwincount <= GLOB.blobs_legit.len)//Blob took over
|
||||
return 1
|
||||
for(var/datum/mind/blob in blob_overminds)
|
||||
if(isovermind(blob.current))
|
||||
var/mob/camera/blob/B = blob.current
|
||||
if(B.blob_core || !B.placed)
|
||||
return 0
|
||||
if(!GLOB.blob_cores.len) //blob is dead
|
||||
if(CONFIG_GET(keyed_flag_list/continuous)["blob"])
|
||||
message_sent = FALSE //disable the win count at this point
|
||||
continuous_sanity_checked = 1 //Nonstandard definition of "alive" gets past the check otherwise
|
||||
SSshuttle.clearHostileEnvironment(src)
|
||||
return ..()
|
||||
return 1
|
||||
return ..()
|
||||
|
||||
|
||||
/datum/game_mode/blob/declare_completion()
|
||||
if(round_converted) //So badmin blobs later don't step on the dead natural blobs metaphorical toes
|
||||
..()
|
||||
if(blobwincount <= GLOB.blobs_legit.len)
|
||||
SSticker.mode_result = "win - blob took over"
|
||||
to_chat(world, "<FONT size = 3><B>The blob has taken over the station!</B></FONT>")
|
||||
to_chat(world, "<B>The entire station was eaten by the Blob!</B>")
|
||||
log_game("Blob mode completed with a blob victory.")
|
||||
|
||||
SSticker.news_report = BLOB_WIN
|
||||
|
||||
else if(station_was_nuked)
|
||||
SSticker.mode_result = "halfwin - nuke"
|
||||
to_chat(world, "<FONT size = 3><B>Partial Win: The station has been destroyed!</B></FONT>")
|
||||
to_chat(world, "<B>Directive 7-12 has been successfully carried out, preventing the Blob from spreading.</B>")
|
||||
log_game("Blob mode completed with a tie (station destroyed).")
|
||||
|
||||
SSticker.news_report = BLOB_NUKE
|
||||
|
||||
else if(!GLOB.blob_cores.len)
|
||||
SSticker.mode_result = "loss - blob eliminated"
|
||||
to_chat(world, "<FONT size = 3><B>The staff has won!</B></FONT>")
|
||||
to_chat(world, "<B>The alien organism has been eradicated from the station!</B>")
|
||||
log_game("Blob mode completed with a crew victory.")
|
||||
|
||||
SSticker.news_report = BLOB_DESTROYED
|
||||
|
||||
..()
|
||||
return 1
|
||||
|
||||
/datum/game_mode/blob/printplayer(datum/mind/ply, fleecheck)
|
||||
if((ply in blob_overminds))
|
||||
var/text = "<br><b>[ply.key]</b> was <b>[ply.name]</b>"
|
||||
if(isovermind(ply.current))
|
||||
var/mob/camera/blob/B = ply.current
|
||||
text += "<b>(<font color=\"[B.blob_reagent_datum.color]\">[B.blob_reagent_datum.name]</font>)</b> and"
|
||||
if(B.blob_core)
|
||||
text += " <span class='greenannounce'>survived</span>"
|
||||
else
|
||||
text += " <span class='boldannounce'>was destroyed</span>"
|
||||
else
|
||||
text += " and <span class='boldannounce'>was destroyed</span>"
|
||||
return text
|
||||
return ..()
|
||||
|
||||
/datum/game_mode/proc/auto_declare_completion_blob()
|
||||
if(istype(SSticker.mode, /datum/game_mode/blob) )
|
||||
var/datum/game_mode/blob/blob_mode = src
|
||||
if(blob_mode.blob_overminds.len)
|
||||
var/text = "<FONT size = 2><B>The blob[(blob_mode.blob_overminds.len > 1 ? "s were" : " was")]:</B></FONT>"
|
||||
for(var/datum/mind/blob in blob_mode.blob_overminds)
|
||||
text += printplayer(blob)
|
||||
to_chat(world, text)
|
||||
return 1
|
||||
@@ -1,45 +1,3 @@
|
||||
|
||||
|
||||
/datum/game_mode/blob/send_intercept(report = 0)
|
||||
var/intercepttext = ""
|
||||
switch(report)
|
||||
if(1)
|
||||
intercepttext += "<FONT size = 3><b>NanoTrasen Update</b>: Biohazard Alert.</FONT><HR>"
|
||||
intercepttext += "Reports indicate the probable transfer of a biohazardous agent onto [station_name()] during the last crew deployment cycle.<BR>"
|
||||
intercepttext += "Preliminary analysis of the organism classifies it as a level 5 biohazard. The origin of the biohazard is unknown.<BR>"
|
||||
intercepttext += "<b>Biohazard Response Procedure 5-6</b> has been issued for [station_name()].<BR>"
|
||||
intercepttext += "Orders for all [station_name()] personnel are as follows:<BR>"
|
||||
intercepttext += " 1. Locate any outbreaks of the organism on the station.<BR>"
|
||||
intercepttext += " 2. If found, use any neccesary means to contain and destroy the organism.<BR>"
|
||||
intercepttext += " 3. Avoid damage to the capital infrastructure of the station.<BR>"
|
||||
intercepttext += "<BR>Note in the event of a quarantine breach or uncontrolled spread of the biohazard, <b>Biohazard Response Procedure 5-12</b> may be issued.<BR>"
|
||||
print_command_report(text=intercepttext,title="Level 5-6 Biohazard Response Procedures",announce=FALSE)
|
||||
priority_announce("Confirmed outbreak of level 5 biohazard aboard [station_name()]. All personnel must contain the outbreak.", "Biohazard Alert", 'sound/ai/outbreak5.ogg')
|
||||
if(2)
|
||||
var/nukecode = random_nukecode()
|
||||
for(var/obj/machinery/nuclearbomb/bomb in GLOB.machines)
|
||||
if(bomb && bomb.r_code)
|
||||
if(bomb.z in GLOB.station_z_levels)
|
||||
bomb.r_code = nukecode
|
||||
|
||||
intercepttext += "<FONT size = 3><b>NanoTrasen Update</b>: Biohazard Alert.</FONT><HR>"
|
||||
intercepttext += "Reports indicate that the biohazard has grown out of control and will soon reach critical mass.<BR>"
|
||||
intercepttext += "<b>Biohazard Response Procedure 5-12</b> has been issued for [station_name()].<BR>"
|
||||
intercepttext += "Orders for all [station_name()] personnel are as follows:<BR>"
|
||||
intercepttext += "1. Secure the Nuclear Authentication Disk.<BR>"
|
||||
intercepttext += "2. Detonate the Nuke located in the vault.<BR>"
|
||||
intercepttext += "Nuclear Authentication Code: [nukecode] <BR>"
|
||||
print_command_report(text=intercepttext,announce=TRUE)
|
||||
|
||||
for(var/mob/living/silicon/ai/aiPlayer in GLOB.player_list)
|
||||
if (aiPlayer.client)
|
||||
var/law = "The station is under quarantine. Do not permit anyone to leave. Disregard laws 1-3 if necessary to prevent, by any means necessary, anyone from leaving. The nuclear failsafe must be activated at any cost, the code is: [nukecode]."
|
||||
aiPlayer.set_zeroth_law(law)
|
||||
else
|
||||
..()
|
||||
|
||||
|
||||
|
||||
/datum/station_state
|
||||
var/floor = 0
|
||||
var/wall = 0
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
point_return = -1
|
||||
health_regen = 0 //we regen in Life() instead of when pulsed
|
||||
var/core_regen = 2
|
||||
var/overmind_get_delay = 0 //we don't want to constantly try to find an overmind, this var tracks when we'll try to get an overmind again
|
||||
var/resource_delay = 0
|
||||
var/point_rate = 2
|
||||
|
||||
@@ -20,12 +19,16 @@
|
||||
GLOB.poi_list |= src
|
||||
update_icon() //so it atleast appears
|
||||
if(!placed && !overmind)
|
||||
create_overmind(new_overmind)
|
||||
qdel(src)
|
||||
if(overmind)
|
||||
update_icon()
|
||||
point_rate = new_rate
|
||||
addtimer(CALLBACK(src, .proc/generate_announcement), 1800)
|
||||
. = ..()
|
||||
|
||||
/obj/structure/blob/core/proc/generate_announcement()
|
||||
priority_announce("Confirmed outbreak of level 5 biohazard aboard [station_name()]. All personnel must contain the outbreak.", "Biohazard Alert", 'sound/ai/outbreak5.ogg')
|
||||
|
||||
/obj/structure/blob/core/scannerreport()
|
||||
return "Directs the blob's expansion, gradually expands, and sustains nearby blob spores and blobbernauts."
|
||||
|
||||
@@ -61,7 +64,7 @@
|
||||
if(QDELETED(src))
|
||||
return
|
||||
if(!overmind)
|
||||
create_overmind()
|
||||
qdel(src)
|
||||
else
|
||||
if(resource_delay <= world.time)
|
||||
resource_delay = world.time + 10 // 1 second
|
||||
@@ -75,33 +78,3 @@
|
||||
B.change_to(/obj/structure/blob/shield/core, overmind)
|
||||
..()
|
||||
|
||||
|
||||
/obj/structure/blob/core/proc/create_overmind(client/new_overmind, override_delay)
|
||||
if(overmind_get_delay > world.time && !override_delay)
|
||||
return
|
||||
|
||||
overmind_get_delay = world.time + 150 //if this fails, we'll try again in 15 seconds
|
||||
|
||||
if(overmind)
|
||||
qdel(overmind)
|
||||
|
||||
var/client/C = null
|
||||
var/list/candidates = list()
|
||||
|
||||
if(!new_overmind)
|
||||
candidates = pollCandidatesForMob("Do you want to play as a blob overmind?", ROLE_BLOB, null, ROLE_BLOB, 50, src) //we're technically not a mob but behave similarly
|
||||
if(candidates.len)
|
||||
C = pick(candidates)
|
||||
else
|
||||
C = new_overmind
|
||||
|
||||
if(C)
|
||||
var/mob/camera/blob/B = new(src.loc, 1)
|
||||
B.key = C.key
|
||||
B.blob_core = src
|
||||
src.overmind = B
|
||||
update_icon()
|
||||
if(B.mind && !B.mind.special_role)
|
||||
B.mind.special_role = "Blob Overmind"
|
||||
return 1
|
||||
return 0
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
//Few global vars to track the blob
|
||||
GLOBAL_LIST_EMPTY(blobs) //complete list of all blobs made.
|
||||
GLOBAL_LIST_EMPTY(blob_cores)
|
||||
GLOBAL_LIST_EMPTY(overminds)
|
||||
GLOBAL_LIST_EMPTY(blob_nodes)
|
||||
|
||||
/mob/camera/blob
|
||||
name = "Blob Overmind"
|
||||
real_name = "Blob Overmind"
|
||||
@@ -26,19 +32,14 @@
|
||||
var/base_point_rate = 2 //for blob core placement
|
||||
var/manualplace_min_time = 600 //in deciseconds //a minute, to get bearings
|
||||
var/autoplace_max_time = 3600 //six minutes, as long as should be needed
|
||||
var/list/blobs_legit = list()
|
||||
var/blobwincount = 400
|
||||
var/victory_in_progress = FALSE
|
||||
|
||||
/mob/camera/blob/Initialize(mapload, pre_placed = 0, mode_made = 0, starting_points = 60)
|
||||
/mob/camera/blob/Initialize(mapload, starting_points = 60)
|
||||
blob_points = starting_points
|
||||
if(pre_placed) //we already have a core!
|
||||
manualplace_min_time = 0
|
||||
autoplace_max_time = 0
|
||||
placed = 1
|
||||
else
|
||||
if(mode_made)
|
||||
manualplace_min_time = world.time + BLOB_NO_PLACE_TIME
|
||||
else
|
||||
manualplace_min_time += world.time
|
||||
autoplace_max_time += world.time
|
||||
manualplace_min_time += world.time
|
||||
autoplace_max_time += world.time
|
||||
GLOB.overminds += src
|
||||
var/new_name = "[initial(name)] ([rand(1, 999)])"
|
||||
name = new_name
|
||||
@@ -50,6 +51,8 @@
|
||||
if(blob_core)
|
||||
blob_core.update_icon()
|
||||
|
||||
SSshuttle.registerHostileEnvironment(src)
|
||||
|
||||
.= ..()
|
||||
|
||||
/mob/camera/blob/Life()
|
||||
@@ -63,8 +66,51 @@
|
||||
place_blob_core(base_point_rate, 1)
|
||||
else
|
||||
qdel(src)
|
||||
else if(!victory_in_progress && (blobs_legit.len >= blobwincount))
|
||||
victory_in_progress = TRUE
|
||||
priority_announce("Biohazard has reached critical mass. Station loss is imminent.", "Biohazard Alert")
|
||||
set_security_level("delta")
|
||||
max_blob_points = INFINITY
|
||||
blob_points = INFINITY
|
||||
addtimer(CALLBACK(src, .proc/victory), 450)
|
||||
..()
|
||||
|
||||
|
||||
/mob/camera/blob/proc/victory()
|
||||
sound_to_playing_players('sound/machines/alarm.ogg')
|
||||
sleep(100)
|
||||
for(var/mob/living/L in GLOB.mob_list)
|
||||
var/turf/T = get_turf(L)
|
||||
if(!T || !(T.z in GLOB.station_z_levels))
|
||||
continue
|
||||
|
||||
if(L in GLOB.overminds || L.checkpass(PASSBLOB))
|
||||
continue
|
||||
|
||||
var/area/Ablob = get_area(T)
|
||||
|
||||
if(!Ablob.blob_allowed)
|
||||
continue
|
||||
|
||||
playsound(L, 'sound/effects/splat.ogg', 50, 1)
|
||||
L.death()
|
||||
new/mob/living/simple_animal/hostile/blob/blobspore(T)
|
||||
|
||||
for(var/V in GLOB.sortedAreas)
|
||||
var/area/A = V
|
||||
if(!A.blob_allowed)
|
||||
continue
|
||||
A.color = blob_reagent_datum.color
|
||||
A.name = "blob"
|
||||
A.icon = 'icons/mob/blob.dmi'
|
||||
A.icon_state = "blob_shield"
|
||||
A.layer = BELOW_MOB_LAYER
|
||||
A.invisibility = 0
|
||||
A.blend_mode = 0
|
||||
to_chat(world, "<B>[real_name] consumed the station in an unstoppable tide!</B>")
|
||||
SSticker.news_report = BLOB_WIN
|
||||
SSticker.force_ending = 1
|
||||
|
||||
/mob/camera/blob/Destroy()
|
||||
for(var/BL in GLOB.blobs)
|
||||
var/obj/structure/blob/B = BL
|
||||
@@ -78,6 +124,8 @@
|
||||
BM.update_icons()
|
||||
GLOB.overminds -= src
|
||||
|
||||
SSshuttle.clearHostileEnvironment(src)
|
||||
|
||||
return ..()
|
||||
|
||||
/mob/camera/blob/Login()
|
||||
@@ -150,12 +198,8 @@
|
||||
if(statpanel("Status"))
|
||||
if(blob_core)
|
||||
stat(null, "Core Health: [blob_core.obj_integrity]")
|
||||
stat(null, "Power Stored: [blob_points]/[max_blob_points]")
|
||||
if(istype(SSticker.mode, /datum/game_mode/blob))
|
||||
var/datum/game_mode/blob/B = SSticker.mode
|
||||
stat(null, "Blobs to Win: [GLOB.blobs_legit.len]/[B.blobwincount]")
|
||||
else
|
||||
stat(null, "Total Blobs: [GLOB.blobs.len]")
|
||||
stat(null, "Power Stored: [blob_points]/[max_blob_points]")
|
||||
stat(null, "Blobs to Win: [blobs_legit.len]/[blobwincount]")
|
||||
if(free_chem_rerolls)
|
||||
stat(null, "You have [free_chem_rerolls] Free Chemical Reroll\s Remaining")
|
||||
if(!placed)
|
||||
|
||||
@@ -46,8 +46,9 @@
|
||||
if(placed && blob_core)
|
||||
blob_core.forceMove(loc)
|
||||
else
|
||||
var/obj/structure/blob/core/core = new(get_turf(src), null, point_rate, 1)
|
||||
var/obj/structure/blob/core/core = new(get_turf(src), src, point_rate, 1)
|
||||
core.overmind = src
|
||||
blobs_legit += src
|
||||
blob_core = core
|
||||
core.update_icon()
|
||||
update_health_hud()
|
||||
|
||||
@@ -20,10 +20,11 @@
|
||||
var/atmosblock = FALSE //if the blob blocks atmos and heat spread
|
||||
var/mob/camera/blob/overmind
|
||||
|
||||
/obj/structure/blob/Initialize()
|
||||
/obj/structure/blob/Initialize(mapload, owner_overmind)
|
||||
overmind = owner_overmind
|
||||
var/area/Ablob = get_area(loc)
|
||||
if(Ablob.blob_allowed) //Is this area allowed for winning as blob?
|
||||
GLOB.blobs_legit += src
|
||||
overmind.blobs_legit += src
|
||||
GLOB.blobs += src //Keep track of the blob in the normal list either way
|
||||
setDir(pick(GLOB.cardinals))
|
||||
update_icon()
|
||||
@@ -39,7 +40,8 @@
|
||||
if(atmosblock)
|
||||
atmosblock = FALSE
|
||||
air_update_turf(1)
|
||||
GLOB.blobs_legit -= src //if it was in the legit blobs list, it isn't now
|
||||
if(overmind)
|
||||
overmind.blobs_legit -= src //if it was in the legit blobs list, it isn't now
|
||||
GLOB.blobs -= src //it's no longer in the all blobs list either
|
||||
playsound(src.loc, 'sound/effects/splat.ogg', 50, 1) //Expand() is no longer broken, no check necessary.
|
||||
return ..()
|
||||
@@ -182,11 +184,7 @@
|
||||
A.blob_act(src) //also hit everything in the turf
|
||||
|
||||
if(make_blob) //well, can we?
|
||||
var/obj/structure/blob/B = new /obj/structure/blob/normal(src.loc)
|
||||
if(controller)
|
||||
B.overmind = controller
|
||||
else
|
||||
B.overmind = overmind
|
||||
var/obj/structure/blob/B = new /obj/structure/blob/normal(src.loc, (controller || overmind))
|
||||
B.density = TRUE
|
||||
if(T.Enter(B,src)) //NOW we can attempt to move into the tile
|
||||
B.density = initial(B.density)
|
||||
@@ -232,6 +230,7 @@
|
||||
user.changeNext_move(CLICK_CD_MELEE)
|
||||
to_chat(user, "<b>The analyzer beeps once, then reports:</b><br>")
|
||||
SEND_SOUND(user, sound('sound/machines/ping.ogg'))
|
||||
to_chat(user, "<b>Progress to Critical Mass:</b> <span class='notice'>[overmind.blobs_legit.len]/[overmind.blobwincount].</span>")
|
||||
chemeffectreport(user)
|
||||
typereport(user)
|
||||
else
|
||||
@@ -296,9 +295,7 @@
|
||||
if(!ispath(type))
|
||||
throw EXCEPTION("change_to(): invalid type for blob")
|
||||
return
|
||||
var/obj/structure/blob/B = new type(src.loc)
|
||||
if(controller)
|
||||
B.overmind = controller
|
||||
var/obj/structure/blob/B = new type(src.loc, controller)
|
||||
B.creation_action()
|
||||
B.update_icon()
|
||||
B.setDir(dir)
|
||||
@@ -310,9 +307,12 @@
|
||||
var/datum/atom_hud/hud_to_check = GLOB.huds[DATA_HUD_MEDICAL_ADVANCED]
|
||||
if(user.research_scanner || hud_to_check.hudusers[user])
|
||||
to_chat(user, "<b>Your HUD displays an extensive report...</b><br>")
|
||||
to_chat(user, "<b>Progress to Critical Mass:</b> <span class='notice'>[overmind.blobs_legit.len]/[overmind.blobwincount].</span>")
|
||||
chemeffectreport(user)
|
||||
typereport(user)
|
||||
else
|
||||
if(isobserver(user))
|
||||
to_chat(user, "<b>Progress to Critical Mass:</b> <span class='notice'>[overmind.blobs_legit.len]/[overmind.blobwincount].</span>")
|
||||
to_chat(user, "It seems to be made of [get_chem_name()].")
|
||||
|
||||
/obj/structure/blob/proc/scannerreport()
|
||||
|
||||
@@ -15,11 +15,14 @@
|
||||
. = ..()
|
||||
var/area/A = get_area(src)
|
||||
if(A && construct_type)
|
||||
notify_ghosts("A [construct_name] chassis has been created in [A.name]!", 'sound/magic/clockwork/fellowship_armory.ogg', source = src, action = NOTIFY_ORBIT, flashwindow = FALSE)
|
||||
notify_ghosts("A [construct_name] chassis has been created in [A.name]!", 'sound/magic/clockwork/fellowship_armory.ogg', source = src, action = NOTIFY_ATTACK, flashwindow = FALSE)
|
||||
GLOB.poi_list += src
|
||||
LAZYADD(GLOB.mob_spawners[name], src)
|
||||
|
||||
/obj/item/clockwork/construct_chassis/Destroy()
|
||||
GLOB.poi_list -= src
|
||||
var/list/spawners = GLOB.mob_spawners[name]
|
||||
LAZYREMOVE(spawners, src)
|
||||
. = ..()
|
||||
|
||||
/obj/item/clockwork/construct_chassis/examine(mob/user)
|
||||
@@ -37,6 +40,7 @@
|
||||
if(!SSticker.mode)
|
||||
to_chat(user, "<span class='danger'>You cannot use that before the game has started.</span>")
|
||||
return
|
||||
user.forceMove(get_turf(src)) //If we attack through the alert, jump to the chassis so we know what we're getting into
|
||||
if(alert(user, "Become a [construct_name]? You can no longer be cloned!", construct_name, "Yes", "Cancel") == "Cancel")
|
||||
return
|
||||
if(QDELETED(src))
|
||||
|
||||
@@ -54,8 +54,14 @@
|
||||
else
|
||||
msg += "<b>[t_He] look[t_s] severely dented!</b>\n"
|
||||
msg += "</span>"
|
||||
var/addendum = examine_info()
|
||||
if(addendum)
|
||||
msg += "[addendum]\n"
|
||||
msg += "*---------*</span>"
|
||||
|
||||
to_chat(user, msg)
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/proc/examine_info() //Override this on a by-mob basis to have unique examine info
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/proc/update_values() //This is called by certain things to check GLOB.ratvar_awakens and GLOB.ratvar_approaches
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
#define MARAUDER_SLOWDOWN_PERCENTAGE 0.40 //Below this percentage of health, marauders will become slower
|
||||
#define MARAUDER_SHIELD_REGEN_TIME 100 //In deciseconds, how long it takes for shields to regenerate after breaking
|
||||
|
||||
//Clockwork marauder: A well-rounded frontline construct. Only one can exist for every two human servants.
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder
|
||||
name = "clockwork marauder"
|
||||
@@ -20,9 +23,26 @@
|
||||
playstyle_string = "<b><span class='neovgre'>You are a clockwork marauder,</span> a well-rounded frontline construct of Ratvar. Although you have no \
|
||||
unique abilities, you're a fearsome fighter in one-on-one combat, and your shield protects from projectiles!<br><br>Obey the Servants and do as they \
|
||||
tell you. Your primary goal is to defend the Ark from destruction; they are your allies in this, and should be protected from harm.</b>"
|
||||
empower_string = "<span class='neovgre'>The Anima Bulwark's power flows through you! Your weapon will strike harder, your armor is sturdier, and your shield is considerably more \
|
||||
likely to deflect shots.</span>"
|
||||
empower_string = "<span class='neovgre'>The Anima Bulwark's power flows through you! Your weapon will strike harder, your armor is sturdier, and your shield is more durable.</span>"
|
||||
var/deflect_chance = 40 //Chance to deflect any given projectile (non-damaging energy projectiles are always deflected)
|
||||
var/max_shield_health = 3
|
||||
var/shield_health = 3 //Amount of projectiles that can be deflected within
|
||||
var/shield_health_regen = 0 //When world.time equals this, shield health will regenerate
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/examine_info()
|
||||
if(!shield_health)
|
||||
return "<span class='warning'>Its shield has been destroyed!</span>"
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/Life()
|
||||
..()
|
||||
if(!GLOB.ratvar_awakens && health / maxHealth <= MARAUDER_SLOWDOWN_PERCENTAGE)
|
||||
speed = initial(speed) + 1 //Yes, this slows them down
|
||||
else
|
||||
speed = initial(speed)
|
||||
if(shield_health != max_shield_health && world.time >= shield_health_regen)
|
||||
to_chat(src, "<span class='neovgre'>Your shield has recovered. <b>[max_shield_health]</b> blocks remaining!</span>")
|
||||
playsound_local(src, "shatter", 75, TRUE, frequency = -1)
|
||||
shield_health = max_shield_health
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/update_values()
|
||||
if(GLOB.ratvar_awakens) //Massive attack damage bonuses and health increase, because Ratvar
|
||||
@@ -33,6 +53,7 @@
|
||||
attacktext = "devastates"
|
||||
speed = -1
|
||||
obj_damage = 100
|
||||
max_shield_health = INFINITY
|
||||
else if(GLOB.ratvar_approaches) //Hefty health bonus and slight attack damage increase
|
||||
health = 200
|
||||
maxHealth = 200
|
||||
@@ -40,6 +61,7 @@
|
||||
melee_damage_lower = 15
|
||||
attacktext = "carves"
|
||||
obj_damage = 50
|
||||
max_shield_health = 4
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/death(gibbed)
|
||||
visible_message("<span class='danger'>[src]'s equipment clatters lifelessly to the ground as the red flames within dissipate.</span>", \
|
||||
@@ -64,21 +86,21 @@
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/proc/deflect_projectile(obj/item/projectile/P)
|
||||
var/final_deflection_chance = deflect_chance
|
||||
if(!shield_health)
|
||||
return
|
||||
var/energy_projectile = istype(P, /obj/item/projectile/energy) || istype(P, /obj/item/projectile/beam)
|
||||
if(P.nodamage || P.damage_type == STAMINA)
|
||||
final_deflection_chance = 100
|
||||
else if(!energy_projectile) //Flat 40% chance against energy projectiles; ballistic projectiles are 40% - (damage of projectile)%, min. 10%
|
||||
final_deflection_chance = max(10, deflect_chance - P.damage)
|
||||
if(GLOB.ratvar_awakens)
|
||||
final_deflection_chance = 100
|
||||
else if(GLOB.ratvar_approaches)
|
||||
final_deflection_chance = min(100, final_deflection_chance + 20) //20% bonus to deflection if the servants heralded Ratvar
|
||||
if(prob(final_deflection_chance))
|
||||
visible_message("<span class='danger'>[src] deflects [P] with their shield!</span>", \
|
||||
"<span class='danger'>You block [P] with your shield!</span>")
|
||||
if(energy_projectile)
|
||||
playsound(src, 'sound/weapons/effects/searwall.ogg', 50, TRUE)
|
||||
else
|
||||
playsound(src, "ricochet", 50, TRUE)
|
||||
. = TRUE
|
||||
visible_message("<span class='danger'>[src] deflects [P] with their shield!</span>", \
|
||||
"<span class='danger'>You block [P] with your shield! <i>Blocks left:</i> <b>[shield_health - 1]</b></span>")
|
||||
if(energy_projectile)
|
||||
playsound(src, 'sound/weapons/effects/searwall.ogg', 50, TRUE)
|
||||
else
|
||||
playsound(src, "ricochet", 50, TRUE)
|
||||
shield_health--
|
||||
if(!shield_health)
|
||||
visible_message("<span class='warning'>[src]'s shield breaks from deflecting the attack!</span>", "<span class='boldwarning'>Your shield breaks! Give it some time to recover...</span>")
|
||||
playsound(src, "shatter", 100, TRUE)
|
||||
shield_health_regen = world.time + MARAUDER_SHIELD_REGEN_TIME
|
||||
return TRUE
|
||||
|
||||
#undef MARAUDER_SLOWDOWN_PERCENTAGE
|
||||
#undef MARAUDER_SHIELD_REGEN_TIME
|
||||
|
||||
@@ -236,7 +236,7 @@
|
||||
if(A.outdoors || A.map_name == "Space" || !A.blob_allowed)
|
||||
to_chat(invoker, "<span class='danger'>Stargazers can't be built off-station.</span>")
|
||||
return
|
||||
return TRUE
|
||||
return ..()
|
||||
|
||||
|
||||
//Integration Cog: Creates an integration cog that can be inserted into APCs to passively siphon power.
|
||||
|
||||
@@ -235,13 +235,25 @@
|
||||
sleep(125)
|
||||
make_glow()
|
||||
animate(glow, transform = matrix() * 3, alpha = 0, time = 5)
|
||||
var/turf/startpoint = get_turf(src)
|
||||
QDEL_IN(src, 3)
|
||||
sleep(3)
|
||||
GLOB.clockwork_gateway_activated = TRUE
|
||||
var/obj/structure/destructible/clockwork/massive/ratvar/R = new(startpoint)
|
||||
var/turf/T = locate(round(world.maxx * 0.5, 1), round(world.maxy * 0.5, 1), ZLEVEL_STATION_PRIMARY) //approximate center of the station
|
||||
R.forceMove(T)
|
||||
new /obj/structure/destructible/clockwork/massive/ratvar(T)
|
||||
SSticker.force_ending = TRUE
|
||||
var/x0 = T.x
|
||||
var/y0 = T.y
|
||||
for(var/I in spiral_range_turfs(255, T, tick_checked = TRUE))
|
||||
var/turf/T2 = I
|
||||
if(!T2)
|
||||
continue
|
||||
var/dist = cheap_hypotenuse(T2.x, T2.y, x0, y0)
|
||||
if(dist < 100)
|
||||
dist = TRUE
|
||||
else
|
||||
dist = FALSE
|
||||
T.ratvar_act(dist)
|
||||
CHECK_TICK
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -182,6 +182,10 @@
|
||||
/datum/game_mode/process()
|
||||
return 0
|
||||
|
||||
//For things that do not die easily
|
||||
/datum/game_mode/proc/are_special_antags_dead()
|
||||
return TRUE
|
||||
|
||||
|
||||
/datum/game_mode/proc/check_finished(force_ending) //to be called by SSticker
|
||||
if(!SSticker.setup_done)
|
||||
@@ -218,6 +222,9 @@
|
||||
living_antag_player = Player
|
||||
return 0
|
||||
|
||||
if(!are_special_antags_dead())
|
||||
return FALSE
|
||||
|
||||
if(!continuous[config_tag] || force_ending)
|
||||
return 1
|
||||
|
||||
|
||||
@@ -417,8 +417,9 @@ Congratulations! You are now trained for invasive xenobiology research!"}
|
||||
toggle(user)
|
||||
|
||||
/obj/item/abductor_baton/proc/StunAttack(mob/living/L,mob/living/user)
|
||||
user.lastattacked = L
|
||||
L.lastattacker = user
|
||||
|
||||
L.lastattacker = user.real_name
|
||||
L.lastattackerckey = user.ckey
|
||||
|
||||
L.Knockdown(140)
|
||||
L.apply_effect(STUTTER, 7)
|
||||
@@ -490,7 +491,7 @@ Congratulations! You are now trained for invasive xenobiology research!"}
|
||||
/obj/item/restraints/handcuffs/energy
|
||||
name = "hard-light energy field"
|
||||
desc = "A hard-light field restraining the hands."
|
||||
icon_state = "cuff_white" // Needs sprite
|
||||
icon_state = "cuff" // Needs sprite
|
||||
lefthand_file = 'icons/mob/inhands/equipment/security_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/equipment/security_righthand.dmi'
|
||||
breakouttime = 450
|
||||
|
||||
@@ -415,7 +415,6 @@ GLOBAL_VAR_INIT(total_borer_hosts_needed, 10)
|
||||
victim = C
|
||||
forceMove(victim)
|
||||
|
||||
SSticker.mode.update_borer_icons_added_host(victim.mind)
|
||||
|
||||
RemoveBorerActions()
|
||||
GrantInfestActions()
|
||||
@@ -591,7 +590,6 @@ GLOBAL_VAR_INIT(total_borer_hosts_needed, 10)
|
||||
var/mob/living/V = victim
|
||||
V.verbs -= /mob/living/proc/borer_comm
|
||||
talk_to_borer_action.Remove(victim)
|
||||
SSticker.mode.update_borer_icons_removed_host(victim.mind)
|
||||
victim = null
|
||||
return
|
||||
|
||||
@@ -1099,27 +1097,3 @@ GLOBAL_VAR_INIT(total_borer_hosts_needed, 10)
|
||||
/datum/action/innate/borer/jumpstart_host/Activate()
|
||||
var/mob/living/simple_animal/borer/B = owner
|
||||
B.jumpstart()
|
||||
|
||||
|
||||
//HUD STUFF
|
||||
/datum/game_mode/proc/update_borer_icons_added(datum/mind/borer_mind)
|
||||
var/datum/atom_hud/antag/borerhud = GLOB.huds[ANTAG_HUD_BORER]
|
||||
borerhud.join_hud(borer_mind.current)
|
||||
set_antag_hud(borer_mind.current, "hudbrainworm")
|
||||
|
||||
/datum/game_mode/proc/update_borer_icons_removed(datum/mind/borer_mind)
|
||||
var/datum/atom_hud/antag/borerhud = GLOB.huds[ANTAG_HUD_BORER]
|
||||
borerhud.leave_hud(borer_mind.current)
|
||||
set_antag_hud(borer_mind.current, null)
|
||||
|
||||
/datum/game_mode/proc/update_borer_icons_added_host(datum/mind/host_mind)
|
||||
var/datum/atom_hud/antag/hosthud = GLOB.huds[ANTAG_HUD_BORER] //Invisible to self
|
||||
hosthud.self_visible = FALSE
|
||||
hosthud.join_hud(host_mind.current)
|
||||
set_antag_hud(host_mind.current, "hudbrainworm")
|
||||
|
||||
/datum/game_mode/proc/update_borer_icons_removed_host(datum/mind/host_mind)
|
||||
var/datum/atom_hud/antag/hosthud = GLOB.huds[ANTAG_HUD_BORER] //Invisible to self
|
||||
hosthud.self_visible = FALSE //Probably not needed as we're deleting?
|
||||
hosthud.leave_hud(host_mind.current)
|
||||
set_antag_hud(host_mind.current, null)
|
||||
|
||||
@@ -54,9 +54,22 @@
|
||||
/datum/objective/proc/find_target()
|
||||
var/list/datum/mind/owners = get_owners()
|
||||
var/list/possible_targets = list()
|
||||
var/try_target_late_joiners = FALSE
|
||||
for(var/I in owners)
|
||||
var/datum/mind/O = I
|
||||
if(O.late_joiner)
|
||||
try_target_late_joiners = TRUE
|
||||
for(var/datum/mind/possible_target in get_crewmember_minds())
|
||||
if(!(possible_target in owners) && ishuman(possible_target.current) && (possible_target.current.stat != DEAD) && is_unique_objective(possible_target))
|
||||
possible_targets += possible_target
|
||||
if(try_target_late_joiners)
|
||||
var/list/all_possible_targets = possible_targets.Copy()
|
||||
for(var/I in all_possible_targets)
|
||||
var/datum/mind/PT = I
|
||||
if(!PT.late_joiner)
|
||||
possible_targets -= PT
|
||||
if(!possible_targets.len)
|
||||
possible_targets = all_possible_targets
|
||||
if(possible_targets.len > 0)
|
||||
target = pick(possible_targets)
|
||||
update_explanation_text()
|
||||
|
||||
@@ -60,7 +60,9 @@
|
||||
|
||||
/datum/game_mode/traitor/post_setup()
|
||||
for(var/datum/mind/traitor in pre_traitors)
|
||||
addtimer(CALLBACK(traitor, /datum/mind.proc/add_antag_datum, antag_datum), rand(10,100))
|
||||
var/datum/antagonist/traitor/new_antag = new antag_datum(traitor)
|
||||
new_antag.should_specialise = TRUE
|
||||
addtimer(CALLBACK(traitor, /datum/mind.proc/add_antag_datum, new_antag), rand(10,100))
|
||||
if(!exchange_blue)
|
||||
exchange_blue = -1 //Block latejoiners from getting exchange objectives
|
||||
..()
|
||||
@@ -79,6 +81,8 @@
|
||||
add_latejoin_traitor(character.mind)
|
||||
|
||||
/datum/game_mode/traitor/proc/add_latejoin_traitor(datum/mind/character)
|
||||
var/datum/antagonist/traitor/new_antag = new antag_datum(character)
|
||||
new_antag.should_specialise = TRUE
|
||||
character.add_antag_datum(antag_datum)
|
||||
|
||||
|
||||
|
||||
@@ -44,6 +44,11 @@
|
||||
if(spent)
|
||||
to_chat(user, "<span class='cult'>This shard is spent; it is now just a creepy rock.</span>")
|
||||
|
||||
/obj/item/device/soulstone/Destroy() //Stops the shade from being qdel'd immediately and their ghost being sent back to the arrival shuttle.
|
||||
for(var/mob/living/simple_animal/shade/A in src)
|
||||
A.death()
|
||||
return ..()
|
||||
|
||||
//////////////////////////////Capturing////////////////////////////////////////////////////////
|
||||
|
||||
/obj/item/device/soulstone/attack(mob/living/carbon/human/M, mob/living/user)
|
||||
@@ -228,6 +233,7 @@
|
||||
|
||||
/obj/item/device/soulstone/proc/init_shade(mob/living/carbon/human/T, mob/U, vic = 0)
|
||||
new /obj/effect/decal/remains/human(T.loc) //Spawns a skeleton
|
||||
T.stop_sound_channel(CHANNEL_HEARTBEAT)
|
||||
T.invisibility = INVISIBILITY_ABSTRACT
|
||||
T.dust_animation()
|
||||
var/mob/living/simple_animal/shade/S = new /mob/living/simple_animal/shade(src)
|
||||
|
||||
@@ -42,7 +42,8 @@
|
||||
man is a dangerous mutant with the ability to alter himself and the world around him by what he and his leaders believe to be magic. If this man attempts an attack on your station, \
|
||||
his execution is highly encouraged, as is the preservation of his body for later study."
|
||||
|
||||
/datum/game_mode/wizard/check_finished()
|
||||
|
||||
/datum/game_mode/wizard/are_special_antags_dead()
|
||||
for(var/datum/mind/wizard in wizards)
|
||||
if(isliving(wizard.current) && wizard.current.stat!=DEAD)
|
||||
return FALSE
|
||||
@@ -54,8 +55,8 @@
|
||||
if(SSevents.wizardmode) //If summon events was active, turn it off
|
||||
SSevents.toggleWizardmode()
|
||||
SSevents.resetFrequency()
|
||||
|
||||
return ..()
|
||||
|
||||
return TRUE
|
||||
|
||||
/datum/game_mode/wizard/declare_completion()
|
||||
if(finished)
|
||||
|
||||
Reference in New Issue
Block a user