From 36f5bd0c52196e6a9a043c22baf865f596f862aa Mon Sep 17 00:00:00 2001 From: Markolie Date: Thu, 5 Feb 2015 14:58:12 +0100 Subject: [PATCH] Add AI latejoining, fix Ofitser again, blob damages pods --- code/game/jobs/job/job.dm | 5 +- code/game/jobs/job/silicon.dm | 6 ++- code/game/jobs/job_controller.dm | 4 +- code/game/machinery/bots/bots.dm | 4 +- code/game/machinery/bots/ed209bot.dm | 1 + code/game/machinery/bots/secbot.dm | 1 + code/game/machinery/computer/ai_core.dm | 65 +++++++++++++++++++---- code/game/vehicles/spacepods/spacepod.dm | 4 ++ code/global.dm | 5 +- code/modules/admin/admin_verbs.dm | 3 +- code/modules/mob/living/silicon/ai/ai.dm | 2 +- code/modules/mob/new_player/new_player.dm | 28 +++++++--- code/modules/mob/transform_procs.dm | 53 +++++++++--------- paradise.dme | 1 + 14 files changed, 131 insertions(+), 51 deletions(-) diff --git a/code/game/jobs/job/job.dm b/code/game/jobs/job/job.dm index 5424eaa6a7c..563a469e821 100644 --- a/code/game/jobs/job/job.dm +++ b/code/game/jobs/job/job.dm @@ -115,4 +115,7 @@ H.l_store.add_fingerprint(H,1) if(H.r_store) H.r_store.add_fingerprint(H,1) - return 1 \ No newline at end of file + return 1 + +/datum/job/proc/is_position_available() + return (current_positions < total_positions) || (total_positions == -1) \ No newline at end of file diff --git a/code/game/jobs/job/silicon.dm b/code/game/jobs/job/silicon.dm index 67d10b876a5..7bb2b006f87 100644 --- a/code/game/jobs/job/silicon.dm +++ b/code/game/jobs/job/silicon.dm @@ -2,7 +2,7 @@ title = "AI" flag = AI department_flag = ENGSEC - total_positions = 0 + total_positions = 0 // Not used for AI, see is_position_available below and modules/mob/living/silicon/ai/latejoin.dm spawn_positions = 1 selection_color = "#ccffcc" supervisors = "your laws" @@ -13,7 +13,9 @@ if(!H) return 0 return 1 - +/datum/job/ai/is_position_available() + return (empty_playable_ai_cores.len != 0) + /datum/job/cyborg title = "Cyborg" diff --git a/code/game/jobs/job_controller.dm b/code/game/jobs/job_controller.dm index 647a405bf18..1e7dfe99d5f 100644 --- a/code/game/jobs/job_controller.dm +++ b/code/game/jobs/job_controller.dm @@ -443,7 +443,9 @@ var/global/datum/controller/occupations/job_master switch(rank) if("Cyborg") return H.Robotize() - if("AI","Clown") //don't need bag preference stuff! + if("AI") + return H + if("Clown") //don't need bag preference stuff! if(rank=="Clown") // Clowns DO need to breathe, though - N3X H.species.equip(H) else diff --git a/code/game/machinery/bots/bots.dm b/code/game/machinery/bots/bots.dm index 626f6aad274..539dd775b0f 100644 --- a/code/game/machinery/bots/bots.dm +++ b/code/game/machinery/bots/bots.dm @@ -565,7 +565,7 @@ obj/machinery/bot/proc/start_patrol() send_status() if(awaiting_beacon) // awaiting beacon response awaiting_beacon++ - if(awaiting_beacon > 20) // wait 20 secs for beacon response + if(awaiting_beacon > 40) // wait 40 secs for beacon response find_nearest_beacon() // then go to nearest instead return if(next_destination) @@ -583,7 +583,7 @@ obj/machinery/bot/proc/start_patrol() new_destination = "__nearest__" post_signal(beacon_freq, "findbeacon", "patrol") awaiting_beacon = 1 - spawn(100) + spawn(150) awaiting_beacon = 0 if(nearest_beacon) set_destination(nearest_beacon) diff --git a/code/game/machinery/bots/ed209bot.dm b/code/game/machinery/bots/ed209bot.dm index 21fb72573e4..6b1514391bd 100644 --- a/code/game/machinery/bots/ed209bot.dm +++ b/code/game/machinery/bots/ed209bot.dm @@ -69,6 +69,7 @@ spawn(3) var/datum/job/detective/J = new/datum/job/detective botcard.access = J.get_access() + botcard.access += 2 prev_access = botcard.access diff --git a/code/game/machinery/bots/secbot.dm b/code/game/machinery/bots/secbot.dm index 5da885441de..663646cb999 100644 --- a/code/game/machinery/bots/secbot.dm +++ b/code/game/machinery/bots/secbot.dm @@ -88,6 +88,7 @@ var/datum/job/detective/J = new/datum/job/detective botcard.access = J.get_access() + botcard.access += 2 prev_access = botcard.access add_to_beacons(bot_filter) diff --git a/code/game/machinery/computer/ai_core.dm b/code/game/machinery/computer/ai_core.dm index 6b5d3abe41f..597386eff5a 100644 --- a/code/game/machinery/computer/ai_core.dm +++ b/code/game/machinery/computer/ai_core.dm @@ -156,11 +156,15 @@ if(istype(P, /obj/item/weapon/screwdriver)) playsound(loc, 'sound/items/Screwdriver.ogg', 50, 1) user << "You connect the monitor." - if(!laws.inherent.len) //If laws isn't set to null but nobody supplied a board, the AI would normally be created lawless. We don't want that. - laws = null - var/mob/living/silicon/ai/A = new /mob/living/silicon/ai (loc, laws, brain) - if(A) //if there's no brain, the mob is deleted and a structure/AIcore is created - A.rename_self("ai", 1) + if(!brain) + var/open_for_latejoin = alert(user, "Would you like this core to be open for latejoining AIs?", "Latejoin", "Yes", "Yes", "No") == "Yes" + var/obj/structure/AIcore/deactivated/D = new(loc) + if(open_for_latejoin) + empty_playable_ai_cores += D + else + var/mob/living/silicon/ai/A = new /mob/living/silicon/ai ( loc, laws, brain ) + if(A) //if there's no brain, the mob is deleted and a structure/AIcore is created + A.rename_self("ai", 1) feedback_inc("cyborg_ais_created",1) del(src) @@ -171,10 +175,53 @@ anchored = 1 state = 20//So it doesn't interact based on the above. Not really necessary. - attackby(var/obj/item/device/aicard/A as obj, var/mob/user as mob) - if(istype(A, /obj/item/device/aicard))//Is it? - A.transfer_ai("INACTIVE","AICARD",src,user) - return +/obj/structure/AIcore/deactivated/attackby(var/obj/item/weapon/W, var/mob/user) + if(istype(W, /obj/item/device/aicard))//Is it? + var/obj/item/device/aicard/card = W + card.transfer_ai("INACTIVE","AICARD",src,user) + else if(istype(W, /obj/item/weapon/wrench)) + if(anchored) + user.visible_message("\blue \The [user] starts to unbolt \the [src] from the plating...") + if(!do_after(user,40)) + user.visible_message("\blue \The [user] decides not to unbolt \the [src].") + return + user.visible_message("\blue \The [user] finishes unfastening \the [src]!") + anchored = 0 + return + else + user.visible_message("\blue \The [user] starts to bolt \the [src] to the plating...") + if(!do_after(user,40)) + user.visible_message("\blue \The [user] decides not to bolt \the [src].") + return + user.visible_message("\blue \The [user] finishes fastening down \the [src]!") + anchored = 1 + return + else + return ..() + +/client/proc/empty_ai_core_toggle_latejoin() + set name = "Toggle AI Core Latejoin" + set category = "Admin" + + var/list/cores = list() + for(var/obj/structure/AIcore/deactivated/D in world) + cores["[D] ([D.loc.loc])"] = D + + if(!cores.len) + src << "No deactivated AI cores were found." + + var/id = input("Which core?", "Toggle AI Core Latejoin", null) as null|anything in cores + if(!id) return + + var/obj/structure/AIcore/deactivated/D = cores[id] + if(!D) return + + if(D in empty_playable_ai_cores) + empty_playable_ai_cores -= D + src << "\The [id] is now not available for latejoining AIs." + else + empty_playable_ai_cores += D + src << "\The [id] is now available for latejoining AIs." /* diff --git a/code/game/vehicles/spacepods/spacepod.dm b/code/game/vehicles/spacepods/spacepod.dm index 248868e1957..7d81ba1ebbd 100644 --- a/code/game/vehicles/spacepods/spacepod.dm +++ b/code/game/vehicles/spacepods/spacepod.dm @@ -75,6 +75,10 @@ if(P.damage && !P.nodamage) deal_damage(P.damage) +/obj/spacepod/blob_act() + deal_damage(30) + return + /obj/spacepod/attack_animal(mob/living/simple_animal/user as mob) if(user.melee_damage_upper == 0) user.emote("[user.friendly] [src]") diff --git a/code/global.dm b/code/global.dm index fc7bb7511f9..28ed508a5f4 100644 --- a/code/global.dm +++ b/code/global.dm @@ -332,4 +332,7 @@ var/recall_time_limit=72000 var/global/list/alphabet_uppercase = list("A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z") // AI controlled bots -var/global/list/aibots = list() \ No newline at end of file +var/global/list/aibots = list() + +// Announcer intercom, because too much stuff creates an intercom for one message then hard del()s it. +var/global/obj/item/device/radio/intercom/global_announcer = new(null) \ No newline at end of file diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index ed8989c3302..727dfc58c61 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -64,7 +64,8 @@ var/list/admin_verbs_admin = list( /client/proc/man_up, /client/proc/global_man_up, /client/proc/delbook, - /client/proc/event_manager_panel + /client/proc/event_manager_panel, + /client/proc/empty_ai_core_toggle_latejoin ) var/list/admin_verbs_ban = list( /client/proc/unban_panel, diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm index 657713ca60a..f34da6c2e75 100644 --- a/code/modules/mob/living/silicon/ai/ai.dm +++ b/code/modules/mob/living/silicon/ai/ai.dm @@ -115,7 +115,7 @@ var/list/ai_list = list() if(!safety)//Only used by AIize() to successfully spawn an AI. if (!B)//If there is no player/brain inside. - new/obj/structure/AIcore/deactivated(loc)//New empty terminal. + empty_playable_ai_cores += new/obj/structure/AIcore/deactivated(loc)//New empty terminal. del(src)//Delete AI. return else diff --git a/code/modules/mob/new_player/new_player.dm b/code/modules/mob/new_player/new_player.dm index 7e7ae9c3f59..c8403d5b671 100644 --- a/code/modules/mob/new_player/new_player.dm +++ b/code/modules/mob/new_player/new_player.dm @@ -272,7 +272,7 @@ proc/IsJobAvailable(rank) var/datum/job/job = job_master.GetJob(rank) if(!job) return 0 - if((job.current_positions >= job.total_positions) && job.total_positions != -1) return 0 + if(!job.is_position_available()) return 0 if(jobban_isbanned(src,rank)) return 0 if(!is_job_whitelisted(src, rank)) return 0 if(!job.player_old_enough(src.client)) return 0 @@ -309,6 +309,24 @@ EquipRacialItems(character) character = job_master.EquipRank(character, rank, 1) //equips the human EquipCustomItems(character) + + // AIs don't need a spawnpoint, they must spawn at an empty core + if(character.mind.assigned_role == "AI") + + character = character.AIize(move=0) // AIize the character, but don't move them yet + + // IsJobAvailable for AI checks that there is an empty core available in this list + var/obj/structure/AIcore/deactivated/C = empty_playable_ai_cores[1] + empty_playable_ai_cores -= C + + character.loc = C.loc + + AnnounceCyborg(character, rank, "has been downloaded to the empty core in \the [character.loc.loc]") + ticker.mode.latespawn(character) + + del(C) + del(src) + return //Find our spawning point. var/join_message @@ -364,13 +382,11 @@ arrivalmessage = replacetext(arrivalmessage,"$rank",rank ? "[rank]" : "visitor") announcer.say(";[arrivalmessage]") else - var/obj/item/device/radio/intercom/a = new /obj/item/device/radio/intercom(null)// BS12 EDIT Arrivals Announcement Computer, rather than the AI. if(character.mind) if((character.mind.assigned_role != "Cyborg") && (character.mind.special_role != "MODE")) if(character.mind.role_alt_title) rank = character.mind.role_alt_title - a.autosay("[character.real_name],[rank ? " [rank]," : " visitor," ] [join_message ? join_message : "has arrived on the station"].", "Arrivals Announcement Computer") - del(a) + global_announcer.autosay("[character.real_name],[rank ? " [rank]," : " visitor," ] [join_message ? join_message : "has arrived on the station"].", "Arrivals Announcement Computer") proc/AnnounceCyborg(var/mob/living/character, var/rank, var/join_message) if (ticker.current_state == GAME_STATE_PLAYING) @@ -384,12 +400,10 @@ var/arrivalmessage = "A new[rank ? " [rank]" : " visitor" ] [join_message ? join_message : "has arrived on the station"]." announcer.say(";[arrivalmessage]") else - var/obj/item/device/radio/intercom/a = new /obj/item/device/radio/intercom(null)// BS12 EDIT Arrivals Announcement Computer, rather than the AI. if(character.mind) if((character.mind.special_role != "MODE")) // can't use their name here, since cyborg namepicking is done post-spawn, so we'll just say "A new Cyborg has arrived"/"A new Android has arrived"/etc. - a.autosay("A new[rank ? " [rank]" : " visitor" ] [join_message ? join_message : "has arrived on the station"].", "Arrivals Announcement Computer") - del(a) + global_announcer.autosay("A new[rank ? " [rank]" : " visitor" ] [join_message ? join_message : "has arrived on the station"].", "Arrivals Announcement Computer") proc/LateChoices() var/mills = world.time // 1/10 of a second, not real milliseconds but whatever diff --git a/code/modules/mob/transform_procs.dm b/code/modules/mob/transform_procs.dm index a5aad6e3999..29baaab6f11 100644 --- a/code/modules/mob/transform_procs.dm +++ b/code/modules/mob/transform_procs.dm @@ -61,13 +61,13 @@ spawning = 1 return ..() -/mob/living/carbon/human/AIize() +/mob/living/carbon/human/AIize(move=1) // 'move' argument needs defining here too because BYOND is dumb if (monkeyizing) return for(var/t in organs) del(t) - return ..() + return ..(move) /mob/living/carbon/AIize() if (monkeyizing) @@ -80,7 +80,7 @@ invisibility = 101 return ..() -/mob/proc/AIize() +/mob/proc/AIize(move=1) if(client) src << sound(null, repeat = 0, wait = 0, volume = 85, channel = 1) // stop the jams for AIs var/mob/living/silicon/ai/O = new (loc,,,1)//No MMI but safety is in effect. @@ -93,28 +93,29 @@ else O.key = key - var/obj/loc_landmark - for(var/obj/effect/landmark/start/sloc in landmarks_list) - if (sloc.name != "AI") - continue - if (locate(/mob/living) in sloc.loc) - continue - loc_landmark = sloc - if (!loc_landmark) - for(var/obj/effect/landmark/tripai in landmarks_list) - if (tripai.name == "tripai") - if(locate(/mob/living) in tripai.loc) - continue - loc_landmark = tripai - if (!loc_landmark) - O << "Oh god sorry we can't find an unoccupied AI spawn location, so we're spawning you on top of someone." + if(move) + var/obj/loc_landmark for(var/obj/effect/landmark/start/sloc in landmarks_list) - if (sloc.name == "AI") - loc_landmark = sloc + if (sloc.name != "AI") + continue + if ((locate(/mob/living) in sloc.loc) || (locate(/obj/structure/AIcore) in sloc.loc)) + continue + loc_landmark = sloc + if (!loc_landmark) + for(var/obj/effect/landmark/tripai in landmarks_list) + if (tripai.name == "tripai") + if((locate(/mob/living) in tripai.loc) || (locate(/obj/structure/AIcore) in tripai.loc)) + continue + loc_landmark = tripai + if (!loc_landmark) + O << "Oh god sorry we can't find an unoccupied AI spawn location, so we're spawning you on top of someone." + for(var/obj/effect/landmark/start/sloc in landmarks_list) + if (sloc.name == "AI") + loc_landmark = sloc - O.loc = loc_landmark.loc - for (var/obj/item/device/radio/intercom/comm in O.loc) - comm.ai += O + O.loc = loc_landmark.loc + for (var/obj/item/device/radio/intercom/comm in O.loc) + comm.ai += O O << "You are playing the station's AI. The AI cannot move, but can interact with many objects while viewing them (through cameras)." O << "To look at other parts of the station, click on yourself to get a camera menu." @@ -131,9 +132,9 @@ O.job = "AI" O.rename_self("ai",1) - . = O - del(src) - + spawn(0) + del(src) + return O /mob/living/carbon/human/make_into_mask(var/should_gib = 0) for(var/t in organs) diff --git a/paradise.dme b/paradise.dme index f059059abf3..1a6063c3eb8 100644 --- a/paradise.dme +++ b/paradise.dme @@ -1255,6 +1255,7 @@ #include "code\modules\mob\living\silicon\ai\ai.dm" #include "code\modules\mob\living\silicon\ai\death.dm" #include "code\modules\mob\living\silicon\ai\examine.dm" +#include "code\modules\mob\living\silicon\ai\latejoin.dm" #include "code\modules\mob\living\silicon\ai\laws.dm" #include "code\modules\mob\living\silicon\ai\life.dm" #include "code\modules\mob\living\silicon\ai\login.dm"