Merge branch 'master' into upstream-merge-30056

This commit is contained in:
LetterJay
2017-09-13 06:08:59 -05:00
committed by GitHub
545 changed files with 23622 additions and 13702 deletions

View File

@@ -1,74 +1,148 @@
//A set of constants used to determine which type of mute an admin wishes to apply:
//Please read and understand the muting/automuting stuff before changing these. MUTE_IC_AUTO etc = (MUTE_IC << 1)
//Therefore there needs to be a gap between the flags_1 for the automute flags_1
#define MUTE_IC 1
#define MUTE_OOC 2
#define MUTE_PRAY 4
#define MUTE_ADMINHELP 8
#define MUTE_DEADCHAT 16
#define MUTE_ALL 31
//Some constants for DB_Ban
#define BANTYPE_PERMA 1
#define BANTYPE_TEMP 2
#define BANTYPE_JOB_PERMA 3
#define BANTYPE_JOB_TEMP 4
#define BANTYPE_ANY_FULLBAN 5 //used to locate stuff to unban.
#define BANTYPE_ADMIN_PERMA 7
#define BANTYPE_ADMIN_TEMP 8
#define BANTYPE_ANY_JOB 9 //used to remove jobbans
//Please don't edit these values without speaking to Errorage first ~Carn
//Admin Permissions
#define R_BUILDMODE 1
#define R_ADMIN 2
#define R_BAN 4
#define R_FUN 8
#define R_SERVER 16
#define R_DEBUG 32
#define R_POSSESS 64
#define R_PERMISSIONS 128
#define R_STEALTH 256
#define R_POLL 512
#define R_VAREDIT 1024
#define R_SOUNDS 2048
#define R_SPAWN 4096
#if DM_VERSION > 512
#error Remove the flag below , its been long enough
#endif
//legacy , remove post 512, it was replaced by R_POLL
#define R_REJUVINATE 2
#define R_MAXPERMISSION 4096 //This holds the maximum value for a permission. It is used in iteration, so keep it updated.
#define ADMIN_QUE(user) "(<a href='?_src_=holder;adminmoreinfo=\ref[user]'>?</a>)"
#define ADMIN_FLW(user) "(<a href='?_src_=holder;adminplayerobservefollow=\ref[user]'>FLW</a>)"
#define ADMIN_PP(user) "(<a href='?_src_=holder;adminplayeropts=\ref[user]'>PP</a>)"
#define ADMIN_VV(atom) "(<a href='?_src_=vars;Vars=\ref[atom]'>VV</a>)"
#define ADMIN_SM(user) "(<a href='?_src_=holder;subtlemessage=\ref[user]'>SM</a>)"
#define ADMIN_TP(user) "(<a href='?_src_=holder;traitor=\ref[user]'>TP</a>)"
#define ADMIN_KICK(user) "(<a href='?_src_=holder;boot2=\ref[user]'>KICK</a>)"
#define ADMIN_CENTCOM_REPLY(user) "(<a href='?_src_=holder;CentComReply=\ref[user]'>RPLY</a>)"
#define ADMIN_SYNDICATE_REPLY(user) "(<a href='?_src_=holder;SyndicateReply=\ref[user]'>RPLY</a>)"
#define ADMIN_SC(user) "(<a href='?_src_=holder;adminspawncookie=\ref[user]'>SC</a>)"
#define ADMIN_SMITE(user) "(<a href='?_src_=holder;adminsmite=\ref[user]'>SMITE</a>)"
#define ADMIN_LOOKUP(user) "[key_name_admin(user)][ADMIN_QUE(user)]"
#define ADMIN_LOOKUPFLW(user) "[key_name_admin(user)][ADMIN_QUE(user)] [ADMIN_FLW(user)]"
#define ADMIN_SET_SD_CODE "(<a href='?_src_=holder;set_selfdestruct_code=1'>SETCODE</a>)"
#define ADMIN_FULLMONTY_NONAME(user) "[ADMIN_QUE(user)] [ADMIN_PP(user)] [ADMIN_VV(user)] [ADMIN_SM(user)] [ADMIN_FLW(user)] [ADMIN_TP(user)] [ADMIN_INDIVIDUALLOG(user)] [ADMIN_SMITE(user)]"
#define ADMIN_FULLMONTY(user) "[key_name_admin(user)] [ADMIN_FULLMONTY_NONAME(user)]"
#define ADMIN_JMP(src) "(<a href='?_src_=holder;adminplayerobservecoodjump=1;X=[src.x];Y=[src.y];Z=[src.z]'>JMP</a>)"
#define COORD(src) "[src ? "([src.x],[src.y],[src.z])" : "nonexistent location"]"
#define ADMIN_COORDJMP(src) "[src ? "[COORD(src)] [ADMIN_JMP(src)]" : "nonexistent location"]"
#define ADMIN_INDIVIDUALLOG(user) "(<a href='?_src_=holder;individuallog=\ref[user]'>LOGS</a>)"
#define ADMIN_PUNISHMENT_LIGHTNING "Lightning bolt"
#define ADMIN_PUNISHMENT_BRAINDAMAGE "Brain damage"
#define ADMIN_PUNISHMENT_GIB "Gib"
#define ADMIN_PUNISHMENT_BSA "Bluespace Artillery Device"
#define AHELP_ACTIVE 1
#define AHELP_CLOSED 2
#define AHELP_RESOLVED 3
//A set of constants used to determine which type of mute an admin wishes to apply:
//Please read and understand the muting/automuting stuff before changing these. MUTE_IC_AUTO etc = (MUTE_IC << 1)
//Therefore there needs to be a gap between the flags_1 for the automute flags_1
#define MUTE_IC 1
#define MUTE_OOC 2
#define MUTE_PRAY 4
#define MUTE_ADMINHELP 8
#define MUTE_DEADCHAT 16
#define MUTE_ALL 31
//Some constants for DB_Ban
#define BANTYPE_PERMA 1
#define BANTYPE_TEMP 2
#define BANTYPE_JOB_PERMA 3
#define BANTYPE_JOB_TEMP 4
#define BANTYPE_ANY_FULLBAN 5 //used to locate stuff to unban.
#define BANTYPE_ADMIN_PERMA 7
#define BANTYPE_ADMIN_TEMP 8
#define BANTYPE_ANY_JOB 9 //used to remove jobbans
//Please don't edit these values without speaking to Errorage first ~Carn
//Admin Permissions
#define R_BUILDMODE 1
#define R_ADMIN 2
#define R_BAN 4
#define R_FUN 8
#define R_SERVER 16
#define R_DEBUG 32
#define R_POSSESS 64
#define R_PERMISSIONS 128
#define R_STEALTH 256
#define R_POLL 512
#define R_VAREDIT 1024
#define R_SOUNDS 2048
#define R_SPAWN 4096
#if DM_VERSION > 512
#error Remove the flag below , its been long enough
#endif
//legacy , remove post 512, it was replaced by R_POLL
#define R_REJUVINATE 2
#define R_MAXPERMISSION 4096 //This holds the maximum value for a permission. It is used in iteration, so keep it updated.
#define ADMIN_QUE(user) "(<a href='?_src_=holder;adminmoreinfo=\ref[user]'>?</a>)"
#define ADMIN_FLW(user) "(<a href='?_src_=holder;adminplayerobservefollow=\ref[user]'>FLW</a>)"
#define ADMIN_PP(user) "(<a href='?_src_=holder;adminplayeropts=\ref[user]'>PP</a>)"
#define ADMIN_VV(atom) "(<a href='?_src_=vars;Vars=\ref[atom]'>VV</a>)"
#define ADMIN_SM(user) "(<a href='?_src_=holder;subtlemessage=\ref[user]'>SM</a>)"
#define ADMIN_TP(user) "(<a href='?_src_=holder;traitor=\ref[user]'>TP</a>)"
#define ADMIN_KICK(user) "(<a href='?_src_=holder;boot2=\ref[user]'>KICK</a>)"
#define ADMIN_CENTCOM_REPLY(user) "(<a href='?_src_=holder;CentComReply=\ref[user]'>RPLY</a>)"
#define ADMIN_SYNDICATE_REPLY(user) "(<a href='?_src_=holder;SyndicateReply=\ref[user]'>RPLY</a>)"
#define ADMIN_SC(user) "(<a href='?_src_=holder;adminspawncookie=\ref[user]'>SC</a>)"
#define ADMIN_SMITE(user) "(<a href='?_src_=holder;adminsmite=\ref[user]'>SMITE</a>)"
#define ADMIN_LOOKUP(user) "[key_name_admin(user)][ADMIN_QUE(user)]"
#define ADMIN_LOOKUPFLW(user) "[key_name_admin(user)][ADMIN_QUE(user)] [ADMIN_FLW(user)]"
#define ADMIN_SET_SD_CODE "(<a href='?_src_=holder;set_selfdestruct_code=1'>SETCODE</a>)"
#define ADMIN_FULLMONTY_NONAME(user) "[ADMIN_QUE(user)] [ADMIN_PP(user)] [ADMIN_VV(user)] [ADMIN_SM(user)] [ADMIN_FLW(user)] [ADMIN_TP(user)] [ADMIN_INDIVIDUALLOG(user)] [ADMIN_SMITE(user)]"
#define ADMIN_FULLMONTY(user) "[key_name_admin(user)] [ADMIN_FULLMONTY_NONAME(user)]"
#define ADMIN_JMP(src) "(<a href='?_src_=holder;adminplayerobservecoodjump=1;X=[src.x];Y=[src.y];Z=[src.z]'>JMP</a>)"
#define COORD(src) "[src ? "([src.x],[src.y],[src.z])" : "nonexistent location"]"
#define ADMIN_COORDJMP(src) "[src ? "[COORD(src)] [ADMIN_JMP(src)]" : "nonexistent location"]"
#define ADMIN_INDIVIDUALLOG(user) "(<a href='?_src_=holder;individuallog=\ref[user]'>LOGS</a>)"
#define ADMIN_PUNISHMENT_LIGHTNING "Lightning bolt"
#define ADMIN_PUNISHMENT_BRAINDAMAGE "Brain damage"
#define ADMIN_PUNISHMENT_GIB "Gib"
#define ADMIN_PUNISHMENT_BSA "Bluespace Artillery Device"
#define AHELP_ACTIVE 1
#define AHELP_CLOSED 2
#define AHELP_RESOLVED 3
//A set of constants used to determine which type of mute an admin wishes to apply:
//Please read and understand the muting/automuting stuff before changing these. MUTE_IC_AUTO etc = (MUTE_IC << 1)
//Therefore there needs to be a gap between the flags for the automute flags
#define MUTE_IC 1
#define MUTE_OOC 2
#define MUTE_PRAY 4
#define MUTE_ADMINHELP 8
#define MUTE_DEADCHAT 16
#define MUTE_ALL 31
//Some constants for DB_Ban
#define BANTYPE_PERMA 1
#define BANTYPE_TEMP 2
#define BANTYPE_JOB_PERMA 3
#define BANTYPE_JOB_TEMP 4
#define BANTYPE_ANY_FULLBAN 5 //used to locate stuff to unban.
#define BANTYPE_ADMIN_PERMA 7
#define BANTYPE_ADMIN_TEMP 8
#define BANTYPE_ANY_JOB 9 //used to remove jobbans
//Please don't edit these values without speaking to Errorage first ~Carn
//Admin Permissions
#define R_BUILDMODE 1
#define R_ADMIN 2
#define R_BAN 4
#define R_FUN 8
#define R_SERVER 16
#define R_DEBUG 32
#define R_POSSESS 64
#define R_PERMISSIONS 128
#define R_STEALTH 256
#define R_POLL 512
#define R_VAREDIT 1024
#define R_SOUNDS 2048
#define R_SPAWN 4096
#if DM_VERSION > 512
#error Remove the flag below , its been long enough
#endif
//legacy , remove post 512, it was replaced by R_POLL
#define R_REJUVINATE 2
#define R_MAXPERMISSION 4096 //This holds the maximum value for a permission. It is used in iteration, so keep it updated.
#define ADMIN_QUE(user) "(<a href='?_src_=holder;[HrefToken(TRUE)];adminmoreinfo=\ref[user]'>?</a>)"
#define ADMIN_FLW(user) "(<a href='?_src_=holder;[HrefToken(TRUE)];adminplayerobservefollow=\ref[user]'>FLW</a>)"
#define ADMIN_PP(user) "(<a href='?_src_=holder;[HrefToken(TRUE)];adminplayeropts=\ref[user]'>PP</a>)"
#define ADMIN_VV(atom) "(<a href='?_src_=vars;[HrefToken(TRUE)];Vars=\ref[atom]'>VV</a>)"
#define ADMIN_SM(user) "(<a href='?_src_=holder;[HrefToken(TRUE)];subtlemessage=\ref[user]'>SM</a>)"
#define ADMIN_TP(user) "(<a href='?_src_=holder;[HrefToken(TRUE)];traitor=\ref[user]'>TP</a>)"
#define ADMIN_KICK(user) "(<a href='?_src_=holder;[HrefToken(TRUE)];boot2=\ref[user]'>KICK</a>)"
#define ADMIN_CENTCOM_REPLY(user) "(<a href='?_src_=holder;[HrefToken(TRUE)];CentComReply=\ref[user]'>RPLY</a>)"
#define ADMIN_SYNDICATE_REPLY(user) "(<a href='?_src_=holder;[HrefToken(TRUE)];SyndicateReply=\ref[user]'>RPLY</a>)"
#define ADMIN_SC(user) "(<a href='?_src_=holder;[HrefToken(TRUE)];adminspawncookie=\ref[user]'>SC</a>)"
#define ADMIN_SMITE(user) "(<a href='?_src_=holder;[HrefToken(TRUE)];adminsmite=\ref[user]'>SMITE</a>)"
#define ADMIN_LOOKUP(user) "[key_name_admin(user)][ADMIN_QUE(user)]"
#define ADMIN_LOOKUPFLW(user) "[key_name_admin(user)][ADMIN_QUE(user)] [ADMIN_FLW(user)]"
#define ADMIN_SET_SD_CODE "(<a href='?_src_=holder;[HrefToken(TRUE)];set_selfdestruct_code=1'>SETCODE</a>)"
#define ADMIN_FULLMONTY_NONAME(user) "[ADMIN_QUE(user)] [ADMIN_PP(user)] [ADMIN_VV(user)] [ADMIN_SM(user)] [ADMIN_FLW(user)] [ADMIN_TP(user)] [ADMIN_INDIVIDUALLOG(user)] [ADMIN_SMITE(user)]"
#define ADMIN_FULLMONTY(user) "[key_name_admin(user)] [ADMIN_FULLMONTY_NONAME(user)]"
#define ADMIN_JMP(src) "(<a href='?_src_=holder;[HrefToken(TRUE)];adminplayerobservecoodjump=1;X=[src.x];Y=[src.y];Z=[src.z]'>JMP</a>)"
#define COORD(src) "[src ? "([src.x],[src.y],[src.z])" : "nonexistent location"]"
#define ADMIN_COORDJMP(src) "[src ? "[COORD(src)] [ADMIN_JMP(src)]" : "nonexistent location"]"
#define ADMIN_INDIVIDUALLOG(user) "(<a href='?_src_=holder;[HrefToken(TRUE)];individuallog=\ref[user]'>LOGS</a>)"
#define ADMIN_PUNISHMENT_LIGHTNING "Lightning bolt"
#define ADMIN_PUNISHMENT_BRAINDAMAGE "Brain damage"
#define ADMIN_PUNISHMENT_GIB "Gib"
#define ADMIN_PUNISHMENT_BSA "Bluespace Artillery Device"
#define AHELP_ACTIVE 1
#define AHELP_CLOSED 2
#define AHELP_RESOLVED 3

View File

@@ -49,6 +49,7 @@
//Health Defines
#define HEALTH_THRESHOLD_CRIT 0
#define HEALTH_THRESHOLD_FULLCRIT -30
#define HEALTH_THRESHOLD_DEAD -100
//Actual combat defines
@@ -73,6 +74,10 @@
#define GRAB_NECK 2
#define GRAB_KILL 3
//slowdown when in softcrit
#define SOFTCRIT_MIN_SLOWDOWN 8
#define SOFTCRIT_ADD_SLOWDOWN 6
//Attack types for checking shields/hit reactions
#define MELEE_ATTACK 1
#define UNARMED_ATTACK 2

View File

@@ -5,7 +5,7 @@
// How multiple components of the exact same type are handled in the same datum
#define COMPONENT_DUPE_HIGHLANDER 0 //old component is deleted (default)
#define COMPONENT_DUPE_ALLOWED 1 //duplicates allowed
#define COMPONENT_DUPE_ALLOWED 1 //duplicates allowed
#define COMPONENT_DUPE_UNIQUE 2 //new component is deleted
// All signals. Format:
@@ -16,3 +16,9 @@
#define COMSIG_PARENT_QDELETED "parent_qdeleted" //before a datum's Destroy() is called: ()
#define COMSIG_ATOM_ENTERED "atom_entered" //from base of atom/Entered(): (atom/movable, atom)
#define COMSIG_MOVABLE_CROSSED "movable_crossed" //from base of atom/movable/Crossed(): (atom/movable)
#define COMSIG_PARENT_ATTACKBY "atom_attackby" //from the base of atom/attackby: (obj/item, mob/living, params)
#define COMSIG_PARENT_EXAMINE "atom_examine" //from the base of atom/examine: (mob)
#define COMSIG_ATOM_ENTERED "atom_entered" //from base of atom/Entered(): (atom/movable, atom)
#define COMSIG_ATOM_EX_ACT "atom_ex_act" //from base of atom/ex_act(): (severity, target)
#define COMSIG_ATOM_SING_PULL "atom_sing_pull" //from base of atom/singularity_pull(): (S, current_size)
#define COMSIG_MOVABLE_CROSSED "movable_crossed" //from base of atom/movable/Crossed(): (atom/movable)

View File

@@ -101,6 +101,7 @@
#define CAT_ROBOT "Robots"
#define CAT_MISC "Misc"
#define CAT_PRIMAL "Tribal"
#define CAT_CLOTHING "Clothing"
#define CAT_FOOD "Foods"
#define CAT_BREAD "Breads"
#define CAT_BURGER "Burgers"

View File

@@ -1,5 +1,7 @@
// simple is_type and similar inline helpers
#define isdatum(D) (istype(D, /datum))
#define islist(L) (istype(L, /list))
#define in_range(source, user) (get_dist(source, user) <= 1)
@@ -25,6 +27,8 @@
#define islava(A) (istype(A, /turf/open/lava))
#define isplatingturf(A) (istype(A, /turf/open/floor/plating))
//Mobs
#define isliving(A) (istype(A, /mob/living))

View File

