Merge branch 'master' of https://github.com/Verkister/Citadel-Station-13
This commit is contained in:
@@ -23,6 +23,7 @@
|
||||
#define WACKY "Wacky"
|
||||
#define MUT_MUTE "Mute"
|
||||
#define SMILE "Smile"
|
||||
#define STONER "Stoner"
|
||||
#define UNINTELLIGABLE "Unintelligable"
|
||||
#define SWEDISH "Swedish"
|
||||
#define CHAV "Chav"
|
||||
@@ -81,9 +82,6 @@
|
||||
#define DNA_MUTANTTAIL_BLOCK 17
|
||||
#define DNA_MUTANTWING_BLOCK 18
|
||||
#define DNA_WINGCOLOR_BLOCK 19
|
||||
//#define DNA_SUBSPECIES_BLOCK 20
|
||||
//#define DNA_TAUR_BLOCK 21 //Taurs will be tails for now, easier - Pooj
|
||||
|
||||
#define DNA_STRUC_ENZYMES_BLOCKS 19
|
||||
#define DNA_UNIQUE_ENZYMES_LEN 32
|
||||
|
||||
@@ -128,9 +126,9 @@
|
||||
#define EASYLIMBATTACHMENT 23
|
||||
#define TOXINLOVER 24
|
||||
#define DIGITIGRADE 25 //Uses weird leg sprites. Optional for Lizards, required for ashwalkers. Don't give it to other races unless you make sprites for this (see human_parts_greyscale.dmi)
|
||||
#define MUTCOLORS2 26
|
||||
#define MUTCOLORS3 27
|
||||
#define NO_UNDERWEAR 26
|
||||
#define MUTCOLORS2 27
|
||||
#define MUTCOLORS3 28
|
||||
//citadel code
|
||||
#define NOAROUSAL 28//Stops all arousal effects
|
||||
#define NOGENITALS 29//Cannot create, use, or otherwise have genitals
|
||||
//#define SUBSPECIES 28
|
||||
#define NOAROUSAL 29//Stops all arousal effects
|
||||
#define NOGENITALS 30//Cannot create, use, or otherwise have genitals
|
||||
+16
-15
@@ -1,18 +1,22 @@
|
||||
#define MC_TICK_CHECK ( ( world.tick_usage > GLOB.CURRENT_TICKLIMIT || src.state != SS_RUNNING ) ? pause() : 0 )
|
||||
#define MC_TICK_CHECK ( ( world.tick_usage > Master.current_ticklimit || src.state != SS_RUNNING ) ? pause() : 0 )
|
||||
|
||||
#define MC_SPLIT_TICK_INIT(phase_count) var/original_tick_limit = GLOB.CURRENT_TICKLIMIT; var/split_tick_phases = ##phase_count
|
||||
#define MC_SPLIT_TICK_INIT(phase_count) var/original_tick_limit = Master.current_ticklimit; var/split_tick_phases = ##phase_count
|
||||
#define MC_SPLIT_TICK \
|
||||
if(split_tick_phases > 1){\
|
||||
GLOB.CURRENT_TICKLIMIT = ((original_tick_limit - world.tick_usage) / split_tick_phases) + world.tick_usage;\
|
||||
Master.current_ticklimit = ((original_tick_limit - world.tick_usage) / split_tick_phases) + world.tick_usage;\
|
||||
--split_tick_phases;\
|
||||
} else {\
|
||||
GLOB.CURRENT_TICKLIMIT = original_tick_limit;\
|
||||
Master.current_ticklimit = original_tick_limit;\
|
||||
}
|
||||
|
||||
// Used to smooth out costs to try and avoid oscillation.
|
||||
#define MC_AVERAGE_FAST(average, current) (0.7 * (average) + 0.3 * (current))
|
||||
#define MC_AVERAGE(average, current) (0.8 * (average) + 0.2 * (current))
|
||||
#define MC_AVERAGE_SLOW(average, current) (0.9 * (average) + 0.1 * (current))
|
||||
|
||||
#define MC_AVG_FAST_UP_SLOW_DOWN(average, current) (average > current ? MC_AVERAGE_SLOW(average, current) : MC_AVERAGE_FAST(average, current))
|
||||
#define MC_AVG_SLOW_UP_FAST_DOWN(average, current) (average < current ? MC_AVERAGE_SLOW(average, current) : MC_AVERAGE_FAST(average, current))
|
||||
|
||||
#define NEW_SS_GLOBAL(varname) if(varname != src){if(istype(varname)){Recover();qdel(varname);}varname = src;}
|
||||
|
||||
#define START_PROCESSING(Processor, Datum) if (!Datum.isprocessing) {Datum.isprocessing = 1;Processor.processing += Datum}
|
||||
@@ -20,39 +24,36 @@
|
||||
|
||||
//SubSystem flags (Please design any new flags so that the default is off, to make adding flags to subsystems easier)
|
||||
|
||||
//subsystem should fire during pre-game lobby.
|
||||
#define SS_FIRE_IN_LOBBY 1
|
||||
|
||||
//subsystem does not initialize.
|
||||
#define SS_NO_INIT 2
|
||||
#define SS_NO_INIT 1
|
||||
|
||||
//subsystem does not fire.
|
||||
// (like can_fire = 0, but keeps it from getting added to the processing subsystems list)
|
||||
// (Requires a MC restart to change)
|
||||
#define SS_NO_FIRE 4
|
||||
#define SS_NO_FIRE 2
|
||||
|
||||
//subsystem only runs on spare cpu (after all non-background subsystems have ran that tick)
|
||||
// SS_BACKGROUND has its own priority bracket
|
||||
#define SS_BACKGROUND 8
|
||||
#define SS_BACKGROUND 4
|
||||
|
||||
//subsystem does not tick check, and should not run unless there is enough time (or its running behind (unless background))
|
||||
#define SS_NO_TICK_CHECK 16
|
||||
#define SS_NO_TICK_CHECK 8
|
||||
|
||||
//Treat wait as a tick count, not DS, run every wait ticks.
|
||||
// (also forces it to run first in the tick, above even SS_NO_TICK_CHECK subsystems)
|
||||
// (implies SS_FIRE_IN_LOBBY because of how it works)
|
||||
// (implies all runlevels because of how it works)
|
||||
// (overrides SS_BACKGROUND)
|
||||
// This is designed for basically anything that works as a mini-mc (like SStimer)
|
||||
#define SS_TICKER 32
|
||||
#define SS_TICKER 16
|
||||
|
||||
//keep the subsystem's timing on point by firing early if it fired late last fire because of lag
|
||||
// ie: if a 20ds subsystem fires say 5 ds late due to lag or what not, its next fire would be in 15ds, not 20ds.
|
||||
#define SS_KEEP_TIMING 64
|
||||
#define SS_KEEP_TIMING 32
|
||||
|
||||
//Calculate its next fire after its fired.
|
||||
// (IE: if a 5ds wait SS takes 2ds to run, its next fire should be 5ds away, not 3ds like it normally would be)
|
||||
// This flag overrides SS_KEEP_TIMING
|
||||
#define SS_POST_FIRE_TIMING 128
|
||||
#define SS_POST_FIRE_TIMING 64
|
||||
|
||||
//SUBSYSTEM STATES
|
||||
#define SS_IDLE 0 //aint doing shit.
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
#define ANTAG_DATUM_CULT /datum/antagonist/cult
|
||||
#define ANTAG_DATUM_CULT_MASTER /datum/antagonist/cult/master
|
||||
#define ANTAG_DATUM_CLOCKCULT /datum/antagonist/clockcult
|
||||
#define ANTAG_DATUM_CLOCKCULT_SILENT /datum/antagonist/clockcult/silent
|
||||
#define ANTAG_DATUM_DEVIL /datum/antagonist/devil
|
||||
#define ANTAG_DATUM_NINJA /datum/antagonist/ninja
|
||||
#define ANTAG_DATUM_NINJA_FRIENDLY /datum/antagonist/ninja/friendly
|
||||
#define ANTAG_DATUM_NINJA_RANDOM /datum/antagonist/ninja/randomAllegiance/
|
||||
@@ -14,8 +14,9 @@
|
||||
#define GAS_META 3
|
||||
#define META_GAS_SPECIFIC_HEAT 1
|
||||
#define META_GAS_NAME 2
|
||||
#define META_GAS_OVERLAY 4
|
||||
#define META_GAS_MOLES_VISIBLE 3
|
||||
#define META_GAS_OVERLAY 4
|
||||
#define META_GAS_DANGER 5
|
||||
|
||||
//stuff you should probably leave well alone!
|
||||
//ATMOS
|
||||
@@ -169,4 +170,4 @@
|
||||
#define ATMOS_PASS_NO 0
|
||||
#define ATMOS_PASS_PROC -1 //ask CanAtmosPass()
|
||||
#define ATMOS_PASS_DENSITY -2 //just check density
|
||||
#define CANATMOSPASS(A, O) ( A.CanAtmosPass == ATMOS_PASS_PROC ? A.CanAtmosPass(O) : ( A.CanAtmosPass == ATMOS_PASS_DENSITY ? !A.density : A.CanAtmosPass ) )
|
||||
#define CANATMOSPASS(A, O) ( A.CanAtmosPass == ATMOS_PASS_PROC ? A.CanAtmosPass(O) : ( A.CanAtmosPass == ATMOS_PASS_DENSITY ? !A.density : A.CanAtmosPass ) )
|
||||
|
||||
+10
-10
@@ -37,15 +37,15 @@ GLOBAL_LIST_EMPTY(all_scripture) //a list containing scripture instances; not us
|
||||
#define JUDGEMENT_CV_REQ 300
|
||||
|
||||
//general component/cooldown things
|
||||
#define SLAB_PRODUCTION_TIME 900 //how long(deciseconds) slabs require to produce a single component; defaults to 1 minute 30 seconds
|
||||
#define SLAB_PRODUCTION_TIME 450 //how long(deciseconds) slabs require to produce a single component; defaults to 45 seconds
|
||||
|
||||
#define SLAB_SERVANT_SLOWDOWN 300 //how much each servant above 5 slows down slab-based generation; defaults to 30 seconds per sevant
|
||||
#define SLAB_SERVANT_SLOWDOWN 150 //how much each servant above 5 slows down slab-based generation; defaults to 15 seconds per sevant
|
||||
|
||||
#define SLAB_SLOWDOWN_MAXIMUM 2700 //maximum slowdown from additional servants; defaults to 4 minutes 30 seconds
|
||||
#define SLAB_SLOWDOWN_MAXIMUM 1350 //maximum slowdown from additional servants; defaults to 2 minutes 15 seconds
|
||||
|
||||
#define CACHE_PRODUCTION_TIME 600 //how long(deciseconds) caches require to produce a component; defaults to 1 minute
|
||||
#define CACHE_PRODUCTION_TIME 300 //how long(deciseconds) caches require to produce a component; defaults to 30 seconds
|
||||
|
||||
#define ACTIVE_CACHE_SLOWDOWN 100 //how many additional deciseconds caches take to produce a component for each linked cache; defaults to 10 seconds
|
||||
#define ACTIVE_CACHE_SLOWDOWN 50 //how many additional deciseconds caches take to produce a component for each linked cache; defaults to 5 seconds
|
||||
|
||||
#define LOWER_PROB_PER_COMPONENT 10 //how much each component in the cache reduces the weight of getting another of that component type
|
||||
|
||||
@@ -58,7 +58,7 @@ GLOBAL_LIST_EMPTY(all_scripture) //a list containing scripture instances; not us
|
||||
//clockcult power defines
|
||||
#define MIN_CLOCKCULT_POWER 25 //the minimum amount of power clockcult machines will handle gracefully
|
||||
|
||||
#define CLOCKCULT_POWER_UNIT (MIN_CLOCKCULT_POWER*100) //standard power amount for clockwork proselytizer costs
|
||||
#define CLOCKCULT_POWER_UNIT (MIN_CLOCKCULT_POWER*100) //standard power amount for replica fabricator costs
|
||||
|
||||
#define POWER_STANDARD (CLOCKCULT_POWER_UNIT*0.2) //how much power is in anything else; doesn't matter as much as the following
|
||||
|
||||
@@ -76,7 +76,7 @@ GLOBAL_LIST_EMPTY(all_scripture) //a list containing scripture instances; not us
|
||||
|
||||
#define POWER_PLASTEEL (CLOCKCULT_POWER_UNIT*0.05) //how much power is in one sheet of plasteel
|
||||
|
||||
#define RATVAR_POWER_CHECK "ratvar?" //when passed into can_use_power(), converts it into a check for if ratvar has woken/the proselytizer is debug
|
||||
#define RATVAR_POWER_CHECK "ratvar?" //when passed into can_use_power(), converts it into a check for if ratvar has woken/the fabricator is debug
|
||||
|
||||
//Ark defines
|
||||
#define GATEWAY_SUMMON_RATE 1 //the time amount the Gateway to the Celestial Derelict gets each process tick; defaults to 1 per tick
|
||||
@@ -87,9 +87,9 @@ GLOBAL_LIST_EMPTY(all_scripture) //a list containing scripture instances; not us
|
||||
|
||||
#define GATEWAY_RATVAR_ARRIVAL 300 //when progress is at or above this, game over ratvar's here everybody go home
|
||||
|
||||
#define ARK_SUMMON_COST 3 //how many of each component an Ark costs to summon
|
||||
#define ARK_SUMMON_COST 5 //how many of each component an Ark costs to summon
|
||||
|
||||
#define ARK_CONSUME_COST 7 //how many of each component an Ark needs to consume to activate
|
||||
#define ARK_CONSUME_COST 15 //how many of each component an Ark needs to consume to activate
|
||||
|
||||
//Objective text define
|
||||
#define CLOCKCULT_OBJECTIVE "Construct the Ark of the Clockwork Justicar and free Ratvar."
|
||||
@@ -99,7 +99,7 @@ GLOBAL_LIST_EMPTY(all_scripture) //a list containing scripture instances; not us
|
||||
|
||||
#define SIGIL_ACCESS_RANGE 2 //range at which transmission sigils can access power
|
||||
|
||||
#define PROSELYTIZER_REPAIR_PER_TICK 4 //how much a proselytizer repairs each tick, and also how many deciseconds each tick is
|
||||
#define FABRICATOR_REPAIR_PER_TICK 4 //how much a fabricator repairs each tick, and also how many deciseconds each tick is
|
||||
|
||||
#define OCULAR_WARDEN_EXCLUSION_RANGE 3 //the range at which ocular wardens cannot be placed near other ocular wardens
|
||||
|
||||
|
||||
@@ -95,11 +95,13 @@
|
||||
|
||||
//tablecrafting defines
|
||||
#define CAT_NONE ""
|
||||
#define CAT_WEAPON "Weaponry"
|
||||
#define CAT_WEAPONRY "Weaponry"
|
||||
#define CAT_WEAPON "Weapons"
|
||||
#define CAT_AMMO "Ammunition"
|
||||
#define CAT_ROBOT "Robots"
|
||||
#define CAT_MISC "Misc"
|
||||
#define CAT_PRIMAL "Tribal"
|
||||
#define CAT_FOOD "Foods"
|
||||
#define CAT_BREAD "Breads"
|
||||
#define CAT_BURGER "Burgers"
|
||||
#define CAT_CAKE "Cakes"
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#define CONTRACT_PRESTIGE "prestige"
|
||||
#define CONTRACT_MAGIC "magic"
|
||||
#define CONTRACT_REVIVE "revive"
|
||||
#define CONTRACT_FRIEND "friend"
|
||||
#define CONTRACT_KNOWLEDGE "knowledge"
|
||||
#define CONTRACT_UNWILLING "unwilling"
|
||||
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
//rune colors, for easy reference
|
||||
#define RUNE_COLOR_TALISMAN "#0000FF"
|
||||
#define RUNE_COLOR_TELEPORT "#551A8B"
|
||||
#define RUNE_COLOR_OFFER "#FFFFFF"
|
||||
#define RUNE_COLOR_DARKRED "#7D1717"
|
||||
#define RUNE_COLOR_MEDIUMRED "#C80000"
|
||||
#define RUNE_COLOR_RED "#FF0000"
|
||||
#define RUNE_COLOR_EMP "#4D94FF"
|
||||
#define RUNE_COLOR_SUMMON "#00FF00"
|
||||
@@ -4,6 +4,8 @@
|
||||
#define ALL ~0 //For convenience.
|
||||
#define NONE 0
|
||||
|
||||
GLOBAL_LIST_INIT(bitflags, list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768))
|
||||
|
||||
//FLAGS BITMASK
|
||||
#define STOPSPRESSUREDMAGE 1 //This flag is used on the flags variable for SUIT and HEAD items which stop pressure damage. Note that the flag 1 was previous used as ONBACK, so it is possible for some code to use (flags & 1) when checking if something can be put on your back. Replace this code with (inv_flags & SLOT_BACK) if you see it anywhere
|
||||
//To successfully stop you taking all pressure damage you must have both a suit and head item with this flag.
|
||||
@@ -12,6 +14,7 @@
|
||||
#define NOBLUDGEON 4 // when an item has this it produces no "X has been hit by Y with Z" message in the default attackby()
|
||||
#define MASKINTERNALS 8 // mask allows internals
|
||||
#define HEAR 16 // This flag is what recursive_hear_check() uses to determine wether to add an item to the hearer list or not.
|
||||
#define CHECK_RICOCHET 32 // Projectiels will check ricochet on things impacted that have this.
|
||||
#define CONDUCT 64 // conducts electricity (metal etc.)
|
||||
#define ABSTRACT 128 // for all things that are technically items but used for various different stuff, made it 128 because it could conflict with other flags other way
|
||||
#define NODECONSTRUCT 128 // For machines and structures that should not break into parts, eg, holodeck stuff
|
||||
@@ -25,6 +28,7 @@
|
||||
#define BLOCK_GAS_SMOKE_EFFECT 4096 // blocks the effect that chemical clouds would have on a mob --glasses, mask and helmets ONLY!
|
||||
#define THICKMATERIAL 8192 //prevents syringes, parapens and hypos if the external suit or helmet (if targeting head) has this flag. Example: space suits, biosuit, bombsuits, thick suits that cover your body.
|
||||
#define DROPDEL 16384 // When dropped, it calls qdel on itself
|
||||
#define PREVENT_CLICK_UNDER 32768 //Prevent clicking things below it on the same turf eg. doors/ fulltile windows
|
||||
|
||||
/* Secondary atom flags, access using the SECONDARY_FLAG macros */
|
||||
|
||||
@@ -54,6 +58,7 @@
|
||||
#define UNUSED_TRANSIT_TURF 2
|
||||
#define CAN_BE_DIRTY 4 //If a turf can be made dirty at roundstart. This is also used in areas.
|
||||
#define NO_DEATHRATTLE 16 // Do not notify deadchat about any deaths that occur on this turf.
|
||||
//#define CHECK_RICOCHET 32 //Same thing as atom flag.
|
||||
|
||||
/*
|
||||
These defines are used specifically with the atom/pass_flags bitmask
|
||||
|
||||
+42
-42
@@ -1,43 +1,43 @@
|
||||
|
||||
#define ENGSEC (1<<0)
|
||||
|
||||
#define CAPTAIN (1<<0)
|
||||
#define HOS (1<<1)
|
||||
#define WARDEN (1<<2)
|
||||
#define DETECTIVE (1<<3)
|
||||
#define OFFICER (1<<4)
|
||||
#define CHIEF (1<<5)
|
||||
#define ENGINEER (1<<6)
|
||||
#define ATMOSTECH (1<<7)
|
||||
#define ROBOTICIST (1<<8)
|
||||
#define AI_JF (1<<9)
|
||||
#define CYBORG (1<<10)
|
||||
|
||||
|
||||
#define MEDSCI (1<<1)
|
||||
|
||||
#define RD_JF (1<<0)
|
||||
#define SCIENTIST (1<<1)
|
||||
#define CHEMIST (1<<2)
|
||||
#define CMO_JF (1<<3)
|
||||
#define DOCTOR (1<<4)
|
||||
#define GENETICIST (1<<5)
|
||||
#define VIROLOGIST (1<<6)
|
||||
|
||||
|
||||
#define CIVILIAN (1<<2)
|
||||
|
||||
#define HOP (1<<0)
|
||||
#define BARTENDER (1<<1)
|
||||
#define BOTANIST (1<<2)
|
||||
#define COOK (1<<3)
|
||||
#define JANITOR (1<<4)
|
||||
#define LIBRARIAN (1<<5)
|
||||
#define QUARTERMASTER (1<<6)
|
||||
#define CARGOTECH (1<<7)
|
||||
#define MINER (1<<8)
|
||||
#define LAWYER (1<<9)
|
||||
#define CHAPLAIN (1<<10)
|
||||
#define CLOWN (1<<11)
|
||||
#define MIME (1<<12)
|
||||
|
||||
#define ENGSEC (1<<0)
|
||||
|
||||
#define CAPTAIN (1<<0)
|
||||
#define HOS (1<<1)
|
||||
#define WARDEN (1<<2)
|
||||
#define DETECTIVE (1<<3)
|
||||
#define OFFICER (1<<4)
|
||||
#define CHIEF (1<<5)
|
||||
#define ENGINEER (1<<6)
|
||||
#define ATMOSTECH (1<<7)
|
||||
#define ROBOTICIST (1<<8)
|
||||
#define AI_JF (1<<9)
|
||||
#define CYBORG (1<<10)
|
||||
|
||||
|
||||
#define MEDSCI (1<<1)
|
||||
|
||||
#define RD_JF (1<<0)
|
||||
#define SCIENTIST (1<<1)
|
||||
#define CHEMIST (1<<2)
|
||||
#define CMO_JF (1<<3)
|
||||
#define DOCTOR (1<<4)
|
||||
#define GENETICIST (1<<5)
|
||||
#define VIROLOGIST (1<<6)
|
||||
|
||||
|
||||
#define CIVILIAN (1<<2)
|
||||
|
||||
#define HOP (1<<0)
|
||||
#define BARTENDER (1<<1)
|
||||
#define BOTANIST (1<<2)
|
||||
#define COOK (1<<3)
|
||||
#define JANITOR (1<<4)
|
||||
#define CURATOR (1<<5)
|
||||
#define QUARTERMASTER (1<<6)
|
||||
#define CARGOTECH (1<<7)
|
||||
#define MINER (1<<8)
|
||||
#define LAWYER (1<<9)
|
||||
#define CHAPLAIN (1<<10)
|
||||
#define CLOWN (1<<11)
|
||||
#define MIME (1<<12)
|
||||
#define ASSISTANT (1<<13)
|
||||
@@ -1,2 +1,7 @@
|
||||
#define NO_STUTTER 1
|
||||
#define TONGUELESS_SPEECH 2
|
||||
#define LANGUAGE_HIDE_ICON_IF_UNDERSTOOD 4
|
||||
#define LANGUAGE_HIDE_ICON_IF_NOT_UNDERSTOOD 8
|
||||
|
||||
#define LANGUAGE_KNOWN "language_known"
|
||||
#define LANGUAGE_SHADOWED "language_shadowed"
|
||||
|
||||
@@ -16,10 +16,10 @@
|
||||
#define LIGHTING_BASE_MATRIX \
|
||||
list \
|
||||
( \
|
||||
LIGHTING_SOFT_THRESHOLD, LIGHTING_SOFT_THRESHOLD, LIGHTING_SOFT_THRESHOLD, 0, \
|
||||
LIGHTING_SOFT_THRESHOLD, LIGHTING_SOFT_THRESHOLD, LIGHTING_SOFT_THRESHOLD, 0, \
|
||||
LIGHTING_SOFT_THRESHOLD, LIGHTING_SOFT_THRESHOLD, LIGHTING_SOFT_THRESHOLD, 0, \
|
||||
LIGHTING_SOFT_THRESHOLD, LIGHTING_SOFT_THRESHOLD, LIGHTING_SOFT_THRESHOLD, 0, \
|
||||
1, 1, 1, 0, \
|
||||
1, 1, 1, 0, \
|
||||
1, 1, 1, 0, \
|
||||
1, 1, 1, 0, \
|
||||
0, 0, 0, 1 \
|
||||
) \
|
||||
|
||||
@@ -51,8 +51,10 @@
|
||||
#define LIGHT_COLOR_GREEN "#64C864" //Bright but quickly dissipating neon green. rgb(100, 200, 100)
|
||||
#define LIGHT_COLOR_BLUE "#6496FA" //Cold, diluted blue. rgb(100, 150, 250)
|
||||
|
||||
#define LIGHT_COLOR_BLUEGREEN "#7DE1AF" //Light blueish green. rgb(125, 225, 175)
|
||||
#define LIGHT_COLOR_CYAN "#7DE1E1" //Diluted cyan. rgb(125, 225, 225)
|
||||
#define LIGHT_COLOR_LIGHT_CYAN "#40CEFF" //More-saturated cyan. rgb(64, 206, 255)
|
||||
#define LIGHT_COLOR_DARK_BLUE "#6496FA" //Saturated blue. rgb(51, 117, 248)
|
||||
#define LIGHT_COLOR_PINK "#E17DE1" //Diluted, mid-warmth pink. rgb(225, 125, 225)
|
||||
#define LIGHT_COLOR_YELLOW "#E1E17D" //Dimmed yellow, leaning kaki. rgb(225, 225, 125)
|
||||
#define LIGHT_COLOR_BROWN "#966432" //Clear brown, mostly dim. rgb(150, 100, 50)
|
||||
@@ -78,4 +80,11 @@
|
||||
#define DYNAMIC_LIGHTING_ENABLED 1 //dynamic lighting enabled
|
||||
#define DYNAMIC_LIGHTING_FORCED 2 //dynamic lighting enabled even if the area doesn't require power
|
||||
#define DYNAMIC_LIGHTING_IFSTARLIGHT 3 //dynamic lighting enabled only if starlight is.
|
||||
#define IS_DYNAMIC_LIGHTING(A) A.dynamic_lighting
|
||||
#define IS_DYNAMIC_LIGHTING(A) A.dynamic_lighting
|
||||
|
||||
|
||||
//code assumes higher numbers override lower numbers.
|
||||
#define LIGHTING_NO_UPDATE 0
|
||||
#define LIGHTING_VIS_UPDATE 1
|
||||
#define LIGHTING_CHECK_UPDATE 2
|
||||
#define LIGHTING_FORCE_UPDATE 3
|
||||
@@ -0,0 +1,18 @@
|
||||
//Investigate logging defines
|
||||
#define INVESTIGATE_ATMOS "atmos"
|
||||
#define INVESTIGATE_BOTANY "botany"
|
||||
#define INVESTIGATE_CARGO "cargo"
|
||||
#define INVESTIGATE_EXPERIMENTOR "experimentor"
|
||||
#define INVESTIGATE_GRAVITY "gravity"
|
||||
#define INVESTIGATE_RECORDS "records"
|
||||
#define INVESTIGATE_SINGULO "singulo"
|
||||
#define INVESTIGATE_SUPERMATTER "supermatter"
|
||||
#define INVESTIGATE_TELESCI "telesci"
|
||||
#define INVESTIGATE_WIRES "wires"
|
||||
|
||||
//Individual logging defines
|
||||
#define INDIVIDUAL_ATTACK_LOG "Attack log"
|
||||
#define INDIVIDUAL_SAY_LOG "Say log"
|
||||
#define INDIVIDUAL_EMOTE_LOG "Emote log"
|
||||
#define INDIVIDUAL_OOC_LOG "OOC log"
|
||||
#define INDIVIDUAL_SHOW_ALL_LOG "All logs"
|
||||
@@ -23,6 +23,7 @@
|
||||
#define MECHFAB 16 //Remember, objects utilising this flag should have construction_time and construction_cost vars.
|
||||
#define BIOGENERATOR 32 //Uses biomass
|
||||
#define LIMBGROWER 64 //Uses synthetic flesh
|
||||
#define SMELTER 128 //uses various minerals
|
||||
//Note: More then one of these can be added to a design but imprinter and lathe designs are incompatable.
|
||||
|
||||
//Modular computer/NTNet defines
|
||||
|
||||
@@ -34,8 +34,8 @@ Last space-z level = empty
|
||||
#define MAP_REMOVE_JOB(jobpath) /datum/job/##jobpath/map_check() { return (SSmapping.config.map_name != JOB_MODIFICATION_MAP_NAME) && ..() }
|
||||
|
||||
//zlevel defines, can be overridden for different maps in the appropriate _maps file.
|
||||
#define ZLEVEL_STATION 1
|
||||
#define ZLEVEL_CENTCOM 2
|
||||
#define ZLEVEL_CENTCOM 1
|
||||
#define ZLEVEL_STATION 2
|
||||
#define ZLEVEL_MINING 5
|
||||
#define ZLEVEL_LAVALAND 5
|
||||
#define ZLEVEL_EMPTY_SPACE 11
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
#define CHECKBOX_NONE 0
|
||||
#define CHECKBOX_GROUP 1
|
||||
#define CHECKBOX_TOGGLE 2
|
||||
@@ -4,6 +4,19 @@
|
||||
// #define EAST 4
|
||||
// #define WEST 8
|
||||
|
||||
//These get to go at the top, because they're special
|
||||
//You can use these defines to get the typepath of the currently running proc/verb (yes procs + verbs are objects)
|
||||
/* eg:
|
||||
/mob/living/carbon/human/death()
|
||||
world << THIS_PROC_TYPE_STR //You can only output the string versions
|
||||
Will print: "/mob/living/carbon/human/death" (you can optionally embed it in a string with () (eg: the _WITH_ARGS defines) to make it look nicer)
|
||||
*/
|
||||
#define THIS_PROC_TYPE .....
|
||||
#define THIS_PROC_TYPE_STR "[THIS_PROC_TYPE]" //Because you can only obtain a string of THIS_PROC_TYPE using "[]", and it's nice to just +/+= strings
|
||||
#define THIS_PROC_TYPE_STR_WITH_ARGS "[THIS_PROC_TYPE]([args.Join(",")])"
|
||||
#define THIS_PROC_TYPE_WEIRD ...... //This one is WEIRD, in some cases (When used in certain defines? (eg: ASSERT)) THIS_PROC_TYPE will fail to work, but THIS_PROC_TYPE_WEIRD will work instead
|
||||
#define THIS_PROC_TYPE_WEIRD_STR "[THIS_PROC_TYPE_WEIRD]" //Included for completeness
|
||||
#define THIS_PROC_TYPE_WEIRD_STR_WITH_ARGS "[THIS_PROC_TYPE_WEIRD]([args.Join(",")])" //Ditto
|
||||
|
||||
#define MIDNIGHT_ROLLOVER 864000 //number of deciseconds in a day
|
||||
|
||||
@@ -201,6 +214,21 @@ GLOBAL_LIST_EMPTY(bloody_footprints_cache)
|
||||
#define BLOOD_STATE_XENO "xeno"
|
||||
#define BLOOD_STATE_OIL "oil"
|
||||
#define BLOOD_STATE_NOT_BLOODY "no blood whatsoever"
|
||||
|
||||
//suit sensors: sensor_mode defines
|
||||
|
||||
#define SENSOR_OFF 0
|
||||
#define SENSOR_LIVING 1
|
||||
#define SENSOR_VITALS 2
|
||||
#define SENSOR_COORDS 3
|
||||
|
||||
//suit sensors: has_sensor defines
|
||||
|
||||
#define BROKEN_SENSORS -1
|
||||
#define NO_SENSORS 0
|
||||
#define HAS_SENSORS 1
|
||||
#define LOCKED_SENSORS 2
|
||||
|
||||
//Turf wet states
|
||||
#define TURF_DRY 0
|
||||
#define TURF_WET_WATER 1
|
||||
@@ -392,3 +420,19 @@ GLOBAL_LIST_INIT(ghost_others_options, list(GHOST_OTHERS_SIMPLE, GHOST_OTHERS_DE
|
||||
|
||||
//Error handler defines
|
||||
#define ERROR_USEFUL_LEN 2
|
||||
|
||||
#define NO_FIELD 0
|
||||
#define FIELD_TURF 1
|
||||
#define FIELD_EDGE 2
|
||||
|
||||
//gibtonite state defines
|
||||
#define GIBTONITE_UNSTRUCK 0
|
||||
#define GIBTONITE_ACTIVE 1
|
||||
#define GIBTONITE_STABLE 2
|
||||
#define GIBTONITE_DETONATE 3
|
||||
//for obj explosion block calculation
|
||||
#define EXPLOSION_BLOCK_PROC -1
|
||||
//Gangster starting influences
|
||||
|
||||
#define GANGSTER_SOLDIER_STARTING_INFLUENCE 5
|
||||
#define GANGSTER_BOSS_STARTING_INFLUENCE 20
|
||||
|
||||
+14
-7
@@ -80,6 +80,15 @@
|
||||
#define AI_IDLE 2
|
||||
#define AI_OFF 3
|
||||
|
||||
#define ENVIRONMENT_SMASH_NONE 0
|
||||
|
||||
#define ENVIRONMENT_SMASH_STRUCTURES 1
|
||||
|
||||
#define ENVIRONMENT_SMASH_WALLS 2
|
||||
|
||||
#define ENVIRONMENT_SMASH_RWALLS 3
|
||||
|
||||
|
||||
//SNPCs
|
||||
//AI defines
|
||||
#define INTERACTING 2
|
||||
@@ -105,13 +114,6 @@
|
||||
#define SNPC_MARTYR 3
|
||||
#define SNPC_PSYCHO 4
|
||||
|
||||
//Individual logging defines
|
||||
#define INDIVIDUAL_ATTACK_LOG "Attack log"
|
||||
#define INDIVIDUAL_SAY_LOG "Say log"
|
||||
#define INDIVIDUAL_EMOTE_LOG "Emote log"
|
||||
#define INDIVIDUAL_OOC_LOG "OOC log"
|
||||
#define INDIVIDUAL_SHOW_ALL_LOG "All logs"
|
||||
|
||||
#define TK_MAXRANGE 15
|
||||
|
||||
#define NO_SLIP_WHEN_WALKING 1
|
||||
@@ -122,3 +124,8 @@
|
||||
#define MAX_CHICKENS 50
|
||||
|
||||
#define UNHEALING_EAR_DAMAGE 100
|
||||
|
||||
|
||||
#define INCORPOREAL_MOVE_BASIC 1
|
||||
#define INCORPOREAL_MOVE_SHADOW 2 // leaves a trail of shadows
|
||||
#define INCORPOREAL_MOVE_JAUNT 3 // is blocked by holy water/salt
|
||||
@@ -0,0 +1,28 @@
|
||||
#define REBOOT_MODE_NORMAL 0
|
||||
#define REBOOT_MODE_HARD 1
|
||||
#define REBOOT_MODE_SHUTDOWN 2
|
||||
|
||||
#define IRC_STATUS_THROTTLE 50
|
||||
|
||||
//keep these in sync with TGS3
|
||||
#define SERVICE_WORLD_PARAM "server_service"
|
||||
#define SERVICE_PR_TEST_JSON "..\\..\\prtestjob.json"
|
||||
|
||||
#define SERVICE_CMD_HARD_REBOOT "hard_reboot"
|
||||
#define SERVICE_CMD_GRACEFUL_SHUTDOWN "graceful_shutdown"
|
||||
#define SERVICE_CMD_WORLD_ANNOUNCE "world_announce"
|
||||
#define SERVICE_CMD_IRC_CHECK "irc_check"
|
||||
#define SERVICE_CMD_IRC_STATUS "irc_status"
|
||||
#define SERVICE_CMD_ADMIN_MSG "adminmsg"
|
||||
#define SERVICE_CMD_NAME_CHECK "namecheck"
|
||||
#define SERVICE_CMD_ADMIN_WHO "adminwho"
|
||||
|
||||
//#define SERVICE_CMD_PARAM_KEY //defined in __compile_options.dm
|
||||
#define SERVICE_CMD_PARAM_COMMAND "command"
|
||||
#define SERVICE_CMD_PARAM_MESSAGE "message"
|
||||
#define SERVICE_CMD_PARAM_TARGET "target"
|
||||
#define SERVICE_CMD_PARAM_SENDER "sender"
|
||||
|
||||
#define SERVICE_REQUEST_KILL_PROCESS "killme"
|
||||
#define SERVICE_REQUEST_IRC_BROADCAST "irc"
|
||||
#define SERVICE_REQUEST_IRC_ADMIN_CHANNEL_MESSAGE "send2irc"
|
||||
@@ -30,6 +30,24 @@
|
||||
// DEBUFFS //
|
||||
/////////////
|
||||
|
||||
#define STATUS_EFFECT_SIGILMARK /datum/status_effect/sigil_mark
|
||||
#define STATUS_EFFECT_BELLIGERENT /datum/status_effect/belligerent //forces the affected to walk, doing damage if they try to run
|
||||
|
||||
#define STATUS_EFFECT_MANIAMOTOR /datum/status_effect/maniamotor //disrupts, damages, and confuses the affected as long as they're in range of the motor
|
||||
#define MAX_MANIA_SEVERITY 100 //how high the mania severity can go
|
||||
#define MANIA_DAMAGE_TO_CONVERT 90 //how much damage is required before it'll convert affected targets
|
||||
|
||||
#define STATUS_EFFECT_HISWRATH /datum/status_effect/his_wrath //His Wrath.
|
||||
|
||||
#define STATUS_EFFECT_SUMMONEDGHOST /datum/status_effect/cultghost //is a cult ghost and can't use manifest runes
|
||||
#define STATUS_EFFECT_CRUSHERMARK /datum/status_effect/crusher_mark //if struck with a proto-kinetic crusher, takes a ton of damage
|
||||
|
||||
|
||||
/////////////
|
||||
// NEUTRAL //
|
||||
/////////////
|
||||
|
||||
#define STATUS_EFFECT_SIGILMARK /datum/status_effect/sigil_mark
|
||||
|
||||
#define STATUS_EFFECT_CRUSHERDAMAGETRACKING /datum/status_effect/crusher_damage //tracks total kinetic crusher damage on a target
|
||||
|
||||
#define STATUS_EFFECT_SYPHONMARK /datum/status_effect/syphon_mark //tracks kills for the KA death syphon module
|
||||
|
||||
@@ -39,13 +39,17 @@
|
||||
|
||||
|
||||
// Subsystem init_order, from highest priority to lowest priority
|
||||
// Subsystems shutdown in the reverse of the order they initialize in
|
||||
// The numbers just define the ordering, they are meaningless otherwise.
|
||||
|
||||
#define INIT_ORDER_DBCORE 17
|
||||
#define INIT_ORDER_SERVER_MAINT 16
|
||||
#define INIT_ORDER_JOBS 15
|
||||
#define INIT_ORDER_EVENTS 14
|
||||
#define INIT_ORDER_TICKER 13
|
||||
#define INIT_ORDER_MAPPING 12
|
||||
#define INIT_ORDER_ATOMS 11
|
||||
#define INIT_ORDER_LANGUAGE 10
|
||||
#define INIT_ORDER_MACHINES 9
|
||||
#define INIT_ORDER_SHUTTLE 3
|
||||
#define INIT_ORDER_TIMER 1
|
||||
@@ -60,3 +64,13 @@
|
||||
#define INIT_ORDER_LIGHTING -20
|
||||
#define INIT_ORDER_SQUEAK -40
|
||||
#define INIT_ORDER_PERSISTENCE -100
|
||||
|
||||
// SS runlevels
|
||||
|
||||
#define RUNLEVEL_INIT 0
|
||||
#define RUNLEVEL_LOBBY 1
|
||||
#define RUNLEVEL_SETUP 2
|
||||
#define RUNLEVEL_GAME 4
|
||||
#define RUNLEVEL_POSTGAME 8
|
||||
|
||||
#define RUNLEVELS_DEFAULT (RUNLEVEL_SETUP | RUNLEVEL_GAME | RUNLEVEL_POSTGAME)
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
diff a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm (rejected hunks)
|
||||
@@ -26,4 +26,13 @@
|
||||
|
||||
#define INITIALIZE_HINT_NORMAL 0 //Nothing happens
|
||||
#define INITIALIZE_HINT_LATELOAD 1 //Call LateInitialize
|
||||
-#define INITIALIZE_HINT_QDEL 2 //Call qdel on the atom
|
||||
\ No newline at end of file
|
||||
+#define INITIALIZE_HINT_QDEL 2 //Call qdel on the atom
|
||||
+
|
||||
+//type and all subtypes should always call Initialize in New()
|
||||
+#define INITIALIZE_IMMEDIATE(X) ##X/New(loc, ...){\
|
||||
+ ..();\
|
||||
+ if(!initialized) {\
|
||||
+ args[1] = TRUE;\
|
||||
+ SSatoms.InitAtom(src, args);\
|
||||
+ }\
|
||||
+}
|
||||
\ No newline at end of file
|
||||
@@ -3,5 +3,5 @@
|
||||
#define TICK_LIMIT_MC 70
|
||||
#define TICK_LIMIT_MC_INIT_DEFAULT 98
|
||||
|
||||
#define TICK_CHECK ( world.tick_usage > GLOB.CURRENT_TICKLIMIT )
|
||||
#define TICK_CHECK ( world.tick_usage > Master.current_ticklimit )
|
||||
#define CHECK_TICK if TICK_CHECK stoplag()
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
#define WIRE_AI "AI Connection"
|
||||
#define WIRE_ALARM "Alarm"
|
||||
#define WIRE_AVOIDANCE "Avoidance"
|
||||
#define WIRE_BACKUP1 "Auxillary Power 1"
|
||||
#define WIRE_BACKUP2 "Auxillary Power 2"
|
||||
#define WIRE_BACKUP1 "Auxiliary Power 1"
|
||||
#define WIRE_BACKUP2 "Auxiliary Power 2"
|
||||
#define WIRE_BEACON "Beacon"
|
||||
#define WIRE_BOLTS "Bolts"
|
||||
#define WIRE_BOOM "Boom"
|
||||
|
||||
+493
-490
@@ -1,490 +1,493 @@
|
||||
/*
|
||||
* Holds procs to help with list operations
|
||||
* Contains groups:
|
||||
* Misc
|
||||
* Sorting
|
||||
*/
|
||||
|
||||
/*
|
||||
* Misc
|
||||
*/
|
||||
|
||||
//Returns a list in plain english as a string
|
||||
/proc/english_list(list/input, nothing_text = "nothing", and_text = " and ", comma_text = ", ", final_comma_text = "" )
|
||||
var/total = input.len
|
||||
if (!total)
|
||||
return "[nothing_text]"
|
||||
else if (total == 1)
|
||||
return "[input[1]]"
|
||||
else if (total == 2)
|
||||
return "[input[1]][and_text][input[2]]"
|
||||
else
|
||||
var/output = ""
|
||||
var/index = 1
|
||||
while (index < total)
|
||||
if (index == total - 1)
|
||||
comma_text = final_comma_text
|
||||
|
||||
output += "[input[index]][comma_text]"
|
||||
index++
|
||||
|
||||
return "[output][and_text][input[index]]"
|
||||
|
||||
//Returns list element or null. Should prevent "index out of bounds" error.
|
||||
/proc/listgetindex(list/L, index)
|
||||
if(istype(L))
|
||||
if(isnum(index) && IsInteger(index))
|
||||
if(IsInRange(index,1,L.len))
|
||||
return L[index]
|
||||
else if(index in L)
|
||||
return L[index]
|
||||
return
|
||||
|
||||
//Return either pick(list) or null if list is not of type /list or is empty
|
||||
/proc/safepick(list/L)
|
||||
if(istype(L) && L.len)
|
||||
return pick(L)
|
||||
|
||||
//Checks if the list is empty
|
||||
/proc/isemptylist(list/L)
|
||||
if(!L.len)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
//Checks for specific types in a list
|
||||
/proc/is_type_in_list(atom/A, list/L)
|
||||
if(!L || !L.len || !A)
|
||||
return 0
|
||||
for(var/type in L)
|
||||
if(istype(A, type))
|
||||
return 1
|
||||
return 0
|
||||
|
||||
//Checks for specific types in specifically structured (Assoc "type" = TRUE) lists ('typecaches')
|
||||
/proc/is_type_in_typecache(atom/A, list/L)
|
||||
if(!L || !L.len || !A)
|
||||
|
||||
return 0
|
||||
if(ispath(A))
|
||||
. = L[A]
|
||||
else
|
||||
. = L[A.type]
|
||||
|
||||
//Checks for a string in a list
|
||||
/proc/is_string_in_list(string, list/L)
|
||||
if(!L || !L.len || !string)
|
||||
return
|
||||
for(var/V in L)
|
||||
if(string == V)
|
||||
return 1
|
||||
return
|
||||
|
||||
//Removes a string from a list
|
||||
/proc/remove_strings_from_list(string, list/L)
|
||||
if(!L || !L.len || !string)
|
||||
return
|
||||
for(var/V in L)
|
||||
if(V == string)
|
||||
L -= V //No return here so that it removes all strings of that type
|
||||
return
|
||||
|
||||
//returns a new list with only atoms that are in typecache L
|
||||
/proc/typecache_filter_list(list/atoms, list/typecache)
|
||||
. = list()
|
||||
for (var/thing in atoms)
|
||||
var/atom/A = thing
|
||||
if (typecache[A.type])
|
||||
. += A
|
||||
|
||||
//Like typesof() or subtypesof(), but returns a typecache instead of a list
|
||||
/proc/typecacheof(path, ignore_root_path, only_root_path = FALSE)
|
||||
if(ispath(path))
|
||||
var/list/types = list()
|
||||
if(only_root_path)
|
||||
types = list(path)
|
||||
else
|
||||
types = ignore_root_path ? subtypesof(path) : typesof(path)
|
||||
var/list/L = list()
|
||||
for(var/T in types)
|
||||
L[T] = TRUE
|
||||
return L
|
||||
else if(islist(path))
|
||||
var/list/pathlist = path
|
||||
var/list/L = list()
|
||||
if(ignore_root_path)
|
||||
for(var/P in pathlist)
|
||||
for(var/T in subtypesof(P))
|
||||
L[T] = TRUE
|
||||
else
|
||||
for(var/P in pathlist)
|
||||
if(only_root_path)
|
||||
L[P] = TRUE
|
||||
else
|
||||
for(var/T in typesof(P))
|
||||
L[T] = TRUE
|
||||
return L
|
||||
|
||||
//Empties the list by setting the length to 0. Hopefully the elements get garbage collected
|
||||
/proc/clearlist(list/list)
|
||||
if(istype(list))
|
||||
list.len = 0
|
||||
return
|
||||
|
||||
//Removes any null entries from the list
|
||||
/proc/listclearnulls(list/L)
|
||||
var/list/N = new(L.len)
|
||||
L -= N
|
||||
|
||||
/*
|
||||
* Returns list containing all the entries from first list that are not present in second.
|
||||
* If skiprep = 1, repeated elements are treated as one.
|
||||
* If either of arguments is not a list, returns null
|
||||
*/
|
||||
/proc/difflist(list/first, list/second, skiprep=0)
|
||||
if(!islist(first) || !islist(second))
|
||||
return
|
||||
var/list/result = new
|
||||
if(skiprep)
|
||||
for(var/e in first)
|
||||
if(!(e in result) && !(e in second))
|
||||
result += e
|
||||
else
|
||||
result = first - second
|
||||
return result
|
||||
|
||||
/*
|
||||
* Returns list containing entries that are in either list but not both.
|
||||
* If skipref = 1, repeated elements are treated as one.
|
||||
* If either of arguments is not a list, returns null
|
||||
*/
|
||||
/proc/uniquemergelist(list/first, list/second, skiprep=0)
|
||||
if(!islist(first) || !islist(second))
|
||||
return
|
||||
var/list/result = new
|
||||
if(skiprep)
|
||||
result = difflist(first, second, skiprep)+difflist(second, first, skiprep)
|
||||
else
|
||||
result = first ^ second
|
||||
return result
|
||||
|
||||
//Pretends to pick an element based on its weight but really just seems to pick a random element.
|
||||
/proc/pickweight(list/L)
|
||||
var/total = 0
|
||||
var/item
|
||||
for (item in L)
|
||||
if (!L[item])
|
||||
L[item] = 1
|
||||
total += L[item]
|
||||
|
||||
total = rand(1, total)
|
||||
for (item in L)
|
||||
total -=L [item]
|
||||
if (total <= 0)
|
||||
return item
|
||||
|
||||
return null
|
||||
|
||||
//Pick a random element from the list and remove it from the list.
|
||||
/proc/pick_n_take(list/L)
|
||||
if(L.len)
|
||||
var/picked = rand(1,L.len)
|
||||
. = L[picked]
|
||||
L.Cut(picked,picked+1) //Cut is far more efficient that Remove()
|
||||
|
||||
//Returns the top(last) element from the list and removes it from the list (typical stack function)
|
||||
/proc/pop(list/L)
|
||||
if(L.len)
|
||||
. = L[L.len]
|
||||
L.len--
|
||||
|
||||
/proc/popleft(list/L)
|
||||
if(L.len)
|
||||
. = L[1]
|
||||
L.Cut(1,2)
|
||||
|
||||
/proc/sorted_insert(list/L, thing, comparator)
|
||||
var/pos = L.len
|
||||
while(pos > 0 && call(comparator)(thing, L[pos]) > 0)
|
||||
pos--
|
||||
L.Insert(pos+1, thing)
|
||||
|
||||
// Returns the next item in a list
|
||||
/proc/next_list_item(item, list/L)
|
||||
var/i
|
||||
i = L.Find(item)
|
||||
if(i == L.len)
|
||||
i = 1
|
||||
else
|
||||
i++
|
||||
return L[i]
|
||||
|
||||
// Returns the previous item in a list
|
||||
/proc/previous_list_item(item, list/L)
|
||||
var/i
|
||||
i = L.Find(item)
|
||||
if(i == 1)
|
||||
i = L.len
|
||||
else
|
||||
i--
|
||||
return L[i]
|
||||
|
||||
//Randomize: Return the list in a random order
|
||||
/proc/shuffle(list/L)
|
||||
if(!L)
|
||||
return
|
||||
L = L.Copy()
|
||||
|
||||
for(var/i=1, i<L.len, ++i)
|
||||
L.Swap(i,rand(i,L.len))
|
||||
|
||||
return L
|
||||
|
||||
//same, but returns nothing and acts on list in place
|
||||
/proc/shuffle_inplace(list/L)
|
||||
if(!L)
|
||||
return
|
||||
|
||||
for(var/i=1, i<L.len, ++i)
|
||||
L.Swap(i,rand(i,L.len))
|
||||
|
||||
//Return a list with no duplicate entries
|
||||
/proc/uniqueList(list/L)
|
||||
. = list()
|
||||
for(var/i in L)
|
||||
. |= i
|
||||
|
||||
//same, but returns nothing and acts on list in place (also handles associated values properly)
|
||||
/proc/uniqueList_inplace(list/L)
|
||||
var/temp = L.Copy()
|
||||
L.len = 0
|
||||
for(var/key in temp)
|
||||
if (isnum(key))
|
||||
L |= key
|
||||
else
|
||||
L[key] = temp[key]
|
||||
|
||||
//for sorting clients or mobs by ckey
|
||||
/proc/sortKey(list/L, order=1)
|
||||
return sortTim(L, order >= 0 ? /proc/cmp_ckey_asc : /proc/cmp_ckey_dsc)
|
||||
|
||||
//Specifically for record datums in a list.
|
||||
/proc/sortRecord(list/L, field = "name", order = 1)
|
||||
GLOB.cmp_field = field
|
||||
return sortTim(L, order >= 0 ? /proc/cmp_records_asc : /proc/cmp_records_dsc)
|
||||
|
||||
//any value in a list
|
||||
/proc/sortList(list/L, cmp=/proc/cmp_text_asc)
|
||||
return sortTim(L.Copy(), cmp)
|
||||
|
||||
//uses sortList() but uses the var's name specifically. This should probably be using mergeAtom() instead
|
||||
/proc/sortNames(list/L, order=1)
|
||||
return sortTim(L, order >= 0 ? /proc/cmp_name_asc : /proc/cmp_name_dsc)
|
||||
|
||||
|
||||
//Converts a bitfield to a list of numbers (or words if a wordlist is provided)
|
||||
/proc/bitfield2list(bitfield = 0, list/wordlist)
|
||||
var/list/r = list()
|
||||
if(istype(wordlist,/list))
|
||||
var/max = min(wordlist.len,16)
|
||||
var/bit = 1
|
||||
for(var/i=1, i<=max, i++)
|
||||
if(bitfield & bit)
|
||||
r += wordlist[i]
|
||||
bit = bit << 1
|
||||
else
|
||||
for(var/bit=1, bit<=65535, bit = bit << 1)
|
||||
if(bitfield & bit)
|
||||
r += bit
|
||||
|
||||
return r
|
||||
|
||||
// Returns the key based on the index
|
||||
#define KEYBYINDEX(L, index) (((index <= L:len) && (index > 0)) ? L[index] : null)
|
||||
|
||||
/proc/count_by_type(list/L, type)
|
||||
var/i = 0
|
||||
for(var/T in L)
|
||||
if(istype(T, type))
|
||||
i++
|
||||
return i
|
||||
|
||||
/proc/find_record(field, value, list/L)
|
||||
for(var/datum/data/record/R in L)
|
||||
if(R.fields[field] == value)
|
||||
return R
|
||||
|
||||
|
||||
//Move a single element from position fromIndex within a list, to position toIndex
|
||||
//All elements in the range [1,toIndex) before the move will be before the pivot afterwards
|
||||
//All elements in the range [toIndex, L.len+1) before the move will be after the pivot afterwards
|
||||
//In other words, it's as if the range [fromIndex,toIndex) have been rotated using a <<< operation common to other languages.
|
||||
//fromIndex and toIndex must be in the range [1,L.len+1]
|
||||
//This will preserve associations ~Carnie
|
||||
/proc/moveElement(list/L, fromIndex, toIndex)
|
||||
if(fromIndex == toIndex || fromIndex+1 == toIndex) //no need to move
|
||||
return
|
||||
if(fromIndex > toIndex)
|
||||
++fromIndex //since a null will be inserted before fromIndex, the index needs to be nudged right by one
|
||||
|
||||
L.Insert(toIndex, null)
|
||||
L.Swap(fromIndex, toIndex)
|
||||
L.Cut(fromIndex, fromIndex+1)
|
||||
|
||||
|
||||
//Move elements [fromIndex,fromIndex+len) to [toIndex-len, toIndex)
|
||||
//Same as moveElement but for ranges of elements
|
||||
//This will preserve associations ~Carnie
|
||||
/proc/moveRange(list/L, fromIndex, toIndex, len=1)
|
||||
var/distance = abs(toIndex - fromIndex)
|
||||
if(len >= distance) //there are more elements to be moved than the distance to be moved. Therefore the same result can be achieved (with fewer operations) by moving elements between where we are and where we are going. The result being, our range we are moving is shifted left or right by dist elements
|
||||
if(fromIndex <= toIndex)
|
||||
return //no need to move
|
||||
fromIndex += len //we want to shift left instead of right
|
||||
|
||||
for(var/i=0, i<distance, ++i)
|
||||
L.Insert(fromIndex, null)
|
||||
L.Swap(fromIndex, toIndex)
|
||||
L.Cut(toIndex, toIndex+1)
|
||||
else
|
||||
if(fromIndex > toIndex)
|
||||
fromIndex += len
|
||||
|
||||
for(var/i=0, i<len, ++i)
|
||||
L.Insert(toIndex, null)
|
||||
L.Swap(fromIndex, toIndex)
|
||||
L.Cut(fromIndex, fromIndex+1)
|
||||
|
||||
//Move elements from [fromIndex, fromIndex+len) to [toIndex, toIndex+len)
|
||||
//Move any elements being overwritten by the move to the now-empty elements, preserving order
|
||||
//Note: if the two ranges overlap, only the destination order will be preserved fully, since some elements will be within both ranges ~Carnie
|
||||
/proc/swapRange(list/L, fromIndex, toIndex, len=1)
|
||||
var/distance = abs(toIndex - fromIndex)
|
||||
if(len > distance) //there is an overlap, therefore swapping each element will require more swaps than inserting new elements
|
||||
if(fromIndex < toIndex)
|
||||
toIndex += len
|
||||
else
|
||||
fromIndex += len
|
||||
|
||||
for(var/i=0, i<distance, ++i)
|
||||
L.Insert(fromIndex, null)
|
||||
L.Swap(fromIndex, toIndex)
|
||||
L.Cut(toIndex, toIndex+1)
|
||||
else
|
||||
if(toIndex > fromIndex)
|
||||
var/a = toIndex
|
||||
toIndex = fromIndex
|
||||
fromIndex = a
|
||||
|
||||
for(var/i=0, i<len, ++i)
|
||||
L.Swap(fromIndex++, toIndex++)
|
||||
|
||||
//replaces reverseList ~Carnie
|
||||
/proc/reverseRange(list/L, start=1, end=0)
|
||||
if(L.len)
|
||||
start = start % L.len
|
||||
end = end % (L.len+1)
|
||||
if(start <= 0)
|
||||
start += L.len
|
||||
if(end <= 0)
|
||||
end += L.len + 1
|
||||
|
||||
--end
|
||||
while(start < end)
|
||||
L.Swap(start++,end--)
|
||||
|
||||
return L
|
||||
|
||||
|
||||
//return first thing in L which has var/varname == value
|
||||
//this is typecaste as list/L, but you could actually feed it an atom instead.
|
||||
//completely safe to use
|
||||
/proc/getElementByVar(list/L, varname, value)
|
||||
varname = "[varname]"
|
||||
for(var/datum/D in L)
|
||||
if(D.vars.Find(varname))
|
||||
if(D.vars[varname] == value)
|
||||
return D
|
||||
|
||||
//remove all nulls from a list
|
||||
/proc/removeNullsFromList(list/L)
|
||||
while(L.Remove(null))
|
||||
continue
|
||||
return L
|
||||
|
||||
//Copies a list, and all lists inside it recusively
|
||||
//Does not copy any other reference type
|
||||
/proc/deepCopyList(list/l)
|
||||
if(!islist(l))
|
||||
return l
|
||||
. = l.Copy()
|
||||
for(var/i = 1 to l.len)
|
||||
if(islist(.[i]))
|
||||
.[i] = .(.[i])
|
||||
|
||||
//takes an input_key, as text, and the list of keys already used, outputting a replacement key in the format of "[input_key] ([number_of_duplicates])" if it finds a duplicate
|
||||
//use this for lists of things that might have the same name, like mobs or objects, that you plan on giving to a player as input
|
||||
/proc/avoid_assoc_duplicate_keys(input_key, list/used_key_list)
|
||||
if(!input_key || !istype(used_key_list))
|
||||
return
|
||||
if(used_key_list[input_key])
|
||||
used_key_list[input_key]++
|
||||
input_key = "[input_key] ([used_key_list[input_key]])"
|
||||
else
|
||||
used_key_list[input_key] = 1
|
||||
return input_key
|
||||
|
||||
#if DM_VERSION > 512
|
||||
#error Remie said that lummox was adding a way to get a lists
|
||||
#error contents via list.values, if that is true remove this
|
||||
#error otherwise, update the version and bug lummox
|
||||
#elseif
|
||||
//Flattens a keyed list into a list of it's contents
|
||||
/proc/flatten_list(list/key_list)
|
||||
if(!islist(key_list))
|
||||
return null
|
||||
. = list()
|
||||
for(var/key in key_list)
|
||||
. |= key_list[key]
|
||||
|
||||
//Picks from the list, with some safeties, and returns the "default" arg if it fails
|
||||
#define DEFAULTPICK(L, default) ((istype(L, /list) && L:len) ? pick(L) : default)
|
||||
|
||||
#define LAZYINITLIST(L) if (!L) L = list()
|
||||
|
||||
#define UNSETEMPTY(L) if (L && !L.len) L = null
|
||||
#define LAZYREMOVE(L, I) if(L) { L -= I; if(!L.len) { L = null; } }
|
||||
#define LAZYADD(L, I) if(!L) { L = list(); } L += I;
|
||||
#define LAZYACCESS(L, I) (L ? (isnum(I) ? (I > 0 && I <= L.len ? L[I] : null) : L[I]) : null)
|
||||
#define LAZYLEN(L) length(L)
|
||||
#define LAZYCLEARLIST(L) if(L) L.Cut()
|
||||
|
||||
/* Definining a counter as a series of key -> numeric value entries
|
||||
|
||||
* All these procs modify in place.
|
||||
*/
|
||||
|
||||
/proc/counterlist_scale(list/L, scalar)
|
||||
var/list/out = list()
|
||||
for(var/key in L)
|
||||
out[key] = L[key] * scalar
|
||||
. = out
|
||||
|
||||
/proc/counterlist_sum(list/L)
|
||||
. = 0
|
||||
for(var/key in L)
|
||||
. += L[key]
|
||||
|
||||
/proc/counterlist_normalise(list/L)
|
||||
var/avg = counterlist_sum(L)
|
||||
if(avg != 0)
|
||||
. = counterlist_scale(L, 1 / avg)
|
||||
else
|
||||
. = L
|
||||
|
||||
/proc/counterlist_combine(list/L1, list/L2)
|
||||
for(var/key in L2)
|
||||
var/other_value = L2[key]
|
||||
if(key in L1)
|
||||
L1[key] += other_value
|
||||
else
|
||||
L1[key] = other_value
|
||||
/*
|
||||
* Holds procs to help with list operations
|
||||
* Contains groups:
|
||||
* Misc
|
||||
* Sorting
|
||||
*/
|
||||
|
||||
/*
|
||||
* Misc
|
||||
*/
|
||||
|
||||
//Returns a list in plain english as a string
|
||||
/proc/english_list(list/input, nothing_text = "nothing", and_text = " and ", comma_text = ", ", final_comma_text = "" )
|
||||
var/total = input.len
|
||||
if (!total)
|
||||
return "[nothing_text]"
|
||||
else if (total == 1)
|
||||
return "[input[1]]"
|
||||
else if (total == 2)
|
||||
return "[input[1]][and_text][input[2]]"
|
||||
else
|
||||
var/output = ""
|
||||
var/index = 1
|
||||
while (index < total)
|
||||
if (index == total - 1)
|
||||
comma_text = final_comma_text
|
||||
|
||||
output += "[input[index]][comma_text]"
|
||||
index++
|
||||
|
||||
return "[output][and_text][input[index]]"
|
||||
|
||||
//Returns list element or null. Should prevent "index out of bounds" error.
|
||||
/proc/listgetindex(list/L, index)
|
||||
if(istype(L))
|
||||
if(isnum(index) && IsInteger(index))
|
||||
if(IsInRange(index,1,L.len))
|
||||
return L[index]
|
||||
else if(index in L)
|
||||
return L[index]
|
||||
return
|
||||
|
||||
//Return either pick(list) or null if list is not of type /list or is empty
|
||||
/proc/safepick(list/L)
|
||||
if(istype(L) && L.len)
|
||||
return pick(L)
|
||||
|
||||
//Checks if the list is empty
|
||||
/proc/isemptylist(list/L)
|
||||
if(!L.len)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
//Checks for specific types in a list
|
||||
/proc/is_type_in_list(atom/A, list/L)
|
||||
if(!L || !L.len || !A)
|
||||
return 0
|
||||
for(var/type in L)
|
||||
if(istype(A, type))
|
||||
return 1
|
||||
return 0
|
||||
|
||||
//Checks for specific types in specifically structured (Assoc "type" = TRUE) lists ('typecaches')
|
||||
/proc/is_type_in_typecache(atom/A, list/L)
|
||||
if(!L || !L.len || !A)
|
||||
|
||||
return 0
|
||||
if(ispath(A))
|
||||
. = L[A]
|
||||
else
|
||||
. = L[A.type]
|
||||
|
||||
//Checks for a string in a list
|
||||
/proc/is_string_in_list(string, list/L)
|
||||
if(!L || !L.len || !string)
|
||||
return
|
||||
for(var/V in L)
|
||||
if(string == V)
|
||||
return 1
|
||||
return
|
||||
|
||||
//Removes a string from a list
|
||||
/proc/remove_strings_from_list(string, list/L)
|
||||
if(!L || !L.len || !string)
|
||||
return
|
||||
for(var/V in L)
|
||||
if(V == string)
|
||||
L -= V //No return here so that it removes all strings of that type
|
||||
return
|
||||
|
||||
//returns a new list with only atoms that are in typecache L
|
||||
/proc/typecache_filter_list(list/atoms, list/typecache)
|
||||
. = list()
|
||||
for (var/thing in atoms)
|
||||
var/atom/A = thing
|
||||
if (typecache[A.type])
|
||||
. += A
|
||||
|
||||
//Like typesof() or subtypesof(), but returns a typecache instead of a list
|
||||
/proc/typecacheof(path, ignore_root_path, only_root_path = FALSE)
|
||||
if(ispath(path))
|
||||
var/list/types = list()
|
||||
if(only_root_path)
|
||||
types = list(path)
|
||||
else
|
||||
types = ignore_root_path ? subtypesof(path) : typesof(path)
|
||||
var/list/L = list()
|
||||
for(var/T in types)
|
||||
L[T] = TRUE
|
||||
return L
|
||||
else if(islist(path))
|
||||
var/list/pathlist = path
|
||||
var/list/L = list()
|
||||
if(ignore_root_path)
|
||||
for(var/P in pathlist)
|
||||
for(var/T in subtypesof(P))
|
||||
L[T] = TRUE
|
||||
else
|
||||
for(var/P in pathlist)
|
||||
if(only_root_path)
|
||||
L[P] = TRUE
|
||||
else
|
||||
for(var/T in typesof(P))
|
||||
L[T] = TRUE
|
||||
return L
|
||||
|
||||
//Empties the list by setting the length to 0. Hopefully the elements get garbage collected
|
||||
/proc/clearlist(list/list)
|
||||
if(istype(list))
|
||||
list.len = 0
|
||||
return
|
||||
|
||||
//Removes any null entries from the list
|
||||
//Returns TRUE if the list had nulls, FALSE otherwise
|
||||
/proc/listclearnulls(list/L)
|
||||
var/start_len = L.len
|
||||
var/list/N = new(start_len)
|
||||
L -= N
|
||||
return L.len < start_len
|
||||
|
||||
/*
|
||||
* Returns list containing all the entries from first list that are not present in second.
|
||||
* If skiprep = 1, repeated elements are treated as one.
|
||||
* If either of arguments is not a list, returns null
|
||||
*/
|
||||
/proc/difflist(list/first, list/second, skiprep=0)
|
||||
if(!islist(first) || !islist(second))
|
||||
return
|
||||
var/list/result = new
|
||||
if(skiprep)
|
||||
for(var/e in first)
|
||||
if(!(e in result) && !(e in second))
|
||||
result += e
|
||||
else
|
||||
result = first - second
|
||||
return result
|
||||
|
||||
/*
|
||||
* Returns list containing entries that are in either list but not both.
|
||||
* If skipref = 1, repeated elements are treated as one.
|
||||
* If either of arguments is not a list, returns null
|
||||
*/
|
||||
/proc/uniquemergelist(list/first, list/second, skiprep=0)
|
||||
if(!islist(first) || !islist(second))
|
||||
return
|
||||
var/list/result = new
|
||||
if(skiprep)
|
||||
result = difflist(first, second, skiprep)+difflist(second, first, skiprep)
|
||||
else
|
||||
result = first ^ second
|
||||
return result
|
||||
|
||||
//Pretends to pick an element based on its weight but really just seems to pick a random element.
|
||||
/proc/pickweight(list/L)
|
||||
var/total = 0
|
||||
var/item
|
||||
for (item in L)
|
||||
if (!L[item])
|
||||
L[item] = 1
|
||||
total += L[item]
|
||||
|
||||
total = rand(1, total)
|
||||
for (item in L)
|
||||
total -=L [item]
|
||||
if (total <= 0)
|
||||
return item
|
||||
|
||||
return null
|
||||
|
||||
//Pick a random element from the list and remove it from the list.
|
||||
/proc/pick_n_take(list/L)
|
||||
if(L.len)
|
||||
var/picked = rand(1,L.len)
|
||||
. = L[picked]
|
||||
L.Cut(picked,picked+1) //Cut is far more efficient that Remove()
|
||||
|
||||
//Returns the top(last) element from the list and removes it from the list (typical stack function)
|
||||
/proc/pop(list/L)
|
||||
if(L.len)
|
||||
. = L[L.len]
|
||||
L.len--
|
||||
|
||||
/proc/popleft(list/L)
|
||||
if(L.len)
|
||||
. = L[1]
|
||||
L.Cut(1,2)
|
||||
|
||||
/proc/sorted_insert(list/L, thing, comparator)
|
||||
var/pos = L.len
|
||||
while(pos > 0 && call(comparator)(thing, L[pos]) > 0)
|
||||
pos--
|
||||
L.Insert(pos+1, thing)
|
||||
|
||||
// Returns the next item in a list
|
||||
/proc/next_list_item(item, list/L)
|
||||
var/i
|
||||
i = L.Find(item)
|
||||
if(i == L.len)
|
||||
i = 1
|
||||
else
|
||||
i++
|
||||
return L[i]
|
||||
|
||||
// Returns the previous item in a list
|
||||
/proc/previous_list_item(item, list/L)
|
||||
var/i
|
||||
i = L.Find(item)
|
||||
if(i == 1)
|
||||
i = L.len
|
||||
else
|
||||
i--
|
||||
return L[i]
|
||||
|
||||
//Randomize: Return the list in a random order
|
||||
/proc/shuffle(list/L)
|
||||
if(!L)
|
||||
return
|
||||
L = L.Copy()
|
||||
|
||||
for(var/i=1, i<L.len, ++i)
|
||||
L.Swap(i,rand(i,L.len))
|
||||
|
||||
return L
|
||||
|
||||
//same, but returns nothing and acts on list in place
|
||||
/proc/shuffle_inplace(list/L)
|
||||
if(!L)
|
||||
return
|
||||
|
||||
for(var/i=1, i<L.len, ++i)
|
||||
L.Swap(i,rand(i,L.len))
|
||||
|
||||
//Return a list with no duplicate entries
|
||||
/proc/uniqueList(list/L)
|
||||
. = list()
|
||||
for(var/i in L)
|
||||
. |= i
|
||||
|
||||
//same, but returns nothing and acts on list in place (also handles associated values properly)
|
||||
/proc/uniqueList_inplace(list/L)
|
||||
var/temp = L.Copy()
|
||||
L.len = 0
|
||||
for(var/key in temp)
|
||||
if (isnum(key))
|
||||
L |= key
|
||||
else
|
||||
L[key] = temp[key]
|
||||
|
||||
//for sorting clients or mobs by ckey
|
||||
/proc/sortKey(list/L, order=1)
|
||||
return sortTim(L, order >= 0 ? /proc/cmp_ckey_asc : /proc/cmp_ckey_dsc)
|
||||
|
||||
//Specifically for record datums in a list.
|
||||
/proc/sortRecord(list/L, field = "name", order = 1)
|
||||
GLOB.cmp_field = field
|
||||
return sortTim(L, order >= 0 ? /proc/cmp_records_asc : /proc/cmp_records_dsc)
|
||||
|
||||
//any value in a list
|
||||
/proc/sortList(list/L, cmp=/proc/cmp_text_asc)
|
||||
return sortTim(L.Copy(), cmp)
|
||||
|
||||
//uses sortList() but uses the var's name specifically. This should probably be using mergeAtom() instead
|
||||
/proc/sortNames(list/L, order=1)
|
||||
return sortTim(L, order >= 0 ? /proc/cmp_name_asc : /proc/cmp_name_dsc)
|
||||
|
||||
|
||||
//Converts a bitfield to a list of numbers (or words if a wordlist is provided)
|
||||
/proc/bitfield2list(bitfield = 0, list/wordlist)
|
||||
var/list/r = list()
|
||||
if(istype(wordlist,/list))
|
||||
var/max = min(wordlist.len,16)
|
||||
var/bit = 1
|
||||
for(var/i=1, i<=max, i++)
|
||||
if(bitfield & bit)
|
||||
r += wordlist[i]
|
||||
bit = bit << 1
|
||||
else
|
||||
for(var/bit=1, bit<=65535, bit = bit << 1)
|
||||
if(bitfield & bit)
|
||||
r += bit
|
||||
|
||||
return r
|
||||
|
||||
// Returns the key based on the index
|
||||
#define KEYBYINDEX(L, index) (((index <= L:len) && (index > 0)) ? L[index] : null)
|
||||
|
||||
/proc/count_by_type(list/L, type)
|
||||
var/i = 0
|
||||
for(var/T in L)
|
||||
if(istype(T, type))
|
||||
i++
|
||||
return i
|
||||
|
||||
/proc/find_record(field, value, list/L)
|
||||
for(var/datum/data/record/R in L)
|
||||
if(R.fields[field] == value)
|
||||
return R
|
||||
|
||||
|
||||
//Move a single element from position fromIndex within a list, to position toIndex
|
||||
//All elements in the range [1,toIndex) before the move will be before the pivot afterwards
|
||||
//All elements in the range [toIndex, L.len+1) before the move will be after the pivot afterwards
|
||||
//In other words, it's as if the range [fromIndex,toIndex) have been rotated using a <<< operation common to other languages.
|
||||
//fromIndex and toIndex must be in the range [1,L.len+1]
|
||||
//This will preserve associations ~Carnie
|
||||
/proc/moveElement(list/L, fromIndex, toIndex)
|
||||
if(fromIndex == toIndex || fromIndex+1 == toIndex) //no need to move
|
||||
return
|
||||
if(fromIndex > toIndex)
|
||||
++fromIndex //since a null will be inserted before fromIndex, the index needs to be nudged right by one
|
||||
|
||||
L.Insert(toIndex, null)
|
||||
L.Swap(fromIndex, toIndex)
|
||||
L.Cut(fromIndex, fromIndex+1)
|
||||
|
||||
|
||||
//Move elements [fromIndex,fromIndex+len) to [toIndex-len, toIndex)
|
||||
//Same as moveElement but for ranges of elements
|
||||
//This will preserve associations ~Carnie
|
||||
/proc/moveRange(list/L, fromIndex, toIndex, len=1)
|
||||
var/distance = abs(toIndex - fromIndex)
|
||||
if(len >= distance) //there are more elements to be moved than the distance to be moved. Therefore the same result can be achieved (with fewer operations) by moving elements between where we are and where we are going. The result being, our range we are moving is shifted left or right by dist elements
|
||||
if(fromIndex <= toIndex)
|
||||
return //no need to move
|
||||
fromIndex += len //we want to shift left instead of right
|
||||
|
||||
for(var/i=0, i<distance, ++i)
|
||||
L.Insert(fromIndex, null)
|
||||
L.Swap(fromIndex, toIndex)
|
||||
L.Cut(toIndex, toIndex+1)
|
||||
else
|
||||
if(fromIndex > toIndex)
|
||||
fromIndex += len
|
||||
|
||||
for(var/i=0, i<len, ++i)
|
||||
L.Insert(toIndex, null)
|
||||
L.Swap(fromIndex, toIndex)
|
||||
L.Cut(fromIndex, fromIndex+1)
|
||||
|
||||
//Move elements from [fromIndex, fromIndex+len) to [toIndex, toIndex+len)
|
||||
//Move any elements being overwritten by the move to the now-empty elements, preserving order
|
||||
//Note: if the two ranges overlap, only the destination order will be preserved fully, since some elements will be within both ranges ~Carnie
|
||||
/proc/swapRange(list/L, fromIndex, toIndex, len=1)
|
||||
var/distance = abs(toIndex - fromIndex)
|
||||
if(len > distance) //there is an overlap, therefore swapping each element will require more swaps than inserting new elements
|
||||
if(fromIndex < toIndex)
|
||||
toIndex += len
|
||||
else
|
||||
fromIndex += len
|
||||
|
||||
for(var/i=0, i<distance, ++i)
|
||||
L.Insert(fromIndex, null)
|
||||
L.Swap(fromIndex, toIndex)
|
||||
L.Cut(toIndex, toIndex+1)
|
||||
else
|
||||
if(toIndex > fromIndex)
|
||||
var/a = toIndex
|
||||
toIndex = fromIndex
|
||||
fromIndex = a
|
||||
|
||||
for(var/i=0, i<len, ++i)
|
||||
L.Swap(fromIndex++, toIndex++)
|
||||
|
||||
//replaces reverseList ~Carnie
|
||||
/proc/reverseRange(list/L, start=1, end=0)
|
||||
if(L.len)
|
||||
start = start % L.len
|
||||
end = end % (L.len+1)
|
||||
if(start <= 0)
|
||||
start += L.len
|
||||
if(end <= 0)
|
||||
end += L.len + 1
|
||||
|
||||
--end
|
||||
while(start < end)
|
||||
L.Swap(start++,end--)
|
||||
|
||||
return L
|
||||
|
||||
|
||||
//return first thing in L which has var/varname == value
|
||||
//this is typecaste as list/L, but you could actually feed it an atom instead.
|
||||
//completely safe to use
|
||||
/proc/getElementByVar(list/L, varname, value)
|
||||
varname = "[varname]"
|
||||
for(var/datum/D in L)
|
||||
if(D.vars.Find(varname))
|
||||
if(D.vars[varname] == value)
|
||||
return D
|
||||
|
||||
//remove all nulls from a list
|
||||
/proc/removeNullsFromList(list/L)
|
||||
while(L.Remove(null))
|
||||
continue
|
||||
return L
|
||||
|
||||
//Copies a list, and all lists inside it recusively
|
||||
//Does not copy any other reference type
|
||||
/proc/deepCopyList(list/l)
|
||||
if(!islist(l))
|
||||
return l
|
||||
. = l.Copy()
|
||||
for(var/i = 1 to l.len)
|
||||
if(islist(.[i]))
|
||||
.[i] = .(.[i])
|
||||
|
||||
//takes an input_key, as text, and the list of keys already used, outputting a replacement key in the format of "[input_key] ([number_of_duplicates])" if it finds a duplicate
|
||||
//use this for lists of things that might have the same name, like mobs or objects, that you plan on giving to a player as input
|
||||
/proc/avoid_assoc_duplicate_keys(input_key, list/used_key_list)
|
||||
if(!input_key || !istype(used_key_list))
|
||||
return
|
||||
if(used_key_list[input_key])
|
||||
used_key_list[input_key]++
|
||||
input_key = "[input_key] ([used_key_list[input_key]])"
|
||||
else
|
||||
used_key_list[input_key] = 1
|
||||
return input_key
|
||||
|
||||
#if DM_VERSION > 512
|
||||
#error Remie said that lummox was adding a way to get a lists
|
||||
#error contents via list.values, if that is true remove this
|
||||
#error otherwise, update the version and bug lummox
|
||||
#elseif
|
||||
//Flattens a keyed list into a list of it's contents
|
||||
/proc/flatten_list(list/key_list)
|
||||
if(!islist(key_list))
|
||||
return null
|
||||
. = list()
|
||||
for(var/key in key_list)
|
||||
. |= key_list[key]
|
||||
|
||||
//Picks from the list, with some safeties, and returns the "default" arg if it fails
|
||||
#define DEFAULTPICK(L, default) ((istype(L, /list) && L:len) ? pick(L) : default)
|
||||
#define LAZYINITLIST(L) if (!L) L = list()
|
||||
#define UNSETEMPTY(L) if (L && !L.len) L = null
|
||||
#define LAZYREMOVE(L, I) if(L) { L -= I; if(!L.len) { L = null; } }
|
||||
#define LAZYADD(L, I) if(!L) { L = list(); } L += I;
|
||||
#define LAZYACCESS(L, I) (L ? (isnum(I) ? (I > 0 && I <= L.len ? L[I] : null) : L[I]) : null)
|
||||
#define LAZYSET(L, K, V) if(!L) { L = list(); } L[K] = V;
|
||||
#define LAZYLEN(L) length(L)
|
||||
#define LAZYCLEARLIST(L) if(L) L.Cut()
|
||||
#define SANITIZE_LIST(L) ( islist(L) ? L : list() )
|
||||
|
||||
/* Definining a counter as a series of key -> numeric value entries
|
||||
|
||||
* All these procs modify in place.
|
||||
*/
|
||||
|
||||
/proc/counterlist_scale(list/L, scalar)
|
||||
var/list/out = list()
|
||||
for(var/key in L)
|
||||
out[key] = L[key] * scalar
|
||||
. = out
|
||||
|
||||
/proc/counterlist_sum(list/L)
|
||||
. = 0
|
||||
for(var/key in L)
|
||||
. += L[key]
|
||||
|
||||
/proc/counterlist_normalise(list/L)
|
||||
var/avg = counterlist_sum(L)
|
||||
if(avg != 0)
|
||||
. = counterlist_scale(L, 1 / avg)
|
||||
else
|
||||
. = L
|
||||
|
||||
/proc/counterlist_combine(list/L1, list/L2)
|
||||
for(var/key in L2)
|
||||
var/other_value = L2[key]
|
||||
if(key in L1)
|
||||
L1[key] += other_value
|
||||
else
|
||||
L1[key] = other_value
|
||||
|
||||
+17
-20
@@ -20,13 +20,13 @@
|
||||
/proc/log_admin(text)
|
||||
GLOB.admin_log.Add(text)
|
||||
if (config.log_admin)
|
||||
GLOB.diary << "\[[time_stamp()]]ADMIN: [text]"
|
||||
GLOB.world_game_log << "\[[time_stamp()]]ADMIN: [text]"
|
||||
|
||||
//Items using this proc are stripped from public logs - use with caution
|
||||
/proc/log_admin_private(text)
|
||||
GLOB.admin_log.Add(text)
|
||||
if (config.log_admin)
|
||||
GLOB.diary << "\[[time_stamp()]]ADMINPRIVATE: [text]"
|
||||
GLOB.world_game_log << "\[[time_stamp()]]ADMINPRIVATE: [text]"
|
||||
|
||||
/proc/log_adminsay(text)
|
||||
if (config.log_adminchat)
|
||||
@@ -38,67 +38,64 @@
|
||||
|
||||
/proc/log_game(text)
|
||||
if (config.log_game)
|
||||
GLOB.diary << "\[[time_stamp()]]GAME: [text]"
|
||||
GLOB.world_game_log << "\[[time_stamp()]]GAME: [text]"
|
||||
|
||||
/proc/log_vote(text)
|
||||
if (config.log_vote)
|
||||
GLOB.diary << "\[[time_stamp()]]VOTE: [text]"
|
||||
GLOB.world_game_log << "\[[time_stamp()]]VOTE: [text]"
|
||||
|
||||
/proc/log_access(text)
|
||||
if (config.log_access)
|
||||
GLOB.diary << "\[[time_stamp()]]ACCESS: [text]"
|
||||
GLOB.world_game_log << "\[[time_stamp()]]ACCESS: [text]"
|
||||
|
||||
/proc/log_say(text)
|
||||
if (config.log_say)
|
||||
GLOB.diary << "\[[time_stamp()]]SAY: [text]"
|
||||
GLOB.world_game_log << "\[[time_stamp()]]SAY: [text]"
|
||||
|
||||
/proc/log_prayer(text)
|
||||
if (config.log_prayer)
|
||||
GLOB.diary << "\[[time_stamp()]]PRAY: [text]"
|
||||
GLOB.world_game_log << "\[[time_stamp()]]PRAY: [text]"
|
||||
|
||||
/proc/log_law(text)
|
||||
if (config.log_law)
|
||||
GLOB.diary << "\[[time_stamp()]]LAW: [text]"
|
||||
GLOB.world_game_log << "\[[time_stamp()]]LAW: [text]"
|
||||
|
||||
/proc/log_ooc(text)
|
||||
if (config.log_ooc)
|
||||
GLOB.diary << "\[[time_stamp()]]OOC: [text]"
|
||||
GLOB.world_game_log << "\[[time_stamp()]]OOC: [text]"
|
||||
|
||||
/proc/log_whisper(text)
|
||||
if (config.log_whisper)
|
||||
GLOB.diary << "\[[time_stamp()]]WHISPER: [text]"
|
||||
GLOB.world_game_log << "\[[time_stamp()]]WHISPER: [text]"
|
||||
|
||||
/proc/log_emote(text)
|
||||
if (config.log_emote)
|
||||
GLOB.diary << "\[[time_stamp()]]EMOTE: [text]"
|
||||
GLOB.world_game_log << "\[[time_stamp()]]EMOTE: [text]"
|
||||
|
||||
/proc/log_attack(text)
|
||||
if (config.log_attack)
|
||||
GLOB.diaryofmeanpeople << "\[[time_stamp()]]ATTACK: [text]"
|
||||
GLOB.world_attack_log << "\[[time_stamp()]]ATTACK: [text]"
|
||||
|
||||
/proc/log_pda(text)
|
||||
if (config.log_pda)
|
||||
GLOB.diary << "\[[time_stamp()]]PDA: [text]"
|
||||
GLOB.world_game_log << "\[[time_stamp()]]PDA: [text]"
|
||||
|
||||
/proc/log_comment(text)
|
||||
if (config.log_pda)
|
||||
//reusing the PDA option because I really don't think news comments are worth a config option
|
||||
GLOB.diary << "\[[time_stamp()]]COMMENT: [text]"
|
||||
GLOB.world_game_log << "\[[time_stamp()]]COMMENT: [text]"
|
||||
|
||||
/proc/log_chat(text)
|
||||
if (config.log_pda)
|
||||
GLOB.diary << "\[[time_stamp()]]CHAT: [text]"
|
||||
GLOB.world_game_log << "\[[time_stamp()]]CHAT: [text]"
|
||||
|
||||
/proc/log_sql(text)
|
||||
if(config.sql_enabled)
|
||||
GLOB.diary << "\[[time_stamp()]]SQL: [text]"
|
||||
GLOB.world_game_log << "\[[time_stamp()]]SQL: [text]"
|
||||
|
||||
//This replaces world.log so it displays both in DD and the file
|
||||
/proc/log_world(text)
|
||||
if(config && config.log_runtimes)
|
||||
world.log = GLOB.runtime_diary
|
||||
world.log << text
|
||||
world.log = null
|
||||
GLOB.world_runtime_log << text
|
||||
world.log << text
|
||||
|
||||
// Helper procs for building detailed log lines
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
#define YOUNG 4
|
||||
|
||||
|
||||
/client/proc/join_date_check(y,m,d)
|
||||
var/datum/DBQuery/query_datediff = SSdbcore.NewQuery("SELECT DATEDIFF(Now(),'[y]-[m]-[d]')")
|
||||
|
||||
if(!query_datediff.Execute())
|
||||
return FALSE
|
||||
|
||||
if(query_datediff.NextRow())
|
||||
var/diff = text2num(query_datediff.item[1])
|
||||
if(config.use_account_age_for_jobs)
|
||||
player_age = max(0,diff) //So job code soesn't freak out if they are time traveling.
|
||||
if(diff < YOUNG)
|
||||
var/msg = "(IP: [address], ID: [computer_id]) is a new BYOND account made on [y]-[m]-[d]."
|
||||
if(diff < 0)
|
||||
msg += " They are also apparently from the future."
|
||||
message_admins("[key_name_admin(src)] [msg]")
|
||||
return TRUE
|
||||
#undef YOUNG
|
||||
|
||||
|
||||
/client/proc/findJoinDate()
|
||||
var/http[] = world.Export("http://byond.com/members/[src.ckey]?format=text")
|
||||
if(!http)
|
||||
log_world("Failed to connect to byond age check for [src.ckey]")
|
||||
return FALSE
|
||||
|
||||
var/F = file2text(http["CONTENT"])
|
||||
if(F)
|
||||
var/regex/R = regex("joined = \"(\\d{4})-(\\d{2})-(\\d{2})\"")
|
||||
if(!R.Find(F))
|
||||
CRASH("Age check regex failed")
|
||||
var/y = R.group[1]
|
||||
var/m = R.group[2]
|
||||
var/d = R.group[3]
|
||||
return join_date_check(y,m,d)
|
||||
@@ -3,7 +3,7 @@
|
||||
for(var/file in args)
|
||||
src << browse_rsc(file)
|
||||
|
||||
/client/proc/browse_files(root="data/logs/", max_iterations=10, list/valid_extensions=list(".txt",".log",".htm"))
|
||||
/client/proc/browse_files(root="data/logs/", max_iterations=10, list/valid_extensions=list("txt","log","htm", "html"))
|
||||
var/path = root
|
||||
|
||||
for(var/i=0, i<max_iterations, i++)
|
||||
@@ -22,9 +22,13 @@
|
||||
|
||||
if(copytext(path,-1,0) != "/") //didn't choose a directory, no need to iterate again
|
||||
break
|
||||
|
||||
var/extension = copytext(path,-4,0)
|
||||
if( !fexists(path) || !(extension in valid_extensions) )
|
||||
var/extensions
|
||||
for(var/i in valid_extensions)
|
||||
if(extensions)
|
||||
extensions += "|"
|
||||
extensions += "[i]"
|
||||
var/regex/valid_ext = new("\\.([extensions])$", "i")
|
||||
if( !fexists(path) || !(valid_ext.Find(path)) )
|
||||
to_chat(src, "<font color='red'>Error: browse_files(): File not found/Invalid file([path]).</font>")
|
||||
return
|
||||
|
||||
|
||||
+554
-536
File diff suppressed because it is too large
Load Diff
@@ -167,23 +167,14 @@
|
||||
underlay_appearance.icon = fixed_underlay["icon"]
|
||||
underlay_appearance.icon_state = fixed_underlay["icon_state"]
|
||||
else
|
||||
var/turf/T = get_step(src, turn(adjacencies, 180))
|
||||
if(T && (T.density || T.smooth))
|
||||
var/turned_adjacency = turn(adjacencies, 180)
|
||||
var/turf/T = get_step(src, turned_adjacency)
|
||||
if(!T.get_smooth_underlay_icon(underlay_appearance, src, turned_adjacency))
|
||||
T = get_step(src, turn(adjacencies, 135))
|
||||
if(T && (T.density || T.smooth))
|
||||
if(!T.get_smooth_underlay_icon(underlay_appearance, src, turned_adjacency))
|
||||
T = get_step(src, turn(adjacencies, 225))
|
||||
|
||||
if(isspaceturf(T) && !istype(T, /turf/open/space/transit))
|
||||
underlay_appearance.icon = 'icons/turf/space.dmi'
|
||||
underlay_appearance.icon_state = SPACE_ICON_STATE
|
||||
underlay_appearance.plane = PLANE_SPACE
|
||||
else if(T && !T.density && !T.smooth)
|
||||
underlay_appearance.icon = T.icon
|
||||
underlay_appearance.icon_state = T.icon_state
|
||||
else if(baseturf && !initial(baseturf.density) && !initial(baseturf.smooth))
|
||||
underlay_appearance.icon = initial(baseturf.icon)
|
||||
underlay_appearance.icon_state = initial(baseturf.icon_state)
|
||||
else
|
||||
//if all else fails, ask our own turf
|
||||
if(!T.get_smooth_underlay_icon(underlay_appearance, src, turned_adjacency) && !get_smooth_underlay_icon(underlay_appearance, src, turned_adjacency))
|
||||
underlay_appearance.icon = DEFAULT_UNDERLAY_ICON
|
||||
underlay_appearance.icon_state = DEFAULT_UNDERLAY_ICON_STATE
|
||||
underlays = U
|
||||
|
||||
+16
-2
@@ -130,6 +130,22 @@ GLOBAL_LIST_INIT(sqrtTable, list(1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 4,
|
||||
var/t = round((val - min) / d)
|
||||
return val - (t * d)
|
||||
|
||||
#define NORM_ROT(rot) ((((rot % 360) + (rot - round(rot, 1))) > 0) ? ((rot % 360) + (rot - round(rot, 1))) : (((rot % 360) + (rot - round(rot, 1))) + 360))
|
||||
|
||||
/proc/get_angle_of_incidence(face_angle, angle_in, auto_normalize = TRUE)
|
||||
|
||||
var/angle_in_s = NORM_ROT(angle_in)
|
||||
var/face_angle_s = NORM_ROT(face_angle)
|
||||
var/incidence = face_angle_s - angle_in_s
|
||||
var/incidence_s = incidence
|
||||
while(incidence_s < -90)
|
||||
incidence_s += 180
|
||||
while(incidence_s > 90)
|
||||
incidence_s -= 180
|
||||
if(auto_normalize)
|
||||
return incidence_s
|
||||
else
|
||||
return incidence
|
||||
|
||||
//A logarithm that converts an integer to a number scaled between 0 and 1 (can be tweaked to be higher).
|
||||
//Currently, this is used for hydroponics-produce sprite transforming, but could be useful for other transform functions.
|
||||
@@ -141,8 +157,6 @@ GLOBAL_LIST_INIT(sqrtTable, list(1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 4,
|
||||
return size_factor + scaling_modifier //scale mod of 0 results in a number from 0 to 1. A scale modifier of +0.5 returns 0.5 to 1.5
|
||||
//to_chat(world, "Transform multiplier of [src] is [size_factor + scaling_modifer]")
|
||||
|
||||
|
||||
|
||||
//converts a uniform distributed random number into a normal distributed one
|
||||
//since this method produces two random numbers, one is saved for subsequent calls
|
||||
//(making the cost negligble for every second call)
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
//doesn't have an object argument because this is "Stacking" with the animate call above
|
||||
//3 billion% intentional
|
||||
|
||||
|
||||
//Dumps the matrix data in format a-f
|
||||
/matrix/proc/tolist()
|
||||
. = list()
|
||||
|
||||
@@ -340,6 +340,20 @@ Proc for attack log creation, because really why not
|
||||
qdel(progbar)
|
||||
|
||||
|
||||
//some additional checks as a callback for for do_afters that want to break on losing health or on the mob taking action
|
||||
/mob/proc/break_do_after_checks(list/checked_health, check_clicks)
|
||||
if(check_clicks && next_move > world.time)
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
//pass a list in the format list("health" = mob's health var) to check health during this
|
||||
/mob/living/break_do_after_checks(list/checked_health, check_clicks)
|
||||
if(islist(checked_health))
|
||||
if(health < checked_health["health"])
|
||||
return FALSE
|
||||
checked_health["health"] = health
|
||||
return ..()
|
||||
|
||||
/proc/do_after(mob/user, delay, needhand = 1, atom/target = null, progress = 1, datum/callback/extra_checks = null)
|
||||
if(!user)
|
||||
return 0
|
||||
|
||||
@@ -626,14 +626,13 @@ GLOBAL_DATUM_INIT(sortInstance, /datum/sortInstance, new())
|
||||
var/val2 = fetchElement(L,cursor2)
|
||||
|
||||
while(1)
|
||||
if(call(cmp)(val1,val2) < 0)
|
||||
if(call(cmp)(val1,val2) <= 0)
|
||||
if(++cursor1 >= end1)
|
||||
break
|
||||
val1 = fetchElement(L,cursor1)
|
||||
else
|
||||
moveElement(L,cursor2,cursor1)
|
||||
|
||||
++cursor2
|
||||
if(++cursor2 >= end2)
|
||||
break
|
||||
++end1
|
||||
@@ -653,4 +652,4 @@ GLOBAL_DATUM_INIT(sortInstance, /datum/sortInstance, new())
|
||||
#undef MIN_GALLOP
|
||||
#undef MIN_MERGE
|
||||
|
||||
#undef fetchElement
|
||||
#undef fetchElement
|
||||
|
||||
@@ -24,4 +24,4 @@ GLOBAL_LIST_EMPTY(whitelisted_species_list)
|
||||
|
||||
/proc/log_mentor(text)
|
||||
GLOB.mentor_log.Add(text)
|
||||
GLOB.diary << "\[[time_stamp()]]MENTOR: [text]"
|
||||
GLOB.world_game_log << "\[[time_stamp()]]MENTOR: [text]"
|
||||
+29
-10
@@ -723,7 +723,7 @@ Turf and target are seperate in case you want to teleport some distance from a t
|
||||
//Irregular objects
|
||||
var/icon/AMicon = icon(AM.icon, AM.icon_state)
|
||||
var/icon/AMiconheight = AMicon.Height()
|
||||
var/icon/AMiconwidth = AMicon.Width()
|
||||
var/icon/AMiconwidth = AMicon.Width()
|
||||
if(AMiconheight != world.icon_size || AMiconwidth != world.icon_size)
|
||||
pixel_x_offset += ((AMicon.Width()/world.icon_size)-1)*(world.icon_size*0.5)
|
||||
pixel_y_offset += ((AMicon.Height()/world.icon_size)-1)*(world.icon_size*0.5)
|
||||
@@ -1079,18 +1079,17 @@ B --><-- A
|
||||
return L
|
||||
|
||||
//similar function to RANGE_TURFS(), but will search spiralling outwards from the center (like the above, but only turfs)
|
||||
/proc/spiral_range_turfs(dist=0, center=usr, orange=0)
|
||||
/proc/spiral_range_turfs(dist=0, center=usr, orange=0, list/outlist = list(), tick_checked)
|
||||
outlist.Cut()
|
||||
if(!dist)
|
||||
if(!orange)
|
||||
return list(center)
|
||||
else
|
||||
return list()
|
||||
outlist += center
|
||||
return outlist
|
||||
|
||||
var/turf/t_center = get_turf(center)
|
||||
if(!t_center)
|
||||
return list()
|
||||
return outlist
|
||||
|
||||
var/list/L = list()
|
||||
var/list/L = outlist
|
||||
var/turf/T
|
||||
var/y
|
||||
var/x
|
||||
@@ -1128,6 +1127,8 @@ B --><-- A
|
||||
if(T)
|
||||
L += T
|
||||
c_dist++
|
||||
if(tick_checked)
|
||||
CHECK_TICK
|
||||
|
||||
return L
|
||||
|
||||
@@ -1215,7 +1216,7 @@ proc/pick_closest_path(value, list/matches = get_fancy_list_of_atom_types())
|
||||
. += round(i*DELTA_CALC)
|
||||
sleep(i*world.tick_lag*DELTA_CALC)
|
||||
i *= 2
|
||||
while (world.tick_usage > min(TICK_LIMIT_TO_RUN, GLOB.CURRENT_TICKLIMIT))
|
||||
while (world.tick_usage > min(TICK_LIMIT_TO_RUN, Master.current_ticklimit))
|
||||
|
||||
#undef DELTA_CALC
|
||||
|
||||
@@ -1342,7 +1343,8 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new)
|
||||
//This prevents RCEs from badmins
|
||||
//kevinz000 if you touch this I will hunt you down
|
||||
GLOBAL_VAR_INIT(valid_HTTPSGet, FALSE)
|
||||
/proc/HTTPSGet(url)
|
||||
GLOBAL_PROTECT(valid_HTTPSGet)
|
||||
/proc/HTTPSGet(url) //tgs2 support
|
||||
if(findtext(url, "\""))
|
||||
GLOB.valid_HTTPSGet = FALSE
|
||||
|
||||
@@ -1398,3 +1400,20 @@ GLOBAL_VAR_INIT(valid_HTTPSGet, FALSE)
|
||||
|
||||
/proc/pass()
|
||||
return
|
||||
|
||||
/proc/get_mob_or_brainmob(occupant)
|
||||
var/mob/living/mob_occupant
|
||||
|
||||
if(isliving(occupant))
|
||||
mob_occupant = occupant
|
||||
|
||||
else if(isbodypart(occupant))
|
||||
var/obj/item/bodypart/head/head = occupant
|
||||
|
||||
mob_occupant = head.brainmob
|
||||
|
||||
else if(isorgan(occupant))
|
||||
var/obj/item/organ/brain/brain = occupant
|
||||
mob_occupant = brain.brainmob
|
||||
|
||||
return mob_occupant
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
//MINOR TWEAKS/MISC
|
||||
#define AGE_MIN 17 //youngest a character can be
|
||||
#define AGE_MAX 85 //oldest a character can be
|
||||
#define WIZARD_AGE_MIN 30 //youngest a wizard can be
|
||||
#define SHOES_SLOWDOWN 0 //How much shoes slow you down by default. Negative values speed you up
|
||||
#define POCKET_STRIP_DELAY 40 //time taken (in deciseconds) to search somebody's pockets
|
||||
#define DOOR_CRUSH_DAMAGE 15 //the amount of damage that airlocks deal when they crush you
|
||||
@@ -61,14 +62,12 @@
|
||||
#endif
|
||||
|
||||
//Update this whenever you need to take advantage of more recent byond features
|
||||
#define MIN_COMPILER_VERSION 511
|
||||
#define MIN_COMPILER_VERSION 511
|
||||
#if DM_VERSION < MIN_COMPILER_VERSION
|
||||
//Don't forget to update this part
|
||||
#error Your version of BYOND is too out-of-date to compile this project. Go to byond.com/download and update.
|
||||
#error You need version 511 or higher
|
||||
#error You need version 511 or higher
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef SERVERTOOLS
|
||||
#define SERVERTOOLS 0
|
||||
#endif
|
||||
#define SERVICE_CMD_PARAM_KEY "serviceCommsKey"
|
||||
|
||||
@@ -22,12 +22,12 @@ GLOBAL_VAR_INIT(tinted_weldhelh, TRUE)
|
||||
// Debug2 is used in conjunction with a lot of admin verbs and therefore is actually legit.
|
||||
GLOBAL_VAR_INIT(Debug, FALSE) // global debug switch
|
||||
GLOBAL_VAR_INIT(Debug2, FALSE)
|
||||
|
||||
//This was a define, but I changed it to a variable so it can be changed in-game.(kept the all-caps definition because... code...) -Errorage
|
||||
GLOBAL_VAR_INIT(MAX_EX_DEVESTATION_RANGE, 3)
|
||||
GLOBAL_VAR_INIT(MAX_EX_HEAVY_RANGE, 7)
|
||||
GLOBAL_VAR_INIT(MAX_EX_LIGHT_RANGE, 14)
|
||||
GLOBAL_VAR_INIT(MAX_EX_FLASH_RANGE, 14)
|
||||
GLOBAL_VAR_INIT(MAX_EX_FLAME_RANGE, 14)
|
||||
GLOBAL_VAR_INIT(DYN_EX_SCALE, 0.5)
|
||||
|
||||
|
||||
//This was a define, but I changed it to a variable so it can be changed in-game.(kept the all-caps definition because... code...) -Errorage
|
||||
GLOBAL_VAR_INIT(MAX_EX_DEVESTATION_RANGE, 3)
|
||||
GLOBAL_VAR_INIT(MAX_EX_HEAVY_RANGE, 7)
|
||||
GLOBAL_VAR_INIT(MAX_EX_LIGHT_RANGE, 14)
|
||||
GLOBAL_VAR_INIT(MAX_EX_FLASH_RANGE, 14)
|
||||
GLOBAL_VAR_INIT(MAX_EX_FLAME_RANGE, 14)
|
||||
GLOBAL_VAR_INIT(DYN_EX_SCALE, 0.5)
|
||||
|
||||
|
||||
@@ -1,5 +1,18 @@
|
||||
GLOBAL_VAR_INIT(master_mode, "traitor") //"extended"
|
||||
GLOBAL_VAR_INIT(master_mode, "traitor") //"extended"
|
||||
GLOBAL_VAR_INIT(secret_force_mode, "secret") // if this is anything but "secret", the secret rotation will forceably choose this mode
|
||||
|
||||
GLOBAL_VAR_INIT(wavesecret, 0) // meteor mode, delays wave progression, terrible name
|
||||
GLOBAL_DATUM(start_state, /datum/station_state) // Used in round-end report
|
||||
|
||||
// Cult, needs to be global so admin cultists are functional
|
||||
GLOBAL_VAR_INIT(blood_target, null) // Cult Master's target or Construct's Master
|
||||
GLOBAL_DATUM(blood_target_image, /image)
|
||||
GLOBAL_VAR_INIT(blood_target_reset_timer, null)
|
||||
GLOBAL_DATUM(sac_mind, /datum/mind)
|
||||
GLOBAL_VAR_INIT(sac_image, null)
|
||||
GLOBAL_VAR_INIT(cult_vote_called, FALSE)
|
||||
GLOBAL_VAR_INIT(cult_mastered, FALSE)
|
||||
GLOBAL_VAR_INIT(reckoning_complete, FALSE)
|
||||
GLOBAL_VAR_INIT(sac_complete, FALSE)
|
||||
GLOBAL_DATUM(cult_narsie, /obj/singularity/narsie/large/cult)
|
||||
GLOBAL_LIST_EMPTY(summon_spots)
|
||||
@@ -43,11 +43,11 @@ GLOBAL_LIST_INIT(security_depts_prefs, list(SEC_DEPT_RANDOM, SEC_DEPT_NONE, SEC_
|
||||
//Backpacks
|
||||
#define GBACKPACK "Grey Backpack"
|
||||
#define GSATCHEL "Grey Satchel"
|
||||
#define GDUFFLEBAG "Grey Dufflebag"
|
||||
#define GDUFFLEBAG "Grey Dufflebag"
|
||||
#define LSATCHEL "Leather Satchel"
|
||||
#define DBACKPACK "Department Backpack"
|
||||
#define DSATCHEL "Department Satchel"
|
||||
#define DDUFFLEBAG "Department Dufflebag"
|
||||
#define DDUFFLEBAG "Department Dufflebag"
|
||||
GLOBAL_LIST_INIT(backbaglist, list(DBACKPACK, DSATCHEL, DDUFFLEBAG, GBACKPACK, GSATCHEL, GDUFFLEBAG, LSATCHEL))
|
||||
|
||||
//Uplink spawn loc
|
||||
@@ -161,3 +161,4 @@ GLOBAL_LIST_INIT(numbers_as_words, list("One", "Two", "Three", "Four",
|
||||
return L
|
||||
|
||||
GLOBAL_LIST_INIT(station_numerals, greek_letters + phonetic_alphabet + numbers_as_words + generate_number_strings())
|
||||
GLOBAL_LIST_INIT(admiral_messages, list("Do you know how expensive these stations are?","Stop wasting my time.","I was sleeping, thanks a lot.","Stand and fight you cowards!","You knew the risks coming in.","Stop being paranoid.","Whatever's broken just build a new one.","No.", "<i>null</i>","<i>Error: No comment given.</i>", "It's a good day to die!"))
|
||||
|
||||
@@ -104,5 +104,6 @@ GLOBAL_LIST_INIT(maintenance_loot, list(
|
||||
/obj/item/weapon/storage/secure/briefcase = 3,
|
||||
/obj/item/weapon/storage/toolbox/artistic = 2,
|
||||
/obj/item/toy/eightball = 1,
|
||||
/obj/item/weapon/storage/daki = 3,
|
||||
"" = 3
|
||||
))
|
||||
|
||||
@@ -32,7 +32,6 @@ GLOBAL_LIST_EMPTY(generic_event_spawns) //list of all spawns for events
|
||||
|
||||
GLOBAL_LIST_EMPTY(wizardstart)
|
||||
GLOBAL_LIST_EMPTY(newplayer_start)
|
||||
GLOBAL_LIST_EMPTY(latejoin)
|
||||
GLOBAL_LIST_EMPTY(prisonwarp) //prisoners go to these
|
||||
GLOBAL_LIST_EMPTY(holdingfacility) //captured people go here
|
||||
GLOBAL_LIST_EMPTY(xeno_spawn)//Aliens spawn at these.
|
||||
@@ -54,3 +53,4 @@ GLOBAL_LIST_EMPTY(awaydestinations) //a list of landmarks that the warpgate can
|
||||
GLOBAL_LIST_EMPTY(sortedAreas)
|
||||
|
||||
GLOBAL_LIST_EMPTY(transit_markers)
|
||||
GLOBAL_LIST_EMPTY(all_abstract_markers)
|
||||
Executable
+1
@@ -0,0 +1 @@
|
||||
GLOBAL_LIST_EMPTY(commendations)
|
||||
@@ -11,6 +11,7 @@ GLOBAL_LIST_EMPTY(stealthminID) //reference list with IDs that store ckeys,
|
||||
|
||||
GLOBAL_LIST_EMPTY(player_list) //all mobs **with clients attached**. Excludes /mob/dead/new_player
|
||||
GLOBAL_LIST_EMPTY(mob_list) //all mobs, including clientless
|
||||
GLOBAL_LIST_EMPTY(mob_directory) //mob_id -> mob
|
||||
GLOBAL_LIST_EMPTY(living_mob_list) //all alive mobs, including clientless. Excludes /mob/dead/new_player
|
||||
GLOBAL_LIST_EMPTY(dead_mob_list) //all dead mobs, including clientless. Excludes /mob/dead/new_player
|
||||
GLOBAL_LIST_EMPTY(joined_player_list) //all clients that have joined the game at round-start or as a latejoin.
|
||||
@@ -18,5 +19,7 @@ GLOBAL_LIST_EMPTY(silicon_mobs) //all silicon mobs
|
||||
GLOBAL_LIST_EMPTY(ai_list)
|
||||
GLOBAL_LIST_EMPTY(pai_list)
|
||||
GLOBAL_LIST_EMPTY(available_ai_shells)
|
||||
GLOBAL_LIST_EMPTY(language_datums)
|
||||
GLOBAL_LIST_EMPTY(simple_animals)
|
||||
GLOBAL_LIST_EMPTY(simple_animals)
|
||||
|
||||
GLOBAL_LIST_EMPTY(language_datum_instances)
|
||||
GLOBAL_LIST_EMPTY(all_languages)
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
GLOBAL_LIST_INIT(ai_names, world.file2list("config/names/ai.txt"))
|
||||
GLOBAL_LIST_INIT(wizard_first, world.file2list("config/names/wizardfirst.txt"))
|
||||
GLOBAL_LIST_INIT(wizard_second, world.file2list("config/names/wizardsecond.txt"))
|
||||
GLOBAL_LIST_INIT(ninja_titles, world.file2list("config/names/ninjatitle.txt"))
|
||||
GLOBAL_LIST_INIT(ninja_names, world.file2list("config/names/ninjaname.txt"))
|
||||
GLOBAL_LIST_INIT(commando_names, world.file2list("config/names/death_commando.txt"))
|
||||
GLOBAL_LIST_INIT(first_names_male, world.file2list("config/names/first_male.txt"))
|
||||
GLOBAL_LIST_INIT(first_names_female, world.file2list("config/names/first_female.txt"))
|
||||
GLOBAL_LIST_INIT(last_names, world.file2list("config/names/last.txt"))
|
||||
GLOBAL_LIST_INIT(lizard_names_male, world.file2list("config/names/lizard_male.txt"))
|
||||
GLOBAL_LIST_INIT(lizard_names_female, world.file2list("config/names/lizard_female.txt"))
|
||||
GLOBAL_LIST_INIT(clown_names, world.file2list("config/names/clown.txt"))
|
||||
GLOBAL_LIST_INIT(mime_names, world.file2list("config/names/mime.txt"))
|
||||
GLOBAL_LIST_INIT(carp_names, world.file2list("config/names/carp.txt"))
|
||||
GLOBAL_LIST_INIT(golem_names, world.file2list("config/names/golem.txt"))
|
||||
GLOBAL_LIST_INIT(plasmaman_names, world.file2list("config/names/plasmaman.txt"))
|
||||
GLOBAL_LIST_INIT(posibrain_names, list("PBU","HIU","SINA","ARMA","OSI","HBL","MSO","RR","CHRI","CDB","HG","XSI","ORNG","GUN","KOR","MET","FRE","XIS","SLI","PKP","HOG","RZH","GOOF","MRPR","JJR","FIRC","INC","PHL","BGB","ANTR","MIW","WJ","JRD","CHOC","ANCL","JLLO","JNLG","KOS","TKRG","XAL","STLP","CBOS","DUNC","FXMC","DRSD","COI"))
|
||||
GLOBAL_LIST_INIT(ai_names, world.file2list("strings/names/ai.txt"))
|
||||
GLOBAL_LIST_INIT(wizard_first, world.file2list("strings/names/wizardfirst.txt"))
|
||||
GLOBAL_LIST_INIT(wizard_second, world.file2list("strings/names/wizardsecond.txt"))
|
||||
GLOBAL_LIST_INIT(ninja_titles, world.file2list("strings/names/ninjatitle.txt"))
|
||||
GLOBAL_LIST_INIT(ninja_names, world.file2list("strings/names/ninjaname.txt"))
|
||||
GLOBAL_LIST_INIT(commando_names, world.file2list("strings/names/death_commando.txt"))
|
||||
GLOBAL_LIST_INIT(first_names_male, world.file2list("strings/names/first_male.txt"))
|
||||
GLOBAL_LIST_INIT(first_names_female, world.file2list("strings/names/first_female.txt"))
|
||||
GLOBAL_LIST_INIT(last_names, world.file2list("strings/names/last.txt"))
|
||||
GLOBAL_LIST_INIT(lizard_names_male, world.file2list("strings/names/lizard_male.txt"))
|
||||
GLOBAL_LIST_INIT(lizard_names_female, world.file2list("strings/names/lizard_female.txt"))
|
||||
GLOBAL_LIST_INIT(clown_names, world.file2list("strings/names/clown.txt"))
|
||||
GLOBAL_LIST_INIT(mime_names, world.file2list("strings/names/mime.txt"))
|
||||
GLOBAL_LIST_INIT(carp_names, world.file2list("strings/names/carp.txt"))
|
||||
GLOBAL_LIST_INIT(golem_names, world.file2list("strings/names/golem.txt"))
|
||||
GLOBAL_LIST_INIT(plasmaman_names, world.file2list("strings/names/plasmaman.txt"))
|
||||
GLOBAL_LIST_INIT(posibrain_names, world.file2list("strings/names/posibrain.txt"))
|
||||
|
||||
|
||||
GLOBAL_LIST_INIT(verbs, world.file2list("config/names/verbs.txt"))
|
||||
GLOBAL_LIST_INIT(adjectives, world.file2list("config/names/adjectives.txt"))
|
||||
GLOBAL_LIST_INIT(verbs, world.file2list("strings/names/verbs.txt"))
|
||||
GLOBAL_LIST_INIT(adjectives, world.file2list("strings/names/adjectives.txt"))
|
||||
//loaded on startup because of "
|
||||
//would include in rsc if ' was used
|
||||
|
||||
@@ -29,6 +29,9 @@ GLOBAL_LIST_EMPTY(zombie_infection_list) // A list of all zombie_infection org
|
||||
GLOBAL_LIST_EMPTY(meteor_list) // List of all meteors.
|
||||
GLOBAL_LIST_EMPTY(active_jammers) // List of active radio jammers
|
||||
GLOBAL_LIST_EMPTY(ladders)
|
||||
GLOBAL_LIST_EMPTY(trophy_cases)
|
||||
|
||||
GLOBAL_LIST_EMPTY(wire_color_directory)
|
||||
GLOBAL_LIST_EMPTY(wire_name_directory)
|
||||
GLOBAL_LIST_EMPTY(wire_name_directory)
|
||||
|
||||
GLOBAL_LIST_EMPTY(ai_status_displays)
|
||||
|
||||
@@ -5,5 +5,6 @@
|
||||
#define POLL_IGNORE_POSSESSED_BLADE "possessed_blade"
|
||||
#define POLL_IGNORE_ALIEN_LARVA "alien_larva"
|
||||
#define POLL_IGNORE_CLOCKWORK_MARAUDER "clockwork_marauder"
|
||||
#define POLL_IGNORE_SYNDICATE "syndicate"
|
||||
|
||||
GLOBAL_LIST_EMPTY(poll_ignore)
|
||||
|
||||
+35
-27
@@ -1,28 +1,36 @@
|
||||
GLOBAL_VAR(diary)
|
||||
GLOBAL_PROTECT(diary)
|
||||
GLOBAL_VAR(runtime_diary)
|
||||
GLOBAL_PROTECT(runtime_diary)
|
||||
GLOBAL_VAR(diaryofmeanpeople)
|
||||
GLOBAL_PROTECT(diaryofmeanpeople)
|
||||
GLOBAL_VAR(href_logfile)
|
||||
GLOBAL_PROTECT(href_logfile)
|
||||
|
||||
GLOBAL_LIST_EMPTY(bombers)
|
||||
GLOBAL_PROTECT(bombers)
|
||||
GLOBAL_LIST_EMPTY(admin_log)
|
||||
GLOBAL_PROTECT(admin_log)
|
||||
GLOBAL_LIST_EMPTY(lastsignalers) //keeps last 100 signals here in format: "[src] used \ref[src] @ location [src.loc]: [freq]/[code]"
|
||||
GLOBAL_PROTECT(lastsignalers)
|
||||
GLOBAL_LIST_EMPTY(lawchanges) //Stores who uploaded laws to which silicon-based lifeform, and what the law was
|
||||
GLOBAL_PROTECT(lawchanges)
|
||||
|
||||
GLOBAL_LIST_EMPTY(combatlog)
|
||||
GLOBAL_PROTECT(combatlog)
|
||||
GLOBAL_LIST_EMPTY(IClog)
|
||||
GLOBAL_PROTECT(IClog)
|
||||
GLOBAL_LIST_EMPTY(OOClog)
|
||||
GLOBAL_PROTECT(OOClog)
|
||||
GLOBAL_LIST_EMPTY(adminlog)
|
||||
GLOBAL_PROTECT(adminlog)
|
||||
|
||||
GLOBAL_VAR(log_directory)
|
||||
GLOBAL_PROTECT(log_directory)
|
||||
GLOBAL_VAR(world_game_log)
|
||||
GLOBAL_PROTECT(world_game_log)
|
||||
GLOBAL_VAR(world_runtime_log)
|
||||
GLOBAL_PROTECT(world_runtime_log)
|
||||
GLOBAL_VAR(world_attack_log)
|
||||
GLOBAL_PROTECT(world_attack_log)
|
||||
GLOBAL_VAR(world_href_log)
|
||||
GLOBAL_PROTECT(world_href_log)
|
||||
GLOBAL_VAR(round_id)
|
||||
GLOBAL_PROTECT(round_id)
|
||||
GLOBAL_VAR(config_error_log)
|
||||
GLOBAL_PROTECT(config_error_log)
|
||||
|
||||
GLOBAL_LIST_EMPTY(bombers)
|
||||
GLOBAL_PROTECT(bombers)
|
||||
GLOBAL_LIST_EMPTY(admin_log)
|
||||
GLOBAL_PROTECT(admin_log)
|
||||
GLOBAL_LIST_EMPTY(lastsignalers) //keeps last 100 signals here in format: "[src] used \ref[src] @ location [src.loc]: [freq]/[code]"
|
||||
GLOBAL_PROTECT(lastsignalers)
|
||||
GLOBAL_LIST_EMPTY(lawchanges) //Stores who uploaded laws to which silicon-based lifeform, and what the law was
|
||||
GLOBAL_PROTECT(lawchanges)
|
||||
|
||||
GLOBAL_LIST_EMPTY(combatlog)
|
||||
GLOBAL_PROTECT(combatlog)
|
||||
GLOBAL_LIST_EMPTY(IClog)
|
||||
GLOBAL_PROTECT(IClog)
|
||||
GLOBAL_LIST_EMPTY(OOClog)
|
||||
GLOBAL_PROTECT(OOClog)
|
||||
GLOBAL_LIST_EMPTY(adminlog)
|
||||
GLOBAL_PROTECT(adminlog)
|
||||
|
||||
GLOBAL_LIST_EMPTY(individual_log_list) // Logs each mob individual logs, a global so it doesn't get lost on cloning/changing mobs
|
||||
|
||||
GLOBAL_LIST_EMPTY(active_turfs_startlist)
|
||||
@@ -8,7 +8,7 @@ GLOBAL_VAR_INIT(fileaccess_timer, 0)
|
||||
|
||||
GLOBAL_VAR_INIT(TAB, " ")
|
||||
|
||||
GLOBAL_DATUM(data_core, /datum/datacore)
|
||||
GLOBAL_DATUM_INIT(data_core, /datum/datacore, new)
|
||||
|
||||
GLOBAL_VAR_INIT(CELLRATE, 0.002) // multiplier for watts per tick <> cell storage (eg: .002 means if there is a load of 1000 watts, 20 units will be taken from a cell per second)
|
||||
GLOBAL_VAR_INIT(CHARGELEVEL, 0.001) // Cap for how fast cells charge, as a percentage-per-tick (.001 means cellcharge is capped to 1% per second)
|
||||
|
||||
@@ -13,4 +13,4 @@ GLOBAL_REAL_VAR(sqlport) = "3306"
|
||||
GLOBAL_REAL_VAR(sqlfdbkdb) = "test"
|
||||
GLOBAL_REAL_VAR(sqlfdbklogin) = "root"
|
||||
GLOBAL_REAL_VAR(sqlfdbkpass) = ""
|
||||
GLOBAL_REAL_VAR(sqlfdbktableprefix) = "erro_"
|
||||
GLOBAL_REAL_VAR(sqlfdbktableprefix) = ""
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
/client
|
||||
var/list/atom/selected_target[2]
|
||||
var/obj/item/active_mousedown_item = null
|
||||
var/mouseParams = ""
|
||||
var/mouseLocation = null
|
||||
var/mouseObject = null
|
||||
var/mouseControlObject = null
|
||||
|
||||
/client/MouseDown(object, location, control, params)
|
||||
var/delay = mob.CanMobAutoclick(object, location, params)
|
||||
@@ -9,14 +14,26 @@
|
||||
while(selected_target[1])
|
||||
Click(selected_target[1], location, control, selected_target[2])
|
||||
sleep(delay)
|
||||
active_mousedown_item = mob.canMobMousedown(object, location, params)
|
||||
if(active_mousedown_item)
|
||||
active_mousedown_item.onMouseDown(object, location, params, mob)
|
||||
|
||||
/client/MouseUp(object, location, control, params)
|
||||
selected_target[1] = null
|
||||
if(active_mousedown_item)
|
||||
active_mousedown_item.onMouseUp(object, location, params, mob)
|
||||
active_mousedown_item = null
|
||||
|
||||
/client/MouseDrag(src_object,atom/over_object,src_location,over_location,src_control,over_control,params)
|
||||
if(selected_target[1] && over_object.IsAutoclickable())
|
||||
mouseParams = params
|
||||
mouseLocation = over_location
|
||||
mouseObject = over_object
|
||||
mouseControlObject = over_control
|
||||
if(selected_target[1] && over_object && over_object.IsAutoclickable())
|
||||
selected_target[1] = over_object
|
||||
selected_target[2] = params
|
||||
if(active_mousedown_item)
|
||||
active_mousedown_item.onMouseDrag(src_object, over_object, src_location, over_location, params, mob)
|
||||
|
||||
/mob/proc/CanMobAutoclick(object, location, params)
|
||||
|
||||
@@ -27,8 +44,31 @@
|
||||
if(h)
|
||||
. = h.CanItemAutoclick(object, location, params)
|
||||
|
||||
/mob/proc/canMobMousedown(object, location, params)
|
||||
|
||||
/mob/living/carbon/canMobMousedown(atom/object, location, params)
|
||||
var/obj/item/H = get_active_held_item()
|
||||
if(H)
|
||||
. = H.canItemMouseDown(object, location, params)
|
||||
|
||||
/obj/item/proc/CanItemAutoclick(object, location, params)
|
||||
|
||||
/obj/item/proc/canItemMouseDown(object, location, params)
|
||||
if(canMouseDown)
|
||||
return src
|
||||
|
||||
/obj/item/proc/onMouseDown(object, location, params, mob)
|
||||
return
|
||||
|
||||
/obj/item/proc/onMouseUp(object, location, params, mob)
|
||||
return
|
||||
|
||||
/obj/item/proc/onMouseDrag(src_object, over_object, src_location, over_location, params, mob)
|
||||
return
|
||||
|
||||
/obj/item
|
||||
var/canMouseDown = FALSE
|
||||
|
||||
/obj/item/weapon/gun
|
||||
var/automatic = 0 //can gun use it, 0 is no, anything above 0 is the delay between clicks in ds
|
||||
|
||||
@@ -42,4 +82,11 @@
|
||||
. = 0
|
||||
|
||||
/obj/screen/click_catcher/IsAutoclickable()
|
||||
. = 1
|
||||
. = 1
|
||||
|
||||
//Please don't roast me too hard
|
||||
/client/MouseMove(object,location,control,params)
|
||||
mouseParams = params
|
||||
mouseLocation = location
|
||||
mouseObject = object
|
||||
mouseControlObject = control
|
||||
|
||||
+468
-413
@@ -1,413 +1,468 @@
|
||||
/*
|
||||
Click code cleanup
|
||||
~Sayu
|
||||
*/
|
||||
|
||||
// 1 decisecond click delay (above and beyond mob/next_move)
|
||||
//This is mainly modified by click code, to modify click delays elsewhere, use next_move and changeNext_move()
|
||||
/mob/var/next_click = 0
|
||||
|
||||
// THESE DO NOT EFFECT THE BASE 1 DECISECOND DELAY OF NEXT_CLICK
|
||||
/mob/var/next_move_adjust = 0 //Amount to adjust action/click delays by, + or -
|
||||
/mob/var/next_move_modifier = 1 //Value to multiply action/click delays by
|
||||
|
||||
|
||||
//Delays the mob's next click/action by num deciseconds
|
||||
// eg: 10-3 = 7 deciseconds of delay
|
||||
// eg: 10*0.5 = 5 deciseconds of delay
|
||||
// DOES NOT EFFECT THE BASE 1 DECISECOND DELAY OF NEXT_CLICK
|
||||
|
||||
/mob/proc/changeNext_move(num)
|
||||
next_move = world.time + ((num+next_move_adjust)*next_move_modifier)
|
||||
|
||||
|
||||
/*
|
||||
Before anything else, defer these calls to a per-mobtype handler. This allows us to
|
||||
remove istype() spaghetti code, but requires the addition of other handler procs to simplify it.
|
||||
|
||||
Alternately, you could hardcode every mob's variation in a flat ClickOn() proc; however,
|
||||
that's a lot of code duplication and is hard to maintain.
|
||||
|
||||
Note that this proc can be overridden, and is in the case of screen objects.
|
||||
*/
|
||||
/atom/Click(location,control,params)
|
||||
if(initialized)
|
||||
usr.ClickOn(src, params)
|
||||
|
||||
/atom/DblClick(location,control,params)
|
||||
if(initialized)
|
||||
usr.DblClickOn(src,params)
|
||||
|
||||
/atom/MouseWheel(delta_x,delta_y,location,control,params)
|
||||
if(initialized)
|
||||
usr.MouseWheelOn(src, delta_x, delta_y, params)
|
||||
|
||||
/*
|
||||
Standard mob ClickOn()
|
||||
Handles exceptions: Buildmode, middle click, modified clicks, mech actions
|
||||
|
||||
After that, mostly just check your state, check whether you're holding an item,
|
||||
check whether you're adjacent to the target, then pass off the click to whoever
|
||||
is recieving it.
|
||||
The most common are:
|
||||
* mob/UnarmedAttack(atom,adjacent) - used here only when adjacent, with no item in hand; in the case of humans, checks gloves
|
||||
* atom/attackby(item,user) - used only when adjacent
|
||||
* item/afterattack(atom,user,adjacent,params) - used both ranged and adjacent
|
||||
* mob/RangedAttack(atom,params) - used only ranged, only used for tk and laser eyes but could be changed
|
||||
*/
|
||||
/mob/proc/ClickOn( atom/A, params )
|
||||
if(world.time <= next_click)
|
||||
return
|
||||
next_click = world.time + 1
|
||||
|
||||
if(client && client.click_intercept)
|
||||
if(call(client.click_intercept, "InterceptClickOn")(src, params, A))
|
||||
return
|
||||
|
||||
var/list/modifiers = params2list(params)
|
||||
if(modifiers["shift"] && modifiers["middle"])
|
||||
ShiftMiddleClickOn(A)
|
||||
return
|
||||
if(modifiers["shift"] && modifiers["ctrl"])
|
||||
CtrlShiftClickOn(A)
|
||||
return
|
||||
if(modifiers["middle"])
|
||||
MiddleClickOn(A)
|
||||
return
|
||||
if(modifiers["shift"])
|
||||
ShiftClickOn(A)
|
||||
return
|
||||
if(modifiers["alt"]) // alt and alt-gr (rightalt)
|
||||
AltClickOn(A)
|
||||
return
|
||||
if(modifiers["ctrl"])
|
||||
CtrlClickOn(A)
|
||||
return
|
||||
|
||||
if(incapacitated(ignore_restraints = 1))
|
||||
return
|
||||
|
||||
face_atom(A)
|
||||
|
||||
if(next_move > world.time) // in the year 2000...
|
||||
return
|
||||
|
||||
if(istype(loc,/obj/mecha))
|
||||
var/obj/mecha/M = loc
|
||||
return M.click_action(A,src,params)
|
||||
|
||||
if(restrained())
|
||||
changeNext_move(CLICK_CD_HANDCUFFED) //Doing shit in cuffs shall be vey slow
|
||||
RestrainedClickOn(A)
|
||||
return
|
||||
|
||||
if(in_throw_mode)
|
||||
throw_item(A)
|
||||
return
|
||||
|
||||
var/obj/item/W = get_active_held_item()
|
||||
|
||||
|
||||
if(W == A)
|
||||
W.attack_self(src)
|
||||
update_inv_hands()
|
||||
return
|
||||
|
||||
// operate three levels deep here (item in backpack in src; item in box in backpack in src, not any deeper)
|
||||
if(A.ClickAccessible(src, depth=INVENTORY_DEPTH))
|
||||
// No adjacency needed
|
||||
if(W)
|
||||
melee_item_attack_chain(src, W, A, params)
|
||||
else
|
||||
if(ismob(A))
|
||||
changeNext_move(CLICK_CD_MELEE)
|
||||
UnarmedAttack(A)
|
||||
return
|
||||
|
||||
if(!isturf(loc)) // This is going to stop you from telekinesing from inside a closet, but I don't shed many tears for that
|
||||
return
|
||||
|
||||
// Allows you to click on a box's contents, if that box is on the ground, but no deeper than that
|
||||
if(isturf(A) || isturf(A.loc) || (A.loc && isturf(A.loc.loc)))
|
||||
if(Adjacent(A) || (W && CheckReach(src, A, W.reach))) //Adjacent or reaching attacks
|
||||
if(W)
|
||||
melee_item_attack_chain(src, W, A, params)
|
||||
else
|
||||
if(ismob(A))
|
||||
changeNext_move(CLICK_CD_MELEE)
|
||||
UnarmedAttack(A, 1)
|
||||
return
|
||||
else // non-adjacent click
|
||||
if(W)
|
||||
W.afterattack(A,src,0,params) // 0: not Adjacent
|
||||
else
|
||||
RangedAttack(A, params)
|
||||
|
||||
/proc/CheckReach(atom/movable/here, atom/movable/there, reach)
|
||||
if(!here || !there)
|
||||
return
|
||||
switch(reach)
|
||||
if(0)
|
||||
return here.loc == there.loc
|
||||
if(1)
|
||||
return here.Adjacent(there)
|
||||
if(2 to INFINITY)
|
||||
var/obj/dummy = new(get_turf(here)) //We'll try to move this every tick, failing if we can't
|
||||
dummy.pass_flags |= PASSTABLE
|
||||
for(var/i in 1 to reach) //Limit it to that many tries
|
||||
var/turf/T = get_step(dummy, get_dir(dummy, there))
|
||||
if(dummy.loc == there.loc)
|
||||
qdel(dummy)
|
||||
return 1
|
||||
if(there.density && dummy in range(1, there)) //For windows and suchlike
|
||||
qdel(dummy)
|
||||
return 1
|
||||
if(!dummy.Move(T)) //we're blocked!
|
||||
qdel(dummy)
|
||||
return
|
||||
|
||||
// Default behavior: ignore double clicks (the second click that makes the doubleclick call already calls for a normal click)
|
||||
/mob/proc/DblClickOn(atom/A, params)
|
||||
return
|
||||
|
||||
|
||||
/*
|
||||
Translates into attack_hand, etc.
|
||||
|
||||
Note: proximity_flag here is used to distinguish between normal usage (flag=1),
|
||||
and usage when clicking on things telekinetically (flag=0). This proc will
|
||||
not be called at ranged except with telekinesis.
|
||||
|
||||
proximity_flag is not currently passed to attack_hand, and is instead used
|
||||
in human click code to allow glove touches only at melee range.
|
||||
*/
|
||||
/mob/proc/UnarmedAttack(atom/A, proximity_flag)
|
||||
if(ismob(A))
|
||||
changeNext_move(CLICK_CD_MELEE)
|
||||
return
|
||||
|
||||
/*
|
||||
Ranged unarmed attack:
|
||||
|
||||
This currently is just a default for all mobs, involving
|
||||
laser eyes and telekinesis. You could easily add exceptions
|
||||
for things like ranged glove touches, spitting alien acid/neurotoxin,
|
||||
animals lunging, etc.
|
||||
*/
|
||||
/mob/proc/RangedAttack(atom/A, params)
|
||||
/*
|
||||
Restrained ClickOn
|
||||
|
||||
Used when you are handcuffed and click things.
|
||||
Not currently used by anything but could easily be.
|
||||
*/
|
||||
/mob/proc/RestrainedClickOn(atom/A)
|
||||
return
|
||||
|
||||
/*
|
||||
Middle click
|
||||
Only used for swapping hands
|
||||
*/
|
||||
/mob/proc/MiddleClickOn(atom/A)
|
||||
return
|
||||
|
||||
/mob/living/carbon/MiddleClickOn(atom/A)
|
||||
if(!src.stat && src.mind && src.mind.changeling && src.mind.changeling.chosen_sting && (istype(A, /mob/living/carbon)) && (A != src))
|
||||
next_click = world.time + 5
|
||||
mind.changeling.chosen_sting.try_to_sting(src, A)
|
||||
else
|
||||
swap_hand()
|
||||
|
||||
/mob/living/simple_animal/drone/MiddleClickOn(atom/A)
|
||||
swap_hand()
|
||||
|
||||
// In case of use break glass
|
||||
/*
|
||||
/atom/proc/MiddleClick(mob/M as mob)
|
||||
return
|
||||
*/
|
||||
|
||||
/*
|
||||
Shift click
|
||||
For most mobs, examine.
|
||||
This is overridden in ai.dm
|
||||
*/
|
||||
/mob/proc/ShiftClickOn(atom/A)
|
||||
A.ShiftClick(src)
|
||||
return
|
||||
/atom/proc/ShiftClick(mob/user)
|
||||
if(user.client && user.client.eye == user || user.client.eye == user.loc)
|
||||
user.examinate(src)
|
||||
return
|
||||
|
||||
/*
|
||||
Ctrl click
|
||||
For most objects, pull
|
||||
*/
|
||||
|
||||
/mob/proc/CtrlClickOn(atom/A)
|
||||
A.CtrlClick(src)
|
||||
return
|
||||
|
||||
/atom/proc/CtrlClick(mob/user)
|
||||
var/mob/living/ML = user
|
||||
if(istype(ML))
|
||||
ML.pulled(src)
|
||||
|
||||
/mob/living/carbon/human/CtrlClick(mob/user)
|
||||
if(ishuman(user) && Adjacent(user))
|
||||
var/mob/living/carbon/human/H = user
|
||||
H.dna.species.grab(H, src, H.martial_art)
|
||||
H.next_click = world.time + CLICK_CD_MELEE
|
||||
else
|
||||
..()
|
||||
/*
|
||||
Alt click
|
||||
Unused except for AI
|
||||
*/
|
||||
/mob/proc/AltClickOn(atom/A)
|
||||
A.AltClick(src)
|
||||
return
|
||||
|
||||
/mob/living/carbon/AltClickOn(atom/A)
|
||||
if(!src.stat && src.mind && src.mind.changeling && src.mind.changeling.chosen_sting && (istype(A, /mob/living/carbon)) && (A != src))
|
||||
next_click = world.time + 5
|
||||
mind.changeling.chosen_sting.try_to_sting(src, A)
|
||||
else
|
||||
..()
|
||||
|
||||
/atom/proc/AltClick(mob/user)
|
||||
var/turf/T = get_turf(src)
|
||||
if(T && user.TurfAdjacent(T))
|
||||
if(user.listed_turf == T)
|
||||
user.listed_turf = null
|
||||
else
|
||||
user.listed_turf = T
|
||||
user.client.statpanel = T.name
|
||||
return
|
||||
|
||||
/mob/proc/TurfAdjacent(turf/T)
|
||||
return T.Adjacent(src)
|
||||
|
||||
/*
|
||||
Control+Shift click
|
||||
Unused except for AI
|
||||
*/
|
||||
/mob/proc/CtrlShiftClickOn(atom/A)
|
||||
A.CtrlShiftClick(src)
|
||||
return
|
||||
|
||||
/mob/proc/ShiftMiddleClickOn(atom/A)
|
||||
src.pointed(A)
|
||||
return
|
||||
|
||||
/atom/proc/CtrlShiftClick(mob/user)
|
||||
return
|
||||
|
||||
/*
|
||||
Helper to check can the mob click/access an item.
|
||||
Used by mob inventory and storage items.
|
||||
*/
|
||||
/atom/proc/ClickAccessible(mob/user, depth=1)
|
||||
if(src == user.loc || (src in user.contents))
|
||||
return TRUE
|
||||
|
||||
if(loc && depth > 1)
|
||||
return loc.ClickAccessible(user, depth-1)
|
||||
|
||||
/turf/ClickAccessible(mob/user, depth=1)
|
||||
return
|
||||
|
||||
|
||||
/*
|
||||
Misc helpers
|
||||
|
||||
Laser Eyes: as the name implies, handles this since nothing else does currently
|
||||
face_atom: turns the mob towards what you clicked on
|
||||
*/
|
||||
/mob/proc/LaserEyes(atom/A)
|
||||
return
|
||||
|
||||
/mob/living/LaserEyes(atom/A)
|
||||
changeNext_move(CLICK_CD_RANGE)
|
||||
var/turf/T = get_turf(src)
|
||||
var/turf/U = get_turf(A)
|
||||
|
||||
var/obj/item/projectile/beam/LE = new /obj/item/projectile/beam( loc )
|
||||
LE.icon = 'icons/effects/genetics.dmi'
|
||||
LE.icon_state = "eyelasers"
|
||||
playsound(usr.loc, 'sound/weapons/taser2.ogg', 75, 1)
|
||||
|
||||
LE.firer = src
|
||||
LE.def_zone = get_organ_target()
|
||||
LE.original = A
|
||||
LE.current = T
|
||||
LE.yo = U.y - T.y
|
||||
LE.xo = U.x - T.x
|
||||
LE.fire()
|
||||
|
||||
// Simple helper to face what you clicked on, in case it should be needed in more than one place
|
||||
/mob/proc/face_atom(atom/A)
|
||||
if( buckled || stat != CONSCIOUS || !A || !x || !y || !A.x || !A.y )
|
||||
return
|
||||
var/dx = A.x - x
|
||||
var/dy = A.y - y
|
||||
if(!dx && !dy) // Wall items are graphically shifted but on the floor
|
||||
if(A.pixel_y > 16)
|
||||
setDir(NORTH)
|
||||
else if(A.pixel_y < -16)
|
||||
setDir(SOUTH)
|
||||
else if(A.pixel_x > 16)
|
||||
setDir(EAST)
|
||||
else if(A.pixel_x < -16)
|
||||
setDir(WEST)
|
||||
return
|
||||
|
||||
if(abs(dx) < abs(dy))
|
||||
if(dy > 0)
|
||||
setDir(NORTH)
|
||||
else
|
||||
setDir(SOUTH)
|
||||
else
|
||||
if(dx > 0)
|
||||
setDir(EAST)
|
||||
else
|
||||
setDir(WEST)
|
||||
|
||||
/obj/screen/click_catcher
|
||||
icon = 'icons/mob/screen_gen.dmi'
|
||||
icon_state = "click_catcher"
|
||||
plane = CLICKCATCHER_PLANE
|
||||
mouse_opacity = 2
|
||||
screen_loc = "CENTER"
|
||||
|
||||
/obj/screen/click_catcher/New()
|
||||
..()
|
||||
transform = matrix(200, 0, 0, 0, 200, 0)
|
||||
|
||||
/obj/screen/click_catcher/Click(location, control, params)
|
||||
var/list/modifiers = params2list(params)
|
||||
if(modifiers["middle"] && istype(usr, /mob/living/carbon))
|
||||
var/mob/living/carbon/C = usr
|
||||
C.swap_hand()
|
||||
else
|
||||
var/turf/T = params2turf(modifiers["screen-loc"], get_turf(usr))
|
||||
if(T)
|
||||
T.Click(location, control, params)
|
||||
. = 1
|
||||
|
||||
|
||||
/* MouseWheelOn */
|
||||
|
||||
/mob/proc/MouseWheelOn(atom/A, delta_x, delta_y, params)
|
||||
return
|
||||
|
||||
/mob/dead/observer/MouseWheelOn(atom/A, delta_x, delta_y, params)
|
||||
var/list/modifier = params2list(params)
|
||||
if(modifier["shift"])
|
||||
var/view = 0
|
||||
if(delta_y > 0)
|
||||
view = -1
|
||||
else
|
||||
view = 1
|
||||
add_view_range(view)
|
||||
/*
|
||||
Click code cleanup
|
||||
~Sayu
|
||||
*/
|
||||
|
||||
// 1 decisecond click delay (above and beyond mob/next_move)
|
||||
//This is mainly modified by click code, to modify click delays elsewhere, use next_move and changeNext_move()
|
||||
/mob/var/next_click = 0
|
||||
|
||||
// THESE DO NOT EFFECT THE BASE 1 DECISECOND DELAY OF NEXT_CLICK
|
||||
/mob/var/next_move_adjust = 0 //Amount to adjust action/click delays by, + or -
|
||||
/mob/var/next_move_modifier = 1 //Value to multiply action/click delays by
|
||||
|
||||
|
||||
//Delays the mob's next click/action by num deciseconds
|
||||
// eg: 10-3 = 7 deciseconds of delay
|
||||
// eg: 10*0.5 = 5 deciseconds of delay
|
||||
// DOES NOT EFFECT THE BASE 1 DECISECOND DELAY OF NEXT_CLICK
|
||||
|
||||
/mob/proc/changeNext_move(num)
|
||||
next_move = world.time + ((num+next_move_adjust)*next_move_modifier)
|
||||
|
||||
|
||||
/*
|
||||
Before anything else, defer these calls to a per-mobtype handler. This allows us to
|
||||
remove istype() spaghetti code, but requires the addition of other handler procs to simplify it.
|
||||
|
||||
Alternately, you could hardcode every mob's variation in a flat ClickOn() proc; however,
|
||||
that's a lot of code duplication and is hard to maintain.
|
||||
|
||||
Note that this proc can be overridden, and is in the case of screen objects.
|
||||
*/
|
||||
/atom/Click(location,control,params)
|
||||
if(initialized)
|
||||
usr.ClickOn(src, params)
|
||||
|
||||
/atom/DblClick(location,control,params)
|
||||
if(initialized)
|
||||
usr.DblClickOn(src,params)
|
||||
|
||||
/atom/MouseWheel(delta_x,delta_y,location,control,params)
|
||||
if(initialized)
|
||||
usr.MouseWheelOn(src, delta_x, delta_y, params)
|
||||
|
||||
/*
|
||||
Standard mob ClickOn()
|
||||
Handles exceptions: Buildmode, middle click, modified clicks, mech actions
|
||||
|
||||
After that, mostly just check your state, check whether you're holding an item,
|
||||
check whether you're adjacent to the target, then pass off the click to whoever
|
||||
is recieving it.
|
||||
The most common are:
|
||||
* mob/UnarmedAttack(atom,adjacent) - used here only when adjacent, with no item in hand; in the case of humans, checks gloves
|
||||
* atom/attackby(item,user) - used only when adjacent
|
||||
* item/afterattack(atom,user,adjacent,params) - used both ranged and adjacent
|
||||
* mob/RangedAttack(atom,params) - used only ranged, only used for tk and laser eyes but could be changed
|
||||
*/
|
||||
/mob/proc/ClickOn( atom/A, params )
|
||||
if(world.time <= next_click)
|
||||
return
|
||||
next_click = world.time + 1
|
||||
|
||||
if(client && client.click_intercept)
|
||||
if(call(client.click_intercept, "InterceptClickOn")(src, params, A))
|
||||
return
|
||||
|
||||
var/list/modifiers = params2list(params)
|
||||
if(modifiers["shift"] && modifiers["middle"])
|
||||
ShiftMiddleClickOn(A)
|
||||
return
|
||||
if(modifiers["shift"] && modifiers["ctrl"])
|
||||
CtrlShiftClickOn(A)
|
||||
return
|
||||
if(modifiers["middle"])
|
||||
MiddleClickOn(A)
|
||||
return
|
||||
if(modifiers["shift"])
|
||||
ShiftClickOn(A)
|
||||
return
|
||||
if(modifiers["alt"]) // alt and alt-gr (rightalt)
|
||||
AltClickOn(A)
|
||||
return
|
||||
if(modifiers["ctrl"])
|
||||
CtrlClickOn(A)
|
||||
return
|
||||
|
||||
if(incapacitated(ignore_restraints = 1))
|
||||
return
|
||||
|
||||
face_atom(A)
|
||||
|
||||
if(next_move > world.time) // in the year 2000...
|
||||
return
|
||||
|
||||
if(!modifiers["catcher"] && A.IsObscured())
|
||||
return
|
||||
|
||||
if(istype(loc,/obj/mecha))
|
||||
var/obj/mecha/M = loc
|
||||
return M.click_action(A,src,params)
|
||||
|
||||
if(restrained())
|
||||
changeNext_move(CLICK_CD_HANDCUFFED) //Doing shit in cuffs shall be vey slow
|
||||
RestrainedClickOn(A)
|
||||
return
|
||||
|
||||
if(in_throw_mode)
|
||||
throw_item(A)
|
||||
return
|
||||
|
||||
var/obj/item/W = get_active_held_item()
|
||||
|
||||
if(W == A)
|
||||
W.attack_self(src)
|
||||
update_inv_hands()
|
||||
return
|
||||
|
||||
//These are always reachable.
|
||||
//User itself, current loc, and user inventory
|
||||
if(DirectAccess(A))
|
||||
if(W)
|
||||
W.melee_attack_chain(src, A, params)
|
||||
else
|
||||
if(ismob(A))
|
||||
changeNext_move(CLICK_CD_MELEE)
|
||||
UnarmedAttack(A)
|
||||
return
|
||||
|
||||
//Can't reach anything else in lockers or other weirdness
|
||||
if(!loc.AllowClick())
|
||||
return
|
||||
|
||||
//Standard reach turf to turf or reaching inside storage
|
||||
if(CanReach(A,W))
|
||||
if(W)
|
||||
W.melee_attack_chain(src, A, params)
|
||||
else
|
||||
if(ismob(A))
|
||||
changeNext_move(CLICK_CD_MELEE)
|
||||
UnarmedAttack(A,1)
|
||||
else
|
||||
if(W)
|
||||
W.afterattack(A,src,0,params)
|
||||
else
|
||||
RangedAttack(A,params)
|
||||
|
||||
//Is the atom obscured by a PREVENT_CLICK_UNDER object above it
|
||||
/atom/proc/IsObscured()
|
||||
if(!isturf(loc)) //This only makes sense for things directly on turfs for now
|
||||
return FALSE
|
||||
var/turf/T = get_turf_pixel(src)
|
||||
if(!T)
|
||||
return FALSE
|
||||
for(var/atom/movable/AM in T)
|
||||
if(AM.flags & PREVENT_CLICK_UNDER && AM.density && AM.layer > layer)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/turf/IsObscured()
|
||||
for(var/atom/movable/AM in src)
|
||||
if(AM.flags & PREVENT_CLICK_UNDER && AM.density)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/atom/movable/proc/CanReach(atom/target,obj/item/tool,view_only = FALSE)
|
||||
if(isturf(target) || isturf(target.loc) || DirectAccess(target)) //Directly accessible atoms
|
||||
if(Adjacent(target) || (tool && CheckToolReach(src, target, tool.reach))) //Adjacent or reaching attacks
|
||||
return TRUE
|
||||
else
|
||||
//Things inside storage insde another storage
|
||||
//Eg Contents of a box in a backpack
|
||||
var/atom/outer_storage = get_atom_on_turf(target)
|
||||
if(outer_storage == target) //whatever that is we don't want infinite loop.
|
||||
return FALSE
|
||||
if(outer_storage && CanReach(outer_storage,tool) && outer_storage.CanReachStorage(target,src,view_only ? STORAGE_VIEW_DEPTH : INVENTORY_DEPTH))
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
//Can [target] in this container be reached by [user], can't be more than [depth] levels deep
|
||||
/atom/proc/CanReachStorage(atom/target,user,depth)
|
||||
return FALSE
|
||||
|
||||
/obj/item/weapon/storage/CanReachStorage(atom/target,user,depth)
|
||||
while(target && depth > 0)
|
||||
target = target.loc
|
||||
depth--
|
||||
if(target == src)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/atom/movable/proc/DirectAccess(atom/target)
|
||||
if(target == src)
|
||||
return TRUE
|
||||
if(target == loc)
|
||||
return TRUE
|
||||
|
||||
/mob/DirectAccess(atom/target)
|
||||
if(..())
|
||||
return TRUE
|
||||
if(target in contents) //This could probably use moving down and restricting to inventory only
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/mob/living/DirectAccess(atom/target)
|
||||
if(..()) //Lightweight checks first
|
||||
return TRUE
|
||||
if(target in GetAllContents())
|
||||
return TRUE
|
||||
|
||||
/atom/proc/AllowClick()
|
||||
return FALSE
|
||||
|
||||
/turf/AllowClick()
|
||||
return TRUE
|
||||
|
||||
/proc/CheckToolReach(atom/movable/here, atom/movable/there, reach)
|
||||
if(!here || !there)
|
||||
return
|
||||
switch(reach)
|
||||
if(0)
|
||||
return FALSE
|
||||
if(1)
|
||||
return FALSE //here.Adjacent(there)
|
||||
if(2 to INFINITY)
|
||||
var/obj/dummy = new(get_turf(here))
|
||||
dummy.pass_flags |= PASSTABLE
|
||||
dummy.invisibility = INVISIBILITY_ABSTRACT
|
||||
for(var/i in 1 to reach) //Limit it to that many tries
|
||||
var/turf/T = get_step(dummy, get_dir(dummy, there))
|
||||
if(dummy.CanReach(there))
|
||||
qdel(dummy)
|
||||
return TRUE
|
||||
if(!dummy.Move(T)) //we're blocked!
|
||||
qdel(dummy)
|
||||
return
|
||||
qdel(dummy)
|
||||
|
||||
// Default behavior: ignore double clicks (the second click that makes the doubleclick call already calls for a normal click)
|
||||
/mob/proc/DblClickOn(atom/A, params)
|
||||
return
|
||||
|
||||
|
||||
/*
|
||||
Translates into attack_hand, etc.
|
||||
|
||||
Note: proximity_flag here is used to distinguish between normal usage (flag=1),
|
||||
and usage when clicking on things telekinetically (flag=0). This proc will
|
||||
not be called at ranged except with telekinesis.
|
||||
|
||||
proximity_flag is not currently passed to attack_hand, and is instead used
|
||||
in human click code to allow glove touches only at melee range.
|
||||
*/
|
||||
/mob/proc/UnarmedAttack(atom/A, proximity_flag)
|
||||
if(ismob(A))
|
||||
changeNext_move(CLICK_CD_MELEE)
|
||||
return
|
||||
|
||||
/*
|
||||
Ranged unarmed attack:
|
||||
|
||||
This currently is just a default for all mobs, involving
|
||||
laser eyes and telekinesis. You could easily add exceptions
|
||||
for things like ranged glove touches, spitting alien acid/neurotoxin,
|
||||
animals lunging, etc.
|
||||
*/
|
||||
/mob/proc/RangedAttack(atom/A, params)
|
||||
/*
|
||||
Restrained ClickOn
|
||||
|
||||
Used when you are handcuffed and click things.
|
||||
Not currently used by anything but could easily be.
|
||||
*/
|
||||
/mob/proc/RestrainedClickOn(atom/A)
|
||||
return
|
||||
|
||||
/*
|
||||
Middle click
|
||||
Only used for swapping hands
|
||||
*/
|
||||
/mob/proc/MiddleClickOn(atom/A)
|
||||
return
|
||||
|
||||
/mob/living/carbon/MiddleClickOn(atom/A)
|
||||
if(!src.stat && src.mind && src.mind.changeling && src.mind.changeling.chosen_sting && (istype(A, /mob/living/carbon)) && (A != src))
|
||||
next_click = world.time + 5
|
||||
mind.changeling.chosen_sting.try_to_sting(src, A)
|
||||
else
|
||||
swap_hand()
|
||||
|
||||
/mob/living/simple_animal/drone/MiddleClickOn(atom/A)
|
||||
swap_hand()
|
||||
|
||||
// In case of use break glass
|
||||
/*
|
||||
/atom/proc/MiddleClick(mob/M as mob)
|
||||
return
|
||||
*/
|
||||
|
||||
/*
|
||||
Shift click
|
||||
For most mobs, examine.
|
||||
This is overridden in ai.dm
|
||||
*/
|
||||
/mob/proc/ShiftClickOn(atom/A)
|
||||
A.ShiftClick(src)
|
||||
return
|
||||
/atom/proc/ShiftClick(mob/user)
|
||||
if(user.client && user.client.eye == user || user.client.eye == user.loc)
|
||||
user.examinate(src)
|
||||
return
|
||||
|
||||
/*
|
||||
Ctrl click
|
||||
For most objects, pull
|
||||
*/
|
||||
|
||||
/mob/proc/CtrlClickOn(atom/A)
|
||||
A.CtrlClick(src)
|
||||
return
|
||||
|
||||
/atom/proc/CtrlClick(mob/user)
|
||||
var/mob/living/ML = user
|
||||
if(istype(ML))
|
||||
ML.pulled(src)
|
||||
|
||||
/mob/living/carbon/human/CtrlClick(mob/user)
|
||||
if(ishuman(user) && Adjacent(user))
|
||||
var/mob/living/carbon/human/H = user
|
||||
H.dna.species.grab(H, src, H.mind.martial_art)
|
||||
H.changeNext_move(CLICK_CD_MELEE)
|
||||
else
|
||||
..()
|
||||
/*
|
||||
Alt click
|
||||
Unused except for AI
|
||||
*/
|
||||
/mob/proc/AltClickOn(atom/A)
|
||||
A.AltClick(src)
|
||||
return
|
||||
|
||||
/mob/living/carbon/AltClickOn(atom/A)
|
||||
if(!src.stat && src.mind && src.mind.changeling && src.mind.changeling.chosen_sting && (istype(A, /mob/living/carbon)) && (A != src))
|
||||
next_click = world.time + 5
|
||||
mind.changeling.chosen_sting.try_to_sting(src, A)
|
||||
else
|
||||
..()
|
||||
|
||||
/atom/proc/AltClick(mob/user)
|
||||
var/turf/T = get_turf(src)
|
||||
if(T && user.TurfAdjacent(T))
|
||||
if(user.listed_turf == T)
|
||||
user.listed_turf = null
|
||||
else
|
||||
user.listed_turf = T
|
||||
user.client.statpanel = T.name
|
||||
return
|
||||
|
||||
/mob/proc/TurfAdjacent(turf/T)
|
||||
return T.Adjacent(src)
|
||||
|
||||
/*
|
||||
Control+Shift click
|
||||
Unused except for AI
|
||||
*/
|
||||
/mob/proc/CtrlShiftClickOn(atom/A)
|
||||
A.CtrlShiftClick(src)
|
||||
return
|
||||
|
||||
/mob/proc/ShiftMiddleClickOn(atom/A)
|
||||
src.pointed(A)
|
||||
return
|
||||
|
||||
/atom/proc/CtrlShiftClick(mob/user)
|
||||
return
|
||||
|
||||
/*
|
||||
Misc helpers
|
||||
|
||||
Laser Eyes: as the name implies, handles this since nothing else does currently
|
||||
face_atom: turns the mob towards what you clicked on
|
||||
*/
|
||||
/mob/proc/LaserEyes(atom/A)
|
||||
return
|
||||
|
||||
/mob/living/LaserEyes(atom/A)
|
||||
changeNext_move(CLICK_CD_RANGE)
|
||||
var/turf/T = get_turf(src)
|
||||
var/turf/U = get_turf(A)
|
||||
|
||||
var/obj/item/projectile/beam/LE = new /obj/item/projectile/beam( loc )
|
||||
LE.icon = 'icons/effects/genetics.dmi'
|
||||
LE.icon_state = "eyelasers"
|
||||
playsound(usr.loc, 'sound/weapons/taser2.ogg', 75, 1)
|
||||
|
||||
LE.firer = src
|
||||
LE.def_zone = get_organ_target()
|
||||
LE.original = A
|
||||
LE.current = T
|
||||
LE.yo = U.y - T.y
|
||||
LE.xo = U.x - T.x
|
||||
LE.fire()
|
||||
|
||||
// Simple helper to face what you clicked on, in case it should be needed in more than one place
|
||||
/mob/proc/face_atom(atom/A)
|
||||
if( buckled || stat != CONSCIOUS || !A || !x || !y || !A.x || !A.y )
|
||||
return
|
||||
var/dx = A.x - x
|
||||
var/dy = A.y - y
|
||||
if(!dx && !dy) // Wall items are graphically shifted but on the floor
|
||||
if(A.pixel_y > 16)
|
||||
setDir(NORTH)
|
||||
else if(A.pixel_y < -16)
|
||||
setDir(SOUTH)
|
||||
else if(A.pixel_x > 16)
|
||||
setDir(EAST)
|
||||
else if(A.pixel_x < -16)
|
||||
setDir(WEST)
|
||||
return
|
||||
|
||||
if(abs(dx) < abs(dy))
|
||||
if(dy > 0)
|
||||
setDir(NORTH)
|
||||
else
|
||||
setDir(SOUTH)
|
||||
else
|
||||
if(dx > 0)
|
||||
setDir(EAST)
|
||||
else
|
||||
setDir(WEST)
|
||||
|
||||
/obj/screen/click_catcher
|
||||
icon = 'icons/mob/screen_gen.dmi'
|
||||
icon_state = "click_catcher"
|
||||
plane = CLICKCATCHER_PLANE
|
||||
mouse_opacity = 2
|
||||
screen_loc = "CENTER"
|
||||
|
||||
/obj/screen/click_catcher/New()
|
||||
..()
|
||||
transform = matrix(200, 0, 0, 0, 200, 0)
|
||||
|
||||
/obj/screen/click_catcher/Click(location, control, params)
|
||||
var/list/modifiers = params2list(params)
|
||||
if(modifiers["middle"] && istype(usr, /mob/living/carbon))
|
||||
var/mob/living/carbon/C = usr
|
||||
C.swap_hand()
|
||||
else
|
||||
var/turf/T = params2turf(modifiers["screen-loc"], get_turf(usr))
|
||||
params += "&catcher=1"
|
||||
if(T)
|
||||
T.Click(location, control, params)
|
||||
. = 1
|
||||
|
||||
|
||||
/* MouseWheelOn */
|
||||
|
||||
/mob/proc/MouseWheelOn(atom/A, delta_x, delta_y, params)
|
||||
return
|
||||
|
||||
/mob/dead/observer/MouseWheelOn(atom/A, delta_x, delta_y, params)
|
||||
var/list/modifier = params2list(params)
|
||||
if(modifier["shift"])
|
||||
var/view = 0
|
||||
if(delta_y > 0)
|
||||
view = -1
|
||||
else
|
||||
view = 1
|
||||
add_view_range(view)
|
||||
@@ -71,7 +71,7 @@
|
||||
|
||||
// cyborgs are prohibited from using storage items so we can I think safely remove (A.loc in contents)
|
||||
if(A == loc || (A in loc) || (A in contents))
|
||||
melee_item_attack_chain(src, W, A, params)
|
||||
W.melee_attack_chain(src, A, params)
|
||||
return
|
||||
|
||||
if(!isturf(loc))
|
||||
@@ -80,7 +80,7 @@
|
||||
// cyborgs are prohibited from using storage items so we can I think safely remove (A.loc && isturf(A.loc.loc))
|
||||
if(isturf(A) || isturf(A.loc))
|
||||
if(A.Adjacent(src)) // see adjacent.dm
|
||||
melee_item_attack_chain(src, W, A, params)
|
||||
W.melee_attack_chain(src, A, params)
|
||||
return
|
||||
else
|
||||
W.afterattack(A, src, 0, params)
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
#define ui_inventory "WEST:6,SOUTH:5"
|
||||
|
||||
//Middle left indicators
|
||||
#define ui_lingchemdisplay "WEST:6,CENTER-1:15"
|
||||
#define ui_lingchemdisplay "WEST,CENTER-1:15"
|
||||
#define ui_lingstingdisplay "WEST:6,CENTER-3:11"
|
||||
#define ui_crafting "12:-10,1:5"
|
||||
#define ui_building "12:-10,1:21"
|
||||
@@ -104,12 +104,17 @@
|
||||
#define ui_health "EAST-1:28,CENTER-1:15"
|
||||
#define ui_internal "EAST-1:28,CENTER:17"
|
||||
|
||||
//borgs and aliens
|
||||
#define ui_alien_nightvision "EAST-1:28,CENTER:17"
|
||||
//borgs
|
||||
#define ui_borg_health "EAST-1:28,CENTER-1:15" //borgs have the health display where humans have the pressure damage indicator.
|
||||
#define ui_alien_health "EAST-1:28,CENTER-1:15" //aliens have the health display where humans have the pressure damage indicator.
|
||||
#define ui_alienplasmadisplay "EAST-1:28,CENTER-2:15"
|
||||
#define ui_alien_queen_finder "EAST-1:28,CENTER-3:15"
|
||||
|
||||
//aliens
|
||||
#define ui_alien_health "EAST,CENTER-1:15" //aliens have the health display where humans have the pressure damage indicator.
|
||||
#define ui_alienplasmadisplay "EAST,CENTER-2:15"
|
||||
#define ui_alien_queen_finder "EAST,CENTER-3:15"
|
||||
|
||||
//constructs
|
||||
#define ui_construct_pull "EAST,CENTER-2:15"
|
||||
#define ui_construct_health "EAST,CENTER:15" //same as borgs and humans
|
||||
|
||||
// AI
|
||||
|
||||
|
||||
+105
-10
@@ -42,6 +42,7 @@
|
||||
thealert.override_alerts = override
|
||||
if(override)
|
||||
thealert.timeout = null
|
||||
thealert.mob_viewer = src
|
||||
|
||||
if(new_master)
|
||||
var/old_layer = new_master.layer
|
||||
@@ -96,6 +97,7 @@
|
||||
var/severity = 0
|
||||
var/alerttooltipstyle = ""
|
||||
var/override_alerts = FALSE //If it is overriding other alerts of the same type
|
||||
var/mob/mob_viewer //the mob viewing this alert
|
||||
|
||||
|
||||
/obj/screen/alert/MouseEntered(location,control,params)
|
||||
@@ -256,6 +258,101 @@ or shoot a gun to move around via Newton's 3rd Law of Motion."
|
||||
icon_state = "blobbernaut_nofactory"
|
||||
alerttooltipstyle = "blob"
|
||||
|
||||
// BLOODCULT
|
||||
|
||||
/obj/screen/alert/bloodsense
|
||||
name = "Blood Sense"
|
||||
desc = "Allows you to sense blood that is manipulated by dark magicks."
|
||||
icon_state = "cult_sense"
|
||||
alerttooltipstyle = "cult"
|
||||
var/static/image/narnar
|
||||
var/angle = 0
|
||||
var/mob/living/simple_animal/hostile/construct/Cviewer = null
|
||||
|
||||
/obj/screen/alert/bloodsense/Initialize()
|
||||
. = ..()
|
||||
narnar = new('icons/mob/screen_alert.dmi', "mini_nar")
|
||||
START_PROCESSING(SSprocessing, src)
|
||||
|
||||
/obj/screen/alert/bloodsense/Destroy()
|
||||
Cviewer = null
|
||||
STOP_PROCESSING(SSprocessing, src)
|
||||
return ..()
|
||||
|
||||
/obj/screen/alert/bloodsense/process()
|
||||
var/atom/blood_target
|
||||
if(GLOB.blood_target)
|
||||
if(!get_turf(GLOB.blood_target))
|
||||
GLOB.blood_target = null
|
||||
else
|
||||
blood_target = GLOB.blood_target
|
||||
if(Cviewer && Cviewer.seeking && Cviewer.master)
|
||||
blood_target = Cviewer.master
|
||||
desc = "Your blood sense is leading you to [Cviewer.master]"
|
||||
if(!blood_target)
|
||||
if(!GLOB.sac_complete)
|
||||
if(icon_state == "runed_sense0")
|
||||
return
|
||||
animate(src, transform = null, time = 1, loop = 0)
|
||||
angle = 0
|
||||
cut_overlays()
|
||||
icon_state = "runed_sense0"
|
||||
desc = "Nar-Sie demands that [GLOB.sac_mind] be sacrificed before the summoning ritual can begin."
|
||||
add_overlay(GLOB.sac_image)
|
||||
else
|
||||
if(icon_state == "runed_sense1")
|
||||
return
|
||||
animate(src, transform = null, time = 1, loop = 0)
|
||||
angle = 0
|
||||
cut_overlays()
|
||||
icon_state = "runed_sense1"
|
||||
desc = "The sacrifice is complete, summon Nar-Sie! The summoning can only take place in [english_list(GLOB.summon_spots)]!"
|
||||
add_overlay(narnar)
|
||||
return
|
||||
var/turf/P = get_turf(blood_target)
|
||||
var/turf/Q = get_turf(mob_viewer)
|
||||
var/area/A = get_area(P)
|
||||
if(P.z != Q.z) //The target is on a different Z level, we cannot sense that far.
|
||||
icon_state = "runed_sense2"
|
||||
desc = "[blood_target] is no longer in your sector, you cannot sense its presence here."
|
||||
return
|
||||
desc = "You are currently tracking [blood_target] in [A.name]."
|
||||
var/target_angle = Get_Angle(Q, P)
|
||||
var/target_dist = get_dist(P, Q)
|
||||
cut_overlays()
|
||||
switch(target_dist)
|
||||
if(0 to 1)
|
||||
icon_state = "runed_sense2"
|
||||
if(2 to 8)
|
||||
icon_state = "arrow8"
|
||||
if(9 to 15)
|
||||
icon_state = "arrow7"
|
||||
if(16 to 22)
|
||||
icon_state = "arrow6"
|
||||
if(23 to 29)
|
||||
icon_state = "arrow5"
|
||||
if(30 to 36)
|
||||
icon_state = "arrow4"
|
||||
if(37 to 43)
|
||||
icon_state = "arrow3"
|
||||
if(44 to 50)
|
||||
icon_state = "arrow2"
|
||||
if(51 to 57)
|
||||
icon_state = "arrow1"
|
||||
if(58 to 64)
|
||||
icon_state = "arrow0"
|
||||
if(65 to 400)
|
||||
icon_state = "arrow"
|
||||
var/difference = target_angle - angle
|
||||
angle = target_angle
|
||||
if(!difference)
|
||||
return
|
||||
var/matrix/final = matrix(transform)
|
||||
final.Turn(difference)
|
||||
animate(src, transform = final, time = 5, loop = 0)
|
||||
|
||||
|
||||
|
||||
// CLOCKCULT
|
||||
/obj/screen/alert/clockwork
|
||||
alerttooltipstyle = "clockcult"
|
||||
@@ -264,7 +361,7 @@ or shoot a gun to move around via Newton's 3rd Law of Motion."
|
||||
name = "Next Tier Requirements"
|
||||
desc = "You shouldn't be seeing this description unless you're very fast. If you're very fast, good job!"
|
||||
icon_state = "no-servants-caches"
|
||||
var/static/list/scripture_states = list(SCRIPTURE_DRIVER = TRUE, SCRIPTURE_SCRIPT = FALSE, SCRIPTURE_APPLICATION = FALSE, SCRIPTURE_REVENANT = FALSE, SCRIPTURE_JUDGEMENT = FALSE)
|
||||
|
||||
|
||||
/obj/screen/alert/clockwork/scripture_reqs/Initialize()
|
||||
. = ..()
|
||||
@@ -277,12 +374,11 @@ or shoot a gun to move around via Newton's 3rd Law of Motion."
|
||||
|
||||
/obj/screen/alert/clockwork/scripture_reqs/process()
|
||||
if(GLOB.clockwork_gateway_activated)
|
||||
qdel(src)
|
||||
mob_viewer.clear_alert("scripturereq")
|
||||
return
|
||||
var/current_state
|
||||
scripture_states = scripture_unlock_check()
|
||||
for(var/i in scripture_states)
|
||||
if(!scripture_states[i])
|
||||
for(var/i in SSticker.scripture_states)
|
||||
if(!SSticker.scripture_states[i])
|
||||
current_state = i
|
||||
break
|
||||
icon_state = "no"
|
||||
@@ -362,7 +458,6 @@ or shoot a gun to move around via Newton's 3rd Law of Motion."
|
||||
var/servants = 0
|
||||
var/validservants = 0
|
||||
var/unconverted_ais_exist = get_unconverted_ais()
|
||||
var/list/scripture_states = scripture_unlock_check()
|
||||
var/list/textlist
|
||||
for(var/mob/living/L in GLOB.living_mob_list)
|
||||
if(is_servant_of_ratvar(L))
|
||||
@@ -393,12 +488,13 @@ or shoot a gun to move around via Newton's 3rd Law of Motion."
|
||||
textlist += "<br>"
|
||||
else
|
||||
textlist += "Seconds until Ratvar's arrival: <b>[G.get_arrival_text(TRUE)]</b><br>"
|
||||
break
|
||||
if(unconverted_ais_exist)
|
||||
if(unconverted_ais_exist > 1)
|
||||
textlist += "<b>[unconverted_ais_exist] unconverted AIs exist!</b><br>"
|
||||
else
|
||||
textlist += "<b>An unconverted AI exists!</b><br>"
|
||||
if(scripture_states[SCRIPTURE_REVENANT])
|
||||
if(SSticker.scripture_states[SCRIPTURE_REVENANT])
|
||||
var/inathneq_available = GLOB.clockwork_generals_invoked["inath-neq"] <= world.time
|
||||
var/sevtug_available = GLOB.clockwork_generals_invoked["sevtug"] <= world.time
|
||||
var/nezbere_available = GLOB.clockwork_generals_invoked["nezbere"] <= world.time
|
||||
@@ -410,9 +506,9 @@ or shoot a gun to move around via Newton's 3rd Law of Motion."
|
||||
textlist += "Generals available: <b>NONE</b><br>"
|
||||
else
|
||||
textlist += "Generals available: <b>NONE</b><br>"
|
||||
for(var/i in scripture_states)
|
||||
for(var/i in SSticker.scripture_states)
|
||||
if(i != SCRIPTURE_DRIVER) //ignore the always-unlocked stuff
|
||||
textlist += "[i] Scripture: <b>[scripture_states[i] ? "UNLOCKED":"LOCKED"]</b><br>"
|
||||
textlist += "[i] Scripture: <b>[SSticker.scripture_states[i] ? "UNLOCKED":"LOCKED"]</b><br>"
|
||||
desc = textlist.Join()
|
||||
..()
|
||||
|
||||
@@ -604,4 +700,3 @@ so as to remain in compliance with the most up-to-date laws."
|
||||
severity = 0
|
||||
master = null
|
||||
screen_loc = ""
|
||||
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
|
||||
/datum/hud/construct
|
||||
ui_style_icon = 'icons/mob/screen_construct.dmi'
|
||||
|
||||
/datum/hud/construct/New(mob/owner)
|
||||
..()
|
||||
pull_icon = new /obj/screen/pull()
|
||||
pull_icon.icon = ui_style_icon
|
||||
pull_icon.update_icon(mymob)
|
||||
pull_icon.screen_loc = ui_pull_resist
|
||||
static_inventory += pull_icon
|
||||
|
||||
healths = new /obj/screen/healths/construct()
|
||||
infodisplay += healths
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/create_mob_hud()
|
||||
if(client && !hud_used)
|
||||
hud_used = new /datum/hud/construct(src)
|
||||
@@ -68,6 +68,10 @@
|
||||
using.screen_loc = ui_ghost_pai
|
||||
static_inventory += using
|
||||
|
||||
using = new /obj/screen/language_menu
|
||||
using.icon = ui_style
|
||||
static_inventory += using
|
||||
|
||||
/datum/hud/ghost/show_hud(version = 0, mob/viewmob)
|
||||
..()
|
||||
if(!mymob.client.prefs.ghost_hud)
|
||||
|
||||
+270
-268
@@ -1,268 +1,270 @@
|
||||
/*
|
||||
The hud datum
|
||||
Used to show and hide huds for all the different mob types,
|
||||
including inventories and item quick actions.
|
||||
*/
|
||||
|
||||
/datum/hud
|
||||
var/mob/mymob
|
||||
|
||||
var/hud_shown = 1 //Used for the HUD toggle (F12)
|
||||
var/hud_version = 1 //Current displayed version of the HUD
|
||||
var/inventory_shown = 0 //Equipped item inventory
|
||||
var/show_intent_icons = 0
|
||||
var/hotkey_ui_hidden = 0 //This is to hide the buttons that can be used via hotkeys. (hotkeybuttons list of buttons)
|
||||
|
||||
var/obj/screen/ling/chems/lingchemdisplay
|
||||
var/obj/screen/ling/sting/lingstingdisplay
|
||||
|
||||
var/obj/screen/blobpwrdisplay
|
||||
|
||||
var/obj/screen/alien_plasma_display
|
||||
var/obj/screen/alien_queen_finder
|
||||
|
||||
var/obj/screen/devil/soul_counter/devilsouldisplay
|
||||
|
||||
var/obj/screen/deity_power_display
|
||||
var/obj/screen/deity_follower_display
|
||||
|
||||
var/obj/screen/nightvisionicon
|
||||
var/obj/screen/action_intent
|
||||
var/obj/screen/zone_select
|
||||
var/obj/screen/pull_icon
|
||||
var/obj/screen/throw_icon
|
||||
var/obj/screen/module_store_icon
|
||||
|
||||
var/list/static_inventory = list() //the screen objects which are static
|
||||
var/list/toggleable_inventory = list() //the screen objects which can be hidden
|
||||
var/list/obj/screen/hotkeybuttons = list() //the buttons that can be used via hotkeys
|
||||
var/list/infodisplay = list() //the screen objects that display mob info (health, alien plasma, etc...)
|
||||
var/list/screenoverlays = list() //the screen objects used as whole screen overlays (flash, damageoverlay, etc...)
|
||||
var/list/inv_slots[slots_amt] // /obj/screen/inventory objects, ordered by their slot ID.
|
||||
var/list/hand_slots // /obj/screen/inventory/hand objects, assoc list of "[held_index]" = object
|
||||
var/list/obj/screen/plane_master/plane_masters = list() // see "appearance_flags" in the ref, assoc list of "[plane]" = object
|
||||
|
||||
var/obj/screen/movable/action_button/hide_toggle/hide_actions_toggle
|
||||
var/action_buttons_hidden = 0
|
||||
|
||||
var/obj/screen/healths
|
||||
var/obj/screen/healthdoll
|
||||
var/obj/screen/internals
|
||||
|
||||
var/ui_style_icon = 'icons/mob/screen_midnight.dmi'
|
||||
|
||||
/datum/hud/New(mob/owner , ui_style = 'icons/mob/screen_midnight.dmi')
|
||||
mymob = owner
|
||||
|
||||
ui_style_icon = ui_style
|
||||
|
||||
hide_actions_toggle = new
|
||||
hide_actions_toggle.InitialiseIcon(src)
|
||||
|
||||
hand_slots = list()
|
||||
|
||||
for(var/mytype in subtypesof(/obj/screen/plane_master))
|
||||
var/obj/screen/plane_master/instance = new mytype()
|
||||
plane_masters["[instance.plane]"] = instance
|
||||
instance.backdrop(mymob)
|
||||
|
||||
/datum/hud/Destroy()
|
||||
if(mymob.hud_used == src)
|
||||
mymob.hud_used = null
|
||||
|
||||
qdel(hide_actions_toggle)
|
||||
hide_actions_toggle = null
|
||||
|
||||
qdel(module_store_icon)
|
||||
module_store_icon = null
|
||||
|
||||
if(static_inventory.len)
|
||||
for(var/thing in static_inventory)
|
||||
qdel(thing)
|
||||
static_inventory.Cut()
|
||||
|
||||
inv_slots.Cut()
|
||||
action_intent = null
|
||||
zone_select = null
|
||||
pull_icon = null
|
||||
|
||||
if(toggleable_inventory.len)
|
||||
for(var/thing in toggleable_inventory)
|
||||
qdel(thing)
|
||||
toggleable_inventory.Cut()
|
||||
|
||||
if(hotkeybuttons.len)
|
||||
for(var/thing in hotkeybuttons)
|
||||
qdel(thing)
|
||||
hotkeybuttons.Cut()
|
||||
|
||||
throw_icon = null
|
||||
|
||||
if(infodisplay.len)
|
||||
for(var/thing in infodisplay)
|
||||
qdel(thing)
|
||||
infodisplay.Cut()
|
||||
|
||||
healths = null
|
||||
healthdoll = null
|
||||
internals = null
|
||||
lingchemdisplay = null
|
||||
devilsouldisplay = null
|
||||
lingstingdisplay = null
|
||||
blobpwrdisplay = null
|
||||
alien_plasma_display = null
|
||||
alien_queen_finder = null
|
||||
deity_power_display = null
|
||||
deity_follower_display = null
|
||||
nightvisionicon = null
|
||||
|
||||
if(plane_masters.len)
|
||||
for(var/thing in plane_masters)
|
||||
qdel(plane_masters[thing])
|
||||
plane_masters.Cut()
|
||||
|
||||
if(screenoverlays.len)
|
||||
for(var/thing in screenoverlays)
|
||||
qdel(thing)
|
||||
screenoverlays.Cut()
|
||||
mymob = null
|
||||
|
||||
return ..()
|
||||
|
||||
/mob/proc/create_mob_hud()
|
||||
if(client && !hud_used)
|
||||
hud_used = new /datum/hud(src)
|
||||
update_sight()
|
||||
|
||||
//Version denotes which style should be displayed. blank or 0 means "next version"
|
||||
/datum/hud/proc/show_hud(version = 0,mob/viewmob)
|
||||
if(!ismob(mymob))
|
||||
return 0
|
||||
var/mob/screenmob = viewmob || mymob
|
||||
if(!screenmob.client)
|
||||
return 0
|
||||
|
||||
screenmob.client.screen = list()
|
||||
|
||||
var/display_hud_version = version
|
||||
if(!display_hud_version) //If 0 or blank, display the next hud version
|
||||
display_hud_version = hud_version + 1
|
||||
if(display_hud_version > HUD_VERSIONS) //If the requested version number is greater than the available versions, reset back to the first version
|
||||
display_hud_version = 1
|
||||
|
||||
switch(display_hud_version)
|
||||
if(HUD_STYLE_STANDARD) //Default HUD
|
||||
hud_shown = 1 //Governs behavior of other procs
|
||||
if(static_inventory.len)
|
||||
screenmob.client.screen += static_inventory
|
||||
if(toggleable_inventory.len && screenmob.hud_used && screenmob.hud_used.inventory_shown)
|
||||
screenmob.client.screen += toggleable_inventory
|
||||
if(hotkeybuttons.len && !hotkey_ui_hidden)
|
||||
screenmob.client.screen += hotkeybuttons
|
||||
if(infodisplay.len)
|
||||
screenmob.client.screen += infodisplay
|
||||
|
||||
screenmob.client.screen += hide_actions_toggle
|
||||
|
||||
if(action_intent)
|
||||
action_intent.screen_loc = initial(action_intent.screen_loc) //Restore intent selection to the original position
|
||||
|
||||
if(HUD_STYLE_REDUCED) //Reduced HUD
|
||||
hud_shown = 0 //Governs behavior of other procs
|
||||
if(static_inventory.len)
|
||||
screenmob.client.screen -= static_inventory
|
||||
if(toggleable_inventory.len)
|
||||
screenmob.client.screen -= toggleable_inventory
|
||||
if(hotkeybuttons.len)
|
||||
screenmob.client.screen -= hotkeybuttons
|
||||
if(infodisplay.len)
|
||||
screenmob.client.screen += infodisplay
|
||||
|
||||
//These ones are a part of 'static_inventory', 'toggleable_inventory' or 'hotkeybuttons' but we want them to stay
|
||||
for(var/h in hand_slots)
|
||||
var/obj/screen/hand = hand_slots[h]
|
||||
if(hand)
|
||||
screenmob.client.screen += hand
|
||||
if(action_intent)
|
||||
screenmob.client.screen += action_intent //we want the intent switcher visible
|
||||
action_intent.screen_loc = ui_acti_alt //move this to the alternative position, where zone_select usually is.
|
||||
|
||||
if(HUD_STYLE_NOHUD) //No HUD
|
||||
hud_shown = 0 //Governs behavior of other procs
|
||||
if(static_inventory.len)
|
||||
screenmob.client.screen -= static_inventory
|
||||
if(toggleable_inventory.len)
|
||||
screenmob.client.screen -= toggleable_inventory
|
||||
if(hotkeybuttons.len)
|
||||
screenmob.client.screen -= hotkeybuttons
|
||||
if(infodisplay.len)
|
||||
screenmob.client.screen -= infodisplay
|
||||
|
||||
for(var/thing in plane_masters)
|
||||
screenmob.client.screen += plane_masters[thing]
|
||||
|
||||
hud_version = display_hud_version
|
||||
persistent_inventory_update(screenmob)
|
||||
mymob.update_action_buttons(1)
|
||||
reorganize_alerts()
|
||||
mymob.reload_fullscreen()
|
||||
update_parallax_pref(screenmob)
|
||||
|
||||
|
||||
/datum/hud/human/show_hud(version = 0,mob/viewmob)
|
||||
..()
|
||||
hidden_inventory_update(viewmob)
|
||||
|
||||
/datum/hud/robot/show_hud(version = 0, mob/viewmob)
|
||||
..()
|
||||
update_robot_modules_display()
|
||||
|
||||
/datum/hud/proc/hidden_inventory_update()
|
||||
return
|
||||
|
||||
/datum/hud/proc/persistent_inventory_update(mob/viewer)
|
||||
if(!mymob)
|
||||
return
|
||||
|
||||
//Triggered when F12 is pressed (Unless someone changed something in the DMF)
|
||||
/mob/verb/button_pressed_F12()
|
||||
set name = "F12"
|
||||
set hidden = 1
|
||||
|
||||
if(hud_used && client)
|
||||
hud_used.show_hud() //Shows the next hud preset
|
||||
to_chat(usr, "<span class ='info'>Switched HUD mode. Press F12 to toggle.</span>")
|
||||
else
|
||||
to_chat(usr, "<span class ='warning'>This mob type does not use a HUD.</span>")
|
||||
|
||||
|
||||
//(re)builds the hand ui slots, throwing away old ones
|
||||
//not really worth jugglying existing ones so we just scrap+rebuild
|
||||
//9/10 this is only called once per mob and only for 2 hands
|
||||
/datum/hud/proc/build_hand_slots(ui_style = 'icons/mob/screen_midnight.dmi')
|
||||
for(var/h in hand_slots)
|
||||
var/obj/screen/inventory/hand/H = hand_slots[h]
|
||||
if(H)
|
||||
static_inventory -= H
|
||||
hand_slots = list()
|
||||
var/obj/screen/inventory/hand/hand_box
|
||||
for(var/i in 1 to mymob.held_items.len)
|
||||
hand_box = new /obj/screen/inventory/hand()
|
||||
hand_box.name = mymob.get_held_index_name(i)
|
||||
hand_box.icon = ui_style
|
||||
hand_box.icon_state = "hand_[mymob.held_index_to_dir(i)]"
|
||||
hand_box.screen_loc = ui_hand_position(i)
|
||||
hand_box.held_index = i
|
||||
hand_slots["[i]"] = hand_box
|
||||
hand_box.hud = src
|
||||
static_inventory += hand_box
|
||||
hand_box.update_icon()
|
||||
|
||||
var/i = 1
|
||||
for(var/obj/screen/swap_hand/SH in static_inventory)
|
||||
SH.screen_loc = ui_swaphand_position(mymob,!(i % 2) ? 2: 1)
|
||||
i++
|
||||
for(var/obj/screen/human/equip/E in static_inventory)
|
||||
E.screen_loc = ui_equip_position(mymob)
|
||||
if(mymob.hud_used)
|
||||
show_hud(HUD_STYLE_STANDARD,mymob)
|
||||
/*
|
||||
The hud datum
|
||||
Used to show and hide huds for all the different mob types,
|
||||
including inventories and item quick actions.
|
||||
*/
|
||||
|
||||
/datum/hud
|
||||
var/mob/mymob
|
||||
|
||||
var/hud_shown = 1 //Used for the HUD toggle (F12)
|
||||
var/hud_version = 1 //Current displayed version of the HUD
|
||||
var/inventory_shown = 0 //Equipped item inventory
|
||||
var/show_intent_icons = 0
|
||||
var/hotkey_ui_hidden = 0 //This is to hide the buttons that can be used via hotkeys. (hotkeybuttons list of buttons)
|
||||
|
||||
var/obj/screen/ling/chems/lingchemdisplay
|
||||
var/obj/screen/ling/sting/lingstingdisplay
|
||||
|
||||
var/obj/screen/blobpwrdisplay
|
||||
|
||||
var/obj/screen/alien_plasma_display
|
||||
var/obj/screen/alien_queen_finder
|
||||
|
||||
var/obj/screen/devil/soul_counter/devilsouldisplay
|
||||
|
||||
var/obj/screen/deity_power_display
|
||||
var/obj/screen/deity_follower_display
|
||||
|
||||
var/obj/screen/nightvisionicon
|
||||
var/obj/screen/action_intent
|
||||
var/obj/screen/zone_select
|
||||
var/obj/screen/pull_icon
|
||||
var/obj/screen/throw_icon
|
||||
var/obj/screen/module_store_icon
|
||||
|
||||
var/list/static_inventory = list() //the screen objects which are static
|
||||
var/list/toggleable_inventory = list() //the screen objects which can be hidden
|
||||
var/list/obj/screen/hotkeybuttons = list() //the buttons that can be used via hotkeys
|
||||
var/list/infodisplay = list() //the screen objects that display mob info (health, alien plasma, etc...)
|
||||
var/list/screenoverlays = list() //the screen objects used as whole screen overlays (flash, damageoverlay, etc...)
|
||||
var/list/inv_slots[slots_amt] // /obj/screen/inventory objects, ordered by their slot ID.
|
||||
var/list/hand_slots // /obj/screen/inventory/hand objects, assoc list of "[held_index]" = object
|
||||
var/list/obj/screen/plane_master/plane_masters = list() // see "appearance_flags" in the ref, assoc list of "[plane]" = object
|
||||
|
||||
var/obj/screen/movable/action_button/hide_toggle/hide_actions_toggle
|
||||
var/action_buttons_hidden = 0
|
||||
|
||||
var/obj/screen/healths
|
||||
var/obj/screen/healthdoll
|
||||
var/obj/screen/internals
|
||||
|
||||
var/ui_style_icon = 'icons/mob/screen_midnight.dmi'
|
||||
|
||||
/datum/hud/New(mob/owner , ui_style = 'icons/mob/screen_midnight.dmi')
|
||||
mymob = owner
|
||||
|
||||
ui_style_icon = ui_style
|
||||
|
||||
hide_actions_toggle = new
|
||||
hide_actions_toggle.InitialiseIcon(src)
|
||||
|
||||
hand_slots = list()
|
||||
|
||||
for(var/mytype in subtypesof(/obj/screen/plane_master))
|
||||
var/obj/screen/plane_master/instance = new mytype()
|
||||
plane_masters["[instance.plane]"] = instance
|
||||
instance.backdrop(mymob)
|
||||
|
||||
/datum/hud/Destroy()
|
||||
if(mymob.hud_used == src)
|
||||
mymob.hud_used = null
|
||||
|
||||
qdel(hide_actions_toggle)
|
||||
hide_actions_toggle = null
|
||||
|
||||
qdel(module_store_icon)
|
||||
module_store_icon = null
|
||||
|
||||
if(static_inventory.len)
|
||||
for(var/thing in static_inventory)
|
||||
qdel(thing)
|
||||
static_inventory.Cut()
|
||||
|
||||
inv_slots.Cut()
|
||||
action_intent = null
|
||||
zone_select = null
|
||||
pull_icon = null
|
||||
|
||||
if(toggleable_inventory.len)
|
||||
for(var/thing in toggleable_inventory)
|
||||
qdel(thing)
|
||||
toggleable_inventory.Cut()
|
||||
|
||||
if(hotkeybuttons.len)
|
||||
for(var/thing in hotkeybuttons)
|
||||
qdel(thing)
|
||||
hotkeybuttons.Cut()
|
||||
|
||||
throw_icon = null
|
||||
|
||||
if(infodisplay.len)
|
||||
for(var/thing in infodisplay)
|
||||
qdel(thing)
|
||||
infodisplay.Cut()
|
||||
|
||||
healths = null
|
||||
healthdoll = null
|
||||
internals = null
|
||||
lingchemdisplay = null
|
||||
devilsouldisplay = null
|
||||
lingstingdisplay = null
|
||||
blobpwrdisplay = null
|
||||
alien_plasma_display = null
|
||||
alien_queen_finder = null
|
||||
deity_power_display = null
|
||||
deity_follower_display = null
|
||||
nightvisionicon = null
|
||||
|
||||
if(plane_masters.len)
|
||||
for(var/thing in plane_masters)
|
||||
qdel(plane_masters[thing])
|
||||
plane_masters.Cut()
|
||||
|
||||
if(screenoverlays.len)
|
||||
for(var/thing in screenoverlays)
|
||||
qdel(thing)
|
||||
screenoverlays.Cut()
|
||||
mymob = null
|
||||
|
||||
return ..()
|
||||
|
||||
/mob/proc/create_mob_hud()
|
||||
if(client && !hud_used)
|
||||
hud_used = new /datum/hud(src)
|
||||
update_sight()
|
||||
|
||||
//Version denotes which style should be displayed. blank or 0 means "next version"
|
||||
/datum/hud/proc/show_hud(version = 0,mob/viewmob)
|
||||
if(!ismob(mymob))
|
||||
return 0
|
||||
var/mob/screenmob = viewmob || mymob
|
||||
if(!screenmob.client)
|
||||
return 0
|
||||
|
||||
screenmob.client.screen = list()
|
||||
|
||||
var/display_hud_version = version
|
||||
if(!display_hud_version) //If 0 or blank, display the next hud version
|
||||
display_hud_version = hud_version + 1
|
||||
if(display_hud_version > HUD_VERSIONS) //If the requested version number is greater than the available versions, reset back to the first version
|
||||
display_hud_version = 1
|
||||
|
||||
switch(display_hud_version)
|
||||
if(HUD_STYLE_STANDARD) //Default HUD
|
||||
hud_shown = 1 //Governs behavior of other procs
|
||||
if(static_inventory.len)
|
||||
screenmob.client.screen += static_inventory
|
||||
if(toggleable_inventory.len && screenmob.hud_used && screenmob.hud_used.inventory_shown)
|
||||
screenmob.client.screen += toggleable_inventory
|
||||
if(hotkeybuttons.len && !hotkey_ui_hidden)
|
||||
screenmob.client.screen += hotkeybuttons
|
||||
if(infodisplay.len)
|
||||
screenmob.client.screen += infodisplay
|
||||
|
||||
screenmob.client.screen += hide_actions_toggle
|
||||
|
||||
if(action_intent)
|
||||
action_intent.screen_loc = initial(action_intent.screen_loc) //Restore intent selection to the original position
|
||||
|
||||
if(HUD_STYLE_REDUCED) //Reduced HUD
|
||||
hud_shown = 0 //Governs behavior of other procs
|
||||
if(static_inventory.len)
|
||||
screenmob.client.screen -= static_inventory
|
||||
if(toggleable_inventory.len)
|
||||
screenmob.client.screen -= toggleable_inventory
|
||||
if(hotkeybuttons.len)
|
||||
screenmob.client.screen -= hotkeybuttons
|
||||
if(infodisplay.len)
|
||||
screenmob.client.screen += infodisplay
|
||||
|
||||
//These ones are a part of 'static_inventory', 'toggleable_inventory' or 'hotkeybuttons' but we want them to stay
|
||||
for(var/h in hand_slots)
|
||||
var/obj/screen/hand = hand_slots[h]
|
||||
if(hand)
|
||||
screenmob.client.screen += hand
|
||||
if(action_intent)
|
||||
screenmob.client.screen += action_intent //we want the intent switcher visible
|
||||
action_intent.screen_loc = ui_acti_alt //move this to the alternative position, where zone_select usually is.
|
||||
|
||||
if(HUD_STYLE_NOHUD) //No HUD
|
||||
hud_shown = 0 //Governs behavior of other procs
|
||||
if(static_inventory.len)
|
||||
screenmob.client.screen -= static_inventory
|
||||
if(toggleable_inventory.len)
|
||||
screenmob.client.screen -= toggleable_inventory
|
||||
if(hotkeybuttons.len)
|
||||
screenmob.client.screen -= hotkeybuttons
|
||||
if(infodisplay.len)
|
||||
screenmob.client.screen -= infodisplay
|
||||
|
||||
for(var/thing in plane_masters)
|
||||
screenmob.client.screen += plane_masters[thing]
|
||||
|
||||
hud_version = display_hud_version
|
||||
persistent_inventory_update(screenmob)
|
||||
mymob.update_action_buttons(1)
|
||||
reorganize_alerts()
|
||||
mymob.reload_fullscreen()
|
||||
update_parallax_pref(screenmob)
|
||||
|
||||
/datum/hud/human/show_hud(version = 0,mob/viewmob)
|
||||
..()
|
||||
hidden_inventory_update(viewmob)
|
||||
|
||||
/datum/hud/robot/show_hud(version = 0, mob/viewmob)
|
||||
..()
|
||||
update_robot_modules_display()
|
||||
|
||||
/datum/hud/proc/hidden_inventory_update()
|
||||
return
|
||||
|
||||
/datum/hud/proc/persistent_inventory_update(mob/viewer)
|
||||
if(!mymob)
|
||||
return
|
||||
|
||||
//Triggered when F12 is pressed (Unless someone changed something in the DMF)
|
||||
/mob/verb/button_pressed_F12()
|
||||
set name = "F12"
|
||||
set hidden = 1
|
||||
|
||||
if(hud_used && client)
|
||||
hud_used.show_hud() //Shows the next hud preset
|
||||
to_chat(usr, "<span class ='info'>Switched HUD mode. Press F12 to toggle.</span>")
|
||||
else
|
||||
to_chat(usr, "<span class ='warning'>This mob type does not use a HUD.</span>")
|
||||
|
||||
|
||||
//(re)builds the hand ui slots, throwing away old ones
|
||||
//not really worth jugglying existing ones so we just scrap+rebuild
|
||||
//9/10 this is only called once per mob and only for 2 hands
|
||||
/datum/hud/proc/build_hand_slots(ui_style = 'icons/mob/screen_midnight.dmi')
|
||||
for(var/h in hand_slots)
|
||||
var/obj/screen/inventory/hand/H = hand_slots[h]
|
||||
if(H)
|
||||
static_inventory -= H
|
||||
hand_slots = list()
|
||||
var/obj/screen/inventory/hand/hand_box
|
||||
for(var/i in 1 to mymob.held_items.len)
|
||||
hand_box = new /obj/screen/inventory/hand()
|
||||
hand_box.name = mymob.get_held_index_name(i)
|
||||
hand_box.icon = ui_style
|
||||
hand_box.icon_state = "hand_[mymob.held_index_to_dir(i)]"
|
||||
hand_box.screen_loc = ui_hand_position(i)
|
||||
hand_box.held_index = i
|
||||
hand_slots["[i]"] = hand_box
|
||||
hand_box.hud = src
|
||||
static_inventory += hand_box
|
||||
hand_box.update_icon()
|
||||
|
||||
var/i = 1
|
||||
for(var/obj/screen/swap_hand/SH in static_inventory)
|
||||
SH.screen_loc = ui_swaphand_position(mymob,!(i % 2) ? 2: 1)
|
||||
i++
|
||||
for(var/obj/screen/human/equip/E in static_inventory)
|
||||
E.screen_loc = ui_equip_position(mymob)
|
||||
if(mymob.hud_used)
|
||||
show_hud(HUD_STYLE_STANDARD,mymob)
|
||||
|
||||
/datum/hud/proc/update_locked_slots()
|
||||
return
|
||||
+438
-440
@@ -1,440 +1,438 @@
|
||||
/obj/screen/human
|
||||
icon = 'icons/mob/screen_midnight.dmi'
|
||||
|
||||
/obj/screen/human/toggle
|
||||
name = "toggle"
|
||||
icon_state = "toggle"
|
||||
|
||||
/obj/screen/human/toggle/Click()
|
||||
|
||||
var/mob/targetmob = usr
|
||||
|
||||
if(isobserver(usr))
|
||||
if(ishuman(usr.client.eye) && (usr.client.eye != usr))
|
||||
var/mob/M = usr.client.eye
|
||||
targetmob = M
|
||||
|
||||
if(usr.hud_used.inventory_shown && targetmob.hud_used)
|
||||
usr.hud_used.inventory_shown = 0
|
||||
usr.client.screen -= targetmob.hud_used.toggleable_inventory
|
||||
else
|
||||
usr.hud_used.inventory_shown = 1
|
||||
usr.client.screen += targetmob.hud_used.toggleable_inventory
|
||||
|
||||
targetmob.hud_used.hidden_inventory_update(usr)
|
||||
|
||||
/obj/screen/human/equip
|
||||
name = "equip"
|
||||
icon_state = "act_equip"
|
||||
|
||||
/obj/screen/human/equip/Click()
|
||||
if(istype(usr.loc,/obj/mecha)) // stops inventory actions in a mech
|
||||
return 1
|
||||
var/mob/living/carbon/human/H = usr
|
||||
H.quick_equip()
|
||||
|
||||
/obj/screen/devil
|
||||
invisibility = INVISIBILITY_ABSTRACT
|
||||
|
||||
/obj/screen/devil/soul_counter
|
||||
icon = 'icons/mob/screen_gen.dmi'
|
||||
name = "souls owned"
|
||||
icon_state = "Devil-6"
|
||||
screen_loc = ui_devilsouldisplay
|
||||
|
||||
/obj/screen/devil/soul_counter/proc/update_counter(souls = 0)
|
||||
invisibility = 0
|
||||
maptext = "<div align='center' valign='middle' style='position:relative; top:0px; left:6px'><font color='#FF0000'>[souls]</font></div>"
|
||||
switch(souls)
|
||||
if(0,null)
|
||||
icon_state = "Devil-1"
|
||||
if(1,2)
|
||||
icon_state = "Devil-2"
|
||||
if(3 to 5)
|
||||
icon_state = "Devil-3"
|
||||
if(6 to 8)
|
||||
icon_state = "Devil-4"
|
||||
if(9 to INFINITY)
|
||||
icon_state = "Devil-5"
|
||||
else
|
||||
icon_state = "Devil-6"
|
||||
|
||||
/obj/screen/devil/soul_counter/proc/clear()
|
||||
invisibility = INVISIBILITY_ABSTRACT
|
||||
|
||||
/obj/screen/ling
|
||||
invisibility = INVISIBILITY_ABSTRACT
|
||||
|
||||
/obj/screen/ling/sting
|
||||
name = "current sting"
|
||||
screen_loc = ui_lingstingdisplay
|
||||
|
||||
/obj/screen/ling/sting/Click()
|
||||
if(isobserver(usr))
|
||||
return
|
||||
var/mob/living/carbon/U = usr
|
||||
U.unset_sting()
|
||||
|
||||
/obj/screen/ling/chems
|
||||
name = "chemical storage"
|
||||
icon_state = "power_display"
|
||||
screen_loc = ui_lingchemdisplay
|
||||
|
||||
/mob/living/carbon/human/create_mob_hud()
|
||||
if(client && !hud_used)
|
||||
hud_used = new /datum/hud/human(src, ui_style2icon(client.prefs.UI_style))
|
||||
|
||||
|
||||
/datum/hud/human/New(mob/living/carbon/human/owner, ui_style = 'icons/mob/screen_midnight.dmi')
|
||||
..()
|
||||
owner.overlay_fullscreen("see_through_darkness", /obj/screen/fullscreen/see_through_darkness)
|
||||
|
||||
var/obj/screen/using
|
||||
var/obj/screen/inventory/inv_box
|
||||
|
||||
using = new /obj/screen/craft
|
||||
using.icon = ui_style
|
||||
static_inventory += using
|
||||
|
||||
using = new/obj/screen/language_menu
|
||||
using.icon = ui_style
|
||||
static_inventory += using
|
||||
|
||||
using = new /obj/screen/area_creator
|
||||
using.icon = ui_style
|
||||
static_inventory += using
|
||||
|
||||
action_intent = new /obj/screen/act_intent/segmented
|
||||
action_intent.icon_state = mymob.a_intent
|
||||
static_inventory += action_intent
|
||||
|
||||
using = new /obj/screen/mov_intent
|
||||
using.icon = ui_style
|
||||
using.icon_state = (mymob.m_intent == MOVE_INTENT_RUN ? "running" : "walking")
|
||||
using.screen_loc = ui_movi
|
||||
static_inventory += using
|
||||
|
||||
using = new /obj/screen/drop()
|
||||
using.icon = ui_style
|
||||
using.screen_loc = ui_drop_throw
|
||||
static_inventory += using
|
||||
|
||||
inv_box = new /obj/screen/inventory()
|
||||
inv_box.name = "i_clothing"
|
||||
inv_box.icon = ui_style
|
||||
inv_box.slot_id = slot_w_uniform
|
||||
inv_box.icon_state = "uniform"
|
||||
// inv_box.icon_full = "template"
|
||||
inv_box.screen_loc = ui_iclothing
|
||||
toggleable_inventory += inv_box
|
||||
|
||||
inv_box = new /obj/screen/inventory()
|
||||
inv_box.name = "o_clothing"
|
||||
inv_box.icon = ui_style
|
||||
inv_box.slot_id = slot_wear_suit
|
||||
inv_box.icon_state = "suit"
|
||||
// inv_box.icon_full = "template"
|
||||
inv_box.screen_loc = ui_oclothing
|
||||
toggleable_inventory += inv_box
|
||||
|
||||
build_hand_slots(ui_style)
|
||||
|
||||
using = new /obj/screen/swap_hand()
|
||||
using.icon = ui_style
|
||||
using.icon_state = "swap_1"
|
||||
using.screen_loc = ui_swaphand_position(owner,1)
|
||||
static_inventory += using
|
||||
|
||||
using = new /obj/screen/swap_hand()
|
||||
using.icon = ui_style
|
||||
using.icon_state = "swap_2"
|
||||
using.screen_loc = ui_swaphand_position(owner,2)
|
||||
static_inventory += using
|
||||
|
||||
inv_box = new /obj/screen/inventory()
|
||||
inv_box.name = "id"
|
||||
inv_box.icon = ui_style
|
||||
inv_box.icon_state = "id"
|
||||
// inv_box.icon_full = "template_small"
|
||||
inv_box.screen_loc = ui_id
|
||||
inv_box.slot_id = slot_wear_id
|
||||
static_inventory += inv_box
|
||||
|
||||
inv_box = new /obj/screen/inventory()
|
||||
inv_box.name = "mask"
|
||||
inv_box.icon = ui_style
|
||||
inv_box.icon_state = "mask"
|
||||
// inv_box.icon_full = "template"
|
||||
inv_box.screen_loc = ui_mask
|
||||
inv_box.slot_id = slot_wear_mask
|
||||
toggleable_inventory += inv_box
|
||||
|
||||
inv_box = new /obj/screen/inventory()
|
||||
inv_box.name = "neck"
|
||||
inv_box.icon = ui_style
|
||||
inv_box.icon_state = "neck"
|
||||
// inv_box.icon_full = "template"
|
||||
inv_box.screen_loc = ui_neck
|
||||
inv_box.slot_id = slot_neck
|
||||
toggleable_inventory += inv_box
|
||||
|
||||
inv_box = new /obj/screen/inventory()
|
||||
inv_box.name = "back"
|
||||
inv_box.icon = ui_style
|
||||
inv_box.icon_state = "back"
|
||||
// inv_box.icon_full = "template_small"
|
||||
inv_box.screen_loc = ui_back
|
||||
inv_box.slot_id = slot_back
|
||||
static_inventory += inv_box
|
||||
|
||||
inv_box = new /obj/screen/inventory()
|
||||
inv_box.name = "storage1"
|
||||
inv_box.icon = ui_style
|
||||
inv_box.icon_state = "pocket"
|
||||
// inv_box.icon_full = "template_small"
|
||||
inv_box.screen_loc = ui_storage1
|
||||
inv_box.slot_id = slot_l_store
|
||||
static_inventory += inv_box
|
||||
|
||||
inv_box = new /obj/screen/inventory()
|
||||
inv_box.name = "storage2"
|
||||
inv_box.icon = ui_style
|
||||
inv_box.icon_state = "pocket"
|
||||
// inv_box.icon_full = "template_small"
|
||||
inv_box.screen_loc = ui_storage2
|
||||
inv_box.slot_id = slot_r_store
|
||||
static_inventory += inv_box
|
||||
|
||||
inv_box = new /obj/screen/inventory()
|
||||
inv_box.name = "suit storage"
|
||||
inv_box.icon = ui_style
|
||||
inv_box.icon_state = "suit_storage"
|
||||
// inv_box.icon_full = "template"
|
||||
inv_box.screen_loc = ui_sstore1
|
||||
inv_box.slot_id = slot_s_store
|
||||
static_inventory += inv_box
|
||||
|
||||
using = new /obj/screen/resist()
|
||||
using.icon = ui_style
|
||||
using.screen_loc = ui_pull_resist
|
||||
hotkeybuttons += using
|
||||
|
||||
using = new /obj/screen/human/toggle()
|
||||
using.icon = ui_style
|
||||
using.screen_loc = ui_inventory
|
||||
static_inventory += using
|
||||
|
||||
using = new /obj/screen/human/equip()
|
||||
using.icon = ui_style
|
||||
using.screen_loc = ui_equip_position(mymob)
|
||||
static_inventory += using
|
||||
|
||||
inv_box = new /obj/screen/inventory()
|
||||
inv_box.name = "gloves"
|
||||
inv_box.icon = ui_style
|
||||
inv_box.icon_state = "gloves"
|
||||
// inv_box.icon_full = "template"
|
||||
inv_box.screen_loc = ui_gloves
|
||||
inv_box.slot_id = slot_gloves
|
||||
toggleable_inventory += inv_box
|
||||
|
||||
inv_box = new /obj/screen/inventory()
|
||||
inv_box.name = "eyes"
|
||||
inv_box.icon = ui_style
|
||||
inv_box.icon_state = "glasses"
|
||||
// inv_box.icon_full = "template"
|
||||
inv_box.screen_loc = ui_glasses
|
||||
inv_box.slot_id = slot_glasses
|
||||
toggleable_inventory += inv_box
|
||||
|
||||
inv_box = new /obj/screen/inventory()
|
||||
inv_box.name = "ears"
|
||||
inv_box.icon = ui_style
|
||||
inv_box.icon_state = "ears"
|
||||
// inv_box.icon_full = "template"
|
||||
inv_box.screen_loc = ui_ears
|
||||
inv_box.slot_id = slot_ears
|
||||
toggleable_inventory += inv_box
|
||||
|
||||
inv_box = new /obj/screen/inventory()
|
||||
inv_box.name = "head"
|
||||
inv_box.icon = ui_style
|
||||
inv_box.icon_state = "head"
|
||||
// inv_box.icon_full = "template"
|
||||
inv_box.screen_loc = ui_head
|
||||
inv_box.slot_id = slot_head
|
||||
toggleable_inventory += inv_box
|
||||
|
||||
inv_box = new /obj/screen/inventory()
|
||||
inv_box.name = "shoes"
|
||||
inv_box.icon = ui_style
|
||||
inv_box.icon_state = "shoes"
|
||||
// inv_box.icon_full = "template"
|
||||
inv_box.screen_loc = ui_shoes
|
||||
inv_box.slot_id = slot_shoes
|
||||
toggleable_inventory += inv_box
|
||||
|
||||
inv_box = new /obj/screen/inventory()
|
||||
inv_box.name = "belt"
|
||||
inv_box.icon = ui_style
|
||||
inv_box.icon_state = "belt"
|
||||
// inv_box.icon_full = "template_small"
|
||||
inv_box.screen_loc = ui_belt
|
||||
inv_box.slot_id = slot_belt
|
||||
static_inventory += inv_box
|
||||
|
||||
throw_icon = new /obj/screen/throw_catch()
|
||||
throw_icon.icon = ui_style
|
||||
throw_icon.screen_loc = ui_drop_throw
|
||||
hotkeybuttons += throw_icon
|
||||
|
||||
internals = new /obj/screen/internals()
|
||||
infodisplay += internals
|
||||
|
||||
healths = new /obj/screen/healths()
|
||||
infodisplay += healths
|
||||
|
||||
//citadel code
|
||||
arousal = new /obj/screen/arousal()
|
||||
infodisplay += arousal
|
||||
|
||||
healthdoll = new /obj/screen/healthdoll()
|
||||
infodisplay += healthdoll
|
||||
|
||||
pull_icon = new /obj/screen/pull()
|
||||
pull_icon.icon = ui_style
|
||||
pull_icon.update_icon(mymob)
|
||||
pull_icon.screen_loc = ui_pull_resist
|
||||
static_inventory += pull_icon
|
||||
|
||||
lingchemdisplay = new /obj/screen/ling/chems()
|
||||
infodisplay += lingchemdisplay
|
||||
|
||||
lingstingdisplay = new /obj/screen/ling/sting()
|
||||
infodisplay += lingstingdisplay
|
||||
|
||||
devilsouldisplay = new /obj/screen/devil/soul_counter
|
||||
infodisplay += devilsouldisplay
|
||||
|
||||
zone_select = new /obj/screen/zone_sel()
|
||||
zone_select.icon = ui_style
|
||||
zone_select.update_icon(mymob)
|
||||
static_inventory += zone_select
|
||||
|
||||
for(var/obj/screen/inventory/inv in (static_inventory + toggleable_inventory))
|
||||
if(inv.slot_id)
|
||||
inv.hud = src
|
||||
inv_slots[inv.slot_id] = inv
|
||||
inv.update_icon()
|
||||
|
||||
/datum/hud/human/hidden_inventory_update(mob/viewer)
|
||||
if(!mymob)
|
||||
return
|
||||
var/mob/living/carbon/human/H = mymob
|
||||
|
||||
var/mob/screenmob = viewer || H
|
||||
|
||||
if(screenmob.hud_used.inventory_shown && screenmob.hud_used.hud_shown)
|
||||
if(H.shoes)
|
||||
H.shoes.screen_loc = ui_shoes
|
||||
screenmob.client.screen += H.shoes
|
||||
if(H.gloves)
|
||||
H.gloves.screen_loc = ui_gloves
|
||||
screenmob.client.screen += H.gloves
|
||||
if(H.ears)
|
||||
H.ears.screen_loc = ui_ears
|
||||
screenmob.client.screen += H.ears
|
||||
if(H.glasses)
|
||||
H.glasses.screen_loc = ui_glasses
|
||||
screenmob.client.screen += H.glasses
|
||||
if(H.w_uniform)
|
||||
H.w_uniform.screen_loc = ui_iclothing
|
||||
screenmob.client.screen += H.w_uniform
|
||||
if(H.wear_suit)
|
||||
H.wear_suit.screen_loc = ui_oclothing
|
||||
screenmob.client.screen += H.wear_suit
|
||||
if(H.wear_mask)
|
||||
H.wear_mask.screen_loc = ui_mask
|
||||
screenmob.client.screen += H.wear_mask
|
||||
if(H.wear_neck)
|
||||
H.wear_neck.screen_loc = ui_neck
|
||||
screenmob.client.screen += H.wear_neck
|
||||
if(H.head)
|
||||
H.head.screen_loc = ui_head
|
||||
screenmob.client.screen += H.head
|
||||
else
|
||||
if(H.shoes) screenmob.client.screen -= H.shoes
|
||||
if(H.gloves) screenmob.client.screen -= H.gloves
|
||||
if(H.ears) screenmob.client.screen -= H.ears
|
||||
if(H.glasses) screenmob.client.screen -= H.glasses
|
||||
if(H.w_uniform) screenmob.client.screen -= H.w_uniform
|
||||
if(H.wear_suit) screenmob.client.screen -= H.wear_suit
|
||||
if(H.wear_mask) screenmob.client.screen -= H.wear_mask
|
||||
if(H.wear_neck) screenmob.client.screen -= H.wear_neck
|
||||
if(H.head) screenmob.client.screen -= H.head
|
||||
|
||||
|
||||
|
||||
/datum/hud/human/persistent_inventory_update(mob/viewer)
|
||||
if(!mymob)
|
||||
return
|
||||
..()
|
||||
var/mob/living/carbon/human/H = mymob
|
||||
|
||||
var/mob/screenmob = viewer || H
|
||||
|
||||
if(screenmob.hud_used)
|
||||
if(screenmob.hud_used.hud_shown)
|
||||
if(H.s_store)
|
||||
H.s_store.screen_loc = ui_sstore1
|
||||
screenmob.client.screen += H.s_store
|
||||
if(H.wear_id)
|
||||
H.wear_id.screen_loc = ui_id
|
||||
screenmob.client.screen += H.wear_id
|
||||
if(H.belt)
|
||||
H.belt.screen_loc = ui_belt
|
||||
screenmob.client.screen += H.belt
|
||||
if(H.back)
|
||||
H.back.screen_loc = ui_back
|
||||
screenmob.client.screen += H.back
|
||||
if(H.l_store)
|
||||
H.l_store.screen_loc = ui_storage1
|
||||
screenmob.client.screen += H.l_store
|
||||
if(H.r_store)
|
||||
H.r_store.screen_loc = ui_storage2
|
||||
screenmob.client.screen += H.r_store
|
||||
else
|
||||
if(H.s_store)
|
||||
screenmob.client.screen -= H.s_store
|
||||
if(H.wear_id)
|
||||
screenmob.client.screen -= H.wear_id
|
||||
if(H.belt)
|
||||
screenmob.client.screen -= H.belt
|
||||
if(H.back)
|
||||
screenmob.client.screen -= H.back
|
||||
if(H.l_store)
|
||||
screenmob.client.screen -= H.l_store
|
||||
if(H.r_store)
|
||||
screenmob.client.screen -= H.r_store
|
||||
|
||||
if(hud_version != HUD_STYLE_NOHUD)
|
||||
for(var/obj/item/I in H.held_items)
|
||||
I.screen_loc = ui_hand_position(H.get_held_index_of_item(I))
|
||||
screenmob.client.screen += I
|
||||
else
|
||||
for(var/obj/item/I in H.held_items)
|
||||
I.screen_loc = null
|
||||
screenmob.client.screen -= I
|
||||
|
||||
|
||||
/mob/living/carbon/human/verb/toggle_hotkey_verbs()
|
||||
set category = "OOC"
|
||||
set name = "Toggle hotkey buttons"
|
||||
set desc = "This disables or enables the user interface buttons which can be used with hotkeys."
|
||||
|
||||
if(hud_used.hotkey_ui_hidden)
|
||||
client.screen += hud_used.hotkeybuttons
|
||||
hud_used.hotkey_ui_hidden = 0
|
||||
else
|
||||
client.screen -= hud_used.hotkeybuttons
|
||||
hud_used.hotkey_ui_hidden = 1
|
||||
/obj/screen/human
|
||||
icon = 'icons/mob/screen_midnight.dmi'
|
||||
|
||||
/obj/screen/human/toggle
|
||||
name = "toggle"
|
||||
icon_state = "toggle"
|
||||
|
||||
/obj/screen/human/toggle/Click()
|
||||
|
||||
var/mob/targetmob = usr
|
||||
|
||||
if(isobserver(usr))
|
||||
if(ishuman(usr.client.eye) && (usr.client.eye != usr))
|
||||
var/mob/M = usr.client.eye
|
||||
targetmob = M
|
||||
|
||||
if(usr.hud_used.inventory_shown && targetmob.hud_used)
|
||||
usr.hud_used.inventory_shown = 0
|
||||
usr.client.screen -= targetmob.hud_used.toggleable_inventory
|
||||
else
|
||||
usr.hud_used.inventory_shown = 1
|
||||
usr.client.screen += targetmob.hud_used.toggleable_inventory
|
||||
|
||||
targetmob.hud_used.hidden_inventory_update(usr)
|
||||
|
||||
/obj/screen/human/equip
|
||||
name = "equip"
|
||||
icon_state = "act_equip"
|
||||
|
||||
/obj/screen/human/equip/Click()
|
||||
if(istype(usr.loc,/obj/mecha)) // stops inventory actions in a mech
|
||||
return 1
|
||||
var/mob/living/carbon/human/H = usr
|
||||
H.quick_equip()
|
||||
|
||||
/obj/screen/devil
|
||||
invisibility = INVISIBILITY_ABSTRACT
|
||||
|
||||
/obj/screen/devil/soul_counter
|
||||
icon = 'icons/mob/screen_gen.dmi'
|
||||
name = "souls owned"
|
||||
icon_state = "Devil-6"
|
||||
screen_loc = ui_devilsouldisplay
|
||||
|
||||
/obj/screen/devil/soul_counter/proc/update_counter(souls = 0)
|
||||
invisibility = 0
|
||||
maptext = "<div align='center' valign='middle' style='position:relative; top:0px; left:6px'><font color='#FF0000'>[souls]</font></div>"
|
||||
switch(souls)
|
||||
if(0,null)
|
||||
icon_state = "Devil-1"
|
||||
if(1,2)
|
||||
icon_state = "Devil-2"
|
||||
if(3 to 5)
|
||||
icon_state = "Devil-3"
|
||||
if(6 to 8)
|
||||
icon_state = "Devil-4"
|
||||
if(9 to INFINITY)
|
||||
icon_state = "Devil-5"
|
||||
else
|
||||
icon_state = "Devil-6"
|
||||
|
||||
/obj/screen/devil/soul_counter/proc/clear()
|
||||
invisibility = INVISIBILITY_ABSTRACT
|
||||
|
||||
/obj/screen/ling
|
||||
invisibility = INVISIBILITY_ABSTRACT
|
||||
|
||||
/obj/screen/ling/sting
|
||||
name = "current sting"
|
||||
screen_loc = ui_lingstingdisplay
|
||||
|
||||
/obj/screen/ling/sting/Click()
|
||||
if(isobserver(usr))
|
||||
return
|
||||
var/mob/living/carbon/U = usr
|
||||
U.unset_sting()
|
||||
|
||||
/obj/screen/ling/chems
|
||||
name = "chemical storage"
|
||||
icon_state = "power_display"
|
||||
screen_loc = ui_lingchemdisplay
|
||||
|
||||
/mob/living/carbon/human/create_mob_hud()
|
||||
if(client && !hud_used)
|
||||
hud_used = new /datum/hud/human(src, ui_style2icon(client.prefs.UI_style))
|
||||
|
||||
|
||||
/datum/hud/human/New(mob/living/carbon/human/owner, ui_style = 'icons/mob/screen_midnight.dmi')
|
||||
..()
|
||||
owner.overlay_fullscreen("see_through_darkness", /obj/screen/fullscreen/see_through_darkness)
|
||||
|
||||
var/obj/screen/using
|
||||
var/obj/screen/inventory/inv_box
|
||||
|
||||
using = new /obj/screen/craft
|
||||
using.icon = ui_style
|
||||
static_inventory += using
|
||||
|
||||
using = new/obj/screen/language_menu
|
||||
using.icon = ui_style
|
||||
static_inventory += using
|
||||
|
||||
using = new /obj/screen/area_creator
|
||||
using.icon = ui_style
|
||||
static_inventory += using
|
||||
|
||||
action_intent = new /obj/screen/act_intent/segmented
|
||||
action_intent.icon_state = mymob.a_intent
|
||||
static_inventory += action_intent
|
||||
|
||||
using = new /obj/screen/mov_intent
|
||||
using.icon = ui_style
|
||||
using.icon_state = (mymob.m_intent == MOVE_INTENT_RUN ? "running" : "walking")
|
||||
using.screen_loc = ui_movi
|
||||
static_inventory += using
|
||||
|
||||
using = new /obj/screen/drop()
|
||||
using.icon = ui_style
|
||||
using.screen_loc = ui_drop_throw
|
||||
static_inventory += using
|
||||
|
||||
inv_box = new /obj/screen/inventory()
|
||||
inv_box.name = "i_clothing"
|
||||
inv_box.icon = ui_style
|
||||
inv_box.slot_id = slot_w_uniform
|
||||
inv_box.icon_state = "uniform"
|
||||
inv_box.screen_loc = ui_iclothing
|
||||
toggleable_inventory += inv_box
|
||||
|
||||
inv_box = new /obj/screen/inventory()
|
||||
inv_box.name = "o_clothing"
|
||||
inv_box.icon = ui_style
|
||||
inv_box.slot_id = slot_wear_suit
|
||||
inv_box.icon_state = "suit"
|
||||
inv_box.screen_loc = ui_oclothing
|
||||
toggleable_inventory += inv_box
|
||||
|
||||
build_hand_slots(ui_style)
|
||||
|
||||
using = new /obj/screen/swap_hand()
|
||||
using.icon = ui_style
|
||||
using.icon_state = "swap_1"
|
||||
using.screen_loc = ui_swaphand_position(owner,1)
|
||||
static_inventory += using
|
||||
|
||||
using = new /obj/screen/swap_hand()
|
||||
using.icon = ui_style
|
||||
using.icon_state = "swap_2"
|
||||
using.screen_loc = ui_swaphand_position(owner,2)
|
||||
static_inventory += using
|
||||
|
||||
inv_box = new /obj/screen/inventory()
|
||||
inv_box.name = "id"
|
||||
inv_box.icon = ui_style
|
||||
inv_box.icon_state = "id"
|
||||
inv_box.screen_loc = ui_id
|
||||
inv_box.slot_id = slot_wear_id
|
||||
static_inventory += inv_box
|
||||
|
||||
inv_box = new /obj/screen/inventory()
|
||||
inv_box.name = "mask"
|
||||
inv_box.icon = ui_style
|
||||
inv_box.icon_state = "mask"
|
||||
inv_box.screen_loc = ui_mask
|
||||
inv_box.slot_id = slot_wear_mask
|
||||
toggleable_inventory += inv_box
|
||||
|
||||
inv_box = new /obj/screen/inventory()
|
||||
inv_box.name = "neck"
|
||||
inv_box.icon = ui_style
|
||||
inv_box.icon_state = "neck"
|
||||
inv_box.screen_loc = ui_neck
|
||||
inv_box.slot_id = slot_neck
|
||||
toggleable_inventory += inv_box
|
||||
|
||||
inv_box = new /obj/screen/inventory()
|
||||
inv_box.name = "back"
|
||||
inv_box.icon = ui_style
|
||||
inv_box.icon_state = "back"
|
||||
inv_box.screen_loc = ui_back
|
||||
inv_box.slot_id = slot_back
|
||||
static_inventory += inv_box
|
||||
|
||||
inv_box = new /obj/screen/inventory()
|
||||
inv_box.name = "storage1"
|
||||
inv_box.icon = ui_style
|
||||
inv_box.icon_state = "pocket"
|
||||
inv_box.screen_loc = ui_storage1
|
||||
inv_box.slot_id = slot_l_store
|
||||
static_inventory += inv_box
|
||||
|
||||
inv_box = new /obj/screen/inventory()
|
||||
inv_box.name = "storage2"
|
||||
inv_box.icon = ui_style
|
||||
inv_box.icon_state = "pocket"
|
||||
inv_box.screen_loc = ui_storage2
|
||||
inv_box.slot_id = slot_r_store
|
||||
static_inventory += inv_box
|
||||
|
||||
inv_box = new /obj/screen/inventory()
|
||||
inv_box.name = "suit storage"
|
||||
inv_box.icon = ui_style
|
||||
inv_box.icon_state = "suit_storage"
|
||||
inv_box.screen_loc = ui_sstore1
|
||||
inv_box.slot_id = slot_s_store
|
||||
static_inventory += inv_box
|
||||
|
||||
using = new /obj/screen/resist()
|
||||
using.icon = ui_style
|
||||
using.screen_loc = ui_pull_resist
|
||||
hotkeybuttons += using
|
||||
|
||||
using = new /obj/screen/human/toggle()
|
||||
using.icon = ui_style
|
||||
using.screen_loc = ui_inventory
|
||||
static_inventory += using
|
||||
|
||||
using = new /obj/screen/human/equip()
|
||||
using.icon = ui_style
|
||||
using.screen_loc = ui_equip_position(mymob)
|
||||
static_inventory += using
|
||||
|
||||
inv_box = new /obj/screen/inventory()
|
||||
inv_box.name = "gloves"
|
||||
inv_box.icon = ui_style
|
||||
inv_box.icon_state = "gloves"
|
||||
inv_box.screen_loc = ui_gloves
|
||||
inv_box.slot_id = slot_gloves
|
||||
toggleable_inventory += inv_box
|
||||
|
||||
inv_box = new /obj/screen/inventory()
|
||||
inv_box.name = "eyes"
|
||||
inv_box.icon = ui_style
|
||||
inv_box.icon_state = "glasses"
|
||||
inv_box.screen_loc = ui_glasses
|
||||
inv_box.slot_id = slot_glasses
|
||||
toggleable_inventory += inv_box
|
||||
|
||||
inv_box = new /obj/screen/inventory()
|
||||
inv_box.name = "ears"
|
||||
inv_box.icon = ui_style
|
||||
inv_box.icon_state = "ears"
|
||||
inv_box.screen_loc = ui_ears
|
||||
inv_box.slot_id = slot_ears
|
||||
toggleable_inventory += inv_box
|
||||
|
||||
inv_box = new /obj/screen/inventory()
|
||||
inv_box.name = "head"
|
||||
inv_box.icon = ui_style
|
||||
inv_box.icon_state = "head"
|
||||
inv_box.screen_loc = ui_head
|
||||
inv_box.slot_id = slot_head
|
||||
toggleable_inventory += inv_box
|
||||
|
||||
inv_box = new /obj/screen/inventory()
|
||||
inv_box.name = "shoes"
|
||||
inv_box.icon = ui_style
|
||||
inv_box.icon_state = "shoes"
|
||||
inv_box.screen_loc = ui_shoes
|
||||
inv_box.slot_id = slot_shoes
|
||||
toggleable_inventory += inv_box
|
||||
|
||||
inv_box = new /obj/screen/inventory()
|
||||
inv_box.name = "belt"
|
||||
inv_box.icon = ui_style
|
||||
inv_box.icon_state = "belt"
|
||||
// inv_box.icon_full = "template_small"
|
||||
inv_box.screen_loc = ui_belt
|
||||
inv_box.slot_id = slot_belt
|
||||
static_inventory += inv_box
|
||||
|
||||
throw_icon = new /obj/screen/throw_catch()
|
||||
throw_icon.icon = ui_style
|
||||
throw_icon.screen_loc = ui_drop_throw
|
||||
hotkeybuttons += throw_icon
|
||||
|
||||
internals = new /obj/screen/internals()
|
||||
infodisplay += internals
|
||||
|
||||
healths = new /obj/screen/healths()
|
||||
infodisplay += healths
|
||||
|
||||
//citadel code
|
||||
arousal = new /obj/screen/arousal()
|
||||
infodisplay += arousal
|
||||
|
||||
healthdoll = new /obj/screen/healthdoll()
|
||||
infodisplay += healthdoll
|
||||
|
||||
pull_icon = new /obj/screen/pull()
|
||||
pull_icon.icon = ui_style
|
||||
pull_icon.update_icon(mymob)
|
||||
pull_icon.screen_loc = ui_pull_resist
|
||||
static_inventory += pull_icon
|
||||
|
||||
lingchemdisplay = new /obj/screen/ling/chems()
|
||||
infodisplay += lingchemdisplay
|
||||
|
||||
lingstingdisplay = new /obj/screen/ling/sting()
|
||||
infodisplay += lingstingdisplay
|
||||
|
||||
devilsouldisplay = new /obj/screen/devil/soul_counter
|
||||
infodisplay += devilsouldisplay
|
||||
|
||||
zone_select = new /obj/screen/zone_sel()
|
||||
zone_select.icon = ui_style
|
||||
zone_select.update_icon(mymob)
|
||||
static_inventory += zone_select
|
||||
|
||||
for(var/obj/screen/inventory/inv in (static_inventory + toggleable_inventory))
|
||||
if(inv.slot_id)
|
||||
inv.hud = src
|
||||
inv_slots[inv.slot_id] = inv
|
||||
inv.update_icon()
|
||||
|
||||
/datum/hud/human/update_locked_slots()
|
||||
if(!mymob)
|
||||
return
|
||||
var/mob/living/carbon/human/H = mymob
|
||||
var/datum/species/S = H.dna.species
|
||||
for(var/obj/screen/inventory/inv in (static_inventory + toggleable_inventory))
|
||||
if(inv.slot_id)
|
||||
if(inv.slot_id in S.no_equip)
|
||||
inv.alpha = 128
|
||||
else
|
||||
inv.alpha = initial(inv.alpha)
|
||||
|
||||
/datum/hud/human/hidden_inventory_update(mob/viewer)
|
||||
if(!mymob)
|
||||
return
|
||||
var/mob/living/carbon/human/H = mymob
|
||||
|
||||
var/mob/screenmob = viewer || H
|
||||
|
||||
if(screenmob.hud_used.inventory_shown && screenmob.hud_used.hud_shown)
|
||||
if(H.shoes)
|
||||
H.shoes.screen_loc = ui_shoes
|
||||
screenmob.client.screen += H.shoes
|
||||
if(H.gloves)
|
||||
H.gloves.screen_loc = ui_gloves
|
||||
screenmob.client.screen += H.gloves
|
||||
if(H.ears)
|
||||
H.ears.screen_loc = ui_ears
|
||||
screenmob.client.screen += H.ears
|
||||
if(H.glasses)
|
||||
H.glasses.screen_loc = ui_glasses
|
||||
screenmob.client.screen += H.glasses
|
||||
if(H.w_uniform)
|
||||
H.w_uniform.screen_loc = ui_iclothing
|
||||
screenmob.client.screen += H.w_uniform
|
||||
if(H.wear_suit)
|
||||
H.wear_suit.screen_loc = ui_oclothing
|
||||
screenmob.client.screen += H.wear_suit
|
||||
if(H.wear_mask)
|
||||
H.wear_mask.screen_loc = ui_mask
|
||||
screenmob.client.screen += H.wear_mask
|
||||
if(H.wear_neck)
|
||||
H.wear_neck.screen_loc = ui_neck
|
||||
screenmob.client.screen += H.wear_neck
|
||||
if(H.head)
|
||||
H.head.screen_loc = ui_head
|
||||
screenmob.client.screen += H.head
|
||||
else
|
||||
if(H.shoes) screenmob.client.screen -= H.shoes
|
||||
if(H.gloves) screenmob.client.screen -= H.gloves
|
||||
if(H.ears) screenmob.client.screen -= H.ears
|
||||
if(H.glasses) screenmob.client.screen -= H.glasses
|
||||
if(H.w_uniform) screenmob.client.screen -= H.w_uniform
|
||||
if(H.wear_suit) screenmob.client.screen -= H.wear_suit
|
||||
if(H.wear_mask) screenmob.client.screen -= H.wear_mask
|
||||
if(H.wear_neck) screenmob.client.screen -= H.wear_neck
|
||||
if(H.head) screenmob.client.screen -= H.head
|
||||
|
||||
|
||||
|
||||
/datum/hud/human/persistent_inventory_update(mob/viewer)
|
||||
if(!mymob)
|
||||
return
|
||||
..()
|
||||
var/mob/living/carbon/human/H = mymob
|
||||
|
||||
var/mob/screenmob = viewer || H
|
||||
|
||||
if(screenmob.hud_used)
|
||||
if(screenmob.hud_used.hud_shown)
|
||||
if(H.s_store)
|
||||
H.s_store.screen_loc = ui_sstore1
|
||||
screenmob.client.screen += H.s_store
|
||||
if(H.wear_id)
|
||||
H.wear_id.screen_loc = ui_id
|
||||
screenmob.client.screen += H.wear_id
|
||||
if(H.belt)
|
||||
H.belt.screen_loc = ui_belt
|
||||
screenmob.client.screen += H.belt
|
||||
if(H.back)
|
||||
H.back.screen_loc = ui_back
|
||||
screenmob.client.screen += H.back
|
||||
if(H.l_store)
|
||||
H.l_store.screen_loc = ui_storage1
|
||||
screenmob.client.screen += H.l_store
|
||||
if(H.r_store)
|
||||
H.r_store.screen_loc = ui_storage2
|
||||
screenmob.client.screen += H.r_store
|
||||
else
|
||||
if(H.s_store)
|
||||
screenmob.client.screen -= H.s_store
|
||||
if(H.wear_id)
|
||||
screenmob.client.screen -= H.wear_id
|
||||
if(H.belt)
|
||||
screenmob.client.screen -= H.belt
|
||||
if(H.back)
|
||||
screenmob.client.screen -= H.back
|
||||
if(H.l_store)
|
||||
screenmob.client.screen -= H.l_store
|
||||
if(H.r_store)
|
||||
screenmob.client.screen -= H.r_store
|
||||
|
||||
if(hud_version != HUD_STYLE_NOHUD)
|
||||
for(var/obj/item/I in H.held_items)
|
||||
I.screen_loc = ui_hand_position(H.get_held_index_of_item(I))
|
||||
screenmob.client.screen += I
|
||||
else
|
||||
for(var/obj/item/I in H.held_items)
|
||||
I.screen_loc = null
|
||||
screenmob.client.screen -= I
|
||||
|
||||
|
||||
/mob/living/carbon/human/verb/toggle_hotkey_verbs()
|
||||
set category = "OOC"
|
||||
set name = "Toggle hotkey buttons"
|
||||
set desc = "This disables or enables the user interface buttons which can be used with hotkeys."
|
||||
|
||||
if(hud_used.hotkey_ui_hidden)
|
||||
client.screen += hud_used.hotkeybuttons
|
||||
hud_used.hotkey_ui_hidden = 0
|
||||
else
|
||||
client.screen -= hud_used.hotkeybuttons
|
||||
hud_used.hotkey_ui_hidden = 1
|
||||
|
||||
Regular → Executable
+6
@@ -21,6 +21,7 @@
|
||||
C.parallax_layers_cached = list()
|
||||
C.parallax_layers_cached += new /obj/screen/parallax_layer/layer_1(null, C.view)
|
||||
C.parallax_layers_cached += new /obj/screen/parallax_layer/layer_2(null, C.view)
|
||||
C.parallax_layers_cached += new /obj/screen/parallax_layer/layer_3(null, C.view)
|
||||
|
||||
C.parallax_layers = C.parallax_layers_cached.Copy()
|
||||
|
||||
@@ -278,6 +279,11 @@
|
||||
speed = 1
|
||||
layer = 2
|
||||
|
||||
/obj/screen/parallax_layer/layer_3
|
||||
icon_state = "layer3"
|
||||
speed = 1.4
|
||||
layer = 3
|
||||
|
||||
#undef LOOP_NONE
|
||||
#undef LOOP_NORMAL
|
||||
#undef LOOP_REVERSE
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
/obj/screen/plane_master/game_world
|
||||
name = "game world plane master"
|
||||
plane = GAME_PLANE
|
||||
appearance_flags = PLANE_MASTER //should use client color
|
||||
blend_mode = BLEND_OVERLAY
|
||||
|
||||
/obj/screen/plane_master/lighting
|
||||
|
||||
@@ -91,10 +91,9 @@
|
||||
screen_loc = ui_language_menu
|
||||
|
||||
/obj/screen/language_menu/Click()
|
||||
var/mob/living/L = usr
|
||||
if(!istype(L))
|
||||
return
|
||||
L.open_language_menu(usr)
|
||||
var/mob/M = usr
|
||||
var/datum/language_holder/H = M.get_language_holder()
|
||||
H.open_language_menu(usr)
|
||||
|
||||
/obj/screen/inventory
|
||||
var/slot_id // The indentifier for the slot. It has nothing to do with ID cards.
|
||||
@@ -532,6 +531,12 @@
|
||||
screen_loc = ui_health
|
||||
mouse_opacity = 0
|
||||
|
||||
/obj/screen/healths/construct
|
||||
icon = 'icons/mob/screen_construct.dmi'
|
||||
icon_state = "artificer_health0"
|
||||
screen_loc = ui_construct_health
|
||||
mouse_opacity = 0
|
||||
|
||||
/obj/screen/healthdoll
|
||||
name = "health doll"
|
||||
screen_loc = ui_healthdoll
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
|
||||
/proc/melee_item_attack_chain(mob/user, obj/item/I, atom/target, params)
|
||||
if(I.pre_attackby(target, user, params))
|
||||
/obj/item/proc/melee_attack_chain(mob/user, atom/target, params)
|
||||
if(pre_attackby(target, user, params))
|
||||
// Return 1 in attackby() to prevent afterattack() effects (when safely moving items for example)
|
||||
var/resolved = target.attackby(I,user,params)
|
||||
if(!resolved && target && I)
|
||||
I.afterattack(target, user, 1, params) // 1: clicking something Adjacent
|
||||
var/resolved = target.attackby(src, user, params)
|
||||
if(!resolved && target && !QDELETED(src))
|
||||
afterattack(target, user, 1, params) // 1: clicking something Adjacent
|
||||
|
||||
|
||||
// Called when the item is in the active hand, and clicked; alternately, there is an 'activate held object' verb or you can hit pagedown.
|
||||
@@ -28,7 +28,7 @@
|
||||
if(sharpness)
|
||||
to_chat(user, "<span class='notice'>You begin to butcher [src]...</span>")
|
||||
playsound(loc, 'sound/weapons/slice.ogg', 50, 1, -1)
|
||||
if(do_mob(user, src, 80/sharpness))
|
||||
if(do_mob(user, src, 80/sharpness) && Adjacent(I))
|
||||
harvest(user)
|
||||
return 1
|
||||
return I.attack(src, user)
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
/atom/proc/attack_tk(mob/user)
|
||||
if(user.stat)
|
||||
return
|
||||
new /obj/effect/overlay/temp/telekinesis(loc)
|
||||
new /obj/effect/temp_visual/telekinesis(loc)
|
||||
user.UnarmedAttack(src,0) // attack_hand, attack_paw, etc
|
||||
return
|
||||
|
||||
@@ -124,7 +124,8 @@
|
||||
|
||||
if(!isturf(target) && istype(focus,/obj/item) && target.Adjacent(focus))
|
||||
apply_focus_overlay()
|
||||
melee_item_attack_chain(tk_user, focus, target, params) //isn't copying the attack chain fun. we should do it more often.
|
||||
var/obj/item/I = focus
|
||||
I.melee_attack_chain(tk_user, target, params) //isn't copying the attack chain fun. we should do it more often.
|
||||
if(check_if_focusable(focus))
|
||||
focus.do_attack_animation(target, null, focus)
|
||||
else
|
||||
@@ -163,7 +164,7 @@
|
||||
/obj/item/tk_grab/proc/apply_focus_overlay()
|
||||
if(!focus)
|
||||
return
|
||||
new /obj/effect/overlay/temp/telekinesis(get_turf(focus))
|
||||
new /obj/effect/temp_visual/telekinesis(get_turf(focus))
|
||||
|
||||
/obj/item/tk_grab/update_icon()
|
||||
cut_overlays()
|
||||
|
||||
@@ -117,7 +117,7 @@ GLOBAL_VAR_INIT(dlooc_allowed, 1)
|
||||
prefs.chat_toggles ^= CHAT_LOOC
|
||||
prefs.save_preferences()
|
||||
src << "You will [(prefs.chat_toggles & CHAT_LOOC) ? "now" : "no longer"] see messages on the LOOC channel."
|
||||
feedback_add_details("admin_verb","TLOOC") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
SSblackbox.add_details("admin_verb","TLOOC") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/datum/admins/proc/togglelooc()
|
||||
set category = "Server"
|
||||
@@ -126,7 +126,7 @@ GLOBAL_VAR_INIT(dlooc_allowed, 1)
|
||||
toggle_looc()
|
||||
log_admin("[key_name(usr)] toggled LOOC.")
|
||||
message_admins("[key_name_admin(usr)] toggled LOOC.")
|
||||
feedback_add_details("admin_verb","TLOOC") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
SSblackbox.add_details("admin_verb","TLOOC") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/proc/toggle_looc(toggle = null)
|
||||
if(toggle != null) //if we're specifically en/disabling ooc
|
||||
@@ -146,7 +146,7 @@ GLOBAL_VAR_INIT(dlooc_allowed, 1)
|
||||
|
||||
log_admin("[key_name(usr)] toggled Dead LOOC.")
|
||||
message_admins("[key_name_admin(usr)] toggled Dead LOOC.")
|
||||
feedback_add_details("admin_verb","TDLOOC") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
SSblackbox.add_details("admin_verb","TDLOOC") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
|
||||
/mob/living/carbon/proc/has_penis()
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
var/arousal_gain_rate = 1 //Rate at which this species becomes aroused
|
||||
var/arousal_lose_rate = 1 //Multiplier for how easily arousal can be relieved
|
||||
var/list/cum_fluids = list("semen")
|
||||
var/list/milk_fludis = list("milk")
|
||||
var/list/milk_fluids = list("milk")
|
||||
var/list/femcum_fluids = list("femcum")
|
||||
|
||||
//Mob procs
|
||||
@@ -254,16 +254,34 @@
|
||||
"<span class='green'>You cum into [SC].</span>", \
|
||||
"<span class='green'>You have relieved yourself.</span>")
|
||||
finished = 1
|
||||
|
||||
|
||||
if(/obj/item/organ/genital/vagina)
|
||||
var/obj/item/organ/genital/vagina/V = SG
|
||||
if(!V.linked_womb)
|
||||
src << "<span class='warning'>No womb!</span>"
|
||||
return
|
||||
fluid_source = V.linked_womb.reagents
|
||||
total_cum = fluid_source.total_volume
|
||||
if(into_container)//into a glass or beaker or whatever
|
||||
src.visible_message("<span class='danger'>[src] starts fingering their vagina over [SC].</span>", \
|
||||
"<span class='userdanger'>You start fingering over [SC.name].</span>", \
|
||||
"<span class='userdanger'>You start masturbating.</span>")
|
||||
if(do_after(src, mb_time, target = src) && in_range(src, SC))
|
||||
fluid_source.trans_to(SC, total_cum)
|
||||
src.visible_message("<span class='danger'>[src] orgasms, [pick("cumming into", "emptying themself into")] [SC]!</span>", \
|
||||
"<span class='green'>You cum into [SC].</span>", \
|
||||
"<span class='green'>You have relieved yourself.</span>")
|
||||
finished = 1
|
||||
|
||||
else//not into a container
|
||||
src.visible_message("<span class='danger'>[src] starts [pick("jerking off","stroking")] their [pick(GLOB.dick_nouns)].</span>", \
|
||||
"<span class='userdanger'>You start jerking off your [pick(GLOB.dick_nouns)].</span>", \
|
||||
src.visible_message("<span class='danger'>[src] starts fingering their vagina.</span>", \
|
||||
"<span class='userdanger'>You start fingering your vagina.</span>", \
|
||||
"<span class='userdanger'>You start masturbating.</span>")
|
||||
if(do_after(src, mb_time, target = src))
|
||||
if(total_cum > 5)
|
||||
fluid_source.reaction(src.loc, TOUCH, 1, 0)
|
||||
fluid_source.clear_reagents()
|
||||
src.visible_message("<span class='danger'>[src] orgasms, [pick("shooting cum", "draining their balls")][istype(src.loc, /turf/open/floor) ? " onto [src.loc]" : ""]!</span>", \
|
||||
src.visible_message("<span class='danger'>[src] orgasms, cumming[istype(src.loc, /turf/open/floor) ? " onto [src.loc]" : ""]!</span>", \
|
||||
"<span class='green'>You cum[istype(src.loc, /turf/open/floor) ? " onto [src.loc]" : ""].</span>", \
|
||||
"<span class='green'>You have relieved yourself.</span>")
|
||||
finished = 1
|
||||
@@ -285,4 +303,4 @@
|
||||
/mob/living/carbon/proc/force_orgasm(intensity)
|
||||
if(canbearoused && has_dna() && (has_penis() || has_vagina()))
|
||||
return 1
|
||||
return 0
|
||||
return 0
|
||||
|
||||
@@ -80,7 +80,7 @@
|
||||
var/obj/effect/decal/cleanable/femcum/S = locate() in T
|
||||
if(!S)
|
||||
S = new(T)
|
||||
S.reagents.add_reagent("semen", reac_volume)
|
||||
S.reagents.add_reagent("femcum", reac_volume)
|
||||
if(data["blood_DNA"])
|
||||
S.blood_DNA[data["blood_DNA"]] = data["blood_type"]
|
||||
|
||||
@@ -219,4 +219,4 @@
|
||||
results = list("anaphro+" = 1)
|
||||
required_reagents = list("anaphro" = 5, "acetone" = 1)
|
||||
required_temp = 300
|
||||
mix_message = "The mixture thickens and heats up slighty..."
|
||||
mix_message = "The mixture thickens and heats up slighty..."
|
||||
|
||||
@@ -16,7 +16,8 @@
|
||||
|
||||
/obj/item/organ/genital/Initialize()
|
||||
. = ..()
|
||||
reagents = create_reagents(fluid_max_volume)
|
||||
if(!reagents)
|
||||
create_reagents(fluid_max_volume)
|
||||
update()
|
||||
|
||||
/obj/item/organ/genital/Destroy()
|
||||
|
||||
@@ -6,8 +6,28 @@
|
||||
zone = "groin"
|
||||
slot = "womb"
|
||||
w_class = 3
|
||||
var/internal = FALSE
|
||||
fluid_id = "femcum"
|
||||
producing = TRUE
|
||||
var/obj/item/organ/genital/vagina/linked_vag
|
||||
|
||||
/obj/item/organ/genital/womb/Initialize()
|
||||
. = ..()
|
||||
reagents.add_reagent(fluid_id, fluid_max_volume)
|
||||
|
||||
/obj/item/organ/genital/womb/on_life()
|
||||
if(QDELETED(src))
|
||||
return
|
||||
if(reagents && producing)
|
||||
generate_femcum()
|
||||
|
||||
/obj/item/organ/genital/womb/proc/generate_femcum()
|
||||
reagents.maximum_volume = fluid_max_volume
|
||||
update_link()
|
||||
if(!linked_vag)
|
||||
return FALSE
|
||||
reagents.isolate_reagent(fluid_id)//remove old reagents if it changed and just clean up generally
|
||||
reagents.add_reagent(fluid_id, (fluid_mult * fluid_rate))//generate the cum
|
||||
|
||||
/obj/item/organ/genital/womb/update_link()
|
||||
if(owner)
|
||||
@@ -25,4 +45,4 @@
|
||||
linked_vag = null
|
||||
|
||||
/obj/item/organ/genital/womb/Destroy()
|
||||
return ..()
|
||||
return ..()
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
INITIALIZE_IMMEDIATE(/obj/effect/statclick)
|
||||
|
||||
/obj/effect/statclick/Initialize(mapload, text, target) //Don't port this to Initialize it's too critical
|
||||
..()
|
||||
. = ..()
|
||||
name = text
|
||||
src.target = target
|
||||
|
||||
@@ -45,9 +45,9 @@ INITIALIZE_IMMEDIATE(/obj/effect/statclick)
|
||||
switch(controller)
|
||||
if("Master")
|
||||
Recreate_MC()
|
||||
feedback_add_details("admin_verb","Restart Master Controller")
|
||||
SSblackbox.add_details("admin_verb","Restart Master Controller")
|
||||
if("Failsafe")
|
||||
new /datum/controller/failsafe()
|
||||
feedback_add_details("admin_verb","Restart Failsafe Controller")
|
||||
SSblackbox.add_details("admin_verb","Restart Failsafe Controller")
|
||||
|
||||
message_admins("Admin [key_name_admin(usr)] has restarted the [controller] controller.")
|
||||
|
||||
+930
-923
File diff suppressed because it is too large
Load Diff
@@ -52,6 +52,12 @@ GLOBAL_REAL(GLOB, /datum/controller/global_vars)
|
||||
/datum/controller/global_vars/Initialize()
|
||||
gvars_datum_init_order = list()
|
||||
gvars_datum_protected_varlist = list("gvars_datum_protected_varlist")
|
||||
|
||||
//See https://github.com/tgstation/tgstation/issues/26954
|
||||
for(var/I in typesof(/datum/controller/global_vars/proc))
|
||||
var/CLEANBOT_RETURNS = "[I]"
|
||||
pass(CLEANBOT_RETURNS)
|
||||
|
||||
for(var/I in vars - gvars_datum_in_built_vars)
|
||||
var/start_tick = world.time
|
||||
call(src, "InitGlobal[I]")()
|
||||
|
||||
+91
-70
@@ -14,15 +14,6 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
|
||||
//Master -> SSPreInit -> GLOB -> world -> config -> SSInit -> Failsafe
|
||||
//GOT IT MEMORIZED?
|
||||
|
||||
GLOBAL_VAR_INIT(MC_restart_clear, 0)
|
||||
GLOBAL_VAR_INIT(MC_restart_timeout, 0)
|
||||
GLOBAL_VAR_INIT(MC_restart_count, 0)
|
||||
|
||||
|
||||
//current tick limit, assigned by the queue controller before running a subsystem.
|
||||
//used by check_tick as well so that the procs subsystems call can obey that SS's tick limits
|
||||
GLOBAL_VAR_INIT(CURRENT_TICKLIMIT, TICK_LIMIT_RUNNING)
|
||||
|
||||
/datum/controller/master
|
||||
name = "Master"
|
||||
|
||||
@@ -47,8 +38,6 @@ GLOBAL_VAR_INIT(CURRENT_TICKLIMIT, TICK_LIMIT_RUNNING)
|
||||
var/make_runtime = 0
|
||||
|
||||
var/initializations_finished_with_no_players_logged_in //I wonder what this could be?
|
||||
// Has round started? (So we know what subsystems to run)
|
||||
var/round_started = 0
|
||||
|
||||
// The type of the last subsystem to be process()'d.
|
||||
var/last_type_processed
|
||||
@@ -59,6 +48,16 @@ GLOBAL_VAR_INIT(CURRENT_TICKLIMIT, TICK_LIMIT_RUNNING)
|
||||
var/queue_priority_count_bg = 0 //Same, but for background subsystems
|
||||
var/map_loading = FALSE //Are we loading in a new map?
|
||||
|
||||
var/current_runlevel //for scheduling different subsystems for different stages of the round
|
||||
|
||||
var/static/restart_clear = 0
|
||||
var/static/restart_timeout = 0
|
||||
var/static/restart_count = 0
|
||||
|
||||
//current tick limit, assigned before running a subsystem.
|
||||
//used by CHECK_TICK as well so that the procs subsystems call can obey that SS's tick limits
|
||||
var/static/current_ticklimit = TICK_LIMIT_RUNNING
|
||||
|
||||
/datum/controller/master/New()
|
||||
// Highlander-style: there can only be one! Kill off the old and replace it with the new.
|
||||
subsystems = list()
|
||||
@@ -83,20 +82,21 @@ GLOBAL_VAR_INIT(CURRENT_TICKLIMIT, TICK_LIMIT_RUNNING)
|
||||
sortTim(subsystems, /proc/cmp_subsystem_init)
|
||||
reverseRange(subsystems)
|
||||
for(var/datum/controller/subsystem/ss in subsystems)
|
||||
testing("Shutdown [ss.name] subsystem")
|
||||
ss.Shutdown()
|
||||
|
||||
// Returns 1 if we created a new mc, 0 if we couldn't due to a recent restart,
|
||||
// -1 if we encountered a runtime trying to recreate it
|
||||
/proc/Recreate_MC()
|
||||
. = -1 //so if we runtime, things know we failed
|
||||
if (world.time < GLOB.MC_restart_timeout)
|
||||
if (world.time < Master.restart_timeout)
|
||||
return 0
|
||||
if (world.time < GLOB.MC_restart_clear)
|
||||
GLOB.MC_restart_count *= 0.5
|
||||
if (world.time < Master.restart_clear)
|
||||
Master.restart_count *= 0.5
|
||||
|
||||
var/delay = 50 * ++GLOB.MC_restart_count
|
||||
GLOB.MC_restart_timeout = world.time + delay
|
||||
GLOB.MC_restart_clear = world.time + (delay * 2)
|
||||
var/delay = 50 * ++Master.restart_count
|
||||
Master.restart_timeout = world.time + delay
|
||||
Master.restart_clear = world.time + (delay * 2)
|
||||
Master.processing = 0 //stop ticking this one
|
||||
try
|
||||
new/datum/controller/master()
|
||||
@@ -132,13 +132,14 @@ GLOBAL_VAR_INIT(CURRENT_TICKLIMIT, TICK_LIMIT_RUNNING)
|
||||
msg = "The [BadBoy.name] subsystem seems to be destabilizing the MC and will be offlined."
|
||||
BadBoy.flags |= SS_NO_FIRE
|
||||
if(msg)
|
||||
to_chat(GLOB.admins, "<span class='boldannounce'>[msg]</span>")
|
||||
to_chat(GLOB.admins, "<span class='boldannounce'>[msg]</span>")
|
||||
log_world(msg)
|
||||
|
||||
if (istype(Master.subsystems))
|
||||
if(FireHim)
|
||||
Master.subsystems += new BadBoy.type //NEW_SS_GLOBAL will remove the old one
|
||||
subsystems = Master.subsystems
|
||||
current_runlevel = Master.current_runlevel
|
||||
StartProcessing(10)
|
||||
else
|
||||
to_chat(world, "<span class='boldannounce'>The Master Controller is having some issues, we will need to re-initialize EVERYTHING</span>")
|
||||
@@ -163,19 +164,22 @@ GLOBAL_VAR_INIT(CURRENT_TICKLIMIT, TICK_LIMIT_RUNNING)
|
||||
|
||||
var/start_timeofday = REALTIMEOFDAY
|
||||
// Initialize subsystems.
|
||||
GLOB.CURRENT_TICKLIMIT = config.tick_limit_mc_init
|
||||
current_ticklimit = config.tick_limit_mc_init
|
||||
for (var/datum/controller/subsystem/SS in subsystems)
|
||||
if (SS.flags & SS_NO_INIT)
|
||||
continue
|
||||
SS.Initialize(REALTIMEOFDAY)
|
||||
CHECK_TICK
|
||||
GLOB.CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING
|
||||
current_ticklimit = TICK_LIMIT_RUNNING
|
||||
var/time = (REALTIMEOFDAY - start_timeofday) / 10
|
||||
|
||||
var/msg = "Initializations complete within [time] second[time == 1 ? "" : "s"]!"
|
||||
to_chat(world, "<span class='boldannounce'>[msg]</span>")
|
||||
log_world(msg)
|
||||
|
||||
if (!current_runlevel)
|
||||
SetRunLevel(1)
|
||||
|
||||
// Sort subsystems by display setting for easy access.
|
||||
sortTim(subsystems, /proc/cmp_subsystem_display)
|
||||
// Set world options.
|
||||
@@ -187,22 +191,22 @@ GLOBAL_VAR_INIT(CURRENT_TICKLIMIT, TICK_LIMIT_RUNNING)
|
||||
// Loop.
|
||||
Master.StartProcessing(0)
|
||||
|
||||
// Notify the MC that the round has started.
|
||||
/datum/controller/master/proc/RoundStart()
|
||||
round_started = 1
|
||||
var/timer = world.time
|
||||
for (var/datum/controller/subsystem/SS in subsystems)
|
||||
if (SS.flags & SS_FIRE_IN_LOBBY || SS.flags & SS_TICKER)
|
||||
continue //already firing
|
||||
// Stagger subsystems.
|
||||
timer += world.tick_lag * rand(1, 5)
|
||||
SS.next_fire = timer
|
||||
/datum/controller/master/proc/SetRunLevel(new_runlevel)
|
||||
var/old_runlevel = current_runlevel
|
||||
if(isnull(old_runlevel))
|
||||
old_runlevel = "NULL"
|
||||
|
||||
testing("MC: Runlevel changed from [old_runlevel] to [new_runlevel]")
|
||||
current_runlevel = log(2, new_runlevel) + 1
|
||||
if(current_runlevel < 1)
|
||||
CRASH("Attempted to set invalid runlevel: [new_runlevel]")
|
||||
|
||||
// Starts the mc, and sticks around to restart it if the loop ever ends.
|
||||
/datum/controller/master/proc/StartProcessing(delay)
|
||||
set waitfor = 0
|
||||
if(delay)
|
||||
sleep(delay)
|
||||
testing("Master starting processing")
|
||||
var/rtn = Loop()
|
||||
if (rtn > 0 || processing < 0)
|
||||
return //this was suppose to happen.
|
||||
@@ -221,12 +225,9 @@ GLOBAL_VAR_INIT(CURRENT_TICKLIMIT, TICK_LIMIT_RUNNING)
|
||||
//Prep the loop (most of this is because we want MC restarts to reset as much state as we can, and because
|
||||
// local vars rock
|
||||
|
||||
// Schedule the first run of the Subsystems.
|
||||
round_started = world.has_round_started()
|
||||
//all this shit is here so that flag edits can be refreshed by restarting the MC. (and for speed)
|
||||
var/list/tickersubsystems = list()
|
||||
var/list/normalsubsystems = list()
|
||||
var/list/lobbysubsystems = list()
|
||||
var/list/runlevel_sorted_subsystems = list(list()) //ensure we always have at least one runlevel
|
||||
var/timer = world.time
|
||||
for (var/thing in subsystems)
|
||||
var/datum/controller/subsystem/SS = thing
|
||||
@@ -241,25 +242,29 @@ GLOBAL_VAR_INIT(CURRENT_TICKLIMIT, TICK_LIMIT_RUNNING)
|
||||
timer += world.tick_lag * rand(1, 5)
|
||||
SS.next_fire = timer
|
||||
continue
|
||||
if (SS.flags & SS_FIRE_IN_LOBBY)
|
||||
lobbysubsystems += SS
|
||||
timer += world.tick_lag * rand(1, 5)
|
||||
SS.next_fire = timer
|
||||
else if (round_started)
|
||||
timer += world.tick_lag * rand(1, 5)
|
||||
SS.next_fire = timer
|
||||
normalsubsystems += SS
|
||||
|
||||
var/ss_runlevels = SS.runlevels
|
||||
var/added_to_any = FALSE
|
||||
for(var/I in 1 to GLOB.bitflags.len)
|
||||
if(ss_runlevels & GLOB.bitflags[I])
|
||||
while(runlevel_sorted_subsystems.len < I)
|
||||
runlevel_sorted_subsystems += list(list())
|
||||
runlevel_sorted_subsystems[I] += SS
|
||||
added_to_any = TRUE
|
||||
if(!added_to_any)
|
||||
WARNING("[SS.name] subsystem is not SS_NO_FIRE but also does not have any runlevels set!")
|
||||
|
||||
queue_head = null
|
||||
queue_tail = null
|
||||
//these sort by lower priorities first to reduce the number of loops needed to add subsequent SS's to the queue
|
||||
//(higher subsystems will be sooner in the queue, adding them later in the loop means we don't have to loop thru them next queue add)
|
||||
sortTim(tickersubsystems, /proc/cmp_subsystem_priority)
|
||||
sortTim(normalsubsystems, /proc/cmp_subsystem_priority)
|
||||
sortTim(lobbysubsystems, /proc/cmp_subsystem_priority)
|
||||
for(var/I in runlevel_sorted_subsystems)
|
||||
sortTim(runlevel_sorted_subsystems, /proc/cmp_subsystem_priority)
|
||||
I += tickersubsystems
|
||||
|
||||
normalsubsystems += tickersubsystems
|
||||
lobbysubsystems += tickersubsystems
|
||||
var/cached_runlevel = current_runlevel
|
||||
var/list/current_runlevel_subsystems = runlevel_sorted_subsystems[cached_runlevel]
|
||||
|
||||
init_timeofday = REALTIMEOFDAY
|
||||
init_time = world.time
|
||||
@@ -272,7 +277,7 @@ GLOBAL_VAR_INIT(CURRENT_TICKLIMIT, TICK_LIMIT_RUNNING)
|
||||
while (1)
|
||||
tickdrift = max(0, MC_AVERAGE_FAST(tickdrift, (((REALTIMEOFDAY - init_timeofday) - (world.time - init_time)) / world.tick_lag)))
|
||||
if (processing <= 0)
|
||||
GLOB.CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING
|
||||
current_ticklimit = TICK_LIMIT_RUNNING
|
||||
sleep(10)
|
||||
continue
|
||||
|
||||
@@ -280,7 +285,7 @@ GLOBAL_VAR_INIT(CURRENT_TICKLIMIT, TICK_LIMIT_RUNNING)
|
||||
// because sleeps are processed in the order received, so longer sleeps are more likely to run first
|
||||
if (world.tick_usage > TICK_LIMIT_MC)
|
||||
sleep_delta += 2
|
||||
GLOB.CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING - (TICK_LIMIT_RUNNING * 0.5)
|
||||
current_ticklimit = TICK_LIMIT_RUNNING * 0.5
|
||||
sleep(world.tick_lag * (processing + sleep_delta))
|
||||
continue
|
||||
|
||||
@@ -296,32 +301,41 @@ GLOBAL_VAR_INIT(CURRENT_TICKLIMIT, TICK_LIMIT_RUNNING)
|
||||
if (!Failsafe || (Failsafe.processing_interval > 0 && (Failsafe.lasttick+(Failsafe.processing_interval*5)) < world.time))
|
||||
new/datum/controller/failsafe() // (re)Start the failsafe.
|
||||
if (!queue_head || !(iteration % 3))
|
||||
if (round_started)
|
||||
subsystems_to_check = normalsubsystems
|
||||
else
|
||||
subsystems_to_check = lobbysubsystems
|
||||
var/checking_runlevel = current_runlevel
|
||||
if(cached_runlevel != checking_runlevel)
|
||||
//resechedule subsystems
|
||||
cached_runlevel = checking_runlevel
|
||||
current_runlevel_subsystems = runlevel_sorted_subsystems[cached_runlevel]
|
||||
var/stagger = world.time
|
||||
for(var/I in current_runlevel_subsystems)
|
||||
var/datum/controller/subsystem/SS = I
|
||||
if(SS.next_fire <= world.time)
|
||||
stagger += world.tick_lag * rand(1, 5)
|
||||
SS.next_fire = stagger
|
||||
|
||||
subsystems_to_check = current_runlevel_subsystems
|
||||
else
|
||||
subsystems_to_check = tickersubsystems
|
||||
if (CheckQueue(subsystems_to_check) <= 0)
|
||||
if (!SoftReset(tickersubsystems, normalsubsystems, lobbysubsystems))
|
||||
if (!SoftReset(tickersubsystems, runlevel_sorted_subsystems))
|
||||
log_world("MC: SoftReset() failed, crashing")
|
||||
return
|
||||
if (!error_level)
|
||||
iteration++
|
||||
error_level++
|
||||
GLOB.CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING
|
||||
current_ticklimit = TICK_LIMIT_RUNNING
|
||||
sleep(10)
|
||||
continue
|
||||
|
||||
if (queue_head)
|
||||
if (RunQueue() <= 0)
|
||||
if (!SoftReset(tickersubsystems, normalsubsystems, lobbysubsystems))
|
||||
if (!SoftReset(tickersubsystems, runlevel_sorted_subsystems))
|
||||
log_world("MC: SoftReset() failed, crashing")
|
||||
return
|
||||
if (!error_level)
|
||||
iteration++
|
||||
error_level++
|
||||
GLOB.CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING
|
||||
current_ticklimit = TICK_LIMIT_RUNNING
|
||||
sleep(10)
|
||||
continue
|
||||
error_level--
|
||||
@@ -332,7 +346,7 @@ GLOBAL_VAR_INIT(CURRENT_TICKLIMIT, TICK_LIMIT_RUNNING)
|
||||
iteration++
|
||||
last_run = world.time
|
||||
src.sleep_delta = MC_AVERAGE_FAST(src.sleep_delta, sleep_delta)
|
||||
GLOB.CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING - (TICK_LIMIT_RUNNING * 0.25) //reserve the tail 1/4 of the next tick for the mc.
|
||||
current_ticklimit = TICK_LIMIT_RUNNING - (TICK_LIMIT_RUNNING * 0.25) //reserve the tail 1/4 of the next tick for the mc.
|
||||
sleep(world.tick_lag * (processing + sleep_delta))
|
||||
|
||||
|
||||
@@ -421,26 +435,31 @@ GLOBAL_VAR_INIT(CURRENT_TICKLIMIT, TICK_LIMIT_RUNNING)
|
||||
else
|
||||
tick_precentage = tick_remaining
|
||||
|
||||
GLOB.CURRENT_TICKLIMIT = world.tick_usage + tick_precentage
|
||||
tick_precentage = max(tick_precentage*0.5, tick_precentage-queue_node.tick_overrun)
|
||||
|
||||
current_ticklimit = round(world.tick_usage + tick_precentage)
|
||||
|
||||
if (!(queue_node_flags & SS_TICKER))
|
||||
ran_non_ticker = TRUE
|
||||
ran = TRUE
|
||||
tick_usage = world.tick_usage
|
||||
|
||||
queue_node_paused = (queue_node.state == SS_PAUSED || queue_node.state == SS_PAUSING)
|
||||
last_type_processed = queue_node
|
||||
|
||||
queue_node.state = SS_RUNNING
|
||||
|
||||
tick_usage = world.tick_usage
|
||||
var/state = queue_node.ignite(queue_node_paused)
|
||||
tick_usage = world.tick_usage - tick_usage
|
||||
|
||||
if (state == SS_RUNNING)
|
||||
state = SS_IDLE
|
||||
current_tick_budget -= queue_node_priority
|
||||
tick_usage = world.tick_usage - tick_usage
|
||||
|
||||
|
||||
if (tick_usage < 0)
|
||||
tick_usage = 0
|
||||
|
||||
queue_node.tick_overrun = max(0, MC_AVG_FAST_UP_SLOW_DOWN(queue_node.tick_overrun, tick_usage-tick_precentage))
|
||||
queue_node.state = state
|
||||
|
||||
if (state == SS_PAUSED)
|
||||
@@ -467,13 +486,13 @@ GLOBAL_VAR_INIT(CURRENT_TICKLIMIT, TICK_LIMIT_RUNNING)
|
||||
queue_node.times_fired++
|
||||
|
||||
if (queue_node_flags & SS_TICKER)
|
||||
queue_node.next_fire = world.time + (world.tick_lag * queue_node.wait)
|
||||
queue_node.next_fire = world.time + (world.tick_lag * (queue_node.wait + (queue_node.tick_overrun/100)))
|
||||
else if (queue_node_flags & SS_POST_FIRE_TIMING)
|
||||
queue_node.next_fire = world.time + queue_node.wait
|
||||
queue_node.next_fire = world.time + queue_node.wait + (world.tick_lag * (queue_node.tick_overrun/100))
|
||||
else if (queue_node_flags & SS_KEEP_TIMING)
|
||||
queue_node.next_fire += queue_node.wait
|
||||
else
|
||||
queue_node.next_fire = queue_node.queued_time + queue_node.wait
|
||||
queue_node.next_fire = queue_node.queued_time + queue_node.wait + (world.tick_lag * (queue_node.tick_overrun/100))
|
||||
|
||||
queue_node.queued_time = 0
|
||||
|
||||
@@ -486,13 +505,15 @@ GLOBAL_VAR_INIT(CURRENT_TICKLIMIT, TICK_LIMIT_RUNNING)
|
||||
|
||||
//resets the queue, and all subsystems, while filtering out the subsystem lists
|
||||
// called if any mc's queue procs runtime or exit improperly.
|
||||
/datum/controller/master/proc/SoftReset(list/ticker_SS, list/normal_SS, list/lobby_SS)
|
||||
/datum/controller/master/proc/SoftReset(list/ticker_SS, list/runlevel_SS)
|
||||
. = 0
|
||||
log_world("MC: SoftReset called, resetting MC queue state.")
|
||||
if (!istype(subsystems) || !istype(ticker_SS) || !istype(normal_SS) || !istype(lobby_SS))
|
||||
log_world("MC: SoftReset: Bad list contents: '[subsystems]' '[ticker_SS]' '[normal_SS]' '[lobby_SS]' Crashing!")
|
||||
if (!istype(subsystems) || !istype(ticker_SS) || !istype(runlevel_SS))
|
||||
log_world("MC: SoftReset: Bad list contents: '[subsystems]' '[ticker_SS]' '[runlevel_SS]'")
|
||||
return
|
||||
var/subsystemstocheck = subsystems + ticker_SS + normal_SS + lobby_SS
|
||||
var/subsystemstocheck = subsystems + ticker_SS
|
||||
for(var/I in runlevel_SS)
|
||||
subsystemstocheck |= I
|
||||
|
||||
for (var/thing in subsystemstocheck)
|
||||
var/datum/controller/subsystem/SS = thing
|
||||
@@ -500,8 +521,8 @@ GLOBAL_VAR_INIT(CURRENT_TICKLIMIT, TICK_LIMIT_RUNNING)
|
||||
//list(SS) is so if a list makes it in the subsystem list, we remove the list, not the contents
|
||||
subsystems -= list(SS)
|
||||
ticker_SS -= list(SS)
|
||||
normal_SS -= list(SS)
|
||||
lobby_SS -= list(SS)
|
||||
for(var/I in runlevel_SS)
|
||||
I -= list(SS)
|
||||
log_world("MC: SoftReset: Found bad entry in subsystem list, '[SS]'")
|
||||
continue
|
||||
if (SS.queue_next && !istype(SS.queue_next))
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
var/next_fire = 0 //scheduled world.time for next fire()
|
||||
var/cost = 0 //average time to execute
|
||||
var/tick_usage = 0 //average tick usage
|
||||
var/tick_overrun = 0 //average tick overrun
|
||||
var/state = SS_IDLE //tracks the current state of the ss, running, paused, etc.
|
||||
var/paused_ticks = 0 //ticks this ss is taking to run right now.
|
||||
var/paused_tick_usage //total tick_usage of all of our runs while pausing this run
|
||||
@@ -28,6 +29,8 @@
|
||||
var/datum/controller/subsystem/queue_next
|
||||
var/datum/controller/subsystem/queue_prev
|
||||
|
||||
var/runlevels = RUNLEVELS_DEFAULT //points of the game at which the SS can fire
|
||||
|
||||
var/static/failure_strikes = 0 //How many times we suspect this subsystem has crashed the MC, 3 strikes and you're out!
|
||||
|
||||
//Do not override
|
||||
@@ -168,7 +171,7 @@
|
||||
|
||||
|
||||
if(can_fire && !(SS_NO_FIRE in flags))
|
||||
msg = "[round(cost,1)]ms|[round(tick_usage,1)]%|[round(ticks,0.1)]\t[msg]"
|
||||
msg = "[round(cost,1)]ms|[round(tick_usage,1)]%([round(tick_overrun,1)]%)|[round(ticks,0.1)]\t[msg]"
|
||||
else
|
||||
msg = "OFFLINE\t[msg]"
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ SUBSYSTEM_DEF(acid)
|
||||
name = "Acid"
|
||||
priority = 40
|
||||
flags = SS_NO_INIT|SS_BACKGROUND
|
||||
runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME
|
||||
|
||||
var/list/currentrun = list()
|
||||
var/list/processing = list()
|
||||
|
||||
@@ -7,11 +7,12 @@
|
||||
#define SSAIR_SUPERCONDUCTIVITY 7
|
||||
|
||||
SUBSYSTEM_DEF(air)
|
||||
name = "Air"
|
||||
name = "Atmospherics"
|
||||
init_order = INIT_ORDER_AIR
|
||||
priority = 20
|
||||
wait = 5
|
||||
flags = SS_BACKGROUND
|
||||
runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME
|
||||
|
||||
var/cost_turfs = 0
|
||||
var/cost_groups = 0
|
||||
@@ -299,7 +300,7 @@ SUBSYSTEM_DEF(air)
|
||||
var/timer = world.timeofday
|
||||
warning("There are [starting_ats] active turfs at roundstart, this is a mapping error caused by a difference of the air between the adjacent turfs. You can see its coordinates using \"Mapping -> Show roundstart AT list\" verb (debug verbs required)")
|
||||
for(var/turf/T in active_turfs)
|
||||
GLOB.active_turfs_startlist += text("[T.x], [T.y], [T.z]\n")
|
||||
GLOB.active_turfs_startlist += T
|
||||
|
||||
//now lets clear out these active turfs
|
||||
var/list/turfs_to_check = active_turfs.Copy()
|
||||
|
||||
@@ -150,7 +150,7 @@ SUBSYSTEM_DEF(atoms)
|
||||
/datum/controller/subsystem/atoms/Shutdown()
|
||||
var/initlog = InitLog()
|
||||
if(initlog)
|
||||
log_world(initlog)
|
||||
text2file(initlog, "[GLOB.log_directory]/initialize.log")
|
||||
|
||||
#undef BAD_INIT_QDEL_BEFORE
|
||||
#undef BAD_INIT_DIDNT_INIT
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
diff a/code/controllers/subsystem/atoms.dm b/code/controllers/subsystem/atoms.dm (rejected hunks)
|
||||
@@ -12,6 +12,7 @@ SUBSYSTEM_DEF(atoms)
|
||||
var/old_initialized
|
||||
|
||||
var/list/late_loaders
|
||||
+ var/list/created_atoms
|
||||
|
||||
var/list/BadInitializeCalls = list()
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
SUBSYSTEM_DEF(augury)
|
||||
name = "Augury"
|
||||
flags = SS_NO_INIT
|
||||
runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME
|
||||
|
||||
var/list/watchers = list()
|
||||
var/list/doombringers = list()
|
||||
|
||||
@@ -0,0 +1,241 @@
|
||||
SUBSYSTEM_DEF(blackbox)
|
||||
name = "Blackbox"
|
||||
wait = 6000
|
||||
flags = SS_NO_TICK_CHECK | SS_NO_INIT
|
||||
runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME
|
||||
|
||||
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
|
||||
|
||||
//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
|
||||
|
||||
//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()
|
||||
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)
|
||||
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)
|
||||
var/datum/feedback_variable/FV = find_feedback_datum(variable)
|
||||
FV.set_value(value)
|
||||
|
||||
/datum/controller/subsystem/blackbox/proc/inc(variable, value)
|
||||
var/datum/feedback_variable/FV = find_feedback_datum(variable)
|
||||
FV.inc(value)
|
||||
|
||||
/datum/controller/subsystem/blackbox/proc/dec(variable,value)
|
||||
var/datum/feedback_variable/FV = find_feedback_datum(variable)
|
||||
FV.dec(value)
|
||||
|
||||
/datum/controller/subsystem/blackbox/proc/set_details(variable,details)
|
||||
var/datum/feedback_variable/FV = find_feedback_datum(variable)
|
||||
FV.set_details(details)
|
||||
|
||||
/datum/controller/subsystem/blackbox/proc/add_details(variable,details)
|
||||
var/datum/feedback_variable/FV = find_feedback_datum(variable)
|
||||
FV.add_details(details)
|
||||
|
||||
/datum/controller/subsystem/blackbox/proc/ReportDeath(mob/living/L)
|
||||
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/sqlgender = sanitizeSQL(L.gender)
|
||||
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/coord = sanitizeSQL("[L.x], [L.y], [L.z]")
|
||||
var/map = sanitizeSQL(SSmapping.config.map_name)
|
||||
var/datum/DBQuery/query_report_death = SSdbcore.NewQuery("INSERT INTO [format_table_name("death")] (name, byondkey, job, special, pod, tod, laname, lakey, gender, bruteloss, fireloss, brainloss, oxyloss, toxloss, cloneloss, staminaloss, coord, mapname, server_ip, server_port) VALUES ('[sqlname]', '[sqlkey]', '[sqljob]', '[sqlspecial]', '[sqlpod]', '[SQLtime()]', '[laname]', '[lakey]', '[sqlgender]', [sqlbrute], [sqlfire], [sqlbrain], [sqloxy], [sqltox], [sqlclone], [sqlstamina], '[coord]', '[map]', INET_ATON(IF('[world.internet_address]' LIKE '', '0', '[world.internet_address]')), '[world.port]')")
|
||||
query_report_death.Execute()
|
||||
|
||||
|
||||
//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
|
||||
|
||||
/datum/feedback_variable/proc/set_details(text)
|
||||
if (istext(text))
|
||||
details = text
|
||||
|
||||
/datum/feedback_variable/proc/add_details(text)
|
||||
if (istext(text))
|
||||
text = replacetext(text, " ", "_")
|
||||
if (!details)
|
||||
details = text
|
||||
else
|
||||
details += " [text]"
|
||||
|
||||
/datum/feedback_variable/proc/get_details()
|
||||
return details
|
||||
|
||||
/datum/feedback_variable/proc/get_parsed()
|
||||
return list(variable,value,details)
|
||||
@@ -1,7 +1,7 @@
|
||||
SUBSYSTEM_DEF(dbcore)
|
||||
name = "Database"
|
||||
flags = SS_NO_INIT|SS_NO_FIRE
|
||||
|
||||
init_order = INIT_ORDER_DBCORE
|
||||
var/const/FAILED_DB_CONNECTION_CUTOFF = 5
|
||||
|
||||
var/const/Default_Cursor = 0
|
||||
@@ -23,12 +23,18 @@ SUBSYSTEM_DEF(dbcore)
|
||||
var/failed_connections = 0
|
||||
|
||||
/datum/controller/subsystem/dbcore/PreInit()
|
||||
_db_con = _dm_db_new_con()
|
||||
if(!_db_con)
|
||||
_db_con = _dm_db_new_con()
|
||||
|
||||
/datum/controller/subsystem/dbcore/Recover()
|
||||
_db_con = SSdbcore._db_con
|
||||
|
||||
/datum/controller/subsystem/dbcore/Shutdown()
|
||||
//This is as close as we can get to the true round end before Disconnect() without changing where it's called, defeating the reason this is a subsystem
|
||||
if(SSdbcore.Connect())
|
||||
var/sql_station_name = sanitizeSQL(station_name())
|
||||
var/datum/DBQuery/query_round_end = SSdbcore.NewQuery("UPDATE [format_table_name("round")] SET end_datetime = Now(), game_mode_result = '[SSticker.mode_result]', end_state = '[SSticker.end_state]', station_name = '[sql_station_name]' WHERE id = [GLOB.round_id]")
|
||||
query_round_end.Execute()
|
||||
if(IsConnected())
|
||||
Disconnect()
|
||||
|
||||
@@ -47,7 +53,7 @@ SUBSYSTEM_DEF(dbcore)
|
||||
|
||||
if(failed_connections > FAILED_DB_CONNECTION_CUTOFF) //If it failed to establish a connection more than 5 times in a row, don't bother attempting to connect anymore.
|
||||
return FALSE
|
||||
|
||||
|
||||
if(!config.sql_enabled)
|
||||
return FALSE
|
||||
|
||||
@@ -77,15 +83,87 @@ SUBSYSTEM_DEF(dbcore)
|
||||
return FALSE
|
||||
return _dm_db_is_connected(_db_con)
|
||||
|
||||
/datum/controller/subsystem/dbcore/proc/Quote(str)
|
||||
/datum/controller/subsystem/dbcore/proc/Quote(str)
|
||||
return _dm_db_quote(_db_con, str)
|
||||
|
||||
/datum/controller/subsystem/dbcore/proc/ErrorMsg()
|
||||
/datum/controller/subsystem/dbcore/proc/ErrorMsg()
|
||||
if(!config.sql_enabled)
|
||||
return "Database disabled by configuration"
|
||||
return _dm_db_error_msg(_db_con)
|
||||
|
||||
/datum/controller/subsystem/dbcore/proc/NewQuery(sql_query, cursor_handler = Default_Cursor)
|
||||
if(IsAdminAdvancedProcCall())
|
||||
log_admin_private("ERROR: Advanced admin proc call led to sql query: [sql_query]. Query has been blocked")
|
||||
message_admins("ERROR: Advanced admin proc call led to sql query. Query has been blocked")
|
||||
return FALSE
|
||||
return new /datum/DBQuery(sql_query, src, cursor_handler)
|
||||
|
||||
/*
|
||||
Takes a list of rows (each row being an associated list of column => value) and inserts them via a single mass query.
|
||||
Rows missing columns present in other rows will resolve to SQL NULL
|
||||
You are expected to do your own escaping of the data, and expected to provide your own quotes for strings.
|
||||
The duplicate_key arg can be true to automatically generate this part of the query
|
||||
or set to a string that is appended to the end of the query
|
||||
Ignore_errors instructes mysql to continue inserting rows if some of them have errors.
|
||||
the erroneous row(s) aren't inserted and there isn't really any way to know why or why errored
|
||||
Delayed insert mode was removed in mysql 7 and only works with MyISAM type tables,
|
||||
It was included because it is still supported in mariadb.
|
||||
It does not work with duplicate_key and the mysql server ignores it in those cases
|
||||
*/
|
||||
/datum/controller/subsystem/dbcore/proc/MassInsert(table, list/rows, duplicate_key = FALSE, ignore_errors = FALSE, delayed = FALSE, warn = FALSE)
|
||||
if (!table || !rows || !istype(rows))
|
||||
return
|
||||
var/list/columns = list()
|
||||
var/list/sorted_rows = list()
|
||||
|
||||
for (var/list/row in rows)
|
||||
var/list/sorted_row = list()
|
||||
sorted_row.len = columns.len
|
||||
for (var/column in row)
|
||||
var/idx = columns[column]
|
||||
if (!idx)
|
||||
idx = columns.len + 1
|
||||
columns[column] = idx
|
||||
sorted_row.len = columns.len
|
||||
|
||||
sorted_row[idx] = row[column]
|
||||
sorted_rows[++sorted_rows.len] = sorted_row
|
||||
|
||||
if (duplicate_key == TRUE)
|
||||
var/list/column_list = list()
|
||||
for (var/column in columns)
|
||||
column_list += "[column] = VALUES([column])"
|
||||
duplicate_key = "ON DUPLICATE KEY UPDATE [column_list.Join(", ")]\n"
|
||||
else if (duplicate_key == FALSE)
|
||||
duplicate_key = null
|
||||
|
||||
if (ignore_errors)
|
||||
ignore_errors = " IGNORE"
|
||||
else
|
||||
ignore_errors = null
|
||||
|
||||
if (delayed)
|
||||
delayed = " DELAYED"
|
||||
else
|
||||
delayed = null
|
||||
|
||||
var/list/sqlrowlist = list()
|
||||
var/len = columns.len
|
||||
for (var/list/row in sorted_rows)
|
||||
if (length(row) != len)
|
||||
row.len = len
|
||||
for (var/value in row)
|
||||
if (value == null)
|
||||
value = "NULL"
|
||||
sqlrowlist += "([row.Join(", ")])"
|
||||
|
||||
sqlrowlist = " [sqlrowlist.Join(",\n ")]"
|
||||
var/datum/DBQuery/Query = NewQuery("INSERT[delayed][ignore_errors] INTO [table]\n([columns.Join(", ")])\nVALUES\n[sqlrowlist]\n[duplicate_key]")
|
||||
if (warn)
|
||||
return Query.warn_execute()
|
||||
else
|
||||
return Query.Execute()
|
||||
|
||||
|
||||
/datum/DBQuery
|
||||
var/sql // The sql query being executed.
|
||||
@@ -98,16 +176,16 @@ SUBSYSTEM_DEF(dbcore)
|
||||
var/_db_query
|
||||
|
||||
/datum/DBQuery/New(sql_query, datum/controller/subsystem/dbcore/connection_handler, cursor_handler)
|
||||
if(sql_query)
|
||||
if(sql_query)
|
||||
sql = sql_query
|
||||
if(connection_handler)
|
||||
if(connection_handler)
|
||||
db_connection = connection_handler
|
||||
if(cursor_handler)
|
||||
if(cursor_handler)
|
||||
default_cursor = cursor_handler
|
||||
item = list()
|
||||
_db_query = _dm_db_new_query()
|
||||
|
||||
/datum/DBQuery/proc/Connect(datum/controller/subsystem/dbcore/connection_handler)
|
||||
/datum/DBQuery/proc/Connect(datum/controller/subsystem/dbcore/connection_handler)
|
||||
db_connection = connection_handler
|
||||
|
||||
/datum/DBQuery/proc/warn_execute()
|
||||
@@ -121,16 +199,16 @@ SUBSYSTEM_DEF(dbcore)
|
||||
if(!. && log_error)
|
||||
log_sql("[ErrorMsg()] | Query used: [sql]")
|
||||
|
||||
/datum/DBQuery/proc/NextRow()
|
||||
/datum/DBQuery/proc/NextRow()
|
||||
return _dm_db_next_row(_db_query,item,conversions)
|
||||
|
||||
/datum/DBQuery/proc/RowsAffected()
|
||||
return _dm_db_rows_affected(_db_query)
|
||||
|
||||
/datum/DBQuery/proc/RowCount()
|
||||
/datum/DBQuery/proc/RowCount()
|
||||
return _dm_db_row_count(_db_query)
|
||||
|
||||
/datum/DBQuery/proc/ErrorMsg()
|
||||
/datum/DBQuery/proc/ErrorMsg()
|
||||
return _dm_db_error_msg(_db_query)
|
||||
|
||||
/datum/DBQuery/proc/Columns()
|
||||
@@ -159,11 +237,11 @@ SUBSYSTEM_DEF(dbcore)
|
||||
return db_connection.Quote(str)
|
||||
|
||||
/datum/DBQuery/proc/SetConversion(column,conversion)
|
||||
if(istext(column))
|
||||
if(istext(column))
|
||||
column = columns.Find(column)
|
||||
if(!conversions)
|
||||
if(!conversions)
|
||||
conversions = list(column)
|
||||
else if(conversions.len < column)
|
||||
else if(conversions.len < column)
|
||||
conversions.len = column
|
||||
conversions[column] = conversion
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
SUBSYSTEM_DEF(disease)
|
||||
name = "Disease"
|
||||
flags = SS_KEEP_TIMING|SS_NO_INIT
|
||||
runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME
|
||||
|
||||
var/list/currentrun = list()
|
||||
var/list/processing = list()
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
SUBSYSTEM_DEF(events)
|
||||
name = "Events"
|
||||
init_order = INIT_ORDER_EVENTS
|
||||
runlevels = RUNLEVEL_GAME
|
||||
|
||||
var/list/control = list() //list of all datum/round_event_control. Used for selecting events based on weight and occurrences.
|
||||
var/list/running = list() //list of all existing /datum/round_event
|
||||
@@ -104,7 +105,7 @@ SUBSYSTEM_DEF(events)
|
||||
//These are needed because /area/engine has to be removed from the list, but we still want these areas to get fucked up.
|
||||
var/list/danger_areas = list(
|
||||
/area/engine/break_room,
|
||||
/area/engine/chiefs_office)
|
||||
/area/crew_quarters/heads/chief)
|
||||
|
||||
//Need to locate() as it's just a list of paths.
|
||||
return locate(pick((GLOB.the_station_areas - safe_areas) + danger_areas))
|
||||
|
||||
@@ -0,0 +1,510 @@
|
||||
SUBSYSTEM_DEF(explosion)
|
||||
priority = 99
|
||||
wait = 1
|
||||
flags = SS_TICKER|SS_NO_INIT
|
||||
|
||||
var/list/explosions
|
||||
|
||||
var/rebuild_tick_split_count = FALSE
|
||||
var/tick_portions_required = 0
|
||||
|
||||
var/list/logs
|
||||
|
||||
var/list/zlevels_that_ignore_bombcap
|
||||
var/list/doppler_arrays
|
||||
|
||||
//legacy caps, set by config
|
||||
var/devastation_cap = 3
|
||||
var/heavy_cap = 7
|
||||
var/light_cap = 14
|
||||
var/flash_cap = 14
|
||||
var/flame_cap = 14
|
||||
var/dyn_ex_scale = 0.5
|
||||
|
||||
var/id_counter = 0
|
||||
|
||||
/datum/controller/subsystem/explosion/PreInit()
|
||||
doppler_arrays = list()
|
||||
logs = list()
|
||||
explosions = list()
|
||||
zlevels_that_ignore_bombcap = list("[ZLEVEL_MINING]")
|
||||
|
||||
/datum/controller/subsystem/explosion/Shutdown()
|
||||
QDEL_LIST(explosions)
|
||||
QDEL_LIST(logs)
|
||||
zlevels_that_ignore_bombcap.Cut()
|
||||
|
||||
/datum/controller/subsystem/explosion/Recover()
|
||||
explosions = SSexplosion.explosions
|
||||
logs = SSexplosion.logs
|
||||
id_counter = SSexplosion.id_counter
|
||||
rebuild_tick_split_count = TRUE
|
||||
zlevels_that_ignore_bombcap = SSexplosion.zlevels_that_ignore_bombcap
|
||||
doppler_arrays = SSexplosion.doppler_arrays
|
||||
|
||||
devastation_cap = SSexplosion.devastation_cap
|
||||
heavy_cap = SSexplosion.heavy_cap
|
||||
light_cap = SSexplosion.light_cap
|
||||
flash_cap = SSexplosion.flash_cap
|
||||
flame_cap = SSexplosion.flame_cap
|
||||
dyn_ex_scale = SSexplosion.dyn_ex_scale
|
||||
|
||||
/datum/controller/subsystem/explosion/fire()
|
||||
var/list/cached_explosions = explosions
|
||||
var/num_explosions = cached_explosions.len
|
||||
if(!num_explosions)
|
||||
return
|
||||
|
||||
//figure exactly how many tick splits are required
|
||||
var/num_splits
|
||||
if(rebuild_tick_split_count)
|
||||
var/reactionary = config.reactionary_explosions
|
||||
num_splits = num_explosions
|
||||
for(var/I in cached_explosions)
|
||||
var/datum/explosion/E = I
|
||||
if(!E.turfs_processed)
|
||||
++num_splits
|
||||
if(reactionary && !E.densities_processed)
|
||||
++num_splits
|
||||
tick_portions_required = num_splits
|
||||
else
|
||||
num_splits = tick_portions_required
|
||||
|
||||
MC_SPLIT_TICK_INIT(num_splits)
|
||||
|
||||
for(var/I in cached_explosions)
|
||||
var/datum/explosion/E = I
|
||||
|
||||
var/etp = E.turfs_processed
|
||||
if(!etp)
|
||||
if(GatherTurfs(E))
|
||||
--tick_portions_required
|
||||
etp = TRUE
|
||||
MC_SPLIT_TICK
|
||||
|
||||
var/edp = E.densities_processed
|
||||
if(!edp)
|
||||
if(DensityCalculate(E, etp))
|
||||
--tick_portions_required
|
||||
edp = TRUE
|
||||
MC_SPLIT_TICK
|
||||
|
||||
if(ProcessExplosion(E, edp)) //splits the tick
|
||||
--tick_portions_required
|
||||
explosions -= E
|
||||
logs += E
|
||||
NotifyDopplers(E)
|
||||
MC_SPLIT_TICK
|
||||
|
||||
/datum/controller/subsystem/explosion/proc/NotifyDopplers(datum/explosion/E)
|
||||
for(var/array in doppler_arrays)
|
||||
var/obj/machinery/doppler_array/A = array
|
||||
A.sense_explosion(E.epicenter, E.devastation, E.heavy, E.light, E.finished_at - E.started_at, E.orig_dev_range, E.orig_heavy_range, E.orig_light_range)
|
||||
|
||||
/datum/controller/subsystem/explosion/proc/Create(atom/epicenter, devastation_range, heavy_impact_range, light_impact_range, flash_range, adminlog = TRUE, ignorecap = FALSE, flame_range = 0 , silent = FALSE, smoke = FALSE)
|
||||
epicenter = get_turf(epicenter)
|
||||
if(!epicenter)
|
||||
return
|
||||
|
||||
if(adminlog)
|
||||
message_admins("Explosion with size ([devastation_range], [heavy_impact_range], [light_impact_range], [flame_range]) in area: [get_area(epicenter)] [ADMIN_COORDJMP(epicenter)]")
|
||||
log_game("Explosion with size ([devastation_range], [heavy_impact_range], [light_impact_range], [flame_range]) in area [epicenter.loc.name] ([epicenter.x],[epicenter.y],[epicenter.z])")
|
||||
|
||||
var/datum/explosion/E = new(++id_counter, epicenter, devastation_range, heavy_impact_range, light_impact_range, flash_range, flame_range, silent, smoke, ignorecap)
|
||||
|
||||
if(heavy_impact_range > 1)
|
||||
var/datum/effect_system/explosion/Eff
|
||||
if(smoke)
|
||||
Eff = new /datum/effect_system/explosion/smoke
|
||||
else
|
||||
Eff = new
|
||||
Eff.set_up(epicenter)
|
||||
Eff.start()
|
||||
|
||||
//flash mobs
|
||||
if(flash_range)
|
||||
for(var/mob/living/L in viewers(flash_range, epicenter))
|
||||
L.flash_act()
|
||||
|
||||
if(!silent)
|
||||
ExplosionSound(epicenter, devastation_range, heavy_impact_range, E.extent)
|
||||
|
||||
//add to SS
|
||||
if(E.extent)
|
||||
tick_portions_required += 2 + (config.reactionary_explosions ? 1 : 0)
|
||||
explosions += E
|
||||
else
|
||||
logs += E //Already done processing
|
||||
|
||||
/datum/controller/subsystem/explosion/proc/CreateDynamic(atom/epicenter, power, flash_range, adminlog = TRUE, ignorecap = TRUE, flame_range = 0 , silent = FALSE, smoke = TRUE)
|
||||
if(!power)
|
||||
return
|
||||
var/range = round((2 * power) ** dyn_ex_scale)
|
||||
Create(epicenter, round(range * 0.25), round(range * 0.5), round(range), flash_range*range, adminlog, ignorecap, flame_range*range, silent, smoke)
|
||||
|
||||
// Using default dyn_ex scale:
|
||||
// 100 explosion power is a (5, 10, 20) explosion.
|
||||
// 75 explosion power is a (4, 8, 17) explosion.
|
||||
// 50 explosion power is a (3, 7, 14) explosion.
|
||||
// 25 explosion power is a (2, 5, 10) explosion.
|
||||
// 10 explosion power is a (1, 3, 6) explosion.
|
||||
// 5 explosion power is a (0, 1, 3) explosion.
|
||||
// 1 explosion power is a (0, 0, 1) explosion.
|
||||
|
||||
/datum/explosion
|
||||
var/explosion_id
|
||||
var/turf/epicenter
|
||||
|
||||
var/started_at
|
||||
var/finished_at
|
||||
var/tick_started
|
||||
var/tick_finished
|
||||
|
||||
var/turfs_processed = FALSE
|
||||
var/densities_processed = FALSE
|
||||
|
||||
var/orig_dev_range
|
||||
var/orig_heavy_range
|
||||
var/orig_light_range
|
||||
var/orig_flash_range
|
||||
var/orig_flame_range
|
||||
|
||||
var/devastation
|
||||
var/heavy
|
||||
var/light
|
||||
var/extent
|
||||
|
||||
var/flash
|
||||
var/flame
|
||||
|
||||
var/gather_dist = 0
|
||||
|
||||
var/list/gathered_turfs
|
||||
var/list/calculated_turfs
|
||||
|
||||
var/list/unsafe_turfs
|
||||
|
||||
/datum/explosion/New(id, turf/epi, devastation_range, heavy_impact_range, light_impact_range, flash_range, flame_range, silent, smoke, ignorecap)
|
||||
explosion_id = id
|
||||
epicenter = epi
|
||||
|
||||
densities_processed = !config.reactionary_explosions
|
||||
|
||||
orig_dev_range = devastation_range
|
||||
orig_heavy_range = heavy_impact_range
|
||||
orig_light_range = light_impact_range
|
||||
orig_flash_range = flash_range
|
||||
orig_flame_range = flame_range
|
||||
|
||||
if(!ignorecap && !("[epicenter.z]" in SSexplosion.zlevels_that_ignore_bombcap))
|
||||
//Clamp all values
|
||||
devastation_range = min(SSexplosion.devastation_cap, devastation_range)
|
||||
heavy_impact_range = min(SSexplosion.heavy_cap, heavy_impact_range)
|
||||
light_impact_range = min(SSexplosion.light_cap, light_impact_range)
|
||||
flash_range = min(SSexplosion.flash_cap, flash_range)
|
||||
flame_range = min(SSexplosion.flame_cap, flame_range)
|
||||
|
||||
//store this
|
||||
devastation = devastation_range
|
||||
heavy = heavy_impact_range
|
||||
light = light_impact_range
|
||||
|
||||
extent = max(devastation_range, heavy_impact_range, light_impact_range, flame_range)
|
||||
|
||||
flash = flash_range
|
||||
flame = flame_range
|
||||
|
||||
started_at = REALTIMEOFDAY
|
||||
tick_started = world.time
|
||||
|
||||
gathered_turfs = list()
|
||||
calculated_turfs = list()
|
||||
unsafe_turfs = list()
|
||||
|
||||
// Play sounds; we want sounds to be different depending on distance so we will manually do it ourselves.
|
||||
// Stereo users will also hear the direction of the explosion!
|
||||
|
||||
// Calculate far explosion sound range. Only allow the sound effect for heavy/devastating explosions.
|
||||
// 3/7/14 will calculate to 80 + 35
|
||||
/proc/ExplosionSound(turf/epicenter, devastation_range, heavy_impact_range, extent)
|
||||
var/far_dist = 0
|
||||
far_dist += heavy_impact_range * 5
|
||||
far_dist += devastation_range * 20
|
||||
|
||||
var/z0 = epicenter.z
|
||||
|
||||
var/frequency = get_rand_frequency()
|
||||
var/ex_sound = get_sfx("explosion")
|
||||
for(var/mob/M in GLOB.player_list)
|
||||
// Double check for client
|
||||
var/turf/M_turf = get_turf(M)
|
||||
if(M_turf && M_turf.z == z0)
|
||||
var/dist = get_dist(M_turf, epicenter)
|
||||
// If inside the blast radius + world.view - 2
|
||||
if(dist <= round(extent + world.view - 2, 1))
|
||||
M.playsound_local(epicenter, ex_sound, 100, 1, frequency, falloff = 5)
|
||||
// You hear a far explosion if you're outside the blast radius. Small bombs shouldn't be heard all over the station.
|
||||
else if(dist <= far_dist)
|
||||
var/far_volume = Clamp(far_dist, 30, 50) // Volume is based on explosion size and dist
|
||||
far_volume += (dist <= far_dist * 0.5 ? 50 : 0) // add 50 volume if the mob is pretty close to the explosion
|
||||
M.playsound_local(epicenter, 'sound/effects/explosionfar.ogg', far_volume, 1, frequency, falloff = 5)
|
||||
|
||||
/datum/explosion/Destroy()
|
||||
SSexplosion.explosions -= src
|
||||
SSexplosion.logs -= src
|
||||
LAZYCLEARLIST(gathered_turfs)
|
||||
LAZYCLEARLIST(calculated_turfs)
|
||||
LAZYCLEARLIST(unsafe_turfs)
|
||||
return ..()
|
||||
|
||||
/datum/controller/subsystem/explosion/proc/GatherTurfs(datum/explosion/E)
|
||||
var/turf/epicenter = E.epicenter
|
||||
|
||||
var/x0 = epicenter.x
|
||||
var/y0 = epicenter.y
|
||||
var/z0 = epicenter.z
|
||||
|
||||
var/c_dist = E.gather_dist
|
||||
var/dist = E.extent
|
||||
|
||||
var/list/L = E.gathered_turfs
|
||||
|
||||
if(!c_dist)
|
||||
L += epicenter
|
||||
++c_dist
|
||||
|
||||
while( c_dist <= dist )
|
||||
var/y = y0 + c_dist
|
||||
var/x = x0 - c_dist + 1
|
||||
for(x in x to x0 + c_dist)
|
||||
var/turf/T = locate(x, y, z0)
|
||||
if(T)
|
||||
L += T
|
||||
|
||||
y = y0 + c_dist - 1
|
||||
x = x0 + c_dist
|
||||
for(y in y0 - c_dist to y)
|
||||
var/turf/T = locate(x, y, z0)
|
||||
if(T)
|
||||
L += T
|
||||
|
||||
y = y0 - c_dist
|
||||
x = x0 + c_dist - 1
|
||||
for(x in x0 - c_dist to x)
|
||||
var/turf/T = locate(x, y, z0)
|
||||
if(T)
|
||||
L += T
|
||||
|
||||
y = y0 - c_dist + 1
|
||||
x = x0 - c_dist
|
||||
for(y in y to y0 + c_dist)
|
||||
var/turf/T = locate(x, y, z0)
|
||||
if(T)
|
||||
L += T
|
||||
++c_dist
|
||||
|
||||
if(MC_TICK_CHECK)
|
||||
break
|
||||
|
||||
if(c_dist > dist)
|
||||
E.turfs_processed = TRUE
|
||||
return TRUE
|
||||
else
|
||||
E.gather_dist = c_dist
|
||||
return FALSE
|
||||
|
||||
/datum/controller/subsystem/explosion/proc/DensityCalculate(datum/explosion/E, done_gathering_turfs)
|
||||
var/list/L = E.calculated_turfs
|
||||
var/cut_to = 1
|
||||
for(var/I in E.gathered_turfs) // we cache the explosion block rating of every turf in the explosion area
|
||||
var/turf/T = I
|
||||
++cut_to
|
||||
|
||||
var/current_exp_block = T.density ? T.explosion_block : 0
|
||||
|
||||
for(var/obj/machinery/door/D in T)
|
||||
if(D.density)
|
||||
current_exp_block += D.explosion_block
|
||||
|
||||
for(var/obj/structure/window/W in T)
|
||||
if(W.reinf && W.fulltile)
|
||||
current_exp_block += W.explosion_block
|
||||
|
||||
for(var/obj/structure/blob/B in T)
|
||||
current_exp_block += B.explosion_block
|
||||
|
||||
L[T] = current_exp_block
|
||||
|
||||
if(MC_TICK_CHECK)
|
||||
E.gathered_turfs.Cut(1, cut_to)
|
||||
return FALSE
|
||||
|
||||
E.gathered_turfs.Cut()
|
||||
return done_gathering_turfs
|
||||
|
||||
/datum/controller/subsystem/explosion/proc/ProcessExplosion(datum/explosion/E, done_calculating_turfs)
|
||||
//cache shit for speed
|
||||
var/id = E.explosion_id
|
||||
|
||||
var/list/cached_unsafe = E.unsafe_turfs
|
||||
var/list/cached_exp_block = E.calculated_turfs
|
||||
var/list/affected_turfs = cached_exp_block ? cached_exp_block : E.gathered_turfs
|
||||
|
||||
var/devastation_range = E.devastation
|
||||
var/heavy_impact_range = E.heavy
|
||||
var/light_impact_range = E.light
|
||||
|
||||
var/flame_range = E.flame
|
||||
var/throw_range_max = E.extent
|
||||
|
||||
var/turf/epi = E.epicenter
|
||||
|
||||
var/x0 = epi.x
|
||||
var/y0 = epi.y
|
||||
|
||||
var/cut_to = 1
|
||||
for(var/TI in affected_turfs)
|
||||
var/turf/T = TI
|
||||
++cut_to
|
||||
|
||||
var/init_dist = cheap_hypotenuse(T.x, T.y, x0, y0)
|
||||
var/dist = init_dist
|
||||
|
||||
if(cached_exp_block)
|
||||
var/turf/Trajectory = T
|
||||
while(Trajectory != epi)
|
||||
Trajectory = get_step_towards(Trajectory, epi)
|
||||
dist += cached_exp_block[Trajectory]
|
||||
|
||||
var/flame_dist = dist < flame_range
|
||||
var/throw_dist = dist
|
||||
|
||||
if(dist < devastation_range)
|
||||
dist = 1
|
||||
else if(dist < heavy_impact_range)
|
||||
dist = 2
|
||||
else if(dist < light_impact_range)
|
||||
dist = 3
|
||||
else
|
||||
dist = 0
|
||||
|
||||
//------- EX_ACT AND TURF FIRES -------
|
||||
|
||||
if(flame_dist && prob(40) && !isspaceturf(T) && !T.density)
|
||||
new /obj/effect/hotspot(T) //Mostly for ambience!
|
||||
|
||||
if(dist > 0)
|
||||
T.explosion_level = max(T.explosion_level, dist) //let the bigger one have it
|
||||
T.explosion_id = id
|
||||
T.ex_act(dist)
|
||||
cached_unsafe += T
|
||||
|
||||
//--- THROW ITEMS AROUND ---
|
||||
|
||||
var/throw_dir = get_dir(epi, T)
|
||||
for(var/obj/item/I in T)
|
||||
if(!I.anchored)
|
||||
var/throw_range = rand(throw_dist, throw_range_max)
|
||||
var/turf/throw_at = get_ranged_target_turf(I, throw_dir, throw_range)
|
||||
I.throw_speed = 4 //Temporarily change their throw_speed for embedding purposes (Resets when it finishes throwing, regardless of hitting anything)
|
||||
I.throw_at(throw_at, throw_range, 4)
|
||||
|
||||
if(MC_TICK_CHECK)
|
||||
var/circumference = (PI * (init_dist + 4) * 2) //+4 to radius to prevent shit gaps
|
||||
if(cached_unsafe.len > circumference) //only do this every revolution
|
||||
for(var/Unexplode in cached_unsafe)
|
||||
var/turf/UnexplodeT = Unexplode
|
||||
UnexplodeT.explosion_level = 0
|
||||
cached_unsafe.Cut()
|
||||
done_calculating_turfs = FALSE
|
||||
break
|
||||
|
||||
affected_turfs.Cut(1, cut_to)
|
||||
|
||||
if(!done_calculating_turfs)
|
||||
return FALSE
|
||||
|
||||
//unfuck the shit
|
||||
for(var/Unexplode in cached_unsafe)
|
||||
var/turf/UnexplodeT = Unexplode
|
||||
UnexplodeT.explosion_level = 0
|
||||
cached_unsafe.Cut()
|
||||
|
||||
E.finished_at = REALTIMEOFDAY
|
||||
E.tick_finished = world.time
|
||||
|
||||
return TRUE
|
||||
|
||||
/client/proc/check_bomb_impacts()
|
||||
set name = "Check Bomb Impact"
|
||||
set category = "Debug"
|
||||
|
||||
var/newmode = alert("Use reactionary explosions?","Check Bomb Impact", "Yes", "No")
|
||||
var/turf/epicenter = get_turf(mob)
|
||||
if(!epicenter)
|
||||
return
|
||||
|
||||
var/x0 = epicenter.x
|
||||
var/y0 = epicenter.y
|
||||
|
||||
var/dev = 0
|
||||
var/heavy = 0
|
||||
var/light = 0
|
||||
var/list/choices = list("Small Bomb","Medium Bomb","Big Bomb","Custom Bomb")
|
||||
var/choice = input("Bomb Size?") in choices
|
||||
switch(choice)
|
||||
if(null)
|
||||
return 0
|
||||
if("Small Bomb")
|
||||
dev = 1
|
||||
heavy = 2
|
||||
light = 3
|
||||
if("Medium Bomb")
|
||||
dev = 2
|
||||
heavy = 3
|
||||
light = 4
|
||||
if("Big Bomb")
|
||||
dev = 3
|
||||
heavy = 5
|
||||
light = 7
|
||||
if("Custom Bomb")
|
||||
dev = input("Devestation range (Tiles):") as num
|
||||
heavy = input("Heavy impact range (Tiles):") as num
|
||||
light = input("Light impact range (Tiles):") as num
|
||||
else
|
||||
return
|
||||
|
||||
var/datum/explosion/E = new(null, epicenter, dev, heavy, light, ignorecap = TRUE)
|
||||
|
||||
while(!SSexplosion.GatherTurfs(E))
|
||||
stoplag()
|
||||
var/list/turfs
|
||||
if(newmode)
|
||||
while(!SSexplosion.DensityCalculate(E, TRUE))
|
||||
stoplag()
|
||||
turfs = E.calculated_turfs.Copy()
|
||||
else
|
||||
turfs = E.gathered_turfs.Copy()
|
||||
|
||||
qdel(E)
|
||||
|
||||
for(var/I in turfs)
|
||||
var/turf/T = I
|
||||
var/dist = cheap_hypotenuse(T.x, T.y, x0, y0) + turfs[T]
|
||||
|
||||
if(dist < dev)
|
||||
T.color = "red"
|
||||
T.maptext = "Dev"
|
||||
else if (dist < heavy)
|
||||
T.color = "yellow"
|
||||
T.maptext = "Heavy"
|
||||
else if (dist < light)
|
||||
T.color = "blue"
|
||||
T.maptext = "Light"
|
||||
CHECK_TICK
|
||||
|
||||
sleep(100)
|
||||
for(var/I in turfs)
|
||||
var/turf/T = I
|
||||
T.color = null
|
||||
T.maptext = null
|
||||
@@ -2,6 +2,7 @@ SUBSYSTEM_DEF(fire_burning)
|
||||
name = "Fire Burning"
|
||||
priority = 40
|
||||
flags = SS_NO_INIT|SS_BACKGROUND
|
||||
runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME
|
||||
|
||||
var/list/currentrun = list()
|
||||
var/list/processing = list()
|
||||
|
||||
@@ -2,7 +2,8 @@ SUBSYSTEM_DEF(garbage)
|
||||
name = "Garbage"
|
||||
priority = 15
|
||||
wait = 5
|
||||
flags = SS_FIRE_IN_LOBBY|SS_POST_FIRE_TIMING|SS_BACKGROUND|SS_NO_INIT
|
||||
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
|
||||
@@ -60,7 +61,7 @@ SUBSYSTEM_DEF(garbage)
|
||||
for(var/path in sleptDestroy)
|
||||
dellog += "Path : [path] \n"
|
||||
dellog += "Sleeps : [sleptDestroy[path]] \n"
|
||||
log_world(dellog.Join())
|
||||
text2file(dellog.Join(), "[GLOB.log_directory]/qdel.log")
|
||||
|
||||
/datum/controller/subsystem/garbage/fire()
|
||||
HandleToBeQueued()
|
||||
@@ -163,8 +164,8 @@ SUBSYSTEM_DEF(garbage)
|
||||
if (time > highest_del_time)
|
||||
highest_del_time = time
|
||||
if (time > 10)
|
||||
log_game("Error: [type]([refID]) took longer then 1 second to delete (took [time/10] seconds to delete)")
|
||||
message_admins("Error: [type]([refID]) took longer then 1 second to delete (took [time/10] seconds to delete).")
|
||||
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)
|
||||
|
||||
@@ -2,6 +2,7 @@ SUBSYSTEM_DEF(inbounds)
|
||||
name = "Inbounds"
|
||||
priority = 40
|
||||
flags = SS_NO_INIT
|
||||
runlevels = RUNLEVEL_GAME
|
||||
|
||||
var/list/processing = list()
|
||||
var/list/currentrun = list()
|
||||
|
||||
@@ -11,6 +11,7 @@ SUBSYSTEM_DEF(job)
|
||||
var/initial_players_to_assign = 0 //used for checking against population caps
|
||||
|
||||
var/list/prioritized_jobs = list()
|
||||
var/list/latejoin_trackers = list() //Don't read this list, use GetLateJoinTurfs() instead
|
||||
|
||||
/datum/controller/subsystem/job/Initialize(timeofday)
|
||||
if(!occupations.len)
|
||||
@@ -308,7 +309,6 @@ SUBSYSTEM_DEF(job)
|
||||
Debug("DO non-human failed, Player: [player], Job:[job.title]")
|
||||
continue
|
||||
|
||||
|
||||
// If the player wants that job on this level, then try give it to him.
|
||||
if(player.client.prefs.GetJobDepartment(job, level) & job.flag)
|
||||
|
||||
@@ -319,6 +319,7 @@ SUBSYSTEM_DEF(job)
|
||||
unassigned -= player
|
||||
break
|
||||
|
||||
|
||||
// Hand out random jobs to the people who didn't get any in the last check
|
||||
// Also makes sure that they got their preference correct
|
||||
for(var/mob/dead/new_player/player in unassigned)
|
||||
@@ -378,23 +379,11 @@ SUBSYSTEM_DEF(job)
|
||||
continue
|
||||
S = sloc
|
||||
break
|
||||
if(S)
|
||||
SendToAtom(H, S, buckle = FALSE)
|
||||
if(!S) //if there isn't a spawnpoint send them to latejoin, if there's no latejoin go yell at your mapper
|
||||
log_world("Couldn't find a round start spawn point for [rank]")
|
||||
S = get_turf(pick(GLOB.latejoin))
|
||||
if(!S) //final attempt, lets find some area in the arrivals shuttle to spawn them in to.
|
||||
log_world("Couldn't find a round start latejoin spawn point.")
|
||||
for(var/turf/T in get_area_turfs(/area/shuttle/arrival))
|
||||
if(!T.density)
|
||||
var/clear = 1
|
||||
for(var/obj/O in T)
|
||||
if(O.density)
|
||||
clear = 0
|
||||
break
|
||||
if(clear)
|
||||
S = T
|
||||
continue
|
||||
if(istype(S, /obj/effect/landmark) && isturf(S.loc))
|
||||
H.loc = S.loc
|
||||
SendToLateJoin(H)
|
||||
|
||||
if(H.mind)
|
||||
H.mind.assigned_role = rank
|
||||
@@ -483,7 +472,7 @@ SUBSYSTEM_DEF(job)
|
||||
else level4++ //not selected
|
||||
|
||||
tmp_str += "HIGH=[level1]|MEDIUM=[level2]|LOW=[level3]|NEVER=[level4]|BANNED=[level5]|YOUNG=[level6]|-"
|
||||
feedback_add_details("job_preferences",tmp_str)
|
||||
SSblackbox.add_details("job_preferences",tmp_str)
|
||||
|
||||
/datum/controller/subsystem/job/proc/PopcapReached()
|
||||
if(config.hard_popcap || config.extreme_popcap)
|
||||
@@ -516,3 +505,45 @@ SUBSYSTEM_DEF(job)
|
||||
newjob.total_positions = J.total_positions
|
||||
newjob.spawn_positions = J.spawn_positions
|
||||
newjob.current_positions = J.current_positions
|
||||
|
||||
/datum/controller/subsystem/job/proc/SendToAtom(mob/M, atom/A, buckle)
|
||||
if(buckle && isliving(M) && istype(A, /obj/structure/chair))
|
||||
var/obj/structure/chair/C = A
|
||||
if(C.buckle_mob(M, FALSE, FALSE))
|
||||
return
|
||||
M.forceMove(get_turf(A))
|
||||
|
||||
/datum/controller/subsystem/job/proc/SendToLateJoin(mob/M, buckle = TRUE)
|
||||
if(latejoin_trackers.len)
|
||||
SendToAtom(M, pick(latejoin_trackers), buckle)
|
||||
else
|
||||
//bad mojo
|
||||
var/area/shuttle/arrival/A = locate() in GLOB.sortedAreas
|
||||
if(A)
|
||||
//first check if we can find a chair
|
||||
var/obj/structure/chair/C = locate() in A
|
||||
if(C)
|
||||
SendToAtom(M, C, buckle)
|
||||
return
|
||||
else //last hurrah
|
||||
var/list/avail = list()
|
||||
for(var/turf/T in A)
|
||||
if(!is_blocked_turf(T, TRUE))
|
||||
avail += T
|
||||
if(avail.len)
|
||||
SendToAtom(M, pick(avail), FALSE)
|
||||
return
|
||||
|
||||
//pick an open spot on arrivals and dump em
|
||||
var/list/arrivals_turfs = shuffle(get_area_turfs(/area/shuttle/arrival))
|
||||
if(arrivals_turfs.len)
|
||||
for(var/turf/T in arrivals_turfs)
|
||||
if(!is_blocked_turf(T, TRUE))
|
||||
SendToAtom(M, T, FALSE)
|
||||
return
|
||||
//last chance, pick ANY spot on arrivals and dump em
|
||||
SendToAtom(M, arrivals_turfs[1], FALSE)
|
||||
else
|
||||
var/msg = "Unable to send mob [M] to late join!"
|
||||
message_admins(msg)
|
||||
CRASH(msg)
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
SUBSYSTEM_DEF(language)
|
||||
name = "Language"
|
||||
init_order = INIT_ORDER_LANGUAGE
|
||||
flags = SS_NO_FIRE
|
||||
|
||||
/datum/controller/subsystem/language/Initialize(timeofday)
|
||||
for(var/L in subtypesof(/datum/language))
|
||||
var/datum/language/language = L
|
||||
if(!initial(language.key))
|
||||
continue
|
||||
|
||||
GLOB.all_languages += language
|
||||
|
||||
var/datum/language/instance = new language
|
||||
|
||||
GLOB.language_datum_instances[language] = instance
|
||||
|
||||
return ..()
|
||||
@@ -15,14 +15,15 @@ SUBSYSTEM_DEF(lighting)
|
||||
|
||||
|
||||
/datum/controller/subsystem/lighting/Initialize(timeofday)
|
||||
if (config.starlight)
|
||||
for(var/I in GLOB.sortedAreas)
|
||||
var/area/A = I
|
||||
if (A.dynamic_lighting == DYNAMIC_LIGHTING_IFSTARLIGHT)
|
||||
A.luminosity = 0
|
||||
if(!initialized)
|
||||
if (config.starlight)
|
||||
for(var/I in GLOB.sortedAreas)
|
||||
var/area/A = I
|
||||
if (A.dynamic_lighting == DYNAMIC_LIGHTING_IFSTARLIGHT)
|
||||
A.luminosity = 0
|
||||
|
||||
create_all_lighting_objects()
|
||||
initialized = TRUE
|
||||
create_all_lighting_objects()
|
||||
initialized = TRUE
|
||||
|
||||
fire(FALSE, TRUE)
|
||||
|
||||
@@ -36,18 +37,10 @@ SUBSYSTEM_DEF(lighting)
|
||||
for (i in 1 to GLOB.lighting_update_lights.len)
|
||||
var/datum/light_source/L = GLOB.lighting_update_lights[i]
|
||||
|
||||
if (L.check() || QDELETED(L) || L.force_update)
|
||||
L.remove_lum()
|
||||
if (!QDELETED(L))
|
||||
L.apply_lum()
|
||||
L.update_corners()
|
||||
|
||||
else if (L.vis_update) //We smartly update only tiles that became (in) visible to use.
|
||||
L.smart_vis_update()
|
||||
L.needs_update = LIGHTING_NO_UPDATE
|
||||
|
||||
L.vis_update = FALSE
|
||||
L.force_update = FALSE
|
||||
L.needs_update = FALSE
|
||||
|
||||
if(init_tick_checks)
|
||||
CHECK_TICK
|
||||
else if (MC_TICK_CHECK)
|
||||
|
||||
@@ -37,11 +37,11 @@ SUBSYSTEM_DEF(machines)
|
||||
|
||||
var/seconds = wait * 0.1
|
||||
while(currentrun.len)
|
||||
var/datum/thing = currentrun[currentrun.len]
|
||||
var/obj/machinery/thing = currentrun[currentrun.len]
|
||||
currentrun.len--
|
||||
if(thing && thing.process(seconds) != PROCESS_KILL)
|
||||
if(thing:use_power)
|
||||
thing:auto_use_power() //add back the power state
|
||||
if(thing.use_power)
|
||||
thing.auto_use_power() //add back the power state
|
||||
else
|
||||
processing -= thing
|
||||
if (thing)
|
||||
|
||||
@@ -43,7 +43,7 @@ SUBSYSTEM_DEF(mapping)
|
||||
loading_ruins = TRUE
|
||||
var/mining_type = config.minetype
|
||||
if (mining_type == "lavaland")
|
||||
seedRuins(list(5), global.config.lavaland_budget, /area/lavaland/surface/outdoors, lava_ruins_templates)
|
||||
seedRuins(list(5), global.config.lavaland_budget, /area/lavaland/surface/outdoors/unexplored, lava_ruins_templates)
|
||||
spawn_rivers()
|
||||
|
||||
// deep space ruins
|
||||
@@ -113,13 +113,15 @@ SUBSYSTEM_DEF(mapping)
|
||||
/datum/controller/subsystem/mapping/proc/loadWorld()
|
||||
//if any of these fail, something has gone horribly, HORRIBLY, wrong
|
||||
var/list/FailedZs = list()
|
||||
|
||||
|
||||
var/start_time = REALTIMEOFDAY
|
||||
|
||||
|
||||
INIT_ANNOUNCE("Loading [config.map_name]...")
|
||||
TryLoadZ(config.GetFullMapPath(), FailedZs, ZLEVEL_STATION)
|
||||
INIT_ANNOUNCE("Loaded station in [(REALTIMEOFDAY - start_time)/10]s!")
|
||||
feedback_add_details("map_name", config.map_name)
|
||||
if(SSdbcore.Connect())
|
||||
var/datum/DBQuery/query_round_map_name = SSdbcore.NewQuery("UPDATE [format_table_name("round")] SET map_name = '[config.map_name]' WHERE id = [GLOB.round_id]")
|
||||
query_round_map_name.Execute()
|
||||
|
||||
if(config.minetype != "lavaland")
|
||||
INIT_ANNOUNCE("WARNING: A map without lavaland set as it's minetype was loaded! This is being ignored! Update the maploader code!")
|
||||
|
||||
@@ -2,6 +2,7 @@ SUBSYSTEM_DEF(mobs)
|
||||
name = "Mobs"
|
||||
priority = 100
|
||||
flags = SS_KEEP_TIMING|SS_NO_INIT
|
||||
runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME
|
||||
|
||||
var/list/currentrun = list()
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ SUBSYSTEM_DEF(npcpool)
|
||||
name = "NPC Pool"
|
||||
flags = SS_POST_FIRE_TIMING|SS_NO_INIT|SS_BACKGROUND
|
||||
priority = 20
|
||||
runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME
|
||||
|
||||
var/list/canBeUsed = list()
|
||||
var/list/needsDelegate = list()
|
||||
|
||||
@@ -150,7 +150,7 @@ SUBSYSTEM_DEF(pai)
|
||||
if(!(ROLE_PAI in G.client.prefs.be_special))
|
||||
continue
|
||||
//G << 'sound/misc/server-ready.ogg' //Alerting them to their consideration
|
||||
to_chat(G, "<span class='ghostalert'>Someone is requesting a pAI personality! Use the pAI button to submit yourself as one.</span>")
|
||||
to_chat(G, "<span class='ghostalert'>[user] is requesting a pAI personality! Use the pAI button to submit yourself as one.</span>")
|
||||
addtimer(CALLBACK(src, .proc/spam_again), spam_delay)
|
||||
var/list/available = list()
|
||||
for(var/datum/paiCandidate/c in SSpai.candidates)
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
SUBSYSTEM_DEF(parallax)
|
||||
name = "Parallax"
|
||||
wait = 2
|
||||
flags = SS_POST_FIRE_TIMING | SS_FIRE_IN_LOBBY | SS_BACKGROUND | SS_NO_INIT
|
||||
flags = SS_POST_FIRE_TIMING | SS_BACKGROUND | SS_NO_INIT
|
||||
priority = 65
|
||||
runlevels = RUNLEVEL_LOBBY | RUNLEVELS_DEFAULT
|
||||
var/list/currentrun
|
||||
|
||||
/datum/controller/subsystem/parallax/fire(resumed = 0)
|
||||
|
||||
@@ -9,12 +9,15 @@ SUBSYSTEM_DEF(persistence)
|
||||
|
||||
var/list/obj/structure/chisel_message/chisel_messages = list()
|
||||
var/list/saved_messages = list()
|
||||
var/savefile/chisel_messages_sav
|
||||
|
||||
var/savefile/trophy_sav
|
||||
var/list/saved_trophies = list()
|
||||
|
||||
/datum/controller/subsystem/persistence/Initialize()
|
||||
LoadSatchels()
|
||||
LoadPoly()
|
||||
LoadChiselMessages()
|
||||
LoadTrophies()
|
||||
..()
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/LoadSatchels()
|
||||
@@ -71,14 +74,14 @@ SUBSYSTEM_DEF(persistence)
|
||||
break //Who's been duping the bird?!
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/LoadChiselMessages()
|
||||
chisel_messages_sav = new /savefile("data/npc_saves/ChiselMessages.sav")
|
||||
var/savefile/chisel_messages_sav = new /savefile("data/npc_saves/ChiselMessages.sav")
|
||||
var/saved_json
|
||||
chisel_messages_sav[SSmapping.config.map_name] >> saved_json
|
||||
|
||||
if(!saved_json)
|
||||
return
|
||||
|
||||
var/saved_messages = json_decode(saved_json)
|
||||
var/list/saved_messages = json_decode(saved_json)
|
||||
|
||||
for(var/item in saved_messages)
|
||||
if(!islist(item))
|
||||
@@ -100,15 +103,57 @@ SUBSYSTEM_DEF(persistence)
|
||||
|
||||
var/obj/structure/chisel_message/M = new(T)
|
||||
|
||||
M.unpack(item)
|
||||
if(!M.loc)
|
||||
M.persists = FALSE
|
||||
qdel(M)
|
||||
if(!QDELETED(M))
|
||||
M.unpack(item)
|
||||
|
||||
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
|
||||
|
||||
if(!saved_json)
|
||||
return
|
||||
|
||||
var/decoded_json = json_decode(saved_json)
|
||||
|
||||
if(!islist(decoded_json))
|
||||
return
|
||||
|
||||
saved_trophies = decoded_json
|
||||
|
||||
SetUpTrophies(saved_trophies.Copy())
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/SetUpTrophies(list/trophy_items)
|
||||
for(var/A in GLOB.trophy_cases)
|
||||
var/obj/structure/displaycase/trophy/T = A
|
||||
T.added_roundstart = TRUE
|
||||
|
||||
var/trophy_data = pick_n_take(trophy_items)
|
||||
|
||||
if(!islist(trophy_data))
|
||||
continue
|
||||
|
||||
var/list/chosen_trophy = trophy_data
|
||||
|
||||
if(!chosen_trophy || isemptylist(chosen_trophy)) //Malformed
|
||||
continue
|
||||
|
||||
var/path = text2path(chosen_trophy["path"]) //If the item no longer exist, this returns null
|
||||
if(!path)
|
||||
continue
|
||||
|
||||
T.showpiece = new /obj/item/showpiece_dummy(T, path)
|
||||
T.trophy_message = chosen_trophy["message"]
|
||||
T.placer_key = chosen_trophy["placer_key"]
|
||||
T.update_icon()
|
||||
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/CollectData()
|
||||
CollectChiselMessages()
|
||||
CollectSecretSatchels()
|
||||
CollectTrophies()
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/CollectSecretSatchels()
|
||||
for(var/A in new_secret_satchels)
|
||||
@@ -129,10 +174,26 @@ SUBSYSTEM_DEF(persistence)
|
||||
secret_satchels[SSmapping.config.map_name] << old_secret_satchels
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/CollectChiselMessages()
|
||||
var/savefile/chisel_messages_sav = new /savefile("data/npc_saves/ChiselMessages.sav")
|
||||
|
||||
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]")
|
||||
|
||||
chisel_messages_sav[SSmapping.config.map_name] << json_encode(saved_messages)
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/SaveChiselMessage(obj/structure/chisel_message/M)
|
||||
saved_messages += list(M.pack()) // dm eats one list.
|
||||
saved_messages += list(M.pack()) // dm eats one list
|
||||
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/CollectTrophies()
|
||||
trophy_sav << json_encode(saved_trophies)
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/SaveTrophy(obj/structure/displaycase/trophy/T)
|
||||
if(!T.added_roundstart && T.showpiece)
|
||||
var/list/data = list()
|
||||
data["path"] = T.showpiece.type
|
||||
data["message"] = T.trophy_message
|
||||
data["placer_key"] = T.placer_key
|
||||
saved_trophies += list(data)
|
||||
|
||||
@@ -3,14 +3,20 @@
|
||||
SUBSYSTEM_DEF(ping)
|
||||
name = "Ping"
|
||||
wait = 6
|
||||
flags = SS_NO_INIT|SS_POST_FIRE_TIMING|SS_FIRE_IN_LOBBY
|
||||
flags = SS_POST_FIRE_TIMING|SS_FIRE_IN_LOBBY
|
||||
priority = 10
|
||||
var/list/currentrun
|
||||
|
||||
/datum/controller/subsystem/ping/Initialize()
|
||||
if (config.hub)
|
||||
world.visibility = 1
|
||||
..()
|
||||
|
||||
/datum/controller/subsystem/ping/fire(resumed = FALSE)
|
||||
if (!resumed)
|
||||
src.currentrun = GLOB.clients.Copy()
|
||||
|
||||
var/round_started = Master.round_started
|
||||
var/list/currentrun = src.currentrun
|
||||
while (length(currentrun))
|
||||
var/client/C = currentrun[currentrun.len]
|
||||
@@ -19,7 +25,15 @@ SUBSYSTEM_DEF(ping)
|
||||
if (MC_TICK_CHECK)
|
||||
return
|
||||
continue
|
||||
|
||||
if(round_started && C.is_afk(INACTIVITY_KICK))
|
||||
if(!istype(C.mob, /mob/dead))
|
||||
log_access("AFK: [key_name(C)]")
|
||||
to_chat(C, "<span class='danger'>You have been inactive for more than 10 minutes and have been disconnected.</span>")
|
||||
qdel(C)
|
||||
|
||||
winset(C, null, "command=.update_ping+[world.time+world.tick_lag*world.tick_usage/100]")
|
||||
|
||||
if (MC_TICK_CHECK) //one day, when ss13 has 1000 people per server, you guys are gonna be glad I added this tick check
|
||||
return
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
PROCESSING_SUBSYSTEM_DEF(fields)
|
||||
name = "Fields"
|
||||
wait = 2
|
||||
priority = 40
|
||||
flags = SS_KEEP_TIMING | SS_NO_INIT
|
||||
runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME
|
||||
@@ -5,7 +5,7 @@ PROCESSING_SUBSYSTEM_DEF(flightpacks)
|
||||
stat_tag = "FM"
|
||||
flags = SS_NO_INIT|SS_TICKER|SS_KEEP_TIMING
|
||||
|
||||
var/flightsuit_processing = FLIGHTSUIT_PROCESSING_FULL
|
||||
var/flightsuit_processing = FLIGHTSUIT_PROCESSING_NONE
|
||||
|
||||
/datum/controller/subsystem/processing/flightpacks/Initialize()
|
||||
sync_flightsuit_processing()
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user