diff --git a/code/ATMOSPHERICS/components/unary_devices/cryo.dm b/code/ATMOSPHERICS/components/unary_devices/cryo.dm index 2f79446bac7..88fb4e5bc03 100644 --- a/code/ATMOSPHERICS/components/unary_devices/cryo.dm +++ b/code/ATMOSPHERICS/components/unary_devices/cryo.dm @@ -59,15 +59,16 @@ /obj/machinery/atmospherics/components/unary/cryo_cell/process() ..() - if(occupant && occupant.health >= 100 && autoEject) + if(occupant && occupant.health >= 100) on = 0 - open_machine() playsound(src.loc, 'sound/machines/ding.ogg', 50, 1) + if(autoEject) + open_machine() + if(!NODE1 || !is_operational()) return - if(AIR1) - if (occupant) + if(on && occupant) process_occupant() expel_gas() @@ -82,7 +83,7 @@ return /obj/machinery/atmospherics/components/unary/cryo_cell/container_resist() - usr << "Release sequence activated. This will take a few seconds." + usr << "You struggle inside the cryotube, kicking the release with your foot." sleep(150) if(!src || !usr || (!occupant && !contents.Find(usr))) // Make sure they didn't disappear. return @@ -260,6 +261,8 @@ /obj/machinery/atmospherics/components/unary/cryo_cell/proc/process_occupant() var/datum/gas_mixture/air_contents = AIR1 + if(!on) + return if(air_contents.total_moles() < 10) return if(occupant) diff --git a/code/__DEFINES/bots.dm b/code/__DEFINES/bots.dm new file mode 100644 index 00000000000..d6da76b02e4 --- /dev/null +++ b/code/__DEFINES/bots.dm @@ -0,0 +1,25 @@ +//Bot defines, placed here so they can be read by other things! + +#define BOT_STEP_DELAY 4 //Delay between movemements + +#define DEFAULT_SCAN_RANGE 7 //default view range for finding targets. + +//Mode defines +#define BOT_IDLE 0 // idle +#define BOT_HUNT 1 // found target, hunting +#define BOT_PREP_ARREST 2 // at target, preparing to arrest +#define BOT_ARREST 3 // arresting target +#define BOT_START_PATROL 4 // start patrol +#define BOT_PATROL 5 // patrolling +#define BOT_SUMMON 6 // summoned by PDA +#define BOT_CLEANING 7 // cleaning (cleanbots) +#define BOT_REPAIRING 8 // repairing hull breaches (floorbots) +#define BOT_MOVING 9 // for clean/floor/med bots, when moving. +#define BOT_HEALING 10 // healing people (medbots) +#define BOT_RESPONDING 11 // responding to a call from the AI +#define BOT_DELIVER 12 // moving to deliver +#define BOT_GO_HOME 13 // returning to home +#define BOT_BLOCKED 14 // blocked +#define BOT_NAV 15 // computing navigation +#define BOT_WAIT_FOR_NAV 16 // waiting for nav computation +#define BOT_NO_ROUTE 17 // no destination beacon found (or no route) \ No newline at end of file diff --git a/code/__DEFINES/hud.dm b/code/__DEFINES/hud.dm index c10e56598de..0ac66f3092d 100644 --- a/code/__DEFINES/hud.dm +++ b/code/__DEFINES/hud.dm @@ -13,6 +13,7 @@ #define DIAG_HUD "9" // Silicon health bar #define DIAG_BATT_HUD "10"// Borg/Mech power meter #define DIAG_MECH_HUD "11"// Mech health bar +#define DIAG_BOT_HUD "12"// Bot HUDs //for antag huds. these are used at the /mob level #define ANTAG_HUD "12" diff --git a/code/datums/mind.dm b/code/datums/mind.dm index 8e06a970e71..8d61b841478 100644 --- a/code/datums/mind.dm +++ b/code/datums/mind.dm @@ -1797,7 +1797,7 @@ mind.assigned_role = "Shade" mind.special_role = "Shade" -/mob/living/simple_animal/construct/mind_initialize() +/mob/living/simple_animal/hostile/construct/mind_initialize() ..() mind.assigned_role = "[initial(name)]" mind.special_role = "Cultist" diff --git a/code/datums/spells/shapeshift.dm b/code/datums/spells/shapeshift.dm index 1a11d0476a5..68e3a07825a 100644 --- a/code/datums/spells/shapeshift.dm +++ b/code/datums/spells/shapeshift.dm @@ -31,7 +31,7 @@ var/mob/living/shape = new shapeshift_type(caster.loc) caster.loc = shape caster.status_flags |= GODMODE - + current_shapes |= shape current_casters |= caster clothes_req = 0 @@ -54,7 +54,7 @@ human_req = initial(human_req) current_casters.Remove(caster) current_shapes.Remove(shape) - + shape.mind.transfer_to(caster) qdel(shape) //Gib it maybe ? @@ -65,7 +65,7 @@ var/list/possible_shapes = list(/mob/living/simple_animal/pet/dog/corgi,\ /mob/living/simple_animal/hostile/poison/giant_spider/hunter,\ /mob/living/simple_animal/hostile/carp/megacarp,\ - /mob/living/simple_animal/construct/armored) + /mob/living/simple_animal/hostile/construct/armored) /obj/effect/proc_holder/spell/targeted/shapeshift/wild/New() ..() diff --git a/code/datums/spells/wizard.dm b/code/datums/spells/wizard.dm index 931de5a65a2..49e5d968f96 100644 --- a/code/datums/spells/wizard.dm +++ b/code/datums/spells/wizard.dm @@ -333,7 +333,7 @@ var/mob/living/M = AM M.Weaken(2) M << "You're thrown back by [user]!" - spawn(0) AM.throw_at(throwtarget, ((Clamp((maxthrow - (Clamp(distfromcaster - 2, 0, distfromcaster))), 3, maxthrow))), 1,user)//So stuff gets tossed around at the same time. + AM.throw_at_fast(throwtarget, ((Clamp((maxthrow - (Clamp(distfromcaster - 2, 0, distfromcaster))), 3, maxthrow))), 1,user)//So stuff gets tossed around at the same time. /obj/effect/proc_holder/spell/aoe_turf/repulse/xeno //i fixed conflicts only to find out that this is in the WIZARD file instead of the xeno file?! diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index da6e6895049..a3c326abfa1 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -165,6 +165,10 @@ step(src, AM.dir) ..() +/atom/movable/proc/throw_at_fast(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0) + set waitfor = 0 + throw_at(target, range, speed, thrower, spin, diagonals_first) + /atom/movable/proc/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0) if(!target || !src || (flags & NODROP)) return 0 //use a modified version of Bresenham's algorithm to get from the atom's current position to that of the target diff --git a/code/game/data_huds.dm b/code/game/data_huds.dm index 7e25943ea11..3ae2e05f76d 100644 --- a/code/game/data_huds.dm +++ b/code/game/data_huds.dm @@ -45,7 +45,7 @@ hud_icons = list(ID_HUD, IMPTRACK_HUD, IMPLOYAL_HUD, IMPCHEM_HUD, WANTED_HUD) /datum/atom_hud/data/diagnostic - hud_icons = list (DIAG_HUD, DIAG_STAT_HUD, DIAG_BATT_HUD, DIAG_MECH_HUD) + hud_icons = list (DIAG_HUD, DIAG_STAT_HUD, DIAG_BATT_HUD, DIAG_MECH_HUD, DIAG_BOT_HUD) /* MED/SEC/DIAG HUD HOOKS */ @@ -248,4 +248,40 @@ var/image/holder = hud_list[DIAG_STAT_HUD] holder.icon_state = null if(internal_damage) - holder.icon_state = "hudwarn" \ No newline at end of file + holder.icon_state = "hudwarn" + +/*~~~~~~~~~ + Bots! +~~~~~~~~~~*/ +/mob/living/simple_animal/bot/proc/diag_hud_set_bothealth() + var/image/holder = hud_list[DIAG_HUD] + holder.icon_state = "huddiag[RoundDiagBar(health/maxHealth)]" + +/mob/living/simple_animal/bot/proc/diag_hud_set_botstat() //On (With wireless on or off), Off, EMP'ed + var/image/holder = hud_list[DIAG_STAT_HUD] + if(on) + holder.icon_state = "hudstat" + else if(stat) //Generally EMP causes this + holder.icon_state = "hudoffline" + else //Bot is off + holder.icon_state = "huddead2" + +/mob/living/simple_animal/bot/proc/diag_hud_set_botmode() //Shows a bot's current operation + var/image/holder = hud_list[DIAG_BOT_HUD] + if(client) //If the bot is player controlled, it will not be following mode logic! + holder.icon_state = "hudsentient" + return + + switch(mode) + if(BOT_SUMMON, BOT_RESPONDING) //Responding to PDA or AI summons + holder.icon_state = "hudcalled" + if(BOT_CLEANING, BOT_REPAIRING, BOT_HEALING) //Cleanbot cleaning, Floorbot fixing, or Medibot Healing + holder.icon_state = "hudworking" + if(BOT_PATROL, BOT_START_PATROL) //Patrol mode + holder.icon_state = "hudpatrol" + if(BOT_PREP_ARREST, BOT_ARREST, BOT_HUNT) //STOP RIGHT THERE, CRIMINAL SCUM! + holder.icon_state = "hudalert" + if(BOT_MOVING, BOT_DELIVER, BOT_GO_HOME, BOT_NAV) //Moving to target for normal bots, moving to deliver or go home for MULES. + holder.icon_state = "hudmove" + else + holder.icon_state = "" \ No newline at end of file diff --git a/code/game/gamemodes/cult/cult.dm b/code/game/gamemodes/cult/cult.dm index 952b6ed925c..cd0d3b4315a 100644 --- a/code/game/gamemodes/cult/cult.dm +++ b/code/game/gamemodes/cult/cult.dm @@ -183,6 +183,7 @@ if(!(cult_mind in cult) && is_convertable_to_cult(cult_mind)) cult_mind.current.Paralyse(5) cult += cult_mind + cult_mind.current.faction |= "cult" cult_mind.current.cult_add_comm() update_cult_icons_added(cult_mind) cult_mind.current.attack_log += "\[[time_stamp()]\] Has been converted to the cult!" @@ -200,6 +201,7 @@ /datum/game_mode/proc/remove_cultist(datum/mind/cult_mind, show_message = 1) if(cult_mind in cult) cult -= cult_mind + cult_mind.current.faction -= "cult" cult_mind.current.verbs -= /mob/living/proc/cult_innate_comm cult_mind.current.Paralyse(5) cult_mind.current << "An unfamiliar white light flashes through your mind, cleansing the taint of the Dark One and all your memories as its servant." diff --git a/code/game/gamemodes/cult/runes.dm b/code/game/gamemodes/cult/runes.dm index 19d682e3e1b..9be02034637 100644 --- a/code/game/gamemodes/cult/runes.dm +++ b/code/game/gamemodes/cult/runes.dm @@ -106,7 +106,7 @@ structure_check() searches for nearby cultist structures required for the invoca if(iscultist(L)) var/mob/living/carbon/human/H = L if(!istype(H)) - if(istype(L, /mob/living/simple_animal/construct)) + if(istype(L, /mob/living/simple_animal/hostile/construct)) if(invocation) L.say(invocation) cultists_in_range++ diff --git a/code/game/gamemodes/wizard/soulstone.dm b/code/game/gamemodes/wizard/soulstone.dm index 9638980408e..eee99d5d765 100644 --- a/code/game/gamemodes/wizard/soulstone.dm +++ b/code/game/gamemodes/wizard/soulstone.dm @@ -171,13 +171,13 @@ return switch(construct_class) if("Juggernaut") - makeNewConstruct(/mob/living/simple_animal/construct/armored, A, user) + makeNewConstruct(/mob/living/simple_animal/hostile/construct/armored, A, user, 0, T.loc) if("Wraith") - makeNewConstruct(/mob/living/simple_animal/construct/wraith, A, user) + makeNewConstruct(/mob/living/simple_animal/hostile/construct/wraith, A, user, 0, T.loc) if("Artificer") - makeNewConstruct(/mob/living/simple_animal/construct/builder, A, user) + makeNewConstruct(/mob/living/simple_animal/hostile/construct/builder, A, user, 0, T.loc) qdel(T) qdel(src) @@ -186,8 +186,8 @@ return -/proc/makeNewConstruct(mob/living/simple_animal/construct/ctype, mob/target, mob/stoner = null, cultoverride = 0, loc_override = null) - var/mob/living/simple_animal/construct/newstruct = new ctype((loc_override) ? (loc_override) : (get_turf(target))) +/proc/makeNewConstruct(mob/living/simple_animal/hostile/construct/ctype, mob/target, mob/stoner = null, cultoverride = 0, loc_override = null) + var/mob/living/simple_animal/hostile/construct/newstruct = new ctype((loc_override) ? (loc_override) : (get_turf(target))) newstruct.faction |= "\ref[stoner]" newstruct.key = target.key if(stoner && iscultist(stoner) || cultoverride) diff --git a/code/game/machinery/mass_driver.dm b/code/game/machinery/mass_driver.dm index cbae21bc11e..bb77e578741 100644 --- a/code/game/machinery/mass_driver.dm +++ b/code/game/machinery/mass_driver.dm @@ -26,8 +26,7 @@ audible_message("[src] lets out a screech, it doesn't seem to be able to handle the load.") break use_power(500) - spawn(0) - O.throw_at(target, drive_range * power, power) + O.throw_at_fast(target, drive_range * power, power) flick("mass_driver1", src) diff --git a/code/game/mecha/equipment/weapons/weapons.dm b/code/game/mecha/equipment/weapons/weapons.dm index ae89085fdb2..855408d7461 100644 --- a/code/game/mecha/equipment/weapons/weapons.dm +++ b/code/game/mecha/equipment/weapons/weapons.dm @@ -285,8 +285,7 @@ log_message("Launched a [O.name] from [name], targeting [target].") projectiles-- proj_init(O) - spawn(0) - O.throw_at(target, missile_range, missile_speed, spin = 0) + O.throw_at_fast(target, missile_range, missile_speed, spin = 0) return 1 //used for projectile initilisation (priming flashbang) and additional logging diff --git a/code/game/objects/explosion.dm b/code/game/objects/explosion.dm index bcc57984f30..3b013c70306 100644 --- a/code/game/objects/explosion.dm +++ b/code/game/objects/explosion.dm @@ -134,12 +134,11 @@ var/throw_dir = get_dir(epicenter,T) for(var/obj/item/I in T) - spawn(0) //Simultaneously not one at a time - if(I && !I.anchored) - var/throw_range = rand(throw_dist, max_range) - var/turf/throw_at = get_ranged_target_turf(I, throw_dir, throw_range) - I.throw_speed = 4 //Temporarily change their throw_speed for embedding purposes (Reset when it finishes throwing, regardless of hitting anything) - I.throw_at(throw_at, throw_range, 2)//Throw it at 2 speed, this is purely visual anyway. + if(I && !I.anchored) + var/throw_range = rand(throw_dist, max_range) + var/turf/throw_at = get_ranged_target_turf(I, throw_dir, throw_range) + I.throw_speed = 4 //Temporarily change their throw_speed for embedding purposes (Reset when it finishes throwing, regardless of hitting anything) + I.throw_at_fast(throw_at, throw_range, 2)//Throw it at 2 speed, this is purely visual anyway. var/took = (world.timeofday-start)/10 diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index b15607062af..bfbd12f0b99 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -467,10 +467,9 @@ var/global/image/fire_overlay = image("icon" = 'icons/effects/fire.dmi', "icon_s bloody_hands_mob = null /obj/item/singularity_pull(S, current_size) - spawn(0) //this is needed or multiple items will be thrown sequentially and not simultaneously - if(current_size >= STAGE_FOUR) - throw_at(S,14,3, spin=0) - else ..() + if(current_size >= STAGE_FOUR) + throw_at_fast(S,14,3, spin=0) + else ..() /obj/item/acid_act(acidpwr, acid_volume) . = 1 diff --git a/code/game/objects/items/weapons/pneumaticCannon.dm b/code/game/objects/items/weapons/pneumaticCannon.dm index 9b8516f8413..5d73339b164 100644 --- a/code/game/objects/items/weapons/pneumaticCannon.dm +++ b/code/game/objects/items/weapons/pneumaticCannon.dm @@ -116,12 +116,11 @@ add_logs(user, target, "fired at", src) playsound(src.loc, 'sound/weapons/sonic_jackhammer.ogg', 50, 1) for(var/obj/item/ITD in loadedItems) //Item To Discharge - spawn(0) - loadedItems.Remove(ITD) - loadedWeightClass -= ITD.w_class - ITD.throw_speed = pressureSetting * 2 - ITD.loc = get_turf(src) - ITD.throw_at(target, pressureSetting * 5, pressureSetting * 2,user) + loadedItems.Remove(ITD) + loadedWeightClass -= ITD.w_class + ITD.throw_speed = pressureSetting * 2 + ITD.loc = get_turf(src) + ITD.throw_at_fast(target, pressureSetting * 5, pressureSetting * 2,user) if(pressureSetting >= 3 && user) user.visible_message("[user] is thrown down by the force of the cannon!", "[src] slams into your shoulder, knocking you down!") user.Weaken(3) diff --git a/code/game/objects/items/weapons/storage/wallets.dm b/code/game/objects/items/weapons/storage/wallets.dm index d5483c8d8d0..c7da0007656 100644 --- a/code/game/objects/items/weapons/storage/wallets.dm +++ b/code/game/objects/items/weapons/storage/wallets.dm @@ -30,21 +30,31 @@ slot_flags = SLOT_ID var/obj/item/weapon/card/id/front_id = null + var/list/combined_access = list() /obj/item/weapon/storage/wallet/remove_from_storage(obj/item/W, atom/new_location) . = ..(W, new_location) if(.) - if(W == front_id) - front_id = null + if(istype(W, /obj/item/weapon/card/id)) + if(W == front_id) + front_id = null + refreshID() update_icon() +/obj/item/weapon/storage/wallet/proc/refreshID() + combined_access.Cut() + for(var/obj/item/weapon/card/id/I in contents) + if(!front_id) + front_id = I + update_icon() + combined_access |= I.access + /obj/item/weapon/storage/wallet/handle_item_insertion(obj/item/W, prevent_warning = 0) . = ..(W, prevent_warning) if(.) - if(!front_id && istype(W, /obj/item/weapon/card/id)) - front_id = W - update_icon() + if(istype(W, /obj/item/weapon/card/id)) + refreshID() /obj/item/weapon/storage/wallet/update_icon() @@ -69,9 +79,8 @@ return front_id /obj/item/weapon/storage/wallet/GetAccess() - var/obj/item/I = GetID() - if(I) - return I.GetAccess() + if(combined_access.len) + return combined_access else return ..() @@ -89,4 +98,4 @@ if(item2_type) new item2_type(src) if(item3_type) - new item3_type(src) \ No newline at end of file + new item3_type(src) diff --git a/code/modules/admin/IsBanned.dm b/code/modules/admin/IsBanned.dm index 19eff86457e..4b468866d9f 100644 --- a/code/modules/admin/IsBanned.dm +++ b/code/modules/admin/IsBanned.dm @@ -4,6 +4,10 @@ if (!key || !address || !computer_id) log_access("Failed Login (invalid data): [key] [address]-[computer_id]") return list("reason"="invalid login data", "desc"="Error: Could not check ban status, Please try again. Error message: Your computer provided invalid or blank information to the server on connection (byond username, IP, and Computer ID.) Provided information for reference: Username:'[key]' IP:'[address]' Computer ID:'[computer_id]'. (If you continue to get this error, please restart byond or contact byond support.)") + + if (computer_id == 2147483647) //this cid causes stickybans to go haywire + log_access("Failed Login (invalid cid): [key] [address]-[computer_id]") + return list("reason"="invalid login data", "desc"="Error: Could not check ban status, Please try again. Error message: Your computer provided an invalid Computer ID.)") var/admin = 0 var/ckey = ckey(key) if((ckey in admin_datums) || (ckey in deadmins)) diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index 41b09e52cbd..fb19826c0d3 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -400,9 +400,9 @@ if("coffee") M.change_mob_type( /mob/living/simple_animal/crab/Coffee , null, null, delmob ) if("parrot") M.change_mob_type( /mob/living/simple_animal/parrot , null, null, delmob ) if("polyparrot") M.change_mob_type( /mob/living/simple_animal/parrot/Poly , null, null, delmob ) - if("constructarmored") M.change_mob_type( /mob/living/simple_animal/construct/armored , null, null, delmob ) - if("constructbuilder") M.change_mob_type( /mob/living/simple_animal/construct/builder , null, null, delmob ) - if("constructwraith") M.change_mob_type( /mob/living/simple_animal/construct/wraith , null, null, delmob ) + if("constructarmored") M.change_mob_type( /mob/living/simple_animal/hostile/construct/armored , null, null, delmob ) + if("constructbuilder") M.change_mob_type( /mob/living/simple_animal/hostile/construct/builder , null, null, delmob ) + if("constructwraith") M.change_mob_type( /mob/living/simple_animal/hostile/construct/wraith , null, null, delmob ) if("shade") M.change_mob_type( /mob/living/simple_animal/shade , null, null, delmob ) diff --git a/code/modules/awaymissions/mission_code/stationCollision.dm b/code/modules/awaymissions/mission_code/stationCollision.dm index ac53dca5b18..3805af7cb1c 100644 --- a/code/modules/awaymissions/mission_code/stationCollision.dm +++ b/code/modules/awaymissions/mission_code/stationCollision.dm @@ -163,7 +163,7 @@ var/sc_safecode5 = "[rand(0,9)]" desc = "Your body becomes weak and your feel your mind slipping away as you try to comprehend what you know can't be possible." move_self = 0 //Contianed narsie does not move! grav_pull = 0 //Contained narsie does not pull stuff in! - var/uneatable = list(/turf/space, /obj/effect/overlay, /mob/living/simple_animal/construct) + var/uneatable = list(/turf/space, /obj/effect/overlay, /mob/living/simple_animal/hostile/construct) //Override this to prevent no adminlog runtimes and admin warnings about a singularity without containment /obj/singularity/narsie/sc_Narsie/admin_investigate_setup() return diff --git a/code/modules/food&drinks/kitchen machinery/gibber.dm b/code/modules/food&drinks/kitchen machinery/gibber.dm index 1e796de56c0..79f11788a74 100644 --- a/code/modules/food&drinks/kitchen machinery/gibber.dm +++ b/code/modules/food&drinks/kitchen machinery/gibber.dm @@ -207,7 +207,7 @@ var/list/nearby_turfs = orange(3, get_turf(src)) var/obj/item/meatslab = allmeat[i] meatslab.loc = src.loc - meatslab.throw_at(pick(nearby_turfs),i,3) + meatslab.throw_at_fast(pick(nearby_turfs),i,3) for (var/turfs=1 to meat_produced*3) var/turf/gibturf = pick(nearby_turfs) if (!gibturf.density && src in viewers(gibturf)) diff --git a/code/modules/library/lib_machines.dm b/code/modules/library/lib_machines.dm index d8f08e5eddb..ae9ec6cf95f 100644 --- a/code/modules/library/lib_machines.dm +++ b/code/modules/library/lib_machines.dm @@ -316,7 +316,7 @@ var/global/list/datum/cachedbook/cachedbooks // List of our cached book datums usr << browse(null, "window=library") onclose(usr, "library") return - if(href_list["page"] && screenstate == 4 && isnum(href_list["page"])) + if(href_list["page"] && screenstate == 4) page = text2num(href_list["page"]) if(href_list["switchscreen"]) switch(href_list["switchscreen"]) diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 28dee2912aa..f1754abcbd5 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -766,7 +766,7 @@ Sorry Giacom. Please don't be mad :( /mob/living/narsie_act() if(client) - makeNewConstruct(/mob/living/simple_animal/construct/harvester, src, null, 0) + makeNewConstruct(/mob/living/simple_animal/hostile/construct/harvester, src, null, 0) spawn_dust() gib() return diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm index 1115cb8aeb8..642634e0032 100644 --- a/code/modules/mob/living/silicon/ai/ai.dm +++ b/code/modules/mob/living/silicon/ai/ai.dm @@ -517,15 +517,16 @@ var/list/ai_list = list() var/ai_Zlevel = ai_current_turf.z var/d var/area/bot_area - d += "Query network status
" + d += "Query network status
" d += "" for (Bot in living_mob_list) if(Bot.z == ai_Zlevel && !Bot.remote_disabled) //Only non-emagged bots on the same Z-level are detected! bot_area = get_area(Bot) - d += "" + var/bot_mode = Bot.get_mode() + d += "" //If the bot is on, it will display the bot's current mode status. If the bot is not mode, it will just report "Idle". "Inactive if it is not on at all. - d += "" + d += "" d += "" d += "" d += "" diff --git a/code/modules/mob/living/simple_animal/bot/bot.dm b/code/modules/mob/living/simple_animal/bot/bot.dm index a4600e376e6..a97048584aa 100644 --- a/code/modules/mob/living/simple_animal/bot/bot.dm +++ b/code/modules/mob/living/simple_animal/bot/bot.dm @@ -1,26 +1,4 @@ -#define BOT_STEP_DELAY 4 //Delay between movemements - -#define DEFAULT_SCAN_RANGE 7 //default view range for finding targets. - -//Mode defines -#define BOT_IDLE 0 // idle -#define BOT_HUNT 1 // found target, hunting -#define BOT_PREP_ARREST 2 // at target, preparing to arrest -#define BOT_ARREST 3 // arresting target -#define BOT_START_PATROL 4 // start patrol -#define BOT_PATROL 5 // patrolling -#define BOT_SUMMON 6 // summoned by PDA -#define BOT_CLEANING 7 // cleaning (cleanbots) -#define BOT_REPAIRING 8 // repairing hull breaches (floorbots) -#define BOT_MOVING 9 // for clean/floor/med bots, when moving. -#define BOT_HEALING 10 // healing people (medbots) -#define BOT_RESPONDING 11 // responding to a call from the AI -#define BOT_DELIVER 12 // moving to deliver -#define BOT_GO_HOME 13 // returning to home -#define BOT_BLOCKED 14 // blocked -#define BOT_NAV 15 // computing navigation -#define BOT_WAIT_FOR_NAV 16 // waiting for nav computation -#define BOT_NO_ROUTE 17 // no destination beacon found (or no route) +//Defines for bots are now found in code\__DEFINES\bots.dm // AI (i.e. game AI, not the AI player) controlled bots /mob/living/simple_animal/bot @@ -92,17 +70,24 @@ "Waiting for clear path", "Calculating navigation path", "Pinging beacon network", "Unable to reach destination") //This holds text for what the bot is mode doing, reported on the remote bot control interface. + hud_possible = list(DIAG_STAT_HUD, DIAG_BOT_HUD, DIAG_HUD) //Diagnostic HUD views + /mob/living/simple_animal/bot/proc/get_mode() - if(!mode) - return "Idle" + if(client) //Player bots do not have modes, thus the override. Also an easy way for PDA users/AI to know when a bot is a player. + return "Sentient" + else if(!on) + return "Inactive" + else if(!mode) + return "Idle" else - return mode_name[mode] + return "[mode_name[mode]]" /mob/living/simple_animal/bot/proc/turn_on() if(stat) return 0 on = 1 SetLuminosity(initial(luminosity)) update_icon() + diag_hud_set_botstat() return 1 /mob/living/simple_animal/bot/proc/turn_off() @@ -125,6 +110,13 @@ bot_core = new bot_core_type(src) + prepare_huds() + var/datum/atom_hud/data/diagnostic/diag_hud = huds[DATA_HUD_DIAGNOSTIC] + diag_hud.add_to_hud(src) + diag_hud_set_bothealth() + diag_hud_set_botstat() + diag_hud_set_botmode() + /mob/living/simple_animal/bot/update_canmove() . = ..() if(!on) @@ -181,8 +173,13 @@ new /obj/effect/decal/cleanable/oil(loc) return ..(amount) +/mob/living/simple_animal/bot/updatehealth() + ..() + diag_hud_set_bothealth() + /mob/living/simple_animal/bot/handle_automated_action() //Master process which handles code common across most bots. set background = BACKGROUND_ENABLED + diag_hud_set_botmode() if(!on || client) return @@ -280,7 +277,7 @@ text_dehack_fail = "You fail to reset [name]." /mob/living/simple_animal/bot/attack_ai(mob/user as mob) - attack_hand(user) + show_controls(user) /mob/living/simple_animal/bot/proc/speak(message,channel) //Pass a message to have the bot say() it. Pass a frequency to say it on the radio. if((!on) || (!message)) @@ -376,7 +373,7 @@ Pass a positive integer as an argument to override a bot's default speed. path = list() return 0 var/step_count = move_speed ? move_speed : base_speed //If a value is passed into move_speed, use that instead of the default speed var. - + if(step_count >= 1 && tries < 4) for(var/step_number = 0, step_number < step_count,step_number++) spawn(BOT_STEP_DELAY*step_number) @@ -453,6 +450,8 @@ Pass a positive integer as an argument to override a bot's default speed. access_card.access = prev_access tries = 0 mode = BOT_IDLE + diag_hud_set_botstat() + diag_hud_set_botmode() @@ -709,13 +708,12 @@ Pass a positive integer as an argument to override a bot's default speed. //No ..() to prevent strip panel showing up - Todo: make that saner if(topic_denied(usr)) usr << "[src]'s interface is not responding!" - href_list = list() - return + return 1 add_fingerprint(usr) if(href_list["close"])// HUE HUE if(usr in users) users.Remove(usr) - return + return 1 if((href_list["power"]) && (bot_core.allowed(usr) || !locked)) if (on) turn_off() @@ -761,12 +759,11 @@ Pass a positive integer as an argument to override a bot's default speed. /mob/living/simple_animal/bot/proc/topic_denied(mob/user) //Access check proc for bot topics! Remember to place in a bot's individual Topic if desired. // 0 for access, 1 for denied. if(emagged == 2) //An emagged bot cannot be controlled by humans, silicons can if one hacked it. - if(hacked) //Manually emagged by a human - access denied to all. + if(!hacked) //Manually emagged by a human - access denied to all. return 1 else if(!issilicon(user) || IsAdminGhost(user)) //Bot is hacked, so only silicons and admins are allowed access. return 1 - else - return 0 + return 0 /mob/living/simple_animal/bot/proc/hack(mob/user) var/hack @@ -780,6 +777,7 @@ Pass a positive integer as an argument to override a bot's default speed. /mob/living/simple_animal/bot/Login() . = ..() access_card.access += player_access + diag_hud_set_botmode() /mob/living/simple_animal/bot/Logout() . = ..() diff --git a/code/modules/mob/living/simple_animal/bot/cleanbot.dm b/code/modules/mob/living/simple_animal/bot/cleanbot.dm index f018b94fb74..ff680cf7131 100644 --- a/code/modules/mob/living/simple_animal/bot/cleanbot.dm +++ b/code/modules/mob/living/simple_animal/bot/cleanbot.dm @@ -231,7 +231,8 @@ text("[on ? "On" : "Off"]")) return dat /mob/living/simple_animal/bot/cleanbot/Topic(href, href_list) - ..() + if(..()) + return 1 switch(href_list["operation"]) if("blood") blood =!blood diff --git a/code/modules/mob/living/simple_animal/bot/ed209bot.dm b/code/modules/mob/living/simple_animal/bot/ed209bot.dm index b787b2d4bc8..f8a304ad3e3 100644 --- a/code/modules/mob/living/simple_animal/bot/ed209bot.dm +++ b/code/modules/mob/living/simple_animal/bot/ed209bot.dm @@ -130,7 +130,8 @@ Auto Patrol[]"}, return else if((lasercolor == "r") && (istype(H.wear_suit, /obj/item/clothing/suit/bluetag))) return - ..() + if(..()) + return 1 switch(href_list["operation"]) if ("idcheck") @@ -149,19 +150,27 @@ Auto Patrol[]"}, declare_arrests = !declare_arrests update_controls() +/mob/living/simple_animal/bot/ed209/proc/retaliate(mob/living/carbon/human/H) + threatlevel = H.assess_threat(src) + threatlevel += 6 + if(threatlevel >= 4) + target = H + mode = BOT_HUNT + +/mob/living/simple_animal/bot/ed209/attack_hand(mob/living/carbon/human/H) + if(H.a_intent == "harm") + retaliate(H) + return ..() + /mob/living/simple_animal/bot/ed209/attackby(obj/item/weapon/W, mob/user, params) ..() if(istype(W, /obj/item/weapon/weldingtool) && user.a_intent != "harm") // Any intent but harm will heal, so we shouldn't get angry. return if (!istype(W, /obj/item/weapon/screwdriver) && (!target)) // Added check for welding tool to fix #2432. Welding tool behavior is handled in superclass. if(W.force && W.damtype != STAMINA)//If force is non-zero and damage type isn't stamina. - threatlevel = user.assess_threat(src) - threatlevel += 6 - if(threatlevel >= 4) - target = user - if(lasercolor)//To make up for the fact that lasertag bots don't hunt - shootAt(user) - mode = BOT_HUNT + retaliate(user) + if(lasercolor)//To make up for the fact that lasertag bots don't hunt + shootAt(user) /mob/living/simple_animal/bot/ed209/Emag(mob/user) ..() @@ -178,11 +187,7 @@ Auto Patrol[]"}, if(istype(Proj ,/obj/item/projectile/beam)||istype(Proj,/obj/item/projectile/bullet)) if((Proj.damage_type == BURN) || (Proj.damage_type == BRUTE)) if (!Proj.nodamage && Proj.damage < src.health) - threatlevel = Proj.firer.assess_threat(src) - threatlevel += 6 - if(threatlevel >= 4) - target = Proj.firer - mode = BOT_HUNT + retaliate(Proj.firer) ..() /mob/living/simple_animal/bot/ed209/handle_automated_action() @@ -522,10 +527,7 @@ Auto Patrol[]"}, /mob/living/simple_animal/bot/ed209/RangedAttack(atom/A) if(!on) return - if(ismob(A)) - shootAt(A) - else - ..() + shootAt(A) /mob/living/simple_animal/bot/ed209/proc/stun_attack(mob/living/carbon/C) playsound(loc, 'sound/weapons/Egloves.ogg', 50, 1, -1) diff --git a/code/modules/mob/living/simple_animal/bot/floorbot.dm b/code/modules/mob/living/simple_animal/bot/floorbot.dm index 8e36d9fb65b..a8c3c93aaa5 100644 --- a/code/modules/mob/living/simple_animal/bot/floorbot.dm +++ b/code/modules/mob/living/simple_animal/bot/floorbot.dm @@ -118,7 +118,9 @@ user << "[src] buzzes and beeps." /mob/living/simple_animal/bot/floorbot/Topic(href, href_list) - ..() + if(..()) + return 1 + switch(href_list["operation"]) if("replace") replacetiles = !replacetiles diff --git a/code/modules/mob/living/simple_animal/bot/medbot.dm b/code/modules/mob/living/simple_animal/bot/medbot.dm index 8eda5b8fd3c..3a9460174ec 100644 --- a/code/modules/mob/living/simple_animal/bot/medbot.dm +++ b/code/modules/mob/living/simple_animal/bot/medbot.dm @@ -157,7 +157,8 @@ return dat /mob/living/simple_animal/bot/medbot/Topic(href, href_list) - ..() + if(..()) + return 1 if(href_list["adj_threshold"]) var/adjust_num = text2num(href_list["adj_threshold"]) diff --git a/code/modules/mob/living/simple_animal/bot/secbot.dm b/code/modules/mob/living/simple_animal/bot/secbot.dm index a6f4bcaeb1b..49c59f60a18 100644 --- a/code/modules/mob/living/simple_animal/bot/secbot.dm +++ b/code/modules/mob/living/simple_animal/bot/secbot.dm @@ -106,8 +106,8 @@ Auto Patrol: []"}, return dat /mob/living/simple_animal/bot/secbot/Topic(href, href_list) - - ..() + if(..()) + return 1 switch(href_list["operation"]) if("idcheck") @@ -126,16 +126,24 @@ Auto Patrol: []"}, declare_arrests = !declare_arrests update_controls() +/mob/living/simple_animal/bot/secbot/proc/retaliate(mob/living/carbon/human/H) + threatlevel = H.assess_threat(src) + threatlevel += 6 + if(threatlevel >= 4) + target = H + mode = BOT_HUNT + +/mob/living/simple_animal/bot/secbot/attack_hand(mob/living/carbon/human/H) + if(H.a_intent == "harm") + retaliate(H) + return ..() + /mob/living/simple_animal/bot/secbot/attackby(obj/item/weapon/W, mob/user, params) ..() if(istype(W, /obj/item/weapon/weldingtool) && user.a_intent != "harm") // Any intent but harm will heal, so we shouldn't get angry. return if(!istype(W, /obj/item/weapon/screwdriver) && (W.force) && (!target) && (W.damtype != STAMINA) ) // Added check for welding tool to fix #2432. Welding tool behavior is handled in superclass. - threatlevel = user.assess_threat(src) - threatlevel += 6 - if(threatlevel >= 4) - target = user - mode = BOT_HUNT + retaliate(user) /mob/living/simple_animal/bot/secbot/Emag(mob/user) ..() @@ -152,11 +160,7 @@ Auto Patrol: []"}, if(istype(Proj ,/obj/item/projectile/beam)||istype(Proj,/obj/item/projectile/bullet)) if((Proj.damage_type == BURN) || (Proj.damage_type == BRUTE)) if (!Proj.nodamage && Proj.damage < src.health) - threatlevel = Proj.firer.assess_threat(src) - threatlevel += 6 - if(threatlevel >= 4) - target = Proj.firer - mode = BOT_HUNT + retaliate(Proj.firer) ..() diff --git a/code/modules/mob/living/simple_animal/constructs.dm b/code/modules/mob/living/simple_animal/constructs.dm index 5dc4c2c0f5e..ee584f7cbbe 100644 --- a/code/modules/mob/living/simple_animal/constructs.dm +++ b/code/modules/mob/living/simple_animal/constructs.dm @@ -1,9 +1,8 @@ -/mob/living/simple_animal/construct +/mob/living/simple_animal/hostile/construct name = "Construct" real_name = "Construct" desc = "" speak_emote = list("hisses") - emote_hear = list("wails.","screeches.") response_help = "thinks better of touching" response_disarm = "flails at" response_harm = "punches" @@ -14,7 +13,6 @@ stop_automated_movement = 1 status_flags = CANPUSH attack_sound = 'sound/weapons/punch1.ogg' - environment_smash = 1 see_in_dark = 7 damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 0, CLONE = 0, STAMINA = 0, OXY = 0) 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) @@ -23,17 +21,19 @@ healable = 0 faction = list("cult") flying = 1 + pressure_resistance = 200 unique_name = 1 + AIStatus = AI_OFF //normal constructs don't have AI var/list/construct_spells = list() - var/playstyle_string = "You are a generic construct! Your job is to not exist." + var/playstyle_string = "You are a generic construct! Your job is to not exist, and you should probably adminhelp this." -/mob/living/simple_animal/construct/New() +/mob/living/simple_animal/hostile/construct/New() ..() for(var/spell in construct_spells) AddSpell(new spell(null)) -/mob/living/simple_animal/construct/death() +/mob/living/simple_animal/hostile/construct/death() ..(1) new /obj/item/weapon/ectoplasm (src.loc) visible_message("[src] collapses in a shattered heap.") @@ -41,7 +41,7 @@ qdel(src) return -/mob/living/simple_animal/construct/examine(mob/user) +/mob/living/simple_animal/hostile/construct/examine(mob/user) var/msg = "*---------*\nThis is \icon[src] \a [src]!\n" if (src.health < src.maxHealth) msg += "" @@ -54,17 +54,17 @@ user << msg -/mob/living/simple_animal/construct/attack_animal(mob/living/simple_animal/M) - if(istype(M, /mob/living/simple_animal/construct/builder)) +/mob/living/simple_animal/hostile/construct/attack_animal(mob/living/simple_animal/M) + if(istype(M, /mob/living/simple_animal/hostile/construct/builder)) if(health < maxHealth) adjustBruteLoss(-5) if(src != M) Beam(M,icon_state="sendbeam",icon='icons/effects/effects.dmi',time=4) M.visible_message("[M] repairs some of \the [src]'s dents.", \ - "You repair some of [src]'s dents, leaving [src] at [health]/[maxHealth] health.") + "You repair some of [src]'s dents, leaving [src] at [health]/[maxHealth] health.") else M.visible_message("[M] repairs some of its own dents.", \ - "You repair some of your own dents, leaving you at [M.health]/[M.maxHealth] health.") + "You repair some of your own dents, leaving you at [M.health]/[M.maxHealth] health.") else if(src != M) M << "You cannot repair [src]'s dents, as it has none!" @@ -73,16 +73,16 @@ else if(src != M) ..() -/mob/living/simple_animal/construct/Process_Spacemove(movement_dir = 0) +/mob/living/simple_animal/hostile/construct/Process_Spacemove(movement_dir = 0) return 1 -/mob/living/simple_animal/construct/narsie_act() +/mob/living/simple_animal/hostile/construct/narsie_act() return /////////////////Juggernaut/////////////// -/mob/living/simple_animal/construct/armored +/mob/living/simple_animal/hostile/construct/armored name = "Juggernaut" real_name = "Juggernaut" desc = "A massive, armored construct built to spearhead attacks and soak up enemy fire." @@ -90,7 +90,7 @@ icon_living = "behemoth" maxHealth = 250 health = 250 - response_harm = "harmlessly punches" + response_harm = "harmlessly punches" harm_intent_damage = 0 melee_damage_lower = 30 melee_damage_upper = 30 @@ -105,7 +105,11 @@ playstyle_string = "You are a Juggernaut. Though slow, your shell can withstand extreme punishment, \ create shield walls, rip apart enemies and walls alike, and even deflect energy weapons." -/mob/living/simple_animal/construct/armored/bullet_act(obj/item/projectile/P) +/mob/living/simple_animal/hostile/construct/armored/hostile //actually hostile, will move around, hit things + AIStatus = AI_ON + environment_smash = 1 //only token destruction, don't smash the cult wall NO STOP + +/mob/living/simple_animal/hostile/construct/armored/bullet_act(obj/item/projectile/P) if(istype(P, /obj/item/projectile/energy) || istype(P, /obj/item/projectile/beam)) var/reflectchance = 80 - round(P.damage/3) if(prob(reflectchance)) @@ -134,7 +138,7 @@ ////////////////////////Wraith///////////////////////////////////////////// -/mob/living/simple_animal/construct/wraith +/mob/living/simple_animal/hostile/construct/wraith name = "Wraith" real_name = "Wraith" desc = "A wicked, clawed shell constructed to assassinate enemies and sow chaos behind enemy lines." @@ -144,15 +148,19 @@ health = 75 melee_damage_lower = 25 melee_damage_upper = 25 + retreat_distance = 2 //AI wraiths will move in and out of combat attacktext = "slashes" attack_sound = 'sound/weapons/bladeslice.ogg' construct_spells = list(/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/shift) playstyle_string = "You are a Wraith. Though relatively fragile, you are fast, deadly, and even able to phase through walls." +/mob/living/simple_animal/hostile/construct/wraith/hostile //actually hostile, will move around, hit things + AIStatus = AI_ON + /////////////////////////////Artificer///////////////////////// -/mob/living/simple_animal/construct/builder +/mob/living/simple_animal/hostile/construct/builder name = "Artificer" real_name = "Artificer" desc = "A bulbous construct dedicated to building and maintaining the Cult of Nar-Sie's armies." @@ -164,6 +172,8 @@ harm_intent_damage = 5 melee_damage_lower = 5 melee_damage_upper = 5 + retreat_distance = 10 + minimum_distance = 10 //AI artificers will flee like fuck attacktext = "rams" environment_smash = 2 attack_sound = 'sound/weapons/punch2.ogg' @@ -177,10 +187,52 @@ and, most important of all, create new constructs by producing soulstones to capture souls, \ and shells to place those soulstones into." +/mob/living/simple_animal/hostile/construct/builder/Found(atom/A) //what have we found here? + if(istype(A, /mob/living/simple_animal/hostile/construct)) //is it a construct? + var/mob/living/simple_animal/hostile/construct/C = A + if(C.health < C.maxHealth) //is it hurt? let's go heal it if it is + return 1 + else + return 0 + else + return 0 + +/mob/living/simple_animal/hostile/construct/builder/CanAttack(atom/the_target) + if(see_invisible < the_target.invisibility)//Target's invisible to us, forget it + return 0 + if(Found(the_target) || ..()) //If we Found it or Can_Attack it normally, we Can_Attack it as long as it wasn't invisible + return 1 //as a note this shouldn't be added to base hostile mobs because it'll mess up retaliate hostile mobs + +/mob/living/simple_animal/hostile/construct/builder/MoveToTarget(var/list/possible_targets) + ..() + if(isliving(target)) + var/mob/living/L = target + if(istype(L, /mob/living/simple_animal/hostile/construct) && L.health >= L.maxHealth) //is this target an unhurt construct? stop trying to heal it + LoseTarget() + return 0 + if(L.health <= melee_damage_lower+melee_damage_upper) //ey bucko you're hurt as fuck let's go hit you + retreat_distance = null + minimum_distance = 1 + +/mob/living/simple_animal/hostile/construct/builder/Aggro() + ..() + if(istype(target, /mob/living/simple_animal/hostile/construct)) //oh the target is a construct no need to flee + retreat_distance = null + minimum_distance = 1 + +/mob/living/simple_animal/hostile/construct/builder/LoseAggro() + ..() + retreat_distance = initial(retreat_distance) + minimum_distance = initial(minimum_distance) + +/mob/living/simple_animal/hostile/construct/builder/hostile //actually hostile, will move around, hit things, heal other constructs + AIStatus = AI_ON + environment_smash = 1 //only token destruction, don't smash the cult wall NO STOP + /////////////////////////////Harvester///////////////////////// -/mob/living/simple_animal/construct/harvester +/mob/living/simple_animal/hostile/construct/harvester name = "Harvester" real_name = "Harvester" desc = "A long, thin construct built to herald Nar-Sie's rise. It'll be all over soon." @@ -190,9 +242,16 @@ health = 60 melee_damage_lower = 1 melee_damage_upper = 5 + retreat_distance = 2 //AI harvesters will move in and out of combat, like wraiths, but shittier attacktext = "prods" + environment_smash = 3 attack_sound = 'sound/weapons/tap.ogg' - construct_spells = list(/obj/effect/proc_holder/spell/targeted/smoke/disable) + construct_spells = list(/obj/effect/proc_holder/spell/aoe_turf/conjure/wall, + /obj/effect/proc_holder/spell/aoe_turf/conjure/floor, + /obj/effect/proc_holder/spell/targeted/smoke/disable) playstyle_string = "You are a Harvester. You are not strong, but your powers of domination will assist you in your role: \ Bring those who still cling to this world of illusion back to the Geometer so they may know Truth." +/mob/living/simple_animal/hostile/construct/harvester/hostile //actually hostile, will move around, hit things + AIStatus = AI_ON + environment_smash = 1 //only token destruction, don't smash the cult wall NO STOP diff --git a/code/modules/mob/living/simple_animal/hostile/hostile.dm b/code/modules/mob/living/simple_animal/hostile/hostile.dm index 2b11da4eda2..31ae1247d0a 100644 --- a/code/modules/mob/living/simple_animal/hostile/hostile.dm +++ b/code/modules/mob/living/simple_animal/hostile/hostile.dm @@ -182,7 +182,7 @@ /mob/living/simple_animal/hostile/adjustBruteLoss(damage) ..(damage) - if(!ckey && !stat && search_objects < 3)//Not unconscious, and we don't ignore mobs + if(!ckey && !stat && search_objects < 3 && damage > 0)//Not unconscious, and we don't ignore mobs 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 @@ -221,10 +221,13 @@ /mob/living/simple_animal/hostile/proc/summon_backup(distance) do_alert_animation(src) playsound(loc, 'sound/machines/chime.ogg', 50, 1, -1) - for (var/mob/living/simple_animal/hostile/M in oview(distance, src)) + for(var/mob/living/simple_animal/hostile/M in oview(distance, src)) var/list/L = M.faction&faction if(L.len) - M.Goto(src,M.move_to_delay,M.minimum_distance) + if(M.AIStatus == AI_OFF) + return + else + M.Goto(src,M.move_to_delay,M.minimum_distance) /mob/living/simple_animal/hostile/proc/OpenFire(atom/A) diff --git a/code/modules/mob/living/simple_animal/morph/morph.dm b/code/modules/mob/living/simple_animal/morph/morph.dm index 01653d3731c..784b7df12b6 100644 --- a/code/modules/mob/living/simple_animal/morph/morph.dm +++ b/code/modules/mob/living/simple_animal/morph/morph.dm @@ -37,11 +37,11 @@ var/morph_time = 0 var/playstyle_string = "You are a morph, an abomination of science created primarily with changeling cells. \ - You may take the form of anything nearby by middle-clicking it. This process will alert any nearby \ + You may take the form of anything nearby by shift-clicking it. This process will alert any nearby \ observers, and can only be performed once every five seconds. While morphed, you move faster, but do \ less damage. In addition, anyone within three tiles will note an uncanny wrongness if examining you. \ You can attack any item or dead creature to consume it - creatures will fully restore your health. \ - Finally, you can restore yourself to your original form while morphed by middle-clicking yourself." + Finally, you can restore yourself to your original form while morphed by shift-clicking yourself." /mob/living/simple_animal/hostile/morph/examine(mob/user) if(morphed) diff --git a/code/modules/mob/living/simple_animal/revenant/revenant_spawn_event.dm b/code/modules/mob/living/simple_animal/revenant/revenant_spawn_event.dm index d21e9c04b03..ba32dba49ed 100644 --- a/code/modules/mob/living/simple_animal/revenant/revenant_spawn_event.dm +++ b/code/modules/mob/living/simple_animal/revenant/revenant_spawn_event.dm @@ -4,7 +4,7 @@ name = "Spawn Revenant" typepath = /datum/round_event/revenant weight = 7 - max_occurrences = 3 + max_occurrences = 1 earliest_start = 6000 //Meant to mix things up early-game. diff --git a/code/modules/mob/transform_procs.dm b/code/modules/mob/transform_procs.dm index 404ccc92e8d..f4dc55f7dbf 100644 --- a/code/modules/mob/transform_procs.dm +++ b/code/modules/mob/transform_procs.dm @@ -536,7 +536,7 @@ if(!MP) return 0 //Sanity, this should never happen. - if(ispath(MP, /mob/living/simple_animal/construct)) + if(ispath(MP, /mob/living/simple_animal/hostile/construct)) return 0 //Verbs do not appear for players. //Good mobs! diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm index c13223cd31e..55e57887ba6 100644 --- a/code/modules/power/apc.dm +++ b/code/modules/power/apc.dm @@ -1137,9 +1137,13 @@ lighting = 0 equipment = 0 environ = 0 + update_icon() + update() spawn(600) equipment = 3 environ = 3 + update_icon() + update() ..() /obj/machinery/power/apc/ex_act(severity, target) diff --git a/code/modules/power/singularity/narsie.dm b/code/modules/power/singularity/narsie.dm index 78564886196..a7eb8fac14b 100644 --- a/code/modules/power/singularity/narsie.dm +++ b/code/modules/power/singularity/narsie.dm @@ -39,7 +39,7 @@ /obj/singularity/narsie/large/attack_ghost(mob/dead/observer/user as mob) - makeNewConstruct(/mob/living/simple_animal/construct/harvester, user, null, 0, loc_override = src.loc) + makeNewConstruct(/mob/living/simple_animal/hostile/construct/harvester, user, null, 0, loc_override = src.loc) PoolOrNew(/obj/effect/particle_effect/smoke/sleeping, src.loc) diff --git a/code/modules/recycling/disposal-structures.dm b/code/modules/recycling/disposal-structures.dm index 7ea048f1bf3..24e12478be0 100644 --- a/code/modules/recycling/disposal-structures.dm +++ b/code/modules/recycling/disposal-structures.dm @@ -278,9 +278,7 @@ for(var/atom/movable/AM in H) AM.loc = T AM.pipe_eject(direction) - spawn(1) - if(AM) - AM.throw_at(target, 10, 1) + AM.throw_at_fast(target, 10, 1) else // no specified direction, so throw in random direction @@ -291,9 +289,7 @@ AM.loc = T AM.pipe_eject(0) - spawn(1) - if(AM) - AM.throw_at(target, 5, 1) + AM.throw_at_fast(target, 5, 1) H.vent_gas(T) qdel(H) return @@ -800,9 +796,7 @@ for(var/atom/movable/AM in H) AM.loc = src.loc AM.pipe_eject(dir) - spawn(5) - if(AM) - AM.throw_at(target, eject_range, 1) + AM.throw_at_fast(target, eject_range, 1) H.vent_gas(src.loc) qdel(H) return diff --git a/code/modules/recycling/disposal-unit.dm b/code/modules/recycling/disposal-unit.dm index 74be5a2317d..ed95abc4232 100644 --- a/code/modules/recycling/disposal-unit.dm +++ b/code/modules/recycling/disposal-unit.dm @@ -258,9 +258,7 @@ AM.loc = src.loc AM.pipe_eject(0) - spawn(1) - if(AM) - AM.throw_at(target, 5, 1) + AM.throw_at_fast(target, 5, 1) H.vent_gas(loc) qdel(H) diff --git a/code/modules/research/experimentor.dm b/code/modules/research/experimentor.dm index 8b058c4096c..346264b7354 100644 --- a/code/modules/research/experimentor.dm +++ b/code/modules/research/experimentor.dm @@ -457,10 +457,9 @@ visible_message("[src]'s crusher goes way too many levels too high, crushing right through space-time!") playsound(src.loc, 'sound/effects/supermatter.ogg', 50, 1, -3) investigate_log("Experimentor has triggered the 'throw things' reaction.", "experimentor") - spawn(0) - for(var/atom/movable/AM in oview(7,src)) - if(!AM.anchored) - AM.throw_at(src,10,1) + for(var/atom/movable/AM in oview(7,src)) + if(!AM.anchored) + AM.throw_at_fast(src,10,1) if(prob(EFFECT_PROB_LOW-badThingCoeff)) visible_message("[src]'s crusher goes one level too high, crushing right into space-time!") @@ -470,10 +469,9 @@ for(var/atom/movable/AM in oview(7,src)) if(!AM.anchored) throwAt.Add(AM) - spawn(0) - for(var/counter = 1, counter < throwAt.len, ++counter) - var/atom/movable/cast = throwAt[counter] - cast.throw_at(pick(throwAt),10,1) + for(var/counter = 1, counter < throwAt.len, ++counter) + var/atom/movable/cast = throwAt[counter] + cast.throw_at_fast(pick(throwAt),10,1) ejectItem(TRUE) //////////////////////////////////////////////////////////////////////////////////////////////// if(exp == FAIL) @@ -693,8 +691,7 @@ R.realProc = realProc R.revealed = TRUE dupes |= R - spawn() - R.throw_at(pick(oview(7,get_turf(src))),10,1) + R.throw_at_fast(pick(oview(7,get_turf(src))),10,1) counter = 0 spawn(rand(10,100)) for(counter = 1; counter <= dupes.len; counter++) diff --git a/html/changelog.html b/html/changelog.html index a96327de807..50b532f92ee 100644 --- a/html/changelog.html +++ b/html/changelog.html @@ -55,6 +55,25 @@ -->
+

