mirror of
https://github.com/CHOMPStation2/CHOMPStation2.git
synced 2025-12-29 03:22:12 +00:00
Adds ghost click to posibrains.
Added ghost trap system used by plants and posibrains to get players. Added attack_ghost() to hydro trays and posibrains for the aforementioned. Changelog. Minor typo. Topic fixes. Minor fix.
This commit is contained in:
@@ -1007,6 +1007,7 @@
|
||||
#include "code\modules\food\recipes_microwave.dm"
|
||||
#include "code\modules\games\cards.dm"
|
||||
#include "code\modules\genetics\side_effects.dm"
|
||||
#include "code\modules\ghosttrap\trap.dm"
|
||||
#include "code\modules\holodeck\HolodeckControl.dm"
|
||||
#include "code\modules\holodeck\HolodeckObjects.dm"
|
||||
#include "code\modules\holodeck\HolodeckPrograms.dm"
|
||||
|
||||
114
code/modules/ghosttrap/trap.dm
Normal file
114
code/modules/ghosttrap/trap.dm
Normal file
@@ -0,0 +1,114 @@
|
||||
// This system is used to grab a ghost from observers with the required preferences and
|
||||
// lack of bans set. See posibrain.dm for an example of how they are called/used. ~Z
|
||||
|
||||
var/list/ghost_traps
|
||||
|
||||
proc/get_ghost_trap(var/trap_key)
|
||||
if(!ghost_traps)
|
||||
populate_ghost_traps()
|
||||
return ghost_traps[trap_key]
|
||||
|
||||
proc/populate_ghost_traps()
|
||||
ghost_traps = list()
|
||||
for(var/traptype in typesof(/datum/ghosttrap))
|
||||
var/datum/ghosttrap/G = new traptype
|
||||
ghost_traps[G.object] = G
|
||||
|
||||
/datum/ghosttrap
|
||||
var/object = "positronic brain"
|
||||
var/list/ban_checks = list("AI","Cyborg")
|
||||
var/pref_check = BE_AI
|
||||
var/ghost_trap_message = "They are occupying a positronic brain now."
|
||||
var/ghost_trap_role = "Positronic Brain"
|
||||
|
||||
// Check for bans, proper atom types, etc.
|
||||
/datum/ghosttrap/proc/assess_candidate(var/mob/dead/observer/candidate)
|
||||
if(!istype(candidate) || !candidate.client || !candidate.ckey)
|
||||
return 0
|
||||
if(!candidate.MayRespawn())
|
||||
candidate << "You have made use of the AntagHUD and hence cannot enter play as \a [object]."
|
||||
return 0
|
||||
if(islist(ban_checks))
|
||||
for(var/bantype in ban_checks)
|
||||
if(jobban_isbanned(candidate, "[bantype]"))
|
||||
candidate << "You are banned from one or more required roles and hence cannot enter play as \a [object]."
|
||||
return 0
|
||||
return 1
|
||||
|
||||
// Print a message to all ghosts with the right prefs/lack of bans.
|
||||
/datum/ghosttrap/proc/request_player(var/mob/target, var/request_string)
|
||||
if(!target)
|
||||
return
|
||||
for(var/mob/dead/observer/O in player_list)
|
||||
if(!O.MayRespawn())
|
||||
continue
|
||||
if(islist(ban_checks))
|
||||
for(var/bantype in ban_checks)
|
||||
if(jobban_isbanned(O, "[bantype]"))
|
||||
continue
|
||||
if(pref_check && !(O.client.prefs.be_special & pref_check))
|
||||
continue
|
||||
if(O.client)
|
||||
O << "[request_string]<a href='?src=\ref[src];candidate=\ref[O];target=\ref[target]'>Click here</a> if you wish to play as this option."
|
||||
|
||||
// Handles a response to request_player().
|
||||
/datum/ghosttrap/Topic(href, href_list)
|
||||
if(..())
|
||||
return 1
|
||||
if(href_list["candidate"] && href_list["target"])
|
||||
var/mob/dead/observer/candidate = locate(href_list["candidate"]) // BYOND magic.
|
||||
var/mob/target = locate(href_list["target"]) // So much BYOND magic.
|
||||
if(!target || !candidate)
|
||||
return
|
||||
if(candidate == usr && assess_candidate(candidate) && !target.ckey)
|
||||
transfer_personality(candidate,target)
|
||||
return 1
|
||||
|
||||
// Shunts the ckey/mind into the target mob.
|
||||
/datum/ghosttrap/proc/transfer_personality(var/mob/candidate, var/mob/target)
|
||||
if(!assess_candidate(candidate))
|
||||
return 0
|
||||
target.ckey = candidate.ckey
|
||||
if(target.mind)
|
||||
target.mind.assigned_role = "[ghost_trap_role]"
|
||||
announce_ghost_joinleave(candidate, 0, "[ghost_trap_message]")
|
||||
welcome_candidate(target)
|
||||
set_new_name(target)
|
||||
return 1
|
||||
|
||||
// Fluff!
|
||||
/datum/ghosttrap/proc/welcome_candidate(var/mob/target)
|
||||
target << "<b>You are a positronic brain, brought into existence on [station_name()].</b>"
|
||||
target << "<b>As a synthetic intelligence, you answer to all crewmembers, as well as the AI.</b>"
|
||||
target << "<b>Remember, the purpose of your existence is to serve the crew and the station. Above all else, do no harm.</b>"
|
||||
target << "<b>Use say :b to speak to other artificial intelligences.</b>"
|
||||
var/turf/T = get_turf(target)
|
||||
T.visible_message("<span class='notice'>\The [src] chimes quietly.</span>")
|
||||
var/obj/item/device/mmi/digital/posibrain/P = target.loc
|
||||
if(!istype(P)) //wat
|
||||
return
|
||||
P.searching = 0
|
||||
P.name = "positronic brain ([P.brainmob.name])"
|
||||
P.icon_state = "posibrain-occupied"
|
||||
|
||||
// Allows people to set their own name. May or may not need to be removed for posibrains if people are dumbasses.
|
||||
/datum/ghosttrap/proc/set_new_name(var/mob/target)
|
||||
var/newname = sanitizeSafe(input(target,"Enter a name, or leave blank for the default name.", "Name change","") as text, MAX_NAME_LEN)
|
||||
if (newname != "")
|
||||
target.real_name = newname
|
||||
target.name = target.real_name
|
||||
|
||||
// Doona pods and walking mushrooms.
|
||||
/datum/ghosttrap/plant
|
||||
object = "living plant"
|
||||
ban_checks = list("Dionaea")
|
||||
pref_check = BE_PLANT
|
||||
ghost_trap_message = "They are occupying a living plant now."
|
||||
ghost_trap_role = "Plant"
|
||||
|
||||
/datum/ghosttrap/plant/welcome_candidate(var/mob/target)
|
||||
target << "<span class='alium><B>You awaken slowly, stirring into sluggish motion as the air caresses you.</B></span>"
|
||||
// This is a hack, replace with some kind of species blurb proc.
|
||||
if(istype(host,/mob/living/carbon/alien/diona))
|
||||
target << "<B>You are \a [target], one of a race of drifting interstellar plantlike creatures that sometimes share their seeds with human traders.</B>"
|
||||
target << "<B>Too much darkness will send you into shock and starve you, but light will help you heal.</B>"
|
||||
@@ -680,7 +680,6 @@
|
||||
total_yield = get_trait(TRAIT_YIELD) + rand(yield_mod)
|
||||
total_yield = max(1,total_yield)
|
||||
|
||||
currently_querying = list()
|
||||
for(var/i = 0;i<total_yield;i++)
|
||||
var/obj/item/product
|
||||
if(has_mob_product)
|
||||
|
||||
@@ -1,15 +1,11 @@
|
||||
/datum/seed
|
||||
var/list/currently_querying // Used to avoid asking the same ghost repeatedly.
|
||||
|
||||
// The following procs are used to grab players for mobs produced by a seed (mostly for dionaea).
|
||||
/datum/seed/proc/handle_living_product(var/mob/living/host)
|
||||
|
||||
if(!host || !istype(host)) return
|
||||
|
||||
spawn(0)
|
||||
request_player(host)
|
||||
if(istype(host,/mob/living/simple_animal))
|
||||
return
|
||||
var/datum/ghosttrap/plant/P = get_ghost_trap("living plant")
|
||||
P.request_player(host, "Someone is harvesting [display_name]. ")
|
||||
|
||||
spawn(75)
|
||||
if(!host.ckey && !host.client)
|
||||
host.death() // This seems redundant, but a lot of mobs don't
|
||||
@@ -21,59 +17,3 @@
|
||||
var/obj/item/seeds/S = new(get_turf(host))
|
||||
S.seed_type = name
|
||||
S.update_seed()
|
||||
|
||||
/datum/seed/proc/request_player(var/mob/living/host)
|
||||
if(!host) return
|
||||
for(var/mob/dead/observer/O in player_list)
|
||||
if(jobban_isbanned(O, "Dionaea"))
|
||||
continue
|
||||
if(O.client && O.MayRespawn())
|
||||
if(O.client.prefs.be_special & BE_PLANT && !(O.client in currently_querying))
|
||||
currently_querying |= O.client
|
||||
question(O.client,host)
|
||||
|
||||
/datum/seed/proc/question(var/client/C,var/mob/living/host)
|
||||
spawn(0)
|
||||
|
||||
if(!C || !host || !(C.mob && istype(C.mob,/mob/dead))) return // We don't want to spam them repeatedly if they're already in a mob.
|
||||
|
||||
var/response = alert(C, "Someone is harvesting [display_name]. Would you like to play as one?", "Sentient plant harvest", "Yes", "No", "Never for this round.")
|
||||
|
||||
if(!C || !host || !(C.mob && istype(C.mob,/mob/dead))) return // ...or accidentally accept an invalid argument for transfer.
|
||||
|
||||
if(response == "Yes")
|
||||
transfer_personality(C,host)
|
||||
else if (response == "Never for this round")
|
||||
C.prefs.be_special ^= BE_PLANT
|
||||
|
||||
currently_querying -= C
|
||||
|
||||
/datum/seed/proc/transfer_personality(var/client/player,var/mob/living/host)
|
||||
|
||||
//Something is wrong, abort.
|
||||
if(!player || !host) return
|
||||
|
||||
//Host already has a controller, pike off slowpoke.
|
||||
if(host.client && host.ckey) return
|
||||
|
||||
//Transfer them over.
|
||||
host.ckey = player.ckey
|
||||
if(player.mob && player.mob.mind)
|
||||
player.mob.mind.transfer_to(host)
|
||||
|
||||
if(host.dna) host.dna.real_name = host.real_name
|
||||
|
||||
// Update mode specific HUD icons.
|
||||
callHook("harvest_podman", list(host))
|
||||
|
||||
host << "\green <B>You awaken slowly, stirring into sluggish motion as the air caresses you.</B>"
|
||||
|
||||
// This is a hack, replace with some kind of species blurb proc.
|
||||
if(istype(host,/mob/living/carbon/alien/diona))
|
||||
host << "<B>You are [host], one of a race of drifting interstellar plantlike creatures that sometimes share their seeds with human traders.</B>"
|
||||
host << "<B>Too much darkness will send you into shock and starve you, but light will help you heal.</B>"
|
||||
|
||||
var/newname = sanitizeSafe(input(host,"Enter a name, or leave blank for the default name.", "Name change","") as text, MAX_NAME_LEN)
|
||||
if (newname != "")
|
||||
host.real_name = newname
|
||||
host.name = host.real_name
|
||||
@@ -129,7 +129,22 @@
|
||||
return
|
||||
return ..()
|
||||
|
||||
/obj/machinery/portable_atmospherics/hydroponics/attack_ghost(var/mob/dead/observer/user)
|
||||
|
||||
if(!(harvest && seed && seed.has_mob_product))
|
||||
return
|
||||
|
||||
var/datum/ghosttrap/plant/G = get_ghost_trap("living plant")
|
||||
if(!G.assess_candidate(user))
|
||||
return
|
||||
var/response = alert(user, "Are you sure you want to harvest this [seed.display_name]?", "Living plant request", "Yes", "No")
|
||||
if(response == "Yes")
|
||||
harvest()
|
||||
return
|
||||
|
||||
/obj/machinery/portable_atmospherics/hydroponics/attack_generic(var/mob/user)
|
||||
|
||||
// Why did I ever think this was a good idea. TODO: move this onto the nymph mob.
|
||||
if(istype(user,/mob/living/carbon/alien/diona))
|
||||
var/mob/living/carbon/alien/diona/nymph = user
|
||||
|
||||
|
||||
@@ -5,47 +5,41 @@
|
||||
icon_state = "posibrain"
|
||||
w_class = 3
|
||||
origin_tech = "engineering=4;materials=4;bluespace=2;programming=4"
|
||||
|
||||
var/searching = 0
|
||||
construction_cost = list(DEFAULT_WALL_MATERIAL=500,"glass"=500,"silver"=200,"gold"=200,"phoron"=100,"diamond"=10)
|
||||
construction_time = 75
|
||||
var/searching = 0
|
||||
var/askDelay = 10 * 60 * 1
|
||||
req_access = list(access_robotics)
|
||||
locked = 0
|
||||
mecha = null//This does not appear to be used outside of reference in mecha.dm.
|
||||
|
||||
/obj/item/device/mmi/digital/posibrain/New()
|
||||
..()
|
||||
brainmob.name = "[pick(list("PBU","HIU","SINA","ARMA","OSI"))]-[rand(100, 999)]"
|
||||
brainmob.real_name = src.brainmob.name
|
||||
|
||||
/obj/item/device/mmi/digital/posibrain/attack_self(mob/user as mob)
|
||||
if(brainmob && !brainmob.key && searching == 0)
|
||||
/obj/item/device/mmi/digital/posibrain/attack_self(var/mob/user)
|
||||
if(brainmob && !brainmob.key && !searching)
|
||||
//Start the process of searching for a new user.
|
||||
user << "\blue You carefully locate the manual activation switch and start the positronic brain's boot process."
|
||||
user << "<span class='notice'>You carefully locate the manual activation switch and start the positronic brain's boot process.</span>"
|
||||
icon_state = "posibrain-searching"
|
||||
src.searching = 1
|
||||
src.request_player()
|
||||
searching = 1
|
||||
var/datum/ghosttrap/G = get_ghost_trap("positronic brain")
|
||||
G.request_player(brainmob, "A [src.name] has been booted by \the [user] in [get_area(user)]. ")
|
||||
spawn(600) reset_search()
|
||||
|
||||
/obj/item/device/mmi/digital/posibrain/proc/request_player()
|
||||
for(var/mob/dead/observer/O in player_list)
|
||||
if(!O.MayRespawn())
|
||||
continue
|
||||
if(jobban_isbanned(O, "AI") && jobban_isbanned(O, "Cyborg"))
|
||||
continue
|
||||
if(O.client)
|
||||
if(O.client.prefs.be_special & BE_AI)
|
||||
question(O.client)
|
||||
|
||||
/obj/item/device/mmi/digital/posibrain/proc/question(var/client/C)
|
||||
spawn(0)
|
||||
if(!C) return
|
||||
var/response = alert(C, "Someone is requesting a personality for a positronic brain. Would you like to play as one?", "Positronic brain request", "Yes", "No", "Never for this round")
|
||||
/obj/item/device/mmi/digital/posibrain/attack_ghost(var/mob/dead/observer/user)
|
||||
var/datum/ghosttrap/G = get_ghost_trap("positronic brain")
|
||||
if(!G.assess_candidate(user))
|
||||
return
|
||||
var/response = alert(user, "Are you sure you want to play as a positronic brain?", "Positronic brain request", "Yes", "No")
|
||||
if(response == "Yes")
|
||||
response = alert(C, "Are you sure you want to play as a positronic brain?", "Positronic brain request", "Yes", "No")
|
||||
if(!C || brainmob.key || 0 == searching) return //handle logouts that happen whilst the alert is waiting for a response, and responses issued after a brain has been located.
|
||||
if(response == "Yes")
|
||||
transfer_personality(C.mob)
|
||||
else if (response == "Never for this round")
|
||||
C.prefs.be_special ^= BE_AI
|
||||
|
||||
if(G.transfer_personality(user, brainmob))
|
||||
var/turf/T = get_turf(src)
|
||||
T.visible_message("<span class='notice'>\The [src] chimes quietly.</span>")
|
||||
searching = 0
|
||||
name = "positronic brain ([brainmob.name])"
|
||||
icon_state = "posibrain-occupied"
|
||||
return
|
||||
|
||||
/obj/item/device/mmi/digital/posibrain/transfer_identity(var/mob/living/carbon/H)
|
||||
..()
|
||||
@@ -55,33 +49,13 @@
|
||||
icon_state = "posibrain-occupied"
|
||||
return
|
||||
|
||||
/obj/item/device/mmi/digital/posibrain/proc/transfer_personality(var/mob/candidate)
|
||||
announce_ghost_joinleave(candidate, 0, "They are occupying a positronic brain now.")
|
||||
src.searching = 0
|
||||
src.brainmob.mind = candidate.mind
|
||||
src.brainmob.ckey = candidate.ckey
|
||||
src.name = "positronic brain ([src.brainmob.name])"
|
||||
src.brainmob << "<b>You are a positronic brain, brought into existence on [station_name()].</b>"
|
||||
src.brainmob << "<b>As a synthetic intelligence, you answer to all crewmembers, as well as the AI.</b>"
|
||||
src.brainmob << "<b>Remember, the purpose of your existence is to serve the crew and the station. Above all else, do no harm.</b>"
|
||||
src.brainmob << "<b>Use say :b to speak to other artificial intelligences.</b>"
|
||||
src.brainmob.mind.assigned_role = "Positronic Brain"
|
||||
|
||||
var/turf/T = get_turf_or_move(src.loc)
|
||||
for (var/mob/M in viewers(T))
|
||||
M.show_message("\blue The positronic brain chimes quietly.")
|
||||
icon_state = "posibrain-occupied"
|
||||
|
||||
/obj/item/device/mmi/digital/posibrain/proc/reset_search() //We give the players sixty seconds to decide, then reset the timer.
|
||||
|
||||
if(src.brainmob && src.brainmob.key) return
|
||||
|
||||
src.searching = 0
|
||||
/obj/item/device/mmi/digital/posibrain/proc/reset_search()
|
||||
if(!searching || (src.brainmob && src.brainmob.key))
|
||||
return
|
||||
searching = 0
|
||||
icon_state = "posibrain"
|
||||
|
||||
var/turf/T = get_turf_or_move(src.loc)
|
||||
for (var/mob/M in viewers(T))
|
||||
M.show_message("\blue The positronic brain buzzes quietly, and the golden lights fade away. Perhaps you could try again?")
|
||||
var/turf/T = get_turf(src)
|
||||
T.visible_message("<span class='notice'>\The [src] brain buzzes quietly, and the golden lights fade away. Perhaps you could try again?</span>")
|
||||
|
||||
/obj/item/device/mmi/digital/posibrain/examine(mob/user)
|
||||
if(!..(user))
|
||||
@@ -115,7 +89,3 @@
|
||||
src.brainmob.emp_damage += rand(0,10)
|
||||
..()
|
||||
|
||||
/obj/item/device/mmi/digital/posibrain/New()
|
||||
..()
|
||||
src.brainmob.name = "[pick(list("PBU","HIU","SINA","ARMA","OSI"))]-[rand(100, 999)]"
|
||||
src.brainmob.real_name = src.brainmob.name
|
||||
|
||||
@@ -1,15 +1,10 @@
|
||||
/proc/spawn_diona_nymph_from_organ(var/obj/item/organ/organ)
|
||||
if(!istype(organ))
|
||||
return
|
||||
|
||||
//This is a terrible hack and I should be ashamed.
|
||||
var/datum/seed/diona = plant_controller.seeds["diona"]
|
||||
if(!diona)
|
||||
qdel(src)
|
||||
|
||||
spawn(1) // So it has time to be thrown about by the gib() proc.
|
||||
var/mob/living/carbon/alien/diona/D = new(get_turf(organ))
|
||||
diona.request_player(D)
|
||||
var/datum/ghosttrap/plant/P = get_ghost_trap("living plant")
|
||||
P.request_player(D, "A diona nymph has split off from its gestalt. ")
|
||||
qdel(organ)
|
||||
|
||||
/obj/item/organ/external/diona
|
||||
|
||||
5
html/changelogs/Zuhayr-GhostTrap.yml
Normal file
5
html/changelogs/Zuhayr-GhostTrap.yml
Normal file
@@ -0,0 +1,5 @@
|
||||
author: Zuhayr
|
||||
delete-after: True
|
||||
changes:
|
||||
- rscadd: "Added a ghost requisition system for posibrains and living plants."
|
||||
- rscadd: "Added attack_ghost() to hydro trays and posibrains to allow ghosts to enter them."
|
||||
Reference in New Issue
Block a user