Merge pull request #4116 from TheDZD/NOTTHEBEES

It's the Bees!
This commit is contained in:
Fox McCloud
2016-04-14 21:27:01 -04:00
39 changed files with 784 additions and 730 deletions
@@ -1,180 +0,0 @@
/mob/living/simple_animal/bee
name = "bees"
icon = 'icons/obj/apiary_bees_etc.dmi'
icon_state = "bees1"
icon_living = "bees1"
icon_dead = "bees1"
var/strength = 1
var/feral = 0
var/mut = 0
var/toxic = 0
var/turf/target_turf
var/mob/target_mob
var/obj/machinery/apiary/parent
pass_flags = PASSTABLE
turns_per_move = 6
var/obj/machinery/portable_atmospherics/hydroponics/my_hydrotray
// Allow final solutions.
minbodytemp = 0
maxbodytemp = 360
/mob/living/simple_animal/bee/New(loc, var/obj/machinery/apiary/new_parent)
..()
parent = new_parent
/mob/living/simple_animal/bee/Destroy()
if(parent)
parent.owned_bee_swarms.Remove(src)
return ..()
/mob/living/simple_animal/bee/process_ai()
//if we're strong enough, sting some people
var/mob/living/carbon/human/M = target_mob
var/sting_prob = 100 // Bees will always try to sting.
if(M in view(src,1)) // Can I see my target?
if(prob(max(feral * 10, 0))) // Am I mad enough to want to sting? And yes, when I initially appear, I AM mad enough
var/obj/item/clothing/worn_suit = M.wear_suit
var/obj/item/clothing/worn_helmet = M.head
if(worn_suit) // Are you wearing clothes?
sting_prob -= min(worn_suit.armor["bio"],70) // Is it sealed? I can't get to 70% of your body.
if(worn_helmet)
sting_prob -= min(worn_helmet.armor["bio"],30) // Is your helmet sealed? I can't get to 30% of your body.
if( prob(sting_prob) && (M.stat == CONSCIOUS || (M.stat == UNCONSCIOUS && prob(25))) ) // Try to sting! If you're not moving, think about stinging.
M.apply_damage(min(strength,2)+mut, BRUTE, sharp=1) // Stinging. The more mutated I am, the harder I sting.
M.apply_damage((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!
to_chat(M, "\red You have been stung!")
//if we're chasing someone, get a little bit angry
if(target_mob && prob(10))
feral++
//calm down a little bit
if(feral > 0)
if(prob(feral * 10))
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(pick(orange(src,1))))
B.strength = rand(1,5)
src.strength -= B.strength
if(src.strength <= 5)
src.icon_living = "bees[src.strength]"
B.icon_living = "bees[B.strength]"
if(src.parent)
B.parent = src.parent
src.parent.owned_bee_swarms.Add(B)
//make some noise
if(prob(0.5))
src.visible_message("\blue [pick("Buzzzz.","Hmmmmm.","Bzzz.")]")
//smoke, water and steam calms us down
var/calming = 0
var/list/calmers = list(/obj/effect/effect/chem_smoke, \
/obj/effect/effect/water, \
/obj/effect/effect/foam, \
/obj/effect/effect/steam, \
/obj/effect/mist)
for(var/obj/effect/check_effect in src.loc)
if(check_effect.type in calmers)
calming = 1
break
if(calming)
if(feral > 0)
src.visible_message("\blue The bees calm down!")
feral = -10
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
qdel(B)
src.icon_living = "bees[src.strength]"
if(strength > 5)
icon_living = "bees_swarm"
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
B.icon_living = "bees[B.strength]"
if(src.strength <= 0)
qdel(src)
return
src.icon_living = "bees[B.strength]"
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(target_mob)
if(target_mob in view(src,7))
target_turf = get_turf(target_mob)
wander = 0
else // My target's gone! But I might still be pissed! You there. You look like a good stinging target!
for(var/mob/living/carbon/G in view(src,7))
target_mob = G
break
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(0.1))
src.visible_message("\blue 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)
/mob/living/simple_animal/bee/handle_state_icons()
if(!parent && prob(10))
strength -= 1
if(strength <= 0)
qdel(src)
else if(strength <= 5)
icon_living = "bees[strength]"
//debugging
/*icon_living = "[strength]"
if(strength > 5)
icon_living = "unknown"*/
..()
@@ -43,13 +43,12 @@
var/plant_cooldown = 30
var/plants_off = 0
/mob/living/simple_animal/hostile/alien/drone/process_ai()
. = ..()
if(!.)
/mob/living/simple_animal/hostile/alien/drone/handle_automated_action()
if(!..()) //AIStatus is off
return
plant_cooldown--
if(stance==HOSTILE_STANCE_IDLE)
if(AIStatus == AI_IDLE)
if(!plants_off && prob(10) && plant_cooldown<=0)
plant_cooldown = initial(plant_cooldown)
SpreadPlants()
@@ -90,12 +89,12 @@
var/egg_cooldown = 30
var/plant_cooldown = 30
/mob/living/simple_animal/hostile/alien/queen/process_ai()
..()
/mob/living/simple_animal/hostile/alien/queen/handle_automated_action()
if(!..())
return
egg_cooldown--
plant_cooldown--
if(stance==HOSTILE_STANCE_IDLE)
if(AIStatus == AI_IDLE)
if(!plants_off && prob(10) && plant_cooldown<=0)
plant_cooldown = initial(plant_cooldown)
SpreadPlants()
@@ -23,12 +23,12 @@
melee_damage_lower = 20
melee_damage_upper = 30
attacktext = "mauls"
friendly = "bear hugs"
attack_sound = 'sound/weapons/genhit3.ogg'
//Space bears aren't affected by atmos.
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
minbodytemp = 0
var/stance_step = 0
faction = list("russian")
gold_core_spawnable = CHEM_MOB_SPAWN_HOSTILE
@@ -36,10 +36,12 @@
//SPACE BEARS! SQUEEEEEEEE~ OW! FUCK! IT BIT MY HAND OFF!!
/mob/living/simple_animal/hostile/bear/Hudson
name = "Hudson"
desc = ""
response_help = "pets"
response_disarm = "gently pushes aside"
response_harm = "hits"
desc = "Feared outlaw, this guy is one bad news bear." //I'm sorry...
/mob/living/simple_animal/hostile/bear/Hudson/New()
..()
var/unbearable_pun = pick("He's unbearably cute.", "It looks like he is a bearer of bad news.", "Sadly, he is bearly able to comprehend puns.")
desc = "That's Hudson. " + unbearable_pun// I am not sorry for this.
/mob/living/simple_animal/hostile/bear/Move()
..()
@@ -49,121 +51,5 @@
else
icon_state = "bearfloor"
/mob/living/simple_animal/hostile/bear/process_ai()
. = ..()
if(!.)
return
switch(stance)
if(HOSTILE_STANCE_TIRED)
stop_automated_movement = 1
stance_step++
if(stance_step >= 10) //rests for 10 ticks
if(target && target in ListTargets())
stance = HOSTILE_STANCE_ATTACK //If the mob he was chasing is still nearby, resume the attack, otherwise go idle.
else
stance = HOSTILE_STANCE_IDLE
if(HOSTILE_STANCE_ALERT)
stop_automated_movement = 1
var/found_mob = 0
if(target && target in ListTargets())
if(CanAttack(target))
stance_step = max(0, stance_step) //If we have not seen a mob in a while, the stance_step will be negative, we need to reset it to 0 as soon as we see a mob again.
stance_step++
found_mob = 1
src.dir = get_dir(src,target) //Keep staring at the mob
if(stance_step in list(1,4,7)) //every 3 ticks
var/action = pick( list( "growls at [target]", "stares angrily at [target]", "prepares to attack [target]", "closely watches [target]" ) )
if(action)
custom_emote(1, action)
if(!found_mob)
stance_step--
if(stance_step <= -20) //If we have not found a mob for 20-ish ticks, revert to idle mode
stance = HOSTILE_STANCE_IDLE
if(stance_step >= 7) //If we have been staring at a mob for 7 ticks,
stance = HOSTILE_STANCE_ATTACK
if(HOSTILE_STANCE_ATTACKING)
if(stance_step >= 20) //attacks for 20 ticks, then it gets tired and needs to rest
custom_emote(1, "is worn out and needs to rest" )
stance = HOSTILE_STANCE_TIRED
stance_step = 0
walk(src, 0) //This stops the bear's walking
return
/mob/living/simple_animal/hostile/bear/attackby(var/obj/item/O as obj, var/mob/user as mob, params)
if(stance != HOSTILE_STANCE_ATTACK && stance != HOSTILE_STANCE_ATTACKING)
stance = HOSTILE_STANCE_ALERT
stance_step = 6
target = user
..()
/mob/living/simple_animal/hostile/bear/attack_hand(mob/living/carbon/human/M as mob)
if(stance != HOSTILE_STANCE_ATTACK && stance != HOSTILE_STANCE_ATTACKING)
stance = HOSTILE_STANCE_ALERT
stance_step = 6
target = M
..()
/mob/living/simple_animal/hostile/bear/Process_Spacemove(var/movement_dir = 0)
return 1 //No drifting in space for space bears!
/mob/living/simple_animal/hostile/bear/FindTarget()
. = ..()
if(.)
custom_emote(1, "stares alertly at [.]")
stance = HOSTILE_STANCE_ALERT
/mob/living/simple_animal/hostile/bear/LoseTarget()
..(5)
/mob/living/simple_animal/hostile/bear/AttackingTarget()
custom_emote(1, pick( list("slashes at [target]", "bites [target]") ) )
var/damage = rand(20,30)
if(ishuman(target))
var/mob/living/carbon/human/H = target
var/dam_zone = pick("head", "chest", "groin", "l_arm", "l_hand", "r_arm", "r_hand", "l_leg", "l_foot", "r_leg", "r_foot")
var/obj/item/organ/external/affecting = H.get_organ(ran_zone(dam_zone))
H.apply_damage(damage, BRUTE, affecting, H.run_armor_check(affecting, "melee"), sharp=1, edge=1)
return H
else if(isliving(target))
var/mob/living/L = target
L.adjustBruteLoss(damage)
return L
else if(istype(target,/obj/mecha))
var/obj/mecha/M = target
M.attack_animal(src)
return M
@@ -0,0 +1,290 @@
#define BEE_IDLE_ROAMING 70 //The value of idle at which a bee in a beebox will try to wander
#define BEE_IDLE_GOHOME 0 //The value of idle at which a bee will try to go home
#define BEE_PROB_GOHOME 35 //Probability to go home when idle is below BEE_IDLE_GOHOME
#define BEE_PROB_GOROAM 5 //Probability to go roaming when idle is above BEE_IDLE_ROAMING
#define BEE_TRAY_RECENT_VISIT 200 //How long in deciseconds until a tray can be visited by a bee again
#define BEE_DEFAULT_COLOUR "#e5e500" //the colour we make the stripes of the bee if our reagent has no colour (or we have no reagent)
#define BEE_POLLINATE_YIELD_CHANCE 10
#define BEE_POLLINATE_PEST_CHANCE 33
#define BEE_POLLINATE_POTENTCY_CHANCE 50
/mob/living/simple_animal/hostile/poison/bees
name = "bee"
desc = "buzzy buzzy bee, stingy sti- Ouch!"
icon_state = ""
icon_living = ""
icon = 'icons/mob/bees.dmi'
speak_emote = list("buzzes")
emote_hear = list("buzzes")
turns_per_move = 0
melee_damage_lower = 1
melee_damage_upper = 1
attacktext = "stings"
response_help = "shoos"
response_disarm = "swats away"
response_harm = "squashes"
maxHealth = 10
health = 10
faction = list("hostile")
move_to_delay = 0
environment_smash = 0
mouse_opacity = 2
pass_flags = PASSTABLE | PASSGRILLE | PASSMOB
flying = 1
search_objects = 1 //have to find those plant trays!
density = 0
small = 1
//Spaceborn beings don't get hurt by space
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
minbodytemp = 0
var/datum/reagent/beegent = null //hehe, beegent
var/obj/structure/beebox/beehome = null
var/idle = 0
var/isqueen = FALSE
var/icon_base = "bee"
var/static/list/bee_icons = list()
/mob/living/simple_animal/hostile/poison/bees/Process_Spacemove(movement_dir = 0)
return 1
/mob/living/simple_animal/hostile/poison/bees/New()
..()
generate_bee_visuals()
/mob/living/simple_animal/hostile/poison/bees/Destroy()
if(beehome)
beehome.bees.Remove(src)
beehome = null
beegent = null
return ..()
/mob/living/simple_animal/hostile/poison/bees/death(gibbed)
if(beehome)
beehome.bees.Remove(src)
beehome = null
beegent = null
..()
ghostize()
qdel(src)
/mob/living/simple_animal/hostile/poison/bees/examine(mob/user)
..()
if(!beehome)
to_chat(user, "<span class='warning'>This bee is homeless!</span>")
/mob/living/simple_animal/hostile/poison/bees/proc/generate_bee_visuals()
overlays.Cut()
var/col = BEE_DEFAULT_COLOUR
if(beegent && beegent.color)
col = beegent.color
var/image/base
if(!bee_icons["[icon_base]_base"])
bee_icons["[icon_base]_base"] = image(icon = 'icons/mob/bees.dmi', icon_state = "[icon_base]_base")
base = bee_icons["[icon_base]_base"]
overlays += base
var/image/greyscale
if(!bee_icons["[icon_base]_grey_[col]"])
bee_icons["[icon_base]_grey_[col]"] = image(icon = 'icons/mob/bees.dmi', icon_state = "[icon_base]_grey")
greyscale = bee_icons["[icon_base]_grey_[col]"]
greyscale.color = col
overlays += greyscale
var/image/wings
if(!bee_icons["[icon_base]_wings"])
bee_icons["[icon_base]_wings"] = image(icon = 'icons/mob/bees.dmi', icon_state = "[icon_base]_wings")
wings = bee_icons["[icon_base]_wings"]
overlays += wings
//We don't attack beekeepers/people dressed as bees//Todo: bee costume
/mob/living/simple_animal/hostile/poison/bees/CanAttack(atom/the_target)
. = ..()
if(!.)
return 0
if(ishuman(the_target))
var/mob/living/carbon/human/H = the_target
return !H.bee_friendly()
/mob/living/simple_animal/hostile/poison/bees/Found(atom/A)
if(istype(A, /obj/machinery/portable_atmospherics/hydroponics))
var/obj/machinery/portable_atmospherics/hydroponics/Hydro = A
if(Hydro.seed && !Hydro.dead && !Hydro.recent_bee_visit)
wanted_objects |= /obj/machinery/portable_atmospherics/hydroponics //so we only hunt them while they're alive/seeded/not visisted
return 1
if(ishuman(A))
var/mob/living/carbon/human/H = A
return !H.bee_friendly()
return 0
/mob/living/simple_animal/hostile/poison/bees/AttackingTarget()
//Pollinate
if(istype(target, /obj/machinery/portable_atmospherics/hydroponics))
var/obj/machinery/portable_atmospherics/hydroponics/Hydro = target
pollinate(Hydro)
else if(target == beehome)
var/obj/structure/beebox/BB = target
forceMove(BB)
target = null
wanted_objects.Remove(/obj/structure/beebox) //so we don't attack beeboxes when not going home
else
if(beegent && isliving(target))
var/mob/living/L = target
if(!isnull(target.reagents))
beegent.reaction_mob(L, TOUCH)
L.reagents.add_reagent(beegent.id, rand(1,5))
target.attack_animal(src)
/mob/living/simple_animal/hostile/poison/bees/proc/assign_reagent(datum/reagent/R)
if(istype(R))
beegent = R
name = "[initial(name)] ([R.name])"
generate_bee_visuals()
/mob/living/simple_animal/hostile/poison/bees/proc/pollinate(obj/machinery/portable_atmospherics/hydroponics/Hydro)
if(!istype(Hydro) || !Hydro.seed || Hydro.dead || Hydro.recent_bee_visit)
target = null
return
target = null //so we pick a new hydro tray next FindTarget(), instead of loving the same plant for eternity
wanted_objects.Remove(/obj/machinery/portable_atmospherics/hydroponics) //so we only hunt them while they're alive/seeded/not visisted
Hydro.recent_bee_visit = TRUE
spawn(BEE_TRAY_RECENT_VISIT)
if(Hydro)
Hydro.recent_bee_visit = FALSE
var/growth = health //Health also means how many bees are in the swarm, roughly.
//better healthier plants!
Hydro.health += round(growth*0.5)
if(prob(BEE_POLLINATE_PEST_CHANCE))
Hydro.pestlevel = max(0, --Hydro.pestlevel)
if(prob(BEE_POLLINATE_YIELD_CHANCE)) //Yield mod is HELLA powerful, but quite rare
if(!isnull(plant_controller.seeds[Hydro.seed.name]))
Hydro.seed = Hydro.seed.diverge()
var/seed_yield = Hydro.seed.get_trait(TRAIT_YIELD)
Hydro.seed.set_trait(TRAIT_YIELD, seed_yield + 1, 10, 0)
if(prob(BEE_POLLINATE_POTENTCY_CHANCE))
if(!isnull(plant_controller.seeds[Hydro.seed.name]))
Hydro.seed = Hydro.seed.diverge()
var/seed_potency = Hydro.seed.get_trait(TRAIT_POTENCY)
Hydro.seed.set_trait(TRAIT_POTENCY, seed_potency + 1, 200, 0)
if(beehome)
beehome.bee_resources = min(beehome.bee_resources + growth, 100)
/mob/living/simple_animal/hostile/poison/bees/handle_automated_action()
. = ..()
if(!.)
return
if(!isqueen)
if(loc == beehome)
idle = min(100, ++idle)
if(idle >= BEE_IDLE_ROAMING && prob(BEE_PROB_GOROAM))
forceMove(get_turf(beehome))
else
idle = max(0, --idle)
if(idle <= BEE_IDLE_GOHOME && prob(BEE_PROB_GOHOME))
if(!FindTarget())
wanted_objects.Add(/obj/structure/beebox) //so we don't attack beeboxes when not going home
target = beehome
if(!beehome) //add outselves to a beebox (of the same reagent) if we have no home
for(var/obj/structure/beebox/BB in view(vision_range, src))
if(reagent_incompatible(BB.queen_bee) || BB.bees.len >= BB.get_max_bees())
continue
BB.bees |= src
beehome = BB
/mob/living/simple_animal/hostile/poison/bees/queen
name = "queen bee"
desc = "she's the queen of bees, BZZ BZZ"
icon_base = "queen"
isqueen = TRUE
//the Queen doesn't leave the box on her own, and she CERTAINLY doesn't pollinate by herself
/mob/living/simple_animal/hostile/poison/bees/queen/Found(atom/A)
return 0
//leave pollination for the peasent bees
/mob/living/simple_animal/hostile/poison/bees/queen/AttackingTarget()
if(beegent && isliving(target))
var/mob/living/L = target
beegent.reaction_mob(L, TOUCH)
L.reagents.add_reagent(beegent.id, rand(1,5))
target.attack_animal(src)
//PEASENT BEES
/mob/living/simple_animal/hostile/poison/bees/queen/pollinate()
return
/mob/living/simple_animal/hostile/poison/bees/proc/reagent_incompatible(mob/living/simple_animal/hostile/poison/bees/B)
if(!B)
return 0
if(B.beegent && beegent && B.beegent.id != beegent.id || B.beegent && !beegent || !B.beegent && beegent)
return 1
return 0
/obj/item/queen_bee
name = "queen bee"
desc = "she's the queen of bees, BZZ BZZ"
icon_state = "queen_item"
item_state = ""
icon = 'icons/mob/bees.dmi'
var/mob/living/simple_animal/hostile/poison/bees/queen/queen
/obj/item/queen_bee/attackby(obj/item/I, mob/user, params)
if(istype(I,/obj/item/weapon/reagent_containers/syringe))
var/obj/item/weapon/reagent_containers/syringe/S = I
if(S.reagents.has_reagent("royal_bee_jelly")) //checked twice, because I really don't want royal bee jelly to be duped
if(S.reagents.has_reagent("royal_bee_jelly",5))
S.reagents.remove_reagent("royal_bee_jelly", 5)
var/obj/item/queen_bee/qb = new(get_turf(user))
qb.queen = new(qb)
if(queen && queen.beegent)
qb.queen.assign_reagent(queen.beegent) //Bees use the global singleton instances of reagents, so we don't need to worry about one bee being deleted and her copies losing their reagents.
user.put_in_active_hand(qb)
user.visible_message("<span class='notice'>[user] injects [src] with royal bee jelly, causing it to split into two bees, MORE BEES!</span>","<span class ='warning'>You inject [src] with royal bee jelly, causing it to split into two bees, MORE BEES!</span>")
else
to_chat(user, "<span class='warning'>You don't have enough royal bee jelly to split a bee in two!</span>")
else
var/datum/reagent/R = chemical_reagents_list[S.reagents.get_master_reagent_id()]
if(R && S.reagents.has_reagent(R.id, 5))
S.reagents.remove_reagent(R.id,5)
queen.assign_reagent(R)
user.visible_message("<span class='warning'>[user] injects [src]'s genome with [R.name], mutating it's DNA!</span>","<span class='warning'>You inject [src]'s genome with [R.name], mutating it's DNA!</span>")
name = queen.name
else
to_chat(user, "<span class='warning'>You don't have enough units of that chemical to modify the bee's DNA!</span>")
..()
/obj/item/queen_bee/bought/New()
..()
queen = new(src)
/obj/item/queen_bee/Destroy()
qdel(queen)
return ..()
@@ -82,18 +82,17 @@
move_to_delay = 5
/mob/living/simple_animal/hostile/poison/giant_spider/hunter/handle_automated_action()
if(!stat)
if(stance == HOSTILE_STANCE_IDLE)
//1% chance to skitter madly away
if(!busy && prob(1))
/*var/list/move_targets = list()
for(var/turf/T in orange(20, src))
move_targets.Add(T)*/
stop_automated_movement = 1
Goto(pick(orange(20, src)), move_to_delay)
spawn(50)
stop_automated_movement = 0
walk(src,0)
if(!..()) //AIStatus is off
return
if(AIStatus == AI_IDLE)
//1% chance to skitter madly away
if(!busy && prob(1))
stop_automated_movement = 1
Goto(pick(orange(20, src)), move_to_delay)
spawn(50)
stop_automated_movement = 0
walk(src,0)
return 1
/mob/living/simple_animal/hostile/poison/giant_spider/nurse/proc/GiveUp(var/C)
spawn(100)
@@ -104,36 +103,31 @@
stop_automated_movement = 0
/mob/living/simple_animal/hostile/poison/giant_spider/nurse/handle_automated_action()
if(!stat && !ckey)
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)
if(C.stat && !istype(C,/mob/living/simple_animal/hostile/poison/giant_spider))
cocoon_target = C
busy = MOVING_TO_TARGET
Goto(C, move_to_delay)
//give up if we can't reach them after 10 seconds
GiveUp(C)
return
//second, spin a sticky spiderweb on this tile
var/obj/effect/spider/stickyweb/W = locate() in get_turf(src)
if(!W)
Web()
if(..())
var/list/can_see = view(src, 10)
if(!busy && prob(30)) //30% chance to stop wandering and do something
//first, check for potential food nearby to cocoon
for(var/mob/living/C in can_see)
if(C.stat && !istype(C,/mob/living/simple_animal/hostile/poison/giant_spider))
cocoon_target = C
busy = MOVING_TO_TARGET
Goto(C, move_to_delay)
//give up if we can't reach them after 10 seconds
GiveUp(C)
return
//second, spin a sticky spiderweb on this tile
var/obj/effect/spider/stickyweb/W = locate() in get_turf(src)
if(!W)
Web()
else
//third, lay an egg cluster there
if(fed)
LayEggs()
else
//third, lay an egg cluster there
if(fed)
LayEggs()
else
//fourthly, cocoon any nearby items so those pesky pinkskins can't use them
for(var/obj/O in can_see)
if(O.anchored)
continue
//fourthly, cocoon any nearby items so those pesky pinkskins can't use them
for(var/obj/O in can_see)
if(O.anchored)
continue
if(istype(O, /obj/item) || istype(O, /obj/structure) || istype(O, /obj/machinery))
cocoon_target = O
busy = MOVING_TO_TARGET
@@ -142,13 +136,13 @@
//give up if we can't reach them after 10 seconds
GiveUp(O)
else if(busy == MOVING_TO_TARGET && cocoon_target)
if(get_dist(src, cocoon_target) <= 1)
Wrap()
else if(busy == MOVING_TO_TARGET && cocoon_target)
if(get_dist(src, cocoon_target) <= 1)
Wrap()
else
busy = 0
stop_automated_movement = 0
else
busy = 0
stop_automated_movement = 0
/mob/living/simple_animal/hostile/poison/giant_spider/verb/Web()
set name = "Lay Web"
@@ -254,4 +248,4 @@
#undef SPINNING_WEB
#undef LAYING_EGGS
#undef MOVING_TO_TARGET
#undef SPINNING_COCOON
#undef SPINNING_COCOON
@@ -101,9 +101,8 @@
qdel(src)
return
/mob/living/simple_animal/hostile/hivebot/tele/process_ai()
. = ..()
if(!.)
/mob/living/simple_animal/hostile/hivebot/tele/handle_automated_action()
if(!..())
return
if(prob(2))//Might be a bit low, will mess with it likely
warpbots()
warpbots()
@@ -3,7 +3,6 @@
mouse_opacity = 2 //This makes it easier to hit hostile mobs, you only need to click on their tile, and is set back to 1 when they die
stop_automated_movement_when_pulled = 0
environment_smash = 1 //Set to 1 to break closets,tables,racks, etc; 2 for walls; 3 for rwalls
var/stance = HOSTILE_STANCE_IDLE //Used to determine behavior
var/atom/target
var/ranged = 0
var/rapid = 0
@@ -30,39 +29,35 @@
var/stat_exclusive = 0 //Mobs with this set to 1 will exclusively attack things defined by stat_attack, stat_attack 2 means they will only attack corpses
var/attack_same = 0 //Set us to 1 to allow us to attack our own faction, or 2, to only ever attack our own faction
var/AIStatus = AI_ON //The Status of our AI, can be set to AI_ON (On, usual processing), AI_SLEEP (Will not process, but will return to AI_ON if an enemy comes near), AI_OFF (Off, Not processing ever)
var/AIStatus = AI_ON //The Status of our AI, can be set to AI_ON (On, usual processing), AI_IDLE (Will not process, but will return to AI_ON if an enemy comes near), AI_OFF (Off, Not processing ever)
/mob/living/simple_animal/hostile/Life()
. = ..()
if(!.)
walk(src, 0)
return 0
if(ranged)
ranged_cooldown--
/mob/living/simple_animal/hostile/process_ai()
..()
if(!AICanContinue())
return 0
switch(stance)
if(HOSTILE_STANCE_IDLE)
var/new_target = FindTarget()
GiveTarget(new_target)
if(HOSTILE_STANCE_ATTACK)
MoveToTarget()
DestroySurroundings()
if(HOSTILE_STANCE_ATTACKING)
AttackTarget()
DestroySurroundings()
if(AIShouldSleep())
AIStatus = AI_SLEEP
return 1
/mob/living/simple_animal/hostile/handle_automated_action()
if(AIStatus == AI_OFF)
return 0
if(ranged)
ranged_cooldown--
var/list/possible_targets = ListTargets() //we look around for potential targets and make it a list for later use.
if(environment_smash)
EscapeConfinement()
if(AICanContinue(possible_targets))
DestroySurroundings()
if(!MoveToTarget(possible_targets)) //if we lose our target
if(AIShouldSleep(possible_targets)) // we try to acquire a new one
AIStatus = AI_IDLE // otherwise we go idle
return 1
//////////////HOSTILE MOB TARGETTING AND AGGRESSION////////////
@@ -82,19 +77,18 @@
L += Objects
return L
/mob/living/simple_animal/hostile/proc/FindTarget()//Step 2, filter down possible targets to things we actually care about
/mob/living/simple_animal/hostile/proc/FindTarget(var/list/possible_targets, var/HasTargetsList = 0)//Step 2, filter down possible targets to things we actually care about
var/list/Targets = list()
var/Target
for(var/atom/A in ListTargets())
if(!HasTargetsList)
possible_targets = ListTargets()
for(var/atom/A in possible_targets)
if(Found(A))//Just in case people want to override targetting
var/list/FoundTarget = list()
FoundTarget += A
Targets = FoundTarget
Targets = list(A)
break
if(CanAttack(A))//Can we attack it?
Targets += A
continue
Target = PickTarget(Targets)
var/Target = PickTarget(Targets)
GiveTarget(Target)
return Target //We now have a target
@@ -102,14 +96,14 @@
return
/mob/living/simple_animal/hostile/proc/PickTarget(var/list/Targets)//Step 3, pick amongst the possible, attackable targets
if(!Targets.len)//We didnt find nothin!
return
if(target != null)//If we already have a target, but are told to pick again, calculate the lowest distance between all possible, and pick from the lowest distance targets
for(var/atom/A in Targets)
var/target_dist = get_dist(src, target)
var/possible_target_distance = get_dist(src, A)
if(target_dist < possible_target_distance)
Targets -= A
if(!Targets.len)//We didnt find nothin!
return
var/chosen_target = pick(Targets)//Pick the remaining targets (if any) at random
return chosen_target
@@ -148,23 +142,21 @@
return 0
return 1
if(isobj(the_target))
if(the_target.type in wanted_objects)
if(is_type_in_list(the_target, wanted_objects))
return 1
return 0
/mob/living/simple_animal/hostile/proc/GiveTarget(var/new_target)//Step 4, give us our selected target
target = new_target
if(target != null)
Aggro()
stance = HOSTILE_STANCE_ATTACK
return
return 1
/mob/living/simple_animal/hostile/proc/MoveToTarget()//Step 5, handle movement between us and our target
/mob/living/simple_animal/hostile/proc/MoveToTarget(var/list/possible_targets)//Step 5, handle movement between us and our target
stop_automated_movement = 1
if(!target || !CanAttack(target))
LoseTarget()
return
if(target in ListTargets())
return 0
if(target in possible_targets)
var/target_distance = get_dist(src,target)
if(ranged)//We ranged? Shoot at em
if(target_distance >= 2 && ranged_cooldown <= 0)//But make sure they're a tile away at least, and our range attack is off cooldown
@@ -178,17 +170,18 @@
Goto(target,move_to_delay,minimum_distance)
if(isturf(loc) && target.Adjacent(src)) //If they're next to us, attack
AttackingTarget()
return
return 1
if(environment_smash)
if(target.loc != null && get_dist(src, target.loc) <= vision_range)//We can't see our target, but he's in our vision range still
if(environment_smash >= 2)//If we're capable of smashing through walls, forget about vision completely after finding our target
Goto(target,move_to_delay,minimum_distance)
FindHidden()
return
return 1
else
if(FindHidden())
return
return 1
LostTarget()
return 0
/mob/living/simple_animal/hostile/proc/Goto(var/target, var/delay, var/minimum_distance)
walk_to(src, target, minimum_distance, delay)
@@ -199,27 +192,11 @@
if(search_objects)//Turn off item searching and ignore whatever item we were looking at, we're more concerned with fight or flight
search_objects = 0
target = null
if(stance == HOSTILE_STANCE_IDLE)//If we took damage while idle, immediately attempt to find the source of it so we find a living target
Aggro()
var/new_target = FindTarget()
GiveTarget(new_target)
if(stance == HOSTILE_STANCE_ATTACK)//No more pulling a mob forever and having a second player attack it, it can switch targets now if it finds a more suitable one
if(target != null && prob(25))
var/new_target = FindTarget()
GiveTarget(new_target)
/mob/living/simple_animal/hostile/proc/AttackTarget()
stop_automated_movement = 1
if(!target || !CanAttack(target))
LoseTarget()
return 0
if(!(target in ListTargets()))
LostTarget()
return 0
if(isturf(loc) && target.Adjacent(src))
AttackingTarget()
return 1
if(AIStatus == AI_IDLE)
AIStatus = AI_ON
FindTarget()
else if(target != null && prob(40))//No more pulling a mob forever and having a second player attack it, it can switch targets now if it finds a more suitable one
FindTarget()
/mob/living/simple_animal/hostile/proc/AttackingTarget()
target.attack_animal(src)
@@ -232,13 +209,11 @@
vision_range = idle_vision_range
/mob/living/simple_animal/hostile/proc/LoseTarget()
stance = HOSTILE_STANCE_IDLE
target = null
walk(src, 0)
LoseAggro()
/mob/living/simple_animal/hostile/proc/LostTarget()
stance = HOSTILE_STANCE_IDLE
walk(src, 0)
LoseAggro()
@@ -340,28 +315,16 @@
////// AI Status ///////
/mob/living/simple_animal/hostile/proc/AICanContinue()
/mob/living/simple_animal/hostile/proc/AICanContinue(var/list/possible_targets)
switch(AIStatus)
if(AI_ON)
. = 1
if(AI_SLEEP)
if(AIShouldWake())
if(AI_IDLE)
if(FindTarget(possible_targets, 1))
. = 1
AIStatus = AI_ON //Wake up for more than one Life() cycle.
else
. = 0
if(AI_OFF)
. = 0
//Returns 1 if the AI should wake up
//Returns 0 if the AI should remain asleep
/mob/living/simple_animal/hostile/proc/AIShouldWake()
. = 0
if(FindTarget())
. = 1
//Convenience
/mob/living/simple_animal/hostile/proc/AIShouldSleep()
. = !(AIShouldWake())
/mob/living/simple_animal/hostile/proc/AIShouldSleep(var/list/possible_targets)
return !FindTarget(possible_targets, 1)
@@ -32,13 +32,7 @@
var/stalk_tick_delay = 3
gold_core_spawnable = CHEM_MOB_SPAWN_HOSTILE
/mob/living/simple_animal/hostile/panther/ListTargets()
var/list/targets = list()
for(var/mob/living/carbon/human/H in view(src, 10))
targets += H
return targets
/mob/living/simple_animal/hostile/panther/FindTarget()
/mob/living/simple_animal/hostile/panther/FindTarget(var/list/possible_targets)
. = ..()
if(.)
emote("nashes at [.]")
@@ -51,14 +45,6 @@
L.Weaken(3)
L.visible_message("<span class='danger'>\the [src] knocks down \the [L]!</span>")
/mob/living/simple_animal/hostile/panther/AttackTarget()
..()
if(stance == HOSTILE_STANCE_ATTACKING && get_dist(src, target))
stalk_tick_delay -= 1
if(stalk_tick_delay <= 0)
src.loc = get_step_towards(src, target)
stalk_tick_delay = 3
//*******//
// Snake //
//*******//
@@ -90,12 +76,6 @@
var/stalk_tick_delay = 3
gold_core_spawnable = CHEM_MOB_SPAWN_HOSTILE
/mob/living/simple_animal/hostile/snake/ListTargets()
var/list/targets = list()
for(var/mob/living/carbon/human/H in view(src, 10))
targets += H
return targets
/mob/living/simple_animal/hostile/snake/FindTarget()
. = ..()
if(.)
@@ -106,11 +86,3 @@
var/mob/living/L = .
if(istype(L))
L.apply_damage(rand(3,12), TOX)
/mob/living/simple_animal/hostile/snake/AttackTarget()
..()
if(stance == HOSTILE_STANCE_ATTACKING && get_dist(src, target))
stalk_tick_delay -= 1
if(stalk_tick_delay <= 0)
src.loc = get_step_towards(src, target)
stalk_tick_delay = 3
@@ -84,16 +84,12 @@
temperature = 50
/mob/living/simple_animal/hostile/asteroid/basilisk/GiveTarget(var/new_target)
target = new_target
if(target != null)
Aggro()
stance = HOSTILE_STANCE_ATTACK
if(..()) //we have a target
if(isliving(target))
var/mob/living/L = target
if(L.bodytemperature > 261)
L.bodytemperature = 261
visible_message("<span class='danger'>The [src.name]'s stare chills [L.name] to the bone!</span>")
return
/mob/living/simple_animal/hostile/asteroid/basilisk/ex_act(severity)
switch(severity)
@@ -156,17 +152,12 @@
if(target != null)
if(istype(target, /obj/item/weapon/ore))
visible_message("<span class='notice'>The [src.name] looks at [target.name] with hungry eyes.</span>")
stance = HOSTILE_STANCE_ATTACK
return
if(isliving(target))
else if(isliving(target))
Aggro()
stance = HOSTILE_STANCE_ATTACK
visible_message("<span class='danger'>The [src.name] tries to flee from [target.name]!</span>")
retreat_distance = 10
minimum_distance = 10
Burrow()
return
return
/mob/living/simple_animal/hostile/asteroid/goldgrub/AttackingTarget()
if(istype(target, /obj/item/weapon/ore))
@@ -387,7 +378,7 @@
/mob/living/simple_animal/hostile/asteroid/goliath/proc/handle_preattack()
if(ranged_cooldown <= 2 && !pre_attack)
pre_attack++
if(!pre_attack || stat || stance == HOSTILE_STANCE_IDLE)
if(!pre_attack || stat || AIStatus == AI_IDLE)
return
icon_state = "Goliath_preattack"
@@ -511,4 +502,4 @@
to_chat(user, "<span class='warning'>You can't add armour onto the mech while someone is inside!</span>")
else
to_chat(user, "<span class='warning'>You can't improve [D] any further!</span>")
return
return
@@ -1,65 +0,0 @@
/mob/living/simple_animal/hostile/poison/bees
name = "space bee swarm"
desc = ""
icon_state = "bee_1"
icon_living = "bee"
speak_emote = list("buzzes")
emote_hear = list("buzzes")
turns_per_move = 0
melee_damage_lower = 1
melee_damage_upper = 1
attacktext = "stings"
response_help = "shoos"
response_disarm = "swats away"
response_harm = "squashes"
maxHealth = 10
health = 10
faction = list("hostile")
move_to_delay = 0
environment_smash = 0
mouse_opacity = 2
pass_flags = PASSTABLE | PASSGRILLE | PASSMOB
flying = 1
//Spaceborn beings don't get hurt by space
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
minbodytemp = 0
gold_core_spawnable = CHEM_MOB_SPAWN_HOSTILE
/mob/living/simple_animal/hostile/poison/bees/Process_Spacemove(var/check_drift = 0)
return 1
/mob/living/simple_animal/hostile/poison/bees/New()
..()
var/bees = rand(2, 10)
for(var/i, i <= bees, i++)
var/N = rand(1, 4)
var/image/I = image(icon='icons/mob/animal.dmi',icon_state="bee_[N]", pixel_x = rand(-8, 8), pixel_y = rand(-8, 8))
overlays += I
//update_bees()
/mob/living/simple_animal/hostile/poison/bees/death()
..()
ghostize()
qdel(src)
return
/*/mob/living/simple_animal/hostile/poison/bees/Life()
..()
update_bees()
/mob/living/simple_animal/hostile/poison/bees/proc/update_bees()
while(overlays.len != health-1) //how many bees do we have in the swarm?
var/N = rand(1, 4)
var/image/I = image(icon='icons/mob/animal.dmi',icon_state="bee_[N]", pixel_x = rand(-8, 8), pixel_y = rand(-8, 8))
if(overlays.len < health-1)
overlays.Add(I)
if(overlays.len > health-1)
overlays.Remove(I) //REMOVING A RANDOM IMAGE FROM AN OVERLAYS LIST THAT DOES NOT CONTAIN THAT IMAGE
poison_per_bite = health * 0.5 //each bee is half a toxin reagent //WHAT A GREAT FUCKING PLAN
if(health > 1)
desc = "A buzzy swarm of [health] poisonous space bees, renowned for their aggressiveness"
else
desc = "Although now lonely, this single space bee is still poisonous and very angry at you."*///NOVEL IDEA: INFINITE LOOP IMPLEMENTATION
@@ -5,19 +5,16 @@
if(isliving(A))
var/mob/living/L = A
if(!L.stat)
stance = HOSTILE_STANCE_ATTACK
return L
else
enemies -= L
else if(istype(A, /obj/mecha))
var/obj/mecha/M = A
if(M.occupant)
stance = HOSTILE_STANCE_ATTACK
return A
else if(istype(A, /obj/spacepod))
var/obj/spacepod/M = A
if(M.occupant || M.occupant2)
stance = HOSTILE_STANCE_ATTACK
return A
/mob/living/simple_animal/hostile/retaliate/ListTargets()
@@ -72,4 +69,4 @@
for(var/dir in cardinal) // North, South, East, West
var/obj/structure/obstacle = locate(/obj/structure, get_step(src, dir))
if(istype(obstacle, /obj/structure/closet) || istype(obstacle, /obj/structure/table))
obstacle.attack_animal(src)
obstacle.attack_animal(src)
@@ -70,9 +70,9 @@
return 0
return ..()
/mob/living/simple_animal/hostile/statue/process_ai()
..()
/mob/living/simple_animal/hostile/statue/handle_automated_action()
if(!..())
return
if(target) // If we have a target and we're AI controlled
var/mob/watching = can_be_seen()
// If they're not our target
@@ -211,11 +211,10 @@
name = "Toggle Nightvision \[OFF\]"
return
/mob/living/simple_animal/hostile/statue/sentience_act()
faction -= "neutral"
/mob/living/simple_animal/hostile/statue/restrained()
. = ..()
if(can_be_seen(loc))
return 1
return 1