Mob AI SS & Misc. Mob Cleanup (#3990)

This commit is contained in:
Lohikar
2017-12-24 14:24:55 -06:00
committed by GitHub
parent 071045b28e
commit 6feaf1a218
39 changed files with 589 additions and 547 deletions
+1
View File
@@ -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"
+5
View File
@@ -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;
+6
View File
@@ -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
+1 -1
View File
@@ -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
+66
View File
@@ -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
+10 -3
View File
@@ -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
@@ -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.
+1
View File
@@ -11,6 +11,7 @@ var/mob/dview/dview_mob = new
simulated = 0
see_in_dark = 1e6
mob_thinks = FALSE
/mob/dview/New()
..()
+12 -8
View File
@@ -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
+4 -3
View File
@@ -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)
+17 -11
View File
@@ -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
+32 -35
View File
@@ -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(!..())
+38 -24
View File
@@ -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("<span class='warning'>[C] was prodded by [src] with a stun baton!</span>")
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("<span class='warning'>[M] was beaten by [src] with a stun baton!</span>")
/mob/living/bot/secbot/proc/stop_attacking_cb()
is_attacking = FALSE
update_icons()
/mob/living/bot/secbot/explode()
visible_message("<span class='warning'>[src] blows apart!</span>")
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
@@ -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)
..()
@@ -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()
+4 -3
View File
@@ -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
@@ -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)
+3 -1
View File
@@ -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)
layer = initial(layer)
+138 -147
View File
@@ -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 << "<span class='warning'>You have been stung!</span>"
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 << "<span class='warning'>You have been stung!</span>"
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("<span class='notice'>[pick("Buzzzz.","Hmmmmm.","Bzzz.")]</span>")
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("<span class='notice'>The bees calm down!</span>")
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("<span class='notice'>[pick("Buzzzz.","Hmmmmm.","Bzzz.")]</span>")
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("<span class='notice'>The bees calm down!</span>")
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("<span class='notice'>The bees swarm after [target_mob]!</span>")
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("<span class='notice'>The bees swarm after [target_mob]!</span>")
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
@@ -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
@@ -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
@@ -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("<span class='notice'>[user] baps [name] on the nose with the rolled up [O]</span>")
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(
"<span class='notice'>[user] baps [src] on the nose with the rolled up [O.name].</span>",
"<span class='alert'>[user] baps you on the nose with the rolled up [O.name]!</span>"
)
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))
@@ -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)
@@ -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("<span class='notice'>[src] calms down.</span>")
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("<span class='notice'>[src] calms down.</span>")
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()
..()
@@ -40,7 +40,7 @@
..()
/mob/living/simple_animal/lizard/death()
.=..()
. = ..()
desc = "It doesn't hiss anymore."
/mob/living/simple_animal/lizard/dust()
@@ -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()
. = ..()
@@ -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)
@@ -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
friends -= M
@@ -89,7 +89,7 @@
O.implants += eggs
H << "<span class='warning'>The [src] injects something into your [O.name]!</span>"
/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
@@ -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
@@ -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"
+4 -13
View File
@@ -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("<span class='warning'>[src] lets out a contented sigh as their form unwinds.</span>")
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("<span class='warning'>[src] lets out a contented sigh as their form unwinds.</span>")
ghostize()
qdel(src)
return
/mob/living/simple_animal/shade/can_fall()
return FALSE
@@ -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
+6 -5
View File
@@ -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)
+6 -1
View File
@@ -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
+7 -2
View File
@@ -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)
+2
View File
@@ -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
+1 -1
View File
@@ -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)
+3 -2
View File
@@ -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 += "<b>[config.server_name]</b> &#8212; "
@@ -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 <b>[config.hostedby]</b>"
if (features)
s += ": [list2text(features, ", ")]"
s = s.Join()
/* does this help? I do not know */
if (src.status != s)
src.status = s