From e3fe41a70cb305d9557656a320aff253791bb1f8 Mon Sep 17 00:00:00 2001 From: VerySoft Date: Tue, 28 Jun 2022 07:06:44 -0400 Subject: [PATCH] Another one --- code/game/machinery/recharger.dm | 27 +- code/game/objects/items/devices/paicard.dm | 21 +- code/game/objects/items/devices/paicard_vr.dm | 337 ++++++++++++++---- code/modules/mob/dead/observer/observer.dm | 7 + code/modules/mob/living/silicon/pai/death.dm | 2 + code/modules/mob/living/silicon/pai/life.dm | 7 +- code/modules/mob/living/silicon/pai/pai.dm | 4 + code/modules/mob/living/silicon/pai/pai_vr.dm | 7 +- .../modules/mob/living/silicon/pai/recruit.dm | 11 + code/modules/mob/living/silicon/pai/say.dm | 2 +- code/modules/mob/new_player/new_player.dm | 6 +- icons/obj/paicard.dmi | Bin 5270 -> 6526 bytes 12 files changed, 337 insertions(+), 94 deletions(-) diff --git a/code/game/machinery/recharger.dm b/code/game/machinery/recharger.dm index 491aa22457e..65bc9c5d9c2 100644 --- a/code/game/machinery/recharger.dm +++ b/code/game/machinery/recharger.dm @@ -10,7 +10,7 @@ active_power_usage = 40000 //40 kW var/efficiency = 40000 //will provide the modified power rate when upgraded var/obj/item/charging = null - var/list/allowed_devices = list(/obj/item/weapon/gun/energy, /obj/item/weapon/melee/baton, /obj/item/modular_computer, /obj/item/weapon/computer_hardware/battery_module, /obj/item/weapon/cell, /obj/item/device/suit_cooling_unit/emergency, /obj/item/device/flashlight, /obj/item/device/electronic_assembly, /obj/item/weapon/weldingtool/electric, /obj/item/ammo_magazine/smart, /obj/item/device/flash, /obj/item/device/defib_kit, /obj/item/ammo_casing/microbattery) //VOREStation Add - NSFW Batteries + var/list/allowed_devices = list(/obj/item/weapon/gun/energy, /obj/item/weapon/melee/baton, /obj/item/modular_computer, /obj/item/weapon/computer_hardware/battery_module, /obj/item/weapon/cell, /obj/item/device/suit_cooling_unit/emergency, /obj/item/device/flashlight, /obj/item/device/electronic_assembly, /obj/item/weapon/weldingtool/electric, /obj/item/ammo_magazine/smart, /obj/item/device/flash, /obj/item/device/defib_kit, /obj/item/ammo_casing/microbattery, /obj/item/device/paicard) //VOREStation Add - NSFW Batteries var/icon_state_charged = "recharger2" var/icon_state_charging = "recharger1" var/icon_state_idle = "recharger0" //also when unpowered @@ -68,9 +68,14 @@ if(EW.use_external_power) to_chat(user, "\The [EW] has no recharge port.") return - if(!G.get_cell() && !istype(G, /obj/item/ammo_casing/microbattery)) //VOREStation Edit: NSFW charging + if(!G.get_cell() && !istype(G, /obj/item/ammo_casing/microbattery) && !istype(G, /obj/item/device/paicard)) //VOREStation Edit: NSFW charging to_chat(user, "\The [G] does not have a battery installed.") return + if(istype(G, /obj/item/device/paicard)) + var/obj/item/device/paicard/ourcard = G + if(ourcard.panel_open) + to_chat(user, "\The [ourcard] won't fit in the recharger with its panel open.") + return user.drop_item() G.loc = src @@ -122,6 +127,24 @@ if(!charging) update_use_power(USE_POWER_IDLE) icon_state = icon_state_idle + //VOREStation Edit Start - pAI revival! + else if(istype(charging, /obj/item/device/paicard)) + var/obj/item/device/paicard/pcard = charging + if(pcard.is_damage_critical()) + pcard.forceMove(get_turf(src)) + charging = null + pcard.damage_random_component() + update_icon() + else if(pcard.pai.bruteloss) + pcard.pai.adjustBruteLoss(-1) + else if(pcard.pai.fireloss) + pcard.pai.adjustFireLoss(-1) + else + pcard.forceMove(get_turf(src)) + pcard.pai.full_restore() + charging = null + update_icon() + //VOREStation Edit End else var/obj/item/weapon/cell/C = charging.get_cell() if(istype(C)) diff --git a/code/game/objects/items/devices/paicard.dm b/code/game/objects/items/devices/paicard.dm index ae8b3903819..4fae67a9f9e 100644 --- a/code/game/objects/items/devices/paicard.dm +++ b/code/game/objects/items/devices/paicard.dm @@ -58,11 +58,21 @@ GLOBAL_LIST_BOILERPLATE(all_pai_cards, /obj/item/device/paicard) /obj/item/device/paicard/attack_ghost(mob/user as mob) if(pai != null) //Have a person in them already? return ..() - + var/time_till_respawn = user.time_till_respawn() + if(time_till_respawn == -1) // Special case, never allowed to respawn + to_chat(usr, "Respawning is not allowed!") + else if(time_till_respawn) // Nonzero time to respawn + to_chat(usr, "You can't do that yet! You died too recently. You need to wait another [round(time_till_respawn/10/60, 0.1)] minutes.") + return if(jobban_isbanned(usr, "pAI")) to_chat(usr,"You cannot join a pAI card when you are banned from playing as a pAI.") return + for(var/ourkey in paikeys) + if(ourkey == user.ckey) + to_chat(usr, "You can't just rejoin any old pAI card!!! Your card still exists.") + return + var/choice = tgui_alert(user, "You sure you want to inhabit this PAI, or submit yourself to being recruited?", "Confirmation", list("Inhabit", "Recruit", "Cancel")) if(choice == "Cancel") return ..() @@ -81,12 +91,14 @@ GLOBAL_LIST_BOILERPLATE(all_pai_cards, /obj/item/device/paicard) var/obj/item/device/paicard/typeb/card = new(location) var/mob/living/silicon/pai/new_pai = new(card) new_pai.key = user.key + paikeys |= new_pai.ckey card.setPersonality(new_pai) new_pai.SetName(actual_pai_name) else var/obj/item/device/paicard/card = new(location) var/mob/living/silicon/pai/new_pai = new(card) new_pai.key = user.key + paikeys |= new_pai.ckey card.setPersonality(new_pai) new_pai.SetName(actual_pai_name) @@ -95,6 +107,7 @@ GLOBAL_LIST_BOILERPLATE(all_pai_cards, /obj/item/device/paicard) var/obj/item/device/paicard/typeb/card = new(location) var/mob/living/silicon/pai/new_pai = new(card) new_pai.key = user.key + paikeys |= new_pai.ckey card.setPersonality(new_pai) if(!new_pai.savefile_load(new_pai)) var/pai_name = tgui_input_text(new_pai, "Choose your character's name", "Character Name") @@ -105,6 +118,7 @@ GLOBAL_LIST_BOILERPLATE(all_pai_cards, /obj/item/device/paicard) var/obj/item/device/paicard/card = new(location) var/mob/living/silicon/pai/new_pai = new(card) new_pai.key = user.key + paikeys |= new_pai.ckey card.setPersonality(new_pai) if(!new_pai.savefile_load(new_pai)) var/pai_name = tgui_input_text(new_pai, "Choose your character's name", "Character Name") @@ -513,6 +527,5 @@ GLOBAL_LIST_BOILERPLATE(all_pai_cards, /obj/item/device/paicard) return pick(/obj/item/device/paicard ,/obj/item/device/paicard/typeb) /obj/item/device/paicard/digest_act(var/atom/movable/item_storage = null) - if(!pai.digestable) - return - . = ..() + if(pai.digestable) + return ..() diff --git a/code/game/objects/items/devices/paicard_vr.dm b/code/game/objects/items/devices/paicard_vr.dm index a54a9fdf405..723218348ba 100644 --- a/code/game/objects/items/devices/paicard_vr.dm +++ b/code/game/objects/items/devices/paicard_vr.dm @@ -1,163 +1,346 @@ +#define PP_FUNCTIONAL 0 +#define PP_BROKEN 1 +#define PP_MISSING 2 + +var/global/list/paikeys = list() + /obj/item/device/paicard var/panel_open = FALSE - var/cell = TRUE //critical- power - var/processor = TRUE //critical- the thinky part - var/board = TRUE //critical- makes everything work - var/capacitor = TRUE //critical- power processing - var/projector = TRUE //non-critical- affects unfolding - var/emitter = TRUE //non-critical- affects unfolding - var/speech_synthesizer = TRUE //non-critical- affects speech - var/list/parts = list( - "cell", - "processor", - "board", - "capacitor", - "projector", - "emitter", - "speech synthesizer") + var/cell = PP_FUNCTIONAL //critical- power + var/processor = PP_FUNCTIONAL //critical- the thinky part + var/board = PP_FUNCTIONAL //critical- makes everything work + var/capacitor = PP_FUNCTIONAL //critical- power processing + var/projector = PP_FUNCTIONAL //non-critical- affects unfolding + var/emitter = PP_FUNCTIONAL //non-critical- affects unfolding + var/speech_synthesizer = PP_FUNCTIONAL //non-critical- affects speech /obj/item/device/paicard/attackby(var/obj/item/I as obj, mob/user as mob) if(istype(I,/obj/item/weapon/tool/screwdriver)) if(panel_open) panel_open = FALSE - user.visible_message("\The [user] secured \the [src]'s maintenance panel.") + user.visible_message("\The [user] secured \the [src]'s maintenance panel.") else panel_open = TRUE - user.visible_message("\The [user] opened \the [src]'s maintenance panel.") + user.visible_message("\The [user] opened \the [src]'s maintenance panel.") if(istype(I,/obj/item/device/robotanalyzer)) if(!panel_open) to_chat(user, "The panel isn't open. You will need to unscrew it to open it.") else - if(cell) + if(cell == PP_FUNCTIONAL) to_chat(user,"Power cell: functional") - else + else if(cell == PP_BROKEN) to_chat(user,"Power cell: damaged - CRITICAL") - if(processor) + else + to_chat(user,"Power cell: missing - CRITICAL") + + if(processor == PP_FUNCTIONAL) to_chat(user,"Processor: functional") - else + else if(processor == PP_BROKEN) to_chat(user,"Processor: damaged - CRITICAL") - if(board) + else + to_chat(user,"Processor: missing - CRITICAL") + + if(board == PP_FUNCTIONAL) to_chat(user,"Board: functional") - else + else if(board == PP_BROKEN) to_chat(user,"Board: damaged - CRITICAL") - if(capacitor) + else + to_chat(user,"Board: missing - CRITICAL") + + if(capacitor == PP_FUNCTIONAL) to_chat(user,"Capacitors: functional") - else + else if(capacitor == PP_BROKEN) to_chat(user,"Capacitors: damaged - CRITICAL") - if(projector) + else + to_chat(user,"Capacitors: missing - CRITICAL") + + if(projector == PP_FUNCTIONAL) to_chat(user,"Projectors: functional") - else + else if(projector == PP_BROKEN) to_chat(user,"Projectors: damaged") - if(emitter) + else + to_chat(user,"Projectors: missing") + + if(emitter == PP_FUNCTIONAL) to_chat(user,"Emitters: functional") - else + else if(emitter == PP_BROKEN) to_chat(user,"Emitters: damaged") - if(speech_synthesizer) - to_chat(user,"Speech Synthesizer: functional") else + to_chat(user,"Emitters: missing") + + if(speech_synthesizer == PP_FUNCTIONAL) + to_chat(user,"Speech Synthesizer: functional") + else if(speech_synthesizer == PP_BROKEN) to_chat(user,"Speech Synthesizer: damaged") + else + to_chat(user,"Speech Synthesizer: missing") + if(istype(I,/obj/item/device/multitool)) if(!panel_open) to_chat(user, "You can't do that in this state.") else + var/list/parts = list() + if(cell != PP_MISSING) + parts |= "cell" + if(processor != PP_MISSING) + parts |= "processor" + if(board != PP_MISSING) + parts |= "board" + if(capacitor != PP_MISSING) + parts |= "capacitor" + if(projector != PP_MISSING) + parts |= "projector" + if(emitter != PP_MISSING) + parts |= "emitter" + if(speech_synthesizer != PP_MISSING) + parts |= "speech synthesizer" + var/choice = tgui_input_list(user, "Which part would you like to check?", "Check part", parts) switch(choice) if("cell") - if(cell) + if(cell == PP_FUNCTIONAL) to_chat(user,"Power cell: functional") - else + else if(speech_synthesizer == PP_BROKEN) to_chat(user,"Power cell: damaged") + else + to_chat(user,"Power cell: missing") + if("processor") - if(processor) + if(processor == PP_FUNCTIONAL) to_chat(user,"Processor: functional") - else + else if(speech_synthesizer == PP_BROKEN) to_chat(user,"Processor: damaged") + else + to_chat(user,"Processor: missing") + if("board") - if(board) + if(board == PP_FUNCTIONAL) to_chat(user,"Board: functional") - else + else if(speech_synthesizer == PP_BROKEN) to_chat(user,"Board: damaged") + else + to_chat(user,"Board: missing") + if("capacitor") - if(capacitor) + if(capacitor == PP_FUNCTIONAL) to_chat(user,"Capacitors: functional") - else + else if(speech_synthesizer == PP_BROKEN) to_chat(user,"Capacitors: damaged") + else + to_chat(user,"Capacitors: missing") + if("projector") - if(projector) + if(projector == PP_FUNCTIONAL) to_chat(user,"Projectors: functional") - else + else if(speech_synthesizer == PP_BROKEN) to_chat(user,"Projectors: damaged") + else + to_chat(user,"Projectors: missing") + if("emitter") - if(emitter) + if(emitter == PP_FUNCTIONAL) to_chat(user,"Emitters: functional") - else + else if(speech_synthesizer == PP_BROKEN) to_chat(user,"Emitters: damaged") - if("speech synthesizer") - if(speech_synthesizer) - to_chat(user,"Speech Synthesizer: functional") else + to_chat(user,"Emitters: missing") + + if("speech synthesizer") + if(speech_synthesizer == PP_FUNCTIONAL) + to_chat(user,"Speech Synthesizer: functional") + else if(speech_synthesizer == PP_BROKEN) to_chat(user,"Speech Synthesizer: damaged") + else + to_chat(user,"Speech Synthesizer: missing") + + if(istype(I,/obj/item/paiparts/cell) && cell == PP_MISSING) + user.visible_message("\The [user] installs \the [I] into \the [src].","You install \the [I] into \the [src].") + cell = PP_FUNCTIONAL + user.drop_from_inventory(I) + qdel(I) + if(istype(I,/obj/item/paiparts/processor) && processor == PP_MISSING) + user.visible_message("\The [user] installs \the [I] into \the [src].","You install \the [I] into \the [src].") + processor = PP_FUNCTIONAL + user.drop_from_inventory(I) + qdel(I) + if(istype(I,/obj/item/paiparts/board) && board == PP_MISSING) + user.visible_message("\The [user] installs \the [I] into \the [src].","You install \the [I] into \the [src].") + board = PP_FUNCTIONAL + user.drop_from_inventory(I) + qdel(I) + if(istype(I,/obj/item/paiparts/capacitor) && capacitor == PP_MISSING) + user.visible_message("\The [user] installs \the [I] into \the [src].","You install \the [I] into \the [src].") + capacitor = PP_FUNCTIONAL + user.drop_from_inventory(I) + qdel(I) + if(istype(I,/obj/item/paiparts/projector) && projector == PP_MISSING) + user.visible_message("\The [user] installs \the [I] into \the [src].","You install \the [I] into \the [src].") + projector = PP_FUNCTIONAL + user.drop_from_inventory(I) + qdel(I) + if(istype(I,/obj/item/paiparts/emitter) && emitter == PP_MISSING) + user.visible_message("\The [user] installs \the [I] into \the [src].","You install \the [I] into \the [src].") + emitter = PP_FUNCTIONAL + user.drop_from_inventory(I) + qdel(I) + if(istype(I,/obj/item/paiparts/speech_synthesizer) && speech_synthesizer == PP_MISSING) + user.visible_message("\The [user] installs \the [I] into \the [src].","You install \the [I] into \the [src].") + speech_synthesizer = PP_FUNCTIONAL + user.drop_from_inventory(I) + qdel(I) /obj/item/device/paicard/attack_self(mob/user) if(!panel_open) access_screen(user) return + var/list/parts = list() + if(cell != PP_MISSING) + parts |= "cell" + if(processor != PP_MISSING) + parts |= "processor" + if(board != PP_MISSING) + parts |= "board" + if(capacitor != PP_MISSING) + parts |= "capacitor" + if(projector != PP_MISSING) + parts |= "projector" + if(emitter != PP_MISSING) + parts |= "emitter" + if(speech_synthesizer != PP_MISSING) + parts |= "speech synthesizer" + var/choice = tgui_input_list(user, "Which part would you like to remove?", "Remove part", parts) switch(choice) if("cell") - cell = FALSE - if(pai.stat != DEAD) - pai.death() + if(cell == PP_FUNCTIONAL) + new /obj/item/paiparts/capacitor(get_turf(user)) + else + new /obj/item/paiparts(get_turf(user)) + user.visible_message("\The [user] removes \the [choice] from \the [src].","You remove \the [choice] from \the [src].") + cell = PP_MISSING if("processor") - processor = FALSE - if(pai.stat != DEAD) - pai.death() + if(processor == PP_FUNCTIONAL) + new /obj/item/paiparts/capacitor(get_turf(user)) + else + new /obj/item/paiparts(get_turf(user)) + user.visible_message("\The [user] removes \the [choice] from \the [src].","You remove \the [choice] from \the [src].") + processor = PP_MISSING if("board") - board = FALSE - if(pai.stat != DEAD) - pai.death() + board = PP_MISSING + if(board == PP_FUNCTIONAL) + new /obj/item/paiparts/capacitor(get_turf(user)) + else + new /obj/item/paiparts(get_turf(user)) + user.visible_message("\The [user] removes \the [choice] from \the [src].","You remove \the [choice] from \the [src].") + if("capacitor") - capacitor = FALSE - if(pai.stat != DEAD) - pai.death() + if(capacitor == PP_FUNCTIONAL) + new /obj/item/paiparts/capacitor(get_turf(user)) + else + new /obj/item/paiparts(get_turf(user)) + user.visible_message("\The [user] removes \the [choice] from \the [src].","You remove \the [choice] from \the [src].") + capacitor = PP_MISSING if("projector") - projector = FALSE + if(projector == PP_FUNCTIONAL) + new /obj/item/paiparts/capacitor(get_turf(user)) + else + new /obj/item/paiparts(get_turf(user)) + user.visible_message("\The [user] removes \the [choice] from \the [src].","You remove \the [choice] from \the [src].") + projector = PP_MISSING if("emitter") - emitter = FALSE + if(emitter == PP_FUNCTIONAL) + new /obj/item/paiparts/capacitor(get_turf(user)) + else + new /obj/item/paiparts(get_turf(user)) + user.visible_message("\The [user] removes \the [choice] from \the [src].","You remove \the [choice] from \the [src].") + emitter = PP_MISSING if("speech synthesizer") - speech_synthesizer = FALSE - parts -= choice + if(speech_synthesizer == PP_FUNCTIONAL) + new /obj/item/paiparts/capacitor(get_turf(user)) + else + new /obj/item/paiparts(get_turf(user)) + user.visible_message("\The [user] removes \the [choice] from \the [src].","You remove \the [choice] from \the [src].") + speech_synthesizer = PP_MISSING /obj/item/device/paicard/proc/death_damage() - var/number = pick(1,4) + var/number = rand(1,4) while(number) - switch(pick(1,4)) + number -- + switch(rand(1,4)) if(1) - cell = FALSE + cell = PP_BROKEN if(2) - processor = FALSE + processor = PP_BROKEN if(3) - board = FALSE + board = PP_BROKEN if(4) - capacitor = FALSE + capacitor = PP_BROKEN + /obj/item/device/paicard/proc/damage_random_component(nonfatal = FALSE) + var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread + s.set_up(2, 1, src) + s.start() if(prob(80) || nonfatal) //Way more likely to be non-fatal part damage - switch(pick(1,3)) + switch(rand(1,3)) if(1) - projector = FALSE + projector = PP_BROKEN if(2) - emitter = FALSE + emitter = PP_BROKEN if(3) - speech_synthesizer = FALSE + speech_synthesizer = PP_BROKEN else - switch(pick(1,4)) + switch(rand(1,4)) if(1) - cell = FALSE + cell = PP_BROKEN if(2) - processor = FALSE + processor = PP_BROKEN if(3) - board = FALSE + board = PP_BROKEN if(4) - capacitor = FALSE + capacitor = PP_BROKEN + +/obj/item/device/paicard/proc/is_damage_critical() + if(cell != PP_FUNCTIONAL || processor != PP_FUNCTIONAL || board != PP_FUNCTIONAL || capacitor != PP_FUNCTIONAL) + return TRUE + return FALSE + +/obj/item/paiparts + name = "broken pAI component" + desc = "It's broken scrap from a pAI card!" + icon = 'icons/obj/paicard.dmi' + icon_state = "broken" +/obj/item/paiparts/Initialize() + . = ..() + pixel_x = rand(-10,10) + pixel_y = rand(-10,10) + +/obj/item/paiparts/cell + name = "pAI power cell" + desc = "It's very small and efficient! It powers the pAI!" + icon_state = "cell" +/obj/item/paiparts/processor + name = "pAI processor" + desc = "It's the brain of your computer friend!" + icon_state = "processor" +/obj/item/paiparts/board + name = "pAI board" + desc = "It's the thing all the other parts get attatched to!" + icon_state = "board" +/obj/item/paiparts/capacitor + name = "pAI capacitor" + desc = "It helps regulate power flow!" + icon_state = "capacitor" +/obj/item/paiparts/projector + name = "pAI projector" + desc = "It projects the pAI's form!" + icon_state = "projector" +/obj/item/paiparts/emitter + name = "pAI emitter" + desc = "It emits the fields to help the pAI get around!" + icon_state = "emitter" +/obj/item/paiparts/speech_synthesizer + name = "pAI speech synthesizer" + desc = "It's a little voice box!" + icon_state = "speech_synthesizer" diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm index 106bd0aef25..043e339c47c 100644 --- a/code/modules/mob/dead/observer/observer.dm +++ b/code/modules/mob/dead/observer/observer.dm @@ -983,6 +983,13 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp set name = "Blank pAI alert" set desc = "Flash an indicator light on available blank pAI devices for a smidgen of hope." + var/time_till_respawn = time_till_respawn() + if(time_till_respawn == -1) // Special case, never allowed to respawn + to_chat(usr, "Respawning is not allowed!") + else if(time_till_respawn) // Nonzero time to respawn + to_chat(usr, "You can't do that yet! You died too recently. You need to wait another [round(time_till_respawn/10/60, 0.1)] minutes.") + return + if(jobban_isbanned(usr, "pAI")) to_chat(usr,"You cannot alert pAI cards when you are banned from playing as a pAI.") return diff --git a/code/modules/mob/living/silicon/pai/death.dm b/code/modules/mob/living/silicon/pai/death.dm index 5a8efb1e193..6290b72f51c 100644 --- a/code/modules/mob/living/silicon/pai/death.dm +++ b/code/modules/mob/living/silicon/pai/death.dm @@ -1,10 +1,12 @@ //VOREStation Edit - Let's make it so that pAIs don't just always cease to be when they die! It would be cool if we could fix them. /mob/living/silicon/pai/death(gibbed,deathmessage="fizzles out and clatters to the floor...") +// set_respawn_timer() release_vore_contents() close_up(TRUE) if(card) card.cut_overlays() card.setEmotion(16) + card.damage_random_component() if(gibbed) qdel(card) diff --git a/code/modules/mob/living/silicon/pai/life.dm b/code/modules/mob/living/silicon/pai/life.dm index 2ad35532b04..6e7e8a42a10 100644 --- a/code/modules/mob/living/silicon/pai/life.dm +++ b/code/modules/mob/living/silicon/pai/life.dm @@ -13,14 +13,14 @@ if (src.stat == DEAD) return - if(!card.cell || !card.processor || !card.board || !card.capacitor) + if(card.cell != PP_FUNCTIONAL|| card.processor != PP_FUNCTIONAL || card.board != PP_FUNCTIONAL || card.capacitor != PP_FUNCTIONAL) death() - if(!card.projector && !card.emitter) + if(card.projector != PP_FUNCTIONAL && card.emitter != PP_FUNCTIONAL) if(loc != card) close_up() to_chat(src, "ERROR: System malfunction. Service required!") - else if(!card.projector || !card.emitter) + else if(card.projector != PP_FUNCTIONAL|| card.emitter != PP_FUNCTIONAL) if(prob(5)) close_up() to_chat(src, "ERROR: System malfunction. Service recommended!") @@ -36,6 +36,7 @@ handle_statuses() if(health <= 0) + card.death_damage() death(null,"fizzles out and clatters to the floor...") else if(health < maxHealth && istype(src.loc , /obj/item/device/paicard)) adjustBruteLoss(-0.5) diff --git a/code/modules/mob/living/silicon/pai/pai.dm b/code/modules/mob/living/silicon/pai/pai.dm index 7d6f73eed7b..417a8d08a6e 100644 --- a/code/modules/mob/living/silicon/pai/pai.dm +++ b/code/modules/mob/living/silicon/pai/pai.dm @@ -251,6 +251,9 @@ if(src.loc != card) return + if(card.projector != PP_FUNCTIONAL && card.emitter != PP_FUNCTIONAL) + to_chat(src, "ERROR: System malfunction. Service required!") + if(world.time <= last_special) to_chat(src, "You can't unfold yet.") return @@ -531,6 +534,7 @@ return close_up() + paikeys -= ckey visible_message("[src] fades away from the screen, the pAI device goes silent.") card.removePersonality() clear_client() diff --git a/code/modules/mob/living/silicon/pai/pai_vr.dm b/code/modules/mob/living/silicon/pai/pai_vr.dm index a13f21eca6d..444dacd2923 100644 --- a/code/modules/mob/living/silicon/pai/pai_vr.dm +++ b/code/modules/mob/living/silicon/pai/pai_vr.dm @@ -76,14 +76,13 @@ /mob/living/silicon/pai/proc/full_restore() adjustBruteLoss(- bruteloss) adjustFireLoss(- fireloss) - spawn(10) - card.cut_overlays() + spawn(100) card.setEmotion(16) - update_icon() - spawn(50) + spawn(500) stat = CONSCIOUS canmove = TRUE card.setEmotion(15) + card.visible_message("\The [card] chimes.", runemessage = "chime") /mob/living/silicon/pai/proc/pai_nom(var/mob/living/T in oview(1)) set name = "pAI Nom" diff --git a/code/modules/mob/living/silicon/pai/recruit.dm b/code/modules/mob/living/silicon/pai/recruit.dm index a6365e45858..b7485fa7150 100644 --- a/code/modules/mob/living/silicon/pai/recruit.dm +++ b/code/modules/mob/living/silicon/pai/recruit.dm @@ -37,6 +37,7 @@ var/datum/paiController/paiController // Global handler for pAI candidates if(istype(card,/obj/item/device/paicard) && istype(candidate,/datum/paiCandidate)) var/mob/living/silicon/pai/pai = new(card) pai.key = candidate.key + paikeys |= pai.ckey card.setPersonality(pai) if(!candidate.name) pai.SetName(pick(ninja_names)) @@ -379,6 +380,16 @@ var/datum/paiController/paiController // Global handler for pAI candidates if(!C) return asked.Add(C.key) asked[C.key] = world.time + + var/mob/ourmob = C.mob + if(ourmob) + var/time_till_respawn = ourmob.time_till_respawn() + if(time_till_respawn == -1 || time_till_respawn) + return + for(var/ourkey in paikeys) + if(ourkey == ourmob.ckey) + return + var/response = tgui_alert(C, "[inquirer] is requesting a pAI personality. Would you like to play as a personal AI?", "pAI Request", list("Yes", "No", "Never for this round")) if(!C) return //handle logouts that happen whilst the alert is waiting for a response. if(response == "Yes") diff --git a/code/modules/mob/living/silicon/pai/say.dm b/code/modules/mob/living/silicon/pai/say.dm index 9223e16c5a6..b06a221859f 100644 --- a/code/modules/mob/living/silicon/pai/say.dm +++ b/code/modules/mob/living/silicon/pai/say.dm @@ -1,7 +1,7 @@ /mob/living/silicon/pai/say(var/message, var/datum/language/speaking = null, var/whispering = 0) if(silence_time) to_chat(src, "Communication circuits remain uninitialized.") - else if(!card.speech_synthesizer) + else if(card.speech_synthesizer != PP_FUNCTIONAL) to_chat(src, "Communication circuits damaged. Service required.") else ..() diff --git a/code/modules/mob/new_player/new_player.dm b/code/modules/mob/new_player/new_player.dm index f3683f6ca4b..dca1d5954fd 100644 --- a/code/modules/mob/new_player/new_player.dm +++ b/code/modules/mob/new_player/new_player.dm @@ -182,7 +182,7 @@ if(!ticker || ticker.current_state != GAME_STATE_PLAYING) to_chat(usr, "The round is either not ready, or has already finished...") return - + var/time_till_respawn = time_till_respawn() if(time_till_respawn == -1) // Special case, never allowed to respawn to_chat(usr, "Respawning is not allowed!") @@ -224,7 +224,7 @@ return 0 var/datum/species/S = GLOB.all_species[client.prefs.species] - + if(!(S.spawn_flags & SPECIES_CAN_JOIN)) tgui_alert_async(src,"Your current species, [client.prefs.species], is not available for play on the station.") return 0 @@ -367,7 +367,7 @@ popup.set_content(dat) popup.open() -/mob/new_player/proc/time_till_respawn() +/mob/proc/time_till_respawn() if(!ckey) return -1 // What? diff --git a/icons/obj/paicard.dmi b/icons/obj/paicard.dmi index 97fe95121ae04fe4fbf340d8a47a712e633a1e7c..4403d47a3d526a088ba481906a7ff692af3c30ce 100644 GIT binary patch literal 6526 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 G2mc1ru~Rh%oNQ` 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