07 December 2015

+

octareenroon91 updated:

+
    +
  • Wallets now use the access of all IDs stored inside them.
  • +
  • As the accesses of all IDs are merged, two IDs in a wallet may grant access to a door that neither one alone would open.
  • +
  • Wallets used to be useless for access if the first ID card put into it was taken out, until another ID card was put back in. That should not happen anymore.
  • +
+ +

06 December 2015

+

Gun Hog updated:

+
    +
  • Nanotrasen is proud to announce that it has improved its Diagnostic HUD firmware to include the station's automated robot population! New features include integrity tracking, Off/On status, and mode tracking! If your little robot friend suddenly manages to acquire free will, you will be able to track that as well!
  • +
  • Artificial Intelligence units may find that their bot management interface now shows when a robot gains free will. This is also displayed on the Personal Data Assistant's bot control interface.
  • +
+

neersighted updated:

+
    +
  • Cryo now properly checks it is on before healing...
  • +
+

05 December 2015

Joan updated:

    diff --git a/html/changelogs/.all_changelog.yml b/html/changelogs/.all_changelog.yml index 3c39d7beaed..72baf0b9694 100644 --- a/html/changelogs/.all_changelog.yml +++ b/html/changelogs/.all_changelog.yml @@ -2740,3 +2740,22 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py. 2015-12-05: Joan: - rscdel: Magic missiles no longer do damage. +2015-12-06: + Gun Hog: + - rscadd: Nanotrasen is proud to announce that it has improved its Diagnostic HUD + firmware to include the station's automated robot population! New features include + integrity tracking, Off/On status, and mode tracking! If your little robot friend + suddenly manages to acquire free will, you will be able to track that as well! + - tweak: Artificial Intelligence units may find that their bot management interface + now shows when a robot gains free will. This is also displayed on the Personal + Data Assistant's bot control interface. + neersighted: + - bugfix: Cryo now properly checks it is on before healing... +2015-12-07: + octareenroon91: + - rscadd: Wallets now use the access of all IDs stored inside them. + - rscadd: As the accesses of all IDs are merged, two IDs in a wallet may grant access + to a door that neither one alone would open. + - bugfix: Wallets used to be useless for access if the first ID card put into it + was taken out, until another ID card was put back in. That should not happen + anymore. diff --git a/icons/mob/hud.dmi b/icons/mob/hud.dmi index 90afe2db200..81d7d489e48 100644 Binary files a/icons/mob/hud.dmi and b/icons/mob/hud.dmi differ diff --git a/tgstation.dme b/tgstation.dme index 56c074acee9..45ec129db87 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -24,6 +24,7 @@ #include "code\__DATASTRUCTURES\stacks.dm" #include "code\__DEFINES\admin.dm" #include "code\__DEFINES\atmospherics.dm" +#include "code\__DEFINES\bots.dm" #include "code\__DEFINES\clothing.dm" #include "code\__DEFINES\combat.dm" #include "code\__DEFINES\flags.dm"

Name

Status

Location

Control

[Bot.hacked ? "(!)" : ""] [Bot.name] ([Bot.model])
[Bot.hacked ? "(!)" : ""] [Bot.name] ([Bot.model])[Bot.on ? "[Bot.mode ? "[ Bot.get_mode() ]": "Idle"]" : "Inactive"][bot_mode][bot_area.name]InterfaceCall