From 0f0f126142e9802eda59977c1efd3e496fdd56bc Mon Sep 17 00:00:00 2001 From: Ren Erthilo Date: Mon, 23 Apr 2012 21:51:10 +0100 Subject: [PATCH] TG: Sanity check for facehuggers. Sanity checks galore for simple_animals (if(list) behaviour seems to have changed lately). Humans once again get their bodies burned into husks in fire. This only changes their appearance and name now, however, leaving their DNA intact. WIP space worms. Revision: r3140 Author: uporotiy --- code/game/objects/alien/facehugger.dm | 399 ------------------------- code/modules/mob/simple_animal/life.dm | 46 +-- code/modules/mob/simple_animal/worm.dm | 199 ++++++++++++ 3 files changed, 223 insertions(+), 421 deletions(-) create mode 100644 code/modules/mob/simple_animal/worm.dm diff --git a/code/game/objects/alien/facehugger.dm b/code/game/objects/alien/facehugger.dm index 5c9db1b572d..7c54a78d604 100644 --- a/code/game/objects/alien/facehugger.dm +++ b/code/game/objects/alien/facehugger.dm @@ -220,402 +220,3 @@ var/const return -/* NOPE.png -- Urist - -// Returns the surrounding cardinal turfs with open links -// Including through doors openable with the ID -// Includes spacetiles -/turf/proc/CardinalTurfsWithAccessSpace(var/obj/item/weapon/card/id/ID) - var/L[] = new() - for(var/d in cardinal) - var/turf/simulated/T = get_step(src, d) - if((istype(T) || istype(T,/turf/space))&& !T.density) - if(!LinkBlockedWithAccess(src, T, ID)) - L.Add(T) - return L - -/obj/effect/alien/facehugger - name = "alien" - desc = "An alien, looks pretty scary!" - icon_state = "facehugger" - layer = 5.0 - density = 1 - anchored = 0 - - var/state = 0 - - var/list/path = new/list() - - var/frustration = 0 - var/mob/living/carbon/target - var/list/path_target = new/list() - - var/turf/trg_idle - var/list/path_idle = new/list() - - var/alive = 1 //1 alive, 0 dead - var/health = 10 - var/maxhealth = 10 - var/lamarr = 0 - flags = 258.0 - - - - - - New() - ..() - if(aliens_allowed) - health = maxhealth - process() - else - del(src) - - examine() - set src in view() - ..() - if(!alive) - usr << text("\red The alien is not moving.") - else if (health > 5) - usr << text("\red The alien looks fresh, just out of the egg.") - else - usr << text("\red The alien looks injured.") - if (lamarr) - usr << text("\red It looks like the proboscis has been removed.") - return - - - attack_hand(user as mob) - return - - attackby(obj/item/weapon/W as obj, mob/user as mob) - switch(W.damtype) - if("fire") - health -= W.force * 0.75 - if("brute") - health -= W.force * 0.5 - else - if (health <= 0) - death() - else if (W.force) - if(ishuman(user) || ismonkey(user)) - target = user - state = 1 - ..() - - bullet_act(var/obj/item/projectile/Proj) - health -= round(Proj.damage / 2) - ..() - healthcheck() - - ex_act(severity) - switch(severity) - if(1.0) - death() - if(2.0) - health -= 15 - healthcheck() - return - - meteorhit() - death() - return - - blob_act() - if(prob(50)) - death() - return - - Bumped(AM as mob|obj) - if(ismob(AM) && (ishuman(AM) || ismonkey(AM)) ) - target = AM - set_attack() - else if(ismob(AM)) - spawn(0) - var/turf/T = get_turf(src) - AM:loc = T - - Bump(atom/A) - if(ismob(A) && (ishuman(A) || ismonkey(A))) - target = A - set_attack() - else if(ismob(A)) - loc = A:loc - - temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume) - if(exposed_temperature > 300) - health -= 5 - healthcheck() - - - - - verb/follow() - set src in view() //set src in get_aliens(view()) - does not work, damn shitty byond :( -- rastaf0 - set name = "Follow Me" - set category = "Object" //"Alien" does not work perfect - humans get "Alien" tab too, that's annoying - if(!alive) return - if(!isalien(usr)) - usr << text("\red The alien ignores you.") - return - if(state != 2 || health < maxhealth) - usr << text("\red The alien is too busy to follow you.") - return - usr << text("\green The alien will now try to follow you.") - trg_idle = usr - path_idle = new/list() - return - - verb/stop() - set src in view() - set name = "Stop Following" - set category = "Object" - if(!alive) return - if(!isalien(usr)) - usr << text("\red The alien ignores you.") - return - if(state != 2) - usr << text("\red The alien is too busy to follow you.") - return - usr << text("\green The alien stops following you.") - set_null() - return - - - - - proc/call_to(var/mob/user) - if(!alive || !isalien(user) || state != 2) return - trg_idle = user - path_idle = new/list() - return - - proc/set_attack() - state = 1 - if(path_idle.len) path_idle = new/list() - trg_idle = null - - proc/set_idle() - state = 2 - if (path_target.len) path_target = new/list() - target = null - frustration = 0 - - proc/set_null() - state = 0 - if (path_target.len) path_target = new/list() - if (path_idle.len) path_idle = new/list() - target = null - trg_idle = null - frustration = 0 - - process() - set background = 1 - var/quick_move = 0 - - if (!alive) - return - - if (!target) - if (path_target.len) path_target = new/list() - - var/last_health = INFINITY - var/view - if (lamarr) - view = 1 - else - view = viewrange-2 - for (var/mob/living/carbon/C in range(view,loc)) - if (C.stat == 2 || isalien(C) || C.alien_egg_flag || !can_see(src,C,viewrange) || istype(C, /mob/living/carbon/metroid)) - continue - if(C:stunned || C:paralysis || C:weakened) - target = C - - break - if(C:health < last_health) - last_health = C:health - target = C - - if(target) - if (!lamarr || prob(10)) - set_attack() - else if(state != 2) - set_idle() - idle() - - else if(target) - var/turf/distance = get_dist(src, target) - if (!lamarr || prob(10)) - set_attack() - - if(can_see(src,target,viewrange)) - if(distance <= 1 && (!lamarr || prob(20))) - for(var/mob/O in viewers(world.view,src)) - O.show_message("\red [target] has been leapt on by [lamarr ? name : "the alien"]!", 1, "\red You hear someone fall", 2) - if (!lamarr) - target:take_overall_damage(5) - if(prob(70)) - target:paralysis = max(target:paralysis, 5) - loc = target.loc - - if(!target.alien_egg_flag && ( ishuman(target) || ismonkey(target) ) ) - if (!lamarr && target) - var/mob/trg = target - death() - //if(trg.virus)//Viruses are stored in a global database. - //trg.virus.cure(0)//You need to either cure() or del() them to stop their processing. - trg.contract_disease(new /datum/disease/alien_embryo(0))//So after that you need to infect the target anew. - for(var/datum/disease/alien_embryo/A in trg.viruses) - trg.alien_egg_flag = 1//We finally set their flag to 1. - return - else - sleep(50) - else - set_null() - spawn(cycle_pause) process() - return - - step_towards(src,get_step_towards2(src , target)) - else - if( !path_target.len ) - - path_attack(target) - if(!path_target.len) - set_null() - spawn(cycle_pause) process() - return - else - var/turf/next = path_target[1] - - if(next in range(1,src)) - path_attack(target) - - if(!path_target.len) - frustration += 5 - else - next = path_target[1] - path_target -= next - step_towards(src,next) - quick_move = 1 - - if (get_dist(src, target) >= distance) frustration++ - else frustration-- - if(frustration >= 35 || lamarr) set_null() - - if(quick_move) - spawn(cycle_pause/2) - process() - else - spawn(cycle_pause) - process() - - proc/idle() - set background = 1 - var/quick_move = 0 - - if(state != 2 || !alive || target) return - - if(locate(/obj/effect/alien/weeds) in loc && health < maxhealth) - health++ - spawn(cycle_pause) idle() - return - - if(!path_idle.len) - - if(isalien(trg_idle)) - if(can_see(src,trg_idle,viewrange)) - step_towards(src,get_step_towards2(src , trg_idle)) - else - path_idle(trg_idle) - if(!path_idle.len) - trg_idle = null - set_idle() - spawn(cycle_pause) idle() - return - else - var/obj/effect/alien/weeds/W = null - if(health < maxhealth) - var/list/the_weeds = new/list() - - find_weeds: - for(var/obj/effect/alien/weeds/weed in range(viewrange,loc)) - if(!can_see(src,weed,viewrange)) continue - for(var/atom/A in get_turf(weed)) - if(A.density) continue find_weeds - the_weeds += weed - if(the_weeds.len) - W = pick(the_weeds) - - if(W) - path_idle(W) - if(!path_idle.len) - trg_idle = null - spawn(cycle_pause) idle() - return - else - for(var/mob/living/carbon/alien/humanoid/H in range(1,src)) - spawn(cycle_pause) idle() - return - step(src,pick(cardinal)) - - else - - if(can_see(src,trg_idle,viewrange)) - switch(get_dist(src, trg_idle)) - if(1) - if(istype(trg_idle,/obj/effect/alien/weeds)) - step_towards(src,get_step_towards2(src , trg_idle)) - if(2 to INFINITY) - step_towards(src,get_step_towards2(src , trg_idle)) - if(path_idle.len) path_idle = new/list() - /* - if(viewrange+1 to INFINITY) - step_towards(src,get_step_towards2(src , trg_idle)) - if(path_idle.len) path_idle = new/list() - quick_move = 1 - */ - else - var/turf/next = path_idle[1] - if(!next in range(1,src)) - path_idle(trg_idle) - - if(!path_idle.len) - spawn(cycle_pause) idle() - return - else - next = path_idle[1] - path_idle -= next - step_towards(src,next) - quick_move = 1 - - if(quick_move) - spawn(cycle_pause/2) - idle() - else - spawn(cycle_pause) - idle() - - proc/path_idle(var/atom/trg) - path_idle = AStar(loc, get_turf(trg), /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance, 0, 250, null, null) - path_idle = reverselist(path_idle) - - proc/path_attack(var/atom/trg) - target = trg - path_target = AStar(loc, target.loc, /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance, 0, 250, null, null) - path_target = reverselist(path_target) - - - proc/death() - if(!alive) return - alive = 0 - density = 0 - icon_state = "facehugger_l" - set_null() - for(var/mob/O in hearers(src, null)) - O.show_message("\red [src] curls up into a ball!", 1) - - proc/healthcheck() - if (health <= 0) - death() - -*/ \ No newline at end of file diff --git a/code/modules/mob/simple_animal/life.dm b/code/modules/mob/simple_animal/life.dm index 29da09bb6ed..fea5278ddbc 100644 --- a/code/modules/mob/simple_animal/life.dm +++ b/code/modules/mob/simple_animal/life.dm @@ -68,7 +68,7 @@ if(health > 0) icon_state = icon_living alive = 1 - stat = 0 //Alive - conscious + stat = CONSCIOUS density = 1 return @@ -128,35 +128,37 @@ //Speaking if(speak_chance) if(prob(speak_chance)) - if(speak && (emote_hear || emote_see) ) - var/length = speak.len - if(emote_hear) - length += emote_hear.len - if(emote_see) - length += emote_see.len - var/pick = rand(1,length) - if(pick <= speak.len) - say(pick(speak)) - else - pick -= speak.len - if(emote_see && pick <= emote_see.len) - emote(pick(emote_see),1) + 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 - emote(pick(emote_hear),2) - if(!speak) - if(!emote_hear && emote_see) + randomValue -= speak.len + if(emote_see && randomValue <= emote_see.len) + emote(pick(emote_see),1) + else + emote(pick(emote_hear),2) + else + say(pick(speak)) + else + if(!(emote_hear && emote_hear.len) && (emote_see && emote_see.len)) emote(pick(emote_see),1) - if(emote_hear && !emote_see) + if((emote_hear && emote_hear.len) && !(emote_see && emote_see.len)) emote(pick(emote_hear),2) - if(emote_hear && emote_see) + 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) emote(pick(emote_see),1) else emote(pick(emote_hear),2) - if(speak && !(emote_see || emote_hear)) - say(pick(speak)) + //Atmos var/atmos_suitable = 1 @@ -230,7 +232,7 @@ ..() /mob/living/simple_animal/say_quote(var/text) - if(speak_emote) + if(speak_emote && speak_emote.len) var/emote = pick(speak_emote) if(emote) return "[emote], \"[text]\"" diff --git a/code/modules/mob/simple_animal/worm.dm b/code/modules/mob/simple_animal/worm.dm new file mode 100644 index 00000000000..18b66178e64 --- /dev/null +++ b/code/modules/mob/simple_animal/worm.dm @@ -0,0 +1,199 @@ +/mob/living/simple_animal/space_worm + name = "space worm segment" + desc = "A part of a space worm." + icon = 'critter.dmi' + icon_state = "spaceworm" + icon_living = "spaceworm" + icon_dead = "spacewormdead" + + speak_emote = list("transmits") //not supposed to be used under AI control + emote_hear = list("transmits") //I'm just adding it so it doesn't runtime if controlled by player who speaks + + response_help = "touches" + response_disarm = "flails at" + response_harm = "punches the" + + harm_intent_damage = 2 + + maxHealth = 30 + health = 30 + + stop_automated_movement = 1 + animate_movement = SYNC_STEPS + + minbodytemp = 0 + maxbodytemp = 350 + min_oxy = 0 + max_co2 = 0 + max_tox = 0 + + a_intent = "harm" //so they don't get pushed around + + nopush = 1 + wall_smash = 1 + + speed = -1 + + var/mob/living/simple_animal/space_worm/previous //next/previous segments, correspondingly + var/mob/living/simple_animal/space_worm/next //head is the nextest segment + + var/stomachProcessProbability = 50 + var/digestionProbability = 20 + var/flatPlasmaValue = 5 //flat plasma amount given for non-items + + var/atom/currentlyEating //what the worm is currently eating + var/eatingDuration = 0 //how long he's been eating it for + + head + name = "space worm head" + icon_state = "spacewormhead" + icon_living = "spacewormhead" + icon_dead = "spacewormdead" + + maxHealth = 20 + health = 20 + + melee_damage_lower = 10 + melee_damage_upper = 15 + attacktext = "bites" + + animate_movement = SLIDE_STEPS + + New(var/location, var/segments = 6) + ..() + + var/mob/living/simple_animal/space_worm/current = src + + for(var/i = 1 to segments) + var/mob/living/simple_animal/space_worm/newSegment = new /mob/living/simple_animal/space_worm(loc) + current.Attach(newSegment) + current = newSegment + + update_icon() + if(stat == CONSCIOUS || stat == UNCONSCIOUS) + icon_state = "spacewormhead[previous?1:0]" + if(previous) + dir = get_dir(previous,src) + else + icon_state = "spacewormheaddead" + + Life() + ..() + + if(next && !(next in view(src,1))) + Detach() + + if(stat == DEAD) //dead chunks fall off and die immediately + if(previous) + previous.Detach() + if(next) + Detach(1) + + if(prob(stomachProcessProbability)) + ProcessStomach() + + update_icon() + + return + + Del() //if a chunk a destroyed, make a new worm out of the split halves + if(previous) + previous.Detach() + ..() + + Move() + var/attachementNextPosition = loc + if(..()) + if(previous) + previous.Move(attachementNextPosition) + update_icon() + + Bump(atom/obstacle) + if(currentlyEating != obstacle) + currentlyEating = obstacle + eatingDuration = 0 + + if(!AttemptToEat(obstacle)) + eatingDuration++ + else + currentlyEating = null + eatingDuration = 0 + + return + + proc/update_icon() //only for the sake of consistency with the other update icon procs + if(stat == CONSCIOUS || stat == UNCONSCIOUS) + if(previous) //midsection + icon_state = "spaceworm[get_dir(src,previous) | get_dir(src,next)]" //see 3 lines below + else //tail + icon_state = "spacewormtail" + dir = get_dir(src,next) //next will always be present since it's not a head and if it's dead, it goes in the other if branch + else + icon_state = "spacewormdead" + + return + + proc/AttemptToEat(var/atom/target) + if(istype(target,/turf/simulated/wall)) + if((!istype(target,/turf/simulated/wall/r_wall) && eatingDuration >= 100) || eatingDuration >= 200) //need 20 ticks to eat an rwall, 10 for a regular one + var/turf/simulated/wall/wall = target + wall.ReplaceWithFloor() + new /obj/item/stack/sheet/metal(src, flatPlasmaValue) + return 1 + else if(istype(target,/atom/movable)) + if(istype(target,/mob) || eatingDuration >= 50) //5 ticks to eat stuff like airlocks + var/atom/movable/objectOrMob = target + contents += objectOrMob + return 1 + + return 0 + + proc/Attach(var/mob/living/simple_animal/space_worm/attachement) + if(!attachement) + return + + previous = attachement + attachement.next = src + + return + + proc/Detach(die = 0) + var/mob/living/simple_animal/space_worm/newHead = new /mob/living/simple_animal/space_worm/head(loc,0) + var/mob/living/simple_animal/space_worm/newHeadPrevious = previous + + previous = null //so that no extra heads are spawned + + newHead.Attach(newHeadPrevious) + + if(die) + newHead.Die() + + del(src) + + proc/ProcessStomach() + for(var/atom/movable/stomachContent in contents) + if(prob(digestionProbability)) + if(istype(stomachContent,/obj/item/stack)) //converts to plasma, keeping the stack value + if(!istype(stomachContent,/obj/item/stack/sheet/plasma)) + var/obj/item/stack/oldStack = stomachContent + new /obj/item/stack/sheet/plasma(src, oldStack.amount) + del(oldStack) + continue + else if(istype(stomachContent,/obj/item)) //converts to plasma, keeping the w_class + var/obj/item/oldItem = stomachContent + new /obj/item/stack/sheet/plasma(src, oldItem.w_class) + del(oldItem) + continue + else + new /obj/item/stack/sheet/plasma(src, flatPlasmaValue) //just flat amount + del(stomachContent) + continue + + if(previous) + for(var/atom/movable/stomachContent in contents) //transfer it along the digestive tract + previous.contents += stomachContent + else + for(var/atom/movable/stomachContent in contents) //or poop it out + loc.contents += stomachContent + + return \ No newline at end of file