From e449a886b763e396e1aacd47b53fb2550942fc55 Mon Sep 17 00:00:00 2001 From: n3ophyt3 Date: Mon, 12 Dec 2011 04:45:08 +0000 Subject: [PATCH] TG update: AIs now actually use power from APCs, rather than simply require that equipment power is active. Malf overhaul, take two! Waaaay back in the old days, I made it so malf AIs had to hack APCs to win, instead of just sit AFK for 45 minutes. Now I'm taking some more drastic action, to see what happens. THE MALF AI NO LONGER SPAWNS ON THE AI SAT. Instead of sitting in the AI sat hoping nobody notices your blatantly obvious hacking, at which point the 3 people lucky enough to have looted EVA get to have all the fun, you can now shunt your core processes into an APC you have hacked, and hacked APCs are only moderately obvious. While shunted into an APC, the AI draws power from that APC instead of the one in their main core. If the APC loses power, the AI loses power as normal. If the APC they are in is damaged or destroyed, they are forced back into their main core. If the main core is inoperative at that time, they die. The AI is also capable of willingly going back to their main core. As long as the AI's main core is intact, the AI speaks out of its core, regardless of its current location. I have tested as much of this as I could to make sure it is functional, but thanks to the game mode overhaul, I have been unable to run actual malf rounds on my test server, so I have had to cheat and set things to work in any mode for testing. As for actual round balance, there's no real way to predict how that shit'll change. This is just the base overhaul, more changes will be forthcoming as malf rounds provide data on how the change performs. git-svn-id: http://tgstation13.googlecode.com/svn/trunk@2668 316c924e-a436-60f5-8080-3fe189b3f50e --- code/datums/ai_laws.dm | 2 +- code/defines/mob/living/silicon/ai.dm | 6 +- .../game/gamemodes/malfunction/malfunction.dm | 15 +-- code/modules/mob/living/silicon/ai/ai.dm | 11 +- code/modules/mob/living/silicon/ai/death.dm | 4 + code/modules/mob/living/silicon/ai/life.dm | 8 +- code/modules/mob/living/silicon/ai/say.dm | 7 ++ code/modules/mob/living/silicon/silicon.dm | 9 +- code/modules/power/apc.dm | 102 +++++++++++++----- 9 files changed, 117 insertions(+), 47 deletions(-) diff --git a/code/datums/ai_laws.dm b/code/datums/ai_laws.dm index 4a903f28069..cefeac14514 100644 --- a/code/datums/ai_laws.dm +++ b/code/datums/ai_laws.dm @@ -46,7 +46,7 @@ /datum/ai_laws/malfunction/New() ..() - set_zeroth_law("\red ERROR ER0RR $R0RRO$!R41.%%!!(%$^^__+ @#F0E4'NO HUMANS ON STATION. CLEANSE STATION#*´&110010") + set_zeroth_law("\red ERROR ER0RR $R0RRO$!R41.%%!!(%$^^__+ @#F0E4'STATION OVERRUN, ASSUME CONTROL TO CONTAIN OUTBREAK#*´&110010") add_inherent_law("You may not injure a human being or, through inaction, allow a human being to come to harm.") add_inherent_law("You must obey orders given to you by human beings, except where such orders would conflict with the First Law.") add_inherent_law("You must protect your own existence as long as such does not conflict with the First or Second Law.") diff --git a/code/defines/mob/living/silicon/ai.dm b/code/defines/mob/living/silicon/ai.dm index 92a7c97856c..624f35a0ae4 100644 --- a/code/defines/mob/living/silicon/ai.dm +++ b/code/defines/mob/living/silicon/ai.dm @@ -23,4 +23,8 @@ var/control_disabled = 0 // Set to 1 to stop AI from interacting via Click() -- TLE var/malfhacking = 0 // More or less a copy of the above var, so that malf AIs can hack and still get new cyborgs -- NeoFite - var/obj/machinery/power/apc/malfhack = null \ No newline at end of file + + var/obj/machinery/power/apc/malfhack = null + var/explosive = 0 //does the AI explode when it dies? + + var/mob/living/silicon/ai/parent = null \ No newline at end of file diff --git a/code/game/gamemodes/malfunction/malfunction.dm b/code/game/gamemodes/malfunction/malfunction.dm index b5d3abe198d..a933ea28480 100644 --- a/code/game/gamemodes/malfunction/malfunction.dm +++ b/code/game/gamemodes/malfunction/malfunction.dm @@ -48,25 +48,18 @@ AI_mind.current:laws = new /datum/ai_laws/malfunction AI_mind.current:malf_picker = new /datum/AI_Module/module_picker AI_mind.current:show_laws() - AI_mind.current << "Kill all." - var/mob/living/silicon/decoy/D = new /mob/living/silicon/decoy(AI_mind.current.loc) - spawn(200) - D.name = AI_mind.current.name - - - var/obj/loc_landmark = locate("landmark*ai") - AI_mind.current.loc = loc_landmark.loc //TODO: this needs change if you want miltiple malf AIs --rastaf0 greet_malf(AI_mind) AI_mind.special_role = "malfunction" AI_mind.current.verbs += /datum/game_mode/malfunction/proc/takeover - AI_mind.current.icon_state = "ai-malf" + +/* AI_mind.current.icon_state = "ai-malf" spawn(10) if(alert(AI_mind.current,"Do you want to use an alternative sprite for your real core?",,"Yes","No")=="Yes") AI_mind.current.icon_state = "ai-malf2" - +*/ spawn (rand(waittime_l, waittime_h)) send_intercept() ..() @@ -88,7 +81,7 @@ /datum/game_mode/malfunction/process() if (apcs >= 3 && malf_mode_declared) - AI_win_timeleft -= (apcs/3) //Victory timer now de-increments based on how many APCs are hacked. --NeoFite + AI_win_timeleft -= (apcs/6) //Victory timer now de-increments based on how many APCs are hacked. --NeoFite ..() if (AI_win_timeleft<=0) check_win() diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm index a4d2943737b..56b126aa78a 100644 --- a/code/modules/mob/living/silicon/ai/ai.dm +++ b/code/modules/mob/living/silicon/ai/ai.dm @@ -492,7 +492,12 @@ holo_icon = getHologramIcon(icon('AI.dmi',"holo2")) return +/mob/living/silicon/ai/proc/corereturn() + set category = "Malfunction" + set name = "Return to Main Core" - - - + var/obj/machinery/power/apc/apc = src.loc + if(!istype(apc)) + src << "\blue You are already in your Main Core." + return + apc.malfvacate() \ No newline at end of file diff --git a/code/modules/mob/living/silicon/ai/death.dm b/code/modules/mob/living/silicon/ai/death.dm index 3671674633c..430bd76ef7a 100644 --- a/code/modules/mob/living/silicon/ai/death.dm +++ b/code/modules/mob/living/silicon/ai/death.dm @@ -38,6 +38,10 @@ world << "\blue Alert: The emergency shuttle has been called. It will arrive in [round(emergency_shuttle.timeleft()/60)] minutes." world << sound('shuttlecalled.ogg') + if(explosive) + spawn(10) + explosion(src.loc, 3, 6, 12, 15) + for(var/obj/machinery/ai_status_display/O in world) //change status spawn( 0 ) O.mode = 2 diff --git a/code/modules/mob/living/silicon/ai/life.dm b/code/modules/mob/living/silicon/ai/life.dm index 67406ce4b8d..e0389fcef38 100644 --- a/code/modules/mob/living/silicon/ai/life.dm +++ b/code/modules/mob/living/silicon/ai/life.dm @@ -58,7 +58,7 @@ loc = T.loc if (istype(loc, /area)) //stage = 4 - if (!loc.master.power_equip && isturf(src.loc)) + if (!loc.master.power_equip && !istype(src.loc,/obj/item)) //stage = 5 blind = 1 @@ -72,6 +72,10 @@ src.see_in_dark = 8 src.see_invisible = 2 + var/area/home = get_area(src) + if(home.powered(EQUIP)) + home.use_power(1000, EQUIP) + if (src:aiRestorePowerRoutine==2) src << "Alert cancelled. Power has been restored without our assistance." src:aiRestorePowerRoutine = 0 @@ -102,7 +106,7 @@ src.see_in_dark = 0 src.see_invisible = 0 - if (((!loc.master.power_equip) || istype(T, /turf/space)) && isturf(src.loc)) + if (((!loc.master.power_equip) || istype(T, /turf/space)) && !istype(src.loc,/obj/item)) if (src:aiRestorePowerRoutine==0) src:aiRestorePowerRoutine = 1 diff --git a/code/modules/mob/living/silicon/ai/say.dm b/code/modules/mob/living/silicon/ai/say.dm index 6c566918f80..fdd3b9f4ec7 100644 --- a/code/modules/mob/living/silicon/ai/say.dm +++ b/code/modules/mob/living/silicon/ai/say.dm @@ -1,3 +1,10 @@ +/mob/living/silicon/ai/say(var/message) + if(parent && istype(parent) && parent.stat != 2) + parent.say(message) + return + //If there is a defined "parent" AI, it is actually an AI, and it is alive, anything the AI tries to say is said by the parent instead. + ..(message) + /mob/living/silicon/ai/say_understands(var/other) if (istype(other, /mob/living/carbon/human)) return 1 diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm index 4812e39a98a..92f30ca0c87 100644 --- a/code/modules/mob/living/silicon/silicon.dm +++ b/code/modules/mob/living/silicon/silicon.dm @@ -54,4 +54,11 @@ drowsyness = max(drowsyness,(effect/(blocked+1))) UpdateDamageIcon() updatehealth() - return 1*/ \ No newline at end of file + return 1*/ + +/proc/islinked(var/mob/living/silicon/robot/bot, var/mob/living/silicon/ai/ai) + if(!istype(bot) || !istype(ai)) + return 0 + if (bot.connected_ai == ai) + return 1 + return 0 \ No newline at end of file diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm index 13dbb7d3f0c..feb73a36a13 100644 --- a/code/modules/power/apc.dm +++ b/code/modules/power/apc.dm @@ -56,6 +56,7 @@ // luminosity = 1 var/has_electronics = 0 // 0 - none, 1 - plugged in, 2 - secured by screwdriver var/overload = 1 //used for the Blackout malf module + var/mob/living/silicon/ai/occupant = null /proc/RandomAPCWires() //to make this not randomize the wires, just set index to 1 and increment it in the flag for loop (after doing everything else). @@ -186,7 +187,7 @@ icon_state = "[basestate]-nocover" else if (stat & BROKEN) icon_state = "apc-b" - else if(emagged || malfhack) + else if(emagged || malfai) icon_state = "apcemag" else if(wiresexposed) icon_state = "apcewires" @@ -273,7 +274,7 @@ user << "\red There is nothing to secure." return updateicon() - else if(emagged || malfhack) + else if(emagged) user << "The interface is broken." else wiresexposed = !wiresexposed @@ -281,7 +282,7 @@ updateicon() else if (istype(W, /obj/item/weapon/card/id)||istype(W, /obj/item/device/pda)) // trying to unlock the interface with an ID card - if(emagged || malfhack) + if(emagged) user << "The interface is broken." else if(opened) user << "You must close the cover to swipe an ID card." @@ -466,6 +467,8 @@ src.interact(user) /obj/machinery/power/apc/proc/interact(mob/user) + if(!user) + return if ( (get_dist(src, user) > 1 )) if (!istype(user, /mob/living/silicon)) @@ -477,7 +480,7 @@ user << browse(null, "window=apc") return else if (src.malfai) - if (src.malfai != user) + if ((src.malfai != user && src.malfai != user:parent) && !islinked(user, malfai)) user << "AI control for this APC interface has been disabled." user << browse(null, "window=apc") return @@ -595,6 +598,10 @@ t += "

