diff --git a/Dockerfile b/Dockerfile
index a0370935..ec3694c7 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,4 +1,4 @@
-FROM tgstation/byond:512.1484 as base
+FROM tgstation/byond:512.1488 as base
FROM base as build_base
diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm
index bb6fab9f..935d71a3 100644
--- a/code/__DEFINES/misc.dm
+++ b/code/__DEFINES/misc.dm
@@ -496,3 +496,6 @@ GLOBAL_LIST_INIT(pda_reskins, list(PDA_SKIN_CLASSIC = 'icons/obj/pda.dmi', PDA_S
#define VOMIT_TOXIC 1
#define VOMIT_PURPLE 2
+
+//Misc text define. Does 4 spaces. Used as a makeshift tabulator.
+#define FOURSPACES " "
\ No newline at end of file
diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm
index 3394fba9..3ec3650c 100644
--- a/code/__DEFINES/subsystems.dm
+++ b/code/__DEFINES/subsystems.dm
@@ -83,7 +83,8 @@
#define INIT_ORDER_SHUTTLE -21
#define INIT_ORDER_MINOR_MAPPING -40
#define INIT_ORDER_PATH -50
-#define INIT_ORDER_PERSISTENCE -100
+#define INIT_ORDER_PERSISTENCE -95
+#define INIT_ORDER_CHAT -100 //Should be last to ensure chat remains smooth during init.
// Subsystem fire priority, from lowest to highest priority
// If the subsystem isn't listed here it's either DEFAULT or PROCESS (if it's a processing subsystem child)
@@ -97,7 +98,7 @@
#define FIRE_PRIORITY_GARBAGE 15
#define FIRE_PRIORITY_WET_FLOORS 20
#define FIRE_PRIORITY_AIR 20
-#define FIRE_PRIORITY_NPC 20
+#define FIRE_PRIORITY_NPC 80
#define FIRE_PRIORITY_PROCESS 25
#define FIRE_PRIORITY_THROWING 25
#define FIRE_PRIORITY_SPACEDRIFT 30
@@ -114,6 +115,7 @@
#define FIRE_PRIORITY_MOBS 100
#define FIRE_PRIORITY_TGUI 110
#define FIRE_PRIORITY_TICKER 200
+#define FIRE_PRIORITY_CHAT 400
#define FIRE_PRIORITY_OVERLAYS 500
#define FIRE_PRIORITY_INPUT 1000 // This must always always be the max highest priority. Player input must never be lost.
diff --git a/code/__HELPERS/roundend.dm b/code/__HELPERS/roundend.dm
index 55d9e7a6..6a80f230 100644
--- a/code/__HELPERS/roundend.dm
+++ b/code/__HELPERS/roundend.dm
@@ -280,34 +280,34 @@
if(GLOB.round_id)
var/statspage = CONFIG_GET(string/roundstatsurl)
var/info = statspage ? "[GLOB.round_id]" : GLOB.round_id
- parts += "[GLOB.TAB]Round ID: [info]"
+ parts += "[FOURSPACES]Round ID: [info]"
var/list/voting_results = SSvote.stored_gamemode_votes
if(length(voting_results))
- parts += "[GLOB.TAB]Voting: "
+ parts += "[FOURSPACES]Voting: "
var/total_score = 0
for(var/choice in voting_results)
var/score = voting_results[choice]
total_score += score
- parts += "[GLOB.TAB][GLOB.TAB][choice]: [score]"
+ parts += "[FOURSPACES][FOURSPACES][choice]: [score]"
- parts += "[GLOB.TAB]Shift Duration: [DisplayTimeText(world.time - SSticker.round_start_time)]"
- parts += "[GLOB.TAB]Station Integrity: [mode.station_was_nuked ? "Destroyed" : "[popcount["station_integrity"]]%"]"
+ parts += "[FOURSPACES]Shift Duration: [DisplayTimeText(world.time - SSticker.round_start_time)]"
+ parts += "[FOURSPACES]Station Integrity: [mode.station_was_nuked ? "Destroyed" : "[popcount["station_integrity"]]%"]"
var/total_players = GLOB.joined_player_list.len
if(total_players)
- parts+= "[GLOB.TAB]Total Population: [total_players]"
+ parts+= "[FOURSPACES]Total Population: [total_players]"
if(station_evacuated)
- parts += "
[GLOB.TAB]Evacuation Rate: [popcount[POPCOUNT_ESCAPEES]] ([PERCENT(popcount[POPCOUNT_ESCAPEES]/total_players)]%)"
- parts += "[GLOB.TAB](on emergency shuttle): [popcount[POPCOUNT_SHUTTLE_ESCAPEES]] ([PERCENT(popcount[POPCOUNT_SHUTTLE_ESCAPEES]/total_players)]%)"
- parts += "[GLOB.TAB]Survival Rate: [popcount[POPCOUNT_SURVIVORS]] ([PERCENT(popcount[POPCOUNT_SURVIVORS]/total_players)]%)"
+ parts += "
[FOURSPACES]Evacuation Rate: [popcount[POPCOUNT_ESCAPEES]] ([PERCENT(popcount[POPCOUNT_ESCAPEES]/total_players)]%)"
+ parts += "[FOURSPACES](on emergency shuttle): [popcount[POPCOUNT_SHUTTLE_ESCAPEES]] ([PERCENT(popcount[POPCOUNT_SHUTTLE_ESCAPEES]/total_players)]%)"
+ parts += "[FOURSPACES]Survival Rate: [popcount[POPCOUNT_SURVIVORS]] ([PERCENT(popcount[POPCOUNT_SURVIVORS]/total_players)]%)"
if(SSblackbox.first_death)
var/list/ded = SSblackbox.first_death
if(ded.len)
- parts += "[GLOB.TAB]First Death: [ded["name"]], [ded["role"]], at [ded["area"]]. Damage taken: [ded["damage"]].[ded["last_words"] ? " Their last words were: \"[ded["last_words"]]\"" : ""]"
+ parts += "[FOURSPACES]First Death: [ded["name"]], [ded["role"]], at [ded["area"]]. Damage taken: [ded["damage"]].[ded["last_words"] ? " Their last words were: \"[ded["last_words"]]\"" : ""]"
//ignore this comment, it fixes the broken sytax parsing caused by the " above
else
- parts += "[GLOB.TAB]Nobody died this shift!"
+ parts += "[FOURSPACES]Nobody died this shift!"
return parts.Join("
")
/client/proc/roundend_report_file()
diff --git a/code/_globalvars/misc.dm b/code/_globalvars/misc.dm
index d8d22289..899ccbe7 100644
--- a/code/_globalvars/misc.dm
+++ b/code/_globalvars/misc.dm
@@ -6,8 +6,6 @@ GLOBAL_VAR_INIT(timezoneOffset, 0) // The difference betwen midnight (of the hos
// However it'd be ok to use for accessing attack logs and such too, which are even laggier.
GLOBAL_VAR_INIT(fileaccess_timer, 0)
-GLOBAL_VAR_INIT(TAB, " ")
-
GLOBAL_DATUM_INIT(data_core, /datum/datacore, new)
GLOBAL_VAR_INIT(CELLRATE, 0.002) // conversion ratio between a watt-tick and kilojoule
diff --git a/code/controllers/subsystem/chat.dm b/code/controllers/subsystem/chat.dm
new file mode 100644
index 00000000..a579752a
--- /dev/null
+++ b/code/controllers/subsystem/chat.dm
@@ -0,0 +1,67 @@
+SUBSYSTEM_DEF(chat)
+ name = "Chat"
+ flags = SS_TICKER|SS_NO_INIT
+ wait = 1
+ priority = FIRE_PRIORITY_CHAT
+ init_order = INIT_ORDER_CHAT
+ var/list/payload = list()
+
+
+/datum/controller/subsystem/chat/fire()
+ for(var/i in payload)
+ var/client/C = i
+ C << output(payload[C], "browseroutput:output")
+ payload -= C
+
+ if(MC_TICK_CHECK)
+ return
+
+
+/datum/controller/subsystem/chat/proc/queue(target, message, handle_whitespace = TRUE)
+ if(!target || !message)
+ return
+
+ if(!istext(message))
+ stack_trace("to_chat called with invalid input type")
+ return
+
+ if(target == world)
+ target = GLOB.clients
+
+ //Some macros remain in the string even after parsing and fuck up the eventual output
+ message = replacetext(message, "\improper", "")
+ message = replacetext(message, "\proper", "")
+ if(handle_whitespace)
+ message = replacetext(message, "\n", "
")
+ message = replacetext(message, "\t", "[FOURSPACES][FOURSPACES]")
+ message += "
"
+
+
+ //url_encode it TWICE, this way any UTF-8 characters are able to be decoded by the Javascript.
+ //Do the double-encoding here to save nanoseconds
+ var/twiceEncoded = url_encode(url_encode(message))
+
+ if(islist(target))
+ for(var/I in target)
+ var/client/C = CLIENT_FROM_VAR(I) //Grab us a client if possible
+
+ if(!C?.chatOutput || C.chatOutput.broken) //A player who hasn't updated his skin file.
+ continue
+
+ if(!C.chatOutput.loaded) //Client still loading, put their messages in a queue
+ C.chatOutput.messageQueue += message
+ continue
+
+ payload[C] += twiceEncoded
+
+ else
+ var/client/C = CLIENT_FROM_VAR(target) //Grab us a client if possible
+
+ if(!C?.chatOutput || C.chatOutput.broken) //A player who hasn't updated his skin file.
+ return
+
+ if(!C.chatOutput.loaded) //Client still loading, put their messages in a queue
+ C.chatOutput.messageQueue += message
+ return
+
+ payload[C] += twiceEncoded
\ No newline at end of file
diff --git a/code/controllers/subsystem/npcpool.dm b/code/controllers/subsystem/npcpool.dm
index c69154a1..7fd35124 100644
--- a/code/controllers/subsystem/npcpool.dm
+++ b/code/controllers/subsystem/npcpool.dm
@@ -1,6 +1,6 @@
SUBSYSTEM_DEF(npcpool)
name = "NPC Pool"
- flags = SS_POST_FIRE_TIMING|SS_NO_INIT|SS_BACKGROUND
+ flags = SS_KEEP_TIMING | SS_NO_INIT
priority = FIRE_PRIORITY_NPC
runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME
diff --git a/code/game/machinery/computer/teleporter.dm b/code/game/machinery/computer/teleporter.dm
index b9b95eec..e53e3cb4 100644
--- a/code/game/machinery/computer/teleporter.dm
+++ b/code/game/machinery/computer/teleporter.dm
@@ -124,12 +124,12 @@
L[avoid_assoc_duplicate_keys(A.name, areaindex)] = R
for(var/obj/item/implant/tracking/I in GLOB.tracked_implants)
- if(!I.imp_in || !isliving(I.loc))
+ if(!I.imp_in || !I.allow_teleport || !isliving(I.imp_in))
continue
else
var/mob/living/M = I.loc
if(M.stat == DEAD)
- if(M.timeofdeath + 6000 < world.time)
+ if(M.timeofdeath + I.lifespan_postmortem < world.time)
continue
if(is_eligible(I))
L[avoid_assoc_duplicate_keys(M.real_name, areaindex)] = I
diff --git a/code/game/machinery/suit_storage_unit.dm b/code/game/machinery/suit_storage_unit.dm
index 3051a72d..559d880f 100644
--- a/code/game/machinery/suit_storage_unit.dm
+++ b/code/game/machinery/suit_storage_unit.dm
@@ -210,13 +210,13 @@
add_fingerprint(user)
/obj/machinery/suit_storage_unit/proc/cook()
+ var/mob/living/mob_occupant = occupant
if(uv_cycles)
uv_cycles--
uv = TRUE
locked = TRUE
update_icon()
if(occupant)
- var/mob/living/mob_occupant = occupant
if(uv_super)
mob_occupant.adjustFireLoss(rand(20, 36))
else
@@ -245,6 +245,7 @@
visible_message("[src]'s door slides open. The glowing yellow lights dim to a gentle green.")
else
visible_message("[src]'s door slides open, barraging you with the nauseating smell of charred flesh.")
+ mob_occupant.radiation = 0
playsound(src, 'sound/machines/airlockclose.ogg', 25, 1)
for(var/obj/item/I in src) //Scorches away blood and forensic evidence, although the SSU itself is unaffected
SEND_SIGNAL(I, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRONG)
diff --git a/code/game/machinery/syndicatebeacon.dm b/code/game/machinery/syndicatebeacon.dm
index c52a0334..1da89fb3 100644
--- a/code/game/machinery/syndicatebeacon.dm
+++ b/code/game/machinery/syndicatebeacon.dm
@@ -1,3 +1,7 @@
+GLOBAL_VAR_INIT(singularity_counter, 0)
+
+#define METEOR_DISASTER_MODIFIER 0.5
+
////////////////////////////////////////
//Singularity beacon
////////////////////////////////////////
@@ -14,38 +18,58 @@
verb_say = "states"
var/cooldown = 0
- var/active = 0
+ var/active = FALSE
+ var/meteor_buff = FALSE
var/icontype = "beacon"
-
/obj/machinery/power/singularity_beacon/proc/Activate(mob/user = null)
+ if(active)
+ return FALSE
if(surplus() < 1500)
if(user)
to_chat(user, "The connected wire doesn't have enough current.")
- return
+ return FALSE
+ if(is_station_level(z))
+ increment_meteor_waves()
for(var/obj/singularity/singulo in GLOB.singularities)
if(singulo.z == z)
singulo.target = src
icon_state = "[icontype]1"
- active = 1
+ active = TRUE
if(user)
to_chat(user, "You activate the beacon.")
+ return TRUE
-
-/obj/machinery/power/singularity_beacon/proc/Deactivate(mob/user = null)
+/obj/machinery/power/singularity_beacon/proc/Deactivate(mob/user)
+ if(!active)
+ return FALSE
for(var/obj/singularity/singulo in GLOB.singularities)
if(singulo.target == src)
singulo.target = null
icon_state = "[icontype]0"
- active = 0
+ active = FALSE
if(user)
to_chat(user, "You deactivate the beacon.")
+ if(meteor_buff)
+ decrement_meteor_waves()
+ return TRUE
+
+/obj/machinery/power/singularity_beacon/proc/increment_meteor_waves()
+ meteor_buff = TRUE
+ GLOB.singularity_counter++
+ for(var/datum/round_event_control/meteor_wave/W in SSevents.control)
+ W.weight += round(initial(W.weight) * METEOR_DISASTER_MODIFIER)
+
+/obj/machinery/power/singularity_beacon/proc/decrement_meteor_waves()
+ meteor_buff = FALSE
+ GLOB.singularity_counter--
+ for(var/datum/round_event_control/meteor_wave/W in SSevents.control)
+ W.weight -= round(initial(W.weight) * METEOR_DISASTER_MODIFIER)
/obj/machinery/power/singularity_beacon/attack_ai(mob/user)
return
-
/obj/machinery/power/singularity_beacon/attack_hand(mob/user)
. = ..()
if(.)
@@ -86,6 +110,12 @@
if(!active)
return
+ var/is_on_station = is_station_level(z)
+ if(meteor_buff && !is_on_station)
+ decrement_meteor_waves()
+ else if(!meteor_buff && is_on_station)
+ increment_meteor_waves()
+
if(surplus() >= 1500)
add_load(1500)
if(cooldown <= world.time)
@@ -133,3 +163,5 @@
/obj/item/sbeacondrop/clownbomb
desc = "A label on it reads: Warning: Activating this device will send a silly explosive to your location."
droptype = /obj/machinery/syndicatebomb/badmin/clown
+
+#undef METEOR_DISASTER_MODIFIER
\ No newline at end of file
diff --git a/code/game/objects/buckling.dm b/code/game/objects/buckling.dm
index 9c3df539..693d32e5 100644
--- a/code/game/objects/buckling.dm
+++ b/code/game/objects/buckling.dm
@@ -89,6 +89,7 @@
buckled_mob.clear_alert("buckled")
buckled_mobs -= buckled_mob
SEND_SIGNAL(src, COMSIG_MOVABLE_UNBUCKLE, buckled_mob, force)
+ SEND_SIGNAL(src, COMSIG_MOVABLE_UNBUCKLE, src, force)
post_unbuckle_mob(.)
diff --git a/code/game/objects/items/holy_weapons.dm b/code/game/objects/items/holy_weapons.dm
index e67bb6bf..65478a84 100644
--- a/code/game/objects/items/holy_weapons.dm
+++ b/code/game/objects/items/holy_weapons.dm
@@ -249,7 +249,7 @@
return
var/obj/item/nullrod/holy_weapon
var/list/holy_weapons_list = typesof(/obj/item/nullrod) + list(
- /obj/item/melee/transforming/energy/sword/cx/chaplain
+ /obj/item/twohanded/dualsaber/hypereutactic/chaplain
)
var/list/display_names = list()
for(var/V in holy_weapons_list)
@@ -710,7 +710,7 @@
righthand_file = 'icons/mob/inhands/weapons/staves_righthand.dmi'
w_class = WEIGHT_CLASS_NORMAL
attack_verb = list("bashes", "smacks", "whacks")
-
+
/obj/item/nullrod/hypertool
icon = 'icons/obj/device.dmi'
icon_state = "hypertool"
diff --git a/code/game/objects/items/implants/implant_track.dm b/code/game/objects/items/implants/implant_track.dm
index 913c577f..4398688c 100644
--- a/code/game/objects/items/implants/implant_track.dm
+++ b/code/game/objects/items/implants/implant_track.dm
@@ -1,7 +1,19 @@
/obj/item/implant/tracking
name = "tracking implant"
desc = "Track with this."
- activated = 0
+ activated = FALSE
+ var/lifespan_postmortem = 10 MINUTES //for how many deciseconds after user death will the implant work?
+ var/allow_teleport = TRUE //will people implanted with this act as teleporter beacons?
+
+/obj/item/implant/tracking/c38
+ name = "TRAC implant"
+ desc = "A smaller tracking implant that supplies power for only a few minutes."
+ var/lifespan = 5 MINUTES //how many deciseconds does the implant last?
+ allow_teleport = FALSE
+
+/obj/item/implant/tracking/c38/Initialize()
+ . = ..()
+ QDEL_IN(src, lifespan)
/obj/item/implant/tracking/New()
..()
@@ -21,7 +33,7 @@
var/dat = {"Implant Specifications:
Name: Tracking Beacon
Life: 10 minutes after death of host
- Important Notes: None
+ Important Notes: Implant also works as a teleporter beacon.
Implant Details:
Function: Continuously transmits low power signal. Useful for tracking.
diff --git a/code/game/objects/items/teleportation.dm b/code/game/objects/items/teleportation.dm
index 5a4fc697..dd64c671 100644
--- a/code/game/objects/items/teleportation.dm
+++ b/code/game/objects/items/teleportation.dm
@@ -75,15 +75,14 @@
temp += "Implant Signals:
"
for (var/obj/item/implant/tracking/W in GLOB.tracked_implants)
- if (!W.imp_in || !isliving(W.loc))
+ if (!isliving(W.imp_in))
continue
- else
- var/mob/living/M = W.loc
- if (M.stat == DEAD)
- if (M.timeofdeath + 6000 < world.time)
- continue
+ var/mob/living/M = W.imp_in
+ if (M.stat == DEAD)
+ if (M.timeofdeath + W.lifespan_postmortem < world.time)
+ continue
- var/turf/tr = get_turf(W)
+ var/turf/tr = get_turf(M)
if (tr.z == sr.z && tr)
var/direct = max(abs(tr.x - sr.x), abs(tr.y - sr.y))
if (direct < 20)
@@ -188,8 +187,13 @@
user.show_message("\The [src] is recharging!")
return
var/atom/T = L[t1]
+ var/implantcheckmate = FALSE
+ if(isliving(T))
+ var/mob/living/M = T
+ if(!locate(/obj/item/implant/tracking) in M.implants) //The user was too slow and let the target mob's tracking implant expire or get removed.
+ implantcheckmate = TRUE
var/area/A = get_area(T)
- if(A.noteleport)
+ if(A.noteleport || implantcheckmate)
to_chat(user, "\The [src] is malfunctioning.")
return
current_location = get_turf(user) //Recheck.
@@ -233,4 +237,4 @@
itemUser.visible_message("The portal snaps closed taking [user]'s head with it!")
else
itemUser.visible_message("[user] looks even further depressed as they realize they do not have a head...and suddenly dies of shame!")
- return (BRUTELOSS)
+ return (BRUTELOSS)
\ No newline at end of file
diff --git a/code/game/objects/items/theft_tools.dm b/code/game/objects/items/theft_tools.dm
index 0c74f610..b99be7e9 100644
--- a/code/game/objects/items/theft_tools.dm
+++ b/code/game/objects/items/theft_tools.dm
@@ -232,7 +232,7 @@
. = ..()
if(!sliver)
return
- if(ismovableatom(O) && O != sliver)
+ if(proximity && ismovableatom(O) && O != sliver)
Consume(O, user)
/obj/item/hemostat/supermatter/throw_impact(atom/hit_atom) // no instakill supermatter javelins
diff --git a/code/game/objects/structures/ghost_role_spawners.dm b/code/game/objects/structures/ghost_role_spawners.dm
index 12827a0a..4a56272a 100644
--- a/code/game/objects/structures/ghost_role_spawners.dm
+++ b/code/game/objects/structures/ghost_role_spawners.dm
@@ -561,7 +561,7 @@
icon = 'icons/obj/machines/sleeper.dmi'
icon_state = "sleeper"
mob_name = "a space pirate"
- mob_species = /datum/species/skeleton/pirate
+ mob_species = /datum/species/skeleton/space
outfit = /datum/outfit/pirate/space
roundstart = FALSE
death = FALSE
diff --git a/code/game/sound.dm b/code/game/sound.dm
index 5503c610..e7562476 100644
--- a/code/game/sound.dm
+++ b/code/game/sound.dm
@@ -182,6 +182,8 @@
soundin = pick('sound/voice/beepsky/god.ogg', 'sound/voice/beepsky/iamthelaw.ogg', 'sound/voice/beepsky/secureday.ogg', 'sound/voice/beepsky/radio.ogg', 'sound/voice/beepsky/insult.ogg', 'sound/voice/beepsky/creep.ogg')
if("honkbot_e")
soundin = pick('sound/items/bikehorn.ogg', 'sound/items/AirHorn2.ogg', 'sound/misc/sadtrombone.ogg', 'sound/items/AirHorn.ogg', 'sound/effects/reee.ogg', 'sound/items/WEEOO1.ogg', 'sound/voice/beepsky/iamthelaw.ogg', 'sound/voice/beepsky/creep.ogg','sound/magic/Fireball.ogg' ,'sound/effects/pray.ogg', 'sound/voice/hiss1.ogg','sound/machines/buzz-sigh.ogg', 'sound/machines/ping.ogg', 'sound/weapons/flashbang.ogg', 'sound/weapons/bladeslice.ogg')
+ if("goose")
+ soundin = pick('sound/creatures/goose1.ogg', 'sound/creatures/goose2.ogg', 'sound/creatures/goose3.ogg', 'sound/creatures/goose4.ogg')
//START OF CIT CHANGES - adds random vore sounds
if ("struggle_sound")
soundin = pick( 'sound/vore/pred/struggle_01.ogg','sound/vore/pred/struggle_02.ogg','sound/vore/pred/struggle_03.ogg',
diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm
index 7110ff44..19e6fc68 100644
--- a/code/game/turfs/turf.dm
+++ b/code/game/turfs/turf.dm
@@ -452,16 +452,21 @@
/turf/AllowDrop()
return TRUE
-/turf/proc/add_vomit_floor(mob/living/carbon/M, toxvomit = NONE)
+/turf/proc/add_vomit_floor(mob/living/M, toxvomit = NONE)
+
var/obj/effect/decal/cleanable/vomit/V = new /obj/effect/decal/cleanable/vomit(src, M.get_static_viruses())
- // If the vomit combined, apply toxicity and reagents to the old vomit
+ //if the vomit combined, apply toxicity and reagents to the old vomit
if (QDELETED(V))
V = locate() in src
// Make toxins and blazaam vomit look different
if(toxvomit == VOMIT_PURPLE)
V.icon_state = "vomitpurp_[pick(1,4)]"
- else if(toxvomit == VOMIT_TOXIC)
+ else if (toxvomit == VOMIT_TOXIC)
V.icon_state = "vomittox_[pick(1,4)]"
+ if (iscarbon(M))
+ var/mob/living/carbon/C = M
+ if(C.reagents)
+ clear_reagents_to_vomit_pool(C,V)
/proc/clear_reagents_to_vomit_pool(mob/living/carbon/M, obj/effect/decal/cleanable/vomit/V)
M.reagents.trans_to(V, M.reagents.total_volume / 10)
diff --git a/code/modules/admin/verbs/adminhelp.dm b/code/modules/admin/verbs/adminhelp.dm
index d6727f78..d0ec5920 100644
--- a/code/modules/admin/verbs/adminhelp.dm
+++ b/code/modules/admin/verbs/adminhelp.dm
@@ -413,9 +413,9 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
dat += "CLOSED"
else
dat += "UNKNOWN"
- dat += "[GLOB.TAB][TicketHref("Refresh", ref_src)][GLOB.TAB][TicketHref("Re-Title", ref_src, "retitle")]"
+ dat += "[FOURSPACES][TicketHref("Refresh", ref_src)][FOURSPACES][TicketHref("Re-Title", ref_src, "retitle")]"
if(state != AHELP_ACTIVE)
- dat += "[GLOB.TAB][TicketHref("Reopen", ref_src, "reopen")]"
+ dat += "[FOURSPACES][TicketHref("Reopen", ref_src, "reopen")]"
dat += "
Opened at: [GAMETIMESTAMP("hh:mm:ss", closed_at)] (Approx [DisplayTimeText(world.time - opened_at)] ago)"
if(closed_at)
dat += "
Closed at: [GAMETIMESTAMP("hh:mm:ss", closed_at)] (Approx [DisplayTimeText(world.time - closed_at)] ago)"
@@ -423,7 +423,7 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
if(initiator)
dat += "Actions: [FullMonty(ref_src)]
"
else
- dat += "DISCONNECTED[GLOB.TAB][ClosureLinks(ref_src)]
"
+ dat += "DISCONNECTED[FOURSPACES][ClosureLinks(ref_src)]
"
dat += "
Log:
"
for(var/I in _interactions)
dat += "[I]
"
diff --git a/code/modules/antagonists/devil/devil.dm b/code/modules/antagonists/devil/devil.dm
index 3f2bd003..dc649025 100644
--- a/code/modules/antagonists/devil/devil.dm
+++ b/code/modules/antagonists/devil/devil.dm
@@ -539,10 +539,10 @@ GLOBAL_LIST_INIT(devil_suffix, list(" the Red", " the Soulless", " the Master",
var/list/parts = list()
parts += "The devil's true name is: [truename]"
parts += "The devil's bans were:"
- parts += "[GLOB.TAB][GLOB.lawlorify[LORE][ban]]"
- parts += "[GLOB.TAB][GLOB.lawlorify[LORE][bane]]"
- parts += "[GLOB.TAB][GLOB.lawlorify[LORE][obligation]]"
- parts += "[GLOB.TAB][GLOB.lawlorify[LORE][banish]]"
+ parts += "[FOURSPACES][GLOB.lawlorify[LORE][ban]]"
+ parts += "[FOURSPACES][GLOB.lawlorify[LORE][bane]]"
+ parts += "[FOURSPACES][GLOB.lawlorify[LORE][obligation]]"
+ parts += "[FOURSPACES][GLOB.lawlorify[LORE][banish]]"
return parts.Join("
")
/datum/antagonist/devil/roundend_report()
diff --git a/code/modules/antagonists/nukeop/equipment/nuclear_challenge.dm b/code/modules/antagonists/nukeop/equipment/nuclear_challenge.dm
index edae8a42..daa38767 100644
--- a/code/modules/antagonists/nukeop/equipment/nuclear_challenge.dm
+++ b/code/modules/antagonists/nukeop/equipment/nuclear_challenge.dm
@@ -1,7 +1,8 @@
#define CHALLENGE_TELECRYSTALS 280
#define PLAYER_SCALING 1.5
#define CHALLENGE_TIME_LIMIT 3000
-#define CHALLENGE_MIN_PLAYERS 50
+#define CHALLENGE_PLAYERS_TARGET 50 //target players population. anything below is a malus to the challenge tc bonus.
+#define TELECRYSTALS_MALUS_SCALING 1 //the higher the value, the bigger the malus.
#define CHALLENGE_SHUTTLE_DELAY 15000 // 25 minutes, so the ops have at least 5 minutes before the shuttle is callable.
GLOBAL_LIST_EMPTY(jam_on_wardec)
@@ -62,12 +63,15 @@ GLOBAL_VAR_INIT(war_declared, FALSE)
for(var/obj/machinery/computer/camera_advanced/shuttle_docker/D in GLOB.jam_on_wardec)
D.jammed = TRUE
-
+
GLOB.war_declared = TRUE
var/list/nukeops = get_antag_minds(/datum/antagonist/nukeop)
var/actual_players = GLOB.joined_player_list.len - nukeops.len
+ var/tc_malus = 0
+ if(actual_players < CHALLENGE_PLAYERS_TARGET)
+ tc_malus = FLOOR((CHALLENGE_TELECRYSTALS - actual_players * INVERSE(CHALLENGE_PLAYERS_TARGET)) * TELECRYSTALS_MALUS_SCALING, 1)
- new uplink_type(get_turf(user), user.key, CHALLENGE_TELECRYSTALS + CEILING(PLAYER_SCALING * actual_players, 1))
+ new uplink_type(get_turf(user), user.key, CHALLENGE_TELECRYSTALS - tc_malus + CEILING(PLAYER_SCALING * actual_players, 1))
CONFIG_SET(number/shuttle_refuel_delay, max(CONFIG_GET(number/shuttle_refuel_delay), CHALLENGE_SHUTTLE_DELAY))
SSblackbox.record_feedback("amount", "nuclear_challenge_mode", 1)
@@ -79,11 +83,6 @@ GLOBAL_VAR_INIT(war_declared, FALSE)
to_chat(user, "You are already in the process of declaring war! Make your mind up.")
return FALSE
- var/list/nukeops = get_antag_minds(/datum/antagonist/nukeop)
- var/actual_players = GLOB.joined_player_list.len - nukeops.len
- if(actual_players < CHALLENGE_MIN_PLAYERS)
- to_chat(user, "The enemy crew is too small to be worth declaring war on.")
- return FALSE
if(!user.onSyndieBase())
to_chat(user, "You have to be at your base to use this.")
return FALSE
@@ -102,5 +101,6 @@ GLOBAL_VAR_INIT(war_declared, FALSE)
#undef CHALLENGE_TELECRYSTALS
#undef CHALLENGE_TIME_LIMIT
-#undef CHALLENGE_MIN_PLAYERS
+#undef CHALLENGE_PLAYERS_TARGET
+#undef TELECRYSTALS_MALUS_SCALING
#undef CHALLENGE_SHUTTLE_DELAY
diff --git a/code/modules/antagonists/wizard/equipment/artefact.dm b/code/modules/antagonists/wizard/equipment/artefact.dm
index 562d6f25..7207adc4 100644
--- a/code/modules/antagonists/wizard/equipment/artefact.dm
+++ b/code/modules/antagonists/wizard/equipment/artefact.dm
@@ -198,7 +198,7 @@
to_chat(user, "This artifact can only affect three undead at a time!")
return
- M.set_species(/datum/species/skeleton, icon_update=0)
+ M.set_species(/datum/species/skeleton/space, icon_update=0)
M.revive(full_heal = 1, admin_revive = 1)
spooky_scaries |= M
to_chat(M, "You have been revived by [user.real_name]!")
diff --git a/code/modules/events/meteor_wave.dm b/code/modules/events/meteor_wave.dm
index 743f2edf..662053f8 100644
--- a/code/modules/events/meteor_wave.dm
+++ b/code/modules/events/meteor_wave.dm
@@ -1,5 +1,8 @@
// Normal strength
+#define SINGULO_BEACON_DISTURBANCE 0.2 //singularity beacon also improve the odds of meteor waves and speed them up a little.
+#define SINGULO_BEACON_MAX_DISTURBANCE 0.6 //maximum cap due to how meteor waves can be potentially round ending.
+
/datum/round_event_control/meteor_wave
name = "Meteor Wave: Normal"
typepath = /datum/round_event/meteor_wave
@@ -18,6 +21,8 @@
/datum/round_event/meteor_wave/setup()
announceWhen = 1
startWhen = rand(300, 600) //Yeah for SOME REASON this is measured in seconds and not deciseconds???
+ if(GLOB.singularity_counter)
+ startWhen *= 1 - min(GLOB.singularity_counter * SINGULO_BEACON_DISTURBANCE, SINGULO_BEACON_MAX_DISTURBANCE)
endWhen = startWhen + 60
@@ -52,7 +57,7 @@
kill()
/datum/round_event/meteor_wave/announce(fake)
- priority_announce("Meteors have been detected on collision course with the station. Estimated time until impact: [round(startWhen/60)] minutes.", "Meteor Alert", 'sound/ai/meteors.ogg')
+ priority_announce("Meteors have been detected on collision course with the station. Estimated time until impact: [round(startWhen/60)] minutes.[GLOB.singularity_counter ? " Warning: Anomalous gravity pulse detected, Syndicate technology interference likely." : ""]", "Meteor Alert", 'sound/ai/meteors.ogg')
/datum/round_event/meteor_wave/tick()
if(ISMULTIPLE(activeFor, 3))
@@ -79,3 +84,6 @@
/datum/round_event/meteor_wave/catastrophic
wave_name = "catastrophic"
+
+#undef SINGULO_BEACON_DISTURBANCE
+#undef SINGULO_BEACON_MAX_DISTURBANCE
\ No newline at end of file
diff --git a/code/modules/flufftext/Hallucination.dm b/code/modules/flufftext/Hallucination.dm
index 88f72d27..d035db82 100644
--- a/code/modules/flufftext/Hallucination.dm
+++ b/code/modules/flufftext/Hallucination.dm
@@ -771,7 +771,7 @@ GLOBAL_LIST_INIT(hallucination_list, list(
..()
var/turf/source = random_far_turf()
if(!sound_type)
- sound_type = pick("airlock","airlock pry","console","explosion","far explosion","mech","glass","alarm","beepsky","mech","wall decon","door hack")
+ sound_type = pick("airlock","airlock pry","console","flash","explosion","far explosion","mech","glass","alarm","beepsky","mech","wall decon","door hack")
feedback_details += "Type: [sound_type]"
//Strange audio
switch(sound_type)
@@ -788,6 +788,8 @@ GLOBAL_LIST_INIT(hallucination_list, list(
target.playsound_local(source,'sound/effects/explosion1.ogg', 50, 1)
else
target.playsound_local(source, 'sound/effects/explosion2.ogg', 50, 1)
+ if("flash")
+ target.playsound_local(source, 'sound/weapons/flash.ogg', 50, 1)
if("far explosion")
target.playsound_local(source, 'sound/effects/explosionfar.ogg', 50, 1)
if("glass")
diff --git a/code/modules/goonchat/browserOutput.dm b/code/modules/goonchat/browserOutput.dm
index 7fe6b41b..f31d8dc9 100644
--- a/code/modules/goonchat/browserOutput.dm
+++ b/code/modules/goonchat/browserOutput.dm
@@ -5,17 +5,9 @@ For the main html chat area
//Precaching a bunch of shit
GLOBAL_DATUM_INIT(iconCache, /savefile, new("tmp/iconCache.sav")) //Cache of icons for the browser output
-//Should match the value set in the browser js
-#define MAX_COOKIE_LENGTH 5
-
-
//On client, created on login
/datum/chatOutput
var/client/owner //client ref
- // How many times client data has been checked
- var/total_checks = 0
- // When to next clear the client data checks counter
- var/next_time_to_clear = 0
var/loaded = FALSE // Has the client loaded the browser output area?
var/list/messageQueue //If they haven't loaded chat, this is where messages will go until they do
var/cookieSent = FALSE // Has the client sent a cookie for analysis
@@ -90,11 +82,13 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("tmp/iconCache.sav")) //Cache of ico
if("setMusicVolume")
data = setMusicVolume(arglist(params))
- if("swaptodarkmode")
- swaptodarkmode()
+ if("colorPresetPost") //User just swapped color presets in their goonchat preferences. Do we do anything else?
+ switch(href_list["preset"])
+ if("light")
+ owner.force_white_theme()
+ if("dark" || "normal")
+ owner.force_dark_theme()
- if("swaptolightmode")
- swaptolightmode()
if(data)
ehjax_send(data = data)
@@ -156,19 +150,6 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("tmp/iconCache.sav")) //Cache of ico
//Called by client, sent data to investigate (cookie history so far)
/datum/chatOutput/proc/analyzeClientData(cookie = "")
- //Spam check
- if(world.time > next_time_to_clear)
- next_time_to_clear = world.time + (3 SECONDS)
- total_checks = 0
-
- total_checks += 1
-
- if(total_checks > SPAM_TRIGGER_AUTOMUTE)
- message_admins("[key_name(owner)] kicked for goonchat topic spam")
- qdel(owner)
- return
-
-
if(!cookie)
return
@@ -177,24 +158,13 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("tmp/iconCache.sav")) //Cache of ico
if (connData && islist(connData) && connData.len > 0 && connData["connData"])
connectionHistory = connData["connData"] //lol fuck
var/list/found = new()
-
- if(connectionHistory.len > MAX_COOKIE_LENGTH)
- message_admins("[key_name(src.owner)] was kicked for an invalid ban cookie)")
- qdel(owner)
- return
-
-
for(var/i in connectionHistory.len to 1 step -1)
- if(QDELETED(owner))
- //he got cleaned up before we were done
- return
var/list/row = src.connectionHistory[i]
if (!row || row.len < 3 || (!row["ckey"] || !row["compid"] || !row["ip"])) //Passed malformed history object
return
if (world.IsBanned(row["ckey"], row["ip"], row["compid"], real_bans_only=TRUE))
found = row
break
- CHECK_TICK
//Uh oh this fucker has a history of playing on a banned account!!
if (found.len > 0)
@@ -213,8 +183,8 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("tmp/iconCache.sav")) //Cache of ico
log_world("\[[time2text(world.realtime, "YYYY-MM-DD hh:mm:ss")]\] Client: [(src.owner.key ? src.owner.key : src.owner)] triggered JS error: [error]")
//Global chat procs
-/proc/to_chat(target, message, handle_whitespace=TRUE)
- if(!target)
+/proc/to_chat_immediate(target, message, handle_whitespace=TRUE)
+ if(!target || !message)
return
//Ok so I did my best but I accept that some calls to this will be for shit like sound and images
@@ -236,7 +206,7 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("tmp/iconCache.sav")) //Cache of ico
message = replacetext(message, "\proper", "")
if(handle_whitespace)
message = replacetext(message, "\n", "
")
- message = replacetext(message, "\t", "[GLOB.TAB][GLOB.TAB]")
+ message = replacetext(message, "\t", "[FOURSPACES][FOURSPACES]")
if(islist(target))
// Do the double-encoding outside the loop to save nanoseconds
@@ -279,12 +249,14 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("tmp/iconCache.sav")) //Cache of ico
// url_encode it TWICE, this way any UTF-8 characters are able to be decoded by the Javascript.
C << output(url_encode(url_encode(message)), "browseroutput:output")
+/proc/to_chat(target, message, handle_whitespace = TRUE)
+ if(Master.current_runlevel == RUNLEVEL_INIT || !SSchat?.initialized)
+ to_chat_immediate(target, message, handle_whitespace)
+ return
+ SSchat.queue(target, message, handle_whitespace)
/datum/chatOutput/proc/swaptolightmode() //Dark mode light mode stuff. Yell at KMC if this breaks! (See darkmode.dm for documentation)
owner.force_white_theme()
/datum/chatOutput/proc/swaptodarkmode()
- owner.force_dark_theme()
-
-
-#undef MAX_COOKIE_LENGTH
+ owner.force_dark_theme()
\ No newline at end of file
diff --git a/code/modules/mob/dead/new_player/sprite_accessories/tails.dm b/code/modules/mob/dead/new_player/sprite_accessories/tails.dm
index 31faabf6..84c9feaa 100644
--- a/code/modules/mob/dead/new_player/sprite_accessories/tails.dm
+++ b/code/modules/mob/dead/new_player/sprite_accessories/tails.dm
@@ -43,13 +43,668 @@
/datum/sprite_accessory/tails_animated/human/none
name = "None"
icon_state = "none"
-/*
+
+/datum/sprite_accessory/tails/lizard/axolotl
+ name = "Axolotl"
+ icon_state = "axolotl"
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+
+/datum/sprite_accessory/tails_animated/lizard/axolotl
+ name = "Axolotl"
+ icon_state = "axolotl"
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+
+/datum/sprite_accessory/body_markings/guilmon
+ name = "Guilmon"
+ icon_state = "guilmon"
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/markings_notmammals.dmi'
+
+/datum/sprite_accessory/tails/lizard/guilmon
+ name = "Guilmon"
+ icon_state = "guilmon"
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+
+/datum/sprite_accessory/tails_animated/lizard/guilmon
+ name = "Guilmon"
+ icon_state = "guilmon"
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+
+/******************************************
+************** Human Tails ****************
+*******************************************/
+
+/datum/sprite_accessory/tails/human/none
+ name = "None"
+ icon_state = "none"
+
+/datum/sprite_accessory/tails_animated/human/none
+ name = "None"
+ icon_state = "none"
+
+/datum/sprite_accessory/tails/human/ailurus
+ name = "Red Panda"
+ icon_state = "wah"
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/tails_animated/human/ailurus
+ name = "Red Panda"
+ icon_state = "wah"
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/tails/human/axolotl
+ name = "Axolotl"
+ icon_state = "axolotl"
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/tails_animated/human/axolotl
+ name = "Axolotl"
+ icon_state = "axolotl"
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/tails/human/bee
+ name = "Bee"
+ icon_state = "bee"
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/tails_animated/human/bee
+ name = "Bee"
+ icon_state = "bee"
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+ color_src = MATRIXED
+
/datum/sprite_accessory/tails/human/cat
name = "Cat"
icon_state = "cat"
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
color_src = HAIR
/datum/sprite_accessory/tails_animated/human/cat
name = "Cat"
icon_state = "cat"
- color_src = HAIR*/
\ No newline at end of file
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+ color_src = HAIR
+
+/datum/sprite_accessory/tails/human/catbig
+ name = "Cat, Big"
+ icon_state = "catbig"
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/tails_animated/human/catbig
+ name = "Cat, Big"
+ icon_state = "catbig"
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/tails/human/cow
+ name = "Cow"
+ icon_state = "cow"
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/tails_animated/human/cow
+ name = "Cow"
+ icon_state = "cow"
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/tails/human/corvid
+ name = "Corvid"
+ icon_state = "crow"
+
+/datum/sprite_accessory/tails_animated/human/corvid
+ name = "Corvid"
+ icon_state = "crow"
+
+/datum/sprite_accessory/tails/human/eevee
+ name = "Eevee"
+ icon_state = "eevee"
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/tails_animated/human/eevee
+ name = "Eevee"
+ icon_state = "eevee"
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/tails/human/fennec
+ name = "Fennec"
+ icon_state = "fennec"
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/tails_animated/human/fennec
+ name = "Fennec"
+ icon_state = "fennec"
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/tails/human/fish
+ name = "Fish"
+ icon_state = "fish"
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/tails_animated/human/fish
+ name = "Fish"
+ icon_state = "fish"
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/tails/human/fox
+ name = "Fox"
+ icon_state = "fox"
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/tails_animated/human/fox
+ name = "Fox"
+ icon_state = "fox"
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/tails/human/horse
+ name = "Horse"
+ icon_state = "horse"
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+ color_src = HAIR
+
+/datum/sprite_accessory/tails_animated/human/horse
+ name = "Horse"
+ icon_state = "horse"
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+ color_src = HAIR
+
+/datum/sprite_accessory/tails/human/husky
+ name = "Husky"
+ icon_state = "husky"
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/tails_animated/human/husky
+ name = "Husky"
+ icon_state = "husky"
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/tails/human/insect
+ name = "Insect"
+ icon_state = "insect"
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/tails_animated/human/insect
+ name = "insect"
+ icon_state = "insect"
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+ color_src = MATRIXED
+
+/datum/sprite_accessory/tails/human/kitsune
+ name = "Kitsune"
+ icon_state = "kitsune"
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+
+/datum/sprite_accessory/tails_animated/human/kitsune
+ name = "Kitsune"
+ icon_state = "kitsune"
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+
+/datum/sprite_accessory/tails/human/murid
+ name = "Murid"
+ icon_state = "murid"
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+
+/datum/sprite_accessory/tails_animated/human/murid
+ name = "Murid"
+ icon_state = "murid"
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+
+/datum/sprite_accessory/tails/human/otie
+ name = "Otusian"
+ icon_state = "otie"
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+
+/datum/sprite_accessory/tails_animated/human/otie
+ name = "Otusian"
+ icon_state = "otie"
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+
+/datum/sprite_accessory/tails/orca
+ name = "Orca"
+ icon_state = "orca"
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+
+/datum/sprite_accessory/tails_animated/orca
+ name = "Orca"
+ icon_state = "orca"
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+
+/datum/sprite_accessory/tails/human/pede
+ name = "Scolipede"
+ icon_state = "pede"
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+
+/datum/sprite_accessory/tails_animated/human/pede
+ name = "Scolipede"
+ icon_state = "pede"
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+
+/datum/sprite_accessory/tails/human/rabbit
+ name = "Rabbit"
+ icon_state = "rabbit"
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+
+/datum/sprite_accessory/tails_animated/human/rabbit
+ name = "Rabbit"
+ icon_state = "rabbit"
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+
+/datum/sprite_accessory/tails/human/sergal
+ name = "Sergal"
+ icon_state = "sergal"
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+
+/datum/sprite_accessory/tails_animated/human/sergal
+ name = "Sergal"
+ icon_state = "sergal"
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+
+/datum/sprite_accessory/tails/human/skunk
+ name = "skunk"
+ icon_state = "skunk"
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+
+/datum/sprite_accessory/tails_animated/human/skunk
+ name = "skunk"
+ icon_state = "skunk"
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+
+/datum/sprite_accessory/tails/human/shark
+ name = "Shark"
+ icon_state = "shark"
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+
+/datum/sprite_accessory/tails_animated/human/shark
+ name = "Shark"
+ icon_state = "shark"
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+
+/datum/sprite_accessory/tails/human/datashark
+ name = "datashark"
+ icon_state = "datashark"
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+
+/datum/sprite_accessory/tails_animated/human/datashark
+ name = "datashark"
+ icon_state = "datashark"
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+
+/datum/sprite_accessory/tails/human/straighttail
+ name = "Straight Tail"
+ icon_state = "straighttail"
+
+/datum/sprite_accessory/tails_animated/human/straighttail
+ name = "Straight Tail"
+ icon_state = "straighttail"
+
+/datum/sprite_accessory/tails/human/squirrel
+ name = "Squirrel"
+ icon_state = "squirrel"
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+
+/datum/sprite_accessory/tails_animated/human/squirrel
+ name = "Squirrel"
+ icon_state = "squirrel"
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+
+/datum/sprite_accessory/tails/human/tentacle
+ name = "Tentacle"
+ icon_state = "tentacle"
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+
+/datum/sprite_accessory/tails_animated/human/tentacle
+ name = "Tentacle"
+ icon_state = "tentacle"
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+
+/datum/sprite_accessory/tails/human/tiger
+ name = "Tiger"
+ icon_state = "tiger"
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+
+/datum/sprite_accessory/tails_animated/human/tiger
+ name = "Tiger"
+ icon_state = "tiger"
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+
+/datum/sprite_accessory/tails/human/wolf
+ name = "Wolf"
+ icon_state = "wolf"
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+
+/datum/sprite_accessory/tails_animated/human/wolf
+ name = "Wolf"
+ icon_state = "wolf"
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+
+/******************************************
+************** Furry Tails ****************
+*******************************************/
+
+/datum/sprite_accessory/mam_tails
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+
+/datum/sprite_accessory/mam_tails/none
+ name = "None"
+ icon_state = "none"
+
+/datum/sprite_accessory/mam_tails_animated
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+
+/datum/sprite_accessory/mam_tails_animated/none
+ name = "None"
+ icon_state = "none"
+ color_src = MATRIXED
+
+/datum/sprite_accessory/mam_tails/ailurus
+ name = "Red Panda"
+ icon_state = "wah"
+ extra = TRUE
+
+/datum/sprite_accessory/mam_tails_animated/ailurus
+ name = "Red Panda"
+ icon_state = "wah"
+ extra = TRUE
+
+/datum/sprite_accessory/mam_tails/axolotl
+ name = "Axolotl"
+ icon_state = "axolotl"
+
+/datum/sprite_accessory/mam_tails_animated/axolotl
+ name = "Axolotl"
+ icon_state = "axolotl"
+
+/datum/sprite_accessory/mam_tails/bee
+ name = "Bee"
+ icon_state = "bee"
+
+/datum/sprite_accessory/mam_tails_animated/bee
+ name = "Bee"
+ icon_state = "bee"
+
+/datum/sprite_accessory/mam_tails/cat
+ name = "Cat"
+ icon_state = "cat"
+ color_src = HAIR
+
+/datum/sprite_accessory/mam_tails_animated/cat
+ name = "Cat"
+ icon_state = "cat"
+ color_src = HAIR
+
+/datum/sprite_accessory/mam_tails/catbig
+ name = "Cat, Big"
+ icon_state = "catbig"
+
+/datum/sprite_accessory/mam_tails_animated/catbig
+ name = "Cat, Big"
+ icon_state = "catbig"
+
+/datum/sprite_accessory/mam_tails/corvid
+ name = "Corvid"
+ icon_state = "crow"
+
+/datum/sprite_accessory/mam_tails_animated/corvid
+ name = "Corvid"
+ icon_state = "crow"
+
+/datum/sprite_accessory/mam_tail/cow
+ name = "Cow"
+ icon_state = "cow"
+
+/datum/sprite_accessory/mam_tails_animated/cow
+ name = "Cow"
+ icon_state = "cow"
+
+/datum/sprite_accessory/mam_tails/eevee
+ name = "Eevee"
+ icon_state = "eevee"
+
+/datum/sprite_accessory/mam_tails_animated/eevee
+ name = "Eevee"
+ icon_state = "eevee"
+
+/datum/sprite_accessory/mam_tails/fennec
+ name = "Fennec"
+ icon_state = "fennec"
+
+/datum/sprite_accessory/mam_tails_animated/fennec
+ name = "Fennec"
+ icon_state = "fennec"
+
+/datum/sprite_accessory/mam_tails/human/fish
+ name = "Fish"
+ icon_state = "fish"
+
+/datum/sprite_accessory/mam_tails_animated/human/fish
+ name = "Fish"
+ icon_state = "fish"
+
+/datum/sprite_accessory/mam_tails/fox
+ name = "Fox"
+ icon_state = "fox"
+
+/datum/sprite_accessory/mam_tails_animated/fox
+ name = "Fox"
+ icon_state = "fox"
+
+/datum/sprite_accessory/mam_tails/hawk
+ name = "Hawk"
+ icon_state = "hawk"
+
+/datum/sprite_accessory/mam_tails_animated/hawk
+ name = "Hawk"
+ icon_state = "hawk"
+
+/datum/sprite_accessory/mam_tails/horse
+ name = "Horse"
+ icon_state = "horse"
+ color_src = HAIR
+
+/datum/sprite_accessory/mam_tails_animated/horse
+ name = "Horse"
+ icon_state = "horse"
+ color_src = HAIR
+
+/datum/sprite_accessory/mam_tails/husky
+ name = "Husky"
+ icon_state = "husky"
+
+/datum/sprite_accessory/mam_tails_animated/husky
+ name = "Husky"
+ icon_state = "husky"
+
+datum/sprite_accessory/mam_tails/insect
+ name = "Insect"
+ icon_state = "insect"
+
+/datum/sprite_accessory/mam_tails_animated/insect
+ name = "Insect"
+ icon_state = "insect"
+
+/datum/sprite_accessory/mam_tails/kangaroo
+ name = "kangaroo"
+ icon_state = "kangaroo"
+
+/datum/sprite_accessory/mam_tails_animated/kangaroo
+ name = "kangaroo"
+ icon_state = "kangaroo"
+
+/datum/sprite_accessory/mam_tails/kitsune
+ name = "Kitsune"
+ icon_state = "kitsune"
+
+/datum/sprite_accessory/mam_tails_animated/kitsune
+ name = "Kitsune"
+ icon_state = "kitsune"
+
+/datum/sprite_accessory/mam_tails/lab
+ name = "Lab"
+ icon_state = "lab"
+
+/datum/sprite_accessory/mam_tails_animated/lab
+ name = "Lab"
+ icon_state = "lab"
+
+/datum/sprite_accessory/mam_tails/murid
+ name = "Murid"
+ icon_state = "murid"
+
+/datum/sprite_accessory/mam_tails_animated/murid
+ name = "Murid"
+ icon_state = "murid"
+
+/datum/sprite_accessory/mam_tails/otie
+ name = "Otusian"
+ icon_state = "otie"
+
+/datum/sprite_accessory/mam_tails_animated/otie
+ name = "Otusian"
+ icon_state = "otie"
+
+/datum/sprite_accessory/mam_tails/orca
+ name = "Orca"
+ icon_state = "orca"
+
+/datum/sprite_accessory/mam_tails_animated/orca
+ name = "Orca"
+ icon_state = "orca"
+
+/datum/sprite_accessory/mam_tails/pede
+ name = "Scolipede"
+ icon_state = "pede"
+
+/datum/sprite_accessory/mam_tails_animated/pede
+ name = "Scolipede"
+ icon_state = "pede"
+
+/datum/sprite_accessory/mam_tails/rabbit
+ name = "Rabbit"
+ icon_state = "rabbit"
+
+/datum/sprite_accessory/mam_tails_animated/rabbit
+ name = "Rabbit"
+ icon_state = "rabbit"
+
+/datum/sprite_accessory/mam_tails/sergal
+ name = "Sergal"
+ icon_state = "sergal"
+
+/datum/sprite_accessory/mam_tails_animated/sergal
+ name = "Sergal"
+ icon_state = "sergal"
+
+/datum/sprite_accessory/mam_tails/skunk
+ name = "Skunk"
+ icon_state = "skunk"
+
+/datum/sprite_accessory/mam_tails_animated/skunk
+ name = "Skunk"
+ icon_state = "skunk"
+
+/datum/sprite_accessory/mam_tails/shark
+ name = "Shark"
+ icon_state = "shark"
+
+/datum/sprite_accessory/mam_tails_animated/shark
+ name = "Shark"
+ icon_state = "shark"
+
+/datum/sprite_accessory/mam_tails/shepherd
+ name = "Shepherd"
+ icon_state = "shepherd"
+
+/datum/sprite_accessory/mam_tails_animated/shepherd
+ name = "Shepherd"
+ icon_state = "shepherd"
+
+/datum/sprite_accessory/mam_tails/straighttail
+ name = "Straight Tail"
+ icon_state = "straighttail"
+
+/datum/sprite_accessory/mam_tails_animated/straighttail
+ name = "Straight Tail"
+ icon_state = "straighttail"
+
+/datum/sprite_accessory/mam_tails/squirrel
+ name = "Squirrel"
+ icon_state = "squirrel"
+
+/datum/sprite_accessory/mam_tails_animated/squirrel
+ name = "Squirrel"
+ icon_state = "squirrel"
+
+/datum/sprite_accessory/mam_tails/tentacle
+ name = "Tentacle"
+ icon_state = "tentacle"
+
+/datum/sprite_accessory/mam_tails_animated/tentacle
+ name = "Tentacle"
+ icon_state = "tentacle"
+
+/datum/sprite_accessory/mam_tails/tiger
+ name = "Tiger"
+ icon_state = "tiger"
+
+/datum/sprite_accessory/mam_tails_animated/tiger
+ name = "Tiger"
+ icon_state = "tiger"
+
+/datum/sprite_accessory/mam_tails/wolf
+ name = "Wolf"
+ icon_state = "wolf"
+
+/datum/sprite_accessory/mam_tails_animated/wolf
+ name = "Wolf"
+ icon_state = "wolf"
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index b4a8839e..6312db1e 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -860,7 +860,7 @@
piggyback(target)
return
//If you dragged them to you and you're aggressively grabbing try to fireman carry them
- else if(user != target && can_be_firemanned(target))
+ else if(user != target)
fireman_carry(target)
return
. = ..()
diff --git a/code/modules/mob/living/carbon/human/species_types/skeletons.dm b/code/modules/mob/living/carbon/human/species_types/skeletons.dm
index dcb875e1..6c9d95e8 100644
--- a/code/modules/mob/living/carbon/human/species_types/skeletons.dm
+++ b/code/modules/mob/living/carbon/human/species_types/skeletons.dm
@@ -3,7 +3,7 @@
name = "Spooky Scary Skeleton"
id = "skeleton"
say_mod = "rattles"
- blacklisted = 1
+ blacklisted = 0
sexes = 0
meat = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/skeleton
species_traits = list(NOBLOOD,NOGENITALS,NOAROUSAL)
@@ -12,13 +12,18 @@
mutanttongue = /obj/item/organ/tongue/bone
damage_overlay_type = ""//let's not show bloody wounds or burns over bones.
disliked_food = NONE
- liked_food = GROSS | MEAT | RAW
+ liked_food = GROSS | MEAT | RAW | DAIRY
/datum/species/skeleton/check_roundstart_eligible()
if(SSevents.holidays && SSevents.holidays[HALLOWEEN])
return TRUE
return ..()
-/datum/species/skeleton/pirate
- name = "Space Queen's Skeleton"
+/datum/species/skeleton/space
+ name = "Spooky Spacey Skeleton"
+ id = "spaceskeleton"
+ blacklisted = 1
inherent_traits = list(TRAIT_RESISTHEAT,TRAIT_NOBREATH,TRAIT_RESISTCOLD,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_RADIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NOHUNGER,TRAIT_EASYDISMEMBER,TRAIT_LIMBATTACHMENT,TRAIT_FAKEDEATH, TRAIT_CALCIUM_HEALER)
+
+/datum/species/skeleton/pirate/check_roundstart_eligible()
+ return FALSE
diff --git a/code/modules/mob/living/carbon/human/species_types/zombies.dm b/code/modules/mob/living/carbon/human/species_types/zombies.dm
index 61454150..9263aea9 100644
--- a/code/modules/mob/living/carbon/human/species_types/zombies.dm
+++ b/code/modules/mob/living/carbon/human/species_types/zombies.dm
@@ -16,7 +16,12 @@
disliked_food = NONE
liked_food = GROSS | MEAT | RAW
-/datum/species/zombie/check_roundstart_eligible()
+/datum/species/zombie/notspaceproof
+ id = "notspaceproofzombie"
+ blacklisted = 0
+ inherent_traits = list(TRAIT_RESISTCOLD,TRAIT_RADIMMUNE,TRAIT_EASYDISMEMBER,TRAIT_LIMBATTACHMENT,TRAIT_NOBREATH,TRAIT_NODEATH,TRAIT_FAKEDEATH)
+
+/datum/species/zombie/notspaceproof/check_roundstart_eligible()
if(SSevents.holidays && SSevents.holidays[HALLOWEEN])
return TRUE
return ..()
@@ -47,7 +52,7 @@
/datum/species/zombie/infectious/spec_life(mob/living/carbon/C)
. = ..()
C.a_intent = INTENT_HARM // THE SUFFERING MUST FLOW
-
+
//Zombies never actually die, they just fall down until they regenerate enough to rise back up.
//They must be restrained, beheaded or gibbed to stop being a threat.
if(regen_cooldown < world.time)
@@ -58,7 +63,7 @@
C.adjustToxLoss(-heal_amt)
if(!C.InCritical() && prob(4))
playsound(C, pick(spooks), 50, TRUE, 10)
-
+
//Congrats you somehow died so hard you stopped being a zombie
/datum/species/zombie/infectious/spec_death(mob/living/carbon/C)
. = ..()
diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm
index 72ff7e7a..3df86ce4 100644
--- a/code/modules/mob/living/carbon/human/update_icons.dm
+++ b/code/modules/mob/living/carbon/human/update_icons.dm
@@ -123,15 +123,16 @@ There are several things that need to be remembered:
if(U.adjusted == ALT_STYLE)
t_color = "[t_color]_d"
- if(U.mutantrace_variation)
- if(U.suit_style == DIGITIGRADE_SUIT_STYLE)
- U.alternate_worn_icon = 'modular_citadel/icons/mob/uniform_digi.dmi'
- if(U.adjusted == ALT_STYLE)
- t_color = "[t_color]_d_l"
- else if(U.adjusted == NORMAL_STYLE)
- t_color = "[t_color]_l"
- else
- U.alternate_worn_icon = null
+ if(!U.force_alternate_icon)
+ if(U.mutantrace_variation)
+ if(U.suit_style == DIGITIGRADE_SUIT_STYLE)
+ U.alternate_worn_icon = 'modular_citadel/icons/mob/uniform_digi.dmi'
+ if(U.adjusted == ALT_STYLE)
+ t_color = "[t_color]_d_l"
+ else if(U.adjusted == NORMAL_STYLE)
+ t_color = "[t_color]_l"
+ else
+ U.alternate_worn_icon = null
var/mutable_appearance/uniform_overlay
diff --git a/code/modules/mob/living/simple_animal/hostile/goose.dm b/code/modules/mob/living/simple_animal/hostile/goose.dm
new file mode 100644
index 00000000..6f6dc992
--- /dev/null
+++ b/code/modules/mob/living/simple_animal/hostile/goose.dm
@@ -0,0 +1,173 @@
+#define GOOSE_SATIATED 50
+
+/mob/living/simple_animal/hostile/retaliate/goose
+ name = "goose"
+ desc = "It's loose"
+ icon_state = "goose" // sprites by cogwerks from goonstation, used with permission
+ icon_living = "goose"
+ icon_dead = "goose_dead"
+ mob_biotypes = list(MOB_ORGANIC, MOB_BEAST)
+ speak_chance = 0
+ turns_per_move = 5
+ butcher_results = list(/obj/item/reagent_containers/food/snacks/meat = 2)
+ response_help = "pets"
+ response_disarm = "gently pushes aside"
+ response_harm = "kicks"
+ emote_taunt = list("hisses")
+ taunt_chance = 30
+ speed = 0
+ maxHealth = 25
+ health = 25
+ harm_intent_damage = 5
+ melee_damage_lower = 5
+ melee_damage_upper = 5
+ attacktext = "pecks"
+ attack_sound = "goose"
+ speak_emote = list("honks")
+ faction = list("neutral")
+ attack_same = TRUE
+ gold_core_spawnable = HOSTILE_SPAWN
+ var/random_retaliate = TRUE
+ var/icon_vomit_start = "vomit_start"
+ var/icon_vomit = "vomit"
+ var/icon_vomit_end = "vomit_end"
+
+/mob/living/simple_animal/hostile/retaliate/goose/handle_automated_movement()
+ . = ..()
+ if(prob(5) && random_retaliate == TRUE)
+ Retaliate()
+
+/mob/living/simple_animal/hostile/retaliate/goose/vomit
+ name = "Birdboat"
+ real_name = "Birdboat"
+ desc = "It's a sick-looking goose, probably ate too much maintenance trash. Best not to move it around too much."
+ gender = MALE
+ response_help = "pets"
+ response_disarm = "gently pushes aside"
+ response_harm = "kicks"
+ gold_core_spawnable = NO_SPAWN
+ random_retaliate = FALSE
+ var/vomiting = FALSE
+ var/vomitCoefficient = 1
+ var/vomitTimeBonus = 0
+ var/datum/action/cooldown/vomit/goosevomit
+
+/mob/living/simple_animal/hostile/retaliate/goose/vomit/cargo
+ name = "Sickly Goose"
+ real_name = "Sickly Goose"
+
+/mob/living/simple_animal/hostile/retaliate/goose/vomit/Initialize()
+ . = ..()
+ goosevomit = new
+ goosevomit.Grant(src)
+
+/mob/living/simple_animal/hostile/retaliate/goose/vomit/Destroy()
+ QDEL_NULL(goosevomit)
+ return ..()
+
+/mob/living/simple_animal/hostile/retaliate/goose/vomit/examine(user)
+ . = ..()
+ . += "Somehow, it still looks hungry."
+
+/mob/living/simple_animal/hostile/retaliate/goose/vomit/attacked_by(obj/item/O, mob/user)
+ . = ..()
+ feed(O)
+
+/mob/living/simple_animal/hostile/retaliate/goose/vomit/proc/feed(obj/item/O)
+ var/obj/item/reagent_containers/food/tasty = O
+ if(!istype(O))
+ return
+ if (contents.len > GOOSE_SATIATED)
+ visible_message("[src] looks too full to eat \the [tasty]!")
+ return
+ if (tasty.foodtype & GROSS)
+ visible_message("[src] hungrily gobbles up \the [tasty]!")
+ tasty.forceMove(src)
+ playsound(src,'sound/items/eatfood.ogg', 70, 1)
+ vomitCoefficient += 3
+ vomitTimeBonus += 2
+ else
+ visible_message("[src] refuses to eat \the [tasty].")
+
+/mob/living/simple_animal/hostile/retaliate/goose/vomit/proc/vomit()
+ var/turf/T = get_turf(src)
+ var/obj/item/reagent_containers/food/consumed = locate() in contents //Barf out a single food item from our guts
+ if (prob(50) && consumed)
+ barf_food(consumed)
+ else
+ playsound(T, 'sound/effects/splat.ogg', 50, 1)
+ T.add_vomit_floor(src)
+
+/mob/living/simple_animal/hostile/retaliate/goose/vomit/proc/barf_food(var/atom/A, var/hard = FALSE)
+ if(!istype(A, /obj/item/reagent_containers/food))
+ return
+ var/turf/currentTurf = get_turf(src)
+ var/obj/item/reagent_containers/food/consumed = A
+ consumed.forceMove(currentTurf)
+ var/destination = get_edge_target_turf(currentTurf, pick(GLOB.alldirs)) //Pick a random direction to toss them in
+ var/throwRange = hard ? rand(2,8) : 1
+ consumed.safe_throw_at(destination, throwRange, 2) //Thow the food at a random tile 1 spot away
+ sleep(2)
+ if (QDELETED(src) || QDELETED(consumed))
+ return
+ currentTurf = get_turf(consumed)
+ currentTurf.add_vomit_floor(src)
+ playsound(currentTurf, 'sound/effects/splat.ogg', 50, 1)
+
+/mob/living/simple_animal/hostile/retaliate/goose/vomit/proc/vomit_prestart(duration)
+ flick("vomit_start",src)
+ addtimer(CALLBACK(src, .proc/vomit_start, duration), 13) //13 is the length of the vomit_start animation in gooseloose.dmi
+
+/mob/living/simple_animal/hostile/retaliate/goose/vomit/proc/vomit_start(duration)
+ vomiting = TRUE
+ icon_state = "vomit"
+ vomit()
+ addtimer(CALLBACK(src, .proc/vomit_preend), duration)
+
+/mob/living/simple_animal/hostile/retaliate/goose/vomit/proc/vomit_preend()
+ for (var/obj/item/consumed in contents) //Get rid of any food left in the poor thing
+ barf_food(consumed, TRUE)
+ sleep(1)
+ if (QDELETED(src))
+ return
+ vomit_end()
+
+/mob/living/simple_animal/hostile/retaliate/goose/vomit/proc/vomit_end()
+ flick("vomit_end",src)
+ vomiting = FALSE
+ icon_state = initial(icon_state)
+
+/mob/living/simple_animal/hostile/retaliate/goose/vomit/Moved(oldLoc, dir)
+ . = ..()
+ if(vomiting)
+ vomit() // its supposed to keep vomiting if you move
+ return
+ var/turf/currentTurf = get_turf(src)
+ while (currentTurf == get_turf(src))
+ var/obj/item/reagent_containers/food/tasty = locate() in currentTurf
+ if (tasty)
+ feed(tasty)
+ stoplag(20)
+ if(prob(vomitCoefficient * 0.2))
+ vomit_prestart(vomitTimeBonus + 25)
+ vomitCoefficient = 1
+ vomitTimeBonus = 0
+
+/datum/action/cooldown/vomit
+ name = "Vomit"
+ check_flags = AB_CHECK_CONSCIOUS
+ button_icon_state = "vomit"
+ icon_icon = 'icons/mob/animal.dmi'
+ cooldown_time = 250
+
+/datum/action/cooldown/vomit/Trigger()
+ if(!..())
+ return FALSE
+ if(!istype(owner, /mob/living/simple_animal/hostile/retaliate/goose/vomit))
+ return FALSE
+ var/mob/living/simple_animal/hostile/retaliate/goose/vomit/vomit = owner
+ if(!vomit.vomiting)
+ vomit.vomit_prestart(vomit.vomitTimeBonus + 25)
+ vomit.vomitCoefficient = 1
+ vomit.vomitTimeBonus = 0
+ return TRUE
\ No newline at end of file
diff --git a/code/modules/paperwork/filingcabinet.dm b/code/modules/paperwork/filingcabinet.dm
index 9706526a..aa1fd7db 100644
--- a/code/modules/paperwork/filingcabinet.dm
+++ b/code/modules/paperwork/filingcabinet.dm
@@ -67,6 +67,9 @@
/obj/structure/filingcabinet/ui_interact(mob/user)
. = ..()
+ if(isobserver(user))
+ return
+
if(contents.len <= 0)
to_chat(user, "[src] is empty.")
return
diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm
index 135d9b85..19ff4728 100644
--- a/code/modules/power/apc.dm
+++ b/code/modules/power/apc.dm
@@ -267,7 +267,7 @@
to_chat(user, "There is an integration cog installed!")
to_chat(user, "Alt-Click the APC to [ locked ? "unlock" : "lock"] the interface.")
-
+
if(issilicon(user))
to_chat(user, "Ctrl-Click the APC to switch the breaker [ operating ? "off" : "on"].")
@@ -793,7 +793,7 @@
if(damage_flag == "melee" && damage_amount < damage_deflection)
return 0
. = ..()
-
+
/obj/machinery/power/apc/deconstruct(disassembled = TRUE)
if(!(flags_1 & NODECONSTRUCT_1))
if(!(stat & BROKEN))
@@ -846,8 +846,6 @@
if(!ui)
ui = new(user, src, ui_key, "apc", name, 535, 515, master_ui, state)
ui.open()
- if(ui)
- ui.set_autoupdate(state = (failure_timer ? 1 : 0))
/obj/machinery/power/apc/ui_data(mob/user)
var/list/data = list(
diff --git a/code/modules/power/supermatter/supermatter.dm b/code/modules/power/supermatter/supermatter.dm
index 7f6306e3..9837d4e7 100644
--- a/code/modules/power/supermatter/supermatter.dm
+++ b/code/modules/power/supermatter/supermatter.dm
@@ -329,6 +329,12 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
if(power)
soundloop.volume = min(40, (round(power/100)/50)+1) // 5 +1 volume per 20 power. 2500 power is max
+ if(isclosedturf(T))
+ var/turf/did_it_melt = T.Melt()
+ if(!isclosedturf(did_it_melt)) //In case some joker finds way to place these on indestructible walls
+ visible_message("[src] melts through [T]!")
+ return
+
//Ok, get the air from the turf
var/datum/gas_mixture/env = T.return_air()
diff --git a/code/modules/projectiles/ammunition/ballistic/revolver.dm b/code/modules/projectiles/ammunition/ballistic/revolver.dm
index 9e2fa3a9..d5a9fab4 100644
--- a/code/modules/projectiles/ammunition/ballistic/revolver.dm
+++ b/code/modules/projectiles/ammunition/ballistic/revolver.dm
@@ -6,6 +6,11 @@
caliber = "357"
projectile_type = /obj/item/projectile/bullet/a357
+/obj/item/ammo_casing/a357/ap
+ name = ".357 armor-piercing bullet casing"
+ desc = "A .357 armor-piercing bullet casing."
+ projectile_type = /obj/item/projectile/bullet/a357/ap
+
// 7.62x38mmR (Nagant Revolver)
/obj/item/ammo_casing/n762
@@ -20,9 +25,26 @@
name = ".38 rubber bullet casing"
desc = "A .38 rubber bullet casing."
caliber = "38"
- projectile_type = /obj/item/projectile/bullet/c38
+ projectile_type = /obj/item/projectile/bullet/c38/rubber
/obj/item/ammo_casing/c38/lethal
name = ".38 bullet casing"
desc = "A .38 bullet casing"
- projectile_type = /obj/item/projectile/bullet/c38lethal
+ projectile_type = /obj/item/projectile/bullet/c38
+
+/obj/item/ammo_casing/c38/trac
+ name = ".38 TRAC bullet casing"
+ desc = "A .38 \"TRAC\" bullet casing."
+ projectile_type = /obj/item/projectile/bullet/c38/trac
+
+/obj/item/ammo_casing/c38/hotshot
+ name = ".38 Hot Shot bullet casing"
+ desc = "A .38 Hot Shot bullet casing."
+ caliber = "38"
+ projectile_type = /obj/item/projectile/bullet/c38/hotshot
+
+/obj/item/ammo_casing/c38/iceblox
+ name = ".38 Iceblox bullet casing"
+ desc = "A .38 Iceblox bullet casing."
+ caliber = "38"
+ projectile_type = /obj/item/projectile/bullet/c38/iceblox
\ No newline at end of file
diff --git a/code/modules/projectiles/boxes_magazines/ammo_boxes.dm b/code/modules/projectiles/boxes_magazines/ammo_boxes.dm
index 7cd27e85..b0e699a4 100644
--- a/code/modules/projectiles/boxes_magazines/ammo_boxes.dm
+++ b/code/modules/projectiles/boxes_magazines/ammo_boxes.dm
@@ -3,18 +3,39 @@
desc = "Designed to quickly reload revolvers."
icon_state = "357"
ammo_type = /obj/item/ammo_casing/a357
+ caliber = "357"
max_ammo = 7
multiple_sprites = 1
+/obj/item/ammo_box/a357/ap
+ name = "speed loader (.357 AP)"
+ ammo_type = /obj/item/ammo_casing/a357/ap
+
/obj/item/ammo_box/c38
name = "speed loader (.38 rubber)"
desc = "Designed to quickly reload revolvers."
icon_state = "38"
+ caliber = "38"
ammo_type = /obj/item/ammo_casing/c38
max_ammo = 6
multiple_sprites = 1
materials = list(MAT_METAL = 20000)
+/obj/item/ammo_box/c38/trac
+ name = "speed loader (.38 TRAC)"
+ desc = "Designed to quickly reload revolvers. TRAC bullets embed a tracking implant within the target's body."
+ ammo_type = /obj/item/ammo_casing/c38/trac
+
+/obj/item/ammo_box/c38/hotshot
+ name = "speed loader (.38 Hot Shot)"
+ desc = "Designed to quickly reload revolvers. Hot Shot bullets contain an incendiary payload."
+ ammo_type = /obj/item/ammo_casing/c38/hotshot
+
+/obj/item/ammo_box/c38/iceblox
+ name = "speed loader (.38 Iceblox)"
+ desc = "Designed to quickly reload revolvers. Iceblox bullets contain a cryogenic payload."
+ ammo_type = /obj/item/ammo_casing/c38/iceblox
+
/obj/item/ammo_box/c38/lethal
name = "speed loader (.38)"
ammo_type = /obj/item/ammo_casing/c38/lethal
diff --git a/code/modules/projectiles/projectile/bullets/revolver.dm b/code/modules/projectiles/projectile/bullets/revolver.dm
index 68d51361..8ba2ba97 100644
--- a/code/modules/projectiles/projectile/bullets/revolver.dm
+++ b/code/modules/projectiles/projectile/bullets/revolver.dm
@@ -14,15 +14,58 @@
/obj/item/projectile/bullet/c38
name = ".38 rubber bullet"
+ damage = 25
+ stamina = 48
+
+/obj/item/projectile/bullet/c38/rubber
+ name = ".38 bullet"
damage = 15
stamina = 48
-/obj/item/projectile/bullet/c38lethal
- name = ".38 bullet"
- damage = 25
+/obj/item/projectile/bullet/c38/trac
+ name = ".38 TRAC bullet"
+ damage = 10
+
+/obj/item/projectile/bullet/c38/trac/on_hit(atom/target, blocked = FALSE)
+ . = ..()
+ var/mob/living/carbon/M = target
+ var/obj/item/implant/tracking/c38/imp
+ for(var/obj/item/implant/tracking/c38/TI in M.implants) //checks if the target already contains a tracking implant
+ imp = TI
+ return
+ if(!imp)
+ imp = new /obj/item/implant/tracking/c38(M)
+ imp.implant(M)
+
+/obj/item/projectile/bullet/c38/hotshot //similar to incendiary bullets, but do not leave a flaming trail
+ name = ".38 Hot Shot bullet"
+ damage = 20
+
+/obj/item/projectile/bullet/c38/hotshot/on_hit(atom/target, blocked = FALSE)
+ . = ..()
+ if(iscarbon(target))
+ var/mob/living/carbon/M = target
+ M.adjust_fire_stacks(6)
+ M.IgniteMob()
+
+/obj/item/projectile/bullet/c38/iceblox //see /obj/item/projectile/temp for the original code
+ name = ".38 Iceblox bullet"
+ damage = 20
+ var/temperature = 100
+
+/obj/item/projectile/bullet/c38/iceblox/on_hit(atom/target, blocked = FALSE)
+ . = ..()
+ if(isliving(target))
+ var/mob/living/M = target
+ M.adjust_bodytemperature(((100-blocked)/100)*(temperature - M.bodytemperature))
// .357 (Syndie Revolver)
/obj/item/projectile/bullet/a357
name = ".357 bullet"
damage = 60
+
+/obj/item/projectile/bullet/a357/ap
+ name = ".357 armor-piercing bullet"
+ damage = 45
+ armour_penetration = 45
\ No newline at end of file
diff --git a/code/modules/reagents/chemistry/machinery/pandemic.dm b/code/modules/reagents/chemistry/machinery/pandemic.dm
index 0e482f8c..720d411d 100644
--- a/code/modules/reagents/chemistry/machinery/pandemic.dm
+++ b/code/modules/reagents/chemistry/machinery/pandemic.dm
@@ -125,12 +125,6 @@
else
cut_overlays()
-/obj/machinery/computer/pandemic/proc/eject_beaker()
- if(beaker)
- beaker.forceMove(drop_location())
- beaker = null
- update_icon()
-
/obj/machinery/computer/pandemic/ui_interact(mob/user, ui_key = "main", datum/tgui/ui, force_open = FALSE, datum/tgui/master_ui, datum/ui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
@@ -165,7 +159,7 @@
return
switch(action)
if("eject_beaker")
- eject_beaker()
+ replace_beaker(usr)
. = TRUE
if("empty_beaker")
if(beaker)
@@ -174,7 +168,7 @@
if("empty_eject_beaker")
if(beaker)
beaker.reagents.clear_reagents()
- eject_beaker()
+ replace_beaker(usr)
. = TRUE
if("rename_disease")
var/id = get_virus_id_by_index(text2num(params["index"]))
@@ -232,18 +226,32 @@
. = TRUE //no afterattack
if(stat & (NOPOWER|BROKEN))
return
- if(beaker)
- to_chat(user, "A container is already loaded into [src]!")
+ var/obj/item/reagent_containers/B = I
+ if(!user.transferItemToLoc(B, src))
return
- if(!user.transferItemToLoc(I, src))
- return
-
- beaker = I
+ replace_beaker(user, B)
to_chat(user, "You insert [I] into [src].")
- update_icon()
else
return ..()
+/obj/machinery/computer/pandemic/AltClick(mob/living/user)
+ if(!istype(user) || !user.canUseTopic(src, BE_CLOSE, FALSE, NO_TK))
+ return
+ replace_beaker(user)
+ return
+
+/obj/machinery/computer/pandemic/proc/replace_beaker(mob/living/user, obj/item/reagent_containers/new_beaker)
+ if(beaker)
+ beaker.forceMove(drop_location())
+ if(user && Adjacent(user) && !issiliconoradminghost(user))
+ user.put_in_hands(beaker)
+ if(new_beaker)
+ beaker = new_beaker
+ else
+ beaker = null
+ update_icon()
+ return TRUE
+
/obj/machinery/computer/pandemic/on_deconstruction()
- eject_beaker()
+ replace_beaker(usr)
. = ..()
diff --git a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm
index aa8faa5f..7ff2a40d 100644
--- a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm
@@ -236,10 +236,12 @@
/datum/reagent/medicine/silver_sulfadiazine
name = "Silver Sulfadiazine"
id = "silver_sulfadiazine"
- description = "If used in touch-based applications, immediately restores burn wounds as well as restoring more over time. If ingested through other means, deals minor toxin damage."
+ description = "If used in touch-based applications, immediately restores burn wounds as well as restoring more over time. It is mildly poisonous taken orally or by injection. If overdosed, deals brute and minor liver damage."
reagent_state = LIQUID
pH = 7.2
color = "#ffeac9"
+ metabolization_rate = 5 * REAGENTS_METABOLISM
+ overdose_threshold = 50
/datum/reagent/medicine/silver_sulfadiazine/reaction_mob(mob/living/M, method=TOUCH, reac_volume, show_message = 1)
if(iscarbon(M) && M.stat != DEAD)
@@ -260,6 +262,15 @@
..()
. = 1
+/datum/reagent/medicine/silver_sulfadiazine/overdose_start(mob/living/M)
+ metabolization_rate = 15 * REAGENTS_METABOLISM
+ M.adjustBruteLoss(2*REM, 0)
+ if(iscarbon(M))
+ var/mob/living/carbon/C = M
+ C.applyLiverDamage(1)
+ ..()
+ . = 1
+
/datum/reagent/medicine/oxandrolone
name = "Oxandrolone"
id = "oxandrolone"
@@ -287,10 +298,12 @@
/datum/reagent/medicine/styptic_powder
name = "Styptic Powder"
id = "styptic_powder"
- description = "If used in touch-based applications, immediately restores bruising as well as restoring more over time. If ingested through other means, deals minor toxin damage."
+ description = "If used in touch-based applications, immediately restores bruising as well as restoring more over time. It is poisonous if taken orally or by injection. If overdosed, deals brute and minor liver damage."
reagent_state = LIQUID
color = "#FF9696"
pH = 6.7
+ metabolization_rate = 5 * REAGENTS_METABOLISM
+ overdose_threshold = 50
/datum/reagent/medicine/styptic_powder/reaction_mob(mob/living/M, method=TOUCH, reac_volume, show_message = 1)
if(iscarbon(M) && M.stat != DEAD)
@@ -312,6 +325,15 @@
..()
. = 1
+datum/reagent/medicine/styptic_powder/overdose_start(mob/living/M)
+ metabolization_rate = 15 * REAGENTS_METABOLISM
+ M.adjustBruteLoss(2*REM, 0)
+ if(iscarbon(M))
+ var/mob/living/carbon/C = M
+ C.applyLiverDamage(1)
+ ..()
+ . = 1
+
/datum/reagent/medicine/salglu_solution
name = "Saline-Glucose Solution"
id = "salglu_solution"
@@ -398,23 +420,35 @@
/datum/reagent/medicine/synthflesh
name = "Synthflesh"
id = "synthflesh"
- description = "Has a 100% chance of instantly healing brute and burn damage. One unit of the chemical will heal one point of damage. Touch application only."
+ description = "Has a 100% chance of healing large amounts of brute and burn damage very quickly. One unit of the chemical will heal one point of damage. Touch application only."
reagent_state = LIQUID
color = "#FFEBEB"
pH = 11.5
+ metabolization_rate = 5 * REAGENTS_METABOLISM
+ overdose_threshold = 40
/datum/reagent/medicine/synthflesh/reaction_mob(mob/living/M, method=TOUCH, reac_volume,show_message = 1)
if(iscarbon(M))
if (M.stat == DEAD)
show_message = 0
- if(method in list(PATCH, TOUCH))
- M.adjustBruteLoss(-1.25 * reac_volume)
- M.adjustFireLoss(-1.25 * reac_volume)
+ if(method in list(INGEST, VAPOR))
+ var/mob/living/carbon/C = M
+ C.losebreath++
+ C.emote("cough")
+ to_chat(M, "You feel your throat closing up!")
+ else if(method == INJECT)
+ return
+ else if(method in list(PATCH, TOUCH))
+ M.adjustBruteLoss(-1 * reac_volume)
+ M.adjustFireLoss(-1 * reac_volume)
if(show_message)
to_chat(M, "You feel your burns and bruises healing! It stings like hell!")
SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "painful_medicine", /datum/mood_event/painful_medicine)
..()
+/datum/reagent/medicine/synthflesh/overdose_start(mob/living/M)
+ metabolization_rate = 15 * REAGENTS_METABOLISM
+
/datum/reagent/medicine/charcoal
name = "Charcoal"
id = "charcoal"
diff --git a/code/modules/reagents/reagent_containers/medspray.dm b/code/modules/reagents/reagent_containers/medspray.dm
index 54a38eef..df7c7af2 100644
--- a/code/modules/reagents/reagent_containers/medspray.dm
+++ b/code/modules/reagents/reagent_containers/medspray.dm
@@ -19,8 +19,8 @@
var/can_fill_from_container = TRUE
var/apply_type = PATCH
var/apply_method = "spray"
- var/self_delay = 30
- var/squirt_mode = 0
+ var/self_delay = 3 SECONDS
+ var/squirt_mode = FALSE
var/squirt_amount = 5
/obj/item/reagent_containers/medspray/attack_self(mob/user)
@@ -31,40 +31,51 @@
amount_per_transfer_from_this = initial(amount_per_transfer_from_this)
to_chat(user, "You will now apply the medspray's contents in [squirt_mode ? "short bursts":"extended sprays"]. You'll now use [amount_per_transfer_from_this] units per use.")
-/obj/item/reagent_containers/medspray/attack(mob/M, mob/user, def_zone)
+/obj/item/reagent_containers/medspray/attack(mob/living/L, mob/user, def_zone)
if(!reagents || !reagents.total_volume)
to_chat(user, "[src] is empty!")
return
- if(M == user)
- M.visible_message("[user] attempts to [apply_method] [src] on [user.p_them()]self.")
+ if(ishuman(L))
+ var/obj/item/bodypart/affecting = L.get_bodypart(check_zone(user.zone_selected))
+ if(!affecting)
+ to_chat(user, "The limb is missing!")
+ return
+ if(!L.can_inject(user, TRUE, user.zone_selected, FALSE, TRUE)) //stopped by clothing, like patches
+ return
+ if(affecting.status != BODYPART_ORGANIC)
+ to_chat(user, "Medicine won't work on a robotic limb!")
+ return
+
+ if(L == user)
+ L.visible_message("[user] attempts to [apply_method] [src] on [user.p_them()]self.")
if(self_delay)
- if(!do_mob(user, M, self_delay))
+ if(!do_mob(user, L, self_delay))
return
if(!reagents || !reagents.total_volume)
return
- to_chat(M, "You [apply_method] yourself with [src].")
+ to_chat(L, "You [apply_method] yourself with [src].")
else
- log_combat(user, M, "attempted to apply", src, reagents.log_list())
- M.visible_message("[user] attempts to [apply_method] [src] on [M].", \
- "[user] attempts to [apply_method] [src] on [M].")
- if(!do_mob(user, M))
+ log_combat(user, L, "attempted to apply", src, reagents.log_list())
+ L.visible_message("[user] attempts to [apply_method] [src] on [L].", \
+ "[user] attempts to [apply_method] [src] on [L].")
+ if(!do_mob(user, L))
return
if(!reagents || !reagents.total_volume)
return
- M.visible_message("[user] [apply_method]s [M] down with [src].", \
- "[user] [apply_method]s [M] down with [src].")
+ L.visible_message("[user] [apply_method]s [L] down with [src].", \
+ "[user] [apply_method]s [L] down with [src].")
if(!reagents || !reagents.total_volume)
return
else
- log_combat(user, M, "applied", src, reagents.log_list())
+ log_combat(user, L, "applied", src, reagents.log_list())
playsound(src, 'sound/effects/spray2.ogg', 50, 1, -6)
var/fraction = min(amount_per_transfer_from_this/reagents.total_volume, 1)
- reagents.reaction(M, apply_type, fraction)
- reagents.trans_to(M, amount_per_transfer_from_this)
+ reagents.reaction(L, apply_type, fraction)
+ reagents.trans_to(L, amount_per_transfer_from_this)
return
/obj/item/reagent_containers/medspray/styptic
diff --git a/code/modules/research/designs/weapon_designs.dm b/code/modules/research/designs/weapon_designs.dm
index 214ef36a..7dd85ea1 100644
--- a/code/modules/research/designs/weapon_designs.dm
+++ b/code/modules/research/designs/weapon_designs.dm
@@ -17,6 +17,36 @@
id = "sec_38lethal"
build_path = /obj/item/ammo_box/c38/lethal
+/datum/design/c38_trac
+ name = "Speed Loader (.38 TRAC)"
+ desc = "Designed to quickly reload revolvers. TRAC bullets embed a tracking implant within the target's body."
+ id = "c38_trac"
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 20000, MAT_SILVER = 5000, MAT_GOLD = 1000)
+ build_path = /obj/item/ammo_box/c38/trac
+ category = list("Ammo")
+ departmental_flags = DEPARTMENTAL_FLAG_SECURITY
+
+/datum/design/c38_hotshot
+ name = "Speed Loader (.38 Hot Shot)"
+ desc = "Designed to quickly reload revolvers. Hot Shot bullets contain an incendiary payload."
+ id = "c38_hotshot"
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 20000, MAT_PLASMA = 5000)
+ build_path = /obj/item/ammo_box/c38/hotshot
+ category = list("Ammo")
+ departmental_flags = DEPARTMENTAL_FLAG_SECURITY
+
+/datum/design/c38_iceblox
+ name = "Speed Loader (.38 Iceblox)"
+ desc = "Designed to quickly reload revolvers. Iceblox bullets contain a cryogenic payload."
+ id = "c38_iceblox"
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 20000, MAT_PLASMA = 5000)
+ build_path = /obj/item/ammo_box/c38/iceblox
+ category = list("Ammo")
+ departmental_flags = DEPARTMENTAL_FLAG_SECURITY
+
//////////////
//WT550 Mags//
//////////////
diff --git a/code/modules/research/techweb/all_nodes.dm b/code/modules/research/techweb/all_nodes.dm
index 80c43540..843244c5 100644
--- a/code/modules/research/techweb/all_nodes.dm
+++ b/code/modules/research/techweb/all_nodes.dm
@@ -518,7 +518,7 @@
display_name = "Subdermal Implants"
description = "Electronic implants buried beneath the skin."
prereq_ids = list("biotech", "datatheory")
- design_ids = list("implanter", "implantcase", "implant_chem", "implant_tracking", "locator")
+ design_ids = list("implanter", "implantcase", "implant_chem", "implant_tracking", "locator", "c38_trac")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
export_price = 5000
@@ -694,12 +694,12 @@
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2750)
export_price = 5000
-/datum/techweb_node/tech_shell
- id = "tech_shell"
- display_name = "Technological Shells"
- description = "They're more technological than regular shot."
+/datum/techweb_node/exotic_ammo
+ id = "exotic_ammo"
+ display_name = "Exotic Ammunition"
+ description = "They won't know what hit em."
prereq_ids = list("weaponry", "ballistic_weapons")
- design_ids = list("techshotshell")
+ design_ids = list("techshotshell", "c38_hotshot", "c38_iceblox")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 3500)
export_price = 5000
diff --git a/code/modules/spells/spell_types/lichdom.dm b/code/modules/spells/spell_types/lichdom.dm
index efc80101..0cbb3a82 100644
--- a/code/modules/spells/spell_types/lichdom.dm
+++ b/code/modules/spells/spell_types/lichdom.dm
@@ -57,7 +57,7 @@
new /obj/item/phylactery(marked_item, M.mind)
to_chat(M, "With a hideous feeling of emptiness you watch in horrified fascination as skin sloughs off bone! Blood boils, nerves disintegrate, eyes boil in their sockets! As your organs crumble to dust in your fleshless chest you come to terms with your choice. You're a lich!")
- M.set_species(/datum/species/skeleton)
+ M.set_species(/datum/species/skeleton/space)
if(ishuman(M))
var/mob/living/carbon/human/H = M
H.dropItemToGround(H.w_uniform)
@@ -132,7 +132,7 @@
lich.real_name = mind.name
mind.transfer_to(lich)
mind.grab_ghost(force=TRUE)
- lich.hardset_dna(null,null,lich.real_name,null, new /datum/species/skeleton)
+ lich.hardset_dna(null,null,lich.real_name,null, new /datum/species/skeleton/space)
to_chat(lich, "Your bones clatter and shudder as you are pulled back into this world!")
var/turf/body_turf = get_turf(old_body)
lich.Knockdown(200 + 200*resurrections)
diff --git a/code/modules/uplink/uplink_items.dm b/code/modules/uplink/uplink_items.dm
index 781fdb24..f93bdbae 100644
--- a/code/modules/uplink/uplink_items.dm
+++ b/code/modules/uplink/uplink_items.dm
@@ -767,9 +767,15 @@ datum/uplink_item/stealthy_weapons/taeclowndo_shoes
desc = "A speed loader that contains seven additional .357 Magnum rounds; usable with the Syndicate revolver. \
For when you really need a lot of things dead."
item = /obj/item/ammo_box/a357
- cost = 4
+ cost = 3
exclude_modes = list(/datum/game_mode/nuclear/clown_ops)
+/datum/uplink_item/ammo/revolver/ap
+ name = ".357 Armor Piercing Speed Loader"
+ desc = "A speed loader that contains seven additional .357 AP Magnum rounds; usable with the Syndicate revolver. \
+ Cuts through like a hot knife through butter."
+ item = /obj/item/ammo_box/a357/ap
+
/datum/uplink_item/ammo/a40mm
name = "40mm Grenade"
desc = "A 40mm HE grenade for use with the M-90gl's under-barrel grenade launcher. \
@@ -1487,9 +1493,10 @@ datum/uplink_item/stealthy_weapons/taeclowndo_shoes
/datum/uplink_item/device_tools/singularity_beacon
name = "Power Beacon"
desc = "When screwed to wiring attached to an electric grid and activated, this large device pulls any \
- active gravitational singularities or tesla balls towards it. This will not work when the engine is still \
- in containment. Because of its size, it cannot be carried. Ordering this \
- sends you a small beacon that will teleport the larger beacon to your location upon activation."
+ active gravitational singularities or tesla balls towards it (provided they are not safely \
+ contained), as well as increasing the odds of incoming meteor waves. \
+ Because of its size, it cannot be carried. Ordering this sends you a small beacon \
+ that will teleport the larger beacon to your location upon activation."
item = /obj/item/sbeacondrop
cost = 14
diff --git a/config/config.txt b/config/config.txt
index ba8303ff..d6a6f18f 100644
--- a/config/config.txt
+++ b/config/config.txt
@@ -242,10 +242,10 @@ CHECK_RANDOMIZER
# WIKIURL http://www.tgstation13.org/wiki
## Rules address
-# RULESURL http://www.tgstation13.org/wiki/Rules
+# RULESURL https://hyperstation13.com/rules
## Github address
-# GITHUBURL https://www.github.com/tgstation/tgstation
+# GITHUBURL https://github.com/quotefox/Hyper-Station-13
## Round specific stats address
## Link to round specific parsed logs; IE statbus. It is appended with the RoundID automatically by ticker/Reboot()
diff --git a/icons/mob/animal.dmi b/icons/mob/animal.dmi
index 2a85f8a4..e9343c7e 100644
Binary files a/icons/mob/animal.dmi and b/icons/mob/animal.dmi differ
diff --git a/modular_citadel/code/game/objects/items/melee/eutactic_blades.dm b/modular_citadel/code/game/objects/items/melee/eutactic_blades.dm
index 68ab229f..033057ba 100644
--- a/modular_citadel/code/game/objects/items/melee/eutactic_blades.dm
+++ b/modular_citadel/code/game/objects/items/melee/eutactic_blades.dm
@@ -130,15 +130,6 @@
else
return ..()
-/obj/item/melee/transforming/energy/sword/cx/chaplain
- name = "divine lightblade"
- force_on = 20 //haha i'll regret this
- block_chance = 50
-
-/obj/item/melee/transforming/energy/sword/cx/chaplain/Initialize()
- . = ..()
- AddComponent(/datum/component/anti_magic, TRUE, TRUE)
-
//OBLIGATORY TOY MEMES /////////////////////////////////////
/obj/item/toy/sword/cx
@@ -271,6 +262,24 @@
spinnable = FALSE
total_mass_on = 4
+/obj/item/twohanded/dualsaber/hypereutactic/chaplain
+ name = "\improper divine lightblade"
+ desc = "A giant blade of bright and holy light, said to cut down the wicked with ease."
+ force = 5
+ force_unwielded = 5
+ force_wielded = 20
+ block_chance = 50
+ armour_penetration = 0
+ var/chaplain_spawnable = TRUE
+ obj_flags = UNIQUE_RENAME
+
+/obj/item/twohanded/dualsaber/hypereutactic/chaplain/Initialize()
+ . = ..()
+ AddComponent(/datum/component/anti_magic, TRUE, TRUE)
+
+/obj/item/twohanded/dualsaber/hypereutactic/chaplain/IsReflect()
+ return FALSE
+
/obj/item/twohanded/dualsaber/hypereutactic/pre_altattackby(atom/A, mob/living/user, params) //checks if it can do right click memes
altafterattack(A, user, TRUE, params)
return TRUE
diff --git a/modular_citadel/code/modules/clothing/clothing.dm b/modular_citadel/code/modules/clothing/clothing.dm
index fc71d5bd..7f366ecf 100644
--- a/modular_citadel/code/modules/clothing/clothing.dm
+++ b/modular_citadel/code/modules/clothing/clothing.dm
@@ -38,6 +38,8 @@
var/secondary_color = "#FFFFFF"
var/tertiary_color = "#808080"
+ var/force_alternate_icon = FALSE
+
/obj/item/clothing/update_icon() // picks the colored overlays from the ICON file
..()
if(hasprimary) //Checks if the overlay is enabled
diff --git a/modular_citadel/code/modules/clothing/under/trek_under.dm b/modular_citadel/code/modules/clothing/under/trek_under.dm
index a60f7653..e29fd1a6 100644
--- a/modular_citadel/code/modules/clothing/under/trek_under.dm
+++ b/modular_citadel/code/modules/clothing/under/trek_under.dm
@@ -14,6 +14,7 @@
desc = "Oooh... right."
icon = 'modular_citadel/icons/obj/clothing/trek_item_icon.dmi'
alternate_worn_icon = 'modular_citadel/icons/mob/clothing/trek_mob_icon.dmi'
+ force_alternate_icon = TRUE
item_state = ""
can_adjust = FALSE //to prevent you from "wearing it casually"
@@ -23,17 +24,20 @@
desc = "The uniform worn by command officers in the mid 2260s."
icon_state = "trek_command"
item_state = "trek_command"
- armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 0)
+ force_alternate_icon = TRUE
+ armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 0)
/obj/item/clothing/under/rank/trek/engsec
name = "Operations Uniform"
desc = "The uniform worn by operations officers of the mid 2260s. You feel strangely vulnerable just seeing this..."
+ force_alternate_icon = TRUE
icon_state = "trek_engsec"
item_state = "trek_engsec"
/obj/item/clothing/under/rank/trek/medsci
name = "MedSci Uniform"
desc = "The uniform worn by medsci officers in the mid 2260s."
+ force_alternate_icon = TRUE
icon_state = "trek_medsci"
item_state = "trek_medsci"
permeability_coefficient = 0.50
diff --git a/modular_citadel/code/modules/mob/living/silicon/robot/dogborg_equipment.dm b/modular_citadel/code/modules/mob/living/silicon/robot/dogborg_equipment.dm
index c413644b..a3213ef1 100644
--- a/modular_citadel/code/modules/mob/living/silicon/robot/dogborg_equipment.dm
+++ b/modular_citadel/code/modules/mob/living/silicon/robot/dogborg_equipment.dm
@@ -18,7 +18,7 @@ SLEEPER CODE IS IN game/objects/items/devices/dogborg_sleeper.dm !
name = "combat jaws"
desc = "The jaws of the law. Very sharp."
icon_state = "jaws"
- force = 12
+ force = 10 //Lowered to match secborg. No reason it should be more than a secborg's baton.
attack_verb = list("chomped", "bit", "ripped", "mauled", "enforced")
/obj/item/dogborg/jaws/small
@@ -32,7 +32,6 @@ SLEEPER CODE IS IN game/objects/items/devices/dogborg_sleeper.dm !
/obj/item/dogborg/jaws/attack(atom/A, mob/living/silicon/robot/user)
..()
user.do_attack_animation(A, ATTACK_EFFECT_BITE)
- log_combat(user, A, "bit")
/obj/item/dogborg/jaws/small/attack_self(mob/user)
var/mob/living/silicon/robot.R = user
@@ -307,8 +306,8 @@ SLEEPER CODE IS IN game/objects/items/devices/dogborg_sleeper.dm !
/mob/living/silicon/robot
var/leaping = 0
var/pounce_cooldown = 0
- var/pounce_cooldown_time = 50 //Nearly doubled, u happy?
- var/pounce_spoolup = 3
+ var/pounce_cooldown_time = 20 //Buffed to counter balance changes
+ var/pounce_spoolup = 1
var/leap_at
var/disabler
var/laser
@@ -338,7 +337,7 @@ SLEEPER CODE IS IN game/objects/items/devices/dogborg_sleeper.dm !
//It's also extremely buggy visually, so it's balance+bugfix
return
- if(cell.charge <= 500)
+ if(cell.charge <= 750)
to_chat(src,"Insufficent reserves for jump actuators!")
return
@@ -348,7 +347,7 @@ SLEEPER CODE IS IN game/objects/items/devices/dogborg_sleeper.dm !
pixel_y = 10
update_icons()
throw_at(A, MAX_K9_LEAP_DIST, 1, spin=0, diagonals_first = 1)
- cell.use(500) //Doubled the energy consumption
+ cell.use(750) //Less than a stunbaton since stunbatons hit everytime.
weather_immunities -= "lava"
/mob/living/silicon/robot/throw_impact(atom/A)
@@ -366,13 +365,13 @@ SLEEPER CODE IS IN game/objects/items/devices/dogborg_sleeper.dm !
blocked = 1
if(!blocked)
L.visible_message("[src] pounces on [L]!", "[src] pounces on you!")
- L.Knockdown(iscarbon(L) ? 450 : 45) // Temporary. If someone could rework how dogborg pounces work to accomodate for combat changes, that'd be nice.
+ L.Knockdown(iscarbon(L) ? 225 : 45) // Temporary. If someone could rework how dogborg pounces work to accomodate for combat changes, that'd be nice.
playsound(src, 'sound/weapons/Egloves.ogg', 50, 1)
sleep(2)//Runtime prevention (infinite bump() calls on hulks)
step_towards(src,L)
log_combat(src, L, "borg pounced")
else
- Knockdown(45, 1, 1)
+ Knockdown(15, 1, 1)
pounce_cooldown = !pounce_cooldown
spawn(pounce_cooldown_time) //3s by default
@@ -380,7 +379,7 @@ SLEEPER CODE IS IN game/objects/items/devices/dogborg_sleeper.dm !
else if(A.density && !A.CanPass(src))
visible_message("[src] smashes into [A]!", "You smash into [A]!")
playsound(src, 'sound/items/trayhit1.ogg', 50, 1)
- Knockdown(45, 1, 1)
+ Knockdown(15, 1, 1)
if(leaping)
leaping = 0
diff --git a/modular_citadel/icons/mob/mam_tails.dmi b/modular_citadel/icons/mob/mam_tails.dmi
index b16de1c0..5e03cc86 100644
Binary files a/modular_citadel/icons/mob/mam_tails.dmi and b/modular_citadel/icons/mob/mam_tails.dmi differ
diff --git a/modular_citadel/icons/obj/clothing/trek_item_icon.dmi b/modular_citadel/icons/obj/clothing/trek_item_icon.dmi
index ed328661..570acbf4 100644
Binary files a/modular_citadel/icons/obj/clothing/trek_item_icon.dmi and b/modular_citadel/icons/obj/clothing/trek_item_icon.dmi differ
diff --git a/sound/creatures/goose1.ogg b/sound/creatures/goose1.ogg
new file mode 100644
index 00000000..3d605ad6
Binary files /dev/null and b/sound/creatures/goose1.ogg differ
diff --git a/sound/creatures/goose2.ogg b/sound/creatures/goose2.ogg
new file mode 100644
index 00000000..735faba7
Binary files /dev/null and b/sound/creatures/goose2.ogg differ
diff --git a/sound/creatures/goose3.ogg b/sound/creatures/goose3.ogg
new file mode 100644
index 00000000..1aeec773
Binary files /dev/null and b/sound/creatures/goose3.ogg differ
diff --git a/sound/creatures/goose4.ogg b/sound/creatures/goose4.ogg
new file mode 100644
index 00000000..699f143b
Binary files /dev/null and b/sound/creatures/goose4.ogg differ
diff --git a/tgstation.dme b/tgstation.dme
index 360498ed..f00f6aa1 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -231,6 +231,7 @@
#include "code\controllers\subsystem\augury.dm"
#include "code\controllers\subsystem\autotransfer.dm"
#include "code\controllers\subsystem\blackbox.dm"
+#include "code\controllers\subsystem\chat.dm"
#include "code\controllers\subsystem\communications.dm"
#include "code\controllers\subsystem\dbcore.dm"
#include "code\controllers\subsystem\dcs.dm"
@@ -2183,6 +2184,7 @@
#include "code\modules\mob\living\simple_animal\hostile\eyeballs.dm"
#include "code\modules\mob\living\simple_animal\hostile\faithless.dm"
#include "code\modules\mob\living\simple_animal\hostile\giant_spider.dm"
+#include "code\modules\mob\living\simple_animal\hostile\goose.dm"
#include "code\modules\mob\living\simple_animal\hostile\headcrab.dm"
#include "code\modules\mob\living\simple_animal\hostile\heart.dm"
#include "code\modules\mob\living\simple_animal\hostile\hivebot.dm"