Merge remote-tracking branch 'upstream/master' into system-corruption
This commit is contained in:
@@ -508,7 +508,7 @@
|
||||
if("constructwraith")
|
||||
M.change_mob_type( /mob/living/simple_animal/hostile/construct/wraith , null, null, delmob )
|
||||
if("shade")
|
||||
M.change_mob_type( /mob/living/simple_animal/shade , null, null, delmob )
|
||||
M.change_mob_type( /mob/living/simple_animal/hostile/construct/shade , null, null, delmob )
|
||||
|
||||
|
||||
/////////////////////////////////////new ban stuff
|
||||
|
||||
@@ -684,10 +684,10 @@
|
||||
min_cold_protection_temperature = GLOVES_MIN_TEMP_PROTECT
|
||||
max_heat_protection_temperature = GLOVES_MAX_TEMP_PROTECT
|
||||
armor = list("melee" = 20, "bullet" = 20, "laser" = 20, "energy" = 20, "bomb" = 35, "bio" = 35, "rad" = 35, "fire" = 0, "acid" = 0)
|
||||
enhancement = 9 // first, do harm. all of it. all of the harm. just fuck em up.
|
||||
wound_enhancement = 9
|
||||
var/fast_enhancement = 9
|
||||
var/fast_wound_enhancement = 9
|
||||
enhancement = 6 // first, do harm. all of it. all of the harm. just fuck em up.
|
||||
wound_enhancement = 6
|
||||
var/fast_enhancement = 6
|
||||
var/fast_wound_enhancement = 6
|
||||
var/slow_enhancement = 20
|
||||
var/slow_wound_enhancement = 20
|
||||
silent = TRUE
|
||||
|
||||
@@ -216,6 +216,14 @@
|
||||
else if(get_clockwork_power())
|
||||
to_chat(L, "<span class='brass'>You feel a slight, static shock.</span>")
|
||||
|
||||
/obj/effect/clockwork/sigil/transmission/Initialize()
|
||||
. = ..()
|
||||
START_PROCESSING(SSobj, src)
|
||||
|
||||
/obj/effect/clockwork/sigil/transmission/Destroy()
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
return ..()
|
||||
|
||||
/obj/effect/clockwork/sigil/transmission/process()
|
||||
var/power_drained = 0
|
||||
var/power_mod = 0.005
|
||||
|
||||
@@ -1,41 +1,57 @@
|
||||
//horrifying power drain proc made for clockcult's power drain in lieu of six istypes or six for(x in view) loops
|
||||
/atom/movable/proc/power_drain(clockcult_user, drain_weapons = FALSE) //This proc as of now is only in use for void volt
|
||||
/*
|
||||
horrifying power drain proc made for clockcult's power drain in lieu of six istypes or six for(x in view) loops
|
||||
args:
|
||||
clockcult_user: If the user / source has to do with clockcult stuff
|
||||
drain_weapons: If this drains weaponry, such as batons and guns
|
||||
recursive: If this recurses through mob / storage contents. ONLY USE THIS IF IT'S NOT CALLED TOO FREQUENTLY, or I'm not liable for any lag / functional issues caused
|
||||
drain_amount: How much is drained by default; Influenced by a multiplier on most things depending on how much power they usually hold.
|
||||
*/
|
||||
/atom/movable/proc/power_drain(clockcult_user, drain_weapons = FALSE, recursive = FALSE, drain_amount = MIN_CLOCKCULT_POWER) //This proc as of now is only in use for void volt and transmission sigils
|
||||
if(recursive)
|
||||
var/succ = 0
|
||||
for(var/V in contents)
|
||||
var/atom/movable/target = V
|
||||
succ += target.power_drain(clockcult_user, drain_weapons, recursive, drain_amount)
|
||||
return succ
|
||||
var/obj/item/stock_parts/cell/cell = get_cell()
|
||||
if(cell)
|
||||
return cell.power_drain(clockcult_user)
|
||||
return cell.power_drain(clockcult_user, drain_weapons, recursive, drain_amount)
|
||||
return 0 //Returns 0 instead of FALSE to symbolise it returning the power amount in other cases, not TRUE aka 1
|
||||
|
||||
/obj/item/melee/baton/power_drain(clockcult_user, drain_weapons = FALSE) //balance memes
|
||||
/obj/item/melee/baton/power_drain(clockcult_user, drain_weapons = FALSE, recursive = FALSE, drain_amount = MIN_CLOCKCULT_POWER) //balance memes
|
||||
if(!drain_weapons)
|
||||
return 0
|
||||
return ..()
|
||||
var/obj/item/stock_parts/cell/cell = get_cell()
|
||||
if(cell)
|
||||
return cell.power_drain(clockcult_user, drain_weapons, recursive, drain_amount)
|
||||
return 0 //No need to recurse further in batons
|
||||
|
||||
/obj/item/gun/power_drain(clockcult_user, drain_weapons = FALSE) //balance memes
|
||||
/obj/item/gun/power_drain(clockcult_user, drain_weapons = FALSE, recursive = FALSE, drain_amount = MIN_CLOCKCULT_POWER) //balance memes
|
||||
if(!drain_weapons)
|
||||
return 0
|
||||
var/obj/item/stock_parts/cell/cell = get_cell()
|
||||
if(!cell)
|
||||
return 0
|
||||
if(cell.charge)
|
||||
. = min(cell.charge, MIN_CLOCKCULT_POWER*4) //Done snowflakey because guns have far smaller cells than batons / other equipment
|
||||
. = min(cell.charge, drain_amount*4) //Done snowflakey because guns have far smaller cells than batons / other equipment, also no need to recurse further in guns
|
||||
cell.use(.)
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/power/apc/power_drain(clockcult_user, drain_weapons = FALSE)
|
||||
/obj/machinery/power/apc/power_drain(clockcult_user, drain_weapons = FALSE, recursive = FALSE, drain_amount = MIN_CLOCKCULT_POWER)
|
||||
if(cell && cell.charge)
|
||||
playsound(src, "sparks", 50, 1)
|
||||
flick("apc-spark", src)
|
||||
. = min(cell.charge, MIN_CLOCKCULT_POWER*4)
|
||||
cell.use(.) //Better than a power sink!
|
||||
. = min(cell.charge, drain_amount*4)
|
||||
cell.use(min(cell.charge, . * 4)) //Better than a power sink!
|
||||
if(!cell.charge && !shorted)
|
||||
shorted = 1
|
||||
visible_message("<span class='warning'>The [name]'s screen blurs with static.</span>")
|
||||
update()
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/power/smes/power_drain(clockcult_user, drain_weapons = FALSE)
|
||||
/obj/machinery/power/smes/power_drain(clockcult_user, drain_weapons = FALSE, recursive = FALSE, drain_amount = MIN_CLOCKCULT_POWER)
|
||||
if(charge)
|
||||
. = min(charge, MIN_CLOCKCULT_POWER*4)
|
||||
. = min(charge, drain_amount*4)
|
||||
charge -= . * 50
|
||||
if(!charge && !panel_open)
|
||||
panel_open = TRUE
|
||||
@@ -44,20 +60,26 @@
|
||||
visible_message("<span class='warning'>[src]'s panel flies open with a flurry of sparks!</span>")
|
||||
update_icon()
|
||||
|
||||
/obj/item/stock_parts/cell/power_drain(clockcult_user, drain_weapons = FALSE)
|
||||
/obj/item/stock_parts/cell/power_drain(clockcult_user, drain_weapons = FALSE, recursive = FALSE, drain_amount = MIN_CLOCKCULT_POWER)
|
||||
if(charge)
|
||||
. = min(charge, MIN_CLOCKCULT_POWER * 4) //Done like this because normal cells are usually quite a bit bigger than the ones used in guns / APCs
|
||||
. = min(charge, drain_amount * 4) //Done like this because normal cells are usually quite a bit bigger than the ones used in guns / APCs
|
||||
use(min(charge, . * 10)) //Usually cell-powered equipment that is not a gun has at least ten times the capacity of a gun / 5 times the amount of an APC. This adjusts the drain to account for that.
|
||||
update_icon()
|
||||
|
||||
/mob/living/silicon/robot/power_drain(clockcult_user, drain_weapons = FALSE)
|
||||
/mob/living/silicon/robot/power_drain(clockcult_user, drain_weapons = FALSE, recursive = FALSE, drain_amount = MIN_CLOCKCULT_POWER)
|
||||
if((!clockcult_user || !is_servant_of_ratvar(src)) && cell && cell.charge)
|
||||
. = min(cell.charge, MIN_CLOCKCULT_POWER*4)
|
||||
. = min(cell.charge, drain_amount*8) //Silicons are very susceptible to Ratvar's might
|
||||
cell.use(.)
|
||||
spark_system.start()
|
||||
|
||||
/obj/mecha/power_drain(clockcult_user, drain_weapons = FALSE)
|
||||
if((!clockcult_user || (occupant && !is_servant_of_ratvar(occupant))) && cell && cell.charge)
|
||||
. = min(cell.charge, MIN_CLOCKCULT_POWER*4)
|
||||
cell.use(.)
|
||||
spark_system.start()
|
||||
/obj/mecha/power_drain(clockcult_user, drain_weapons = FALSE, recursive = FALSE, drain_amount = MIN_CLOCKCULT_POWER)
|
||||
if(!clockcult_user || (occupant && !is_servant_of_ratvar(occupant)))
|
||||
if(recursive)
|
||||
var/succ = 0
|
||||
for(var/atom/movable/target in contents) //Hiding in your mech won't save you.
|
||||
succ += target.power_drain(clockcult_user, drain_weapons, recursive, drain_amount)
|
||||
. = succ
|
||||
else if(cell && cell.charge)
|
||||
. = min(cell.charge, drain_amount*4)
|
||||
cell.use(.)
|
||||
spark_system.start()
|
||||
|
||||
@@ -167,7 +167,7 @@ Judgement 5 converts
|
||||
set waitfor = FALSE
|
||||
chanting = TRUE
|
||||
for(var/invocation in invocations)
|
||||
sleep(channel_time / invocations.len)
|
||||
sleep(channel_time / (invocations.len + 1)) //So it always finishes the invocation
|
||||
if(QDELETED(src) || QDELETED(slab) || !chanting)
|
||||
return
|
||||
if(multiple_invokers_used)
|
||||
|
||||
@@ -393,45 +393,49 @@
|
||||
<b>Left-click a target to fire, quickly!</b></span>"
|
||||
timeout_time = 20
|
||||
|
||||
/datum/clockwork_scripture/channeled/void_volt
|
||||
descname = "Channeled, Power Drain"
|
||||
/datum/clockwork_scripture/void_volt
|
||||
descname = "Pulse, Power Drain"
|
||||
name = "Void Volt"
|
||||
desc = "A channeled spell that quickly drains any powercells in a radius of eight tiles, but burns the invoker. \
|
||||
Can be channeled with more cultists to increase range and split the caused damage evenly over all invokers. \
|
||||
desc = "A spell that releases a pulse which drains the power of anything in a radius of eight tiles, but burns the invoker. \
|
||||
Can be used with more servants to increase range and split the caused damage evenly among all invokers. \
|
||||
Also charges clockwork power by a small percentage of the drained power amount, which can help offset this scriptures powercost."
|
||||
invocations = list("Channel their energy through my body... ", "... so it may fuel Engine!")
|
||||
chant_invocations = list("Make their lights fall dark!", "They shall be powerless!", "Rob them of their power!")
|
||||
chant_amount = 20
|
||||
chant_interval = 10 //100KW drain per pulse for guns / APCs / 1MW for other cells = 10 chants / 100ds / 10s to drain a charged weapon or a baton with a nonupgraded cell
|
||||
channel_time = 50
|
||||
power_cost = 300
|
||||
invocations = list("Take the energy...", "...of their inventions...", "...and grant it to Engine...", "...for they already live in utter darkness!")
|
||||
channel_time = 130 //You need alot of time, but it pays off. - ten times as powerful as a regular drain (done by transmission sigils) and recurses + affects weapons - incredibly useful if you can pull this off before a big fight.
|
||||
power_cost = 500 //Relatively medium powercost, but can be offset due to it adding a part of drained power to the power pool.
|
||||
multiple_invokers_used = TRUE
|
||||
multiple_invokers_optional = TRUE
|
||||
usage_tip = "It may be useful to end channelling early if the burning becomes too much to handle.."
|
||||
usage_tip = "Be sure to not be injured when using this, or the power channeled through you may overwhelm your body."
|
||||
tier = SCRIPTURE_SCRIPT
|
||||
primary_component = GEIS_CAPACITOR
|
||||
sort_priority = 11
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Quickly drains power in an area around the invoker, causing burns proportional to the amount of energy drained.<br><b>Maximum of 20 chants.</b>"
|
||||
quickbind_desc = "Quickly drains power in an area around the invoker, causing burns proportional to the amount of energy drained."
|
||||
|
||||
/datum/clockwork_scripture/channeled/void_volt/scripture_effects()
|
||||
/datum/clockwork_scripture/void_volt/chant()
|
||||
invoker.visible_message("<span class='warning'>[invoker] glows in a brilliant golden light!</span>")
|
||||
invoker.add_atom_colour("#FFD700", ADMIN_COLOUR_PRIORITY)
|
||||
invoker.light_power = 2
|
||||
invoker.light_range = 4
|
||||
invoker.light_color = LIGHT_COLOR_FIRE
|
||||
invoker.update_light()
|
||||
return ..()
|
||||
addtimer(CALLBACK(invoker, /mob.proc/stop_void_volt_glow), channel_time)
|
||||
..()//Do the timer & Chant
|
||||
|
||||
/mob/proc/stop_void_volt_glow() //Needed so the scripture being qdel()d doesn't prevent it.
|
||||
visible_message("<span class='warning'>[src] stops glowing...</span>")
|
||||
remove_atom_colour(ADMIN_COLOUR_PRIORITY)
|
||||
light_power = 0
|
||||
light_range = 0
|
||||
update_light()
|
||||
|
||||
/datum/clockwork_scripture/channeled/void_volt/chant_effects(chant_number)
|
||||
/datum/clockwork_scripture/void_volt/scripture_effects()
|
||||
var/power_drained = 0
|
||||
var/power_mod = 0.005 //Amount of power drained (generally) is multiplied with this, and subsequently dealt in damage to the invoker, then 15 times that is added to the clockwork cult's power reserves.
|
||||
var/drain_range = 8
|
||||
var/drain_range = 12
|
||||
var/additional_chanters = 0
|
||||
var/list/chanters = list()
|
||||
chanters += invoker
|
||||
for(var/mob/living/L in range(1, invoker))
|
||||
for(var/mob/living/L in orange(1, invoker))
|
||||
if(!L.stat && is_servant_of_ratvar(L))
|
||||
additional_chanters++
|
||||
chanters += L
|
||||
@@ -440,22 +444,14 @@
|
||||
var/turf/T = t
|
||||
for(var/M in T)
|
||||
var/atom/movable/A = M
|
||||
power_drained += A.power_drain(TRUE, TRUE) //Yes, this absolutely does drain weaponry. 10 pulses to drain guns / batons, though of course they can just be recharged.
|
||||
power_drained += A.power_drain(TRUE, TRUE, TRUE, MIN_CLOCKCULT_POWER * 10) //Yes, this absolutely does drain weaponry, aswell as recurse through objects. No more hiding in lockers / mechs to avoid it.
|
||||
new /obj/effect/temp_visual/ratvar/sigil/transgression(invoker.loc, 1 + (power_drained * power_mod))
|
||||
var/datum/effect_system/spark_spread/S = new
|
||||
S.set_up(round(1 + (power_drained * power_mod), 1), 0, get_turf(invoker))
|
||||
S.start()
|
||||
adjust_clockwork_power(power_drained * power_mod * 15)
|
||||
for(var/mob/living/L in chanters)
|
||||
L.adjustFireLoss(round(clamp(power_drained * power_mod / (1 + additional_chanters), 0, 20), 0.1)) //No you won't just immediately melt if you do this in a very power-rich area
|
||||
L.adjustFireLoss(round(clamp(power_drained * power_mod / (1 + additional_chanters), 0, 70), 0.1)) //No you won't just immediately melt if you do this in a very power-rich area, but it'll be close.
|
||||
|
||||
|
||||
return TRUE
|
||||
|
||||
/datum/clockwork_scripture/channeled/void_volt/chant_end_effects()
|
||||
invoker.visible_message("<span class='warning'>[invoker] stops glowing...</span>")
|
||||
invoker.remove_atom_colour(ADMIN_COLOUR_PRIORITY)
|
||||
invoker.light_power = 0
|
||||
invoker.light_range = 0
|
||||
invoker.update_light()
|
||||
return ..()
|
||||
|
||||
@@ -295,6 +295,8 @@
|
||||
++cultplayers
|
||||
else
|
||||
++alive
|
||||
if(!alive)
|
||||
return
|
||||
var/ratio = cultplayers/alive
|
||||
if(ratio > CULT_RISEN && !cult_risen)
|
||||
for(var/datum/mind/B in members)
|
||||
|
||||
@@ -82,7 +82,7 @@ Runes can either be invoked by one's self or with many different cultists. Each
|
||||
fail_invoke()
|
||||
|
||||
/obj/effect/rune/attack_animal(mob/living/simple_animal/M)
|
||||
if(istype(M, /mob/living/simple_animal/shade) || istype(M, /mob/living/simple_animal/hostile/construct))
|
||||
if(isshade(M) || istype(M, /mob/living/simple_animal/hostile/construct))
|
||||
if(construct_invoke || !iscultist(M)) //if you're not a cult construct we want the normal fail message
|
||||
attack_hand(M)
|
||||
else
|
||||
@@ -191,7 +191,7 @@ structure_check() searches for nearby cultist structures required for the invoca
|
||||
/obj/effect/rune/convert/do_invoke_glow()
|
||||
return
|
||||
|
||||
/obj/effect/rune/convert/invoke(var/list/invokers)
|
||||
/obj/effect/rune/convert/invoke(list/invokers)
|
||||
if(rune_in_use)
|
||||
return
|
||||
var/list/myriad_targets = list()
|
||||
@@ -203,11 +203,16 @@ structure_check() searches for nearby cultist structures required for the invoca
|
||||
fail_invoke()
|
||||
log_game("Offer rune failed - no eligible targets")
|
||||
return
|
||||
var/mob/living/L = pick(myriad_targets)
|
||||
if(HAS_TRAIT(L, TRAIT_SACRIFICED))
|
||||
fail_invoke()
|
||||
log_game("Offer rune failed - target has already been sacrificed")
|
||||
to_chat(invokers, "<span class='warning'>[L] has already been sacrificed!</span>")
|
||||
return
|
||||
rune_in_use = TRUE
|
||||
visible_message("<span class='warning'>[src] pulses blood red!</span>")
|
||||
var/oldcolor = color
|
||||
color = RUNE_COLOR_DARKRED
|
||||
var/mob/living/L = pick(myriad_targets)
|
||||
var/is_clock = is_servant_of_ratvar(L)
|
||||
|
||||
var/mob/living/F = invokers[1]
|
||||
@@ -264,7 +269,7 @@ structure_check() searches for nearby cultist structures required for the invoca
|
||||
H.uncuff()
|
||||
H.stuttering = 0
|
||||
H.cultslurring = 0
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
/obj/effect/rune/convert/proc/do_sacrifice(mob/living/sacrificial, list/invokers)
|
||||
var/mob/living/first_invoker = invokers[1]
|
||||
@@ -308,12 +313,16 @@ structure_check() searches for nearby cultist structures required for the invoca
|
||||
stone.invisibility = 0
|
||||
|
||||
if(sacrificial)
|
||||
ADD_TRAIT(sacrificial, TRAIT_SACRIFICED, "sacrificed")
|
||||
if(iscyborg(sacrificial))
|
||||
playsound(sacrificial, 'sound/magic/disable_tech.ogg', 100, 1)
|
||||
sacrificial.dust() //To prevent the MMI from remaining
|
||||
else
|
||||
playsound(sacrificial, 'sound/magic/disintegrate.ogg', 100, 1)
|
||||
sacrificial.gib()
|
||||
var/mob/living/silicon/robot/bot = sacrificial
|
||||
playsound(sacrificial, 'sound/magic/disable_tech.ogg', 100, TRUE)
|
||||
bot.deconstruct()
|
||||
|
||||
else if(ishuman(sacrificial))
|
||||
playsound(sacrificial, 'sound/magic/disintegrate.ogg', 100, TRUE)
|
||||
var/mob/living/carbon/human/H = sacrificial
|
||||
H.spew_organ(2, 6)
|
||||
return TRUE
|
||||
|
||||
/obj/effect/rune/empower
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
|
||||
/obj/item/soulstone/examine(mob/user)
|
||||
. = ..()
|
||||
if(usability || iscultist(user, TRUE) || iswizard(user) || isobserver(user))
|
||||
if(usability || iscultist(user) || iswizard(user) || isobserver(user))
|
||||
if (old_shard)
|
||||
. += "<span class='cult'>A soulstone, used to capture a soul, either from dead humans or from freed shades.</span>"
|
||||
else
|
||||
@@ -46,7 +46,7 @@
|
||||
. += "<span class='cult'>This shard is spent; it is now just a creepy rock.</span>"
|
||||
|
||||
/obj/item/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)
|
||||
for(var/mob/living/simple_animal/hostile/construct/shade/A in src)
|
||||
A.death()
|
||||
return ..()
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
to_chat(user, "<span class='userdanger'>Your body is wracked with debilitating pain!</span>")
|
||||
return
|
||||
if(spent)
|
||||
to_chat(user, "<span class='warning'>There is no power left in the shard.</span>")
|
||||
to_chat(user, "<span class='warning'>There is no power left in [src].</span>")
|
||||
return
|
||||
if(!ishuman(M))//If target is not a human.
|
||||
return ..()
|
||||
@@ -81,7 +81,7 @@
|
||||
release_shades(user)
|
||||
|
||||
/obj/item/soulstone/proc/release_shades(mob/user)
|
||||
for(var/mob/living/simple_animal/shade/A in src)
|
||||
for(var/mob/living/simple_animal/hostile/construct/shade/A in src)
|
||||
A.status_flags &= ~GODMODE
|
||||
A.forceMove(get_turf(user))
|
||||
A.mobility_flags = MOBILITY_FLAGS_DEFAULT
|
||||
@@ -103,12 +103,12 @@
|
||||
|
||||
/obj/structure/constructshell/examine(mob/user)
|
||||
. = ..()
|
||||
if(iscultist(user, TRUE) || iswizard(user) || user.stat == DEAD)
|
||||
. += "<span class='cult'>A construct shell, used to house bound souls from a soulstone.</span>"
|
||||
. += "<span class='cult'>Placing a soulstone with a soul into this shell allows you to produce your choice of the following:</span>"
|
||||
. += "<span class='cult'>An <b>Artificer</b>, which can produce <b>more shells and soulstones</b>, as well as fortifications.</span>"
|
||||
. += "<span class='cult'>A <b>Wraith</b>, which does high damage and can jaunt through walls, though it is quite fragile.</span>"
|
||||
. += "<span class='cult'>A <b>Juggernaut</b>, which is very hard to kill and can produce temporary walls, but is slow.</span>"
|
||||
if(iscultist(user) || iswizard(user) || user.stat == DEAD)
|
||||
. += {"<span class='cult'>A construct shell, used to house bound souls from a soulstone.\n
|
||||
Placing a soulstone with a soul into this shell allows you to produce your choice of the following:\n
|
||||
An <b>Artificer</b>, which can produce <b>more shells and soulstones</b>, as well as fortifications.\n
|
||||
A <b>Wraith</b>, which does high damage and can jaunt through walls, though it is quite fragile.\n
|
||||
A <b>Juggernaut</b>, which is very hard to kill and can produce temporary walls, but is slow.</span>"}
|
||||
|
||||
/obj/structure/constructshell/attackby(obj/item/O, mob/user, params)
|
||||
if(istype(O, /obj/item/soulstone))
|
||||
@@ -145,14 +145,14 @@
|
||||
if("VICTIM")
|
||||
var/mob/living/carbon/human/T = target
|
||||
var/datum/antagonist/cult/C = user.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
|
||||
if(C && C.cult_team?.is_sacrifice_target(T.mind))
|
||||
if(C?.cult_team.is_sacrifice_target(T.mind))
|
||||
if(iscultist(user))
|
||||
to_chat(user, "<span class='cult'><b>\"This soul is mine.</b></span> <span class='cultlarge'>SACRIFICE THEM!\"</span>")
|
||||
else
|
||||
to_chat(user, "<span class='danger'>The soulstone seems to reject this soul.</span>")
|
||||
to_chat(user, "<span class='danger'>[src] seems to reject this soul.</span>")
|
||||
return FALSE
|
||||
if(contents.len)
|
||||
to_chat(user, "<span class='userdanger'>Capture failed!</span>: The soulstone is full! Free an existing soul to make room.")
|
||||
to_chat(user, "<span class='userdanger'>Capture failed!</span>: [src] is full! Free an existing soul to make room.")
|
||||
else
|
||||
if((!old_shard && T.stat != CONSCIOUS) || (old_shard && T.stat == DEAD))
|
||||
if(T.client == null)
|
||||
@@ -167,7 +167,7 @@
|
||||
to_chat(user, "<span class='userdanger'>Capture failed!</span>: Kill or maim the victim first!")
|
||||
|
||||
if("SHADE")
|
||||
var/mob/living/simple_animal/shade/T = target
|
||||
var/mob/living/simple_animal/hostile/construct/shade/T = target
|
||||
if(contents.len)
|
||||
to_chat(user, "<span class='userdanger'>Capture failed!</span>: The soulstone is full! Free an existing soul to make room.")
|
||||
else
|
||||
@@ -177,13 +177,13 @@
|
||||
T.health = T.maxHealth
|
||||
icon_state = "soulstone2"
|
||||
name = "soulstone: Shade of [T.real_name]"
|
||||
to_chat(T, "<span class='notice'>Your soul has been captured by the soulstone. Its arcane energies are reknitting your ethereal form.</span>")
|
||||
to_chat(T, "<span class='notice'>Your soul has been captured by [src]. Its arcane energies are reknitting your ethereal form.</span>")
|
||||
if(user != T)
|
||||
to_chat(user, "<span class='info'><b>Capture successful!</b>:</span> [T.real_name]'s soul has been captured and stored within the soulstone.")
|
||||
to_chat(user, "<span class='info'><b>Capture successful!</b>:</span> [T.real_name]'s soul has been captured and stored within [src].")
|
||||
|
||||
if("CONSTRUCT")
|
||||
var/obj/structure/constructshell/T = target
|
||||
var/mob/living/simple_animal/shade/A = locate() in src
|
||||
var/mob/living/simple_animal/hostile/construct/shade/A = locate() in src
|
||||
if(A)
|
||||
var/construct_class = alert(user, "Please choose which type of construct you wish to create.",,"Juggernaut","Wraith","Artificer")
|
||||
if(!T || !T.loc)
|
||||
@@ -199,8 +199,8 @@
|
||||
if(iscultist(user) || iswizard(user))
|
||||
makeNewConstruct(/mob/living/simple_animal/hostile/construct/builder, A, user, 0, T.loc)
|
||||
|
||||
else
|
||||
makeNewConstruct(/mob/living/simple_animal/hostile/construct/builder/noncult, A, user, 0, T.loc)
|
||||
else
|
||||
return
|
||||
for(var/datum/mind/B in SSticker.mode.cult)
|
||||
if(B == A.mind)
|
||||
SSticker.mode.cult -= A.mind
|
||||
@@ -208,19 +208,24 @@
|
||||
qdel(T)
|
||||
qdel(src)
|
||||
else
|
||||
to_chat(user, "<span class='userdanger'>Creation failed!</span>: The soul stone is empty! Go kill someone!")
|
||||
to_chat(user, "<span class='userdanger'>Creation failed!</span>: [src] is empty! Go kill someone!")
|
||||
|
||||
|
||||
/proc/makeNewConstruct(mob/living/simple_animal/hostile/construct/ctype, mob/target, mob/stoner = null, cultoverride = 0, loc_override = null)
|
||||
if(QDELETED(target))
|
||||
return
|
||||
var/mob/living/simple_animal/hostile/construct/newstruct = new ctype((loc_override) ? (loc_override) : (get_turf(target)))
|
||||
if(stoner)
|
||||
newstruct.faction |= "[REF(stoner)]"
|
||||
newstruct.master = stoner
|
||||
var/datum/action/innate/seek_master/SM = new()
|
||||
SM.Grant(newstruct)
|
||||
target.transfer_ckey(newstruct)
|
||||
newstruct.key = target.key
|
||||
if(target.type == /mob/living/simple_animal/hostile/construct/shade) //Make sure we remember which body belonged to the shade
|
||||
var/mob/living/simple_animal/hostile/construct/shade/shade = target
|
||||
newstruct.original_mind = shade.original_mind
|
||||
var/obj/screen/alert/bloodsense/BS
|
||||
if(newstruct.mind && ((stoner && iscultist(stoner)) || cultoverride) && SSticker && SSticker.mode)
|
||||
if(newstruct.mind && ((stoner && iscultist(stoner)) || cultoverride) && SSticker?.mode)
|
||||
SSticker.mode.add_cultist(newstruct.mind, 0)
|
||||
if(iscultist(stoner) || cultoverride)
|
||||
to_chat(newstruct, "<b>You are still bound to serve the cult[stoner ? " and [stoner]":""], follow [stoner ? stoner.p_their() : "their"] orders and help [stoner ? stoner.p_them() : "them"] complete [stoner ? stoner.p_their() : "their"] goals at all costs.</b>")
|
||||
@@ -234,19 +239,18 @@
|
||||
|
||||
|
||||
/obj/item/soulstone/proc/init_shade(mob/living/carbon/human/T, mob/user, vic = 0)
|
||||
new /obj/effect/decal/remains/human(T.loc) //Spawns a skeleton
|
||||
if(HAS_TRAIT_FROM(T, TRAIT_SACRIFICED, "sacrificed"))
|
||||
if(user)
|
||||
to_chat(user, "This body has already been harvested!")
|
||||
return
|
||||
ADD_TRAIT(T, TRAIT_SACRIFICED, "sacrificed")
|
||||
T.stop_sound_channel(CHANNEL_HEARTBEAT)
|
||||
T.invisibility = INVISIBILITY_ABSTRACT
|
||||
T.dust_animation()
|
||||
QDEL_IN(T, 5)
|
||||
var/mob/living/simple_animal/shade/S = new /mob/living/simple_animal/shade(src)
|
||||
S.status_flags |= GODMODE //So they won't die inside the stone somehow
|
||||
S.mobility_flags = NONE //Can't move out of the soul stone
|
||||
var/mob/living/simple_animal/hostile/construct/shade/S = new /mob/living/simple_animal/hostile/construct/shade(src)
|
||||
S.name = "Shade of [T.real_name]"
|
||||
S.real_name = "Shade of [T.real_name]"
|
||||
T.transfer_ckey(S)
|
||||
S.original_mind = T.mind.current
|
||||
S.copy_languages(T, LANGUAGE_MIND)//Copies the old mobs languages into the new mob holder.
|
||||
S.copy_languages(user, LANGUAGE_MASTER)
|
||||
S.update_atom_languages()
|
||||
grant_all_languages(FALSE, FALSE, TRUE) //Grants omnitongue
|
||||
if(user)
|
||||
@@ -264,7 +268,7 @@
|
||||
to_chat(user, "<span class='info'><b>Capture successful!</b>:</span> [T.real_name]'s soul has been ripped from [T.p_their()] body and stored within the soul stone.")
|
||||
|
||||
|
||||
/obj/item/soulstone/proc/getCultGhost(mob/living/carbon/human/T, mob/U)
|
||||
/obj/item/soulstone/proc/getCultGhost(mob/living/carbon/human/T, mob/user)
|
||||
var/mob/dead/observer/chosen_ghost
|
||||
|
||||
for(var/mob/dead/observer/ghost in GLOB.player_list) //We put them back in their body
|
||||
@@ -279,13 +283,12 @@
|
||||
if(!T)
|
||||
return FALSE
|
||||
if(!chosen_ghost)
|
||||
to_chat(U, "<span class='danger'>There were no spirits willing to become a shade.</span>")
|
||||
to_chat(user, "<span class='danger'>There were no spirits willing to become a shade.</span>")
|
||||
return FALSE
|
||||
if(contents.len) //If they used the soulstone on someone else in the meantime
|
||||
return FALSE
|
||||
T.ckey = chosen_ghost.ckey
|
||||
for(var/obj/item/W in T)
|
||||
T.dropItemToGround(W)
|
||||
init_shade(T, U)
|
||||
qdel(T)
|
||||
init_shade(T, user)
|
||||
return TRUE
|
||||
|
||||
@@ -237,12 +237,21 @@
|
||||
. += "<span class='notice'>Alt-click to [locked ? "unlock" : "lock"] the interface.</span>"
|
||||
|
||||
/obj/machinery/airalarm/ui_status(mob/user)
|
||||
if(hasSiliconAccessInArea(user) && aidisabled)
|
||||
to_chat(user, "AI control has been disabled.")
|
||||
else if(!shorted)
|
||||
if(hasSiliconAccessInArea(user))
|
||||
if(aidisabled)
|
||||
to_chat(user, "AI control has been disabled")
|
||||
return UI_CLOSE
|
||||
else if(!issilicon(user)) //True sillycones use ..()
|
||||
return UI_INTERACTIVE
|
||||
if(!shorted)
|
||||
return ..()
|
||||
return UI_CLOSE
|
||||
|
||||
/obj/machinery/airalarm/can_interact(mob/user)
|
||||
. = ..()
|
||||
if (!issilicon(user) && hasSiliconAccessInArea(user))
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/airalarm/ui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
|
||||
@@ -196,8 +196,8 @@
|
||||
icon_state = "inje_map-1"
|
||||
|
||||
/obj/machinery/atmospherics/components/unary/outlet_injector/layer3
|
||||
piping_layer = 2
|
||||
icon_state = "inje_map-2"
|
||||
piping_layer = 3
|
||||
icon_state = "inje_map-3"
|
||||
|
||||
/obj/machinery/atmospherics/components/unary/outlet_injector/on
|
||||
on = TRUE
|
||||
@@ -207,8 +207,8 @@
|
||||
icon_state = "inje_map-1"
|
||||
|
||||
/obj/machinery/atmospherics/components/unary/outlet_injector/on/layer3
|
||||
piping_layer = 2
|
||||
icon_state = "inje_map-2"
|
||||
piping_layer = 3
|
||||
icon_state = "inje_map-3"
|
||||
|
||||
/obj/machinery/atmospherics/components/unary/outlet_injector/atmos
|
||||
frequency = FREQ_ATMOS_STORAGE
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
// welcome to the jungle, we got fun and games
|
||||
|
||||
//areas
|
||||
|
||||
/area/awaymission/jungleresort
|
||||
name = "Jungle Resort"
|
||||
icon_state = "awaycontent30"
|
||||
|
||||
//objects
|
||||
|
||||
/obj/item/paper/crumpled/awaymissions/jungleresort/notice
|
||||
name = "Resort Notice"
|
||||
info = "Due to unforeseen circumstances and the disappearance of several resort employees and visitors, the resort shall be closed to the public until further notice. - <i>Resort Manager Joe Lawrence</i.>"
|
||||
|
||||
/obj/item/melee/chainofcommand/jungle
|
||||
name = "treasure hunter's whip"
|
||||
desc = "The tool of a fallen treasure hunter, old and outdated, it still stings like hell to be hit by."
|
||||
hitsound = 'sound/weapons/whip.ogg'
|
||||
icon_state = "whip"
|
||||
|
||||
//turfs
|
||||
|
||||
/turf/open/water/jungle
|
||||
initial_gas_mix = "o2=22;n2=82;TEMP=293.15"
|
||||
|
||||
/turf/open/floor/plating/dirt/jungle
|
||||
initial_gas_mix = "o2=22;n2=82;TEMP=293.15"
|
||||
|
||||
/turf/open/floor/plating/dirt/dark/jungle
|
||||
initial_gas_mix = "o2=22;n2=82;TEMP=293.15"
|
||||
|
||||
/turf/closed/mineral/random/labormineral/jungle
|
||||
baseturfs = /turf/open/floor/plating/asteroid
|
||||
turf_type = /turf/open/floor/plating/asteroid
|
||||
|
||||
//mobs
|
||||
|
||||
/mob/living/carbon/monkey/punpun/curiousgorge
|
||||
name = "Curious Gorge"
|
||||
pet_monkey_names = list("Curious Gorge", "Jungle Gorge", "Jungah Joe", "Mr. Monke")
|
||||
rare_pet_monkey_names = list("Sun Mukong", "Monkey Kong")
|
||||
|
||||
/mob/living/simple_animal/hostile/jungle/leaper/boss
|
||||
health = 450
|
||||
@@ -268,7 +268,7 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
|
||||
else
|
||||
prefs = new /datum/preferences(src)
|
||||
GLOB.preferences_datums[ckey] = prefs
|
||||
|
||||
|
||||
addtimer(CALLBACK(src, .proc/ensure_keys_set), 10) //prevents possible race conditions
|
||||
|
||||
prefs.last_ip = address //these are gonna be used for banning
|
||||
@@ -561,36 +561,49 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
|
||||
if(!query_client_in_db.Execute())
|
||||
qdel(query_client_in_db)
|
||||
return
|
||||
if(!query_client_in_db.NextRow())
|
||||
if (CONFIG_GET(flag/panic_bunker) && !holder && !GLOB.deadmins[ckey] && !(ckey in GLOB.bunker_passthrough))
|
||||
log_access("Failed Login: [key] - New account attempting to connect during panic bunker")
|
||||
message_admins("<span class='adminnotice'>Failed Login: [key] - New account attempting to connect during panic bunker</span>")
|
||||
to_chat(src, "<span class='notice'>You must first join the Discord to verify your account before joining this server.<br>To do so, read the rules and post a request in the #station-access-requests channel under the \"Main server\" category in the Discord server linked here: <a href='https://discord.gg/E6SQuhz'>https://discord.gg/E6SQuhz</a><br>If you have already done so, wait a few minutes then try again; sometimes the server needs to fully load before you can join.</span>") //CIT CHANGE - makes the panic bunker disconnect message point to the discord
|
||||
var/list/connectiontopic_a = params2list(connectiontopic)
|
||||
var/list/panic_addr = CONFIG_GET(string/panic_server_address)
|
||||
if(panic_addr && !connectiontopic_a["redirect"])
|
||||
var/panic_name = CONFIG_GET(string/panic_server_name)
|
||||
to_chat(src, "<span class='notice'>Sending you to [panic_name ? panic_name : panic_addr].</span>")
|
||||
winset(src, null, "command=.options")
|
||||
src << link("[panic_addr]?redirect=1")
|
||||
qdel(query_client_in_db)
|
||||
qdel(src)
|
||||
return
|
||||
if(!query_client_in_db.NextRow()) //new user detected
|
||||
if(!holder && !GLOB.deadmins[ckey])
|
||||
if(CONFIG_GET(flag/panic_bunker) && !(ckey in GLOB.bunker_passthrough))
|
||||
log_access("Failed Login: [key] - New account attempting to connect during panic bunker")
|
||||
message_admins("<span class='adminnotice'>Failed Login: [key] - New account attempting to connect during panic bunker</span>")
|
||||
to_chat(src, "<span class='notice'>You must first join the Discord to verify your account before joining this server.<br>To do so, read the rules and post a request in the #station-access-requests channel under the \"Main server\" category in the Discord server linked here: <a href='https://discord.gg/E6SQuhz'>https://discord.gg/E6SQuhz</a><br>If you have already done so, wait a few minutes then try again; sometimes the server needs to fully load before you can join.</span>") //CIT CHANGE - makes the panic bunker disconnect message point to the discord
|
||||
var/list/connectiontopic_a = params2list(connectiontopic)
|
||||
var/list/panic_addr = CONFIG_GET(string/panic_server_address)
|
||||
if(panic_addr && !connectiontopic_a["redirect"])
|
||||
var/panic_name = CONFIG_GET(string/panic_server_name)
|
||||
to_chat(src, "<span class='notice'>Sending you to [panic_name ? panic_name : panic_addr].</span>")
|
||||
winset(src, null, "command=.options")
|
||||
src << link("[panic_addr]?redirect=1")
|
||||
qdel(query_client_in_db)
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
new_player = 1
|
||||
account_join_date = sanitizeSQL(findJoinDate())
|
||||
var/sql_key = sanitizeSQL(key)
|
||||
var/datum/DBQuery/query_add_player = SSdbcore.NewQuery("INSERT INTO [format_table_name("player")] (`ckey`, `byond_key`, `firstseen`, `firstseen_round_id`, `lastseen`, `lastseen_round_id`, `ip`, `computerid`, `lastadminrank`, `accountjoindate`) VALUES ('[sql_ckey]', '[sql_key]', Now(), '[GLOB.round_id]', Now(), '[GLOB.round_id]', INET_ATON('[sql_ip]'), '[sql_computerid]', '[sql_admin_rank]', [account_join_date ? "'[account_join_date]'" : "NULL"])")
|
||||
if(!query_add_player.Execute())
|
||||
qdel(query_client_in_db)
|
||||
new_player = 1
|
||||
account_join_date = sanitizeSQL(findJoinDate())
|
||||
var/sql_key = sanitizeSQL(key)
|
||||
var/datum/DBQuery/query_add_player = SSdbcore.NewQuery("INSERT INTO [format_table_name("player")] (`ckey`, `byond_key`, `firstseen`, `firstseen_round_id`, `lastseen`, `lastseen_round_id`, `ip`, `computerid`, `lastadminrank`, `accountjoindate`) VALUES ('[sql_ckey]', '[sql_key]', Now(), '[GLOB.round_id]', Now(), '[GLOB.round_id]', INET_ATON('[sql_ip]'), '[sql_computerid]', '[sql_admin_rank]', [account_join_date ? "'[account_join_date]'" : "NULL"])")
|
||||
if(!query_add_player.Execute())
|
||||
qdel(query_client_in_db)
|
||||
qdel(query_add_player)
|
||||
return
|
||||
qdel(query_add_player)
|
||||
return
|
||||
qdel(query_add_player)
|
||||
if(!account_join_date)
|
||||
account_join_date = "Error"
|
||||
account_age = -1
|
||||
else if(ckey in GLOB.bunker_passthrough)
|
||||
GLOB.bunker_passthrough -= ckey
|
||||
if(!account_join_date)
|
||||
account_join_date = "Error"
|
||||
account_age = -1
|
||||
else if(ckey in GLOB.bunker_passthrough)
|
||||
GLOB.bunker_passthrough -= ckey
|
||||
if(CONFIG_GET(flag/age_verification)) //setup age verification
|
||||
if(!set_db_player_flags())
|
||||
message_admins(usr, "<span class='danger'>ERROR: Unable to read player flags from database. Please check logs.</span>")
|
||||
return
|
||||
else
|
||||
var/dbflags = prefs.db_flags
|
||||
if(!(dbflags & DB_FLAG_AGE_CONFIRMATION_COMPLETE)) //they have not completed age verification
|
||||
if((ckey in GLOB.bunker_passthrough)) //they're verified in the panic bunker though
|
||||
update_flag_db(DB_FLAG_AGE_CONFIRMATION_COMPLETE, TRUE)
|
||||
else
|
||||
update_flag_db(DB_FLAG_AGE_CONFIRMATION_INCOMPLETE, TRUE)
|
||||
|
||||
qdel(query_client_in_db)
|
||||
var/datum/DBQuery/query_get_client_age = SSdbcore.NewQuery("SELECT firstseen, DATEDIFF(Now(),firstseen), accountjoindate, DATEDIFF(Now(),accountjoindate) FROM [format_table_name("player")] WHERE ckey = '[sql_ckey]'")
|
||||
if(!query_get_client_age.Execute())
|
||||
|
||||
@@ -482,7 +482,6 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
dat += "<span style='border: 1px solid #161616; background-color: #[features["mcolor3"]];'> </span> <a href='?_src_=prefs;preference=mutant_color3;task=input'>Change</a><BR>"
|
||||
mutant_colors = TRUE
|
||||
|
||||
if (CONFIG_GET(number/body_size_min) != CONFIG_GET(number/body_size_max))
|
||||
dat += "<b>Sprite Size:</b> <a href='?_src_=prefs;preference=body_size;task=input'>[features["body_size"]*100]%</a><br>"
|
||||
|
||||
if(!(NOEYES in pref_species.species_traits))
|
||||
@@ -2245,21 +2244,10 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
gender = chosengender
|
||||
|
||||
if("body_size")
|
||||
var/min = CONFIG_GET(number/body_size_min)
|
||||
var/max = CONFIG_GET(number/body_size_max)
|
||||
var/danger = CONFIG_GET(number/threshold_body_size_slowdown)
|
||||
var/new_body_size = input(user, "Choose your desired sprite size: ([min*100]%-[max*100]%)\nWarning: This may make your character look distorted[danger > min ? "! Additionally, a proportional movement speed penalty will be applied to characters smaller than [danger*100]%." : "!"]", "Character Preference", features["body_size"]*100) as num|null
|
||||
if (new_body_size)
|
||||
new_body_size = clamp(new_body_size * 0.01, min, max)
|
||||
var/dorfy
|
||||
if((new_body_size + 0.01) < danger) // Adding 0.01 as a dumb fix to prevent the warning message from appearing when exactly at threshold... Not sure why that happens in the first place.
|
||||
dorfy = alert(user, "You have chosen a size below the slowdown threshold of [danger*100]%. For balancing purposes, the further you go below this percentage, the slower your character will be. Do you wish to keep this size?", "Speed Penalty Alert", "Yes", "Move it to the threshold", "No")
|
||||
if(dorfy == "Move it to the threshold")
|
||||
new_body_size = danger
|
||||
if(!dorfy) //Aborts if this var is somehow empty
|
||||
return
|
||||
if(dorfy != "No")
|
||||
features["body_size"] = new_body_size
|
||||
var/new_body_size = input(user, "Choose your desired sprite size: (90-125%)\nWarning: This may make your character look distorted. Additionally, any size under 100% takes a 10% maximum health penalty", "Character Preference", features["body_size"]*100) as num|null
|
||||
if(new_body_size)
|
||||
features["body_size"] = clamp(new_body_size * 0.01, CONFIG_GET(number/body_size_min), CONFIG_GET(number/body_size_max))
|
||||
|
||||
if("tongue")
|
||||
var/selected_custom_tongue = input(user, "Choose your desired tongue (none means your species tongue)", "Character Preference") as null|anything in GLOB.roundstart_tongues
|
||||
if(selected_custom_tongue)
|
||||
@@ -2653,6 +2641,12 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
else if(firstspace == name_length)
|
||||
real_name += "[pick(GLOB.last_names)]"
|
||||
|
||||
//reset size if applicable
|
||||
if(character.dna.features["body_size"])
|
||||
var/initial_old_size = character.dna.features["body_size"]
|
||||
character.dna.features["body_size"] = RESIZE_DEFAULT_SIZE
|
||||
character.dna.update_body_size(initial_old_size)
|
||||
|
||||
character.real_name = nameless ? "[real_name] #[rand(10000, 99999)]" : real_name
|
||||
character.name = character.real_name
|
||||
character.nameless = nameless
|
||||
@@ -2695,8 +2689,6 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
pref_species = new /datum/species/human
|
||||
save_character()
|
||||
|
||||
var/old_size = character.dna.features["body_size"]
|
||||
|
||||
character.dna.features = features.Copy()
|
||||
character.set_species(chosen_species, icon_update = FALSE, pref_load = TRUE)
|
||||
character.dna.species.eye_type = eye_type
|
||||
@@ -2706,6 +2698,10 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
character.dna.nameless = character.nameless
|
||||
character.dna.custom_species = character.custom_species
|
||||
|
||||
var/old_size = RESIZE_DEFAULT_SIZE
|
||||
if(isdwarf(character))
|
||||
character.dna.features["body_size"] = RESIZE_DEFAULT_SIZE
|
||||
|
||||
if((parent && parent.can_have_part("meat_type")) || pref_species.mutant_bodyparts["meat_type"])
|
||||
character.type_of_meat = GLOB.meat_types[features["meat_type"]]
|
||||
|
||||
|
||||
@@ -68,8 +68,8 @@
|
||||
|
||||
triggering = TRUE
|
||||
if (alert_observers)
|
||||
message_admins("Random Event triggering in 10 seconds: [name] (<a href='?src=[REF(src)];cancel=1'>CANCEL</a>)")
|
||||
sleep(100)
|
||||
message_admins("Random Event triggering in 30 seconds: [name] (<a href='?src=[REF(src)];cancel=1'>CANCEL</a>)")
|
||||
sleep(300)
|
||||
var/gamemode = SSticker.mode.config_tag
|
||||
var/players_amt = get_active_player_count(alive_check = TRUE, afk_check = TRUE, human_check = TRUE)
|
||||
if(!canSpawnEvent(players_amt, gamemode))
|
||||
|
||||
@@ -44,7 +44,13 @@
|
||||
priority_announce("Localized energetic flux wave detected on long range scanners. Expected location of impact: [impact_area.name].", "Anomaly Alert")
|
||||
|
||||
/datum/round_event/anomaly/start()
|
||||
var/turf/T = pick(get_area_turfs(impact_area))
|
||||
var/list/turf/valid = list()
|
||||
for(var/i in get_area_turfs(impact_area))
|
||||
var/turf/T = i
|
||||
if(T.density)
|
||||
continue
|
||||
valid += T
|
||||
var/turf/T = pick(valid)
|
||||
var/newAnomaly
|
||||
if(T)
|
||||
newAnomaly = new anomaly_path(T)
|
||||
|
||||
@@ -219,7 +219,7 @@
|
||||
suit_type = /obj/item/clothing/suit/space
|
||||
helmet_type = /obj/item/clothing/head/helmet/space
|
||||
mask_type = /obj/item/clothing/mask/breath
|
||||
storage_type = /obj/item/tank/internals/oxygen
|
||||
storage_type = /obj/item/tank/jetpack/void
|
||||
|
||||
|
||||
/obj/machinery/loot_locator
|
||||
@@ -275,6 +275,7 @@
|
||||
|
||||
/obj/machinery/computer/piratepad_control
|
||||
name = "cargo hold control terminal"
|
||||
resistance_flags = INDESTRUCTIBLE
|
||||
ui_x = 600
|
||||
ui_y = 230
|
||||
var/status_report = "Ready for delivery."
|
||||
|
||||
@@ -86,7 +86,7 @@
|
||||
else if(trapped == HOWLING_GHOST)
|
||||
visible_message("<span class='userdanger'><font size='5'>[pick("OooOOooooOOOoOoOOooooOOOOO", "BooOOooOooooOOOO", "BOO!", "WoOOoOoooOooo")]</font></span>")
|
||||
playsound(loc, 'sound/spookoween/ghosty_wind.ogg', 300, 1)
|
||||
new /mob/living/simple_animal/shade/howling_ghost(loc)
|
||||
new /mob/living/simple_animal/hostile/construct/shade/howling_ghost(loc)
|
||||
trapped = 0
|
||||
|
||||
else if(trapped == SCARY_BATS)
|
||||
@@ -123,7 +123,7 @@
|
||||
//Spookoween Ghost//
|
||||
////////////////////
|
||||
|
||||
/mob/living/simple_animal/shade/howling_ghost
|
||||
/mob/living/simple_animal/hostile/construct/shade/howling_ghost
|
||||
name = "ghost"
|
||||
real_name = "ghost"
|
||||
icon = 'icons/mob/mob.dmi'
|
||||
@@ -137,13 +137,13 @@
|
||||
layer = 4
|
||||
var/timer = 0
|
||||
|
||||
/mob/living/simple_animal/shade/howling_ghost/Initialize()
|
||||
/mob/living/simple_animal/hostile/construct/shade/howling_ghost/Initialize()
|
||||
. = ..()
|
||||
icon_state = pick("ghost","ghostian","ghostian2","ghostking","ghost1","ghost2")
|
||||
icon_living = icon_state
|
||||
timer = rand(1,15)
|
||||
|
||||
/mob/living/simple_animal/shade/howling_ghost/Life()
|
||||
/mob/living/simple_animal/hostile/construct/shade/howling_ghost/Life()
|
||||
..()
|
||||
timer--
|
||||
if(prob(20))
|
||||
@@ -152,16 +152,16 @@
|
||||
spooky_ghosty()
|
||||
timer = rand(1,15)
|
||||
|
||||
/mob/living/simple_animal/shade/howling_ghost/proc/EtherealMove(direction)
|
||||
/mob/living/simple_animal/hostile/construct/shade/howling_ghost/proc/EtherealMove(direction)
|
||||
forceMove(get_step(src, direction))
|
||||
setDir(direction)
|
||||
|
||||
/mob/living/simple_animal/shade/howling_ghost/proc/roam()
|
||||
/mob/living/simple_animal/hostile/construct/shade/howling_ghost/proc/roam()
|
||||
if(prob(80))
|
||||
var/direction = pick(NORTH,SOUTH,EAST,WEST,NORTHEAST,NORTHWEST,SOUTHEAST,SOUTHWEST)
|
||||
EtherealMove(direction)
|
||||
|
||||
/mob/living/simple_animal/shade/howling_ghost/proc/spooky_ghosty()
|
||||
/mob/living/simple_animal/hostile/construct/shade/howling_ghost/proc/spooky_ghosty()
|
||||
if(prob(20)) //haunt
|
||||
playsound(loc, pick('sound/spookoween/ghosty_wind.ogg','sound/spookoween/ghost_whisper.ogg','sound/spookoween/chain_rattling.ogg'), 300, 1)
|
||||
if(prob(10)) //flickers
|
||||
@@ -175,7 +175,7 @@
|
||||
step(I,direction)
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/shade/howling_ghost/CanPass(atom/movable/mover, turf/target)
|
||||
/mob/living/simple_animal/hostile/construct/shade/howling_ghost/CanPass(atom/movable/mover, turf/target)
|
||||
return 1
|
||||
|
||||
///////////////////////////
|
||||
|
||||
@@ -50,6 +50,13 @@
|
||||
var/cached_z
|
||||
/// I'm busy, don't move.
|
||||
var/busy = FALSE
|
||||
var/static/blacklisted_items = typecacheof(list(
|
||||
/obj/effect,
|
||||
/obj/belly,
|
||||
/obj/mafia_game_board,
|
||||
/obj/docking_port,
|
||||
/obj/shapeshift_holder,
|
||||
/obj/screen))
|
||||
|
||||
/mob/living/simple_animal/jacq/Initialize()
|
||||
..()
|
||||
@@ -112,7 +119,7 @@
|
||||
|
||||
/mob/living/simple_animal/jacq/proc/jacqrunes(message, mob/living/carbon/C) //Displays speechtext over Jacq for the user only.
|
||||
var/atom/hearer = C
|
||||
var/list/spans = list("spooky")
|
||||
var/list/spans = list("spooky")
|
||||
new /datum/chatmessage(message, src, hearer, spans)
|
||||
|
||||
|
||||
@@ -228,10 +235,13 @@
|
||||
return
|
||||
|
||||
var/new_obj = pick(subtypesof(/obj))
|
||||
//for(var/item in blacklist)
|
||||
// if(new_obj == item)
|
||||
// panic()
|
||||
for(var/item in blacklisted_items)
|
||||
if(is_type_in_typecache(new_obj, blacklisted_items))
|
||||
new_obj = /obj/item/reagent_containers/food/snacks/special_candy
|
||||
var/reward = new new_obj(C.loc)
|
||||
if(new_obj == /obj/item/reagent_containers/food/snacks/special_candy)
|
||||
new new_obj(C.loc)
|
||||
new new_obj(C.loc) //Giving them back their candies in case it's something from the blacklist or if the game literally rolled candies. What rotten luck.
|
||||
C.put_in_hands(reward)
|
||||
visible_message("<b>[src]</b> waves her hands, magicking up a [reward] from thin air, <span class='spooky'>\"There ye are [gender], enjoy! \"</span>")
|
||||
jacqrunes("There ye are [gender], enjoy!", C)
|
||||
|
||||
@@ -109,9 +109,12 @@ GLOBAL_LIST(labor_sheet_values)
|
||||
qdel(src)
|
||||
|
||||
/obj/machinery/mineral/labor_claim_console/emag_act(mob/user)
|
||||
if(!(obj_flags & EMAGGED))
|
||||
obj_flags |= EMAGGED
|
||||
to_chat(user, "<span class='warning'>PZZTTPFFFT</span>")
|
||||
. = ..()
|
||||
if((obj_flags & EMAGGED))
|
||||
return
|
||||
obj_flags |= EMAGGED
|
||||
to_chat(user, "<span class='warning'>PZZTTPFFFT</span>")
|
||||
return TRUE
|
||||
|
||||
/**********************Prisoner Collection Unit**************************/
|
||||
|
||||
|
||||
@@ -78,6 +78,28 @@
|
||||
popup.set_content(output)
|
||||
popup.open(FALSE)
|
||||
|
||||
/mob/dead/new_player/proc/age_verify()
|
||||
if(CONFIG_GET(flag/age_verification) && !check_rights_for(client, R_ADMIN) && !(client.ckey in GLOB.bunker_passthrough)) //make sure they are verified
|
||||
if(!client.set_db_player_flags())
|
||||
message_admins("Blocked [src] from new player panel because age gate could not access player database flags.")
|
||||
return FALSE
|
||||
else
|
||||
var/dbflags = client.prefs.db_flags
|
||||
if(dbflags & DB_FLAG_AGE_CONFIRMATION_INCOMPLETE) //they have not completed age gate
|
||||
var/age_verification = askuser(src, "Are you 18+", "Age Gate", "I am 18+", "I am not 18+", null, TRUE, null)
|
||||
if(age_verification != 1)
|
||||
client.add_system_note("Automated-Age-Gate", "Failed automatic age gate process")
|
||||
qdel(client) //kick the user
|
||||
return FALSE
|
||||
else
|
||||
//they claim to be of age, so allow them to continue and update their flags
|
||||
client.update_flag_db(DB_FLAG_AGE_CONFIRMATION_COMPLETE, TRUE)
|
||||
client.update_flag_db(DB_FLAG_AGE_CONFIRMATION_INCOMPLETE, FALSE)
|
||||
//log this
|
||||
message_admins("[ckey] has joined through the automated age gate process.")
|
||||
return TRUE
|
||||
return TRUE
|
||||
|
||||
/mob/dead/new_player/Topic(href, href_list[])
|
||||
if(src != usr)
|
||||
return 0
|
||||
@@ -85,6 +107,9 @@
|
||||
if(!client)
|
||||
return 0
|
||||
|
||||
if(!age_verify())
|
||||
return
|
||||
|
||||
//Determines Relevent Population Cap
|
||||
var/relevant_cap
|
||||
var/hpc = CONFIG_GET(number/hard_popcap)
|
||||
|
||||
@@ -611,7 +611,7 @@
|
||||
update_mobility()
|
||||
UpdateStaminaBuffer()
|
||||
update_health_hud()
|
||||
|
||||
|
||||
/mob/living/carbon/update_sight()
|
||||
if(!client)
|
||||
return
|
||||
|
||||
@@ -212,6 +212,7 @@
|
||||
// called when something steps onto a human
|
||||
// this could be made more general, but for now just handle mulebot
|
||||
/mob/living/carbon/human/Crossed(atom/movable/AM)
|
||||
SEND_SIGNAL(src, COMSIG_MOVABLE_CROSSED, AM)
|
||||
var/mob/living/simple_animal/bot/mulebot/MB = AM
|
||||
if(istype(MB))
|
||||
MB.RunOver(src)
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
/mob/living/carbon/human/getarmor(def_zone, type)
|
||||
if(HAS_TRAIT(src, TRAIT_ARMOR_BROKEN)) //trait that makes it act as if you have no armor at all, you take natural damage from all sources
|
||||
return 0
|
||||
var/armorval = 0
|
||||
var/organnum = 0
|
||||
|
||||
@@ -18,7 +20,6 @@
|
||||
organnum++
|
||||
return (armorval/max(organnum, 1))
|
||||
|
||||
|
||||
/mob/living/carbon/human/proc/checkarmor(obj/item/bodypart/def_zone, d_type)
|
||||
if(!d_type || !def_zone)
|
||||
return 0
|
||||
|
||||
@@ -1451,9 +1451,9 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
target.apply_damage(damage*1.5, attack_type, affecting, armor_block, wound_bonus = punchwoundbonus)
|
||||
target.apply_damage(damage*0.5, STAMINA, affecting, armor_block)
|
||||
log_combat(user, target, "kicked")
|
||||
else if(HAS_TRAIT(user, TRAIT_MAULER)) // mauler punches deal 1.3x raw damage + 1x stam damage, and have some armor pierce
|
||||
target.apply_damage(damage*1.3, attack_type, affecting, armor_block, wound_bonus = punchwoundbonus)
|
||||
target.apply_damage(damage, STAMINA, affecting, armor_block)
|
||||
else if(HAS_TRAIT(user, TRAIT_MAULER)) // mauler punches deal 1.1x raw damage + 1.3x stam damage, and have some armor pierce
|
||||
target.apply_damage(damage*1.1, attack_type, affecting, armor_block, wound_bonus = punchwoundbonus)
|
||||
target.apply_damage(damage*1.3, STAMINA, affecting, armor_block)
|
||||
log_combat(user, target, "punched (mauler)")
|
||||
else //other attacks deal full raw damage + 2x in stamina damage
|
||||
target.apply_damage(damage, attack_type, affecting, armor_block, wound_bonus = punchwoundbonus)
|
||||
|
||||
@@ -714,18 +714,25 @@
|
||||
return FALSE
|
||||
|
||||
/datum/action/innate/slime_puddle/Activate()
|
||||
var/mob/living/carbon/human/H = owner
|
||||
//if they have anything stuck to their hands, we immediately say 'no' and return
|
||||
for(var/obj/item/I in H.held_items)
|
||||
if(HAS_TRAIT(I, TRAIT_NODROP))
|
||||
to_chat(owner, "There's something stuck to your hand, stopping you from transforming!")
|
||||
return
|
||||
if(isjellyperson(owner) && IsAvailable())
|
||||
transforming = TRUE
|
||||
UpdateButtonIcon()
|
||||
var/mob/living/carbon/human/H = owner
|
||||
var/mutcolor = "#" + H.dna.features["mcolor"]
|
||||
if(!is_puddle)
|
||||
if(CHECK_MOBILITY(H, MOBILITY_USE))
|
||||
is_puddle = TRUE
|
||||
owner.cut_overlays()
|
||||
if(CHECK_MOBILITY(H, MOBILITY_USE)) //if we can use items, we can turn into a puddle
|
||||
is_puddle = TRUE //so we know which transformation to use when its used
|
||||
owner.cut_overlays() //we dont show our normal sprite, we show a puddle sprite
|
||||
var/obj/effect/puddle_effect = new puddle_into_effect(get_turf(owner), owner.dir)
|
||||
puddle_effect.color = mutcolor
|
||||
H.Stun(in_transformation_duration, ignore_canstun = TRUE)
|
||||
H.Stun(in_transformation_duration, ignore_canstun = TRUE) //cant move while transforming
|
||||
|
||||
//series of traits that make up the puddle behaviour
|
||||
ADD_TRAIT(H, TRAIT_PARALYSIS_L_ARM, SLIMEPUDDLE_TRAIT)
|
||||
ADD_TRAIT(H, TRAIT_PARALYSIS_R_ARM, SLIMEPUDDLE_TRAIT)
|
||||
ADD_TRAIT(H, TRAIT_MOBILITY_NOPICKUP, SLIMEPUDDLE_TRAIT)
|
||||
@@ -733,19 +740,30 @@
|
||||
ADD_TRAIT(H, TRAIT_SPRINT_LOCKED, SLIMEPUDDLE_TRAIT)
|
||||
ADD_TRAIT(H, TRAIT_COMBAT_MODE_LOCKED, SLIMEPUDDLE_TRAIT)
|
||||
ADD_TRAIT(H, TRAIT_MOBILITY_NOREST, SLIMEPUDDLE_TRAIT)
|
||||
ADD_TRAIT(H, TRAIT_ARMOR_BROKEN, SLIMEPUDDLE_TRAIT)
|
||||
H.update_disabled_bodyparts(silent = TRUE) //silently update arms to be paralysed
|
||||
|
||||
H.add_movespeed_modifier(/datum/movespeed_modifier/slime_puddle)
|
||||
H.update_disabled_bodyparts(silent = TRUE)
|
||||
|
||||
H.layer -= 1 //go one layer down so people go over you
|
||||
ENABLE_BITFIELD(H.pass_flags, PASSMOB)
|
||||
squeak = H.AddComponent(/datum/component/squeak, custom_sounds = list('sound/effects/blobattack.ogg'))
|
||||
sleep(in_transformation_duration)
|
||||
ENABLE_BITFIELD(H.pass_flags, PASSMOB) //this actually lets people pass over you
|
||||
squeak = H.AddComponent(/datum/component/squeak, custom_sounds = list('sound/effects/blobattack.ogg')) //blorble noise when people step on you
|
||||
|
||||
//if the user is a changeling, retract their sting
|
||||
H.unset_sting()
|
||||
|
||||
sleep(in_transformation_duration) //wait for animation to end
|
||||
|
||||
//set the puddle overlay up
|
||||
var/mutable_appearance/puddle_overlay = mutable_appearance(icon = puddle_icon, icon_state = puddle_state)
|
||||
puddle_overlay.color = mutcolor
|
||||
tracked_overlay = puddle_overlay
|
||||
owner.add_overlay(puddle_overlay)
|
||||
|
||||
transforming = FALSE
|
||||
UpdateButtonIcon()
|
||||
else
|
||||
//like the above, but reverse everything done!
|
||||
owner.cut_overlay(tracked_overlay)
|
||||
var/obj/effect/puddle_effect = new puddle_from_effect(get_turf(owner), owner.dir)
|
||||
puddle_effect.color = mutcolor
|
||||
@@ -758,6 +776,7 @@
|
||||
REMOVE_TRAIT(H, TRAIT_SPRINT_LOCKED, SLIMEPUDDLE_TRAIT)
|
||||
REMOVE_TRAIT(H, TRAIT_COMBAT_MODE_LOCKED, SLIMEPUDDLE_TRAIT)
|
||||
REMOVE_TRAIT(H, TRAIT_MOBILITY_NOREST, SLIMEPUDDLE_TRAIT)
|
||||
REMOVE_TRAIT(H, TRAIT_ARMOR_BROKEN, SLIMEPUDDLE_TRAIT)
|
||||
H.update_disabled_bodyparts(silent = TRUE)
|
||||
H.remove_movespeed_modifier(/datum/movespeed_modifier/slime_puddle)
|
||||
H.layer += 1 //go one layer back above!
|
||||
|
||||
@@ -15,8 +15,13 @@
|
||||
skinned_type = /obj/item/stack/sheet/animalhide/human
|
||||
var/info_text = "You are a <span class='danger'>Vampire</span>. You will slowly but constantly lose blood if outside of a coffin. If inside a coffin, you will slowly heal. You may gain more blood by grabbing a live victim and using your drain ability."
|
||||
species_category = SPECIES_CATEGORY_UNDEAD
|
||||
var/batform_enabled = TRUE
|
||||
|
||||
/datum/species/vampire/check_roundstart_eligible()
|
||||
/datum/species/vampire/roundstart
|
||||
id = SPECIES_VAMPIRE_WEAK
|
||||
batform_enabled = FALSE
|
||||
|
||||
/datum/species/vampire/roundstart/check_roundstart_eligible()
|
||||
if(SSevents.holidays && SSevents.holidays[HALLOWEEN])
|
||||
return TRUE
|
||||
return FALSE
|
||||
@@ -27,8 +32,9 @@
|
||||
if(!C.dna.skin_tone_override)
|
||||
C.skin_tone = "albino"
|
||||
C.update_body(0)
|
||||
var/obj/effect/proc_holder/spell/targeted/shapeshift/bat/B = new
|
||||
C.AddSpell(B)
|
||||
if(batform_enabled)
|
||||
var/obj/effect/proc_holder/spell/targeted/shapeshift/bat/B = new
|
||||
C.AddSpell(B)
|
||||
|
||||
/datum/species/vampire/on_species_loss(mob/living/carbon/C)
|
||||
. = ..()
|
||||
|
||||
@@ -443,6 +443,7 @@
|
||||
key = "me"
|
||||
key_third_person = "custom"
|
||||
message = null
|
||||
emote_type = EMOTE_BOTH
|
||||
|
||||
/datum/emote/living/custom/proc/check_invalid(mob/user, input)
|
||||
if(stop_bad_mime.Find(input, 1, 1))
|
||||
@@ -462,24 +463,12 @@
|
||||
else if(!params)
|
||||
var/custom_emote = stripped_multiline_input_or_reflect(user, "Choose an emote to display.", "Custom Emote", null, MAX_MESSAGE_LEN)
|
||||
if(custom_emote && !check_invalid(user, custom_emote))
|
||||
var/type = input("Is this a visible or hearable emote?") as null|anything in list("Visible", "Hearable")
|
||||
switch(type)
|
||||
if("Visible")
|
||||
emote_type = EMOTE_VISIBLE
|
||||
if("Hearable")
|
||||
emote_type = EMOTE_AUDIBLE
|
||||
else
|
||||
alert("Unable to use this emote, must be either hearable or visible.")
|
||||
return
|
||||
message = custom_emote
|
||||
else
|
||||
message = params
|
||||
if(type_override)
|
||||
emote_type = type_override
|
||||
message = user.say_emphasis(message)
|
||||
. = ..()
|
||||
message = null
|
||||
emote_type = EMOTE_VISIBLE
|
||||
|
||||
/datum/emote/living/custom/replace_pronoun(mob/user, message)
|
||||
return message
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
var/can_repair_constructs = FALSE
|
||||
var/can_repair_self = FALSE
|
||||
var/runetype
|
||||
var/original_mind
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/Initialize()
|
||||
. = ..()
|
||||
@@ -66,6 +67,11 @@
|
||||
CR.button.screen_loc = "6:[pos],4:-2"
|
||||
CR.button.moved = "6:[pos],4:-2"
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/death()
|
||||
if(original_mind)
|
||||
transfer_ckey(original_mind)
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/Login()
|
||||
..()
|
||||
to_chat(src, playstyle_string)
|
||||
@@ -107,7 +113,7 @@
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/electrocute_act(shock_damage, source, siemens_coeff = 1, flags = NONE)
|
||||
return 0
|
||||
return FALSE
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/adjustHealth(amount, updating_health = TRUE, forced = FALSE)
|
||||
. = ..()
|
||||
|
||||
@@ -87,7 +87,7 @@ Difficulty: Medium
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/visible_message(message, self_message, blind_message, vision_distance = DEFAULT_MESSAGE_RANGE, list/ignored_mobs, mob/target, target_message)
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/visible_message(message, self_message, blind_message, vision_distance = DEFAULT_MESSAGE_RANGE, list/ignored_mobs, mob/target, target_message, omni = FALSE)
|
||||
if(swooping & SWOOP_INVULNERABLE) //to suppress attack messages without overriding every single proc that could send a message saying we got hit
|
||||
return
|
||||
return ..()
|
||||
|
||||
@@ -1,53 +1,33 @@
|
||||
/mob/living/simple_animal/shade
|
||||
/mob/living/simple_animal/hostile/construct/shade
|
||||
name = "Shade"
|
||||
real_name = "Shade"
|
||||
desc = "A bound spirit."
|
||||
gender = PLURAL
|
||||
icon = 'icons/mob/mob.dmi'
|
||||
icon_state = "shade"
|
||||
icon_living = "shade"
|
||||
mob_biotypes = MOB_SPIRIT
|
||||
maxHealth = 40
|
||||
health = 40
|
||||
spacewalk = TRUE
|
||||
healable = 0
|
||||
speak_emote = list("hisses")
|
||||
emote_hear = list("wails.","screeches.")
|
||||
response_help_continuous = "puts their hand through"
|
||||
response_help_simple = "put your hand through"
|
||||
response_disarm_continuous = "flails at"
|
||||
response_disarm_simple = "flail at"
|
||||
response_harm_continuous = "punches"
|
||||
response_harm_simple = "punch"
|
||||
speak_chance = 1
|
||||
melee_damage_lower = 5
|
||||
melee_damage_upper = 12
|
||||
attack_verb_continuous = "metaphysically strikes"
|
||||
attack_verb_simple = "metaphysically strike"
|
||||
minbodytemp = 0
|
||||
maxbodytemp = INFINITY
|
||||
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
|
||||
stop_automated_movement = 1
|
||||
status_flags = 0
|
||||
faction = list("cult")
|
||||
status_flags = CANPUSH
|
||||
movement_type = FLYING
|
||||
speed = -1 //they don't have to lug a body made of runed metal around
|
||||
loot = list(/obj/item/ectoplasm)
|
||||
del_on_death = TRUE
|
||||
initial_language_holder = /datum/language_holder/construct
|
||||
blood_volume = 0
|
||||
has_field_of_vision = FALSE //we are a spoopy ghost
|
||||
playstyle_string = "<span class='big bold'>You are a shade!</span><b> Your job is to survive until you are granted a shell, and help out cultists with casting runes!</b>"
|
||||
|
||||
/mob/living/simple_animal/shade/death()
|
||||
/mob/living/simple_animal/hostile/construct/shade/death()
|
||||
deathmessage = "lets out a contented sigh as [p_their()] form unwinds."
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/shade/canSuicide()
|
||||
/mob/living/simple_animal/hostile/construct/shade/canSuicide()
|
||||
if(istype(loc, /obj/item/soulstone)) //do not suicide inside the soulstone
|
||||
return 0
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/shade/attack_animal(mob/living/simple_animal/M)
|
||||
/mob/living/simple_animal/hostile/construct/shade/attack_animal(mob/living/simple_animal/M)
|
||||
if(isconstruct(M))
|
||||
var/mob/living/simple_animal/hostile/construct/C = M
|
||||
if(!C.can_repair_constructs)
|
||||
@@ -62,7 +42,7 @@
|
||||
else if(src != M)
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/shade/attackby(obj/item/O, mob/user, params) //Marker -Agouri
|
||||
/mob/living/simple_animal/hostile/construct/shade/attackby(obj/item/O, mob/user, params) //Marker -Agouri
|
||||
if(istype(O, /obj/item/soulstone))
|
||||
var/obj/item/soulstone/SS = O
|
||||
SS.transfer_soul("SHADE", src, user)
|
||||
|
||||
+22
-12
@@ -127,8 +127,9 @@
|
||||
* * ignored_mobs (optional) doesn't show any message to any given mob in the list.
|
||||
* * target (optional) is the other mob involved with the visible message. For example, the attacker in many combat messages.
|
||||
* * target_message (optional) is what the target mob will see e.g. "[src] does something to you!"
|
||||
* * omni (optional) if TRUE, will show to users no matter what.
|
||||
*/
|
||||
/atom/proc/visible_message(message, self_message, blind_message, vision_distance = DEFAULT_MESSAGE_RANGE, ignored_mobs, mob/target, target_message)
|
||||
/atom/proc/visible_message(message, self_message, blind_message, vision_distance = DEFAULT_MESSAGE_RANGE, ignored_mobs, mob/target, target_message, omni = FALSE)
|
||||
var/turf/T = get_turf(src)
|
||||
if(!T)
|
||||
return
|
||||
@@ -139,20 +140,26 @@
|
||||
|
||||
if(target_message && target && istype(target) && target.client)
|
||||
hearers -= target
|
||||
//This entire if/else chain could be in two lines but isn't for readibilties sake.
|
||||
var/msg = target_message
|
||||
if(target.see_invisible<invisibility) //if src is invisible to us,
|
||||
msg = blind_message
|
||||
//the light object is dark and not invisible to us, darkness does not matter if you're directly next to the target
|
||||
else if(T.lighting_object && T.lighting_object.invisibility <= target.see_invisible && T.is_softly_lit() && !in_range(T,target))
|
||||
msg = blind_message
|
||||
if(msg)
|
||||
target.show_message(msg, MSG_VISUAL,blind_message, MSG_AUDIBLE)
|
||||
if(omni)
|
||||
target.show_message(target_message)
|
||||
else
|
||||
//This entire if/else chain could be in two lines but isn't for readibilties sake.
|
||||
var/msg = target_message
|
||||
if(target.see_invisible<invisibility) //if src is invisible to us,
|
||||
msg = blind_message
|
||||
//the light object is dark and not invisible to us, darkness does not matter if you're directly next to the target
|
||||
else if(T.lighting_object && T.lighting_object.invisibility <= target.see_invisible && T.is_softly_lit() && !in_range(T,target))
|
||||
msg = blind_message
|
||||
if(msg)
|
||||
target.show_message(msg, MSG_VISUAL,blind_message, MSG_AUDIBLE)
|
||||
if(self_message)
|
||||
hearers -= src
|
||||
for(var/mob/M in hearers)
|
||||
if(!M.client)
|
||||
continue
|
||||
if(omni)
|
||||
M.show_message(message)
|
||||
continue
|
||||
//This entire if/else chain could be in two lines but isn't for readibilties sake.
|
||||
var/msg = message
|
||||
//CITADEL EDIT, required for vore code to remove (T != loc && T != src)) as a check
|
||||
@@ -167,10 +174,13 @@
|
||||
M.show_message(msg, MSG_VISUAL,blind_message, MSG_AUDIBLE)
|
||||
|
||||
///Adds the functionality to self_message.
|
||||
mob/visible_message(message, self_message, blind_message, vision_distance = DEFAULT_MESSAGE_RANGE, list/ignored_mobs, mob/target, target_message)
|
||||
/mob/visible_message(message, self_message, blind_message, vision_distance = DEFAULT_MESSAGE_RANGE, list/ignored_mobs, mob/target, target_message, omni = FALSE)
|
||||
. = ..()
|
||||
if(self_message && target != src)
|
||||
show_message(self_message, MSG_VISUAL, blind_message, MSG_AUDIBLE)
|
||||
if(!omni)
|
||||
show_message(self_message, MSG_VISUAL, blind_message, MSG_AUDIBLE)
|
||||
else
|
||||
show_message(self_message)
|
||||
|
||||
/**
|
||||
* Show a message to all mobs in earshot of this atom
|
||||
|
||||
@@ -39,15 +39,6 @@ proc/get_top_level_mob(var/mob/S)
|
||||
else if(!params)
|
||||
var/subtle_emote = stripped_multiline_input_or_reflect(user, "Choose an emote to display.", "Subtle", null, MAX_MESSAGE_LEN)
|
||||
if(subtle_emote && !check_invalid(user, subtle_emote))
|
||||
var/type = input("Is this a visible or hearable emote?") as null|anything in list("Visible", "Hearable")
|
||||
switch(type)
|
||||
if("Visible")
|
||||
emote_type = EMOTE_VISIBLE
|
||||
if("Hearable")
|
||||
emote_type = EMOTE_AUDIBLE
|
||||
else
|
||||
alert("Unable to use this emote, must be either hearable or visible.")
|
||||
return
|
||||
message = subtle_emote
|
||||
else
|
||||
return FALSE
|
||||
@@ -69,11 +60,7 @@ proc/get_top_level_mob(var/mob/S)
|
||||
if(M.stat == DEAD && M.client && (M.client.prefs.chat_toggles & CHAT_GHOSTSIGHT) && !(M in viewers(T, null)))
|
||||
M.show_message(message)
|
||||
|
||||
if(emote_type == EMOTE_AUDIBLE)
|
||||
user.audible_message(message=message,hearing_distance=1)
|
||||
else
|
||||
user.visible_message(message=message,self_message=message,vision_distance=1)
|
||||
|
||||
user.visible_message(message = message, self_message = message, vision_distance = 1, omni = TRUE)
|
||||
|
||||
///////////////// SUBTLE 2: NO GHOST BOOGALOO
|
||||
|
||||
@@ -122,10 +109,7 @@ proc/get_top_level_mob(var/mob/S)
|
||||
user.log_message(message, LOG_SUBTLER)
|
||||
message = "<b>[user]</b> " + "<i>[user.say_emphasis(message)]</i>"
|
||||
|
||||
if(emote_type == EMOTE_AUDIBLE)
|
||||
user.audible_message(message=message,hearing_distance=1, ignored_mobs = GLOB.dead_mob_list)
|
||||
else
|
||||
user.visible_message(message=message,self_message=message,vision_distance=1, ignored_mobs = GLOB.dead_mob_list)
|
||||
user.visible_message(message = message, self_message = message, vision_distance = 1, ignored_mobs = GLOB.dead_mob_list, omni = TRUE)
|
||||
|
||||
///////////////// VERB CODE
|
||||
/mob/living/verb/subtle()
|
||||
|
||||
@@ -617,7 +617,7 @@
|
||||
return 1
|
||||
if(ispath(MP, /mob/living/simple_animal/hostile/mushroom))
|
||||
return 1
|
||||
if(ispath(MP, /mob/living/simple_animal/shade))
|
||||
if(ispath(MP, /mob/living/simple_animal/hostile/construct/shade))
|
||||
return 1
|
||||
if(ispath(MP, /mob/living/simple_animal/hostile/killertomato))
|
||||
return 1
|
||||
|
||||
@@ -20,5 +20,6 @@
|
||||
flags = IGNORE_NOSLOW
|
||||
|
||||
/datum/movespeed_modifier/slime_puddle
|
||||
multiplicative_slowdown = 2
|
||||
multiplicative_slowdown = 4.5
|
||||
flags = IGNORE_NOSLOW
|
||||
variable = TRUE
|
||||
|
||||
@@ -111,6 +111,7 @@
|
||||
var/obj/machinery/computer/apc_control/remote_control = null
|
||||
var/mob/living/carbon/hijacker
|
||||
var/hijackerlast = TRUE
|
||||
var/being_hijacked = FALSE
|
||||
|
||||
/obj/machinery/power/apc/unlocked
|
||||
locked = FALSE
|
||||
@@ -902,7 +903,7 @@
|
||||
if(H && !H.stealthmode && H.toggled)
|
||||
abilitiesavail = TRUE
|
||||
var/list/data = list(
|
||||
"locked" = locked,
|
||||
"locked" = locked && !(integration_cog && is_servant_of_ratvar(user)) && !area.hasSiliconAccessInArea(user, PRIVILEDGES_SILICON|PRIVILEDGES_DRONE),
|
||||
"failTime" = failure_timer,
|
||||
"isOperating" = operating,
|
||||
"externalPower" = main_status,
|
||||
@@ -1119,10 +1120,14 @@
|
||||
/obj/machinery/power/apc/proc/hijack(mob/living/L)
|
||||
if (!istype(L))
|
||||
return
|
||||
if(being_hijacked)
|
||||
to_chat(L, "<span class='warning'>This APC is already being hijacked!</span>")
|
||||
return
|
||||
if (hijacker && hijacker != L)
|
||||
var/obj/item/implant/hijack/H = L.getImplant(/obj/item/implant/hijack)
|
||||
to_chat(L, "<span class='warning'>Someone already has control of this APC. Beginning counter-hijack.</span>")
|
||||
H.hijacking = TRUE
|
||||
being_hijacked = TRUE
|
||||
if (do_after(L,20 SECONDS,target=src))
|
||||
hijacker.toggleSiliconAccessArea(area)
|
||||
if (L.toggleSiliconAccessArea(area))
|
||||
@@ -1130,23 +1135,28 @@
|
||||
update_icon()
|
||||
set_hijacked_lighting()
|
||||
H.hijacking = FALSE
|
||||
being_hijacked = FALSE
|
||||
return
|
||||
else
|
||||
to_chat(L, "<span class='warning'>Aborting.</span>")
|
||||
H.hijacking = FALSE
|
||||
being_hijacked = FALSE
|
||||
return
|
||||
to_chat(L, "<span class='notice'>Beginning hijack of APC.</span>")
|
||||
var/obj/item/implant/hijack/H = L.getImplant(/obj/item/implant/hijack)
|
||||
H.hijacking = TRUE
|
||||
being_hijacked = TRUE
|
||||
if (do_after(L,H.stealthmode ? 12 SECONDS : 5 SECONDS,target=src))
|
||||
if (L.toggleSiliconAccessArea(area))
|
||||
hijacker = L
|
||||
update_icon()
|
||||
set_hijacked_lighting()
|
||||
H.hijacking = FALSE
|
||||
being_hijacked = FALSE
|
||||
else
|
||||
to_chat(L, "<span class='warning'>Aborting.</span>")
|
||||
H.hijacking = FALSE
|
||||
being_hijacked = FALSE
|
||||
return
|
||||
|
||||
/obj/machinery/power/apc/proc/malfhack(mob/living/silicon/ai/malf)
|
||||
|
||||
@@ -54,11 +54,10 @@
|
||||
|
||||
/obj/item/gun/ballistic/automatic/pistol/m1911
|
||||
name = "\improper M1911"
|
||||
desc = "A classic .45 handgun with a small magazine capacity."
|
||||
desc = "A classic .45 handgun with a small magazine capacity. Has a threaded barrel for suppressors."
|
||||
icon_state = "m1911"
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
mag_type = /obj/item/ammo_box/magazine/m45
|
||||
can_suppress = FALSE
|
||||
|
||||
/obj/item/gun/ballistic/automatic/pistol/m1911/no_mag
|
||||
spawnwithmagazine = FALSE
|
||||
@@ -67,6 +66,7 @@
|
||||
name = "\improper Kitchen Gun (TM)"
|
||||
desc = "Say goodbye to dirt with Kitchen Gun (TM)! Laser sight and night vision accessories sold separately."
|
||||
icon_state = "kitchengun"
|
||||
can_suppress = FALSE
|
||||
mag_type = /obj/item/ammo_box/magazine/m45/kitchengun
|
||||
|
||||
/obj/item/gun/ballistic/automatic/pistol/deagle
|
||||
@@ -98,11 +98,10 @@
|
||||
|
||||
/obj/item/gun/ballistic/automatic/pistol/APS
|
||||
name = "stechkin APS pistol"
|
||||
desc = "The original Russian version of a widely used Syndicate sidearm. Uses 9mm ammo."
|
||||
desc = "The original Russian version of a widely used Syndicate sidearm. Uses 9mm ammo. Has a threaded barrel for suppressors."
|
||||
icon_state = "aps"
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
mag_type = /obj/item/ammo_box/magazine/pistolm9mm
|
||||
can_suppress = FALSE
|
||||
burst_size = 3
|
||||
fire_delay = 2
|
||||
actions_types = list(/datum/action/item_action/toggle_firemode)
|
||||
@@ -136,7 +135,7 @@
|
||||
mag_type = /obj/item/ammo_box/magazine/sniper_rounds
|
||||
fire_delay = 50
|
||||
burst_size = 1
|
||||
can_suppress = 0
|
||||
can_suppress = FALSE
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
actions_types = list()
|
||||
fire_sound = 'sound/weapons/blastcannon.ogg'
|
||||
|
||||
@@ -83,6 +83,16 @@
|
||||
updateUsrDialog()
|
||||
update_icon()
|
||||
return
|
||||
|
||||
if(beaker)
|
||||
if(istype(I, /obj/item/reagent_containers/dropper))
|
||||
var/obj/item/reagent_containers/dropper/D = I
|
||||
D.afterattack(beaker, user, 1)
|
||||
return
|
||||
if(istype(I, /obj/item/reagent_containers/syringe))
|
||||
var/obj/item/reagent_containers/syringe/S = I
|
||||
S.afterattack(beaker, user, 1)
|
||||
return
|
||||
return ..()
|
||||
|
||||
/obj/machinery/chem_heater/on_deconstruction()
|
||||
|
||||
@@ -970,7 +970,7 @@
|
||||
M.emote("gasp")
|
||||
log_combat(M, M, "revived", src)
|
||||
var/list/policies = CONFIG_GET(keyed_list/policyconfig)
|
||||
var/timelimit = CONFIG_GET(number/defib_cmd_time_limit)
|
||||
var/timelimit = CONFIG_GET(number/defib_cmd_time_limit) * 10 //the config is in seconds, not deciseconds
|
||||
var/late = timelimit && (tplus > timelimit)
|
||||
var/policy = late? policies[POLICYCONFIG_ON_DEFIB_LATE] : policies[POLICYCONFIG_ON_DEFIB_INTACT]
|
||||
if(policy)
|
||||
@@ -1321,7 +1321,7 @@
|
||||
pH = 11
|
||||
value = REAGENT_VALUE_COMMON //not any higher. Ambrosia is a milestone for hydroponics already.
|
||||
|
||||
|
||||
|
||||
//Earthsblood is still a wonderdrug. Just... don't expect to be able to mutate something that makes plants so healthy.
|
||||
/datum/reagent/medicine/earthsblood/on_hydroponics_apply(obj/item/seeds/myseed, datum/reagents/chems, obj/machinery/hydroponics/mytray, mob/user)
|
||||
. = ..()
|
||||
@@ -1335,7 +1335,7 @@
|
||||
myseed.adjust_yield(round(chems.get_reagent_amount(src.type) * 1))
|
||||
myseed.adjust_endurance(round(chems.get_reagent_amount(src.type) * 0.5))
|
||||
myseed.adjust_production(-round(chems.get_reagent_amount(src.type) * 0.5))
|
||||
|
||||
|
||||
/datum/reagent/medicine/earthsblood/on_mob_life(mob/living/carbon/M)
|
||||
M.adjustBruteLoss(-3 * REM, FALSE)
|
||||
M.adjustFireLoss(-3 * REM, FALSE)
|
||||
|
||||
@@ -132,7 +132,7 @@
|
||||
lich.real_name = mind.name
|
||||
mind.transfer_to(lich)
|
||||
mind.grab_ghost(force=TRUE)
|
||||
lich.hardset_dna(null,null,null,lich.real_name,null, new /datum/species/skeleton)
|
||||
lich.hardset_dna(null,null,null,lich.real_name,null, new /datum/species/skeleton/space)
|
||||
to_chat(lich, "<span class='warning'>Your bones clatter and shudder as you are pulled back into this world!</span>")
|
||||
var/turf/body_turf = get_turf(old_body)
|
||||
lich.DefaultCombatKnockdown(200 + 200*resurrections)
|
||||
|
||||
@@ -70,7 +70,7 @@
|
||||
if(O.organ_flags & ORGAN_FAILING)
|
||||
O.applyOrganDamage(-5)
|
||||
var/list/policies = CONFIG_GET(keyed_list/policyconfig)
|
||||
var/timelimit = CONFIG_GET(number/defib_cmd_time_limit)
|
||||
var/timelimit = CONFIG_GET(number/defib_cmd_time_limit) * 10 //the config is in seconds, not deciseconds
|
||||
var/late = timelimit && (tplus > timelimit)
|
||||
var/policy = late? policies[POLICYCONFIG_ON_DEFIB_LATE] : policies[POLICYCONFIG_ON_DEFIB_INTACT]
|
||||
if(policy)
|
||||
|
||||
@@ -50,7 +50,7 @@ TGS_PROTECT_DATUM(/datum/tgs_api)
|
||||
/datum/tgs_api/proc/ChatTargetedBroadcast(message, admin_only)
|
||||
return TGS_UNIMPLEMENTED
|
||||
|
||||
/datum/tgs_api/proc/ChatPrivateMessage(message, admin_only)
|
||||
/datum/tgs_api/proc/ChatPrivateMessage(message, datum/tgs_chat_user/user)
|
||||
return TGS_UNIMPLEMENTED
|
||||
|
||||
/datum/tgs_api/proc/SecurityLevel()
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
var/warned_custom_commands = FALSE
|
||||
|
||||
/datum/tgs_api/v3210/ApiVersion()
|
||||
return new /datum/tgs_version("3.2.1.0")
|
||||
return new /datum/tgs_version("3.2.1.3")
|
||||
|
||||
/datum/tgs_api/v3210/proc/trim_left(text)
|
||||
for (var/i = 1 to length(text))
|
||||
@@ -180,7 +180,7 @@
|
||||
ExportService(SERVICE_REQUEST_KILL_PROCESS)
|
||||
|
||||
/datum/tgs_api/v3210/ChatChannelInfo()
|
||||
return list()
|
||||
return list() // :omegalul:
|
||||
|
||||
/datum/tgs_api/v3210/ChatBroadcast(message, list/channels)
|
||||
if(channels)
|
||||
|
||||
@@ -42,5 +42,11 @@
|
||||
var/datum/tgs_chat_command/stc = new command_type
|
||||
var/datum/tgs_chat_user/user = new
|
||||
user.friendly_name = sender
|
||||
|
||||
// Discord hack, fix the mention if it's only numbers (fuck you IRC trolls)
|
||||
var/regex/discord_id_regex = regex(@"^[0-9]+$")
|
||||
if(findtext(sender, discord_id_regex))
|
||||
sender = "<@[sender]>"
|
||||
|
||||
user.mention = sender
|
||||
return stc.Run(user, params) || TRUE
|
||||
|
||||
@@ -114,13 +114,6 @@
|
||||
/datum/tgs_api/v4/OnInitializationComplete()
|
||||
Export(TGS4_COMM_SERVER_PRIMED)
|
||||
|
||||
var/tgs4_secret_sleep_offline_sauce = 24051994
|
||||
var/old_sleep_offline = world.sleep_offline
|
||||
world.sleep_offline = tgs4_secret_sleep_offline_sauce
|
||||
sleep(1)
|
||||
if(world.sleep_offline == tgs4_secret_sleep_offline_sauce) //if not someone changed it
|
||||
world.sleep_offline = old_sleep_offline
|
||||
|
||||
/datum/tgs_api/v4/OnTopic(T)
|
||||
var/list/params = params2list(T)
|
||||
var/their_sCK = params[TGS4_INTEROP_ACCESS_IDENTIFIER]
|
||||
@@ -255,7 +248,7 @@
|
||||
return instance_name
|
||||
|
||||
/datum/tgs_api/v4/TestMerges()
|
||||
return cached_test_merges
|
||||
return cached_test_merges.Copy()
|
||||
|
||||
/datum/tgs_api/v4/EndProcess()
|
||||
Export(TGS4_COMM_END_PROCESS)
|
||||
|
||||
+10
-11
@@ -15,8 +15,10 @@
|
||||
var/datum/tgs_revision_information/revision
|
||||
var/list/chat_channels
|
||||
|
||||
var/initialized = FALSE
|
||||
|
||||
/datum/tgs_api/v5/ApiVersion()
|
||||
return new /datum/tgs_version("5.2.1")
|
||||
return new /datum/tgs_version(TGS_DMAPI_VERSION)
|
||||
|
||||
/datum/tgs_api/v5/OnWorldNew(minimum_required_security_level)
|
||||
server_port = world.params[DMAPI5_PARAM_SERVER_PORT]
|
||||
@@ -79,6 +81,7 @@
|
||||
chat_channels = list()
|
||||
DecodeChannels(runtime_information)
|
||||
|
||||
initialized = TRUE
|
||||
return TRUE
|
||||
|
||||
/datum/tgs_api/v5/proc/RequireInitialBridgeResponse()
|
||||
@@ -88,13 +91,6 @@
|
||||
/datum/tgs_api/v5/OnInitializationComplete()
|
||||
Bridge(DMAPI5_BRIDGE_COMMAND_PRIME)
|
||||
|
||||
var/tgs4_secret_sleep_offline_sauce = 29051994
|
||||
var/old_sleep_offline = world.sleep_offline
|
||||
world.sleep_offline = tgs4_secret_sleep_offline_sauce
|
||||
sleep(1)
|
||||
if(world.sleep_offline == tgs4_secret_sleep_offline_sauce) //if not someone changed it
|
||||
world.sleep_offline = old_sleep_offline
|
||||
|
||||
/datum/tgs_api/v5/proc/TopicResponse(error_message = null)
|
||||
var/list/response = list()
|
||||
response[DMAPI5_RESPONSE_ERROR_MESSAGE] = error_message
|
||||
@@ -102,10 +98,13 @@
|
||||
return json_encode(response)
|
||||
|
||||
/datum/tgs_api/v5/OnTopic(T)
|
||||
if(!initialized)
|
||||
return FALSE //continue world/Topic
|
||||
|
||||
var/list/params = params2list(T)
|
||||
var/json = params[DMAPI5_TOPIC_DATA]
|
||||
if(!json)
|
||||
return FALSE //continue world/Topic
|
||||
return FALSE
|
||||
|
||||
var/list/topic_parameters = json_decode(json)
|
||||
if(!topic_parameters)
|
||||
@@ -282,7 +281,7 @@
|
||||
|
||||
/datum/tgs_api/v5/TestMerges()
|
||||
RequireInitialBridgeResponse()
|
||||
return test_merges
|
||||
return test_merges.Copy()
|
||||
|
||||
/datum/tgs_api/v5/EndProcess()
|
||||
Bridge(DMAPI5_BRIDGE_COMMAND_KILL)
|
||||
@@ -327,7 +326,7 @@
|
||||
|
||||
/datum/tgs_api/v5/ChatChannelInfo()
|
||||
RequireInitialBridgeResponse()
|
||||
return chat_channels
|
||||
return chat_channels.Copy()
|
||||
|
||||
/datum/tgs_api/v5/proc/DecodeChannels(chat_update_json)
|
||||
var/list/chat_channels_json = chat_update_json[DMAPI5_CHAT_UPDATE_CHANNELS]
|
||||
|
||||
Reference in New Issue
Block a user