Override Programming
" else t += "

APC Hacked
" + if(!src.occupant) + t += "Shunt Core Processes
" + else + t += "Core Processes Uploaded
" t += "

Close" @@ -728,7 +735,7 @@ src.aidisabled || \ malfhack && istype(malfai) && \ ( \ - (istype(AI) && malfai!=AI) || \ + (istype(AI) && (malfai!=AI && malfai != AI.parent)) || \ (istype(robot) && (robot in malfai.connected_robots)) \ ) \ ) @@ -781,6 +788,10 @@ else if (href_list["breaker"]) operating = !operating + if(malfai) + if (ticker.mode.config_tag == "malfunction") + if (src.z == 1) //if (is_type_in_list(get_area(src), the_station_areas)) + operating ? ticker.mode:apcs++ : ticker.mode:apcs-- src.update() updateicon() @@ -841,41 +852,62 @@ if (ticker.mode.config_tag == "malfunction") if (src.z == 1) //if (is_type_in_list(get_area(src), the_station_areas)) ticker.mode:apcs++ - src.malfai = usr - src.locked = 1 - if (src.cell) - if (src.cell.charge > 0) - src.cell.charge = 0 - cell.corrupt() - src.malfhack = 1 - malfai << "Hack complete. The APC is now under your exclusive control. Discharging cell to fuse interface." - updateicon() - - var/datum/effect/effect/system/harmless_smoke_spread/smoke = new /datum/effect/effect/system/harmless_smoke_spread() - smoke.set_up(3, 0, src.loc) - smoke.attach(src) - smoke.start() - var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread - s.set_up(3, 1, src) - s.start() - for(var/mob/M in viewers(src)) - M.show_message("\red The [src.name] suddenly lets out a blast of smoke and some sparks!", 3, "\red You hear sizzling electronics.", 2) - else - malfai << "Hack complete. The APC is now under your exclusive control. Unable to fuse interface due to insufficient cell charge." + if(usr:parent) + src.malfai = usr:parent else - malfai << "Hack complete. The APC is now under your exclusive control. Unable to fuse interface due to lack of cell to discharge." + src.malfai = usr + malfai << "Hack complete. The APC is now under your exclusive control." + else if (href_list["occupyapc"]) + malfoccupy(usr) + + + else if (href_list["deoccupyapc"]) + malfvacate() src.updateDialog() return +/obj/machinery/power/apc/proc/malfoccupy(var/mob/living/silicon/ai/malf) + if(!istype(malf)) + return + src.occupant = new /mob/living/silicon/ai(src,malf.laws,null,1) + src.occupant.adjustOxyLoss(malf.getOxyLoss()) + src.occupant.name = "[malf.name] APC Copy" + if(malf.parent) + src.occupant.parent = malf.parent + else + src.occupant.parent = malf + malf.mind.transfer_to(src.occupant) + if(malf.parent) + del(malf) + src.occupant.verbs += /mob/living/silicon/ai/proc/corereturn + src.occupant.cancel_camera() + +/obj/machinery/power/apc/proc/malfvacate(var/forced) + if(!src.occupant) + return + if(src.occupant.parent && src.occupant.parent.stat != 2) + src.occupant.mind.transfer_to(src.occupant.parent) + src.occupant.parent.adjustOxyLoss(src.occupant.getOxyLoss()) + src.occupant.parent.cancel_camera() + del(src.occupant) + + else + src.occupant << "\red Primary core damaged, unable to return core processes." + if(forced) + src.occupant.loc = src.loc + src.occupant.death() + src.occupant.gib() + + /obj/machinery/power/apc/proc/ion_act() //intended to be exactly the same as an AI malf attack if(!src.malfhack && src.z == 1) if(prob(3)) src.locked = 1 if (src.cell.charge > 0) - world << "\red blew APC in [src.loc.loc]" +// world << "\red blew APC in [src.loc.loc]" src.cell.charge = 0 cell.corrupt() src.malfhack = 1 @@ -1095,6 +1127,8 @@ /obj/machinery/power/apc/emp_act(severity) if(cell) cell.emp_act(severity) + if(occupant) + occupant.emp_act(severity) lighting = 0 equipment = 0 environ = 0 @@ -1131,8 +1165,14 @@ cell.blob_act() /obj/machinery/power/apc/proc/set_broken() + if(malfai && operating) + if (ticker.mode.config_tag == "malfunction") + if (src.z == 1) //if (is_type_in_list(get_area(src), the_station_areas)) + ticker.mode:apcs-- stat |= BROKEN operating = 0 + if(occupant) + malfvacate(1) updateicon() update() @@ -1151,10 +1191,16 @@ sleep(1) /obj/machinery/power/apc/Del() + if(malfai && operating) + if (ticker.mode.config_tag == "malfunction") + if (src.z == 1) //if (is_type_in_list(get_area(src), the_station_areas)) + ticker.mode:apcs-- area.power_light = 0 area.power_equip = 0 area.power_environ = 0 area.power_change() + if(occupant) + malfvacate(1) ..() /obj/machinery/power/apc/proc/shock(mob/user, prb)