mirror of
https://github.com/SPLURT-Station/S.P.L.U.R.T-Station-13.git
synced 2025-12-09 16:07:40 +00:00
Merge pull request #13772 from silicons/respawn_system_2
adds a respawn/return to lobby system, tweaks cryo to preserve everything instead of just ""important items""
This commit is contained in:
@@ -40,6 +40,7 @@
|
||||
//#define ROLE_MONSTERHUNTER "monster hunter" Disabled for now
|
||||
#define ROLE_GHOSTCAFE "ghostcafe"
|
||||
#define ROLE_MINOR_ANTAG "minorantag"
|
||||
#define ROLE_RESPAWN "respawnsystem"
|
||||
//Missing assignment means it's not a gamemode specific role, IT'S NOT A BUG OR ERROR.
|
||||
//The gamemode specific ones are just so the gamemodes can query whether a player is old enough
|
||||
//(in game days played) to play that role
|
||||
|
||||
@@ -172,8 +172,6 @@
|
||||
|
||||
/datum/config_entry/string/hostedby
|
||||
|
||||
/datum/config_entry/flag/norespawn
|
||||
|
||||
/datum/config_entry/flag/guest_jobban
|
||||
|
||||
/datum/config_entry/flag/usewhitelist
|
||||
|
||||
47
code/controllers/configuration/entries/respawns.dm
Normal file
47
code/controllers/configuration/entries/respawns.dm
Normal file
@@ -0,0 +1,47 @@
|
||||
/// Allows usage of respawn system
|
||||
/datum/config_entry/flag/respawns_enabled
|
||||
config_entry_value = FALSE
|
||||
|
||||
/// Minutes before allowing respawns.
|
||||
/datum/config_entry/number/respawn_delay
|
||||
config_entry_value = 15.0
|
||||
integer = FALSE
|
||||
|
||||
/// Minutes before allowing respawn, if user cryo'd.
|
||||
/datum/config_entry/number/respawn_delay_cryo
|
||||
config_entry_value = 5.0
|
||||
integer = FALSE
|
||||
|
||||
/// Allows respawning as non-assistant. Overrides all others of this type.
|
||||
/datum/config_entry/flag/allow_non_assistant_respawn
|
||||
config_entry_value = FALSE
|
||||
|
||||
/// Allows respawning as a combat role, defined as security/head.
|
||||
/datum/config_entry/flag/allow_combat_role_respawn
|
||||
config_entry_value = FALSE
|
||||
|
||||
/// Allows respawning as the same character as a previous life
|
||||
/datum/config_entry/flag/allow_same_character_respawn
|
||||
config_entry_value = FALSE
|
||||
|
||||
/// Observing penalizes for respawns, not just joining.
|
||||
/datum/config_entry/flag/respawn_penalty_includes_observe
|
||||
config_entry_value = FALSE
|
||||
|
||||
/// Minutes from roundstart before someone can respawn
|
||||
/datum/config_entry/number/respawn_minimum_delay_roundstart
|
||||
config_entry_value = 30.0
|
||||
integer = FALSE
|
||||
|
||||
/// Gamemode config tags that are banned from respawning
|
||||
/datum/config_entry/keyed_list/respawn_chaos_gamemodes
|
||||
key_mode = KEY_MODE_TEXT
|
||||
value_mode = VALUE_MODE_FLAG
|
||||
|
||||
/datum/config_entry/keyed_list/respawn_chaos_gamemodes/ValidateListEntry(key_name, key_value)
|
||||
. = ..()
|
||||
return . && (key_name in config.modes)
|
||||
|
||||
/datum/config_entry/keyed_list/respawn_chaos_gamemodes/preprocess_key(key)
|
||||
. = ..()
|
||||
return lowertext(key)
|
||||
@@ -371,6 +371,11 @@ SUBSYSTEM_DEF(ticker)
|
||||
if(player.ready == PLAYER_READY_TO_PLAY && player.mind)
|
||||
GLOB.joined_player_list += player.ckey
|
||||
player.create_character(FALSE)
|
||||
if(player.new_character && player.client && player.client.prefs) // we cannot afford a runtime, ever
|
||||
LAZYOR(player.client.prefs.slots_joined_as, player.client.prefs.default_slot)
|
||||
LAZYOR(player.client.prefs.characters_joined_as, player.new_character.real_name)
|
||||
else
|
||||
stack_trace("WARNING: Either a player did not have a new_character, did not have a client, or did not have preferences. This is VERY bad.")
|
||||
else
|
||||
player.new_player_panel()
|
||||
CHECK_TICK
|
||||
|
||||
@@ -164,7 +164,7 @@
|
||||
. = list()
|
||||
.["version"] = GLOB.game_version
|
||||
.["mode"] = "hidden" //CIT CHANGE - hides the gamemode in topic() calls to prevent meta'ing the gamemode
|
||||
.["respawn"] = config ? !CONFIG_GET(flag/norespawn) : FALSE
|
||||
.["respawn"] = config ? CONFIG_GET(flag/respawns_enabled) : FALSE
|
||||
.["enter"] = GLOB.enter_allowed
|
||||
.["vote"] = CONFIG_GET(flag/allow_vote_mode)
|
||||
.["ai"] = CONFIG_GET(flag/allow_ai)
|
||||
|
||||
@@ -22,17 +22,16 @@
|
||||
|
||||
//Used for logging people entering cryosleep and important items they are carrying.
|
||||
var/list/frozen_crew = list()
|
||||
var/list/frozen_items = list()
|
||||
|
||||
// Used for containing rare items traitors need to steal, so it's not
|
||||
// game-over if they get iced
|
||||
var/list/objective_items = list()
|
||||
// A cache of theft datums so you don't have to re-create them for
|
||||
// each item check
|
||||
var/list/theft_cache = list()
|
||||
var/list/obj/stored_packages = list()
|
||||
|
||||
var/allow_items = TRUE
|
||||
|
||||
/obj/machinery/computer/cryopod/deconstruct()
|
||||
. = ..()
|
||||
for(var/i in stored_packages)
|
||||
var/obj/O = i
|
||||
O.forceMove(drop_location())
|
||||
|
||||
/obj/machinery/computer/cryopod/attack_ai()
|
||||
attack_hand()
|
||||
|
||||
@@ -67,11 +66,11 @@
|
||||
if(3)
|
||||
dat += "<a href='byond://?src=[REF(src)];menu=1'><< Back</a><br><br>"
|
||||
dat += "<h3>Recently stored objects</h3><br/><hr/><br/>"
|
||||
if(!frozen_items.len)
|
||||
if(!stored_packages.len)
|
||||
dat += "There has been no storage usage at this terminal.<br/>"
|
||||
else
|
||||
for(var/obj/item/I in frozen_items)
|
||||
dat += "[I.name]<br/>"
|
||||
for(var/obj/O in stored_packages)
|
||||
dat += "[O.name]<br/>"
|
||||
dat += "<hr/>"
|
||||
|
||||
var/datum/browser/popup = new(user, "cryopod_console", "Cryogenic System Control")
|
||||
@@ -87,25 +86,27 @@
|
||||
add_fingerprint(user)
|
||||
|
||||
if(href_list["item"])
|
||||
if(!allowed(user))
|
||||
if(!allowed(user) && !(obj_flags & EMAGGED))
|
||||
to_chat(user, "<span class='warning'>Access Denied.</span>")
|
||||
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
|
||||
updateUsrDialog()
|
||||
return
|
||||
if(!allow_items) return
|
||||
|
||||
if(frozen_items.len == 0)
|
||||
if(!allow_items)
|
||||
return
|
||||
|
||||
if(stored_packages.len == 0)
|
||||
to_chat(user, "<span class='notice'>There is nothing to recover from storage.</span>")
|
||||
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
|
||||
updateUsrDialog()
|
||||
return
|
||||
|
||||
var/obj/item/I = input(user, "Please choose which object to retrieve.","Object recovery",null) as null|anything in frozen_items
|
||||
var/obj/I = input(user, "Please choose which object to retrieve.","Object recovery",null) as null|anything in stored_packages
|
||||
playsound(src, "terminal_type", 25, 0)
|
||||
if(!I)
|
||||
return
|
||||
|
||||
if(!(I in frozen_items))
|
||||
if(!(I in stored_packages))
|
||||
to_chat(user, "<span class='notice'>\The [I] is no longer in storage.</span>")
|
||||
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
|
||||
updateUsrDialog()
|
||||
@@ -117,20 +118,21 @@
|
||||
I.forceMove(drop_location())
|
||||
if(user && Adjacent(user) && user.can_hold_items())
|
||||
user.put_in_hands(I)
|
||||
frozen_items -= I
|
||||
stored_packages -= I
|
||||
updateUsrDialog()
|
||||
|
||||
else if(href_list["allitems"])
|
||||
playsound(src, "terminal_type", 25, 0)
|
||||
if(!allowed(user))
|
||||
if(!allowed(user) && !(obj_flags & EMAGGED))
|
||||
to_chat(user, "<span class='warning'>Access Denied.</span>")
|
||||
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
|
||||
updateUsrDialog()
|
||||
return
|
||||
|
||||
if(!allow_items)
|
||||
return
|
||||
|
||||
if(frozen_items.len == 0)
|
||||
if(stored_packages.len == 0)
|
||||
to_chat(user, "<span class='notice'>There is nothing to recover from storage.</span>")
|
||||
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
|
||||
return
|
||||
@@ -138,10 +140,10 @@
|
||||
visible_message("<span class='notice'>The console beeps happily as it disgorges the desired objects.</span>")
|
||||
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
|
||||
|
||||
for(var/obj/item/I in frozen_items)
|
||||
I.forceMove(drop_location())
|
||||
frozen_items -= I
|
||||
updateUsrDialog()
|
||||
for(var/obj/O in stored_packages)
|
||||
O.forceMove(get_turf(src))
|
||||
stored_packages.Cut()
|
||||
updateUsrDialog()
|
||||
|
||||
else if (href_list["menu"])
|
||||
src.menu = text2num(href_list["menu"])
|
||||
@@ -159,6 +161,13 @@
|
||||
/obj/machinery/computer/cryopod/contents_explosion()
|
||||
return
|
||||
|
||||
/obj/machinery/computer/cryopod/contents_explosion()
|
||||
return //don't blow everyone's shit up.
|
||||
|
||||
/// The box
|
||||
/obj/item/storage/box/blue/cryostorage_items
|
||||
w_class = WEIGHT_CLASS_HUGE
|
||||
|
||||
//Cryopods themselves.
|
||||
/obj/machinery/cryopod
|
||||
name = "cryogenic freezer"
|
||||
@@ -177,44 +186,9 @@
|
||||
var/despawn_world_time = null // Used to keep track of the safe period.
|
||||
|
||||
var/obj/machinery/computer/cryopod/control_computer
|
||||
var/item_storage_type = /obj/item/storage/box/blue/cryostorage_items //with how storage components work this can be anything the player can open or anything with a storage component.
|
||||
var/last_no_computer_message = 0
|
||||
|
||||
// These items are preserved when the process() despawn proc occurs.
|
||||
var/static/list/preserve_items = typecacheof(list(
|
||||
/obj/item/hand_tele,
|
||||
/obj/item/card/id/captains_spare,
|
||||
/obj/item/aicard,
|
||||
/obj/item/mmi,
|
||||
/obj/item/paicard,
|
||||
/obj/item/gun,
|
||||
/obj/item/pinpointer,
|
||||
/obj/item/clothing/shoes/magboots,
|
||||
/obj/item/areaeditor/blueprints,
|
||||
/obj/item/clothing/head/helmet/space,
|
||||
/obj/item/clothing/suit/space,
|
||||
/obj/item/clothing/suit/armor,
|
||||
/obj/item/defibrillator/compact,
|
||||
/obj/item/reagent_containers/hypospray/CMO,
|
||||
/obj/item/clothing/accessory/medal/gold/captain,
|
||||
/obj/item/clothing/gloves/krav_maga,
|
||||
/obj/item/nullrod,
|
||||
/obj/item/tank/jetpack,
|
||||
/obj/item/documents,
|
||||
/obj/item/nuke_core_container
|
||||
))
|
||||
// These items will NOT be preserved
|
||||
var/static/list/do_not_preserve_items = typecacheof(list(
|
||||
/obj/item/mmi/posibrain,
|
||||
/obj/item/gun/energy/laser/mounted,
|
||||
/obj/item/gun/energy/e_gun/advtaser/mounted,
|
||||
/obj/item/gun/ballistic/revolver/grenadelauncher/cyborg,
|
||||
/obj/item/gun/energy/disabler/cyborg,
|
||||
/obj/item/gun/energy/e_gun/advtaser/cyborg,
|
||||
/obj/item/gun/energy/printer,
|
||||
/obj/item/gun/energy/kinetic_accelerator/cyborg,
|
||||
/obj/item/gun/energy/laser/cyborg
|
||||
))
|
||||
|
||||
/obj/machinery/cryopod/Initialize(mapload)
|
||||
. = ..()
|
||||
update_icon()
|
||||
@@ -286,73 +260,89 @@
|
||||
|
||||
despawn_occupant()
|
||||
|
||||
#define CRYO_DESTROY 0
|
||||
#define CRYO_PRESERVE 1
|
||||
#define CRYO_OBJECTIVE 2
|
||||
#define CRYO_IGNORE 3
|
||||
#define CRYO_DESTROY_LATER 4
|
||||
|
||||
/obj/machinery/cryopod/proc/should_preserve_item(obj/item/I)
|
||||
for(var/datum/objective_item/steal/T in control_computer.theft_cache)
|
||||
if(istype(I, T.targetitem) && T.check_special_completion(I))
|
||||
return CRYO_OBJECTIVE
|
||||
if(preserve_items[I] && !do_not_preserve_items[I])
|
||||
return CRYO_PRESERVE
|
||||
return CRYO_DESTROY
|
||||
|
||||
// This function can not be undone; do not call this unless you are sure
|
||||
/obj/machinery/cryopod/proc/despawn_occupant()
|
||||
if(!control_computer)
|
||||
find_control_computer()
|
||||
|
||||
var/mob/living/mob_occupant = occupant
|
||||
var/list/obj/item/cryo_items = list()
|
||||
|
||||
var/list/obj/item/storing = list()
|
||||
var/list/obj/item/destroying = list()
|
||||
var/list/obj/item/destroy_later = list()
|
||||
|
||||
investigate_log("Despawning [key_name(mob_occupant)].", INVESTIGATE_CRYOGENICS)
|
||||
|
||||
//Handle Borg stuff first
|
||||
var/atom/target_store = (control_computer?.allow_items && control_computer) || src //the double control computer check makes it return the control computer.
|
||||
var/drop_to_ground = !istype(target_store, /obj/machinery/computer/cryopod)
|
||||
|
||||
var/mind_identity = mob_occupant.mind?.name
|
||||
var/occupant_identity = mob_occupant.real_name
|
||||
|
||||
if(iscyborg(mob_occupant))
|
||||
var/mob/living/silicon/robot/R = mob_occupant
|
||||
if(R.mmi?.brain)
|
||||
cryo_items[R.mmi] = CRYO_DESTROY_LATER
|
||||
cryo_items[R.mmi.brain] = CRYO_DESTROY_LATER
|
||||
for(var/obj/item/I in R.module) // the tools the borg has; metal, glass, guns etc
|
||||
for(var/obj/item/O in I) // the things inside the tools, if anything; mainly for janiborg trash bags
|
||||
cryo_items[O] = should_preserve_item(O)
|
||||
O.forceMove(src)
|
||||
R.module.remove_module(I, TRUE) //delete the module itself so it doesn't transfer over.
|
||||
|
||||
//Drop all items into the pod.
|
||||
for(var/obj/item/I in mob_occupant)
|
||||
if(cryo_items[I] == CRYO_IGNORE || cryo_items[I] ==CRYO_DESTROY_LATER)
|
||||
continue
|
||||
cryo_items[I] = should_preserve_item(I)
|
||||
mob_occupant.transferItemToLoc(I, src, TRUE)
|
||||
if(I.contents.len) //Make sure we catch anything not handled by qdel() on the items.
|
||||
if(cryo_items[I] != CRYO_DESTROY) // Don't remove the contents of things that need preservation
|
||||
destroy_later += R.mmi
|
||||
destroy_later += R.mmi.brain
|
||||
for(var/i in R.module)
|
||||
if(!isitem(i))
|
||||
destroying += i
|
||||
continue
|
||||
for(var/obj/item/O in I.contents)
|
||||
cryo_items[O] = should_preserve_item(O)
|
||||
O.forceMove(src)
|
||||
|
||||
for(var/A in cryo_items)
|
||||
var/obj/item/I = A
|
||||
if(QDELETED(I)) //edge cases and DROPDEL.
|
||||
continue
|
||||
var/preserve = cryo_items[I]
|
||||
if(preserve == CRYO_DESTROY_LATER)
|
||||
continue
|
||||
if(preserve != CRYO_IGNORE)
|
||||
if(preserve == CRYO_DESTROY)
|
||||
qdel(I)
|
||||
else if(control_computer?.allow_items)
|
||||
control_computer.frozen_items += I
|
||||
if(preserve == CRYO_OBJECTIVE)
|
||||
control_computer.objective_items += I
|
||||
I.moveToNullspace()
|
||||
var/obj/item/I = i
|
||||
// let's be honest we only care about the trash bag don't beat around the bush
|
||||
if(SEND_SIGNAL(I, COMSIG_CONTAINS_STORAGE))
|
||||
storing += I.contents
|
||||
for(var/atom/movable/AM in I.contents)
|
||||
AM.forceMove(src)
|
||||
R.module.remove_module(I, TRUE)
|
||||
else
|
||||
var/list/gear = list()
|
||||
if(iscarbon(mob_occupant)) // sorry simp-le-mobs deserve no mercy
|
||||
var/mob/living/carbon/C = mob_occupant
|
||||
gear = C.get_all_gear()
|
||||
for(var/i in gear)
|
||||
var/obj/item/I = i
|
||||
I.forceMove(src)
|
||||
if(!istype(I))
|
||||
destroying += I
|
||||
continue
|
||||
if(I.item_flags & (DROPDEL | ABSTRACT))
|
||||
destroying += I
|
||||
continue
|
||||
if(HAS_TRAIT(I, TRAIT_NODROP))
|
||||
destroying += I
|
||||
continue
|
||||
// WEE WOO SNOWFLAKE TIME
|
||||
if(istype(I, /obj/item/pda))
|
||||
var/obj/item/pda/P = I
|
||||
if((P.owner == mind_identity) || (P.owner == occupant_identity))
|
||||
destroying += P
|
||||
else
|
||||
storing += P
|
||||
else if(istype(I, /obj/item/card/id))
|
||||
var/obj/item/card/id/idcard = I
|
||||
if((idcard.registered_name == mind_identity) || (idcard.registered_name == occupant_identity))
|
||||
destroying += idcard
|
||||
else
|
||||
storing += idcard
|
||||
else
|
||||
I.forceMove(loc)
|
||||
cryo_items -= I
|
||||
storing += I
|
||||
|
||||
// get rid of mobs
|
||||
for(var/mob/living/L in mob_occupant.GetAllContents() - mob_occupant)
|
||||
L.forceMove(drop_location())
|
||||
|
||||
if(storing.len)
|
||||
var/obj/O = new item_storage_type
|
||||
O.name = "cryogenic retrieval package: [mob_occupant.real_name]"
|
||||
for(var/i in storing)
|
||||
var/obj/item/I = i
|
||||
I.forceMove(O)
|
||||
O.forceMove(drop_to_ground? target_store.drop_location() : target_store)
|
||||
if((target_store == control_computer) && !drop_to_ground)
|
||||
control_computer.stored_packages += O
|
||||
|
||||
QDEL_LIST(destroying)
|
||||
|
||||
//Update any existing objectives involving this mob.
|
||||
for(var/i in GLOB.objectives)
|
||||
@@ -414,22 +404,13 @@
|
||||
|
||||
// Ghost and delete the mob.
|
||||
if(!mob_occupant.get_ghost(1))
|
||||
mob_occupant.ghostize(FALSE, penalize = TRUE, voluntary = TRUE)
|
||||
mob_occupant.ghostize(FALSE, penalize = TRUE, voluntary = TRUE, cryo = TRUE)
|
||||
|
||||
QDEL_NULL(occupant)
|
||||
for(var/I in cryo_items) //only "CRYO_DESTROY_LATER" atoms are left)
|
||||
var/atom/A = I
|
||||
if(!QDELETED(A))
|
||||
qdel(A)
|
||||
QDEL_LIST(destroy_later)
|
||||
open_machine()
|
||||
name = initial(name)
|
||||
|
||||
#undef CRYO_DESTROY
|
||||
#undef CRYO_PRESERVE
|
||||
#undef CRYO_OBJECTIVE
|
||||
#undef CRYO_IGNORE
|
||||
#undef CRYO_DESTROY_LATER
|
||||
|
||||
/obj/machinery/cryopod/MouseDrop_T(mob/living/target, mob/user)
|
||||
if(!istype(target) || user.incapacitated() || !target.Adjacent(user) || !Adjacent(user) || !ismob(target) || (!ishuman(user) && !iscyborg(user)) || !istype(user.loc, /turf) || target.buckled)
|
||||
return
|
||||
|
||||
@@ -679,8 +679,8 @@
|
||||
set category = "Server"
|
||||
set desc="Respawn basically"
|
||||
set name="Toggle Respawn"
|
||||
var/new_nores = !CONFIG_GET(flag/norespawn)
|
||||
CONFIG_SET(flag/norespawn, new_nores)
|
||||
var/new_nores = CONFIG_GET(flag/respawns_enabled)
|
||||
CONFIG_SET(flag/respawns_enabled, !new_nores)
|
||||
if (!new_nores)
|
||||
to_chat(world, "<B>You may now respawn.</B>", confidential = TRUE)
|
||||
else
|
||||
|
||||
@@ -78,8 +78,11 @@ GLOBAL_PROTECT(admin_verbs_admin)
|
||||
/client/proc/mark_datum_mapview,
|
||||
/client/proc/hide_verbs, /*hides all our adminverbs*/
|
||||
/client/proc/hide_most_verbs, /*hides all our hideable adminverbs*/
|
||||
/datum/admins/proc/open_borgopanel
|
||||
/datum/admins/proc/open_borgopanel,
|
||||
/client/proc/admin_cmd_respawn_return_to_lobby,
|
||||
/client/proc/admin_cmd_remove_ghost_respawn_timer
|
||||
)
|
||||
|
||||
GLOBAL_LIST_INIT(admin_verbs_ban, list(/client/proc/unban_panel, /client/proc/DB_ban_panel, /client/proc/stickybanpanel))
|
||||
GLOBAL_PROTECT(admin_verbs_ban)
|
||||
GLOBAL_LIST_INIT(admin_verbs_sounds, list(/client/proc/play_local_sound, /client/proc/play_sound, /client/proc/manual_play_web_sound, /client/proc/set_round_end_sound))
|
||||
|
||||
@@ -936,6 +936,12 @@
|
||||
else
|
||||
dat += "<td width='20%'><a href='?src=[REF(src)];[HrefToken()];jobban3=[ROLE_MIND_TRANSFER];jobban4=[REF(M)]'>Mind Transfer Potion</a></td>"
|
||||
|
||||
//Respawns
|
||||
if(jobban_isbanned(M, ROLE_RESPAWN))
|
||||
dat += "<td width='20%'><a href='?src=[REF(src)];[HrefToken()];jobban3=[ROLE_RESPAWN];jobban4=[REF(M)]'><font color=red>Respawns</font></a></td>"
|
||||
else
|
||||
dat += "<td width='20%'><a href='?src=[REF(src)];[HrefToken()];jobban3=[ROLE_RESPAWN];jobban4=[REF(M)]'>Respawns</a></td>"
|
||||
|
||||
dat += "</tr></table>"
|
||||
usr << browse(dat, "window=jobban2;size=800x450")
|
||||
return
|
||||
@@ -1799,12 +1805,15 @@
|
||||
if(alert(usr, "Send [key_name(M)] back to Lobby?", "Message", "Yes", "No") != "Yes")
|
||||
return
|
||||
|
||||
log_admin("[key_name(usr)] has sent [key_name(M)] back to the Lobby.")
|
||||
message_admins("[key_name(usr)] has sent [key_name(M)] back to the Lobby.")
|
||||
log_admin("[key_name(usr)] has sent [key_name(M)] back to the Lobby, removing their respawn restrictions if they existed.")
|
||||
message_admins("[key_name(usr)] has sent [key_name(M)] back to the Lobby, removing their respawn restrictions if they existed.")
|
||||
|
||||
var/mob/dead/new_player/NP = new()
|
||||
NP.ckey = M.ckey
|
||||
qdel(M)
|
||||
if(GLOB.preferences_datums[NP.ckey])
|
||||
var/datum/preferences/P = GLOB.preferences_datums[NP.ckey]
|
||||
P.respawn_restrictions_active = FALSE
|
||||
|
||||
else if(href_list["tdome1"])
|
||||
if(!check_rights(R_FUN))
|
||||
|
||||
@@ -12,11 +12,29 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
var/default_slot = 1 //Holder so it doesn't default to slot 1, rather the last one used
|
||||
var/max_save_slots = 24
|
||||
|
||||
//non-preference stuff
|
||||
var/muted = 0
|
||||
// Intra-round persistence begin
|
||||
/// Flags for admin mutes
|
||||
var/muted = NONE
|
||||
/// Last IP the person was seen on
|
||||
var/last_ip
|
||||
/// Last CID the person was seen on
|
||||
var/last_id
|
||||
/// Do we log their clicks to disk?
|
||||
var/log_clicks = FALSE
|
||||
/// Characters they have joined the round under - Lazylist of names
|
||||
var/list/characters_joined_as
|
||||
/// Slots they have joined the round under - Lazylist of numbers
|
||||
var/list/slots_joined_as
|
||||
/// Are we currently subject to respawn restrictions? Usually set by us using the "respawn" verb, but can be lifted by admins.
|
||||
var/respawn_restrictions_active = FALSE
|
||||
/// time of death we consider for respawns
|
||||
var/respawn_time_of_death = -INFINITY
|
||||
/// did they DNR? used to prevent respawns.
|
||||
var/dnr_triggered = FALSE
|
||||
/// did they cryo on their last ghost?
|
||||
var/respawn_did_cryo = FALSE
|
||||
|
||||
// Intra-round persistence end
|
||||
|
||||
var/icon/custom_holoform_icon
|
||||
var/list/cached_holoform_icons
|
||||
|
||||
@@ -73,6 +73,12 @@
|
||||
/// Starting skill modifiers.
|
||||
var/list/starting_modifiers
|
||||
|
||||
// These can be flags but I don't care because they're never changed
|
||||
/// Can you always join as this job even while respawning (should probably only be on for assistant)
|
||||
var/always_can_respawn_as = FALSE
|
||||
/// Is this job considered a combat role for respawning? (usually sec/command)
|
||||
var/considered_combat_role = FALSE
|
||||
|
||||
/**
|
||||
* Checks if we should be created on a certain map
|
||||
*/
|
||||
@@ -118,6 +124,12 @@
|
||||
|
||||
//Used for a special check of whether to allow a client to latejoin as this job.
|
||||
/datum/job/proc/special_check_latejoin(client/C)
|
||||
var/joined = LAZYLEN(C.prefs?.characters_joined_as)
|
||||
if(C.prefs?.respawn_restrictions_active && (joined || CONFIG_GET(flag/respawn_penalty_includes_observe)))
|
||||
if(!CONFIG_GET(flag/allow_non_assistant_respawn) && always_can_respawn_as)
|
||||
return FALSE
|
||||
if(!CONFIG_GET(flag/allow_combat_role_respawn) && considered_combat_role)
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/job/proc/GetAntagRep()
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
display_order = JOB_DISPLAY_ORDER_AI
|
||||
var/do_special_check = TRUE
|
||||
threat = 5
|
||||
considered_combat_role = TRUE
|
||||
|
||||
starting_modifiers = list(/datum/skill_modifier/job/level/wiring/basic)
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ Assistant
|
||||
paycheck_department = ACCOUNT_CIV
|
||||
display_order = JOB_DISPLAY_ORDER_ASSISTANT
|
||||
dresscodecompliant = FALSE
|
||||
always_can_respawn_as = TRUE
|
||||
threat = 0.2
|
||||
|
||||
/datum/job/assistant/get_access()
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
exp_requirements = 180
|
||||
exp_type = EXP_TYPE_COMMAND
|
||||
exp_type_department = EXP_TYPE_COMMAND
|
||||
considered_combat_role = TRUE
|
||||
|
||||
|
||||
outfit = /datum/outfit/job/captain
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
exp_requirements = 180
|
||||
exp_type = EXP_TYPE_CREW
|
||||
exp_type_department = EXP_TYPE_ENGINEERING
|
||||
considered_combat_role = TRUE
|
||||
|
||||
outfit = /datum/outfit/job/ce
|
||||
plasma_outfit = /datum/outfit/plasmaman/ce
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
exp_requirements = 180
|
||||
exp_type = EXP_TYPE_CREW
|
||||
exp_type_department = EXP_TYPE_MEDICAL
|
||||
considered_combat_role = TRUE
|
||||
|
||||
outfit = /datum/outfit/job/cmo
|
||||
plasma_outfit = /datum/outfit/plasmaman/cmo
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
minimal_player_age = 21
|
||||
exp_requirements = 120
|
||||
exp_type = EXP_TYPE_CREW
|
||||
considered_combat_role = TRUE
|
||||
|
||||
starting_modifiers = list(/datum/skill_modifier/job/level/wiring/basic)
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
outfit = /datum/outfit/job/detective
|
||||
plasma_outfit = /datum/outfit/plasmaman/detective
|
||||
considered_combat_role = TRUE
|
||||
|
||||
access = list(ACCESS_SEC_DOORS, ACCESS_FORENSICS_LOCKERS, ACCESS_MORGUE, ACCESS_MAINT_TUNNELS, ACCESS_COURT, ACCESS_BRIG, ACCESS_WEAPONS, ACCESS_MINERAL_STOREROOM)
|
||||
minimal_access = list(ACCESS_SEC_DOORS, ACCESS_FORENSICS_LOCKERS, ACCESS_MORGUE, ACCESS_MAINT_TUNNELS, ACCESS_COURT, ACCESS_BRIG, ACCESS_WEAPONS, ACCESS_MINERAL_STOREROOM)
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
exp_requirements = 180
|
||||
exp_type = EXP_TYPE_CREW
|
||||
exp_type_department = EXP_TYPE_SERVICE
|
||||
|
||||
considered_combat_role = TRUE
|
||||
outfit = /datum/outfit/job/hop
|
||||
plasma_outfit = /datum/outfit/plasmaman/hop
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
minimal_player_age = 10
|
||||
exp_requirements = 300
|
||||
exp_type = EXP_TYPE_CREW
|
||||
considered_combat_role = TRUE
|
||||
exp_type_department = EXP_TYPE_SECURITY
|
||||
|
||||
outfit = /datum/outfit/job/hos
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
exp_requirements = 180
|
||||
exp_type = EXP_TYPE_CREW
|
||||
exp_type_department = EXP_TYPE_SUPPLY
|
||||
considered_combat_role = TRUE
|
||||
|
||||
outfit = /datum/outfit/job/quartermaster
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
exp_type_department = EXP_TYPE_SCIENCE
|
||||
exp_requirements = 180
|
||||
exp_type = EXP_TYPE_CREW
|
||||
considered_combat_role = TRUE
|
||||
|
||||
outfit = /datum/outfit/job/rd
|
||||
plasma_outfit = /datum/outfit/plasmaman/rd
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
minimal_player_age = 7
|
||||
exp_requirements = 300
|
||||
exp_type = EXP_TYPE_CREW
|
||||
considered_combat_role = TRUE
|
||||
|
||||
outfit = /datum/outfit/job/security
|
||||
plasma_outfit = /datum/outfit/plasmaman/security
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
minimal_player_age = 7
|
||||
exp_requirements = 300
|
||||
exp_type = EXP_TYPE_CREW
|
||||
considered_combat_role = TRUE
|
||||
|
||||
outfit = /datum/outfit/job/warden
|
||||
plasma_outfit = /datum/outfit/plasmaman/warden
|
||||
|
||||
@@ -375,7 +375,9 @@
|
||||
ready = PLAYER_NOT_READY
|
||||
return FALSE
|
||||
|
||||
var/this_is_like_playing_right = alert(src,"Are you sure you wish to observe? You will not be able to play this round!","Player Setup","Yes","No")
|
||||
var/mintime = max(CONFIG_GET(number/respawn_delay), (SSticker.round_start_time + (CONFIG_GET(number/respawn_minimum_delay_roundstart) * 600)) - world.time, 0)
|
||||
|
||||
var/this_is_like_playing_right = alert(src,"Are you sure you wish to observe? You will not be able to respawn for [round(mintime / 600, 0.1)] minutes!!","Player Setup","Yes","No")
|
||||
|
||||
if(QDELETED(src) || !src.client || this_is_like_playing_right != "Yes")
|
||||
ready = PLAYER_NOT_READY
|
||||
@@ -397,6 +399,7 @@
|
||||
stack_trace("There's no freaking observer landmark available on this map or you're making observers before the map is initialised")
|
||||
transfer_ckey(observer, FALSE)
|
||||
observer.client = client
|
||||
observer.client.prefs?.respawn_time_of_death = world.time
|
||||
observer.set_ghost_appearance()
|
||||
if(observer.client && observer.client.prefs)
|
||||
observer.real_name = observer.client.prefs.real_name
|
||||
@@ -463,6 +466,9 @@
|
||||
alert(src, "An administrator has disabled late join spawning.")
|
||||
return FALSE
|
||||
|
||||
if(!respawn_latejoin_check(notify = TRUE))
|
||||
return FALSE
|
||||
|
||||
var/arrivals_docked = TRUE
|
||||
if(SSshuttle.arrivals)
|
||||
close_spawn_windows() //In case we get held up
|
||||
@@ -526,6 +532,8 @@
|
||||
|
||||
GLOB.joined_player_list += character.ckey
|
||||
GLOB.latejoiners += character
|
||||
LAZYOR(character.client.prefs.slots_joined_as, character.client.prefs.default_slot)
|
||||
LAZYOR(character.client.prefs.characters_joined_as, character.real_name)
|
||||
|
||||
if(CONFIG_GET(flag/allow_latejoin_antagonists) && humanc) //Borgs aren't allowed to be antags. Will need to be tweaked if we get true latejoin ais.
|
||||
if(SSshuttle.emergency)
|
||||
|
||||
@@ -264,7 +264,7 @@ Transfer_mind is there to check if mob is being deleted/not going to have a body
|
||||
Works together with spawning an observer, noted above.
|
||||
*/
|
||||
|
||||
/mob/proc/ghostize(can_reenter_corpse = TRUE, special = FALSE, penalize = FALSE, voluntary = FALSE)
|
||||
/mob/proc/ghostize(can_reenter_corpse = TRUE, special = FALSE, penalize = FALSE, voluntary = FALSE, cryo = FALSE)
|
||||
var/sig_flags = SEND_SIGNAL(src, COMSIG_MOB_GHOSTIZE, can_reenter_corpse, special, penalize)
|
||||
penalize = !(sig_flags & COMPONENT_DO_NOT_PENALIZE_GHOSTING) && (suiciding || penalize) // suicide squad.
|
||||
voluntary_ghosted = voluntary
|
||||
@@ -277,6 +277,12 @@ Works together with spawning an observer, noted above.
|
||||
if (client && client.prefs && client.prefs.auto_ooc)
|
||||
if (!(client.prefs.chat_toggles & CHAT_OOC))
|
||||
client.prefs.chat_toggles ^= CHAT_OOC
|
||||
if(ckey && penalize)
|
||||
var/datum/preferences/P = GLOB.preferences_datums[ckey]
|
||||
if(P)
|
||||
P.respawn_restrictions_active = TRUE
|
||||
P.respawn_time_of_death = world.time
|
||||
P.respawn_did_cryo = cryo
|
||||
transfer_ckey(ghost, FALSE)
|
||||
ghost.client.init_verbs()
|
||||
if(penalize)
|
||||
@@ -423,12 +429,14 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
|
||||
to_chat(usr, "<span class='warning'>You're already stuck out of your body!</span>")
|
||||
return FALSE
|
||||
|
||||
var/response = alert(src, "Are you sure you want to prevent (almost) all means of resuscitation? This cannot be undone. ","Are you sure you want to stay dead?","Yes","No")
|
||||
var/response = alert(src, "Are you sure you want to prevent (almost) all means of resuscitation? This cannot be undone. THIS WILL ALSO STOP YOU FROM RESPAWNING!!!","Are you sure you want to stay dead and never respawn?","Yes","No")
|
||||
|
||||
if(response != "Yes")
|
||||
return
|
||||
|
||||
can_reenter_corpse = FALSE
|
||||
to_chat(src, "You can no longer be brought back into your body.")
|
||||
client.prefs?.dnr_triggered = TRUE
|
||||
to_chat(src, "You can no longer be brought back into your body or respawn.")
|
||||
return TRUE
|
||||
|
||||
/mob/dead/observer/proc/notify_cloning(var/message, var/sound, var/atom/source, flashwindow = TRUE)
|
||||
|
||||
181
code/modules/mob/dead/observer/respawn.dm
Normal file
181
code/modules/mob/dead/observer/respawn.dm
Normal file
@@ -0,0 +1,181 @@
|
||||
// ADMIN VERBS BEGIN
|
||||
/**
|
||||
* Fully returns a player to lobby, allowing them to bypass all respawn restrictions
|
||||
* Works on ghosts or new players (lobby players)
|
||||
* If a lobby player is selected, their restrictions are removed.
|
||||
*/
|
||||
/client/proc/admin_cmd_respawn_return_to_lobby()
|
||||
set name = "Respawn Player (Unrestricted)"
|
||||
set desc = "Gives a player an unrestricted respawn, resetting all respawn restrictions for them."
|
||||
set category = "Admin"
|
||||
|
||||
var/list/mob/valid = list()
|
||||
for(var/mob/dead/observer/I in GLOB.dead_mob_list)
|
||||
if(!I.client)
|
||||
continue
|
||||
valid["[I.ckey] - Observing: [I]"] = I.ckey
|
||||
for(var/mob/dead/new_player/I in GLOB.dead_mob_list)
|
||||
if(!I.client || !I.client.prefs.respawn_restrictions_active)
|
||||
continue
|
||||
valid["[I.ckey] - IN LOBBY"] = I.ckey
|
||||
if(!valid.len)
|
||||
to_chat(src, "<span class='warning'>No player found that is either a ghost or is in lobby with restrictions active.</span>")
|
||||
return
|
||||
var/ckey = valid[input(src, "Choose a player (only showing logged in players who have restrictions)", "Unrestricted Respawn") as null|anything in valid]
|
||||
var/client/player = GLOB.directory[ckey]
|
||||
if(!player)
|
||||
to_chat(src, "<span class='warning'>Client not found.</span>")
|
||||
return
|
||||
var/mob/M = player.mob
|
||||
if(istype(M, /mob/dead/observer))
|
||||
var/mob/dead/observer/O = M
|
||||
var/confirm = alert(src, "Send [O]([ckey]) back to the lobby without respawn restrictions?", "Send to Lobby", "Yes", "No")
|
||||
if(confirm != "Yes")
|
||||
return
|
||||
message_admins("[key_name_admin(src)] gave [key_name_admin(O)] a full respawn and sent them back to the lobby.")
|
||||
log_admin("[key_name(src)] gave [key_name(O)] a full respawn and sent them back to the lobby.")
|
||||
to_chat(O, "<span class='userdanger'>You have been given a full respawn.</span>")
|
||||
O.do_respawn(FALSE)
|
||||
O.client.prefs.dnr_triggered = FALSE
|
||||
else if(istype(M, /mob/dead/new_player))
|
||||
var/mob/dead/new_player/NP = M
|
||||
var/confirm = alert(src, "Remove [NP]'s respawn restrictions?", "Remove Restrictions", "Yes", "No")
|
||||
if(confirm != "Yes")
|
||||
return
|
||||
message_admins("[key_name_admin(src)] removed [ckey]'s respawn restrictions.")
|
||||
log_admin("[key_name(src)] removed [ckey]'s respawn restrictions")
|
||||
NP.client.prefs.respawn_restrictions_active = FALSE
|
||||
NP.client.prefs.dnr_triggered = FALSE
|
||||
to_chat(NP, "<span class='boldnotie'>Your respawn restrictions have been removed.")
|
||||
else
|
||||
CRASH("Invalid mobtype")
|
||||
|
||||
/**
|
||||
* Allows a ghost to bypass respawn delay without lifting respawn restrictions
|
||||
*/
|
||||
/client/proc/admin_cmd_remove_ghost_respawn_timer()
|
||||
set name = "Remove Respawn Timer for Player"
|
||||
set desc = "Removes a player's respawn timer without removing their respawning restrictions."
|
||||
set category = "Admin"
|
||||
|
||||
var/list/mob/dead/observer/valid = list()
|
||||
for(var/mob/dead/observer/I in GLOB.dead_mob_list)
|
||||
if(!I.client)
|
||||
continue
|
||||
valid["[I.ckey] - [I.name]"] = I
|
||||
|
||||
if(!valid.len)
|
||||
to_chat(src, "<span class='warning'>No logged in ghosts found.</span>")
|
||||
return
|
||||
var/mob/dead/observer/O = valid[input(src, "Choose a player (only showing logged in)", "Remove Respawn Timer") as null|anything in valid]
|
||||
|
||||
if(!O.client)
|
||||
to_chat(src, "<span class='warning'>[O] has no client.</span>")
|
||||
return
|
||||
var/timeleft = O.time_left_to_respawn()
|
||||
if(!timeleft)
|
||||
to_chat(src, "<span class='warning'>[O] can already respawn.")
|
||||
return
|
||||
message_admins("[key_name_admin(src)] removed [key_name_admin(O)]'s respawn timer.")
|
||||
log_admin("[key_name(src)] removed [key_name(O)]'s respawn timer.")
|
||||
O.client.prefs.respawn_time_of_death = -INFINITY
|
||||
to_chat(O, "<span class='boldnotice'>Your respawn timer has been removed.")
|
||||
|
||||
// ADMIN VERBS END
|
||||
|
||||
/**
|
||||
* Checks if we can latejoin on the currently selected slot, taking into account respawn status.
|
||||
*/
|
||||
/mob/dead/new_player/proc/respawn_latejoin_check(notify = FALSE)
|
||||
if(!client.prefs.respawn_restrictions_active)
|
||||
return TRUE
|
||||
var/can_same_person = CONFIG_GET(flag/allow_same_character_respawn)
|
||||
if(can_same_person)
|
||||
return TRUE
|
||||
var/nameless = client.prefs.nameless
|
||||
var/randomname = client.prefs.be_random_name
|
||||
var/randombody = client.prefs.be_random_body
|
||||
if(randombody && (nameless || randomname))
|
||||
return TRUE // somewhat unrecognizable
|
||||
if(client.prefs.slots_joined_as && (client.prefs.default_slot in client.prefs.slots_joined_as))
|
||||
if(notify)
|
||||
to_chat(src, "<span class='userdanger'>You cannot respawn on the same slot. Joined slots: [english_list(client.prefs.slots_joined_as)].")
|
||||
return FALSE
|
||||
if((!nameless && !randomname) && (client.prefs.characters_joined_as && (client.prefs.real_name in client.prefs.characters_joined_as)))
|
||||
if(notify)
|
||||
to_chat(src, "<span class='userdanger'>You cannot respawn on the same character. Joined slots: [english_list(client.prefs.characters_joined_as)].")
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* Attempts to respawn.
|
||||
*/
|
||||
/mob/dead/observer/verb/respawn()
|
||||
set name = "Respawn"
|
||||
set category = "OOC"
|
||||
|
||||
if(!CONFIG_GET(flag/respawns_enabled))
|
||||
to_chat(src, "<span class='warning'>Respawns are disabled in configuration.</span>")
|
||||
return
|
||||
|
||||
if(client.prefs.dnr_triggered)
|
||||
to_chat(src, "<span class='danger'>You cannot respawn as you have enabled DNR.</span>")
|
||||
return
|
||||
|
||||
var/roundstart_timeleft = (SSticker.round_start_time + (CONFIG_GET(number/respawn_minimum_delay_roundstart) * 600)) - world.time
|
||||
if(roundstart_timeleft > 0)
|
||||
to_chat(src, "<span class='warning'>It's been too short of a time since the round started! Please wait [CEILING(roundstart_timeleft / 600, 0.1)] more minutes.</span>")
|
||||
return
|
||||
|
||||
var/list/banned_modes = CONFIG_GET(keyed_list/respawn_chaos_gamemodes)
|
||||
if(SSticker.mode && banned_modes[lowertext(SSticker.mode.config_tag)])
|
||||
to_chat(src, "<span class='warning'>The current mode tag, [SSticker.mode.config_tag], is not eligible for respawn.</span>")
|
||||
return
|
||||
|
||||
var/timeleft = time_left_to_respawn()
|
||||
if(timeleft)
|
||||
to_chat(src, "<span class='warning'>It's been too short of a time since you died/observed! Please wait [round(timeleft / 600, 0.1)] more minutes.</span>")
|
||||
return
|
||||
do_respawn(TRUE)
|
||||
|
||||
/**
|
||||
* Gets time left until we can respawn. Returns 0 if we can respawn now.
|
||||
*/
|
||||
/mob/dead/observer/verb/time_left_to_respawn()
|
||||
ASSERT(client)
|
||||
return max(0, ((client.prefs.respawn_did_cryo? CONFIG_GET(number/respawn_delay_cryo) : CONFIG_GET(number/respawn_delay)) MINUTES + client.prefs.respawn_time_of_death) - world.time)
|
||||
|
||||
/**
|
||||
* Handles respawning
|
||||
*/
|
||||
/mob/dead/observer/proc/do_respawn(penalize)
|
||||
if(!client)
|
||||
return
|
||||
if(isnull(penalize))
|
||||
penalize = client.prefs.respawn_restrictions_active
|
||||
client.prefs.respawn_restrictions_active = penalize
|
||||
|
||||
to_chat(src, "<span class='userdanger'>You have been respawned to the lobby. \
|
||||
Remember to take heed of rules regarding round knowledge - notably, that ALL past lives are forgotten. \
|
||||
Any character you join as has NO knowledge of round events unless specified otherwise by an admin.</span>")
|
||||
|
||||
message_admins("[key_name_admin(src)] was respawned to lobby [penalize? "with" : "without"] restrictions.")
|
||||
log_game("[key_name(src)] was respawned to lobby [penalize? "with" : "without"] restrictions.")
|
||||
transfer_to_lobby()
|
||||
|
||||
/**
|
||||
* Actual proc that removes us and puts us back on lobby
|
||||
*/
|
||||
/mob/dead/observer/proc/transfer_to_lobby()
|
||||
if(!client) // if no one's in us we can just be deleted
|
||||
qdel(src)
|
||||
return
|
||||
client.screen.Cut()
|
||||
client.view_size.resetToDefault()
|
||||
client.generate_clickcatcher()
|
||||
client.apply_clickcatcher()
|
||||
client.view_size.setDefault(getScreenSize(client.prefs.widescreenpref))
|
||||
client.view_size.resetToDefault()
|
||||
|
||||
var/mob/dead/new_player/M = new /mob/dead/new_player
|
||||
M.ckey = ckey
|
||||
@@ -66,6 +66,10 @@
|
||||
GLOB.alive_mob_list -= src
|
||||
if(!gibbed)
|
||||
GLOB.dead_mob_list += src
|
||||
if(ckey)
|
||||
var/datum/preferences/P = GLOB.preferences_datums[ckey]
|
||||
if(P)
|
||||
P.respawn_time_of_death = world.time
|
||||
set_drugginess(0)
|
||||
set_disgust(0)
|
||||
SetSleeping(0, 0)
|
||||
|
||||
@@ -457,39 +457,6 @@
|
||||
else
|
||||
to_chat(src, "You don't have a mind datum for some reason, so you can't add a note to it.")
|
||||
|
||||
/mob/verb/abandon_mob()
|
||||
set name = "Respawn"
|
||||
set category = "OOC"
|
||||
|
||||
if (CONFIG_GET(flag/norespawn))
|
||||
return
|
||||
if ((stat != DEAD || !( SSticker )))
|
||||
to_chat(usr, "<span class='boldnotice'>You must be dead to use this!</span>")
|
||||
return
|
||||
|
||||
log_game("[key_name(usr)] used abandon mob.")
|
||||
|
||||
to_chat(usr, "<span class='boldnotice'>Please roleplay correctly!</span>")
|
||||
|
||||
if(!client)
|
||||
log_game("[key_name(usr)] AM failed due to disconnect.")
|
||||
return
|
||||
client.screen.Cut()
|
||||
client.screen += client.void
|
||||
if(!client)
|
||||
log_game("[key_name(usr)] AM failed due to disconnect.")
|
||||
return
|
||||
|
||||
var/mob/dead/new_player/M = new /mob/dead/new_player()
|
||||
if(!client)
|
||||
log_game("[key_name(usr)] AM failed due to disconnect.")
|
||||
qdel(M)
|
||||
return
|
||||
|
||||
M.key = key
|
||||
// M.Login() //wat
|
||||
return
|
||||
|
||||
/mob/proc/transfer_ckey(mob/new_mob, send_signal = TRUE)
|
||||
if(!new_mob || (!ckey && new_mob.ckey))
|
||||
CRASH("transfer_ckey() called [new_mob ? "on ckey-less mob with a player mob as target" : "without a valid mob target"]!")
|
||||
|
||||
@@ -11,6 +11,7 @@ $include dynamic_config.txt
|
||||
$include plushies/defines.txt
|
||||
$include job_threats.txt
|
||||
$include policy.txt
|
||||
$include respawns.txt
|
||||
|
||||
# You can use the @ character at the beginning of a config option to lock it from being edited in-game
|
||||
# Example usage:
|
||||
@@ -206,9 +207,6 @@ VOTE_AUTOTRANSFER_MAXIMUM 4
|
||||
## players' votes default to "No vote" (otherwise, default to "No change")
|
||||
# DEFAULT_NO_VOTE
|
||||
|
||||
## disable abandon mob
|
||||
NORESPAWN
|
||||
|
||||
## disables calling del(src) on newmobs if they logout before spawnin in
|
||||
# DONT_DEL_NEWMOB
|
||||
|
||||
|
||||
29
config/respawns.txt
Normal file
29
config/respawns.txt
Normal file
@@ -0,0 +1,29 @@
|
||||
## Allow usage of the respawn system
|
||||
RESPAWNS_ENABLED
|
||||
|
||||
## Minutes delay before allowing respawns, either from death or observing. Not an integer.
|
||||
RESPAWN_DELAY 15.0
|
||||
|
||||
## Minutes delay before allowing respawns, if the user cryo'd. Not an integer.
|
||||
RESPAWN_DELAY_CRYO 5.0
|
||||
|
||||
## Allow respawning as anything but an assistant.
|
||||
ALLOW_NON_ASSISTANT_RESPAWN
|
||||
|
||||
## Allow respawning as security and command. Only works if ALLOW_NON_ASSISTANT_RESPAWN is on.
|
||||
# ALLOW_COMBAT_ROLE_RESPAWN
|
||||
|
||||
## Allow respawning as the same character
|
||||
# ALLOW_SAME_CHARACTER_RESPAWN
|
||||
|
||||
## Observing is considered a respawn for the purposes of role lockouts. Defaults to disabled. When disabled, only RESPAWNING rather than returning from observe locks you out.
|
||||
# RESPAWN_PENALTY_INCLUDES_OBSERVE
|
||||
|
||||
## Time in minutes from round start before respawn is enabled
|
||||
RESPAWN_MINIMUM_DELAY_ROUNDSTART 30.0
|
||||
|
||||
## Gamemode (config tags!) banlist for respawn
|
||||
RESPAWN_CHAOS_GAMEMODES WIZARD
|
||||
RESPAWN_CHAOS_GAMEMODES NUCLEAR
|
||||
RESPAWN_CHAOS_GAMEMODES CLONWOPS
|
||||
RESPAWN_CHOAS_GAMEMODES REVOLUTION
|
||||
@@ -295,6 +295,7 @@
|
||||
#include "code\controllers\configuration\entries\plushies.dm"
|
||||
#include "code\controllers\configuration\entries\policy.dm"
|
||||
#include "code\controllers\configuration\entries\resources.dm"
|
||||
#include "code\controllers\configuration\entries\respawns.dm"
|
||||
#include "code\controllers\configuration\entries\stamina_combat.dm"
|
||||
#include "code\controllers\subsystem\acid.dm"
|
||||
#include "code\controllers\subsystem\adjacent_air.dm"
|
||||
@@ -2454,6 +2455,7 @@
|
||||
#include "code\modules\mob\dead\observer\observer.dm"
|
||||
#include "code\modules\mob\dead\observer\observer_movement.dm"
|
||||
#include "code\modules\mob\dead\observer\orbit.dm"
|
||||
#include "code\modules\mob\dead\observer\respawn.dm"
|
||||
#include "code\modules\mob\dead\observer\say.dm"
|
||||
#include "code\modules\mob\living\blood.dm"
|
||||
#include "code\modules\mob\living\bloodcrawl.dm"
|
||||
|
||||
Reference in New Issue
Block a user