diff --git a/aurorastation.dme b/aurorastation.dme
index 4aa198007ed..31f9ed09f43 100644
--- a/aurorastation.dme
+++ b/aurorastation.dme
@@ -167,6 +167,7 @@
#include "code\controllers\subsystems\lighting.dm"
#include "code\controllers\subsystems\machinery.dm"
#include "code\controllers\subsystems\mob.dm"
+#include "code\controllers\subsystems\mob_ai.dm"
#include "code\controllers\subsystems\night_lighting.dm"
#include "code\controllers\subsystems\openturf.dm"
#include "code\controllers\subsystems\orbit.dm"
diff --git a/code/__defines/subsystem-defines.dm b/code/__defines/subsystem-defines.dm
index d7b72ed06ac..3f7ade85b33 100644
--- a/code/__defines/subsystem-defines.dm
+++ b/code/__defines/subsystem-defines.dm
@@ -90,3 +90,8 @@
// -- SSicon_cache --
#define LIGHT_FIXTURE_CACHE(icon,state,color) SSicon_cache.light_fixture_cache["[icon]_[state]_[color]"] || (SSicon_cache.light_fixture_cache["[icon]_[state]_[color]"] = SSicon_cache.generate_color_variant(icon,state,color))
+
+
+// -- SSmob_ai --
+#define MOB_START_THINKING(mob) if (!mob.thinking_enabled) { SSmob_ai.processing += mob; mob.on_think_enabled(); mob.thinking_enabled = TRUE; }
+#define MOB_STOP_THINKING(mob) SSmob_ai.processing -= mob; mob.on_think_disabled(); mob.thinking_enabled = FALSE;
diff --git a/code/_helpers/lists.dm b/code/_helpers/lists.dm
index f9fb8680235..12c75b33e31 100644
--- a/code/_helpers/lists.dm
+++ b/code/_helpers/lists.dm
@@ -318,6 +318,12 @@
if(typecache_include[A.type] && !typecache_exclude[A.type])
. += A
+/proc/range_in_typecache(dist, center, list/typecache)
+ for (var/thing in range(dist, center))
+ var/atom/A = thing
+ if (typecache[A.type])
+ return TRUE
+
/proc/typecache_first_match(list/target, list/typecache)
for (var/thing in target)
var/datum/D = thing
diff --git a/code/controllers/subsystems/mob.dm b/code/controllers/subsystems/mob.dm
index 53d99ad16d7..5110482edfe 100644
--- a/code/controllers/subsystems/mob.dm
+++ b/code/controllers/subsystems/mob.dm
@@ -1,7 +1,7 @@
/var/datum/controller/subsystem/mobs/SSmob
/datum/controller/subsystem/mobs
- name = "Mobs"
+ name = "Mobs - Life"
flags = SS_NO_INIT
priority = SS_PRIORITY_MOB
diff --git a/code/controllers/subsystems/mob_ai.dm b/code/controllers/subsystems/mob_ai.dm
new file mode 100644
index 00000000000..d381ff63668
--- /dev/null
+++ b/code/controllers/subsystems/mob_ai.dm
@@ -0,0 +1,66 @@
+/var/datum/controller/subsystem/mob_ai/SSmob_ai
+
+/datum/controller/subsystem/mob_ai
+ name = "Mobs - AI"
+ flags = SS_NO_INIT
+ priority = SS_PRIORITY_MOB
+
+ var/list/processing = list()
+ var/list/currentrun = list()
+ var/list/slept = list()
+
+/datum/controller/subsystem/mob_ai/New()
+ NEW_SS_GLOBAL(SSmob_ai)
+
+/datum/controller/subsystem/mob_ai/stat_entry()
+ ..("P:[processing.len]")
+
+/datum/controller/subsystem/mob_ai/fire(resumed = FALSE)
+ if (!resumed)
+ src.currentrun = processing.Copy()
+
+ var/list/currentrun = src.currentrun
+ while (currentrun.len)
+ var/mob/M = currentrun[currentrun.len]
+ currentrun.len--
+
+ if (QDELETED(M))
+ processing -= M
+
+ if (MC_TICK_CHECK)
+ return
+ continue
+
+ if (M.ckey)
+ // cliented mobs are not allowed to think
+ log_debug("SSmob_ai: Type '[M.type]' was still thinking despite having a client!")
+ MOB_STOP_THINKING(M)
+
+ if (MC_TICK_CHECK)
+ return
+ continue
+
+ var/time = world.time
+
+ if (!M.frozen && !M.stat)
+ M.think()
+
+ if (time != world.time && !slept[M.type])
+ slept[M.type] = TRUE
+ var/diff = world.time - time
+ log_debug("SSmob_ai: Type '[M.type]' slept for [diff] ds in think()! Suppressing further warnings.")
+
+ if (MC_TICK_CHECK)
+ return
+
+/mob
+ var/tmp/thinking_enabled = FALSE
+
+/mob/proc/think()
+ return
+
+/mob/proc/on_think_disabled()
+ walk_to(src, 0)
+
+/mob/proc/on_think_enabled()
+ return
diff --git a/code/controllers/subsystems/statistics.dm b/code/controllers/subsystems/statistics.dm
index d70a4885321..290a24e0947 100644
--- a/code/controllers/subsystems/statistics.dm
+++ b/code/controllers/subsystems/statistics.dm
@@ -25,13 +25,12 @@
var/list/datum/feedback_variable/feedback = list()
+ var/status_needs_update = FALSE
+
/datum/controller/subsystem/statistics/New()
NEW_SS_GLOBAL(SSfeedback)
/datum/controller/subsystem/statistics/Initialize(timeofday)
- if (!config.kick_inactive && !(config.sql_enabled && config.sql_stats))
- can_fire = FALSE
-
for (var/type in subtypesof(/datum/statistic) - list(/datum/statistic/numeric, /datum/statistic/grouped))
var/datum/statistic/S = new type
if (!S.name)
@@ -70,6 +69,14 @@
var/err = query.ErrorMsg()
log_game("SQL ERROR during population polling. Error : \[[err]\]\n")
+ if (status_needs_update)
+ // Update world status.
+ world.update_status()
+ status_needs_update = FALSE
+
+/datum/controller/subsystem/statistics/proc/update_status()
+ status_needs_update = TRUE
+
/datum/controller/subsystem/statistics/Recover()
src.messages = SSfeedback.messages
src.messages_admin = SSfeedback.messages_admin
diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm
index 0f3f46c77da..c4d50061e9c 100644
--- a/code/modules/mob/dead/observer/observer.dm
+++ b/code/modules/mob/dead/observer/observer.dm
@@ -38,6 +38,8 @@ var/global/list/image/ghost_sightless_images = list() //this is a list of images
var/obj/item/device/multitool/ghost_multitool
incorporeal_move = 1
+ mob_thinks = FALSE
+
/mob/dead/observer/New(mob/body)
if (istype(body, /mob/dead/observer))
return//A ghost can't become a ghost.
diff --git a/code/modules/mob/dview.dm b/code/modules/mob/dview.dm
index d65aa461a57..33c677e2b48 100644
--- a/code/modules/mob/dview.dm
+++ b/code/modules/mob/dview.dm
@@ -11,6 +11,7 @@ var/mob/dview/dview_mob = new
simulated = 0
see_in_dark = 1e6
+ mob_thinks = FALSE
/mob/dview/New()
..()
diff --git a/code/modules/mob/living/bot/cleanbot.dm b/code/modules/mob/living/bot/cleanbot.dm
index 423def2c956..5ecae44b822 100644
--- a/code/modules/mob/living/bot/cleanbot.dm
+++ b/code/modules/mob/living/bot/cleanbot.dm
@@ -90,9 +90,11 @@ var/list/cleanbot_types // Going to use this to generate a list of types once th
return 1
return
+/mob/living/bot/cleanbot/proc/remove_from_ignore(path)
+ ignorelist -= path
+
/mob/living/bot/cleanbot/Life()
..()
-
if(!on)
ignorelist = list()
return
@@ -117,16 +119,21 @@ var/list/cleanbot_types // Going to use this to generate a list of types once th
visible_message("Something flies out of [src]. He seems to be acting oddly.")
var/obj/effect/decal/cleanable/blood/gibs/gib = new /obj/effect/decal/cleanable/blood/gibs(loc)
ignorelist += gib
- spawn(600)
- ignorelist -= gib
+ addtimer(CALLBACK(src, .proc/remove_from_ignore, gib), 600)
+/mob/living/bot/cleanbot/think()
+ ..()
+ if (!on)
+ return
if(pulledby) // Don't wiggle if someone pulls you
- patrol_path = list()
+ patrol_path.Cut()
return
var/found_spot
- if(!should_patrol) return
+ if(!should_patrol)
+ return
+
// This loop will progressively search outwards for /cleanables in view(), gradually to prevent excessively large view() calls when none are needed.
search_for: // We use the label so we can break out of this loop from within the next loop.
// Not breaking out of these loops properly is where the infinite loop was coming from before.
@@ -154,7 +161,6 @@ var/list/cleanbot_types // Going to use this to generate a list of types once th
D.clean_marked = null
-
if(!found_spot && !target) // No targets in range
if(!patrol_path || !patrol_path.len)
if(!signal_sent || signal_sent > world.time + 200) // Waited enough or didn't send yet
@@ -188,8 +194,6 @@ var/list/cleanbot_types // Going to use this to generate a list of types once th
if(moved)
patrol_path -= patrol_path[1]
-
-
/mob/living/bot/cleanbot/UnarmedAttack(var/obj/effect/decal/cleanable/D, var/proximity)
if(!..())
return
diff --git a/code/modules/mob/living/bot/farmbot.dm b/code/modules/mob/living/bot/farmbot.dm
index 6120398a646..c434b05c989 100644
--- a/code/modules/mob/living/bot/farmbot.dm
+++ b/code/modules/mob/living/bot/farmbot.dm
@@ -125,11 +125,12 @@
/mob/living/bot/farmbot/Life()
..()
- if(!on)
- return
if(emagged && prob(1))
flick("farmbot_broke", src)
- if(client)
+
+/mob/living/bot/farmbot/think()
+ ..()
+ if(!on)
return
if(target)
diff --git a/code/modules/mob/living/bot/floorbot.dm b/code/modules/mob/living/bot/floorbot.dm
index 6fdc875f9fd..127a1066dec 100644
--- a/code/modules/mob/living/bot/floorbot.dm
+++ b/code/modules/mob/living/bot/floorbot.dm
@@ -106,7 +106,6 @@
/mob/living/bot/floorbot/Life()
..()
-
if(!on)
return
@@ -115,17 +114,13 @@
tilemake = 0
addTiles(1)
- if(client)
- return
-
if(prob(5))
custom_emote(2, "makes an excited booping beeping sound!")
- if(ignorelist.len) // Don't stick forever
- for(var/T in ignorelist)
- if(prob(1))
- ignorelist -= T
-
+/mob/living/bot/floorbot/think()
+ ..()
+ if (!on)
+ return
if(amount && !emagged)
if(!target && targetdirection) // Building a bridge
var/turf/T = get_step(src, targetdirection)
@@ -137,7 +132,7 @@
if(!target) // Fixing floors
for(var/turf/T in view(src))
- if(T.loc.name == "Space")
+ if (istype(T.loc, /area/space))
continue
if(T in ignorelist)
continue
@@ -151,7 +146,7 @@
if(emagged) // Time to griff
for(var/turf/simulated/floor/D in view(src))
- if(D.loc.name == "Space")
+ if (istype(D.loc, /area/space))
continue
if(D in ignorelist)
continue
@@ -187,6 +182,17 @@
step_to(src, path[1])
path -= path[1]
+ if(ignorelist.len) // Don't stick forever
+ for(var/T in ignorelist)
+ if(prob(1))
+ ignorelist -= T
+
+/mob/living/bot/floorbot/on_think_disabled()
+ ..()
+ ignorelist.Cut()
+ path.Cut()
+ target = null
+
/mob/living/bot/floorbot/UnarmedAttack(var/atom/A, var/proximity)
if(!..())
return
diff --git a/code/modules/mob/living/bot/medbot.dm b/code/modules/mob/living/bot/medbot.dm
index 86a9895dd8c..47f2798aaf1 100644
--- a/code/modules/mob/living/bot/medbot.dm
+++ b/code/modules/mob/living/bot/medbot.dm
@@ -34,47 +34,44 @@
QDEL_NULL(reagent_glass)
return ..()
-/mob/living/bot/medbot/Life()
+/mob/living/bot/medbot/think()
..()
-
if(!on)
return
- if(!client)
+ if(vocal && prob(1))
+ var/message = pick("Radar, put a mask on!", "There's always a catch, and it's the best there is.", "I knew it, I should've been a plastic surgeon.", "What kind of medbay is this? Everyone's dropping like dead flies.", "Delicious!")
+ say(message)
- if(vocal && prob(1))
- var/message = pick("Radar, put a mask on!", "There's always a catch, and it's the best there is.", "I knew it, I should've been a plastic surgeon.", "What kind of medbay is this? Everyone's dropping like dead flies.", "Delicious!")
- say(message)
-
- if(patient)
- if(Adjacent(patient))
- if(!currently_healing)
- INVOKE_ASYNC(src, .proc/UnarmedAttack, patient)
- else
- if(path.len && (get_dist(patient, path[path.len]) > 2)) // We have a path, but it's off
- path = list()
- if(!path.len && (get_dist(src, patient) > 1))
- spawn(0)
- path = AStar(loc, get_turf(patient), /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance, 0, 30, id = botcard)
- if(!path)
- path = list()
- if(path.len)
- step_to(src, path[1])
- path -= path[1]
- ++frustration
- if(get_dist(src, patient) > 7 || frustration > 8)
- patient = null
+ if(patient)
+ if(Adjacent(patient))
+ if(!currently_healing)
+ INVOKE_ASYNC(src, .proc/UnarmedAttack, patient)
else
- for(var/mob/living/carbon/human/H in view(7, src)) // Time to find a patient!
- if(valid_healing_target(H))
- patient = H
- frustration = 0
- if(last_newpatient_speak + 300 < world.time)
- var/message = pick("Hey, [H.name]! Hold on, I'm coming.", "Wait [H.name]! I want to help!", "[H.name], you appear to be injured!")
- say(message)
- custom_emote(1, "points at [H.name].")
- last_newpatient_speak = world.time
- break
+ if(path.len && (get_dist(patient, path[path.len]) > 2)) // We have a path, but it's off
+ path = list()
+ if(!path.len && (get_dist(src, patient) > 1))
+ spawn(0)
+ path = AStar(loc, get_turf(patient), /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance, 0, 30, id = botcard)
+ if(!path)
+ path = list()
+ if(path.len)
+ step_to(src, path[1])
+ path -= path[1]
+ ++frustration
+ if(get_dist(src, patient) > 7 || frustration > 8)
+ patient = null
+ else
+ for(var/mob/living/carbon/human/H in view(7, src)) // Time to find a patient!
+ if(valid_healing_target(H))
+ patient = H
+ frustration = 0
+ if(last_newpatient_speak + 300 < world.time)
+ var/message = pick("Hey, [H.name]! Hold on, I'm coming.", "Wait [H.name]! I want to help!", "[H.name], you appear to be injured!")
+ say(message)
+ custom_emote(1, "points at [H.name].")
+ last_newpatient_speak = world.time
+ break
/mob/living/bot/medbot/UnarmedAttack(var/mob/living/carbon/human/H, var/proximity)
if(!..())
diff --git a/code/modules/mob/living/bot/secbot.dm b/code/modules/mob/living/bot/secbot.dm
index b74d1b5a5d6..7837078f06f 100644
--- a/code/modules/mob/living/bot/secbot.dm
+++ b/code/modules/mob/living/bot/secbot.dm
@@ -40,8 +40,21 @@
var/nearest_beacon // Tag of the beakon that we assume to be the closest one
var/bot_version = 1.4
- var/list/threat_found_sounds = new('sound/voice/bcriminal.ogg', 'sound/voice/bjustice.ogg', 'sound/voice/bfreeze.ogg')
- var/list/preparing_arrest_sounds = new('sound/voice/bgod.ogg', 'sound/voice/biamthelaw.ogg', 'sound/voice/bsecureday.ogg', 'sound/voice/bradio.ogg', 'sound/voice/binsult.ogg', 'sound/voice/bcreep.ogg')
+ var/list/threat_found_sounds = list(
+ 'sound/voice/bcriminal.ogg',
+ 'sound/voice/bjustice.ogg',
+ 'sound/voice/bfreeze.ogg'
+ )
+ var/list/preparing_arrest_sounds = list(
+ 'sound/voice/bgod.ogg',
+ 'sound/voice/biamthelaw.ogg',
+ 'sound/voice/bsecureday.ogg',
+ 'sound/voice/bradio.ogg',
+ 'sound/voice/binsult.ogg',
+ 'sound/voice/bcreep.ogg'
+ )
+
+ var/datum/callback/patrol_callback // this is here so we don't constantly recreate this datum, it being identical each time.
/mob/living/bot/secbot/beepsky
name = "Officer Beepsky"
@@ -56,6 +69,9 @@
if(SSradio)
SSradio.add_object(listener, control_freq, filter = RADIO_SECBOT)
SSradio.add_object(listener, beacon_freq, filter = RADIO_NAVBEACONS)
+
+ if (!patrol_callback)
+ patrol_callback = CALLBACK(src, .proc/patrol_step)
/mob/living/bot/secbot/Destroy()
QDEL_NULL(listener)
@@ -145,14 +161,12 @@
awaiting_surrender = 5
mode = SECBOT_HUNT
-/mob/living/bot/secbot/Life()
+/mob/living/bot/secbot/think()
..()
if(!on)
return
- if(client)
- return
- if(!target)
+ if(QDELETED(target))
scan_view()
if(!locked && (mode == SECBOT_START_PATROL || mode == SECBOT_PATROL)) // Stop running away when we set you up
@@ -189,12 +203,10 @@
RangedAttack(target)
else
step_towards(src, target) // Melee bots chase a bit faster
- spawn(8)
- if(!Adjacent(target))
- step_towards(src, target)
- spawn(16)
- if(!Adjacent(target))
- step_towards(src, target)
+
+ var/cb = CALLBACK(src, .proc/step_nonadjacent, target)
+ addtimer(cb, 8)
+ addtimer(cb, 16)
if(SECBOT_ARREST) // Target is next to us - attack it
if(!target)
@@ -253,18 +265,19 @@
if(SECBOT_PATROL)
patrol_step()
- spawn(10)
- patrol_step()
+ addtimer(patrol_callback, 10)
return
if(SECBOT_SUMMON)
patrol_step()
- spawn(8)
- patrol_step()
- spawn(16)
- patrol_step()
+ addtimer(patrol_callback, 8)
+ addtimer(patrol_callback, 16)
return
+/mob/living/bot/secbot/proc/step_nonadjacent(target)
+ if (!Adjacent(target))
+ step_towards(src, target)
+
/mob/living/bot/secbot/UnarmedAttack(var/mob/M, var/proximity)
if(!..())
return
@@ -287,9 +300,7 @@
do_attack_animation(C)
is_attacking = 1
update_icons()
- spawn(2)
- is_attacking = 0
- update_icons()
+ addtimer(CALLBACK(src, .proc/stop_attacking_cb), 2)
visible_message("[C] was prodded by [src] with a stun baton!")
else
playsound(loc, 'sound/weapons/handcuffs.ogg', 30, 1, -2)
@@ -308,11 +319,13 @@
playsound(loc, "swing_hit", 50, 1, -1)
is_attacking = 1
update_icons()
- spawn(2)
- is_attacking = 0
- update_icons()
+ addtimer(CALLBACK(src, .proc/stop_attacking_cb), 2)
visible_message("[M] was beaten by [src] with a stun baton!")
+/mob/living/bot/secbot/proc/stop_attacking_cb()
+ is_attacking = FALSE
+ update_icons()
+
/mob/living/bot/secbot/explode()
visible_message("[src] blows apart!")
var/turf/Tsec = get_turf(src)
@@ -332,6 +345,7 @@
qdel(src)
/mob/living/bot/secbot/proc/scan_view()
+ target = null
for(var/mob/living/M in view(7, src))
if(M.invisibility >= INVISIBILITY_LEVEL_ONE)
continue
diff --git a/code/modules/mob/living/carbon/alien/diona/life.dm b/code/modules/mob/living/carbon/alien/diona/life.dm
index 4a7ec297929..9cae23c109d 100644
--- a/code/modules/mob/living/carbon/alien/diona/life.dm
+++ b/code/modules/mob/living/carbon/alien/diona/life.dm
@@ -33,12 +33,13 @@
updatehealth()
check_status_as_organ()
+ if (!gestalt)
+ ..()
+
+/mob/living/carbon/alien/diona/think()
+ ..()
if (!gestalt)
if(master_nymph && !client && master_nymph != src)
walk_to(src,master_nymph,1,movement_delay())
else
walk_to(src,0)
- ..()
-
-
-
diff --git a/code/modules/mob/living/carbon/human/human_species.dm b/code/modules/mob/living/carbon/human/human_species.dm
index 4ae5d4bb40a..42af6f52cf0 100644
--- a/code/modules/mob/living/carbon/human/human_species.dm
+++ b/code/modules/mob/living/carbon/human/human_species.dm
@@ -2,6 +2,9 @@
real_name = "Test Dummy"
status_flags = GODMODE|CANPUSH
+/mob/living/carbon/human/dummy/mannequin
+ mob_thinks = FALSE
+
INITIALIZE_IMMEDIATE(/mob/living/carbon/human/dummy/mannequin)
/mob/living/carbon/human/dummy/mannequin/Initialize()
diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm
index fd28ae6b76e..8f8adfe11fb 100644
--- a/code/modules/mob/living/carbon/human/life.dm
+++ b/code/modules/mob/living/carbon/human/life.dm
@@ -85,9 +85,6 @@
if (is_diona())
diona_handle_light(DS)
- if(!client)
- species.handle_npc(src)
-
handle_stasis_bag()
if(!handle_some_updates())
@@ -101,6 +98,10 @@
if(mind && mind.vampire)
handle_vampire()
+/mob/living/carbon/human/think()
+ ..()
+ species.handle_npc(src)
+
/mob/living/carbon/human/proc/handle_some_updates()
if(life_tick > 5 && timeofdeath && (timeofdeath < 5 || world.time - timeofdeath > 6000)) //We are long dead, or we're junk mobs spawned like the clowns on the clown shuttle
return 0
diff --git a/code/modules/mob/living/carbon/metroid/life.dm b/code/modules/mob/living/carbon/metroid/life.dm
index d4ebc5ff131..81e72c40332 100644
--- a/code/modules/mob/living/carbon/metroid/life.dm
+++ b/code/modules/mob/living/carbon/metroid/life.dm
@@ -12,12 +12,12 @@
if(is_ventcrawling == 0) // Stops sight returning to normal if inside a vent
sight = initial(sight)
- if (!client)
- handle_targets()
- if (!AIproc)
- spawn()
- handle_AI()
- handle_speech_and_mood()
+/mob/living/carbon/slime/think()
+ ..()
+ handle_targets()
+ if (!AIproc)
+ handle_AI()
+ handle_speech_and_mood()
/mob/living/carbon/slime/handle_environment(datum/gas_mixture/environment)
if(!environment)
diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm
index de262786def..fe97d67bcd7 100644
--- a/code/modules/mob/living/silicon/silicon.dm
+++ b/code/modules/mob/living/silicon/silicon.dm
@@ -29,6 +29,8 @@
var/obj/item/weapon/card/id/idcard
var/idcard_type = /obj/item/weapon/card/id/synthetic
+ mob_thinks = FALSE
+
#define SEC_HUD 1 //Security HUD mode
#define MED_HUD 2 //Medical HUD mode
@@ -384,4 +386,4 @@
if (!underdoor)
spawn(3)//A slight delay to let us finish walking out from under the door
- layer = initial(layer)
\ No newline at end of file
+ layer = initial(layer)
diff --git a/code/modules/mob/living/simple_animal/bees.dm b/code/modules/mob/living/simple_animal/bees.dm
index b2a8abe0c77..e8b04f296cd 100644
--- a/code/modules/mob/living/simple_animal/bees.dm
+++ b/code/modules/mob/living/simple_animal/bees.dm
@@ -67,163 +67,155 @@
..()
- if(stat == CONSCIOUS)
- //if we're strong enough, sting some people
- var/mob/living/carbon/human/M = target_mob
- var/sting_prob = 40 // Bees will always try to sting.
- var/prob_mult = 1
- if(M && M in view(src,1)) // Can I see my target?
- var/obj/item/clothing/worn_suit = M.wear_suit
- var/obj/item/clothing/worn_helmet = M.head
- if(worn_suit) // Are you wearing clothes?
- if ((worn_suit.flags & THICKMATERIAL))
- prob_mult -= 0.7
- else
- prob_mult -= 0.01 * (min(LAZYACCESS(worn_suit.armor, "bio"), 70)) // Is it sealed? I can't get to 70% of your body.
- if(worn_helmet)
- if ((worn_helmet.flags & THICKMATERIAL))
- prob_mult -= 0.3
- else
- prob_mult -= 0.01 *(min(LAZYACCESS(worn_helmet.armor, "bio"), 30))// Is your helmet sealed? I can't get to 30% of your body.
- if( prob(sting_prob*prob_mult) && (M.stat == CONSCIOUS || (M.stat == UNCONSCIOUS && prob(25*prob_mult))) ) // Try to sting! If you're not moving, think about stinging.
- M.apply_damage(min(strength*0.85,2)+mut, BURN, sharp=1) // Stinging. The more mutated I am, the harder I sting.
- M.apply_damage(max(strength*0.2,(round(feral/10,1)*(max((round(strength/20,1)),1)))+toxic), TOX) // Bee venom based on how angry I am and how many there are of me!
- M << "You have been stung!"
- M.flash_pain()
+
+/mob/living/simple_animal/bee/think()
+ ..()
+ if (stat != CONSCIOUS)
+ return
+
+ //if we're strong enough, sting some people
+ var/mob/living/carbon/human/M = target_mob
+ var/sting_prob = 40 // Bees will always try to sting.
+ var/prob_mult = 1
+ if(M && M in view(src,1)) // Can I see my target?
+ var/obj/item/clothing/worn_suit = M.wear_suit
+ var/obj/item/clothing/worn_helmet = M.head
+ if(worn_suit) // Are you wearing clothes?
+ if ((worn_suit.flags & THICKMATERIAL))
+ prob_mult -= 0.7
+ else
+ prob_mult -= 0.01 * (min(LAZYACCESS(worn_suit.armor, "bio"), 70)) // Is it sealed? I can't get to 70% of your body.
+ if(worn_helmet)
+ if ((worn_helmet.flags & THICKMATERIAL))
+ prob_mult -= 0.3
+ else
+ prob_mult -= 0.01 *(min(LAZYACCESS(worn_helmet.armor, "bio"), 30))// Is your helmet sealed? I can't get to 30% of your body.
+ if( prob(sting_prob*prob_mult) && (M.stat == CONSCIOUS || (M.stat == UNCONSCIOUS && prob(25*prob_mult))) ) // Try to sting! If you're not moving, think about stinging.
+ M.apply_damage(min(strength*0.85,2)+mut, BURN, sharp=1) // Stinging. The more mutated I am, the harder I sting.
+ M.apply_damage(max(strength*0.2,(round(feral/10,1)*(max((round(strength/20,1)),1)))+toxic), TOX) // Bee venom based on how angry I am and how many there are of me!
+ M << "You have been stung!"
+ M.flash_pain()
- //calm down a little bit
- if(feral > 0 && !target_mob)
- if(prob(feral * 20))
- feral -= 1
- else
- //if feral is less than 0, we're becalmed by smoke or steam
- if(feral < 0)
- feral += 1
+ //calm down a little bit
+ if(feral > 0 && !target_mob)
+ if(prob(feral * 20))
+ feral -= 1
+ else
+ //if feral is less than 0, we're becalmed by smoke or steam
+ if(feral < 0)
+ feral += 1
+
+ if(target_mob)
+ target_mob = null
+ target_turf = null
+ if(strength > 5)
+ //calm down and spread out a little
+ var/mob/living/simple_animal/bee/B = new(get_turf(src))
+ B.strength = rand(1,5)
+ src.strength -= B.strength
+ update_icons()
+ B.update_icons()
+ if(src.parent)
+ B.parent = src.parent
+ src.parent.owned_bee_swarms.Add(B)
+
+ //make some noise
+ if(prob(3))
+ src.visible_message("[pick("Buzzzz.","Hmmmmm.","Bzzz.")]")
+ playsound(src.loc, pick('sound/effects/Buzz1.ogg','sound/effects/Buzz2.ogg'), 15, 1,-4)
+
+ if (feral && isturf(loc))
+ //smoke, water and steam calms us down
+ var/static/list/calmers = typecacheof(list(
+ /obj/effect/effect/smoke,
+ /obj/effect/effect/water,
+ /obj/effect/effect/foam,
+ /obj/effect/effect/steam,
+ /obj/effect/mist
+ ))
+
+ if(range_in_typecache(src, 2, calmers))
+ if(feral > 0)
+ src.visible_message("The bees calm down!")
+ feral = -15
+ target_mob = null
+ target_turf = null
+ wander = 1
+
+ for(var/mob/living/simple_animal/bee/B in src.loc)
+ if(B == src)
+ continue
+
+ if(feral > 0)
+ src.strength += B.strength
+ B.strength = 0
+ B.update_icons()
+ update_icons()
+
+ else if(prob(10))
+ //make the other swarm of bees stronger, then move away
+ var/total_bees = B.strength + src.strength
+ if(total_bees < 10)
+ B.strength = min(5, total_bees)
+ src.strength = total_bees - B.strength
- if(target_mob)
- target_mob = null
- target_turf = null
- if(strength > 5)
- //calm down and spread out a little
- var/mob/living/simple_animal/bee/B = new(get_turf(src))
- B.strength = rand(1,5)
- src.strength -= B.strength
update_icons()
B.update_icons()
- if(src.parent)
- B.parent = src.parent
- src.parent.owned_bee_swarms.Add(B)
-
- //make some noise
- if(prob(3))
- src.visible_message("[pick("Buzzzz.","Hmmmmm.","Bzzz.")]")
- playsound(src.loc, pick('sound/effects/Buzz1.ogg','sound/effects/Buzz2.ogg'), 15, 1,-4)
-
- var/calming = 0
- if (feral && istype(loc, /turf))
- //smoke, water and steam calms us down
-
- var/list/calmers = list(/obj/effect/effect/smoke, \
- /obj/effect/effect/water, \
- /obj/effect/effect/foam, \
- /obj/effect/effect/steam, \
- /obj/effect/mist)
-
- for(var/obj/effect/E in range(src, 2))//Check in 1-tile range because these effects often have 3x3 sprites
- for (var/e in calmers)
- if(istype(E, e))
- calming = 1
- break
- if (calming)
- break
-
- if(calming)
- if(feral > 0)
- src.visible_message("The bees calm down!")
- feral = -15
- target_mob = null
- target_turf = null
- wander = 1
-
- for(var/mob/living/simple_animal/bee/B in src.loc)
- if(B == src)
- continue
-
- if(feral > 0)
-
- src.strength += B.strength
- B.strength = 0
- B.update_icons()
- update_icons()
-
- else if(prob(10))
- //make the other swarm of bees stronger, then move away
- var/total_bees = B.strength + src.strength
- if(total_bees < 10)
- B.strength = min(5, total_bees)
- src.strength = total_bees - B.strength
-
- update_icons()
- B.update_icons()
- if(src.strength <= 0)
- qdel(src)
- return
- var/turf/simulated/floor/T = get_turf(get_step(src, pick(1,2,4,8)))
- density = 1
- if(T.Enter(src, get_turf(src)))
- src.loc = T
- density = 0
- break
+ if(src.strength <= 0)
+ qdel(src)
+ return
+ var/turf/simulated/floor/T = get_step(src, pick(1,2,4,8))
+ density = 1
+ Move(T)
+ density = 0
+ break
- if(target_mob)//If we have a target
- if(target_mob in view(src,7))//Check that we can still see them
- target_turf = get_turf(target_mob)//If so, update the location
- wander = 0
- else//Otherwise, if our target is out of view, we clear them so we can pick a new one in the next step
- target_mob = null
- target_turf = null
- wander = 1
+ if(target_mob)//If we have a target
+ if(target_mob in view(src,7))//Check that we can still see them
+ target_turf = get_turf(target_mob)//If so, update the location
+ wander = 0
+ else//Otherwise, if our target is out of view, we clear them so we can pick a new one in the next step
+ target_mob = null
+ target_turf = null
+ wander = 1
- //If we're angry but have no target, lets search for one
- if (!target_mob && feral)
- for(var/mob/living/carbon/G in view(src,7))
- target_mob = G
- break
+ //If we're angry but have no target, lets search for one
+ if (!target_mob && feral)
+ for(var/mob/living/carbon/G in view(src,7))
+ target_mob = G
+ break
- //if we're chasing someone, get a little bit angry
- if(target_mob && prob(5))
- feral++
-
- if(target_turf)
- if (!(DirBlocked(get_step(src, get_dir(src,target_turf)),get_dir(src,target_turf)))) // Check for windows and doors!
- Move(get_step(src, get_dir(src,target_turf)))
- if (prob(10))
- src.visible_message("The bees swarm after [target_mob]!")
- if(src.loc == target_turf)
- target_turf = null
- wander = 1
- else
- //find some flowers, harvest
- //angry bee swarms don't hang around
- if(feral > 0)
- turns_per_move = rand(1,3)
- else if(feral < 0)
- turns_since_move = 0
- else if(!my_hydrotray || my_hydrotray.loc != src.loc || my_hydrotray.dead || !my_hydrotray.seed)
- var/obj/machinery/portable_atmospherics/hydroponics/my_hydrotray = locate() in src.loc
- if(my_hydrotray)
- if(!my_hydrotray.dead && my_hydrotray.seed)
- turns_per_move = rand(20,50)
- else
- my_hydrotray = null
-
- pixel_x = rand(-12,12)
- pixel_y = rand(-12,12)
+ //if we're chasing someone, get a little bit angry
+ if(target_mob && prob(5))
+ feral++
+ if(target_turf)
+ if (!(DirBlocked(get_step(src, get_dir(src,target_turf)),get_dir(src,target_turf)))) // Check for windows and doors!
+ Move(get_step(src, get_dir(src,target_turf)))
+ if (prob(10))
+ src.visible_message("The bees swarm after [target_mob]!")
+ if(src.loc == target_turf)
+ target_turf = null
+ wander = 1
+ else
+ //find some flowers, harvest
+ //angry bee swarms don't hang around
+ if(feral > 0)
+ turns_per_move = rand(1,3)
+ else if(feral < 0)
+ turns_since_move = 0
+ else if(!my_hydrotray || my_hydrotray.loc != src.loc || my_hydrotray.dead || !my_hydrotray.seed)
+ var/obj/machinery/portable_atmospherics/hydroponics/my_hydrotray = locate() in src.loc
+ if(my_hydrotray)
+ if(!my_hydrotray.dead && my_hydrotray.seed)
+ turns_per_move = rand(20,50)
+ else
+ my_hydrotray = null
+ animate(src, pixel_x = rand(-12, 12), pixel_y = rand(-12, 12), time = 0.5)
/mob/living/simple_animal/bee/update_icons()
@@ -234,8 +226,7 @@
//Kill it with fire!
/mob/living/simple_animal/bee/adjustFireLoss(damage)
- damage *= 2
- ..()
+ ..(damage * 2)
//No more grabbing bee swarms
diff --git a/code/modules/mob/living/simple_animal/constructs/constructs.dm b/code/modules/mob/living/simple_animal/constructs/constructs.dm
index e6b5949f1a1..f7550eca204 100644
--- a/code/modules/mob/living/simple_animal/constructs/constructs.dm
+++ b/code/modules/mob/living/simple_animal/constructs/constructs.dm
@@ -40,6 +40,8 @@
var/list/construct_spells = list()
var/can_repair = 0
+ var/health_prefix = ""
+
/mob/living/simple_animal/construct/cultify()
return
@@ -114,6 +116,7 @@
icon_living = "behemoth"
maxHealth = 400
health = 400
+ health_prefix = "juggernaut"
response_harm = "harmlessly punches"
harm_intent_damage = 0
melee_damage_lower = 30
@@ -165,6 +168,7 @@
icon_living = "floating"
maxHealth = 75
health = 75
+ health_prefix = "wraith"
melee_damage_lower = 25
melee_damage_upper = 25
attacktext = "slashed"
@@ -196,6 +200,7 @@
icon_living = "artificer"
maxHealth = 50
health = 50
+ health_prefix = "artificer"
response_harm = "viciously beaten"
harm_intent_damage = 5
melee_damage_lower = 5
@@ -225,6 +230,7 @@
icon_living = "behemoth"
maxHealth = 750
health = 750
+ health_prefix = "juggernaut"
speak_emote = list("rumbles")
response_harm = "harmlessly punched"
harm_intent_damage = 0
@@ -252,6 +258,7 @@
icon_living = "harvester"
maxHealth = 150
health = 150
+ health_prefix = "harvester"
melee_damage_lower = 25
melee_damage_upper = 25
attacktext = "violently stabbed"
@@ -297,84 +304,44 @@
/mob/living/simple_animal/construct/Life()
. = ..()
if(.)
+ var/newstate
if(fire)
- if(fire_alert) fire.icon_state = "fire1"
- else fire.icon_state = "fire0"
+ newstate = fire_alert ? "fire1" : "fire0"
+ if (fire.icon_state != newstate)
+ fire.icon_state = newstate
+
if(pullin)
- if(pulling) pullin.icon_state = "pull1"
- else pullin.icon_state = "pull0"
+ newstate = pulling ? "pull1" : "pull0"
+ if (pullin.icon_state != newstate)
+ pullin.icon_state = newstate
if(purged)
- if(purge > 0) purged.icon_state = "purge1"
- else purged.icon_state = "purge0"
+ newstate = purge > 0 ? "purge1" : "purge0"
+ if (purged.icon_state != newstate)
+ purged.icon_state = newstate
silence_spells(purge)
-/mob/living/simple_animal/construct/armoured/Life()
- ..()
- if(healths)
- switch(health)
- if(250 to INFINITY) healths.icon_state = "juggernaut_health0"
- if(208 to 249) healths.icon_state = "juggernaut_health1"
- if(167 to 207) healths.icon_state = "juggernaut_health2"
- if(125 to 166) healths.icon_state = "juggernaut_health3"
- if(84 to 124) healths.icon_state = "juggernaut_health4"
- if(42 to 83) healths.icon_state = "juggernaut_health5"
- if(1 to 41) healths.icon_state = "juggernaut_health6"
- else healths.icon_state = "juggernaut_health7"
-
-
-/mob/living/simple_animal/construct/behemoth/Life()
- ..()
- if(healths)
- switch(health)
- if(750 to INFINITY) healths.icon_state = "juggernaut_health0"
- if(625 to 749) healths.icon_state = "juggernaut_health1"
- if(500 to 624) healths.icon_state = "juggernaut_health2"
- if(375 to 499) healths.icon_state = "juggernaut_health3"
- if(250 to 374) healths.icon_state = "juggernaut_health4"
- if(125 to 249) healths.icon_state = "juggernaut_health5"
- if(1 to 124) healths.icon_state = "juggernaut_health6"
- else healths.icon_state = "juggernaut_health7"
-
-/mob/living/simple_animal/construct/builder/Life()
- ..()
- if(healths)
- switch(health)
- if(50 to INFINITY) healths.icon_state = "artificer_health0"
- if(42 to 49) healths.icon_state = "artificer_health1"
- if(34 to 41) healths.icon_state = "artificer_health2"
- if(26 to 33) healths.icon_state = "artificer_health3"
- if(18 to 25) healths.icon_state = "artificer_health4"
- if(10 to 17) healths.icon_state = "artificer_health5"
- if(1 to 9) healths.icon_state = "artificer_health6"
- else healths.icon_state = "artificer_health7"
-
-
-
-/mob/living/simple_animal/construct/wraith/Life()
- ..()
- if(healths)
- switch(health)
- if(75 to INFINITY) healths.icon_state = "wraith_health0"
- if(62 to 74) healths.icon_state = "wraith_health1"
- if(50 to 61) healths.icon_state = "wraith_health2"
- if(37 to 49) healths.icon_state = "wraith_health3"
- if(25 to 36) healths.icon_state = "wraith_health4"
- if(12 to 24) healths.icon_state = "wraith_health5"
- if(1 to 11) healths.icon_state = "wraith_health6"
- else healths.icon_state = "wraith_health7"
-
-
-/mob/living/simple_animal/construct/harvester/Life()
- ..()
- if(healths)
- switch(health)
- if(150 to INFINITY) healths.icon_state = "harvester_health0"
- if(125 to 149) healths.icon_state = "harvester_health1"
- if(100 to 124) healths.icon_state = "harvester_health2"
- if(75 to 99) healths.icon_state = "harvester_health3"
- if(50 to 74) healths.icon_state = "harvester_health4"
- if(25 to 49) healths.icon_state = "harvester_health5"
- if(1 to 24) healths.icon_state = "harvester_health6"
- else healths.icon_state = "harvester_health7"
+ if (healths)
+ var/health_percent = (health/maxHealth)*100
+ var/newstate = 0
+ switch (health_percent)
+ if (84 to INFINITY)
+ newstate = 0
+ if (70 to 84)
+ newstate = 1
+ if (56 to 70)
+ newstate = 2
+ if (42 to 56)
+ newstate = 3
+ if (28 to 42)
+ newstate = 4
+ if (14 to 28)
+ newstate = 5
+ if (1 to 14)
+ newstate = 6
+ else
+ newstate = 7
+ newstate = "[health_prefix][newstate]"
+ if (healths.icon_state != newstate)
+ healths.icon_state = newstate
diff --git a/code/modules/mob/living/simple_animal/friendly/cat.dm b/code/modules/mob/living/simple_animal/friendly/cat.dm
index 938d7470b35..7f9010aa7d5 100644
--- a/code/modules/mob/living/simple_animal/friendly/cat.dm
+++ b/code/modules/mob/living/simple_animal/friendly/cat.dm
@@ -34,22 +34,22 @@
pass_flags = PASSTABLE
possession_candidate = 1
-/mob/living/simple_animal/cat/Life()
+/mob/living/simple_animal/cat/think()
//MICE!
-
-
..()
-
if (!stat)
for(var/mob/living/simple_animal/mouse/snack in oview(src,7))
if(snack.stat != DEAD && prob(65))//The probability allows her to not get stuck target the first mouse, reducing exploits
mousetarget = snack
movement_target = snack
- foodtarget = 0//chasing mice takes precedence over eating food
+ foodtarget = 0 //chasing mice takes precedence over eating food
if(prob(15))
audible_emote(pick("hisses and spits!","mrowls fiercely!","eyes [snack] hungrily."))
+
+ addtimer(CALLBACK(src, .proc/attack_mice), 2)
break
+
if(!buckled)
if (turns_since_move > 5 || (flee_target || mousetarget))
walk_to(src,0)
@@ -63,8 +63,6 @@
if (!movement_target)
walk_to(src,0)
- addtimer(CALLBACK(src, .proc/attack_mice), 2)
-
if(prob(2)) //spooky
var/mob/dead/observer/spook = locate() in range(src,5)
if(spook)
@@ -89,7 +87,7 @@
if(movement_target)
stop_automated_movement = 1
- walk_to(src,movement_target,0,seek_move_delay)
+ walk_to(src, movement_target, 0, DS2TICKS(seek_move_delay))
/mob/living/simple_animal/cat/proc/attack_mice()
if((src.loc) && isturf(src.loc))
@@ -183,7 +181,7 @@
//walk to friend
stop_automated_movement = 1
movement_target = friend
- walk_to(src, movement_target, near_dist, seek_move_delay)
+ walk_to(src, movement_target, near_dist, DS2TICKS(seek_move_delay))
//already following and close enough, stop
else if (current_dist <= near_dist)
@@ -196,7 +194,7 @@
if (!friend || movement_target != friend)
..()
-/mob/living/simple_animal/cat/fluff/Life()
+/mob/living/simple_animal/cat/fluff/think()
..()
if (stat || QDELETED(friend))
return
diff --git a/code/modules/mob/living/simple_animal/friendly/corgi.dm b/code/modules/mob/living/simple_animal/friendly/corgi.dm
index b110b499434..efc6c4141f7 100644
--- a/code/modules/mob/living/simple_animal/friendly/corgi.dm
+++ b/code/modules/mob/living/simple_animal/friendly/corgi.dm
@@ -45,7 +45,7 @@
response_disarm = "bops"
response_harm = "kicks"
-/mob/living/simple_animal/corgi/Ian/Life()
+/mob/living/simple_animal/corgi/Ian/think()
..()
if(!stat && !resting && !buckled)
@@ -68,14 +68,16 @@
/mob/living/simple_animal/corgi/attackby(var/obj/item/O as obj, var/mob/user as mob) //Marker -Agouri
if(istype(O, /obj/item/weapon/newspaper))
if(!stat)
- for(var/mob/M in viewers(user, null))
- if ((M.client && !( M.blinded )))
- M.show_message("[user] baps [name] on the nose with the rolled up [O]")
- scan_interval = max_scan_interval//discipline your dog to make it stop stealing food for a while
- movement_target = null
- foodtarget = 0
- stop_automated_movement = 0
- turns_since_scan = 0
+ visible_message(
+ "[user] baps [src] on the nose with the rolled up [O.name].",
+ "[user] baps you on the nose with the rolled up [O.name]!"
+ )
+ scan_interval = max_scan_interval
+ movement_target = null
+ foodtarget = 0
+ stop_automated_movement = 0
+ turns_since_scan = 0
+
INVOKE_ASYNC(src, .proc/do_dance, list(1,2,4,8,4,2,1,2))
else
..()
@@ -138,9 +140,8 @@
return
..()
-/mob/living/simple_animal/corgi/Lisa/Life()
+/mob/living/simple_animal/corgi/Lisa/think()
..()
-
if(!stat && !resting && !buckled)
turns_since_scan++
if(turns_since_scan > 15)
@@ -161,8 +162,8 @@
if(near_camera(src) || near_camera(ian))
return
new /mob/living/simple_animal/corgi/puppy(loc)
+ puppies++
-
- if(prob(1))
- visible_emote(pick("dances around","chases her tail"),0)
- INVOKE_ASYNC(src, .proc/do_dance, list(1,2,4,8,4,2,1,2,4,8,4,2,1,2,4,8,4,2))
+ if (!stat && !resting && !buckled && prob(1))
+ visible_emote(pick("dances around","chases her tail"),0)
+ INVOKE_ASYNC(src, .proc/do_dance, list(1,2,4,8,4,2,1,2,4,8,4,2,1,2,4,8,4,2))
diff --git a/code/modules/mob/living/simple_animal/friendly/crab.dm b/code/modules/mob/living/simple_animal/friendly/crab.dm
index 6f8fa4fae97..40ba2617567 100644
--- a/code/modules/mob/living/simple_animal/friendly/crab.dm
+++ b/code/modules/mob/living/simple_animal/friendly/crab.dm
@@ -23,7 +23,7 @@
var/obj/item/inventory_mask
possession_candidate = 1
-/mob/living/simple_animal/crab/Life()
+/mob/living/simple_animal/crab/think()
..()
//CRAB movement
if(!ckey && !stat)
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 1cdaccd168d..2a0a9a9be5a 100644
--- a/code/modules/mob/living/simple_animal/friendly/farm_animals.dm
+++ b/code/modules/mob/living/simple_animal/friendly/farm_animals.dm
@@ -36,15 +36,6 @@
/mob/living/simple_animal/hostile/retaliate/goat/Life()
. = ..()
if(.)
- //chance to go crazy and start wacking stuff
- if(!enemies.len && prob(1))
- Retaliate()
-
- if(enemies.len && prob(10))
- enemies = list()
- LoseTarget()
- src.visible_message("[src] calms down.")
-
if(stat == CONSCIOUS)
if(udder && prob(5))
udder.add_reagent("milk", rand(5, 10))
@@ -57,12 +48,22 @@
var/obj/machinery/portable_atmospherics/hydroponics/soil/invisible/SP = locate() in loc
qdel(SP)
- if(!pulledby)
- var/obj/effect/plant/food
- food = locate(/obj/effect/plant) in oview(5,loc)
- if(food)
- var/step = get_step_to(src, food, 0)
- Move(step)
+/mob/living/simple_animal/hostile/retaliate/goat/think()
+ ..()
+ //chance to go crazy and start wacking stuff
+ if(!enemies.len && prob(1))
+ Retaliate()
+
+ if(enemies.len && prob(10))
+ enemies = list()
+ LoseTarget()
+ src.visible_message("[src] calms down.")
+
+ if(!pulledby)
+ var/obj/effect/plant/food = locate(/obj/effect/plant) in oview(5,loc)
+ if(food)
+ var/step = get_step_to(src, food, 0)
+ Move(step)
/mob/living/simple_animal/hostile/retaliate/goat/Retaliate()
..()
diff --git a/code/modules/mob/living/simple_animal/friendly/lizard.dm b/code/modules/mob/living/simple_animal/friendly/lizard.dm
index 89820d7733b..f39d7f37e5d 100644
--- a/code/modules/mob/living/simple_animal/friendly/lizard.dm
+++ b/code/modules/mob/living/simple_animal/friendly/lizard.dm
@@ -40,7 +40,7 @@
..()
/mob/living/simple_animal/lizard/death()
- .=..()
+ . = ..()
desc = "It doesn't hiss anymore."
/mob/living/simple_animal/lizard/dust()
diff --git a/code/modules/mob/living/simple_animal/friendly/mouse.dm b/code/modules/mob/living/simple_animal/friendly/mouse.dm
index 5920fd567bf..70ac73b1799 100644
--- a/code/modules/mob/living/simple_animal/friendly/mouse.dm
+++ b/code/modules/mob/living/simple_animal/friendly/mouse.dm
@@ -89,11 +89,15 @@
/mob/living/simple_animal/mouse/Move()
if(..())
if (prob(50))
- pixel_x += rand(-2,2)
- pixel_x = Clamp(pixel_x, -10, 10)
+ var/new_pixelx = pixel_x
+ new_pixelx += rand(-2,2)
+ new_pixelx = Clamp(new_pixelx, -10, 10)
+ animate(src, pixel_x = new_pixelx, time = 0.5)
else
- pixel_y += rand(-2,2)
- pixel_y = Clamp(pixel_y, -4, 14)
+ var/new_pixely = pixel_y
+ new_pixely += rand(-2,2)
+ new_pixely = Clamp(new_pixely, -4, 14)
+ animate(src, pixel_y = new_pixely, time = 0.5)
/mob/living/simple_animal/mouse/Initialize()
. = ..()
diff --git a/code/modules/mob/living/simple_animal/hostile/bear.dm b/code/modules/mob/living/simple_animal/hostile/bear.dm
index 1c0125e68b5..ba78b3dae7e 100644
--- a/code/modules/mob/living/simple_animal/hostile/bear.dm
+++ b/code/modules/mob/living/simple_animal/hostile/bear.dm
@@ -91,7 +91,7 @@
if (stance != previous)
stance_step = 0
-/mob/living/simple_animal/hostile/bear/Life()
+/mob/living/simple_animal/hostile/bear/think()
. =..()
safety = 0
if (stat != CONSCIOUS)
@@ -100,7 +100,6 @@
if (life_tick % 5 == 0)
update_bearmode()
-
//This covers cases where the bear is damaged by things it can't detect.
//Most notably, security bots, beepsky kept murdering them without resistance
if (health < health_last_tick && stance != HOSTILE_STANCE_TIRED)
@@ -111,7 +110,6 @@
anger = max(0, anger-1)
switch(stance)
-
if(HOSTILE_STANCE_TIRED)
stop_automated_movement = 1
stance_step++
@@ -145,9 +143,6 @@
else
stance_step--
-
-
-
if (anger && found_mob)
instant_aggro()//If we're angry and someone is nearby, skip waiting and charge them
@@ -166,7 +161,6 @@
tire_out()
return
-
//If we're having no luck attacking our current target
if (target_mob && !Adjacent(target_mob) && turns_since_hit > 3)
LoseTarget()
@@ -175,7 +169,6 @@
health_last_tick = health
-
//Causes the bear to find and start attacking the nearest target.
//This will overwrite any existing target if a different one is closer
//If there are no other suitable targets, targeting will not be changed
@@ -461,7 +454,7 @@
else if (forcechange)
MoveToTarget()
-/mob/living/simple_animal/hostile/bear/spatial/Life()
+/mob/living/simple_animal/hostile/bear/spatial/think()
..()
if (stat != CONSCIOUS)
return
@@ -482,7 +475,6 @@
if (focus_time % tactical_delay == 0)
teleport_tactical(target_mob)
-
//Teleport away from other bears
for (var/mob/living/simple_animal/hostile/bear/bear in view(world.view, get_turf(src)))
if (bear != src && bear.stat != DEAD)
diff --git a/code/modules/mob/living/simple_animal/hostile/commanded/commanded.dm b/code/modules/mob/living/simple_animal/hostile/commanded/commanded.dm
index 055f46ab865..5aab4a5e0a7 100644
--- a/code/modules/mob/living/simple_animal/hostile/commanded/commanded.dm
+++ b/code/modules/mob/living/simple_animal/hostile/commanded/commanded.dm
@@ -11,18 +11,18 @@
var/retribution = 1 //whether or not they will attack us if we attack them like some kinda dick.
/mob/living/simple_animal/hostile/commanded/hear_say(var/message, var/verb = "says", var/datum/language/language = null, var/alt_name = "", var/italics = 0, var/mob/speaker = null, var/sound/speech_sound, var/sound_vol)
- if((speaker in friends) || speaker == master)
+ if(thinking_enabled && !stat && ((speaker in friends) || speaker == master))
command_buffer.Add(speaker)
command_buffer.Add(lowertext(html_decode(message)))
return 0
/mob/living/simple_animal/hostile/commanded/hear_radio(var/message, var/verb="says", var/datum/language/language=null, var/part_a, var/part_b, var/part_c, var/mob/speaker = null, var/hard_to_hear = 0)
- if((speaker in friends) || speaker == master)
+ if(thinking_enabled && !stat && ((speaker in friends) || speaker == master))
command_buffer.Add(speaker)
command_buffer.Add(lowertext(html_decode(message)))
return 0
-/mob/living/simple_animal/hostile/commanded/Life()
+/mob/living/simple_animal/hostile/commanded/think()
while(command_buffer.len > 0)
var/mob/speaker = command_buffer[1]
var/text = command_buffer[2]
@@ -31,15 +31,16 @@
var/substring = copytext(text,length(filtered_name)+1) //get rid of the name.
listen(speaker,substring)
command_buffer.Remove(command_buffer[1],command_buffer[2])
- . = ..()
- if(.)
- switch(stance)
- if(COMMANDED_FOLLOW)
- follow_target()
- if(COMMANDED_STOP)
- commanded_stop()
-
+ ..()
+ switch(stance)
+ if(COMMANDED_FOLLOW)
+ follow_target()
+ if(COMMANDED_STOP)
+ commanded_stop()
+/mob/living/simple_animal/hostile/commanded/on_think_disabled()
+ ..()
+ command_buffer.Cut()
/mob/living/simple_animal/hostile/commanded/FindTarget(var/new_stance = HOSTILE_STANCE_ATTACK)
if(!allowed_targets.len)
@@ -197,4 +198,4 @@
allowed_targets += M
stance = HOSTILE_STANCE_ATTACK
if(M in friends)
- friends -= M
\ No newline at end of file
+ friends -= M
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 04388607531..e049a44b4d9 100644
--- a/code/modules/mob/living/simple_animal/hostile/giant_spider.dm
+++ b/code/modules/mob/living/simple_animal/hostile/giant_spider.dm
@@ -89,7 +89,7 @@
O.implants += eggs
H << "The [src] injects something into your [O.name]!"
-/mob/living/simple_animal/hostile/giant_spider/Life()
+/mob/living/simple_animal/hostile/giant_spider/think()
..()
if(!stat)
if(stance == HOSTILE_STANCE_IDLE)
@@ -106,15 +106,14 @@
stop_automated_movement = 0
walk(src, 0)
-/mob/living/simple_animal/hostile/giant_spider/nurse/Life()
+/mob/living/simple_animal/hostile/giant_spider/nurse/think()
..()
if(!stat)
if(stance == HOSTILE_STANCE_IDLE)
- var/list/can_see = view(src, 10)
//30% chance to stop wandering and do something
if(!busy && prob(30))
//first, check for potential food nearby to cocoon
- for(var/mob/living/C in can_see)
+ for(var/mob/living/C in view(src, world.view))
if(C.stat)
cocoon_target = C
busy = MOVING_TO_TARGET
@@ -140,8 +139,7 @@
addtimer(CALLBACK(src, .proc/finalize_eggs), 50, TIMER_UNIQUE)
else
//fourthly, cocoon any nearby items so those pesky pinkskins can't use them
- for(var/obj/O in can_see)
-
+ for(var/obj/O in view(src, world.view))
if(O.anchored)
continue
diff --git a/code/modules/mob/living/simple_animal/hostile/hostile.dm b/code/modules/mob/living/simple_animal/hostile/hostile.dm
index 01c52fe893e..3e52189ac3c 100644
--- a/code/modules/mob/living/simple_animal/hostile/hostile.dm
+++ b/code/modules/mob/living/simple_animal/hostile/hostile.dm
@@ -149,28 +149,20 @@
..()
walk(src, 0)
-/mob/living/simple_animal/hostile/Life()
+/mob/living/simple_animal/hostile/think()
+ ..()
+ switch(stance)
+ if(HOSTILE_STANCE_IDLE)
+ target_mob = FindTarget()
- . = ..()
- if(!.)
- walk(src, 0)
- return 0
- if(client)
- return 0
+ if(HOSTILE_STANCE_ATTACK)
+ if(destroy_surroundings)
+ DestroySurroundings()
+ MoveToTarget()
- if(!stat)
- switch(stance)
- if(HOSTILE_STANCE_IDLE)
- target_mob = FindTarget()
-
- if(HOSTILE_STANCE_ATTACK)
- if(destroy_surroundings)
- DestroySurroundings()
- MoveToTarget()
-
- if(HOSTILE_STANCE_ATTACKING)
- if(!AttackTarget() && destroy_surroundings)//hit a window OR a mob, not both at once
- DestroySurroundings()
+ if(HOSTILE_STANCE_ATTACKING)
+ if(!AttackTarget() && destroy_surroundings) //hit a window OR a mob, not both at once
+ DestroySurroundings()
/mob/living/simple_animal/hostile/proc/OpenFire(target_mob)
@@ -186,7 +178,7 @@
else
Shoot(target, src.loc, src)
if(casingtype)
- new casingtype
+ new casingtype(loc)
stance = HOSTILE_STANCE_IDLE
target_mob = null
diff --git a/code/modules/mob/living/simple_animal/parrot.dm b/code/modules/mob/living/simple_animal/parrot.dm
index 76c162985fd..36fbf7647e6 100644
--- a/code/modules/mob/living/simple_animal/parrot.dm
+++ b/code/modules/mob/living/simple_animal/parrot.dm
@@ -266,9 +266,8 @@
/*
* AI - Not really intelligent, but I'm calling it AI anyway.
*/
-/mob/living/simple_animal/parrot/Life()
+/mob/living/simple_animal/parrot/think()
..()
-
//Sprite and AI update for when a parrot gets pulled
if(pulledby && stat == CONSCIOUS)
icon_state = "parrot_fly"
diff --git a/code/modules/mob/living/simple_animal/shade.dm b/code/modules/mob/living/simple_animal/shade.dm
index a5f4c71a489..e8f9d02acb5 100644
--- a/code/modules/mob/living/simple_animal/shade.dm
+++ b/code/modules/mob/living/simple_animal/shade.dm
@@ -32,9 +32,10 @@
/mob/living/simple_animal/shade/cultify()
return
-/mob/living/simple_animal/shade/Life()
- ..()
- OnDeathInLife()
+/mob/living/simple_animal/shade/death()
+ visible_message("[src] lets out a contented sigh as their form unwinds.")
+ new /obj/item/weapon/ectoplasm(loc)
+ . = ..()
/mob/living/simple_animal/shade/attackby(var/obj/item/O as obj, var/mob/user as mob) //Marker -Agouri
if(istype(O, /obj/item/device/soulstone))
@@ -42,16 +43,6 @@
S.transfer_soul("SHADE", src, user)
return
-/mob/living/simple_animal/shade/proc/OnDeathInLife()
- if(stat == 2)
- new /obj/item/weapon/ectoplasm (src.loc)
- for(var/mob/M in viewers(src, null))
- if((M.client && !( M.blinded )))
- M.show_message("[src] lets out a contented sigh as their form unwinds.")
- ghostize()
- qdel(src)
- return
-
/mob/living/simple_animal/shade/can_fall()
return FALSE
diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm
index 0783e6cdf3a..165bc94903e 100644
--- a/code/modules/mob/living/simple_animal/simple_animal.dm
+++ b/code/modules/mob/living/simple_animal/simple_animal.dm
@@ -107,7 +107,7 @@
/mob/living/simple_animal/Initialize()
. = ..()
- seek_move_delay = (1 / seek_speed) / (world.tick_lag / 10)//number of ticks between moves
+ seek_move_delay = (1 / seek_speed) * 10 //number of ds between moves
turns_since_scan = rand(min_scan_interval, max_scan_interval)//Randomise this at the start so animals don't sync up
health = maxHealth
verbs -= /mob/verb/observe
@@ -177,102 +177,37 @@
handle_supernatural()
process_food()
- handle_foodscanning()
//Movement
turns_since_move++
- if (!client)
- if(!stop_automated_movement && wander && !anchored)
- if(isturf(src.loc) && !resting && !buckled && canmove) //This is so it only moves if it's not inside a closet, gentics machine, etc.
-
- if(turns_since_move >= turns_per_move)
- if(!(stop_automated_movement_when_pulled && pulledby)) //Soma animals don't move when pulled
- var/moving_to = 0 // otherwise it always picks 4, fuck if I know. Did I mention fuck BYOND
- moving_to = pick(cardinal)
- dir = moving_to //How about we turn them the direction they are moving, yay.
- Move(get_step(src,moving_to))
- turns_since_move = 0
-
- //Speaking
- if(speak_chance)
- if(rand(0,200) < speak_chance)
- if(speak && speak.len)
- if((emote_hear && emote_hear.len) || (emote_see && emote_see.len))
- var/length = speak.len
- if(emote_hear && emote_hear.len)
- length += emote_hear.len
- if(emote_see && emote_see.len)
- length += emote_see.len
- var/randomValue = rand(1,length)
- if(randomValue <= speak.len)
- say(pick(speak))
- else
- randomValue -= speak.len
- if(emote_see && randomValue <= emote_see.len)
- visible_emote("[pick(emote_see)].",0)
- else
- audible_emote("[pick(emote_hear)].",0)
- else
- say(pick(speak))
- else
- if(!(emote_hear && emote_hear.len) && (emote_see && emote_see.len))
- visible_emote("[pick(emote_see)].",0)
- if((emote_hear && emote_hear.len) && !(emote_see && emote_see.len))
- audible_emote("[pick(emote_hear)].",0)
- if((emote_hear && emote_hear.len) && (emote_see && emote_see.len))
- var/length = emote_hear.len + emote_see.len
- var/pick = rand(1,length)
- if(pick <= emote_see.len)
- visible_emote("[pick(emote_see)].",0)
- else
- audible_emote("[pick(emote_hear)].",0)
- speak_audio()
-
- if (can_nap)
- if (!resting && prob(1))
- fall_asleep()
- else if (resting && (prob(0.5) || !stat))
- wake_up()
-
//Atmos
var/atmos_suitable = 1
- var/atom/A = src.loc
-
- if(istype(A,/turf))
- var/turf/T = A
+ if(isturf(loc))
+ var/turf/T = loc
var/datum/gas_mixture/Environment = T.return_air()
if(Environment)
-
- if( abs(Environment.temperature - bodytemperature) > 40 )
+ if (abs(Environment.temperature - bodytemperature) > 40)
bodytemperature += ((Environment.temperature - bodytemperature) / 5)
- if(min_oxy)
- if(Environment.gas["oxygen"] < min_oxy)
- atmos_suitable = 0
- if(max_oxy)
- if(Environment.gas["oxygen"] > max_oxy)
- atmos_suitable = 0
- if(min_tox)
- if(Environment.gas["phoron"] < min_tox)
- atmos_suitable = 0
- if(max_tox)
- if(Environment.gas["phoron"] > max_tox)
- atmos_suitable = 0
- if(min_n2)
- if(Environment.gas["nitrogen"] < min_n2)
- atmos_suitable = 0
- if(max_n2)
- if(Environment.gas["nitrogen"] > max_n2)
- atmos_suitable = 0
- if(min_co2)
- if(Environment.gas["carbon_dioxide"] < min_co2)
- atmos_suitable = 0
- if(max_co2)
- if(Environment.gas["carbon_dioxide"] > max_co2)
- atmos_suitable = 0
+ if(min_oxy && Environment.gas["oxygen"] < min_oxy)
+ atmos_suitable = 0
+ else if(max_oxy && Environment.gas["oxygen"] > max_oxy)
+ atmos_suitable = 0
+ else if(min_tox && Environment.gas["phoron"] < min_tox)
+ atmos_suitable = 0
+ else if(max_tox && Environment.gas["phoron"] > max_tox)
+ atmos_suitable = 0
+ else if(min_n2 && Environment.gas["nitrogen"] < min_n2)
+ atmos_suitable = 0
+ else if(max_n2 && Environment.gas["nitrogen"] > max_n2)
+ atmos_suitable = 0
+ else if(min_co2 && Environment.gas["carbon_dioxide"] < min_co2)
+ atmos_suitable = 0
+ else if(max_co2 && Environment.gas["carbon_dioxide"] > max_co2)
+ atmos_suitable = 0
//Atmos effect
if(bodytemperature < minbodytemp)
@@ -288,12 +223,64 @@
apply_damage(unsuitable_atoms_damage, OXY, used_weapon = "Atmosphere")
return 1
+/mob/living/simple_animal/think()
+ ..()
+ handle_foodscanning()
+ if(!stop_automated_movement && wander && !anchored)
+ if(isturf(loc) && !resting && !buckled && canmove) //This is so it only moves if it's not inside a closet, gentics machine, etc.
+ if(turns_since_move >= turns_per_move && !(stop_automated_movement_when_pulled && pulledby)) //Some animals don't move when pulled
+ var/moving_to = 0 // otherwise it always picks 4, fuck if I know. Did I mention fuck BYOND
+ moving_to = pick(cardinal)
+ set_dir(moving_to) //How about we turn them the direction they are moving, yay.
+ Move(get_step(src,moving_to))
+ turns_since_move = 0
+
+ //Speaking
+ if(speak_chance && rand(0,200) < speak_chance)
+ if(LAZYLEN(speak))
+ if(LAZYLEN(emote_hear) || LAZYLEN(emote_see))
+ var/length = speak.len
+ if(emote_hear && emote_hear.len)
+ length += emote_hear.len
+ if(emote_see && emote_see.len)
+ length += emote_see.len
+ var/randomValue = rand(1,length)
+ if(randomValue <= speak.len)
+ say(pick(speak))
+ else
+ randomValue -= speak.len
+ if(emote_see && randomValue <= emote_see.len)
+ visible_emote("[pick(emote_see)].",0)
+ else
+ audible_emote("[pick(emote_hear)].",0)
+ else
+ say(pick(speak))
+ else
+ if(!(emote_hear && emote_hear.len) && (emote_see && emote_see.len))
+ visible_emote("[pick(emote_see)].",0)
+ if((emote_hear && emote_hear.len) && !(emote_see && emote_see.len))
+ audible_emote("[pick(emote_hear)].",0)
+ if((emote_hear && emote_hear.len) && (emote_see && emote_see.len))
+ var/length = emote_hear.len + emote_see.len
+ var/pick = rand(1,length)
+ if(pick <= emote_see.len)
+ visible_emote("[pick(emote_see)].",0)
+ else
+ audible_emote("[pick(emote_hear)].",0)
+ speak_audio()
+
+ if (can_nap)
+ if (resting)
+ if (prob(1))
+ fall_asleep()
+ else
+ if (!stat || prob(0.5))
+ wake_up()
+
/mob/living/simple_animal/proc/handle_supernatural()
if(purge)
purge -= 1
-
-
//Simple reagent processing for simple animals
//This allows animals to digest food, and only food
//Most drugs, poisons etc, are designed to work on carbons and affect many values a simple animal doesnt have
@@ -337,7 +324,7 @@
else return 2//hungry
/mob/living/simple_animal/gib()
- ..(icon_gib,1)
+ ..(icon_gib, 1)
/mob/living/simple_animal/emote(var/act, var/type, var/desc)
if(act)
@@ -589,29 +576,18 @@ mob/living/simple_animal/bullet_act(var/obj/item/projectile/Proj)
scan_interval = min_scan_interval
stop_automated_movement = 1
- if (istype(movement_target.loc, /turf))
- walk_to(src,movement_target,0, seek_move_delay)//Stand ontop of food
+ if (isturf(movement_target.loc))
+ walk_to(src, movement_target, 0, DS2TICKS(seek_move_delay)) //Stand ontop of food
else
- walk_to(src,movement_target.loc,1, seek_move_delay)//Don't stand ontop of people
+ walk_to(src, get_turf(movement_target), 1, DS2TICKS(seek_move_delay)) //Don't stand ontop of people
-
-
- if(movement_target) //Not redundant due to sleeps, Item can be gone in 6 decisecomds
- if (movement_target.loc.x < src.x)
- set_dir(WEST)
- else if (movement_target.loc.x > src.x)
- set_dir(EAST)
- else if (movement_target.loc.y < src.y)
- set_dir(SOUTH)
- else if (movement_target.loc.y > src.y)
- set_dir(NORTH)
- else
- set_dir(SOUTH)
+ if (movement_target)
+ set_dir(get_dir(src, movement_target))
if(isturf(movement_target.loc) && Adjacent(get_turf(movement_target), src))
UnarmedAttack(movement_target)
- if (get_turf(movement_target) == src.loc)
- set_dir(pick(1,2,4,8,1,1))//Face a random direction when eating, but mostly upwards
+ if (get_turf(movement_target) == loc)
+ set_dir(pick(NORTH, SOUTH, EAST, WEST, NORTH, NORTH))//Face a random direction when eating, but mostly upwards
else if(ishuman(movement_target.loc) && Adjacent(src, get_turf(movement_target)) && prob(10))
beg(movement_target, movement_target.loc)
else
diff --git a/code/modules/mob/login.dm b/code/modules/mob/login.dm
index f1c3232c6a1..e1420a3b4ea 100644
--- a/code/modules/mob/login.dm
+++ b/code/modules/mob/login.dm
@@ -24,14 +24,14 @@
log_access("Notice: [key_name(src)] has the same [matches] as [key_name(M)] (no longer logged in).",ckey=key_name(src))
/mob/Login()
-
player_list |= src
update_Login_details()
- world.update_status()
+ SSfeedback.update_status()
- client.images = null //remove the images such as AIs being unable to see runes
- client.screen = null //remove hud items just in case
- if(hud_used) qdel(hud_used) //remove the hud objects
+ client.images.Cut() //remove the images such as AIs being unable to see runes
+ client.screen.Cut() //remove hud items just in case
+ if(hud_used)
+ qdel(hud_used) //remove the hud objects
hud_used = new /datum/hud(src)
disconnect_time = null
@@ -48,3 +48,4 @@
//set macro to normal incase it was overriden (like cyborg currently does)
winset(src, null, "mainwindow.macro=macro hotkey_toggle.is-checked=false input.focus=true input.background-color=#D3B5B5")
+ MOB_STOP_THINKING(src)
diff --git a/code/modules/mob/logout.dm b/code/modules/mob/logout.dm
index de0c7c10ca7..1e1e1bd0363 100644
--- a/code/modules/mob/logout.dm
+++ b/code/modules/mob/logout.dm
@@ -3,11 +3,13 @@
player_list -= src
disconnect_time = world.realtime
log_access("Logout: [key_name(src)]",ckey=key_name(src))
+ SSfeedback.update_status()
+
if(admin_datums[src.ckey])
if (SSticker.current_state == GAME_STATE_PLAYING) //Only report this stuff if we are currently playing.
var/admins_number = 0
var/admins_number_afk = 0
- for (var/client/C)
+ for (var/client/C in clients)
if (C.holder && (C.holder.rights & (R_MOD|R_ADMIN)))
admins_number++
if (C.is_afk())
@@ -21,5 +23,8 @@
else if ((admins_number - admins_number_afk) <= 0)
post_webhook_event(WEBHOOK_ADMIN, list("title"="Admin has logged out", "message"="**[key_name(src)]** logged out - only AFK admins _([admins_number_afk])_ are online."))
discord_bot.send_to_admins("[key_name(src)] logged out - only AFK admins ([admins_number_afk]) are online.")
+
+ if (mob_thinks)
+ MOB_START_THINKING(src)
..()
return 1
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index 25414c73651..0d9a391dd66 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -33,6 +33,8 @@
var/atom/movable/AM = src.loc
LAZYREMOVE(AM.contained_mobs, src)
+ MOB_STOP_THINKING(src)
+
return ..()
@@ -61,13 +63,16 @@
spell_masters = null
zone_sel = null
-/mob/New()
+/mob/Initialize()
+ . = ..()
mob_list += src
if(stat == DEAD)
dead_mob_list += src
else
living_mob_list += src
- ..()
+
+ if (!ckey && mob_thinks)
+ MOB_START_THINKING(src)
/mob/proc/show_message(msg, type, alt, alt_type)//Message, type of message (1 or 2), alternative message, alt message type (1 or 2)
diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm
index 2a23b6e9c9f..1724ad29bdf 100644
--- a/code/modules/mob/mob_defines.dm
+++ b/code/modules/mob/mob_defines.dm
@@ -222,3 +222,5 @@
gfi_layer_rotation = GFI_ROTATION_DEFDIR
var/disconnect_time = null//Time of client loss, set by Logout(), for timekeeping
+
+ var/mob_thinks = TRUE
diff --git a/code/modules/spells/spells.dm b/code/modules/spells/spells.dm
index d5a8217f61a..ca3e50bde35 100644
--- a/code/modules/spells/spells.dm
+++ b/code/modules/spells/spells.dm
@@ -3,7 +3,7 @@
/mob/Life()
..()
- if(spell_masters && spell_masters.len)
+ if(LAZYLEN(spell_masters))
for(var/obj/screen/movable/spell_master/spell_master in spell_masters)
spell_master.update_spells(0, src)
diff --git a/code/world.dm b/code/world.dm
index fa9d0adbce6..910e1d9c939 100644
--- a/code/world.dm
+++ b/code/world.dm
@@ -321,7 +321,7 @@ var/list/world_api_rate_limit = list()
D.associate(directory[ckey])
/world/proc/update_status()
- var/s = ""
+ var/list/s = list()
if (config && config.server_name)
s += "[config.server_name] — "
@@ -363,13 +363,14 @@ var/list/world_api_rate_limit = list()
else if (n > 0)
features += "~[n] player"
-
if (config && config.hostedby)
features += "hosted by [config.hostedby]"
if (features)
s += ": [list2text(features, ", ")]"
+ s = s.Join()
+
/* does this help? I do not know */
if (src.status != s)
src.status = s