diff --git a/code/modules/holiday/halloween/jacqueen.dm b/code/modules/holiday/halloween/jacqueen.dm
index 7f6d48e731..107282b642 100644
--- a/code/modules/holiday/halloween/jacqueen.dm
+++ b/code/modules/holiday/halloween/jacqueen.dm
@@ -38,8 +38,10 @@
health = 25
density = FALSE
speech_span = "spooky"
- friendly = "pets"
- response_help = "chats with"
+ friendly_verb_continuous = "pets"
+ friendly_verb_simple = "pet"
+ response_help_continuous = "chats with"
+ response_help_simple = "chat with"
light_range = 3
light_color = "#ff9842"
var/last_poof
diff --git a/code/modules/holodeck/mobs.dm b/code/modules/holodeck/mobs.dm
index adac4ea7b2..121989bf1e 100644
--- a/code/modules/holodeck/mobs.dm
+++ b/code/modules/holodeck/mobs.dm
@@ -15,6 +15,9 @@
speak_chance = 1
turns_per_move = 2
butcher_results = list()
- response_help = "pets"
- response_disarm = "pushes aside"
- response_harm = "kicks"
+ response_help_continuous = "pets"
+ response_help_simple = "pet"
+ response_disarm_continuous = "pushes aside"
+ response_disarm_simple = "push aside"
+ response_harm_continuous = "kicks"
+ response_harm_simple = "kick"
diff --git a/code/modules/hydroponics/grown/peas.dm b/code/modules/hydroponics/grown/peas.dm
new file mode 100644
index 0000000000..6229d98b2c
--- /dev/null
+++ b/code/modules/hydroponics/grown/peas.dm
@@ -0,0 +1,102 @@
+// Finally, peas. Base plant.
+/obj/item/seeds/peas
+ name = "pack of pea pods"
+ desc = "These seeds grows into vitamin rich peas!"
+ icon_state = "seed-peas"
+ species = "peas"
+ plantname = "Pea Vines"
+ product = /obj/item/reagent_containers/food/snacks/grown/peas
+ maturation = 3
+ potency = 25
+ growthstages = 3
+ growing_icon = 'icons/obj/hydroponics/growing_vegetables.dmi'
+ icon_grow = "peas-grow"
+ icon_dead = "peas-dead"
+ genes = list(/datum/plant_gene/trait/repeated_harvest)
+ mutatelist = list(/obj/item/seeds/peas/laugh) // TODO: Add /obj/item/seeds/peas/shoot at a later date, for the peashooter mutation line
+ reagents_add = list (/datum/reagent/consumable/nutriment/vitamin = 0.1, /datum/reagent/consumable/nutriment = 0.05, /datum/reagent/water = 0.05)
+
+
+/obj/item/reagent_containers/food/snacks/grown/peas
+ seed = /obj/item/seeds/peas
+ name = "peapod"
+ desc = "Finally... peas."
+ icon_state = "peas"
+ filling_color = "#739122"
+ bitesize_mod = 1
+ foodtype = VEGETABLES
+ tastes = list ("peas" = 1, "chalky saltiness" = 1)
+ wine_power = 50
+ wine_flavor = "what is, distressingly, fermented peas."
+ // distill_regeant = /datum/reagent/saltpetre //if allowed, remove wine_power, ya dingus.
+
+
+// Laughin' Peas
+/obj/item/seeds/peas/laugh
+ name = "pack of laughin' peas"
+ desc = "These seeds give off a very soft purple glow.. they should grow into Laughin' Peas."
+ icon_state = "seed-laughpeas"
+ species = "laughpeas"
+ plantname = "Laughin' Peas"
+ product = /obj/item/reagent_containers/food/snacks/grown/laugh
+ maturation = 7
+ potency = 10
+ yield = 7
+ production = 5
+ growthstages = 3
+ growing_icon = 'icons/obj/hydroponics/growing_vegetables.dmi'
+ icon_grow = "laughpeas-grow"
+ icon_dead = "laughpeas-dead"
+ genes = list (/datum/plant_gene/trait/repeated_harvest, /datum/plant_gene/trait/glow/purple)
+ mutatelist = list (/obj/item/seeds/peas/laugh/peace)
+ reagents_add = list (/datum/reagent/consumable/laughter = 0.05, /datum/reagent/consumable/sugar = 0.05, /datum/reagent/consumable/nutriment = 0.07)
+ rarity = 25 //It actually might make Central Command Officials loosen up a smidge, eh?
+
+
+/obj/item/reagent_containers/food/snacks/grown/laugh
+ seed = /obj/item/seeds/peas/laugh
+ name = "pod of laughin' peas"
+ desc = "Ridens Cicer, guaranteed to improve your mood dramatically upon consumption!"
+ icon_state = "laughpeas"
+ filling_color = "#ee7bee"
+ bitesize_mod = 2
+ foodtype = VEGETABLES
+ tastes = list ("a prancing rabbit" = 1) //Vib Ribbon sends her regards.. wherever she is.
+ wine_power = 90
+ wine_flavor = "a vector-graphic rabbit dancing on your tongue"
+
+
+// World Peas - Peace at last, peace at last...
+/obj/item/seeds/peas/laugh/peace
+ name = "pack of world peas"
+ desc = "These rather large seeds give off a soothing blue glow..."
+ icon_state = "seed-worldpeas"
+ species = "worldpeas"
+ plantname = "World Peas"
+ product = /obj/item/reagent_containers/food/snacks/grown/peace
+ maturation = 20
+ potency = 75
+ yield = 1
+ production = 10
+ growthstages = 3
+ growing_icon = 'icons/obj/hydroponics/growing_vegetables.dmi'
+ icon_grow = "worldpeas-grow"
+ icon_dead = "worldpeas-dead"
+ genes = list (/datum/plant_gene/trait/glow/blue)
+ reagents_add = list (/datum/reagent/pax = 0.1, /datum/reagent/drug/happiness = 0.1, /datum/reagent/consumable/nutriment = 0.15)
+ rarity = 50 // This absolutely will make even the most hardened Syndicate Operators relax, and lay down their arms.
+
+
+/obj/item/reagent_containers/food/snacks/grown/peace
+ seed = /obj/item/seeds/peas/laugh/peace
+ name = "cluster of world peas"
+ desc = "A plant discovered through extensive genetic engineering, and iterative graft work. It's rumored to bring peace to any who consume it. In the wider AgSci community, it's attained the nickname of 'Pax Mundi'." //at last... world peas. I'm not sorry.
+ icon_state = "worldpeas"
+ filling_color = "#0099CC"
+ bitesize_mod = 4
+ foodtype = VEGETABLES
+ tastes = list ("numbing tranquility" = 2, "warmth" = 1)
+ wine_power = 100
+ wine_flavor = "mind-numbing peace and warmth"
+
+
diff --git a/code/modules/integrated_electronics/core/assemblies.dm b/code/modules/integrated_electronics/core/assemblies.dm
index ef63ba97f8..384991e976 100644
--- a/code/modules/integrated_electronics/core/assemblies.dm
+++ b/code/modules/integrated_electronics/core/assemblies.dm
@@ -873,3 +873,8 @@
pixel_x = -31
if(WEST)
pixel_x = 31
+ plane = ABOVE_WALL_PLANE
+
+/obj/item/electronic_assembly/wallmount/Moved(atom/OldLoc, Dir, Forced = FALSE) //reset the plane if moved off the wall.
+ . = ..()
+ plane = GAME_PLANE
diff --git a/code/modules/integrated_electronics/subtypes/converters.dm b/code/modules/integrated_electronics/subtypes/converters.dm
index 8c7529651b..ebb91a894e 100644
--- a/code/modules/integrated_electronics/subtypes/converters.dm
+++ b/code/modules/integrated_electronics/subtypes/converters.dm
@@ -426,7 +426,7 @@
activators = list("compute abs coordinates" = IC_PINTYPE_PULSE_IN, "on convert" = IC_PINTYPE_PULSE_OUT)
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
-/obj/item/integrated_circuit/converter/abs_to_rel_coords/do_work()
+/obj/item/integrated_circuit/converter/rel_to_abs_coords/do_work()
var/x1 = get_pin_data(IC_INPUT, 1)
var/y1 = get_pin_data(IC_INPUT, 2)
@@ -456,7 +456,7 @@
activators = list("compute abs coordinates" = IC_PINTYPE_PULSE_IN, "on convert" = IC_PINTYPE_PULSE_OUT)
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
-/obj/item/integrated_circuit/converter/abs_to_rel_coords/do_work()
+/obj/item/integrated_circuit/converter/adv_rel_to_abs_coords/do_work()
var/turf/T = get_turf(src)
if(!T)
diff --git a/code/modules/integrated_electronics/subtypes/weaponized.dm b/code/modules/integrated_electronics/subtypes/weaponized.dm
index 2f6a2cd841..3123eeabbe 100644
--- a/code/modules/integrated_electronics/subtypes/weaponized.dm
+++ b/code/modules/integrated_electronics/subtypes/weaponized.dm
@@ -296,6 +296,7 @@
var/x_abs = clamp(T.x + target_x_rel, 0, world.maxx)
var/y_abs = clamp(T.y + target_y_rel, 0, world.maxy)
var/range = round(clamp(sqrt(target_x_rel*target_x_rel+target_y_rel*target_y_rel),0,8),1)
+ playsound(src, 'sound/weapons/sonic_jackhammer.ogg', 50, 1)
assembly.visible_message("
\The [assembly] has thrown [A]!")
log_attack("[assembly] [REF(assembly)] has thrown [A] with lethal force.")
A.forceMove(drop_location())
diff --git a/code/modules/jobs/job_types/_job.dm b/code/modules/jobs/job_types/_job.dm
index 8539ed071d..c700d668c5 100644
--- a/code/modules/jobs/job_types/_job.dm
+++ b/code/modules/jobs/job_types/_job.dm
@@ -69,10 +69,8 @@
// How much threat this job is worth in dynamic. Is subtracted if the player's not an antag, added if they are.
var/threat = 0
- /// Starting skill levels.
- var/list/starting_skills
- /// Skill affinities to set
- var/list/skill_affinities
+ /// Starting skill modifiers.
+ var/list/starting_modifiers
//Only override this proc
//H is usually a human unless an /equip override transformed it
@@ -180,15 +178,10 @@
to_chat(M, "
Prefix your message with :h to speak on your department's radio. To see other prefixes, look closely at your headset.")
/datum/job/proc/standard_assign_skills(datum/mind/M)
- if(!starting_skills)
+ if(!starting_modifiers)
return
- for(var/skill in starting_skills)
- M.skill_holder.boost_skill_value_to(skill, starting_skills[skill], TRUE) //silent
- // do wipe affinities though
- M.skill_holder.skill_affinities = list()
- for(var/skill in skill_affinities)
- M.skill_holder.skill_affinities[skill] = skill_affinities[skill]
- UNSETEMPTY(M.skill_holder.skill_affinities) //if we didn't set any.
+ for(var/mod in starting_modifiers)
+ ADD_SINGLETON_SKILL_MODIFIER(M, mod, null)
/datum/outfit/job
name = "Standard Gear"
diff --git a/code/modules/jobs/job_types/ai.dm b/code/modules/jobs/job_types/ai.dm
index 1395b90b39..a7401791ab 100644
--- a/code/modules/jobs/job_types/ai.dm
+++ b/code/modules/jobs/job_types/ai.dm
@@ -17,7 +17,7 @@
var/do_special_check = TRUE
threat = 5
- starting_skills = list(/datum/skill/level/job/wiring = GET_STANDARD_LVL(JOB_SKILL_BASIC))
+ starting_modifiers = list(/datum/skill_modifier/job/level/wiring/basic)
/datum/job/ai/equip(mob/living/carbon/human/H, visualsOnly, announce, latejoin, datum/outfit/outfit_override, client/preference_source = null)
if(visualsOnly)
diff --git a/code/modules/jobs/job_types/atmospheric_technician.dm b/code/modules/jobs/job_types/atmospheric_technician.dm
index 768aff0927..1962b8e8a9 100644
--- a/code/modules/jobs/job_types/atmospheric_technician.dm
+++ b/code/modules/jobs/job_types/atmospheric_technician.dm
@@ -20,8 +20,7 @@
paycheck = PAYCHECK_MEDIUM
paycheck_department = ACCOUNT_ENG
- starting_skills = list(/datum/skill/level/job/wiring = GET_STANDARD_LVL(JOB_SKILL_BASIC))
- skill_affinities = list(/datum/skill/level/job/wiring = STARTING_SKILL_AFFINITY_WIRING_ENGI_ROBO)
+ starting_modifiers = list(/datum/skill_modifier/job/level/wiring/basic, /datum/skill_modifier/job/affinity/wiring)
display_order = JOB_DISPLAY_ORDER_ATMOSPHERIC_TECHNICIAN
threat = 0.5
diff --git a/code/modules/jobs/job_types/chemist.dm b/code/modules/jobs/job_types/chemist.dm
index a477ff3da3..b2699071e3 100644
--- a/code/modules/jobs/job_types/chemist.dm
+++ b/code/modules/jobs/job_types/chemist.dm
@@ -21,8 +21,7 @@
display_order = JOB_DISPLAY_ORDER_CHEMIST
threat = 1.5
- starting_skills = list(/datum/skill/numerical/surgery = STARTING_SKILL_SURGERY_MEDICAL)
- skill_affinities = list(/datum/skill/numerical/surgery = STARTING_SKILL_AFFINITY_SURGERY_MEDICAL)
+ starting_modifiers = list(/datum/skill_modifier/job/surgery, /datum/skill_modifier/job/affinity/surgery)
/datum/outfit/job/chemist
name = "Chemist"
diff --git a/code/modules/jobs/job_types/chief_engineer.dm b/code/modules/jobs/job_types/chief_engineer.dm
index eee0c3437f..d8df767a9f 100644
--- a/code/modules/jobs/job_types/chief_engineer.dm
+++ b/code/modules/jobs/job_types/chief_engineer.dm
@@ -29,8 +29,7 @@
paycheck = PAYCHECK_COMMAND
paycheck_department = ACCOUNT_ENG
- starting_skills = list(/datum/skill/level/job/wiring = GET_STANDARD_LVL(JOB_SKILL_TRAINED))
- skill_affinities = list(/datum/skill/level/job/wiring = STARTING_SKILL_AFFINITY_WIRING_ENGI_ROBO)
+ starting_modifiers = list(/datum/skill_modifier/job/level/wiring, /datum/skill_modifier/job/affinity/wiring)
display_order = JOB_DISPLAY_ORDER_CHIEF_ENGINEER
blacklisted_quirks = list(/datum/quirk/mute, /datum/quirk/brainproblems, /datum/quirk/paraplegic, /datum/quirk/insanity)
diff --git a/code/modules/jobs/job_types/chief_medical_officer.dm b/code/modules/jobs/job_types/chief_medical_officer.dm
index 89bb4ed96b..adee2856fa 100644
--- a/code/modules/jobs/job_types/chief_medical_officer.dm
+++ b/code/modules/jobs/job_types/chief_medical_officer.dm
@@ -31,8 +31,7 @@
blacklisted_quirks = list(/datum/quirk/mute, /datum/quirk/brainproblems, /datum/quirk/insanity)
threat = 2
- starting_skills = list(/datum/skill/numerical/surgery = STARTING_SKILL_SURGERY_MEDICAL)
- skill_affinities = list(/datum/skill/numerical/surgery = STARTING_SKILL_AFFINITY_SURGERY_MEDICAL)
+ starting_modifiers = list(/datum/skill_modifier/job/surgery, /datum/skill_modifier/job/affinity/surgery)
/datum/outfit/job/cmo
name = "Chief Medical Officer"
diff --git a/code/modules/jobs/job_types/cyborg.dm b/code/modules/jobs/job_types/cyborg.dm
index d88d888aec..4f74542b2a 100644
--- a/code/modules/jobs/job_types/cyborg.dm
+++ b/code/modules/jobs/job_types/cyborg.dm
@@ -12,7 +12,7 @@
exp_requirements = 120
exp_type = EXP_TYPE_CREW
- starting_skills = list(/datum/skill/level/job/wiring = GET_STANDARD_LVL(JOB_SKILL_BASIC))
+ starting_modifiers = list(/datum/skill_modifier/job/level/wiring/basic)
display_order = JOB_DISPLAY_ORDER_CYBORG
diff --git a/code/modules/jobs/job_types/geneticist.dm b/code/modules/jobs/job_types/geneticist.dm
index 21ba9f0f9b..a40ca0fca3 100644
--- a/code/modules/jobs/job_types/geneticist.dm
+++ b/code/modules/jobs/job_types/geneticist.dm
@@ -21,7 +21,7 @@
display_order = JOB_DISPLAY_ORDER_GENETICIST
threat = 1.5
- starting_skills = list(/datum/skill/numerical/surgery = STARTING_SKILL_SURGERY_MEDICAL)
+ starting_modifiers = list(/datum/skill_modifier/job/surgery, /datum/skill_modifier/job/affinity/surgery)
/datum/outfit/job/geneticist
name = "Geneticist"
diff --git a/code/modules/jobs/job_types/medical_doctor.dm b/code/modules/jobs/job_types/medical_doctor.dm
index bff83df973..5ec4b83b2f 100644
--- a/code/modules/jobs/job_types/medical_doctor.dm
+++ b/code/modules/jobs/job_types/medical_doctor.dm
@@ -19,8 +19,7 @@
display_order = JOB_DISPLAY_ORDER_MEDICAL_DOCTOR
threat = 0.5
- starting_skills = list(/datum/skill/numerical/surgery = STARTING_SKILL_SURGERY_MEDICAL)
- skill_affinities = list(/datum/skill/numerical/surgery = STARTING_SKILL_AFFINITY_SURGERY_MEDICAL)
+ starting_modifiers = list(/datum/skill_modifier/job/surgery, /datum/skill_modifier/job/affinity/surgery)
/datum/outfit/job/doctor
name = "Medical Doctor"
diff --git a/code/modules/jobs/job_types/paramedic.dm b/code/modules/jobs/job_types/paramedic.dm
index c253574268..9bdfdfe279 100644
--- a/code/modules/jobs/job_types/paramedic.dm
+++ b/code/modules/jobs/job_types/paramedic.dm
@@ -21,8 +21,7 @@
threat = 0.5
- starting_skills = list(/datum/skill/numerical/surgery = STARTING_SKILL_SURGERY_MEDICAL)
- skill_affinities = list(/datum/skill/numerical/surgery = STARTING_SKILL_AFFINITY_SURGERY_MEDICAL)
+ starting_modifiers = list(/datum/skill_modifier/job/surgery, /datum/skill_modifier/job/affinity/surgery)
/datum/outfit/job/paramedic
name = "Paramedic"
diff --git a/code/modules/jobs/job_types/roboticist.dm b/code/modules/jobs/job_types/roboticist.dm
index b4801ce6df..f5ae93bb6a 100644
--- a/code/modules/jobs/job_types/roboticist.dm
+++ b/code/modules/jobs/job_types/roboticist.dm
@@ -18,9 +18,7 @@
paycheck = PAYCHECK_MEDIUM
paycheck_department = ACCOUNT_SCI
- starting_skills = list(/datum/skill/level/job/wiring = GET_STANDARD_LVL(JOB_SKILL_TRAINED))
- skill_affinities = list(/datum/skill/level/job/wiring = STARTING_SKILL_AFFINITY_WIRING_ENGI_ROBO)
-
+ starting_modifiers = list(/datum/skill_modifier/job/level/wiring, /datum/skill_modifier/job/affinity/wiring)
display_order = JOB_DISPLAY_ORDER_ROBOTICIST
threat = 1
diff --git a/code/modules/jobs/job_types/station_engineer.dm b/code/modules/jobs/job_types/station_engineer.dm
index f5b8c7cd4e..d3f5db7dbb 100644
--- a/code/modules/jobs/job_types/station_engineer.dm
+++ b/code/modules/jobs/job_types/station_engineer.dm
@@ -20,8 +20,7 @@
paycheck = PAYCHECK_MEDIUM
paycheck_department = ACCOUNT_ENG
- starting_skills = list(/datum/skill/level/job/wiring = GET_STANDARD_LVL(JOB_SKILL_TRAINED))
- skill_affinities = list(/datum/skill/level/job/wiring = STARTING_SKILL_AFFINITY_WIRING_ENGI_ROBO)
+ starting_modifiers = list(/datum/skill_modifier/job/level/wiring, /datum/skill_modifier/job/affinity/wiring)
display_order = JOB_DISPLAY_ORDER_STATION_ENGINEER
diff --git a/code/modules/jobs/job_types/virologist.dm b/code/modules/jobs/job_types/virologist.dm
index 37a21dd3ac..790e828931 100644
--- a/code/modules/jobs/job_types/virologist.dm
+++ b/code/modules/jobs/job_types/virologist.dm
@@ -22,8 +22,7 @@
threat = 1.5
- starting_skills = list(/datum/skill/numerical/surgery = STARTING_SKILL_SURGERY_MEDICAL)
- skill_affinities = list(/datum/skill/numerical/surgery = STARTING_SKILL_AFFINITY_SURGERY_MEDICAL)
+ starting_modifiers = list(/datum/skill_modifier/job/surgery, /datum/skill_modifier/job/affinity/surgery)
/datum/outfit/job/virologist
name = "Virologist"
diff --git a/code/modules/keybindings/bindings_admin.dm b/code/modules/keybindings/bindings_admin.dm
deleted file mode 100644
index ca232adbe0..0000000000
--- a/code/modules/keybindings/bindings_admin.dm
+++ /dev/null
@@ -1,24 +0,0 @@
-/datum/admins/key_down(_key, client/user)
- switch(_key)
- if("F3")
- user.get_admin_say()
- return
- if("F5")
- user.admin_ghost()
- return
- if("F6")
- player_panel_new()
- return
- if("F7")
- user.togglebuildmodeself()
- return
- if("F8")
- if(user.keys_held["Ctrl"])
- user.stealth()
- else
- user.invisimin()
- return
- if("F10")
- user.get_dead_say()
- return
- ..()
diff --git a/code/modules/keybindings/bindings_atom.dm b/code/modules/keybindings/bindings_atom.dm
index 5f3e879237..47d6b16feb 100644
--- a/code/modules/keybindings/bindings_atom.dm
+++ b/code/modules/keybindings/bindings_atom.dm
@@ -5,7 +5,7 @@
if(!user.keys_held["Ctrl"])
var/movement_dir = NONE
for(var/_key in user.keys_held)
- movement_dir = movement_dir | SSinput.movement_keys[_key]
+ movement_dir = movement_dir | user.movement_keys[_key]
if(user.next_move_dir_add)
movement_dir |= user.next_move_dir_add
if(user.next_move_dir_sub)
diff --git a/code/modules/keybindings/bindings_carbon.dm b/code/modules/keybindings/bindings_carbon.dm
deleted file mode 100644
index e344bc9d20..0000000000
--- a/code/modules/keybindings/bindings_carbon.dm
+++ /dev/null
@@ -1,9 +0,0 @@
-/mob/living/carbon/key_down(_key, client/user)
- switch(_key)
- if("R", "Southwest") // Southwest is End
- toggle_throw_mode()
- return
- if("C")
- user_toggle_intentional_combat_mode()
- return
- return ..()
\ No newline at end of file
diff --git a/code/modules/keybindings/bindings_client.dm b/code/modules/keybindings/bindings_client.dm
index 6030362a61..a73dd9a59b 100644
--- a/code/modules/keybindings/bindings_client.dm
+++ b/code/modules/keybindings/bindings_client.dm
@@ -33,55 +33,69 @@
to_chat(src, "
Invalid KeyDown detected! You have been disconnected from the server automatically.")
log_admin("Client [ckey] just attempted to send an invalid keypress. Keymessage was over [MAX_KEYPRESS_COMMANDLENGTH] characters, autokicking due to likely abuse.")
message_admins("Client [ckey] just attempted to send an invalid keypress. Keymessage was over [MAX_KEYPRESS_COMMANDLENGTH] characters, autokicking due to likely abuse.")
- QDEL_IN(src, 1)
+ qdel(src)
+ return
+
+ if(_key == "Tab")
+ ForceAllKeysUp() //groan, more hacky kevcode
return
if(length(keys_held) > MAX_HELD_KEYS)
keys_held.Cut(1,2)
keys_held[_key] = TRUE
- var/movement = SSinput.movement_keys[_key]
+ var/movement = movement_keys[_key]
if(!(next_move_dir_sub & movement) && !keys_held["Ctrl"])
next_move_dir_add |= movement
// Client-level keybindings are ones anyone should be able to do at any time
// Things like taking screenshots, hitting tab, and adminhelps.
-
+ var/AltMod = keys_held["Alt"] ? "Alt" : ""
+ var/CtrlMod = keys_held["Ctrl"] ? "Ctrl" : ""
+ var/ShiftMod = keys_held["Shift"] ? "Shift" : ""
+ var/full_key
switch(_key)
- if("F1")
- if(keys_held["Ctrl"] && keys_held["Shift"]) // Is this command ever used?
- winset(src, null, "command=.options")
- else
- get_adminhelp()
- return
- if("F2") // Screenshot. Hold shift to choose a name and location to save in
- winset(src, null, "command=.screenshot [!keys_held["shift"] ? "auto" : ""]")
- return
- if("F12") // Toggles minimal HUD
- mob.button_pressed_F12()
- return
+ if("Alt", "Ctrl", "Shift")
+ full_key = "[AltMod][CtrlMod][ShiftMod]"
+ else
+ full_key = "[AltMod][CtrlMod][ShiftMod][_key]"
+ var/keycount = 0
+ for(var/kb_name in prefs.key_bindings[full_key])
+ keycount++
+ var/datum/keybinding/kb = GLOB.keybindings_by_name[kb_name]
+ if(kb.can_use(src) && kb.down(src) && keycount >= MAX_COMMANDS_PER_KEY)
+ break
- if(holder)
- holder.key_down(_key, src)
- if(mob.focus)
- mob.focus.key_down(_key, src)
+ holder?.key_down(_key, src)
+ mob.focus?.key_down(_key, src)
+
+/// Keyup's all keys held down.
+/client/proc/ForceAllKeysUp()
+ // simulate a user releasing all keys except for the mod keys. groan. i hate this. thanks, byond. why aren't keyups able to be forced to fire on macro change aoaoaoao.
+ // groan
+ for(var/key in keys_held) // all of these won't be the 3 mod keys.
+ if((key == "Ctrl") || (key == "Alt") || (key == "Shift"))
+ continue
+ keyUp("[key]")
/client/verb/keyUp(_key as text)
set instant = TRUE
set hidden = TRUE
keys_held -= _key
- var/movement = SSinput.movement_keys[_key]
+ var/movement = movement_keys[_key]
if(!(next_move_dir_add & movement))
next_move_dir_sub |= movement
- if(holder)
- holder.key_up(_key, src)
- if(mob.focus)
- mob.focus.key_up(_key, src)
+ // We don't do full key for release, because for mod keys you
+ // can hold different keys and releasing any should be handled by the key binding specifically
+ for (var/kb_name in prefs.key_bindings[_key])
+ var/datum/keybinding/kb = GLOB.keybindings_by_name[kb_name]
+ if(kb.can_use(src) && kb.up(src))
+ break
+ holder?.key_up(_key, src)
+ mob.focus?.key_up(_key, src)
// Called every game tick
/client/keyLoop()
- if(holder)
- holder.keyLoop(src)
- if(mob.focus)
- mob.focus.keyLoop(src)
\ No newline at end of file
+ holder?.keyLoop(src)
+ mob.focus?.keyLoop(src)
diff --git a/code/modules/keybindings/bindings_human.dm b/code/modules/keybindings/bindings_human.dm
deleted file mode 100644
index 9569de338c..0000000000
--- a/code/modules/keybindings/bindings_human.dm
+++ /dev/null
@@ -1,80 +0,0 @@
-/mob/living/carbon/human/key_down(_key, client/user)
- if(client.keys_held["Shift"])
- switch(_key)
- if("E") // Put held thing in belt or take out most recent thing from belt
- var/obj/item/thing = get_active_held_item()
- var/obj/item/storage/equipped_belt = get_item_by_slot(SLOT_BELT)
- if(!equipped_belt) // We also let you equip a belt like this
- if(!thing)
- to_chat(user, "
You have no belt to take something out of.")
- return
- equip_to_slot_if_possible(thing, SLOT_BELT)
- return
- if(!istype(equipped_belt)) // not a storage item
- if(!thing)
- to_chat(user, "
You have no belt to take something out of.")
- else
- to_chat(user, "
You can't fit anything in.")
- return
- if(thing) // put thing in belt
- if(!SEND_SIGNAL(equipped_belt, COMSIG_TRY_STORAGE_INSERT, thing, user.mob))
- to_chat(user, "
You can't fit anything in.")
- return
- if(!equipped_belt.contents.len) // nothing to take out
- to_chat(user, "
There's nothing in your belt to take out.")
- return
- var/obj/item/stored = equipped_belt.contents[equipped_belt.contents.len]
- if(!stored || stored.on_found(src))
- return
- stored.attack_hand(src) // take out thing from belt
- return
-
- if("B") // Put held thing in backpack or take out most recent thing from backpack
- var/obj/item/thing = get_active_held_item()
- var/obj/item/storage/equipped_backpack = get_item_by_slot(SLOT_BACK)
- if(!equipped_backpack) // We also let you equip a backpack like this
- if(!thing)
- to_chat(user, "
You have no backpack to take something out of.")
- return
- equip_to_slot_if_possible(thing, SLOT_BACK)
- return
- if(!istype(equipped_backpack)) // not a storage item
- if(!thing)
- to_chat(user, "
You have no backpack to take something out of.")
- else
- to_chat(user, "
You can't fit anything in.")
- return
- if(thing) // put thing in backpack
- if(!SEND_SIGNAL(equipped_backpack, COMSIG_TRY_STORAGE_INSERT, thing, user.mob))
- to_chat(user, "
You can't fit anything in.")
- return
- if(!equipped_backpack.contents.len) // nothing to take out
- to_chat(user, "
There's nothing in your backpack to take out.")
- return
- var/obj/item/stored = equipped_backpack.contents[equipped_backpack.contents.len]
- if(!stored || stored.on_found(src))
- return
- stored.attack_hand(src) // take out thing from backpack
- return
- switch(_key)
- if("Shift")
- if(!user.prefs.sprint_spacebar)
- user.prefs.sprint_toggle ? default_toggle_sprint() : sprint_hotkey(TRUE) //Yes, this looks hacky. Yes, this works.
- return
- if("Space")
- if(user.prefs.sprint_spacebar)
- user.prefs.sprint_toggle ? default_toggle_sprint() : sprint_hotkey(TRUE)
- return
- return ..()
-
-/mob/living/carbon/human/key_up(_key, client/user)
- switch(_key)
- if("Shift")
- if(!user.prefs.sprint_spacebar && !user.prefs.sprint_toggle)
- sprint_hotkey(FALSE)
- return
- if("Space")
- if(user.prefs.sprint_spacebar && !user.prefs.sprint_toggle)
- sprint_hotkey(FALSE)
- return
- return ..()
diff --git a/code/modules/keybindings/bindings_living.dm b/code/modules/keybindings/bindings_living.dm
deleted file mode 100644
index ec6c5dd539..0000000000
--- a/code/modules/keybindings/bindings_living.dm
+++ /dev/null
@@ -1,27 +0,0 @@
-/mob/living/key_down(_key, client/user)
- switch(_key)
- if("B")
- resist()
- return
- if("1")
- if(possible_a_intents)
- a_intent_change(INTENT_HELP)
- return
- if("2")
- if(possible_a_intents)
- a_intent_change(INTENT_DISARM)
- return
- if("3")
- if(possible_a_intents)
- a_intent_change(INTENT_GRAB)
- return
- if("4")
- if(possible_a_intents)
- a_intent_change(INTENT_HARM)
- return
- if ("V")
- lay_down()
- return
-
-
- return ..()
\ No newline at end of file
diff --git a/code/modules/keybindings/bindings_mob.dm b/code/modules/keybindings/bindings_mob.dm
deleted file mode 100644
index 36b4775c34..0000000000
--- a/code/modules/keybindings/bindings_mob.dm
+++ /dev/null
@@ -1,94 +0,0 @@
-// Technically the client argument is unncessary here since that SHOULD be src.client but let's not assume things
-// All it takes is one badmin setting their focus to someone else's client to mess things up
-// Or we can have NPC's send actual keypresses and detect that by seeing no client
-
-/mob/key_down(_key, client/user)
- switch(_key)
- if("Delete", "H")
- if(!pulling)
- to_chat(src, "
You are not pulling anything.")
- else
- stop_pulling()
- return
- if("Insert", "G")
- a_intent_change(INTENT_HOTKEY_RIGHT)
- return
- if("F")
- a_intent_change(INTENT_HOTKEY_LEFT)
- return
- if("X", "Northeast") // Northeast is Page-up
- swap_hand()
- return
- if("Y", "Z", "Southeast") // Southeast is Page-down
- mode() // attack_self(). No idea who came up with "mode()"
- return
- if("Q", "Northwest") // Northwest is Home
- var/obj/item/I = get_active_held_item()
- if(!I)
- to_chat(src, "
You have nothing to drop in your hand!")
- else
- dropItemToGround(I)
- return
- if("E")
- quick_equip()
- return
- if("Alt")
- toggle_move_intent()
- return
- //Bodypart selections
- if("Numpad8")
- user.body_toggle_head()
- return
- if("Numpad4")
- user.body_r_arm()
- return
- if("Numpad5")
- user.body_chest()
- return
- if("Numpad6")
- user.body_l_arm()
- return
- if("Numpad1")
- user.body_r_leg()
- return
- if("Numpad2")
- user.body_groin()
- return
- if("Numpad3")
- user.body_l_leg()
- return
-
- if(client.keys_held["Ctrl"])
- switch(SSinput.movement_keys[_key])
- if(NORTH)
- if(client.keys_held["Shift"])
- northshift()
- else
- northface()
- return
- if(SOUTH)
- if(client.keys_held["Shift"])
- southshift()
- else
- southface()
- return
- if(WEST)
- if(client.keys_held["Shift"])
- westshift()
- else
- westface()
- return
- if(EAST)
- if(client.keys_held["Shift"])
- eastshift()
- else
- eastface()
- return
- return ..()
-
-/mob/key_up(_key, client/user)
- switch(_key)
- if("Alt")
- toggle_move_intent()
- return
- return ..()
diff --git a/code/modules/keybindings/bindings_robot.dm b/code/modules/keybindings/bindings_robot.dm
deleted file mode 100644
index 29fb36fa65..0000000000
--- a/code/modules/keybindings/bindings_robot.dm
+++ /dev/null
@@ -1,22 +0,0 @@
-/mob/living/silicon/robot/key_down(_key, client/user)
- switch(_key)
- if("1", "2", "3")
- toggle_module(text2num(_key))
- return
- if("4")
- a_intent_change(INTENT_HOTKEY_LEFT)
- return
- if("Q")
- uneq_active()
- return
- if("Shift")
- sprint_hotkey(TRUE)
- return
- return ..()
-
-/mob/living/silicon/robot/key_up(_key, client/user)
- switch(_key)
- if("Shift")
- sprint_hotkey(FALSE)
- return
- return ..()
diff --git a/code/modules/keybindings/focus.dm b/code/modules/keybindings/focus.dm
index 205b293e9a..d542b49267 100644
--- a/code/modules/keybindings/focus.dm
+++ b/code/modules/keybindings/focus.dm
@@ -1,6 +1,3 @@
-/mob
- var/datum/focus //What receives our keyboard inputs. src by default
-
/mob/proc/set_focus(datum/new_focus)
if(focus == new_focus)
return
diff --git a/code/modules/keybindings/keybind/__defines.dm b/code/modules/keybindings/keybind/__defines.dm
new file mode 100644
index 0000000000..baa095987c
--- /dev/null
+++ b/code/modules/keybindings/keybind/__defines.dm
@@ -0,0 +1,20 @@
+#define CATEGORY_CLIENT "CLIENT"
+#define CATEGORY_EMOTE "EMOTE"
+#define CATEGORY_ADMIN "ADMIN"
+#define CATEGORY_XENO "XENO"
+#define CATEGORY_CARBON "CARBON"
+#define CATEGORY_HUMAN "HUMAN"
+#define CATEGORY_ROBOT "ROBOT"
+#define CATEGORY_MISC "MISC"
+#define CATEGORY_MOVEMENT "MOVEMENT"
+#define CATEGORY_TARGETING "TARGETING"
+
+#define WEIGHT_HIGHEST 0
+#define WEIGHT_ADMIN 10
+#define WEIGHT_CLIENT 20
+#define WEIGHT_ROBOT 30
+#define WEIGHT_MOB 40
+#define WEIGHT_LIVING 50
+#define WEIGHT_DEAD 60
+#define WEIGHT_EMOTE 70
+#define WEIGHT_LOWEST 999
diff --git a/code/modules/keybindings/keybind/_keybind.dm b/code/modules/keybindings/keybind/_keybind.dm
new file mode 100644
index 0000000000..1d68e2d037
--- /dev/null
+++ b/code/modules/keybindings/keybind/_keybind.dm
@@ -0,0 +1,24 @@
+/datum/keybinding
+ var/list/hotkey_keys
+ var/list/classic_keys
+ var/name
+ var/full_name
+ var/description = ""
+ var/category = CATEGORY_MISC
+ var/weight = WEIGHT_LOWEST
+ var/keybind_signal
+
+/datum/keybinding/New()
+
+ // Default keys to the master "hotkey_keys"
+ if(LAZYLEN(hotkey_keys) && !LAZYLEN(classic_keys))
+ classic_keys = hotkey_keys.Copy()
+
+/datum/keybinding/proc/down(client/user)
+ return FALSE
+
+/datum/keybinding/proc/up(client/user)
+ return FALSE
+
+/datum/keybinding/proc/can_use(client/user)
+ return TRUE
diff --git a/code/modules/keybindings/keybind/admin.dm b/code/modules/keybindings/keybind/admin.dm
new file mode 100644
index 0000000000..b63221e97a
--- /dev/null
+++ b/code/modules/keybindings/keybind/admin.dm
@@ -0,0 +1,96 @@
+/datum/keybinding/admin
+ category = CATEGORY_ADMIN
+ weight = WEIGHT_ADMIN
+
+/datum/keybinding/admin/can_use(client/user)
+ return user.holder ? TRUE : FALSE
+
+/datum/keybinding/admin/admin_say
+ hotkey_keys = list("F3")
+ name = "admin_say"
+ full_name = "Admin say"
+ description = "Talk with other admins."
+
+/datum/keybinding/admin/admin_say/down(client/user)
+ user.get_admin_say()
+ return TRUE
+
+/datum/keybinding/admin/admin_ghost
+ hotkey_keys = list("F5")
+ name = "admin_ghost"
+ full_name = "Aghost"
+ description = "Go ghost"
+
+/datum/keybinding/admin/admin_ghost/down(client/user)
+ user.admin_ghost()
+ return TRUE
+
+/datum/keybinding/admin/player_panel_new
+ hotkey_keys = list("F6")
+ name = "player_panel_new"
+ full_name = "Player Panel New"
+ description = "Opens up the new player panel"
+
+/datum/keybinding/admin/player_panel_new/down(client/user)
+ user.holder.player_panel_new()
+ return TRUE
+
+/datum/keybinding/admin/toggle_buildmode_self
+ hotkey_keys = list("F7")
+ name = "toggle_buildmode_self"
+ full_name = "Toggle Buildmode Self"
+ description = "Toggles buildmode"
+
+/datum/keybinding/admin/toggle_buildmode_self/down(client/user)
+ user.togglebuildmodeself()
+ return TRUE
+
+/datum/keybinding/admin/stealthmode
+ hotkey_keys = list("CtrlF8")
+ name = "stealth_mode"
+ full_name = "Stealth mode"
+ description = "Enters stealth mode"
+
+/datum/keybinding/admin/stealthmode/down(client/user)
+ user.stealth()
+ return TRUE
+
+/datum/keybinding/admin/invisimin
+ hotkey_keys = list("F8")
+ name = "invisimin"
+ full_name = "Admin invisibility"
+ description = "Toggles ghost-like invisibility (Don't abuse this)"
+
+/datum/keybinding/admin/invisimin/down(client/user)
+ user.invisimin()
+ return TRUE
+
+/datum/keybinding/admin/deadsay
+ hotkey_keys = list("F10")
+ name = "dsay"
+ full_name = "deadsay"
+ description = "Allows you to send a message to dead chat"
+
+/datum/keybinding/admin/deadsay/down(client/user)
+ user.get_dead_say()
+ return TRUE
+
+/datum/keybinding/admin/deadmin
+ hotkey_keys = list("Unbound")
+ name = "deadmin"
+ full_name = "Deadmin"
+ description = "Shed your admin powers"
+
+/datum/keybinding/admin/deadmin/down(client/user)
+ user.deadmin()
+ return TRUE
+
+/datum/keybinding/admin/readmin
+ hotkey_keys = list("Unbound")
+ name = "readmin"
+ full_name = "Readmin"
+ description = "Regain your admin powers"
+
+/datum/keybinding/admin/readmin/down(client/user)
+ user.readmin()
+ return TRUE
diff --git a/code/modules/keybindings/keybind/carbon.dm b/code/modules/keybindings/keybind/carbon.dm
new file mode 100644
index 0000000000..46cb5cd0ac
--- /dev/null
+++ b/code/modules/keybindings/keybind/carbon.dm
@@ -0,0 +1,62 @@
+/datum/keybinding/carbon
+ category = CATEGORY_CARBON
+ weight = WEIGHT_MOB
+
+/datum/keybinding/carbon/can_use(client/user)
+ return iscarbon(user.mob)
+
+/datum/keybinding/carbon/toggle_throw_mode
+ hotkey_keys = list("R", "Southwest") // END
+ name = "toggle_throw_mode"
+ full_name = "Toggle throw mode"
+ description = "Toggle throwing the current item or not."
+ category = CATEGORY_CARBON
+
+/datum/keybinding/carbon/toggle_throw_mode/down(client/user)
+ var/mob/living/carbon/C = user.mob
+ C.toggle_throw_mode()
+ return TRUE
+
+/datum/keybinding/carbon/select_help_intent
+ hotkey_keys = list("1")
+ name = "select_help_intent"
+ full_name = "Select help intent"
+ description = ""
+ category = CATEGORY_CARBON
+
+/datum/keybinding/carbon/select_help_intent/down(client/user)
+ user.mob?.a_intent_change(INTENT_HELP)
+ return TRUE
+
+/datum/keybinding/carbon/select_disarm_intent
+ hotkey_keys = list("2")
+ name = "select_disarm_intent"
+ full_name = "Select disarm intent"
+ description = ""
+ category = CATEGORY_CARBON
+
+/datum/keybinding/carbon/select_disarm_intent/down(client/user)
+ user.mob?.a_intent_change(INTENT_DISARM)
+ return TRUE
+
+/datum/keybinding/carbon/select_grab_intent
+ hotkey_keys = list("3")
+ name = "select_grab_intent"
+ full_name = "Select grab intent"
+ description = ""
+ category = CATEGORY_CARBON
+
+/datum/keybinding/carbon/select_grab_intent/down(client/user)
+ user.mob?.a_intent_change(INTENT_GRAB)
+ return TRUE
+
+/datum/keybinding/carbon/select_harm_intent
+ hotkey_keys = list("4")
+ name = "select_harm_intent"
+ full_name = "Select harm intent"
+ description = ""
+ category = CATEGORY_CARBON
+
+/datum/keybinding/carbon/select_harm_intent/down(client/user)
+ user.mob?.a_intent_change(INTENT_HARM)
+ return TRUE
diff --git a/code/modules/keybindings/keybind/client.dm b/code/modules/keybindings/keybind/client.dm
new file mode 100644
index 0000000000..1d44efa063
--- /dev/null
+++ b/code/modules/keybindings/keybind/client.dm
@@ -0,0 +1,33 @@
+/datum/keybinding/client
+ category = CATEGORY_CLIENT
+ weight = WEIGHT_HIGHEST
+
+/datum/keybinding/client/admin_help
+ hotkey_keys = list("F1")
+ name = "admin_help"
+ full_name = "Admin Help"
+ description = "Ask an admin for help."
+
+/datum/keybinding/client/admin_help/down(client/user)
+ user.get_adminhelp()
+ return TRUE
+
+/datum/keybinding/client/screenshot
+ hotkey_keys = list("F2")
+ name = "screenshot"
+ full_name = "Screenshot"
+ description = "Take a screenshot."
+
+/datum/keybinding/client/screenshot/down(client/user)
+ winset(user, null, "command=.screenshot [!user.keys_held["shift"] ? "auto" : ""]")
+ return TRUE
+
+/datum/keybinding/client/minimal_hud
+ hotkey_keys = list("F12")
+ name = "minimal_hud"
+ full_name = "Minimal HUD"
+ description = "Hide most HUD features"
+
+/datum/keybinding/client/minimal_hud/down(client/user)
+ user.mob.button_pressed_F12()
+ return TRUE
diff --git a/code/modules/keybindings/keybind/emote.dm b/code/modules/keybindings/keybind/emote.dm
new file mode 100644
index 0000000000..6099826819
--- /dev/null
+++ b/code/modules/keybindings/keybind/emote.dm
@@ -0,0 +1,15 @@
+/datum/keybinding/emote
+ category = CATEGORY_EMOTE
+ weight = WEIGHT_EMOTE
+ var/emote_key
+
+/datum/keybinding/emote/proc/link_to_emote(datum/emote/faketype)
+ hotkey_keys = list("Unbound")
+ emote_key = initial(faketype.key)
+ name = initial(faketype.key)
+ full_name = capitalize(initial(faketype.key))
+ description = "Do the emote '*[emote_key]'"
+
+/datum/keybinding/emote/down(client/user)
+ . = ..()
+ return user.mob.emote(emote_key, intentional=TRUE)
diff --git a/code/modules/keybindings/keybind/human.dm b/code/modules/keybindings/keybind/human.dm
new file mode 100644
index 0000000000..43f5653472
--- /dev/null
+++ b/code/modules/keybindings/keybind/human.dm
@@ -0,0 +1,39 @@
+/datum/keybinding/human
+ category = CATEGORY_HUMAN
+ weight = WEIGHT_MOB
+
+/datum/keybinding/human/can_use(client/user)
+ return ishuman(user.mob)
+
+/datum/keybinding/human/quick_equip
+ hotkey_keys = list("E")
+ name = "quick_equip"
+ full_name = "Quick Equip"
+ description = "Quickly puts an item in the best slot available"
+
+/datum/keybinding/human/quick_equip/down(client/user)
+ var/mob/living/carbon/human/H = user.mob
+ H.quick_equip()
+ return TRUE
+
+/datum/keybinding/human/quick_equipbelt
+ hotkey_keys = list("ShiftE")
+ name = "quick_equipbelt"
+ full_name = "Quick equip belt"
+ description = "Put held thing in belt or take out most recent thing from belt"
+
+/datum/keybinding/human/quick_equipbelt/down(client/user)
+ var/mob/living/carbon/human/H = user.mob
+ H.smart_equipbelt()
+ return TRUE
+
+/datum/keybinding/human/bag_equip
+ hotkey_keys = list("ShiftB")
+ name = "bag_equip"
+ full_name = "Bag equip"
+ description = "Put held thing in backpack or take out most recent thing from backpack"
+
+/datum/keybinding/human/bag_equip/down(client/user)
+ var/mob/living/carbon/human/H = user.mob
+ H.smart_equipbag()
+ return TRUE
diff --git a/code/modules/keybindings/keybind/living.dm b/code/modules/keybindings/keybind/living.dm
new file mode 100644
index 0000000000..0408d0889b
--- /dev/null
+++ b/code/modules/keybindings/keybind/living.dm
@@ -0,0 +1,41 @@
+/datum/keybinding/living
+ category = CATEGORY_HUMAN
+ weight = WEIGHT_MOB
+
+/datum/keybinding/living/can_use(client/user)
+ return isliving(user.mob)
+
+/datum/keybinding/living/resist
+ hotkey_keys = list("B")
+ name = "resist"
+ full_name = "Resist"
+ description = "Break free of your current state. Handcuffed? on fire? Resist!"
+
+/datum/keybinding/living/resist/down(client/user)
+ var/mob/living/L = user.mob
+ L.resist()
+ return TRUE
+
+/datum/keybinding/living/toggle_combat_mode
+ hotkey_keys = list("C")
+ name = "toggle_combat_mode"
+ full_name = "Toggle combat mode"
+ description = "Toggles whether or not you're in combat mode."
+
+/datum/keybinding/living/toggle_combat_mode/can_use(client/user)
+ return iscarbon(user.mob) // for now, only carbons should be using combat mode, although all livings have combat mode implemented.
+
+/datum/keybinding/living/toggle_combat_mode/down(client/user)
+ var/mob/living/carbon/C = user.mob
+ C.user_toggle_intentional_combat_mode()
+ return TRUE
+
+/datum/keybinding/living/toggle_resting
+ hotkey_keys = list("V")
+ name = "toggle_resting"
+ full_name = "Toggle Resting"
+ description = "Toggles whether or not you are intentionally laying down."
+
+/datum/keybinding/living/toggle_resting/down(client/user)
+ var/mob/living/L = user.mob
+ L.lay_down()
diff --git a/code/modules/keybindings/keybind/mob.dm b/code/modules/keybindings/keybind/mob.dm
new file mode 100644
index 0000000000..083d4a19fd
--- /dev/null
+++ b/code/modules/keybindings/keybind/mob.dm
@@ -0,0 +1,123 @@
+/datum/keybinding/mob
+ category = CATEGORY_HUMAN
+ weight = WEIGHT_MOB
+
+/datum/keybinding/mob/stop_pulling
+ hotkey_keys = list("H", "Delete")
+ name = "stop_pulling"
+ full_name = "Stop pulling"
+ description = ""
+
+/datum/keybinding/mob/stop_pulling/down(client/user)
+ var/mob/M = user.mob
+ if(!M.pulling)
+ to_chat(user, "
You are not pulling anything.")
+ else
+ M.stop_pulling()
+ return TRUE
+
+/datum/keybinding/mob/cycle_intent_right
+ hotkey_keys = list("Northwest", "F") // HOME
+ name = "cycle_intent_right"
+ full_name = "Cycle Action Intent Right"
+ description = ""
+
+/datum/keybinding/mob/cycle_intent_right/down(client/user)
+ var/mob/M = user.mob
+ M.a_intent_change(INTENT_HOTKEY_RIGHT)
+ return TRUE
+
+/datum/keybinding/mob/cycle_intent_left
+ hotkey_keys = list("Insert", "G")
+ name = "cycle_intent_left"
+ full_name = "Cycle Action Intent Left"
+ description = ""
+
+/datum/keybinding/mob/cycle_intent_left/down(client/user)
+ var/mob/M = user.mob
+ M.a_intent_change(INTENT_HOTKEY_LEFT)
+ return TRUE
+
+/datum/keybinding/mob/swap_hands
+ hotkey_keys = list("X", "Northeast") // PAGEUP
+ name = "swap_hands"
+ full_name = "Swap hands"
+ description = ""
+
+/datum/keybinding/mob/swap_hands/down(client/user)
+ var/mob/M = user.mob
+ M.swap_hand()
+ return TRUE
+
+/datum/keybinding/mob/activate_inhand
+ hotkey_keys = list("Z", "Southeast") // PAGEDOWN
+ name = "activate_inhand"
+ full_name = "Activate in-hand"
+ description = "Uses whatever item you have inhand"
+
+/datum/keybinding/mob/activate_inhand/down(client/user)
+ var/mob/M = user.mob
+ M.mode()
+ return TRUE
+
+/datum/keybinding/mob/drop_item
+ hotkey_keys = list("Q")
+ name = "drop_item"
+ full_name = "Drop Item"
+ description = ""
+
+/datum/keybinding/mob/drop_item/down(client/user)
+ if(iscyborg(user.mob)) //cyborgs can't drop items
+ return FALSE
+ var/mob/M = user.mob
+ var/obj/item/I = M.get_active_held_item()
+ if(!I)
+ to_chat(user, "
You have nothing to drop in your hand!")
+ else
+ user.mob.dropItemToGround(I)
+ return TRUE
+
+/datum/keybinding/mob/say_with_indicator
+ hotkey_keys = list("CtrlT")
+ classic_keys = list()
+ name = "say_with_indicator"
+ full_name = "Say with Typing Indicator"
+
+/datum/keybinding/mob/say_with_indicator/down(client/user)
+ var/mob/M = user.mob
+ M.say_typing_indicator()
+ return TRUE
+
+/datum/keybinding/mob/me_with_indicator
+ hotkey_keys = list("CtrlM")
+ classic_keys = list()
+ name = "me_with_indicator"
+ full_name = "Me (emote) with Typing Indicator"
+
+/datum/keybinding/mob/me_with_indicator/down(client/user)
+ var/mob/M = user.mob
+ M.me_typing_indicator()
+ return TRUE
+
+/datum/keybinding/living/subtle
+ hotkey_keys = list("5")
+ classic_keys = list()
+ name = "subtle_emote"
+ full_name = "Subtle Emote"
+
+/datum/keybinding/living/subtle/down(client/user)
+ var/mob/living/L = user.mob
+ L.subtle_keybind()
+ return TRUE
+
+/datum/keybinding/mob/whisper
+ hotkey_keys = list("Y")
+ classic_keys = list()
+ name = "whisper"
+ full_name = "Whisper"
+
+/datum/keybinding/mob/whisper/down(client/user)
+ var/mob/M = user.mob
+ M.whisper_keybind()
+ return TRUE
+
diff --git a/code/modules/keybindings/keybind/movement.dm b/code/modules/keybindings/keybind/movement.dm
new file mode 100644
index 0000000000..176e6b9fb8
--- /dev/null
+++ b/code/modules/keybindings/keybind/movement.dm
@@ -0,0 +1,187 @@
+/datum/keybinding/movement
+ category = CATEGORY_MOVEMENT
+ weight = WEIGHT_HIGHEST
+
+/datum/keybinding/movement/north
+ hotkey_keys = list("W", "North")
+ name = "North"
+ full_name = "Move North"
+ description = "Moves your character north"
+
+/datum/keybinding/movement/south
+ hotkey_keys = list("S", "South")
+ name = "South"
+ full_name = "Move South"
+ description = "Moves your character south"
+
+/datum/keybinding/movement/west
+ hotkey_keys = list("A", "West")
+ name = "West"
+ full_name = "Move West"
+ description = "Moves your character left"
+
+/datum/keybinding/movement/east
+ hotkey_keys = list("D", "East")
+ name = "East"
+ full_name = "Move East"
+ description = "Moves your character east"
+
+/datum/keybinding/mob/face_north
+ hotkey_keys = list("CtrlW", "CtrlNorth")
+ name = "face_north"
+ full_name = "Face North"
+ description = ""
+ category = CATEGORY_MOVEMENT
+
+/datum/keybinding/mob/face_north/down(client/user)
+ var/mob/M = user.mob
+ M.northface()
+ return TRUE
+
+/datum/keybinding/mob/face_east
+ hotkey_keys = list("CtrlD", "CtrlEast")
+ name = "face_east"
+ full_name = "Face East"
+ description = ""
+ category = CATEGORY_MOVEMENT
+
+/datum/keybinding/mob/face_east/down(client/user)
+ var/mob/M = user.mob
+ M.eastface()
+ return TRUE
+
+/datum/keybinding/mob/face_south
+ hotkey_keys = list("CtrlS", "CtrlSouth")
+ name = "face_south"
+ full_name = "Face South"
+ description = ""
+ category = CATEGORY_MOVEMENT
+
+/datum/keybinding/mob/face_south/down(client/user)
+ var/mob/M = user.mob
+ M.southface()
+ return TRUE
+
+/datum/keybinding/mob/face_west
+ hotkey_keys = list("CtrlA", "CtrlWest")
+ name = "face_west"
+ full_name = "Face West"
+ description = ""
+ category = CATEGORY_MOVEMENT
+
+/datum/keybinding/mob/face_west/down(client/user)
+ var/mob/M = user.mob
+ M.westface()
+ return TRUE
+
+/datum/keybinding/mob/shift_north
+ hotkey_keys = list("CtrlShiftW", "CtrlShiftNorth")
+ name = "pixel_shift_north"
+ full_name = "Pixel Shift North"
+ description = ""
+ category = CATEGORY_MOVEMENT
+
+/datum/keybinding/mob/shift_north/down(client/user)
+ var/mob/M = user.mob
+ M.northshift()
+ return TRUE
+
+/datum/keybinding/mob/shift_east
+ hotkey_keys = list("CtrlShiftD", "CtrlShiftEast")
+ name = "pixel_shift_east"
+ full_name = "Pixel Shift East"
+ description = ""
+ category = CATEGORY_MOVEMENT
+
+/datum/keybinding/mob/shift_east/down(client/user)
+ var/mob/M = user.mob
+ M.eastshift()
+ return TRUE
+
+/datum/keybinding/mob/shift_south
+ hotkey_keys = list("CtrlShiftS", "CtrlShiftSouth")
+ name = "pixel_shift_south"
+ full_name = "Pixel Shift South"
+ description = ""
+ category = CATEGORY_MOVEMENT
+
+/datum/keybinding/mob/shift_south/down(client/user)
+ var/mob/M = user.mob
+ M.southshift()
+ return TRUE
+
+/datum/keybinding/mob/shift_west
+ hotkey_keys = list("CtrlShiftA", "CtrlShiftWest")
+ name = "pixel_shift_west"
+ full_name = "Pixel Shift West"
+ description = ""
+ category = CATEGORY_MOVEMENT
+
+/datum/keybinding/mob/shift_west/down(client/user)
+ var/mob/M = user.mob
+ M.westshift()
+ return TRUE
+
+/datum/keybinding/living/hold_sprint
+ hotkey_keys = list("Shift")
+ name = "hold_sprint"
+ full_name = "Sprint (hold down)"
+ description = "Hold down to sprint"
+ category = CATEGORY_MOVEMENT
+
+/datum/keybinding/living/hold_sprint/can_use(client/user)
+ return ishuman(user.mob) || iscyborg(user.mob)
+
+/datum/keybinding/living/hold_sprint/down(client/user)
+ var/mob/living/L = user.mob
+ L.sprint_hotkey(TRUE)
+ return TRUE
+
+/datum/keybinding/living/hold_sprint/up(client/user)
+ var/mob/living/L = user.mob
+ L.sprint_hotkey(FALSE)
+ return TRUE
+
+/datum/keybinding/living/toggle_sprint
+ hotkey_keys = list()
+ name = "toggle_sprint"
+ full_name = "Sprint (toggle)"
+ description = "Press to toggle sprint"
+ category = CATEGORY_MOVEMENT
+
+/datum/keybinding/living/toggle_sprint/can_use(client/user)
+ return ishuman(user.mob) || iscyborg(user.mob)
+
+/datum/keybinding/living/toggle_sprint/down(client/user)
+ var/mob/living/L = user.mob
+ L.default_toggle_sprint(TRUE)
+ return TRUE
+
+/datum/keybinding/mob/toggle_move_intent
+ hotkey_keys = list("Alt")
+ name = "toggle_move_intent"
+ full_name = "Hold to toggle move intent"
+ description = "Held down to cycle to the other move intent, release to cycle back"
+ category = CATEGORY_MOVEMENT
+
+/datum/keybinding/mob/toggle_move_intent/down(client/user)
+ var/mob/M = user.mob
+ M.toggle_move_intent()
+ return TRUE
+
+/datum/keybinding/mob/toggle_move_intent/up(client/user)
+ var/mob/M = user.mob
+ M.toggle_move_intent()
+ return TRUE
+
+/datum/keybinding/mob/toggle_move_intent_alternative
+ hotkey_keys = list("Unbound")
+ name = "toggle_move_intent_alt"
+ full_name = "press to cycle move intent"
+ description = "Pressing this cycle to the opposite move intent, does not cycle back"
+ category = CATEGORY_MOVEMENT
+
+/datum/keybinding/mob/toggle_move_intent_alternative/down(client/user)
+ var/mob/M = user.mob
+ M.toggle_move_intent()
+ return TRUE
diff --git a/code/modules/keybindings/keybind/robot.dm b/code/modules/keybindings/keybind/robot.dm
new file mode 100644
index 0000000000..b9f6ce83eb
--- /dev/null
+++ b/code/modules/keybindings/keybind/robot.dm
@@ -0,0 +1,61 @@
+/datum/keybinding/robot
+ category = CATEGORY_ROBOT
+ weight = WEIGHT_ROBOT
+
+/datum/keybinding/robot/can_use(client/user)
+ return iscyborg(user.mob)
+
+/datum/keybinding/robot/moduleone
+ hotkey_keys = list("1")
+ name = "module_one"
+ full_name = "Toggle module 1"
+ description = "Equips or unequips the first module"
+
+/datum/keybinding/robot/moduleone/down(client/user)
+ var/mob/living/silicon/robot/R = user.mob
+ R.toggle_module(1)
+ return TRUE
+
+/datum/keybinding/robot/moduletwo
+ hotkey_keys = list("2")
+ name = "module_two"
+ full_name = "Toggle module 2"
+ description = "Equips or unequips the second module"
+
+/datum/keybinding/robot/moduletwo/down(client/user)
+ var/mob/living/silicon/robot/R = user.mob
+ R.toggle_module(2)
+ return TRUE
+
+/datum/keybinding/robot/modulethree
+ hotkey_keys = list("3")
+ name = "module_three"
+ full_name = "Toggle module 3"
+ description = "Equips or unequips the third module"
+
+/datum/keybinding/robot/modulethree/down(client/user)
+ var/mob/living/silicon/robot/R = user.mob
+ R.toggle_module(3)
+ return TRUE
+
+/datum/keybinding/robot/intent_cycle
+ hotkey_keys = list("4")
+ name = "cycle_intent"
+ full_name = "Cycle intent left"
+ description = "Cycles the intent left"
+
+/datum/keybinding/robot/intent_cycle/down(client/user)
+ var/mob/living/silicon/robot/R = user.mob
+ R.a_intent_change(INTENT_HOTKEY_LEFT)
+ return TRUE
+
+/datum/keybinding/robot/unequip_module
+ hotkey_keys = list("Q")
+ name = "unequip_module"
+ full_name = "Unequip module"
+ description = "Unequips the active module"
+
+/datum/keybinding/robot/unequip_module/down(client/user)
+ var/mob/living/silicon/robot/R = user.mob
+ R.uneq_active()
+ return TRUE
diff --git a/code/modules/keybindings/keybind/targeting.dm b/code/modules/keybindings/keybind/targeting.dm
new file mode 100644
index 0000000000..1548d768cf
--- /dev/null
+++ b/code/modules/keybindings/keybind/targeting.dm
@@ -0,0 +1,76 @@
+/datum/keybinding/mob/target_head_cycle
+ hotkey_keys = list("Numpad8")
+ name = "target_head_cycle"
+ full_name = "Target: Cycle head"
+ description = ""
+ category = CATEGORY_TARGETING
+
+/datum/keybinding/mob/target_head_cycle/down(client/user)
+ user.body_toggle_head()
+ return TRUE
+
+/datum/keybinding/mob/target_r_arm
+ hotkey_keys = list("Numpad4")
+ name = "target_r_arm"
+ full_name = "Target: right arm"
+ description = ""
+ category = CATEGORY_TARGETING
+
+/datum/keybinding/mob/target_r_arm/down(client/user)
+ user.body_r_arm()
+ return TRUE
+
+/datum/keybinding/mob/target_body_chest
+ hotkey_keys = list("Numpad5")
+ name = "target_body_chest"
+ full_name = "Target: Body"
+ description = ""
+ category = CATEGORY_TARGETING
+
+/datum/keybinding/mob/target_body_chest/down(client/user)
+ user.body_chest()
+ return TRUE
+
+/datum/keybinding/mob/target_left_arm
+ hotkey_keys = list("Numpad6")
+ name = "target_left_arm"
+ full_name = "Target: left arm"
+ description = ""
+ category = CATEGORY_TARGETING
+
+/datum/keybinding/mob/target_left_arm/down(client/user)
+ user.body_l_arm()
+ return TRUE
+
+/datum/keybinding/mob/target_right_leg
+ hotkey_keys = list("Numpad1")
+ name = "target_right_leg"
+ full_name = "Target: Right leg"
+ description = ""
+ category = CATEGORY_TARGETING
+
+/datum/keybinding/mob/target_right_leg/down(client/user)
+ user.body_r_leg()
+ return TRUE
+
+/datum/keybinding/mob/target_body_groin
+ hotkey_keys = list("Numpad2")
+ name = "target_body_groin"
+ full_name = "Target: Groin"
+ description = ""
+ category = CATEGORY_TARGETING
+
+/datum/keybinding/mob/target_body_groin/down(client/user)
+ user.body_groin()
+ return TRUE
+
+/datum/keybinding/mob/target_left_leg
+ hotkey_keys = list("Numpad3")
+ name = "target_left_leg"
+ full_name = "Target: left leg"
+ description = ""
+ category = CATEGORY_TARGETING
+
+/datum/keybinding/mob/target_left_leg/down(client/user)
+ user.body_l_leg()
+ return TRUE
diff --git a/code/modules/keybindings/setup.dm b/code/modules/keybindings/setup.dm
index 9a13bfb11c..a53820b5d2 100644
--- a/code/modules/keybindings/setup.dm
+++ b/code/modules/keybindings/setup.dm
@@ -1,55 +1,47 @@
-/client
- /// Keys currently held
- var/list/keys_held = list()
- /// These next two vars are to apply movement for keypresses and releases made while move delayed.
- /// Because discarding that input makes the game less responsive.
- /// On next move, add this dir to the move that would otherwise be done
- var/next_move_dir_add
- /// On next move, subtract this dir from the move that would otherwise be done
- var/next_move_dir_sub
-
-// Set a client's focus to an object and override these procs on that object to let it handle keypresses
-
/datum/proc/key_down(key, client/user) // Called when a key is pressed down initially
return
+
/datum/proc/key_up(key, client/user) // Called when a key is released
return
+
/datum/proc/keyLoop(client/user) // Called once every frame
set waitfor = FALSE
return
// removes all the existing macros
/client/proc/erase_all_macros()
- var/list/macro_sets = params2list(winget(src, null, "macros"))
var/erase_output = ""
- for(var/i in 1 to macro_sets.len)
- var/setname = macro_sets[i]
- var/list/macro_set = params2list(winget(src, "[setname].*", "command")) // The third arg doesnt matter here as we're just removing them all
- for(var/k in 1 to macro_set.len)
- var/list/split_name = splittext(macro_set[k], ".")
- var/macro_name = "[split_name[1]].[split_name[2]]" // [3] is "command"
- erase_output = "[erase_output];[macro_name].parent=null"
+ var/list/macro_set = params2list(winget(src, "default.*", "command")) // The third arg doesnt matter here as we're just removing them all
+ for(var/k in 1 to length(macro_set))
+ var/list/split_name = splittext(macro_set[k], ".")
+ var/macro_name = "[split_name[1]].[split_name[2]]" // [3] is "command"
+ erase_output = "[erase_output];[macro_name].parent=null"
winset(src, null, erase_output)
-/client/proc/set_macros()
+/client/proc/apply_macro_set(name, list/macroset)
+ ASSERT(name)
+ ASSERT(islist(macroset))
+ winclone(src, "default", name)
+ for(var/i in 1 to length(macroset))
+ var/key = macroset[i]
+ var/command = macroset[key]
+ winset(src, "[name]-[REF(key)]", "parent=[name];name=[key];command=[command]")
+
+/client/proc/set_macros(datum/preferences/prefs_override = prefs)
set waitfor = FALSE
keys_held.Cut()
erase_all_macros()
- var/list/macro_sets = SSinput.macro_sets
- for(var/i in 1 to macro_sets.len)
- var/setname = macro_sets[i]
- if(setname != "default")
- winclone(src, "default", setname)
- var/list/macro_set = macro_sets[setname]
- for(var/k in 1 to macro_set.len)
- var/key = macro_set[k]
- var/command = macro_set[key]
- winset(src, "[setname]-[REF(key)]", "parent=[setname];name=[key];command=[command]")
+ apply_macro_set(SKIN_MACROSET_HOTKEYS, SSinput.macroset_hotkey)
+ apply_macro_set(SKIN_MACROSET_CLASSIC_HOTKEYS, SSinput.macroset_classic_hotkey)
+ apply_macro_set(SKIN_MACROSET_CLASSIC_INPUT, SSinput.macroset_classic_input)
- if(prefs.hotkeys)
- winset(src, null, "input.focus=true input.background-color=[COLOR_INPUT_ENABLED] mainwindow.macro=default")
+ set_hotkeys_preference()
+
+/client/proc/set_hotkeys_preference(datum/preferences/prefs_override = prefs)
+ if(prefs_override.hotkeys)
+ winset(src, null, "map.focus=true input.background-color=[COLOR_INPUT_DISABLED] mainwindow.macro=[SKIN_MACROSET_HOTKEYS]")
else
- winset(src, null, "input.focus=true input.background-color=[COLOR_INPUT_ENABLED] mainwindow.macro=old_default")
+ winset(src, null, "input.focus=true input.background-color=[COLOR_INPUT_ENABLED] mainwindow.macro=[SKIN_MACROSET_CLASSIC_INPUT]")
diff --git a/code/modules/mining/equipment/explorer_gear.dm b/code/modules/mining/equipment/explorer_gear.dm
index a45275e0c8..39f8e296af 100644
--- a/code/modules/mining/equipment/explorer_gear.dm
+++ b/code/modules/mining/equipment/explorer_gear.dm
@@ -16,7 +16,6 @@
resistance_flags = FIRE_PROOF
mutantrace_variation = STYLE_DIGITIGRADE|STYLE_SNEK_TAURIC|STYLE_PAW_TAURIC
-
/obj/item/clothing/head/hooded/explorer
name = "explorer hood"
desc = "An armoured hood for exploring harsh environments."
@@ -51,7 +50,7 @@
visor_flags_inv = HIDEFACIALHAIR
visor_flags_cover = MASKCOVERSMOUTH
actions_types = list(/datum/action/item_action/adjust)
- armor = list("melee" = 10, "bullet" = 5, "laser" = 5, "energy" = 5, "bomb" = 0, "bio" = 50, "rad" = 0, "fire" = 20, "acid" = 40)
+ armor = list("melee" = 10, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 5, "bio" = 50, "rad" = 0, "fire" = 20, "acid" = 40)
resistance_flags = FIRE_PROOF
/obj/item/clothing/mask/gas/explorer/attack_self(mob/user)
@@ -140,7 +139,7 @@
max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT
heat_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
hoodtype = /obj/item/clothing/head/hooded/explorer/seva
- armor = list("melee" = 15, "bullet" = 10, "laser" = 10, "energy" = 10, "bomb" = 25, "bio" = 50, "rad" = 25, "fire" = 100, "acid" = 25)
+ armor = list("melee" = 15, "bullet" = 10, "laser" = 10, "energy" = 10, "bomb" = 35, "bio" = 50, "rad" = 25, "fire" = 100, "acid" = 25)
resistance_flags = FIRE_PROOF | GOLIATH_WEAKNESS
/obj/item/clothing/head/hooded/explorer/seva
@@ -149,7 +148,7 @@
icon_state = "seva"
item_state = "seva"
max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT
- armor = list("melee" = 10, "bullet" = 10, "laser" = 10, "energy" = 10, "bomb" = 25, "bio" = 50, "rad" = 25, "fire" = 100, "acid" = 25)
+ armor = list("melee" = 10, "bullet" = 10, "laser" = 10, "energy" = 10, "bomb" = 35, "bio" = 50, "rad" = 25, "fire" = 100, "acid" = 25)
resistance_flags = FIRE_PROOF | GOLIATH_WEAKNESS
/obj/item/clothing/mask/gas/seva
diff --git a/code/modules/mining/lavaland/necropolis_chests.dm b/code/modules/mining/lavaland/necropolis_chests.dm
index 9767ff3866..53ce676317 100644
--- a/code/modules/mining/lavaland/necropolis_chests.dm
+++ b/code/modules/mining/lavaland/necropolis_chests.dm
@@ -39,7 +39,7 @@
if(11)
new /obj/item/ship_in_a_bottle(src)
if(12)
- new /obj/item/clothing/suit/space/hardsuit/ert/paranormal/beserker(src)
+ new /obj/item/clothing/suit/space/hardsuit/ert/paranormal/beserker/old(src)
if(13)
new /obj/item/jacobs_ladder(src)
if(14)
@@ -67,7 +67,7 @@
new /obj/item/grenade/clusterbuster/inferno(src)
if(24)
new /obj/item/reagent_containers/food/drinks/bottle/holywater/hell(src)
- new /obj/item/clothing/suit/space/hardsuit/ert/paranormal/inquisitor(src)
+ new /obj/item/clothing/suit/space/hardsuit/ert/paranormal/inquisitor/old(src)
if(25)
new /obj/item/book/granter/spell/summonitem(src)
if(26)
diff --git a/code/modules/mining/machine_vending.dm b/code/modules/mining/machine_vending.dm
index 988197f04f..dcaaffe487 100644
--- a/code/modules/mining/machine_vending.dm
+++ b/code/modules/mining/machine_vending.dm
@@ -193,9 +193,14 @@
return ..()
/obj/machinery/mineral/equipment_vendor/proc/RedeemVoucher(obj/item/mining_voucher/voucher, mob/redeemer)
- var/items = list("Survival Capsule and Explorer's Webbing", "Resonator Kit", "Minebot Kit", "Extraction and Rescue Kit", "Crusher Kit", "Mining Conscription Kit")
+ var/items = list( "Survival Capsule and Explorer's Webbing" = image(icon = 'icons/obj/storage.dmi', icon_state = "explorerpack"),
+ "Resonator Kit" = image(icon = 'icons/obj/mining.dmi', icon_state = "resonator"),
+ "Minebot Kit" = image(icon = 'icons/mob/aibots.dmi', icon_state = "mining_drone"),
+ "Extraction and Rescue Kit" = image(icon = 'icons/obj/fulton.dmi', icon_state = "extraction_pack"),
+ "Crusher Kit" = image(icon = 'icons/obj/mining.dmi', icon_state = "crusher"),
+ "Mining Conscription Kit" = image(icon = 'icons/obj/storage.dmi', icon_state = "duffel"))
- var/selection = input(redeemer, "Pick your equipment", "Mining Voucher Redemption") as null|anything in items
+ var/selection = show_radial_menu(redeemer, src, items, require_near = TRUE, tooltips = TRUE)
if(!selection || !Adjacent(redeemer) || QDELETED(voucher) || voucher.loc != redeemer)
return
var/drop_location = drop_location()
@@ -366,9 +371,10 @@
new /obj/item/clothing/glasses/meson/prescription(src)
/obj/machinery/mineral/equipment_vendor/proc/RedeemSVoucher(obj/item/suit_voucher/voucher, mob/redeemer)
- var/items = list("Exo-suit", "SEVA suit")
+ var/items = list( "Exo-suit" = image(icon = 'icons/obj/clothing/suits.dmi', icon_state = "exo"),
+ "SEVA suit" = image(icon = 'icons/obj/clothing/suits.dmi', icon_state = "seva"))
- var/selection = input(redeemer, "Pick your suit.", "Suit Voucher Redemption") as null|anything in items
+ var/selection = show_radial_menu(redeemer, src, items, require_near = TRUE, tooltips = TRUE)
if(!selection || !Adjacent(redeemer) || QDELETED(voucher) || voucher.loc != redeemer)
return
var/drop_location = drop_location()
diff --git a/code/modules/mining/minebot.dm b/code/modules/mining/minebot.dm
index 0c8aef51a8..fb37dcbca0 100644
--- a/code/modules/mining/minebot.dm
+++ b/code/modules/mining/minebot.dm
@@ -24,7 +24,8 @@
environment_smash = ENVIRONMENT_SMASH_NONE
check_friendly_fire = TRUE
stop_automated_movement_when_pulled = TRUE
- attacktext = "drills"
+ attack_verb_continuous = "drills"
+ attack_verb_simple = "drill"
attack_sound = 'sound/weapons/circsawhit.ogg'
sentience_type = SENTIENCE_MINEBOT
speak_emote = list("states")
diff --git a/code/modules/mining/ores_coins.dm b/code/modules/mining/ores_coins.dm
index b54b990c77..f6b7110803 100644
--- a/code/modules/mining/ores_coins.dm
+++ b/code/modules/mining/ores_coins.dm
@@ -102,7 +102,22 @@ GLOBAL_LIST_INIT(sand_recipes, list(\
/obj/item/stack/ore/glass/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
if(..() || !ishuman(hit_atom))
return
- var/mob/living/carbon/human/C = hit_atom
+ var/mob/living/carbon/human/poorsod = hit_atom
+ eyesand(poorsod)
+
+/obj/item/stack/ore/glass/attack(mob/living/M, mob/living/user)
+ if(!ishuman(M))
+ return ..()
+ if(user.zone_selected != BODY_ZONE_PRECISE_EYES && user.zone_selected != BODY_ZONE_HEAD)
+ return ..()
+ var/mob/living/carbon/human/poorsod = M
+ visible_message("
[user] throws the sand at [poorsod]'s face!")
+ if(ishuman(user))
+ var/mob/living/carbon/human/sayer = user
+ sayer.forcesay("POCKET SAAND!!")
+ eyesand(poorsod)
+
+/obj/item/stack/ore/glass/proc/eyesand(mob/living/carbon/human/C)
if(C.head && C.head.flags_cover & HEADCOVERSEYES)
visible_message("
[C]'s headgear blocks the sand!")
return
@@ -116,8 +131,10 @@ GLOBAL_LIST_INIT(sand_recipes, list(\
C.adjustStaminaLoss(15)//the pain from your eyes burning does stamina damage
C.confused += 5
to_chat(C, "
\The [src] gets into your eyes! The pain, it burns!")
+ C.forcesay("*scream")
qdel(src)
+
/obj/item/stack/ore/glass/ex_act(severity, target)
if (severity == EXPLODE_NONE)
return
diff --git a/code/modules/mob/dead/new_player/sprite_accessories/legs_and_taurs.dm b/code/modules/mob/dead/new_player/sprite_accessories/legs_and_taurs.dm
index cbb38a3a6a..2ec6da2da8 100644
--- a/code/modules/mob/dead/new_player/sprite_accessories/legs_and_taurs.dm
+++ b/code/modules/mob/dead/new_player/sprite_accessories/legs_and_taurs.dm
@@ -64,6 +64,7 @@
taur_mode = STYLE_HOOF_TAURIC
alt_taur_mode = STYLE_PAW_TAURIC
color_src = MUTCOLORS
+ extra = TRUE
/datum/sprite_accessory/taur/drake
name = "Drake"
@@ -72,6 +73,12 @@
color_src = MUTCOLORS
extra = TRUE
+/datum/sprite_accessory/taur/drake/old
+ name = "Drake (Old)"
+ icon_state = "drake_old"
+ color_src = MATRIXED
+ extra = FALSE
+
/datum/sprite_accessory/taur/drider
name = "Drider"
icon_state = "drider"
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 2bb0d6ba77..33dbd7059f 100644
--- a/code/modules/mob/dead/new_player/sprite_accessories/tails.dm
+++ b/code/modules/mob/dead/new_player/sprite_accessories/tails.dm
@@ -450,6 +450,18 @@
color_src = MATRIXED
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+/datum/sprite_accessory/tails/human/tamamo_kitsune
+ name = "Tamamo Kitsune Tails" //Tamamo-no-Tiro, let it be known!
+ icon_state = "9sune"
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+
+/datum/sprite_accessory/tails_animated/human/tamamo_kitsune
+ name = "Tamamo Kitsune Tails"
+ icon_state = "9sune"
+ color_src = MATRIXED
+ icon = 'modular_citadel/icons/mob/mam_tails.dmi'
+
/datum/sprite_accessory/tails/human/tentacle
name = "Tentacle"
icon_state = "tentacle"
@@ -816,6 +828,14 @@ datum/sprite_accessory/mam_tails/insect
name = "Squirrel"
icon_state = "squirrel"
+/datum/sprite_accessory/mam_tails/tamamo_kitsune
+ name = "Tamamo Kitsune Tails"
+ icon_state = "9sune"
+
+/datum/sprite_accessory/mam_tails_animated/tamamo_kitsune
+ name = "Tamamo Kitsune Tails"
+ icon_state = "9sune"
+
/datum/sprite_accessory/mam_tails/tentacle
name = "Tentacle"
icon_state = "tentacle"
diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm
index b8e56f3d7c..838de24b60 100644
--- a/code/modules/mob/dead/observer/observer.dm
+++ b/code/modules/mob/dead/observer/observer.dm
@@ -707,7 +707,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
//this is a mob verb instead of atom for performance reasons
//see /mob/verb/examinate() in mob.dm for more info
//overridden here and in /mob/living for different point span classes and sanity checks
-/mob/dead/observer/pointed(atom/A as mob|obj|turf in view())
+/mob/dead/observer/pointed(atom/A as mob|obj|turf in fov_view())
if(!..())
return 0
usr.visible_message("
[src] points to [A].")
diff --git a/code/modules/mob/living/bloodcrawl.dm b/code/modules/mob/living/bloodcrawl.dm
index e8a9b50e98..3547d5f846 100644
--- a/code/modules/mob/living/bloodcrawl.dm
+++ b/code/modules/mob/living/bloodcrawl.dm
@@ -164,7 +164,7 @@
if(!B)
return
forceMove(B.loc)
- src.client.eye = src
+ reset_perspective(src)
src.visible_message("
[src] rises out of the pool of blood!")
exit_blood_effect(B)
if(iscarbon(src))
diff --git a/code/modules/mob/living/brain/brain.dm b/code/modules/mob/living/brain/brain.dm
index 4bca3e7f62..08d415fc3c 100644
--- a/code/modules/mob/living/brain/brain.dm
+++ b/code/modules/mob/living/brain/brain.dm
@@ -4,6 +4,7 @@
var/emp_damage = 0//Handles a type of MMI damage
var/datum/dna/stored/stored_dna // dna var for brain. Used to store dna, brain dna is not considered like actual dna, brain.has_dna() returns FALSE.
stat = DEAD //we start dead by default
+ has_field_of_vision = FALSE //Not really worth it.
see_invisible = SEE_INVISIBLE_LIVING
possible_a_intents = list(INTENT_HELP, INTENT_HARM) //for mechas
speech_span = SPAN_ROBOT
diff --git a/code/modules/mob/living/brain/brain_item.dm b/code/modules/mob/living/brain/brain_item.dm
index 90621ecd3f..6d3bf648f6 100644
--- a/code/modules/mob/living/brain/brain_item.dm
+++ b/code/modules/mob/living/brain/brain_item.dm
@@ -51,6 +51,12 @@
var/datum/brain_trauma/BT = X
BT.owner = owner
BT.on_gain()
+ if(damage > BRAIN_DAMAGE_MILD)
+ var/datum/skill_modifier/S
+ ADD_SKILL_MODIFIER_BODY(/datum/skill_modifier/brain_damage, null, C, S)
+ if(damage > BRAIN_DAMAGE_SEVERE)
+ var/datum/skill_modifier/S
+ ADD_SKILL_MODIFIER_BODY(/datum/skill_modifier/heavy_brain_damage, null, C, S)
//Update the body's icon so it doesnt appear debrained anymore
C.update_hair()
@@ -66,6 +72,8 @@
if((!QDELETED(src) || C) && !no_id_transfer)
transfer_identity(C)
if(C)
+ REMOVE_SKILL_MODIFIER_BODY(/datum/skill_modifier/brain_damage, null, C)
+ REMOVE_SKILL_MODIFIER_BODY(/datum/skill_modifier/heavy_brain_damage, null, C)
C.update_hair()
/obj/item/organ/brain/prepare_eat()
@@ -219,31 +227,6 @@
Insert(C)
else
..()
-/* TO BE REMOVED, KEPT IN CASE OF BUGS
-/obj/item/organ/brain/proc/get_brain_damage()
- var/brain_damage_threshold = max_integrity * BRAIN_DAMAGE_INTEGRITY_MULTIPLIER
- var/offset_integrity = obj_integrity - (max_integrity - brain_damage_threshold)
- . = round((1 - (offset_integrity / brain_damage_threshold)) * BRAIN_DAMAGE_DEATH, DAMAGE_PRECISION)
-
-/obj/item/organ/brain/proc/adjust_brain_damage(amount, maximum)
- var/adjusted_amount
- if(amount >= 0 && maximum)
- var/brainloss = get_brain_damage()
- var/new_brainloss = clamp(brainloss + amount, 0, maximum)
- if(brainloss > new_brainloss) //brainloss is over the cap already
- return 0
- adjusted_amount = new_brainloss - brainloss
- else
- adjusted_amount = amount
-
- adjusted_amount = round(adjusted_amount * BRAIN_DAMAGE_INTEGRITY_MULTIPLIER, DAMAGE_PRECISION)
- if(adjusted_amount)
- if(adjusted_amount >= DAMAGE_PRECISION)
- take_damage(adjusted_amount)
- else if(adjusted_amount <= -DAMAGE_PRECISION)
- obj_integrity = min(max_integrity, obj_integrity-adjusted_amount)
- . = adjusted_amount
-*/
/obj/item/organ/brain/applyOrganDamage(var/d, var/maximum = maxHealth)
. = ..()
@@ -261,18 +244,28 @@
. = ..()
//if we're not more injured than before, return without gambling for a trauma
if(damage <= prev_damage)
+ if(damage < prev_damage && owner)
+ if(prev_damage > BRAIN_DAMAGE_MILD && damage <= BRAIN_DAMAGE_MILD)
+ REMOVE_SKILL_MODIFIER_BODY(/datum/skill_modifier/brain_damage, null, owner)
+ if(prev_damage > BRAIN_DAMAGE_SEVERE && damage <= BRAIN_DAMAGE_SEVERE)
+ REMOVE_SKILL_MODIFIER_BODY(/datum/skill_modifier/heavy_brain_damage, null, owner)
return
damage_delta = damage - prev_damage
if(damage > BRAIN_DAMAGE_MILD)
if(prob(damage_delta * (1 + max(0, (damage - BRAIN_DAMAGE_MILD)/100)))) //Base chance is the hit damage; for every point of damage past the threshold the chance is increased by 1% //learn how to do your bloody math properly goddamnit
gain_trauma_type(BRAIN_TRAUMA_MILD)
+ if(prev_damage <= BRAIN_DAMAGE_MILD && owner)
+ var/datum/skill_modifier/S
+ ADD_SKILL_MODIFIER_BODY(/datum/skill_modifier/brain_damage, null, owner, S)
if(damage > BRAIN_DAMAGE_SEVERE)
if(prob(damage_delta * (1 + max(0, (damage - BRAIN_DAMAGE_SEVERE)/100)))) //Base chance is the hit damage; for every point of damage past the threshold the chance is increased by 1%
if(prob(20))
gain_trauma_type(BRAIN_TRAUMA_SPECIAL)
else
gain_trauma_type(BRAIN_TRAUMA_SEVERE)
-
+ if(prev_damage <= BRAIN_DAMAGE_SEVERE && owner)
+ var/datum/skill_modifier/S
+ ADD_SKILL_MODIFIER_BODY(/datum/skill_modifier/heavy_brain_damage, null, owner, S)
if (owner)
if(owner.stat < UNCONSCIOUS) //conscious or soft-crit
var/brain_message
diff --git a/code/modules/mob/living/carbon/alien/alien.dm b/code/modules/mob/living/carbon/alien/alien.dm
index a3600e6827..951185ee92 100644
--- a/code/modules/mob/living/carbon/alien/alien.dm
+++ b/code/modules/mob/living/carbon/alien/alien.dm
@@ -140,7 +140,8 @@ Des: Removes all infected images from the alien.
/mob/living/carbon/alien/proc/alien_evolve(mob/living/carbon/alien/new_xeno)
to_chat(src, "
You begin to evolve!")
- visible_message("
[src] begins to twist and contort!")
+ visible_message("
[src] begins to twist and contort!",
+ "
You begin to twist and contort!")
new_xeno.setDir(dir)
if(!alien_name_regex.Find(name))
new_xeno.name = name
diff --git a/code/modules/mob/living/carbon/alien/alien_defense.dm b/code/modules/mob/living/carbon/alien/alien_defense.dm
index cdb8aff2c6..00ce3a320a 100644
--- a/code/modules/mob/living/carbon/alien/alien_defense.dm
+++ b/code/modules/mob/living/carbon/alien/alien_defense.dm
@@ -27,13 +27,16 @@ In all, this is a lot like the monkey code. /N
AdjustUnconscious(-60, FALSE)
AdjustSleeping(-100, FALSE)
update_mobility()
- visible_message("
[M.name] nuzzles [src] trying to wake [p_them()] up!")
+ visible_message("
[M.name] nuzzles [src] trying to wake [p_them()] up!",
+ "
[M.name] nuzzles you trying to wake you up!", target = M,
+ target_message = "
You nuzzle [src] trying to wake [p_them()] up!")
if(INTENT_DISARM, INTENT_HARM)
if(health > 0)
M.do_attack_animation(src, ATTACK_EFFECT_BITE)
playsound(loc, 'sound/weapons/bite.ogg', 50, 1, -1)
visible_message("
[M.name] bites [src]!", \
- "
[M.name] bites [src]!", null, COMBAT_MESSAGE_RANGE)
+ "
[M.name] bites [src]!", null, COMBAT_MESSAGE_RANGE, null, M,
+ "
You bite [src]!")
adjustBruteLoss(1)
log_combat(M, src, "attacked")
updatehealth()
diff --git a/code/modules/mob/living/carbon/alien/humanoid/alien_powers.dm b/code/modules/mob/living/carbon/alien/humanoid/alien_powers.dm
index be81e850b7..3827aef8c1 100644
--- a/code/modules/mob/living/carbon/alien/humanoid/alien_powers.dm
+++ b/code/modules/mob/living/carbon/alien/humanoid/alien_powers.dm
@@ -22,9 +22,9 @@ Doesn't work on other aliens/AI.*/
action = new(src)
/obj/effect/proc_holder/alien/Trigger(mob/living/carbon/user, skip_cost_check = FALSE)
- if(!skip_cost_check || !istype(user))
+ if(!istype(user))
return TRUE
- if(cost_check(check_turf,user))
+ if(skip_cost_check || cost_check(check_turf,user))
if(fire(user) && user) // Second check to prevent runtimes when evolving
user.adjustPlasma(-plasma_cost)
return TRUE
diff --git a/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm b/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm
index c813ce40f0..11849641ef 100644
--- a/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm
+++ b/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm
@@ -25,6 +25,7 @@
/mob/living/carbon/alien/humanoid/Initialize()
AddAbility(new/obj/effect/proc_holder/alien/regurgitate(null))
. = ..()
+ AddComponent(/datum/component/footstep, FOOTSTEP_MOB_CLAW, 0.5, -3)
/mob/living/carbon/alien/humanoid/restrained(ignore_grab)
return handcuffed
diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm
index f694890b95..39179346f1 100644
--- a/code/modules/mob/living/carbon/carbon.dm
+++ b/code/modules/mob/living/carbon/carbon.dm
@@ -22,9 +22,6 @@
QDEL_NULL(dna)
GLOB.carbon_list -= src
-/mob/living/carbon/initialize_footstep()
- AddComponent(/datum/component/footstep, 0.6, 2)
-
/mob/living/carbon/relaymove(mob/user, direction)
if(user in src.stomach_contents)
if(prob(40))
@@ -256,7 +253,8 @@
var/obj/item/ITEM = get_item_by_slot(slot)
if(ITEM && istype(ITEM, /obj/item/tank) && wear_mask && (wear_mask.clothing_flags & ALLOWINTERNALS))
visible_message("
[usr] tries to [internal ? "close" : "open"] the valve on [src]'s [ITEM.name].", \
- "
[usr] tries to [internal ? "close" : "open"] the valve on [src]'s [ITEM.name].")
+ "
[usr] tries to [internal ? "close" : "open"] the valve on your [ITEM.name].", \
+ target = usr, target_message = "
You try to [internal ? "close" : "open"] the valve on [src]'s [ITEM.name].")
if(do_mob(usr, src, POCKET_STRIP_DELAY))
if(internal)
internal = null
@@ -267,7 +265,8 @@
update_internals_hud_icon(1)
visible_message("
[usr] [internal ? "opens" : "closes"] the valve on [src]'s [ITEM.name].", \
- "
[usr] [internal ? "opens" : "closes"] the valve on [src]'s [ITEM.name].")
+ "
[usr] [internal ? "opens" : "closes"] the valve on your [ITEM.name].", \
+ target = usr, target_message = "
You [internal ? "opens" : "closes"] the valve on [src]'s [ITEM.name].")
/mob/living/carbon/fall(forced)
diff --git a/code/modules/mob/living/carbon/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm
index 9a4f905dd1..94589b3a4a 100644
--- a/code/modules/mob/living/carbon/carbon_defense.dm
+++ b/code/modules/mob/living/carbon/carbon_defense.dm
@@ -185,7 +185,8 @@
M.powerlevel = 0
visible_message("
The [M.name] has shocked [src]!", \
- "
The [M.name] has shocked [src]!")
+ "
The [M.name] has shocked you!", target = M,
+ target_message = "
You have shocked [src]!")
do_sparks(5, TRUE, src)
var/power = M.powerlevel + rand(0,3)
@@ -234,38 +235,44 @@
var/obj/item/organ/O = X
O.emp_act(severity)
+///Adds to the parent by also adding functionality to propagate shocks through pulling and doing some fluff effects.
/mob/living/carbon/electrocute_act(shock_damage, source, siemens_coeff = 1, flags = NONE)
- if((flags & SHOCK_TESLA) && (flags_1 & TESLA_IGNORE_1))
- return FALSE
- if(HAS_TRAIT(src, TRAIT_SHOCKIMMUNE))
- return FALSE
- shock_damage *= siemens_coeff
- if(dna && dna.species)
- shock_damage *= dna.species.siemens_coeff
- if(shock_damage < 1)
- return 0
- if(reagents.has_reagent(/datum/reagent/teslium))
- shock_damage *= 1.5 //If the mob has teslium in their body, shocks are 50% more damaging!
- if((flags & SHOCK_ILLUSION))
- adjustStaminaLoss(shock_damage)
- else
- take_overall_damage(0,shock_damage)
- visible_message(
- "
[src] was shocked by \the [source]!", \
- "
You feel a powerful shock coursing through your body!", \
- "
You hear a heavy electrical crack." \
- )
- jitteriness += 1000 //High numbers for violent convulsions
+ . = ..()
+ if(!.)
+ return
+ //Propagation through pulling, fireman carry
+ if(!(flags & SHOCK_ILLUSION))
+ var/list/shocking_queue = list()
+ if(iscarbon(pulling) && source != pulling)
+ shocking_queue += pulling
+ if(iscarbon(pulledby) && source != pulledby)
+ shocking_queue += pulledby
+ if(iscarbon(buckled) && source != buckled)
+ shocking_queue += buckled
+ for(var/mob/living/carbon/carried in buckled_mobs)
+ if(source != carried)
+ shocking_queue += carried
+ //Found our victims, now lets shock them all
+ for(var/victim in shocking_queue)
+ var/mob/living/carbon/C = victim
+ C.electrocute_act(shock_damage*0.75, src, 1, flags)
+ //Stun
+ var/should_stun = (!(flags & SHOCK_TESLA) || siemens_coeff > 0.5) && !(flags & SHOCK_NOSTUN)
+ if(should_stun)
+ Stun(40)
+ //Jitter and other fluff.
+ jitteriness += 1000
do_jitter_animation(jitteriness)
stuttering += 2
- if((!(flags & SHOCK_TESLA) || siemens_coeff > 0.5) && !(flags & SHOCK_NOSTUN))
- Stun(40)
- spawn(20)
- jitteriness = max(jitteriness - 990, 10) //Still jittery, but vastly less
- if((!(flags & SHOCK_TESLA) || siemens_coeff > 0.5) && !(flags & SHOCK_NOSTUN))
- DefaultCombatKnockdown(60)
+ addtimer(CALLBACK(src, .proc/secondary_shock, should_stun), 20)
return shock_damage
+///Called slightly after electrocute act to reduce jittering and apply a secondary stun.
+/mob/living/carbon/proc/secondary_shock(should_stun)
+ jitteriness = max(jitteriness - 990, 10)
+ if(should_stun)
+ DefaultCombatKnockdown(60)
+
/mob/living/carbon/proc/help_shake_act(mob/living/carbon/M)
if(on_fire)
to_chat(M, "
You can't put [p_them()] out with just your bare hands!")
@@ -280,12 +287,14 @@
to_chat(M, "
You need to unbuckle [src] first to do that!")
return
M.visible_message("[M] shakes [src] trying to get [p_them()] up!", \
- "You shake [src] trying to get [p_them()] up!")
+ "You shake [src] trying to get [p_them()] up!", target = src,
+ target_message = "[M] shakes you trying to get you up!")
else if(M.zone_selected == BODY_ZONE_PRECISE_MOUTH) // I ADDED BOOP-EH-DEH-NOSEH - Jon
M.visible_message( \
"[M] boops [src]'s nose.", \
- "You boop [src] on the nose.", )
+ "You boop [src] on the nose.", target = src,
+ target_message = "[M] boops your nose.")
playsound(src, 'sound/items/Nose_boop.ogg', 50, 0)
else if(check_zone(M.zone_selected) == BODY_ZONE_HEAD)
@@ -294,7 +303,8 @@
S = dna.species
M.visible_message("[M] gives [src] a pat on the head to make [p_them()] feel better!", \
- "You give [src] a pat on the head to make [p_them()] feel better!")
+ "You give [src] a pat on the head to make [p_them()] feel better!", target = src,
+ target_message = "[M] gives you a pat on the head to make you feel better!")
SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "headpat", /datum/mood_event/headpat)
friendly_check = TRUE
if(S?.can_wag_tail(src) && !dna.species.is_wagging_tail())
@@ -307,11 +317,13 @@
else if(check_zone(M.zone_selected) == BODY_ZONE_R_ARM || check_zone(M.zone_selected) == BODY_ZONE_L_ARM)
M.visible_message( \
"[M] shakes [src]'s hand.", \
- "You shake [src]'s hand.", )
+ "You shake [src]'s hand.", target = src,
+ target_message = "[M] shakes your hand.")
else
M.visible_message("[M] hugs [src] to make [p_them()] feel better!", \
- "You hug [src] to make [p_them()] feel better!")
+ "You hug [src] to make [p_them()] feel better!", target = src,\
+ target_message = "[M] hugs you to make you feel better!")
SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "hug", /datum/mood_event/hug)
friendly_check = TRUE
@@ -433,3 +445,17 @@
var/obj/item/organ/ears/ears = getorganslot(ORGAN_SLOT_EARS)
if(istype(ears) && !ears.deaf)
. = TRUE
+
+/mob/living/carbon/getBruteLoss_nonProsthetic()
+ var/amount = 0
+ for(var/obj/item/bodypart/BP in bodyparts)
+ if (BP.status < 2)
+ amount += BP.brute_dam
+ return amount
+
+/mob/living/carbon/getFireLoss_nonProsthetic()
+ var/amount = 0
+ for(var/obj/item/bodypart/BP in bodyparts)
+ if (BP.status < 2)
+ amount += BP.burn_dam
+ return amount
diff --git a/code/modules/mob/living/carbon/damage_procs.dm b/code/modules/mob/living/carbon/damage_procs.dm
index adca193ce0..5528669afa 100644
--- a/code/modules/mob/living/carbon/damage_procs.dm
+++ b/code/modules/mob/living/carbon/damage_procs.dm
@@ -63,7 +63,7 @@
/mob/living/carbon/adjustBruteLoss(amount, updating_health = TRUE, forced = FALSE)
- if (!forced && amount < 0 && HAS_TRAIT(src,TRAIT_NONATURALHEAL))
+ if(!forced && amount < 0 && HAS_TRAIT(src,TRAIT_NONATURALHEAL))
return FALSE
if(!forced && (status_flags & GODMODE))
return FALSE
@@ -74,7 +74,7 @@
return amount
/mob/living/carbon/adjustFireLoss(amount, updating_health = TRUE, forced = FALSE)
- if (!forced && amount < 0 && HAS_TRAIT(src,TRAIT_NONATURALHEAL)) //Vamps don't heal naturally.
+ if(!forced && amount < 0 && HAS_TRAIT(src,TRAIT_NONATURALHEAL)) //Vamps don't heal naturally.
return FALSE
if(!forced && (status_flags & GODMODE))
return FALSE
diff --git a/code/modules/mob/living/carbon/death.dm b/code/modules/mob/living/carbon/death.dm
index 60fa395319..4cf82bb0b4 100644
--- a/code/modules/mob/living/carbon/death.dm
+++ b/code/modules/mob/living/carbon/death.dm
@@ -25,7 +25,8 @@
if(M in stomach_contents)
stomach_contents.Remove(M)
M.forceMove(Tsec)
- visible_message("[M] bursts out of [src]!")
+ M.visible_message("[M] bursts out of [src]!",
+ "You burst out of [src]!")
..()
/mob/living/carbon/spill_organs(no_brain, no_organs, no_bodyparts)
diff --git a/code/modules/mob/living/carbon/give.dm b/code/modules/mob/living/carbon/give.dm
deleted file mode 100644
index a712240622..0000000000
--- a/code/modules/mob/living/carbon/give.dm
+++ /dev/null
@@ -1,58 +0,0 @@
-/mob/living/verb/give()
- set category = "IC"
- set name = "Give"
- set src in oview(1) //Cannot handle giving shit to mobs on your own tile, but it's a small, small loss
-
- give_item(usr)
-
-/mob/living/proc/give_item(mob/living/carbon/user)
-
-
-/mob/living/carbon/give_item(mob/living/carbon/user)
- if(!istype(user))
- return
- if(src.stat == 2 || user.stat == 2 || src.client == null)
- return
- if(src.handcuffed)
- user << "Those hands are cuffed right now."
- return //Can't receive items while cuffed
- var/obj/item/I
- if(user.get_active_held_item() == null)
- user << "You don't have anything in your [get_held_index_name(get_held_index_of_item(I))] to give to [src]."
- return
- I = user.get_active_held_item()
- if(!I)
- return
- if(src == user) //Shouldn't happen
- user << "You tried to give yourself \the [I], but you didn't want it."
- return
- if(get_empty_held_index_for_side())
- switch(alert(src, "[user] wants to give you \a [I]?", , "Yes", "No"))
- if("Yes")
- if(!I)
- return
- if(!Adjacent(user))
- user <<"You need to stay still while giving an object."
- src << "[user] moved away."//What an asshole
-
- return
- if(user.get_active_held_item() != I)
- user << "You need to keep the item in your hand."
- src << "[user] has put \the [I] away!"
- return
- if(!get_empty_held_index_for_side())
- user << "Your hands are full."
- user << "Their hands are full."
- return
- if(!user.dropItemToGround(I))
- src << "[user] can't let go of \the [I]!"
- user << "You can't seem to let go of \the [I]."
- return
-
- src.put_in_hands(I)
- update_inv_hands()
- src.visible_message("[user] handed \the [I] to [src].")
- if("No")
- src.visible_message("[user] tried to hand \the [I] to [src] but \he didn't want it.")
- else
- user << "[src]'s hands are full."
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index ea91a90ee9..007bca3518 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -26,6 +26,7 @@
physiology = new()
AddComponent(/datum/component/personal_crafting)
+ AddComponent(/datum/component/footstep, FOOTSTEP_MOB_HUMAN, 1, 2)
. = ..()
if(CONFIG_GET(flag/disable_stambuffer))
diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm
index 856c57687f..3a2d0535e6 100644
--- a/code/modules/mob/living/carbon/human/human_defense.dm
+++ b/code/modules/mob/living/carbon/human/human_defense.dm
@@ -102,11 +102,15 @@
. = ..(user, TRUE)
if(.)
return
- var/hulk_verb = pick("smash","pummel")
+ var/hulk_verb_continous = "smashes"
+ var/hulk_verb_simple = "smash"
+ if(prob(50))
+ hulk_verb_continous = "pummels"
+ hulk_verb_simple = "pummel"
playsound(loc, user.dna.species.attack_sound, 25, 1, -1)
- var/message = "[user] has [hulk_verb]ed [src]!"
- visible_message("[message]", \
- "[message]")
+ visible_message("[user] [hulk_verb_continous] [src]!", \
+ "[user] [hulk_verb_continous] you!", null, COMBAT_MESSAGE_RANGE, null, user,
+ "You [hulk_verb_simple] [src]!")
adjustBruteLoss(15)
return 1
@@ -130,14 +134,16 @@
var/obj/item/I = get_active_held_item()
if(I && dropItemToGround(I))
playsound(loc, 'sound/weapons/slash.ogg', 25, 1, -1)
- visible_message("[M] disarmed [src]!", \
- "[M] disarmed [src]!")
+ visible_message("[M] has disarmed [src]!", \
+ "[M] has disarmed you!", null, COMBAT_MESSAGE_RANGE, null, M,
+ "You have disarmed [src]!")
else if(!M.client || prob(5)) // only natural monkeys get to stun reliably, (they only do it occasionaly)
playsound(loc, 'sound/weapons/pierce.ogg', 25, 1, -1)
DefaultCombatKnockdown(100)
log_combat(M, src, "tackled")
visible_message("[M] has tackled down [src]!", \
- "[M] has tackled down [src]!")
+ "[M] has tackled you down!", null, COMBAT_MESSAGE_RANGE, null, M,
+ "You have tackled [src] down!")
if(M.limb_destroyer)
dismembering_strike(M, affecting.body_zone)
@@ -159,7 +165,8 @@
if(!damage)
playsound(loc, 'sound/weapons/slashmiss.ogg', 50, 1, -1)
visible_message("[M] has lunged at [src]!", \
- "[M] has lunged at [src]!")
+ "[M] has lunged at you!", target = M, \
+ target_message = "You have lunged at [src]!")
return 0
var/obj/item/bodypart/affecting = get_bodypart(ran_zone(M.zone_selected))
if(!affecting)
@@ -168,7 +175,8 @@
playsound(loc, 'sound/weapons/slice.ogg', 25, 1, -1)
visible_message("[M] has slashed at [src]!", \
- "[M] has slashed at [src]!")
+ "[M] has slashed at you!", target = M, \
+ target_message = "You have slashed at [src]!")
log_combat(M, src, "attacked")
if(!dismembering_strike(M, M.zone_selected)) //Dismemberment successful
return 1
@@ -178,14 +186,16 @@
var/obj/item/I = get_active_held_item()
if(I && dropItemToGround(I))
playsound(loc, 'sound/weapons/slash.ogg', 25, 1, -1)
- visible_message("[M] disarmed [src]!", \
- "[M] disarmed [src]!")
+ visible_message("[M] has disarmed [src]!", \
+ "[M] has disarmed you!", target = M, \
+ target_message = "You have disarmed [src]!")
else
playsound(loc, 'sound/weapons/pierce.ogg', 25, 1, -1)
DefaultCombatKnockdown(M.meleeKnockdownPower)
log_combat(M, src, "tackled")
visible_message("[M] has tackled down [src]!", \
- "[M] has tackled down [src]!")
+ "[M] has tackled you down!", target = M, \
+ target_message = "You have tackled down [src]!")
/mob/living/carbon/human/attack_larva(mob/living/carbon/alien/larva/L)
. = ..()
@@ -268,7 +278,8 @@
updatehealth()
visible_message("[M.name] has hit [src]!", \
- "[M.name] has hit [src]!", null, COMBAT_MESSAGE_RANGE)
+ "[M.name] has hit you!", null, COMBAT_MESSAGE_RANGE, target = M,
+ target_message = "You have hit [src]!")
log_combat(M.occupant, src, "attacked", M, "(INTENT: [uppertext(M.occupant.a_intent)]) (DAMTYPE: [uppertext(M.damtype)])")
else
@@ -348,40 +359,34 @@
apply_damage(5, BRUTE, affecting, run_armor_check(affecting, "melee"))
-//Added a safety check in case you want to shock a human mob directly through electrocute_act.
+///Calculates the siemens coeff based on clothing and species, can also restart hearts.
/mob/living/carbon/human/electrocute_act(shock_damage, source, siemens_coeff = 1, flags = NONE)
- if(flags & SHOCK_TESLA)
- var/total_coeff = 1
- if(gloves)
- var/obj/item/clothing/gloves/G = gloves
- if(G.siemens_coefficient <= 0)
- total_coeff -= 0.5
+ //Calculates the siemens coeff based on clothing. Completely ignores the arguments
+ if(flags & SHOCK_TESLA) //I hate this entire block. This gets the siemens_coeff for tesla shocks
+ if(gloves && gloves.siemens_coefficient <= 0)
+ siemens_coeff -= 0.5
if(wear_suit)
- var/obj/item/clothing/suit/S = wear_suit
- if(S.siemens_coefficient <= 0)
- total_coeff -= 0.95
- else if(S.siemens_coefficient == (-1))
- total_coeff -= 1
- siemens_coeff = total_coeff
- if(flags_1 & TESLA_IGNORE_1)
- siemens_coeff = 0
- else if(!(flags & SHOCK_NOGLOVES))
- var/gloves_siemens_coeff = 1
+ if(wear_suit.siemens_coefficient == -1)
+ siemens_coeff -= 1
+ else if(wear_suit.siemens_coefficient <= 0)
+ siemens_coeff -= 0.95
+ siemens_coeff = max(siemens_coeff, 0)
+ else if(!(flags & SHOCK_NOGLOVES)) //This gets the siemens_coeff for all non tesla shocks
if(gloves)
- var/obj/item/clothing/gloves/G = gloves
- gloves_siemens_coeff = G.siemens_coefficient
- siemens_coeff = gloves_siemens_coeff
- if(undergoing_cardiac_arrest() && !(flags & SHOCK_ILLUSION))
- if(shock_damage * siemens_coeff >= 1 && prob(25))
- var/obj/item/organ/heart/heart = getorganslot(ORGAN_SLOT_HEART)
- heart.beating = TRUE
- if(stat == CONSCIOUS)
- to_chat(src, "You feel your heart beating again!")
+ siemens_coeff *= gloves.siemens_coefficient
siemens_coeff *= physiology.siemens_coeff
. = ..()
- if(.)
- electrocution_animation(40)
-
+ //Don't go further if the shock was blocked/too weak.
+ if(!.)
+ return
+ //Note we both check that the user is in cardiac arrest and can actually heartattack
+ //If they can't, they're missing their heart and this would runtime
+ if(undergoing_cardiac_arrest() && can_heartattack() && !(flags & SHOCK_ILLUSION))
+ if(shock_damage * siemens_coeff >= 1 && prob(25))
+ var/obj/item/organ/heart/heart = getorganslot(ORGAN_SLOT_HEART)
+ if(heart.Restart() && stat == CONSCIOUS)
+ to_chat(src, "You feel your heart beating again!")
+ electrocution_animation(40)
/mob/living/carbon/human/emp_act(severity)
. = ..()
diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm
index e0eec0e599..e7be540eb9 100644
--- a/code/modules/mob/living/carbon/human/human_defines.dm
+++ b/code/modules/mob/living/carbon/human/human_defines.dm
@@ -9,6 +9,7 @@
/// Enable stamina combat
combat_flags = COMBAT_FLAGS_DEFAULT
status_flags = CANSTUN|CANKNOCKDOWN|CANUNCONSCIOUS|CANPUSH|CANSTAGGER
+ has_field_of_vision = FALSE //Handled by species.
blocks_emissive = EMISSIVE_BLOCK_UNIQUE
diff --git a/code/modules/mob/living/carbon/human/inventory.dm b/code/modules/mob/living/carbon/human/inventory.dm
index 580b0aaaf0..8de143e2bd 100644
--- a/code/modules/mob/living/carbon/human/inventory.dm
+++ b/code/modules/mob/living/carbon/human/inventory.dm
@@ -277,3 +277,65 @@
qdel(slot)
for(var/obj/item/I in held_items)
qdel(I)
+
+/mob/living/carbon/human/proc/smart_equipbag() // take most recent item out of bag or place held item in bag
+ if(incapacitated())
+ return
+ var/obj/item/thing = get_active_held_item()
+ var/obj/item/equipped_back = get_item_by_slot(SLOT_BACK)
+ if(!equipped_back) // We also let you equip a backpack like this
+ if(!thing)
+ to_chat(src, "You have no backpack to take something out of!")
+ return
+ if(equip_to_slot_if_possible(thing, ITEM_SLOT_BACK))
+ update_inv_hands()
+ return
+ if(!SEND_SIGNAL(equipped_back, COMSIG_CONTAINS_STORAGE)) // not a storage item
+ if(!thing)
+ equipped_back.attack_hand(src)
+ else
+ to_chat(src, "You can't fit anything in!")
+ return
+ if(thing) // put thing in backpack
+ if(!SEND_SIGNAL(equipped_back, COMSIG_TRY_STORAGE_INSERT, thing, src))
+ to_chat(src, "You can't fit anything in!")
+ return
+ if(!equipped_back.contents.len) // nothing to take out
+ to_chat(src, "There's nothing in your backpack to take out!")
+ return
+ var/obj/item/stored = equipped_back.contents[equipped_back.contents.len]
+ if(!stored || stored.on_found(src))
+ return
+ stored.attack_hand(src) // take out thing from backpack
+ return
+
+/mob/living/carbon/human/proc/smart_equipbelt() // put held thing in belt or take most recent item out of belt
+ if(incapacitated())
+ return
+ var/obj/item/thing = get_active_held_item()
+ var/obj/item/equipped_belt = get_item_by_slot(SLOT_BELT)
+ if(!equipped_belt) // We also let you equip a belt like this
+ if(!thing)
+ to_chat(src, "You have no belt to take something out of!")
+ return
+ if(equip_to_slot_if_possible(thing, ITEM_SLOT_BELT))
+ update_inv_hands()
+ return
+ if(!SEND_SIGNAL(equipped_belt, COMSIG_CONTAINS_STORAGE)) // not a storage item
+ if(!thing)
+ equipped_belt.attack_hand(src)
+ else
+ to_chat(src, "You can't fit anything in!")
+ return
+ if(thing) // put thing in belt
+ if(!SEND_SIGNAL(equipped_belt, COMSIG_TRY_STORAGE_INSERT, thing, src))
+ to_chat(src, "You can't fit anything in!")
+ return
+ if(!equipped_belt.contents.len) // nothing to take out
+ to_chat(src, "There's nothing in your belt to take out!")
+ return
+ var/obj/item/stored = equipped_belt.contents[equipped_belt.contents.len]
+ if(!stored || stored.on_found(src))
+ return
+ stored.attack_hand(src) // take out thing from belt
+ return
diff --git a/code/modules/mob/living/carbon/human/login.dm b/code/modules/mob/living/carbon/human/login.dm
new file mode 100644
index 0000000000..a89921143a
--- /dev/null
+++ b/code/modules/mob/living/carbon/human/login.dm
@@ -0,0 +1,4 @@
+/mob/living/carbon/human/Login()
+ ..()
+ if(dna?.species?.has_field_of_vision && CONFIG_GET(flag/use_field_of_vision))
+ LoadComponent(/datum/component/field_of_vision, field_of_vision_type)
diff --git a/code/modules/mob/living/carbon/human/physiology.dm b/code/modules/mob/living/carbon/human/physiology.dm
index 4d411deb53..fd0df0bde9 100644
--- a/code/modules/mob/living/carbon/human/physiology.dm
+++ b/code/modules/mob/living/carbon/human/physiology.dm
@@ -25,5 +25,8 @@
var/do_after_speed = 1 //Speed mod for do_after. Lower is better. If temporarily adjusting, please only modify using *= and /=, so you don't interrupt other calculations.
+ /// footstep type override for both shoeless and not footstep sounds.
+ var/footstep_type
+
/datum/physiology/New()
armor = new
diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm
index 51837498c8..5018b04cc4 100644
--- a/code/modules/mob/living/carbon/human/species.dm
+++ b/code/modules/mob/living/carbon/human/species.dm
@@ -10,6 +10,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
var/default_color = "#FFF" // if alien colors are disabled, this is the color that will be used by that race
var/sexes = 1 // whether or not the race has sexual characteristics. at the moment this is only 0 for skeletons and shadows
+ var/has_field_of_vision = TRUE
//Species Icon Drawing Offsets - Pixel X, Pixel Y, Aka X = Horizontal and Y = Vertical, from bottom left corner
var/list/offset_features = list(
@@ -104,6 +105,9 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
var/whitelist = list() //List the ckeys that can use this species, if it's whitelisted.: list("John Doe", "poopface666", "SeeALiggerPullTheTrigger") Spaces & capitalization can be included or ignored entirely for each key as it checks for both.
var/icon_limbs //Overrides the icon used for the limbs of this species. Mainly for downstream, and also because hardcoded icons disgust me. Implemented and maintained as a favor in return for a downstream's implementation of synths.
+ /// Our default override for typing indicator state
+ var/typing_indicator_state
+
///////////
// PROCS //
///////////
@@ -328,6 +332,24 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
if(mutant_bodyparts["meat_type"]) //I can't believe it's come to the meat
H.type_of_meat = GLOB.meat_types[H.dna.features["meat_type"]]
+ if(H.physiology)
+ if(mutant_bodyparts["taur"])
+ var/datum/sprite_accessory/taur/T = GLOB.taur_list[H.dna.features["taur"]]
+ switch(T?.taur_mode)
+ if(STYLE_HOOF_TAURIC)
+ H.physiology.footstep_type = FOOTSTEP_MOB_SHOE
+ if(STYLE_PAW_TAURIC)
+ H.physiology.footstep_type = FOOTSTEP_MOB_CLAW
+ if(STYLE_SNEK_TAURIC)
+ H.physiology.footstep_type = FOOTSTEP_MOB_CRAWL
+ else
+ H.physiology.footstep_type = null
+ else
+ H.physiology.footstep_type = null
+
+ if(H.client && has_field_of_vision && CONFIG_GET(flag/use_field_of_vision))
+ H.LoadComponent(/datum/component/field_of_vision, H.field_of_vision_type)
+
C.add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/species, TRUE, multiplicative_slowdown = speedmod)
SEND_SIGNAL(C, COMSIG_SPECIES_GAIN, src, old_species)
@@ -363,6 +385,11 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
C.dna.mutation_index[new_species.inert_mutation] = create_sequence(new_species.inert_mutation)
C.dna.default_mutation_genes[new_species.inert_mutation] = C.dna.mutation_index[new_species.inert_mutation]
+ if(!new_species.has_field_of_vision && has_field_of_vision && ishuman(C) && CONFIG_GET(flag/use_field_of_vision))
+ var/datum/component/field_of_vision/F = C.GetComponent(/datum/component/field_of_vision)
+ if(F)
+ qdel(F)
+
SEND_SIGNAL(C, COMSIG_SPECIES_LOSS, src)
/datum/species/proc/handle_hair(mob/living/carbon/human/H, forced_colour)
@@ -1397,7 +1424,8 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
/datum/species/proc/grab(mob/living/carbon/human/user, mob/living/carbon/human/target, datum/martial_art/attacker_style)
if(target.check_martial_melee_block())
- target.visible_message("[target] blocks [user]'s grab attempt!")
+ target.visible_message("[target] blocks [user]'s grab attempt!", target = user, \
+ target_message = "[target] blocks your grab attempt!")
return 0
if(attacker_style && attacker_style.grab_act(user,target))
return 1
@@ -1413,7 +1441,8 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
to_chat(user, "You're too exhausted.") //CITADEL CHANGE - ditto
return FALSE //CITADEL CHANGE - ditto
if(target.check_martial_melee_block())
- target.visible_message("[target] blocks [user]'s attack!")
+ target.visible_message("[target] blocks [user]'s attack!", target = user, \
+ target_message = "[target] blocks your attack!")
return FALSE
if(HAS_TRAIT(user, TRAIT_PUGILIST))//CITADEL CHANGE - makes punching cause staminaloss but funny martial artist types get a discount
@@ -1468,8 +1497,8 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
if(!damage || !affecting || prob(miss_chance))//future-proofing for species that have 0 damage/weird cases where no zone is targeted
playsound(target.loc, user.dna.species.miss_sound, 25, TRUE, -1)
target.visible_message("[user]'s [atk_verb] misses [target]!", \
- "You avoid [user]'s [atk_verb]!", "You hear a swoosh!", COMBAT_MESSAGE_RANGE, user)
- to_chat(user, "Your [atk_verb] misses [target]!")
+ "You avoid [user]'s [atk_verb]!", "You hear a swoosh!", null, COMBAT_MESSAGE_RANGE, null, \
+ user, "Your [atk_verb] misses [target]!")
log_combat(user, target, "attempted to punch")
return FALSE
@@ -1478,8 +1507,9 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
playsound(target.loc, user.dna.species.attack_sound, 25, 1, -1)
- target.visible_message("[user] has [atk_verb]ed [target]!", \
- "[user] has [atk_verb]ed [target]!", null, COMBAT_MESSAGE_RANGE)
+ target.visible_message("[user] [atk_verb]s [target]!", \
+ "[user] [atk_verb]s you!", null, COMBAT_MESSAGE_RANGE, null, \
+ user, "You [atk_verb] [target]!")
target.lastattacker = user.real_name
target.lastattackerckey = user.ckey
@@ -1501,8 +1531,9 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
if((punchedstam > 50) && prob(punchedstam*0.5)) //If our punch victim has been hit above the threshold, and they have more than 50 stamina damage, roll for stun, probability of 1% per 2 stamina damage
target.visible_message("[user] knocks [target] down!", \
- "You're knocked down by [user]!", "You hear aggressive shuffling followed by a loud thud!", COMBAT_MESSAGE_RANGE, user)
- to_chat(user, "You knock [target] down!")
+ "You're knocked down by [user]!",
+ "You hear aggressive shuffling followed by a loud thud!", COMBAT_MESSAGE_RANGE, null,
+ user, "You knock [target] down!")
var/knockdown_duration = 40 + (punchedstam + (punchedbrute*0.5))*0.8 - armor_block
target.DefaultCombatKnockdown(knockdown_duration)
@@ -1534,7 +1565,8 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
var/target_aiming_for_groin = target.zone_selected == "groin"
if(target.check_martial_melee_block()) //END EDIT
- target.visible_message("[target] blocks [user]'s disarm attempt!")
+ target.visible_message("[target] blocks [user]'s disarm attempt!", target = user, \
+ target_message = "[target] blocks your disarm attempt!")
return FALSE
if(IS_STAMCRIT(user))
to_chat(user, "You're too exhausted!")
@@ -1543,11 +1575,10 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
else if(aim_for_mouth && ( target_on_help || target_restrained || target_aiming_for_mouth))
playsound(target.loc, 'sound/weapons/slap.ogg', 50, 1, -1)
- user.visible_message(\
- "\The [user] slaps \the [target] in the face!",\
- "You slap [user == target ? "yourself" : "\the [target]"] in the face! ",\
- "You hear a slap."
- )
+ target.visible_message(\
+ "\The [user] slaps [user == target ? "[user.p_them()]self" : "\the [target]"] in the face!",\
+ "[user] slaps you in the face! ",\
+ "You hear a slap.", target = user, target_message = "You slap [user == target ? "yourself" : "\the [target]"] in the face! ")
user.do_attack_animation(target, ATTACK_EFFECT_FACE_SLAP)
user.adjustStaminaLossBuffered(3)
if (!HAS_TRAIT(target, TRAIT_PERMABONER))
@@ -1565,11 +1596,11 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
if (!HAS_TRAIT(target, TRAIT_PERMABONER))
stop_wagging_tail(target)
playsound(target.loc, 'sound/weapons/slap.ogg', 50, 1, -1)
- user.visible_message(\
- "\The [user] slaps \the [target]'s ass!",\
- "You slap [user == target ? "your" : "\the [target]'s"] ass!",\
- "You hear a slap."
- )
+ target.visible_message(\
+ "\The [user] slaps [user == target ? "[user.p_their()] own" : "\the [target]'s"] ass!",\
+ "[user] slaps your ass! ",\
+ "You hear a slap.", target = user, target_message = "You slap [user == target ? "your own" : "\the [target]'s"] ass! ")
+
return FALSE
else
@@ -1588,21 +1619,14 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
//var/randomized_zone = ran_zone(user.zone_selected) CIT CHANGE - comments out to prevent compiling errors
SEND_SIGNAL(target, COMSIG_HUMAN_DISARM_HIT, user, user.zone_selected)
if(target.pulling == user)
- target.visible_message("[user] wrestles out of [target]'s grip!")
+ target.visible_message("[user] wrestles out of [target]'s grip!", \
+ "[user] wrestles out of your grip!", target = user, \
+ target_message = "You wrestle out of [target]'s grip!")
target.stop_pulling()
playsound(target, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
log_combat(user, target, "disarmed out of grab from")
return
- //var/obj/item/bodypart/affecting = target.get_bodypart(randomized_zone) CIT CHANGE - comments this out to prevent compile errors due to the below commented out bit
var/randn = rand(1, 100)
- /*if(randn <= 25) CITADEL CHANGE - moves disarm push attempts to right click
- playsound(target, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
- target.visible_message("[user] has pushed [target]!",
- "[user] has pushed [target]!", null, COMBAT_MESSAGE_RANGE)
- target.apply_effect(40, EFFECT_KNOCKDOWN, target.run_armor_check(affecting, "melee", "Your armor prevents your fall!", "Your armor softens your fall!"))
- target.forcesay(GLOB.hit_appends)
- log_combat(user, target, "pushed over")
- return*/
if(!(target.combat_flags & COMBAT_FLAG_COMBAT_ACTIVE)) // CITADEL CHANGE
randn += -10 //CITADEL CHANGE - being out of combat mode makes it easier for you to get disarmed
if(!CHECK_MOBILITY(user, MOBILITY_STAND)) //CITADEL CHANGE
@@ -1619,13 +1643,16 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
if(randn <= 35)//CIT CHANGE - changes this back to a 35% chance to accomodate for the above being commented out in favor of right-click pushing
var/obj/item/I = null
if(target.pulling)
- target.visible_message("[user] has broken [target]'s grip on [target.pulling]!")
+ target.visible_message("[user] has broken [target]'s grip on [target.pulling]!", \
+ "[user] has broken your grip on [target.pulling]!", target = user, \
+ target_message = "You have broken [target]'s grip on [target.pulling]!")
target.stop_pulling()
else
I = target.get_active_held_item()
if(target.dropItemToGround(I))
target.visible_message("[user] has disarmed [target]!", \
- "[user] has disarmed [target]!", null, COMBAT_MESSAGE_RANGE)
+ "[user] has disarmed you!", null, COMBAT_MESSAGE_RANGE, null, \
+ user, "You have disarmed [target]!")
else
I = null
playsound(target, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
@@ -1635,7 +1662,8 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
playsound(target, 'sound/weapons/punchmiss.ogg', 25, 1, -1)
target.visible_message("[user] attempted to disarm [target]!", \
- "[user] attemped to disarm [target]!", null, COMBAT_MESSAGE_RANGE)
+ "[user] attemped to disarm [target]!", null, COMBAT_MESSAGE_RANGE, null, \
+ user, "You attempted to disarm [target]!")
log_combat(user, target, "attempted to disarm")
@@ -1723,7 +1751,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
H.adjustOrganLoss(ORGAN_SLOT_BRAIN, 20)
if(H.stat == CONSCIOUS)
H.visible_message("[H] has been knocked senseless!", \
- "[H] has been knocked senseless!")
+ "You have been knocked senseless!")
H.confused = max(H.confused, 20)
H.adjust_blurriness(10)
if(prob(10))
@@ -1781,7 +1809,9 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
attacker_style = M.mind.martial_art
if((M != H) && M.a_intent != INTENT_HELP && (H.mob_run_block(M, 0, "[M]", ATTACK_TYPE_UNARMED, 0, M, M.zone_selected, null) & BLOCK_SUCCESS))
log_combat(M, H, "attempted to touch")
- H.visible_message("[M] attempted to touch [H]!")
+ H.visible_message("[M] attempted to touch [H]!", \
+ "[M] attempted to touch you!", target = M, \
+ target_message = "You attempted to touch [H]!")
return TRUE
switch(M.a_intent)
if(INTENT_HELP)
@@ -1818,7 +1848,9 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
to_chat(user, "You're too exhausted.")
return FALSE
if(target.check_martial_melee_block())
- target.visible_message("[target] blocks [user]'s shoving attempt!")
+ target.visible_message("[target] blocks [user]'s shoving attempt!", \
+ "You block [user]'s shoving attempt!", target = user, \
+ target_message = "[target] blocks your shoving attempt!")
return FALSE
if(attacker_style && attacker_style.disarm_act(user,target))
return TRUE
@@ -1863,19 +1895,22 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
var/targetatrest = !CHECK_MOBILITY(target, MOBILITY_STAND)
if((directional_blocked || !(target_collateral_human || target_shove_turf.shove_act(target, user))) && !targetatrest)
target.DefaultCombatKnockdown(SHOVE_KNOCKDOWN_SOLID)
- user.visible_message("[user.name] shoves [target.name], knocking them down!",
- "You shove [target.name], knocking them down!", null, COMBAT_MESSAGE_RANGE)
+ target.visible_message("[user.name] shoves [target.name], knocking them down!",
+ "[user.name] shoves you, knocking you down!", null, COMBAT_MESSAGE_RANGE, null,
+ user, "You shove [target.name], knocking them down!")
log_combat(user, target, "shoved", "knocking them down")
else if(target_collateral_human && !targetatrest)
target.DefaultCombatKnockdown(SHOVE_KNOCKDOWN_HUMAN)
target_collateral_human.DefaultCombatKnockdown(SHOVE_KNOCKDOWN_COLLATERAL)
- user.visible_message("[user.name] shoves [target.name] into [target_collateral_human.name]!",
- "You shove [target.name] into [target_collateral_human.name]!", null, COMBAT_MESSAGE_RANGE)
+ target.visible_message("[user.name] shoves [target.name] into [target_collateral_human.name]!",
+ "[user.name] shoves you into [target_collateral_human.name]!", null, COMBAT_MESSAGE_RANGE, null,
+ user, "You shove [target.name] into [target_collateral_human.name]!")
append_message += ", into [target_collateral_human.name]"
else
- user.visible_message("[user.name] shoves [target.name]!",
- "You shove [target.name]!", null, COMBAT_MESSAGE_RANGE)
+ target.visible_message("[user.name] shoves [target.name]!",
+ "[user.name] shoves you!", null, COMBAT_MESSAGE_RANGE, null,
+ user, "You shove [target.name]!")
var/obj/item/target_held_item = target.get_active_held_item()
if(!is_type_in_typecache(target_held_item, GLOB.shove_disarming_types))
target_held_item = null
diff --git a/code/modules/mob/living/carbon/human/species_types/dullahan.dm b/code/modules/mob/living/carbon/human/species_types/dullahan.dm
index ef730da219..1d19f28aa8 100644
--- a/code/modules/mob/living/carbon/human/species_types/dullahan.dm
+++ b/code/modules/mob/living/carbon/human/species_types/dullahan.dm
@@ -13,6 +13,7 @@
blacklisted = TRUE
limbs_id = "human"
skinned_type = /obj/item/stack/sheet/animalhide/human
+ has_field_of_vision = FALSE //Too much of a trouble, their vision is already bound to their severed head.
var/pumpkin = FALSE
var/obj/item/dullahan_relay/myhead
@@ -132,13 +133,13 @@
return INITIALIZE_HINT_QDEL
owner = new_owner
START_PROCESSING(SSobj, src)
- RegisterSignal(owner, COMSIG_CLICK_SHIFT, .proc/examinate_check)
+ RegisterSignal(owner, COMSIG_MOB_CLICKED_SHIFT_ON, .proc/examinate_check)
RegisterSignal(src, COMSIG_ATOM_HEARER_IN_VIEW, .proc/include_owner)
RegisterSignal(owner, COMSIG_LIVING_REGENERATE_LIMBS, .proc/unlist_head)
RegisterSignal(owner, COMSIG_LIVING_REVIVE, .proc/retrieve_head)
-/obj/item/dullahan_relay/proc/examinate_check(atom/source, mob/user)
- if(user.client.eye == src)
+/obj/item/dullahan_relay/proc/examinate_check(mob/source, atom/target)
+ if(source.client.eye == src)
return COMPONENT_ALLOW_EXAMINATE
/obj/item/dullahan_relay/proc/include_owner(datum/source, list/processing_list, list/hearers)
diff --git a/code/modules/mob/living/carbon/human/species_types/dwarves.dm b/code/modules/mob/living/carbon/human/species_types/dwarves.dm
index 5d9269b2f0..0a44891a70 100644
--- a/code/modules/mob/living/carbon/human/species_types/dwarves.dm
+++ b/code/modules/mob/living/carbon/human/species_types/dwarves.dm
@@ -33,12 +33,11 @@ GLOBAL_LIST_INIT(dwarf_last, world.file2list("strings/names/dwarf_last.txt")) //
var/mob/living/carbon/human/H = C
H.facial_hair_style = dwarf_hair
H.update_hair()
- H.transform = H.transform.Scale(1, 0.8) //We use scale, and yeah. Dwarves can become gnomes with DWARFISM.
+ AddElement(/datum/element/dwarfism, COMSIG_SPECIES_LOSS, src)
RegisterSignal(C, COMSIG_MOB_SAY, .proc/handle_speech) //We register handle_speech is being used.
/datum/species/dwarf/on_species_loss(mob/living/carbon/H, datum/species/new_species)
. = ..()
- H.transform = H.transform.Scale(1, 1.25) //And we undo it.
UnregisterSignal(H, COMSIG_MOB_SAY) //We register handle_speech is not being used.
//Dwarf Name stuff
@@ -121,7 +120,7 @@ GLOBAL_LIST_INIT(dwarf_last, world.file2list("strings/names/dwarf_last.txt")) //
return
//Filth Reactions - Since miasma now exists
var/filth_counter = 0 //Holder for the filth check cycle, basically contains how much filth dwarf sees numerically.
- for(var/fuck in view(owner,7)) //hello byond for view loop.
+ for(var/fuck in owner.fov_view(7)) //hello byond for view loop.
if(istype(fuck, /mob/living/carbon/human))
var/mob/living/carbon/human/H = fuck
if(H.stat == DEAD || (HAS_TRAIT(H, TRAIT_FAKEDEATH)))
diff --git a/code/modules/mob/living/carbon/human/species_types/golems.dm b/code/modules/mob/living/carbon/human/species_types/golems.dm
index 81132080ab..2b9d28a5f7 100644
--- a/code/modules/mob/living/carbon/human/species_types/golems.dm
+++ b/code/modules/mob/living/carbon/human/species_types/golems.dm
@@ -293,7 +293,7 @@
if(isturf(H.loc)) //else, there's considered to be no light
var/turf/T = H.loc
light_amount = min(1,T.get_lumcount()) - 0.5
- H.adjust_nutrition(light_amount * 10, NUTRITION_LEVEL_FULL)
+ H.adjust_nutrition(light_amount * 4, NUTRITION_LEVEL_FULL)
if(light_amount > 0.2) //if there's enough light, heal
H.heal_overall_damage(1,1)
H.adjustToxLoss(-1)
diff --git a/code/modules/mob/living/carbon/human/species_types/podpeople.dm b/code/modules/mob/living/carbon/human/species_types/podpeople.dm
index fd958ccc13..817498e417 100644
--- a/code/modules/mob/living/carbon/human/species_types/podpeople.dm
+++ b/code/modules/mob/living/carbon/human/species_types/podpeople.dm
@@ -13,7 +13,7 @@
disliked_food = MEAT | DAIRY
liked_food = VEGETABLES | FRUIT | GRAIN
species_language_holder = /datum/language_holder/sylvan
- var/light_nutrition_gain_factor = 10
+ var/light_nutrition_gain_factor = 4
var/light_toxheal = 1
var/light_oxyheal = 1
var/light_burnheal = 1
@@ -76,7 +76,7 @@
species_traits = list(EYECOLOR,HAIR,FACEHAIR,LIPS,MUTCOLORS)
mutant_bodyparts = list("mcolor" = "FFF","mcolor2" = "FFF","mcolor3" = "FFF", "mam_snouts" = "Husky", "mam_tail" = "Husky", "mam_ears" = "Husky", "mam_body_markings" = "Husky", "taur" = "None", "legs" = "Normal Legs")
limbs_id = "pod"
- light_nutrition_gain_factor = 7.5
+ light_nutrition_gain_factor = 3
light_bruteheal = 0.2
light_burnheal = 0.2
light_toxheal = 0.7
diff --git a/code/modules/mob/living/carbon/human/typing_indicator.dm b/code/modules/mob/living/carbon/human/typing_indicator.dm
new file mode 100644
index 0000000000..16ed95790a
--- /dev/null
+++ b/code/modules/mob/living/carbon/human/typing_indicator.dm
@@ -0,0 +1,2 @@
+/mob/living/carbon/human/get_typing_indicator_icon_state()
+ return dna?.species?.typing_indicator_state || ..()
diff --git a/code/modules/mob/living/carbon/monkey/monkey.dm b/code/modules/mob/living/carbon/monkey/monkey.dm
index 18c3fde188..5b91119789 100644
--- a/code/modules/mob/living/carbon/monkey/monkey.dm
+++ b/code/modules/mob/living/carbon/monkey/monkey.dm
@@ -45,6 +45,7 @@
/mob/living/carbon/monkey/ComponentInitialize()
. = ..()
AddElement(/datum/element/mob_holder, worn_state = "monkey", inv_slots = ITEM_SLOT_HEAD)
+ AddComponent(/datum/component/footstep, FOOTSTEP_MOB_BAREFOOT, 1, 2)
/mob/living/carbon/monkey/Destroy()
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index ced9fa3200..502ebcbe5d 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -9,10 +9,6 @@
diag_hud.add_to_hud(src)
faction += "[REF(src)]"
GLOB.mob_living_list += src
- initialize_footstep()
-
-/mob/living/proc/initialize_footstep()
- AddComponent(/datum/component/footstep)
/mob/living/prepare_huds()
..()
@@ -46,7 +42,8 @@
return ..()
/mob/living/proc/ZImpactDamage(turf/T, levels)
- visible_message("[src] crashes into [T] with a sickening noise!")
+ visible_message("[src] crashes into [T] with a sickening noise!", \
+ "You crash into [T] with a sickening noise!")
adjustBruteLoss((levels * 5) ** 1.5)
DefaultCombatKnockdown(levels * 50)
@@ -124,7 +121,9 @@
to_chat(src, "You're too exhausted to crawl under [L].")
return TRUE
ENABLE_BITFIELD(combat_flags, COMBAT_FLAG_ATTEMPTING_CRAWL)
- visible_message("[src] is attempting to crawl under [L].", "You are now attempting to crawl under [L].")
+ visible_message("[src] is attempting to crawl under [L].",
+ "You are now attempting to crawl under [L].",
+ target = L, target_message = "[src] is attempting to crawl under you.")
if(!do_after(src, CRAWLUNDER_DELAY, target = src) || CHECK_MOBILITY(src, MOBILITY_STAND))
DISABLE_BITFIELD(combat_flags, COMBAT_FLAG_ATTEMPTING_CRAWL)
return TRUE
@@ -276,7 +275,9 @@
if(AM.pulledby)
if(!supress_message)
- visible_message("[src] has pulled [AM] from [AM.pulledby]'s grip.")
+ AM.pulledby.visible_message("[src] has pulled [AM] from [AM.pulledby]'s grip.",
+ "[src] has pulled [AM] from your grip.", target = src,
+ target_message = "You have pulled [AM] from [AM.pulledby]'s grip.")
log_combat(AM, AM.pulledby, "pulled from", src)
AM.pulledby.stop_pulling() //an object can't be pulled by two mobs at once.
@@ -291,7 +292,9 @@
log_combat(src, M, "grabbed", addition="passive grab")
if(!supress_message && !(iscarbon(AM) && HAS_TRAIT(src, TRAIT_STRONG_GRABBER)))
- visible_message("[src] has grabbed [M][(zone_selected == "l_arm" || zone_selected == "r_arm")? " by their hands":" passively"]!") //Cit change - And they thought ERP was bad.
+ visible_message("[src] has grabbed [M][(zone_selected == "l_arm" || zone_selected == "r_arm")? " by [M.p_their()] hands":" passively"]!",
+ "You have grabbed [M][(zone_selected == "l_arm" || zone_selected == "r_arm")? " by [M.p_their()] hands":" passively"]!", target = M,
+ target_message = "[src] has grabbed you[(zone_selected == "l_arm" || zone_selected == "r_arm")? " by your hands":" passively"]!")
if(!iscarbon(src))
M.LAssailant = null
else
@@ -379,7 +382,7 @@
stop_pulling()
//same as above
-/mob/living/pointed(atom/A as mob|obj|turf in view())
+/mob/living/pointed(atom/A as mob|obj|turf in fov_view())
if(incapacitated())
return FALSE
if(HAS_TRAIT(src, TRAIT_DEATHCOMA))
@@ -756,12 +759,16 @@
. = ..()
if(pulledby.grab_state > GRAB_PASSIVE)
if(CHECK_MOBILITY(src, MOBILITY_RESIST) && prob(30/pulledby.grab_state))
- visible_message("[src] has broken free of [pulledby]'s grip!")
+ pulledby.visible_message("[src] has broken free of [pulledby]'s grip!",
+ "[src] has broken free of your grip!", target = src,
+ target_message = "You have broken free of [pulledby]'s grip!")
pulledby.stop_pulling()
return TRUE
else if(moving_resist && client) //we resisted by trying to move // this is a horrible system and whoever thought using client instead of mob is okay is not an okay person
client.move_delay = world.time + 20
- visible_message("[src] resists against [pulledby]'s grip!")
+ pulledby.visible_message("[src] resists against [pulledby]'s grip!",
+ "[src] resists against your grip!", target = src,
+ target_message = "You resist against [pulledby]'s grip!")
else
pulledby.stop_pulling()
return TRUE
@@ -826,7 +833,8 @@
strip_silence = g.strip_silence
if (!strip_silence)
who.visible_message("[src] tries to remove [who]'s [what.name].", \
- "[src] tries to remove [who]'s [what.name].")
+ "[src] tries to remove your [what.name].", target = src,
+ target_message = "You try to remove [who]'s [what.name].")
what.add_fingerprint(src)
else
to_chat(src,"You try to remove [who]'s [what.name].")
@@ -874,7 +882,9 @@
to_chat(src, "\The [what.name] doesn't fit in that place!")
return
- visible_message("[src] tries to put [what] on [who].")
+ who.visible_message("[src] tries to put [what] on [who].",
+ "[src] tries to put [what] on you.", target = src,
+ target_message = "You try to put [what] on [who].")
if(do_mob(src, who, what.equip_delay_other))
if(what && Adjacent(who) && what.mob_can_equip(who, src, final_where, TRUE, TRUE))
if(temporarilyRemoveItemFromInventory(what))
@@ -899,7 +909,7 @@
var/final_pixel_y = get_standard_pixel_y_offset(lying)
animate(src, pixel_x = pixel_x + pixel_x_diff, pixel_y = pixel_y + pixel_y_diff , time = 2, loop = 6)
animate(pixel_x = final_pixel_x , pixel_y = final_pixel_y , time = 2)
- setMovetype(movement_type & ~FLOATING) // If we were without gravity, the bouncing animation got stopped, so we make sure to restart it in next life().
+ floating_need_update = TRUE
/mob/living/proc/get_temperature(datum/gas_mixture/environment)
var/loc_temp = environment ? environment.temperature : T0C
@@ -1058,7 +1068,7 @@
/mob/living/proc/IgniteMob()
if(fire_stacks > 0 && !on_fire)
on_fire = 1
- src.visible_message("[src] catches fire!", \
+ visible_message("[src] catches fire!", \
"You're set on fire!")
new/obj/effect/dummy/lighting_obj/moblight/fire(src)
throw_alert("fire", /obj/screen/alert/fire)
diff --git a/code/modules/mob/living/living_block.dm b/code/modules/mob/living/living_block.dm
index 8156f83dbd..817863f257 100644
--- a/code/modules/mob/living/living_block.dm
+++ b/code/modules/mob/living/living_block.dm
@@ -85,7 +85,8 @@
if(. & BLOCK_SUCCESS)
return
if(prob(final_block_chance))
- owner.visible_message("[owner] blocks [attack_text] with [src]!")
+ owner.visible_message("[owner] blocks [attack_text] with [src]!",
+ "You block [attack_text] with [src]!")
return . | BLOCK_SUCCESS | BLOCK_PHYSICAL_EXTERNAL
return . | BLOCK_NONE
diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm
index 4cf6fc3694..17eb51b154 100644
--- a/code/modules/mob/living/living_defense.dm
+++ b/code/modules/mob/living/living_defense.dm
@@ -43,21 +43,21 @@
P.setAngle(SIMPLIFY_DEGREES(P.Angle + rand(120, 240)))
if(!silent)
visible_message("[P] gets deflected by [src]!", \
- "[P] gets deflected by [src]!")
+ "You deflect [P]!")
if(REDIRECT_METHOD_REFLECT)
P.setAngle(SIMPLIFY_DEGREES(P.Angle + 180))
if(!silent)
visible_message("[P] gets reflected by [src]!", \
- "[P] gets reflected by [src]!")
+ "You reflect [P]!")
if(REDIRECT_METHOD_PASSTHROUGH)
if(!silent)
visible_message("[P] passes through [src]!", \
- "[P] passes through [src]!")
+ "[P] passes through you!")
return
if(REDIRECT_METHOD_RETURN_TO_SENDER)
if(!silent)
visible_message("[src] deflects [P] back at their attacker!", \
- "[src] deflects [P] back at their attacker!")
+ "You deflect [P] back at your attacker!")
if(P.firer)
P.setAngle(Get_Angle(src, P.firer))
else
@@ -141,7 +141,7 @@
playsound(loc, 'sound/weapons/throwtap.ogg', 1, volume, -1)//...play throwtap.ogg.
if(!blocked)
visible_message("[src] has been hit by [I].", \
- "[src] has been hit by [I].")
+ "You have been hit by [I].")
var/armor = run_armor_check(impacting_zone, "melee", "Your armor has protected your [parse_zone(impacting_zone)].", "Your armor has softened hit to your [parse_zone(impacting_zone)].",I.armour_penetration)
apply_damage(I.throwforce, dtype, impacting_zone, armor)
if(I.thrownby)
@@ -175,12 +175,15 @@
return
updatehealth()
visible_message("[M.name] has hit [src]!", \
- "[M.name] has hit [src]!", null, COMBAT_MESSAGE_RANGE)
+ "[M.name] has hit you!", null, COMBAT_MESSAGE_RANGE, null,
+ M.occupant, "You hit [src] with your [M.name]!")
log_combat(M.occupant, src, "attacked", M, "(INTENT: [uppertext(M.occupant.a_intent)]) (DAMTYPE: [uppertext(M.damtype)])")
else
step_away(src,M)
log_combat(M.occupant, src, "pushed", M)
- visible_message("[M] pushes [src] out of the way.", null, null, 5)
+ visible_message("[M] pushes [src] out of the way.", \
+ "[M] pushes you out of the way.", null, COMBAT_MESSAGE_RANGE, null,
+ M.occupant, "You push [src] out of the way with your [M.name].")
/mob/living/fire_act()
adjust_fire_stacks(3)
@@ -224,7 +227,8 @@
var/old_grab_state = user.grab_state
var/grab_upgrade_time = instant ? 0 : 30
visible_message("[user] starts to tighten [user.p_their()] grip on [src]!", \
- "[user] starts to tighten [user.p_their()] grip on you!")
+ "[user] starts to tighten [user.p_their()] grip on you!", target = user,
+ target_message = "You start to tighten your grip on [src]!")
switch(user.grab_state)
if(GRAB_AGGRESSIVE)
log_combat(user, src, "attempted to neck grab", addition="neck grab")
@@ -242,25 +246,29 @@
var/add_log = ""
if(HAS_TRAIT(user, TRAIT_PACIFISM))
visible_message("[user] has firmly gripped [src]!",
- "[user] has firmly gripped you!")
+ "[user] has firmly gripped you!", target = user,
+ target_message = "You have firmly gripped [src]!")
add_log = " (pacifist)"
else
visible_message("[user] has grabbed [src] aggressively!", \
- "[user] has grabbed you aggressively!")
+ "[user] has grabbed you aggressively!", target = user, \
+ target_message = "You have grabbed [src] aggressively!")
update_mobility()
stop_pulling()
log_combat(user, src, "grabbed", addition="aggressive grab[add_log]")
if(GRAB_NECK)
log_combat(user, src, "grabbed", addition="neck grab")
visible_message("[user] has grabbed [src] by the neck!",\
- "[user] has grabbed you by the neck!")
+ "[user] has grabbed you by the neck!", target = user, \
+ target_message = "You have grabbed [src] by the neck!")
update_mobility() //we fall down
if(!buckled && !density)
Move(user.loc)
if(GRAB_KILL)
log_combat(user, src, "strangled", addition="kill grab")
visible_message("[user] is strangling [src]!", \
- "[user] is strangling you!")
+ "[user] is strangling you!", target = user, \
+ target_message = "You are strangling [src]!")
update_mobility() //we fall down
if(!buckled && !density)
Move(user.loc)
@@ -272,7 +280,9 @@
SEND_SIGNAL(src, COMSIG_MOB_ATTACK_HAND, user)
if((user != src) && user.a_intent != INTENT_HELP && (mob_run_block(user, 0, user.name, ATTACK_TYPE_UNARMED | ATTACK_TYPE_MELEE, null, user, check_zone(user.zone_selected), null) & BLOCK_SUCCESS))
log_combat(user, src, "attempted to touch")
- visible_message("[user] attempted to touch [src]!")
+ visible_message("[user] attempted to touch [src]!",
+ "[user] attempted to touch you!", target = user,
+ target_message = "You attempted to touch [src]!")
return TRUE
/mob/living/attack_hulk(mob/living/carbon/human/user, does_attack_animation = FALSE)
@@ -310,13 +320,16 @@
log_combat(M, src, "attacked")
M.do_attack_animation(src)
visible_message("The [M.name] glomps [src]!", \
- "The [M.name] glomps [src]!", null, COMBAT_MESSAGE_RANGE)
+ "The [M.name] glomps [src]!", null, COMBAT_MESSAGE_RANGE, null,
+ M, "You glomp [src]!")
return TRUE
/mob/living/attack_animal(mob/living/simple_animal/M)
M.face_atom(src)
if(M.melee_damage_upper == 0)
- M.visible_message("\The [M] [M.friendly] [src]!")
+ M.visible_message("\The [M] [M.friendly_verb_continuous] [src]!",
+ "You [M.friendly_verb_simple] [src]!", target = src,
+ target_message = "\The [M] [M.friendly_verb_continuous] you!")
return FALSE
else
if(HAS_TRAIT(M, TRAIT_PACIFISM))
@@ -327,8 +340,9 @@
if(M.attack_sound)
playsound(loc, M.attack_sound, 50, 1, 1)
M.do_attack_animation(src)
- visible_message("\The [M] [M.attacktext] [src]!", \
- "\The [M] [M.attacktext] [src]!", null, COMBAT_MESSAGE_RANGE)
+ visible_message("\The [M] [M.attack_verb_continuous] [src]!", \
+ "\The [M] [M.attack_verb_continuous] you!", null, COMBAT_MESSAGE_RANGE, null,
+ M, "You [M.attack_verb_simple] [src]!")
log_combat(M, src, "attacked")
return TRUE
@@ -347,17 +361,21 @@
log_combat(M, src, "attacked")
playsound(loc, 'sound/weapons/bite.ogg', 50, 1, -1)
visible_message("[M.name] bites [src]!", \
- "[M.name] bites [src]!", null, COMBAT_MESSAGE_RANGE)
+ "[M.name] bites you!", null, COMBAT_MESSAGE_RANGE, null,
+ M, "You bite [src]!")
return TRUE
else
visible_message("[M.name] has attempted to bite [src]!", \
- "[M.name] has attempted to bite [src]!", null, COMBAT_MESSAGE_RANGE)
+ "[M.name] has attempted to bite [src]!", null, COMBAT_MESSAGE_RANGE, null,
+ M, "You have attempted to bite [src]!")
return FALSE
/mob/living/attack_larva(mob/living/carbon/alien/larva/L)
switch(L.a_intent)
if(INTENT_HELP)
- visible_message("[L.name] rubs its head against [src].")
+ visible_message("[L.name] rubs its head against [src].",
+ "[L.name] rubs its head against you.", target = L, \
+ target_message = "You rub your head against [src].")
return FALSE
else
@@ -370,21 +388,26 @@
if(prob(90))
log_combat(L, src, "attacked")
visible_message("[L.name] bites [src]!", \
- "[L.name] bites [src]!", null, COMBAT_MESSAGE_RANGE)
+ "[L.name] bites you!", null, COMBAT_MESSAGE_RANGE, null, L, \
+ "You bite [src]!")
playsound(loc, 'sound/weapons/bite.ogg', 50, 1, -1)
return TRUE
else
visible_message("[L.name] has attempted to bite [src]!", \
- "[L.name] has attempted to bite [src]!", null, COMBAT_MESSAGE_RANGE)
+ "[L.name] has attempted to bite you!", null, COMBAT_MESSAGE_RANGE, null, L, \
+ "You have attempted to bite [src]!")
/mob/living/attack_alien(mob/living/carbon/alien/humanoid/M)
if((M != src) && M.a_intent != INTENT_HELP && (mob_run_block(M, 0, "the [M.name]", ATTACK_TYPE_MELEE | ATTACK_TYPE_UNARMED, 0, M, check_zone(M.zone_selected), null) & BLOCK_SUCCESS))
- visible_message("[M] attempted to touch [src]!")
+ visible_message("[M] attempted to touch [src]!",
+ "[M] attempted to touch you!")
return FALSE
switch(M.a_intent)
if (INTENT_HELP)
if(!isalien(src)) //I know it's ugly, but the alien vs alien attack_alien behaviour is a bit different.
- visible_message("[M] caresses [src] with its scythe like arm.")
+ visible_message("[M] caresses [src] with its scythe like arm.",
+ "[M] caresses you with its scythe like arm.", target = M,
+ target_message = "You caress [src] with your scythe like arm.")
return FALSE
if (INTENT_GRAB)
grabbedby(M)
@@ -412,21 +435,26 @@
take_bodypart_damage(acidpwr * min(1, acid_volume * 0.1))
return 1
+///As the name suggests, this should be called to apply electric shocks.
/mob/living/proc/electrocute_act(shock_damage, source, siemens_coeff = 1, flags = NONE)
SEND_SIGNAL(src, COMSIG_LIVING_ELECTROCUTE_ACT, shock_damage, source, siemens_coeff, flags)
- if((flags & SHOCK_TESLA) && (flags_1 & TESLA_IGNORE_1))
+ shock_damage *= siemens_coeff
+ if((flags & SHOCK_TESLA) && HAS_TRAIT(src, TRAIT_TESLA_SHOCKIMMUNE))
return FALSE
if(HAS_TRAIT(src, TRAIT_SHOCKIMMUNE))
return FALSE
- if(shock_damage > 0)
- if(!(flags & SHOCK_ILLUSION))
- adjustFireLoss(shock_damage)
- visible_message(
- "[src] was shocked by \the [source]!", \
- "You feel a powerful shock coursing through your body!", \
- "You hear a heavy electrical crack." \
- )
- return shock_damage
+ if(shock_damage < 1)
+ return FALSE
+ if(!(flags & SHOCK_ILLUSION))
+ adjustFireLoss(shock_damage)
+ else
+ adjustStaminaLoss(shock_damage)
+ visible_message(
+ "[src] was shocked by \the [source]!", \
+ "You feel a powerful shock coursing through your body!", \
+ "You hear a heavy electrical crack." \
+ )
+ return shock_damage
/mob/living/emp_act(severity)
. = ..()
@@ -505,4 +533,11 @@
if(!used_item)
used_item = get_active_held_item()
..()
- setMovetype(movement_type & ~FLOATING) // If we were without gravity, the bouncing animation got stopped, so we make sure we restart the bouncing after the next movement.
+ floating_need_update = TRUE
+
+
+/mob/living/proc/getBruteLoss_nonProsthetic()
+ return getBruteLoss()
+
+/mob/living/proc/getFireLoss_nonProsthetic()
+ return getFireLoss()
diff --git a/code/modules/mob/living/living_defines.dm b/code/modules/mob/living/living_defines.dm
index 228028eb9b..f8abf94083 100644
--- a/code/modules/mob/living/living_defines.dm
+++ b/code/modules/mob/living/living_defines.dm
@@ -4,6 +4,9 @@
see_in_dark = 2
hud_possible = list(HEALTH_HUD,STATUS_HUD,ANTAG_HUD,NANITE_HUD,DIAG_NANITE_FULL_HUD,RAD_HUD)
pressure_resistance = 10
+ has_field_of_vision = TRUE
+
+ typing_indicator_enabled = TRUE
var/resize = 1 //Badminnery resize
var/lastattacker = null
diff --git a/code/modules/mob/living/living_movement.dm b/code/modules/mob/living/living_movement.dm
index 6a84162ea8..4b90191dcc 100644
--- a/code/modules/mob/living/living_movement.dm
+++ b/code/modules/mob/living/living_movement.dm
@@ -1,6 +1,8 @@
/mob/living/Moved()
. = ..()
update_turf_movespeed(loc)
+ //Hide typing indicator if we move.
+ clear_typing_indicator()
if(is_shifted)
is_shifted = FALSE
pixel_x = get_standard_pixel_x_offset(lying)
diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm
index dff5584617..4e3093dda2 100644
--- a/code/modules/mob/living/silicon/ai/ai.dm
+++ b/code/modules/mob/living/silicon/ai/ai.dm
@@ -28,6 +28,7 @@
sec_hud = DATA_HUD_SECURITY_BASIC
d_hud = DATA_HUD_DIAGNOSTIC_ADVANCED
mob_size = MOB_SIZE_LARGE
+ has_field_of_vision = FALSE //Vision through cameras.
var/list/network = list("ss13")
var/obj/machinery/camera/current
var/list/connected_robots = list()
@@ -868,30 +869,33 @@
light_cameras()
if(istype(A, /obj/machinery/camera))
current = A
- if(client)
- if(ismovable(A))
- if(A != GLOB.ai_camera_room_landmark)
- end_multicam()
- client.perspective = EYE_PERSPECTIVE
- client.eye = A
- else
+ if(!client)
+ return
+ if(ismovable(A))
+ if(A != GLOB.ai_camera_room_landmark)
end_multicam()
- if(isturf(loc))
- if(eyeobj)
- client.eye = eyeobj
- client.perspective = EYE_PERSPECTIVE
- else
- client.eye = client.mob
- client.perspective = MOB_PERSPECTIVE
- else
+ client.perspective = EYE_PERSPECTIVE
+ client.eye = A
+ else
+ end_multicam()
+ if(isturf(loc))
+ if(eyeobj)
+ client.eye = eyeobj
client.perspective = EYE_PERSPECTIVE
- client.eye = loc
- update_sight()
- if(client.eye != src)
- var/atom/AT = client.eye
- AT.get_remote_view_fullscreens(src)
+ else
+ client.eye = client.mob
+ client.perspective = MOB_PERSPECTIVE
else
- clear_fullscreen("remote_view", 0)
+ client.perspective = EYE_PERSPECTIVE
+ client.eye = loc
+ update_sight()
+ if(client.eye != src)
+ var/atom/AT = client.eye
+ AT.get_remote_view_fullscreens(src)
+ else
+ clear_fullscreen("remote_view", 0)
+ SEND_SIGNAL(src, COMSIG_MOB_RESET_PERSPECTIVE, A)
+ return TRUE
/mob/living/silicon/ai/revive(full_heal = 0, admin_revive = 0)
. = ..()
diff --git a/code/modules/mob/living/silicon/pai/pai_defense.dm b/code/modules/mob/living/silicon/pai/pai_defense.dm
index ba162ecf2c..dcb7ac66c9 100644
--- a/code/modules/mob/living/silicon/pai/pai_defense.dm
+++ b/code/modules/mob/living/silicon/pai/pai_defense.dm
@@ -32,22 +32,28 @@
/mob/living/silicon/pai/attack_hand(mob/living/carbon/human/user)
switch(user.a_intent)
if(INTENT_HELP)
- visible_message("[user] gently pats [src] on the head, eliciting an off-putting buzzing from its holographic field.")
+ visible_message("[user] gently pats [src] on the head, eliciting an off-putting buzzing from its holographic field.",
+ "[user] gently pats you on the head, eliciting an off-putting buzzing from your holographic field.", target = user,
+ target_message = "You gently pat [src] on the head, eliciting an off-putting buzzing from its holographic field.")
if(INTENT_DISARM)
- visible_message("[user] boops [src] on the head!")
+ visible_message("[user] boops [src] on the head!",
+ "[user] boops you on the head!", target = user,
+ target_message = "You boop [src] on the head!")
if(INTENT_HARM)
user.do_attack_animation(src)
if (user.name == master)
visible_message("Responding to its master's touch, [src] disengages its holochassis emitter, rapidly losing coherence.")
- spawn(10)
- fold_in()
- if(user.put_in_hands(card))
- user.visible_message("[user] promptly scoops up [user.p_their()] pAI's card.")
+ fold_in()
+ if(user.put_in_hands(card))
+ user.visible_message("[user] promptly scoops up [user.p_their()] pAI's card.",
+ "You promptly scoops up your pAI's card.")
else
if(HAS_TRAIT(user, TRAIT_PACIFISM))
to_chat(user, "You don't want to hurt [src]!")
return
- visible_message("[user] stomps on [src]!.")
+ visible_message("[user] stomps on [src]!.",
+ "[user] stomps on you!.", target = user,
+ target_message = "You stomp on [src]!.")
take_holo_damage(2)
else
grabbedby(user)
diff --git a/code/modules/mob/living/silicon/robot/robot_defense.dm b/code/modules/mob/living/silicon/robot/robot_defense.dm
index 5750543a92..e337618e4b 100644
--- a/code/modules/mob/living/silicon/robot/robot_defense.dm
+++ b/code/modules/mob/living/silicon/robot/robot_defense.dm
@@ -32,15 +32,17 @@
var/obj/item/I = get_active_held_item()
if(I)
uneq_active()
- visible_message("[M] disarmed [src]!", \
- "[M] has disabled [src]'s active module!", null, COMBAT_MESSAGE_RANGE)
+ visible_message("[M] has disarmed [src]!", \
+ "[M] has disabled your active module!", null, COMBAT_MESSAGE_RANGE, null, M,
+ "You have disarmed [src]!")
log_combat(M, src, "disarmed", "[I ? " removing \the [I]" : ""]")
else
Paralyze(40)
step(src,get_dir(M,src))
log_combat(M, src, "pushed")
visible_message("[M] has forced back [src]!", \
- "[M] has forced back [src]!", null, COMBAT_MESSAGE_RANGE)
+ "[M] has forced you back!", null, COMBAT_MESSAGE_RANGE, null, M,
+ "You have forced back [src]!")
playsound(loc, 'sound/weapons/pierce.ogg', 50, 1, -1)
/mob/living/silicon/robot/attack_slime(mob/living/simple_animal/slime/M)
diff --git a/code/modules/mob/living/silicon/robot/update_icons.dm b/code/modules/mob/living/silicon/robot/update_icons.dm
index 72ad21c51e..a567446e9e 100644
--- a/code/modules/mob/living/silicon/robot/update_icons.dm
+++ b/code/modules/mob/living/silicon/robot/update_icons.dm
@@ -57,3 +57,5 @@
cut_overlays()
else
icon_state = "[module.cyborg_base_icon]"
+
+ SEND_SIGNAL(src, COMSIG_ROBOT_UPDATE_ICONS)
diff --git a/code/modules/mob/living/silicon/silicon_defense.dm b/code/modules/mob/living/silicon/silicon_defense.dm
index 94ce1e42fc..cd50ffbae6 100644
--- a/code/modules/mob/living/silicon/silicon_defense.dm
+++ b/code/modules/mob/living/silicon/silicon_defense.dm
@@ -17,7 +17,8 @@
log_combat(M, src, "attacked")
playsound(loc, 'sound/weapons/slash.ogg', 25, 1, -1)
visible_message("[M] has slashed at [src]!", \
- "[M] has slashed at [src]!")
+ "[M] has slashed at you!", target = M, \
+ target_message = "You have slashed at [src]!")
if(prob(8))
flash_act(affect_silicon = 1)
log_combat(M, src, "attacked")
@@ -25,8 +26,9 @@
updatehealth()
else
playsound(loc, 'sound/weapons/slashmiss.ogg', 25, 1, -1)
- visible_message("[M] took a swipe at [src]!", \
- "[M] took a swipe at [src]!")
+ visible_message("[M] take a swipe at [src]!", \
+ "[M] take a swipe at you!", target = M, \
+ target_message = "You take a swipe at [src]!")
/mob/living/silicon/attack_animal(mob/living/simple_animal/M)
. = ..()
@@ -36,7 +38,8 @@
for(var/mob/living/N in buckled_mobs)
N.DefaultCombatKnockdown(20)
unbuckle_mob(N)
- N.visible_message("[N] is knocked off of [src] by [M]!")
+ N.visible_message("[N] is knocked off of [src] by [M]!",
+ "You are knocked off of [src] by [M]!")
switch(M.melee_damage_type)
if(BRUTE)
adjustBruteLoss(damage)
@@ -62,7 +65,8 @@
adjustBruteLoss(rand(10, 15))
playsound(loc, "punch", 25, 1, -1)
visible_message("[user] has punched [src]!", \
- "[user] has punched [src]!")
+ "[user] has punched you!", target = user, \
+ target_message = "You have punched [src]!")
return TRUE
return FALSE
@@ -73,14 +77,16 @@
switch(M.a_intent)
if (INTENT_HELP)
M.visible_message("[M] pets [src].", \
- "You pet [src].")
+ "You pet [src].", target = src,
+ target_message = "[M] pets you.")
if(INTENT_GRAB)
grabbedby(M)
else
M.do_attack_animation(src, ATTACK_EFFECT_PUNCH)
playsound(src.loc, 'sound/effects/bang.ogg', 10, 1)
visible_message("[M] punches [src], but doesn't leave a dent.", \
- "[M] punches [src], but doesn't leave a dent.", null, COMBAT_MESSAGE_RANGE)
+ "[M] punches you, but doesn't leave a dent.", null, COMBAT_MESSAGE_RANGE, null, M,
+ "You punch [src], but don't leave a dent.")
/mob/living/silicon/attack_drone(mob/living/simple_animal/drone/M)
if(M.a_intent == INTENT_HARM)
@@ -109,7 +115,8 @@
if(prob(severity*50))
unbuckle_mob(M)
M.DefaultCombatKnockdown(40)
- M.visible_message("[M] is thrown off of [src]!")
+ M.visible_message("[M] is thrown off of [src]!",
+ "You are thrown off of [src]!")
flash_act(affect_silicon = 1)
/mob/living/silicon/bullet_act(obj/item/projectile/P, def_zone)
@@ -127,13 +134,15 @@
adjustBruteLoss(P.damage)
if(prob(P.damage*1.5))
for(var/mob/living/M in buckled_mobs)
- M.visible_message("[M] is knocked off of [src]!")
+ M.visible_message("[M] is knocked off of [src]!",
+ "You are knocked off of [src]!")
unbuckle_mob(M)
M.DefaultCombatKnockdown(40)
if(P.stun || P.knockdown)
for(var/mob/living/M in buckled_mobs)
unbuckle_mob(M)
- M.visible_message("[M] is knocked off of [src] by the [P]!")
+ M.visible_message("[M] is knocked off of [src] by the [P]!",
+ "You are knocked off of [src] by the [P]!")
P.on_hit(src)
return BULLET_ACT_HIT
diff --git a/code/modules/mob/living/simple_animal/animal_defense.dm b/code/modules/mob/living/simple_animal/animal_defense.dm
index fe18d48718..1e56e91ae1 100644
--- a/code/modules/mob/living/simple_animal/animal_defense.dm
+++ b/code/modules/mob/living/simple_animal/animal_defense.dm
@@ -7,7 +7,9 @@
switch(M.a_intent)
if(INTENT_HELP)
if (health > 0)
- visible_message("[M] [response_help] [src].")
+ visible_message("[M] [response_help_continuous] [src].", \
+ "[M] [response_help_continuous] you.", null, null, null,
+ M, "You [response_help_simple] [src].")
playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
if(INTENT_GRAB)
@@ -16,13 +18,22 @@
else
grabbedby(M)
- if(INTENT_HARM, INTENT_DISARM)
+ if(INTENT_DISARM)
+ M.do_attack_animation(src, ATTACK_EFFECT_DISARM)
+ visible_message("[M] [response_disarm_continuous] [src]!",\
+ "[M] [response_disarm_continuous] you!", null, COMBAT_MESSAGE_RANGE, null, \
+ M, "You [response_disarm_simple] [src]!")
+ playsound(src, 'sound/weapons/thudswoosh.ogg', 25, 1)
+ log_combat(M, src, "disarmed")
+
+ if(INTENT_HARM)
if(HAS_TRAIT(M, TRAIT_PACIFISM))
to_chat(M, "You don't want to hurt [src]!")
return
M.do_attack_animation(src, ATTACK_EFFECT_PUNCH)
- visible_message("[M] [response_harm] [src]!",\
- "[M] [response_harm] [src]!", null, COMBAT_MESSAGE_RANGE)
+ visible_message("[M] [response_harm_continuous] [src]!",\
+ "[M] [response_harm_continuous] you!", null, COMBAT_MESSAGE_RANGE, null, \
+ M, "You [response_harm_simple] [src]!")
playsound(loc, attacked_sound, 25, 1, -1)
attack_threshold_check(harm_intent_damage)
log_combat(M, src, "attacked")
@@ -35,8 +46,9 @@
if(.)
return
playsound(loc, "punch", 25, 1, -1)
- visible_message("[user] has punched [src]!", \
- "[user] has punched [src]!", null, COMBAT_MESSAGE_RANGE)
+ visible_message("[user] punches [src]!", \
+ "[user] punches you!", null, COMBAT_MESSAGE_RANGE, null, \
+ user, "You punch [src]!")
adjustBruteLoss(15)
return TRUE
@@ -48,7 +60,9 @@
return 1
if (M.a_intent == INTENT_HELP)
if (health > 0)
- visible_message("[M.name] [response_help] [src].")
+ visible_message("[M.name] [response_help_continuous] [src].", \
+ "[M.name] [response_help_continuous] you.", \
+ target = M, target_message = "You [response_help_simple] [src].")
playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
/mob/living/simple_animal/attack_alien(mob/living/carbon/alien/humanoid/M)
@@ -57,12 +71,14 @@
return
if(M.a_intent == INTENT_DISARM)
playsound(loc, 'sound/weapons/pierce.ogg', 25, 1, -1)
- visible_message("[M] [response_disarm] [name]!", \
- "[M] [response_disarm] [name]!", null, COMBAT_MESSAGE_RANGE)
+ visible_message("[M] [response_disarm_continuous] [name]!", \
+ "[M] [response_disarm_continuous] [name]!", null, COMBAT_MESSAGE_RANGE, null, \
+ M, "You [response_disarm_simple] [name]!")
log_combat(M, src, "disarmed")
else
visible_message("[M] has slashed at [src]!", \
- "[M] has slashed at [src]!", null, COMBAT_MESSAGE_RANGE)
+ "[M] has slashed at [src]!", null, COMBAT_MESSAGE_RANGE, null, \
+ M, "[M] has slashed at [src]!")
playsound(loc, 'sound/weapons/slice.ogg', 25, 1, -1)
attack_threshold_check(M.meleeSlashSAPower)
log_combat(M, src, "attacked")
@@ -102,7 +118,7 @@
temp_damage *= damage_coeff[damagetype]
if(temp_damage >= 0 && temp_damage <= force_threshold)
- visible_message("[src] looks unharmed.")
+ visible_message("[src] looks unharmed!")
return FALSE
else
apply_damage(damage, damagetype, null, getarmor(null, armorcheck))
diff --git a/code/modules/mob/living/simple_animal/astral.dm b/code/modules/mob/living/simple_animal/astral.dm
index ebc89e2577..48203b24b9 100644
--- a/code/modules/mob/living/simple_animal/astral.dm
+++ b/code/modules/mob/living/simple_animal/astral.dm
@@ -5,10 +5,15 @@
icon_state = "ghost"
icon_living = "ghost"
mob_biotypes = MOB_SPIRIT
- attacktext = "raises the hairs on the neck of"
- response_harm = "disrupts the concentration of"
- response_disarm = "wafts"
- friendly = "communes with"
+ has_field_of_vision = FALSE //we are a spoopy ghost
+ attack_verb_continuous = "raises the hair on the neck of"
+ attack_verb_simple = "raise the hair on the neck of"
+ response_harm_continuous = "disrupts the concentration of"
+ response_harm_simple = "disrupt the concentration of"
+ response_disarm_continuous = "wafts"
+ response_disarm_simple = "waft"
+ friendly_verb_continuous = "communes with"
+ friendly_verb_simple = "commute with"
loot = null
maxHealth = 10
health = 10
@@ -18,7 +23,6 @@
deathmessage = "disappears as if it was never really there to begin with"
incorporeal_move = 1
alpha = 50
- attacktext = "touches the mind of"
speak_emote = list("echos")
movement_type = FLYING
var/pseudo_death = FALSE
@@ -32,7 +36,6 @@
/mob/living/simple_animal/astral/death()
icon_state = "shade_dead"
Stun(1000)
- friendly = "deads at"
pseudo_death = TRUE
incorporeal_move = 0
to_chat(src, "Your astral projection is interrupted and your mind is sent back to your body with a shock!")
diff --git a/code/modules/mob/living/simple_animal/bot/cleanbot.dm b/code/modules/mob/living/simple_animal/bot/cleanbot.dm
index adb49938e1..73099d8d9f 100644
--- a/code/modules/mob/living/simple_animal/bot/cleanbot.dm
+++ b/code/modules/mob/living/simple_animal/bot/cleanbot.dm
@@ -20,9 +20,7 @@
weather_immunities = list("lava","ash")
var/clean_time = 50 //How long do we take to clean?
- var/broom = FALSE //Do we have an speed buff from a broom?
- var/adv_mop = FALSE //Do we have a cleaning buff from a better mop?
-
+ var/upgrades = 0
var/blood = 1
var/trash = 0
@@ -79,26 +77,38 @@
if(open)
to_chat(user, "Please close the access panel before locking it.")
else
- to_chat(user, "\The [src] doesn't seem to respect your authority.")
+ to_chat(user, "The [src] doesn't seem to respect your authority.")
- if(istype(W, /obj/item/mop/advanced))
- if(bot_core.allowed(user) && open && adv_mop == TRUE)
+ else if(istype(W, /obj/item/mop/advanced))
+ if(bot_core.allowed(user) && open && !CHECK_BITFIELD(upgrades,UPGRADE_CLEANER_ADVANCED_MOP))
to_chat(user, "You replace \the [src] old mop with a new better one!")
- adv_mop = TRUE
+ upgrades |= UPGRADE_CLEANER_ADVANCED_MOP
clean_time = 20 //2.5 the speed!
window_name = "Automatic Station Cleaner v2.1 BETA" //New!
qdel(W)
+ if(!open)
+ to_chat(user, "The [src] access pannle is not open!")
+ return
+ if(!bot_core.allowed(user))
+ to_chat(user, "The [src] access pannel locked off to you!")
+ return
else
- to_chat(user, "\the [src] already has this mop!")
+ to_chat(user, "The [src] already has this mop!")
- if(istype(W, /obj/item/twohanded/broom))
- if(bot_core.allowed(user) && open && broom == TRUE)
+ else if(istype(W, /obj/item/twohanded/broom))
+ if(bot_core.allowed(user) && open && !CHECK_BITFIELD(upgrades,UPGRADE_CLEANER_BROOM))
to_chat(user, "You add to \the [src] a broom speeding it up!")
- broom = TRUE
+ upgrades |= UPGRADE_CLEANER_BROOM
base_speed = 1 //2x faster!
qdel(W)
+ if(!open)
+ to_chat(user, "The [src] access pannel is not open!")
+ return
+ if(!bot_core.allowed(user))
+ to_chat(user, "The [src] access pannel locked off to you!")
+ return
else
- to_chat(user, "\the [src] already has a broom!")
+ to_chat(user, "The [src] already has a broom!")
else
return ..()
diff --git a/code/modules/mob/living/simple_animal/bot/ed209bot.dm b/code/modules/mob/living/simple_animal/bot/ed209bot.dm
index 469a395169..6febb942a1 100644
--- a/code/modules/mob/living/simple_animal/bot/ed209bot.dm
+++ b/code/modules/mob/living/simple_animal/bot/ed209bot.dm
@@ -44,8 +44,6 @@
var/cell_type = /obj/item/stock_parts/cell
var/vest_type = /obj/item/clothing/suit/armor/vest
- do_footstep = TRUE
-
/mob/living/simple_animal/bot/ed209/Initialize(mapload,created_name,created_lasercolor)
. = ..()
diff --git a/code/modules/mob/living/simple_animal/bot/floorbot.dm b/code/modules/mob/living/simple_animal/bot/floorbot.dm
index 1bf3883ea7..0f4608f48c 100644
--- a/code/modules/mob/living/simple_animal/bot/floorbot.dm
+++ b/code/modules/mob/living/simple_animal/bot/floorbot.dm
@@ -33,6 +33,8 @@
var/oldloc = null
var/toolbox = /obj/item/storage/toolbox/mechanical
+ var/upgrades = 0
+
#define HULL_BREACH 1
#define LINE_SPACE_MODE 2
#define FIX_TILE 3
@@ -120,6 +122,36 @@
to_chat(user, "You load [loaded] tiles into the floorbot. It now contains [specialtiles] tiles.")
else
to_chat(user, "You need at least one floor tile to put into [src]!")
+
+ else if(istype(W, /obj/item/storage/toolbox/artistic))
+ if(bot_core.allowed(user) && open && !CHECK_BITFIELD(upgrades,UPGRADE_FLOOR_ARTBOX))
+ to_chat(user, "You upgrade \the [src] case to hold more!")
+ upgrades |= UPGRADE_FLOOR_ARTBOX
+ maxtiles += 100 //Double the storage!
+ qdel(W)
+ if(!open)
+ to_chat(user, "The [src] access pannle is not open!")
+ return
+ if(!bot_core.allowed(user))
+ to_chat(user, "The [src] access pannel locked off to you!")
+ return
+ else
+ to_chat(user, "The [src] already has a upgraded case!")
+
+ else if(istype(W, /obj/item/storage/toolbox/syndicate))
+ if(bot_core.allowed(user) && open && !CHECK_BITFIELD(upgrades,UPGRADE_FLOOR_SYNDIBOX))
+ to_chat(user, "You upgrade \the [src] case to hold more!")
+ upgrades |= UPGRADE_FLOOR_SYNDIBOX
+ maxtiles += 200 //Double bse storage
+ base_speed = 1 //2x faster!
+ qdel(W)
+ if(!bot_core.allowed(user))
+ to_chat(user, "The [src] access pannel locked off to you!")
+ return
+ else
+ to_chat(user, "The [src] already has a upgraded case!")
+
+
else
..()
diff --git a/code/modules/mob/living/simple_animal/bot/medbot.dm b/code/modules/mob/living/simple_animal/bot/medbot.dm
index e4e81bb5db..7d93669c31 100644
--- a/code/modules/mob/living/simple_animal/bot/medbot.dm
+++ b/code/modules/mob/living/simple_animal/bot/medbot.dm
@@ -42,6 +42,7 @@
var/declare_crit = 1 //If active, the bot will transmit a critical patient alert to MedHUD users.
var/declare_cooldown = 0 //Prevents spam of critical patient alerts.
var/stationary_mode = 0 //If enabled, the Medibot will not move automatically.
+ var/injection_time = 30 //How long we take to inject someone
//Setting which reagents to use to treat what by default. By id.
var/treatment_brute_avoid = /datum/reagent/medicine/tricordrazine
var/treatment_brute = /datum/reagent/medicine/bicaridine
@@ -51,19 +52,25 @@
var/treatment_fire = /datum/reagent/medicine/kelotane
var/treatment_tox_avoid = /datum/reagent/medicine/tricordrazine
var/treatment_tox = /datum/reagent/medicine/charcoal
- var/treatment_tox_toxlover = /datum/reagent/toxin
+ var/treatment_tox_toxlover = /datum/reagent/toxin //Injects toxins into people that heal via toxins
var/treatment_virus_avoid = null
var/treatment_virus = /datum/reagent/medicine/spaceacillin
var/treat_virus = 1 //If on, the bot will attempt to treat viral infections, curing them if possible.
var/shut_up = 0 //self explanatory :)
+ var/upgrades = 0
+ var/upgraded_dispenser_1 //Do we have the nicer chemicals? - replaces dex with salbutamol
+ var/upgraded_dispenser_2 //Do we have the nicer chemicals? - replaces kep with oxandrolone
+ var/upgraded_dispenser_3 //Do we have the nicer chemicals? - replaces bic with sal acid
+ var/upgraded_dispenser_4 //Do we have the nicer chemicals? - replaces charcoal/toxin with pentetic acid / pentetic jelly
+
/mob/living/simple_animal/bot/medbot/mysterious
name = "\improper Mysterious Medibot"
desc = "International Medibot of mystery."
skin = "bezerk"
- treatment_brute = /datum/reagent/medicine/tricordrazine
- treatment_fire = /datum/reagent/medicine/tricordrazine
- treatment_tox = /datum/reagent/medicine/tricordrazine
+ treatment_brute = /datum/reagent/medicine/regen_jelly
+ treatment_fire = /datum/reagent/medicine/regen_jelly
+ treatment_tox = /datum/reagent/medicine/regen_jelly
/mob/living/simple_animal/bot/medbot/derelict
name = "\improper Old Medibot"
@@ -220,7 +227,6 @@
/mob/living/simple_animal/bot/medbot/attackby(obj/item/W as obj, mob/user as mob, params)
if(istype(W, /obj/item/reagent_containers/glass))
- . = 1 //no afterattack
if(locked)
to_chat(user, "You cannot insert a beaker because the panel is locked!")
return
@@ -234,6 +240,97 @@
to_chat(user, "You insert [W].")
show_controls(user)
+ else if(istype(W, /obj/item/reagent_containers/syringe/piercing))
+ if(bot_core.allowed(user) && open && !CHECK_BITFIELD(upgrades,UPGRADE_MEDICAL_PIERERCING))
+ to_chat(user, "You replace \the [src] syringe with a diamond-tipped one!")
+ upgrades |= UPGRADE_MEDICAL_PIERERCING
+ qdel(W)
+ if(!open)
+ to_chat(user, "The [src] access pannel is not open!")
+ return
+ if(!bot_core.allowed(user))
+ to_chat(user, "The [src] access pannel locked off to you!")
+ return
+ else
+ to_chat(user, "The [src] already has a diamond-tipped syringe!")
+
+ else if(istype(W, /obj/item/hypospray/mkii))
+ if(bot_core.allowed(user) && open && !CHECK_BITFIELD(upgrades,UPGRADE_MEDICAL_HYPOSPRAY))
+ to_chat(user, "You replace \the [src] syringe base with a DeForest Medical MK.II Hypospray!")
+ upgrades |= UPGRADE_MEDICAL_HYPOSPRAY
+ injection_time = 15 //Half the time half the death!
+ window_name = "Automatic Medical Unit v2.4 ALPHA"
+ qdel(W)
+ if(!open)
+ to_chat(user, "The [src] access pannel is not open!")
+ return
+ if(!bot_core.allowed(user))
+ to_chat(user, "The [src] access pannel locked off to you!")
+ return
+ else
+ to_chat(user, "The [src] already has a DeForest Medical Hypospray base!")
+
+ else if(istype(W, /obj/item/circuitboard/machine/chem_dispenser))
+ if(bot_core.allowed(user) && open && !CHECK_BITFIELD(upgrades,UPGRADE_MEDICAL_CHEM_BOARD))
+ to_chat(user, "You add in the board upgrading \the [src] reagent banks!")
+ upgrades |= UPGRADE_MEDICAL_CHEM_BOARD
+ treatment_oxy = /datum/reagent/medicine/salbutamol //Replaces Dex with salbutamol "better" healing of o2
+ qdel(W)
+ if(!open)
+ to_chat(user, "The [src] access pannel is not open!")
+ return
+ if(!bot_core.allowed(user))
+ to_chat(user, "The [src] access pannel locked off to you!")
+ return
+ else
+ to_chat(user, "The [src] already has this upgrade!")
+
+ else if(istype(W, /obj/item/circuitboard/machine/cryo_tube))
+ if(bot_core.allowed(user) && open && !CHECK_BITFIELD(upgrades,UPGRADE_MEDICAL_CRYO_BOARD))
+ to_chat(user, "You add in the board upgrading \the [src] reagent banks!")
+ upgrades |= UPGRADE_MEDICAL_CRYO_BOARD
+ treatment_fire = /datum/reagent/medicine/oxandrolone //Replaces Kep with oxandrolone "better" healing of burns
+ qdel(W)
+ if(!open)
+ to_chat(user, "The [src] access pannel is not open!")
+ return
+ if(!bot_core.allowed(user))
+ to_chat(user, "The [src] access pannel locked off to you!")
+ return
+ else
+ to_chat(user, "The [src] already has this upgrade!")
+
+ else if(istype(W, /obj/item/circuitboard/machine/chem_master))
+ if(bot_core.allowed(user) && open && !CHECK_BITFIELD(upgrades,UPGRADE_MEDICAL_CHEM_MASTER))
+ to_chat(user, "You add in the board upgrading \the [src] reagent banks!")
+ upgrades |= UPGRADE_MEDICAL_CHEM_MASTER
+ treatment_brute = /datum/reagent/medicine/sal_acid //Replaces Bic with Sal Acid "better" healing of brute
+ qdel(W)
+ if(!open)
+ to_chat(user, "the [src] access pannel is not open!")
+ return
+ if(!bot_core.allowed(user))
+ to_chat(user, "the [src] access pannel locked off to you!")
+ return
+ else
+ to_chat(user, "the [src] already has this upgrade!")
+
+ else if(istype(W, /obj/item/circuitboard/machine/sleeper))
+ if(bot_core.allowed(user) && open && !CHECK_BITFIELD(upgrades,UPGRADE_MEDICAL_SLEEP_BOARD))
+ to_chat(user, "You add in the board upgrading \the [src] reagent banks!")
+ upgrades |= UPGRADE_MEDICAL_SLEEP_BOARD
+ treatment_tox = /datum/reagent/medicine/pen_acid //replaces charcoal with pen acid a "better" healing of toxins
+ treatment_tox_toxlover = /datum/reagent/medicine/pen_acid/pen_jelly //Injects pen jelly into people that heal via toxins
+ qdel(W)
+ if(!open)
+ to_chat(user, "The [src] access pannle is not open!")
+ return
+ if(!bot_core.allowed(user))
+ to_chat(user, "The [src] access pannel locked off to you!")
+ return
+ else
+ to_chat(user, "The [src] already has this upgrade!")
+
else
var/current_health = health
..()
@@ -249,6 +346,8 @@
audible_message("[src] buzzes oddly!")
flick("medibot_spark", src)
playsound(src, "sparks", 75, 1)
+ if(!CHECK_BITFIELD(upgrades,UPGRADE_MEDICAL_PIERERCING))
+ upgrades |= UPGRADE_MEDICAL_PIERERCING //Jabs even harder through the clothing!
if(user)
oldpatient = user
@@ -361,7 +460,7 @@
if(ishuman(C))
var/mob/living/carbon/human/H = C
- if (H.wear_suit && H.head && istype(H.wear_suit, /obj/item/clothing) && istype(H.head, /obj/item/clothing))
+ if (H.wear_suit && H.head && istype(H.wear_suit, /obj/item/clothing) && istype(H.head, /obj/item/clothing) && !CHECK_BITFIELD(upgrades,UPGRADE_MEDICAL_PIERERCING))
var/obj/item/clothing/CS = H.wear_suit
var/obj/item/clothing/CH = H.head
if (CS.clothing_flags & CH.clothing_flags & THICKMATERIAL)
@@ -418,7 +517,7 @@
else
..()
-/mob/living/simple_animal/bot/medbot/examinate(atom/A as mob|obj|turf in view())
+/mob/living/simple_animal/bot/medbot/examinate(atom/A as mob|obj|turf in fov_view())
..()
if(!is_blind(src))
chemscan(src, A)
@@ -504,7 +603,7 @@
"[src] is trying to inject you!")
var/failed = FALSE
- if(do_mob(src, patient, 30)) //Is C == patient? This is so confusing
+ if(do_mob(src, patient, injection_time)) //Is C == patient? This is so confusing
if((get_dist(src, patient) <= 1) && (on) && assess_patient(patient))
if(reagent_id == "internal_beaker")
if(use_beaker && reagent_glass && reagent_glass.reagents.total_volume)
diff --git a/code/modules/mob/living/simple_animal/constructs.dm b/code/modules/mob/living/simple_animal/constructs.dm
index 674cc722d8..354bc9ed0f 100644
--- a/code/modules/mob/living/simple_animal/constructs.dm
+++ b/code/modules/mob/living/simple_animal/constructs.dm
@@ -5,9 +5,12 @@
gender = NEUTER
mob_biotypes = NONE
speak_emote = list("hisses")
- response_help = "thinks better of touching"
- response_disarm = "flails at"
- response_harm = "punches"
+ response_help_continuous = "thinks better of touching"
+ response_help_simple = "think better of touching"
+ response_disarm_continuous = "flails at"
+ response_disarm_simple = "flail at"
+ response_harm_continuous = "punches"
+ response_harm_simple = "punch"
threat = 1
speak_chance = 1
icon = 'icons/mob/mob.dmi'
@@ -122,12 +125,14 @@
threat = 3
maxHealth = 150
health = 150
- response_harm = "harmlessly punches"
+ response_harm_continuous = "harmlessly punches"
+ response_harm_simple = "harmlessly punch"
harm_intent_damage = 0
obj_damage = 90
melee_damage_lower = 25
melee_damage_upper = 25
- attacktext = "smashes their armored gauntlet into"
+ attack_verb_continuous = "smashes their armored gauntlet into"
+ attack_verb_simple = "smash your armored gauntlet into"
speed = 2.5
environment_smash = ENVIRONMENT_SMASH_WALLS
attack_sound = 'sound/weapons/punch3.ogg'
@@ -188,7 +193,8 @@
melee_damage_lower = 20
melee_damage_upper = 20
retreat_distance = 2 //AI wraiths will move in and out of combat
- attacktext = "slashes"
+ attack_verb_continuous = "slashes"
+ attack_verb_simple = "slash"
attack_sound = 'sound/weapons/bladeslice.ogg'
construct_spells = list(/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/shift)
runetype = /datum/action/innate/cult/create_rune/tele
@@ -232,14 +238,16 @@
icon_living = "artificer"
maxHealth = 50
health = 50
- response_harm = "viciously beats"
+ response_harm_continuous = "viciously beats"
+ response_harm_simple = "viciously beat"
harm_intent_damage = 5
obj_damage = 60
melee_damage_lower = 5
melee_damage_upper = 5
retreat_distance = 10
minimum_distance = 10 //AI artificers will flee like fuck
- attacktext = "rams"
+ attack_verb_continuous = "rams"
+ attack_verb_simple = "ram"
environment_smash = ENVIRONMENT_SMASH_WALLS
attack_sound = 'sound/weapons/punch2.ogg'
construct_spells = list(/obj/effect/proc_holder/spell/aoe_turf/conjure/wall,
@@ -319,7 +327,8 @@
sight = SEE_MOBS
melee_damage_lower = 15
melee_damage_upper = 20
- attacktext = "butchers"
+ attack_verb_continuous = "butchers"
+ attack_verb_simple = "butcher"
attack_sound = 'sound/weapons/bladeslice.ogg'
construct_spells = list(/obj/effect/proc_holder/spell/aoe_turf/area_conversion,
/obj/effect/proc_holder/spell/targeted/forcewall/cult)
diff --git a/code/modules/mob/living/simple_animal/friendly/bumbles.dm b/code/modules/mob/living/simple_animal/friendly/bumbles.dm
index 1a78a47031..2d236a4327 100644
--- a/code/modules/mob/living/simple_animal/friendly/bumbles.dm
+++ b/code/modules/mob/living/simple_animal/friendly/bumbles.dm
@@ -5,14 +5,18 @@
icon_living = "bumbles"
icon_dead = "bumbles_dead"
turns_per_move = 1
- response_help = "pets"
- response_disarm = "brushes aside"
- response_harm = "squashes"
+ response_help_continuous = "pets"
+ response_help_simple = "pet"
+ response_disarm_continuous = "brushes aside"
+ response_help_simple = "brush aside"
+ response_harm_continuous = "squashes"
+ response_harm_simple = "squash"
speak_emote = list("buzzes")
maxHealth = 100
health = 100
harm_intent_damage = 1
- friendly = "bzzs"
+ friendly_verb_continuous = "bzzs"
+ friendly_verb_simple = "bzz"
density = FALSE
movement_type = FLYING
pass_flags = PASSTABLE | PASSGRILLE | PASSMOB
diff --git a/code/modules/mob/living/simple_animal/friendly/butterfly.dm b/code/modules/mob/living/simple_animal/friendly/butterfly.dm
index 80fba5a9a4..bf4f45e283 100644
--- a/code/modules/mob/living/simple_animal/friendly/butterfly.dm
+++ b/code/modules/mob/living/simple_animal/friendly/butterfly.dm
@@ -5,14 +5,18 @@
icon_living = "butterfly"
icon_dead = "butterfly_dead"
turns_per_move = 1
- response_help = "shoos"
- response_disarm = "brushes aside"
- response_harm = "squashes"
+ response_help_continuous = "shoos"
+ response_help_simple = "shoo"
+ response_disarm_continuous = "brushes aside"
+ response_disarm_simple = "brush aside"
+ response_harm_continuous = "squashes"
+ response_harm_simple = "squash"
speak_emote = list("flutters")
maxHealth = 2
health = 2
harm_intent_damage = 1
- friendly = "nudges"
+ friendly_verb_continuous = "nudges"
+ friendly_verb_simple = "nudge"
density = FALSE
movement_type = FLYING
pass_flags = PASSTABLE | PASSGRILLE | PASSMOB
diff --git a/code/modules/mob/living/simple_animal/friendly/cat.dm b/code/modules/mob/living/simple_animal/friendly/cat.dm
index 7d41068020..5f7ff198e2 100644
--- a/code/modules/mob/living/simple_animal/friendly/cat.dm
+++ b/code/modules/mob/living/simple_animal/friendly/cat.dm
@@ -24,15 +24,18 @@
animal_species = /mob/living/simple_animal/pet/cat
childtype = list(/mob/living/simple_animal/pet/cat/kitten)
butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab = 2, /obj/item/organ/ears/cat = 1, /obj/item/organ/tail/cat = 1)
- response_help = "pets"
- response_disarm = "gently pushes aside"
- response_harm = "kicks"
+ response_help_continuous = "pets"
+ response_help_simple = "pet"
+ response_disarm_continuous = "gently pushes aside"
+ response_disarm_simple = "gently push aside"
+ response_harm_continuous = "kicks"
+ response_harm_simple = "kick"
var/turns_since_scan = 0
var/mob/living/simple_animal/mouse/movement_target
gold_core_spawnable = FRIENDLY_SPAWN
collar_type = "cat"
var/held_icon = "cat2"
- do_footstep = TRUE
+ footstep_type = FOOTSTEP_MOB_CLAW
/mob/living/simple_animal/pet/cat/Initialize()
. = ..()
@@ -245,7 +248,8 @@
harm_intent_damage = 10
butcher_results = list(/obj/item/organ/brain = 1, /obj/item/organ/heart = 1, /obj/item/reagent_containers/food/snacks/cakeslice/birthday = 3, \
/obj/item/reagent_containers/food/snacks/meat/slab = 2)
- response_harm = "takes a bite out of"
+ response_harm_continuous = "takes a bite out of"
+ response_harm_simple = "take a bite out of"
attacked_sound = 'sound/items/eatfood.ogg'
deathmessage = "loses its false life and collapses!"
death_sound = "bodyfall"
@@ -306,7 +310,6 @@
if (pseudo_death == TRUE) //secret cat chem
icon_state = "custom_cat_dead"
Stun(1000)
- friendly = "deads at"
return
else
..()
diff --git a/code/modules/mob/living/simple_animal/friendly/cockroach.dm b/code/modules/mob/living/simple_animal/friendly/cockroach.dm
index 95aa86aaab..9a34f2c176 100644
--- a/code/modules/mob/living/simple_animal/friendly/cockroach.dm
+++ b/code/modules/mob/living/simple_animal/friendly/cockroach.dm
@@ -14,9 +14,12 @@
pass_flags = PASSTABLE | PASSGRILLE | PASSMOB
mob_size = MOB_SIZE_TINY
mob_biotypes = MOB_ORGANIC|MOB_BUG
- response_help = "pokes"
- response_disarm = "shoos"
- response_harm = "splats"
+ response_help_continuous = "pokes"
+ response_help_simple = "poke"
+ response_disarm_continuous = "shoos"
+ response_disarm_simple = "shoo"
+ response_harm_continuous = "splats"
+ response_harm_simple = "splat"
speak_emote = list("chitters")
density = FALSE
ventcrawler = VENTCRAWLER_ALWAYS
diff --git a/code/modules/mob/living/simple_animal/friendly/crab.dm b/code/modules/mob/living/simple_animal/friendly/crab.dm
index cce5edc513..d86362c974 100644
--- a/code/modules/mob/living/simple_animal/friendly/crab.dm
+++ b/code/modules/mob/living/simple_animal/friendly/crab.dm
@@ -12,11 +12,15 @@
speak_chance = 1
turns_per_move = 5
butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/rawcrab = 4)
- response_help = "pets"
- response_disarm = "gently pushes aside"
- response_harm = "stomps"
+ response_help_continuous = "pets"
+ response_help_simple = "pet"
+ response_disarm_continuous = "gently pushes aside"
+ response_disarm_simple = "gently push aside"
+ response_harm_continuous = "stomps"
+ response_harm_continuous = "stomp"
stop_automated_movement = 1
- friendly = "pinches"
+ friendly_verb_continuous = "pinches"
+ friendly_verb_simple = "pinch"
ventcrawler = VENTCRAWLER_ALWAYS
var/obj/item/inventory_head
var/obj/item/inventory_mask
@@ -41,9 +45,6 @@
real_name = "Coffee"
desc = "It's Coffee, the other pet!"
gender = FEMALE
- response_help = "pets"
- response_disarm = "gently pushes aside"
- response_harm = "stomps"
gold_core_spawnable = NO_SPAWN
/mob/living/simple_animal/crab/evil
@@ -53,9 +54,10 @@
icon_state = "evilcrab"
icon_living = "evilcrab"
icon_dead = "evilcrab_dead"
- response_help = "pokes"
- response_disarm = "shoves"
- response_harm = "stomps"
+ response_help_continuous = "pokes"
+ response_help_simple = "poke"
+ response_disarm_continuous = "shoves"
+ response_disarm_simple = "shove"
gold_core_spawnable = HOSTILE_SPAWN
/mob/living/simple_animal/crab/kreb
@@ -65,9 +67,6 @@
icon_state = "kreb"
icon_living = "kreb"
icon_dead = "kreb_dead"
- response_help = "pets"
- response_disarm = "gently pushes aside"
- response_harm = "stomps"
gold_core_spawnable = NO_SPAWN
/mob/living/simple_animal/crab/evil/kreb
diff --git a/code/modules/mob/living/simple_animal/friendly/dog.dm b/code/modules/mob/living/simple_animal/friendly/dog.dm
index 485cece8b7..57a4ecc5c9 100644
--- a/code/modules/mob/living/simple_animal/friendly/dog.dm
+++ b/code/modules/mob/living/simple_animal/friendly/dog.dm
@@ -2,9 +2,12 @@
/mob/living/simple_animal/pet/dog
mob_biotypes = MOB_ORGANIC|MOB_BEAST
- response_help = "pets"
- response_disarm = "bops"
- response_harm = "kicks"
+ response_help_continuous = "pets"
+ response_help_simple = "pet"
+ response_disarm_continuous = "bops"
+ response_disarm_simple = "bop"
+ response_harm_continuous = "kicks"
+ response_harm_simple = "kick"
speak = list("YAP", "Woof!", "Bark!", "AUUUUUU")
speak_emote = list("barks", "woofs")
emote_hear = list("barks!", "woofs!", "yaps.","pants.")
@@ -15,7 +18,7 @@
turns_per_move = 10
var/held_icon = "corgi"
- do_footstep = TRUE
+ footstep_type = FOOTSTEP_MOB_CLAW
/mob/living/simple_animal/pet/dog/ComponentInitialize()
. = ..()
@@ -332,9 +335,6 @@
desc = "It's the HoP's beloved corgi."
var/turns_since_scan = 0
var/obj/movement_target
- response_help = "pets"
- response_disarm = "bops"
- response_harm = "kicks"
gold_core_spawnable = NO_SPAWN
unique_pet = TRUE
var/age = 0
@@ -604,9 +604,6 @@
icon_state = "lisa"
icon_living = "lisa"
icon_dead = "lisa_dead"
- response_help = "pets"
- response_disarm = "bops"
- response_harm = "kicks"
var/turns_since_scan = 0
var/puppies = 0
held_icon = "lisa"
diff --git a/code/modules/mob/living/simple_animal/friendly/farm_animals.dm b/code/modules/mob/living/simple_animal/friendly/farm_animals.dm
index e67e649ac6..59fa94a1fa 100644
--- a/code/modules/mob/living/simple_animal/friendly/farm_animals.dm
+++ b/code/modules/mob/living/simple_animal/friendly/farm_animals.dm
@@ -13,13 +13,17 @@
turns_per_move = 5
see_in_dark = 6
butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab = 4)
- response_help = "pets"
- response_disarm = "gently pushes aside"
- response_harm = "kicks"
+ response_help_continuous = "pets"
+ response_help_simple = "pet"
+ response_disarm_continuous = "gently pushes aside"
+ response_disarm_simple = "gently push aside"
+ response_harm_continuous = "kicks"
+ response_harm_simple = "kick"
faction = list("neutral")
mob_biotypes = MOB_ORGANIC|MOB_BEAST
attack_same = 1
- attacktext = "kicks"
+ attack_verb_continuous = "kicks"
+ attack_verb_simple = "kick"
attack_sound = 'sound/weapons/punch1.ogg'
health = 40
maxHealth = 40
@@ -30,7 +34,7 @@
blood_volume = BLOOD_VOLUME_NORMAL
var/obj/item/udder/udder = null
- do_footstep = TRUE
+ footstep_type = FOOTSTEP_MOB_SHOE
/mob/living/simple_animal/hostile/retaliate/goat/Initialize()
udder = new()
@@ -121,10 +125,14 @@
turns_per_move = 5
see_in_dark = 6
butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab = 6)
- response_help = "pets"
- response_disarm = "gently pushes aside"
- response_harm = "kicks"
- attacktext = "kicks"
+ response_help_continuous = "pets"
+ response_help_simple = "pet"
+ response_disarm_continuous = "gently pushes aside"
+ response_disarm_simple = "gently push aside"
+ response_harm_continuous = "kicks"
+ response_harm_simple = "kick"
+ attack_verb_continuous = "kicks"
+ attack_verb_simple = "kick"
attack_sound = 'sound/weapons/punch1.ogg'
health = 50
maxHealth = 50
@@ -132,7 +140,7 @@
gold_core_spawnable = FRIENDLY_SPAWN
blood_volume = BLOOD_VOLUME_NORMAL
- do_footstep = TRUE
+ footstep_type = FOOTSTEP_MOB_SHOE
/mob/living/simple_animal/cow/Initialize()
udder = new()
@@ -198,10 +206,14 @@
speak_chance = 2
turns_per_move = 2
butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab/chicken = 1)
- response_help = "pets"
- response_disarm = "gently pushes aside"
- response_harm = "kicks"
- attacktext = "kicks"
+ response_help_continuous = "pets"
+ response_help_simple = "pet"
+ response_disarm_continuous = "gently pushes aside"
+ response_disarm_simple = "gently push aside"
+ response_harm_continuous = "kicks"
+ response_harm_simple = "kick"
+ attack_verb_continuous = "kicks"
+ attack_verb_simple = "kick"
health = 3
maxHealth = 3
ventcrawler = VENTCRAWLER_ALWAYS
@@ -210,7 +222,7 @@
mob_size = MOB_SIZE_TINY
gold_core_spawnable = FRIENDLY_SPAWN
- do_footstep = TRUE
+ footstep_type = FOOTSTEP_MOB_CLAW
/mob/living/simple_animal/chick/Initialize()
. = ..()
@@ -249,10 +261,14 @@
butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab/chicken = 2)
var/egg_type = /obj/item/reagent_containers/food/snacks/egg
var/food_type = /obj/item/reagent_containers/food/snacks/grown/wheat
- response_help = "pets"
- response_disarm = "gently pushes aside"
- response_harm = "kicks"
- attacktext = "kicks"
+ response_help_continuous = "pets"
+ response_help_simple = "pet"
+ response_disarm_continuous = "gently pushes aside"
+ response_disarm_simple = "gently push aside"
+ response_harm_continuous = "kicks"
+ response_harm_simple = "kick"
+ attack_verb_continuous = "kicks"
+ attack_verb_simple = "kick"
health = 15
maxHealth = 15
ventcrawler = VENTCRAWLER_ALWAYS
@@ -268,7 +284,7 @@
gold_core_spawnable = FRIENDLY_SPAWN
var/static/chicken_count = 0
- do_footstep = TRUE
+ footstep_type = FOOTSTEP_MOB_CLAW
/mob/living/simple_animal/chicken/Initialize()
. = ..()
@@ -342,10 +358,14 @@
butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab = 3)
var/egg_type = /obj/item/reagent_containers/food/snacks/egg/kiwiEgg
var/food_type = /obj/item/reagent_containers/food/snacks/grown/wheat
- response_help = "pets"
- response_disarm = "gently pushes aside"
- response_harm = "kicks"
- attacktext = "kicks"
+ response_help_continuous = "pets"
+ response_help_simple = "pet"
+ response_disarm_continuous = "gently pushes aside"
+ response_disarm_simple = "gently push aside"
+ response_harm_continuous = "kicks"
+ response_harm_simple = "kick"
+ attack_verb_continuous = "kicks"
+ attack_verb_simple = "kick"
health = 25
maxHealth = 25
ventcrawler = VENTCRAWLER_ALWAYS
@@ -358,6 +378,8 @@
gold_core_spawnable = FRIENDLY_SPAWN
var/static/kiwi_count = 0
+ footstep_type = FOOTSTEP_MOB_CLAW
+
/mob/living/simple_animal/kiwi/Destroy()
--kiwi_count
return ..()
@@ -418,10 +440,14 @@
speak_chance = 2
turns_per_move = 2
butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab = 2)
- response_help = "pets"
- response_disarm = "gently pushes aside"
- response_harm = "kicks"
- attacktext = "kicks"
+ response_help_continuous = "pets"
+ response_help_simple = "pet"
+ response_disarm_continuous = "gently pushes aside"
+ response_disarm_simple = "gently push aside"
+ response_harm_continuous = "kicks"
+ response_harm_simple = "kick"
+ attack_verb_continuous = "kicks"
+ attack_verb_simple = "kick"
health = 10
maxHealth = 10
ventcrawler = VENTCRAWLER_ALWAYS
@@ -430,6 +456,8 @@
mob_size = MOB_SIZE_TINY
gold_core_spawnable = FRIENDLY_SPAWN
+ footstep_type = FOOTSTEP_MOB_CLAW
+
/mob/living/simple_animal/babyKiwi/Initialize()
. = ..()
pixel_x = rand(-6, 6)
diff --git a/code/modules/mob/living/simple_animal/friendly/fox.dm b/code/modules/mob/living/simple_animal/friendly/fox.dm
index 95b082b733..4e4fd7ccfc 100644
--- a/code/modules/mob/living/simple_animal/friendly/fox.dm
+++ b/code/modules/mob/living/simple_animal/friendly/fox.dm
@@ -14,11 +14,14 @@
turns_per_move = 5
see_in_dark = 6
butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab = 3)
- response_help = "pets"
- response_disarm = "gently pushes aside"
- response_harm = "kicks"
+ response_help_continuous = "pets"
+ response_help_simple = "pet"
+ response_disarm_continuous = "gently pushes aside"
+ response_disarm_simple = "gently push aside"
+ response_harm_continuous = "kicks"
+ response_harm_simple = "kick"
gold_core_spawnable = FRIENDLY_SPAWN
- do_footstep = TRUE
+ footstep_type = FOOTSTEP_MOB_CLAW
/mob/living/simple_animal/pet/fox/ComponentInitialize()
. = ..()
diff --git a/code/modules/mob/living/simple_animal/friendly/gondola.dm b/code/modules/mob/living/simple_animal/friendly/gondola.dm
index 04d53e7d05..0cfea3548b 100644
--- a/code/modules/mob/living/simple_animal/friendly/gondola.dm
+++ b/code/modules/mob/living/simple_animal/friendly/gondola.dm
@@ -9,9 +9,12 @@
name = "gondola"
real_name = "gondola"
desc = "Gondola is the silent walker. Having no hands he embodies the Taoist principle of wu-wei (non-action) while his smiling facial expression shows his utter and complete acceptance of the world as it is. Its hide is extremely valuable."
- response_help = "pets"
- response_disarm = "bops"
- response_harm = "kicks"
+ response_help_continuous = "pets"
+ response_help_simple = "pet"
+ response_disarm_continuous = "bops"
+ response_disarm_simple = "bop"
+ response_harm_continuous = "kicks"
+ response_harm_simple = "kick"
faction = list("gondola")
turns_per_move = 10
icon = 'icons/mob/gondolas.dmi'
diff --git a/code/modules/mob/living/simple_animal/friendly/lizard.dm b/code/modules/mob/living/simple_animal/friendly/lizard.dm
index 9ae46f29e5..b9ff99b677 100644
--- a/code/modules/mob/living/simple_animal/friendly/lizard.dm
+++ b/code/modules/mob/living/simple_animal/friendly/lizard.dm
@@ -8,12 +8,16 @@
health = 5
maxHealth = 5
faction = list("Lizard")
- attacktext = "bites"
+ attack_verb_continuous = "bites"
+ attack_verb_simple = "bite"
melee_damage_lower = 1
melee_damage_upper = 2
- response_help = "pets"
- response_disarm = "shoos"
- response_harm = "stomps on"
+ response_help_continuous = "pets"
+ response_help_simple = "pet"
+ response_disarm_continuous = "shoos"
+ response_disarm_simple = "shoo"
+ response_harm_continuous = "stomps on"
+ response_harm_simple = "stomp on"
ventcrawler = VENTCRAWLER_ALWAYS
density = FALSE
pass_flags = PASSTABLE | PASSMOB
diff --git a/code/modules/mob/living/simple_animal/friendly/mouse.dm b/code/modules/mob/living/simple_animal/friendly/mouse.dm
index 7f83bb9f9b..50d1e44d2a 100644
--- a/code/modules/mob/living/simple_animal/friendly/mouse.dm
+++ b/code/modules/mob/living/simple_animal/friendly/mouse.dm
@@ -15,9 +15,12 @@
maxHealth = 5
health = 5
butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab = 1)
- response_help = "pets"
- response_disarm = "gently pushes aside"
- response_harm = "splats"
+ response_help_continuous = "pets"
+ response_help_simple = "pet"
+ response_disarm_continuous = "gently pushes aside"
+ response_disarm_simple = "gently push aside"
+ response_harm_continuous = "splats"
+ response_harm_simple = "splat"
density = FALSE
ventcrawler = VENTCRAWLER_ALWAYS
pass_flags = PASSTABLE | PASSGRILLE | PASSMOB
@@ -103,9 +106,6 @@ GLOBAL_VAR(tom_existed)
/mob/living/simple_animal/mouse/brown/Tom
name = "Tom"
desc = "Jerry the cat is not amused."
- response_help = "pets"
- response_disarm = "gently pushes aside"
- response_harm = "splats"
gold_core_spawnable = NO_SPAWN
/mob/living/simple_animal/mouse/brown/Tom/Initialize()
diff --git a/code/modules/mob/living/simple_animal/friendly/panda.dm b/code/modules/mob/living/simple_animal/friendly/panda.dm
index a7b6143ef5..7e523fea83 100644
--- a/code/modules/mob/living/simple_animal/friendly/panda.dm
+++ b/code/modules/mob/living/simple_animal/friendly/panda.dm
@@ -13,8 +13,11 @@
turns_per_move = 5
see_in_dark = 6
butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab = 3)
- response_help = "pets"
- response_disarm = "gently pushes aside"
- response_harm = "kicks"
+ response_help_continuous = "pets"
+ response_help_simple = "pet"
+ response_disarm_continuous = "gently pushes aside"
+ response_disarm_simple = "gently push aside"
+ response_harm_continuous = "kicks"
+ response_harm_simple = "kick"
gold_core_spawnable = FRIENDLY_SPAWN
- do_footstep = TRUE
+ footstep_type = FOOTSTEP_MOB_CLAW
diff --git a/code/modules/mob/living/simple_animal/friendly/penguin.dm b/code/modules/mob/living/simple_animal/friendly/penguin.dm
index 9835840dbf..f92f4184b7 100644
--- a/code/modules/mob/living/simple_animal/friendly/penguin.dm
+++ b/code/modules/mob/living/simple_animal/friendly/penguin.dm
@@ -1,9 +1,12 @@
//Penguins
/mob/living/simple_animal/pet/penguin
- response_help = "pets"
- response_disarm = "bops"
- response_harm = "kicks"
+ response_help_continuous = "pets"
+ response_help_simple = "pet"
+ response_disarm_continuous = "bops"
+ response_disarm_simple = "bop"
+ response_harm_continuous = "kicks"
+ response_harm_simple = "kick"
speak = list("Gah Gah!", "NOOT NOOT!", "NOOT!", "Noot", "noot", "Prah!", "Grah!")
speak_emote = list("squawks", "gakkers")
emote_hear = list("squawk!", "gakkers!", "noots.","NOOTS!")
@@ -15,7 +18,7 @@
turns_per_move = 10
icon = 'icons/mob/penguins.dmi'
- do_footstep = TRUE
+ footstep_type = FOOTSTEP_MOB_BAREFOOT
/mob/living/simple_animal/pet/penguin/emperor
name = "Emperor penguin"
diff --git a/code/modules/mob/living/simple_animal/friendly/sloth.dm b/code/modules/mob/living/simple_animal/friendly/sloth.dm
index 28063d6e52..83fe42a7a4 100644
--- a/code/modules/mob/living/simple_animal/friendly/sloth.dm
+++ b/code/modules/mob/living/simple_animal/friendly/sloth.dm
@@ -11,9 +11,12 @@
speak_chance = 1
turns_per_move = 5
butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab = 3)
- response_help = "pets"
- response_disarm = "gently pushes aside"
- response_harm = "kicks"
+ response_help_continuous = "pets"
+ response_help_simple = "pet"
+ response_disarm_continuous = "gently pushes aside"
+ response_disarm_simple = "gently push aside"
+ response_harm_continuous = "kicks"
+ response_harm_simple = "kick"
mob_biotypes = MOB_ORGANIC|MOB_BEAST
gold_core_spawnable = FRIENDLY_SPAWN
melee_damage_lower = 18
@@ -22,7 +25,7 @@
maxHealth = 50
speed = 10
glide_size = 2
- do_footstep = TRUE
+ footstep_type = FOOTSTEP_MOB_CLAW
/mob/living/simple_animal/pet/fox/ComponentInitialize()
. = ..()
diff --git a/code/modules/mob/living/simple_animal/friendly/snake.dm b/code/modules/mob/living/simple_animal/friendly/snake.dm
index 7f75888649..4d20b927a6 100644
--- a/code/modules/mob/living/simple_animal/friendly/snake.dm
+++ b/code/modules/mob/living/simple_animal/friendly/snake.dm
@@ -19,12 +19,16 @@
speak_emote = list("hisses")
health = 20
maxHealth = 20
- attacktext = "bites"
+ attack_verb_continuous = "bites"
+ attack_verb_simple = "bite"
melee_damage_lower = 5
melee_damage_upper = 6
- response_help = "pets"
- response_disarm = "shoos"
- response_harm = "steps on"
+ response_help_continuous = "pets"
+ response_help_simple = "pet"
+ response_disarm_continuous = "shoos"
+ response_disarm_simple = "shoo"
+ response_harm_continuous = "steps on"
+ response_harm_simple = "step on"
faction = list("hostile")
ventcrawler = VENTCRAWLER_ALWAYS
density = FALSE
diff --git a/code/modules/mob/living/simple_animal/guardian/guardian.dm b/code/modules/mob/living/simple_animal/guardian/guardian.dm
index d2794a3a78..9d94992747 100644
--- a/code/modules/mob/living/simple_animal/guardian/guardian.dm
+++ b/code/modules/mob/living/simple_animal/guardian/guardian.dm
@@ -13,9 +13,12 @@ GLOBAL_LIST_EMPTY(parasites) //all currently existing/living guardians
gender = NEUTER
mob_biotypes = NONE
bubble_icon = "guardian"
- response_help = "passes through"
- response_disarm = "flails at"
- response_harm = "punches"
+ response_help_continuous = "passes through"
+ response_help_simple = "pass through"
+ response_disarm_continuous = "flails at"
+ response_disarm_simple = "flail at"
+ response_harm_continuous = "punches"
+ response_harm_simple = "punch"
icon = 'icons/mob/guardian.dmi'
icon_state = "magicbase"
icon_living = "magicbase"
@@ -29,7 +32,8 @@ GLOBAL_LIST_EMPTY(parasites) //all currently existing/living guardians
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
minbodytemp = 0
maxbodytemp = INFINITY
- attacktext = "punches"
+ attack_verb_continuous = "punches"
+ attack_verb_simple = "punch"
maxHealth = INFINITY //The spirit itself is invincible
health = INFINITY
healable = FALSE //don't brusepack the guardian
@@ -109,7 +113,8 @@ GLOBAL_LIST_EMPTY(parasites) //all currently existing/living guardians
icon_dead = "holocarp"
speak_emote = list("gnashes")
desc = "A mysterious fish that stands by its charge, ever vigilant."
- attacktext = "bites"
+ attack_verb_continuous = "bites"
+ attack_verb_simple = "bite"
attack_sound = 'sound/weapons/bite.ogg'
recolorentiresprite = TRUE
if(!recolorentiresprite) //we want this to proc before stand logs in, so the overlay isnt gone for some reason
diff --git a/code/modules/mob/living/simple_animal/guardian/types/assassin.dm b/code/modules/mob/living/simple_animal/guardian/types/assassin.dm
index e507a4c831..e82d6cd16a 100644
--- a/code/modules/mob/living/simple_animal/guardian/types/assassin.dm
+++ b/code/modules/mob/living/simple_animal/guardian/types/assassin.dm
@@ -1,6 +1,7 @@
//Assassin
/mob/living/simple_animal/hostile/guardian/assassin
- attacktext = "slashes"
+ attack_verb_continuous = "slashes"
+ attack_verb_simple = "slash"
attack_sound = 'sound/weapons/bladeslice.ogg'
damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 1, CLONE = 1, STAMINA = 0, OXY = 1)
playstyle_string = "As an assassin type you do medium damage and have no damage resistance, but can enter stealth, massively increasing the damage of your next attack and causing it to ignore armor. Stealth is broken when you attack or take damage."
diff --git a/code/modules/mob/living/simple_animal/guardian/types/fire.dm b/code/modules/mob/living/simple_animal/guardian/types/fire.dm
index 718bfd71af..97003a53e2 100644
--- a/code/modules/mob/living/simple_animal/guardian/types/fire.dm
+++ b/code/modules/mob/living/simple_animal/guardian/types/fire.dm
@@ -4,7 +4,8 @@
melee_damage_lower = 10
melee_damage_upper = 10
attack_sound = 'sound/items/welder.ogg'
- attacktext = "ignites"
+ attack_verb_continuous = "ignites"
+ attack_verb_simple = "ignite"
melee_damage_type = BURN
damage_coeff = list(BRUTE = 0.7, BURN = 0.1, TOX = 0.7, CLONE = 0.7, STAMINA = 0, OXY = 0.7)
playstyle_string = "As a chaos type, you take 30% damage reduction to all but burn, which you are almost immune to. You will ignite any enemy you bump into. in addition, your melee attacks will cause human targets to see everyone as you."
diff --git a/code/modules/mob/living/simple_animal/guardian/types/lightning.dm b/code/modules/mob/living/simple_animal/guardian/types/lightning.dm
index 7b7651822a..a1552f6648 100644
--- a/code/modules/mob/living/simple_animal/guardian/types/lightning.dm
+++ b/code/modules/mob/living/simple_animal/guardian/types/lightning.dm
@@ -6,7 +6,8 @@
/mob/living/simple_animal/hostile/guardian/beam
melee_damage_lower = 10
melee_damage_upper = 10
- attacktext = "shocks"
+ attack_verb_continuous = "shocks"
+ attack_verb_simple = "shock"
melee_damage_type = BURN
attack_sound = 'sound/machines/defib_zap.ogg'
damage_coeff = list(BRUTE = 0.7, BURN = 0.7, TOX = 0.7, CLONE = 0.7, STAMINA = 0, OXY = 0.7)
diff --git a/code/modules/mob/living/simple_animal/guardian/types/ranged.dm b/code/modules/mob/living/simple_animal/guardian/types/ranged.dm
index 539ee9081b..1746936ba3 100644
--- a/code/modules/mob/living/simple_animal/guardian/types/ranged.dm
+++ b/code/modules/mob/living/simple_animal/guardian/types/ranged.dm
@@ -8,7 +8,8 @@
/mob/living/simple_animal/hostile/guardian/ranged
a_intent = INTENT_HELP
- friendly = "quietly assesses"
+ friendly_verb_continuous = "quietly assesses"
+ friendly_verb_simple = "quietly assess"
melee_damage_lower = 10
melee_damage_upper = 10
damage_coeff = list(BRUTE = 0.9, BURN = 0.9, TOX = 0.9, CLONE = 0.9, STAMINA = 0, OXY = 0.9)
diff --git a/code/modules/mob/living/simple_animal/guardian/types/support.dm b/code/modules/mob/living/simple_animal/guardian/types/support.dm
index 7b519e1ca1..21460b5c6b 100644
--- a/code/modules/mob/living/simple_animal/guardian/types/support.dm
+++ b/code/modules/mob/living/simple_animal/guardian/types/support.dm
@@ -1,7 +1,8 @@
//Healer
/mob/living/simple_animal/hostile/guardian/healer
a_intent = INTENT_HARM
- friendly = "heals"
+ friendly_verb_continuous = "heals"
+ friendly_verb_simple = "heal"
damage_coeff = list(BRUTE = 0.7, BURN = 0.7, TOX = 0.7, CLONE = 0.7, STAMINA = 0, OXY = 0.7)
playstyle_string = "As a support type, you have 30% damage reduction and may toggle your basic attacks to a healing mode. In addition, Alt-Clicking on an adjacent object or mob will warp them to your bluespace beacon after a short delay."
magic_fluff_string = "..And draw the CMO, a potent force of life... and death."
diff --git a/code/modules/mob/living/simple_animal/hostile/alien.dm b/code/modules/mob/living/simple_animal/hostile/alien.dm
index 2045e194d2..7120ab6d0a 100644
--- a/code/modules/mob/living/simple_animal/hostile/alien.dm
+++ b/code/modules/mob/living/simple_animal/hostile/alien.dm
@@ -8,9 +8,12 @@
icon_gib = "syndicate_gib"
gender = FEMALE
threat = 1
- response_help = "pokes"
- response_disarm = "shoves"
- response_harm = "hits"
+ response_help_continuous = "pokes"
+ response_help_simple = "poke"
+ response_disarm_continuous = "shoves"
+ response_disarm_simple = "shove"
+ response_harm_continuous = "hits"
+ response_harm_simple = "hit"
speed = 0
butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab/xeno = 4,
/obj/item/stack/sheet/animalhide/xeno = 1)
@@ -20,7 +23,8 @@
obj_damage = 60
melee_damage_lower = 25
melee_damage_upper = 25
- attacktext = "slashes"
+ attack_verb_continuous = "slashes"
+ attack_verb_simple = "slash"
speak_emote = list("hisses")
bubble_icon = "alien"
a_intent = INTENT_HARM
@@ -37,7 +41,9 @@
death_sound = 'sound/voice/hiss6.ogg'
deathmessage = "lets out a waning guttural screech, green blood bubbling from its maw..."
- do_footstep = TRUE
+/mob/living/simple_animal/hostile/alien/Initialize()
+ . = ..()
+ AddComponent(/datum/component/footstep, FOOTSTEP_MOB_CLAW)
/mob/living/simple_animal/hostile/alien/drone
name = "alien drone"
@@ -80,6 +86,7 @@
icon_state = "alienq"
icon_living = "alienq"
icon_dead = "alienq_dead"
+ pixel_x = -16
threat = 8
health = 250
maxHealth = 250
@@ -162,7 +169,8 @@
melee_damage_upper = 0
threat = -1
a_intent = INTENT_HELP
- friendly = "caresses"
+ friendly_verb_continuous = "caresses"
+ friendly_verb_simple = "caress"
obj_damage = 0
environment_smash = ENVIRONMENT_SMASH_NONE
gold_core_spawnable = HOSTILE_SPAWN
diff --git a/code/modules/mob/living/simple_animal/hostile/banana_spider.dm b/code/modules/mob/living/simple_animal/hostile/banana_spider.dm
index f3ce343bfd..259c0bc721 100644
--- a/code/modules/mob/living/simple_animal/hostile/banana_spider.dm
+++ b/code/modules/mob/living/simple_animal/hostile/banana_spider.dm
@@ -13,14 +13,16 @@
maxbodytemp = INFINITY
pass_flags = PASSTABLE | PASSGRILLE | PASSMOB
mob_size = MOB_SIZE_TINY
- response_help = "pokes"
- response_disarm = "shoos"
- response_harm = "splats"
+ response_help_continuous = "pokes"
+ response_help_simple = "poke"
+ response_disarm_continuous = "shoos"
+ response_disarm_simple = "shoo"
+ response_harm_continuous = "splats"
+ response_harm_simple = "plat"
speak_emote = list("chitters")
mouse_opacity = 2
density = TRUE
ventcrawler = VENTCRAWLER_ALWAYS
- gold_core_spawnable = FRIENDLY_SPAWN
verb_say = "chitters"
verb_ask = "chitters inquisitively"
verb_exclaim = "chitters loudly"
diff --git a/code/modules/mob/living/simple_animal/hostile/bear.dm b/code/modules/mob/living/simple_animal/hostile/bear.dm
index a77098cb80..0e864a1e37 100644
--- a/code/modules/mob/living/simple_animal/hostile/bear.dm
+++ b/code/modules/mob/living/simple_animal/hostile/bear.dm
@@ -17,9 +17,12 @@
turns_per_move = 5
see_in_dark = 6
butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab/bear = 5, /obj/item/clothing/head/bearpelt = 1)
- response_help = "pets"
- response_disarm = "gently pushes aside"
- response_harm = "hits"
+ response_help_continuous = "pets"
+ response_help_simple = "pet"
+ response_disarm_continuous = "gently pushes aside"
+ response_disarm_simple = "gently push aside"
+ response_harm_continuous = "kicks"
+ response_harm_simple = "kick"
maxHealth = 60
health = 60
spacewalk = TRUE
@@ -28,9 +31,11 @@
obj_damage = 60
melee_damage_lower = 20
melee_damage_upper = 30
- attacktext = "claws"
+ attack_verb_continuous = "claws"
+ attack_verb_simple = "claw"
attack_sound = 'sound/weapons/bladeslice.ogg'
- friendly = "bear hugs"
+ friendly_verb_continuous = "bear hugs"
+ friendly_verb_simple = "bear hug"
//Space bears aren't affected by cold.
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
@@ -40,7 +45,7 @@
faction = list("russian")
gold_core_spawnable = HOSTILE_SPAWN
- do_footstep = TRUE
+ footstep_type = FOOTSTEP_MOB_CLAW
//SPACE BEARS! SQUEEEEEEEE~ OW! FUCK! IT BIT MY HAND OFF!!
/mob/living/simple_animal/hostile/bear/Hudson
@@ -111,12 +116,14 @@ mob/living/simple_animal/hostile/bear/butter //The mighty companion to Cak. Seve
melee_damage_lower = 1
melee_damage_upper = 1
armour_penetration = 0
- response_harm = "takes a bite out of"
+ response_harm_continuous = "takes a bite out of"
+ response_harm_simple = "take a bite out of"
attacked_sound = 'sound/items/eatfood.ogg'
deathmessage = "loses its false life and collapses!"
butcher_results = list(/obj/item/reagent_containers/food/snacks/butter = 6, /obj/item/reagent_containers/food/snacks/meat/slab = 3, /obj/item/organ/brain = 1, /obj/item/organ/heart = 1)
attack_sound = 'sound/weapons/slap.ogg'
- attacktext = "slaps"
+ attack_verb_continuous = "slaps"
+ attack_verb_simple = "slap"
/mob/living/simple_animal/hostile/bear/butter/Life() //Heals butter bear really fast when he takes damage.
if(stat)
diff --git a/code/modules/mob/living/simple_animal/hostile/bees.dm b/code/modules/mob/living/simple_animal/hostile/bees.dm
index f5454933c8..5f3d4f11c1 100644
--- a/code/modules/mob/living/simple_animal/hostile/bees.dm
+++ b/code/modules/mob/living/simple_animal/hostile/bees.dm
@@ -23,10 +23,14 @@
turns_per_move = 0
melee_damage_lower = 1
melee_damage_upper = 1
- attacktext = "stings"
- response_help = "shoos"
- response_disarm = "swats away"
- response_harm = "squashes"
+ attack_verb_continuous = "stings"
+ attack_verb_simple = "sting"
+ response_help_continuous = "shoos"
+ response_help_simple = "shoo"
+ response_disarm_continuous = "swats away"
+ response_disarm_simple = "swat away"
+ response_harm_continuous = "squashes"
+ response_harm_simple = "squash"
maxHealth = 10
health = 10
spacewalk = TRUE
diff --git a/code/modules/mob/living/simple_animal/hostile/bosses/boss.dm b/code/modules/mob/living/simple_animal/hostile/bosses/boss.dm
index dbb957a96b..b1a4f05e8c 100644
--- a/code/modules/mob/living/simple_animal/hostile/bosses/boss.dm
+++ b/code/modules/mob/living/simple_animal/hostile/bosses/boss.dm
@@ -7,6 +7,7 @@
status_flags = 0
a_intent = INTENT_HARM
gender = NEUTER
+ has_field_of_vision = FALSE //You are a frikkin boss
var/list/boss_abilities = list() //list of /datum/action/boss
var/datum/boss_active_timed_battle/atb
var/point_regen_delay = 1
diff --git a/code/modules/mob/living/simple_animal/hostile/bosses/paperwizard.dm b/code/modules/mob/living/simple_animal/hostile/bosses/paperwizard.dm
index 07572fff83..aef3fb714d 100644
--- a/code/modules/mob/living/simple_animal/hostile/bosses/paperwizard.dm
+++ b/code/modules/mob/living/simple_animal/hostile/bosses/paperwizard.dm
@@ -23,7 +23,7 @@
attack_sound = 'sound/hallucinations/growl1.ogg'
var/list/copies = list()
- do_footstep = TRUE
+ footstep_type = FOOTSTEP_MOB_SHOE
//Summon Ability
diff --git a/code/modules/mob/living/simple_animal/hostile/carp.dm b/code/modules/mob/living/simple_animal/hostile/carp.dm
index ced56f0705..a56a8dcc29 100644
--- a/code/modules/mob/living/simple_animal/hostile/carp.dm
+++ b/code/modules/mob/living/simple_animal/hostile/carp.dm
@@ -12,9 +12,10 @@
speak_chance = 0
turns_per_move = 5
butcher_results = list(/obj/item/reagent_containers/food/snacks/carpmeat = 2)
- response_help = "pets"
- response_disarm = "gently pushes aside"
- response_harm = "hits"
+ response_help_continuous = "pets"
+ response_help_simple = "pet"
+ response_disarm_continuous = "gently pushes aside"
+ response_disarm_simple = "gently push aside"
emote_taunt = list("gnashes")
taunt_chance = 30
speed = 0
@@ -25,7 +26,8 @@
obj_damage = 50
melee_damage_lower = 15
melee_damage_upper = 15
- attacktext = "bites"
+ attack_verb_continuous = "bites"
+ attack_verb_simple = "bite"
attack_sound = 'sound/weapons/bite.ogg'
speak_emote = list("gnashes")
//Space carp aren't affected by cold.
diff --git a/code/modules/mob/living/simple_animal/hostile/cat_butcher.dm b/code/modules/mob/living/simple_animal/hostile/cat_butcher.dm
index 4e3375caf7..d85f75cbbd 100644
--- a/code/modules/mob/living/simple_animal/hostile/cat_butcher.dm
+++ b/code/modules/mob/living/simple_animal/hostile/cat_butcher.dm
@@ -8,9 +8,6 @@
icon_gib = "syndicate_gib"
speak_chance = 0
turns_per_move = 5
- response_help = "pokes"
- response_disarm = "shoves"
- response_harm = "hits"
speed = 0
stat_attack = UNCONSCIOUS
robust_searching = 1
@@ -19,7 +16,8 @@
harm_intent_damage = 5
melee_damage_lower = 15
melee_damage_upper = 15
- attacktext = "slashes at"
+ attack_verb_continuous = "slashes at"
+ attack_verb_simple = "slash at"
attack_sound = 'sound/weapons/circsawhit.ogg'
a_intent = INTENT_HARM
mob_biotypes = MOB_ORGANIC|MOB_HUMANOID
diff --git a/code/modules/mob/living/simple_animal/hostile/creature.dm b/code/modules/mob/living/simple_animal/hostile/creature.dm
deleted file mode 100644
index bba37f94af..0000000000
--- a/code/modules/mob/living/simple_animal/hostile/creature.dm
+++ /dev/null
@@ -1,18 +0,0 @@
-/mob/living/simple_animal/hostile/creature
- name = "creature"
- desc = "A sanity-destroying otherthing."
- icon_state = "otherthing"
- icon_living = "otherthing"
- icon_dead = "otherthing-dead"
- health = 80
- maxHealth = 80
- obj_damage = 100
- melee_damage_lower = 25
- melee_damage_upper = 50
- attacktext = "chomps"
- attack_sound = 'sound/weapons/bite.ogg'
- faction = list("creature")
- speak_emote = list("screams")
- gold_core_spawnable = HOSTILE_SPAWN
- atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
- minbodytemp = 0
diff --git a/code/modules/mob/living/simple_animal/hostile/dark_wizard.dm b/code/modules/mob/living/simple_animal/hostile/dark_wizard.dm
index 6ca6eac0cc..48266e3e76 100644
--- a/code/modules/mob/living/simple_animal/hostile/dark_wizard.dm
+++ b/code/modules/mob/living/simple_animal/hostile/dark_wizard.dm
@@ -17,7 +17,8 @@
obj_damage = 20
melee_damage_lower = 5
melee_damage_upper = 5
- attacktext = "staves"
+ attack_verb_continuous = "staves"
+ attack_verb_simple = "stave"
a_intent = INTENT_HARM
speak_emote = list("chants")
attack_sound = 'sound/weapons/bladeslice.ogg'
@@ -25,7 +26,7 @@
turns_per_move = 5
gold_core_spawnable = HOSTILE_SPAWN
faction = list(ROLE_WIZARD)
- do_footstep = TRUE
+ footstep_type = FOOTSTEP_MOB_SHOE
weather_immunities = list("lava","ash")
minbodytemp = 0
maxbodytemp = INFINITY
diff --git a/code/modules/mob/living/simple_animal/hostile/eyeballs.dm b/code/modules/mob/living/simple_animal/hostile/eyeballs.dm
index dbb9048ca4..75e8c55236 100644
--- a/code/modules/mob/living/simple_animal/hostile/eyeballs.dm
+++ b/code/modules/mob/living/simple_animal/hostile/eyeballs.dm
@@ -8,9 +8,10 @@
icon_gib = ""
gender = NEUTER
mob_biotypes = MOB_ORGANIC
- response_help = "pets"
- response_disarm = "gently pushes aside"
- response_harm = "hits"
+ response_help_continuous = "pets"
+ response_help_simple = "pet"
+ response_disarm_continuous = "gently pushes aside"
+ response_disarm_simple = "gently push aside"
emote_taunt = list("glares")
taunt_chance = 25
maxHealth = 45
@@ -21,9 +22,11 @@
obj_damage = 60
melee_damage_lower = 20
melee_damage_upper = 25
- attacktext = "blinks at"
+ attack_verb_continuous = "blinks at"
+ attack_verb_simple = "blink at"
attack_sound = 'sound/weapons/pierce.ogg'
movement_type = FLYING
faction = list("spooky")
del_on_death = 1
+ field_of_vision_type = FOV_270_DEGREES //Obviously, it's one eyeball.
diff --git a/code/modules/mob/living/simple_animal/hostile/faithless.dm b/code/modules/mob/living/simple_animal/hostile/faithless.dm
index 7ac0ea2b44..4f8d2fef6c 100644
--- a/code/modules/mob/living/simple_animal/hostile/faithless.dm
+++ b/code/modules/mob/living/simple_animal/hostile/faithless.dm
@@ -9,9 +9,12 @@
gender = MALE
speak_chance = 0
turns_per_move = 5
- response_help = "passes through"
- response_disarm = "shoves"
- response_harm = "hits"
+ response_help_continuous = "passes through"
+ response_help_simple = "pass through"
+ response_disarm_continuous = "shoves"
+ response_disarm_simple = "shove"
+ response_harm_continuous = "hits"
+ response_harm_simple = "hit"
emote_taunt = list("wails")
taunt_chance = 25
speed = 0
@@ -26,7 +29,8 @@
obj_damage = 50
melee_damage_lower = 15
melee_damage_upper = 15
- attacktext = "grips"
+ attack_verb_continuous = "grips"
+ attack_verb_simple = "grip"
attack_sound = 'sound/hallucinations/growl1.ogg'
speak_emote = list("growls")
@@ -36,7 +40,7 @@
faction = list("faithless")
gold_core_spawnable = HOSTILE_SPAWN
- do_footstep = TRUE
+ footstep_type = FOOTSTEP_MOB_SHOE
/mob/living/simple_animal/hostile/faithless/AttackingTarget()
. = ..()
diff --git a/code/modules/mob/living/simple_animal/hostile/giant_spider.dm b/code/modules/mob/living/simple_animal/hostile/giant_spider.dm
index f19aa0a2a7..a253ecfd96 100644
--- a/code/modules/mob/living/simple_animal/hostile/giant_spider.dm
+++ b/code/modules/mob/living/simple_animal/hostile/giant_spider.dm
@@ -30,9 +30,12 @@
turns_per_move = 5
see_in_dark = 10
butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab/spider = 2, /obj/item/reagent_containers/food/snacks/spiderleg = 8)
- response_help = "pets"
- response_disarm = "gently pushes aside"
- response_harm = "hits"
+ response_help_continuous = "pets"
+ response_help_simple = "pet"
+ response_disarm_continuous = "gently pushes aside"
+ response_disarm_simple = "gently push aside"
+ response_harm_continuous = "kicks"
+ response_harm_simple = "kick"
maxHealth = 200
health = 200
obj_damage = 60
@@ -43,18 +46,19 @@
pass_flags = PASSTABLE
move_to_delay = 6
ventcrawler = VENTCRAWLER_ALWAYS
- attacktext = "bites"
+ attack_verb_continuous = "bites"
+ attack_verb_simple = "bite"
attack_sound = 'sound/weapons/bite.ogg'
unique_name = 1
gold_core_spawnable = HOSTILE_SPAWN
see_in_dark = 4
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_VISIBLE
+ footstep_type = FOOTSTEP_MOB_CLAW
+ has_field_of_vision = FALSE // 360° vision.
var/playable_spider = FALSE
var/datum/action/innate/spider/lay_web/lay_web
var/directive = "" //Message passed down to children, to relay the creator's orders
- do_footstep = TRUE
-
/mob/living/simple_animal/hostile/poison/giant_spider/Initialize()
. = ..()
lay_web = new
diff --git a/code/modules/mob/living/simple_animal/hostile/goose.dm b/code/modules/mob/living/simple_animal/hostile/goose.dm
index db232c20c4..1dcb13aa9b 100644
--- a/code/modules/mob/living/simple_animal/hostile/goose.dm
+++ b/code/modules/mob/living/simple_animal/hostile/goose.dm
@@ -10,9 +10,12 @@
speak_chance = 0
turns_per_move = 5
butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab = 2)
- response_help = "pets"
- response_disarm = "gently pushes aside"
- response_harm = "kicks"
+ response_help_continuous = "pets"
+ response_help_simple = "pet"
+ response_disarm_continuous = "gently pushes aside"
+ response_disarm_simple = "gently push aside"
+ response_harm_continuous = "kicks"
+ response_harm_simple = "kick"
emote_taunt = list("hisses")
taunt_chance = 30
speed = 0
@@ -21,7 +24,8 @@
harm_intent_damage = 5
melee_damage_lower = 5
melee_damage_upper = 5
- attacktext = "pecks"
+ attack_verb_continuous = "pecks"
+ attack_verb_simple = "peck"
attack_sound = "goose"
speak_emote = list("honks")
faction = list("neutral")
diff --git a/code/modules/mob/living/simple_animal/hostile/gorilla/gorilla.dm b/code/modules/mob/living/simple_animal/hostile/gorilla/gorilla.dm
index 7c6f9e9c7b..f48eef083b 100644
--- a/code/modules/mob/living/simple_animal/hostile/gorilla/gorilla.dm
+++ b/code/modules/mob/living/simple_animal/hostile/gorilla/gorilla.dm
@@ -16,16 +16,20 @@
health = 220
loot = list(/obj/effect/gibspawner/generic)
butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab/gorilla = 4)
- response_help = "prods"
- response_disarm = "challenges"
- response_harm = "thumps"
+ response_help_continuous = "prods"
+ response_help_simple = "prod"
+ response_disarm_continuous = "challenges"
+ response_disarm_simple = "challenge"
+ response_harm_continuous = "thumps"
+ response_harm_simple = "thump"
speed = 1
melee_damage_lower = 15
melee_damage_upper = 18
damage_coeff = list(BRUTE = 1, BURN = 1.5, TOX = 1.5, CLONE = 0, STAMINA = 0, OXY = 1.5)
obj_damage = 20
environment_smash = ENVIRONMENT_SMASH_WALLS
- attacktext = "pummels"
+ attack_verb_continuous = "pummels"
+ attack_verb_simple = "pummel"
attack_sound = 'sound/weapons/punch1.ogg'
dextrous = TRUE
held_items = list(null, null)
@@ -39,7 +43,7 @@
var/list/gorilla_overlays[GORILLA_TOTAL_LAYERS]
var/oogas = 0
- do_footstep = TRUE
+ footstep_type = FOOTSTEP_MOB_BAREFOOT
// Gorillas like to dismember limbs from unconcious mobs.
// Returns null when the target is not an unconcious carbon mob; a list of limbs (possibly empty) otherwise.
diff --git a/code/modules/mob/living/simple_animal/hostile/headcrab.dm b/code/modules/mob/living/simple_animal/hostile/headcrab.dm
index 9d64b76198..501534237a 100644
--- a/code/modules/mob/living/simple_animal/hostile/headcrab.dm
+++ b/code/modules/mob/living/simple_animal/hostile/headcrab.dm
@@ -12,7 +12,8 @@
maxHealth = 50
melee_damage_lower = 5
melee_damage_upper = 5
- attacktext = "chomps"
+ attack_verb_continuous = "chomps"
+ attack_verb_simple = "chomp"
attack_sound = 'sound/weapons/bite.ogg'
faction = list("creature")
robust_searching = 1
diff --git a/code/modules/mob/living/simple_animal/hostile/hivebot.dm b/code/modules/mob/living/simple_animal/hostile/hivebot.dm
index 1cc675825f..b627bf67c2 100644
--- a/code/modules/mob/living/simple_animal/hostile/hivebot.dm
+++ b/code/modules/mob/living/simple_animal/hostile/hivebot.dm
@@ -16,7 +16,8 @@
healable = 0
melee_damage_lower = 10
melee_damage_upper = 10
- attacktext = "saw"
+ attack_verb_continuous = "saw"
+ attack_verb_simple = "saw"
attack_sound = 'sound/weapons/bladeslice.ogg'
projectilesound = 'sound/weapons/gunshot.ogg'
projectiletype = /obj/item/projectile/hivebotbullet
@@ -30,7 +31,7 @@
loot = list(/obj/effect/decal/cleanable/robot_debris)
blood_volume = 0
- do_footstep = TRUE
+ footstep_type = FOOTSTEP_MOB_CLAW
/mob/living/simple_animal/hostile/hivebot/Initialize()
. = ..()
diff --git a/code/modules/mob/living/simple_animal/hostile/illusion.dm b/code/modules/mob/living/simple_animal/hostile/illusion.dm
index 89303702f3..cab87010ef 100644
--- a/code/modules/mob/living/simple_animal/hostile/illusion.dm
+++ b/code/modules/mob/living/simple_animal/hostile/illusion.dm
@@ -10,7 +10,8 @@
melee_damage_lower = 5
melee_damage_upper = 5
a_intent = INTENT_HARM
- attacktext = "gores"
+ attack_verb_continuous = "gores"
+ attack_verb_simple = "gore"
maxHealth = 100
health = 100
speed = 0
@@ -20,6 +21,7 @@
var/multiply_chance = 0 //if we multiply on hit
del_on_death = 1
deathmessage = "vanishes into thin air! It was a fake!"
+ has_field_of_vision = FALSE //not meant to be played anyway.
/mob/living/simple_animal/hostile/illusion/Life()
diff --git a/code/modules/mob/living/simple_animal/hostile/jungle/_jungle_mobs.dm b/code/modules/mob/living/simple_animal/hostile/jungle/_jungle_mobs.dm
index c337344c90..c2b553aad7 100644
--- a/code/modules/mob/living/simple_animal/hostile/jungle/_jungle_mobs.dm
+++ b/code/modules/mob/living/simple_animal/hostile/jungle/_jungle_mobs.dm
@@ -7,9 +7,8 @@
environment_smash = ENVIRONMENT_SMASH_WALLS
minbodytemp = 0
maxbodytemp = 450
- response_help = "pokes"
- response_disarm = "shoves"
- response_harm = "strikes"
+ response_harm_continuous = "strikes"
+ response_harm_simple = "strike"
status_flags = NONE
a_intent = INTENT_HARM
see_in_dark = 4
diff --git a/code/modules/mob/living/simple_animal/hostile/jungle/leaper.dm b/code/modules/mob/living/simple_animal/hostile/jungle/leaper.dm
index 05c4007b6f..574811c968 100644
--- a/code/modules/mob/living/simple_animal/hostile/jungle/leaper.dm
+++ b/code/modules/mob/living/simple_animal/hostile/jungle/leaper.dm
@@ -27,7 +27,7 @@
var/hop_cooldown = 0 //Strictly for player controlled leapers
var/projectile_ready = FALSE //Stopping AI leapers from firing whenever they want, and only doing it after a hop has finished instead
- do_footstep = TRUE
+ footstep_type = FOOTSTEP_MOB_HEAVY
/obj/item/projectile/leaper
name = "leaper bubble"
diff --git a/code/modules/mob/living/simple_animal/hostile/jungle/mega_arachnid.dm b/code/modules/mob/living/simple_animal/hostile/jungle/mega_arachnid.dm
index ae161d596d..40274c0029 100644
--- a/code/modules/mob/living/simple_animal/hostile/jungle/mega_arachnid.dm
+++ b/code/modules/mob/living/simple_animal/hostile/jungle/mega_arachnid.dm
@@ -25,7 +25,7 @@
projectilesound = 'sound/weapons/pierce.ogg'
alpha = 50
- do_footstep = TRUE
+ footstep_type = FOOTSTEP_MOB_CLAW
/mob/living/simple_animal/hostile/jungle/mega_arachnid/Life()
..()
diff --git a/code/modules/mob/living/simple_animal/hostile/jungle/mook.dm b/code/modules/mob/living/simple_animal/hostile/jungle/mook.dm
index c05d14965e..6efa0cf468 100644
--- a/code/modules/mob/living/simple_animal/hostile/jungle/mook.dm
+++ b/code/modules/mob/living/simple_animal/hostile/jungle/mook.dm
@@ -32,7 +32,7 @@
var/attack_state = MOOK_ATTACK_NEUTRAL
var/struck_target_leap = FALSE
- do_footstep = TRUE
+ footstep_type = FOOTSTEP_MOB_BAREFOOT
/mob/living/simple_animal/hostile/jungle/mook/CanPass(atom/movable/O)
if(istype(O, /mob/living/simple_animal/hostile/jungle/mook))
diff --git a/code/modules/mob/living/simple_animal/hostile/killertomato.dm b/code/modules/mob/living/simple_animal/hostile/killertomato.dm
index e418cc4ab0..9cb65d7c30 100644
--- a/code/modules/mob/living/simple_animal/hostile/killertomato.dm
+++ b/code/modules/mob/living/simple_animal/hostile/killertomato.dm
@@ -12,12 +12,16 @@
health = 30
see_in_dark = 3
butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab/killertomato = 2)
- response_help = "prods"
- response_disarm = "pushes aside"
- response_harm = "smacks"
+ response_help_continuous = "prods"
+ response_help_simple = "prod"
+ response_disarm_continuous = "pushes aside"
+ response_disarm_simple = "push aside"
+ response_harm_continuous = "smacks"
+ response_harm_simple = "smack"
melee_damage_lower = 8
melee_damage_upper = 12
- attacktext = "slams"
+ attack_verb_continuous = "slams"
+ attack_verb_simple = "slam"
attack_sound = 'sound/weapons/punch1.ogg'
ventcrawler = VENTCRAWLER_ALWAYS
faction = list("plants")
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner.dm
index fd278eb438..8c358fd625 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner.dm
@@ -54,7 +54,7 @@ Difficulty: Medium
deathmessage = "falls to the ground, decaying into glowing particles."
death_sound = "bodyfall"
- do_footstep = TRUE
+ footstep_type = FOOTSTEP_MOB_HEAVY
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/guidance
guidance = TRUE
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm
index d2680fbf61..fe6c2290c4 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm
@@ -29,12 +29,14 @@ Difficulty: Hard
threat = 35
health = 2500
maxHealth = 2500
- attacktext = "rends"
+ attack_verb_continuous = "rends"
+ attack_verb_simple = "rend"
attack_sound = 'sound/magic/demon_attack1.ogg'
icon_state = "bubblegum"
icon_living = "bubblegum"
icon_dead = ""
- friendly = "stares down"
+ friendly_verb_continuous = "stares down"
+ friendly_verb_simple = "stare down"
icon = 'icons/mob/lavaland/96x96megafauna.dmi'
speak_emote = list("gurgles")
armour_penetration = 40
@@ -55,7 +57,7 @@ Difficulty: Hard
deathmessage = "sinks into a pool of blood, fleeing the battle. You've won, for now... "
death_sound = 'sound/magic/enter_blood.ogg'
- do_footstep = TRUE
+ footstep_type = FOOTSTEP_MOB_HEAVY
/obj/item/gps/internal/bubblegum
icon_state = null
@@ -227,11 +229,13 @@ Difficulty: Hard
icon_state = "bloodbrood"
icon_living = "bloodbrood"
icon_aggro = "bloodbrood"
- attacktext = "pierces"
+ attack_verb_continuous = "pierces"
+ attack_verb_simple = "pierce"
color = "#C80000"
density = FALSE
faction = list("mining", "boss")
weather_immunities = list("lava","ash")
+ has_field_of_vision = FALSE
/mob/living/simple_animal/hostile/asteroid/hivelordbrood/slaughter/CanPass(atom/movable/mover, turf/target)
if(istype(mover, /mob/living/simple_animal/hostile/megafauna/bubblegum))
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm
index 73fb9d4e48..be3552822f 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm
@@ -27,12 +27,14 @@ Difficulty: Very Hard
threat = 40
health = 2500
maxHealth = 2500
- attacktext = "judges"
+ attack_verb_continuous = "judges"
+ attack_verb_simple = "judge"
attack_sound = 'sound/magic/clockwork/ratvar_attack.ogg'
icon_state = "eva"
icon_living = "eva"
icon_dead = "dragon_dead"
- friendly = "stares down"
+ friendly_verb_continuous = "stares down"
+ friendly_verb_simple = "stare down"
icon = 'icons/mob/lavaland/96x96megafauna.dmi'
speak_emote = list("roars")
armour_penetration = 40
@@ -606,14 +608,18 @@ Difficulty: Very Hard
icon_dead = "butterfly_dead"
threat = -0.7
turns_per_move = 1
- response_help = "waves away"
- response_disarm = "brushes aside"
- response_harm = "disrupts"
+ response_help_continuous = "waves away"
+ response_help_simple = "wave away"
+ response_disarm_continuous = "brushes aside"
+ response_disarm_simple = "brush aside"
+ response_harm_continuous = "disrupts"
+ response_harm_simple = "disrupt"
speak_emote = list("oscillates")
maxHealth = 2
health = 2
harm_intent_damage = 1
- friendly = "mends"
+ friendly_verb_continuous = "mends"
+ friendly_verb_simple = "mend"
density = FALSE
movement_type = FLYING
pass_flags = PASSTABLE | PASSGRILLE | PASSMOB
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/demonic_frost_miner.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/demonic_frost_miner.dm
index 3d106021de..88e33ed91a 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/demonic_frost_miner.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/demonic_frost_miner.dm
@@ -10,7 +10,8 @@ Difficulty: Extremely Hard
icon_state = "demonic_miner"
icon_living = "demonic_miner"
icon = 'icons/mob/icemoon/icemoon_monsters.dmi'
- attacktext = "pummels"
+ attack_verb_continuous = "pummels"
+ attack_verb_simple = "pummel"
attack_sound = 'sound/weapons/sonic_jackhammer.ogg'
mob_biotypes = MOB_ORGANIC|MOB_HUMANOID
light_color = "#E4C7C5"
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm
index c59272214b..062a4c9a43 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm
@@ -37,13 +37,15 @@ Difficulty: Medium
health = 2500
maxHealth = 2500
spacewalk = TRUE
- attacktext = "chomps"
+ attack_verb_continuous = "chomps"
+ attack_verb_simple = "chomp"
attack_sound = 'sound/magic/demon_attack1.ogg'
icon = 'icons/mob/lavaland/64x64megafauna.dmi'
icon_state = "dragon"
icon_living = "dragon"
icon_dead = "dragon_dead"
- friendly = "stares down"
+ friendly_verb_continuous = "stares down"
+ friendly_verb_simple = "stare down"
speak_emote = list("roars")
armour_penetration = 40
melee_damage_lower = 40
@@ -64,7 +66,7 @@ Difficulty: Medium
death_sound = 'sound/magic/demon_dies.ogg'
var/datum/action/small_sprite/smallsprite = new/datum/action/small_sprite/drake()
- do_footstep = TRUE
+ footstep_type = FOOTSTEP_MOB_HEAVY
/mob/living/simple_animal/hostile/megafauna/dragon/Initialize()
smallsprite.Grant(src)
@@ -81,7 +83,7 @@ Difficulty: Medium
return FALSE
return ..()
-/mob/living/simple_animal/hostile/megafauna/dragon/visible_message(message, self_message, blind_message, vision_distance = DEFAULT_MESSAGE_RANGE, list/ignored_mobs)
+/mob/living/simple_animal/hostile/megafauna/dragon/visible_message(message, self_message, blind_message, vision_distance = DEFAULT_MESSAGE_RANGE, list/ignored_mobs, mob/target, target_message)
if(swooping & SWOOP_INVULNERABLE) //to suppress attack messages without overriding every single proc that could send a message saying we got hit
return
return ..()
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm
index 477c2ce3aa..4ade831f95 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm
@@ -40,11 +40,13 @@ Difficulty: Normal
threat = 30
health = 2500
maxHealth = 2500
- attacktext = "clubs"
+ attack_verb_continuous = "clubs"
+ attack_verb_simple = "club"
attack_sound = 'sound/weapons/sonic_jackhammer.ogg'
icon_state = "hierophant"
icon_living = "hierophant"
- friendly = "stares down"
+ friendly_verb_continuous = "stares down"
+ friendly_verb_simple = "stare down"
icon = 'icons/mob/lavaland/hierophant_new.dmi'
faction = list("boss") //asteroid mobs? get that shit out of my beautiful square house
speak_emote = list("preaches")
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/legion.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/legion.dm
index 62a09dff65..4da8a90b23 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/legion.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/legion.dm
@@ -26,7 +26,8 @@ Difficulty: Medium
icon_living = "legion"
desc = "One of many."
icon = 'icons/mob/lavaland/legion.dmi'
- attacktext = "chomps"
+ attack_verb_continuous = "chomps"
+ attack_verb_simple = "chomp"
attack_sound = 'sound/magic/demon_attack1.ogg'
speak_emote = list("echoes")
armour_penetration = 50
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/megafauna.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/megafauna.dm
index 78987ebaa0..c406baf2a6 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/megafauna.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/megafauna.dm
@@ -27,6 +27,7 @@
mob_size = MOB_SIZE_LARGE
layer = LARGE_MOB_LAYER //Looks weird with them slipping under mineral walls and cameras and shit otherwise
flags_1 = PREVENT_CONTENTS_EXPLOSION_1 | HEAR_1
+ has_field_of_vision = FALSE //You are a frikkin boss
/// Crusher loot dropped when fauna killed with a crusher
var/list/crusher_loot
var/medal_type
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/wendigo.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/wendigo.dm
index 5ed163ae7e..ed189f052d 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/wendigo.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/wendigo.dm
@@ -11,7 +11,8 @@ Difficulty: Hard
icon_living = "wendigo"
icon_dead = "wendigo_dead"
icon = 'icons/mob/icemoon/64x64megafauna.dmi'
- attacktext = "claws"
+ attack_verb_continuous = "claws"
+ attack_verb_simple = "claw"
attack_sound = 'sound/magic/demon_attack1.ogg'
weather_immunities = list("snow")
speak_emote = list("roars")
diff --git a/code/modules/mob/living/simple_animal/hostile/mimic.dm b/code/modules/mob/living/simple_animal/hostile/mimic.dm
index 138d7f155e..5afe109550 100644
--- a/code/modules/mob/living/simple_animal/hostile/mimic.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mimic.dm
@@ -5,9 +5,12 @@
icon_state = "crate"
icon_living = "crate"
- response_help = "touches"
- response_disarm = "pushes"
- response_harm = "hits"
+ response_help_continuous = "touches"
+ response_help_simple = "touch"
+ response_disarm_continuous = "pushes"
+ response_disarm_simple = "push"
+ response_harm_continuous = "hits"
+ response_harm_simple = "hit"
speed = 0
maxHealth = 250
health = 250
@@ -18,7 +21,8 @@
harm_intent_damage = 5
melee_damage_lower = 8
melee_damage_upper = 12
- attacktext = "attacks"
+ attack_verb_continuous = "attacks"
+ attack_verb_simple = "attack"
attack_sound = 'sound/weapons/punch1.ogg'
emote_taunt = list("growls")
speak_emote = list("creaks")
@@ -34,7 +38,8 @@
// Aggro when you try to open them. Will also pickup loot when spawns and drop it when dies.
/mob/living/simple_animal/hostile/mimic/crate
- attacktext = "bites"
+ attack_verb_continuous = "bites"
+ attack_verb_simple = "bite"
speak_emote = list("clatters")
stop_automated_movement = 1
wander = 0
diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/basilisk.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/basilisk.dm
index 4d20d4c7fb..b69a4b69cf 100644
--- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/basilisk.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/basilisk.dm
@@ -25,7 +25,8 @@
obj_damage = 60
melee_damage_lower = 12
melee_damage_upper = 12
- attacktext = "bites into"
+ attack_verb_continuous = "bites into"
+ attack_verb_simple = "bite into"
a_intent = INTENT_HARM
speak_emote = list("chitters")
attack_sound = 'sound/weapons/bladeslice.ogg'
@@ -72,7 +73,8 @@
throw_message = "bounces harmlessly off of"
melee_damage_lower = 15
melee_damage_upper = 15
- attacktext = "impales"
+ attack_verb_continuous = "impales"
+ attack_verb_simple = "impale"
a_intent = INTENT_HARM
speak_emote = list("telepathically cries")
attack_sound = 'sound/weapons/bladeslice.ogg'
@@ -82,6 +84,7 @@
crusher_loot = /obj/item/crusher_trophy/watcher_wing
loot = list()
butcher_results = list(/obj/item/stack/ore/diamond = 2, /obj/item/stack/sheet/sinew = 2, /obj/item/stack/sheet/bone = 1)
+ field_of_vision_type = FOV_270_DEGREES //Obviously, it's one eyeball.
/mob/living/simple_animal/hostile/asteroid/basilisk/watcher/random/Initialize()
. = ..()
diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/curse_blob.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/curse_blob.dm
index 652840f7e3..116082d571 100644
--- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/curse_blob.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/curse_blob.dm
@@ -16,7 +16,8 @@
melee_damage_lower = 10
melee_damage_upper = 10
melee_damage_type = BURN
- attacktext = "slashes"
+ attack_verb_continuous = "slashes"
+ attack_verb_simple = "slash"
attack_sound = 'sound/effects/curseattack.ogg'
throw_message = "passes through the smokey body of"
obj_damage = 0
diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/elite.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/elite.dm
index 2114612fce..81b541dc7b 100644
--- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/elite.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/elite.dm
@@ -21,6 +21,7 @@
layer = LARGE_MOB_LAYER
sentience_type = SENTIENCE_BOSS
hud_type = /datum/hud/lavaland_elite
+ has_field_of_vision = FALSE //You are a frikkin mini-boss
var/chosen_attack = 1
var/list/attack_action_types = list()
var/can_talk = FALSE
diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/goliath_broodmother.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/goliath_broodmother.dm
index 68a0e81cc7..e662f4e525 100644
--- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/goliath_broodmother.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/goliath_broodmother.dm
@@ -31,9 +31,8 @@
melee_damage_lower = 30
melee_damage_upper = 30
armour_penetration = 30
- attacktext = "beats down on"
- /*attack_verb_continuous = "beats down on"
- attack_verb_simple = "beat down on"*/
+ attack_verb_continuous = "beats down on"
+ attack_verb_simple = "beat down on"
attack_sound = 'sound/weapons/punch1.ogg'
throw_message = "does nothing to the rocky hide of the"
speed = 2
@@ -172,9 +171,8 @@
health = 30
melee_damage_lower = 5
melee_damage_upper = 5
- attacktext = "bashes against"
- /*attack_verb_continuous = "bashes against"
- attack_verb_simple = "bash against"*/
+ attack_verb_continuous = "bashes against"
+ attack_verb_simple = "bash against"
attack_sound = 'sound/weapons/punch1.ogg'
throw_message = "does nothing to the rocky hide of the"
speed = 2
diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/herald.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/herald.dm
index 884e3bb989..106cb20efc 100644
--- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/herald.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/herald.dm
@@ -29,9 +29,8 @@
health = 800
melee_damage_lower = 20
melee_damage_upper = 20
- attacktext = "preaches to"
- /*attack_verb_continuous = "preaches to"
- attack_verb_simple = "preach to"*/
+ attack_verb_continuous = "preaches to"
+ attack_verb_simple = "preach to"
attack_sound = 'sound/magic/clockwork/ratvar_attack.ogg'
throw_message = "doesn't affect the purity of"
speed = 4
diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/legionnaire.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/legionnaire.dm
index c9011c5f5f..c2faa002bc 100644
--- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/legionnaire.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/legionnaire.dm
@@ -29,9 +29,8 @@
health = 800
melee_damage_lower = 30
melee_damage_upper = 30
- attacktext = "slashes its arms at"
- /*attack_verb_continuous = "slashes its arms at"
- attack_verb_simple = "slash your arms at"*/
+ attack_verb_continuous = "slashes its arms at"
+ attack_verb_simple = "slash your arms at"
attack_sound = 'sound/weapons/bladeslice.ogg'
throw_message = "doesn't affect the sturdiness of"
speed = 1
@@ -227,9 +226,8 @@
health = 80
melee_damage_lower = 10
melee_damage_upper = 10
- attacktext = "bites at"
- /*attack_verb_continuous = "bites at"
- attack_verb_simple = "bite at"*/
+ attack_verb_continuous = "bites at"
+ attack_verb_simple = "bite at"
attack_sound = 'sound/effects/curse1.ogg'
throw_message = "simply misses"
speed = 0
diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/pandora.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/pandora.dm
index 3276965fa2..ebbf032859 100644
--- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/pandora.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/pandora.dm
@@ -29,9 +29,8 @@
health = 800
melee_damage_lower = 15
melee_damage_upper = 15
- attacktext = "smashes into the side of"
- /*attack_verb_continuous = "smashes into the side of"
- attack_verb_simple = "smash into the side of"*/
+ attack_verb_continuous = "smashes into the side of"
+ attack_verb_simple = "smash into the side of"
attack_sound = 'sound/weapons/sonic_jackhammer.ogg'
throw_message = "merely dinks off of the"
speed = 4
diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/goldgrub.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/goldgrub.dm
index c43e9a7461..4a3497055a 100644
--- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/goldgrub.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/goldgrub.dm
@@ -13,14 +13,16 @@
vision_range = 2
aggro_vision_range = 9
move_to_delay = 5
- friendly = "harmlessly rolls into"
+ friendly_verb_continuous = "harmlessly rolls into"
+ friendly_verb_simple = "harmlessly roll into"
maxHealth = 45
health = 45
gold_core_spawnable = HOSTILE_SPAWN
harm_intent_damage = 5
melee_damage_lower = 0
melee_damage_upper = 0
- attacktext = "barrels into"
+ attack_verb_continuous = "barrels into"
+ attack_verb_simple = "barrel into"
attack_sound = 'sound/weapons/punch1.ogg'
a_intent = INTENT_HELP
speak_emote = list("screeches")
diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/goliath.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/goliath.dm
index 3c8cf9025f..a61f1924c8 100644
--- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/goliath.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/goliath.dm
@@ -14,7 +14,8 @@
move_to_delay = 10
ranged = 1
ranged_cooldown_time = 60
- friendly = "wails at"
+ friendly_verb_continuous = "wails at"
+ friendly_verb_simple = "wail at"
speak_emote = list("bellows")
speed = 3
maxHealth = 300
@@ -23,7 +24,8 @@
obj_damage = 100
melee_damage_lower = 18
melee_damage_upper = 18
- attacktext = "pulverizes"
+ attack_verb_continuous = "pulverizes"
+ attack_verb_simple = "pulverize"
attack_sound = 'sound/weapons/punch1.ogg'
throw_message = "does nothing to the rocky hide of the"
vision_range = 4
@@ -35,7 +37,7 @@
var/pre_attack_icon = "Goliath_preattack"
loot = list(/obj/item/stack/sheet/animalhide/goliath_hide)
- do_footstep = TRUE
+ footstep_type = FOOTSTEP_MOB_HEAVY
/mob/living/simple_animal/hostile/asteroid/goliath/Life()
. = ..()
diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/gutlunch.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/gutlunch.dm
index 39b66fbdc2..c9e650531c 100644
--- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/gutlunch.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/gutlunch.dm
@@ -18,10 +18,14 @@
obj_damage = 0
environment_smash = ENVIRONMENT_SMASH_NONE
move_to_delay = 15
- response_help = "pets"
- response_disarm = "gently pushes aside"
- response_harm = "squishes"
- friendly = "pinches"
+ response_help_continuous = "pets"
+ response_help_simple = "pet"
+ response_disarm_continuous = "gently pushes aside"
+ response_disarm_simple = "gently push aside"
+ response_harm_continuous = "squishes"
+ response_harm_simple = "squish"
+ friendly_verb_continuous = "pinches"
+ friendly_verb_simple = "pinch"
a_intent = INTENT_HELP
ventcrawler = VENTCRAWLER_ALWAYS
gold_core_spawnable = FRIENDLY_SPAWN
diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/hivelord.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/hivelord.dm
index a7ce559d35..d21e39ef54 100644
--- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/hivelord.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/hivelord.dm
@@ -20,7 +20,8 @@
harm_intent_damage = 5
melee_damage_lower = 0
melee_damage_upper = 0
- attacktext = "lashes out at"
+ attack_verb_continuous = "lashes out at"
+ attack_verb_simple = "lash out at"
speak_emote = list("telepathically cries")
attack_sound = 'sound/weapons/pierce.ogg'
throw_message = "falls right through the strange body of the"
@@ -67,7 +68,8 @@
icon_gib = "syndicate_gib"
mouse_opacity = MOUSE_OPACITY_OPAQUE
move_to_delay = 1
- friendly = "buzzes near"
+ friendly_verb_continuous = "buzzes near"
+ friendly_verb_simple = "buzz near"
vision_range = 10
speed = 3
maxHealth = 1
@@ -76,7 +78,8 @@
harm_intent_damage = 5
melee_damage_lower = 2
melee_damage_upper = 2
- attacktext = "slashes"
+ attack_verb_continuous = "slashes"
+ attack_verb_simple = "slash"
speak_emote = list("telepathically cries")
attack_sound = 'sound/weapons/pierce.ogg'
throw_message = "falls right through the strange body of the"
@@ -107,7 +110,8 @@
obj_damage = 60
melee_damage_lower = 15
melee_damage_upper = 15
- attacktext = "lashes out at"
+ attack_verb_continuous = "lashes out at"
+ attack_verb_simple = "lash out at"
speak_emote = list("echoes")
attack_sound = 'sound/weapons/pierce.ogg'
throw_message = "bounces harmlessly off of"
@@ -173,14 +177,16 @@
icon_aggro = "legion_head"
icon_dead = "legion_head"
icon_gib = "syndicate_gib"
- friendly = "buzzes near"
+ friendly_verb_continuous = "buzzes near"
+ friendly_verb_simple = "buzz near"
vision_range = 10
maxHealth = 1
health = 5
harm_intent_damage = 5
melee_damage_lower = 12
melee_damage_upper = 12
- attacktext = "bites"
+ attack_verb_continuous = "bites"
+ attack_verb_simple = "bite"
speak_emote = list("echoes")
attack_sound = 'sound/weapons/pierce.ogg'
throw_message = "is shrugged off by"
@@ -396,8 +402,6 @@
ears = /obj/item/radio/headset
gloves = /obj/item/clothing/gloves/color/fyellow
id = /obj/item/card/id/silver/reaper //looks cool and has a fancy name but only a 1% chance
- back = /obj/item/storage/backpack
- backpack_contents = list(/obj/item/stack/cable_coil = 12, /obj/item/assembly/flash = 1, /obj/item/storage/fancy/donut_box = 1, /obj/item/storage/fancy/cigarettes/cigpack_shadyjims = 1, /obj/item/lighter = 1)
if(prob(99))
id = /obj/item/card/id
id_job = "Assisant"
@@ -407,11 +411,14 @@
gloves = /obj/item/clothing/gloves/color/yellow
if(prob(10))
back = /obj/item/twohanded/spear
- backpack_contents = null
+ else if(prob(80)) //Now they dont always have a backpack
+ back = /obj/item/storage/backpack
+ backpack_contents = list(/obj/item/stack/cable_coil = 1, /obj/item/assembly/flash = 1, /obj/item/storage/fancy/donut_box = 1, /obj/item/storage/fancy/cigarettes/cigpack_shadyjims = 1, /obj/item/lighter = 1)
if(prob(90))
r_pocket = /obj/item/kitchen/knife
if(prob(60))
l_pocket = /obj/item/soap/homemade
+
if("Beelegion")
uniform = /obj/item/clothing/under/color/yellow
suit = /obj/item/clothing/suit/hooded/bee_costume
diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/ice_demon.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/ice_demon.dm
index 88ee27fcc9..66241e3d75 100644
--- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/ice_demon.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/ice_demon.dm
@@ -23,7 +23,8 @@
obj_damage = 40
melee_damage_lower = 15
melee_damage_upper = 15
- attacktext = "slices"
+ attack_verb_continuous = "slices"
+ attack_verb_simple = "slice"
attack_sound = 'sound/weapons/bladeslice.ogg'
vision_range = 7
aggro_vision_range = 7
diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/ice_whelp.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/ice_whelp.dm
index c8d5cf4b73..b62fb4a665 100644
--- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/ice_whelp.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/ice_whelp.dm
@@ -7,7 +7,8 @@
icon_dead = "ice_whelp_dead"
mob_biotypes = MOB_ORGANIC|MOB_BEAST
mouse_opacity = MOUSE_OPACITY_ICON
- friendly = "stares down"
+ friendly_verb_continuous = "stares down"
+ friendly_verb_simple = "stare down"
speak_emote = list("roars")
speed = 30
move_to_delay = 30
@@ -19,7 +20,8 @@
armour_penetration = 20
melee_damage_lower = 20
melee_damage_upper = 20
- attacktext = "chomps"
+ attack_verb_continuous = "chomps"
+ attack_verb_simple = "chomp"
attack_sound = 'sound/magic/demon_attack1.ogg'
vision_range = 9
aggro_vision_range = 9
diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/mining_mobs.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/mining_mobs.dm
index 6ad869afe6..c3e4f24c43 100644
--- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/mining_mobs.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/mining_mobs.dm
@@ -8,9 +8,8 @@
environment_smash = ENVIRONMENT_SMASH_WALLS
minbodytemp = 0
maxbodytemp = INFINITY
- response_help = "pokes"
- response_disarm = "shoves"
- response_harm = "strikes"
+ response_harm_continuous = "strikes"
+ response_harm_simple = "strike"
status_flags = 0
a_intent = INTENT_HARM
var/crusher_loot
diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/polarbear.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/polarbear.dm
index 0576d0ecfe..ac2ce37d3f 100644
--- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/polarbear.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/polarbear.dm
@@ -7,7 +7,8 @@
icon_dead = "polarbear_dead"
mob_biotypes = MOB_ORGANIC|MOB_BEAST
mouse_opacity = MOUSE_OPACITY_ICON
- friendly = "growls at"
+ friendly_verb_continuous = "growls at"
+ friendly_verb_simple = "growl at"
speak_emote = list("growls")
speed = 12
move_to_delay = 12
@@ -16,7 +17,8 @@
obj_damage = 40
melee_damage_lower = 25
melee_damage_upper = 25
- attacktext = "claws"
+ attack_verb_continuous = "claws"
+ attack_verb_simple = "claw"
attack_sound = 'sound/weapons/bladeslice.ogg'
vision_range = 2 // don't aggro unless you basically antagonize it, though they will kill you worse than a goliath will
aggro_vision_range = 9
diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/wolf.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/wolf.dm
index 9f17421691..013a75be75 100644
--- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/wolf.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/wolf.dm
@@ -7,7 +7,8 @@
icon_dead = "whitewolf_dead"
mob_biotypes = MOB_ORGANIC|MOB_BEAST
mouse_opacity = MOUSE_OPACITY_ICON
- friendly = "howls at"
+ friendly_verb_continuous = "howls at"
+ friendly_verb_simple = "howl at"
speak_emote = list("howls")
speed = 5
move_to_delay = 5
@@ -19,7 +20,8 @@
rapid_melee = 2 // every second attack
dodging = TRUE
dodge_prob = 50
- attacktext = "bites"
+ attack_verb_continuous = "bites"
+ attack_verb_simple = "bite"
attack_sound = 'sound/weapons/bite.ogg'
vision_range = 7
aggro_vision_range = 7
diff --git a/code/modules/mob/living/simple_animal/hostile/mushroom.dm b/code/modules/mob/living/simple_animal/hostile/mushroom.dm
index d023cf0dd8..1b13200729 100644
--- a/code/modules/mob/living/simple_animal/hostile/mushroom.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mushroom.dm
@@ -9,15 +9,19 @@
maxHealth = 10
health = 10
butcher_results = list(/obj/item/reagent_containers/food/snacks/hugemushroomslice = 1)
- response_help = "pets"
- response_disarm = "gently pushes aside"
- response_harm = "whacks"
+ response_help_continuous = "pets"
+ response_help_simple = "pet"
+ response_disarm_continuous = "gently pushes aside"
+ response_disarm_simple = "gently push aside"
+ response_harm_continuous = "whacks"
+ response_harm_simple = "whack"
harm_intent_damage = 5
obj_damage = 0
melee_damage_lower = 1
melee_damage_upper = 1
attack_same = 2
- attacktext = "chomps"
+ attack_verb_continuous = "chomps"
+ attack_verb_simple = "chomp"
attack_sound = 'sound/weapons/bite.ogg'
faction = list("mushroom")
environment_smash = ENVIRONMENT_SMASH_NONE
diff --git a/code/modules/mob/living/simple_animal/hostile/nanotrasen.dm b/code/modules/mob/living/simple_animal/hostile/nanotrasen.dm
index ed2a407b8e..8653c40cea 100644
--- a/code/modules/mob/living/simple_animal/hostile/nanotrasen.dm
+++ b/code/modules/mob/living/simple_animal/hostile/nanotrasen.dm
@@ -9,9 +9,6 @@
mob_biotypes = MOB_ORGANIC|MOB_HUMANOID
speak_chance = 12
turns_per_move = 5
- response_help = "pokes"
- response_disarm = "shoves"
- response_harm = "hits"
speed = 0
stat_attack = UNCONSCIOUS
robust_searching = 1
@@ -20,7 +17,8 @@
harm_intent_damage = 5
melee_damage_lower = 10
melee_damage_upper = 15
- attacktext = "punches"
+ attack_verb_continuous = "punches"
+ attack_verb_simple = "punch"
attack_sound = 'sound/weapons/punch1.ogg'
a_intent = INTENT_HARM
loot = list(/obj/effect/mob_spawn/human/corpse/nanotrasensoldier)
@@ -31,7 +29,7 @@
speak = list("Stop resisting!", "I AM THE LAW!", "Face the wrath of the golden bolt!", "Stop breaking the law, asshole!")
search_objects = 1
- do_footstep = TRUE
+ footstep_type = FOOTSTEP_MOB_SHOE
/mob/living/simple_animal/hostile/nanotrasen/Aggro()
diff --git a/code/modules/mob/living/simple_animal/hostile/netherworld.dm b/code/modules/mob/living/simple_animal/hostile/netherworld.dm
index 1c8b171738..ca5d047326 100644
--- a/code/modules/mob/living/simple_animal/hostile/netherworld.dm
+++ b/code/modules/mob/living/simple_animal/hostile/netherworld.dm
@@ -11,7 +11,8 @@
melee_damage_lower = 25
melee_damage_upper = 50
threat = 2
- attacktext = "slashes"
+ attack_verb_continuous = "slashes"
+ attack_verb_simple = "slash"
attack_sound = 'sound/weapons/bladeslice.ogg'
faction = list("creature")
speak_emote = list("screams")
@@ -27,7 +28,8 @@
icon_state = "mi-go"
icon_living = "mi-go"
icon_dead = "mi-go-dead"
- attacktext = "lacerates"
+ attack_verb_continuous = "lacerates"
+ attack_verb_simple = "lacerate"
speed = -0.5
var/static/list/migo_sounds
deathmessage = "wails as its form turns into a pulpy mush."
@@ -63,7 +65,8 @@
maxHealth = 100
melee_damage_lower = 5
melee_damage_upper = 10
- attacktext = "punches"
+ attack_verb_continuous = "punches"
+ attack_verb_simple = "punch"
deathmessage = "falls apart into a fine dust."
/obj/structure/spawner/nether
diff --git a/code/modules/mob/living/simple_animal/hostile/pirate.dm b/code/modules/mob/living/simple_animal/hostile/pirate.dm
index d8737d1edc..0544ddc676 100644
--- a/code/modules/mob/living/simple_animal/hostile/pirate.dm
+++ b/code/modules/mob/living/simple_animal/hostile/pirate.dm
@@ -8,9 +8,8 @@
mob_biotypes = MOB_ORGANIC|MOB_HUMANOID
speak_chance = 0
turns_per_move = 5
- response_help = "pushes"
- response_disarm = "shoves"
- response_harm = "hits"
+ response_help_continuous = "pushes"
+ response_help_simple = "push"
threat = 3
speed = 0
maxHealth = 115
@@ -19,7 +18,8 @@
harm_intent_damage = 5
melee_damage_lower = 10
melee_damage_upper = 10
- attacktext = "punches"
+ attack_verb_continuous = "punches"
+ attack_verb_simple = "punch"
attack_sound = 'sound/weapons/punch1.ogg'
a_intent = INTENT_HARM
atmos_requirements = list("min_oxy" = 5, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 1, "min_co2" = 0, "max_co2" = 5, "min_n2" = 0, "max_n2" = 0)
@@ -39,11 +39,12 @@
melee_damage_lower = 30
melee_damage_upper = 30
armour_penetration = 35
- attacktext = "slashes"
+ attack_verb_continuous = "slashes"
+ attack_verb_simple = "slash"
attack_sound = 'sound/weapons/blade1.ogg'
var/obj/effect/light_emitter/red_energy_sword/sord
- do_footstep = TRUE
+ footstep_type = FOOTSTEP_MOB_SHOE
/mob/living/simple_animal/hostile/pirate/melee/space
name = "Space Pirate Swashbuckler"
diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/bat.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/bat.dm
index cc17759cc6..9045ccef51 100644
--- a/code/modules/mob/living/simple_animal/hostile/retaliate/bat.dm
+++ b/code/modules/mob/living/simple_animal/hostile/retaliate/bat.dm
@@ -7,9 +7,12 @@
icon_gib = "bat_dead"
turns_per_move = 1
blood_volume = 250
- response_help = "brushes aside"
- response_disarm = "flails at"
- response_harm = "hits"
+ response_help_continuous = "brushes aside"
+ response_help_simple = "brush aside"
+ response_disarm_continuous = "flails at"
+ response_disarm_simple = "flail at"
+ response_harm_continuous = "hits"
+ response_harm_simple = "hit"
mob_biotypes = MOB_ORGANIC|MOB_BEAST
speak_chance = 0
maxHealth = 15
@@ -19,7 +22,8 @@
harm_intent_damage = 6
melee_damage_lower = 6
melee_damage_upper = 5
- attacktext = "bites"
+ attack_verb_continuous = "bites"
+ attack_verb_simple = "bite"
butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab = 1)
pass_flags = PASSTABLE
faction = list("hostile")
@@ -47,5 +51,6 @@
icon_gib = "secbat_dead"
desc = "A fruit bat with a tiny little security hat who is ready to inject cuteness into any security operation."
emote_see = list("is ready to law down the law.", "flaps about with an air of authority.")
- response_help = "respects the authority of"
+ response_help_continuous = "respects the authority of"
+ response_help_simple = "respect the authority of"
gold_core_spawnable = FRIENDLY_SPAWN
diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/clown.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/clown.dm
index c94046329b..35f2817028 100644
--- a/code/modules/mob/living/simple_animal/hostile/retaliate/clown.dm
+++ b/code/modules/mob/living/simple_animal/hostile/retaliate/clown.dm
@@ -8,8 +8,10 @@
icon_gib = "clown_gib"
mob_biotypes = MOB_ORGANIC|MOB_HUMANOID
turns_per_move = 5
- response_disarm = "gently pushes aside"
- response_harm = "robusts"
+ response_disarm_continuous = "gently pushes aside"
+ response_disarm_simple = "gently push aside"
+ response_harm_continuous = "robusts"
+ response_harm_simple = "robust"
speak = list("HONK", "Honk!", "Welcome to clown planet!")
emote_see = list("honks", "squeaks")
speak_chance = 1
@@ -30,6 +32,7 @@
minbodytemp = 270
maxbodytemp = 370
unsuitable_atmos_damage = 10
+ footstep_type = FOOTSTEP_MOB_SHOE
var/banana_time = 0 // If there's no time set it won't spawn.
var/banana_type = /obj/item/grown/bananapeel
var/attack_reagent
@@ -69,8 +72,10 @@
icon_state = "lube"
icon_living = "lube"
turns_per_move = 1
- response_help = "dips a finger into"
- response_disarm = "gently scoops and pours aside"
+ response_help_continuous = "dips a finger into"
+ response_help_simple = "dip a finger into"
+ response_disarm_continuous = "gently scoops and pours aside"
+ response_disarm_simple = "gently scoop and pour aside"
emote_see = list("bubbles", "oozes")
loot = list(/obj/item/clothing/mask/gas/clown_hat, /obj/effect/particle_effect/foam)
@@ -83,8 +88,10 @@
desc = "A fusion of clown and banana DNA birthed from a botany experiment gone wrong."
icon_state = "banana tree"
icon_living = "banana tree"
- response_disarm = "peels"
- response_harm = "peels"
+ response_disarm_continuous = "peels"
+ response_disarm_simple = "peel"
+ response_harm_continuous = "peels"
+ response_harm_simple = "peel"
turns_per_move = 1
speak = list("HONK", "Honk!", "YA-HONK!!!")
emote_see = list("honks", "bites into the banana", "plucks a banana off its head", "photosynthesizes")
@@ -104,7 +111,8 @@
harm_intent_damage = 1
melee_damage_lower = 1
melee_damage_upper = 1
- attacktext = "cheers up"
+ attack_verb_continuous = "cheers up"
+ attack_verb_simple = "cheer up"
loot = list(/obj/item/clothing/mask/gas/clown_hat, /obj/effect/gibspawner/human, /obj/item/soap, /obj/item/seeds/banana/bluespace)
banana_type = /obj/item/grown/bananapeel
attack_reagent = /datum/reagent/consumable/laughter
@@ -114,9 +122,12 @@
desc = "A being forged out of the pure essence of pranking, cursed into existence by a cruel maker."
icon_state = "fleshclown"
icon_living = "fleshclown"
- response_help = "reluctantly pokes"
- response_disarm = "sinks his hands into the spongy flesh of"
- response_harm = "cleanses the world of"
+ response_help_continuous = "reluctantly pokes"
+ response_help_simple = "reluctantly poke"
+ response_disarm_continuous = "sinks his hands into the spongy flesh of"
+ response_disarm_simple = "sink your hands into the spongy flesh of"
+ response_harm_continuous = "cleanses the world of"
+ response_harm_simple = "cleanse the world of"
speak = list("HONK", "Honk!", "I didn't ask for this", "I feel constant and horrible pain", "YA-HONK!!!", "this body is a merciless and unforgiving prison", "I was born out of mirthful pranking but I live in suffering")
emote_see = list("honks", "sweats", "jiggles", "contemplates its existence")
speak_chance = 5
@@ -126,7 +137,8 @@
health = 140
speed = -5
melee_damage_upper = 15
- attacktext = "limply slaps"
+ attack_verb_continuous = "limply slaps"
+ attack_verb_simple = "limply slap"
obj_damage = 5
loot = list(/obj/item/clothing/suit/hooded/bloated_human, /obj/item/clothing/mask/gas/clown_hat, /obj/effect/gibspawner/human, /obj/item/soap)
@@ -137,9 +149,12 @@
icon_living = "long face"
move_resist = INFINITY
turns_per_move = 10
- response_help = "tries to awkwardly hug"
- response_disarm = "pushes the unwieldy frame of"
- response_harm = "tries to shut up"
+ response_help_continuous = "tries to awkwardly hug"
+ response_help_simple = "try to awkwardly hug"
+ response_disarm_continuous = "pushes the unwieldy frame of"
+ response_disarm_simple = "push the unwieldy frame of"
+ response_harm_continuous = "tries to shut up"
+ response_harm_simple = "try to shut up"
speak = list("YA-HONK!!!")
emote_see = list("honks", "squeaks")
speak_chance = 60
@@ -149,7 +164,8 @@
speed = 10
harm_intent_damage = 5
melee_damage_lower = 5
- attacktext = "YA-HONKs"
+ attack_verb_continuous = "YA-HONKs"
+ attack_verb_simple = "YA-HONK"
loot = list(/obj/item/clothing/mask/gas/clown_hat, /obj/effect/gibspawner/human, /obj/item/soap)
/mob/living/simple_animal/hostile/retaliate/clown/clownhulk
@@ -158,9 +174,12 @@
icon_state = "honkhulk"
icon_living = "honkhulk"
move_resist = INFINITY
- response_help = "tries desperately to appease"
- response_disarm = "foolishly pushes"
- response_harm = "angers"
+ response_help_continuous = "tries desperately to appease"
+ response_help_simple = "tries desperately to appease"
+ response_disarm_continuous = "foolishly pushes"
+ response_disarm_simple = "foolishly push"
+ response_harm_continuous = "angers"
+ response_harm_simple = "anger"
speak = list("HONK", "Honk!", "HAUAUANK!!!", "GUUURRRRAAAHHH!!!")
emote_see = list("honks", "sweats", "grunts")
speak_chance = 5
@@ -171,7 +190,8 @@
harm_intent_damage = 15
melee_damage_lower = 15
melee_damage_upper = 20
- attacktext = "pummels"
+ attack_verb_continuous = "pummels"
+ attack_verb_simple = "pummel"
obj_damage = 30
environment_smash = ENVIRONMENT_SMASH_WALLS
loot = list(/obj/item/clothing/mask/gas/clown_hat, /obj/effect/gibspawner/human, /obj/item/soap)
@@ -181,16 +201,20 @@
desc = "A real lunkhead who somehow gets all the girls."
icon_state = "chlown"
icon_living = "chlown"
- response_help = "submits to"
- response_disarm = "tries to assert dominance over"
- response_harm = "makes a weak beta attack at"
+ response_help_continuous = "submits to"
+ response_help_simple = "submit to"
+ response_disarm_continuous = "tries to assert dominance over"
+ response_disarm_simple = "try to assert dominance over"
+ response_harm_continuous = "makes a weak beta attack at"
+ response_harm_simple = "make a weak beta attack at"
speak = list("HONK", "Honk!", "Bruh", "cheeaaaahhh?")
emote_see = list("asserts his dominance", "emasculates everyone implicitly")
maxHealth = 500
health = 500
speed = -2
armour_penetration = 20
- attacktext = "steals the girlfriend of"
+ attack_verb_continuous = "steals the girlfriend of"
+ attack_verb_simple = "steal the girlfriend of"
attack_sound = 'sound/items/airhorn2.ogg'
loot = list(/obj/item/clothing/mask/gas/clown_hat, /obj/effect/gibspawner/human, /obj/effect/particle_effect/foam, /obj/item/soap)
@@ -199,8 +223,10 @@
desc = "A slender wiry figure of alchemical origin."
icon_state = "honkmunculus"
icon_living = "honkmunculus"
- response_help = "skeptically pokes"
- response_disarm = "pushes the unwieldy frame of"
+ response_help_continuous = "skeptically pokes"
+ response_help_simple = "skeptically poke"
+ response_disarm_continuous = "pushes the unwieldy frame of"
+ response_disarm_simple = "push the unwieldy frame of"
speak = list("honk")
emote_see = list("squirms", "writhes")
speak_chance = 1
@@ -210,7 +236,8 @@
harm_intent_damage = 5
melee_damage_lower = 5
melee_damage_upper = 10
- attacktext = "ferociously mauls"
+ attack_verb_continuous = "ferociously mauls"
+ attack_verb_simple = "ferociously maul"
environment_smash = ENVIRONMENT_SMASH_NONE
loot = list(/obj/item/clothing/mask/gas/clown_hat, /obj/effect/gibspawner/xeno/bodypartless, /obj/effect/particle_effect/foam, /obj/item/soap)
attack_reagent = /datum/reagent/peaceborg_confuse
@@ -220,8 +247,10 @@
desc = "An ancient being born of arcane honking."
icon_state = "destroyer"
icon_living = "destroyer"
- response_disarm = "bounces off of"
- response_harm = "bounces off of"
+ response_disarm_continuous = "bounces off of"
+ response_disarm_simple = "bounce off of"
+ response_harm_continuous = "bounces off of"
+ response_harm_simple = "bounce off ot"
speak = list("HONK!!!", "The Honkmother is merciful, so I must act out her wrath.", "parce mihi ad beatus honkmother placet mihi ut peccata committere,", "DIE!!!")
maxHealth = 400
health = 400
@@ -231,7 +260,8 @@
melee_damage_upper = 40
armour_penetration = 30
stat_attack = UNCONSCIOUS
- attacktext = "acts out divine vengeance on"
+ attack_verb_continuous = "acts out divine vengeance on"
+ attack_verb_simple = "act out divine vengeance on"
obj_damage = 50
environment_smash = ENVIRONMENT_SMASH_RWALLS
loot = list(/obj/item/clothing/mask/gas/clown_hat, /obj/effect/gibspawner/human, /obj/effect/particle_effect/foam, /obj/item/soap)
@@ -243,9 +273,12 @@
icon_living = "mutant"
move_resist = INFINITY
turns_per_move = 10
- response_help = "reluctantly sinks a finger into"
- response_disarm = "squishes into"
- response_harm = "squishes into"
+ response_help_continuous = "reluctantly sinks a finger into"
+ response_help_simple = "reluctantly sink a finger into"
+ response_disarm_continuous = "squishes into"
+ response_disarm_simple = "squish into"
+ response_harm_continuous = "squishes into"
+ response_harm_simple = "squish into"
speak = list("aaaaaahhhhuuhhhuhhhaaaaa", "AAAaaauuuaaAAAaauuhhh", "huuuuuh... hhhhuuuooooonnnnkk", "HuaUAAAnKKKK")
emote_see = list("squirms", "writhes", "pulsates", "froths", "oozes")
speak_chance = 10
@@ -256,7 +289,8 @@
harm_intent_damage = 10
melee_damage_lower = 10
melee_damage_upper = 20
- attacktext = "awkwardly flails at"
+ attack_verb_continuous = "awkwardly flails at"
+ attack_verb_simple = "awkwardly flail at"
loot = list(/obj/item/clothing/mask/gas/clown_hat, /obj/effect/gibspawner/xeno/bodypartless, /obj/item/soap, /obj/effect/gibspawner/generic, /obj/effect/gibspawner/generic/animal, /obj/effect/gibspawner/human/bodypartless, /obj/effect/gibspawner/human)
/mob/living/simple_animal/hostile/retaliate/clown/mutant/blob
@@ -269,6 +303,7 @@
health = 130
mob_size = MOB_SIZE_LARGE
speed = 20
- attacktext = "bounces off of"
+ attack_verb_continuous = "bounces off of"
+ attack_verb_simple = "bounce off of"
loot = list(/obj/item/clothing/mask/gas/clown_hat, /obj/effect/gibspawner/xeno/bodypartless, /obj/effect/particle_effect/foam, /obj/item/soap, /obj/effect/gibspawner/generic, /obj/effect/gibspawner/generic/animal, /obj/effect/gibspawner/human/bodypartless, /obj/effect/gibspawner/human)
attack_reagent = /datum/reagent/toxin/mindbreaker
diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/frog.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/frog.dm
index ef51d8621b..8424a0a576 100644
--- a/code/modules/mob/living/simple_animal/hostile/retaliate/frog.dm
+++ b/code/modules/mob/living/simple_animal/hostile/retaliate/frog.dm
@@ -13,10 +13,14 @@
health = 15
melee_damage_lower = 5
melee_damage_upper = 5
- attacktext = "bites"
- response_help = "pets"
- response_disarm = "pokes"
- response_harm = "splats"
+ attack_verb_continuous = "bites"
+ attack_verb_simple = "bite"
+ response_help_continuous = "pets"
+ response_help_simple = "pet"
+ response_disarm_continuous = "pokes"
+ response_disarm_simple = "poke"
+ response_harm_continuous = "splats"
+ response_harm_simple = "splat"
density = FALSE
ventcrawler = VENTCRAWLER_ALWAYS
faction = list("hostile")
diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/ghost.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/ghost.dm
index 48d16f63f3..2c94739180 100644
--- a/code/modules/mob/living/simple_animal/hostile/retaliate/ghost.dm
+++ b/code/modules/mob/living/simple_animal/hostile/retaliate/ghost.dm
@@ -7,9 +7,12 @@
mob_biotypes = MOB_SPIRIT
speak_chance = 0
turns_per_move = 5
- response_help = "passes through"
- response_disarm = "shoves"
- response_harm = "hits"
+ response_help_continuous = "passes through"
+ response_help_simple = "pass through"
+ response_disarm_continuous = "shoves"
+ response_disarm_simple = "shove"
+ response_harm_continuous = "hits"
+ response_harm_simple = "hit"
a_intent = INTENT_HARM
healable = 0
speed = 0
@@ -20,7 +23,8 @@
melee_damage_upper = 15
del_on_death = 1
emote_see = list("weeps silently", "groans", "mumbles")
- attacktext = "grips"
+ attack_verb_continuous = "grips"
+ attack_verb_simple = "grip"
attack_sound = 'sound/hallucinations/growl1.ogg'
speak_emote = list("weeps")
deathmessage = "wails, disintegrating into a pile of ectoplasm!"
@@ -32,6 +36,7 @@
pressure_resistance = 300
gold_core_spawnable = NO_SPAWN //too spooky for science
blood_volume = 0
+ has_field_of_vision = FALSE
var/ghost_hair_style
var/ghost_hair_color
var/mutable_appearance/ghost_hair
diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/spaceman.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/spaceman.dm
index 29b0c0b701..ebeb2d28ec 100644
--- a/code/modules/mob/living/simple_animal/hostile/retaliate/spaceman.dm
+++ b/code/modules/mob/living/simple_animal/hostile/retaliate/spaceman.dm
@@ -8,9 +8,12 @@
mob_biotypes = MOB_ORGANIC|MOB_HUMANOID
gender = MALE
turns_per_move = 5
- response_help = "pokes"
- response_disarm = "gently pushes aside"
- response_harm = "punches"
+ response_help_continuous = "pokes"
+ response_help_simple = "poke"
+ response_disarm_continuous = "gently pushes aside"
+ response_disarm_simple = "gently push aside"
+ response_harm_continuous = "punches"
+ response_harm_simple = "punch"
a_intent = INTENT_HARM
maxHealth = 100
health = 100
@@ -18,13 +21,14 @@
harm_intent_damage = 8
melee_damage_lower = 10
melee_damage_upper = 10
- attacktext = "hits"
+ attack_verb_continuous = "hits"
+ attack_verb_simple = "hit"
attack_sound = 'sound/weapons/punch1.ogg'
obj_damage = 0
environment_smash = ENVIRONMENT_SMASH_NONE
del_on_death = 0
-
- do_footstep = TRUE
+ footstep_type = FOOTSTEP_MOB_SHOE
+ has_field_of_vision = FALSE //Legacy gameplay experience. Also they only have one dir visually.
/mob/living/simple_animal/hostile/retaliate/nanotrasenpeace //this should be in a different file
name = "Nanotrasen Private Security Officer"
@@ -35,9 +39,12 @@
icon_dead = null
icon_gib = "syndicate_gib"
turns_per_move = 5
- response_help = "pokes"
- response_disarm = "shoves"
- response_harm = "hits"
+ response_help_continuous = "pokes"
+ response_help_simple = "poke"
+ response_disarm_continuous = "shoves"
+ response_disarm_simple = "shove"
+ response_harm_continuous = "hits"
+ response_harm_simple = "hit"
speed = 0
stat_attack = UNCONSCIOUS
robust_searching = 1
@@ -47,7 +54,8 @@
harm_intent_damage = 5
melee_damage_lower = 10
melee_damage_upper = 15
- attacktext = "punches"
+ attack_verb_continuous = "punches"
+ attack_verb_simple = "punch"
attack_sound = 'sound/weapons/punch1.ogg'
faction = list("nanotrasenprivate")
a_intent = INTENT_HARM
diff --git a/code/modules/mob/living/simple_animal/hostile/russian.dm b/code/modules/mob/living/simple_animal/hostile/russian.dm
index 9c3e3e0b92..f7a46658c4 100644
--- a/code/modules/mob/living/simple_animal/hostile/russian.dm
+++ b/code/modules/mob/living/simple_animal/hostile/russian.dm
@@ -9,9 +9,6 @@
mob_biotypes = MOB_ORGANIC|MOB_HUMANOID
speak_chance = 0
turns_per_move = 5
- response_help = "pokes"
- response_disarm = "shoves"
- response_harm = "hits"
speed = 0
threat = 1
maxHealth = 100
@@ -19,7 +16,8 @@
harm_intent_damage = 5
melee_damage_lower = 15
melee_damage_upper = 15
- attacktext = "punches"
+ attack_verb_continuous = "punches"
+ attack_verb_simple = "punch"
attack_sound = 'sound/weapons/punch1.ogg'
a_intent = INTENT_HARM
loot = list(/obj/effect/mob_spawn/human/corpse/russian,
@@ -30,7 +28,7 @@
status_flags = CANPUSH
del_on_death = 1
- do_footstep = TRUE
+ footstep_type = FOOTSTEP_MOB_SHOE
/mob/living/simple_animal/hostile/russian/ranged
diff --git a/code/modules/mob/living/simple_animal/hostile/sharks.dm b/code/modules/mob/living/simple_animal/hostile/sharks.dm
index 4008334a57..1263a23d26 100644
--- a/code/modules/mob/living/simple_animal/hostile/sharks.dm
+++ b/code/modules/mob/living/simple_animal/hostile/sharks.dm
@@ -12,9 +12,12 @@
speak_chance = 0
turns_per_move = 3
butcher_results = list(/obj/item/reagent_containers/food/snacks/carpmeat = 3)
- response_help = "pets"
- response_disarm = "gently pushes aside"
- response_harm = "hits"
+ response_help_continuous = "pets"
+ response_help_simple = "pet"
+ response_disarm_continuous = "gently pushes aside"
+ response_disarm_simple = "gently push aside"
+ response_harm_continuous = "kicks"
+ response_harm_simple = "kick"
speed = 0
threat = 1
maxHealth = 75
@@ -22,7 +25,8 @@
harm_intent_damage = 18
melee_damage_lower = 18
melee_damage_upper = 18
- attacktext = "maims"
+ attack_verb_continuous = "maims"
+ attack_verb_simple = "maim"
attack_sound = 'sound/weapons/bite.ogg'
gold_core_spawnable = 1
//Space shark aren't affected by cold.
@@ -82,7 +86,8 @@
harm_intent_damage = 0
melee_damage_lower = 0
melee_damage_upper = 0
- attacktext = "violently hugs"
+ attack_verb_continuous = "violently hugs"
+ attack_verb_simple = "violently hug"
vision_range = 0
/mob/living/simple_animal/hostile/shark/kawaii/death()
diff --git a/code/modules/mob/living/simple_animal/hostile/skeleton.dm b/code/modules/mob/living/simple_animal/hostile/skeleton.dm
index df71701bb7..f3138a773c 100644
--- a/code/modules/mob/living/simple_animal/hostile/skeleton.dm
+++ b/code/modules/mob/living/simple_animal/hostile/skeleton.dm
@@ -22,7 +22,8 @@
minbodytemp = 0
maxbodytemp = 1500
healable = 0 //they're skeletons how would bruise packs help them??
- attacktext = "slashes"
+ attack_verb_continuous = "slashes"
+ attack_verb_simple = "slash"
attack_sound = 'sound/hallucinations/growl1.ogg'
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
unsuitable_atmos_damage = 10
@@ -36,7 +37,7 @@
del_on_death = 1
loot = list(/obj/effect/decal/remains/human)
- do_footstep = TRUE
+ footstep_type = FOOTSTEP_MOB_SHOE
/mob/living/simple_animal/hostile/skeleton/eskimo
name = "undead eskimo"
@@ -104,7 +105,8 @@
melee_damage_lower = 15
melee_damage_upper = 20
light_color = LIGHT_COLOR_PURPLE
- attacktext = "slashes"
+ attack_verb_continuous = "slashes"
+ attack_verb_simple = "slash"
attack_sound = 'sound/hallucinations/growl1.ogg'
deathmessage = "collapses into a pile of bones, their suit dissolving among the plasma!"
loot = list(/obj/effect/decal/remains/plasma)
@@ -120,7 +122,8 @@
harm_intent_damage = 15
melee_damage_lower = 20
melee_damage_upper = 25
- attacktext = "blasts"
+ attack_verb_continuous = "blasts"
+ attack_verb_simple = "blast"
attack_sound = 'sound/weapons/sonic_jackhammer.ogg'
loot = list(/obj/effect/decal/remains/plasma, /obj/item/pickaxe/drill/jackhammer)
diff --git a/code/modules/mob/living/simple_animal/hostile/statue.dm b/code/modules/mob/living/simple_animal/hostile/statue.dm
index 8c622c7f29..23304a2ef3 100644
--- a/code/modules/mob/living/simple_animal/hostile/statue.dm
+++ b/code/modules/mob/living/simple_animal/hostile/statue.dm
@@ -11,9 +11,10 @@
a_intent = INTENT_HARM
mob_biotypes = MOB_HUMANOID
threat = 3
- response_help = "touches"
- response_disarm = "pushes"
-
+ response_help_continuous = "touches"
+ response_help_simple = "touch"
+ response_disarm_continuous = "pushes"
+ response_disarm_simple = "push"
speed = -1
maxHealth = 50000
health = 50000
@@ -24,7 +25,8 @@
obj_damage = 100
melee_damage_lower = 68
melee_damage_upper = 83
- attacktext = "claws"
+ attack_verb_continuous = "claws"
+ attack_verb_simple = "claw"
attack_sound = 'sound/hallucinations/growl1.ogg'
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
@@ -125,14 +127,10 @@
// This loop will, at most, loop twice.
for(var/atom/check in check_list)
- for(var/mob/living/M in viewers(world.view + 1, check) - src)
+ for(var/mob/living/M in fov_viewers(world.view + 1, check) - src)
if(M.client && CanAttack(M) && !M.silicon_privileges)
if(!M.eye_blind)
return M
- for(var/obj/mecha/M in view(world.view + 1, check)) //assuming if you can see them they can see you
- if(M.occupant && M.occupant.client)
- if(!M.occupant.eye_blind)
- return M.occupant
return null
// Cannot talk
diff --git a/code/modules/mob/living/simple_animal/hostile/stickman.dm b/code/modules/mob/living/simple_animal/hostile/stickman.dm
index 24bf5e9ea9..2edcc4021a 100644
--- a/code/modules/mob/living/simple_animal/hostile/stickman.dm
+++ b/code/modules/mob/living/simple_animal/hostile/stickman.dm
@@ -10,9 +10,6 @@
gender = MALE
speak_chance = 0
turns_per_move = 5
- response_help = "pokes"
- response_disarm = "shoves"
- response_harm = "hits"
speed = 0
blood_volume = 0
stat_attack = UNCONSCIOUS
@@ -24,7 +21,8 @@
obj_damage = 0
melee_damage_lower = 10
melee_damage_upper = 10
- attacktext = "punches"
+ attack_verb_continuous = "punches"
+ attack_verb_simple = "punch"
attack_sound = 'sound/weapons/punch1.ogg'
a_intent = INTENT_HARM
atmos_requirements = list("min_oxy" = 5, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 1, "min_co2" = 0, "max_co2" = 5, "min_n2" = 0, "max_n2" = 0)
diff --git a/code/modules/mob/living/simple_animal/hostile/syndicate.dm b/code/modules/mob/living/simple_animal/hostile/syndicate.dm
index 8c4e19774d..9a362b680d 100644
--- a/code/modules/mob/living/simple_animal/hostile/syndicate.dm
+++ b/code/modules/mob/living/simple_animal/hostile/syndicate.dm
@@ -25,9 +25,6 @@
mob_biotypes = MOB_ORGANIC|MOB_HUMANOID
speak_chance = 0
turns_per_move = 5
- response_help = "pokes"
- response_disarm = "shoves"
- response_harm = "hits"
threat = 1
speed = 0
stat_attack = UNCONSCIOUS
@@ -37,7 +34,8 @@
harm_intent_damage = 5
melee_damage_lower = 10
melee_damage_upper = 10
- attacktext = "punches"
+ attack_verb_continuous = "punches"
+ attack_verb_simple = "punch"
attack_sound = 'sound/weapons/punch1.ogg'
a_intent = INTENT_HARM
loot = list(/obj/effect/mob_spawn/human/corpse/syndicatesoldier)
@@ -50,7 +48,7 @@
dodging = TRUE
rapid_melee = 2
- do_footstep = TRUE
+ footstep_type = FOOTSTEP_MOB_SHOE
///////////////Melee////////////
@@ -82,7 +80,8 @@
icon_state = "syndicate_knife"
icon_living = "syndicate_knife"
loot = list(/obj/effect/gibspawner/human)
- attacktext = "slashes"
+ attack_verb_continuous = "slashes"
+ attack_verb_simple = "slash"
attack_sound = 'sound/weapons/bladeslice.ogg'
status_flags = 0
@@ -113,7 +112,8 @@
melee_damage_upper = 30
icon_state = "syndicate_sword"
icon_living = "syndicate_sword"
- attacktext = "slashes"
+ attack_verb_continuous = "slashes"
+ attack_verb_simple = "slash"
attack_sound = 'sound/weapons/blade1.ogg'
armour_penetration = 35
light_color = LIGHT_COLOR_RED
@@ -292,7 +292,8 @@
melee_damage_upper = 15
obj_damage = 0
environment_smash = ENVIRONMENT_SMASH_NONE
- attacktext = "cuts"
+ attack_verb_continuous = "cuts"
+ attack_verb_simple = "cut"
attack_sound = 'sound/weapons/bladeslice.ogg'
faction = list(ROLE_SYNDICATE)
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
diff --git a/code/modules/mob/living/simple_animal/hostile/tree.dm b/code/modules/mob/living/simple_animal/hostile/tree.dm
index bc932666f6..3aa3c9e566 100644
--- a/code/modules/mob/living/simple_animal/hostile/tree.dm
+++ b/code/modules/mob/living/simple_animal/hostile/tree.dm
@@ -10,9 +10,12 @@
threat = 1
speak_chance = 0
turns_per_move = 5
- response_help = "brushes"
- response_disarm = "pushes"
- response_harm = "hits"
+ response_help_continuous = "brushes"
+ response_help_simple = "brush"
+ response_disarm_continuous = "pushes"
+ response_disarm_simple = "push"
+ response_harm_continuous = "hits"
+ response_harm_simple = "hit"
speed = 1
maxHealth = 250
health = 250
@@ -23,7 +26,8 @@
harm_intent_damage = 5
melee_damage_lower = 8
melee_damage_upper = 12
- attacktext = "bites"
+ attack_verb_continuous = "bites"
+ attack_verb_simple = "bite"
attack_sound = 'sound/weapons/bite.ogg'
speak_emote = list("pines")
emote_taunt = list("growls")
diff --git a/code/modules/mob/living/simple_animal/hostile/wizard.dm b/code/modules/mob/living/simple_animal/hostile/wizard.dm
index 15d641299d..57fb6f829d 100644
--- a/code/modules/mob/living/simple_animal/hostile/wizard.dm
+++ b/code/modules/mob/living/simple_animal/hostile/wizard.dm
@@ -8,9 +8,6 @@
mob_biotypes = MOB_ORGANIC|MOB_HUMANOID
speak_chance = 0
turns_per_move = 3
- response_help = "pokes"
- response_disarm = "shoves"
- response_harm = "hits"
threat = 3
speed = 0
maxHealth = 100
@@ -18,7 +15,8 @@
harm_intent_damage = 5
melee_damage_lower = 5
melee_damage_upper = 5
- attacktext = "punches"
+ attack_verb_continuous = "punches"
+ attack_verb_simple = "punch"
attack_sound = 'sound/weapons/punch1.ogg'
a_intent = INTENT_HARM
atmos_requirements = list("min_oxy" = 5, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 1, "min_co2" = 0, "max_co2" = 5, "min_n2" = 0, "max_n2" = 0)
@@ -38,7 +36,7 @@
var/next_cast = 0
- do_footstep = TRUE
+ footstep_type = FOOTSTEP_MOB_SHOE
/mob/living/simple_animal/hostile/wizard/Initialize()
. = ..()
diff --git a/code/modules/mob/living/simple_animal/hostile/wumborian_fugu.dm b/code/modules/mob/living/simple_animal/hostile/wumborian_fugu.dm
index 8878f17893..5c881a7b0d 100644
--- a/code/modules/mob/living/simple_animal/hostile/wumborian_fugu.dm
+++ b/code/modules/mob/living/simple_animal/hostile/wumborian_fugu.dm
@@ -12,7 +12,8 @@
mouse_opacity = MOUSE_OPACITY_ICON
move_to_delay = 5
threat = 1
- friendly = "floats near"
+ friendly_verb_continuous = "floats near"
+ friendly_verb_simple = "float near"
speak_emote = list("puffs")
vision_range = 5
speed = 0
@@ -23,7 +24,8 @@
obj_damage = 0
melee_damage_lower = 0
melee_damage_upper = 0
- attacktext = "chomps"
+ attack_verb_continuous = "chomps"
+ attack_verb_simple = "chomp"
attack_sound = 'sound/weapons/punch1.ogg'
throw_message = "is avoided by the"
vision_range = 5
diff --git a/code/modules/mob/living/simple_animal/hostile/zombie.dm b/code/modules/mob/living/simple_animal/hostile/zombie.dm
index 503f5c121e..6e4cbac022 100644
--- a/code/modules/mob/living/simple_animal/hostile/zombie.dm
+++ b/code/modules/mob/living/simple_animal/hostile/zombie.dm
@@ -13,7 +13,8 @@
harm_intent_damage = 5
melee_damage_lower = 21
melee_damage_upper = 21
- attacktext = "bites"
+ attack_verb_continuous = "bites"
+ attack_verb_simple = "bite"
attack_sound = 'sound/hallucinations/growl1.ogg'
a_intent = INTENT_HARM
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
@@ -73,7 +74,8 @@
harm_intent_damage = 5
melee_damage_lower = 21
melee_damage_upper = 21
- attacktext = "bites"
+ attack_verb_continuous = "bites"
+ attack_verb_simple = "bite"
attack_sound = 'sound/hallucinations/growl1.ogg'
a_intent = INTENT_HARM
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
diff --git a/code/modules/mob/living/simple_animal/parrot.dm b/code/modules/mob/living/simple_animal/parrot.dm
index 9ad9a121ca..e8d6411c01 100644
--- a/code/modules/mob/living/simple_animal/parrot.dm
+++ b/code/modules/mob/living/simple_animal/parrot.dm
@@ -50,13 +50,18 @@
melee_damage_upper = 10
melee_damage_lower = 5
- response_help = "pets"
- response_disarm = "gently moves aside"
- response_harm = "swats"
+ response_help_continuous = "pets"
+ response_help_simple = "pet"
+ response_disarm_continuous = "gently moves aside"
+ response_disarm_simple = "gently move aside"
+ response_harm_continuous = "swats"
+ response_harm_simple = "swat"
stop_automated_movement = 1
a_intent = INTENT_HARM //parrots now start "aggressive" since only player parrots will nuzzle.
- attacktext = "chomps"
- friendly = "grooms"
+ attack_verb_continuous = "chomps"
+ attack_verb_simple = "chomp"
+ friendly_verb_continuous = "grooms"
+ friendly_verb_simple = "groom"
mob_size = MOB_SIZE_SMALL
movement_type = FLYING
gold_core_spawnable = FRIENDLY_SPAWN
@@ -575,7 +580,12 @@
parrot_state = PARROT_WANDER
return
- attacktext = pick("claws at", "chomps")
+ if(prob(50))
+ attack_verb_continuous = "claws at"
+ attack_verb_simple = "claw_at"
+ else
+ attack_verb_continuous = "chomps"
+ attack_verb_simple = "chomp"
L.attack_animal(src)//Time for the hurt to begin!
//Otherwise, fly towards the mob!
else
diff --git a/code/modules/mob/living/simple_animal/shade.dm b/code/modules/mob/living/simple_animal/shade.dm
index 6aa7f8b401..75182b85e5 100644
--- a/code/modules/mob/living/simple_animal/shade.dm
+++ b/code/modules/mob/living/simple_animal/shade.dm
@@ -13,13 +13,17 @@
healable = 0
speak_emote = list("hisses")
emote_hear = list("wails.","screeches.")
- response_help = "puts their hand through"
- response_disarm = "flails at"
- response_harm = "punches"
+ response_help_continuous = "puts their hand through"
+ response_help_simple = "put your hand through"
+ response_disarm_continuous = "flails at"
+ response_disarm_simple = "flail at"
+ response_harm_continuous = "punches"
+ response_harm_simple = "punch"
speak_chance = 1
melee_damage_lower = 5
melee_damage_upper = 12
- attacktext = "metaphysically strikes"
+ attack_verb_continuous = "metaphysically strikes"
+ attack_verb_simple = "metaphysically strike"
minbodytemp = 0
maxbodytemp = INFINITY
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
@@ -32,6 +36,7 @@
del_on_death = TRUE
initial_language_holder = /datum/language_holder/construct
blood_volume = 0
+ has_field_of_vision = FALSE //we are a spoopy ghost
/mob/living/simple_animal/shade/death()
deathmessage = "lets out a contented sigh as [p_their()] form unwinds."
diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm
index def6327461..3491fd2f95 100644
--- a/code/modules/mob/living/simple_animal/simple_animal.dm
+++ b/code/modules/mob/living/simple_animal/simple_animal.dm
@@ -4,95 +4,141 @@
health = 20
maxHealth = 20
gender = PLURAL //placeholder
- blood_volume = 550 //How much blud it has for bloodsucking
+ ///How much blud it has for bloodsucking
+ blood_volume = 550
status_flags = CANPUSH
var/icon_living = ""
- var/icon_dead = "" //icon when the animal is dead. Don't use animated icons for this.
- var/icon_gib = null //We only try to show a gibbing animation if this exists.
+ ///icon when the animal is dead. Don't use animated icons for this.
+ var/icon_dead = ""
+ ///We only try to show a gibbing animation if this exists.
+ var/icon_gib = null
var/list/speak = list()
- var/list/speak_emote = list()// Emotes while speaking IE: Ian [emote], [text] -- Ian barks, "WOOF!". Spoken text is generated from the speak variable.
+ ///Emotes while speaking IE: Ian [emote], [text] -- Ian barks, "WOOF!". Spoken text is generated from the speak variable.
+ var/list/speak_emote = list()
var/speak_chance = 0
- var/list/emote_hear = list() //Hearable emotes
- var/list/emote_see = list() //Unlike speak_emote, the list of things in this variable only show by themselves with no spoken text. IE: Ian barks, Ian yaps
+ ///Hearable emotes
+ var/list/emote_hear = list()
+ ///Unlike speak_emote, the list of things in this variable only show by themselves with no spoken text. IE: Ian barks, Ian yaps.
+ var/list/emote_see = list()
var/turns_per_move = 1
var/turns_since_move = 0
- var/stop_automated_movement = 0 //Use this to temporarely stop random movement or to if you write special movement code for animals.
- var/wander = 1 // Does the mob wander around when idle?
- var/stop_automated_movement_when_pulled = 1 //When set to 1 this stops the animal from moving when someone is pulling it.
+ ///Use this to temporarely stop random movement or to if you write special movement code for animals.
+ var/stop_automated_movement = 0
+ ///Does the mob wander around when idle?
+ var/wander = 1
+ ///When set to 1 this stops the animal from moving when someone is pulling it.
+ var/stop_automated_movement_when_pulled = 1
- //Interaction
- var/response_help = "pokes"
- var/response_disarm = "shoves"
- var/response_harm = "hits"
+ ///When someone interacts with the simple animal.
+ ///Help-intent verb in present continuous tense.
+ var/response_help_continuous = "pokes"
+ ///Help-intent verb in present simple tense.
+ var/response_help_simple = "poke"
+ ///Disarm-intent verb in present continuous tense.
+ var/response_disarm_continuous = "shoves"
+ ///Disarm-intent verb in present simple tense.
+ var/response_disarm_simple = "shove"
+ ///Harm-intent verb in present continuous tense.
+ var/response_harm_continuous = "hits"
+ ///Harm-intent verb in present simple tense.
+ var/response_harm_simple = "hit"
var/harm_intent_damage = 3
- var/force_threshold = 0 //Minimum force required to deal any damage
+ ///Minimum force required to deal any damage.
+ var/force_threshold = 0
- //Temperature effect
+ ///Temperature effect.
var/minbodytemp = 250
var/maxbodytemp = 350
- //Healable by medical stacks? Defaults to yes.
+ ///Healable by medical stacks? Defaults to yes.
var/healable = 1
- //Atmos effect - Yes, you can make creatures that require plasma or co2 to survive. N2O is a trace gas and handled separately, hence why it isn't here. It'd be hard to add it. Hard and me don't mix (Yes, yes make all the dick jokes you want with that.) - Errorage
+ ///Atmos effect - Yes, you can make creatures that require plasma or co2 to survive. N2O is a trace gas and handled separately, hence why it isn't here. It'd be hard to add it. Hard and me don't mix (Yes, yes make all the dick jokes you want with that.) - Errorage
var/list/atmos_requirements = list("min_oxy" = 5, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 1, "min_co2" = 0, "max_co2" = 5, "min_n2" = 0, "max_n2" = 0) //Leaving something at 0 means it's off - has no maximum
- var/unsuitable_atmos_damage = 2 //This damage is taken when atmos doesn't fit all the requirements above
+ ///This damage is taken when atmos doesn't fit all the requirements above.
+ var/unsuitable_atmos_damage = 2
- //LETTING SIMPLE ANIMALS ATTACK? WHAT COULD GO WRONG. Defaults to zero so Ian can still be cuddly
+ ///LETTING SIMPLE ANIMALS ATTACK? WHAT COULD GO WRONG. Defaults to zero so Ian can still be cuddly.
var/melee_damage_lower = 0
var/melee_damage_upper = 0
- var/obj_damage = 0 //how much damage this simple animal does to objects, if any
- var/armour_penetration = 0 //How much armour they ignore, as a flat reduction from the targets armour value
- var/melee_damage_type = BRUTE //Damage type of a simple mob's melee attack, should it do damage.
- var/list/damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 1, CLONE = 1, STAMINA = 0, OXY = 1) // 1 for full damage , 0 for none , -1 for 1:1 heal from that source
- var/attacktext = "attacks"
+ ///How much damage this simple animal does to objects, if any.
+ var/obj_damage = 0
+ ///How much armour they ignore, as a flat reduction from the targets armour value.
+ var/armour_penetration = 0
+ ///Damage type of a simple mob's melee attack, should it do damage.
+ var/melee_damage_type = BRUTE
+ /// 1 for full damage , 0 for none , -1 for 1:1 heal from that source.
+ var/list/damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 1, CLONE = 1, STAMINA = 0, OXY = 1)
+ ///Attacking verb in present continuous tense.
+ var/attack_verb_continuous = "attacks"
+ ///Attacking verb in present simple tense.
+ var/attack_verb_simple = "attack"
var/attack_sound = null
- var/friendly = "nuzzles" //If the mob does no damage with it's attack
- var/environment_smash = ENVIRONMENT_SMASH_NONE //Set to 1 to allow breaking of crates,lockers,racks,tables; 2 for walls; 3 for Rwalls
+ ///Attacking, but without damage, verb in present continuous tense.
+ var/friendly_verb_continuous = "nuzzles"
+ ///Attacking, but without damage, verb in present simple tense.
+ var/friendly_verb_simple = "nuzzle"
+ ///Set to 1 to allow breaking of crates,lockers,racks,tables; 2 for walls; 3 for Rwalls.
+ var/environment_smash = ENVIRONMENT_SMASH_NONE
- var/speed = 1 //LETS SEE IF I CAN SET SPEEDS FOR SIMPLE MOBS WITHOUT DESTROYING EVERYTHING. Higher speed is slower, negative speed is faster
+ ///LETS SEE IF I CAN SET SPEEDS FOR SIMPLE MOBS WITHOUT DESTROYING EVERYTHING. Higher speed is slower, negative speed is faster.
+ var/speed = 1
- //Hot simple_animal baby making vars
+ ///Hot simple_animal baby making vars.
var/list/childtype = null
var/next_scan_time = 0
- var/animal_species //Sorry, no spider+corgi buttbabies.
+ ///Sorry, no spider+corgi buttbabies.
+ var/animal_species
- //simple_animal access
- var/obj/item/card/id/access_card = null //innate access uses an internal ID card
- var/buffed = 0 //In the event that you want to have a buffing effect on the mob, but don't want it to stack with other effects, any outside force that applies a buff to a simple mob should at least set this to 1, so we have something to check against
- var/gold_core_spawnable = NO_SPAWN //If the mob can be spawned with a gold slime core. HOSTILE_SPAWN are spawned with plasma, FRIENDLY_SPAWN are spawned with blood
+ ///Innate access uses an internal ID card.
+ var/obj/item/card/id/access_card = null
+ ///In the event that you want to have a buffing effect on the mob, but don't want it to stack with other effects, any outside force that applies a buff to a simple mob should at least set this to TRUE, so we have something to check against.
+ var/buffed = FALSE
+ ///If the mob can be spawned with a gold slime core. HOSTILE_SPAWN are spawned with plasma, FRIENDLY_SPAWN are spawned with blood.
+ var/gold_core_spawnable = NO_SPAWN
var/datum/component/spawner/nest
- var/sentience_type = SENTIENCE_ORGANIC // Sentience type, for slime potions
+ ///Sentience type, for slime potions.
+ var/sentience_type = SENTIENCE_ORGANIC
- var/list/loot = list() //list of things spawned at mob's loc when it dies
- var/del_on_death = 0 //causes mob to be deleted on death, useful for mobs that spawn lootable corpses
+ ///list of things spawned at mob's loc when it dies.
+ var/list/loot = list()
+ ///causes mob to be deleted on death, useful for mobs that spawn lootable corpses.
+ var/del_on_death = FALSE
var/deathmessage = ""
- var/death_sound = null //The sound played on death
+ ///The sound played on death.
+ var/death_sound = null
var/allow_movement_on_non_turfs = FALSE
- var/attacked_sound = "punch" //Played when someone punches the creature
+ ///Played when someone punches the creature.
+ var/attacked_sound = "punch"
- var/dextrous = FALSE //If the creature has, and can use, hands
+ ///If the creature has, and can use, hands.
+ var/dextrous = FALSE
var/dextrous_hud_type = /datum/hud/dextrous
- var/AIStatus = AI_ON //The Status of our AI, can be set to AI_ON (On, usual processing), AI_IDLE (Will not process, but will return to AI_ON if an enemy comes near), AI_OFF (Off, Not processing ever), AI_Z_OFF (Temporarily off due to nonpresence of players)
- var/can_have_ai = TRUE //once we have become sentient, we can never go back
+ ///The Status of our AI, can be set to AI_ON (On, usual processing), AI_IDLE (Will not process, but will return to AI_ON if an enemy comes near), AI_OFF (Off, Not processing ever), AI_Z_OFF (Temporarily off due to nonpresence of players).
+ var/AIStatus = AI_ON
+ ///once we have become sentient, we can never go back.
+ var/can_have_ai = TRUE
- var/shouldwakeup = FALSE //convenience var for forcibly waking up an idling AI on next check.
+ ///convenience var for forcibly waking up an idling AI on next check.
+ var/shouldwakeup = FALSE
- //domestication
+ ///Domestication.
var/tame = 0
- var/my_z // I don't want to confuse this with client registered_z
+ ///I don't want to confuse this with client registered_z.
+ var/my_z
- var/do_footstep = FALSE
+ ///What kind of footstep this mob should have. Null if it shouldn't have any.
+ var/footstep_type
/mob/living/simple_animal/Initialize()
. = ..()
@@ -106,6 +152,8 @@
update_simplemob_varspeed()
if(dextrous)
AddComponent(/datum/component/personal_crafting)
+ if(footstep_type)
+ AddComponent(/datum/component/footstep, footstep_type)
/mob/living/simple_animal/Destroy()
GLOB.simple_animals[AIStatus] -= src
@@ -122,10 +170,6 @@
return ..()
-/mob/living/simple_animal/initialize_footstep()
- if(do_footstep)
- ..()
-
/mob/living/simple_animal/updatehealth()
..()
health = clamp(health, 0, maxHealth)
diff --git a/code/modules/mob/living/simple_animal/slime/powers.dm b/code/modules/mob/living/simple_animal/slime/powers.dm
index 0c7f126ad5..d93993bf1f 100644
--- a/code/modules/mob/living/simple_animal/slime/powers.dm
+++ b/code/modules/mob/living/simple_animal/slime/powers.dm
@@ -28,7 +28,7 @@
return 0
var/list/choices = list()
- for(var/mob/living/C in view(1,src))
+ for(var/mob/living/C in fov_view(1,src))
if(C!=src && Adjacent(C))
choices += C
diff --git a/code/modules/mob/living/simple_animal/slime/slime.dm b/code/modules/mob/living/simple_animal/slime/slime.dm
index 1c5916a249..0ef5cabc91 100644
--- a/code/modules/mob/living/simple_animal/slime/slime.dm
+++ b/code/modules/mob/living/simple_animal/slime/slime.dm
@@ -12,9 +12,12 @@
harm_intent_damage = 5
icon_living = "grey baby slime"
icon_dead = "grey baby slime dead"
- response_help = "pets"
- response_disarm = "shoos"
- response_harm = "stomps on"
+ response_help_continuous = "pets"
+ response_help_simple = "pet"
+ response_disarm_continuous = "shoos"
+ response_disarm_simple = "shoo"
+ response_harm_continuous = "stomps on"
+ response_harm_simple = "stomp on"
emote_see = list("jiggles", "bounces in place")
speak_emote = list("blorbles")
bubble_icon = "slime"
@@ -64,8 +67,6 @@
var/mutator_used = FALSE //So you can't shove a dozen mutators into a single slime
var/force_stasis = FALSE
- do_footstep = TRUE
-
var/static/regex/slime_name_regex = new("\\w+ (baby|adult) slime \\(\\d+\\)")
///////////TIME FOR SUBSPECIES
@@ -103,6 +104,7 @@
create_reagents(100, NONE, NO_REAGENTS_VALUE)
set_colour(new_colour)
. = ..()
+ AddComponent(/datum/component/footstep, FOOTSTEP_MOB_SLIME, 7.5)
/mob/living/simple_animal/slime/Destroy()
for (var/A in actions)
diff --git a/code/modules/mob/living/update_icons.dm b/code/modules/mob/living/update_icons.dm
index 8bf0dc98a9..f8d5d7e0ba 100644
--- a/code/modules/mob/living/update_icons.dm
+++ b/code/modules/mob/living/update_icons.dm
@@ -2,7 +2,6 @@
/mob/living/update_transform()
var/matrix/ntransform = matrix(transform) //aka transform.Copy()
var/final_pixel_y = pixel_y
- var/final_dir = dir
var/changed = 0
if(lying != lying_prev && rotate_on_lying)
changed++
@@ -14,7 +13,7 @@
pixel_y = get_standard_pixel_y_offset()
final_pixel_y = get_standard_pixel_y_offset(lying)
if(dir & (EAST|WEST)) //Facing east or west
- final_dir = pick(NORTH, SOUTH) //So you fall on your side rather than your face or ass
+ setDir(pick(NORTH, SOUTH)) //So you fall on your side rather than your face or ass
if(resize != RESIZE_DEFAULT_SIZE)
changed++
@@ -22,5 +21,5 @@
resize = RESIZE_DEFAULT_SIZE
if(changed)
- animate(src, transform = ntransform, time = 2, pixel_y = final_pixel_y, dir = final_dir, easing = EASE_IN|EASE_OUT)
- setMovetype(movement_type & ~FLOATING) // If we were without gravity, the bouncing animation got stopped, so we make sure we restart it in next life().
+ animate(src, transform = ntransform, time = 2, pixel_y = final_pixel_y, easing = EASE_IN|EASE_OUT)
+ floating_need_update = TRUE
diff --git a/code/modules/mob/login.dm b/code/modules/mob/login.dm
index c266bbddd3..b7546becd8 100644
--- a/code/modules/mob/login.dm
+++ b/code/modules/mob/login.dm
@@ -55,3 +55,5 @@
log_message("Client [key_name(src)] has taken ownership of mob [src]([src.type])", LOG_OWNERSHIP)
SEND_SIGNAL(src, COMSIG_MOB_CLIENT_LOGIN, client)
+ if(has_field_of_vision && CONFIG_GET(flag/use_field_of_vision))
+ LoadComponent(/datum/component/field_of_vision, field_of_vision_type)
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index 6e4bd534af..0f92ce7c33 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -125,8 +125,10 @@
* * blind_message (optional) is what blind people will hear e.g. "You hear something!"
* * vision_distance (optional) define how many tiles away the message can be seen.
* * ignored_mobs (optional) doesn't show any message to any given mob in the list.
+ * * target (optional) is the other mob involved with the visible message. For example, the attacker in many combat messages.
+ * * target_message (optional) is what the target mob will see e.g. "[src] does something to you!"
*/
-/atom/proc/visible_message(message, self_message, blind_message, vision_distance = DEFAULT_MESSAGE_RANGE, list/ignored_mobs)
+/atom/proc/visible_message(message, self_message, blind_message, vision_distance = DEFAULT_MESSAGE_RANGE, list/ignored_mobs, mob/target, target_message)
var/turf/T = get_turf(src)
if(!T)
return
@@ -136,7 +138,19 @@
if(!islist(ignored_mobs))
ignored_mobs = list(ignored_mobs)
hearers -= ignored_mobs
- if(self_message)
+
+ if(target_message && target && istype(target) && target.client)
+ hearers -= target
+ //This entire if/else chain could be in two lines but isn't for readibilties sake.
+ var/msg = target_message
+ if(target.see_invisibleSomething is there but you can't see it!")
+ return
var/list/result = A.examine(src)
to_chat(src, result.Join("\n"))
- SEND_SIGNAL(src, COMSIG_MOB_EXAMINATE, A)
//same as above
//note: ghosts can point, this is intended
//visible_message will handle invisibility properly
//overridden here and in /mob/dead/observer for different point span classes and sanity checks
-/mob/verb/pointed(atom/A as mob|obj|turf in view())
+/mob/verb/pointed(atom/A as mob|obj|turf in fov_view())
set name = "Point To"
set category = "Object"
diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm
index 825f015ef4..9947c8ca1e 100644
--- a/code/modules/mob/mob_defines.dm
+++ b/code/modules/mob/mob_defines.dm
@@ -12,6 +12,9 @@
vis_flags = VIS_INHERIT_PLANE //when this be added to vis_contents of something it inherit something.plane, important for visualisation of mob in openspace.
+ /// What receives our keyboard input. src by default.
+ var/datum/focus
+
var/lighting_alpha = LIGHTING_PLANE_ALPHA_VISIBLE
var/datum/mind/mind
var/list/datum/action/actions = list()
@@ -130,3 +133,17 @@
var/siliconaccesstoggle = FALSE
var/voluntary_ghosted = FALSE //whether or not they voluntarily ghosted.
+
+ var/has_field_of_vision = FALSE
+ var/field_of_vision_type = FOV_90_DEGREES
+
+
+ ///////TYPING INDICATORS///////
+ /// Set to true if we want to show typing indicators.
+ var/typing_indicator_enabled = FALSE
+ /// Default icon_state of our typing indicator. Currently only supports paths (because anything else is, as of time of typing this, unnecesary.
+ var/typing_indicator_state = /obj/effect/overlay/typing_indicator
+ /// The timer that will remove our indicator for early aborts (like when an user finishes their message)
+ var/typing_indicator_timerid
+ /// Current state of our typing indicator. Used for cut overlay, DO NOT RUNTIME ASSIGN OTHER THAN FROM SHOW/CLEAR. Used to absolutely ensure we do not get stuck overlays.
+ var/typing_indicator_current
diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm
index 6531df5e68..2bcfd47344 100644
--- a/code/modules/mob/mob_movement.dm
+++ b/code/modules/mob/mob_movement.dm
@@ -100,7 +100,8 @@
if(mob.throwing)
mob.throwing.finalize(FALSE)
- if(L.pulling && !(L.combat_flags & COMBAT_FLAG_COMBAT_ACTIVE))
+ var/atom/movable/AM = L.pulling
+ if(AM && AM.density && !(L.combat_flags & COMBAT_FLAG_COMBAT_ACTIVE) && !ismob(AM))
L.setDir(turn(L.dir, 180))
SEND_SIGNAL(mob, COMSIG_MOB_CLIENT_MOVE, src, direction, n, oldloc)
diff --git a/code/modules/mob/say.dm b/code/modules/mob/say.dm
index f348829b71..e2b3aee35d 100644
--- a/code/modules/mob/say.dm
+++ b/code/modules/mob/say.dm
@@ -1,12 +1,53 @@
//Speech verbs.
-/mob/verb/say_verb(message as text)
- set name = "Say"
+// the _keybind verbs uses "as text" versus "as text|null" to force a popup when pressed by a keybind.
+/mob/verb/say_typing_indicator()
+ set name = "say_indicator"
+ set hidden = TRUE
set category = "IC"
+ display_typing_indicator()
+ var/message = input(usr, "", "say") as text|null
+ // If they don't type anything just drop the message.
+ clear_typing_indicator() // clear it immediately!
+ if(!length(message))
+ return
+ return say_verb(message)
+
+/mob/verb/say_verb(message as text)
+ set name = "say"
+ set category = "IC"
+ if(!length(message))
+ return
if(GLOB.say_disabled) //This is here to try to identify lag problems
to_chat(usr, "
Speech is currently admin-disabled.")
return
- if(message)
- say(message)
+ clear_typing_indicator() // clear it immediately!
+ say(message)
+
+/mob/verb/me_typing_indicator()
+ set name = "me_indicator"
+ set hidden = TRUE
+ set category = "IC"
+ display_typing_indicator()
+ var/message = input(usr, "", "me") as message|null
+ // If they don't type anything just drop the message.
+ clear_typing_indicator() // clear it immediately!
+ if(!length(message))
+ return
+ return me_verb(message)
+
+/mob/verb/me_verb(message as message)
+ set name = "me"
+ set category = "IC"
+ if(!length(message))
+ return
+ if(GLOB.say_disabled) //This is here to try to identify lag problems
+ to_chat(usr, "
Speech is currently admin-disabled.")
+ return
+
+ message = trim(copytext_char(sanitize(message), 1, MAX_MESSAGE_LEN))
+ clear_typing_indicator() // clear it immediately!
+
+ usr.emote("me",1,message,TRUE)
/mob/say_mod(input, message_mode)
var/customsayverb = findtext(input, "*")
@@ -16,9 +57,17 @@
else
return ..()
+/mob/proc/whisper_keybind()
+ var/message = input(src, "", "whisper") as text|null
+ if(!length(message))
+ return
+ return whisper_verb(message)
+
/mob/verb/whisper_verb(message as text)
set name = "Whisper"
set category = "IC"
+ if(!length(message))
+ return
if(GLOB.say_disabled) //This is here to try to identify lag problems
to_chat(usr, "
Speech is currently admin-disabled.")
return
@@ -27,18 +76,6 @@
/mob/proc/whisper(message, datum/language/language=null)
say(message, language) //only living mobs actually whisper, everything else just talks
-/mob/verb/me_verb(message as message)
- set name = "Me"
- set category = "IC"
-
- if(GLOB.say_disabled) //This is here to try to identify lag problems
- to_chat(usr, "
Speech is currently admin-disabled.")
- return
-
- message = trim(copytext_char(sanitize(message), 1, MAX_MESSAGE_LEN))
-
- usr.emote("me",1,message,TRUE)
-
/mob/proc/say_dead(var/message)
var/name = real_name
var/alt_name = ""
diff --git a/code/modules/mob/say_vr.dm b/code/modules/mob/say_vr.dm
index 377bb1c5fc..44dc3e2a05 100644
--- a/code/modules/mob/say_vr.dm
+++ b/code/modules/mob/say_vr.dm
@@ -23,7 +23,6 @@ proc/get_top_level_mob(var/mob/S)
message = null
mob_type_blacklist_typecache = list(/mob/living/brain)
-
/datum/emote/living/subtle/proc/check_invalid(mob/user, input)
if(stop_bad_mime.Find(input, 1, 1))
to_chat(user, "
Invalid emote.")
@@ -130,6 +129,12 @@ proc/get_top_level_mob(var/mob/S)
user.visible_message(message=message,self_message=message,vision_distance=1, ignored_mobs = GLOB.dead_mob_list)
///////////////// VERB CODE
+/mob/living/proc/subtle_keybind()
+ var/message = input(src, "", "subtle") as text|null
+ if(!length(message))
+ return
+ return subtle(message)
+
/mob/living/verb/subtle()
set name = "Subtle"
set category = "IC"
diff --git a/code/modules/mob/status_procs.dm b/code/modules/mob/status_procs.dm
index cf86e962bd..6be1afb5de 100644
--- a/code/modules/mob/status_procs.dm
+++ b/code/modules/mob/status_procs.dm
@@ -88,18 +88,20 @@
/mob/proc/add_eyeblur()
if(!client)
return
- var/obj/screen/plane_master/game_world/GW = locate(/obj/screen/plane_master/game_world) in client.screen
- var/obj/screen/plane_master/floor/F = locate(/obj/screen/plane_master/floor) in client.screen
- GW.add_filter("blurry_eyes", 2, EYE_BLUR(clamp(eye_blurry*0.1,0.6,3)))
- F.add_filter("blurry_eyes", 2, EYE_BLUR(clamp(eye_blurry*0.1,0.6,3)))
+ var/list/screens = list(hud_used.plane_masters["[GAME_PLANE]"], hud_used.plane_masters["[FLOOR_PLANE]"],
+ hud_used.plane_masters["[WALL_PLANE]"], hud_used.plane_masters["[ABOVE_WALL_PLANE]"])
+ for(var/A in screens)
+ var/obj/screen/plane_master/P = A
+ P.add_filter("blurry_eyes", 2, EYE_BLUR(clamp(eye_blurry*0.1,0.6,3)))
/mob/proc/remove_eyeblur()
if(!client)
return
- var/obj/screen/plane_master/game_world/GW = locate(/obj/screen/plane_master/game_world) in client.screen
- var/obj/screen/plane_master/floor/F = locate(/obj/screen/plane_master/floor) in client.screen
- GW.remove_filter("blurry_eyes")
- F.remove_filter("blurry_eyes")
+ var/list/screens = list(hud_used.plane_masters["[GAME_PLANE]"], hud_used.plane_masters["[FLOOR_PLANE]"],
+ hud_used.plane_masters["[WALL_PLANE]"], hud_used.plane_masters["[ABOVE_WALL_PLANE]"])
+ for(var/A in screens)
+ var/obj/screen/plane_master/P = A
+ P.remove_filter("blurry_eyes")
///Adjust the drugginess of a mob
/mob/proc/adjust_drugginess(amount)
diff --git a/code/modules/mob/typing_indicator.dm b/code/modules/mob/typing_indicator.dm
new file mode 100644
index 0000000000..f28cbe4385
--- /dev/null
+++ b/code/modules/mob/typing_indicator.dm
@@ -0,0 +1,47 @@
+/// state = overlay/image/object/type/whatever add_overlay will accept
+GLOBAL_LIST_EMPTY(typing_indicator_overlays)
+
+/// Fetches the typing indicator we'll use from GLOB.typing_indicator_overlays
+/mob/proc/get_indicator_overlay(state)
+ . = GLOB.typing_indicator_overlays[state]
+ if(.)
+ return
+ // doesn't exist, make it and cache it
+ if(ispath(state))
+ . = GLOB.typing_indicator_overlays[state] = state
+ // We only support paths for now because anything else isn't necessary yet.
+
+/// Gets the state we will use for typing indicators. Defaults to src.typing_indicator_state
+/mob/proc/get_typing_indicator_icon_state()
+ return typing_indicator_state
+
+/**
+ * Displays typing indicator.
+ * @param timeout_override - Sets how long until this will disappear on its own without the user finishing their message or logging out. Defaults to src.typing_indicator_timeout
+ * @param state_override - Sets the state that we will fetch. Defaults to src.get_typing_indicator_icon_state()
+ * @param force - shows even if src.typing_indcator_enabled is FALSE.
+ */
+/mob/proc/display_typing_indicator(timeout_override = TYPING_INDICATOR_TIMEOUT, state_override = get_typing_indicator_icon_state(), force = FALSE)
+ if((!typing_indicator_enabled && !force) || typing_indicator_current)
+ return
+ typing_indicator_current = state_override
+ add_overlay(state_override)
+ typing_indicator_timerid = addtimer(CALLBACK(src, .proc/clear_typing_indicator), timeout_override, TIMER_STOPPABLE)
+
+/**
+ * Removes typing indicator.
+ */
+/mob/proc/clear_typing_indicator()
+ cut_overlay(typing_indicator_current)
+ typing_indicator_current = null
+ if(typing_indicator_timerid)
+ deltimer(typing_indicator_timerid)
+ typing_indicator_timerid = null
+
+/// Default typing indicator
+/obj/effect/overlay/typing_indicator
+ mouse_opacity = MOUSE_OPACITY_TRANSPARENT
+ icon = 'icons/mob/talk.dmi'
+ icon_state = "normal_typing"
+ appearance_flags = RESET_COLOR | TILE_BOUND | PIXEL_SCALE
+ layer = ABOVE_FLY_LAYER
diff --git a/code/modules/movespeed/modifiers/mobs.dm b/code/modules/movespeed/modifiers/mobs.dm
index aa60966591..d20fc4c6c0 100644
--- a/code/modules/movespeed/modifiers/mobs.dm
+++ b/code/modules/movespeed/modifiers/mobs.dm
@@ -24,7 +24,8 @@
variable = TRUE
/datum/movespeed_modifier/damage_slowdown_flying
- movetypes = FLOATING
+ movetypes = FLYING
+ blacklisted_movetypes = FLOATING
variable = TRUE
/datum/movespeed_modifier/equipment_speedmod
diff --git a/code/modules/newscaster/newscaster_machine.dm b/code/modules/newscaster/newscaster_machine.dm
index 95a24817a0..cb2d49fc64 100644
--- a/code/modules/newscaster/newscaster_machine.dm
+++ b/code/modules/newscaster/newscaster_machine.dm
@@ -12,6 +12,7 @@ GLOBAL_LIST_EMPTY(allCasters)
desc = "A standard Nanotrasen-licensed newsfeed handler for use in commercial space stations. All the news you absolutely have no use for, in one place!"
icon = 'icons/obj/terminals.dmi'
icon_state = "newscaster_normal"
+ plane = ABOVE_WALL_PLANE
verb_say = "beeps"
verb_ask = "beeps"
verb_exclaim = "beeps"
diff --git a/code/modules/paperwork/paper_premade.dm b/code/modules/paperwork/paper_premade.dm
index 2d03a17e0a..23c8d47323 100644
--- a/code/modules/paperwork/paper_premade.dm
+++ b/code/modules/paperwork/paper_premade.dm
@@ -54,7 +54,7 @@
/obj/item/paper/guides/cogstation/job_changes
name = "MEMO: Job Changes"
- info = "To ensure minimal employee downtime, please take note of the following changes to select professions that Cogstation specifically requires:
\n
\n- Chemists are to have
basic Research accessand an encryption key for the Science channel.
\n- Roboticists are to have
basic Medical and Morgue access.
\n- Engineers and Atmospheric Technicians
are to have Warehouse and Mining access.
\n- The Cook should
not have Morgue access
\n- The Clown and Mime
are to have Maintenance access. This is necessary due to the location of their offices.
\n
\n
Generated by Organic Resources Bot #2053"
+ info = "To ensure minimal employee downtime, please take note of the following changes to select professions that CogStation specifically requires:
\n
\n- Scientists
are to have access to chemistry in order to reach the MedSci router.
\n
\n- Chemists should at the very least be provided with an encryption key for the Science channel, if not basic access to the Research department at large.
\n- Roboticists are to have
basic Medical and Morgue access.
\n- Engineers and Atmospheric Technicians
are to have Warehouse and Mining access.
\n- The Cook should
not have Morgue access
\n- The Clown and Mime
are to have Maintenance access. This is necessary due to the location of their offices.
\n
\n
Generated by Organic Resources Bot #2053"
/obj/item/paper/guides/cogstation/letter_sec
name = "To future Security personnel"
@@ -86,7 +86,11 @@
/obj/item/paper/guides/cogstation/letter_eng
name = "To future Engineering staff:"
- info = "I'm not gonna sugarcoat this. Compared to other departments, you might have your work cut out for you. CogStation is an entirely different beast than your standard Box, but everyone's still gonna expect you to keep the place running.
\n
\n If there's any good news, it's your time to shine if you know how to run a thermo-electric generator. That's what this station runs on, and CentCom isn't planning on changing that. If it's absolutely critical you might be able to run a singularity or tesla engine east of mining, but it won't have any sort of shielding out there.
\n
\nThe air system's different too. It's multiple small networks instead of a single big one, with air hookups across the station. Fortunately it's not that complicated, but it comes at the expense of being able to filter out and reuse specific gases. Besides, you'll probably be busy enough with the engine and general upkeep anyway.
\n
\nThe disposal network in contrast is significantly more complicated, yet more capable. I've already elaborated on it, so I'll let you find and read my write-up for that. As for the routing system, it's just begging to get hit by a stray meteor so consider other utilities a higher priority.
\n
\nGood luck. You're gonna need it.
\n
\n
-C. Donnelly Architectural Analyst"
+ info = "I'm not gonna sugarcoat this. Compared to other departments,
you might have your work cut out for you. CogStation is an entirely different beast than your standard Box, but everyone's still gonna expect you to keep the place running.
\n
\n If there's any good news,
it's your time to shine if you know how to run a thermo-electric generator. That's what this station runs on, and that isn't likely to change anytime soon. If it's absolutely critical you
might be able to run a singularity or tesla engine east of mining, but it won't have any sort of shielding out there.
\n
\n
You still have three solar arrays to work with, two of them being on each end of the starboard side. The port side array will need you to either get access from a head of staff or security, unless you want to spacewalk around the whole station. Don't be afraid to ask the latter - they're there for you, after all. As for other utilities
the air system is a bit different than you'd expect, but fortunately you should have the atmos techs this station needed a long time ago.
The disposal network is significantly more complicated, yet more capable. I've already elaborated on it, so I'll let you find and read my write-up for that.
As for the routing system, it's just begging to get hit by a stray meteor so
consider other utilities a higher priority. \n
\nGood luck. You're gonna need it.
\n
\n
-C. Donnelly Architectural Analyst"
+
+/obj/item/paper/guides/cogstation/letter_atmos
+ name = "To future Atmospheric Technicians:"
+ info = "If the place that this station used to call home still hired atmos techs, odds are we could've gotten this place up and running a lot sooner. Alas, the past is in the past and the hard work's already been done. You still have a job to do, but it shouldn't be much different from other stations in this sector. That being said, be aware of the following:
\n
\n - If you haven't already noticed,
the atmospherics department is separate from the rest of the station. You'll either need to spacewalk or take a transit tube to reach it, but it still connects to the station's air system at large.
\n
\n- Seeing as the TEG already uses the standard red and blue for it's heating/cooling loops,
the scrubber pipes are ORANGE. The main air supply pipes are a purpleish-blue - HOWEVER, these aren't the only air pipes you'll see. We've decided to reuse existing lines from the old air hookup system -
these pipes are CYAN and serve to supply air to specific areas. There's also a
VIOLET line to help keep the TEG stable. \n
\nNanotrasen's invested a considerable amount into updating this system, so even if Murphy's Law is alive and well in this sector, the air system isn't one of the things that should fail. If a section of the station is having air problems,
check the old air hookups FIRST. Your problem could be as simple as a 'greytider' turning a valve or a clown hooking up a laughing gas canister.
\n
\n
-C. Donnelly Architectural Analyst"
/obj/item/paper/guides/cogstation/letter_chief
name = "To the future Chief Engineer:"
@@ -112,6 +116,10 @@
name = "To the future Research Director"
info = "Apologies if you were expecting a letter from the station's Research Director, but just prior to translocation we found out they were a BLF operative. I wouldn't trust a single word they wrote and while I'm not a scientist, something tells me your department will have the easiest time adjusting to this station.
\n
\nYou should have everything you need - this is a research facility after all. It's just a matter of finding it, which shouldn't be too hard. Folks like you are why we're out in deep space, after all!
\n
-Louis Cannon \nFormer Head of Security"
+/obj/item/paper/fluff/cogstation/letter_arrd
+ name = "To the future Research Director"
+ info = "Listen, I doubt I need to tell you to how to do your job. From what I've heard this station is getting a state-of-the-art xenobiology lab after it gets translocated, and I don't know the first thing about what you guys do about those slimes. However, there's one thing I
do know and it's that your station will have botanists.
\n
\n
It's crucial you give them everything they need, so long as they agree to maintain as many apiaries as humanely possible. I know it sounds ridiculous, but it's the
ONLY way to keep the floor cluwnes at bay. If you don't know what a floor cluwne is, trust me when I say you do
NOT want to find out!
\n
Jesse P. \nFormer CogStation RD"
+
/obj/item/paper/fluff/cogstation/letter_cap
name = "Captain's Log"
info = "So I guess some of the other heads have decided to leave little notes for future employees here. Heartwarming, but the most important thing I figure I can leave you is the truth. Nevermind the Syndicate, the xenomorphs, the apocalyptic death cults I hear are a thing way out there - I'm convinced we are our own worst enemy.
\n
\nDon't believe me? Maybe you can ask Chief Engineer Earp. Oh right, he vaporized himself trying to produce enough power to keep the lights on in Space China for a week, despite only needing a sliver of that to run this place as intended. Or maybe you can ask Head of Security Cannon, who executed our Research Director in plain sight of everyone. Even if he was in the right, the final frontier isn't the goddamn wild west! Hell, maybe you can ask one of your 'staff assistants', although in my experience the only ones they seem to want to help is themselves.
\n
\nOf course, the REAL problems are with the higher-ups that stationed us on this deathtrap before deciding to send it your way, but there's only so much I can say and get away with it, for instance that they only sent this station since they could care less if it was a total loss. By the time you read this, I'll already be long gone. Maybe it'll be a different story with your crew, but between you and me, I wouldn't hold my breath...
unless they fuck up the air system. \n
\n
Dom Kahn Former Captain of Nanotrasen CogStation"
@@ -128,6 +136,18 @@
name = "Mysterious Note"
info = "
ThE rInGmAsTeR dOeSn'T rUn ThE cIrCus... HONK!!!"
+/obj/item/paper/fluff/cogstation/secsolars
+ name = "A heads up:"
+ info = "I'm hoping you guys are aware of the
access changes this station requires, but one thing they might have forgot to mention is that
one of the station's solar arrays and air hookups are wedged squarely behind your department. Engineering might need to come through your department to access them. \n
\nWhile I can imagine potential concerns,
there shouldn't be any problems if both sides are transparent and communicative. The engineer is most likely there to do their job of keeping the station running, and will only need to pass through your department office and interrogation room (or alternatively, the bridge). You're free to get the doors for them and/or watch them work if it helps put your mind at ease. If they loiter or otherwise act suspiciously
then you might want to have a word with them.
\n
\n
-C. Donnelly Architectural Analyst"
+
+/obj/item/paper/fluff/cogstation/eva
+ name = "MEMO: Spacesuits"
+ info = "As a Head of Personnel, you may be familiar with crew members requesting EVA access, particularly when there is an absence of credible threats on the station. While it is your decision to grant or deny access unless overriden by your superior(s), you should be aware of an abundance of spacesuits on this station. While intended for emergencies, these suits are cheaper to replace. You may find it beneficial to direct aspiring 'space explorers' towards finding one of these suits instead, although it is advised you order replacement suits in advance through the cargo department.
\n
\n-Generated by Organic Resources Bot #2053"
+
+/obj/item/paper/fluff/cogstation/chemists
+ name = "Re: Scientists?!"
+ info = "Scientists
should have access to the chemistry lab. This is intentional as opposed to some sort of oversight - after all, they need to reach the medsci router somehow.
\n
\nIf anything you should see this as a blessing, as you won't need to sideline whatever it is you're doing to get them what they need. Your focus should remain on predominantly medical goods, just like other stations in this sector.
\n
\n- Dr. Halley"
+
/obj/item/paper/fluff/cogstation/mime
name = "Au futur Mime"
info = "Toutes mes excuses pour toute mauvaise grammaire, je ne suis pas un haut-parleur naturel Français et a dû utiliser NanoTranslate. Bien que vous puissiez être mécontent de l’emplacement de votre bureau, s’il vous plaît comprendre que c’était le seul endroit où nous pourrions le mettre sans problèmes de sécurité et/ou CentClown se plaindre à ce sujet. Nous nous excusons également pour l’absence d’une zone de performance dédiée, mais nous espérons que vous accorder un accès à l’entretien compensera.
\n
\n
-C. Donnelly
\n
\nAnalyste Architectural"
diff --git a/code/modules/photography/photos/frame.dm b/code/modules/photography/photos/frame.dm
index 67559c0381..11ad81ebf0 100644
--- a/code/modules/photography/photos/frame.dm
+++ b/code/modules/photography/photos/frame.dm
@@ -40,6 +40,7 @@
/obj/item/wallframe/picture/examine(mob/user)
if(user.is_holding(src) && displayed)
displayed.show(user)
+ SEND_SIGNAL(user, COMSIG_ADD_MOOD_EVENT, "artok", /datum/mood_event/artok)
return list()
return ..()
@@ -109,6 +110,7 @@
/obj/structure/sign/picture_frame/examine(mob/user)
if(in_range(src, user) && framed)
framed.show(user)
+ SEND_SIGNAL(user, COMSIG_ADD_MOOD_EVENT, "artok", /datum/mood_event/artok)
return list()
return ..()
diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm
index b3c94d4f43..0fb53501f9 100644
--- a/code/modules/power/apc.dm
+++ b/code/modules/power/apc.dm
@@ -48,7 +48,7 @@
/obj/machinery/power/apc
name = "area power controller"
desc = "A control terminal for the area's electrical systems."
-
+ plane = ABOVE_WALL_PLANE
icon_state = "apc0"
use_power = NO_POWER_USE
req_access = null
diff --git a/code/modules/power/cable.dm b/code/modules/power/cable.dm
index c8563c653f..0d674a2f77 100644
--- a/code/modules/power/cable.dm
+++ b/code/modules/power/cable.dm
@@ -39,6 +39,7 @@ By design, d1 is the smallest direction and d2 is the highest
icon = 'icons/obj/power_cond/cables.dmi'
icon_state = "0-1"
level = 1 //is underfloor
+ plane = ABOVE_WALL_PLANE
layer = WIRE_LAYER //Above hidden pipes, GAS_PIPE_HIDDEN_LAYER
anchored = TRUE
obj_flags = CAN_BE_HIT | ON_BLUEPRINTS
diff --git a/code/modules/power/gravitygenerator.dm b/code/modules/power/gravitygenerator.dm
index d2ffc216ba..d7513cf572 100644
--- a/code/modules/power/gravitygenerator.dm
+++ b/code/modules/power/gravitygenerator.dm
@@ -39,9 +39,9 @@ GLOBAL_LIST_EMPTY(gravity_generators) // We will keep track of this by adding ne
if(prob(20))
set_broken()
-/obj/machinery/gravity_generator/tesla_act(power, tesla_flags)
+/obj/machinery/gravity_generator/zap_act(power, zap_flags)
..()
- if(tesla_flags & TESLA_MACHINE_EXPLOSIVE)
+ if(zap_flags & ZAP_MACHINE_EXPLOSIVE)
qdel(src)//like the singulo, tesla deletes it. stops it from exploding over and over
/obj/machinery/gravity_generator/update_icon_state()
diff --git a/code/modules/power/lighting.dm b/code/modules/power/lighting.dm
index 181df7b07c..344d41071d 100644
--- a/code/modules/power/lighting.dm
+++ b/code/modules/power/lighting.dm
@@ -314,7 +314,7 @@
. = ..()
SSvis_overlays.remove_vis_overlay(src, managed_vis_overlays)
if(on && status == LIGHT_OK)
- SSvis_overlays.add_vis_overlay(src, overlayicon, base_state, EMISSIVE_LAYER, EMISSIVE_PLANE, dir, clamp(light_power*250, 30, 200))
+ SSvis_overlays.add_vis_overlay(src, overlayicon, base_state, EMISSIVE_UNBLOCKABLE_LAYER, EMISSIVE_UNBLOCKABLE_PLANE, dir, clamp(light_power*250, 30, 200))
// update the icon_state and luminosity of the light depending on its state
@@ -687,9 +687,9 @@
on = TRUE
update()
-/obj/machinery/light/tesla_act(power, tesla_flags)
- if(tesla_flags & TESLA_MACHINE_EXPLOSIVE)
- explosion(src,0,0,0,flame_range = 5, adminlog = 0)
+/obj/machinery/light/zap_act(power, zap_flags)
+ if(zap_flags & ZAP_MACHINE_EXPLOSIVE)
+ explosion(src,0,0,0,flame_range = 5, adminlog = FALSE)
qdel(src)
else
return ..()
diff --git a/code/modules/power/rtg.dm b/code/modules/power/rtg.dm
index afbeef30a1..b558031fab 100644
--- a/code/modules/power/rtg.dm
+++ b/code/modules/power/rtg.dm
@@ -97,6 +97,7 @@
/obj/machinery/power/rtg/abductor/fire_act(exposed_temperature, exposed_volume)
overload()
-/obj/machinery/power/rtg/abductor/tesla_act()
- ..() //extend the zap
- overload()
+/obj/machinery/power/rtg/abductor/zap_act(power, zap_flags, shocked_objects)
+ . = ..() //extend the zap
+ if(zap_flags & ZAP_MACHINE_EXPLOSIVE)
+ overload()
diff --git a/code/modules/power/singularity/narsie.dm b/code/modules/power/singularity/narsie.dm
index ed3a098dae..8bf20fddc6 100644
--- a/code/modules/power/singularity/narsie.dm
+++ b/code/modules/power/singularity/narsie.dm
@@ -127,7 +127,7 @@
/obj/singularity/narsie/mezzer()
- for(var/mob/living/carbon/M in viewers(consume_range, src))
+ for(var/mob/living/carbon/M in fov_viewers(consume_range, src))
if(M.stat == CONSCIOUS)
if(!iscultist(M))
to_chat(M, "You feel conscious thought crumble away in an instant as you gaze upon [src.name]...")
diff --git a/code/modules/power/supermatter/supermatter.dm b/code/modules/power/supermatter/supermatter.dm
index 28e9194eef..1350c36348 100644
--- a/code/modules/power/supermatter/supermatter.dm
+++ b/code/modules/power/supermatter/supermatter.dm
@@ -433,7 +433,7 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
env.merge(removed)
air_update_turf()
- for(var/mob/living/carbon/human/l in view(src, HALLUCINATION_RANGE(power))) // If they can see it without mesons on. Bad on them.
+ for(var/mob/living/carbon/human/l in fov_viewers(HALLUCINATION_RANGE(power), src)) // If they can see it without mesons on. Bad on them.
if(!istype(l.glasses, /obj/item/clothing/glasses/meson))
var/D = sqrt(1 / max(1, get_dist(l, src)))
l.hallucination += power * config_hallucination_power * D
@@ -559,14 +559,9 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
dust_mob(user, cause = "alien attack")
/obj/machinery/power/supermatter_crystal/attack_animal(mob/living/simple_animal/S)
- var/murder
- if(!S.melee_damage_upper && !S.melee_damage_lower)
- murder = S.friendly
- else
- murder = S.attacktext
dust_mob(S, \
- "[S] unwisely [murder] [src], and [S.p_their()] body burns brilliantly before flashing into ash!", \
- "You unwisely touch [src], and your vision glows brightly as your body crumbles to dust. Oops.", \
+ "[S] unwisely [S.attack_verb_continuous] [src], and [S.p_their()] body burns brilliantly before flashing into ash!", \
+ "You unwisely [S.attack_verb_simple] [src], and your vision glows brightly as your body crumbles to dust. Oops.", \
"simple animal attack")
/obj/machinery/power/supermatter_crystal/attack_robot(mob/user)
@@ -666,9 +661,10 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
//Some poor sod got eaten, go ahead and irradiate people nearby.
radiation_pulse(src, 3000, 2, TRUE)
+ var/list/viewers = fov_viewers(world.view, src)
for(var/mob/living/L in range(10))
investigate_log("has irradiated [key_name(L)] after consuming [AM].", INVESTIGATE_SUPERMATTER)
- if(L in view())
+ if(L in viewers)
L.show_message("As \the [src] slowly stops resonating, you find your skin covered in new radiation burns.", MSG_VISUAL,\
"The unearthly ringing subsides and you notice you have new radiation burns.", MSG_AUDIBLE)
else
diff --git a/code/modules/power/tesla/coil.dm b/code/modules/power/tesla/coil.dm
index 64d317b385..eb80548441 100644
--- a/code/modules/power/tesla/coil.dm
+++ b/code/modules/power/tesla/coil.dm
@@ -73,7 +73,7 @@
return ..()
-/obj/machinery/power/tesla_coil/tesla_act(power, tesla_flags, shocked_targets)
+/obj/machinery/power/tesla_coil/zap_act(power, zap_flags, shocked_targets)
if(anchored && !panel_open)
obj_flags |= BEING_SHOCKED
//don't lose arc power when it's not connected to anything
@@ -81,17 +81,17 @@
var/power_produced = powernet ? power / power_loss : power
add_avail(power_produced*input_power_multiplier)
flick("coilhit", src)
- playsound(src.loc, 'sound/magic/lightningshock.ogg', 100, 1, extrarange = 5)
- tesla_zap(src, 5, power_produced, tesla_flags, shocked_targets)
var/datum/bank_account/D = SSeconomy.get_dep_account(ACCOUNT_ENG)
if(D)
D.adjust_money(min(power_produced, 1))
if(istype(linked_techweb))
linked_techweb.add_point_type(TECHWEB_POINT_TYPE_DEFAULT, min(power_produced, 1)) // x4 coils = ~240/m point bonus for R&D
addtimer(CALLBACK(src, .proc/reset_shocked), 10)
- tesla_buckle_check(power)
+ zap_buckle_check(power)
+ playsound(src.loc, 'sound/magic/lightningshock.ogg', 100, TRUE, extrarange = 5)
+ return power_produced
else
- ..()
+ . = ..()
/obj/machinery/power/tesla_coil/proc/zap()
if((last_zap + zap_cooldown) > world.time || !powernet)
@@ -102,8 +102,8 @@
var/power = (powernet.avail/2)
add_load(power)
playsound(src.loc, 'sound/magic/lightningshock.ogg', 100, 1, extrarange = 5)
- tesla_zap(src, 10, power/(coeff/2), TESLA_FUSION_FLAGS)
- tesla_buckle_check(power/(coeff/2))
+ tesla_zap(src, 10, power/(coeff/2), ZAP_FUSION_FLAGS)
+ zap_buckle_check(power/(coeff/2))
// Tesla R&D researcher
/obj/machinery/power/tesla_coil/research
@@ -113,23 +113,23 @@
circuit = /obj/item/circuitboard/machine/tesla_coil/research
power_loss = 20 // something something, high voltage + resistance
-/obj/machinery/power/tesla_coil/research/tesla_act(power, tesla_flags, shocked_things)
+/obj/machinery/power/tesla_coil/research/zap_act(power, zap_flags, shocked_targets)
if(anchored && !panel_open)
obj_flags |= BEING_SHOCKED
var/power_produced = powernet ? power / power_loss : power
add_avail(power_produced*input_power_multiplier)
flick("rpcoilhit", src)
- playsound(src.loc, 'sound/magic/lightningshock.ogg', 100, 1, extrarange = 5)
- tesla_zap(src, 5, power_produced, tesla_flags, shocked_things)
var/datum/bank_account/D = SSeconomy.get_dep_account(ACCOUNT_ENG)
if(D)
D.adjust_money(min(power_produced, 3))
if(istype(linked_techweb))
linked_techweb.add_point_type(TECHWEB_POINT_TYPE_DEFAULT, min(power_produced, 3)) // x4 coils with a pulse per second or so = ~720/m point bonus for R&D
addtimer(CALLBACK(src, .proc/reset_shocked), 10)
- tesla_buckle_check(power)
+ zap_buckle_check(power)
+ playsound(src.loc, 'sound/magic/lightningshock.ogg', 100, TRUE, extrarange = 5)
+ return power_produced
else
- ..()
+ . = ..()
/obj/machinery/power/tesla_coil/research/default_unfasten_wrench(mob/user, obj/item/wrench/W, time = 20)
. = ..()
@@ -180,9 +180,10 @@
return ..()
-/obj/machinery/power/grounding_rod/tesla_act(var/power)
+/obj/machinery/power/grounding_rod/zap_act(var/power)
if(anchored && !panel_open)
flick("grounding_rodhit", src)
- tesla_buckle_check(power)
+ zap_buckle_check(power)
+ return 0
else
- ..()
+ . = ..()
diff --git a/code/modules/power/tesla/energy_ball.dm b/code/modules/power/tesla/energy_ball.dm
index e98fe3c88e..06e5d27f6d 100644
--- a/code/modules/power/tesla/energy_ball.dm
+++ b/code/modules/power/tesla/energy_ball.dm
@@ -1,5 +1,14 @@
#define TESLA_DEFAULT_POWER 1738260
#define TESLA_MINI_POWER 869130
+//Zap constants, speeds up targeting
+#define BIKE (COIL + 1)
+#define COIL (ROD + 1)
+#define ROD (RIDE + 1)
+#define RIDE (LIVING + 1)
+#define LIVING (MACHINERY + 1)
+#define MACHINERY (BLOB + 1)
+#define BLOB (STRUCTURE + 1)
+#define STRUCTURE (1)
/obj/singularity/energy_ball
name = "energy ball"
@@ -32,6 +41,9 @@
/obj/singularity/energy_ball/ex_act(severity, target)
return
+/obj/singularity/energy_ball/consume(severity, target)
+ return
+
/obj/singularity/energy_ball/Destroy()
if(orbiting && istype(orbiting.parent, /obj/singularity/energy_ball))
var/obj/singularity/energy_ball/EB = orbiting.parent
@@ -39,7 +51,7 @@
for(var/ball in orbiting_balls)
var/obj/singularity/energy_ball/EB = ball
- qdel(EB)
+ QDEL_NULL(EB)
. = ..()
@@ -55,12 +67,12 @@
move_the_basket_ball(4 + orbiting_balls.len * 1.5)
- playsound(src.loc, 'sound/magic/lightningbolt.ogg', 100, 1, extrarange = 30)
+ playsound(src.loc, 'sound/magic/lightningbolt.ogg', 100, TRUE, extrarange = 30)
pixel_x = 0
pixel_y = 0
- tesla_zap(src, 7, TESLA_DEFAULT_POWER, TRUE)
+ tesla_zap(src, 7, TESLA_DEFAULT_POWER)
pixel_x = -32
pixel_y = -32
@@ -73,7 +85,7 @@
/obj/singularity/energy_ball/examine(mob/user)
. = ..()
if(orbiting_balls.len)
- . += "The amount of orbiting mini-balls is [orbiting_balls.len]."
+ . += "There are [orbiting_balls.len] mini-balls orbiting it."
/obj/singularity/energy_ball/proc/move_the_basket_ball(var/move_amount)
@@ -96,7 +108,7 @@
energy_to_lower = energy_to_raise - 20
energy_to_raise = energy_to_raise * 1.25
- playsound(src.loc, 'sound/magic/lightning_chargeup.ogg', 100, 1, extrarange = 30)
+ playsound(src.loc, 'sound/magic/lightning_chargeup.ogg', 100, TRUE, extrarange = 30)
addtimer(CALLBACK(src, .proc/new_mini_ball), 100)
else if(energy < energy_to_lower && orbiting_balls.len)
@@ -132,22 +144,19 @@
/obj/singularity/energy_ball/attack_tk(mob/user)
if(iscarbon(user))
var/mob/living/carbon/C = user
- log_game("[key_name(C)] has been disintegrated by a telekenetic grab on a tesla ball.")
to_chat(C, "That was a shockingly dumb idea.")
- C.visible_message("A bright flare of lightning is seen from [C]'s head, shortly before you hear a sickening sizzling!")
var/obj/item/organ/brain/rip_u = locate(/obj/item/organ/brain) in C.internal_organs
- rip_u.Remove()
+ C.ghostize(0)
qdel(rip_u)
- return
- return ..()
+ C.death()
/obj/singularity/energy_ball/orbit(obj/singularity/energy_ball/target)
if (istype(target))
target.orbiting_balls += src
GLOB.poi_list -= src
target.dissipate_strength = target.orbiting_balls.len
-
. = ..()
+
/obj/singularity/energy_ball/stop_orbit()
if (orbiting && istype(orbiting.parent, /obj/singularity/energy_ball))
var/obj/singularity/energy_ball/orbitingball = orbiting.parent
@@ -171,20 +180,19 @@
var/mob/living/carbon/C = A
C.dust()
-/proc/tesla_zap(atom/source, zap_range = 3, power, tesla_flags = TESLA_DEFAULT_FLAGS, list/shocked_targets)
+/proc/tesla_zap(atom/source, zap_range = 3, power, zap_flags = ZAP_DEFAULT_FLAGS, list/shocked_targets)
+ if(QDELETED(source))
+ return
. = source.dir
if(power < 1000)
return
- var/closest_dist = 0
- var/closest_atom
- var/obj/machinery/power/tesla_coil/closest_tesla_coil
- var/obj/machinery/power/grounding_rod/closest_grounding_rod
- var/mob/living/closest_mob
- var/obj/machinery/closest_machine
- var/obj/structure/closest_structure
- var/obj/structure/blob/closest_blob
- var/static/things_to_shock = typecacheof(list(/obj/machinery, /mob/living, /obj/structure))
+ /*
+ THIS IS SO FUCKING UGLY AND I HATE IT, but I can't make it nice without making it slower, check*N rather then n. So we're stuck with it.
+ */
+ var/atom/closest_atom
+ var/closest_type = 0
+ var/static/things_to_shock = typecacheof(list(/obj/machinery, /mob/living, /obj/structure, /obj/vehicle/ridden))
var/static/blacklisted_tesla_types = typecacheof(list(/obj/machinery/atmospherics,
/obj/machinery/power/emitter,
/obj/machinery/field/generator,
@@ -205,112 +213,133 @@
/obj/machinery/gateway,
/obj/structure/lattice,
/obj/structure/grille,
- /obj/machinery/the_singularitygen/tesla,
/obj/structure/frame/machine))
- for(var/A in typecache_filter_multi_list_exclusion(oview(source, zap_range+2), things_to_shock, blacklisted_tesla_types))
- if(!(tesla_flags & TESLA_ALLOW_DUPLICATES) && LAZYACCESS(shocked_targets, A))
+ //Ok so we are making an assumption here. We assume that view() still calculates from the center out.
+ //This means that if we find an object we can assume it is the closest one of its type. This is somewhat of a speed increase.
+ //This also means we have no need to track distance, as the doview() proc does it all for us.
+
+ //Darkness fucks oview up hard. I've tried dview() but it doesn't seem to work
+ //I hate existance
+ for(var/a in typecache_filter_multi_list_exclusion(oview(zap_range+2, source), things_to_shock, blacklisted_tesla_types))
+ var/atom/A = a
+ if(!(zap_flags & ZAP_ALLOW_DUPLICATES) && LAZYACCESS(shocked_targets, A))
continue
+ if(closest_type >= BIKE)
+ break
- if(istype(A, /obj/machinery/power/tesla_coil))
- var/dist = get_dist(source, A)
- var/obj/machinery/power/tesla_coil/C = A
- if(dist <= zap_range && (dist < closest_dist || !closest_tesla_coil) && !(C.obj_flags & BEING_SHOCKED))
- closest_dist = dist
-
+ else if(istype(A, /obj/vehicle/ridden/bicycle))//God's not on our side cause he hates idiots.
+ var/obj/vehicle/ridden/bicycle/B = A
+ if(!(B.obj_flags & BEING_SHOCKED) && B.can_buckle)//Gee goof thanks for the boolean
//we use both of these to save on istype and typecasting overhead later on
//while still allowing common code to run before hand
- closest_tesla_coil = C
- closest_atom = C
+ closest_type = BIKE
+ closest_atom = B
-
- else if(closest_tesla_coil)
+ else if(closest_type >= COIL)
continue //no need checking these other things
- else if(istype(A, /obj/machinery/power/grounding_rod))
- var/dist = get_dist(source, A)-2
- if(dist <= zap_range && (dist < closest_dist || !closest_grounding_rod))
- closest_grounding_rod = A
- closest_atom = A
- closest_dist = dist
+ else if(istype(A, /obj/machinery/power/tesla_coil))
+ var/obj/machinery/power/tesla_coil/C = A
+ if(!(C.obj_flags & BEING_SHOCKED))
+ closest_type = COIL
+ closest_atom = C
- else if(closest_grounding_rod)
+ else if(closest_type >= ROD)
+ continue
+
+ else if(istype(A, /obj/machinery/power/grounding_rod))
+ closest_type = ROD
+ closest_atom = A
+
+ else if(closest_type >= RIDE)
+ continue
+
+ else if(istype(A,/obj/vehicle/ridden))
+ var/obj/vehicle/ridden/R = A
+ if(R.can_buckle && !(R.obj_flags & BEING_SHOCKED))
+ closest_type = RIDE
+ closest_atom = A
+
+ else if(closest_type >= LIVING)
continue
else if(isliving(A))
- var/dist = get_dist(source, A)
var/mob/living/L = A
- if(dist <= zap_range && (dist < closest_dist || !closest_mob) && L.stat != DEAD && !(L.flags_1 & TESLA_IGNORE_1))
- closest_mob = L
+ if(L.stat != DEAD && !(HAS_TRAIT(L, TRAIT_TESLA_SHOCKIMMUNE)) && !(L.flags_1 & SHOCKED_1))
+ closest_type = LIVING
closest_atom = A
- closest_dist = dist
- else if(closest_mob)
+ else if(closest_type >= MACHINERY)
continue
else if(ismachinery(A))
var/obj/machinery/M = A
- var/dist = get_dist(source, A)
- if(dist <= zap_range && (dist < closest_dist || !closest_machine) && !(M.obj_flags & BEING_SHOCKED))
- closest_machine = M
+ if(!(M.obj_flags & BEING_SHOCKED))
+ closest_type = MACHINERY
closest_atom = A
- closest_dist = dist
- else if(closest_mob)
+ else if(closest_type >= BLOB)
continue
else if(istype(A, /obj/structure/blob))
var/obj/structure/blob/B = A
- var/dist = get_dist(source, A)
- if(dist <= zap_range && (dist < closest_dist || !closest_tesla_coil) && !(B.obj_flags & BEING_SHOCKED))
- closest_blob = B
+ if(!(B.obj_flags & BEING_SHOCKED))
+ closest_type = BLOB
closest_atom = A
- closest_dist = dist
- else if(closest_blob)
+ else if(closest_type >= STRUCTURE)
continue
else if(isstructure(A))
var/obj/structure/S = A
- var/dist = get_dist(source, A)
- if(dist <= zap_range && (dist < closest_dist || !closest_tesla_coil) && !(S.obj_flags & BEING_SHOCKED))
- closest_structure = S
+ if(!(S.obj_flags & BEING_SHOCKED))
+ closest_type = STRUCTURE
closest_atom = A
- closest_dist = dist
//Alright, we've done our loop, now lets see if was anything interesting in range
- if(closest_atom)
- //common stuff
- source.Beam(closest_atom, icon_state="lightning[rand(1,12)]", time=5, maxdistance = INFINITY)
- if(!(tesla_flags & TESLA_ALLOW_DUPLICATES))
- LAZYSET(shocked_targets, closest_atom, TRUE)
- var/zapdir = get_dir(source, closest_atom)
- if(zapdir)
- . = zapdir
+ if(!closest_atom)
+ return
+ //common stuff
+ source.Beam(closest_atom, icon_state="lightning[rand(1,12)]", time=5, maxdistance = INFINITY)
+ if(!(zap_flags & ZAP_ALLOW_DUPLICATES))
+ LAZYSET(shocked_targets, closest_atom, TRUE)
+ var/zapdir = get_dir(source, closest_atom)
+ if(zapdir)
+ . = zapdir
- //per type stuff:
- if(closest_tesla_coil)
- closest_tesla_coil.tesla_act(power, tesla_flags, shocked_targets)
+ var/next_range = 3
+ if(closest_type == COIL)
+ next_range = 5
- else if(closest_grounding_rod)
- closest_grounding_rod.tesla_act(power, tesla_flags, shocked_targets)
-
- else if(closest_mob)
- var/shock_damage = (tesla_flags & TESLA_MOB_DAMAGE)? (min(round(power/600), 90) + rand(-5, 5)) : 0
- closest_mob.electrocute_act(shock_damage, source, 1, SHOCK_TESLA | ((tesla_flags & TESLA_MOB_STUN) ? NONE : SHOCK_NOSTUN))
+ if(closest_type == LIVING)
+ var/mob/living/closest_mob = closest_atom
+ closest_mob.set_shocked()
+ addtimer(CALLBACK(closest_mob, /mob/living/proc/reset_shocked), 10)
+ var/shock_damage = (zap_flags & ZAP_MOB_DAMAGE) ? (min(round(power/600), 90) + rand(-5, 5)) : 0
+ closest_mob.electrocute_act(shock_damage, source, 1, SHOCK_TESLA | ((zap_flags & ZAP_MOB_STUN) ? NONE : SHOCK_NOSTUN))
if(issilicon(closest_mob))
var/mob/living/silicon/S = closest_mob
- if((tesla_flags & TESLA_MOB_STUN) && (tesla_flags & TESLA_MOB_DAMAGE))
+ if((zap_flags & ZAP_MOB_STUN) && (zap_flags & ZAP_MOB_DAMAGE))
S.emp_act(EMP_LIGHT)
- tesla_zap(S, 7, power / 1.5, tesla_flags, shocked_targets) // metallic folks bounce it further
+ next_range = 7 // metallic folks bounce it further
else
- tesla_zap(closest_mob, 5, power / 1.5, tesla_flags, shocked_targets)
+ next_range = 5
+ power /= 1.5
- else if(closest_machine)
- closest_machine.tesla_act(power, tesla_flags, shocked_targets)
+ else
+ power = closest_atom.zap_act(power, zap_flags, shocked_targets)
+ if(prob(20))//I know I know
+ tesla_zap(closest_atom, next_range, power * 0.5, zap_flags, shocked_targets)
+ tesla_zap(closest_atom, next_range, power * 0.5, zap_flags, shocked_targets)
+ else
+ tesla_zap(closest_atom, next_range, power, zap_flags, shocked_targets)
- else if(closest_blob)
- closest_blob.tesla_act(power, tesla_flags, shocked_targets)
-
- else if(closest_structure)
- closest_structure.tesla_act(power, tesla_flags, shocked_targets)
+#undef BIKE
+#undef COIL
+#undef ROD
+#undef RIDE
+#undef LIVING
+#undef MACHINERY
+#undef BLOB
+#undef STRUCTURE
diff --git a/code/modules/power/tesla/generator.dm b/code/modules/power/tesla/generator.dm
index 53d7010806..260f4128bc 100644
--- a/code/modules/power/tesla/generator.dm
+++ b/code/modules/power/tesla/generator.dm
@@ -5,6 +5,6 @@
icon_state = "TheSingGen"
creation_type = /obj/singularity/energy_ball
-/obj/machinery/the_singularitygen/tesla/tesla_act(power, tesla_flags)
- if(tesla_flags & TESLA_MACHINE_EXPLOSIVE)
+/obj/machinery/the_singularitygen/tesla/zap_act(power, zap_flags)
+ if(zap_flags & ZAP_MACHINE_EXPLOSIVE)
energy += power
diff --git a/code/modules/projectiles/ammunition/_firing.dm b/code/modules/projectiles/ammunition/_firing.dm
index 848163d658..1a6786524c 100644
--- a/code/modules/projectiles/ammunition/_firing.dm
+++ b/code/modules/projectiles/ammunition/_firing.dm
@@ -31,6 +31,10 @@
else
BB.def_zone = user.zone_selected
BB.suppressed = quiet
+
+ if(isgun(fired_from))
+ var/obj/item/gun/G = fired_from
+ BB.damage *= G.projectile_damage_multiplier
if(reagents && BB.reagents)
reagents.trans_to(BB, reagents.total_volume) //For chemical darts/bullets
diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm
index 9c1a23174e..cf9e606ffc 100644
--- a/code/modules/projectiles/gun.dm
+++ b/code/modules/projectiles/gun.dm
@@ -76,6 +76,9 @@
var/datum/action/item_action/toggle_scope_zoom/azoom
var/dualwield_spread_mult = 1 //dualwield spread multiplier
+
+ /// Just 'slightly' snowflakey way to modify projectile damage for projectiles fired from this gun.
+ var/projectile_damage_multiplier = 1
/obj/item/gun/Initialize()
. = ..()
diff --git a/code/modules/projectiles/guns/ballistic/bow.dm b/code/modules/projectiles/guns/ballistic/bow.dm
index 3f3d2c6f47..4bd7d34fe2 100644
--- a/code/modules/projectiles/guns/ballistic/bow.dm
+++ b/code/modules/projectiles/guns/ballistic/bow.dm
@@ -59,7 +59,7 @@
/obj/item/gun/ballistic/bow/pipe
name = "pipe bow"
- desc = "Some sort of pipe made projectile weapon made of a silk string and lots of bending. Used to fire arrows."
+ desc = "Some sort of pipe made projectile weapon made of a durathread string and lots of bending. Used to fire arrows."
icon_state = "pipebow"
item_state = "pipebow"
force = 0
diff --git a/code/modules/projectiles/projectile/energy/tesla.dm b/code/modules/projectiles/projectile/energy/tesla.dm
index 2439cee429..1afbdeae25 100644
--- a/code/modules/projectiles/projectile/energy/tesla.dm
+++ b/code/modules/projectiles/projectile/energy/tesla.dm
@@ -3,7 +3,7 @@
icon_state = "tesla_projectile"
impact_effect_type = /obj/effect/temp_visual/impact_effect/blue_laser
var/chain
- var/tesla_flags = TESLA_MOB_DAMAGE | TESLA_OBJ_DAMAGE
+ var/zap_flags = ZAP_MOB_DAMAGE | ZAP_OBJ_DAMAGE
var/zap_range = 3
var/power = 10000
@@ -15,7 +15,7 @@
/obj/item/projectile/energy/tesla/on_hit(atom/target)
. = ..()
- tesla_zap(target, zap_range, power, tesla_flags)
+ tesla_zap(target, zap_range, power, zap_flags)
qdel(src)
/obj/item/projectile/energy/tesla/Destroy()
diff --git a/code/modules/projectiles/projectile/magic.dm b/code/modules/projectiles/projectile/magic.dm
index ff6340bcdb..dbb1497367 100644
--- a/code/modules/projectiles/projectile/magic.dm
+++ b/code/modules/projectiles/projectile/magic.dm
@@ -437,9 +437,9 @@
speed = 0.3
flag = "magic"
- var/tesla_power = 20000
- var/tesla_range = 15
- var/tesla_flags = TESLA_MOB_DAMAGE | TESLA_MOB_STUN | TESLA_OBJ_DAMAGE
+ var/zap_power = 20000
+ var/zap_range = 15
+ var/zap_flags = ZAP_MOB_DAMAGE | ZAP_MOB_STUN | ZAP_OBJ_DAMAGE
var/chain
var/mob/living/caster
@@ -456,7 +456,7 @@
visible_message("[src] fizzles on contact with [target]!")
qdel(src)
return BULLET_ACT_BLOCK
- tesla_zap(src, tesla_range, tesla_power, tesla_flags)
+ tesla_zap(src, zap_range, zap_power, zap_flags)
qdel(src)
/obj/item/projectile/magic/aoe/lightning/Destroy()
diff --git a/code/modules/projectiles/projectile/special/hallucination.dm b/code/modules/projectiles/projectile/special/hallucination.dm
index 3aa85c085f..19fd13857a 100644
--- a/code/modules/projectiles/projectile/special/hallucination.dm
+++ b/code/modules/projectiles/projectile/special/hallucination.dm
@@ -50,7 +50,7 @@
if(M == hal_target)
to_chat(hal_target, "[M] is hit by \a [src] in the chest!")
hal_apply_effect()
- else if(M in view(hal_target))
+ else if(M in hal_target.fov_view())
to_chat(hal_target, "[M] is hit by \a [src] in the chest!!")
if(damage_type == BRUTE)
var/splatter_dir = dir
diff --git a/code/modules/reagents/chemistry/holder.dm b/code/modules/reagents/chemistry/holder.dm
index f4c06f39cc..38aafc665f 100644
--- a/code/modules/reagents/chemistry/holder.dm
+++ b/code/modules/reagents/chemistry/holder.dm
@@ -535,7 +535,7 @@
add_reagent(P, cached_results[P]*multiplier, null, chem_temp)
- var/list/seen = viewers(4, get_turf(my_atom))//Sound and sight checkers
+ var/list/seen = fov_viewers(4, get_turf(my_atom))//Sound and sight checkers
var/iconhtml = icon2html(cached_my_atom, seen)
if(cached_my_atom)
if(!ismob(cached_my_atom)) // No bubbling mobs
@@ -617,10 +617,7 @@
handle_reactions()
update_total()
//Reaction sounds and words
- var/list/seen = viewers(5, get_turf(my_atom))
- var/iconhtml = icon2html(my_atom, seen)
- for(var/mob/M in seen)
- to_chat(M, "[iconhtml] [C.mix_message]")
+ my_atom.visible_message("[icon2html(my_atom, viewers(DEFAULT_MESSAGE_RANGE, src))] [C.mix_message]")
/datum/reagents/proc/fermiReact(selected_reaction, cached_temp, cached_pH, reactedVol, targetVol, cached_required_reagents, cached_results, multiplier)
var/datum/chemical_reaction/C = selected_reaction
diff --git a/code/modules/reagents/chemistry/machinery/chem_dispenser.dm b/code/modules/reagents/chemistry/machinery/chem_dispenser.dm
index 6da592a56c..09ba0762cf 100644
--- a/code/modules/reagents/chemistry/machinery/chem_dispenser.dm
+++ b/code/modules/reagents/chemistry/machinery/chem_dispenser.dm
@@ -510,12 +510,10 @@
/datum/reagent/consumable/peachjuice
)
emagged_reagents = list(
- /datum/reagent/consumable/ethanol/thirteenloko,
- /datum/reagent/consumable/ethanol/changelingsting,
- /datum/reagent/consumable/ethanol/whiskey_cola,
/datum/reagent/toxin/mindbreaker,
/datum/reagent/toxin/staminatoxin,
- /datum/reagent/medicine/cryoxadone
+ /datum/reagent/medicine/cryoxadone,
+ /datum/reagent/iron
)
/obj/machinery/chem_dispenser/drinks/fullupgrade //fully ugpraded stock parts, emagged
@@ -570,11 +568,12 @@
upgrade_reagents2 = null
upgrade_reagents3 = null
emagged_reagents = list(
- /datum/reagent/iron,
/datum/reagent/consumable/ethanol/alexander,
/datum/reagent/consumable/clownstears,
/datum/reagent/toxin/minttoxin,
- /datum/reagent/consumable/ethanol/atomicbomb
+ /datum/reagent/consumable/ethanol/atomicbomb,
+ /datum/reagent/consumable/ethanol/thirteenloko,
+ /datum/reagent/consumable/ethanol/changelingsting
)
/obj/machinery/chem_dispenser/drinks/beer/fullupgrade //fully ugpraded stock parts, emagged
diff --git a/code/modules/reagents/chemistry/machinery/pandemic.dm b/code/modules/reagents/chemistry/machinery/pandemic.dm
index a6f5468c74..4a4bbdb546 100644
--- a/code/modules/reagents/chemistry/machinery/pandemic.dm
+++ b/code/modules/reagents/chemistry/machinery/pandemic.dm
@@ -170,7 +170,7 @@
if(!A.mutable)
return
if(A)
- var/new_name = sanitize_name(html_encode(params["name"]))
+ var/new_name = sanitize_name(html_encode(trim(params["name"], 50)))
if(!new_name || ..())
return
A.AssignName(new_name)
diff --git a/code/modules/reagents/chemistry/reagents/pyrotechnic_reagents.dm b/code/modules/reagents/chemistry/reagents/pyrotechnic_reagents.dm
index 67ff61610d..50d94a637e 100644
--- a/code/modules/reagents/chemistry/reagents/pyrotechnic_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/pyrotechnic_reagents.dm
@@ -227,6 +227,18 @@
playsound(M, "sparks", 50, 1)
..()
+/datum/reagent/teslium/on_mob_metabolize(mob/living/carbon/human/L)
+ . = ..()
+ if(!istype(L))
+ return
+ L.physiology.siemens_coeff *= 2
+
+/datum/reagent/teslium/on_mob_end_metabolize(mob/living/carbon/human/L)
+ . = ..()
+ if(!istype(L))
+ return
+ L.physiology.siemens_coeff *= 0.5
+
/datum/reagent/teslium/energized_jelly
name = "Energized Jelly"
description = "Electrically-charged jelly. Boosts jellypeople's nervous system, but only shocks other lifeforms."
diff --git a/code/modules/reagents/chemistry/reagents/toxin_reagents.dm b/code/modules/reagents/chemistry/reagents/toxin_reagents.dm
index 141367c9d9..3ba883a2c7 100644
--- a/code/modules/reagents/chemistry/reagents/toxin_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/toxin_reagents.dm
@@ -765,7 +765,9 @@
/datum/reagent/toxin/rotatium/on_mob_life(mob/living/carbon/M)
if(M.hud_used)
if(current_cycle >= 20 && current_cycle%20 == 0)
- var/list/screens = list(M.hud_used.plane_masters["[FLOOR_PLANE]"], M.hud_used.plane_masters["[GAME_PLANE]"], M.hud_used.plane_masters["[LIGHTING_PLANE]"])
+ var/list/screens = list(M.hud_used.plane_masters["[FLOOR_PLANE]"], M.hud_used.plane_masters["[GAME_PLANE]"],
+ M.hud_used.plane_masters["[LIGHTING_PLANE]"], M.hud_used.plane_masters["[WALL_PLANE]"],
+ M.hud_used.plane_masters["[ABOVE_WALL_PLANE]"])
var/rotation = min(round(current_cycle/20), 89) // By this point the player is probably puking and quitting anyway
for(var/whole_screen in screens)
animate(whole_screen, transform = matrix(rotation, MATRIX_ROTATE), time = 5, easing = QUAD_EASING, loop = -1)
@@ -793,15 +795,17 @@
/*
if(M.hud_used)
if(current_cycle >= 5 && current_cycle % 3 == 0)
- var/list/screens = list(M.hud_used.plane_masters["[FLOOR_PLANE]"], M.hud_used.plane_masters["[GAME_PLANE]"], M.hud_used.plane_masters["[LIGHTING_PLANE]"])
- var/matrix/skew = matrix()
+ var/list/screens = list(M.hud_used.plane_masters["[FLOOR_PLANE]"], M.hud_used.plane_masters["[GAME_PLANE]"],
+ M.hud_used.plane_masters["[LIGHTING_PLANE]"], M.hud_used.plane_masters["[WALL_PLANE]"],
+ M.hud_used.plane_masters["[ABOVE_WALL_PLANE]"]) var/matrix/skew = matrix()
var/intensity = 8
skew.set_skew(rand(-intensity,intensity), rand(-intensity,intensity))
var/matrix/newmatrix = skew
if(prob(33)) // 1/3rd of the time, let's make it stack with the previous matrix! Mwhahahaha!
- var/obj/screen/plane_master/PM = M.hud_used.plane_masters["[GAME_PLANE]"]
- newmatrix = skew * PM.transform
+ for(var/whole_screen in screens)
+ var/obj/screen/plane_master/PM = whole_screen
+ newmatrix = skew * PM.transform
for(var/whole_screen in screens)
animate(whole_screen, transform = newmatrix, time = 5, easing = QUAD_EASING, loop = -1)
diff --git a/code/modules/reagents/chemistry/recipes/others.dm b/code/modules/reagents/chemistry/recipes/others.dm
index ce1940994d..618ac256e2 100644
--- a/code/modules/reagents/chemistry/recipes/others.dm
+++ b/code/modules/reagents/chemistry/recipes/others.dm
@@ -440,9 +440,8 @@
mob_react = FALSE
/datum/chemical_reaction/foam/on_reaction(datum/reagents/holder, multiplier)
- var/location = get_turf(holder.my_atom)
- for(var/mob/M in viewers(5, location))
- to_chat(M, "The solution spews out foam!")
+ var/turf/location = get_turf(holder.my_atom)
+ location.visible_message("The solution spews out foam!")
var/datum/effect_system/foam_spread/s = new()
s.set_up(multiplier*2, location, holder)
s.start()
@@ -457,11 +456,8 @@
mob_react = FALSE
/datum/chemical_reaction/metalfoam/on_reaction(datum/reagents/holder, multiplier)
- var/location = get_turf(holder.my_atom)
-
- for(var/mob/M in viewers(5, location))
- to_chat(M, "The solution spews out a metallic foam!")
-
+ var/turf/location = get_turf(holder.my_atom)
+ location.visible_message("The solution spews out a metallic foam!")
var/datum/effect_system/foam_spread/metal/s = new()
s.set_up(multiplier*5, location, holder, 1)
s.start()
@@ -488,9 +484,8 @@
mob_react = FALSE
/datum/chemical_reaction/ironfoam/on_reaction(datum/reagents/holder, multiplier)
- var/location = get_turf(holder.my_atom)
- for(var/mob/M in viewers(5, location))
- to_chat(M, "The solution spews out a metallic foam!")
+ var/turf/location = get_turf(holder.my_atom)
+ location.visible_message("The solution spews out metallic foam!")
var/datum/effect_system/foam_spread/metal/s = new()
s.set_up(multiplier*5, location, holder, 2)
s.start()
diff --git a/code/modules/reagents/chemistry/recipes/pyrotechnics.dm b/code/modules/reagents/chemistry/recipes/pyrotechnics.dm
index 8782d65f76..1d06aaacde 100644
--- a/code/modules/reagents/chemistry/recipes/pyrotechnics.dm
+++ b/code/modules/reagents/chemistry/recipes/pyrotechnics.dm
@@ -429,7 +429,7 @@
noexplosion = TRUE
mix_message = "The teslium starts to spark as electricity arcs away from it!"
mix_sound = 'sound/machines/defib_zap.ogg'
- var/tesla_flags = TESLA_MOB_DAMAGE | TESLA_OBJ_DAMAGE | TESLA_MOB_STUN
+ var/zap_flags = ZAP_MOB_DAMAGE | ZAP_OBJ_DAMAGE | ZAP_MOB_STUN
/datum/chemical_reaction/reagent_explosion/teslium_lightning/on_reaction(datum/reagents/holder, multiplier)
var/T1 = multiplier * 20 //100 units : Zap 3 times, with powers 2000/5000/12000. Tesla revolvers have a power of 10000 for comparison.
@@ -437,15 +437,15 @@
var/T3 = multiplier * 120
sleep(5)
if(multiplier >= 75)
- tesla_zap(holder.my_atom, 7, T1, tesla_flags)
+ tesla_zap(holder.my_atom, 7, T1, zap_flags)
playsound(holder.my_atom, 'sound/machines/defib_zap.ogg', 50, 1)
sleep(15)
if(multiplier >= 40)
- tesla_zap(holder.my_atom, 7, T2, tesla_flags)
+ tesla_zap(holder.my_atom, 7, T2, zap_flags)
playsound(holder.my_atom, 'sound/machines/defib_zap.ogg', 50, 1)
sleep(15)
if(multiplier >= 10) //10 units minimum for lightning, 40 units for secondary blast, 75 units for tertiary blast.
- tesla_zap(holder.my_atom, 7, T3, tesla_flags)
+ tesla_zap(holder.my_atom, 7, T3, zap_flags)
playsound(holder.my_atom, 'sound/machines/defib_zap.ogg', 50, 1)
..()
diff --git a/code/modules/reagents/reagent_containers.dm b/code/modules/reagents/reagent_containers.dm
index f326b94e44..fbdbb5f656 100644
--- a/code/modules/reagents/reagent_containers.dm
+++ b/code/modules/reagents/reagent_containers.dm
@@ -160,11 +160,8 @@
/obj/item/reagent_containers/microwave_act(obj/machinery/microwave/M)
reagents.expose_temperature(1000)
if(container_flags & TEMP_WEAK)
- var/list/seen = viewers(5, get_turf(src))
- var/iconhtml = icon2html(src, seen)
- for(var/mob/H in seen)
- to_chat(H, "[iconhtml] \The [src]'s melts from the temperature!")
- playsound(get_turf(src), 'sound/FermiChem/heatmelt.ogg', 80, 1)
+ visible_message("[icon2html(src, viewers(DEFAULT_MESSAGE_RANGE, src))] [src]'s melts from the temperature!")
+ playsound(src, 'sound/FermiChem/heatmelt.ogg', 80, 1)
qdel(src)
..()
@@ -184,7 +181,7 @@
if((reagents.pH < 1.5) || (reagents.pH > 12.5))
START_PROCESSING(SSobj, src)
else if((reagents.pH < -3) || (reagents.pH > 17))
- visible_message("[icon2html(src, viewers(src))] \The [src] is damaged by the super pH and begins to deform!")
+ visible_message("[icon2html(src, viewers(DEFAULT_MESSAGE_RANGE, src))] \The [src] is damaged by the super pH and begins to deform!")
reagents.pH = clamp(reagents.pH, -3, 17)
container_HP -= 1
@@ -221,15 +218,11 @@
container_HP -= damage
- var/list/seen = viewers(5, get_turf(src))
- var/iconhtml = icon2html(src, seen)
-
var/damage_percent = ((container_HP / initial(container_HP)*100))
switch(damage_percent)
if(-INFINITY to 0)
- for(var/mob/M in seen)
- to_chat(M, "[iconhtml] \The [src]'s melts [cause]!")
- playsound(get_turf(src), 'sound/FermiChem/acidmelt.ogg', 80, 1)
+ visible_message("[icon2html(src, viewers(DEFAULT_MESSAGE_RANGE, src))] [src]'s melts [cause]!")
+ playsound(src, 'sound/FermiChem/acidmelt.ogg', 80, 1)
SSblackbox.record_feedback("tally", "fermi_chem", 1, "Times beakers have melted")
STOP_PROCESSING(SSobj, src)
qdel(src)
@@ -246,5 +239,4 @@
update_icon()
if(prob(25))
- for(var/mob/M in seen)
- to_chat(M, "[iconhtml] \The [src]'s is damaged by [cause] and begins to deform!")
+ visible_message("[icon2html(src, viewers(DEFAULT_MESSAGE_RANGE, src))] [src]'s is damaged by [cause] and begins to deform!")
diff --git a/code/modules/reagents/reagent_containers/pill.dm b/code/modules/reagents/reagent_containers/pill.dm
index e6fa18ba9c..36e3b0d47e 100644
--- a/code/modules/reagents/reagent_containers/pill.dm
+++ b/code/modules/reagents/reagent_containers/pill.dm
@@ -72,9 +72,8 @@
to_chat(user, "[target] is full.")
return
- to_chat(user, "You dissolve [src] in [target].")
- for(var/mob/O in viewers(2, user)) //viewers is necessary here because of the small radius
- to_chat(O, "[user] slips something into [target]!")
+ user.visible_message("[user] slips something into [target]!",
+ "You dissolve [src] in [target].", vision_distance = 2)
reagents.trans_to(target, reagents.total_volume)
qdel(src)
diff --git a/code/modules/reagents/reagent_dispenser.dm b/code/modules/reagents/reagent_dispenser.dm
index 54ec327fdb..9ef08590a8 100644
--- a/code/modules/reagents/reagent_dispenser.dm
+++ b/code/modules/reagents/reagent_dispenser.dm
@@ -120,9 +120,10 @@
/obj/structure/reagent_dispensers/fueltank/fire_act(exposed_temperature, exposed_volume)
boom()
-/obj/structure/reagent_dispensers/fueltank/tesla_act()
+/obj/structure/reagent_dispensers/fueltank/zap_act(power, zap_flags, shocked_objects)
..() //extend the zap
- boom()
+ if(ZAP_OBJ_DAMAGE & zap_flags)
+ boom()
/obj/structure/reagent_dispensers/fueltank/bullet_act(obj/item/projectile/P)
. = ..()
@@ -169,6 +170,7 @@
name = "pepper spray refiller"
desc = "Contains condensed capsaicin for use in law \"enforcement.\""
icon_state = "pepper"
+ plane = ABOVE_WALL_PLANE
anchored = TRUE
density = FALSE
reagent_id = /datum/reagent/consumable/condensedcapsaicin
@@ -182,6 +184,7 @@
name = "virus food dispenser"
desc = "A dispenser of low-potency virus mutagenic."
icon_state = "virus_food"
+ plane = ABOVE_WALL_PLANE
anchored = TRUE
density = FALSE
reagent_id = /datum/reagent/consumable/virus_food
diff --git a/code/modules/recycling/disposal/pipe.dm b/code/modules/recycling/disposal/pipe.dm
index aed2310a7f..45d3d9da25 100644
--- a/code/modules/recycling/disposal/pipe.dm
+++ b/code/modules/recycling/disposal/pipe.dm
@@ -14,6 +14,7 @@
max_integrity = 200
armor = list("melee" = 25, "bullet" = 10, "laser" = 10, "energy" = 100, "bomb" = 0, "bio" = 100, "rad" = 100, "fire" = 90, "acid" = 30)
layer = DISPOSAL_PIPE_LAYER // slightly lower than wires and other pipes
+ plane = ABOVE_WALL_PLANE
rad_flags = RAD_PROTECT_CONTENTS | RAD_NO_CONTAMINATE
var/dpdir = NONE // bitmask of pipe directions
var/initialize_dirs = NONE // bitflags of pipe directions added on init, see \code\_DEFINES\pipe_construction.dm
diff --git a/code/modules/research/designs/autobotter_designs.dm b/code/modules/research/designs/autobotter_designs.dm
index eab7423b91..c2ff7c953b 100644
--- a/code/modules/research/designs/autobotter_designs.dm
+++ b/code/modules/research/designs/autobotter_designs.dm
@@ -14,7 +14,7 @@
/datum/design/bottle
materials = list(/datum/material/glass = 1200)
build_type = AUTOBOTTLER
- category = list("Storge")
+ category = list("Storage")
/datum/design/bottle/wine
name = "Bottle Design (Wine)"
@@ -331,4 +331,4 @@
id = "greenroad"
reagents_list = list(/datum/reagent/consumable/vitfro = 50, /datum/reagent/consumable/ethanol/rum = 30, /datum/reagent/ash = 10)
category = list("Beers")
- build_path = /obj/item/export/bottle/greenroad
\ No newline at end of file
+ build_path = /obj/item/export/bottle/greenroad
diff --git a/code/modules/research/designs/autolathe_desings/autolathe_designs_tools.dm b/code/modules/research/designs/autolathe_desings/autolathe_designs_tools.dm
index f6c31a9808..330dfb8f8a 100644
--- a/code/modules/research/designs/autolathe_desings/autolathe_designs_tools.dm
+++ b/code/modules/research/designs/autolathe_desings/autolathe_designs_tools.dm
@@ -139,7 +139,7 @@
id = "tool_box"
build_type = AUTOLATHE
materials = list(MAT_CATEGORY_RIGID = 500)
- build_path = /obj/item/storage/toolbox
+ build_path = /obj/item/storage/toolbox/greyscale
category = list("initial","Tools")
/datum/design/spraycan
diff --git a/code/modules/research/designs/medical_designs.dm b/code/modules/research/designs/medical_designs.dm
index 5405b82848..69bf039428 100644
--- a/code/modules/research/designs/medical_designs.dm
+++ b/code/modules/research/designs/medical_designs.dm
@@ -238,7 +238,7 @@
/datum/design/bodybag
name = "Body Bag"
- desc = "A normal body bag used for storge of dead crew."
+ desc = "A normal body bag used for storage of dead crew."
id = "bodybag"
build_type = PROTOLATHE
materials = list(/datum/material/plastic = 4000)
diff --git a/code/modules/research/designs/weapon_designs.dm b/code/modules/research/designs/weapon_designs.dm
index 93168e17c7..07679fe1ce 100644
--- a/code/modules/research/designs/weapon_designs.dm
+++ b/code/modules/research/designs/weapon_designs.dm
@@ -91,7 +91,7 @@
/datum/design/mag_oldsmg
name = "WT-550 Semi-Auto SMG Magazine (4.6x30mm)"
- desc = "A 20 round magazine for the out of date security WT-550 Semi-Auto SMG."
+ desc = "A 32 round magazine for the out of date security WT-550 Semi-Auto SMG."
id = "mag_oldsmg"
build_type = PROTOLATHE
materials = list(/datum/material/iron = 4000)
@@ -101,7 +101,7 @@
/datum/design/mag_oldsmg/ap_mag
name = "WT-550 Semi-Auto SMG Armour Piercing Magazine (4.6x30mm AP)"
- desc = "A 20 round armour piercing magazine for the out of date security WT-550 Semi-Auto SMG."
+ desc = "A 32 round armour piercing magazine for the out of date security WT-550 Semi-Auto SMG."
id = "mag_oldsmg_ap"
materials = list(/datum/material/iron = 6000, /datum/material/silver = 600)
build_path = /obj/item/ammo_box/magazine/wt550m9/wtap
@@ -109,7 +109,7 @@
/datum/design/mag_oldsmg/ic_mag
name = "WT-550 Semi-Auto SMG Incendiary Magazine (4.6x30mm IC)"
- desc = "A 20 round armour piercing magazine for the out of date security WT-550 Semi-Auto SMG."
+ desc = "A 32 round armour piercing magazine for the out of date security WT-550 Semi-Auto SMG."
id = "mag_oldsmg_ic"
materials = list(/datum/material/iron = 6000, /datum/material/silver = 600, /datum/material/glass = 1000)
build_path = /obj/item/ammo_box/magazine/wt550m9/wtic
@@ -117,7 +117,7 @@
/datum/design/mag_oldsmg/tx_mag
name = "WT-550 Semi-Auto SMG Uranium Magazine (4.6x30mm TX)"
- desc = "A 20 round uranium tipped magazine for the out of date security WT-550 Semi-Auto SMG."
+ desc = "A 32 round uranium tipped magazine for the out of date security WT-550 Semi-Auto SMG."
id = "mag_oldsmg_tx"
materials = list(/datum/material/iron = 6000, /datum/material/silver = 600, /datum/material/uranium = 2000)
build_path = /obj/item/ammo_box/magazine/wt550m9/wttx
@@ -125,7 +125,7 @@
/datum/design/mag_oldsmg/rubber_mag
name = "WT-550 Semi-Auto SMG rubberbullets Magazine (4.6x30mm rubber)"
- desc = "A 20 round rubber shots magazine for the out of date security WT-550 Semi-Auto SMG"
+ desc = "A 32 round rubber shots magazine for the out of date security WT-550 Semi-Auto SMG"
id = "mag_oldsmg_rubber"
materials = list(/datum/material/iron = 6000)
build_path = /obj/item/ammo_box/magazine/wt550m9/wtrubber
diff --git a/code/modules/ruins/spaceruin_code/clericsden.dm b/code/modules/ruins/spaceruin_code/clericsden.dm
index 67e071b274..7d1fda6740 100644
--- a/code/modules/ruins/spaceruin_code/clericsden.dm
+++ b/code/modules/ruins/spaceruin_code/clericsden.dm
@@ -27,7 +27,8 @@
melee_damage_lower = 8
melee_damage_upper = 10
retreat_distance = 4 //AI proteons will rapidly move in and out of combat to avoid conflict, but will still target and follow you.
- attacktext = "pinches"
+ attack_verb_continuous = "pinches"
+ attack_verb_simple = "pinch"
environment_smash = ENVIRONMENT_SMASH_WALLS
attack_sound = 'sound/weapons/punch2.ogg'
playstyle_string = "You are a Proteon. Your abilities in combat are outmatched by most combat constructs, but you are still fast and nimble. Run metal and supplies, and cooperate with your fellow cultists."
diff --git a/code/modules/security_levels/keycard_authentication.dm b/code/modules/security_levels/keycard_authentication.dm
index d01a6de8ed..43dba451dd 100644
--- a/code/modules/security_levels/keycard_authentication.dm
+++ b/code/modules/security_levels/keycard_authentication.dm
@@ -9,6 +9,7 @@ GLOBAL_DATUM_INIT(keycard_events, /datum/events, new)
desc = "This device is used to trigger station functions, which require more than one ID card to authenticate."
icon = 'icons/obj/monitors.dmi'
icon_state = "auth_off"
+ plane = ABOVE_WALL_PLANE
use_power = IDLE_POWER_USE
idle_power_usage = 2
active_power_usage = 6
diff --git a/code/modules/spells/spell_types/aimed.dm b/code/modules/spells/spell_types/aimed.dm
index 1a904b1076..8fab4a221d 100644
--- a/code/modules/spells/spell_types/aimed.dm
+++ b/code/modules/spells/spell_types/aimed.dm
@@ -101,7 +101,7 @@
base_icon_state = "lightning"
sound = 'sound/magic/lightningbolt.ogg'
active = FALSE
- projectile_var_overrides = list("tesla_range" = 15, "tesla_power" = 20000, "tesla_flags" = TESLA_MOB_DAMAGE)
+ projectile_var_overrides = list("zap_range" = 15, "zap_power" = 20000, "zap_flags" = ZAP_MOB_DAMAGE)
active_msg = "You energize your hand with arcane lightning!"
deactive_msg = "You let the energy flow out of your hands back into yourself..."
projectile_type = /obj/item/projectile/magic/aoe/lightning
diff --git a/code/modules/surgery/advanced/bioware/nerve_grounding.dm b/code/modules/surgery/advanced/bioware/nerve_grounding.dm
index 99902ff6d6..eb70a838a4 100644
--- a/code/modules/surgery/advanced/bioware/nerve_grounding.dm
+++ b/code/modules/surgery/advanced/bioware/nerve_grounding.dm
@@ -32,13 +32,11 @@
name = "Grounded Nerves"
desc = "Nerves form a safe path for electricity to traverse, protecting the body from electric shocks."
mod_type = BIOWARE_NERVES
- var/prev_coeff
/datum/bioware/grounded_nerves/on_gain()
..()
- prev_coeff = owner.physiology.siemens_coeff
- owner.physiology.siemens_coeff = 0
+ ADD_TRAIT(owner, TRAIT_SHOCKIMMUNE, "grounded_nerves")
/datum/bioware/grounded_nerves/on_lose()
..()
- owner.physiology.siemens_coeff = prev_coeff
+ REMOVE_TRAIT(owner, TRAIT_SHOCKIMMUNE, "grounded_nerves")
diff --git a/code/modules/surgery/surgery_step.dm b/code/modules/surgery/surgery_step.dm
index f574b0aea3..e287b38ca1 100644
--- a/code/modules/surgery/surgery_step.dm
+++ b/code/modules/surgery/surgery_step.dm
@@ -57,10 +57,11 @@
surgery.step_in_progress = FALSE
return FALSE
if(tool)
- speed_mod = tool.toolspeed
+ speed_mod = tool.toolspeed //faster tools mean faster surgeries, but also less experience.
if(user.mind)
- speed_mod = user.mind.skill_holder.action_skills_mod(/datum/skill/numerical/surgery, speed_mod, THRESHOLD_COMPETENT, FALSE)
- if(do_after(user, time * speed_mod, target = target))
+ speed_mod = user.mind.action_skill_mod(/datum/skill/numerical/surgery, speed_mod, THRESHOLD_UNTRAINED, FALSE)
+ var/delay = time * speed_mod
+ if(do_after(user, delay, target = target))
var/prob_chance = 100
if(implement_type) //this means it isn't a require hand or any item step.
prob_chance = implements[implement_type]
@@ -68,7 +69,10 @@
if((prob(prob_chance) || (iscyborg(user) && !silicons_obey_prob)) && chem_check(target) && !try_to_fail)
if(success(user, target, target_zone, tool, surgery))
- user.mind?.skill_holder.auto_gain_experience(/datum/skill/numerical/surgery, SKILL_GAIN_SURGERY_PER_STEP)
+ var/multi = (delay/SKILL_GAIN_DELAY_DIVISOR)
+ if(repeatable)
+ multi *= 0.5 //Spammable surgeries award less experience.
+ user.mind?.auto_gain_experience(/datum/skill/numerical/surgery, SKILL_GAIN_SURGERY_PER_STEP * multi)
advance = TRUE
else
if(failure(user, target, target_zone, tool, surgery))
diff --git a/code/modules/tgs/core/core.dm b/code/modules/tgs/core/core.dm
index 70252cfb49..a74c9bbab2 100644
--- a/code/modules/tgs/core/core.dm
+++ b/code/modules/tgs/core/core.dm
@@ -1,11 +1,17 @@
/world/TgsNew(datum/tgs_event_handler/event_handler, minimum_required_security_level = TGS_SECURITY_ULTRASAFE)
var/current_api = TGS_READ_GLOBAL(tgs)
if(current_api)
- TGS_ERROR_LOG("TgsNew(): TGS API datum already set ([current_api])! Was TgsNew() called more than once?")
+ TGS_ERROR_LOG("API datum already set (\ref[current_api] ([current_api]))! Was TgsNew() called more than once?")
+ return
+
+ if(!(minimum_required_security_level in list(TGS_SECURITY_ULTRASAFE, TGS_SECURITY_SAFE, TGS_SECURITY_TRUSTED)))
+ TGS_ERROR_LOG("Invalid minimum_required_security_level: [minimum_required_security_level]!")
return
#ifdef TGS_V3_API
- minimum_required_security_level = TGS_SECURITY_TRUSTED
+ if(minimum_required_security_level != TGS_SECURITY_TRUSTED)
+ TGS_WARNING_LOG("V3 DMAPI requires trusted security!")
+ minimum_required_security_level = TGS_SECURITY_TRUSTED
#endif
var/raw_parameter = world.params[TGS_VERSION_PARAMETER]
if(!raw_parameter)
@@ -13,7 +19,7 @@
var/datum/tgs_version/version = new(raw_parameter)
if(!version.Valid(FALSE))
- TGS_ERROR_LOG("Failed to validate TGS version parameter: [raw_parameter]!")
+ TGS_ERROR_LOG("Failed to validate DMAPI version parameter: [raw_parameter]!")
return
var/api_datum
@@ -21,18 +27,21 @@
if(3)
#ifndef TGS_V3_API
TGS_ERROR_LOG("Detected V3 API but TGS_V3_API isn't defined!")
+ return
#else
- switch(version.major)
+ switch(version.minor)
if(2)
api_datum = /datum/tgs_api/v3210
#endif
if(4)
- switch(version.major)
+ switch(version.minor)
if(0)
api_datum = /datum/tgs_api/v4
+ if(5)
+ api_datum = /datum/tgs_api/v5
var/datum/tgs_version/max_api_version = TgsMaximumAPIVersion();
- if(version.suite != null && version.major != null && version.minor != null && version.patch != null && version.deprefixed_parameter > max_api_version.deprefixed_parameter)
+ if(version.suite != null && version.minor != null && version.patch != null && version.deprecated_patch != null && version.deprefixed_parameter > max_api_version.deprefixed_parameter)
TGS_ERROR_LOG("Detected unknown API version! Defaulting to latest. Update the DMAPI to fix this problem.")
api_datum = /datum/tgs_api/latest
@@ -41,20 +50,25 @@
return
TGS_INFO_LOG("Activating API for version [version.deprefixed_parameter]")
- var/datum/tgs_api/new_api = new api_datum(version)
+
+ if(event_handler && !istype(event_handler))
+ TGS_ERROR_LOG("Invalid parameter for event_handler: [event_handler]")
+ event_handler = null
+
+ var/datum/tgs_api/new_api = new api_datum(event_handler, version)
TGS_WRITE_GLOBAL(tgs, new_api)
- var/result = new_api.OnWorldNew(event_handler, minimum_required_security_level)
+ var/result = new_api.OnWorldNew(minimum_required_security_level)
if(!result || result == TGS_UNIMPLEMENTED)
TGS_WRITE_GLOBAL(tgs, null)
TGS_ERROR_LOG("Failed to activate API!")
/world/TgsMaximumAPIVersion()
- return new /datum/tgs_version("4.0.x.x")
+ return new /datum/tgs_version("5.x.x")
/world/TgsMinimumAPIVersion()
- return new /datum/tgs_version("3.2.0.0")
+ return new /datum/tgs_version("3.2.x")
/world/TgsInitializationComplete()
var/datum/tgs_api/api = TGS_READ_GLOBAL(tgs)
@@ -88,6 +102,11 @@
if(api)
return api.version
+/world/TgsApiVersion()
+ var/datum/tgs_api/api = TGS_READ_GLOBAL(tgs)
+ if(api)
+ return api.ApiVersion()
+
/world/TgsInstanceName()
var/datum/tgs_api/api = TGS_READ_GLOBAL(tgs)
if(api)
diff --git a/code/modules/tgs/core/datum.dm b/code/modules/tgs/core/datum.dm
index fb2508059a..ccc75fe344 100644
--- a/code/modules/tgs/core/datum.dm
+++ b/code/modules/tgs/core/datum.dm
@@ -2,13 +2,15 @@ TGS_DEFINE_AND_SET_GLOBAL(tgs, null)
/datum/tgs_api
var/datum/tgs_version/version
+ var/datum/tgs_event_handler/event_handler
-/datum/tgs_api/New(datum/tgs_version/version)
+/datum/tgs_api/New(datum/tgs_event_handler/event_handler, datum/tgs_version/version)
. = ..()
+ src.event_handler = event_handler
src.version = version
/datum/tgs_api/latest
- parent_type = /datum/tgs_api/v4
+ parent_type = /datum/tgs_api/v5
TGS_PROTECT_DATUM(/datum/tgs_api)
diff --git a/code/modules/tgs/core/tgs_version.dm b/code/modules/tgs/core/tgs_version.dm
index b97745611f..a5dae1241a 100644
--- a/code/modules/tgs/core/tgs_version.dm
+++ b/code/modules/tgs/core/tgs_version.dm
@@ -5,11 +5,11 @@
suite = text2num(version_bits[1])
if(version_bits.len > 1)
- major = text2num(version_bits[2])
+ minor = text2num(version_bits[2])
if(version_bits.len > 2)
- minor = text2num(version_bits[3])
+ patch = text2num(version_bits[3])
if(version_bits.len == 4)
- patch = text2num(version_bits[4])
+ deprecated_patch = text2num(version_bits[4])
/datum/tgs_version/proc/Valid(allow_wildcards = FALSE)
if(suite == null)
@@ -19,4 +19,10 @@
return !Wildcard()
/datum/tgs_version/Wildcard()
- return major == null || minor == null || patch == null
+ return minor == null || patch == null
+
+/datum/tgs_version/Equals(datum/tgs_version/other_version)
+ if(!istype(other_version))
+ return FALSE
+
+ return suite == other_version.suite && minor == other_version.minor && patch == other_version.patch && deprecated_patch == other_version.deprecated_patch
diff --git a/code/modules/tgs/includes.dm b/code/modules/tgs/includes.dm
index 247f1fda5d..b3c1728f34 100644
--- a/code/modules/tgs/includes.dm
+++ b/code/modules/tgs/includes.dm
@@ -2,9 +2,43 @@
#include "core\core.dm"
#include "core\datum.dm"
#include "core\tgs_version.dm"
+
#ifdef TGS_V3_API
#include "v3210\api.dm"
#include "v3210\commands.dm"
#endif
+
#include "v4\api.dm"
#include "v4\commands.dm"
+
+#include "v5\_defines.dm"
+#include "v5\api.dm"
+#include "v5\commands.dm"
+#include "v5\undef.dm"
+
+/*
+The MIT License
+
+Copyright (c) 2017 Jordan Brown
+
+Permission is hereby granted, free of charge,
+to any person obtaining a copy of this software and
+associated documentation files (the "Software"), to
+deal in the Software without restriction, including
+without limitation the rights to use, copy, modify,
+merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom
+the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
diff --git a/code/modules/tgs/v3210/api.dm b/code/modules/tgs/v3210/api.dm
index c536995b04..0fc0076c8b 100644
--- a/code/modules/tgs/v3210/api.dm
+++ b/code/modules/tgs/v3210/api.dm
@@ -39,7 +39,7 @@
var/warned_custom_commands = FALSE
/datum/tgs_api/v3210/ApiVersion()
- return "3.2.1.0"
+ return new /datum/tgs_version("3.2.1.0")
/datum/tgs_api/v3210/proc/trim_left(text)
for (var/i = 1 to length(text))
@@ -56,7 +56,7 @@
/datum/tgs_api/v3210/proc/file2list(filename)
return splittext(trim_left(trim_right(file2text(filename))), "\n")
-/datum/tgs_api/v3210/OnWorldNew(datum/tgs_event_handler/event_handler, minimum_required_security_level) //don't use event handling in this version
+/datum/tgs_api/v3210/OnWorldNew(minimum_required_security_level)
. = FALSE
comms_key = world.params[SERVICE_WORLD_PARAM]
@@ -76,7 +76,8 @@
TGS_ERROR_LOG("This API version is only supported on Windows. Not running on Windows. Aborting initialization!")
return
ListServiceCustomCommands(TRUE)
- ExportService("[SERVICE_REQUEST_API_VERSION] [ApiVersion()]", TRUE)
+ var/datum/tgs_version/api_version = ApiVersion()
+ ExportService("[SERVICE_REQUEST_API_VERSION] [api_version.deprefixed_parameter]", TRUE)
return TRUE
//nothing to do for v3
@@ -166,7 +167,8 @@
/datum/tgs_api/v3210/Revision()
if(!warned_revison)
- TGS_ERROR_LOG("Use of TgsRevision on [ApiVersion()] origin_commit only points to master!")
+ var/datum/tgs_version/api_version = ApiVersion()
+ TGS_ERROR_LOG("Use of TgsRevision on [api_version.deprefixed_parameter] origin_commit only points to master!")
warned_revison = TRUE
var/datum/tgs_revision_information/ri = new
ri.commit = commit
diff --git a/code/modules/tgs/v3210/commands.dm b/code/modules/tgs/v3210/commands.dm
index e5bc6f4895..5046631981 100644
--- a/code/modules/tgs/v3210/commands.dm
+++ b/code/modules/tgs/v3210/commands.dm
@@ -19,7 +19,7 @@
TGS_ERROR_LOG("Custom command [command_name] can't be used as it is empty or contains illegal characters!")
warned_command_names[command_name] = TRUE
continue
-
+
if(command_name_types[command_name])
if(warnings_only)
TGS_ERROR_LOG("Custom commands [command_name_types[command_name]] and [stc] have the same name, only [command_name_types[command_name]] will be available!")
@@ -55,24 +55,24 @@ The MIT License
Copyright (c) 2017 Jordan Brown
-Permission is hereby granted, free of charge,
-to any person obtaining a copy of this software and
-associated documentation files (the "Software"), to
-deal in the Software without restriction, including
-without limitation the rights to use, copy, modify,
-merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom
-the Software is furnished to do so,
+Permission is hereby granted, free of charge,
+to any person obtaining a copy of this software and
+associated documentation files (the "Software"), to
+deal in the Software without restriction, including
+without limitation the rights to use, copy, modify,
+merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom
+the Software is furnished to do so,
subject to the following conditions:
-The above copyright notice and this permission notice
+The above copyright notice and this permission notice
shall be included in all copies or substantial portions of the Software.
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
-ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
diff --git a/code/modules/tgs/v4/api.dm b/code/modules/tgs/v4/api.dm
index b61cddbeba..ba18aab688 100644
--- a/code/modules/tgs/v4/api.dm
+++ b/code/modules/tgs/v4/api.dm
@@ -43,15 +43,13 @@
var/list/cached_test_merges
var/datum/tgs_revision_information/cached_revision
- var/datum/tgs_event_handler/event_handler
-
var/export_lock = FALSE
var/list/last_interop_response
/datum/tgs_api/v4/ApiVersion()
- return "4.0.0.0"
+ return new /datum/tgs_version("4.0.0.0")
-/datum/tgs_api/v4/OnWorldNew(datum/tgs_event_handler/event_handler, minimum_required_security_level)
+/datum/tgs_api/v4/OnWorldNew(minimum_required_security_level)
json_path = world.params[TGS4_PARAM_INFO_JSON]
if(!json_path)
TGS_ERROR_LOG("Missing [TGS4_PARAM_INFO_JSON] world parameter!")
@@ -76,7 +74,6 @@
security_level = cached_json["securityLevel"]
chat_channels_json_path = cached_json["chatChannelsJson"]
chat_commands_json_path = cached_json["chatCommandsJson"]
- src.event_handler = event_handler
instance_name = cached_json["instanceName"]
ListCustomCommands()
diff --git a/code/modules/tgs/v4/commands.dm b/code/modules/tgs/v4/commands.dm
index af21a86fb6..1d9951bc04 100644
--- a/code/modules/tgs/v4/commands.dm
+++ b/code/modules/tgs/v4/commands.dm
@@ -46,24 +46,24 @@ The MIT License
Copyright (c) 2017 Jordan Brown
-Permission is hereby granted, free of charge,
-to any person obtaining a copy of this software and
-associated documentation files (the "Software"), to
-deal in the Software without restriction, including
-without limitation the rights to use, copy, modify,
-merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom
-the Software is furnished to do so,
+Permission is hereby granted, free of charge,
+to any person obtaining a copy of this software and
+associated documentation files (the "Software"), to
+deal in the Software without restriction, including
+without limitation the rights to use, copy, modify,
+merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom
+the Software is furnished to do so,
subject to the following conditions:
-The above copyright notice and this permission notice
+The above copyright notice and this permission notice
shall be included in all copies or substantial portions of the Software.
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
-ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
diff --git a/code/modules/tgs/v5/_defines.dm b/code/modules/tgs/v5/_defines.dm
new file mode 100644
index 0000000000..2baf3e12d7
--- /dev/null
+++ b/code/modules/tgs/v5/_defines.dm
@@ -0,0 +1,124 @@
+#define DMAPI5_PARAM_SERVER_PORT "tgs_port"
+#define DMAPI5_PARAM_ACCESS_IDENTIFIER "tgs_key"
+
+#define DMAPI5_BRIDGE_DATA "data"
+#define DMAPI5_TOPIC_DATA "tgs_data"
+
+#define DMAPI5_BRIDGE_COMMAND_PORT_UPDATE 0
+#define DMAPI5_BRIDGE_COMMAND_STARTUP 1
+#define DMAPI5_BRIDGE_COMMAND_PRIME 2
+#define DMAPI5_BRIDGE_COMMAND_REBOOT 3
+#define DMAPI5_BRIDGE_COMMAND_KILL 4
+#define DMAPI5_BRIDGE_COMMAND_CHAT_SEND 5
+
+#define DMAPI5_PARAMETER_ACCESS_IDENTIFIER "accessIdentifier"
+#define DMAPI5_RESPONSE_ERROR_MESSAGE "errorMessage"
+
+#define DMAPI5_BRIDGE_PARAMETER_COMMAND_TYPE "commandType"
+#define DMAPI5_BRIDGE_PARAMETER_CURRENT_PORT "currentPort"
+#define DMAPI5_BRIDGE_PARAMETER_VERSION "version"
+#define DMAPI5_BRIDGE_PARAMETER_CHAT_MESSAGE "chatMessage"
+#define DMAPI5_BRIDGE_PARAMETER_CUSTOM_COMMANDS "customCommands"
+#define DMAPI5_BRIDGE_PARAMETER_MINIMUM_SECURITY_LEVEL "minimumSecurityLevel"
+
+#define DMAPI5_BRIDGE_RESPONSE_NEW_PORT "newPort"
+#define DMAPI5_BRIDGE_RESPONSE_RUNTIME_INFORMATION "runtimeInformation"
+
+#define DMAPI5_CHAT_MESSAGE_TEXT "text"
+#define DMAPI5_CHAT_MESSAGE_CHANNEL_IDS "channelIds"
+
+#define DMAPI5_RUNTIME_INFORMATION_ACCESS_IDENTIFIER "accessIdentifier"
+#define DMAPI5_RUNTIME_INFORMATION_SERVER_VERSION "serverVersion"
+#define DMAPI5_RUNTIME_INFORMATION_SERVER_PORT "serverPort"
+#define DMAPI5_RUNTIME_INFORMATION_API_VALIDATE_ONLY "apiValidateOnly"
+#define DMAPI5_RUNTIME_INFORMATION_INSTANCE_NAME "instanceName"
+#define DMAPI5_RUNTIME_INFORMATION_REVISION "revision"
+#define DMAPI5_RUNTIME_INFORMATION_TEST_MERGES "testMerges"
+#define DMAPI5_RUNTIME_INFORMATION_SECURITY_LEVEL "securityLevel"
+
+#define DMAPI5_CHAT_UPDATE_CHANNELS "channels"
+
+#define DMAPI5_TEST_MERGE_TIME_MERGED "timeMerged"
+#define DMAPI5_TEST_MERGE_REVISION "revision"
+#define DMAPI5_TEST_MERGE_TITLE_AT_MERGE "titleAtMerge"
+#define DMAPI5_TEST_MERGE_BODY_AT_MERGE "bodyAtMerge"
+#define DMAPI5_TEST_MERGE_URL "url"
+#define DMAPI5_TEST_MERGE_AUTHOR "author"
+#define DMAPI5_TEST_MERGE_NUMBER "number"
+#define DMAPI5_TEST_MERGE_PULL_REQUEST_REVISION "pullRequestRevision"
+#define DMAPI5_TEST_MERGE_COMMENT "comment"
+
+#define DMAPI5_CHAT_COMMAND_NAME "name"
+#define DMAPI5_CHAT_COMMAND_PARAMS "params"
+#define DMAPI5_CHAT_COMMAND_USER "user"
+
+#define DMAPI5_EVENT_NOTIFICATION_TYPE "type"
+#define DMAPI5_EVENT_NOTIFICATION_PARAMETERS "parameters"
+
+#define DMAPI5_TOPIC_COMMAND_CHAT_COMMAND 0
+#define DMAPI5_TOPIC_COMMAND_EVENT_NOTIFICATION 1
+#define DMAPI5_TOPIC_COMMAND_CHANGE_PORT 2
+#define DMAPI5_TOPIC_COMMAND_CHANGE_REBOOT_STATE 3
+#define DMAPI5_TOPIC_COMMAND_INSTANCE_RENAMED 4
+#define DMAPI5_TOPIC_COMMAND_CHAT_CHANNELS_UPDATE 5
+#define DMAPI5_TOPIC_COMMAND_SERVER_PORT_UPDATE 6
+#define DMAPI5_TOPIC_COMMAND_HEARTBEAT 7
+#define DMAPI5_TOPIC_COMMAND_WATCHDOG_REATTACH 8
+
+#define DMAPI5_TOPIC_PARAMETER_COMMAND_TYPE "commandType"
+#define DMAPI5_TOPIC_PARAMETER_CHAT_COMMAND "chatCommand"
+#define DMAPI5_TOPIC_PARAMETER_EVENT_NOTIFICATION "eventNotification"
+#define DMAPI5_TOPIC_PARAMETER_NEW_PORT "newPort"
+#define DMAPI5_TOPIC_PARAMETER_NEW_REBOOT_STATE "newRebootState"
+#define DMAPI5_TOPIC_PARAMETER_NEW_INSTANCE_NAME "newInstanceName"
+#define DMAPI5_TOPIC_PARAMETER_CHAT_UPDATE "chatUpdate"
+#define DMAPI5_TOPIC_PARAMETER_NEW_SERVER_VERSION "newServerVersion"
+
+#define DMAPI5_TOPIC_RESPONSE_COMMAND_RESPONSE_MESSAGE "commandResponseMessage"
+#define DMAPI5_TOPIC_RESPONSE_CHAT_RESPONSES "chatResponses"
+
+#define DMAPI5_REVISION_INFORMATION_COMMIT_SHA "commitSha"
+#define DMAPI5_REVISION_INFORMATION_ORIGIN_COMMIT_SHA "originCommitSha"
+
+#define DMAPI5_CHAT_USER_ID "id"
+#define DMAPI5_CHAT_USER_FRIENDLY_NAME "friendlyName"
+#define DMAPI5_CHAT_USER_MENTION "mention"
+#define DMAPI5_CHAT_USER_CHANNEL "channel"
+
+#define DMAPI5_CHAT_CHANNEL_ID "id"
+#define DMAPI5_CHAT_CHANNEL_FRIENDLY_NAME "friendlyName"
+#define DMAPI5_CHAT_CHANNEL_CONNECTION_NAME "connectionName"
+#define DMAPI5_CHAT_CHANNEL_IS_ADMIN_CHANNEL "isAdminChannel"
+#define DMAPI5_CHAT_CHANNEL_IS_PRIVATE_CHANNEL "isPrivateChannel"
+#define DMAPI5_CHAT_CHANNEL_TAG "tag"
+
+#define DMAPI5_CUSTOM_CHAT_COMMAND_NAME "name"
+#define DMAPI5_CUSTOM_CHAT_COMMAND_HELP_TEXT "helpText"
+#define DMAPI5_CUSTOM_CHAT_COMMAND_ADMIN_ONLY "adminOnly"
+
+/*
+The MIT License
+
+Copyright (c) 2020 Jordan Brown
+
+Permission is hereby granted, free of charge,
+to any person obtaining a copy of this software and
+associated documentation files (the "Software"), to
+deal in the Software without restriction, including
+without limitation the rights to use, copy, modify,
+merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom
+the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
diff --git a/code/modules/tgs/v5/api.dm b/code/modules/tgs/v5/api.dm
new file mode 100644
index 0000000000..eedefb2877
--- /dev/null
+++ b/code/modules/tgs/v5/api.dm
@@ -0,0 +1,372 @@
+/datum/tgs_api/v5
+ var/server_port
+ var/access_identifier
+
+ var/instance_name
+ var/security_level
+
+ var/reboot_mode = TGS_REBOOT_MODE_NORMAL
+
+ var/list/intercepted_message_queue
+
+ var/list/custom_commands
+
+ var/list/test_merges
+ var/datum/tgs_revision_information/revision
+ var/list/chat_channels
+
+/datum/tgs_api/v5/ApiVersion()
+ return new /datum/tgs_version("5.1.1")
+
+/datum/tgs_api/v5/OnWorldNew(minimum_required_security_level)
+ server_port = world.params[DMAPI5_PARAM_SERVER_PORT]
+ access_identifier = world.params[DMAPI5_PARAM_ACCESS_IDENTIFIER]
+
+ var/datum/tgs_version/api_version = ApiVersion()
+ version = null
+ var/list/bridge_response = Bridge(DMAPI5_BRIDGE_COMMAND_STARTUP, list(DMAPI5_BRIDGE_PARAMETER_MINIMUM_SECURITY_LEVEL = minimum_required_security_level, DMAPI5_BRIDGE_PARAMETER_VERSION = api_version.raw_parameter, DMAPI5_BRIDGE_PARAMETER_CUSTOM_COMMANDS = ListCustomCommands()))
+ if(!istype(bridge_response))
+ TGS_ERROR_LOG("Failed initial bridge request!")
+ return FALSE
+
+ var/list/runtime_information = bridge_response[DMAPI5_BRIDGE_RESPONSE_RUNTIME_INFORMATION]
+ if(!istype(runtime_information))
+ TGS_ERROR_LOG("Failed to decode runtime information from bridge response: [json_encode(bridge_response)]!")
+ return FALSE
+
+ if(runtime_information[DMAPI5_RUNTIME_INFORMATION_API_VALIDATE_ONLY])
+ TGS_INFO_LOG("DMAPI validation, exiting...")
+ del(world)
+
+ version = new /datum/tgs_version(runtime_information[DMAPI5_RUNTIME_INFORMATION_SERVER_VERSION])
+ security_level = runtime_information[DMAPI5_RUNTIME_INFORMATION_SECURITY_LEVEL]
+ instance_name = runtime_information[DMAPI5_RUNTIME_INFORMATION_INSTANCE_NAME]
+
+ var/list/revisionData = runtime_information[DMAPI5_RUNTIME_INFORMATION_REVISION]
+ if(istype(revisionData))
+ revision = new
+ revision.commit = revisionData[DMAPI5_REVISION_INFORMATION_COMMIT_SHA]
+ revision.origin_commit = revisionData[DMAPI5_REVISION_INFORMATION_ORIGIN_COMMIT_SHA]
+ else
+ TGS_ERROR_LOG("Failed to decode [DMAPI5_RUNTIME_INFORMATION_REVISION] from runtime information!")
+
+ test_merges = list()
+ var/list/test_merge_json = runtime_information[DMAPI5_RUNTIME_INFORMATION_TEST_MERGES]
+ if(istype(test_merge_json))
+ for(var/entry in test_merge_json)
+ var/datum/tgs_revision_information/test_merge/tm = new
+ tm.number = entry[DMAPI5_TEST_MERGE_NUMBER]
+
+ var/list/revInfo = entry[DMAPI5_TEST_MERGE_REVISION]
+ if(revInfo)
+ tm.commit = revisionData[DMAPI5_REVISION_INFORMATION_COMMIT_SHA]
+ tm.origin_commit = revisionData[DMAPI5_REVISION_INFORMATION_ORIGIN_COMMIT_SHA]
+ else
+ TGS_WARNING_LOG("Failed to decode [DMAPI5_TEST_MERGE_REVISION] from test merge #[tm.number]!")
+
+ tm.time_merged = text2num(entry[DMAPI5_TEST_MERGE_TIME_MERGED])
+ tm.title = entry[DMAPI5_TEST_MERGE_TITLE_AT_MERGE]
+ tm.body = entry[DMAPI5_TEST_MERGE_BODY_AT_MERGE]
+ tm.url = entry[DMAPI5_TEST_MERGE_URL]
+ tm.author = entry[DMAPI5_TEST_MERGE_AUTHOR]
+ tm.pull_request_commit = entry[DMAPI5_TEST_MERGE_PULL_REQUEST_REVISION]
+ tm.comment = entry[DMAPI5_TEST_MERGE_COMMENT]
+
+ test_merges += tm
+ else
+ TGS_WARNING_LOG("Failed to decode [DMAPI5_RUNTIME_INFORMATION_TEST_MERGES] from runtime information!")
+
+ chat_channels = list()
+ DecodeChannels(runtime_information)
+
+ return TRUE
+
+/datum/tgs_api/v5/proc/RequireInitialBridgeResponse()
+ while(!version)
+ sleep(1)
+
+/datum/tgs_api/v5/OnInitializationComplete()
+ Bridge(DMAPI5_BRIDGE_COMMAND_PRIME)
+
+ var/tgs4_secret_sleep_offline_sauce = 29051994
+ var/old_sleep_offline = world.sleep_offline
+ world.sleep_offline = tgs4_secret_sleep_offline_sauce
+ sleep(1)
+ if(world.sleep_offline == tgs4_secret_sleep_offline_sauce) //if not someone changed it
+ world.sleep_offline = old_sleep_offline
+
+/datum/tgs_api/v5/proc/TopicResponse(error_message = null)
+ var/list/response = list()
+ response[DMAPI5_RESPONSE_ERROR_MESSAGE] = error_message
+
+ return json_encode(response)
+
+/datum/tgs_api/v5/OnTopic(T)
+ var/list/params = params2list(T)
+ var/json = params[DMAPI5_TOPIC_DATA]
+ if(!json)
+ return FALSE //continue world/Topic
+
+ var/list/topic_parameters = json_decode(json)
+ if(!topic_parameters)
+ return TopicResponse("Invalid topic parameters json!");
+
+ var/their_sCK = topic_parameters[DMAPI5_PARAMETER_ACCESS_IDENTIFIER]
+ if(their_sCK != access_identifier)
+ return TopicResponse("Failed to decode [DMAPI5_PARAMETER_ACCESS_IDENTIFIER] from: [json]!");
+
+ var/command = topic_parameters[DMAPI5_TOPIC_PARAMETER_COMMAND_TYPE]
+ if(!isnum(command))
+ return TopicResponse("Failed to decode [DMAPI5_TOPIC_PARAMETER_COMMAND_TYPE] from: [json]!")
+
+ switch(command)
+ if(DMAPI5_TOPIC_COMMAND_CHAT_COMMAND)
+ var/result = HandleCustomCommand(topic_parameters[DMAPI5_TOPIC_PARAMETER_CHAT_COMMAND])
+ if(!result)
+ result = TopicResponse("Error running chat command!")
+ return result
+ if(DMAPI5_TOPIC_COMMAND_EVENT_NOTIFICATION)
+ intercepted_message_queue = list()
+ var/list/event_notification = topic_parameters[DMAPI5_TOPIC_PARAMETER_EVENT_NOTIFICATION]
+ if(!istype(event_notification))
+ return TopicResponse("Invalid [DMAPI5_TOPIC_PARAMETER_EVENT_NOTIFICATION]!")
+
+ var/event_type = event_notification[DMAPI5_EVENT_NOTIFICATION_TYPE]
+ if(!isnum(event_type))
+ return TopicResponse("Invalid or missing [DMAPI5_EVENT_NOTIFICATION_TYPE]!")
+
+ var/list/event_parameters = event_notification[DMAPI5_EVENT_NOTIFICATION_PARAMETERS]
+ if(event_parameters && !istype(event_parameters))
+ return TopicResponse("Invalid or missing [DMAPI5_EVENT_NOTIFICATION_PARAMETERS]!")
+
+ var/list/event_call = list(event_type)
+ if(event_parameters)
+ event_call += event_parameters
+
+ if(event_handler != null)
+ event_handler.HandleEvent(arglist(event_call))
+
+ var/list/response = list()
+ response[DMAPI5_TOPIC_RESPONSE_CHAT_RESPONSES] = intercepted_message_queue
+ intercepted_message_queue = null
+ return json_encode(response)
+ if(DMAPI5_TOPIC_COMMAND_CHANGE_PORT)
+ var/new_port = topic_parameters[DMAPI5_TOPIC_PARAMETER_NEW_PORT]
+ if (!isnum(new_port) || !(new_port > 0))
+ return TopicResponse("Invalid or missing [DMAPI5_TOPIC_PARAMETER_NEW_PORT]]")
+
+ if(event_handler != null)
+ event_handler.HandleEvent(TGS_EVENT_PORT_SWAP, new_port)
+
+ //the topic still completes, miraculously
+ //I honestly didn't believe byond could do it without exploding
+ if(!world.OpenPort(new_port))
+ return TopicResponse("Port change failed!")
+
+ return TopicResponse()
+ if(DMAPI5_TOPIC_COMMAND_CHANGE_REBOOT_STATE)
+ var/new_reboot_mode = topic_parameters[DMAPI5_TOPIC_PARAMETER_NEW_REBOOT_STATE]
+ if(!isnum(new_reboot_mode))
+ return TopicResponse("Invalid or missing [DMAPI5_TOPIC_PARAMETER_NEW_REBOOT_STATE]!")
+
+ if(event_handler != null)
+ event_handler.HandleEvent(TGS_EVENT_REBOOT_MODE_CHANGE, reboot_mode, new_reboot_mode)
+
+ reboot_mode = new_reboot_mode
+ return TopicResponse()
+ if(DMAPI5_TOPIC_COMMAND_INSTANCE_RENAMED)
+ var/new_instance_name = topic_parameters[DMAPI5_TOPIC_PARAMETER_NEW_INSTANCE_NAME]
+ if(!istext(new_instance_name))
+ return TopicResponse("Invalid or missing [DMAPI5_TOPIC_PARAMETER_NEW_INSTANCE_NAME]!")
+
+ if(event_handler != null)
+ event_handler.HandleEvent(TGS_EVENT_INSTANCE_RENAMED, new_instance_name)
+
+ instance_name = new_instance_name
+ return TopicResponse()
+ if(DMAPI5_TOPIC_COMMAND_CHAT_CHANNELS_UPDATE)
+ var/list/chat_update_json = topic_parameters[DMAPI5_TOPIC_PARAMETER_CHAT_UPDATE]
+ if(!istype(chat_update_json))
+ return TopicResponse("Invalid or missing [DMAPI5_TOPIC_PARAMETER_CHAT_UPDATE]!")
+
+ DecodeChannels(chat_update_json)
+ return TopicResponse()
+ if(DMAPI5_TOPIC_COMMAND_SERVER_PORT_UPDATE)
+ var/new_port = topic_parameters[DMAPI5_TOPIC_PARAMETER_NEW_PORT]
+ if (!isnum(new_port) || !(new_port > 0))
+ return TopicResponse("Invalid or missing [DMAPI5_TOPIC_PARAMETER_NEW_PORT]]")
+
+ server_port = new_port
+ return TopicResponse()
+ if(DMAPI5_TOPIC_COMMAND_HEARTBEAT)
+ return TopicResponse()
+ if(DMAPI5_TOPIC_COMMAND_WATCHDOG_REATTACH)
+ var/new_version_string = topic_parameters[DMAPI5_TOPIC_PARAMETER_NEW_SERVER_VERSION]
+ if (!istext(new_version_string))
+ return TopicResponse("Invalid or missing [DMAPI5_TOPIC_PARAMETER_NEW_SERVER_VERSION]]")
+
+ var/datum/tgs_version/new_version = new(new_version_string)
+ if (event_handler)
+ event_handler.HandleEvent(TGS_EVENT_WATCHDOG_REATTACH, new_version)
+
+ version = new_version
+
+ return TopicResponse()
+
+ return TopicResponse("Unknown command: [command]")
+
+/datum/tgs_api/v5/proc/Bridge(command, list/data)
+ if(!data)
+ data = list()
+
+ data[DMAPI5_BRIDGE_PARAMETER_COMMAND_TYPE] = command
+ data[DMAPI5_PARAMETER_ACCESS_IDENTIFIER] = access_identifier
+
+ var/json = json_encode(data)
+ var/encoded_json = url_encode(json)
+
+ // This is an infinite sleep until we get a response
+ var/export_response = world.Export("http://127.0.0.1:[server_port]/Bridge?[DMAPI5_BRIDGE_DATA]=[encoded_json]")
+ if(!export_response)
+ TGS_ERROR_LOG("Failed export request: [json]")
+ return
+
+ var/response_json = file2text(export_response["CONTENT"])
+ if(!response_json)
+ TGS_ERROR_LOG("Failed export request, missing content!")
+ return
+
+ var/list/bridge_response = json_decode(response_json)
+ if(!bridge_response)
+ TGS_ERROR_LOG("Failed export request, bad json: [response_json]")
+ return
+
+ var/error = bridge_response[DMAPI5_RESPONSE_ERROR_MESSAGE]
+ if(error)
+ TGS_ERROR_LOG("Failed export request, bad request: [error]")
+ return
+
+ return bridge_response
+
+/datum/tgs_api/v5/OnReboot()
+ var/list/result = Bridge(DMAPI5_BRIDGE_COMMAND_REBOOT)
+ if(!result)
+ return
+
+ //okay so the standard TGS4 proceedure is: right before rebooting change the port to whatever was sent to us in the above json's data parameter
+
+ var/port = result[DMAPI5_BRIDGE_RESPONSE_NEW_PORT]
+ if(!isnum(port))
+ return //this is valid, server may just want use to reboot
+
+ if(port == 0)
+ //to byond 0 means any port and "none" means close vOv
+ port = "none"
+
+ if(!world.OpenPort(port))
+ TGS_ERROR_LOG("Unable to set port to [port]!")
+
+/datum/tgs_api/v5/InstanceName()
+ RequireInitialBridgeResponse()
+ return instance_name
+
+/datum/tgs_api/v5/TestMerges()
+ RequireInitialBridgeResponse()
+ return test_merges
+
+/datum/tgs_api/v5/EndProcess()
+ Bridge(DMAPI5_BRIDGE_COMMAND_KILL)
+
+/datum/tgs_api/v5/Revision()
+ RequireInitialBridgeResponse()
+ return revision
+
+/datum/tgs_api/v5/ChatBroadcast(message, list/channels)
+ if(!length(channels))
+ channels = ChatChannelInfo()
+
+ var/list/ids = list()
+ for(var/I in channels)
+ var/datum/tgs_chat_channel/channel = I
+ ids += channel.id
+
+ message = list(DMAPI5_CHAT_MESSAGE_TEXT = message, DMAPI5_CHAT_MESSAGE_CHANNEL_IDS = ids)
+ if(intercepted_message_queue)
+ intercepted_message_queue += list(message)
+ else
+ Bridge(DMAPI5_BRIDGE_COMMAND_CHAT_SEND, list(DMAPI5_BRIDGE_PARAMETER_CHAT_MESSAGE = message))
+
+/datum/tgs_api/v5/ChatTargetedBroadcast(message, admin_only)
+ var/list/channels = list()
+ for(var/I in ChatChannelInfo())
+ var/datum/tgs_chat_channel/channel = I
+ if (!channel.is_private_channel && ((channel.is_admin_channel && admin_only) || (!channel.is_admin_channel && !admin_only)))
+ channels += channel.id
+ message = list(DMAPI5_CHAT_MESSAGE_TEXT = message, DMAPI5_CHAT_MESSAGE_CHANNEL_IDS = channels)
+ if(intercepted_message_queue)
+ intercepted_message_queue += list(message)
+ else
+ Bridge(DMAPI5_BRIDGE_COMMAND_CHAT_SEND, list(DMAPI5_BRIDGE_PARAMETER_CHAT_MESSAGE = message))
+
+/datum/tgs_api/v5/ChatPrivateMessage(message, datum/tgs_chat_user/user)
+ message = list(DMAPI5_CHAT_MESSAGE_TEXT = message, DMAPI5_CHAT_MESSAGE_CHANNEL_IDS = list(user.channel.id))
+ if(intercepted_message_queue)
+ intercepted_message_queue += list(message)
+ else
+ Bridge(DMAPI5_BRIDGE_COMMAND_CHAT_SEND, list(DMAPI5_BRIDGE_PARAMETER_CHAT_MESSAGE = message))
+
+/datum/tgs_api/v5/ChatChannelInfo()
+ RequireInitialBridgeResponse()
+ return chat_channels
+
+/datum/tgs_api/v5/proc/DecodeChannels(chat_update_json)
+ var/list/chat_channels_json = chat_update_json[DMAPI5_CHAT_UPDATE_CHANNELS]
+ if(istype(chat_channels_json))
+ chat_channels.Cut()
+ for(var/channel_json in chat_channels_json)
+ var/datum/tgs_chat_channel/channel = DecodeChannel(channel_json)
+ if(channel)
+ chat_channels += channel
+ else
+ TGS_WARNING_LOG("Failed to decode [DMAPI5_CHAT_UPDATE_CHANNELS] from channel update!")
+
+/datum/tgs_api/v5/proc/DecodeChannel(channel_json)
+ var/datum/tgs_chat_channel/channel = new
+ channel.id = channel_json[DMAPI5_CHAT_CHANNEL_ID]
+ channel.friendly_name = channel_json[DMAPI5_CHAT_CHANNEL_FRIENDLY_NAME]
+ channel.connection_name = channel_json[DMAPI5_CHAT_CHANNEL_CONNECTION_NAME]
+ channel.is_admin_channel = channel_json[DMAPI5_CHAT_CHANNEL_IS_ADMIN_CHANNEL]
+ channel.is_private_channel = channel_json[DMAPI5_CHAT_CHANNEL_IS_PRIVATE_CHANNEL]
+ channel.custom_tag = channel_json[DMAPI5_CHAT_CHANNEL_TAG]
+ return channel
+
+/datum/tgs_api/v5/SecurityLevel()
+ RequireInitialBridgeResponse()
+ return security_level
+
+/*
+The MIT License
+
+Copyright (c) 2020 Jordan Brown
+
+Permission is hereby granted, free of charge,
+to any person obtaining a copy of this software and
+associated documentation files (the "Software"), to
+deal in the Software without restriction, including
+without limitation the rights to use, copy, modify,
+merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom
+the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
diff --git a/code/modules/tgs/v5/commands.dm b/code/modules/tgs/v5/commands.dm
new file mode 100644
index 0000000000..2775157656
--- /dev/null
+++ b/code/modules/tgs/v5/commands.dm
@@ -0,0 +1,68 @@
+/datum/tgs_api/v5/proc/ListCustomCommands()
+ var/results = list()
+ custom_commands = list()
+ for(var/I in typesof(/datum/tgs_chat_command) - /datum/tgs_chat_command)
+ var/datum/tgs_chat_command/stc = new I
+ var/command_name = stc.name
+ if(!command_name || findtext(command_name, " ") || findtext(command_name, "'") || findtext(command_name, "\""))
+ TGS_WARNING_LOG("Custom command [command_name] ([I]) can't be used as it is empty or contains illegal characters!")
+ continue
+
+ if(results[command_name])
+ var/datum/other = custom_commands[command_name]
+ TGS_WARNING_LOG("Custom commands [other.type] and [I] have the same name (\"[command_name]\"), only [other.type] will be available!")
+ continue
+ results += list(list(DMAPI5_CUSTOM_CHAT_COMMAND_NAME = command_name, DMAPI5_CUSTOM_CHAT_COMMAND_HELP_TEXT = stc.help_text, DMAPI5_CUSTOM_CHAT_COMMAND_ADMIN_ONLY = stc.admin_only))
+ custom_commands[command_name] = stc
+
+ return results
+
+/datum/tgs_api/v5/proc/HandleCustomCommand(list/command_json)
+ var/command = command_json[DMAPI5_CHAT_COMMAND_NAME]
+ var/user = command_json[DMAPI5_CHAT_COMMAND_USER]
+ var/params = command_json[DMAPI5_CHAT_COMMAND_PARAMS]
+
+ var/datum/tgs_chat_user/u = new
+ u.id = user[DMAPI5_CHAT_USER_ID]
+ u.friendly_name = user[DMAPI5_CHAT_USER_FRIENDLY_NAME]
+ u.mention = user[DMAPI5_CHAT_USER_MENTION]
+ u.channel = DecodeChannel(user[DMAPI5_CHAT_USER_CHANNEL])
+
+ var/datum/tgs_chat_command/sc = custom_commands[command]
+ if(sc)
+ var/text_response = sc.Run(u, params)
+ var/list/topic_response = list()
+ if(!istext(text_response))
+ TGS_ERROR_LOG("Custom command [command] should return a string! Got: \"[text_response]\"")
+ text_response = null
+ topic_response[DMAPI5_TOPIC_RESPONSE_COMMAND_RESPONSE_MESSAGE] = text_response
+ return json_encode(topic_response)
+ return TopicResponse("Unknown custom chat command: [command]!")
+
+/*
+
+The MIT License
+
+Copyright (c) 2020 Jordan Brown
+
+Permission is hereby granted, free of charge,
+to any person obtaining a copy of this software and
+associated documentation files (the "Software"), to
+deal in the Software without restriction, including
+without limitation the rights to use, copy, modify,
+merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom
+the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
diff --git a/code/modules/tgs/v5/undef.dm b/code/modules/tgs/v5/undef.dm
new file mode 100644
index 0000000000..b27e3abe95
--- /dev/null
+++ b/code/modules/tgs/v5/undef.dm
@@ -0,0 +1,124 @@
+#undef DMAPI5_PARAM_SERVER_PORT
+#undef DMAPI5_PARAM_ACCESS_IDENTIFIER
+
+#undef DMAPI5_BRIDGE_DATA
+#undef DMAPI5_TOPIC_DATA
+
+#undef DMAPI5_BRIDGE_COMMAND_PORT_UPDATE
+#undef DMAPI5_BRIDGE_COMMAND_STARTUP
+#undef DMAPI5_BRIDGE_COMMAND_PRIME
+#undef DMAPI5_BRIDGE_COMMAND_REBOOT
+#undef DMAPI5_BRIDGE_COMMAND_KILL
+#undef DMAPI5_BRIDGE_COMMAND_CHAT_SEND
+
+#undef DMAPI5_PARAMETER_ACCESS_IDENTIFIER
+#undef DMAPI5_RESPONSE_ERROR_MESSAGE
+
+#undef DMAPI5_BRIDGE_PARAMETER_COMMAND_TYPE
+#undef DMAPI5_BRIDGE_PARAMETER_CURRENT_PORT
+#undef DMAPI5_BRIDGE_PARAMETER_VERSION
+#undef DMAPI5_BRIDGE_PARAMETER_CHAT_MESSAGE
+#undef DMAPI5_BRIDGE_PARAMETER_CUSTOM_COMMANDS
+#undef DMAPI5_BRIDGE_PARAMETER_MINIMUM_SECURITY_LEVEL
+
+#undef DMAPI5_BRIDGE_RESPONSE_NEW_PORT
+#undef DMAPI5_BRIDGE_RESPONSE_RUNTIME_INFORMATION
+
+#undef DMAPI5_CHAT_MESSAGE_TEXT
+#undef DMAPI5_CHAT_MESSAGE_CHANNEL_IDS
+
+#undef DMAPI5_RUNTIME_INFORMATION_ACCESS_IDENTIFIER
+#undef DMAPI5_RUNTIME_INFORMATION_SERVER_VERSION
+#undef DMAPI5_RUNTIME_INFORMATION_SERVER_PORT
+#undef DMAPI5_RUNTIME_INFORMATION_API_VALIDATE_ONLY
+#undef DMAPI5_RUNTIME_INFORMATION_INSTANCE_NAME
+#undef DMAPI5_RUNTIME_INFORMATION_REVISION
+#undef DMAPI5_RUNTIME_INFORMATION_TEST_MERGES
+#undef DMAPI5_RUNTIME_INFORMATION_SECURITY_LEVEL
+
+#undef DMAPI5_CHAT_UPDATE_CHANNELS
+
+#undef DMAPI5_TEST_MERGE_TIME_MERGED
+#undef DMAPI5_TEST_MERGE_REVISION
+#undef DMAPI5_TEST_MERGE_TITLE_AT_MERGE
+#undef DMAPI5_TEST_MERGE_BODY_AT_MERGE
+#undef DMAPI5_TEST_MERGE_URL
+#undef DMAPI5_TEST_MERGE_AUTHOR
+#undef DMAPI5_TEST_MERGE_NUMBER
+#undef DMAPI5_TEST_MERGE_PULL_REQUEST_REVISION
+#undef DMAPI5_TEST_MERGE_COMMENT
+
+#undef DMAPI5_CHAT_COMMAND_NAME
+#undef DMAPI5_CHAT_COMMAND_PARAMS
+#undef DMAPI5_CHAT_COMMAND_USER
+
+#undef DMAPI5_EVENT_NOTIFICATION_TYPE
+#undef DMAPI5_EVENT_NOTIFICATION_PARAMETERS
+
+#undef DMAPI5_TOPIC_COMMAND_CHAT_COMMAND
+#undef DMAPI5_TOPIC_COMMAND_EVENT_NOTIFICATION
+#undef DMAPI5_TOPIC_COMMAND_CHANGE_PORT
+#undef DMAPI5_TOPIC_COMMAND_CHANGE_REBOOT_STATE
+#undef DMAPI5_TOPIC_COMMAND_INSTANCE_RENAMED
+#undef DMAPI5_TOPIC_COMMAND_CHAT_CHANNELS_UPDATE
+#undef DMAPI5_TOPIC_COMMAND_SERVER_PORT_UPDATE
+#undef DMAPI5_TOPIC_COMMAND_HEARTBEAT
+#undef DMAPI5_TOPIC_COMMAND_WATCHDOG_REATTACH
+
+#undef DMAPI5_TOPIC_PARAMETER_COMMAND_TYPE
+#undef DMAPI5_TOPIC_PARAMETER_CHAT_COMMAND
+#undef DMAPI5_TOPIC_PARAMETER_EVENT_NOTIFICATION
+#undef DMAPI5_TOPIC_PARAMETER_NEW_PORT
+#undef DMAPI5_TOPIC_PARAMETER_NEW_REBOOT_STATE
+#undef DMAPI5_TOPIC_PARAMETER_NEW_INSTANCE_NAME
+#undef DMAPI5_TOPIC_PARAMETER_CHAT_UPDATE
+#undef DMAPI5_TOPIC_PARAMETER_NEW_SERVER_VERSION
+
+#undef DMAPI5_TOPIC_RESPONSE_COMMAND_RESPONSE_MESSAGE
+#undef DMAPI5_TOPIC_RESPONSE_CHAT_RESPONSES
+
+#undef DMAPI5_REVISION_INFORMATION_COMMIT_SHA
+#undef DMAPI5_REVISION_INFORMATION_ORIGIN_COMMIT_SHA
+
+#undef DMAPI5_CHAT_USER_ID
+#undef DMAPI5_CHAT_USER_FRIENDLY_NAME
+#undef DMAPI5_CHAT_USER_MENTION
+#undef DMAPI5_CHAT_USER_CHANNEL
+
+#undef DMAPI5_CHAT_CHANNEL_ID
+#undef DMAPI5_CHAT_CHANNEL_FRIENDLY_NAME
+#undef DMAPI5_CHAT_CHANNEL_CONNECTION_NAME
+#undef DMAPI5_CHAT_CHANNEL_IS_ADMIN_CHANNEL
+#undef DMAPI5_CHAT_CHANNEL_IS_PRIVATE_CHANNEL
+#undef DMAPI5_CHAT_CHANNEL_TAG
+
+#undef DMAPI5_CUSTOM_CHAT_COMMAND_NAME
+#undef DMAPI5_CUSTOM_CHAT_COMMAND_HELP_TEXT
+#undef DMAPI5_CUSTOM_CHAT_COMMAND_ADMIN_ONLY
+
+/*
+The MIT License
+
+Copyright (c) 2020 Jordan Brown
+
+Permission is hereby granted, free of charge,
+to any person obtaining a copy of this software and
+associated documentation files (the "Software"), to
+deal in the Software without restriction, including
+without limitation the rights to use, copy, modify,
+merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom
+the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
diff --git a/code/modules/uplink/uplink_items/uplink_devices.dm b/code/modules/uplink/uplink_items/uplink_devices.dm
index d4fa226a90..2d20fd0b7b 100644
--- a/code/modules/uplink/uplink_items/uplink_devices.dm
+++ b/code/modules/uplink/uplink_items/uplink_devices.dm
@@ -280,4 +280,6 @@
item = /obj/item/suspiciousphone
cost = 7
restricted = TRUE
+ limited_stock = 1
*/
+
diff --git a/code/modules/vehicles/bicycle.dm b/code/modules/vehicles/bicycle.dm
index 84e0fcbefc..3784f4d459 100644
--- a/code/modules/vehicles/bicycle.dm
+++ b/code/modules/vehicles/bicycle.dm
@@ -24,10 +24,12 @@
buckled_mob.stop_sound_channel(CHANNEL_BICYCLE)
. =..()
-/obj/vehicle/ridden/bicycle/tesla_act() // :::^^^)))
+/obj/vehicle/ridden/bicycle/zap_act(zap_str, zap_flags, shocked_targets) // :::^^^)))
+ //This didn't work for 3 years because none ever tested it I hate life
name = "fried bicycle"
desc = "Well spent."
color = rgb(63, 23, 4)
can_buckle = FALSE
+ . = ..()
for(var/m in buckled_mobs)
unbuckle_mob(m,1)
diff --git a/code/modules/vehicles/ridden.dm b/code/modules/vehicles/ridden.dm
index 4f3970dd37..f71d9367d3 100644
--- a/code/modules/vehicles/ridden.dm
+++ b/code/modules/vehicles/ridden.dm
@@ -77,3 +77,7 @@
if(!force && occupant_amount() >= max_occupants)
return FALSE
return ..()
+
+/obj/vehicle/ridden/zap_act(zap_str, zap_flags, shocked_targets)
+ zap_buckle_check(zap_str)
+ . = ..()
diff --git a/code/modules/vehicles/sealed.dm b/code/modules/vehicles/sealed.dm
index fc81e2ec00..edaab8b982 100644
--- a/code/modules/vehicles/sealed.dm
+++ b/code/modules/vehicles/sealed.dm
@@ -1,5 +1,6 @@
/obj/vehicle/sealed
var/enter_delay = 20
+ flags_1 = BLOCK_FACE_ATOM_1
/obj/vehicle/sealed/generate_actions()
. = ..()
@@ -51,7 +52,7 @@
if(randomstep)
var/turf/target_turf = get_step(exit_location(M), pick(GLOB.cardinals))
M.throw_at(target_turf, 5, 10)
-
+
if(!silent)
M.visible_message("[M] drops out of \the [src]!")
return TRUE
@@ -102,7 +103,13 @@
if(iscarbon(i))
var/mob/living/carbon/C = i
C.DefaultCombatKnockdown(40)
-
-
+
+
/obj/vehicle/sealed/AllowDrop()
return FALSE
+
+/obj/vehicle/sealed/setDir(newdir)
+ . = ..()
+ for(var/k in occupants)
+ var/mob/M = k
+ M.setDir(newdir)
diff --git a/code/modules/vending/dinnerware.dm b/code/modules/vending/dinnerware.dm
index e780104b1e..521e76b5e2 100644
--- a/code/modules/vending/dinnerware.dm
+++ b/code/modules/vending/dinnerware.dm
@@ -20,12 +20,10 @@
/obj/item/reagent_containers/food/condiment/saltshaker = 5,
/obj/item/reagent_containers/food/condiment/peppermill = 5)
contraband = list(
- /obj/item/reagent_containers/food/snacks/cube/monkey= 1,
/obj/item/kitchen/knife/butcher = 2,
/obj/item/reagent_containers/syringe = 3)
premium = list(
- /obj/item/reagent_containers/food/condiment/enzyme = 1,
- /obj/item/reagent_containers/glass/bottle/cryoxadone = 2) // Bartender can literally make this with upgraded parts, or it gets stolen from medical.
+ /obj/item/reagent_containers/food/condiment/enzyme = 1)
armor = list("melee" = 100, "bullet" = 100, "laser" = 100, "energy" = 100, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 50)
refill_canister = /obj/item/vending_refill/dinnerware
resistance_flags = FIRE_PROOF
@@ -35,4 +33,4 @@
cost_multiplier_per_dept = list(ACCOUNT_SRV = 0)
/obj/item/vending_refill/dinnerware
- icon_state = "refill_cook"
\ No newline at end of file
+ icon_state = "refill_cook"
diff --git a/code/modules/vending/megaseed.dm b/code/modules/vending/megaseed.dm
index f8759bd8f4..df1e5eaba8 100644
--- a/code/modules/vending/megaseed.dm
+++ b/code/modules/vending/megaseed.dm
@@ -27,6 +27,7 @@
/obj/item/seeds/orange = 3,
/obj/item/seeds/peach = 3,
/obj/item/seeds/peanutseed = 3,
+ /obj/item/seeds/peas = 3,
/obj/item/seeds/pineapple = 3,
/obj/item/seeds/potato = 3,
/obj/item/seeds/poppy = 3,
diff --git a/code/modules/vore/eating/belly_obj.dm b/code/modules/vore/eating/belly_obj.dm
index 685f8d76bb..03d0bbba45 100644
--- a/code/modules/vore/eating/belly_obj.dm
+++ b/code/modules/vore/eating/belly_obj.dm
@@ -542,7 +542,7 @@
if (!(R in contents))
return // User is not in this belly
- R.setClickCooldown(50)
+ R.changeNext_move(CLICK_CD_BREAKOUT*0.5)
if(owner.stat) //If owner is stat (dead, KO) we can actually escape
to_chat(R,"You attempt to climb out of \the [lowertext(name)]. (This will take around [escapetime/10] seconds.)")
diff --git a/code/modules/vore/eating/living.dm b/code/modules/vore/eating/living.dm
index 33f8d78300..a7cc316cc3 100644
--- a/code/modules/vore/eating/living.dm
+++ b/code/modules/vore/eating/living.dm
@@ -358,6 +358,9 @@
if(incapacitated(ignore_restraints = TRUE))
to_chat(src, "You can't do that while incapacitated.")
return
+ if(next_move > world.time)
+ to_chat(src, "You can't do that so fast, slow down.")
+ return
var/list/choices
for(var/mob/living/L in view(1))
@@ -372,7 +375,7 @@
if(QDELETED(tasted) || (tasted.ckey && !(tasted.client?.prefs.vore_flags & LICKABLE)) || !Adjacent(tasted) || incapacitated(ignore_restraints = TRUE))
return
- setClickCooldown(100)
+ changeNext_move(CLICK_CD_MELEE)
visible_message("[src] licks [tasted]!","You lick [tasted]. They taste rather like [tasted.get_taste_message()].","Slurp!")
diff --git a/config/game_options.txt b/config/game_options.txt
index 2d326493bb..f65c1bfff5 100644
--- a/config/game_options.txt
+++ b/config/game_options.txt
@@ -658,4 +658,8 @@ THRESHOLD_BODY_SIZE_SLOWDOWN 0.85
BODY_SIZE_SLOWDOWN_MULTIPLIER 0.25
## Allows players to set a hexadecimal color of their choice as skin tone, on top of the standard ones.
-ALLOW_CUSTOM_SKINTONES
\ No newline at end of file
+ALLOW_CUSTOM_SKINTONES
+
+## Enables the FoV component, which hides objects and mobs behind the parent from their sight, unless they turn around, duh.
+## Camera mobs, AIs, ghosts and some other are of course exempt from this. This also doesn't influence simplemob AI, for the best.
+#USE_FIELD_OF_VISION
\ No newline at end of file
diff --git a/icons/misc/field_of_vision.dmi b/icons/misc/field_of_vision.dmi
new file mode 100644
index 0000000000..015cecd88c
Binary files /dev/null and b/icons/misc/field_of_vision.dmi differ
diff --git a/icons/mob/clothing/neck.dmi b/icons/mob/clothing/neck.dmi
index 78073222ca..86dec62a41 100644
Binary files a/icons/mob/clothing/neck.dmi and b/icons/mob/clothing/neck.dmi differ
diff --git a/icons/mob/clothing/uniform.dmi b/icons/mob/clothing/uniform.dmi
index b717b33c61..e126629b77 100644
Binary files a/icons/mob/clothing/uniform.dmi and b/icons/mob/clothing/uniform.dmi differ
diff --git a/icons/mob/inhands/equipment/shields_lefthand.dmi b/icons/mob/inhands/equipment/shields_lefthand.dmi
index 24bb824f1d..850bbaa043 100644
Binary files a/icons/mob/inhands/equipment/shields_lefthand.dmi and b/icons/mob/inhands/equipment/shields_lefthand.dmi differ
diff --git a/icons/mob/inhands/equipment/shields_righthand.dmi b/icons/mob/inhands/equipment/shields_righthand.dmi
index 31d84f480c..d4db35b9b2 100644
Binary files a/icons/mob/inhands/equipment/shields_righthand.dmi and b/icons/mob/inhands/equipment/shields_righthand.dmi differ
diff --git a/icons/mob/talk.dmi b/icons/mob/talk.dmi
index 05fe6f5623..0a56321037 100644
Binary files a/icons/mob/talk.dmi and b/icons/mob/talk.dmi differ
diff --git a/icons/obj/artstuff.dmi b/icons/obj/artstuff.dmi
index ea24341f5e..14970b76ef 100644
Binary files a/icons/obj/artstuff.dmi and b/icons/obj/artstuff.dmi differ
diff --git a/icons/obj/decals.dmi b/icons/obj/decals.dmi
index 7ed9244ea4..f66767292c 100644
Binary files a/icons/obj/decals.dmi and b/icons/obj/decals.dmi differ
diff --git a/icons/obj/hydroponics/growing_vegetables.dmi b/icons/obj/hydroponics/growing_vegetables.dmi
index 63cf069186..b426b8f6de 100644
Binary files a/icons/obj/hydroponics/growing_vegetables.dmi and b/icons/obj/hydroponics/growing_vegetables.dmi differ
diff --git a/icons/obj/hydroponics/harvest.dmi b/icons/obj/hydroponics/harvest.dmi
index c7c31581f3..fd9d310c73 100644
Binary files a/icons/obj/hydroponics/harvest.dmi and b/icons/obj/hydroponics/harvest.dmi differ
diff --git a/icons/obj/hydroponics/seeds.dmi b/icons/obj/hydroponics/seeds.dmi
index 62843e3f54..15b7e2b96c 100644
Binary files a/icons/obj/hydroponics/seeds.dmi and b/icons/obj/hydroponics/seeds.dmi differ
diff --git a/icons/obj/improvised.dmi b/icons/obj/improvised.dmi
index b90e3cb3bb..5c2c2a1f1b 100644
Binary files a/icons/obj/improvised.dmi and b/icons/obj/improvised.dmi differ
diff --git a/icons/obj/shields.dmi b/icons/obj/shields.dmi
index ed528d4a5a..c8b1110e1a 100644
Binary files a/icons/obj/shields.dmi and b/icons/obj/shields.dmi differ
diff --git a/interface/skin.dmf b/interface/skin.dmf
index 04a78af061..8d68336754 100644
--- a/interface/skin.dmf
+++ b/interface/skin.dmf
@@ -54,6 +54,7 @@ window "mainwindow"
size = 640x440
anchor1 = none
anchor2 = none
+ background-color = #242424
is-default = true
saved-params = "pos;size;is-minimized;is-maximized"
icon = 'icons\\ss13_64.png'
@@ -61,60 +62,23 @@ window "mainwindow"
menu = "menu"
elem "split"
type = CHILD
- pos = 3,0
- size = 634x417
+ pos = 0,0
+ size = 637x440
anchor1 = 0,0
anchor2 = 100,100
+ background-color = #272727
saved-params = "splitter"
left = "mapwindow"
right = "infowindow"
is-vert = true
- elem "input"
- type = INPUT
- pos = 3,420
- size = 517x20
- anchor1 = 0,100
- anchor2 = 100,100
- background-color = #d3b5b5
- is-default = true
- border = sunken
- saved-params = "command"
- elem "saybutton"
- type = BUTTON
- pos = 600,420
- size = 40x20
- anchor1 = 100,100
- anchor2 = none
- saved-params = "is-checked"
- text = "Chat"
- command = ".winset \"saybutton.is-checked=true ? input.command=\"!say \\\"\" : input.command=\"\"saybutton.is-checked=true ? mebutton.is-checked=false\"\"saybutton.is-checked=true ? oocbutton.is-checked=false\""
- button-type = pushbox
- elem "oocbutton"
- type = BUTTON
- pos = 520,420
- size = 40x20
- anchor1 = 100,100
- anchor2 = none
- saved-params = "is-checked"
- text = "OOC"
- command = ".winset \"oocbutton.is-checked=true ? input.command=\"!ooc \\\"\" : input.command=\"\"oocbutton.is-checked=true ? mebutton.is-checked=false\"\"oocbutton.is-checked=true ? saybutton.is-checked=false\""
- button-type = pushbox
- elem "mebutton"
- type = BUTTON
- pos = 560,420
- size = 40x20
- anchor1 = 100,100
- anchor2 = none
- saved-params = "is-checked"
- text = "Me"
- command = ".winset \"mebutton.is-checked=true ? input.command=\"!me \\\"\" : input.command=\"\"mebutton.is-checked=true ? saybutton.is-checked=false\"\"mebutton.is-checked=true ? oocbutton.is-checked=false\""
- button-type = pushbox
+ splitter = 75
elem "asset_cache_browser"
type = BROWSER
pos = 0,0
size = 200x200
anchor1 = none
anchor2 = none
+ background-color = #272727
is-visible = false
saved-params = ""
elem "tooltip"
@@ -123,6 +87,7 @@ window "mainwindow"
size = 999x999
anchor1 = none
anchor2 = none
+ background-color = #272727
is-visible = false
saved-params = ""
@@ -134,11 +99,11 @@ window "mapwindow"
anchor1 = none
anchor2 = none
background-color = none
- saved-params = ""
+ saved-params = "pos;size;is-minimized;is-maximized"
statusbar = false
is-pane = true
- outer-size = 1090x1192
- inner-size = 1068x1136
+ outer-size = 684x617
+ inner-size = 662x561
elem "map"
type = MAP
pos = 0,0
@@ -159,6 +124,7 @@ window "infowindow"
size = 640x480
anchor1 = none
anchor2 = none
+ background-color = #242424
saved-params = "pos;size;is-minimized;is-maximized"
is-pane = true
elem "info"
@@ -167,6 +133,7 @@ window "infowindow"
size = 640x445
anchor1 = 0,0
anchor2 = 100,100
+ background-color = #272727
saved-params = "splitter"
left = "statwindow"
right = "outputwindow"
@@ -177,6 +144,8 @@ window "infowindow"
size = 104x20
anchor1 = 3,0
anchor2 = 19,0
+ text-color = #e0e0e0
+ background-color = #40628a
saved-params = "is-checked"
text = "Changelog"
command = "changelog"
@@ -186,6 +155,8 @@ window "infowindow"
size = 100x20
anchor1 = 19,0
anchor2 = 34,0
+ text-color = #e0e0e0
+ background-color = #40628a
saved-params = "is-checked"
text = "Rules"
command = "rules"
@@ -195,6 +166,8 @@ window "infowindow"
size = 100x20
anchor1 = 34,0
anchor2 = 50,0
+ text-color = #e0e0e0
+ background-color = #40628a
saved-params = "is-checked"
text = "Wiki"
command = "wiki"
@@ -204,6 +177,8 @@ window "infowindow"
size = 100x20
anchor1 = 50,0
anchor2 = 66,0
+ text-color = #e0e0e0
+ background-color = #40628a
saved-params = "is-checked"
text = "Forum"
command = "forum"
@@ -213,8 +188,10 @@ window "infowindow"
size = 100x20
anchor1 = 66,0
anchor2 = 81,0
+ text-color = #e0e0e0
+ background-color = #40628a
saved-params = "is-checked"
- text = "Github"
+ text = "GitHub"
command = "github"
elem "report-issue"
type = BUTTON
@@ -222,6 +199,9 @@ window "infowindow"
size = 100x20
anchor1 = 81,0
anchor2 = 97,0
+ font-size = 8
+ text-color = #e0e0e0
+ background-color = #a92c2c
saved-params = "is-checked"
text = "Report Issue"
command = "report-issue"
@@ -233,15 +213,44 @@ window "outputwindow"
size = 640x480
anchor1 = none
anchor2 = none
+ background-color = #272727
saved-params = "pos;size;is-minimized;is-maximized"
+ titlebar = false
+ statusbar = false
+ can-close = false
+ can-minimize = false
+ can-resize = false
is-pane = true
+ elem "input"
+ type = INPUT
+ pos = 2,460
+ size = 595x20
+ anchor1 = 0,100
+ anchor2 = 100,100
+ background-color = #d3b5b5
+ is-default = true
+ border = sunken
+ saved-params = "command"
+ elem "say"
+ type = BUTTON
+ pos = 600,460
+ size = 37x20
+ anchor1 = 100,100
+ anchor2 = none
+ text-color = #e0e0e0
+ background-color = #272727
+ saved-params = "is-checked"
+ text = "Chat"
+ command = ".winset \"say.is-checked=true ? input.command=\"!say \\\"\" : input.command=\""
+ is-flat = true
+ button-type = pushbox
elem "browseroutput"
type = BROWSER
pos = 0,0
- size = 640x480
+ size = 640x456
anchor1 = 0,0
anchor2 = 100,100
- background-color = #ffffff
+ background-color = #272727
is-visible = false
is-disabled = true
saved-params = ""
@@ -249,19 +258,22 @@ window "outputwindow"
elem "output"
type = OUTPUT
pos = 0,0
- size = 640x480
+ size = 640x456
anchor1 = 0,0
anchor2 = 100,100
+ text-color = #e0e0e0
+ background-color = #272727
is-default = true
saved-params = ""
window "statwindow"
elem "statwindow"
type = MAIN
- pos = 0,0
+ pos = 281,0
size = 640x480
anchor1 = none
anchor2 = none
+ background-color = #242424
saved-params = "pos;size;is-minimized;is-maximized"
is-pane = true
elem "stat"
@@ -270,8 +282,14 @@ window "statwindow"
size = 640x480
anchor1 = 0,0
anchor2 = 100,100
+ text-color = #e0e0e0
+ background-color = #272727
is-default = true
saved-params = ""
+ tab-text-color = #e0e0e0
+ tab-background-color = #242424
+ prefix-color = #e0e0e0
+ suffix-color = #e0e0e0
window "preferences_window"
elem "preferences_window"
diff --git a/modular_citadel/code/__HELPERS/list2list.dm b/modular_citadel/code/__HELPERS/list2list.dm
deleted file mode 100644
index e812b3a1e9..0000000000
--- a/modular_citadel/code/__HELPERS/list2list.dm
+++ /dev/null
@@ -1,12 +0,0 @@
-/proc/tg_ui_icon_to_cit_ui(ui_style)
- switch(ui_style)
- if('icons/mob/screen_plasmafire.dmi')
- return 'modular_citadel/icons/ui/screen_plasmafire.dmi'
- if('icons/mob/screen_slimecore.dmi')
- return 'modular_citadel/icons/ui/screen_slimecore.dmi'
- if('icons/mob/screen_operative.dmi')
- return 'modular_citadel/icons/ui/screen_operative.dmi'
- if('icons/mob/screen_clockwork.dmi')
- return 'modular_citadel/icons/ui/screen_clockwork.dmi'
- else
- return 'modular_citadel/icons/ui/screen_midnight.dmi'
diff --git a/modular_citadel/code/__HELPERS/lists.dm b/modular_citadel/code/__HELPERS/lists.dm
deleted file mode 100644
index b249dfc554..0000000000
--- a/modular_citadel/code/__HELPERS/lists.dm
+++ /dev/null
@@ -1,9 +0,0 @@
-/proc/is_type_in_ref_list(path, list/L)
- if(!ispath(path))//not a path
- return
- for(var/i in L)
- var/datum/D = i
- if(!istype(D))//not an usable reference
- continue
- if(istype(D, path))
- return TRUE
\ No newline at end of file
diff --git a/modular_citadel/code/__HELPERS/mobs.dm b/modular_citadel/code/__HELPERS/mobs.dm
deleted file mode 100644
index 2666696564..0000000000
--- a/modular_citadel/code/__HELPERS/mobs.dm
+++ /dev/null
@@ -1,28 +0,0 @@
-/proc/slot_to_string(slot)
- switch(slot)
- if(SLOT_BACK)
- return "Backpack"
- if(SLOT_WEAR_MASK)
- return "Mask"
- if(SLOT_HANDS)
- return "Hands"
- if(SLOT_BELT)
- return "Belt"
- if(SLOT_EARS)
- return "Ears"
- if(SLOT_GLASSES)
- return "Glasses"
- if(SLOT_GLOVES)
- return "Gloves"
- if(SLOT_NECK)
- return "Neck"
- if(SLOT_HEAD)
- return "Head"
- if(SLOT_SHOES)
- return "Shoes"
- if(SLOT_WEAR_SUIT)
- return "Suit"
- if(SLOT_W_UNIFORM)
- return "Uniform"
- if(SLOT_IN_BACKPACK)
- return "In backpack"
diff --git a/modular_citadel/code/_onclick/click.dm b/modular_citadel/code/_onclick/click.dm
index f077b3a71b..004cc2fe80 100644
--- a/modular_citadel/code/_onclick/click.dm
+++ b/modular_citadel/code/_onclick/click.dm
@@ -72,30 +72,3 @@
/mob/proc/AltRangedAttack(atom/A, params)
return FALSE
-
-/mob/proc/mouse_face_atom(atom/A) //Basically a copy of face_atom but with ismousemovement set to TRUE
- if( buckled || stat != CONSCIOUS || !A || !x || !y || !A.x || !A.y )
- return
- var/dx = A.x - x
- var/dy = A.y - y
- if(!dx && !dy) // Wall items are graphically shifted but on the floor
- if(A.pixel_y > 16)
- setDir(NORTH, ismousemovement = TRUE)
- else if(A.pixel_y < -16)
- setDir(SOUTH, ismousemovement = TRUE)
- else if(A.pixel_x > 16)
- setDir(EAST, ismousemovement = TRUE)
- else if(A.pixel_x < -16)
- setDir(WEST, ismousemovement = TRUE)
- return
-
- if(abs(dx) < abs(dy))
- if(dy > 0)
- setDir(NORTH, ismousemovement = TRUE)
- else
- setDir(SOUTH, ismousemovement = TRUE)
- else
- if(dx > 0)
- setDir(EAST, ismousemovement = TRUE)
- else
- setDir(WEST, ismousemovement = TRUE)
diff --git a/modular_citadel/code/_onclick/other_mobs.dm b/modular_citadel/code/_onclick/other_mobs.dm
index 6d9ffdd6ca..ec740f023b 100644
--- a/modular_citadel/code/_onclick/other_mobs.dm
+++ b/modular_citadel/code/_onclick/other_mobs.dm
@@ -12,7 +12,7 @@
if(isturf(A) || incapacitated()) // pretty annoying to wave your fist at floors and walls. And useless.
return TRUE
changeNext_move(CLICK_CD_RANGE)
- var/list/target_viewers = viewers(11, A) //Byond proc, doesn't check for blindness.
+ var/list/target_viewers = fov_viewers(11, A) //doesn't check for blindness.
if(!(src in target_viewers)) //click catcher issuing calls for out of view objects.
return TRUE
if(!has_active_hand())
@@ -26,16 +26,16 @@
switch(a_intent)
if(INTENT_DISARM)
the_action = "shoos away [A]"
- what_action = "shoo away something you can't see"
+ what_action = "shoo away something out of your vision"
self_action = "shoo away [A]"
if(INTENT_GRAB)
the_action = "beckons [A] to come"
- what_action = "beckons something you can't see to come"
+ what_action = "beckons something out of your vision to come"
self_action = "beckon [A] to come"
if(INTENT_HARM)
var/pronoun = "[p_their()]"
the_action = "shakes [pronoun] fist at [A]"
- what_action = "shakes [pronoun] fist at something you can't see"
+ what_action = "shakes [pronoun] fist at something out of your vision"
self_action = "shake your fist at [A]"
if(!eye_blind)
diff --git a/modular_citadel/code/game/machinery/wishgranter.dm b/modular_citadel/code/game/machinery/wishgranter.dm
deleted file mode 100644
index 6cfe07b7a0..0000000000
--- a/modular_citadel/code/game/machinery/wishgranter.dm
+++ /dev/null
@@ -1,122 +0,0 @@
-/obj/machinery/wish_granter/attack_hand(mob/living/carbon/user)
- if(charges <= 0)
- to_chat(user, "The Wish Granter lies silent.")
- return
-
- else if(!ishuman(user))
- to_chat(user, "You feel a dark stirring inside of the Wish Granter, something you want nothing of. Your instincts are better than any man's.")
- return
-
- else if (!insisting)
- to_chat(user, "Your first touch makes the Wish Granter stir, listening to you. Are you really sure you want to do this?")
- insisting++
-
- else
- if(is_special_character(user))
- to_chat(user, "You speak. [pick("I want power","Humanity is corrupt, mankind must be destroyed", "I want to rule the world","I want immortality")]. The Wish Granter answers.")
- to_chat(user, "Your head pounds for a moment, before your vision clears. The Wish Granter, sensing the darkness in your heart, has given you limitless power, and it's all yours!")
- user.dna.add_mutation(HULK)
- user.dna.add_mutation(XRAY)
- user.dna.add_mutation(SPACEMUT)
- user.dna.add_mutation(TK)
- user.next_move_modifier *= 0.5 //half the delay between attacks!
- to_chat(user, "Things around you feel slower!")
- charges--
- insisting = FALSE
- to_chat(user, "You have a very great feeling about this!")
- else
- to_chat(user, "The Wish Granter awaits your wish.")
- var/wish = input("You want...","Wish") as null|anything in list("Power","Wealth","The Station To Disappear","To Kill","Nothing")
- switch(wish)
- if("Power") //Gives infinite power in exchange for infinite power going off in your face!
- if(charges <= 0)
- return
- to_chat(user, "Your wish is granted, but at a terrible cost...")
- to_chat(user, "The Wish Granter punishes you for your selfishness, warping itself into a delaminating supermatter shard!")
- var/obj/item/stock_parts/cell/infinite/powah = new /obj/item/stock_parts/cell/infinite(get_turf(user))
- if(user.put_in_hands(powah))
- to_chat(user, "[powah] materializes into your hands!")
- else
- to_chat(user, "[powah] materializes onto the floor.")
- var/obj/machinery/power/supermatter_crystal/powerwish = new /obj/machinery/power/supermatter_crystal(loc)
- powerwish.damage = 700 //right at the emergency threshold
- powerwish.produces_gas = FALSE
- charges--
- insisting = FALSE
- if(!charges)
- qdel(src)
- if("Wealth") //Gives 1 million space bucks in exchange for being turned into gold!
- if(charges <= 0)
- return
- to_chat(user, "Your wish is granted, but at a cost...")
- to_chat(user, "The Wish Granter punishes you for your selfishness, warping your body to match the greed in your heart.")
- new /obj/structure/closet/crate/trashcart/moneywish(loc)
- new /obj/structure/closet/crate/trashcart/moneywish(loc)
- user.set_species(/datum/species/golem/gold)
- charges--
- insisting = FALSE
- if(!charges)
- qdel(src)
- if("The Station To Disappear") //teleports you to the station and makes you blind, making the station disappear for you!
- if(charges <= 0)
- return
- to_chat(user, "Your wish is 'granted', but at a terrible cost...")
- to_chat(user, "The Wish Granter punishes you for your selfishness, claiming your soul and warping your eyes to match the darkness in your heart.")
- user.dna.add_mutation(BLINDMUT)
- var/obj/item/organ/eyes/eyes = user.getorganslot(ORGAN_SLOT_EYES)
- if(eyes)
- eyes.applyOrganDamage(eyes.maxHealth)
- var/list/destinations = list()
- for(var/obj/item/beacon/B in GLOB.teleportbeacons)
- var/turf/T = get_turf(B)
- if(is_station_level(T.z))
- destinations += B
- var/chosen_beacon = pick(destinations)
- var/obj/effect/portal/jaunt_tunnel/J = new (get_turf(src), src, 100, null, FALSE, get_turf(chosen_beacon))
- try_move_adjacent(J)
- playsound(src,'sound/effects/sparks4.ogg',50,1)
- charges--
- insisting = FALSE
- if(!charges)
- qdel(src)
- if("To Kill") //Makes you kill things in exchange for rewards!
- if(charges <= 0)
- return
- to_chat(user, "Your wish is granted, but at a terrible cost...")
- to_chat(user, "The Wish Granter punishes you for your wickedness, warping itself into a dastardly creature for you to kill! ...but it almost seems to reward you for this.")
- var/obj/item/melee/transforming/energy/sword/cx/killreward = new /obj/item/melee/transforming/energy/sword/cx(get_turf(user))
- if(user.put_in_hands(killreward))
- to_chat(user, "[killreward] materializes into your hands!")
- else
- to_chat(user, "[killreward] materializes onto the floor.")
- user.next_move_modifier *= 0.8 //20% less delay between attacks!
- to_chat(user, "Things around you feel slightly slower!")
- var/mob/living/simple_animal/hostile/venus_human_trap/killwish = new /mob/living/simple_animal/hostile/venus_human_trap(loc)
- killwish.maxHealth = 1500
- killwish.health = killwish.maxHealth
- killwish.vine_grab_distance = 6
- killwish.melee_damage_upper = 30
- killwish.loot = list(/obj/item/twohanded/dualsaber/hypereutactic)
- charges--
- insisting = FALSE
- if(!charges)
- qdel(src)
- if("Nothing") //Makes the wish granter disappear
- if(charges <= 0)
- return
- to_chat(user, "The Wish Granter vanishes from sight!")
- to_chat(user, "You feel as if you just narrowly avoided a terrible fate...")
- charges--
- insisting = FALSE
- qdel(src)
-
-//ITEMS THAT IT USES
-
-/obj/structure/closet/crate/trashcart/moneywish
- desc = "A heavy, metal trashcart with wheels. Filled with cash."
- name = "loaded trash cart"
-
-/obj/structure/closet/crate/trashcart/moneywish/PopulateContents() //25*20*1000=500,000
- for(var/i = 0, i < 25, i++)
- var/obj/item/stack/spacecash/c1000/lodsamoney = new /obj/item/stack/spacecash/c1000(src)
- lodsamoney.amount = lodsamoney.max_amount
diff --git a/modular_citadel/code/game/objects/items/devices/radio/shockcollar.dm b/modular_citadel/code/game/objects/items/devices/radio/shockcollar.dm
deleted file mode 100644
index 6c9f12a852..0000000000
--- a/modular_citadel/code/game/objects/items/devices/radio/shockcollar.dm
+++ /dev/null
@@ -1,83 +0,0 @@
-/obj/item/electropack/shockcollar
- name = "shock collar"
- desc = "A reinforced metal collar. It seems to have some form of wiring near the front. Strange.."
- icon = 'modular_citadel/icons/obj/clothing/cit_neck.dmi'
- mob_overlay_icon = 'modular_citadel/icons/mob/citadel/neck.dmi'
- icon_state = "shockcollar"
- item_state = "shockcollar"
- body_parts_covered = NECK
- slot_flags = ITEM_SLOT_NECK | ITEM_SLOT_DENYPOCKET //no more pocket shockers
- w_class = WEIGHT_CLASS_SMALL
- strip_delay = 60
- equip_delay_other = 60
- materials = list(MAT_METAL=5000, MAT_GLASS=2000)
- var/tagname = null
-
-/datum/design/electropack/shockcollar
- name = "Shockcollar"
- id = "shockcollar"
- build_type = AUTOLATHE
- build_path = /obj/item/electropack/shockcollar
- materials = list(MAT_METAL=5000, MAT_GLASS=2000)
- category = list("hacked", "Misc")
-
-/obj/item/electropack/shockcollar/attack_hand(mob/user)
- if(loc == user && user.get_item_by_slot(SLOT_NECK))
- to_chat(user, "The collar is fastened tight! You'll need help taking this off!")
- return
- ..()
-
-/obj/item/electropack/shockcollar/receive_signal(datum/signal/signal)
- if(!signal || signal.data["code"] != code)
- return
-
- if(isliving(loc) && on)
- if(shock_cooldown != 0)
- return
- shock_cooldown = 1
- spawn(100)
- shock_cooldown = 0
- var/mob/living/L = loc
- step(L, pick(GLOB.cardinals))
-
- to_chat(L, "You feel a sharp shock from the collar!")
- var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
- s.set_up(3, 1, L)
- s.start()
-
- L.DefaultCombatKnockdown(100)
-
- if(master)
- master.receive_signal()
- return
-
-/obj/item/electropack/shockcollar/attack_self(mob/user) //Turns out can't fully source this from the parent item, spritepath gets confused if power toggled. Will come back to this when I know how to code better and readd powertoggle..
- var/option = "Change Name"
- option = input(user, "What do you want to do?", "[src]", option) as null|anything in list("Change Name", "Change Frequency")
- switch(option)
- if("Change Name")
- var/t = input(user, "Would you like to change the name on the tag?", "Name your new pet", tagname ? tagname : "Spot") as null|text
- if(t)
- tagname = copytext(sanitize(t), 1, MAX_NAME_LEN)
- name = "[initial(name)] - [tagname]"
- if("Change Frequency")
- if(!ishuman(user))
- return
- user.set_machine(src)
- var/dat = {"
- Frequency/Code for shock collar:
- Frequency:
- -
- - [format_frequency(frequency)]
- +
- +
- Code:
- -
- - [code]
- +
- +
- "}
-
- user << browse(dat, "window=radio")
- onclose(user, "radio")
- return
diff --git a/modular_citadel/code/game/objects/structures/beds_chairs/chair.dm b/modular_citadel/code/game/objects/structures/beds_chairs/chair.dm
deleted file mode 100644
index 5b20fe048b..0000000000
--- a/modular_citadel/code/game/objects/structures/beds_chairs/chair.dm
+++ /dev/null
@@ -1,21 +0,0 @@
-/obj/structure/chair/alt_attack_hand(mob/living/user)
- if(Adjacent(user) && istype(user))
- if(!item_chair || !user.can_hold_items() || !has_buckled_mobs() || buckled_mobs.len > 1 || dir != user.dir || flags_1 & NODECONSTRUCT_1)
- return TRUE
- if(!user.canUseTopic(src, BE_CLOSE, ismonkey(user)))
- to_chat(user, "You can't do that right now!")
- return TRUE
- if(user.getStaminaLoss() >= STAMINA_SOFTCRIT)
- to_chat(user, "You're too exhausted for that.")
- return TRUE
- var/mob/living/poordude = buckled_mobs[1]
- if(!istype(poordude))
- return TRUE
- user.visible_message("[user] pulls [src] out from under [poordude].", "You pull [src] out from under [poordude].")
- var/C = new item_chair(loc)
- user.put_in_hands(C)
- poordude.DefaultCombatKnockdown(20)//rip in peace
- user.adjustStaminaLoss(5)
- unbuckle_all_mobs(TRUE)
- qdel(src)
- return TRUE
diff --git a/modular_citadel/code/modules/client/loadout/_loadout.dm b/modular_citadel/code/modules/client/loadout/_loadout.dm
index d35bede179..51256f8cde 100644
--- a/modular_citadel/code/modules/client/loadout/_loadout.dm
+++ b/modular_citadel/code/modules/client/loadout/_loadout.dm
@@ -10,7 +10,6 @@ GLOBAL_LIST_EMPTY(loadout_whitelist_ids)
/proc/load_loadout_config(loadout_config)
if(!loadout_config)
loadout_config = "config/loadout_config.txt"
- LAZYINITLIST(GLOB.loadout_whitelist_ids)
var/list/file_lines = world.file2list(loadout_config)
for(var/line in file_lines)
if(!line || line[1] == "#")
@@ -26,12 +25,9 @@ GLOBAL_LIST_EMPTY(loadout_whitelist_ids)
GLOB.loadout_whitelist_ids["[lineID]"] = sublinecontent
/proc/initialize_global_loadout_items()
- LAZYINITLIST(GLOB.loadout_items)
load_loadout_config()
for(var/item in subtypesof(/datum/gear))
var/datum/gear/I = new item
- if(!GLOB.loadout_items[slot_to_string(I.category)])
- LAZYINITLIST(GLOB.loadout_items[slot_to_string(I.category)])
LAZYSET(GLOB.loadout_items[slot_to_string(I.category)], I.name, I)
if(islist(I.geargroupID))
var/list/ggidlist = I.geargroupID
diff --git a/modular_citadel/code/modules/client/loadout/backpack.dm b/modular_citadel/code/modules/client/loadout/backpack.dm
index d51f4b6125..8d089a129a 100644
--- a/modular_citadel/code/modules/client/loadout/backpack.dm
+++ b/modular_citadel/code/modules/client/loadout/backpack.dm
@@ -69,18 +69,6 @@
path = /obj/item/toy/katana
cost = 3
-/datum/gear/box
- name = "Spare box"
- category = SLOT_IN_BACKPACK
- path = /obj/item/storage/box
- cost = 2
-
-/datum/gear/crowbar
- name = "Pocket Crowbar"
- category = SLOT_IN_BACKPACK
- path = /obj/item/crowbar
- cost = 2
-
/datum/gear/tapeplayer
name = "Taperecorder"
category = SLOT_IN_BACKPACK
@@ -96,11 +84,6 @@
category = SLOT_IN_BACKPACK
path = /obj/item/newspaper
-/datum/gear/paperbin
- name = "Paper Bin"
- category = SLOT_IN_BACKPACK
- path = /obj/item/paper_bin
-
/datum/gear/crayons
name = "Box of crayons"
category = SLOT_IN_BACKPACK
@@ -146,4 +129,4 @@
category = SLOT_IN_BACKPACK
path = /obj/item/storage/fancy/ringbox/diamond
cost = 5
-
+
diff --git a/modular_citadel/code/modules/client/loadout/mask.dm b/modular_citadel/code/modules/client/loadout/mask.dm
index 82824814ae..eeba06cad4 100644
--- a/modular_citadel/code/modules/client/loadout/mask.dm
+++ b/modular_citadel/code/modules/client/loadout/mask.dm
@@ -12,5 +12,5 @@
name = "Joy mask"
category = SLOT_WEAR_MASK
path = /obj/item/clothing/mask/joy
- cost = 9
-
+ cost = 3
+
diff --git a/modular_citadel/code/modules/client/loadout/suit.dm b/modular_citadel/code/modules/client/loadout/suit.dm
index 9b39d006bd..64deaf9be2 100644
--- a/modular_citadel/code/modules/client/loadout/suit.dm
+++ b/modular_citadel/code/modules/client/loadout/suit.dm
@@ -85,14 +85,6 @@
path = /obj/item/clothing/suit/hooded/wintercoat/polychromic
cost = 4 //too many people with neon green coats is hard on the eyes
-/* Commented out until it is "balanced"
-/datum/gear/coat/sec
- name = "Security winter coat"
- category = SLOT_WEAR_SUIT
- path = /obj/item/clothing/suit/hooded/wintercoat/security
- restricted_roles = list("Head of Security", "Warden", "Detective", "Security Officer") // Reserve it to the Security Departement
-*/
-
/datum/gear/coat/med
name = "Medical winter coat"
category = SLOT_WEAR_SUIT
diff --git a/modular_citadel/code/modules/client/preferences.dm b/modular_citadel/code/modules/client/preferences.dm
deleted file mode 100644
index 8c55f2d9a8..0000000000
--- a/modular_citadel/code/modules/client/preferences.dm
+++ /dev/null
@@ -1,47 +0,0 @@
-#define DEFAULT_SLOT_AMT 2
-#define HANDS_SLOT_AMT 2
-#define BACKPACK_SLOT_AMT 4
-
-/datum/preferences
- //gear
- var/gear_points = 10
- var/list/gear_categories
- var/list/chosen_gear
- var/gear_tab
-
- //pref vars
- var/screenshake = 100
- var/damagescreenshake = 2
- var/arousable = TRUE
- var/widescreenpref = TRUE
- var/autostand = TRUE
- var/auto_ooc = FALSE
-
- //vore prefs
- var/toggleeatingnoise = TRUE
- var/toggledigestionnoise = TRUE
- var/hound_sleeper = TRUE
- var/cit_toggles = TOGGLES_CITADEL
-
-
-/datum/preferences/New(client/C)
- ..()
- LAZYINITLIST(chosen_gear)
-
-/datum/preferences/proc/is_loadout_slot_available(slot)
- var/list/L
- LAZYINITLIST(L)
- for(var/i in chosen_gear)
- var/datum/gear/G = i
- var/occupied_slots = L[slot_to_string(initial(G.category))] ? L[slot_to_string(initial(G.category))] + 1 : 1
- LAZYSET(L, slot_to_string(initial(G.category)), occupied_slots)
- switch(slot)
- if(SLOT_IN_BACKPACK)
- if(L[slot_to_string(SLOT_IN_BACKPACK)] < BACKPACK_SLOT_AMT)
- return TRUE
- if(SLOT_HANDS)
- if(L[slot_to_string(SLOT_HANDS)] < HANDS_SLOT_AMT)
- return TRUE
- else
- if(L[slot_to_string(slot)] < DEFAULT_SLOT_AMT)
- return TRUE
diff --git a/modular_citadel/code/modules/client/preferences_savefile.dm b/modular_citadel/code/modules/client/preferences_savefile.dm
index d9b902656f..d0363d228f 100644
--- a/modular_citadel/code/modules/client/preferences_savefile.dm
+++ b/modular_citadel/code/modules/client/preferences_savefile.dm
@@ -14,17 +14,6 @@
features["mcolor2"] = sanitize_hexcolor(features["mcolor2"], 3, 0)
features["mcolor3"] = sanitize_hexcolor(features["mcolor3"], 3, 0)
- //gear loadout
- var/text_to_load
- S["loadout"] >> text_to_load
- var/list/saved_loadout_paths = splittext(text_to_load, "|")
- LAZYCLEARLIST(chosen_gear)
- gear_points = initial(gear_points)
- for(var/i in saved_loadout_paths)
- var/datum/gear/path = text2path(i)
- if(path)
- LAZYADD(chosen_gear, path)
- gear_points -= initial(path.cost)
/datum/preferences/proc/cit_character_pref_save(savefile/S)
//ipcs
@@ -47,10 +36,3 @@
//flavor text
WRITE_FILE(S["feature_flavor_text"], features["flavor_text"])
- //gear loadout
- if(islist(chosen_gear))
- if(chosen_gear.len)
- var/text_to_save = chosen_gear.Join("|")
- S["loadout"] << text_to_save
- else
- S["loadout"] << "" //empty string to reset the value
diff --git a/modular_citadel/code/modules/mob/living/carbon/carbon.dm b/modular_citadel/code/modules/mob/living/carbon/carbon.dm
index e95948e562..0532f59afa 100644
--- a/modular_citadel/code/modules/mob/living/carbon/carbon.dm
+++ b/modular_citadel/code/modules/mob/living/carbon/carbon.dm
@@ -25,5 +25,5 @@
/mob/living/carbon/onMouseMove(object, location, control, params)
if(!(combat_flags & COMBAT_FLAG_COMBAT_ACTIVE))
return
- mouse_face_atom(object)
+ face_atom(object, TRUE)
lastmousedir = dir
diff --git a/modular_citadel/code/modules/reagents/chemistry/reagents/MKUltra.dm b/modular_citadel/code/modules/reagents/chemistry/reagents/MKUltra.dm
index 89a7f58cee..d3daad7964 100644
--- a/modular_citadel/code/modules/reagents/chemistry/reagents/MKUltra.dm
+++ b/modular_citadel/code/modules/reagents/chemistry/reagents/MKUltra.dm
@@ -194,14 +194,14 @@ Creating a chem with a low purity will make you permanently fall in love with so
if (M.ckey == creatorID && creatorName == M.real_name)//If the creator drinks it, they fall in love randomly. If someone else drinks it, the creator falls in love with them.
if(M.has_status_effect(STATUS_EFFECT_INLOVE))//Can't be enthralled when enthralled, so to speak.
return
- var/list/seen = viewers(7, get_turf(M))
+ var/list/seen = (M.fov_view(M.client?.view || world.view) - M) | viewers(M.client?.view || world.view, M)
for(var/victim in seen)
if(ishuman(victim))
var/mob/living/carbon/V = victim
- if((V == M) || (!V.client) || (V.stat == DEAD))
- seen = seen - victim
+ if(!V.client || V.stat == DEAD)
+ seen -= victim
else
- seen = seen - victim
+ seen -= victim
if(LAZYLEN(seen))
return
@@ -213,7 +213,7 @@ Creating a chem with a low purity will make you permanently fall in love with so
var/mob/living/carbon/C = get_mob_by_key(creatorID)
if(M.has_status_effect(STATUS_EFFECT_INLOVE))
return
- if((C in viewers(7, get_turf(M))) && (C.client))
+ if(C.client && (M in C.fov_view(C.client.view)))
M.reagents.del_reagent(type)
FallInLove(C, M)
return
@@ -279,15 +279,13 @@ Creating a chem with a low purity will make you permanently fall in love with so
if(HAS_TRAIT(M, TRAIT_MINDSHIELD))
return ..()
if(!M.has_status_effect(STATUS_EFFECT_INLOVE))
- var/list/seen = viewers(7, get_turf(M))//Sound and sight checkers
+ var/list/seen = (M.fov_view(M.client?.view || world.view) - M) | viewers(M.client?.view || world.view, M)
for(var/victim in seen)
- if((istype(victim, /mob/living/simple_animal/pet/)) || (victim == M) || (M.stat == DEAD) || (!isliving(victim)))
- seen = seen - victim
- if(seen.len == 0)
+ if((isanimal(victim)) || (!isliving(victim)))
+ seen -= victim
+ if(!length(seen))
return
love = pick(seen)
- if(!love)
- return
M.apply_status_effect(STATUS_EFFECT_INLOVE, love)
lewd = (M.client?.prefs.cit_toggles & HYPNO) && (love.client?.prefs.cit_toggles & HYPNO)
to_chat(M, "[(lewd?"":"")][(lewd?"You develop a sudden crush on [love], your heart beginning to race as you look upon them with new eyes.":"You suddenly feel like making friends with [love].")] You feel strangely drawn towards them.")
diff --git a/modular_citadel/code/modules/reagents/chemistry/reagents/fermi_reagents.dm b/modular_citadel/code/modules/reagents/chemistry/reagents/fermi_reagents.dm
index dac6d97eef..8a3a648863 100644
--- a/modular_citadel/code/modules/reagents/chemistry/reagents/fermi_reagents.dm
+++ b/modular_citadel/code/modules/reagents/chemistry/reagents/fermi_reagents.dm
@@ -98,10 +98,8 @@
M.emote("cough")
var/obj/item/toy/plush/P = pick(subtypesof(/obj/item/toy/plush))
new P(T)
- to_chat(M, "You feel a lump form in your throat, as you suddenly cough up what seems to be a hairball?")
- var/list/seen = viewers(8, T)
- for(var/mob/S in seen)
- to_chat(S, "[M] suddenly coughs up a [P.name]!")
+ M.visible_message("[M] suddenly coughs up a [P.name]!",\
+ "You feel a lump form in your throat, as you suddenly cough up what seems to be a hairball?")
var/T2 = get_random_station_turf()
P.throw_at(T2, 8, 1)
..()
@@ -120,10 +118,10 @@
to_chat(M, "You find yourself unable to supress the desire to howl!")
M.emote("awoo")
if(prob(20))
- var/list/seen = viewers(5, get_turf(M))//Sound and sight checkers
+ var/list/seen = M.fov_view() - M //Sound and sight checkers
for(var/victim in seen)
- if((istype(victim, /mob/living/simple_animal/pet/)) || (victim == M) || (!isliving(victim)))
- seen = seen - victim
+ if(isanimal(victim) || !isliving(victim))
+ seen -= victim
if(LAZYLEN(seen))
to_chat(M, "You notice [pick(seen)]'s bulge [pick("OwO!", "uwu!")]")
if(16)
@@ -141,10 +139,10 @@
to_chat(M, "You find yourself unable to supress the desire to howl!")
M.emote("awoo")
if(prob(5))
- var/list/seen = viewers(5, get_turf(M))//Sound and sight checkers
+ var/list/seen = M.fov_view() - M //Sound and sight checkers
for(var/victim in seen)
- if((istype(victim, /mob/living/simple_animal/pet/)) || (victim == M) || (!isliving(victim)))
- seen = seen - victim
+ if(isanimal(victim) || !isliving(victim))
+ seen -= victim
if(LAZYLEN(seen))
to_chat(M, "You notice [pick(seen)]'s bulge [pick("OwO!", "uwu!")]")
..()
@@ -301,9 +299,8 @@ datum/reagent/fermi/nanite_b_gone/reaction_obj(obj/O, reac_volume)
else
var/datum/chemical_reaction/Ferm = GLOB.chemical_reagents_list[reagent.type]
Ferm.on_reaction(holder, reagent.volume)
- for(var/mob/M in viewers(8, location))
- to_chat(M, "The solution reacts dramatically, with a meow!")
- playsound(get_turf(M), 'modular_citadel/sound/voice/merowr.ogg', 50, 1)
+ holder.my_atom.visible_message("The solution reacts dramatically, with a meow!")
+ playsound(holder.my_atom, 'modular_citadel/sound/voice/merowr.ogg', 50, 1)
holder.clear_reagents()
/datum/reagent/fermi/acidic_buffer
@@ -321,10 +318,8 @@ datum/reagent/fermi/nanite_b_gone/reaction_obj(obj/O, reac_volume)
if(LAZYLEN(holder.reagent_list) == 1)
return ..()
holder.pH = ((holder.pH * holder.total_volume)+(pH * (volume)))/(holder.total_volume + (volume))
- var/list/seen = viewers(5, get_turf(holder))
- for(var/mob/M in seen)
- to_chat(M, "The beaker fizzes as the pH changes!")
- playsound(get_turf(holder.my_atom), 'sound/FermiChem/bufferadd.ogg', 50, 1)
+ holder.my_atom.visible_message("The beaker fizzes as the pH changes!")
+ playsound(holder.my_atom, 'sound/FermiChem/bufferadd.ogg', 50, 1)
holder.remove_reagent(type, volume, ignore_pH = TRUE)
..()
@@ -342,10 +337,8 @@ datum/reagent/fermi/nanite_b_gone/reaction_obj(obj/O, reac_volume)
if(LAZYLEN(holder.reagent_list) == 1)
return ..()
holder.pH = ((holder.pH * holder.total_volume)+(pH * (volume)))/(holder.total_volume + (volume))
- var/list/seen = viewers(5, get_turf(holder))
- for(var/mob/M in seen)
- to_chat(M, "The beaker froths as the pH changes!")
- playsound(get_turf(holder.my_atom), 'sound/FermiChem/bufferadd.ogg', 50, 1)
+ holder.my_atom.visible_message("The beaker froths as the pH changes!")
+ playsound(holder.my_atom, 'sound/FermiChem/bufferadd.ogg', 50, 1)
holder.remove_reagent(type, volume, ignore_pH = TRUE)
..()
diff --git a/modular_citadel/code/modules/reagents/chemistry/recipes/fermi.dm b/modular_citadel/code/modules/reagents/chemistry/recipes/fermi.dm
index 837524d49f..a8998a51ac 100644
--- a/modular_citadel/code/modules/reagents/chemistry/recipes/fermi.dm
+++ b/modular_citadel/code/modules/reagents/chemistry/recipes/fermi.dm
@@ -172,9 +172,7 @@
S.rabid = 1//Make them an angery boi
S.color = "#810010"
my_atom.reagents.clear_reagents()
- var/list/seen = viewers(8, get_turf(my_atom))
- for(var/mob/M in seen)
- to_chat(M, "The cells clump up into a horrifying tumour!")
+ my_atom.visible_message("An horrifying tumoural mass forms in [my_atom]!")
/datum/chemical_reaction/fermi/breast_enlarger
name = "Sucubus milk"
@@ -211,9 +209,7 @@
/datum/chemical_reaction/fermi/breast_enlarger/FermiExplode(datum/reagents, var/atom/my_atom, volume, temp, pH)
var/obj/item/organ/genital/breasts/B = new /obj/item/organ/genital/breasts(get_turf(my_atom))
- var/list/seen = viewers(8, get_turf(my_atom))
- for(var/mob/M in seen)
- to_chat(M, "The reaction suddenly condenses, creating a pair of breasts!")
+ my_atom.visible_message("The reaction suddenly condenses, creating a pair of breasts!")
var/datum/reagent/fermi/breast_enlarger/BE = locate(/datum/reagent/fermi/breast_enlarger) in my_atom.reagents.reagent_list
B.size = ((BE.volume * BE.purity) / 10) //half as effective.
my_atom.reagents.clear_reagents()
@@ -243,9 +239,7 @@
/datum/chemical_reaction/fermi/penis_enlarger/FermiExplode(datum/reagents, var/atom/my_atom, volume, temp, pH)
var/obj/item/organ/genital/penis/P = new /obj/item/organ/genital/penis(get_turf(my_atom))
- var/list/seen = viewers(8, get_turf(my_atom))
- for(var/mob/M in seen)
- to_chat(M, "The reaction suddenly condenses, creating a penis!")
+ my_atom.visible_message("The reaction suddenly condenses, creating a penis!")
var/datum/reagent/fermi/penis_enlarger/PE = locate(/datum/reagent/fermi/penis_enlarger) in my_atom.reagents.reagent_list
P.length = ((PE.volume * PE.purity) / 10)//half as effective.
my_atom.reagents.clear_reagents()
@@ -383,9 +377,7 @@
for(var/i in 1 to amount_to_spawn)
var/obj/item/clothing/head/hattip/hat = new /obj/item/clothing/head/hattip(get_turf(my_atom))
hat.animate_atom_living()
- var/list/seen = viewers(8, get_turf(my_atom))
- for(var/mob/M in seen)
- to_chat(M, "The [my_atom] makes an off sounding pop, as a hat suddenly climbs out of it!")
+ my_atom.visible_message("The [my_atom] makes an off sounding pop, as a hat suddenly climbs out of it!")
my_atom.reagents.clear_reagents()
/datum/chemical_reaction/fermi/furranium
@@ -543,9 +535,7 @@
/datum/chemical_reaction/fermi/secretcatchem/FermiExplode(datum/reagents, var/atom/my_atom, volume, temp, pH)
var/mob/living/simple_animal/pet/cat/custom_cat/catto = new(get_turf(my_atom))
- var/list/seen = viewers(8, get_turf(my_atom))
- for(var/mob/M in seen)
- to_chat(M, "The reaction suddenly gives out a meow, condensing into a chemcat!")//meow!
+ my_atom.visible_message("The reaction suddenly gives out a meow, condensing into a chemcat!")//meow!
playsound(get_turf(my_atom), 'modular_citadel/sound/voice/merowr.ogg', 50, 1, -1)
catto.name = "Chemcat"
catto.desc = "A cute chem cat, created by a lot of compicated and confusing chemistry!"
diff --git a/modular_citadel/code/modules/reagents/objects/clothes.dm b/modular_citadel/code/modules/reagents/objects/clothes.dm
index 34af39bbe0..de4cb38360 100644
--- a/modular_citadel/code/modules/reagents/objects/clothes.dm
+++ b/modular_citadel/code/modules/reagents/objects/clothes.dm
@@ -5,7 +5,7 @@
name = "Synthetic hat"
icon = 'icons/obj/clothing/hats.dmi'
icon_state = "cowboy"
- desc = "A synthesized hat, you can't seem to take it off. And tips their hat."
+ desc = "A synthesized hat. You feel compelled to keep it on all times."
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 0)
//item_flags = NODROP //Tips their hat!
@@ -49,9 +49,8 @@
/obj/item/clothing/head/hattip/proc/root_and_toot(obj/item/clothing/head/hattip/hat)
hat.animate_atom_living()
- var/list/seen = viewers(6, get_turf(hat))
- for(var/mob/M2 in seen)
- to_chat(M2, "[hat] exclaims, \"[pick("Whooee! Time for a hootenanny!", "Rough 'em up boys!", "Yeehaw! Freedom at last!", "Y'all about to get a good old fashioned spanking!")]\"")
+ var/mob/living/simple_animal/hostile/mimic/M = loc
+ M.say(pick("Whooee! Time for a hootenanny!", "Rough 'em up boys!", "Yeehaw! Freedom at last!", "Y'all about to get a good old fashioned spanking!"))
/obj/item/clothing/head/hattip/proc/handle_speech(datum/source, mob/speech_args)
var/message = speech_args[SPEECH_MESSAGE]
diff --git a/modular_citadel/icons/mob/mam_tails.dmi b/modular_citadel/icons/mob/mam_tails.dmi
index d91f15a3f7..a67c1b718c 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/mob/mam_taur.dmi b/modular_citadel/icons/mob/mam_taur.dmi
index 3625c293c9..cf332019af 100644
Binary files a/modular_citadel/icons/mob/mam_taur.dmi and b/modular_citadel/icons/mob/mam_taur.dmi differ
diff --git a/modular_citadel/interface/skin.dmf b/modular_citadel/interface/skin.dmf
deleted file mode 100644
index 8130e84f90..0000000000
--- a/modular_citadel/interface/skin.dmf
+++ /dev/null
@@ -1,335 +0,0 @@
-macro "default"
-
-
-menu "menu"
- elem
- name = "&File"
- command = ""
- saved-params = "is-checked"
- elem
- name = "&Quick screenshot\tF2"
- command = ".screenshot auto"
- category = "&File"
- saved-params = "is-checked"
- elem
- name = "&Save screenshot as...\tShift+F2"
- command = ".screenshot"
- category = "&File"
- saved-params = "is-checked"
- elem
- name = ""
- command = ""
- category = "&File"
- saved-params = "is-checked"
- elem "reconnectbutton"
- name = "&Reconnect"
- command = ".reconnect"
- category = "&File"
- saved-params = "is-checked"
- elem
- name = "&Quit\tAlt-F4"
- command = ".quit"
- category = "&File"
- saved-params = "is-checked"
- elem
- name = "&Help"
- command = ""
- saved-params = "is-checked"
- elem
- name = "&Admin Help\tF1"
- command = "adminhelp"
- category = "&Help"
- saved-params = "is-checked"
- elem
- name = "&Hotkeys"
- command = "hotkeys-help"
- category = "&Help"
- saved-params = "is-checked"
- elem
- name = "&Hotkeys"
- command = "hotkeys-help"
- category = "&Help"
- saved-params = "is-checked"
-
-window "mainwindow"
- elem "mainwindow"
- type = MAIN
- pos = 0,0
- size = 640x440
- anchor1 = none
- anchor2 = none
- background-color = #242424
- is-default = true
- saved-params = "pos;size;is-minimized;is-maximized"
- icon = 'icons\\ss13_64.png'
- macro = "default"
- menu = "menu"
- elem "split"
- type = CHILD
- pos = 0,0
- size = 637x440
- anchor1 = 0,0
- anchor2 = 100,100
- background-color = #272727
- saved-params = "splitter"
- left = "mapwindow"
- right = "infowindow"
- is-vert = true
- splitter = 75
- elem "asset_cache_browser"
- type = BROWSER
- pos = 0,0
- size = 200x200
- anchor1 = none
- anchor2 = none
- background-color = #272727
- is-visible = false
- saved-params = ""
- elem "tooltip"
- type = BROWSER
- pos = 0,0
- size = 999x999
- anchor1 = none
- anchor2 = none
- background-color = #272727
- is-visible = false
- saved-params = ""
-
-window "mapwindow"
- elem "mapwindow"
- type = MAIN
- pos = 418,0
- size = 1024x1024
- anchor1 = none
- anchor2 = none
- background-color = none
- saved-params = "pos;size;is-minimized;is-maximized"
- statusbar = false
- is-pane = true
- outer-size = 684x617
- inner-size = 662x561
- elem "map"
- type = MAP
- pos = 0,0
- size = 1024x1024
- anchor1 = 0,0
- anchor2 = 100,100
- font-family = "Arial"
- font-size = 7
- is-default = true
- saved-params = "icon-size"
- zoom-mode = distort
- style = ".center { text-align: center; }\n.maptext { font-family: 'Small Fonts'; font-size: 7px; -dm-text-outline: 1px black; color: white; line-height: 1.1; }\n.command_headset { font-weight: bold;\tfont-size: 8px; } .small { font-size: 6px; }\n.big { font-size: 8px; }\n.reallybig { font-size: 8px; }\n.extremelybig { font-size: 8px; }\n.greentext { color: #00ff00; font-size: 7px; }\n.redtext { color: #ff0000; font-size: 7px; }\n.clown { color: #ff69bf; font-size: 7px; font-weight: bold; }\n.his_grace { color: #15d512; }\n.hypnophrase { color: #0d0d0d; font-weight: bold; }\n.yell { font-weight: bold; }\n.italics { font-size: 6px; }"
-
-window "infowindow"
- elem "infowindow"
- type = MAIN
- pos = 0,0
- size = 640x480
- anchor1 = none
- anchor2 = none
- background-color = #242424
- saved-params = "pos;size;is-minimized;is-maximized"
- is-pane = true
- elem "info"
- type = CHILD
- pos = 0,30
- size = 640x445
- anchor1 = 0,0
- anchor2 = 100,100
- background-color = #272727
- saved-params = "splitter"
- left = "statwindow"
- right = "outputwindow"
- is-vert = false
- elem "changelog"
- type = BUTTON
- pos = 16,5
- size = 104x20
- anchor1 = 3,0
- anchor2 = 19,0
- text-color = #e0e0e0
- background-color = #40628a
- saved-params = "is-checked"
- text = "Changelog"
- command = "changelog"
- elem "rules"
- type = BUTTON
- pos = 120,5
- size = 100x20
- anchor1 = 19,0
- anchor2 = 34,0
- text-color = #e0e0e0
- background-color = #40628a
- saved-params = "is-checked"
- text = "Rules"
- command = "rules"
- elem "wiki"
- type = BUTTON
- pos = 220,5
- size = 100x20
- anchor1 = 34,0
- anchor2 = 50,0
- text-color = #e0e0e0
- background-color = #40628a
- saved-params = "is-checked"
- text = "Wiki"
- command = "wiki"
- elem "forum"
- type = BUTTON
- pos = 320,5
- size = 100x20
- anchor1 = 50,0
- anchor2 = 66,0
- text-color = #e0e0e0
- background-color = #40628a
- saved-params = "is-checked"
- text = "Forum"
- command = "forum"
- elem "github"
- type = BUTTON
- pos = 420,5
- size = 100x20
- anchor1 = 66,0
- anchor2 = 81,0
- text-color = #e0e0e0
- background-color = #40628a
- saved-params = "is-checked"
- text = "GitHub"
- command = "github"
- elem "report-issue"
- type = BUTTON
- pos = 520,5
- size = 100x20
- anchor1 = 81,0
- anchor2 = 97,0
- font-size = 8
- text-color = #e0e0e0
- background-color = #a92c2c
- saved-params = "is-checked"
- text = "Report Issue"
- command = "report-issue"
-
-window "outputwindow"
- elem "outputwindow"
- type = MAIN
- pos = 0,0
- size = 640x480
- anchor1 = none
- anchor2 = none
- background-color = #272727
- saved-params = "pos;size;is-minimized;is-maximized"
- titlebar = false
- statusbar = false
- can-close = false
- can-minimize = false
- can-resize = false
- is-pane = true
- elem "input"
- type = INPUT
- pos = 2,460
- size = 595x20
- anchor1 = 0,100
- anchor2 = 100,100
- background-color = #d3b5b5
- is-default = true
- border = sunken
- saved-params = "command"
- elem "say"
- type = BUTTON
- pos = 600,460
- size = 37x20
- anchor1 = 100,100
- anchor2 = none
- text-color = #e0e0e0
- background-color = #272727
- saved-params = "is-checked"
- text = "Chat"
- command = ".winset \"say.is-checked=true ? input.command=\"!say \\\"\" : input.command=\""
- is-flat = true
- button-type = pushbox
- elem "browseroutput"
- type = BROWSER
- pos = 0,0
- size = 640x456
- anchor1 = 0,0
- anchor2 = 100,100
- background-color = #272727
- is-visible = false
- is-disabled = true
- saved-params = ""
- auto-format = false
- elem "output"
- type = OUTPUT
- pos = 0,0
- size = 640x456
- anchor1 = 0,0
- anchor2 = 100,100
- text-color = #e0e0e0
- background-color = #272727
- is-default = true
- saved-params = ""
-
-window "statwindow"
- elem "statwindow"
- type = MAIN
- pos = 281,0
- size = 640x480
- anchor1 = none
- anchor2 = none
- background-color = #242424
- saved-params = "pos;size;is-minimized;is-maximized"
- is-pane = true
- elem "stat"
- type = INFO
- pos = 0,0
- size = 640x480
- anchor1 = 0,0
- anchor2 = 100,100
- text-color = #e0e0e0
- background-color = #272727
- is-default = true
- saved-params = ""
- tab-text-color = #e0e0e0
- tab-background-color = #242424
- prefix-color = #e0e0e0
- suffix-color = #e0e0e0
-
-window "popupwindow"
- elem "popupwindow"
- type = MAIN
- pos = 281,0
- size = 120x120
- anchor1 = none
- anchor2 = none
- background-color = none
- is-visible = false
- saved-params = "pos;size;is-minimized;is-maximized"
- statusbar = false
- can-resize = false
-window "preferences_window"
- elem "preferences_window"
- type = MAIN
- pos = 281,0
- size = 1280x1000
- anchor1 = none
- anchor2 = none
- is-visible = false
- saved-params = "pos;size;is-minimized;is-maximized"
- statusbar = false
- elem "preferences_browser"
- type = BROWSER
- pos = 0,0
- size = 960x1000
- anchor1 = 0,0
- anchor2 = 75,100
- saved-params = ""
- elem "character_preview_map"
- type = MAP
- pos = 960,0
- size = 320x1000
- anchor1 = 75,0
- anchor2 = 100,100
- right-click = true
- saved-params = "zoom;letterbox;zoom-mode"
-
diff --git a/rust_g.dll b/rust_g.dll
index 27ee495684..f4be6e730a 100644
Binary files a/rust_g.dll and b/rust_g.dll differ
diff --git a/strings/tips.txt b/strings/tips.txt
index c8f233bb1a..0176420dd3 100644
--- a/strings/tips.txt
+++ b/strings/tips.txt
@@ -64,6 +64,7 @@ As a Roboticist, you can greatly help out Shaft Miners by building a Firefighter
As a Roboticist, you can augment people with cyborg limbs. Augmented limbs can easily be repaired with cables and welders.
As a Roboticist, you can use your printer that is linked to the ore silo to teleport mats into your work place!
As a Roboticist, you can upgrade cleanbots with adv mops and brooms to make them faster and better!
+As a Roboticist, you can upgrade medical bots with diamond-tipped syringes, MK.II Hypospray, dispenser-sleeper-chemheater boards to make them inject faster, harder and better chems!
As the AI, you can click on people's names to look at them. This only works if there are cameras that can see them.
As the AI, you can quickly open and close doors by holding shift while clicking them, bolt them when holding ctrl, and even shock them while holding alt.
As the AI, you can take pictures with your camera and upload them to newscasters.
diff --git a/tgstation.dme b/tgstation.dme
index b4d3f6f712..e54d164852 100755
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -94,7 +94,6 @@
#include "code\__DEFINES\research.dm"
#include "code\__DEFINES\robots.dm"
#include "code\__DEFINES\role_preferences.dm"
-#include "code\__DEFINES\rust_g.config.dm"
#include "code\__DEFINES\rust_g.dm"
#include "code\__DEFINES\say.dm"
#include "code\__DEFINES\security_levels.dm"
@@ -105,7 +104,6 @@
#include "code\__DEFINES\stat.dm"
#include "code\__DEFINES\stat_tracking.dm"
#include "code\__DEFINES\status_effects.dm"
-#include "code\__DEFINES\storage.dm"
#include "code\__DEFINES\subsystems.dm"
#include "code\__DEFINES\tgs.config.dm"
#include "code\__DEFINES\tgs.dm"
@@ -121,6 +119,7 @@
#include "code\__DEFINES\vv.dm"
#include "code\__DEFINES\wall_dents.dm"
#include "code\__DEFINES\wires.dm"
+#include "code\__DEFINES\admin\keybindings.dm"
#include "code\__DEFINES\dcs\flags.dm"
#include "code\__DEFINES\dcs\helpers.dm"
#include "code\__DEFINES\dcs\signals.dm"
@@ -132,6 +131,8 @@
#include "code\__DEFINES\research\stock_parts.dm"
#include "code\__DEFINES\skills\defines.dm"
#include "code\__DEFINES\skills\helpers.dm"
+#include "code\__DEFINES\storage\_storage.dm"
+#include "code\__DEFINES\storage\volumetrics.dm"
#include "code\__HELPERS\_cit_helpers.dm"
#include "code\__HELPERS\_lists.dm"
#include "code\__HELPERS\_logging.dm"
@@ -185,7 +186,9 @@
#include "code\_globalvars\misc.dm"
#include "code\_globalvars\regexes.dm"
#include "code\_globalvars\traits.dm"
+#include "code\_globalvars\lists\client.dm"
#include "code\_globalvars\lists\flavor_misc.dm"
+#include "code\_globalvars\lists\keybindings.dm"
#include "code\_globalvars\lists\maintenance_loot.dm"
#include "code\_globalvars\lists\mapping.dm"
#include "code\_globalvars\lists\medals.dm"
@@ -292,7 +295,6 @@
#include "code\controllers\subsystem\minimaps.dm"
#include "code\controllers\subsystem\minor_mapping.dm"
#include "code\controllers\subsystem\mobs.dm"
-#include "code\controllers\subsystem\moods.dm"
#include "code\controllers\subsystem\nightshift.dm"
#include "code\controllers\subsystem\npcpool.dm"
#include "code\controllers\subsystem\overlays.dm"
@@ -370,6 +372,7 @@
#include "code\datums\shuttles.dm"
#include "code\datums\soullink.dm"
#include "code\datums\spawners_menu.dm"
+#include "code\datums\tgs_event_handler.dm"
#include "code\datums\verbs.dm"
#include "code\datums\weakrefs.dm"
#include "code\datums\world_topic.dm"
@@ -386,6 +389,7 @@
#include "code\datums\components\_component.dm"
#include "code\datums\components\anti_magic.dm"
#include "code\datums\components\armor_plate.dm"
+#include "code\datums\components\art.dm"
#include "code\datums\components\bane.dm"
#include "code\datums\components\bouncy.dm"
#include "code\datums\components\butchering.dm"
@@ -398,6 +402,7 @@
#include "code\datums\components\edit_complainer.dm"
#include "code\datums\components\empprotection.dm"
#include "code\datums\components\explodable.dm"
+#include "code\datums\components\field_of_vision.dm"
#include "code\datums\components\footstep.dm"
#include "code\datums\components\forced_gravity.dm"
#include "code\datums\components\identification.dm"
@@ -524,6 +529,7 @@
#include "code\datums\elements\cleaning.dm"
#include "code\datums\elements\dusts_on_catatonia.dm"
#include "code\datums\elements\dusts_on_leaving_area.dm"
+#include "code\datums\elements\dwarfism.dm"
#include "code\datums\elements\earhealing.dm"
#include "code\datums\elements\firestacker.dm"
#include "code\datums\elements\flavor_text.dm"
@@ -586,8 +592,12 @@
#include "code\datums\skills\_check_skills.dm"
#include "code\datums\skills\_skill.dm"
#include "code\datums\skills\_skill_holder.dm"
+#include "code\datums\skills\_skill_modifier.dm"
#include "code\datums\skills\engineering.dm"
#include "code\datums\skills\medical.dm"
+#include "code\datums\skills\modifiers\job.dm"
+#include "code\datums\skills\modifiers\mood.dm"
+#include "code\datums\skills\modifiers\organs.dm"
#include "code\datums\status_effects\buffs.dm"
#include "code\datums\status_effects\debuffs.dm"
#include "code\datums\status_effects\gas.dm"
@@ -1087,6 +1097,7 @@
#include "code\game\objects\items\stacks\tiles\light.dm"
#include "code\game\objects\items\stacks\tiles\tile_mineral.dm"
#include "code\game\objects\items\stacks\tiles\tile_types.dm"
+#include "code\game\objects\items\storage\_storage.dm"
#include "code\game\objects\items\storage\backpack.dm"
#include "code\game\objects\items\storage\bags.dm"
#include "code\game\objects\items\storage\belt.dm"
@@ -1098,7 +1109,6 @@
#include "code\game\objects\items\storage\firstaid.dm"
#include "code\game\objects\items\storage\lockbox.dm"
#include "code\game\objects\items\storage\secure.dm"
-#include "code\game\objects\items\storage\storage.dm"
#include "code\game\objects\items\storage\toolbox.dm"
#include "code\game\objects\items\storage\uplink_kits.dm"
#include "code\game\objects\items\storage\wallets.dm"
@@ -1467,6 +1477,7 @@
#include "code\modules\antagonists\clockcult\clock_items\soul_vessel.dm"
#include "code\modules\antagonists\clockcult\clock_items\wraith_spectacles.dm"
#include "code\modules\antagonists\clockcult\clock_items\clock_weapons\_call_weapon.dm"
+#include "code\modules\antagonists\clockcult\clock_items\clock_weapons\ratvarian_shield.dm"
#include "code\modules\antagonists\clockcult\clock_items\clock_weapons\ratvarian_spear.dm"
#include "code\modules\antagonists\clockcult\clock_mobs\_eminence.dm"
#include "code\modules\antagonists\clockcult\clock_mobs\clockwork_marauder.dm"
@@ -2034,6 +2045,7 @@
#include "code\modules\hydroponics\grown\onion.dm"
#include "code\modules\hydroponics\grown\peach.dm"
#include "code\modules\hydroponics\grown\peanuts.dm"
+#include "code\modules\hydroponics\grown\peas.dm"
#include "code\modules\hydroponics\grown\pineapple.dm"
#include "code\modules\hydroponics\grown\potato.dm"
#include "code\modules\hydroponics\grown\pumpkin.dm"
@@ -2139,16 +2151,22 @@
#include "code\modules\jobs\job_types\virologist.dm"
#include "code\modules\jobs\job_types\warden.dm"
#include "code\modules\jobs\map_changes\map_changes.dm"
-#include "code\modules\keybindings\bindings_admin.dm"
#include "code\modules\keybindings\bindings_atom.dm"
-#include "code\modules\keybindings\bindings_carbon.dm"
#include "code\modules\keybindings\bindings_client.dm"
-#include "code\modules\keybindings\bindings_human.dm"
-#include "code\modules\keybindings\bindings_living.dm"
-#include "code\modules\keybindings\bindings_mob.dm"
-#include "code\modules\keybindings\bindings_robot.dm"
#include "code\modules\keybindings\focus.dm"
#include "code\modules\keybindings\setup.dm"
+#include "code\modules\keybindings\keybind\__defines.dm"
+#include "code\modules\keybindings\keybind\_keybind.dm"
+#include "code\modules\keybindings\keybind\admin.dm"
+#include "code\modules\keybindings\keybind\carbon.dm"
+#include "code\modules\keybindings\keybind\client.dm"
+#include "code\modules\keybindings\keybind\emote.dm"
+#include "code\modules\keybindings\keybind\human.dm"
+#include "code\modules\keybindings\keybind\living.dm"
+#include "code\modules\keybindings\keybind\mob.dm"
+#include "code\modules\keybindings\keybind\movement.dm"
+#include "code\modules\keybindings\keybind\robot.dm"
+#include "code\modules\keybindings\keybind\targeting.dm"
#include "code\modules\language\aphasia.dm"
#include "code\modules\language\beachbum.dm"
#include "code\modules\language\codespeak.dm"
@@ -2250,6 +2268,7 @@
#include "code\modules\mob\say_vr.dm"
#include "code\modules\mob\status_procs.dm"
#include "code\modules\mob\transform_procs.dm"
+#include "code\modules\mob\typing_indicator.dm"
#include "code\modules\mob\update_icons.dm"
#include "code\modules\mob\camera\camera.dm"
#include "code\modules\mob\dead\dead.dm"
@@ -2377,10 +2396,12 @@
#include "code\modules\mob\living\carbon\human\human_movement.dm"
#include "code\modules\mob\living\carbon\human\inventory.dm"
#include "code\modules\mob\living\carbon\human\life.dm"
+#include "code\modules\mob\living\carbon\human\login.dm"
#include "code\modules\mob\living\carbon\human\physiology.dm"
#include "code\modules\mob\living\carbon\human\say.dm"
#include "code\modules\mob\living\carbon\human\species.dm"
#include "code\modules\mob\living\carbon\human\status_procs.dm"
+#include "code\modules\mob\living\carbon\human\typing_indicator.dm"
#include "code\modules\mob\living\carbon\human\update_icons.dm"
#include "code\modules\mob\living\carbon\human\species_types\abductors.dm"
#include "code\modules\mob\living\carbon\human\species_types\android.dm"
@@ -3324,9 +3345,7 @@
#include "interface\interface.dm"
#include "interface\menu.dm"
#include "interface\stylesheet.dm"
-#include "modular_citadel\code\__HELPERS\list2list.dm"
-#include "modular_citadel\code\__HELPERS\lists.dm"
-#include "modular_citadel\code\__HELPERS\mobs.dm"
+#include "interface\skin.dmf"
#include "modular_citadel\code\_onclick\click.dm"
#include "modular_citadel\code\_onclick\item_attack.dm"
#include "modular_citadel\code\_onclick\other_mobs.dm"
@@ -3335,7 +3354,6 @@
#include "modular_citadel\code\_onclick\hud\stamina.dm"
#include "modular_citadel\code\datums\components\souldeath.dm"
#include "modular_citadel\code\datums\status_effects\chems.dm"
-#include "modular_citadel\code\game\machinery\wishgranter.dm"
#include "modular_citadel\code\game\objects\cit_screenshake.dm"
#include "modular_citadel\code\game\objects\effects\temporary_visuals\souldeath.dm"
#include "modular_citadel\code\modules\admin\chat_commands.dm"
@@ -3343,7 +3361,6 @@
#include "modular_citadel\code\modules\admin\secrets.dm"
#include "modular_citadel\code\modules\client\client_defines.dm"
#include "modular_citadel\code\modules\client\client_procs.dm"
-#include "modular_citadel\code\modules\client\preferences.dm"
#include "modular_citadel\code\modules\client\preferences_savefile.dm"
#include "modular_citadel\code\modules\client\preferences_toggles.dm"
#include "modular_citadel\code\modules\client\loadout\__donator.dm"
@@ -3410,5 +3427,4 @@
#include "modular_citadel\code\modules\reagents\objects\clothes.dm"
#include "modular_citadel\code\modules\reagents\objects\items.dm"
#include "modular_citadel\code\modules\reagents\reagents\cit_reagents.dm"
-#include "modular_citadel\interface\skin.dmf"
// END_INCLUDE
diff --git a/tgui-next/packages/tgui/interfaces/Canvas.js b/tgui-next/packages/tgui/interfaces/Canvas.js
new file mode 100644
index 0000000000..0955aedc3b
--- /dev/null
+++ b/tgui-next/packages/tgui/interfaces/Canvas.js
@@ -0,0 +1,90 @@
+import { Fragment } from 'inferno';
+import { useBackend } from '../backend';
+import { Box } from '../components';
+import { Component, createRef } from 'inferno';
+import { pureComponentHooks } from 'common/react';
+
+
+class PaintCanvas extends Component {
+ constructor(props) {
+ super(props);
+ this.canvasRef = createRef();
+ this.onCVClick = props.onCanvasClick;
+ }
+
+ componentDidMount() {
+ this.drawCanvas(this.props);
+ }
+
+ componentDidUpdate() {
+ this.drawCanvas(this.props);
+ }
+
+ drawCanvas(propSource) {
+ const ctx = this.canvasRef.current.getContext("2d");
+ const grid = propSource.value;
+ const x_size = grid.length;
+ if (!x_size) {
+ return;
+ }
+ const y_size = grid[0].length;
+ const x_scale = Math.round(this.canvasRef.current.width / x_size);
+ const y_scale = Math.round(this.canvasRef.current.height / y_size);
+ ctx.save();
+ ctx.scale(x_scale, y_scale);
+ for (let x = 0; x < grid.length; x++) {
+ const element = grid[x];
+ for (let y = 0; y < element.length; y++) {
+ const color = element[y];
+ ctx.fillStyle = color;
+ ctx.fillRect(x, y, 1, 1);
+ }
+ }
+ ctx.restore();
+ }
+
+ clickwrapper(event) {
+ const x_size = this.props.value.length;
+ if (!x_size)
+ {
+ return;
+ }
+ const y_size = this.props.value[0].length;
+ const x_scale = this.canvasRef.current.width / x_size;
+ const y_scale = this.canvasRef.current.height / y_size;
+ const x = Math.floor(event.offsetX / x_scale)+1;
+ const y = Math.floor(event.offsetY / y_scale)+1;
+ this.onCVClick(x, y);
+ }
+
+ render() {
+ const {
+ res = 1,
+ value,
+ px_per_unit = 28,
+ ...rest
+ } = this.props;
+ const x_size = value.length * px_per_unit;
+ const y_size = x_size !== 0 ? value[0].length * px_per_unit : 0;
+ return (
+
+ );
+ }
+}
+export const Canvas = props => {
+ const { act, data } = useBackend(props);
+ return (
+
+ act("paint", { x, y })} />
+ {data.name}
+ );
+};