@@ -315,9 +315,16 @@ GLOBAL_LIST_INIT(ghost_others_options, list(GHOST_OTHERS_SIMPLE, GHOST_OTHERS_DE
#define APPEARANCE_CONSIDER_ALPHA ~RESET_ALPHA
#define APPEARANCE_LONG_GLIDE LONG_GLIDE
// Consider these images/atoms as part of the UI/HUD
#define APPEARANCE_UI_IGNORE_ALPHA RESET_COLOR|RESET_TRANSFORM|NO_CLIENT_COLOR|RESET_ALPHA
#define APPEARANCE_UI RESET_COLOR|RESET_TRANSFORM|NO_CLIENT_COLOR
#ifndef PIXEL_SCALE
#define PIXEL_SCALE 0
#if DM_VERSION >= 512
#error HEY, PIXEL_SCALE probably exists now, remove this gross ass shim.
#endif
#endif
// Consider these images/atoms as part of the UI/HUD
#define APPEARANCE_UI_IGNORE_ALPHA RESET_COLOR|RESET_TRANSFORM|NO_CLIENT_COLOR|RESET_ALPHA|PIXEL_SCALE
#define APPEARANCE_UI RESET_COLOR|RESET_TRANSFORM|NO_CLIENT_COLOR
//Just space
#define SPACE_ICON_STATE "[((x + y) ^ ~(x * y) + z) % 25]"
@@ -440,3 +447,13 @@ GLOBAL_LIST_INIT(ghost_others_options, list(GHOST_OTHERS_SIMPLE, GHOST_OTHERS_DE
#define MOUSE_OPACITY_TRANSPARENT 0
#define MOUSE_OPACITY_ICON 1
#define MOUSE_OPACITY_OPAQUE 2
//world/proc/shelleo
#define SHELLEO_ERRORLEVEL 1
#define SHELLEO_STDOUT 2
#define SHELLEO_STDERR 3
//server security mode
#define SECURITY_SAFE 1
#define SECURITY_ULTRASAFE 2
#define SECURITY_TRUSTED 3

View File

@@ -154,3 +154,5 @@
#define JUDGE_IGNOREMONKEYS 16
#define MEGAFAUNA_DEFAULT_RECOVERY_TIME 5
#define SHADOW_SPECIES_LIGHT_THRESHOLD 0.2

View File

@@ -2,6 +2,3 @@
#define TRACK_NUKE_DISK 1 //We track the nuclear authentication disk, either to protect it or steal it
#define TRACK_MALF_AI 2 //We track the malfunctioning AI, so we can prevent it from blowing us all up
#define TRACK_INFILTRATOR 3 //We track the Syndicate infiltrator, so we can get back to ship when the nuke's armed
#define TRACK_OPERATIVES 4 //We track the closest operative, so we can regroup when we need to
#define TRACK_ATOM 5 //We track a specified atom, so admins can make us function for events
#define TRACK_COORDINATES 6 //We point towards the specified coordinates on our z-level, so we can navigate

View File

@@ -47,4 +47,22 @@
#define SEC_DEPT_ENGINEERING "Engineering"
#define SEC_DEPT_MEDICAL "Medical"
#define SEC_DEPT_SCIENCE "Science"
#define SEC_DEPT_SUPPLY "Supply"
#define SEC_DEPT_SUPPLY "Supply"
// Playtime tracking system, see jobs_exp.dm
#define EXP_TYPE_LIVING "Living"
#define EXP_TYPE_CREW "Crew"
#define EXP_TYPE_COMMAND "Command"
#define EXP_TYPE_ENGINEERING "Engineering"
#define EXP_TYPE_MEDICAL "Medical"
#define EXP_TYPE_SCIENCE "Science"
#define EXP_TYPE_SUPPLY "Supply"
#define EXP_TYPE_SECURITY "Security"
#define EXP_TYPE_SILICON "Silicon"
#define EXP_TYPE_SERVICE "Service"
#define EXP_TYPE_ANTAG "Antag"
#define EXP_TYPE_SPECIAL "Special"
#define EXP_TYPE_GHOST "Ghost"
//Flags in the players table in the db
#define DB_FLAG_EXEMPT 1

View File

@@ -10,6 +10,11 @@
//if TESTING is enabled, qdel will call this object's find_references() verb.
//defines for the gc_destroyed var
#define GC_QUEUE_PREQUEUE 1
#define GC_QUEUE_CHECK 2
#define GC_QUEUE_HARDDELETE 3
#define GC_QUEUE_COUNT 3 //increase this when adding more steps.
#define GC_QUEUED_FOR_QUEUING -1
#define GC_QUEUED_FOR_HARD_DEL -2
#define GC_CURRENTLY_BEING_QDELETED -3

View File

@@ -9,7 +9,9 @@
//keep these in sync with TGS3
#define SERVICE_WORLD_PARAM "server_service"
#define SERVICE_PR_TEST_JSON "..\\..\\prtestjob.json"
#define SERVICE_VERSION_PARAM "server_service_version"
#define SERVICE_PR_TEST_JSON "prtestjob.json"
#define SERVICE_PR_TEST_JSON_OLD "..\\..\\[SERVICE_PR_TEST_JSON]"
#define SERVICE_CMD_HARD_REBOOT "hard_reboot"
#define SERVICE_CMD_GRACEFUL_SHUTDOWN "graceful_shutdown"

View File

@@ -53,9 +53,14 @@
#define ENGINE_COEFF_MAX 2
#define ENGINE_DEFAULT_MAXSPEED_ENGINES 5
//Docking error flags_1
//Docking error flags
#define DOCKING_SUCCESS 0
#define DOCKING_COMPLETE 1
#define DOCKING_BLOCKED 2
#define DOCKING_IMMOBILIZED 4
#define DOCKING_AREA_EMPTY 8
#define DOCKING_BLOCKED 1
#define DOCKING_IMMOBILIZED 2
#define DOCKING_AREA_EMPTY 4
//Docking turf movements
#define MOVE_TURF 1
#define MOVE_AREA 2
#define MOVE_CONTENTS 4

View File

@@ -10,12 +10,13 @@
#define CHANNEL_BICYCLE 1016
//Citadel code
#define CHANNEL_PRED 1018
#define CHANNEL_PRED 1015
#define CHANNEL_PREYLOOP 1014
//THIS SHOULD ALWAYS BE THE LOWEST ONE!
//KEEP IT UPDATED
#define CHANNEL_HIGHEST_AVAILABLE 1015
#define CHANNEL_HIGHEST_AVAILABLE 1013
#define CHANNEL_HIGHEST_AVAILABLE 1017
#define SOUND_MINIMUM_PRESSURE 10

View File

@@ -4,8 +4,9 @@
//mob/var/stat things
#define CONSCIOUS 0
#define UNCONSCIOUS 1
#define DEAD 2
#define SOFT_CRIT 1
#define UNCONSCIOUS 2
#define DEAD 3
//mob disabilities stat
@@ -21,9 +22,8 @@
// bitflags for machine stat variable
#define BROKEN 1
#define NOPOWER 2
#define POWEROFF 4 // tbd
#define MAINT 8 // under maintaince
#define EMPED 16 // temporary broken by EMP pulse
#define MAINT 4 // under maintaince
#define EMPED 8 // temporary broken by EMP pulse
//ai power requirement defines
#define POWER_REQ_NONE 0

View File

@@ -56,7 +56,6 @@
#define INIT_ORDER_TIMER 1
#define INIT_ORDER_DEFAULT 0
#define INIT_ORDER_AIR -1
#define INIT_ORDER_SHUTTLE -2
#define INIT_ORDER_MINIMAP -3
#define INIT_ORDER_ASSETS -4
#define INIT_ORDER_ICON_SMOOTHING -5
@@ -64,6 +63,7 @@
#define INIT_ORDER_XKEYSCORE -10
#define INIT_ORDER_STICKY_BAN -10
#define INIT_ORDER_LIGHTING -20
#define INIT_ORDER_SHUTTLE -21
#define INIT_ORDER_SQUEAK -40
#define INIT_ORDER_PERSISTENCE -100

View File

@@ -13,3 +13,11 @@ When using time2text(), please use "DDD" to find the weekday. Refrain from using
#define FRIDAY "Fri"
#define SATURDAY "Sat"
#define SUNDAY "Sun"
#define SECONDS *10
#define MINUTES SECONDS*60
#define HOURS MINUTES*60
#define TICKS *world.tick_lag

View File

@@ -2,6 +2,7 @@
#define DM_HOLD "Hold"
#define DM_DIGEST "Digest"
#define DM_HEAL "Heal"
#define DM_NOISY "Noisy"
#define VORE_STRUGGLE_EMOTE_CHANCE 40

View File

@@ -96,6 +96,9 @@
if (config.log_pda)
WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]CHAT: [text]")
/proc/log_qdel(text)
WRITE_FILE(GLOB.world_qdel_log, "\[[time_stamp()]]QDEL: [text]")
/proc/log_sql(text)
WRITE_FILE(GLOB.sql_error_log, "\[[time_stamp()]]SQL: [text]")

View File

@@ -49,3 +49,12 @@ GLOBAL_VAR_INIT(cmp_field, "name")
/proc/cmp_ruincost_priority(datum/map_template/ruin/A, datum/map_template/ruin/B)
return initial(A.cost) - initial(B.cost)
/proc/cmp_qdel_item_time(datum/qdel_item/A, datum/qdel_item/B)
. = B.hard_delete_time - A.hard_delete_time
if (!.)
. = B.destroy_time - A.destroy_time
if (!.)
. = B.failures - A.failures
if (!.)
. = B.qdels - A.qdels

View File

@@ -9,10 +9,8 @@
#define CULT_POLL_WAIT 2400
/proc/get_area(atom/A)
if (!istype(A))
return
for(A, A && !isarea(A), A=A.loc); //semicolon is for the empty statement
return A
var/turf/T = get_turf(A)
return T ? T.loc : null
/proc/get_area_name(atom/X)
var/area/Y = get_area(X)

57
code/__HELPERS/shell.dm Normal file
View File

@@ -0,0 +1,57 @@
//Runs the command in the system's shell, returns a list of (error code, stdout, stderr)
#define SHELLEO_NAME "data/shelleo."
#define SHELLEO_ERR ".err"
#define SHELLEO_OUT ".out"
/world/proc/shelleo(command)
var/static/list/shelleo_ids = list()
var/stdout = ""
var/stderr = ""
var/errorcode = 1
var/shelleo_id
var/out_file = ""
var/err_file = ""
var/static/list/interpreters = list("[MS_WINDOWS]" = "cmd /c", "[UNIX]" = "sh -c")
var/interpreter = interpreters["[world.system_type]"]
if(interpreter)
for(var/seo_id in shelleo_ids)
if(!shelleo_ids[seo_id])
shelleo_ids[seo_id] = TRUE
shelleo_id = "[seo_id]"
break
if(!shelleo_id)
shelleo_id = "[shelleo_ids.len + 1]"
shelleo_ids += shelleo_id
shelleo_ids[shelleo_id] = TRUE
out_file = "[SHELLEO_NAME][shelleo_id][SHELLEO_OUT]"
err_file = "[SHELLEO_NAME][shelleo_id][SHELLEO_ERR]"
errorcode = shell("[interpreter] \"[command]\" > [out_file] 2> [err_file]")
if(fexists(out_file))
stdout = file2text(out_file)
fdel(out_file)
if(fexists(err_file))
stderr = file2text(err_file)
fdel(err_file)
shelleo_ids[shelleo_id] = FALSE
else
CRASH("Operating System: [world.system_type] not supported") // If you encounter this error, you are encouraged to update this proc with support for the new operating system
. = list(errorcode, stdout, stderr)
#undef SHELLEO_NAME
#undef SHELLEO_ERR
#undef SHELLEO_OUT
/proc/shell_url_scrub(url)
var/static/regex/bad_chars_regex = regex("\[^#%&./:=?\\w]*", "g")
var/scrubbed_url = ""
var/bad_match = ""
var/last_good = 1
var/bad_chars = 1
do
bad_chars = bad_chars_regex.Find(url)
scrubbed_url += copytext(url, last_good, bad_chars)
if(bad_chars)
bad_match = url_encode(bad_chars_regex.match)
scrubbed_url += bad_match
last_good = bad_chars + length(bad_match)
while(bad_chars)
. = scrubbed_url

View File

@@ -1,5 +1,5 @@
/*
// Contains VOREStation type2type functions
// Contains VOREStation based vore description type2type functions
// list2text - takes delimiter and returns text
// text2list - takes delimiter, and creates list
//

View File

@@ -72,4 +72,4 @@
//Update this whenever the db schema changes
//make sure you add an update to the schema_version stable in the db changelog
#define DB_MAJOR_VERSION 3
#define DB_MINOR_VERSION 0
#define DB_MINOR_VERSION 3

View File

@@ -0,0 +1,11 @@
diff a/code/_compile_options.dm b/code/_compile_options.dm (rejected hunks)
@@ -69,7 +69,7 @@
#error You need version 511 or higher
#endif
-//Update this whenever the db schema changes
+//Update this whenever the db schema changes
//make sure you add an update to the schema_version stable in the db changelog
#define DB_MAJOR_VERSION 3
-#define DB_MINOR_VERSION 2
+#define DB_MINOR_VERSION 3

View File

@@ -105,53 +105,17 @@ GLOBAL_LIST_INIT(TAGGERLOCATIONS, list("Disposals",
GLOBAL_LIST_INIT(guitar_notes, flist("sound/guitar/"))
GLOBAL_LIST_INIT(station_prefixes, list("", "Imperium", "Heretical", "Cuban",
"Psychic", "Elegant", "Common", "Uncommon", "Rare", "Unique",
"Houseruled", "Religious", "Atheist", "Traditional", "Houseruled",
"Mad", "Super", "Ultra", "Secret", "Top Secret", "Deep", "Death",
"Zybourne", "Central", "Main", "Government", "Uoi", "Fat",
"Automated", "Experimental", "Augmented"))
GLOBAL_LIST_INIT(station_prefixes, world.file2list("strings/station_prefixes.txt") + "")
GLOBAL_LIST_INIT(station_names, list("", "Stanford", "Dorf", "Alium",
"Prefix", "Clowning", "Aegis", "Ishimura", "Scaredy", "Death-World",
"Mime", "Honk", "Rogue", "MacRagge", "Ultrameens", "Safety", "Paranoia",
"Explosive", "Neckbear", "Donk", "Muppet", "North", "West", "East",
"South", "Slant-ways", "Widdershins", "Rimward", "Expensive",
"Procreatory", "Imperial", "Unidentified", "Immoral", "Carp", "Ork",
"Pete", "Control", "Nettle", "Aspie", "Class", "Crab", "Fist",
"Corrogated","Skeleton","Race", "Fatguy", "Gentleman", "Capitalist",
"Communist", "Bear", "Beard", "Derp", "Space", "Spess", "Star", "Moon",
"System", "Mining", "Neckbeard", "Research", "Supply", "Military",
"Orbital", "Battle", "Science", "Asteroid", "Home", "Production",
"Transport", "Delivery", "Extraplanetary", "Orbital", "Correctional",
"Robot", "Hats", "Pizza"))
GLOBAL_LIST_INIT(station_names, world.file2list("strings/station_names.txt" + ""))
GLOBAL_LIST_INIT(station_suffixes, list("Station", "Frontier",
"Suffix", "Death-trap", "Space-hulk", "Lab", "Hazard","Spess Junk",
"Fishery", "No-Moon", "Tomb", "Crypt", "Hut", "Monkey", "Bomb",
"Trade Post", "Fortress", "Village", "Town", "City", "Edition", "Hive",
"Complex", "Base", "Facility", "Depot", "Outpost", "Installation",
"Drydock", "Observatory", "Array", "Relay", "Monitor", "Platform",
"Construct", "Hangar", "Prison", "Center", "Port", "Waystation",
"Factory", "Waypoint", "Stopover", "Hub", "HQ", "Office", "Object",
"Fortification", "Colony", "Planet-Cracker", "Roost", "Fat Camp",
"Airstrip"))
GLOBAL_LIST_INIT(station_suffixes, world.file2list("strings/station_suffixes.txt"))
GLOBAL_LIST_INIT(greek_letters, list("Alpha", "Beta", "Gamma", "Delta",
"Epsilon", "Zeta", "Eta", "Theta", "Iota", "Kappa", "Lambda", "Mu",
"Nu", "Xi", "Omicron", "Pi", "Rho", "Sigma", "Tau", "Upsilon", "Phi",
"Chi", "Psi", "Omega"))
GLOBAL_LIST_INIT(greek_letters, world.file2list("strings/greek_letters.txt"))
GLOBAL_LIST_INIT(phonetic_alphabet, list("Alpha", "Bravo", "Charlie",
"Delta", "Echo", "Foxtrot", "Golf", "Hotel", "India", "Juliet",
"Kilo", "Lima", "Mike", "November", "Oscar", "Papa", "Quebec",
"Romeo", "Sierra", "Tango", "Uniform", "Victor", "Whiskey", "X-ray",
"Yankee", "Zulu"))
GLOBAL_LIST_INIT(phonetic_alphabet, world.file2list("strings/phonetic_alphabet.txt"))
GLOBAL_LIST_INIT(numbers_as_words, list("One", "Two", "Three", "Four",
"Five", "Six", "Seven", "Eight", "Nine", "Ten", "Eleven", "Twelve",
"Thirteen", "Fourteen", "Fifteen", "Sixteen", "Seventeen",
"Eighteen", "Nineteen"))
GLOBAL_LIST_INIT(numbers_as_words, world.file2list("strings/numbers_as_words.txt"))
/proc/generate_number_strings()
var/list/L[198]

View File

@@ -4,6 +4,8 @@ GLOBAL_VAR(world_game_log)
GLOBAL_PROTECT(world_game_log)
GLOBAL_VAR(world_runtime_log)
GLOBAL_PROTECT(world_runtime_log)
GLOBAL_VAR(world_qdel_log)
GLOBAL_PROTECT(world_qdel_log)
GLOBAL_VAR(world_attack_log)
GLOBAL_PROTECT(world_attack_log)
GLOBAL_VAR(world_href_log)

View File

@@ -25,7 +25,7 @@
* If you are diagonally adjacent, ensure you can pass through at least one of the mutually adjacent square.
* Passing through in this case ignores anything with the LETPASSTHROW pass flag, such as tables, racks, and morgue trays.
*/
/turf/Adjacent(atom/neighbor, atom/target = null, atom/movable/mover = null)
/turf/Adjacent(atom/neighbor, atom/target = null, atom/movable/mover = null)
var/turf/T0 = get_turf(neighbor)
if(T0 == src) //same turf
@@ -37,7 +37,7 @@
// Non diagonal case
if(T0.x == x || T0.y == y)
// Check for border blockages
return T0.ClickCross(get_dir(T0,src), border_only = 1, target_atom = target, mover = mover) && src.ClickCross(get_dir(src,T0), border_only = 1, target_atom = target, mover = mover)
return T0.ClickCross(get_dir(T0,src), border_only = 1, target_atom = target, mover = mover) && src.ClickCross(get_dir(src,T0), border_only = 1, target_atom = target, mover = mover)
// Diagonal case
var/in_dir = get_dir(T0,src) // eg. northwest (1+8) = 9 (00001001)
@@ -45,16 +45,16 @@
var/d2 = in_dir&12 // eg. west (1+8)&12 (0000 1100) = 8 (0000 1000)
for(var/d in list(d1,d2))
if(!T0.ClickCross(d, border_only = 1, target_atom = target, mover = mover))
if(!T0.ClickCross(d, border_only = 1, target_atom = target, mover = mover))
continue // could not leave T0 in that direction
var/turf/T1 = get_step(T0,d)
if(!T1 || T1.density)
continue
if(!T1.ClickCross(get_dir(T1,src), border_only = 0, target_atom = target, mover = mover) || !T1.ClickCross(get_dir(T1,T0), border_only = 0, target_atom = target, mover = mover))
if(!T1 || T1.density)
continue
if(!T1.ClickCross(get_dir(T1,src), border_only = 0, target_atom = target, mover = mover) || !T1.ClickCross(get_dir(T1,T0), border_only = 0, target_atom = target, mover = mover))
continue // couldn't enter or couldn't leave T1
if(!src.ClickCross(get_dir(src,T1), border_only = 1, target_atom = target, mover = mover))
if(!src.ClickCross(get_dir(src,T1), border_only = 1, target_atom = target, mover = mover))
continue // could not enter src
return 1 // we don't care about our own density
@@ -70,7 +70,7 @@
return TRUE
if(!isturf(loc))
return FALSE
if(loc.Adjacent(neighbor,target = neighbor, mover = src))
if(loc.Adjacent(neighbor,target = neighbor, mover = src))
return TRUE
return FALSE
@@ -85,20 +85,19 @@
/*
This checks if you there is uninterrupted airspace between that turf and this one.
This is defined as any dense ON_BORDER_1 object, or any dense object without LETPASSTHROW.
This is defined as any dense ON_BORDER_1 object, or any dense object without LETPASSTHROW.
The border_only flag allows you to not objects (for source and destination squares)
*/
/turf/proc/ClickCross(target_dir, border_only, target_atom = null, atom/movable/mover = null)
/turf/proc/ClickCross(target_dir, border_only, target_atom = null, atom/movable/mover = null)
for(var/obj/O in src)
if((mover && O.CanPass(mover,get_step(src,target_dir))) || (!mover && !O.density))
continue
if(O == target_atom || (O.pass_flags & LETPASSTHROW)) //check if there's a dense object present on the turf
if((mover && O.CanPass(mover,get_step(src,target_dir))) || (!mover && !O.density))
continue
if(O == target_atom || O == mover || (O.pass_flags & LETPASSTHROW)) //check if there's a dense object present on the turf
continue // LETPASSTHROW is used for anything you can click through (or the firedoor special case, see above)
if( O.flags_1&ON_BORDER_1) // windows are on border, check them first
if( O.flags_1&ON_BORDER_1) // windows are on border, check them first
if( O.dir & target_dir || O.dir & (O.dir-1) ) // full tile windows are just diagonals mechanically
return 0 //O.dir&(O.dir-1) is false for any cardinal direction, but true for diagonal ones
else if( !border_only ) // dense, not on border, cannot pass over
return 0
return 1

View File

@@ -633,6 +633,7 @@ so as to remain in compliance with the most up-to-date laws."
/obj/screen/alert/restrained/buckled
name = "Buckled"
desc = "You've been buckled to something. Click the alert to unbuckle unless you're handcuffed."
icon_state = "buckled"
/obj/screen/alert/restrained/handcuffed
name = "Handcuffed"
@@ -698,4 +699,3 @@ so as to remain in compliance with the most up-to-date laws."
severity = 0
master = null
screen_loc = ""

View File

@@ -67,7 +67,7 @@
screen_loc = "CENTER-7,CENTER-7"
layer = FULLSCREEN_LAYER
plane = FULLSCREEN_PLANE
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
var/severity = 0
var/show_when_dead = FALSE
@@ -95,16 +95,20 @@
layer = CRIT_LAYER
plane = FULLSCREEN_PLANE
/obj/screen/fullscreen/crit/vision
icon_state = "oxydamageoverlay"
layer = BLIND_LAYER
/obj/screen/fullscreen/blind
icon_state = "blackimageoverlay"
layer = BLIND_LAYER
plane = FULLSCREEN_PLANE
/obj/screen/fullscreen/curse
icon_state = "curse"
layer = CURSE_LAYER
plane = FULLSCREEN_PLANE
/obj/screen/fullscreen/curse
icon_state = "curse"
layer = CURSE_LAYER
plane = FULLSCREEN_PLANE
/obj/screen/fullscreen/impaired
icon_state = "impairedoverlay"
@@ -168,4 +172,4 @@
plane = LIGHTING_PLANE
layer = LIGHTING_LAYER
blend_mode = BLEND_ADD
show_when_dead = TRUE
show_when_dead = TRUE

View File

@@ -46,7 +46,7 @@
name = "Female Ejaculate"
id = "femcum"
description = "Vaginal lubricant found in most mammals and other animals of similar nature. Where you found this is your own business."
taste_description = "female arousal"
taste_description = "something with a tang" // wew coders who haven't eaten out a girl.
taste_mult = 2
data = list("donor"=null,"viruses"=null,"donor_DNA"=null,"blood_type"=null,"resistances"=null,"trace_chem"=null,"mind"=null,"ckey"=null,"gender"=null,"real_name"=null)
reagent_state = LIQUID
@@ -90,7 +90,7 @@
//aphrodisiac & anaphrodisiac
/datum/reagent/aphrodisiac
/datum/reagent/drug/aphrodisiac
name = "Crocin"
id = "aphro"
description = "Naturally found in the crocus and gardenia flowers, this drug acts as a natural and safe aphrodisiac."
@@ -98,7 +98,7 @@
taste_mult = 2 //Hide the roofies in stronger flavors
color = "#FFADFF"//PINK, rgb(255, 173, 255)
/datum/reagent/aphrodisiac/on_mob_life(mob/living/M)
/datum/reagent/drug/aphrodisiac/on_mob_life(mob/living/M)
if(prob(33))
M.adjustArousalLoss(2)
if(prob(5))
@@ -108,7 +108,7 @@
to_chat(M, "<span class='love'>[aroused_message]</span>")
..()
/datum/reagent/aphrodisiacplus
/datum/reagent/drug/aphrodisiacplus
name = "Hexacrocin"
id = "aphro+"
description = "Chemically condensed form of basic crocin. This aphrodisiac is extremely powerful and addictive in most animals.\
@@ -119,7 +119,7 @@
addiction_threshold = 20
overdose_threshold = 20
/datum/reagent/aphrodisiacplus/on_mob_life(mob/living/M)
/datum/reagent/drug/aphrodisiacplus/on_mob_life(mob/living/M)
if(prob(33))
M.adjustArousalLoss(6)//not quite six times as powerful, but still considerably more powerful.
if(prob(5))
@@ -135,21 +135,21 @@
aroused_message = pick("You feel a bit hot.", "You feel strong sexual urges.", "You feel in the mood.", "You're ready to go down on someone.")
to_chat(M, "<span class='love'>[aroused_message]</span>")
/datum/reagent/aphrodisiacplus/addiction_act_stage2(mob/living/M)
/datum/reagent/drug/aphrodisiacplus/addiction_act_stage2(mob/living/M)
if(prob(30))
M.adjustBrainLoss(2)
..()
/datum/reagent/aphrodisiacplus/addiction_act_stage3(mob/living/M)
/datum/reagent/drug/aphrodisiacplus/addiction_act_stage3(mob/living/M)
if(prob(30))
M.adjustBrainLoss(3)
..()
/datum/reagent/aphrodisiacplus/addiction_act_stage4(mob/living/M)
/datum/reagent/drug/aphrodisiacplus/addiction_act_stage4(mob/living/M)
if(prob(30))
M.adjustBrainLoss(4)
..()
/datum/reagent/aphrodisiacplus/overdose_process(mob/living/M)
/datum/reagent/drug/aphrodisiacplus/overdose_process(mob/living/M)
if(prob(33))
if(M.getArousalLoss() >= 100 && ishuman(M) && M.has_dna())
var/mob/living/carbon/human/H = M
@@ -163,7 +163,7 @@
M.adjustArousalLoss(2)
..()
/datum/reagent/anaphrodisiac
/datum/reagent/drug/anaphrodisiac
name = "Camphor"
id = "anaphro"
description = "Naturally found in some species of evergreen trees, camphor is a waxy substance. When injested by most animals, it acts as an anaphrodisiac\
@@ -173,12 +173,12 @@
color = "#D9D9D9"//rgb(217, 217, 217)
reagent_state = SOLID
/datum/reagent/anaphrodisiac/on_mob_life(mob/living/M)
/datum/reagent/drug/anaphrodisiac/on_mob_life(mob/living/M)
if(prob(33))
M.adjustArousalLoss(-2)
..()
/datum/reagent/anaphrodisiacplus
/datum/reagent/drug/anaphrodisiacplus
name = "Hexacamphor"
id = "anaphro+"
description = "Chemically condensed camphor. Causes an extreme reduction in libido and a permanent one if overdosed. Non-addictive."
@@ -187,12 +187,12 @@
reagent_state = SOLID
overdose_threshold = 20
/datum/reagent/anaphrodisiacplus/on_mob_life(mob/living/M)
/datum/reagent/drug/anaphrodisiacplus/on_mob_life(mob/living/M)
if(prob(33))
M.adjustArousalLoss(-4)
..()
/datum/reagent/anaphrodisiacplus/overdose_process(mob/living/M)
/datum/reagent/drug/anaphrodisiacplus/overdose_process(mob/living/M)
if(prob(33))
if(M.min_arousal > 0)
M.min_arousal -= 1

View File

@@ -0,0 +1,56 @@
//For custom items.
/obj/item/custom/ceb_soap
name = "Cebutris' Soap"
desc = "A generic bar of soap that doesn't really seem to work right."
gender = PLURAL
icon = 'icons/obj/custom.dmi'
icon_state = "cebu"
w_class = WEIGHT_CLASS_TINY
flags_1 = NOBLUDGEON_1
/*Inferno707*/
/obj/item/clothing/neck/cloak/inferno
name = "Kiara's Cloak"
desc = "The design on this seems a little too familiar."
icon = 'icons/obj/clothing/cloaks.dmi'
icon_state = "infcloak"
item_state = "infcloak"
w_class = WEIGHT_CLASS_SMALL
body_parts_covered = CHEST|GROIN|LEGS|ARMS
/obj/item/clothing/neck/petcollar/inferno
name = "Kiara's Collar"
desc = "A soft black collar that seems to stretch to fit whoever wears it."
icon_state = "infcollar"
item_state = "infcollar"
item_color = null
tagname = null
/*DirtyOldHarry*/
/obj/item/lighter/gold
name = "\improper Engraved Zippo"
desc = "A shiny and relatively expensive zippo lighter. There's a small etched in verse on the bottom that reads, 'No Gods, No Masters, Only Man.'"
icon = 'icons/obj/cigarettes.dmi'
icon_state = "gold_zippo"
item_state = "gold_zippo"
w_class = WEIGHT_CLASS_TINY
flags_1 = CONDUCT_1
slot_flags = SLOT_BELT
heat = 1500
resistance_flags = FIRE_PROOF
light_color = LIGHT_COLOR_FIRE
/*Zombierobin*/
/obj/item/clothing/neck/scarf/zomb //Default white color, same functionality as beanies.
name = "A special scarf"
icon_state = "zombscarf"
desc = "A fashionable collar"
item_color = "zombscarf"
dog_fashion = /datum/dog_fashion/head

View File

@@ -0,0 +1,61 @@
//Proc that does the actual loading of items to mob
/*Itemlists are formatted as
"[typepath]" = number_of_it_to_spawn
*/
#define DROP_TO_FLOOR 0
#define LOADING_TO_HUMAN 1
/proc/handle_roundstart_items(mob/living/M, ckey_override, job_override, special_override)
if(!istype(M) || (!M.ckey && !ckey_override) || (!M.mind && (!job_override || !special_override)))
return FALSE
return load_itemlist_to_mob(M, parse_custom_roundstart_items(ckey_override? ckey_override : M.ckey, M.name, job_override? job_override : M.mind.assigned_role, special_override? special_override : M.mind.special_role), TRUE, TRUE, FALSE)
//Just incase there's extra mob selections in the future.....
/proc/load_itemlist_to_mob(mob/living/L, list/itemlist, drop_on_floor_if_full = TRUE, load_to_all_slots = TRUE, replace_slots = FALSE)
if(!istype(L) || !islist(itemlist))
return FALSE
var/loading_mode = DROP_TO_FLOOR
var/turf/current_turf = get_turf(L)
if(ishuman(L))
loading_mode = LOADING_TO_HUMAN
switch(loading_mode)
if(DROP_TO_FLOOR)
for(var/I in itemlist)
var/typepath = text2path(I)
if(!typepath)
continue
for(var/i = 0, i < itemlist[I], i++)
new typepath(current_turf)
return TRUE
if(LOADING_TO_HUMAN)
return load_itemlist_to_human(L, itemlist, drop_on_floor_if_full, load_to_all_slots, replace_slots)
/proc/load_itemlist_to_human(mob/living/carbon/human/H, list/itemlist, drop_on_floor_if_full = TRUE, load_to_all_slots = TRUE, replace_slots = FALSE)
if(!istype(H) || !islist(itemlist))
return FALSE
var/turf/T = get_turf(H)
for(var/item in itemlist)
var/path = item
if(!ispath(path))
path = text2path(path)
if(!path)
continue
var/amount = itemlist[item]
for(var/i in 1 to amount)
var/atom/movable/loaded_atom = new path
if(!istype(loaded_atom))
QDEL_NULL(loaded_atom)
continue
if(!istype(loaded_atom, /obj/item))
loaded_atom.forceMove(T)
continue
var/obj/item/loaded = loaded_atom
var/obj/item/storage/S = H.get_item_by_slot(slot_back)
if(istype(S))
S.handle_item_insertion(loaded, TRUE, H) //Force it into their backpack
continue
if(!H.put_in_hands(loaded)) //They don't have one/somehow that failed, put it in their hands
loaded.forceMove(T) //Guess we're just dumping it on the floor!
return TRUE

View File

@@ -0,0 +1,71 @@
GLOBAL_LIST(custom_item_list)
//Layered list in form of custom_item_list[ckey][job][items][amounts]
//ckey is key, job is specific jobs, or "ALL" for all jobs, items for items, amounts for amount of item.
//File should be in the format of ckey|exact job name/exact job name/or put ALL instead of any job names|/path/to/item=amount;/path/to/item=amount
//Each ckey should be in a different line
//if there's multiple entries of a single ckey the later ones will add to the earlier definitions.
/proc/reload_custom_roundstart_items_list(custom_filelist)
if(!custom_filelist)
custom_filelist = "config/custom_roundstart_items.txt"
GLOB.custom_item_list = list()
var/list/file_lines = world.file2list(custom_filelist)
for(var/line in file_lines)
if(length(line) == 0) //Emptyline, no one cares.
continue
if(copytext(line,1,3) == "//") //Commented line, ignore.
continue
var/ckey_str_sep = findtext(line, "|") //Process our stuff..
var/char_str_sep = findtext(line, "|", ckey_str_sep+1)
var/job_str_sep = findtext(line, "|", char_str_sep+1)
var/item_str_sep = findtext(line, "|", job_str_sep+1)
var/ckey_str = ckey(copytext(line, 1, ckey_str_sep))
var/char_str = copytext(line, ckey_str_sep+1, char_str_sep)
var/job_str = copytext(line, char_str_sep+1, job_str_sep)
var/item_str = copytext(line, job_str_sep+1, item_str_sep)
if(!ckey_str || !char_str || !job_str || !item_str || !length(ckey_str) || !length(char_str) || !length(job_str) || !length(item_str))
log_admin("Errored custom_items_whitelist line: [line] - Component/separator missing!")
if(!islist(GLOB.custom_item_list[ckey_str]))
GLOB.custom_item_list[ckey_str] = list() //Initialize list for this ckey if it isn't initialized..
var/list/characters = splittext(char_str, "/")
for(var/character in characters)
if(!islist(GLOB.custom_item_list[ckey_str][character]))
GLOB.custom_item_list[ckey_str][character] = list()
var/list/jobs = splittext(job_str, "/")
for(var/job in jobs)
for(var/character in characters)
if(!islist(GLOB.custom_item_list[ckey_str][character][job]))
GLOB.custom_item_list[ckey_str][character][job] = list() //Initialize item list for this job of this ckey if not already initialized.
var/list/item_strings = splittext(item_str, ";") //Get item strings in format of /path/to/item=amount
for(var/item_string in item_strings)
var/path_str_sep = findtext(item_string, "=")
var/path = copytext(item_string, 1, path_str_sep) //Path to spawn
var/amount = copytext(item_string, path_str_sep+1) //Amount to spawn
//world << "DEBUG: Item string [item_string] processed"
amount = text2num(amount)
path = text2path(path)
if(!ispath(path) || !isnum(amount))
log_admin("Errored custom_items_whitelist line: [line] - Path/number for item missing or invalid.")
for(var/character in characters)
for(var/job in jobs)
if(!GLOB.custom_item_list[ckey_str][character][job][path]) //Doesn't exist, make it exist!
GLOB.custom_item_list[ckey_str][character][job][path] = amount
else
GLOB.custom_item_list[ckey_str][character][job][path] += amount //Exists, we want more~
return GLOB.custom_item_list
/proc/parse_custom_roundstart_items(ckey, char_name = "ALL", job_name = "ALL", special_role)
var/list/ret = list()
if(GLOB.custom_item_list[ckey])
for(var/char in GLOB.custom_item_list[ckey])
if((char_name == char) || (char_name == "ALL") || (char == "ALL"))
for(var/job in GLOB.custom_item_list[ckey][char])
if((job_name == job) || (job == "ALL") || (job_name == "ALL") || (special_role && (job == special_role)))
for(var/item_path in GLOB.custom_item_list[ckey][char][job])
if(ret[item_path])
ret[item_path] += GLOB.custom_item_list[ckey][char][job][item_path]
else
ret[item_path] = GLOB.custom_item_list[ckey][char][job][item_path]
return ret

View File

@@ -23,7 +23,6 @@
attack_verb = list("nibbled", "bit", "gnawed", "chomped", "nommed")
w_class = 3
sharpness = IS_SHARP
var/emagged = 0
/obj/item/dogborg/jaws/attack(atom/A, mob/living/silicon/robot/user)
..()
@@ -173,7 +172,6 @@
icon_state = "synthtongue"
hitsound = 'sound/effects/attackblob.ogg'
cleanspeed = 80
var/emagged = 0
/obj/item/soap/tongue/New()
..()

View File

@@ -5,6 +5,10 @@
#define SECURITY_HAS_MAINT_ACCESS 2
#define EVERYONE_HAS_MAINT_ACCESS 4
GLOBAL_VAR_INIT(config_dir, "config/")
GLOBAL_PROTECT(config_dir)
/datum/configuration/can_vv_get(var_name)
var/static/list/banned_gets = list("autoadmin", "autoadmin_rank")
if (var_name in banned_gets)
@@ -12,7 +16,7 @@
return ..()
/datum/configuration/vv_edit_var(var_name, var_value)
var/static/list/banned_edits = list("cross_address", "cross_allowed", "autoadmin", "autoadmin_rank")
var/static/list/banned_edits = list("cross_address", "cross_allowed", "autoadmin", "autoadmin_rank", "invoke_youtubedl")
if(var_name in banned_edits)
return FALSE
return ..()
@@ -90,6 +94,8 @@
var/panic_server_name
var/panic_address //Reconnect a player this linked server if this server isn't accepting new players
var/invoke_youtubedl
//IP Intel vars
var/ipintel_email
var/ipintel_rating_bad = 1
@@ -102,6 +108,15 @@
var/use_age_restriction_for_jobs = 0 //Do jobs use account age restrictions? --requires database
var/use_account_age_for_jobs = 0 //Uses the time they made the account for the job restriction stuff. New player joining alerts should be unaffected.
var/see_own_notes = 0 //Can players see their own admin notes (read-only)? Config option in config.txt
var/note_fresh_days
var/note_stale_days
var/use_exp_tracking = FALSE
var/use_exp_restrictions_heads = FALSE
var/use_exp_restrictions_heads_hours = 0
var/use_exp_restrictions_heads_department = FALSE
var/use_exp_restrictions_other = FALSE
var/use_exp_restrictions_admin_bypass = FALSE
//Population cap vars
var/soft_popcap = 0
@@ -168,6 +183,7 @@
var/rename_cyborg = 0
var/ooc_during_round = 0
var/emojis = 0
var/no_credits_round_end = FALSE
//Used for modifying movement speed for mobs.
//Unversal modifiers
@@ -266,6 +282,8 @@
var/list/policies = list()
var/debug_admin_hrefs = FALSE //turns off admin href token protection for debugging purposes
/datum/configuration/New()
gamemode_cache = typecacheof(/datum/game_mode,TRUE)
for(var/T in gamemode_cache)
@@ -287,18 +305,20 @@
Reload()
/datum/configuration/proc/Reload()
load("config/config.txt")
load("config/comms.txt", "comms")
load("config/game_options.txt","game_options")
load("config/policies.txt", "policies")
loadsql("config/dbconfig.txt")
load("config.txt")
load("comms.txt", "comms")
load("game_options.txt","game_options")
load("policies.txt", "policies")
loadsql("dbconfig.txt")
reload_custom_roundstart_items_list()
if (maprotation)
loadmaplist("config/maps.txt")
loadmaplist("maps.txt")
// apply some settings from config..
GLOB.abandon_allowed = respawn
/datum/configuration/proc/load(filename, type = "config") //the type can also be game_options, in which case it uses a different switch. not making it separate to not copypaste code - Urist
filename = "[GLOB.config_dir][filename]"
var/list/Lines = world.file2list(filename)
for(var/t in Lines)
@@ -336,6 +356,18 @@
use_age_restriction_for_jobs = 1
if("use_account_age_for_jobs")
use_account_age_for_jobs = 1
if("use_exp_tracking")
use_exp_tracking = TRUE
if("use_exp_restrictions_heads")
use_exp_restrictions_heads = TRUE
if("use_exp_restrictions_heads_hours")
use_exp_restrictions_heads_hours = text2num(value)
if("use_exp_restrictions_heads_department")
use_exp_restrictions_heads_department = TRUE
if("use_exp_restrictions_other")
use_exp_restrictions_other = TRUE
if("use_exp_restrictions_admin_bypass")
use_exp_restrictions_admin_bypass = TRUE
if("lobby_countdown")
lobby_countdown = text2num(value)
if("round_end_countdown")
@@ -450,10 +482,16 @@
if("panic_server_address")
if(value != "byond://address:port")
panic_address = value
if("invoke_youtubedl")
invoke_youtubedl = value
if("show_irc_name")
showircname = 1
if("see_own_notes")
see_own_notes = 1
if("note_fresh_days")
note_fresh_days = text2num(value)
if("note_stale_days")
note_stale_days = text2num(value)
if("soft_popcap")
soft_popcap = text2num(value)
if("hard_popcap")
@@ -533,6 +571,8 @@
error_msg_delay = text2num(value)
if("irc_announce_new_game")
irc_announce_new_game = TRUE
if("debug_admin_hrefs")
debug_admin_hrefs = TRUE
else
#if DM_VERSION > 511
#error Replace the line below with WRITE_FILE(GLOB.config_error_log, "Unknown setting in configuration: '[name]'")
@@ -556,6 +596,8 @@
ooc_during_round = 1
if("emojis")
emojis = 1
if("no_credits_round_end")
no_credits_round_end = TRUE
if("run_delay")
run_speed = text2num(value)
if("walk_delay")
@@ -799,6 +841,7 @@
WRITE_FILE(GLOB.config_error_log, "Unknown setting in configuration: '[name]'")
/datum/configuration/proc/loadmaplist(filename)
filename = "[GLOB.config_dir][filename]"
var/list/Lines = world.file2list(filename)
var/datum/map_config/currentmap = null
@@ -851,6 +894,7 @@
/datum/configuration/proc/loadsql(filename)
filename = "[GLOB.config_dir][filename]"
var/list/Lines = world.file2list(filename)
for(var/t in Lines)
if(!t)

View File

@@ -0,0 +1,24 @@
diff a/code/controllers/configuration.dm b/code/controllers/configuration.dm (rejected hunks)
@@ -337,17 +337,17 @@
if("use_account_age_for_jobs")
use_account_age_for_jobs = 1
if("use_exp_tracking")
- use_exp_tracking = 1
+ use_exp_tracking = TRUE
if("use_exp_restrictions_heads")
- use_exp_restrictions_heads = 1
+ use_exp_restrictions_heads = TRUE
if("use_exp_restrictions_heads_hours")
use_exp_restrictions_heads_hours = text2num(value)
if("use_exp_restrictions_heads_department")
- use_exp_restrictions_heads_department = 1
+ use_exp_restrictions_heads_department = TRUE
if("use_exp_restrictions_other")
- use_exp_restrictions_other = 1
+ use_exp_restrictions_other = TRUE
if("use_exp_restrictions_admin_bypass")
- use_exp_restrictions_admin_bypass = 1
+ use_exp_restrictions_admin_bypass = TRUE
if("lobby_countdown")
lobby_countdown = text2num(value)
if("round_end_countdown")

View File

@@ -1,102 +1,102 @@
/**
* Failsafe
*
* Pretty much pokes the MC to make sure it's still alive.
**/
GLOBAL_REAL(Failsafe, /datum/controller/failsafe)
/datum/controller/failsafe // This thing pretty much just keeps poking the master controller
name = "Failsafe"
// The length of time to check on the MC (in deciseconds).
// Set to 0 to disable.
var/processing_interval = 20
// The alert level. For every failed poke, we drop a DEFCON level. Once we hit DEFCON 1, restart the MC.
var/defcon = 5
//the world.time of the last check, so the mc can restart US if we hang.
// (Real friends look out for *eachother*)
var/lasttick = 0
// Track the MC iteration to make sure its still on track.
var/master_iteration = 0
var/running = TRUE
/datum/controller/failsafe/New()
// Highlander-style: there can only be one! Kill off the old and replace it with the new.
if(Failsafe != src)
if(istype(Failsafe))
qdel(Failsafe)
Failsafe = src
Initialize()
/datum/controller/failsafe/Initialize()
set waitfor = 0
Failsafe.Loop()
if(!QDELETED(src))
qdel(src) //when Loop() returns, we delete ourselves and let the mc recreate us
/datum/controller/failsafe/Destroy()
running = FALSE
..()
return QDEL_HINT_HARDDEL_NOW
/datum/controller/failsafe/proc/Loop()
while(running)
lasttick = world.time
if(!Master)
// Replace the missing Master! This should never, ever happen.
new /datum/controller/master()
// Only poke it if overrides are not in effect.
if(processing_interval > 0)
if(Master.processing && Master.iteration)
// Check if processing is done yet.
if(Master.iteration == master_iteration)
switch(defcon)
if(4,5)
--defcon
if(3)
to_chat(GLOB.admins, "<span class='adminnotice'>Notice: DEFCON [defcon_pretty()]. The Master Controller has not fired in the last [(5-defcon) * processing_interval] ticks.")
--defcon
if(2)
to_chat(GLOB.admins, "<span class='boldannounce'>Warning: DEFCON [defcon_pretty()]. The Master Controller has not fired in the last [(5-defcon) * processing_interval] ticks. Automatic restart in [processing_interval] ticks.</span>")
--defcon
if(1)
to_chat(GLOB.admins, "<span class='boldannounce'>Warning: DEFCON [defcon_pretty()]. The Master Controller has still not fired within the last [(5-defcon) * processing_interval] ticks. Killing and restarting...</span>")
--defcon
var/rtn = Recreate_MC()
if(rtn > 0)
defcon = 4
master_iteration = 0
to_chat(GLOB.admins, "<span class='adminnotice'>MC restarted successfully</span>")
else if(rtn < 0)
log_game("FailSafe: Could not restart MC, runtime encountered. Entering defcon 0")
to_chat(GLOB.admins, "<span class='boldannounce'>ERROR: DEFCON [defcon_pretty()]. Could not restart MC, runtime encountered. I will silently keep retrying.</span>")
//if the return number was 0, it just means the mc was restarted too recently, and it just needs some time before we try again
//no need to handle that specially when defcon 0 can handle it
if(0) //DEFCON 0! (mc failed to restart)
var/rtn = Recreate_MC()
if(rtn > 0)
defcon = 4
master_iteration = 0
to_chat(GLOB.admins, "<span class='adminnotice'>MC restarted successfully</span>")
else
defcon = min(defcon + 1,5)
master_iteration = Master.iteration
if (defcon <= 1)
sleep(processing_interval*2)
else
sleep(processing_interval)
else
defcon = 5
sleep(initial(processing_interval))
/datum/controller/failsafe/proc/defcon_pretty()
return defcon
/datum/controller/failsafe/stat_entry()
if(!statclick)
statclick = new/obj/effect/statclick/debug(null, "Initializing...", src)
stat("Failsafe Controller:", statclick.update("Defcon: [defcon_pretty()] (Interval: [Failsafe.processing_interval] | Iteration: [Failsafe.master_iteration])"))
/**
* Failsafe
*
* Pretty much pokes the MC to make sure it's still alive.
**/
GLOBAL_REAL(Failsafe, /datum/controller/failsafe)
/datum/controller/failsafe // This thing pretty much just keeps poking the master controller
name = "Failsafe"
// The length of time to check on the MC (in deciseconds).
// Set to 0 to disable.
var/processing_interval = 20
// The alert level. For every failed poke, we drop a DEFCON level. Once we hit DEFCON 1, restart the MC.
var/defcon = 5
//the world.time of the last check, so the mc can restart US if we hang.
// (Real friends look out for *eachother*)
var/lasttick = 0
// Track the MC iteration to make sure its still on track.
var/master_iteration = 0
var/running = TRUE
/datum/controller/failsafe/New()
// Highlander-style: there can only be one! Kill off the old and replace it with the new.
if(Failsafe != src)
if(istype(Failsafe))
qdel(Failsafe)
Failsafe = src
Initialize()
/datum/controller/failsafe/Initialize()
set waitfor = 0
Failsafe.Loop()
if(!QDELETED(src))
qdel(src) //when Loop() returns, we delete ourselves and let the mc recreate us
/datum/controller/failsafe/Destroy()
running = FALSE
..()
return QDEL_HINT_HARDDEL_NOW
/datum/controller/failsafe/proc/Loop()
while(running)
lasttick = world.time
if(!Master)
// Replace the missing Master! This should never, ever happen.
new /datum/controller/master()
// Only poke it if overrides are not in effect.
if(processing_interval > 0)
if(Master.processing && Master.iteration)
// Check if processing is done yet.
if(Master.iteration == master_iteration)
switch(defcon)
if(4,5)
--defcon
if(3)
message_admins("<span class='adminnotice'>Notice: DEFCON [defcon_pretty()]. The Master Controller has not fired in the last [(5-defcon) * processing_interval] ticks.</span>")
--defcon
if(2)
to_chat(GLOB.admins, "<span class='boldannounce'>Warning: DEFCON [defcon_pretty()]. The Master Controller has not fired in the last [(5-defcon) * processing_interval] ticks. Automatic restart in [processing_interval] ticks.</span>")
--defcon
if(1)
to_chat(GLOB.admins, "<span class='boldannounce'>Warning: DEFCON [defcon_pretty()]. The Master Controller has still not fired within the last [(5-defcon) * processing_interval] ticks. Killing and restarting...</span>")
--defcon
var/rtn = Recreate_MC()
if(rtn > 0)
defcon = 4
master_iteration = 0
to_chat(GLOB.admins, "<span class='adminnotice'>MC restarted successfully</span>")
else if(rtn < 0)
log_game("FailSafe: Could not restart MC, runtime encountered. Entering defcon 0")
to_chat(GLOB.admins, "<span class='boldannounce'>ERROR: DEFCON [defcon_pretty()]. Could not restart MC, runtime encountered. I will silently keep retrying.</span>")
//if the return number was 0, it just means the mc was restarted too recently, and it just needs some time before we try again
//no need to handle that specially when defcon 0 can handle it
if(0) //DEFCON 0! (mc failed to restart)
var/rtn = Recreate_MC()
if(rtn > 0)
defcon = 4
master_iteration = 0
to_chat(GLOB.admins, "<span class='adminnotice'>MC restarted successfully</span>")
else
defcon = min(defcon + 1,5)
master_iteration = Master.iteration
if (defcon <= 1)
sleep(processing_interval*2)
else
sleep(processing_interval)
else
defcon = 5
sleep(initial(processing_interval))
/datum/controller/failsafe/proc/defcon_pretty()
return defcon
/datum/controller/failsafe/stat_entry()
if(!statclick)
statclick = new/obj/effect/statclick/debug(null, "Initializing...", src)
stat("Failsafe Controller:", statclick.update("Defcon: [defcon_pretty()] (Interval: [Failsafe.processing_interval] | Iteration: [Failsafe.master_iteration])"))

View File

@@ -1,269 +1,281 @@
SUBSYSTEM_DEF(blackbox)
name = "Blackbox"
wait = 6000
flags = SS_NO_TICK_CHECK | SS_NO_INIT
runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME
init_order = INIT_ORDER_BLACKBOX
var/list/msg_common = list()
var/list/msg_science = list()
var/list/msg_command = list()
var/list/msg_medical = list()
var/list/msg_engineering = list()
var/list/msg_security = list()
var/list/msg_deathsquad = list()
var/list/msg_syndicate = list()
var/list/msg_service = list()
var/list/msg_cargo = list()
var/list/msg_other = list()
var/list/feedback = list() //list of datum/feedback_variable
var/sealed = FALSE //time to stop tracking stats?
//poll population
/datum/controller/subsystem/blackbox/fire()
if(!SSdbcore.Connect())
return
var/playercount = 0
for(var/mob/M in GLOB.player_list)
if(M.client)
playercount += 1
var/admincount = GLOB.admins.len
var/datum/DBQuery/query_record_playercount = SSdbcore.NewQuery("INSERT INTO [format_table_name("legacy_population")] (playercount, admincount, time, server_ip, server_port) VALUES ([playercount], [admincount], '[SQLtime()]', INET_ATON(IF('[world.internet_address]' LIKE '', '0', '[world.internet_address]')), '[world.port]')")
query_record_playercount.Execute()
/datum/controller/subsystem/blackbox/Recover()
msg_common = SSblackbox.msg_common
msg_science = SSblackbox.msg_science
msg_command = SSblackbox.msg_command
msg_medical = SSblackbox.msg_medical
msg_engineering = SSblackbox.msg_engineering
msg_security = SSblackbox.msg_security
msg_deathsquad = SSblackbox.msg_deathsquad
msg_syndicate = SSblackbox.msg_syndicate
msg_service = SSblackbox.msg_service
msg_cargo = SSblackbox.msg_cargo
msg_other = SSblackbox.msg_other
feedback = SSblackbox.feedback
sealed = SSblackbox.sealed
//no touchie
/datum/controller/subsystem/blackbox/can_vv_get(var_name)
if(var_name == "feedback")
return FALSE
return ..()
/datum/controller/subsystem/blackbox/vv_edit_var(var_name, var_value)
return FALSE
/datum/controller/subsystem/blackbox/Shutdown()
sealed = FALSE
set_val("ahelp_unresolved", GLOB.ahelp_tickets.active_tickets.len)
var/pda_msg_amt = 0
var/rc_msg_amt = 0
for (var/obj/machinery/message_server/MS in GLOB.message_servers)
if (MS.pda_msgs.len > pda_msg_amt)
pda_msg_amt = MS.pda_msgs.len
if (MS.rc_msgs.len > rc_msg_amt)
rc_msg_amt = MS.rc_msgs.len
set_details("radio_usage","")
add_details("radio_usage","COM-[msg_common.len]")
add_details("radio_usage","SCI-[msg_science.len]")
add_details("radio_usage","HEA-[msg_command.len]")
add_details("radio_usage","MED-[msg_medical.len]")
add_details("radio_usage","ENG-[msg_engineering.len]")
add_details("radio_usage","SEC-[msg_security.len]")
add_details("radio_usage","DTH-[msg_deathsquad.len]")
add_details("radio_usage","SYN-[msg_syndicate.len]")
add_details("radio_usage","SRV-[msg_service.len]")
add_details("radio_usage","CAR-[msg_cargo.len]")
add_details("radio_usage","OTH-[msg_other.len]")
add_details("radio_usage","PDA-[pda_msg_amt]")
add_details("radio_usage","RC-[rc_msg_amt]")
if (!SSdbcore.Connect())
return
var/list/sqlrowlist = list()
for (var/datum/feedback_variable/FV in feedback)
sqlrowlist += list(list("time" = "Now()", "round_id" = GLOB.round_id, "var_name" = "'[sanitizeSQL(FV.get_variable())]'", "var_value" = FV.get_value(), "details" = "'[sanitizeSQL(FV.get_details())]'"))
if (!length(sqlrowlist))
return
SSdbcore.MassInsert(format_table_name("feedback"), sqlrowlist, ignore_errors = TRUE, delayed = TRUE)
/datum/controller/subsystem/blackbox/proc/LogBroadcast(blackbox_msg, freq)
if(sealed)
return
switch(freq)
if(1459)
msg_common += blackbox_msg
if(1351)
msg_science += blackbox_msg
if(1353)
msg_command += blackbox_msg
if(1355)
msg_medical += blackbox_msg
if(1357)
msg_engineering += blackbox_msg
if(1359)
msg_security += blackbox_msg
if(1441)
msg_deathsquad += blackbox_msg
if(1213)
msg_syndicate += blackbox_msg
if(1349)
msg_service += blackbox_msg
if(1347)
msg_cargo += blackbox_msg
else
msg_other += blackbox_msg
/datum/controller/subsystem/blackbox/proc/find_feedback_datum(variable)
for(var/datum/feedback_variable/FV in feedback)
if(FV.get_variable() == variable)
return FV
var/datum/feedback_variable/FV = new(variable)
feedback += FV
return FV
/datum/controller/subsystem/blackbox/proc/set_val(variable, value)
if(sealed)
return
var/datum/feedback_variable/FV = find_feedback_datum(variable)
FV.set_value(value)
/datum/controller/subsystem/blackbox/proc/inc(variable, value)
if(sealed)
return
var/datum/feedback_variable/FV = find_feedback_datum(variable)
FV.inc(value)
/datum/controller/subsystem/blackbox/proc/dec(variable,value)
if(sealed)
return
var/datum/feedback_variable/FV = find_feedback_datum(variable)
FV.dec(value)
/datum/controller/subsystem/blackbox/proc/set_details(variable,details)
if(sealed)
return
var/datum/feedback_variable/FV = find_feedback_datum(variable)
FV.set_details(details)
/datum/controller/subsystem/blackbox/proc/add_details(variable,details)
if(sealed)
return
var/datum/feedback_variable/FV = find_feedback_datum(variable)
FV.add_details(details)
/datum/controller/subsystem/blackbox/proc/ReportDeath(mob/living/L)
if(sealed)
return
if(!SSdbcore.Connect())
return
if(!L || !L.key || !L.mind)
return
var/turf/T = get_turf(L)
var/area/placeofdeath = get_area(T.loc)
var/sqlname = sanitizeSQL(L.real_name)
var/sqlkey = sanitizeSQL(L.ckey)
var/sqljob = sanitizeSQL(L.mind.assigned_role)
var/sqlspecial = sanitizeSQL(L.mind.special_role)
var/sqlpod = sanitizeSQL(placeofdeath.name)
var/laname
var/lakey
if(L.lastattacker && ismob(L.lastattacker))
var/mob/LA = L.lastattacker
laname = sanitizeSQL(LA.real_name)
lakey = sanitizeSQL(LA.key)
var/sqlbrute = sanitizeSQL(L.getBruteLoss())
var/sqlfire = sanitizeSQL(L.getFireLoss())
var/sqlbrain = sanitizeSQL(L.getBrainLoss())
var/sqloxy = sanitizeSQL(L.getOxyLoss())
var/sqltox = sanitizeSQL(L.getToxLoss())
var/sqlclone = sanitizeSQL(L.getCloneLoss())
var/sqlstamina = sanitizeSQL(L.getStaminaLoss())
var/x_coord = sanitizeSQL(L.x)
var/y_coord = sanitizeSQL(L.y)
var/z_coord = sanitizeSQL(L.z)
var/map = sanitizeSQL(SSmapping.config.map_name)
var/datum/DBQuery/query_report_death = SSdbcore.NewQuery("INSERT INTO [format_table_name("death")] (pod, x_coord, y_coord, z_coord, mapname, server_ip, server_port, round_id, tod, job, special, name, byondkey, laname, lakey, bruteloss, fireloss, brainloss, oxyloss, toxloss, cloneloss, staminaloss) VALUES ('[sqlpod]', '[x_coord]', '[y_coord]', '[z_coord]', '[map]', INET_ATON(IF('[world.internet_address]' LIKE '', '0', '[world.internet_address]')), '[world.port]', [GLOB.round_id], '[SQLtime()]', '[sqljob]', '[sqlspecial]', '[sqlname]', '[sqlkey]', '[laname]', '[lakey]', [sqlbrute], [sqlfire], [sqlbrain], [sqloxy], [sqltox], [sqlclone], [sqlstamina])")
query_report_death.Execute()
/datum/controller/subsystem/blackbox/proc/Seal()
if(sealed)
return
if(IsAdminAdvancedProcCall())
var/msg = "[key_name_admin(usr)] sealed the blackbox!"
message_admins(msg)
log_game("Blackbox sealed[IsAdminAdvancedProcCall() ? " by [key_name(usr)]" : ""].")
sealed = TRUE
//feedback variable datum, for storing all kinds of data
/datum/feedback_variable
var/variable
var/value
var/details
/datum/feedback_variable/New(param_variable, param_value = 0)
variable = param_variable
value = param_value
/datum/feedback_variable/proc/inc(num = 1)
if (isnum(value))
value += num
else
value = text2num(value)
if (isnum(value))
value += num
else
value = num
/datum/feedback_variable/proc/dec(num = 1)
if (isnum(value))
value -= num
else
value = text2num(value)
if (isnum(value))
value -= num
else
value = -num
/datum/feedback_variable/proc/set_value(num)
if (isnum(num))
value = num
/datum/feedback_variable/proc/get_value()
if (!isnum(value))
return 0
return value
/datum/feedback_variable/proc/get_variable()
return variable
SUBSYSTEM_DEF(blackbox)
name = "Blackbox"
wait = 6000
flags = SS_NO_TICK_CHECK
runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME
init_order = INIT_ORDER_BLACKBOX
var/list/msg_common = list()
var/list/msg_science = list()
var/list/msg_command = list()
var/list/msg_medical = list()
var/list/msg_engineering = list()
var/list/msg_security = list()
var/list/msg_deathsquad = list()
var/list/msg_syndicate = list()
var/list/msg_service = list()
var/list/msg_cargo = list()
var/list/msg_other = list()
var/list/feedback = list() //list of datum/feedback_variable
var/triggertime = 0
var/sealed = FALSE //time to stop tracking stats?
/datum/controller/subsystem/blackbox/Initialize()
triggertime = world.time
. = ..()
//poll population
/datum/controller/subsystem/blackbox/fire()
if(!SSdbcore.Connect())
return
var/playercount = 0
for(var/mob/M in GLOB.player_list)
if(M.client)
playercount += 1
var/admincount = GLOB.admins.len
var/datum/DBQuery/query_record_playercount = SSdbcore.NewQuery("INSERT INTO [format_table_name("legacy_population")] (playercount, admincount, time, server_ip, server_port, round_id) VALUES ([playercount], [admincount], '[SQLtime()]', INET_ATON(IF('[world.internet_address]' LIKE '', '0', '[world.internet_address]')), '[world.port]', '[GLOB.round_id]')")
query_record_playercount.Execute()
if(config.use_exp_tracking)
if((triggertime < 0) || (world.time > (triggertime +3000))) //subsystem fires once at roundstart then once every 10 minutes. a 5 min check skips the first fire. The <0 is midnight rollover check
update_exp(10,FALSE)
/datum/controller/subsystem/blackbox/Recover()
msg_common = SSblackbox.msg_common
msg_science = SSblackbox.msg_science
msg_command = SSblackbox.msg_command
msg_medical = SSblackbox.msg_medical
msg_engineering = SSblackbox.msg_engineering
msg_security = SSblackbox.msg_security
msg_deathsquad = SSblackbox.msg_deathsquad
msg_syndicate = SSblackbox.msg_syndicate
msg_service = SSblackbox.msg_service
msg_cargo = SSblackbox.msg_cargo
msg_other = SSblackbox.msg_other
feedback = SSblackbox.feedback
sealed = SSblackbox.sealed
//no touchie
/datum/controller/subsystem/blackbox/can_vv_get(var_name)
if(var_name == "feedback")
return FALSE
return ..()
/datum/controller/subsystem/blackbox/vv_edit_var(var_name, var_value)
return FALSE
/datum/controller/subsystem/blackbox/Shutdown()
sealed = FALSE
set_val("ahelp_unresolved", GLOB.ahelp_tickets.active_tickets.len)
var/pda_msg_amt = 0
var/rc_msg_amt = 0
for (var/obj/machinery/message_server/MS in GLOB.message_servers)
if (MS.pda_msgs.len > pda_msg_amt)
pda_msg_amt = MS.pda_msgs.len
if (MS.rc_msgs.len > rc_msg_amt)
rc_msg_amt = MS.rc_msgs.len
set_details("radio_usage","")
add_details("radio_usage","COM-[msg_common.len]")
add_details("radio_usage","SCI-[msg_science.len]")
add_details("radio_usage","HEA-[msg_command.len]")
add_details("radio_usage","MED-[msg_medical.len]")
add_details("radio_usage","ENG-[msg_engineering.len]")
add_details("radio_usage","SEC-[msg_security.len]")
add_details("radio_usage","DTH-[msg_deathsquad.len]")
add_details("radio_usage","SYN-[msg_syndicate.len]")
add_details("radio_usage","SRV-[msg_service.len]")
add_details("radio_usage","CAR-[msg_cargo.len]")
add_details("radio_usage","OTH-[msg_other.len]")
add_details("radio_usage","PDA-[pda_msg_amt]")
add_details("radio_usage","RC-[rc_msg_amt]")
if (!SSdbcore.Connect())
return
var/list/sqlrowlist = list()
for (var/datum/feedback_variable/FV in feedback)
sqlrowlist += list(list("time" = "Now()", "round_id" = GLOB.round_id, "var_name" = "'[sanitizeSQL(FV.get_variable())]'", "var_value" = FV.get_value(), "details" = "'[sanitizeSQL(FV.get_details())]'"))
if (!length(sqlrowlist))
return
SSdbcore.MassInsert(format_table_name("feedback"), sqlrowlist, ignore_errors = TRUE, delayed = TRUE)
/datum/controller/subsystem/blackbox/proc/LogBroadcast(blackbox_msg, freq)
if(sealed)
return
switch(freq)
if(1459)
msg_common += blackbox_msg
if(1351)
msg_science += blackbox_msg
if(1353)
msg_command += blackbox_msg
if(1355)
msg_medical += blackbox_msg
if(1357)
msg_engineering += blackbox_msg
if(1359)
msg_security += blackbox_msg
if(1441)
msg_deathsquad += blackbox_msg
if(1213)
msg_syndicate += blackbox_msg
if(1349)
msg_service += blackbox_msg
if(1347)
msg_cargo += blackbox_msg
else
msg_other += blackbox_msg
/datum/controller/subsystem/blackbox/proc/find_feedback_datum(variable)
for(var/datum/feedback_variable/FV in feedback)
if(FV.get_variable() == variable)
return FV
var/datum/feedback_variable/FV = new(variable)
feedback += FV
return FV
/datum/controller/subsystem/blackbox/proc/set_val(variable, value)
if(sealed)
return
var/datum/feedback_variable/FV = find_feedback_datum(variable)
FV.set_value(value)
/datum/controller/subsystem/blackbox/proc/inc(variable, value)
if(sealed)
return
var/datum/feedback_variable/FV = find_feedback_datum(variable)
FV.inc(value)
/datum/controller/subsystem/blackbox/proc/dec(variable,value)
if(sealed)
return
var/datum/feedback_variable/FV = find_feedback_datum(variable)
FV.dec(value)
/datum/controller/subsystem/blackbox/proc/set_details(variable,details)
if(sealed)
return
var/datum/feedback_variable/FV = find_feedback_datum(variable)
FV.set_details(details)
/datum/controller/subsystem/blackbox/proc/add_details(variable,details)
if(sealed)
return
var/datum/feedback_variable/FV = find_feedback_datum(variable)
FV.add_details(details)
/datum/controller/subsystem/blackbox/proc/ReportDeath(mob/living/L)
if(sealed)
return
if(!SSdbcore.Connect())
return
if(!L || !L.key || !L.mind)
return
var/turf/T = get_turf(L)
var/area/placeofdeath = get_area(T.loc)
var/sqlname = sanitizeSQL(L.real_name)
var/sqlkey = sanitizeSQL(L.ckey)
var/sqljob = sanitizeSQL(L.mind.assigned_role)
var/sqlspecial = sanitizeSQL(L.mind.special_role)
var/sqlpod = sanitizeSQL(placeofdeath.name)
var/laname
var/lakey
if(L.lastattacker && ismob(L.lastattacker))
var/mob/LA = L.lastattacker
laname = sanitizeSQL(LA.real_name)
lakey = sanitizeSQL(LA.key)
var/sqlbrute = sanitizeSQL(L.getBruteLoss())
var/sqlfire = sanitizeSQL(L.getFireLoss())
var/sqlbrain = sanitizeSQL(L.getBrainLoss())
var/sqloxy = sanitizeSQL(L.getOxyLoss())
var/sqltox = sanitizeSQL(L.getToxLoss())
var/sqlclone = sanitizeSQL(L.getCloneLoss())
var/sqlstamina = sanitizeSQL(L.getStaminaLoss())
var/x_coord = sanitizeSQL(L.x)
var/y_coord = sanitizeSQL(L.y)
var/z_coord = sanitizeSQL(L.z)
var/last_words = sanitizeSQL(L.last_words)
var/suicide = sanitizeSQL(L.suiciding)
var/map = sanitizeSQL(SSmapping.config.map_name)
var/datum/DBQuery/query_report_death = SSdbcore.NewQuery("INSERT INTO [format_table_name("death")] (pod, x_coord, y_coord, z_coord, mapname, server_ip, server_port, round_id, tod, job, special, name, byondkey, laname, lakey, bruteloss, fireloss, brainloss, oxyloss, toxloss, cloneloss, staminaloss, last_words, suicide) VALUES ('[sqlpod]', '[x_coord]', '[y_coord]', '[z_coord]', '[map]', INET_ATON(IF('[world.internet_address]' LIKE '', '0', '[world.internet_address]')), '[world.port]', [GLOB.round_id], '[SQLtime()]', '[sqljob]', '[sqlspecial]', '[sqlname]', '[sqlkey]', '[laname]', '[lakey]', [sqlbrute], [sqlfire], [sqlbrain], [sqloxy], [sqltox], [sqlclone], [sqlstamina], '[last_words]', [suicide])")
query_report_death.Execute()
/datum/controller/subsystem/blackbox/proc/Seal()
if(sealed)
return
if(IsAdminAdvancedProcCall())
var/msg = "[key_name_admin(usr)] sealed the blackbox!"
message_admins(msg)
log_game("Blackbox sealed[IsAdminAdvancedProcCall() ? " by [key_name(usr)]" : ""].")
sealed = TRUE
//feedback variable datum, for storing all kinds of data
/datum/feedback_variable
var/variable
var/value
var/list/details
/datum/feedback_variable/New(param_variable, param_value = 0)
variable = param_variable
value = param_value
/datum/feedback_variable/proc/inc(num = 1)
if (isnum(value))
value += num
else
value = text2num(value)
if (isnum(value))
value += num
else
value = num
/datum/feedback_variable/proc/dec(num = 1)
if (isnum(value))
value -= num
else
value = text2num(value)
if (isnum(value))
value -= num
else
value = -num
/datum/feedback_variable/proc/set_value(num)
if (isnum(num))
value = num
/datum/feedback_variable/proc/get_value()
if (!isnum(value))
return 0
return value
/datum/feedback_variable/proc/get_variable()
return variable
/datum/feedback_variable/proc/set_details(deets)
details = "\"[deets]\""
details = list("\"[deets]\"")
/datum/feedback_variable/proc/add_details(deets)
if (!details)
set_details(deets)
else
details += " | \"[deets]\""
/datum/feedback_variable/proc/get_details()
return details
/datum/feedback_variable/proc/get_parsed()
return list(variable,value,details)
details += "\"[deets]\""
/datum/feedback_variable/proc/get_details()
return details.Join(" | ")
/datum/feedback_variable/proc/get_parsed()
return list(variable,value,details.Join(" | "))

View File

@@ -0,0 +1,10 @@
diff a/code/controllers/subsystem/blackbox.dm b/code/controllers/subsystem/blackbox.dm (rejected hunks)
@@ -40,7 +40,7 @@ SUBSYSTEM_DEF(blackbox)
if(config.use_exp_tracking)
if((triggertime < 0) || (world.time > (triggertime +3000))) //subsystem fires once at roundstart then once every 10 minutes. a 5 min check skips the first fire. The <0 is midnight rollover check
- SSblackbox.update_exp(10,FALSE)
+ update_exp(10,FALSE)
/datum/controller/subsystem/blackbox/Recover()

View File

@@ -14,3 +14,10 @@ SUBSYSTEM_DEF(disease)
/datum/controller/subsystem/disease/stat_entry(msg)
..("P:[active_diseases.len]")
/datum/controller/subsystem/disease/proc/get_disease_name(id)
var/datum/disease/advance/A = archive_diseases[id]
if(A.name)
return A.name
else
return "Unknown"

View File

@@ -116,6 +116,8 @@ SUBSYSTEM_DEF(events)
//allows a client to trigger an event
//aka Badmin Central
// > Not in modules/admin
// REEEEEEEEE
/client/proc/forceEvent()
set name = "Trigger Event"
set category = "Fun"
@@ -131,7 +133,7 @@ SUBSYSTEM_DEF(events)
var/magic = ""
var/holiday = ""
for(var/datum/round_event_control/E in SSevents.control)
dat = "<BR><A href='?src=\ref[src];forceevent=\ref[E]'>[E]</A>"
dat = "<BR><A href='?src=\ref[src];[HrefToken()];forceevent=\ref[E]'>[E]</A>"
if(E.holidayID)
holiday += dat
else if(E.wizardevent)

View File

@@ -1,40 +1,44 @@
SUBSYSTEM_DEF(garbage)
name = "Garbage"
priority = 15
wait = 20
wait = 2 SECONDS
flags = SS_POST_FIRE_TIMING|SS_BACKGROUND|SS_NO_INIT
runlevels = RUNLEVELS_DEFAULT | RUNLEVEL_LOBBY
var/collection_timeout = 3000// deciseconds to wait to let running procs finish before we just say fuck it and force del() the object
var/delslasttick = 0 // number of del()'s we've done this tick
var/gcedlasttick = 0 // number of things that gc'ed last tick
var/list/collection_timeout = list(0, 2 MINUTES, 10 SECONDS) // deciseconds to wait before moving something up in the queue to the next level
//Stat tracking
var/delslasttick = 0 // number of del()'s we've done this tick
var/gcedlasttick = 0 // number of things that gc'ed last tick
var/totaldels = 0
var/totalgcs = 0
var/highest_del_time = 0
var/highest_del_tickusage = 0
var/list/queue = list() // list of refID's of things that should be garbage collected
// refID's are associated with the time at which they time out and need to be manually del()
// we do this so we aren't constantly locating them and preventing them from being gc'd
var/list/pass_counts
var/list/fail_counts
var/list/tobequeued = list() //We store the references of things to be added to the queue separately so we can spread out GC overhead over a few ticks
var/list/items = list() // Holds our qdel_item statistics datums
var/list/didntgc = list() // list of all types that have failed to GC associated with the number of times that's happened.
// the types are stored as strings
var/list/sleptDestroy = list() //Same as above but these are paths that slept during their Destroy call
//Queue
var/list/queues
var/list/noqdelhint = list()// list of all types that do not return a QDEL_HINT
// all types that did not respect qdel(A, force=TRUE) and returned one
// of the immortality qdel hints
var/list/noforcerespect = list()
#ifdef TESTING
var/list/qdel_list = list() // list of all types that have been qdel()eted
#endif
/datum/controller/subsystem/garbage/PreInit()
queues = new(GC_QUEUE_COUNT)
pass_counts = new(GC_QUEUE_COUNT)
fail_counts = new(GC_QUEUE_COUNT)
for(var/i in 1 to GC_QUEUE_COUNT)
queues[i] = list()
pass_counts[i] = 0
fail_counts[i] = 0
/datum/controller/subsystem/garbage/stat_entry(msg)
msg += "Q:[queue.len]|D:[delslasttick]|G:[gcedlasttick]|"
var/list/counts = list()
for (var/list/L in queues)
counts += length(L)
msg += "Q:[counts.Join(",")]|D:[delslasttick]|G:[gcedlasttick]|"
msg += "GR:"
if (!(delslasttick+gcedlasttick))
msg += "n/a|"
@@ -46,116 +50,179 @@ SUBSYSTEM_DEF(garbage)
msg += "n/a|"
else
msg += "TGR:[round((totalgcs/(totaldels+totalgcs))*100, 0.01)]%"
msg += " P:[pass_counts.Join(",")]"
msg += "|F:[fail_counts.Join(",")]"
..(msg)
/datum/controller/subsystem/garbage/Shutdown()
//Adds the del() log to world.log in a format condensable by the runtime condenser found in tools
if(didntgc.len || sleptDestroy.len)
var/list/dellog = list()
for(var/path in didntgc)
dellog += "Path : [path] \n"
dellog += "Failures : [didntgc[path]] \n"
if(path in sleptDestroy)
dellog += "Sleeps : [sleptDestroy[path]] \n"
sleptDestroy -= path
for(var/path in sleptDestroy)
dellog += "Path : [path] \n"
dellog += "Sleeps : [sleptDestroy[path]] \n"
text2file(dellog.Join(), "[GLOB.log_directory]/qdel.log")
//Adds the del() log to the qdel log file
var/list/dellog = list()
//sort by how long it's wasted hard deleting
sortTim(items, cmp=/proc/cmp_qdel_item_time, associative = TRUE)
for(var/path in items)
var/datum/qdel_item/I = items[path]
dellog += "Path: [path]"
if (I.failures)
dellog += "\tFailures: [I.failures]"
dellog += "\tqdel() Count: [I.qdels]"
dellog += "\tDestroy() Cost: [I.destroy_time]ms"
if (I.hard_deletes)
dellog += "\tTotal Hard Deletes [I.hard_deletes]"
dellog += "\tTime Spent Hard Deleting: [I.hard_delete_time]ms"
if (I.slept_destroy)
dellog += "\tSleeps: [I.slept_destroy]"
if (I.no_respect_force)
dellog += "\tIgnored force: [I.no_respect_force] times"
if (I.no_hint)
dellog += "\tNo hint: [I.no_hint] times"
log_qdel(dellog.Join("\n"))
/datum/controller/subsystem/garbage/fire()
HandleToBeQueued()
if(state == SS_RUNNING)
HandleQueue()
//the fact that this resets its processing each fire (rather then resume where it left off) is intentional.
var/queue = GC_QUEUE_PREQUEUE
while (state == SS_RUNNING)
switch (queue)
if (GC_QUEUE_PREQUEUE)
HandlePreQueue()
queue = GC_QUEUE_PREQUEUE+1
if (GC_QUEUE_CHECK)
HandleQueue(GC_QUEUE_CHECK)
queue = GC_QUEUE_CHECK+1
if (GC_QUEUE_HARDDELETE)
HandleQueue(GC_QUEUE_HARDDELETE)
break
if (state == SS_PAUSED) //make us wait again before the next run.
state = SS_RUNNING
state = SS_RUNNING
//If you see this proc high on the profile, what you are really seeing is the garbage collection/soft delete overhead in byond.
//Don't attempt to optimize, not worth the effort.
/datum/controller/subsystem/garbage/proc/HandleToBeQueued()
var/list/tobequeued = src.tobequeued
var/starttime = world.time
var/starttimeofday = world.timeofday
while(tobequeued.len && starttime == world.time && starttimeofday == world.timeofday)
if (MC_TICK_CHECK)
break
var/ref = tobequeued[1]
Queue(ref)
tobequeued.Cut(1, 2)
/datum/controller/subsystem/garbage/proc/HandlePreQueue()
var/list/tobequeued = queues[GC_QUEUE_PREQUEUE]
var/static/count = 0
if (count)
var/c = count
count = 0 //so if we runtime on the Cut, we don't try again.
tobequeued.Cut(1,c+1)
/datum/controller/subsystem/garbage/proc/HandleQueue()
delslasttick = 0
gcedlasttick = 0
var/time_to_kill = world.time - collection_timeout // Anything qdel() but not GC'd BEFORE this time needs to be manually del()
var/list/queue = src.queue
var/starttime = world.time
var/starttimeofday = world.timeofday
while(queue.len && starttime == world.time && starttimeofday == world.timeofday)
for (var/ref in tobequeued)
count++
Queue(ref, GC_QUEUE_PREQUEUE+1)
if (MC_TICK_CHECK)
break
var/refID = queue[1]
if (count)
tobequeued.Cut(1,count+1)
count = 0
/datum/controller/subsystem/garbage/proc/HandleQueue(level = GC_QUEUE_CHECK)
if (level == GC_QUEUE_CHECK)
delslasttick = 0
gcedlasttick = 0
var/cut_off_time = world.time - collection_timeout[level] //ignore entries newer then this
var/list/queue = queues[level]
var/static/lastlevel
var/static/count = 0
if (count) //runtime last run before we could do this.
var/c = count
count = 0 //so if we runtime on the Cut, we don't try again.
var/list/lastqueue = queues[lastlevel]
lastqueue.Cut(1, c+1)
lastlevel = level
for (var/refID in queue)
if (!refID)
queue.Cut(1, 2)
count++
if (MC_TICK_CHECK)
break
continue
var/GCd_at_time = queue[refID]
if(GCd_at_time > time_to_kill)
if(GCd_at_time > cut_off_time)
break // Everything else is newer, skip them
queue.Cut(1, 2)
var/datum/A
A = locate(refID)
if (A && A.gc_destroyed == GCd_at_time) // So if something else coincidently gets the same ref, it's not deleted by mistake
#ifdef GC_FAILURE_HARD_LOOKUP
A.find_references()
#endif
count++
// Something's still referring to the qdel'd object. Kill it.
var/type = A.type
testing("GC: -- \ref[A] | [type] was unable to be GC'd and was deleted --")
didntgc["[type]"]++
HardDelete(A)
var/datum/D
D = locate(refID)
++delslasttick
++totaldels
else
if (!D || D.gc_destroyed != GCd_at_time) // So if something else coincidently gets the same ref, it's not deleted by mistake
++gcedlasttick
++totalgcs
pass_counts[level]++
if (MC_TICK_CHECK)
break
continue
/datum/controller/subsystem/garbage/proc/QueueForQueuing(datum/A)
if (istype(A) && A.gc_destroyed == GC_CURRENTLY_BEING_QDELETED)
tobequeued += A
A.gc_destroyed = GC_QUEUED_FOR_QUEUING
// Something's still referring to the qdel'd object.
fail_counts[level]++
switch (level)
if (GC_QUEUE_CHECK)
#ifdef GC_FAILURE_HARD_LOOKUP
D.find_references()
#endif
var/type = D.type
var/datum/qdel_item/I = items[type]
testing("GC: -- \ref[D] | [type] was unable to be GC'd --")
I.failures++
if (GC_QUEUE_HARDDELETE)
HardDelete(D)
if (MC_TICK_CHECK)
break
continue
/datum/controller/subsystem/garbage/proc/Queue(datum/A)
if (isnull(A) || (!isnull(A.gc_destroyed) && A.gc_destroyed >= 0))
Queue(D, level+1)
if (MC_TICK_CHECK)
break
if (count)
queue.Cut(1,count+1)
count = 0
/datum/controller/subsystem/garbage/proc/PreQueue(datum/D)
if (D.gc_destroyed == GC_CURRENTLY_BEING_QDELETED)
queues[GC_QUEUE_PREQUEUE] += D
D.gc_destroyed = GC_QUEUED_FOR_QUEUING
/datum/controller/subsystem/garbage/proc/Queue(datum/D, level = GC_QUEUE_CHECK)
if (isnull(D))
return
if (A.gc_destroyed == GC_QUEUED_FOR_HARD_DEL)
HardDelete(A)
if (D.gc_destroyed == GC_QUEUED_FOR_HARD_DEL)
level = GC_QUEUE_HARDDELETE
if (level > GC_QUEUE_COUNT)
HardDelete(D)
return
var/gctime = world.time
var/refid = "\ref[A]"
A.gc_destroyed = gctime
var/refid = "\ref[D]"
D.gc_destroyed = gctime
var/list/queue = queues[level]
if (queue[refid])
queue -= refid // Removing any previous references that were GC'd so that the current object will be at the end of the list.
queue[refid] = gctime
//this is purely to separate things profile wise.
/datum/controller/subsystem/garbage/proc/HardDelete(datum/A)
//this is mainly to separate things profile wise.
/datum/controller/subsystem/garbage/proc/HardDelete(datum/D)
var/time = world.timeofday
var/tick = TICK_USAGE
var/ticktime = world.time
var/type = A.type
var/refID = "\ref[A]"
del(A)
++delslasttick
++totaldels
var/type = D.type
var/refID = "\ref[D]"
del(D)
tick = (TICK_USAGE-tick+((world.time-ticktime)/world.tick_lag*100))
var/datum/qdel_item/I = items[type]
I.hard_deletes++
I.hard_delete_time += TICK_DELTA_TO_MS(tick)
if (tick > highest_del_tickusage)
highest_del_tickusage = tick
time = world.timeofday - time
@@ -166,18 +233,33 @@ SUBSYSTEM_DEF(garbage)
if (time > 10)
log_game("Error: [type]([refID]) took longer than 1 second to delete (took [time/10] seconds to delete)")
message_admins("Error: [type]([refID]) took longer than 1 second to delete (took [time/10] seconds to delete).")
postpone(time/5)
/datum/controller/subsystem/garbage/proc/HardQueue(datum/A)
if (istype(A) && A.gc_destroyed == GC_CURRENTLY_BEING_QDELETED)
tobequeued += A
A.gc_destroyed = GC_QUEUED_FOR_HARD_DEL
postpone(time)
/datum/controller/subsystem/garbage/proc/HardQueue(datum/D)
if (D.gc_destroyed == GC_CURRENTLY_BEING_QDELETED)
queues[GC_QUEUE_PREQUEUE] += D
D.gc_destroyed = GC_QUEUED_FOR_HARD_DEL
/datum/controller/subsystem/garbage/Recover()
if (istype(SSgarbage.queue))
queue |= SSgarbage.queue
if (istype(SSgarbage.tobequeued))
tobequeued |= SSgarbage.tobequeued
if (istype(SSgarbage.queues))
for (var/i in 1 to SSgarbage.queues.len)
queues[i] |= SSgarbage.queues[i]
/datum/qdel_item
var/name = ""
var/qdels = 0 //Total number of times it's passed thru qdel.
var/destroy_time = 0 //Total amount of milliseconds spent processing this type's Destroy()
var/failures = 0 //Times it was queued for soft deletion but failed to soft delete.
var/hard_deletes = 0 //Different from failures because it also includes QDEL_HINT_HARDDEL deletions
var/hard_delete_time = 0//Total amount of milliseconds spent hard deleting this type.
var/no_respect_force = 0//Number of times it's not respected force=TRUE
var/no_hint = 0 //Number of times it's not even bother to give a qdel hint
var/slept_destroy = 0 //Number of times it's slept in its destroy
/datum/qdel_item/New(mytype)
name = "[mytype]"
// Should be treated as a replacement for the 'del' keyword.
// Datums passed to this will be given a chance to clean up references to allow the GC to collect them.
@@ -185,21 +267,27 @@ SUBSYSTEM_DEF(garbage)
if(!istype(D))
del(D)
return
#ifdef TESTING
SSgarbage.qdel_list += "[D.type]"
#endif
var/datum/qdel_item/I = SSgarbage.items[D.type]
if (!I)
I = SSgarbage.items[D.type] = new /datum/qdel_item(D.type)
I.qdels++
if(isnull(D.gc_destroyed))
D.SendSignal(COMSIG_PARENT_QDELETED)
D.gc_destroyed = GC_CURRENTLY_BEING_QDELETED
var/start_time = world.time
var/start_tick = world.tick_usage
var/hint = D.Destroy(force) // Let our friend know they're about to get fucked up.
if(world.time != start_time)
SSgarbage.sleptDestroy["[D.type]"]++
I.slept_destroy++
else
I.destroy_time += TICK_USAGE_TO_MS(start_tick)
if(!D)
return
switch(hint)
if (QDEL_HINT_QUEUE) //qdel should queue the object for deletion.
SSgarbage.QueueForQueuing(D)
SSgarbage.PreQueue(D)
if (QDEL_HINT_IWILLGC)
D.gc_destroyed = world.time
return
@@ -209,28 +297,33 @@ SUBSYSTEM_DEF(garbage)
return
// Returning LETMELIVE after being told to force destroy
// indicates the objects Destroy() does not respect force
if(!SSgarbage.noforcerespect["[D.type]"])
SSgarbage.noforcerespect["[D.type]"] = "[D.type]"
#ifdef TESTING
if(!I.no_respect_force)
testing("WARNING: [D.type] has been force deleted, but is \
returning an immortal QDEL_HINT, indicating it does \
not respect the force flag for qdel(). It has been \
placed in the queue, further instances of this type \
will also be queued.")
SSgarbage.QueueForQueuing(D)
#endif
I.no_respect_force++
SSgarbage.PreQueue(D)
if (QDEL_HINT_HARDDEL) //qdel should assume this object won't gc, and queue a hard delete using a hard reference to save time from the locate()
SSgarbage.HardQueue(D)
if (QDEL_HINT_HARDDEL_NOW) //qdel should assume this object won't gc, and hard del it post haste.
SSgarbage.HardDelete(D)
if (QDEL_HINT_FINDREFERENCE)//qdel will, if TESTING is enabled, display all references to this object, then queue the object for deletion.
SSgarbage.QueueForQueuing(D)
SSgarbage.PreQueue(D)
#ifdef TESTING
D.find_references()
#endif
else
if(!SSgarbage.noqdelhint["[D.type]"])
SSgarbage.noqdelhint["[D.type]"] = "[D.type]"
#ifdef TESTING
if(!I.no_hint)
testing("WARNING: [D.type] is not returning a qdel hint. It is being placed in the queue. Further instances of this type will also be queued.")
SSgarbage.QueueForQueuing(D)
#endif
I.no_hint++
SSgarbage.PreQueue(D)
else if(D.gc_destroyed == GC_CURRENTLY_BEING_QDELETED)
CRASH("[D.type] destroy proc was called multiple times, likely due to a qdel loop in the Destroy logic")
@@ -281,15 +374,6 @@ SUBSYSTEM_DEF(garbage)
SSgarbage.can_fire = 1
SSgarbage.next_fire = world.time + world.tick_lag
/client/verb/purge_all_destroyed_objects()
set category = "Debug"
while(SSgarbage.queue.len)
var/datum/o = locate(SSgarbage.queue[1])
if(istype(o) && o.gc_destroyed)
del(o)
SSgarbage.totaldels++
SSgarbage.queue.Cut(1, 2)
/datum/verb/qdel_then_find_references()
set category = "Debug"
set name = "qdel() then Find References"
@@ -300,24 +384,6 @@ SUBSYSTEM_DEF(garbage)
if(!running_find_references)
find_references(TRUE)
/client/verb/show_qdeleted()
set category = "Debug"
set name = "Show qdel() Log"
set desc = "Render the qdel() log and display it"
var/dat = "<B>List of things that have been qdel()eted this round</B><BR><BR>"
var/tmplist = list()
for(var/elem in SSgarbage.qdel_list)
if(!(elem in tmplist))
tmplist[elem] = 0
tmplist[elem]++
for(var/path in tmplist)
dat += "[path] - [tmplist[path]] times<BR>"
usr << browse(dat, "window=qdeletedlog")
/datum/proc/DoSearchVar(X, Xname)
if(usr && usr.client && !usr.client.running_find_references) return
if(istype(X, /datum))

View File

@@ -73,6 +73,8 @@ SUBSYSTEM_DEF(job)
return 0
if(!job.player_old_enough(player.client))
return 0
if(job.required_playtime_remaining(player.client))
return 0
var/position_limit = job.total_positions
if(!latejoin)
position_limit = job.spawn_positions
@@ -95,6 +97,9 @@ SUBSYSTEM_DEF(job)
if(!job.player_old_enough(player.client))
Debug("FOC player not old enough, Player: [player]")
continue
if(job.required_playtime_remaining(player.client))
Debug("FOC player not enough xp, Player: [player]")
continue
if(flag && (!(flag in player.client.prefs.be_special)))
Debug("FOC flag failed, Player: [player], Flag: [flag], ")
continue
@@ -130,6 +135,10 @@ SUBSYSTEM_DEF(job)
Debug("GRJ player not old enough, Player: [player]")
continue
if(job.required_playtime_remaining(player.client))
Debug("GRJ player not enough xp, Player: [player]")
continue
if(player.mind && job.title in player.mind.restricted_roles)
Debug("GRJ incompatible with antagonist role, Player: [player], Job: [job.title]")
continue
@@ -300,6 +309,10 @@ SUBSYSTEM_DEF(job)
Debug("DO player not old enough, Player: [player], Job:[job.title]")
continue
if(job.required_playtime_remaining(player.client))
Debug("DO player not enough xp, Player: [player], Job:[job.title]")
continue
if(player.mind && job.title in player.mind.restricted_roles)
Debug("DO incompatible with antagonist role, Player: [player], Job:[job.title]")
continue
@@ -407,7 +420,7 @@ SUBSYSTEM_DEF(job)
if(job && H)
job.after_spawn(H, M)
handle_roundstart_items(H, M.ckey, H.mind.assigned_role, H.mind.special_role)
return H
@@ -463,6 +476,9 @@ SUBSYSTEM_DEF(job)
if(!job.player_old_enough(player.client))
level6++
continue
if(job.required_playtime_remaining(player.client))
level6++
continue
if(player.client.prefs.GetJobDepartment(job, 1) & job.flag)
level1++
else if(player.client.prefs.GetJobDepartment(job, 2) & job.flag)

View File

@@ -2,15 +2,15 @@ SUBSYSTEM_DEF(persistence)
name = "Persistence"
init_order = INIT_ORDER_PERSISTENCE
flags = SS_NO_FIRE
var/savefile/secret_satchels
var/secret_satchels
var/list/satchel_blacklist = list() //this is a typecache
var/list/new_secret_satchels = list() //these are objects
var/old_secret_satchels = ""
var/list/old_secret_satchels = ""
var/list/obj/structure/chisel_message/chisel_messages = list()
var/list/saved_messages = list()
var/savefile/trophy_sav
var/trophy_sav
var/list/saved_trophies = list()
/datum/controller/subsystem/persistence/Initialize()
@@ -21,67 +21,53 @@ SUBSYSTEM_DEF(persistence)
..()
/datum/controller/subsystem/persistence/proc/LoadSatchels()
secret_satchels = new /savefile("data/npc_saves/SecretSatchels.sav")
secret_satchels = file("data/npc_saves/SecretSatchels[SSmapping.config.map_name].json")
if(!fexists(secret_satchels))
return
satchel_blacklist = typecacheof(list(/obj/item/stack/tile/plasteel, /obj/item/crowbar))
secret_satchels[SSmapping.config.map_name] >> old_secret_satchels
var/list/expanded_old_satchels = list()
var/placed_satchels = 0
if(!isnull(old_secret_satchels))
expanded_old_satchels = splittext(old_secret_satchels,"#")
if(PlaceSecretSatchel(expanded_old_satchels))
placed_satchels++
else
expanded_old_satchels.len = 0
var/list/json = list()
json = json_decode(file2text(secret_satchels))
old_secret_satchels = json["data"]
var/placed_satchel = 0
if(old_secret_satchels.len)
if(old_secret_satchels.len >= 20) //guards against low drop pools assuring that one player cannot reliably find his own gear.
var/pos = rand(1, old_secret_satchels.len)
old_secret_satchels.Cut(pos, pos+1)
var/obj/item/storage/backpack/satchel/flat/F = new()
F.x = old_secret_satchels[pos]["x"]
F.y = old_secret_satchels[pos]["y"]
F.z = ZLEVEL_STATION
var/path = text2path(old_secret_satchels[pos]["saved_obj"])
if(!ispath(path))
return
if(isfloorturf(F.loc) && !istype(F.loc, /turf/open/floor/plating/))
F.hide(1)
new path(F)
placed_satchel++
var/list/free_satchels = list()
for(var/turf/T in shuffle(block(locate(TRANSITIONEDGE,TRANSITIONEDGE,ZLEVEL_STATION), locate(world.maxx-TRANSITIONEDGE,world.maxy-TRANSITIONEDGE,ZLEVEL_STATION)))) //Nontrivially expensive but it's roundstart only
if(isfloorturf(T) && !istype(T, /turf/open/floor/plating/))
free_satchels += new /obj/item/storage/backpack/satchel/flat/secret(T)
if(!isemptylist(free_satchels) && ((free_satchels.len + placed_satchels) >= (50 - expanded_old_satchels.len) * 0.1)) //up to six tiles, more than enough to kill anything that moves
if(!isemptylist(free_satchels) && ((free_satchels.len + placed_satchel) >= (50 - old_secret_satchels.len) * 0.1)) //up to six tiles, more than enough to kill anything that moves
break
/datum/controller/subsystem/persistence/proc/PlaceSecretSatchel(list/expanded_old_satchels)
var/satchel_string
if(expanded_old_satchels.len >= 20) //guards against low drop pools assuring that one player cannot reliably find his own gear.
satchel_string = pick_n_take(expanded_old_satchels)
old_secret_satchels = jointext(expanded_old_satchels,"#")
WRITE_FILE(secret_satchels[SSmapping.config.map_name], old_secret_satchels)
var/list/chosen_satchel = splittext(satchel_string,"|")
if(!chosen_satchel || isemptylist(chosen_satchel) || chosen_satchel.len != 3) //Malformed
return 0
var/path = text2path(chosen_satchel[3]) //If the item no longer exist, this returns null
if(!path)
return 0
var/obj/item/storage/backpack/satchel/flat/F = new()
F.x = text2num(chosen_satchel[1])
F.y = text2num(chosen_satchel[2])
F.z = ZLEVEL_STATION
if(isfloorturf(F.loc) && !istype(F.loc, /turf/open/floor/plating/))
F.hide(1)
new path(F)
return 1
/datum/controller/subsystem/persistence/proc/LoadPoly()
for(var/mob/living/simple_animal/parrot/Poly/P in GLOB.living_mob_list)
twitterize(P.speech_buffer, "polytalk")
break //Who's been duping the bird?!
/datum/controller/subsystem/persistence/proc/LoadChiselMessages()
var/savefile/chisel_messages_sav = new /savefile("data/npc_saves/ChiselMessages.sav")
var/saved_json
chisel_messages_sav[SSmapping.config.map_name] >> saved_json
var/json_file = file("data/npc_saves/ChiselMessages[SSmapping.config.map_name].json")
if(!fexists(json_file))
return
var/list/json
json = json_decode(file2text(json_file))
if(!saved_json)
if(!json)
return
var/list/saved_messages = json_decode(saved_json)
var/list/saved_messages = json["data"]
for(var/item in saved_messages)
if(!islist(item))
@@ -109,19 +95,16 @@ SUBSYSTEM_DEF(persistence)
log_world("Loaded [saved_messages.len] engraved messages on map [SSmapping.config.map_name]")
/datum/controller/subsystem/persistence/proc/LoadTrophies()
trophy_sav = new /savefile("data/npc_saves/TrophyItems.sav")
var/saved_json
trophy_sav >> saved_json
trophy_sav = file("data/npc_saves/TrophyItems.json")
if(!fexists(trophy_sav))
return
var/list/json = list()
json = json_decode(file2text(trophy_sav))
if(!saved_json)
if(!json)
return
var/decoded_json = json_decode(saved_json)
if(!islist(decoded_json))
return
saved_trophies = decoded_json
saved_trophies = json["data"]
SetUpTrophies(saved_trophies.Copy())
@@ -156,6 +139,7 @@ SUBSYSTEM_DEF(persistence)
CollectTrophies()
/datum/controller/subsystem/persistence/proc/CollectSecretSatchels()
var/list/satchels = list()
for(var/A in new_secret_satchels)
var/obj/item/storage/backpack/satchel/flat/F = A
if(QDELETED(F) || F.z != ZLEVEL_STATION || F.invisibility != INVISIBILITY_MAXIMUM)
@@ -170,25 +154,37 @@ SUBSYSTEM_DEF(persistence)
savable_obj += O.type
if(isemptylist(savable_obj))
continue
old_secret_satchels += "[F.x]|[F.y]|[pick(savable_obj)]#"
WRITE_FILE(secret_satchels[SSmapping.config.map_name], old_secret_satchels)
var/list/data = list()
data["x"] = F.x
data["y"] = F.y
data["saved_obj"] = pick(savable_obj)
satchels += list(data)
var/list/file_data = list()
file_data["data"] = satchels
fdel(secret_satchels)
WRITE_FILE(secret_satchels, json_encode(file_data))
/datum/controller/subsystem/persistence/proc/CollectChiselMessages()
var/savefile/chisel_messages_sav = new /savefile("data/npc_saves/ChiselMessages.sav")
var/json_file = file("data/npc_saves/ChiselMessages[SSmapping.config.map_name].json")
for(var/obj/structure/chisel_message/M in chisel_messages)
saved_messages += list(M.pack())
log_world("Saved [saved_messages.len] engraved messages on map [SSmapping.config.map_name]")
WRITE_FILE(chisel_messages_sav[SSmapping.config.map_name], json_encode(saved_messages))
var/list/file_data = list()
file_data["data"] = saved_messages
fdel(json_file)
WRITE_FILE(json_file, json_encode(file_data))
/datum/controller/subsystem/persistence/proc/SaveChiselMessage(obj/structure/chisel_message/M)
saved_messages += list(M.pack()) // dm eats one list
/datum/controller/subsystem/persistence/proc/CollectTrophies()
WRITE_FILE(trophy_sav, json_encode(saved_trophies))
var/list/file_data = list()
file_data["data"] = saved_trophies
fdel(trophy_sav)
WRITE_FILE(trophy_sav, json_encode(file_data))
/datum/controller/subsystem/persistence/proc/SaveTrophy(obj/structure/displaycase/trophy/T)
if(!T.added_roundstart && T.showpiece)
@@ -196,4 +192,4 @@ SUBSYSTEM_DEF(persistence)
data["path"] = T.showpiece.type
data["message"] = T.trophy_message
data["placer_key"] = T.placer_key
saved_trophies += list(data)
saved_trophies += list(data)

View File

@@ -0,0 +1,30 @@
diff a/code/controllers/subsystem/server_maint.dm b/code/controllers/subsystem/server_maint.dm (rejected hunks)
@@ -6,18 +6,16 @@ SUBSYSTEM_DEF(server_maint)
flags = SS_POST_FIRE_TIMING|SS_FIRE_IN_LOBBY
priority = 10
var/list/currentrun
- var/triggertime = null
/datum/controller/subsystem/server_maint/Initialize(timeofday)
if (config.hub)
world.visibility = 1
- triggertime = REALTIMEOFDAY
..()
/datum/controller/subsystem/server_maint/fire(resumed = FALSE)
if(!resumed)
src.currentrun = GLOB.clients.Copy()
-
+
var/list/currentrun = src.currentrun
var/round_started = SSticker.HasRoundStarted()
@@ -39,8 +37,3 @@ SUBSYSTEM_DEF(server_maint)
return
#undef PING_BUFFER_TIME
- if(config.sql_enabled)
- sql_poll_population()
- if(config.use_exp_tracking)
- if(REALTIMEOFDAY > (triggertime +3000)) //server maint fires once at roundstart then once every 10 minutes. a 5 min check skips the first fire
- update_exp(10,0)

View File

@@ -341,7 +341,7 @@ SUBSYSTEM_DEF(shuttle)
if(M.request(getDock(destination)))
return 2
else
if(M.dock(getDock(destination)))
if(M.dock(getDock(destination)) != DOCKING_SUCCESS)
return 2
return 0 //dock successful
@@ -356,7 +356,7 @@ SUBSYSTEM_DEF(shuttle)
if(M.request(D))
return 2
else
if(M.dock(D))
if(M.dock(D) != DOCKING_SUCCESS)
return 2
return 0 //dock successful

View File

@@ -465,6 +465,12 @@ SUBSYSTEM_DEF(ticker)
to_chat(world, "<BR><BR><BR><FONT size=3><B>The round has ended.</B></FONT>")
/* var/nocredits = config.no_credits_round_end
for(var/client/C in GLOB.clients)
if(!C.credits && !nocredits)
C.RollCredits()
C.playtitlemusic(40)*/
//Player status report
for(var/mob/Player in GLOB.mob_list)
if(Player.mind && !isnewplayer(Player))
@@ -513,7 +519,7 @@ SUBSYSTEM_DEF(ticker)
//Silicon laws report
for (var/mob/living/silicon/ai/aiPlayer in GLOB.mob_list)
if (aiPlayer.stat != 2 && aiPlayer.mind)
if (aiPlayer.stat != DEAD && aiPlayer.mind)
to_chat(world, "<b>[aiPlayer.name] (Played by: [aiPlayer.mind.key])'s laws at the end of the round were:</b>")
aiPlayer.show_laws(1)
else if (aiPlayer.mind) //if the dead ai has a mind, use its key instead
@@ -533,7 +539,7 @@ SUBSYSTEM_DEF(ticker)
for (var/mob/living/silicon/robot/robo in GLOB.mob_list)
if (!robo.connected_ai && robo.mind)
if (robo.stat != 2)
if (robo.stat != DEAD)
to_chat(world, "<b>[robo.name] (Played by: [robo.mind.key]) survived as an AI-less borg! Its laws were:</b>")
else
to_chat(world, "<b>[robo.name] (Played by: [robo.mind.key]) was unable to survive the rigors of being a cyborg without an AI. Its laws were:</b>")

View File

@@ -69,7 +69,7 @@ SUBSYSTEM_DEF(timer)
if (ctime_timer.timeToRun <= REALTIMEOFDAY)
--clienttime_timers.len
var/datum/callback/callBack = ctime_timer.callBack
ctime_timer.spent = TRUE
ctime_timer.spent = REALTIMEOFDAY
callBack.InvokeAsync()
qdel(ctime_timer)
else
@@ -105,11 +105,11 @@ SUBSYSTEM_DEF(timer)
if (!callBack)
qdel(timer)
bucket_resolution = null //force bucket recreation
CRASH("Invalid timer: [timer] timer.timeToRun=[timer.timeToRun]||QDELETED(timer)=[QDELETED(timer)]||world.time=[world.time]||head_offset=[head_offset]||practical_offset=[practical_offset]||timer.spent=[timer.spent]")
CRASH("Invalid timer: [get_timer_debug_string(timer)] world.time: [world.time], head_offset: [head_offset], practical_offset: [practical_offset]")
if (!timer.spent)
spent += timer
timer.spent = TRUE
timer.spent = world.time
callBack.InvokeAsync()
last_invoke_tick = world.time
@@ -135,9 +135,11 @@ SUBSYSTEM_DEF(timer)
. = "Timer: [TE]"
. += "Prev: [TE.prev ? TE.prev : "NULL"], Next: [TE.next ? TE.next : "NULL"]"
if(TE.spent)
. += ", SPENT"
. += ", SPENT([TE.spent])"
if(QDELETED(TE))
. += ", QDELETED"
if(!TE.callBack)
. += ", NO CALLBACK"
/datum/controller/subsystem/timer/proc/shift_buckets()
var/list/bucket_list = src.bucket_list
@@ -216,7 +218,7 @@ SUBSYSTEM_DEF(timer)
var/timeToRun
var/hash
var/list/flags
var/spent = FALSE //set to true right before running.
var/spent = 0 //time we ran the timer.
var/name //for easy debugging.
//cicular doublely linked list
var/datum/timedevent/next
@@ -243,6 +245,9 @@ SUBSYSTEM_DEF(timer)
name = "Timer: " + num2text(id, 8) + ", TTR: [timeToRun], Flags: [jointext(bitfield2list(flags, list("TIMER_UNIQUE", "TIMER_OVERRIDE", "TIMER_CLIENT_TIME", "TIMER_STOPPABLE", "TIMER_NO_HASH_WAIT")), ", ")], callBack: \ref[callBack], callBack.object: [callBack.object]\ref[callBack.object]([getcallingtype()]), callBack.delegate:[callBack.delegate]([callBack.arguments ? callBack.arguments.Join(", ") : ""])"
if (spent)
CRASH("HOLY JESUS. WHAT IS THAT? WHAT THE FUCK IS THAT?")
if (callBack.object != GLOBAL_PROC)
LAZYADD(callBack.object.active_timers, src)

View File

@@ -172,6 +172,7 @@
/datum/action/item_action/rcl
name = "Change Cable Color"
icon_icon = 'icons/mob/actions/actions_items.dmi'
button_icon_state = "rcl_rainbow"
/datum/action/item_action/startchainsaw
@@ -405,27 +406,24 @@
/datum/action/item_action/initialize_ninja_suit
name = "Toggle ninja suit"
/datum/action/item_action/ninjajaunt
name = "Phase Jaunt (10E)"
desc = "Utilizes the internal VOID-shift device to rapidly transit in direction facing."
icon_icon = 'icons/mob/actions/actions_items.dmi'
button_icon_state = "ninja_phase"
/datum/action/item_action/ninjasmoke
name = "Smoke Bomb"
desc = "Blind your enemies momentarily with a well-placed smoke bomb."
button_icon_state = "smoke"
icon_icon = 'icons/mob/actions/actions_spells.dmi'
/datum/action/item_action/ninjaboost
check_flags = AB_CHECK_RESTRAINED|AB_CHECK_CONSCIOUS
check_flags = NONE
name = "Adrenaline Boost"
desc = "Inject a secret chemical that will counteract all movement-impairing effect."
button_icon_state = "repulse"
icon_icon = 'icons/mob/actions/actions_spells.dmi'
/datum/action/item_action/ninjapulse
name = "EM Burst (25E)"
desc = "Disable any nearby technology with a electro-magnetic pulse."
button_icon_state = "emp"
icon_icon = 'icons/mob/actions/actions_spells.dmi'
/datum/action/item_action/ninjastar
name = "Create Throwing Stars (1E)"
@@ -448,8 +446,8 @@
/datum/action/item_action/ninja_stealth
name = "Toggle Stealth"
desc = "Toggles stealth mode on and off."
icon_icon = 'icons/mob/actions/actions_items.dmi'
button_icon_state = "ninja_cloak"
icon_icon = 'icons/mob/actions/actions_minor_antag.dmi'
/datum/action/item_action/toggle_glove
name = "Toggle interaction"
@@ -491,7 +489,7 @@
S.action = src
name = S.name
desc = S.desc
button_icon = S.action_icon
icon_icon = S.action_icon
button_icon_state = S.action_icon_state
background_icon_state = S.action_background_icon_state
button.name = name

View File

@@ -164,7 +164,7 @@ GLOBAL_LIST_INIT(devil_suffix, list(" the Red", " the Soulless", " the Master",
update_hud()
switch(SOULVALUE)
if(0)
to_chat(owner.current, "<span class='warning'>Your hellish powers have been restored.")
to_chat(owner.current, "<span class='warning'>Your hellish powers have been restored.</span>")
give_appropriate_spells()
if(BLOOD_THRESHOLD)
increase_blood_lizard()
@@ -189,10 +189,10 @@ GLOBAL_LIST_INIT(devil_suffix, list(" the Red", " the Soulless", " the Master",
regress_humanoid()
if(SOULVALUE < 0)
give_appropriate_spells()
to_chat(owner.current, "<span class='warning'>As punishment for your failures, all of your powers except contract creation have been revoked.")
to_chat(owner.current, "<span class='warning'>As punishment for your failures, all of your powers except contract creation have been revoked.</span>")
/datum/antagonist/devil/proc/regress_humanoid()
to_chat(owner.current, "<span class='warning'>Your powers weaken, have more contracts be signed to regain power.")
to_chat(owner.current, "<span class='warning'>Your powers weaken, have more contracts be signed to regain power.</span>")
if(ishuman(owner.current))
var/mob/living/carbon/human/H = owner.current
H.set_species(/datum/species/human, 1)
@@ -204,7 +204,7 @@ GLOBAL_LIST_INIT(devil_suffix, list(" the Red", " the Soulless", " the Master",
/datum/antagonist/devil/proc/regress_blood_lizard()
var/mob/living/carbon/true_devil/D = owner.current
to_chat(D, "<span class='warning'>Your powers weaken, have more contracts be signed to regain power.")
to_chat(D, "<span class='warning'>Your powers weaken, have more contracts be signed to regain power.</span>")
D.oldform.loc = D.loc
owner.transfer_to(D.oldform)
give_appropriate_spells()
@@ -214,7 +214,7 @@ GLOBAL_LIST_INIT(devil_suffix, list(" the Red", " the Soulless", " the Master",
/datum/antagonist/devil/proc/increase_blood_lizard()
to_chat(owner.current, "<span class='warning'>You feel as though your humanoid form is about to shed. You will soon turn into a blood lizard.")
to_chat(owner.current, "<span class='warning'>You feel as though your humanoid form is about to shed. You will soon turn into a blood lizard.</span>")
sleep(50)
if(ishuman(owner.current))
var/mob/living/carbon/human/H = owner.current
@@ -232,7 +232,7 @@ GLOBAL_LIST_INIT(devil_suffix, list(" the Red", " the Soulless", " the Master",
/datum/antagonist/devil/proc/increase_true_devil()
to_chat(owner.current, "<span class='warning'>You feel as though your current form is about to shed. You will soon turn into a true devil.")
to_chat(owner.current, "<span class='warning'>You feel as though your current form is about to shed. You will soon turn into a true devil.</span>")
sleep(50)
var/mob/living/carbon/true_devil/A = new /mob/living/carbon/true_devil(owner.current.loc)
A.faction |= "hell"
@@ -248,7 +248,7 @@ GLOBAL_LIST_INIT(devil_suffix, list(" the Red", " the Soulless", " the Master",
if(!ascendable)
return
var/mob/living/carbon/true_devil/D = owner.current
to_chat(D, "<span class='warning'>You feel as though your form is about to ascend.")
to_chat(D, "<span class='warning'>You feel as though your form is about to ascend.</span>")
sleep(50)
if(!D)
return

View File

@@ -41,7 +41,6 @@
H.equip_to_slot_or_del(new /obj/item/clothing/mask/gas/space_ninja(H), slot_wear_mask)
H.equip_to_slot_or_del(new /obj/item/clothing/glasses/night(H), slot_glasses)
H.equip_to_slot_or_del(EK, slot_belt)
H.equip_to_slot_or_del(new /obj/item/device/flashlight(H), slot_r_store)
H.equip_to_slot_or_del(new /obj/item/grenade/plastic/x4(H), slot_l_store)
H.equip_to_slot_or_del(new /obj/item/tank/internals/emergency_oxygen(H), slot_s_store)
H.equip_to_slot_or_del(new /obj/item/tank/jetpack/carbondioxide(H), slot_back)

View File

@@ -0,0 +1,92 @@
/datum/component/archaeology
dupe_type = COMPONENT_DUPE_UNIQUE
var/list/archdrops
var/prob2drop
var/dug
/datum/component/archaeology/Initialize(_prob2drop, list/_archdrops = list())
prob2drop = Clamp(_prob2drop, 0, 100)
archdrops = _archdrops
RegisterSignal(COMSIG_PARENT_ATTACKBY,.proc/Dig)
RegisterSignal(COMSIG_ATOM_EX_ACT, .proc/BombDig)
RegisterSignal(COMSIG_ATOM_SING_PULL, .proc/SingDig)
/datum/component/archaeology/InheritComponent(datum/component/archaeology/A, i_am_original)
var/list/other_archdrops = A.archdrops
var/list/_archdrops = archdrops
for(var/I in other_archdrops)
_archdrops[I] += other_archdrops[I]
/datum/component/archaeology/proc/Dig(mob/user, obj/item/W)
if(dug)
to_chat(user, "<span class='notice'>Looks like someone has dug here already.</span>")
return FALSE
else
var/digging_speed
if (istype(W, /obj/item/shovel))
var/obj/item/shovel/S = W
digging_speed = S.digspeed
else if (istype(W, /obj/item/pickaxe))
var/obj/item/pickaxe/P = W
digging_speed = P.digspeed
if (digging_speed && isturf(user.loc))
to_chat(user, "<span class='notice'>You start digging...</span>")
playsound(parent, 'sound/effects/shovel_dig.ogg', 50, 1)
if(do_after(user, digging_speed, target = parent))
to_chat(user, "<span class='notice'>You dig a hole.</span>")
gets_dug()
dug = TRUE
SSblackbox.add_details("pick_used_mining",W.type)
return TRUE
return FALSE
/datum/component/archaeology/proc/gets_dug()
if(dug)
return
else
var/turf/open/OT = get_turf(parent)
for(var/thing in archdrops)
var/maxtodrop = archdrops[thing]
for(var/i in 1 to maxtodrop)
if(prob(prob2drop)) // can't win them all!
new thing(OT)
if(isopenturf(OT))
if(OT.postdig_icon_change)
if(istype(OT, /turf/open/floor/plating/asteroid/) && !OT.postdig_icon)
var/turf/open/floor/plating/asteroid/AOT = parent
AOT.icon_plating = "[AOT.environment_type]_dug"
AOT.icon_state = "[AOT.environment_type]_dug"
else
if(isplatingturf(OT))
var/turf/open/floor/plating/POT = parent
POT.icon_plating = "[POT.postdig_icon]"
OT.icon_state = "[OT.postdig_icon]"
if(OT.slowdown) //Things like snow slow you down until you dig them.
OT.slowdown = 0
dug = TRUE
/datum/component/archaeology/proc/SingDig(S, current_size)
switch(current_size)
if(STAGE_THREE)
if(prob(30))
gets_dug()
if(STAGE_FOUR)
if(prob(50))
gets_dug()
else
if(current_size >= STAGE_FIVE && prob(70))
gets_dug()
/datum/component/archaeology/proc/BombDig(severity, target)
switch(severity)
if(3)
return
if(2)
if(prob(20))
gets_dug()
if(1)
gets_dug()

File diff suppressed because it is too large Load Diff

View File

@@ -34,20 +34,20 @@
..(process, D, copy)
// Hullucigen
// Hallucigen
/datum/disease/advance/hullucigen/New(var/process = TRUE, var/datum/disease/advance/D, var/copy = FALSE)
/datum/disease/advance/hallucigen/New(var/process = TRUE, var/datum/disease/advance/D, var/copy = FALSE)
if(!D)
name = "Reality Impairment"
name = "Second Sight"
symptoms = list(new/datum/symptom/hallucigen)
..(process, D, copy)
// Sensory Restoration
/datum/disease/advance/sensory_restoration/New(var/process = TRUE, var/datum/disease/advance/D, var/copy = FALSE)
/datum/disease/advance/mind_restoration/New(var/process = TRUE, var/datum/disease/advance/D, var/copy = FALSE)
if(!D)
name = "Reality Enhancer"
symptoms = list(new/datum/symptom/sensory_restoration)
name = "Intelligence Booster"
symptoms = list(new/datum/symptom/mind_restoration)
..(process, D, copy)
// Sensory Destruction

View File

@@ -17,6 +17,7 @@ BONUS
/datum/symptom/beard
name = "Facial Hypertrichosis"
desc = "The virus increases hair production significantly, causing rapid beard growth."
stealth = -3
resistance = -1
stage_speed = -3

View File

@@ -18,6 +18,7 @@ Bonus
/datum/symptom/choking
name = "Choking"
desc = "The virus causes inflammation of the host's air conduits, leading to intermittent choking."
stealth = -3
resistance = -2
stage_speed = -2
@@ -27,6 +28,8 @@ Bonus
base_message_chance = 15
symptom_delay_min = 10
symptom_delay_max = 30
threshold_desc = "<b>Stage Speed 8:</b> Causes choking more frequently.<br>\
<b>Stealth 4:</b> The symptom remains hidden until active."
/datum/symptom/choking/Start(datum/disease/advance/A)
..()
@@ -84,6 +87,7 @@ Bonus
/datum/symptom/asphyxiation
name = "Acute respiratory distress syndrome"
desc = "The virus causes shrinking of the host's lungs, causing severe asphyxiation. May also lead to heart attacks."
stealth = -2
resistance = -0
stage_speed = -1

View File

@@ -18,6 +18,7 @@ Bonus
/datum/symptom/confusion
name = "Confusion"
desc = "The virus interferes with the proper function of the neural system, leading to bouts of confusion and erratic movement."
stealth = 1
resistance = -1
stage_speed = -3
@@ -28,6 +29,9 @@ Bonus
symptom_delay_min = 10
symptom_delay_max = 30
var/brain_damage = FALSE
threshold_desc = "<b>Resistance 6:</b> Causes brain damage over time.<br>\
<b>Transmission 6:</b> Increases confusion duration.<br>\
<b>Stealth 4:</b> The symptom remains hidden until active."
/datum/symptom/confusion/Start(datum/disease/advance/A)
..()

View File

@@ -18,6 +18,7 @@ BONUS
/datum/symptom/cough
name = "Cough"
desc = "The virus irritates the throat of the host, causing occasional coughing."
stealth = -1
resistance = 3
stage_speed = 1
@@ -28,6 +29,11 @@ BONUS
symptom_delay_min = 2
symptom_delay_max = 15
var/infective = FALSE
threshold_desc = "<b>Resistance 3:</b> Host will drop small items when coughing.<br>\
<b>Resistance 10:</b> Occasionally causes coughing fits that stun the host.<br>\
<b>Stage Speed 6:</b> Increases cough frequency.<br>\
<b>If Airborne:</b> Coughing will infect bystanders.<br>\
<b>Stealth 4:</b> The symptom remains hidden until active."
/datum/symptom/cough/Start(datum/disease/advance/A)
..()

View File

@@ -18,6 +18,7 @@ Bonus
/datum/symptom/deafness
name = "Deafness"
desc = "The virus causes inflammation of the eardrums, causing intermittent deafness."
stealth = -1
resistance = -2
stage_speed = -1
@@ -27,6 +28,8 @@ Bonus
base_message_chance = 100
symptom_delay_min = 25
symptom_delay_max = 80
threshold_desc = "<b>Resistance 9:</b> Causes permanent deafness, instead of intermittent.<br>\
<b>Stealth 4:</b> The symptom remains hidden until active."
/datum/symptom/deafness/Start(datum/disease/advance/A)
..()

View File

@@ -18,7 +18,7 @@ Bonus
/datum/symptom/dizzy // Not the egg
name = "Dizziness"
stealth = 2
desc = "The virus causes inflammation of the vestibular system, leading to bouts of dizziness."
resistance = -2
stage_speed = -3
transmittable = -1
@@ -27,6 +27,8 @@ Bonus
base_message_chance = 50
symptom_delay_min = 15
symptom_delay_max = 40
threshold_desc = "<b>Transmission 6:</b> Also causes druggy vision.<br>\
<b>Stealth 4:</b> The symptom remains hidden until active."
/datum/symptom/dizzy/Start(datum/disease/advance/A)
..()

View File

@@ -16,8 +16,8 @@ Bonus
*/
/datum/symptom/fever
name = "Fever"
desc = "The virus causes a febrile response from the host, raising its body temperature."
stealth = 0
resistance = 3
stage_speed = 3
@@ -28,6 +28,8 @@ Bonus
symptom_delay_min = 10
symptom_delay_max = 30
var/unsafe = FALSE //over the heat threshold
threshold_desc = "<b>Resistance 5:</b> Increases fever intensity, fever can overheat and harm the host.<br>\
<b>Resistance 10:</b> Further increases fever intensity."
/datum/symptom/fever/Start(datum/disease/advance/A)
..()

View File

@@ -18,6 +18,7 @@ Bonus
/datum/symptom/fire
name = "Spontaneous Combustion"
desc = "The virus turns fat into an extremely flammable compound, and raises the body's temperature, making the host burst into flames spontaneously."
stealth = 1
resistance = -4
stage_speed = -4
@@ -28,6 +29,10 @@ Bonus
symptom_delay_min = 20
symptom_delay_max = 75
var/infective = FALSE
threshold_desc = "<b>Stage Speed 4:</b> Increases the intensity of the flames.<br>\
<b>Stage Speed 8:</b> Further increases flame intensity.<br>\
<b>Transmission 8:</b> Host will spread the virus through skin flakes when bursting into flame.<br>\
<b>Stealth 4:</b> The symptom remains hidden until active."
/datum/symptom/fire/Start(datum/disease/advance/A)
..()
@@ -94,6 +99,7 @@ Bonus
/datum/symptom/alkali
name = "Alkali perspiration"
desc = "The virus attaches to sudoriparous glands, synthesizing a chemical that bursts into flames when reacting with water, leading to self-immolation."
stealth = 2
resistance = -2
stage_speed = -2
@@ -105,6 +111,9 @@ Bonus
symptom_delay_max = 90
var/chems = FALSE
var/explosion_power = 1
threshold_desc = "<b>Resistance 9:</b> Doubles the intensity of the effect, but reduces its frequency.<br>\
<b>Stage Speed 8:</b> Increases explosion radius when the host is wet.<br>\
<b>Transmission 8:</b> Additionally synthesizes chlorine trifluoride and napalm inside the host."
/datum/symptom/alkali/Start(datum/disease/advance/A)
..()

View File

@@ -18,6 +18,7 @@ Bonus
/datum/symptom/flesh_eating
name = "Necrotizing Fasciitis"
desc = "The virus aggressively attacks body cells, necrotizing tissues and organs."
stealth = -3
resistance = -4
stage_speed = 0
@@ -29,6 +30,8 @@ Bonus
symptom_delay_max = 60
var/bleed = FALSE
var/pain = FALSE
threshold_desc = "<b>Resistance 7:</b> Host will bleed profusely during necrosis.<br>\
<b>Transmission 8:</b> Causes extreme pain to the host, weakening it."
/datum/symptom/flesh_eating/Start(datum/disease/advance/A)
..()
@@ -80,6 +83,7 @@ Bonus
/datum/symptom/flesh_death
name = "Autophagocytosis Necrosis"
desc = "The virus rapidly consumes infected cells, leading to heavy and widespread damage."
stealth = -2
resistance = -2
stage_speed = 1
@@ -91,6 +95,8 @@ Bonus
symptom_delay_max = 6
var/chems = FALSE
var/zombie = FALSE
threshold_desc = "<b>Stage Speed 7:</b> Synthesizes Heparin and Lipolicide inside the host, causing increased bleeding and hunger.<br>\
<b>Stealth 5:</b> The symptom remains hidden until active."
/datum/symptom/flesh_death/Start(datum/disease/advance/A)
..()

View File

@@ -16,8 +16,8 @@ Bonus
*/
/datum/symptom/genetic_mutation
name = "Deoxyribonucleic Acid Saboteur"
desc = "The virus bonds with the DNA of the host, causing damaging mutations until removed."
stealth = -2
resistance = -3
stage_speed = 0
@@ -30,6 +30,9 @@ Bonus
symptom_delay_min = 60
symptom_delay_max = 120
var/no_reset = FALSE
threshold_desc = "<b>Resistance 8:</b> Causes two harmful mutations at once.<br>\
<b>Stage Speed 10:</b> Increases mutation frequency.<br>\
<b>Stealth 5:</b> The mutations persist even if the virus is cured."
/datum/symptom/genetic_mutation/Activate(datum/disease/advance/A)
if(!..())

View File

@@ -16,8 +16,8 @@ Bonus
*/
/datum/symptom/hallucigen
name = "Hallucigen"
desc = "The virus stimulates the brain, causing occasional hallucinations."
stealth = -2
resistance = -3
stage_speed = -3
@@ -28,6 +28,8 @@ Bonus
symptom_delay_min = 25
symptom_delay_max = 90
var/fake_healthy = FALSE
threshold_desc = "<b>Stage Speed 7:</b> Increases the amount of hallucinations.<br>\
<b>Stealth 4:</b> The virus mimics positive symptoms.."
/datum/symptom/hallucigen/Start(datum/disease/advance/A)
..()

View File

@@ -19,6 +19,7 @@ BONUS
/datum/symptom/headache
name = "Headache"
desc = "The virus causes inflammation inside the brain, causing constant headaches."
stealth = -1
resistance = 4
stage_speed = 2
@@ -28,6 +29,9 @@ BONUS
base_message_chance = 100
symptom_delay_min = 15
symptom_delay_max = 30
threshold_desc = "<b>Stage Speed 6:</b> Headaches will cause severe pain, that weakens the host.<br>\
<b>Stage Speed 9:</b> Headaches become less frequent but far more intense, preventing any action from the host.<br>\
<b>Stealth 4:</b> Reduces headache frequency until later stages."
/datum/symptom/headache/Start(datum/disease/advance/A)
..()
@@ -45,11 +49,11 @@ BONUS
return
var/mob/living/M = A.affected_mob
if(power < 2)
if(prob(base_message_chance))
if(prob(base_message_chance) || A.stage >=4)
to_chat(M, "<span class='warning'>[pick("Your head hurts.", "Your head pounds.")]</span>")
if(power >= 2)
if(power >= 2 && A.stage >= 4)
to_chat(M, "<span class='warning'>[pick("Your head hurts a lot.", "Your head pounds incessantly.")]</span>")
M.adjustStaminaLoss(25)
if(power >= 3)
if(power >= 3 && A.stage >= 5)
to_chat(M, "<span class='userdanger'>[pick("Your head hurts!", "You feel a burning knife inside your brain!", "A wave of pain fills your head!")]</span>")
M.Stun(35)

View File

@@ -1,5 +1,6 @@
/datum/symptom/heal
name = "Basic Healing (does nothing)" //warning for adminspawn viruses
desc = "You should not be seeing this."
stealth = 1
resistance = -4
stage_speed = -4
@@ -9,6 +10,9 @@
symptom_delay_min = 1
symptom_delay_max = 1
var/hide_healing = FALSE
threshold_desc = "<b>Stage Speed 6:</b> Doubles healing speed.<br>\
<b>Stage Speed 11:</b> Triples healing speed.<br>\
<b>Stealth 4:</b> Healing will no longer be visible to onlookers."
/datum/symptom/heal/Start(datum/disease/advance/A)
..()
@@ -51,6 +55,7 @@ Bonus
/datum/symptom/heal/toxin
name = "Toxic Filter"
desc = "The virus synthesizes regenerative chemicals in the bloodstream, repairing damage caused by toxins."
stealth = 1
resistance = -4
stage_speed = -4
@@ -87,6 +92,7 @@ Bonus
stage_speed = -2
transmittable = -2
level = 8
desc = "The virus stimulates production of special stem cells in the bloodstream, causing rapid reparation of any damage caused by toxins."
/datum/symptom/heal/toxin/plus/Heal(mob/living/M, datum/disease/advance/A)
var/heal_amt = 2 * power
@@ -115,6 +121,7 @@ Bonus
/datum/symptom/heal/brute
name = "Regeneration"
desc = "The virus stimulates the regenerative process in the host, causing faster wound healing."
stealth = 1
resistance = -4
stage_speed = -4
@@ -158,6 +165,7 @@ Bonus
/datum/symptom/heal/brute/plus
name = "Flesh Mending"
desc = "The virus rapidly mutates into body cells, effectively allowing it to quickly fix the host's wounds."
stealth = 0
resistance = 0
stage_speed = -2
@@ -207,6 +215,7 @@ Bonus
/datum/symptom/heal/burn
name = "Tissue Regrowth"
desc = "The virus recycles dead and burnt tissues, speeding up the healing of damage caused by burns."
stealth = 1
resistance = -4
stage_speed = -4
@@ -248,7 +257,8 @@ Bonus
/datum/symptom/heal/burn/plus
name = "Heat Resistance"
name = "Temperature Adaptation"
desc = "The virus quickly balances body heat, while also replacing tissues damaged by external sources."
stealth = 0
resistance = 0
stage_speed = -2
@@ -297,6 +307,7 @@ Bonus
/datum/symptom/heal/dna
name = "Deoxyribonucleic Acid Restoration"
desc = "The virus repairs the host's genome, purging negative mutations."
stealth = -1
resistance = -1
stage_speed = 0
@@ -304,9 +315,11 @@ Bonus
level = 5
symptom_delay_min = 3
symptom_delay_max = 8
threshold_desc = "<b>Stage Speed 6:</b> Additionally heals brain damage.<br>\
<b>Stage Speed 11:</b> Increases brain damage healing."
/datum/symptom/heal/dna/Heal(mob/living/carbon/M, datum/disease/advance/A)
var/amt_healed = 2 * power
var/amt_healed = 2 * (power - 1)
M.adjustBrainLoss(-amt_healed)
//Non-power mutations, excluding race, so the virus does not force monkey -> human transformations.
var/list/unclean_mutations = (GLOB.not_good_mutations|GLOB.bad_mutations) - GLOB.mutations_list[RACEMUT]

View File

@@ -19,6 +19,7 @@ BONUS
/datum/symptom/itching
name = "Itching"
desc = "The virus irritates the skin, causing itching."
stealth = 0
resistance = 3
stage_speed = 3
@@ -28,6 +29,8 @@ BONUS
symptom_delay_min = 5
symptom_delay_max = 25
var/scratch = FALSE
threshold_desc = "<b>Transmission 6:</b> Increases frequency of itching.<br>\
<b>Stage Speed 7:</b> The host will scrath itself when itching, causing superficial damage."
/datum/symptom/itching/Start(datum/disease/advance/A)
..()

View File

@@ -14,6 +14,7 @@ Bonus
*/
/datum/symptom/narcolepsy
name = "Narcolepsy"
desc = "The virus causes a hormone imbalance, making the host sleepy and narcoleptic."
stealth = -1
resistance = -2
stage_speed = -3
@@ -25,6 +26,8 @@ Bonus
var/sleep_level = 0
var/sleepy_ticks = 0
var/stamina = FALSE
threshold_desc = "<b>Transmission 7:</b> Also relaxes the muscles, weakening and slowing the host.<br>\
<b>Resistance 10:</b> Causes narcolepsy more often, increasing the chance of the host falling asleep."
/datum/symptom/narcolepsy/Start(datum/disease/advance/A)
..()

View File

@@ -18,6 +18,7 @@ Bonus
/datum/symptom/oxygen
name = "Self-Respiration"
desc = "The virus rapidly synthesizes oxygen, effectively removing the need for breathing."
stealth = 1
resistance = -3
stage_speed = -3
@@ -27,6 +28,7 @@ Bonus
symptom_delay_min = 1
symptom_delay_max = 1
var/regenerate_blood = FALSE
threshold_desc = "<b>Resistance 8:</b>Additionally regenerates lost blood.<br>"
/datum/symptom/oxygen/Start(datum/disease/advance/A)
..()

View File

@@ -15,8 +15,9 @@ Bonus
//////////////////////////////////////
*/
/datum/symptom/sensory_restoration
name = "Sensory Restoration"
/datum/symptom/mind_restoration
name = "Mind Restoration"
desc = "The virus strengthens the bonds between neurons, reducing the duration of any ailments of the mind."
stealth = -1
resistance = -4
stage_speed = -4
@@ -27,15 +28,17 @@ Bonus
symptom_delay_max = 10
var/purge_alcohol = FALSE
var/brain_heal = FALSE
threshold_desc = "<b>Resistance 6:</b> Heals brain damage.<br>\
<b>Transmission 8:</b> Purges alcohol in the bloodstream."
/datum/symptom/sensory_restoration/Start(datum/disease/advance/A)
/datum/symptom/mind_restoration/Start(datum/disease/advance/A)
..()
if(A.properties["resistance"] >= 6) //heal brain damage
brain_heal = TRUE
if(A.properties["transmittable"] >= 8) //purge alcohol
purge_alcohol = TRUE
/datum/symptom/sensory_restoration/Activate(var/datum/disease/advance/A)
/datum/symptom/mind_restoration/Activate(var/datum/disease/advance/A)
if(!..())
return
var/mob/living/M = A.affected_mob

View File

@@ -15,8 +15,8 @@ BONUS
*/
/datum/symptom/shedding
name = "Alopecia"
desc = "The virus causes rapid shedding of head and body hair."
stealth = 0
resistance = 1
stage_speed = -1

View File

@@ -16,8 +16,8 @@ Bonus
*/
/datum/symptom/shivering
name = "Shivering"
desc = "The virus inhibits the body's thermoregulation, cooling the body down."
stealth = 0
resistance = 2
stage_speed = 2
@@ -27,6 +27,8 @@ Bonus
symptom_delay_min = 10
symptom_delay_max = 30
var/unsafe = FALSE //over the cold threshold
threshold_desc = "<b>Stage Speed 5:</b> Increases cooling speed; the host can fall below safe temperature levels.<br>\
<b>Stage Speed 10:</b> Further increases cooling speed."
/datum/symptom/fever/Start(datum/disease/advance/A)
..()

View File

@@ -17,6 +17,7 @@ BONUS
/datum/symptom/vitiligo
name = "Vitiligo"
desc = "The virus destroys skin pigment cells, causing rapid loss of pigmentation in the host."
stealth = -3
resistance = -1
stage_speed = -1
@@ -61,6 +62,7 @@ BONUS
/datum/symptom/revitiligo
name = "Revitiligo"
desc = "The virus causes increased production of skin pigment cells, making the host's skin grow darker over time."
stealth = -3
resistance = -1
stage_speed = -1

View File

@@ -18,6 +18,7 @@ Bonus
/datum/symptom/sneeze
name = "Sneezing"
desc = "The virus causes irritation of the nasal cavity, making the host sneeze occasionally."
stealth = -2
resistance = 3
stage_speed = 0
@@ -26,6 +27,8 @@ Bonus
severity = 1
symptom_delay_min = 5
symptom_delay_max = 35
threshold_desc = "<b>Transmission 9:</b> Increases sneezing range, spreading the virus over a larger area.<br>\
<b>Stealth 4:</b> The symptom remains hidden until active."
/datum/symptom/sneeze/Start(datum/disease/advance/A)
..()

View File

@@ -3,6 +3,8 @@
/datum/symptom
// Buffs/Debuffs the symptom has to the overall engineered disease.
var/name = ""
var/desc = "If you see this something went very wrong." //Basic symptom description
var/threshold_desc = "" //Description of threshold effects
var/stealth = 0
var/resistance = 0
var/stage_speed = 0
@@ -25,6 +27,7 @@
var/power = 1
//A neutered symptom has no effect, and only affects statistics.
var/neutered = FALSE
var/list/thresholds
/datum/symptom/New()
var/list/S = SSdisease.list_symptoms
@@ -37,7 +40,6 @@
// Called when processing of the advance disease, which holds this symptom, starts.
/datum/symptom/proc/Start(datum/disease/advance/A)
next_activation = world.time + rand(symptom_delay_min * 10, symptom_delay_max * 10) //so it doesn't instantly activate on infection
return
// Called when the advance disease is going to be deleted or when the advance disease stops processing.
/datum/symptom/proc/End(datum/disease/advance/A)
@@ -58,3 +60,6 @@
new_symp.id = id
new_symp.neutered = neutered
return new_symp
/datum/symptom/proc/generate_threshold_desc()
return

View File

@@ -15,6 +15,7 @@ BONUS
*/
/datum/symptom/viraladaptation
name = "Viral self-adaptation"
desc = "The virus mimics the function of normal body cells, becoming harder to spot and to eradicate, but reducing its speed."
stealth = 3
resistance = 5
stage_speed = -3
@@ -38,6 +39,8 @@ BONUS
*/
/datum/symptom/viralevolution
name = "Viral evolutionary acceleration"
desc = "The virus quickly adapts to spread as fast as possible both outside and inside a host. \
This, however, makes the virus easier to spot, and less able to fight off a cure."
stealth = -2
resistance = -3
stage_speed = 5
@@ -65,6 +68,8 @@ Bonus
/datum/symptom/viralreverse
name = "Viral aggressive metabolism"
desc = "The virus sacrifices its long term survivability to gain a near-instant spread when inside a host. \
The virus will start at the lastest stage, but will eventually decay and die off by itself."
stealth = -2
resistance = 1
stage_speed = 3
@@ -73,6 +78,8 @@ Bonus
symptom_delay_min = 1
symptom_delay_max = 1
var/time_to_cure
threshold_desc = "<b>Resistance/Stage Speed:</b> Highest between these determines the amount of time before self-curing.<br>\
<b>Stealth 4:</b> Doubles the time before the virus self-cures."
/datum/symptom/viralreverse/Activate(datum/disease/advance/A)
if(!..())

View File

@@ -18,6 +18,7 @@ Bonus
/datum/symptom/visionloss
name = "Hyphema"
desc = "The virus causes inflammation of the retina, leading to eye damage and eventually blindness."
stealth = -1
resistance = -4
stage_speed = -4
@@ -28,6 +29,8 @@ Bonus
symptom_delay_min = 25
symptom_delay_max = 80
var/remove_eyes = FALSE
threshold_desc = "<b>Resistance 12:</b> Weakens extraocular muscles, eventually leading to complete detachment of the eyes.<br>\
<b>Stealth 4:</b> The symptom remains hidden until active."
/datum/symptom/visionloss/Start(datum/disease/advance/A)
..()
@@ -88,6 +91,7 @@ Bonus
/datum/symptom/visionaid
name = "Ocular Restoration"
desc = "The virus stimulates the production and replacement of eye cells, causing the host to regenerate its eyes when damaged."
stealth = -1
resistance = -3
stage_speed = -2

View File

@@ -18,6 +18,7 @@ Bonus
/datum/symptom/voice_change
name = "Voice Change"
desc = "The virus alters the pitch and tone of the host's vocal cords, changing how their voice sounds."
stealth = -1
resistance = -2
stage_speed = -2
@@ -30,6 +31,9 @@ Bonus
var/scramble_language = FALSE
var/datum/language/current_language
var/datum/language_holder/original_language
threshold_desc = "<b>Transmission 14:</b> The host's language center of the brain is damaged, leading to complete inability to speak or understand any language.<br>\
<b>Stage Speed 7:</b> Changes voice more often.<br>\
<b>Stealth 3:</b> The symptom remains hidden until active."
/datum/symptom/voice_change/Start(datum/disease/advance/A)
..()

View File

@@ -22,6 +22,7 @@ Bonus
/datum/symptom/vomit
name = "Vomiting"
desc = "The virus causes nausea and irritates the stomach, causing occasional vomit."
stealth = -2
resistance = -1
stage_speed = 0
@@ -33,6 +34,9 @@ Bonus
symptom_delay_max = 80
var/vomit_blood = FALSE
var/proj_vomit = 0
threshold_desc = "<b>Resistance 7:</b> Host will vomit blood, causing internal damage.<br>\
<b>Transmission 7:</b> Host will projectile vomit, increasing vomiting range.<br>\
<b>Stealth 4:</b> The symptom remains hidden until active."
/datum/symptom/vomit/Start(datum/disease/advance/A)
..()

View File

@@ -18,6 +18,7 @@ Bonus
/datum/symptom/weight_gain
name = "Weight Gain"
desc = "The virus mutates the host's metabolism, making it gain weight much faster than normal."
stealth = -3
resistance = -3
stage_speed = -2
@@ -27,6 +28,7 @@ Bonus
base_message_chance = 100
symptom_delay_min = 15
symptom_delay_max = 45
threshold_desc = "<b>Stealth 4:</b> The symptom is less noticeable."
/datum/symptom/weight_gain/Start(datum/disease/advance/A)
..()
@@ -66,6 +68,7 @@ Bonus
/datum/symptom/weight_loss
name = "Weight Loss"
desc = "The virus mutates the host's metabolism, making it almost unable to gain nutrition from food."
stealth = -3
resistance = -2
stage_speed = -2
@@ -75,6 +78,7 @@ Bonus
base_message_chance = 100
symptom_delay_min = 15
symptom_delay_max = 45
threshold_desc = "<b>Stealth 4:</b> The symptom is less noticeable."
/datum/symptom/weight_loss/Start(datum/disease/advance/A)
..()
@@ -116,6 +120,7 @@ Bonus
/datum/symptom/weight_even
name = "Weight Even"
desc = "The virus alters the host's metabolism, making it far more efficient then normal, and synthesizing nutrients from normally unedible sources."
stealth = -3
resistance = -2
stage_speed = -2

View File

@@ -18,6 +18,8 @@ BONUS
/datum/symptom/youth
name = "Eternal Youth"
desc = "The virus becomes symbiotically connected to the cells in the host's body, preventing and reversing aging. \
The virus, in turn, becomes more resistant, spreads faster, and is harder to spot, although it doesn't thrive as well without a host."
stealth = 3
resistance = 4
stage_speed = 4

View File

@@ -6,8 +6,14 @@
var/date
/datum/getrev/New()
if(world.RunningService() && fexists(SERVICE_PR_TEST_JSON))
testmerge = json_decode(file2text(SERVICE_PR_TEST_JSON))
if(world.RunningService())
var/file_name
if(ServiceVersion()) //will return null for versions < 3.0.91.0
file_name = SERVICE_PR_TEST_JSON_OLD
else
file_name = SERVICE_PR_TEST_JSON
if(fexists(file_name))
testmerge = json_decode(file2text(file_name))
#ifdef SERVERTOOLS
else if(!world.RunningService() && fexists("../prtestjob.lk")) //tgs2 support
var/list/tmp = world.file2list("..\\prtestjob.lk")

View File

@@ -4,142 +4,142 @@
// -Cyberboss
/datum/map_config
var/config_filename = "_maps/boxstation.json"
var/map_name = "Box Station"
var/map_path = "map_files/BoxStation"
var/map_file = "BoxStation.dmm"
var/config_filename = "_maps/boxstation.json"
var/map_name = "Box Station"
var/map_path = "map_files/BoxStation"
var/map_file = "BoxStation.dmm"
var/minetype = "lavaland"
var/minetype = "lavaland"
var/list/transition_config = list(CENTCOM = SELFLOOPING,
var/list/transition_config = list(CENTCOM = SELFLOOPING,
MAIN_STATION = CROSSLINKED,
EMPTY_AREA_1 = CROSSLINKED,
EMPTY_AREA_2 = CROSSLINKED,
MINING = SELFLOOPING,
EMPTY_AREA_3 = CROSSLINKED,
EMPTY_AREA_4 = CROSSLINKED,
EMPTY_AREA_5 = CROSSLINKED,
EMPTY_AREA_6 = CROSSLINKED,
EMPTY_AREA_7 = CROSSLINKED,
EMPTY_AREA_8 = CROSSLINKED)
var/defaulted = TRUE //if New failed
EMPTY_AREA_1 = CROSSLINKED,
EMPTY_AREA_2 = CROSSLINKED,
MINING = SELFLOOPING,
EMPTY_AREA_3 = CROSSLINKED,
EMPTY_AREA_4 = CROSSLINKED,
EMPTY_AREA_5 = CROSSLINKED,
EMPTY_AREA_6 = CROSSLINKED,
EMPTY_AREA_7 = CROSSLINKED,
EMPTY_AREA_8 = CROSSLINKED)
var/defaulted = TRUE //if New failed
var/config_max_users = 0
var/config_min_users = 0
var/voteweight = 1
var/allow_custom_shuttles = "yes"
var/config_max_users = 0
var/config_min_users = 0
var/voteweight = 1
var/allow_custom_shuttles = "yes"
/datum/map_config/New(filename = "data/next_map.json", default_to_box, delete_after)
if(default_to_box)
return
LoadConfig(filename)
if(delete_after)
fdel(filename)
if(default_to_box)
return
LoadConfig(filename)
if(delete_after)
fdel(filename)
/datum/map_config/proc/LoadConfig(filename)
if(!fexists(filename))
log_world("map_config not found: [filename]")
return
if(!fexists(filename))
log_world("map_config not found: [filename]")
return
var/json = file(filename)
if(!json)
log_world("Could not open map_config: [filename]")
return
var/json = file(filename)
if(!json)
log_world("Could not open map_config: [filename]")
return
json = file2text(json)
if(!json)
log_world("map_config is not text: [filename]")
return
json = file2text(json)
if(!json)
log_world("map_config is not text: [filename]")
return
json = json_decode(json)
if(!json)
log_world("map_config is not json: [filename]")
return
json = json_decode(json)
if(!json)
log_world("map_config is not json: [filename]")
return
if(!ValidateJSON(json))
log_world("map_config failed to validate for above reason: [filename]")
return
if(!ValidateJSON(json))
log_world("map_config failed to validate for above reason: [filename]")
return
config_filename = filename
config_filename = filename
map_name = json["map_name"]
map_path = json["map_path"]
map_file = json["map_file"]
map_name = json["map_name"]
map_path = json["map_path"]
map_file = json["map_file"]
minetype = json["minetype"]
allow_custom_shuttles = json["allow_custom_shuttles"]
minetype = json["minetype"]
allow_custom_shuttles = json["allow_custom_shuttles"]
var/list/jtcl = json["transition_config"]
var/list/jtcl = json["transition_config"]
if(jtcl != "default")
transition_config.Cut()
if(jtcl != "default")
transition_config.Cut()
for(var/I in jtcl)
transition_config[TransitionStringToEnum(I)] = TransitionStringToEnum(jtcl[I])
for(var/I in jtcl)
transition_config[TransitionStringToEnum(I)] = TransitionStringToEnum(jtcl[I])
defaulted = FALSE
defaulted = FALSE
#define CHECK_EXISTS(X) if(!istext(json[X])) { log_world(X + "missing from json!"); return; }
/datum/map_config/proc/ValidateJSON(list/json)
CHECK_EXISTS("map_name")
CHECK_EXISTS("map_path")
CHECK_EXISTS("map_file")
CHECK_EXISTS("minetype")
CHECK_EXISTS("transition_config")
CHECK_EXISTS("allow_custom_shuttles")
CHECK_EXISTS("map_name")
CHECK_EXISTS("map_path")
CHECK_EXISTS("map_file")
CHECK_EXISTS("minetype")
CHECK_EXISTS("transition_config")
CHECK_EXISTS("allow_custom_shuttles")
var/path = GetFullMapPath(json["map_path"], json["map_file"])
if(!fexists(path))
log_world("Map file ([path]) does not exist!")
return
var/path = GetFullMapPath(json["map_path"], json["map_file"])
if(!fexists(path))
log_world("Map file ([path]) does not exist!")
return
if(json["transition_config"] != "default")
if(!islist(json["transition_config"]))
log_world("transition_config is not a list!")
return
if(json["transition_config"] != "default")
if(!islist(json["transition_config"]))
log_world("transition_config is not a list!")
return
var/list/jtcl = json["transition_config"]
for(var/I in jtcl)
if(isnull(TransitionStringToEnum(I)))
log_world("Invalid transition_config option: [I]!")
if(isnull(TransitionStringToEnum(jtcl[I])))
log_world("Invalid transition_config option: [I]!")
var/list/jtcl = json["transition_config"]
for(var/I in jtcl)
if(isnull(TransitionStringToEnum(I)))
log_world("Invalid transition_config option: [I]!")
if(isnull(TransitionStringToEnum(jtcl[I])))
log_world("Invalid transition_config option: [I]!")
return TRUE
return TRUE
#undef CHECK_EXISTS
/datum/map_config/proc/TransitionStringToEnum(string)
switch(string)
if("CROSSLINKED")
return CROSSLINKED
if("SELFLOOPING")
return SELFLOOPING
if("UNAFFECTED")
return UNAFFECTED
if("MAIN_STATION")
return MAIN_STATION
if("CENTCOM")
return CENTCOM
if("MINING")
return MINING
if("EMPTY_AREA_1")
return EMPTY_AREA_1
if("EMPTY_AREA_2")
return EMPTY_AREA_2
if("EMPTY_AREA_3")
return EMPTY_AREA_3
if("EMPTY_AREA_4")
return EMPTY_AREA_4
if("EMPTY_AREA_5")
return EMPTY_AREA_5
if("EMPTY_AREA_6")
return EMPTY_AREA_6
if("EMPTY_AREA_7")
return EMPTY_AREA_7
if("EMPTY_AREA_8")
return EMPTY_AREA_8
switch(string)
if("CROSSLINKED")
return CROSSLINKED
if("SELFLOOPING")
return SELFLOOPING
if("UNAFFECTED")
return UNAFFECTED
if("MAIN_STATION")
return MAIN_STATION
if("CENTCOM")
return CENTCOM
if("MINING")
return MINING
if("EMPTY_AREA_1")
return EMPTY_AREA_1
if("EMPTY_AREA_2")
return EMPTY_AREA_2
if("EMPTY_AREA_3")
return EMPTY_AREA_3
if("EMPTY_AREA_4")
return EMPTY_AREA_4
if("EMPTY_AREA_5")
return EMPTY_AREA_5
if("EMPTY_AREA_6")
return EMPTY_AREA_6
if("EMPTY_AREA_7")
return EMPTY_AREA_7
if("EMPTY_AREA_8")
return EMPTY_AREA_8
/datum/map_config/proc/GetFullMapPath(mp = map_path, mf = map_file)
return "_maps/[mp]/[mf]"
return "_maps/[mp]/[mf]"
/datum/map_config/proc/MakeNextMap()
return config_filename == "data/next_map.json" || fcopy(config_filename, "data/next_map.json")
return config_filename == "data/next_map.json" || fcopy(config_filename, "data/next_map.json")

View File

@@ -302,7 +302,7 @@
traitor_mob.mind.store_memory("<B>Radio Frequency:</B> [format_frequency(R.traitor_frequency)] ([R.name]).")
else if(uplink_loc == PDA)
PDA.lock_code = "[rand(100,999)] [pick("Alpha","Bravo","Charlie","Delta","Echo","Foxtrot","Golf","Hotel","India","Juliet","Kilo","Lima","Mike","November","Oscar","Papa","Quebec","Romeo","Sierra","Tango","Uniform","Victor","Whiskey","X-ray","Yankee","Zulu")]"
PDA.lock_code = "[rand(100,999)] [pick(GLOB.phonetic_alphabet)]"
if(!silent) to_chat(traitor_mob, "[employer] has cunningly disguised a Syndicate Uplink as your [PDA.name]. Simply enter the code \"[PDA.lock_code]\" into the ringtone select to unlock its hidden features.")
traitor_mob.mind.store_memory("<B>Uplink Passcode:</B> [PDA.lock_code] ([PDA.name]).")
@@ -358,6 +358,9 @@
if(!SSticker.HasRoundStarted())
alert("Not before round-start!", "Alert")
return
if(QDELETED(src) || QDELETED(current))
alert("This mind doesn't have a mob, or is deleted! For some reason!", "Edit Memory")
return
var/out = "<B>[name]</B>[(current&&(current.real_name!=name))?" (as [current.real_name])":""]<br>"
out += "Mind currently owned by key: [key] [active?"(synced)":"(not synced)"]<br>"
@@ -365,193 +368,40 @@
out += "Faction and special role: <b><font color='red'>[special_role]</font></b><br>"
var/list/sections = list(
"revolution",
"cult",
"wizard",
"traitor", // "traitorchan",
"changeling",
"nuclear",
"traitor", // "traitorchan",
"monkey",
"wizard",
"revolution",
"cult",
"clockcult",
"abductor",
"devil",
"ninja"
"ninja",
"monkey"
)
var/text = ""
if(ishuman(current))
/** REVOLUTION ***/
text = "revolution"
if (SSticker.mode.config_tag=="revolution")
text = uppertext(text)
text = "<i><b>[text]</b></i>: "
if (assigned_role in GLOB.command_positions)
text += "<b>HEAD</b>|loyal|employee|headrev|rev"
else if (src in SSticker.mode.head_revolutionaries)
var/last_healthy_headrev = TRUE
for(var/I in SSticker.mode.head_revolutionaries)
if(I == src)
continue
var/mob/M = I
if(M.z == ZLEVEL_STATION && !M.stat)
last_healthy_headrev = FALSE
break
text += "head|loyal|<a href='?src=\ref[src];revolution=clear'>employee</a>|<b>[last_healthy_headrev ? "<font color='red'>LAST </font> " : ""]HEADREV</b>|<a href='?src=\ref[src];revolution=rev'>rev</a>"
text += "<br>Flash: <a href='?src=\ref[src];revolution=flash'>give</a>"
var/list/L = current.get_contents()
var/obj/item/device/assembly/flash/flash = locate() in L
if (flash)
if(!flash.crit_fail)
text += "|<a href='?src=\ref[src];revolution=takeflash'>take</a>."
else
text += "|<a href='?src=\ref[src];revolution=takeflash'>take</a>|<a href='?src=\ref[src];revolution=repairflash'>repair</a>."
else
text += "."
text += " <a href='?src=\ref[src];revolution=reequip'>Reequip</a> (gives traitor uplink)."
if (objectives.len==0)
text += "<br>Objectives are empty! <a href='?src=\ref[src];revolution=autoobjectives'>Set to kill all heads</a>."
else if(current.isloyal())
text += "head|<b>LOYAL</b>|employee|<a href='?src=\ref[src];revolution=headrev'>headrev</a>|rev"
else if (src in SSticker.mode.revolutionaries)
text += "head|loyal|<a href='?src=\ref[src];revolution=clear'>employee</a>|<a href='?src=\ref[src];revolution=headrev'>headrev</a>|<b>REV</b>"
else
text += "head|loyal|<b>EMPLOYEE</b>|<a href='?src=\ref[src];revolution=headrev'>headrev</a>|<a href='?src=\ref[src];revolution=rev'>rev</a>"
if(current && current.client && (ROLE_REV in current.client.prefs.be_special))
text += "|Enabled in Prefs"
else
text += "|Disabled in Prefs"
sections["revolution"] = text
/** Abductors **/
text = "Abductor"
if(SSticker.mode.config_tag == "abductor")
text = uppertext(text)
text = "<i><b>[text]</b></i>: "
if(src in SSticker.mode.abductors)
text += "<b>Abductor</b>|<a href='?src=\ref[src];abductor=clear'>human</a>"
text += "|<a href='?src=\ref[src];common=undress'>undress</a>|<a href='?src=\ref[src];abductor=equip'>equip</a>"
else
text += "<a href='?src=\ref[src];abductor=abductor'>Abductor</a>|<b>human</b>"
if(current && current.client && (ROLE_ABDUCTOR in current.client.prefs.be_special))
text += "|Enabled in Prefs"
else
text += "|Disabled in Prefs"
sections["abductor"] = text
/** NUCLEAR ***/
text = "nuclear"
if (SSticker.mode.config_tag=="nuclear")
text = uppertext(text)
text = "<i><b>[text]</b></i>: "
if (src in SSticker.mode.syndicates)
text += "<b>OPERATIVE</b>|<a href='?src=\ref[src];nuclear=clear'>nanotrasen</a>"
text += "<br><a href='?src=\ref[src];nuclear=lair'>To shuttle</a>, <a href='?src=\ref[src];common=undress'>undress</a>, <a href='?src=\ref[src];nuclear=dressup'>dress up</a>."
var/code
for (var/obj/machinery/nuclearbomb/bombue in GLOB.machines)
if (length(bombue.r_code) <= 5 && bombue.r_code != "LOLNO" && bombue.r_code != "ADMIN")
code = bombue.r_code
break
if (code)
text += " Code is [code]. <a href='?src=\ref[src];nuclear=tellcode'>tell the code.</a>"
else
text += "<a href='?src=\ref[src];nuclear=nuclear'>operative</a>|<b>NANOTRASEN</b>"
if(current && current.client && (ROLE_OPERATIVE in current.client.prefs.be_special))
text += "|Enabled in Prefs"
else
text += "|Disabled in Prefs"
sections["nuclear"] = text
/** WIZARD ***/
text = "wizard"
if (SSticker.mode.config_tag=="wizard")
text = uppertext(text)
text = "<i><b>[text]</b></i>: "
if ((src in SSticker.mode.wizards) || (src in SSticker.mode.apprentices))
text += "<b>YES</b>|<a href='?src=\ref[src];wizard=clear'>no</a>"
text += "<br><a href='?src=\ref[src];wizard=lair'>To lair</a>, <a href='?src=\ref[src];common=undress'>undress</a>, <a href='?src=\ref[src];wizard=dressup'>dress up</a>, <a href='?src=\ref[src];wizard=name'>let choose name</a>."
if (objectives.len==0)
text += "<br>Objectives are empty! <a href='?src=\ref[src];wizard=autoobjectives'>Randomize!</a>"
else
text += "<a href='?src=\ref[src];wizard=wizard'>yes</a>|<b>NO</b>"
if(current && current.client && (ROLE_WIZARD in current.client.prefs.be_special))
text += "|Enabled in Prefs"
else
text += "|Disabled in Prefs"
sections["wizard"] = text
/** CULT ***/
text = "cult"
if (SSticker.mode.config_tag=="cult")
text = uppertext(text)
text = "<i><b>[text]</b></i>: "
if(iscultist(current))
text += "loyal|<a href='?src=\ref[src];cult=clear'>employee</a>|<b>CULTIST</b>"
text += "<br>Give <a href='?src=\ref[src];cult=tome'>tome</a>|<a href='?src=\ref[src];cult=amulet'>amulet</a>."
else if(current.isloyal())
text += "<b>LOYAL</b>|employee|<a href='?src=\ref[src];cult=cultist'>cultist</a>"
else if(is_convertable_to_cult(current))
text += "loyal|<b>EMPLOYEE</b>|<a href='?src=\ref[src];cult=cultist'>cultist</a>"
else
text += "loyal|<b>EMPLOYEE</b>|<i>cannot serve Nar-Sie</i>"
if(current && current.client && (ROLE_CULTIST in current.client.prefs.be_special))
text += "|Enabled in Prefs"
else
text += "|Disabled in Prefs"
sections["cult"] = text
/** CLOCKWORK CULT **/
text = "clockwork cult"
if(SSticker.mode.config_tag == "clockwork cult")
text = uppertext(text)
text = "<i><b>[text]</b></i>: "
if(is_servant_of_ratvar(current))
text += "loyal|<a href='?src=\ref[src];clockcult=clear'>employee</a>|<b>SERVANT</b>"
text += "<br><a href='?src=\ref[src];clockcult=slab'>Give slab</a>"
else if(current.isloyal())
text += "<b>LOYAL</b>|employee|<a href='?src=\ref[src];clockcult=servant'>servant</a>"
else if(is_eligible_servant(current))
text += "loyal|<b>EMPLOYEE</b>|<a href='?src=\ref[src];clockcult=servant'>servant</a>"
else
text += "loyal|<b>EMPLOYEE</b>|<i>cannot serve Ratvar</i>"
if(current && current.client && (ROLE_SERVANT_OF_RATVAR in current.client.prefs.be_special))
text += "|Enabled in Prefs"
else
text += "|Disabled in Prefs"
sections["clockcult"] = text
/** TRAITOR ***/
text = "traitor"
if (SSticker.mode.config_tag=="traitor" || SSticker.mode.config_tag=="traitorchan")
text = uppertext(text)
text = "<i><b>[text]</b></i>: "
if (src in SSticker.mode.traitors)
text += "<b>TRAITOR</b>|<a href='?src=\ref[src];traitor=clear'>loyal</a>"
text += "<b>TRAITOR</b> | <a href='?src=\ref[src];traitor=clear'>loyal</a>"
if (objectives.len==0)
text += "<br>Objectives are empty! <a href='?src=\ref[src];traitor=autoobjectives'>Randomize</a>!"
else
text += "<a href='?src=\ref[src];traitor=traitor'>traitor</a>|<b>LOYAL</b>"
text += "<a href='?src=\ref[src];traitor=traitor'>traitor</a> | <b>LOYAL</b>"
if(current && current.client && (ROLE_TRAITOR in current.client.prefs.be_special))
text += "|Enabled in Prefs"
text += " | Enabled in Prefs"
else
text += "|Disabled in Prefs"
text += " | Disabled in Prefs"
sections["traitor"] = text
if(ishuman(current) || ismonkey(current))
/** CHANGELING ***/
@@ -560,34 +410,35 @@
text = uppertext(text)
text = "<i><b>[text]</b></i>: "
if ((src in SSticker.mode.changelings) && special_role)
text += "<b>YES</b>|<a href='?src=\ref[src];changeling=clear'>no</a>"
text += "<b>YES</b> | <a href='?src=\ref[src];changeling=clear'>no</a>"
if (objectives.len==0)
text += "<br>Objectives are empty! <a href='?src=\ref[src];changeling=autoobjectives'>Randomize!</a>"
if(changeling && changeling.stored_profiles.len && (current.real_name != changeling.first_prof.name) )
text += "<br><a href='?src=\ref[src];changeling=initialdna'>Transform to initial appearance.</a>"
else if(src in SSticker.mode.changelings) //Station Aligned Changeling
text += "<b>YES (but not an antag)</b>|<a href='?src=\ref[src];changeling=clear'>no</a>"
text += "<b>YES (but not an antag)</b> | <a href='?src=\ref[src];changeling=clear'>no</a>"
if (objectives.len==0)
text += "<br>Objectives are empty! <a href='?src=\ref[src];changeling=autoobjectives'>Randomize!</a>"
if(changeling && changeling.stored_profiles.len && (current.real_name != changeling.first_prof.name) )
text += "<br><a href='?src=\ref[src];changeling=initialdna'>Transform to initial appearance.</a>"
else
text += "<a href='?src=\ref[src];changeling=changeling'>yes</a>|<b>NO</b>"
text += "<a href='?src=\ref[src];changeling=changeling'>yes</a> | <b>NO</b>"
if(current && current.client && (ROLE_CHANGELING in current.client.prefs.be_special))
text += "|Enabled in Prefs"
text += " | Enabled in Prefs"
else
text += "|Disabled in Prefs"
text += " | Disabled in Prefs"
sections["changeling"] = text
/** MONKEY ***/
text = "monkey"
if (SSticker.mode.config_tag=="monkey")
text = uppertext(text)
text = "<i><b>[text]</b></i>: "
if (ishuman(current))
text += "<a href='?src=\ref[src];monkey=healthy'>healthy</a>|<a href='?src=\ref[src];monkey=infected'>infected</a>|<b>HUMAN</b>|other"
text += "<a href='?src=\ref[src];monkey=healthy'>healthy</a> | <a href='?src=\ref[src];monkey=infected'>infected</a> | <b>HUMAN</b> | other"
else if(ismonkey(current))
var/found = FALSE
for(var/datum/disease/transformation/jungle_fever/JF in current.viruses)
@@ -595,63 +446,222 @@
break
if(found)
text += "<a href='?src=\ref[src];monkey=healthy'>healthy</a>|<b>INFECTED</b>|<a href='?src=\ref[src];monkey=human'>human</a>|other"
text += "<a href='?src=\ref[src];monkey=healthy'>healthy</a> | <b>INFECTED</b> | <a href='?src=\ref[src];monkey=human'>human</a> | other"
else
text += "<b>HEALTHY</b>|<a href='?src=\ref[src];monkey=infected'>infected</a>|<a href='?src=\ref[src];monkey=human'>human</a>|other"
text += "<b>HEALTHY</b> | <a href='?src=\ref[src];monkey=infected'>infected</a> | <a href='?src=\ref[src];monkey=human'>human</a> | other"
else
text += "healthy|infected|human|<b>OTHER</b>"
text += "healthy | infected | human | <b>OTHER</b>"
if(current && current.client && (ROLE_MONKEY in current.client.prefs.be_special))
text += "|Enabled in Prefs"
text += " | Enabled in Prefs"
else
text += "|Disabled in Prefs"
text += " | Disabled in Prefs"
sections["monkey"] = text
/** devil ***/
text = "devil"
if(SSticker.mode.config_tag == "devil")
text = uppertext(text)
text = "<i><b>[text]</b></i>: "
var/datum/antagonist/devil/devilinfo = has_antag_datum(ANTAG_DATUM_DEVIL)
if(devilinfo)
if(!devilinfo.ascendable)
text += "<b>DEVIL</b>|<a href='?src=\ref[src];devil=ascendable_devil'>Ascendable Devil</a>|sintouched|<a href='?src=\ref[src];devil=clear'>human</a>"
if(ishuman(current))
/** NUCLEAR ***/
text = "nuclear"
if (SSticker.mode.config_tag=="nuclear")
text = uppertext(text)
text = "<i><b>[text]</b></i>: "
if (src in SSticker.mode.syndicates)
text += "<b>OPERATIVE</b> | <a href='?src=\ref[src];nuclear=clear'>nanotrasen</a>"
text += "<br><a href='?src=\ref[src];nuclear=lair'>To shuttle</a>, <a href='?src=\ref[src];common=undress'>undress</a>, <a href='?src=\ref[src];nuclear=dressup'>dress up</a>."
var/code
for (var/obj/machinery/nuclearbomb/bombue in GLOB.machines)
if (length(bombue.r_code) <= 5 && bombue.r_code != "LOLNO" && bombue.r_code != "ADMIN")
code = bombue.r_code
break
if (code)
text += " Code is [code]. <a href='?src=\ref[src];nuclear=tellcode'>tell the code.</a>"
else
text += "<a href='?src=\ref[src];devil=devil'>DEVIL</a>|<b>ASCENDABLE DEVIL</b>|sintouched|<a href='?src=\ref[src];devil=clear'>human</a>"
else if(src in SSticker.mode.sintouched)
text += "devil|Ascendable Devil|<b>SINTOUCHED</b>|<a href='?src=\ref[src];devil=clear'>human</a>"
else
text += "<a href='?src=\ref[src];devil=devil'>devil</a>|<a href='?src=\ref[src];devil=ascendable_devil'>Ascendable Devil</a>|<a href='?src=\ref[src];devil=sintouched'>sintouched</a>|<b>HUMAN</b>"
text += "<a href='?src=\ref[src];nuclear=nuclear'>operative</a> | <b>NANOTRASEN</b>"
if(current && current.client && (ROLE_DEVIL in current.client.prefs.be_special))
text += "|Enabled in Prefs"
else
text += "|Disabled in Prefs"
sections["devil"] = text
/** NINJA ***/
text = "ninja"
if(SSticker.mode.config_tag == "ninja")
text = uppertext(text)
text = "<i><b>[text]</b></i>: "
var/datum/antagonist/ninja/ninjainfo = has_antag_datum(ANTAG_DATUM_NINJA)
if(ninjainfo)
if(ninjainfo.helping_station)
text += "<a href='?src=\ref[src];ninja=clear'>employee</a> | syndicate | <b>NANOTRASEN</b> | <b><a href='?src=\ref[src];ninja=equip'>EQUIP</a></b>"
if(current && current.client && (ROLE_OPERATIVE in current.client.prefs.be_special))
text += " | Enabled in Prefs"
else
text += "<a href='?src=\ref[src];ninja=clear'>employee</a> | <b>SYNDICATE</b> | nanotrasen | <b><a href='?src=\ref[src];ninja=equip'>EQUIP</a></b>"
else
text += "<b>EMPLOYEE</b> | <a href='?src=\ref[src];ninja=syndicate'>syndicate</a> | <a href='?src=\ref[src];ninja=nanotrasen'>nanotrasen</a> | <a href='?src=\ref[src];ninja=random'>random allegiance</a>"
if(current && current.client && (ROLE_NINJA in current.client.prefs.be_special))
text += " | Enabled in Prefs"
else
text += " | Disabled in Prefs"
sections["ninja"] = text
text += " | Disabled in Prefs"
sections["nuclear"] = text
/** SILICON ***/
/** WIZARD ***/
text = "wizard"
if (SSticker.mode.config_tag=="wizard")
text = uppertext(text)
text = "<i><b>[text]</b></i>: "
if ((src in SSticker.mode.wizards) || (src in SSticker.mode.apprentices))
text += "<b>YES</b> | <a href='?src=\ref[src];wizard=clear'>no</a>"
text += "<br><a href='?src=\ref[src];wizard=lair'>To lair</a>, <a href='?src=\ref[src];common=undress'>undress</a>, <a href='?src=\ref[src];wizard=dressup'>dress up</a>, <a href='?src=\ref[src];wizard=name'>let choose name</a>."
if (objectives.len==0)
text += "<br>Objectives are empty! <a href='?src=\ref[src];wizard=autoobjectives'>Randomize!</a>"
else
text += "<a href='?src=\ref[src];wizard=wizard'>yes</a> | <b>NO</b>"
if(current && current.client && (ROLE_WIZARD in current.client.prefs.be_special))
text += " | Enabled in Prefs"
else
text += " | Disabled in Prefs"
sections["wizard"] = text
/** REVOLUTION ***/
text = "revolution"
if (SSticker.mode.config_tag=="revolution")
text = uppertext(text)
text = "<i><b>[text]</b></i>: "
if (assigned_role in GLOB.command_positions)
text += "<b>HEAD</b> | not mindshielded | employee | headrev | rev"
else if (src in SSticker.mode.head_revolutionaries)
var/last_healthy_headrev = TRUE
for(var/I in SSticker.mode.head_revolutionaries)
if(I == src)
continue
var/mob/M = I
if(M.z == ZLEVEL_STATION && !M.stat)
last_healthy_headrev = FALSE
break
text += "head | not mindshielded | <a href='?src=\ref[src];revolution=clear'>employee</a> | <b>[last_healthy_headrev ? "<font color='red'>LAST </font> " : ""]HEADREV</b> | <a href='?src=\ref[src];revolution=rev'>rev</a>"
text += "<br>Flash: <a href='?src=\ref[src];revolution=flash'>give</a>"
var/list/L = current.get_contents()
var/obj/item/device/assembly/flash/flash = locate() in L
if (flash)
if(!flash.crit_fail)
text += " | <a href='?src=\ref[src];revolution=takeflash'>take</a>."
else
text += " | <a href='?src=\ref[src];revolution=takeflash'>take</a> | <a href='?src=\ref[src];revolution=repairflash'>repair</a>."
else
text += "."
text += " <a href='?src=\ref[src];revolution=reequip'>Reequip</a> (gives traitor uplink)."
if (objectives.len==0)
text += "<br>Objectives are empty! <a href='?src=\ref[src];revolution=autoobjectives'>Set to kill all heads</a>."
else if(current.isloyal())
text += "head | <b>MINDSHIELDED</b> | employee | <a href='?src=\ref[src];revolution=headrev'>headrev</a> | rev"
else if (src in SSticker.mode.revolutionaries)
text += "head | not mindshielded | <a href='?src=\ref[src];revolution=clear'>employee</a> | <a href='?src=\ref[src];revolution=headrev'>headrev</a> | <b>REV</b>"
else
text += "head | not mindshielded | <b>EMPLOYEE</b> | <a href='?src=\ref[src];revolution=headrev'>headrev</a> | <a href='?src=\ref[src];revolution=rev'>rev</a>"
if(current && current.client && (ROLE_REV in current.client.prefs.be_special))
text += " | Enabled in Prefs"
else
text += " | Disabled in Prefs"
sections["revolution"] = text
/** Abductors **/
text = "Abductor"
if(SSticker.mode.config_tag == "abductor")
text = uppertext(text)
text = "<i><b>[text]</b></i>: "
if(src in SSticker.mode.abductors)
text += "<b>Abductor</b> | <a href='?src=\ref[src];abductor=clear'>human</a>"
text += " | <a href='?src=\ref[src];common=undress'>undress</a> | <a href='?src=\ref[src];abductor=equip'>equip</a>"
else
text += "<a href='?src=\ref[src];abductor=abductor'>abductor</a> | <b>human</b>"
if(current && current.client && (ROLE_ABDUCTOR in current.client.prefs.be_special))
text += " | Enabled in Prefs"
else
text += " | Disabled in Prefs"
sections["abductor"] = text
/** DEVIL ***/
text = "devil"
if(SSticker.mode.config_tag == "devil")
text = uppertext(text)
text = "<i><b>[text]</b></i>: "
var/datum/antagonist/devil/devilinfo = has_antag_datum(ANTAG_DATUM_DEVIL)
if(devilinfo)
if(!devilinfo.ascendable)
text += "<b>DEVIL</b> | <a href='?src=\ref[src];devil=ascendable_devil'>ascendable devil</a> | sintouched | <a href='?src=\ref[src];devil=clear'>human</a>"
else
text += "<a href='?src=\ref[src];devil=devil'>DEVIL</a> | <b>ASCENDABLE DEVIL</b> | sintouched | <a href='?src=\ref[src];devil=clear'>human</a>"
else if(src in SSticker.mode.sintouched)
text += "devil | ascendable devil | <b>SINTOUCHED</b> | <a href='?src=\ref[src];devil=clear'>human</a>"
else
text += "<a href='?src=\ref[src];devil=devil'>devil</a> | <a href='?src=\ref[src];devil=ascendable_devil'>ascendable devil</a> | <a href='?src=\ref[src];devil=sintouched'>sintouched</a> | <b>HUMAN</b>"
if(current && current.client && (ROLE_DEVIL in current.client.prefs.be_special))
text += " | Enabled in Prefs"
else
text += " | Disabled in Prefs"
sections["devil"] = text
/** NINJA ***/
text = "ninja"
if(SSticker.mode.config_tag == "ninja")
text = uppertext(text)
text = "<i><b>[text]</b></i>: "
var/datum/antagonist/ninja/ninjainfo = has_antag_datum(ANTAG_DATUM_NINJA)
if(ninjainfo)
if(ninjainfo.helping_station)
text += "<a href='?src=\ref[src];ninja=clear'>employee</a> | syndicate | <b>NANOTRASEN</b> | <b><a href='?src=\ref[src];ninja=equip'>EQUIP</a></b>"
else
text += "<a href='?src=\ref[src];ninja=clear'>employee</a> | <b>SYNDICATE</b> | nanotrasen | <b><a href='?src=\ref[src];ninja=equip'>EQUIP</a></b>"
else
text += "<b>EMPLOYEE</b> | <a href='?src=\ref[src];ninja=syndicate'>syndicate</a> | <a href='?src=\ref[src];ninja=nanotrasen'>nanotrasen</a> | <a href='?src=\ref[src];ninja=random'>random allegiance</a>"
if(current && current.client && (ROLE_NINJA in current.client.prefs.be_special))
text += " | Enabled in Prefs"
else
text += " | Disabled in Prefs"
sections["ninja"] = text
if(!issilicon(current))
/** CULT ***/
text = "cult"
if (SSticker.mode.config_tag=="cult")
text = uppertext(text)
text = "<i><b>[text]</b></i>: "
if(iscultist(current))
text += "not mindshielded | <a href='?src=\ref[src];cult=clear'>employee</a> | <b>CULTIST</b>"
text += "<br>Give <a href='?src=\ref[src];cult=tome'>tome</a> | <a href='?src=\ref[src];cult=amulet'>amulet</a>."
else if(is_convertable_to_cult(current))
text += "not mindshielded | <b>EMPLOYEE</b> | <a href='?src=\ref[src];cult=cultist'>cultist</a>"
else
text += "[!current.isloyal() ? "not mindshielded" : "<b>MINDSHIELDED</b>"] | <b>EMPLOYEE</b> | <i>cannot serve Nar-Sie</i>"
if(current && current.client && (ROLE_CULTIST in current.client.prefs.be_special))
text += " | Enabled in Prefs"
else
text += " | Disabled in Prefs"
sections["cult"] = text
if(ishuman(current) || issilicon(current))
/** CLOCKWORK CULT **/
text = "clockwork cult"
if(SSticker.mode.config_tag == "clockwork cult")
text = uppertext(text)
text = "<i><b>[text]</b></i>: "
if(is_servant_of_ratvar(current))
text += "not mindshielded | <a href='?src=\ref[src];clockcult=clear'>employee</a> | <b>SERVANT</b>"
text += "<br><a href='?src=\ref[src];clockcult=slab'>Give slab</a>"
else if(is_eligible_servant(current))
text += "not mindshielded | <b>EMPLOYEE</b> | <a href='?src=\ref[src];clockcult=servant'>servant</a>"
else
text += "[!current.isloyal() ? "not mindshielded" : "<b>MINDSHIELDED</b>"] | <b>EMPLOYEE</b> | <i>cannot serve Ratvar</i>"
if(current && current.client && (ROLE_SERVANT_OF_RATVAR in current.client.prefs.be_special))
text += " | Enabled in Prefs"
else
text += " | Disabled in Prefs"
sections["clockcult"] = text
/** SILICON ***/
if(issilicon(current))
text = "silicon"
var/mob/living/silicon/robot/robot = current
@@ -685,7 +695,7 @@
text = "Uplink: <a href='?src=\ref[src];common=uplink'>give</a>"
var/obj/item/device/uplink/U = find_syndicate_uplink()
if(U)
text += "|<a href='?src=\ref[src];common=takeuplink'>take</a>"
text += " | <a href='?src=\ref[src];common=takeuplink'>take</a>"
if (check_rights(R_FUN, 0))
text += ", <a href='?src=\ref[src];common=crystals'>[U.telecrystals]</a> TC"
else
@@ -710,7 +720,10 @@
out += "<a href='?src=\ref[src];obj_announce=1'>Announce objectives</a><br><br>"
usr << browse(out, "window=edit_memory[src];size=500x600")
var/datum/browser/popup = new(usr, "edit_memory", "", 600, 600)
popup.set_content(out)
popup.open()
//usr << browse(out, "window=edit_memory[src];size=575x600")
/datum/mind/Topic(href, href_list)
@@ -837,7 +850,7 @@
if(objective&&objective.type==text2path("/datum/objective/[new_obj_type]"))
def_num = objective.target_amount
var/target_number = input("Input target number:", "Objective", def_num) as num|null
var/target_number = input("Input target number:", "Objective", def_num) as num | null
if (isnull(target_number))//Ordinarily, you wouldn't need isnull. In this case, the value may already exist.
return
@@ -1267,7 +1280,7 @@
sleep(0) //because deleting of virus is doing throught spawn(0) //What
log_admin("[key_name(usr)] attempting to humanize [key_name(current)]")
message_admins("<span class='notice'>[key_name_admin(usr)] attempting to humanize [key_name_admin(current)]</span>")
H = M.humanize(TR_KEEPITEMS | TR_KEEPIMPLANTS | TR_KEEPORGANS | TR_KEEPDAMAGE | TR_KEEPVIRUS | TR_DEFAULTMSG)
H = M.humanize(TR_KEEPITEMS | TR_KEEPIMPLANTS | TR_KEEPORGANS | TR_KEEPDAMAGE | TR_KEEPVIRUS | TR_DEFAULTMSG)
if(H)
src = H.mind
@@ -1301,7 +1314,7 @@
if(check_rights(R_FUN, 0))
var/obj/item/device/uplink/U = find_syndicate_uplink()
if(U)
var/crystals = input("Amount of telecrystals for [key]","Syndicate uplink", U.telecrystals) as null|num
var/crystals = input("Amount of telecrystals for [key]","Syndicate uplink", U.telecrystals) as null | num
if(!isnull(crystals))
U.telecrystals = crystals
message_admins("[key_name_admin(usr)] changed [current]'s telecrystal count to [crystals].")
@@ -1348,6 +1361,7 @@
if(!(src in SSticker.mode.syndicates))
SSticker.mode.syndicates += src
SSticker.mode.update_synd_icons_added(src)
assigned_role = "Syndicate"
special_role = "Syndicate"
SSticker.mode.forge_syndicate_objectives(src)
SSticker.mode.greet_syndicate(src)
@@ -1585,7 +1599,7 @@
/mob/living/carbon/human/mind_initialize()
..()
if(!mind.assigned_role)
mind.assigned_role = "Assistant" //defualt
mind.assigned_role = "Unassigned" //default
//XENO
/mob/living/carbon/alien/mind_initialize()

View File

@@ -18,6 +18,7 @@
name = "Asteroid 1"
description = "I-spy with my little eye, something beginning with R."
/datum/map_template/ruin/space/asteroid2
id = "asteroid2"
suffix = "asteroid2.dmm"
@@ -247,4 +248,10 @@
id = "miracle"
suffix = "miracle.dmm"
name = "Ordinary Space Tile"
description = "Absolutely nothing strange going on here please move along, plenty more space to see right this way!"
description = "Absolutely nothing strange going on here please move along, plenty more space to see right this way!"
/datum/map_template/ruin/space/gondoland
id = "gondolaasteroid"
suffix = "gondolaasteroid.dmm"
name = "Gondoland"
description = "Just an ordinary rock- wait, what's that thing?"

View File

@@ -4,6 +4,7 @@
status_type = STATUS_EFFECT_UNIQUE
alert_type = /obj/screen/alert/status_effect/freon
var/icon/cube
var/can_melt = TRUE
/obj/screen/alert/status_effect/freon
name = "Frozen Solid"
@@ -20,7 +21,7 @@
/datum/status_effect/freon/tick()
owner.update_canmove()
if(owner && owner.bodytemperature >= 310.055)
if(can_melt && owner.bodytemperature >= 310.055)
qdel(src)
/datum/status_effect/freon/on_remove()
@@ -29,3 +30,7 @@
owner.cut_overlay(cube)
owner.bodytemperature += 100
owner.update_canmove()
/datum/status_effect/freon/watcher
duration = 8
can_melt = FALSE

View File

@@ -29,6 +29,7 @@
var/list/priority_overlays //overlays that should remain on top and not normally removed when using cut_overlay functions, like c4.
var/datum/proximity_monitor/proximity_monitor
var/buckle_message_cooldown = 0
/atom/New(loc, ...)
//atom creation method that preloads variables at creation
@@ -291,7 +292,10 @@
else
to_chat(user, "Nothing.")
/atom/proc/relaymove()
/atom/proc/relaymove(mob/user)
if(buckle_message_cooldown <= world.time)
buckle_message_cooldown = world.time + 50
to_chat(user, "<span class='warning'>You can't move while buckled to [src]!</span>")
return
/atom/proc/contents_explosion(severity, target)
@@ -300,6 +304,7 @@
/atom/proc/ex_act(severity, target)
set waitfor = FALSE
contents_explosion(severity, target)
SendSignal(COMSIG_ATOM_EX_ACT, severity, target)
/atom/proc/blob_act(obj/structure/blob/B)
return
@@ -464,8 +469,8 @@ GLOBAL_LIST_EMPTY(blood_splatter_icons)
/atom/proc/singularity_act()
return
/atom/proc/singularity_pull()
return
/atom/proc/singularity_pull(obj/singularity/S, current_size)
SendSignal(COMSIG_ATOM_SING_PULL, S, current_size)
/atom/proc/acid_act(acidpwr, acid_volume)
return
@@ -609,10 +614,10 @@ GLOBAL_LIST_EMPTY(blood_splatter_icons)
. += "---"
var/turf/curturf = get_turf(src)
if (curturf)
.["Jump to"] = "?_src_=holder;adminplayerobservecoodjump=1;X=[curturf.x];Y=[curturf.y];Z=[curturf.z]"
.["Add reagent"] = "?_src_=vars;addreagent=\ref[src]"
.["Trigger EM pulse"] = "?_src_=vars;emp=\ref[src]"
.["Trigger explosion"] = "?_src_=vars;explode=\ref[src]"
.["Jump to"] = "?_src_=holder;[HrefToken()];adminplayerobservecoodjump=1;X=[curturf.x];Y=[curturf.y];Z=[curturf.z]"
.["Add reagent"] = "?_src_=vars;[HrefToken()];addreagent=\ref[src]"
.["Trigger EM pulse"] = "?_src_=vars;[HrefToken()];emp=\ref[src]"
.["Trigger explosion"] = "?_src_=vars;[HrefToken()];explode=\ref[src]"
/atom/proc/drop_location()
var/atom/L = loc

View File

@@ -1,11 +1,4 @@
#ifndef PIXEL_SCALE
#define PIXEL_SCALE 0
#if DM_VERSION >= 512
#error HEY, PIXEL_SCALE probably exists now, remove this gross ass shim.
#endif
#endif
/atom/movable
layer = OBJ_LAYER
var/last_move = null
@@ -222,7 +215,7 @@
//to differentiate it, naturally everyone forgot about this immediately and so some things
//would bump twice, so now it's called Collide
/atom/movable/proc/Collide(atom/A)
if((A))
if(A)
if(throwing)
throwing.hit_atom(A)
. = 1
@@ -504,7 +497,7 @@
/atom/movable/vv_get_dropdown()
. = ..()
. -= "Jump to"
.["Follow"] = "?_src_=holder;adminplayerobservefollow=\ref[src]"
.["Follow"] = "?_src_=holder;[HrefToken()];adminplayerobservefollow=\ref[src]"
/atom/movable/proc/ex_check(ex_id)
if(!ex_id)

View File

@@ -108,6 +108,7 @@
new_objective.explanation_text = "Protect [usr.real_name], the wizard."
M.mind.objectives += new_objective
SSticker.mode.apprentices += M.mind
M.mind.assigned_role = "Apprentice"
M.mind.special_role = "apprentice"
SSticker.mode.update_wiz_icons_added(M.mind)
SEND_SOUND(M, sound('sound/effects/magic.ogg'))

View File

@@ -0,0 +1,9 @@
diff a/code/game/gamemodes/antag_spawner.dm b/code/game/gamemodes/antag_spawner.dm (rejected hunks)
@@ -108,6 +108,7 @@
new_objective.explanation_text = "Protect [usr.real_name], the wizard."
M.mind.objectives += new_objective
SSticker.mode.apprentices += M.mind
+ M.mind.assigned_role = "Apprentice"
M.mind.special_role = "apprentice"
SSticker.mode.update_wiz_icons_added(M.mind)
M << sound('sound/effects/magic.ogg')

View File

@@ -7,11 +7,9 @@
brute_resist = 0.25
explosion_block = 3
point_return = 4
atmosblock = 1
atmosblock = TRUE
armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 90, acid = 90)
/obj/structure/blob/shield/scannerreport()
if(atmosblock)
return "Will prevent the spread of atmospheric changes."
@@ -26,10 +24,10 @@
icon_state = "blob_shield_damaged"
name = "weakened strong blob"
desc = "A wall of twitching tendrils."
atmosblock = 0
atmosblock = FALSE
else
icon_state = initial(icon_state)
name = initial(name)
desc = initial(desc)
atmosblock = 1
air_update_turf(1)
atmosblock = TRUE
air_update_turf(1)

View File

@@ -363,7 +363,7 @@
to_chat(src, "<i>Node Blobs</i> are blobs which grow, like the core. Like the core it can activate resource and factory blobs.")
to_chat(src, "<b>In addition to the buttons on your HUD, there are a few click shortcuts to speed up expansion and defense.</b>")
to_chat(src, "<b>Shortcuts:</b> Click = Expand Blob <b>|</b> Middle Mouse Click = Rally Spores <b>|</b> Ctrl Click = Create Shield Blob <b>|</b> Alt Click = Remove Blob")
to_chat(src, "Attempting to talk will send a message to all other GLOB.overminds, allowing you to coordinate with them.")
to_chat(src, "Attempting to talk will send a message to all other overminds, allowing you to coordinate with them.")
if(!placed && autoplace_max_time <= world.time)
to_chat(src, "<span class='big'><font color=\"#EE4000\">You will automatically place your blob core in [round((autoplace_max_time - world.time)/600, 0.5)] minutes.</font></span>")
to_chat(src, "<span class='big'><font color=\"#EE4000\">You [manualplace_min_time ? "will be able to":"can"] manually place your blob core by pressing the Place Blob Core button in the bottom right corner of the screen.</font></span>")

View File

@@ -8,6 +8,7 @@
opacity = 0
anchored = TRUE
layer = BELOW_MOB_LAYER
CanAtmosPass = ATMOS_PASS_PROC
var/point_return = 0 //How many points the blob gets back when it removes a blob of that type. If less than 0, blob cannot be removed.
max_integrity = 30
armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 80, acid = 70)
@@ -16,19 +17,9 @@
var/heal_timestamp = 0 //we got healed when?
var/brute_resist = 0.5 //multiplies brute damage by this
var/fire_resist = 1 //multiplies burn damage by this
var/atmosblock = 0 //if the blob blocks atmos and heat spread
var/atmosblock = FALSE //if the blob blocks atmos and heat spread
var/mob/camera/blob/overmind
/obj/structure/blob/attack_hand(mob/M)
. = ..()
M.changeNext_move(CLICK_CD_MELEE)
var/a = pick("gently stroke", "nuzzle", "affectionatly pet", "cuddle")
M.visible_message("<span class='notice'>[M] [a]s [src]!</span>", "<span class='notice'>You [a] [src]!</span>")
to_chat(overmind, "<span class='notice'>[M] [a]s you!</span>")
playsound(src, 'sound/effects/blobattack.ogg', 50, 1) //SQUISH SQUISH
/obj/structure/blob/Initialize()
var/area/Ablob = get_area(loc)
if(Ablob.blob_allowed) //Is this area allowed for winning as blob?
@@ -37,17 +28,16 @@
setDir(pick(GLOB.cardinals))
update_icon()
.= ..()
ConsumeTile()
if(atmosblock)
CanAtmosPass = ATMOS_PASS_NO
air_update_turf(1)
ConsumeTile()
/obj/structure/blob/proc/creation_action() //When it's created by the overmind, do this.
return
/obj/structure/blob/Destroy()
if(atmosblock)
atmosblock = 0
atmosblock = FALSE
air_update_turf(1)
GLOB.blobs_legit -= src //if it was in the legit blobs list, it isn't now
GLOB.blobs -= src //it's no longer in the all blobs list either
@@ -79,6 +69,9 @@
return 1
return 0
/obj/structure/blob/CanAtmosPass(turf/T)
return !atmosblock
/obj/structure/blob/CanAStarPass(ID, dir, caller)
. = 0
if(ismovableatom(caller))
@@ -97,8 +90,10 @@
/obj/structure/blob/proc/Life()
return
/obj/structure/blob/proc/Pulse_Area(pulsing_overmind = overmind, claim_range = 10, pulse_range = 3, expand_range = 2)
src.Be_Pulsed()
/obj/structure/blob/proc/Pulse_Area(mob/camera/blob/pulsing_overmind, claim_range = 10, pulse_range = 3, expand_range = 2)
if(QDELETED(pulsing_overmind))
pulsing_overmind = overmind
Be_Pulsed()
var/expanded = FALSE
if(prob(70) && expand())
expanded = TRUE
@@ -353,4 +348,4 @@
icon_state = "blob"
name = "blob"
desc = "A thick wall of writhing tendrils."
brute_resist = 0.25
brute_resist = 0.25

View File

@@ -1,4 +1,4 @@
//Augmented Eyesight: Gives you thermal and night vision - bye bye, flashlights. Also, high DNA cost because of how powerful it is.
//Augmented Eyesight: Gives you x-ray vision or protection from flashes. Also, high DNA cost because of how powerful it is.
//Possible todo: make a custom message for directing a penlight/flashlight at the eyes - not sure what would display though.
/obj/effect/proc_holder/changeling/augmented_eyesight
@@ -7,21 +7,31 @@
helptext = "Grants us thermal vision or flash protection. We will become a lot more vulnerable to flash-based devices while thermal vision is active."
chemical_cost = 0
dna_cost = 2 //Would be 1 without thermal vision
active = 0 //Whether or not vision is enhanced
active = FALSE
/obj/effect/proc_holder/changeling/augmented_eyesight/on_purchase(mob/user) //The ability starts inactive, so we should be protected from flashes.
var/obj/item/organ/eyes/E = user.getorganslot("eye_sight")
if (E)
E.flash_protect = 2 //Adjust the user's eyes' flash protection
to_chat(user, "We adjust our eyes to protect them from bright lights.")
else
to_chat(user, "We can't adjust our eyes if we don't have any!")
/obj/effect/proc_holder/changeling/augmented_eyesight/sting_action(mob/living/carbon/human/user)
if(!istype(user))
return
var/obj/item/organ/eyes/E = user.getorganslot("eye_sight")
if(E)
if(E.flash_protect)
E.sight_flags |= SEE_MOBS
E.flash_protect = -1
if(!active)
E.sight_flags |= SEE_MOBS | SEE_OBJS | SEE_TURFS //Add sight flags to the user's eyes
E.flash_protect = -1 //Adjust the user's eyes' flash protection
to_chat(user, "We adjust our eyes to sense prey through walls.")
active = TRUE //Defined in code/modules/spells/spell.dm
else
E.sight_flags -= SEE_MOBS
E.flash_protect = 2
E.sight_flags ^= SEE_MOBS | SEE_OBJS | SEE_TURFS //Remove sight flags from the user's eyes
E.flash_protect = 2 //Adjust the user's eyes' flash protection
to_chat(user, "We adjust our eyes to protect them from bright lights.")
active = FALSE
user.update_sight()
else
to_chat(user, "We can't adjust our eyes if we don't have any!")
@@ -31,7 +41,11 @@
return 1
/obj/effect/proc_holder/changeling/augmented_eyesight/on_refund(mob/user)
/obj/effect/proc_holder/changeling/augmented_eyesight/on_refund(mob/user) //Get rid of x-ray vision and flash protection when the user refunds this ability
var/obj/item/organ/eyes/E = user.getorganslot("eye_sight")
if(E)
E.sight_flags -= SEE_MOBS
if (active)
E.sight_flags ^= SEE_MOBS | SEE_OBJS | SEE_TURFS
else
E.flash_protect = 0
user.update_sight()

View File

@@ -247,7 +247,7 @@
/obj/item/gun/magic/tentacle/shoot_with_empty_chamber(mob/living/user as mob|obj)
to_chat(user, "<span class='warning'>The [name] is not ready yet.<span>")
to_chat(user, "<span class='warning'>The [name] is not ready yet.</span>")
/obj/item/gun/magic/tentacle/suicide_act(mob/user)
user.visible_message("<span class='suicide'>[user] coils [src] tightly around [user.p_their()] neck! It looks like [user.p_theyre()] trying to commit suicide!</span>")
@@ -343,10 +343,10 @@
on_hit(I) //grab the item as if you had hit it directly with the tentacle
return 1
else
to_chat(firer, "<span class='danger'>You can't seem to pry [I] off [C]'s hands!<span>")
to_chat(firer, "<span class='danger'>You can't seem to pry [I] off [C]'s hands!</span>")
return 0
else
to_chat(firer, "<span class='danger'>[C] has nothing in hand to disarm!<span>")
to_chat(firer, "<span class='danger'>[C] has nothing in hand to disarm!</span>")
return 0
if(INTENT_GRAB)

View File

@@ -73,7 +73,7 @@
if(!selected_dna)
return
if(NOTRANSSTING in selected_dna.dna.species.species_traits)
to_chat(user, "<span class = 'notice'>That DNA is not compatible with changeling retrovirus!")
to_chat(user, "<span class = 'notice'>That DNA is not compatible with changeling retrovirus!</span>")
return
..()

View File

@@ -26,8 +26,8 @@
to_chat(user, "<span class='inathneq'>An emergency shuttle has arrived and this prism is no longer useful; attempt to activate it to gain a partial refund of components used.</span>")
else
var/efficiency = get_efficiency_mod(TRUE)
to_chat(user, "<span class='inathneq_small'>It requires at least <b>[get_delay_cost()]W</b> of power to attempt to delay the arrival of an emergency shuttle by <b>[2 * efficiency]</b> minutes.</span>")
to_chat(user, "<span class='inathneq_small'>This cost increases by <b>[delay_cost_increase]W</b> for every previous activation.</span>")
to_chat(user, "<span class='inathneq_small'>It requires at least <b>[DisplayPower(get_delay_cost())]</b> of power to attempt to delay the arrival of an emergency shuttle by <b>[2 * efficiency]</b> minutes.</span>")
to_chat(user, "<span class='inathneq_small'>This cost increases by <b>[DisplayPower(delay_cost_increase)]</b> for every previous activation.</span>")
/obj/structure/destructible/clockwork/powered/prolonging_prism/forced_disable(bad_effects)
if(active)
@@ -126,7 +126,7 @@
if(!hex_combo)
hex_combo = mutable_appearance('icons/effects/64x64.dmi', n, RIPPLE_LAYER)
else
hex_combo.overlays += mutable_appearance('icons/effects/64x64.dmi', n, RIPPLE_LAYER)
hex_combo.add_overlay(mutable_appearance('icons/effects/64x64.dmi', n, RIPPLE_LAYER))
if(hex_combo) //YOU BUILT A HEXAGON
hex_combo.pixel_x = -16
hex_combo.pixel_y = -16

View File

@@ -144,7 +144,7 @@
to_chat(mob, "<span class='userdanger'>Unfortunately, you weren't able to get a [item_name]. This is very bad and you should adminhelp immediately (press F1).</span>")
return 0
else
to_chat(mob, "<span class='danger'>You have a [item_name] in your [where].")
to_chat(mob, "<span class='danger'>You have a [item_name] in your [where].</span>")
if(where == "backpack")
var/obj/item/storage/B = mob.back
B.orient2hud(mob)

View File

@@ -118,7 +118,7 @@
if(B.current)
B.current.update_action_buttons_icon()
if(!B.current.incapacitated())
to_chat(B.current,"<span class='cultlarge'>[Nominee] has died in the process of attempting to win the cult's support!")
to_chat(B.current,"<span class='cultlarge'>[Nominee] has died in the process of attempting to win the cult's support!</span>")
return FALSE
if(!Nominee.mind)
GLOB.cult_vote_called = FALSE
@@ -126,7 +126,7 @@
if(B.current)
B.current.update_action_buttons_icon()
if(!B.current.incapacitated())
to_chat(B.current,"<span class='cultlarge'>[Nominee] has gone catatonic in the process of attempting to win the cult's support!")
to_chat(B.current,"<span class='cultlarge'>[Nominee] has gone catatonic in the process of attempting to win the cult's support!</span>")
return FALSE
if(LAZYLEN(yes_voters) <= LAZYLEN(asked_cultists) * 0.5)
GLOB.cult_vote_called = FALSE
@@ -134,7 +134,7 @@
if(B.current)
B.current.update_action_buttons_icon()
if(!B.current.incapacitated())
to_chat(B.current, "<span class='cultlarge'>[Nominee] could not win the cult's support and shall continue to serve as an acolyte.")
to_chat(B.current, "<span class='cultlarge'>[Nominee] could not win the cult's support and shall continue to serve as an acolyte.</span>")
return FALSE
GLOB.cult_mastered = TRUE
SSticker.mode.remove_cultist(Nominee.mind, TRUE)
@@ -144,7 +144,7 @@
for(var/datum/action/innate/cult/mastervote/vote in B.current.actions)
vote.Remove(B.current)
if(!B.current.incapacitated())
to_chat(B.current,"<span class='cultlarge'>[Nominee] has won the cult's support and is now their master. Follow [Nominee.p_their()] orders to the best of your ability!")
to_chat(B.current,"<span class='cultlarge'>[Nominee] has won the cult's support and is now their master. Follow [Nominee.p_their()] orders to the best of your ability!</span>")
return TRUE
/datum/action/innate/cult/master/IsAvailable()

Some files were not shown because too many files have changed in this diff Show More