This commit is contained in:
Ghommie
2020-05-24 04:00:51 +02:00
423 changed files with 6450 additions and 3566 deletions
-7
View File
@@ -83,10 +83,3 @@
#define SPAM_TRIGGER_WARNING 5 //Number of identical messages required before the spam-prevention will warn you to stfu
#define SPAM_TRIGGER_AUTOMUTE 10 //Number of identical messages required before the spam-prevention will automute you
///Max length of a keypress command before it's considered to be a forged packet/bogus command
#define MAX_KEYPRESS_COMMANDLENGTH 16
///Max amount of keypress messages per second over two seconds before client is autokicked
#define MAX_KEYPRESS_AUTOKICK 100
///Length of max held keys
#define MAX_HELD_KEYS 15
+18
View File
@@ -0,0 +1,18 @@
// Defines for managed input/keybinding system.
/// Max length of a keypress command before it's considered to be a forged packet/bogus command
#define MAX_KEYPRESS_COMMANDLENGTH 16
/// Maximum keys that can be bound to one button
#define MAX_COMMANDS_PER_KEY 5
/// Maximum keys per keybind
#define MAX_KEYS_PER_KEYBIND 3
/// Max amount of keypress messages per second over two seconds before client is autokicked
#define MAX_KEYPRESS_AUTOKICK 100
/// Max keys that can be held down at once by a client
#define MAX_HELD_KEYS 15
/// Macroset name of hotkeys/keybind only/modern mode
#define SKIN_MACROSET_HOTKEYS "hotkeys"
/// Macroset name of classic hotkey mode
#define SKIN_MACROSET_CLASSIC_HOTKEYS "oldhotkeys"
/// Macroset name of classic input mode
#define SKIN_MACROSET_CLASSIC_INPUT "oldinput"
+5 -2
View File
@@ -149,7 +149,7 @@
// /mob signals
#define COMSIG_MOB_CLICKED_SHIFT_ON "mob_shift_click_on" //from base of /atom/ShiftClick(): (atom/A), for return values, see COMSIG_CLICK_SHIFT
#define COMSIG_MOB_VISIBLE_ATOMS "mob_visible_atoms" //from base of mob/visible_atoms(): (list/visible_atoms)
#define COMSIG_MOB_FOV_VIEW "mob_visible_atoms" //from base of mob/fov_view(): (list/visible_atoms)
#define COMSIG_MOB_EXAMINATE "mob_examinate" //from base of /mob/verb/examinate(): (atom/A), for return values, see COMSIG_CLICK_SHIFT
#define COMPONENT_EXAMINATE_BLIND 3 //outputs the "something is there but you can't see it" message.
#define COMSIG_MOB_DEATH "mob_death" //from base of mob/death(): (gibbed)
@@ -185,7 +185,7 @@
#define SPEECH_LANGUAGE 5
// #define SPEECH_IGNORE_SPAM 6
// #define SPEECH_FORCED 7
#define COMSIG_MOB_IS_VIEWER "mob_is_viewer" //from base of /get_actual_viewers(): (atom/center, depth, viewers_list)
#define COMSIG_MOB_FOV_VIEWER "mob_is_viewer" //from base of /fov_viewers(): (atom/center, depth, viewers_list)
#define COMSIG_MOB_GET_VISIBLE_MESSAGE "mob_get_visible_message" //from base of atom/visible_message(): (atom/A, msg, range, ignored_mobs)
#define COMPONENT_NO_VISIBLE_MESSAGE 1 //exactly what's said on the tin.
#define COMSIG_MOB_ANTAG_ON_GAIN "mob_antag_on_gain" //from base of /datum/antagonist/on_gain(): (antag_datum)
@@ -326,6 +326,9 @@
#define COMSIG_SPECIES_GAIN "species_gain" //from datum/species/on_species_gain(): (datum/species/new_species, datum/species/old_species)
#define COMSIG_SPECIES_LOSS "species_loss" //from datum/species/on_species_loss(): (datum/species/lost_species)
// /datum/mutation signals
#define COMSIG_HUMAN_MUTATION_LOSS "human_mutation_loss" //from datum/mutation/human/on_losing(): (datum/mutation/human/lost_mutation)
/*******Component Specific Signals*******/
//Janitor
#define COMSIG_TURF_IS_WET "check_turf_wet" //(): Returns bitflags of wet values.
+38 -23
View File
@@ -20,27 +20,41 @@ GLOBAL_LIST_INIT(bitflags, list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 204
#define DF_ISPROCESSING (1<<2)
//FLAGS BITMASK
#define HEAR_1 (1<<3) // This flag is what recursive_hear_check() uses to determine wether to add an item to the hearer list or not.
#define CHECK_RICOCHET_1 (1<<4) // Projectiels will check ricochet on things impacted that have this.
#define CONDUCT_1 (1<<5) // conducts electricity (metal etc.)
#define NODECONSTRUCT_1 (1<<7) // For machines and structures that should not break into parts, eg, holodeck stuff
#define OVERLAY_QUEUED_1 (1<<8) // atom queued to SSoverlay
#define ON_BORDER_1 (1<<9) // item has priority to check when entering or leaving
#define PREVENT_CLICK_UNDER_1 (1<<11) //Prevent clicking things below it on the same turf eg. doors/ fulltile windows
///This flag is what recursive_hear_check() uses to determine wether to add an item to the hearer list or not.
#define HEAR_1 (1<<3)
///Projectiels will check ricochet on things impacted that have this.
#define CHECK_RICOCHET_1 (1<<4)
///Conducts electricity (metal etc.).
#define CONDUCT_1 (1<<5)
///For machines and structures that should not break into parts, eg, holodeck stuff.
#define NODECONSTRUCT_1 (1<<7)
///Atom queued to SSoverlay.
#define OVERLAY_QUEUED_1 (1<<8)
///Item has priority to check when entering or leaving.
#define ON_BORDER_1 (1<<9)
///Prevent clicking things below it on the same turf eg. doors/ fulltile windows.
#define PREVENT_CLICK_UNDER_1 (1<<11)
#define HOLOGRAM_1 (1<<12)
#define TESLA_IGNORE_1 (1<<13) // TESLA_IGNORE grants immunity from being targeted by tesla-style electricity
#define INITIALIZED_1 (1<<14) //Whether /atom/Initialize() has already run for the object
#define ADMIN_SPAWNED_1 (1<<15) //was this spawned by an admin? used for stat tracking stuff.
#define PREVENT_CONTENTS_EXPLOSION_1 (1<<16) /// should not get harmed if this gets caught by an explosion?
#define BLOCK_FACE_ATOM_1 (1<<17) /// Early returns mob.face_atom()
///Prevents mobs from getting chainshocked by teslas and the supermatter.
#define SHOCKED_1 (1<<13)
///Whether /atom/Initialize() has already run for the object.
#define INITIALIZED_1 (1<<14)
///was this spawned by an admin? used for stat tracking stuff.
#define ADMIN_SPAWNED_1 (1<<15)
/// should not get harmed if this gets caught by an explosion?
#define PREVENT_CONTENTS_EXPLOSION_1 (1<<16)
/// Early returns mob.face_atom()
#define BLOCK_FACE_ATOM_1 (1<<17)
//turf-only flags
#define NOJAUNT_1 (1<<0)
#define UNUSED_RESERVATION_TURF_1 (1<<1)
#define CAN_BE_DIRTY_1 (1<<2) // If a turf can be made dirty at roundstart. This is also used in areas.
#define NO_LAVA_GEN_1 (1<<6) //Blocks lava rivers being generated on the turf
#define NO_RUINS_1 (1<<10) //Blocks ruins spawning on the turf
///If a turf can be made dirty at roundstart. This is also used in areas.
#define CAN_BE_DIRTY_1 (1<<2)
///Blocks lava rivers being generated on the turf.
#define NO_LAVA_GEN_1 (1<<6)
///Blocks ruins spawning on the turf.
#define NO_RUINS_1 (1<<10)
/*
These defines are used specifically with the atom/pass_flags bitmask
@@ -76,14 +90,15 @@ GLOBAL_LIST_INIT(bitflags, list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 204
#define GOLIATH_WEAKNESS (1<<9) //CIT CHANGE
//tesla_zap
#define TESLA_MACHINE_EXPLOSIVE (1<<0)
#define TESLA_ALLOW_DUPLICATES (1<<1)
#define TESLA_OBJ_DAMAGE (1<<2)
#define TESLA_MOB_DAMAGE (1<<3)
#define TESLA_MOB_STUN (1<<4)
#define ZAP_MACHINE_EXPLOSIVE (1<<0)
#define ZAP_ALLOW_DUPLICATES (1<<1)
#define ZAP_OBJ_DAMAGE (1<<2)
#define ZAP_MOB_DAMAGE (1<<3)
#define ZAP_MOB_STUN (1<<4)
#define TESLA_DEFAULT_FLAGS ALL
#define TESLA_FUSION_FLAGS TESLA_OBJ_DAMAGE | TESLA_MOB_DAMAGE | TESLA_MOB_STUN
#define ZAP_DEFAULT_FLAGS ALL
#define ZAP_FUSION_FLAGS ZAP_OBJ_DAMAGE | ZAP_MOB_DAMAGE | ZAP_MOB_STUN
#define ZAP_SUPERMATTER_FLAGS NONE
//EMP protection
#define EMP_PROTECT_SELF (1<<0)
+9
View File
@@ -24,6 +24,15 @@
#define FOOTPRINT_SNAKE "snake"
#define FOOTPRINT_DRAG "drag"
//footstep mob defines
#define FOOTSTEP_MOB_CLAW 1
#define FOOTSTEP_MOB_BAREFOOT 2
#define FOOTSTEP_MOB_HEAVY 3
#define FOOTSTEP_MOB_SHOE 4
#define FOOTSTEP_MOB_HUMAN 5 //Warning: Only works on /mob/living/carbon/human
#define FOOTSTEP_MOB_SLIME 6
#define FOOTSTEP_MOB_CRAWL 7
/*
id = list(
-44
View File
@@ -148,50 +148,6 @@ GLOBAL_LIST_INIT(turfs_without_ground, typecacheof(list(
#define isclown(A) (istype(A, /mob/living/simple_animal/hostile/retaliate/clown))
GLOBAL_LIST_INIT(shoefootmob, typecacheof(list(
/mob/living/carbon/human/,
/mob/living/simple_animal/cow,
/mob/living/simple_animal/hostile/cat_butcherer,
/mob/living/simple_animal/hostile/faithless,
/mob/living/simple_animal/hostile/nanotrasen,
/mob/living/simple_animal/hostile/pirate,
/mob/living/simple_animal/hostile/russian,
/mob/living/simple_animal/hostile/syndicate,
/mob/living/simple_animal/hostile/wizard,
/mob/living/simple_animal/hostile/zombie,
/mob/living/simple_animal/hostile/retaliate/clown,
/mob/living/simple_animal/hostile/retaliate/spaceman,
/mob/living/simple_animal/hostile/retaliate/nanotrasenpeace,
/mob/living/simple_animal/hostile/retaliate/goat,
/mob/living/carbon/true_devil,
)))
GLOBAL_LIST_INIT(clawfootmob, typecacheof(list(
/mob/living/carbon/alien/humanoid,
/mob/living/simple_animal/hostile/alien,
/mob/living/simple_animal/pet/cat,
/mob/living/simple_animal/pet/dog,
/mob/living/simple_animal/pet/fox,
/mob/living/simple_animal/chicken,
/mob/living/simple_animal/hostile/bear,
/mob/living/simple_animal/hostile/jungle/mega_arachnid,
/mob/living/simple_animal/hostile/asteroid/ice_whelp,
/mob/living/simple_animal/hostile/asteroid/wolf,
/mob/living/simple_animal/hostile/asteroid/polarbear
)))
GLOBAL_LIST_INIT(barefootmob, typecacheof(list(
/mob/living/carbon/monkey,
/mob/living/simple_animal/pet/penguin,
/mob/living/simple_animal/hostile/gorilla,
/mob/living/simple_animal/hostile/jungle/mook
)))
GLOBAL_LIST_INIT(heavyfootmob, typecacheof(list(
/mob/living/simple_animal/hostile/megafauna,
/mob/living/simple_animal/hostile/jungle/leaper
)))
//Misc mobs
#define isobserver(A) (istype(A, /mob/dead/observer))
+3 -1
View File
@@ -42,6 +42,7 @@
#define BLACKNESS_PLANE 0 //To keep from conflicts with SEE_BLACKNESS internals
#define BLACKNESS_PLANE_RENDER_TARGET "BLACKNESS_PLANE"
///Layers most often used by atoms of plane lower than GAME_PLANE
#define SPACE_LAYER 1.8
//#define TURF_LAYER 2 //For easy recordkeeping; this is a byond define
#define MID_TURF_LAYER 2.02
@@ -61,11 +62,12 @@
#define GAS_PIPE_VISIBLE_LAYER 2.47
#define GAS_FILTER_LAYER 2.48
#define GAS_PUMP_LAYER 2.49
#define LOW_OBJ_LAYER 2.5
#define LOW_SIGIL_LAYER 2.52
#define SIGIL_LAYER 2.54
#define HIGH_SIGIL_LAYER 2.56
///Layers most often used by atoms of plane equal or higher than GAME_PLANE
#define BELOW_OPEN_DOOR_LAYER 2.6
#define BLASTDOOR_LAYER 2.65
#define OPEN_DOOR_LAYER 2.7
+1 -1
View File
@@ -463,7 +463,7 @@ GLOBAL_LIST_INIT(pda_reskins, list(PDA_SKIN_CLASSIC = 'icons/obj/pda.dmi', PDA_S
#define PDAIMG(what) {"<span class="pda16x16 [#what]"></span>"}
//Filters
#define AMBIENT_OCCLUSION list("type"="drop_shadow","x"=0,"y"=-2,"size"=4,"color"="#04080FAA")
#define AMBIENT_OCCLUSION(_size, _color) list("type"="drop_shadow","x"=0,"y"=-2,"size"=_size,"color"=_color)
#define EYE_BLUR(size) list("type"="blur", "size"=size)
#define GRAVITY_MOTION_BLUR list("type"="motion_blur","x"=0,"y"=0)
+13
View File
@@ -51,6 +51,19 @@
#define ASSEMBLY_FOURTH_STEP 3
#define ASSEMBLY_FIFTH_STEP 4
//Bot Upgrade defines
#define UPGRADE_CLEANER_ADVANCED_MOP (1<<0)
#define UPGRADE_CLEANER_BROOM (1<<1)
#define UPGRADE_MEDICAL_HYPOSPRAY (1<<0)
#define UPGRADE_MEDICAL_CHEM_BOARD (1<<1)
#define UPGRADE_MEDICAL_CRYO_BOARD (1<<2)
#define UPGRADE_MEDICAL_CHEM_MASTER (1<<3)
#define UPGRADE_MEDICAL_SLEEP_BOARD (1<<4)
#define UPGRADE_MEDICAL_PIERERCING (1<<5)
#define UPGRADE_FLOOR_ARTBOX (1<<0)
#define UPGRADE_FLOOR_SYNDIBOX (1<<1)
//Checks to determine borg availability depending on the server's config. These are defines in the interest of reducing copypasta
#define BORG_SEC_AVAILABLE (!CONFIG_GET(flag/disable_secborg) && GLOB.security_level >= CONFIG_GET(number/minimum_secborg_alert))
-1
View File
@@ -1 +0,0 @@
#define RUSTG_OVERRIDE_BUILTINS
+18 -1
View File
@@ -1,10 +1,27 @@
// rust_g.dm - DM API for rust_g extension library
#define RUST_G "rust_g"
#define RUSTG_JOB_NO_RESULTS_YET "NO RESULTS YET"
#define RUSTG_JOB_NO_SUCH_JOB "NO SUCH JOB"
#define RUSTG_JOB_ERROR "JOB PANICKED"
#define rustg_dmi_strip_metadata(fname) call(RUST_G, "dmi_strip_metadata")(fname)
#define rustg_dmi_create_png(fname,width,height,data) call(RUST_G, "dmi_create_png")(fname,width,height,data)
#define rustg_git_revparse(rev) call(RUST_G, "rg_git_revparse")(rev)
#define rustg_git_commit_date(rev) call(RUST_G, "rg_git_commit_date")(rev)
#define rustg_log_write(fname, text) call(RUST_G, "log_write")(fname, text)
#define rustg_log_write(fname, text, format) call(RUST_G, "log_write")(fname, text, format)
/proc/rustg_log_close_all() return call(RUST_G, "log_close_all")()
// RUST-G defines & procs for HTTP component
#define RUSTG_HTTP_METHOD_GET "get"
#define RUSTG_HTTP_METHOD_POST "post"
#define RUSTG_HTTP_METHOD_PUT "put"
#define RUSTG_HTTP_METHOD_DELETE "delete"
#define RUSTG_HTTP_METHOD_PATCH "patch"
#define RUSTG_HTTP_METHOD_HEAD "head"
#define rustg_http_request_blocking(method, url, body, headers) call(RUST_G, "http_request_blocking")(method, url, body, headers)
#define rustg_http_request_async(method, url, body, headers) call(RUST_G, "http_request_async")(method, url, body, headers)
#define rustg_http_check_request(req_id) call(RUST_G, "http_check_request")(req_id)
+23 -18
View File
@@ -27,25 +27,27 @@
#define DEF_SKILL_GAIN 1
#define SKILL_GAIN_SURGERY_PER_STEP 0.25
#define SKILL_AFFINITY_MOOD_BONUS 1.25
//An extra point for each few seconds of delay when using a tool. Before the multiplier.
#define SKILL_GAIN_DELAY_DIVISOR 3 SECONDS
///Items skill_flags and other defines
#define SKILL_USE_TOOL (1<<0)
#define SKILL_TRAINING_TOOL (1<<1)
#define SKILL_ATTACK_MOB (1<<2)
#define SKILL_TRAIN_ATTACK_MOB (1<<3)
#define SKILL_ATTACK_OBJ (1<<4)
#define SKILL_TRAIN_ATTACK_OBJ (1<<5)
#define SKILL_STAMINA_COST (1<<6) //Influences the stamina cost from weapon usage.
#define SKILL_THROW_STAM_COST (1<<7)
#define SKILL_COMBAT_MODE (1<<8) //The user must have combat mode on.
#define SKILL_USE_MOOD (1<<9) //Is the skill negatively affected by bad mood.
#define SKILL_TRAIN_MOOD (1<<10) //Is this skill training affected by good mood.
///Items skill_traits and other defines
#define SKILL_USE_TOOL "use_tool"
#define SKILL_TRAINING_TOOL "training_tool"
#define SKILL_ATTACK_MOB "attack_mob"
#define SKILL_TRAIN_ATTACK_MOB "train_attack_mob"
#define SKILL_ATTACK_OBJ "attack_obj"
#define SKILL_TRAIN_ATTACK_OBJ "train_attack_obj"
#define SKILL_STAMINA_COST "stamina_cost" //Influences the stamina cost from weapon usage.
#define SKILL_THROW_STAM_COST "throw_stam_cost"
#define SKILL_COMBAT_MODE "combat_mode" //The user must have combat mode on.
#define SKILL_SANITY "sanity" //Is the skill affected by (in)sanity.
#define SKILL_INTELLIGENCE "intelligence" //Is the skill affected by brain damage?
///competency_threshold index defines
#define THRESHOLD_COMPETENT 1
#define THRESHOLD_EXPERT 2
#define THRESHOLD_MASTER 3
///competency_threshold defines
#define THRESHOLD_UNTRAINED "untrained"
#define THRESHOLD_COMPETENT "competent"
#define THRESHOLD_EXPERT "expert"
#define THRESHOLD_MASTER "master"
/// Level/Experience skills defines.
#define STD_XP_LVL_UP 100
@@ -88,11 +90,14 @@
#define MODIFIER_SKILL_BODYBOUND (1<<6)
///Adds the difference of the current value and the value stored at the time the modifier was added to the result.
#define MODIFIER_SKILL_ORIGIN_DIFF (1<<7)
///Will this skill use competency thresholds instead of preset values
#define MODIFIER_USE_THRESHOLDS (1<<8)
#define MODIFIER_TARGET_VALUE "value"
#define MODIFIER_TARGET_LEVEL "level"
#define MODIFIER_TARGET_AFFINITY "affinity"
///Ascending priority defines.
#define MODIFIER_SKILL_PRIORITY_LOW 100
#define MODIFIER_SKILL_PRIORITY_DEF 50
#define MODIFIER_SKILL_PRIORITY_MAX 100 //max priority, meant for job/antag modifiers so they don't null out any debuff
#define MODIFIER_SKILL_PRIORITY_MAX 1 //max priority, meant for job/antag modifiers so they don't null out other (de)buffs
+3 -2
View File
@@ -4,8 +4,9 @@
#define TGS_READ_GLOBAL(Name) GLOB.##Name
#define TGS_WRITE_GLOBAL(Name, Value) GLOB.##Name = ##Value
#define TGS_WORLD_ANNOUNCE(message) to_chat(world, "<span class='boldannounce'>[html_encode(##message)]</span>")
#define TGS_INFO_LOG(message) log_world("TGS: Info: [##message]")
#define TGS_ERROR_LOG(message) log_world("TGS: Error: [##message]")
#define TGS_INFO_LOG(message) log_world("TGS Info: [##message]")
#define TGS_WARNING_LOG(message) log_world("TGS Warn: [##message]")
#define TGS_ERROR_LOG(message) log_world("TGS Error: [##message]")
#define TGS_NOTIFY_ADMINS(event) message_admins(##event)
#define TGS_CLIENT_COUNT GLOB.clients.len
#define TGS_PROTECT_DATUM(Path) GENERAL_PROTECT_DATUM(##Path)
+56 -35
View File
@@ -1,5 +1,7 @@
//tgstation-server DMAPI
#define TGS_DMAPI_VERSION "5.1.1"
//All functions and datums outside this document are subject to change with any version and should not be relied on
//CONFIGURATION
@@ -17,7 +19,6 @@
//Required interfaces (fill in with your codebase equivalent):
//create a global variable named `Name` and set it to `Value`
//These globals must not be modifiable from anywhere outside of the server tools
#define TGS_DEFINE_AND_SET_GLOBAL(Name, Value)
//Read the value in the global variable `Name`
@@ -26,10 +27,10 @@
//Set the value in the global variable `Name` to `Value`
#define TGS_WRITE_GLOBAL(Name, Value)
//Disallow ANYONE from reflecting a given `path`, security measure to prevent in-game priveledge escalation
//Disallow ANYONE from reflecting a given `path`, security measure to prevent in-game use of DD -> TGS capabilities
#define TGS_PROTECT_DATUM(Path)
//display an announcement `message` from the server to all players
//Display an announcement `message` from the server to all players
#define TGS_WORLD_ANNOUNCE(message)
//Notify current in-game administrators of a string `event`
@@ -38,6 +39,9 @@
//Write an info `message` to a server log
#define TGS_INFO_LOG(message)
//Write an warning `message` to a server log
#define TGS_WARNING_LOG(message)
//Write an error `message` to a server log
#define TGS_ERROR_LOG(message)
@@ -48,10 +52,12 @@
//EVENT CODES
#define TGS_EVENT_PORT_SWAP -2 //before a port change is about to happen, extra parameter is new port
#define TGS_EVENT_REBOOT_MODE_CHANGE -1 //before a reboot mode change, extras parameters are the current and new reboot mode enums
#define TGS_EVENT_REBOOT_MODE_CHANGE -1 //Before a reboot mode change, extras parameters are the current and new reboot mode enums
#define TGS_EVENT_PORT_SWAP -2 //Before a port change is about to happen, extra parameters is new port
#define TGS_EVENT_INSTANCE_RENAMED -3 //Before the instance is renamed, extra parameter is the new name
#define TGS_EVENT_WATCHDOG_REATTACH -4 //After the watchdog reattaches to DD, extra parameter is the new /datum/tgs_version of the server
//See the descriptions for these codes here: https://github.com/tgstation/tgstation-server/blob/master/src/Tgstation.Server.Host/Components/EventType.cs
//See the descriptions for the parameters of these codes here: https://github.com/tgstation/tgstation-server/blob/master/src/Tgstation.Server.Host/Components/EventType.cs
#define TGS_EVENT_REPO_RESET_ORIGIN 0
#define TGS_EVENT_REPO_CHECKOUT 1
#define TGS_EVENT_REPO_FETCH 2
@@ -63,9 +69,12 @@
#define TGS_EVENT_COMPILE_START 8
#define TGS_EVENT_COMPILE_CANCELLED 9
#define TGS_EVENT_COMPILE_FAILURE 10
#define TGS_EVENT_COMPILE_COMPLETE 11
#define TGS_EVENT_COMPILE_COMPLETE 11 // Note, this event fires before the new .dmb is loaded into the watchdog. Consider using the TGS_EVENT_DEPLOYMENT_COMPLETE instead
#define TGS_EVENT_INSTANCE_AUTO_UPDATE_START 12
#define TGS_EVENT_REPO_MERGE_CONFLICT 13
#define TGS_EVENT_DEPLOYMENT_COMPLETE 14
#define TGS_EVENT_WATCHDOG_SHUTDOWN 15
#define TGS_EVENT_WATCHDOG_DETACH 16
//OTHER ENUMS
@@ -80,6 +89,7 @@
//REQUIRED HOOKS
//Call this somewhere in /world/New() that is always run
//IMPORTANT: This function may sleep!
//event_handler: optional user defined event handler. The default behaviour is to broadcast the event in english to all connected admin channels
//minimum_required_security_level: The minimum required security level to run the game in which the DMAPI is integrated
/world/proc/TgsNew(datum/tgs_event_handler/event_handler, minimum_required_security_level = TGS_SECURITY_ULTRASAFE)
@@ -109,12 +119,12 @@
//represents a version of tgstation-server
/datum/tgs_version
var/suite //The suite version, can be >=3
var/suite //The suite/major version, can be >=3
//this group of variables can be null to represent a wild card
var/major //The major version
var/minor //The minor version
var/patch //The patch version
var/deprecated_patch //The legacy version
var/raw_parameter //The unparsed parameter
var/deprefixed_parameter //The version only bit of raw_parameter
@@ -123,6 +133,10 @@
/datum/tgs_version/proc/Wildcard()
return
//if the tgs_version equals some other_version
/datum/tgs_version/proc/Equals(datum/tgs_version/other_version)
return
//represents a merge of a GitHub pull request
/datum/tgs_revision_information/test_merge
var/number //pull request number
@@ -179,14 +193,45 @@
return
//Returns TRUE if the world was launched under the server tools and the API matches, FALSE otherwise
//No function below this succeeds if it returns FALSE
//No function below this succeeds if it returns FALSE or if TgsNew() has yet to be called
/world/proc/TgsAvailable()
return
//Forces a hard reboot of BYOND by ending the process
//unlike del(world) clients will try to reconnect
//If the service has not requested a shutdown, the next server will take over
/world/proc/TgsEndProcess()
return
//Send a message to non-admin connected chats
//message: The message to send
//admin_only: If TRUE, message will instead be sent to only admin connected chats
/world/proc/TgsTargetedChatBroadcast(message, admin_only)
return
//Send a private message to a specific user
//message: The message to send
//user: The /datum/tgs_chat_user to send to
/world/proc/TgsChatPrivateMessage(message, datum/tgs_chat_user/user)
return
//The following functions will sleep if a call to TgsNew() is sleeping
//Sends a message to connected game chats
//message: The message to send
//channels: optional channels to limit the broadcast to
/world/proc/TgsChatBroadcast(message, list/channels)
return
//Gets the current /datum/tgs_version of the server tools running the server
/world/proc/TgsVersion()
return
//Gets the current /datum/tgs_version of the DMAPI being used
/world/proc/TgsApiVersion()
return
//Gets the name of the TGS instance running the game
/world/proc/TgsInstanceName()
return
@@ -202,34 +247,10 @@
/world/proc/TgsTestMerges()
return
//Forces a hard reboot of BYOND by ending the process
//unlike del(world) clients will try to reconnect
//If the service has not requested a shutdown, the next server will take over
/world/proc/TgsEndProcess()
return
//Gets a list of connected tgs_chat_channel
/world/proc/TgsChatChannelInfo()
return
//Sends a message to connected game chats
//message: The message to send
//channels: optional channels to limit the broadcast to
/world/proc/TgsChatBroadcast(message, list/channels)
return
//Send a message to non-admin connected chats
//message: The message to send
//admin_only: If TRUE, message will instead be sent to only admin connected chats
/world/proc/TgsTargetedChatBroadcast(message, admin_only)
return
//Send a private message to a specific user
//message: The message to send
//user: The /datum/tgs_chat_user to send to
/world/proc/TgsChatPrivateMessage(message, datum/tgs_chat_user/user)
return
/*
The MIT License
@@ -255,4 +276,4 @@ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
*/
+1
View File
@@ -88,6 +88,7 @@
#define TRAIT_SLEEPIMMUNE "sleep_immunity"
#define TRAIT_PUSHIMMUNE "push_immunity"
#define TRAIT_SHOCKIMMUNE "shock_immunity"
#define TRAIT_TESLA_SHOCKIMMUNE "tesla_shock_immunity"
#define TRAIT_STABLEHEART "stable_heart"
#define TRAIT_STABLELIVER "stable_liver"
#define TRAIT_RESISTHEAT "resist_heat"
+3
View File
@@ -122,3 +122,6 @@
// misc
#define VV_HK_SPACEVINE_PURGE "spacevine_purge"
// paintings
#define VV_HK_REMOVE_PAINTING "remove_painting"
-3
View File
@@ -1,9 +1,6 @@
//THIS FILE CONTAINS CONSTANTS, PROCS, AND OTHER THINGS//
/////////////////////////////////////////////////////////
/mob/proc/setClickCooldown(var/timeout)
next_move = max(world.time + timeout, next_move)
/proc/get_matrix_largest()
var/matrix/mtrx=new()
return mtrx.Scale(2)
+10
View File
@@ -671,3 +671,13 @@
for(var/key in input)
ret += key
return ret
/proc/is_type_in_ref_list(path, list/L)
if(!ispath(path))//not a path
return
for(var/i in L)
var/datum/D = i
if(!istype(D))//not an usable reference
continue
if(istype(D, path))
return TRUE
+7 -2
View File
@@ -4,7 +4,9 @@
#define SEND_SOUND(target, sound) DIRECT_OUTPUT(target, sound)
#define SEND_TEXT(target, text) DIRECT_OUTPUT(target, text)
#define WRITE_FILE(file, text) DIRECT_OUTPUT(file, text)
#define WRITE_LOG(log, text) rustg_log_write(log, text)
//This is an external call, "true" and "false" are how rust parses out booleans
#define WRITE_LOG(log, text) rustg_log_write(log, text, "true")
#define WRITE_LOG_NO_FORMAT(log, text) rustg_log_write(log, text, "false")
//print a warning message to world.log
#define WARNING(MSG) warning("[MSG] in [__FILE__] at line [__LINE__] src: [UNLINT(src)] usr: [usr].")
@@ -152,6 +154,9 @@
/proc/log_subsystem(subsystem, text)
WRITE_LOG(GLOB.subsystem_log, "[subsystem]: [text]")
/proc/log_click(object, location, control, params, client/C, event = "clicked")
WRITE_LOG(GLOB.click_log, "CLICK: [C.ckey] - [event] : [object] | [location] | [control] | [params]")
/* Log to both DD and the logfile. */
/proc/log_world(text)
#ifdef USE_CUSTOM_ERROR_HANDLER
@@ -181,7 +186,7 @@
/proc/start_log(log)
WRITE_LOG(log, "Starting up round ID [GLOB.round_id].\n-------------------------")
/* ui logging */
/* ui logging */
/proc/log_tgui(text)
WRITE_LOG(GLOB.tgui_log, text)
+2 -2
View File
@@ -250,13 +250,13 @@
processing += A.contents
//viewers() but with a signal, for blacklisting.
/proc/get_actual_viewers(depth = world.view, atom/center)
/proc/fov_viewers(depth = world.view, atom/center)
if(!center)
return
. = viewers(depth, center)
for(var/k in .)
var/mob/M = k
SEND_SIGNAL(M, COMSIG_MOB_IS_VIEWER, center, depth, .)
SEND_SIGNAL(M, COMSIG_MOB_FOV_VIEWER, center, depth, .)
/proc/get_mobs_in_radio_ranges(list/obj/item/radio/radios)
. = list()
+2
View File
@@ -75,6 +75,8 @@
var/datum/emote/E = new path()
E.emote_list[E.key] = E
init_keybindings()
//Uplink Items
for(var/path in subtypesof(/datum/uplink_item))
var/datum/uplink_item/I = path
+6
View File
@@ -18,6 +18,12 @@
return text
return default
/proc/sanitize_islist(value, default)
if(islist(value) && length(value))
return value
if(default)
return default
/proc/sanitize_inlist(value, list/List, default)
if(value in List)
return value
+42
View File
@@ -629,3 +629,45 @@
return null
r += ascii2text(c)
return r
/proc/slot_to_string(slot)
switch(slot)
if(SLOT_BACK)
return "Backpack"
if(SLOT_WEAR_MASK)
return "Mask"
if(SLOT_HANDS)
return "Hands"
if(SLOT_BELT)
return "Belt"
if(SLOT_EARS)
return "Ears"
if(SLOT_GLASSES)
return "Glasses"
if(SLOT_GLOVES)
return "Gloves"
if(SLOT_NECK)
return "Neck"
if(SLOT_HEAD)
return "Head"
if(SLOT_SHOES)
return "Shoes"
if(SLOT_WEAR_SUIT)
return "Suit"
if(SLOT_W_UNIFORM)
return "Uniform"
if(SLOT_IN_BACKPACK)
return "In backpack"
/proc/tg_ui_icon_to_cit_ui(ui_style)
switch(ui_style)
if('icons/mob/screen_plasmafire.dmi')
return 'modular_citadel/icons/ui/screen_plasmafire.dmi'
if('icons/mob/screen_slimecore.dmi')
return 'modular_citadel/icons/ui/screen_slimecore.dmi'
if('icons/mob/screen_operative.dmi')
return 'modular_citadel/icons/ui/screen_operative.dmi'
if('icons/mob/screen_clockwork.dmi')
return 'modular_citadel/icons/ui/screen_clockwork.dmi'
else
return 'modular_citadel/icons/ui/screen_midnight.dmi'
+6 -1
View File
@@ -1600,8 +1600,13 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new)
//empty string - use TgsTargetBroadcast with admin_only = FALSE
//other string - use TgsChatBroadcast with the tag that matches config_setting, only works with TGS4, if using TGS3 the above method is used
/proc/send2chat(message, config_setting)
if(config_setting == null || !world.TgsAvailable())
if(config_setting == null)
return
UNTIL(GLOB.tgs_initialized)
if(!world.TgsAvailable())
return
var/datum/tgs_version/version = world.TgsVersion()
if(config_setting == "" || version.suite == 3)
world.TgsTargetedChatBroadcast(message, FALSE)
+9 -7
View File
@@ -132,9 +132,11 @@ GLOBAL_LIST_INIT(bitfields, list(
"NO_RUINS_1" = NO_RUINS_1,
"PREVENT_CLICK_UNDER_1" = PREVENT_CLICK_UNDER_1,
"HOLOGRAM_1" = HOLOGRAM_1,
"TESLA_IGNORE_1" = TESLA_IGNORE_1,
"SHOCKED_1" = SHOCKED_1,
"INITIALIZED_1" = INITIALIZED_1,
"ADMIN_SPAWNED_1" = ADMIN_SPAWNED_1,
"BLOCK_FACE_ATOM_1" = BLOCK_FACE_ATOM_1,
"PREVENT_CONTENTS_EXPLOSION_1" = PREVENT_CONTENTS_EXPLOSION_1
),
"clothing_flags" = list(
"LAVAPROTECT" = LAVAPROTECT,
@@ -148,12 +150,12 @@ GLOBAL_LIST_INIT(bitfields, list(
"IGNORE_HAT_TOSS" = IGNORE_HAT_TOSS,
"SCAN_REAGENTS" = SCAN_REAGENTS
),
"tesla_flags" = list(
"TESLA_MOB_DAMAGE" = TESLA_MOB_DAMAGE,
"TESLA_OBJ_DAMAGE" = TESLA_OBJ_DAMAGE,
"TESLA_MOB_STUN" = TESLA_MOB_STUN,
"TESLA_ALLOW_DUPLICATES" = TESLA_ALLOW_DUPLICATES,
"TESLA_MACHINE_EXPLOSIVE" = TESLA_MACHINE_EXPLOSIVE,
"zap_flags" = list(
"ZAP_MOB_DAMAGE" = ZAP_MOB_DAMAGE,
"ZAP_OBJ_DAMAGE" = ZAP_OBJ_DAMAGE,
"ZAP_MOB_STUN" = ZAP_MOB_STUN,
"ZAP_ALLOW_DUPLICATES" = ZAP_ALLOW_DUPLICATES,
"ZAP_MACHINE_EXPLOSIVE" = ZAP_MACHINE_EXPLOSIVE,
),
"smooth" = list(
"SMOOTH_TRUE" = SMOOTH_TRUE,
+21
View File
@@ -0,0 +1,21 @@
GLOBAL_LIST_EMPTY(classic_keybinding_list_by_key)
GLOBAL_LIST_EMPTY(hotkey_keybinding_list_by_key)
GLOBAL_LIST_EMPTY(keybindings_by_name)
// This is a mapping from JS keys to Byond - ref: https://keycode.info/
GLOBAL_LIST_INIT(_kbMap, list(
"UP" = "North",
"RIGHT" = "East",
"DOWN" = "South",
"LEFT" = "West",
"INSERT" = "Insert",
"HOME" = "Northwest",
"PAGEUP" = "Northeast",
"DEL" = "Delete",
"END" = "Southwest",
"PAGEDOWN" = "Southeast",
"SPACEBAR" = "Space",
"ALT" = "Alt",
"SHIFT" = "Shift",
"CONTROL" = "Ctrl"
))
+31
View File
@@ -0,0 +1,31 @@
/// Creates and sorts all the keybinding datums
/proc/init_keybindings()
for(var/KB in subtypesof(/datum/keybinding))
var/datum/keybinding/keybinding = KB
if(!initial(keybinding.hotkey_keys))
continue
add_keybinding(new keybinding)
// init_emote_keybinds() - Disabled - I don't particularly want this.
/// Adds an instanced keybinding to the global tracker
/proc/add_keybinding(datum/keybinding/instance)
GLOB.keybindings_by_name[instance.name] = instance
// Classic
if(LAZYLEN(instance.classic_keys))
for(var/bound_key in instance.classic_keys)
LAZYADD(GLOB.classic_keybinding_list_by_key[bound_key], list(instance.name))
// Hotkey
if(LAZYLEN(instance.hotkey_keys))
for(var/bound_key in instance.hotkey_keys)
LAZYADD(GLOB.hotkey_keybinding_list_by_key[bound_key], list(instance.name))
/proc/init_emote_keybinds()
for(var/i in subtypesof(/datum/emote))
var/datum/emote/faketype = i
if(!initial(faketype.key))
continue
var/datum/keybinding/emote/emote_kb = new
emote_kb.link_to_emote(faketype)
add_keybinding(emote_kb)
+2
View File
@@ -36,6 +36,8 @@ GLOBAL_VAR(reagent_log)
GLOBAL_PROTECT(reagent_log)
GLOBAL_VAR(world_crafting_log)
GLOBAL_PROTECT(world_crafting_log)
GLOBAL_VAR(click_log)
GLOBAL_PROTECT(click_log)
GLOBAL_LIST_EMPTY(bombers)
GLOBAL_PROTECT(bombers)
+1
View File
@@ -29,6 +29,7 @@ GLOBAL_LIST_INIT(traits_by_type, list(
"TRAIT_SLEEPIMMUNE" = TRAIT_SLEEPIMMUNE,
"TRAIT_PUSHIMMUNE" = TRAIT_PUSHIMMUNE,
"TRAIT_SHOCKIMMUNE" = TRAIT_SHOCKIMMUNE,
"TRAIT_TESLA_SHOCKIMMUNE" = TRAIT_TESLA_SHOCKIMMUNE,
"TRAIT_STABLEHEART" = TRAIT_STABLEHEART,
"TRAIT_STABLELIVER" = TRAIT_STABLELIVER,
"TRAIT_RESISTHEAT" = TRAIT_RESISTHEAT,
+8 -2
View File
@@ -57,7 +57,7 @@
/obj/screen/plane_master/wall/backdrop(mob/mymob)
if(mymob?.client?.prefs.ambientocclusion)
add_filter("ambient_occlusion", 0, AMBIENT_OCCLUSION)
add_filter("ambient_occlusion", 0, AMBIENT_OCCLUSION(4, "#04080FAA"))
else
remove_filter("ambient_occlusion")
@@ -70,6 +70,12 @@
. = ..()
add_filter("vision_cone", 100, list(type="alpha", render_source=FIELD_OF_VISION_RENDER_TARGET, flags=MASK_INVERSE))
/obj/screen/plane_master/above_wall/backdrop(mob/mymob)
if(mymob?.client?.prefs.ambientocclusion)
add_filter("ambient_occlusion", 0, AMBIENT_OCCLUSION(3, "#04080F64"))
else
remove_filter("ambient_occlusion")
///Contains most things in the game world
/obj/screen/plane_master/game_world
name = "game world plane master"
@@ -83,7 +89,7 @@
/obj/screen/plane_master/game_world/backdrop(mob/mymob)
if(mymob?.client?.prefs.ambientocclusion)
add_filter("ambient_occlusion", 0, AMBIENT_OCCLUSION)
add_filter("ambient_occlusion", 0, AMBIENT_OCCLUSION(4, "#04080FAA"))
else
remove_filter("ambient_occlusion")
@@ -65,6 +65,7 @@
return ..()
/obj/screen/storage/volumetric_box/Destroy()
makeItemInactive()
our_item = null
return ..()
@@ -87,10 +88,14 @@
makeItemInactive()
/obj/screen/storage/volumetric_box/proc/makeItemInactive()
if(!our_item)
return
our_item.layer = VOLUMETRIC_STORAGE_ITEM_LAYER
our_item.plane = VOLUMETRIC_STORAGE_ITEM_PLANE
/obj/screen/storage/volumetric_box/proc/makeItemActive()
if(!our_item)
return
our_item.layer = VOLUMETRIC_STORAGE_ACTIVE_ITEM_LAYER //make sure we display infront of the others!
our_item.plane = VOLUMETRIC_STORAGE_ACTIVE_ITEM_PLANE
+10 -10
View File
@@ -112,13 +112,13 @@
/obj/attacked_by(obj/item/I, mob/living/user)
var/totitemdamage = I.force
var/bad_flag = NONE
var/bad_trait
if(!(user.combat_flags & COMBAT_FLAG_COMBAT_ACTIVE) && iscarbon(user))
totitemdamage *= 0.5
bad_flag |= SKILL_COMBAT_MODE //blacklist combat skills.
bad_trait = SKILL_COMBAT_MODE //blacklist combat skills.
if(I.used_skills && user.mind)
if(totitemdamage)
totitemdamage = user.mind.item_action_skills_mod(I, totitemdamage, I.skill_difficulty, SKILL_ATTACK_OBJ, bad_flag)
totitemdamage = user.mind.item_action_skills_mod(I, totitemdamage, I.skill_difficulty, SKILL_ATTACK_OBJ, bad_trait)
for(var/skill in I.used_skills)
if(!(I.used_skills[skill] & SKILL_TRAIN_ATTACK_OBJ))
continue
@@ -154,16 +154,16 @@
/mob/living/proc/pre_attacked_by(obj/item/I, mob/living/user)
. = I.force
var/bad_flag = NONE
var/bad_trait
if(!(user.combat_flags & COMBAT_FLAG_COMBAT_ACTIVE) && iscarbon(user))
. *= 0.5
bad_flag |= SKILL_COMBAT_MODE //blacklist combat skills.
bad_trait = SKILL_COMBAT_MODE //blacklist combat skills.
if(!CHECK_MOBILITY(user, MOBILITY_STAND))
. *= 0.5
if(!user.mind || !I.used_skills)
return
if(.)
. = user.mind.item_action_skills_mod(I, ., I.skill_difficulty, SKILL_ATTACK_MOB, bad_flag)
. = user.mind.item_action_skills_mod(I, ., I.skill_difficulty, SKILL_ATTACK_MOB, bad_trait)
for(var/skill in I.used_skills)
if(!(I.used_skills[skill] & SKILL_TRAIN_ATTACK_MOB))
continue
@@ -207,16 +207,16 @@
return 1
/// How much stamina this takes to swing this is not for realism purposes hecc off.
/obj/item/proc/getweight(mob/living/user, multiplier = 1, flags = SKILL_STAMINA_COST)
/obj/item/proc/getweight(mob/living/user, multiplier = 1, trait = SKILL_STAMINA_COST)
. = (total_mass || w_class * STAM_COST_W_CLASS_MULT) * multiplier
if(!user)
return
var/bad_flag = NONE
var/bad_trait
if(iscarbon(user) && !(user.combat_flags & COMBAT_FLAG_COMBAT_ACTIVE))
. *= STAM_COST_NO_COMBAT_MULT
bad_flag |= SKILL_COMBAT_MODE
bad_trait = SKILL_COMBAT_MODE
if(used_skills && user.mind)
. = user.mind.item_action_skills_mod(src, ., skill_difficulty, flags, bad_flag, FALSE)
. = user.mind.item_action_skills_mod(src, ., skill_difficulty, trait, bad_trait, FALSE)
/// How long this staggers for. 0 and negatives supported.
/obj/item/proc/melee_stagger_duration(force_override)
@@ -508,6 +508,10 @@
//Allows players to set a hexadecimal color of their choice as skin tone, on top of the standard ones.
/datum/config_entry/flag/allow_custom_skintones
///Initial loadout points
/datum/config_entry/number/initial_gear_points
config_entry_value = 10
/**
* Enables the FoV component, which hides objects and mobs behind the parent from their sight, unless they turn around, duh.
* Camera mobs, AIs, ghosts and some other are of course exempt from this. This also doesn't influence simplemob AI, for the best.
+15
View File
@@ -451,3 +451,18 @@ SUBSYSTEM_DEF(garbage)
#endif
#endif
#ifdef TESTING
/proc/writeDatumCount()
var/list/datums = list()
for(var/datum/D in world)
datums[D.type] += 1
for(var/datum/D)
datums[D.type] += 1
datums = sortTim(datums, /proc/cmp_numeric_dsc, associative = TRUE)
if(fexists("data/DATUMCOUNT.txt"))
fdel("data/DATUMCOUNT.txt")
var/outfile = file("data/DATUMCOUNT.txt")
for(var/path in datums)
outfile << "[datums[path]]\t\t\t\t\t[path]"
#endif
+71 -88
View File
@@ -6,13 +6,20 @@ SUBSYSTEM_DEF(input)
priority = FIRE_PRIORITY_INPUT
runlevels = RUNLEVELS_DEFAULT | RUNLEVEL_LOBBY
var/list/macro_sets
var/list/movement_keys
/// Classic mode input focused macro set. Manually set because we can't define ANY or ANY+UP for classic.
var/static/list/macroset_classic_input
/// Classic mode map focused macro set. Manually set because it needs to be clientside and go to macroset_classic_input.
var/static/list/macroset_classic_hotkey
/// New hotkey mode macro set. All input goes into map, game keeps incessently setting your focus to map, we can use ANY all we want here; we don't care about the input bar, the user has to force the input bar every time they want to type.
var/static/list/macroset_hotkey
/// Macro set for hotkeys
var/list/hotkey_mode_macros
/// Macro set for classic.
var/list/input_mode_macros
/datum/controller/subsystem/input/Initialize()
setup_default_macro_sets()
setup_default_movement_keys()
setup_macrosets()
initialized = TRUE
@@ -20,94 +27,69 @@ SUBSYSTEM_DEF(input)
return ..()
// This is for when macro sets are eventualy datumized
/datum/controller/subsystem/input/proc/setup_default_macro_sets()
var/list/static/default_macro_sets
if(default_macro_sets)
macro_sets = default_macro_sets
return
default_macro_sets = list(
"default" = list(
"Tab" = "\".winset \\\"input.focus=true?map.focus=true input.background-color=[COLOR_INPUT_DISABLED]:input.focus=true input.background-color=[COLOR_INPUT_ENABLED]\\\"\"",
"O" = "ooc",
"Ctrl+O" = "looc",
"T" = "say",
"Ctrl+T" = "say_indicator",
"Y" = "whisper",
"M" = "me",
"Ctrl+M" = "me_indicator",
"5" = "subtle",
"Back" = "\".winset \\\"input.text=\\\"\\\"\\\"\"", // This makes it so backspace can remove default inputs
"Any" = "\"KeyDown \[\[*\]\]\"",
"Any+UP" = "\"KeyUp \[\[*\]\]\"",
),
"old_default" = list(
"Tab" = "\".winset \\\"mainwindow.macro=old_hotkeys map.focus=true input.background-color=[COLOR_INPUT_DISABLED]\\\"\"",
"Ctrl+T" = "say",
"Ctrl+O" = "ooc",
),
"old_hotkeys" = list(
"Tab" = "\".winset \\\"mainwindow.macro=old_default input.focus=true input.background-color=[COLOR_INPUT_ENABLED]\\\"\"",
"O" = "ooc",
"L" = "looc",
"T" = "say",
"Ctrl+T" = "say_indicator",
"M" = "me",
"Ctrl+M" = "me_indicator",
"Back" = "\".winset \\\"input.text=\\\"\\\"\\\"\"", // This makes it so backspace can remove default inputs
"Any" = "\"KeyDown \[\[*\]\]\"",
"Any+UP" = "\"KeyUp \[\[*\]\]\"",
),
)
// Because i'm lazy and don't want to type all these out twice
var/list/old_default = default_macro_sets["old_default"]
var/list/static/oldmode_keys = list(
/// Sets up the key list for classic mode for when badmins screw up vv's.
/datum/controller/subsystem/input/proc/setup_macrosets()
// First, let's do the snowflake keyset!
macroset_classic_input = list()
var/list/classic_mode_keys = list(
"North", "East", "South", "West",
"Northeast", "Southeast", "Northwest", "Southwest",
"Insert", "Delete", "Ctrl", "Alt",
"Insert", "Delete", "Ctrl", "Alt", "Shift",
"F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12",
)
for(var/key in classic_mode_keys)
macroset_classic_input[key] = "\"KeyDown [key]\""
macroset_classic_input["[key]+UP"] = "\"KeyUp [key]\""
// LET'S PLAY THE BIND EVERY KEY GAME!
// oh except for Backspace and Enter; if you want to use those you shouldn't have used oldmode!
var/list/classic_ctrl_override_keys = list(
"\[", "\]", "\\\\", ";", "'", ",", ".", "/", "-", "=", "`"
)
// i'm lazy let's play the list iteration game of numbers
for(var/i in 0 to 9)
classic_ctrl_override_keys += "[i]"
// let's play the ascii game of A to Z (UPPERCASE)
for(var/i in 65 to 90)
classic_ctrl_override_keys += ascii2text(i)
// let's play the game of clientside bind overrides!
classic_ctrl_override_keys -= list("T", "O", "M", "L")
macroset_classic_input["Ctrl+T"] = "say"
macroset_classic_input["Ctrl+O"] = "ooc"
macroset_classic_input["Ctrl+L"] = "looc"
// let's play the list iteration game x2
for(var/key in classic_ctrl_override_keys)
// make sure to double double quote to ensure things are treated as a key combo instead of addition/semicolon logic.
macroset_classic_input["\"Ctrl+[key]\""] = "\"KeyDown [istext(classic_ctrl_override_keys[key])? classic_ctrl_override_keys[key] : key]\""
macroset_classic_input["\"Ctrl+[key]+UP\""] = "\"KeyUp [istext(classic_ctrl_override_keys[key])? classic_ctrl_override_keys[key] : key]\""
// Misc
macroset_classic_input["Tab"] = "\".winset \\\"mainwindow.macro=[SKIN_MACROSET_CLASSIC_HOTKEYS] map.focus=true input.background-color=[COLOR_INPUT_DISABLED]\\\"\""
macroset_classic_input["Escape"] = "\".winset \\\"input.text=\\\"\\\"\\\"\""
for(var/i in 1 to oldmode_keys.len)
var/key = oldmode_keys[i]
old_default[key] = "\"KeyDown [key]\""
old_default["[key]+UP"] = "\"KeyUp [key]\""
// FINALLY, WE CAN DO SOMETHING MORE NORMAL FOR THE SNOWFLAKE-BUT-LESS KEYSET.
macroset_classic_hotkey = list(
"Any" = "\"KeyDown \[\[*\]\]\"",
"Any+UP" = "\"KeyUp \[\[*\]\]\"",
"Tab" = "\".winset \\\"mainwindow.macro=[SKIN_MACROSET_CLASSIC_INPUT] input.focus=true input.background-color=[COLOR_INPUT_ENABLED]\\\"\"",
"Escape" = "\".winset \\\"input.text=\\\"\\\"\\\"\"",
"Back" = "\".winset \\\"input.text=\\\"\\\"\\\"\"",
"O" = "ooc",
"T" = "say",
"L" = "looc",
"M" = "me"
)
var/list/static/oldmode_ctrl_override_keys = list(
"W" = "W", "A" = "A", "S" = "S", "D" = "D", // movement
"1" = "1", "2" = "2", "3" = "3", "4" = "4", // intent
"B" = "B", // resist
"E" = "E", // quick equip
"F" = "F", // intent left
"G" = "G", // intent right
"H" = "H", // stop pulling
"Q" = "Q", // drop
"R" = "R", // throw
"X" = "X", // switch hands
"Y" = "Y", // activate item
"Z" = "Z", // activate item
)
for(var/i in 1 to oldmode_ctrl_override_keys.len)
var/key = oldmode_ctrl_override_keys[i]
var/override = oldmode_ctrl_override_keys[key]
old_default["Ctrl+[key]"] = "\"KeyDown [override]\""
old_default["Ctrl+[key]+UP"] = "\"KeyUp [override]\""
macro_sets = default_macro_sets
// For initially setting up or resetting to default the movement keys
/datum/controller/subsystem/input/proc/setup_default_movement_keys()
var/static/list/default_movement_keys = list(
"W" = NORTH, "A" = WEST, "S" = SOUTH, "D" = EAST, // WASD
"North" = NORTH, "West" = WEST, "South" = SOUTH, "East" = EAST, // Arrow keys & Numpad
)
movement_keys = default_movement_keys.Copy()
// And finally, the modern set.
macroset_hotkey = list(
"Any" = "\"KeyDown \[\[*\]\]\"",
"Any+UP" = "\"KeyUp \[\[*\]\]\"",
"Tab" = "\".winset \\\"input.focus=true?map.focus=true input.background-color=[COLOR_INPUT_DISABLED]:input.focus=true input.background-color=[COLOR_INPUT_ENABLED]\\\"\"",
"Escape" = "\".winset \\\"input.text=\\\"\\\"\\\"\"",
"Back" = "\".winset \\\"input.text=\\\"\\\"\\\"\"",
"O" = "ooc",
"T" = "say",
"L" = "looc",
"M" = "me"
)
// Badmins just wanna have fun ♪
/datum/controller/subsystem/input/proc/refresh_client_macro_sets()
@@ -115,9 +97,10 @@ SUBSYSTEM_DEF(input)
for(var/i in 1 to clients.len)
var/client/user = clients[i]
user.set_macros()
user.update_movement_keys()
/datum/controller/subsystem/input/fire()
var/list/clients = GLOB.clients // Let's sing the list cache song
for(var/i in 1 to length(clients))
for(var/i in 1 to clients.len)
var/client/C = clients[i]
C.keyLoop()
+19
View File
@@ -24,6 +24,8 @@ SUBSYSTEM_DEF(persistence)
var/list/saved_votes = list()
var/list/obj/structure/sign/picture_frame/photo_frames
var/list/obj/item/storage/photo_album/photo_albums
var/list/obj/structure/sign/painting/painting_frames = list()
var/list/paintings = list()
/datum/controller/subsystem/persistence/Initialize()
LoadSatchels()
@@ -265,6 +267,7 @@ SUBSYSTEM_DEF(persistence)
CollectAntagReputation()
SaveRandomizedRecipes()
SavePanicBunker()
SavePaintings()
/datum/controller/subsystem/persistence/proc/LoadPanicBunker()
var/bunker_path = file("data/bunker_passthrough.json")
@@ -528,3 +531,19 @@ SUBSYSTEM_DEF(persistence)
file_data["data"] = saved_votes[ckey]
fdel(json_file)
WRITE_FILE(json_file, json_encode(file_data))
/datum/controller/subsystem/persistence/proc/LoadPaintings()
var/json_file = file("data/paintings.json")
if(fexists(json_file))
paintings = json_decode(file2text(json_file))
for(var/obj/structure/sign/painting/P in painting_frames)
P.load_persistent()
/datum/controller/subsystem/persistence/proc/SavePaintings()
for(var/obj/structure/sign/painting/P in painting_frames)
P.save_persistent()
var/json_file = file("data/paintings.json")
fdel(json_file)
WRITE_FILE(json_file, json_encode(paintings))
+1 -1
View File
@@ -8,11 +8,11 @@
icon_icon = 'icons/mob/actions/actions_spells.dmi'
/datum/action/item_action/ninjaboost
check_flags = NONE
name = "Adrenaline Boost"
desc = "Inject a secret chemical that will counteract all movement-impairing effect."
button_icon_state = "repulse"
icon_icon = 'icons/mob/actions/actions_spells.dmi'
required_mobility_flags = NONE
/datum/action/item_action/ninjapulse
name = "EM Burst (25E)"
+1 -1
View File
@@ -44,7 +44,7 @@
return
if(world.time > next_check && world.time > next_scare)
next_check = world.time + 50
var/list/seen_atoms = owner.visible_atoms(7)
var/list/seen_atoms = owner.fov_view(7)
if(LAZYLEN(trigger_objs))
for(var/obj/O in seen_atoms)
+56
View File
@@ -0,0 +1,56 @@
#define BAD_ART 12.5
#define GOOD_ART 25
#define GREAT_ART 50
/datum/component/art
var/impressiveness = 0
/datum/component/art/Initialize(impress)
impressiveness = impress
if(isobj(parent))
RegisterSignal(parent, COMSIG_PARENT_EXAMINE, .proc/on_obj_examine)
else
RegisterSignal(parent, COMSIG_PARENT_EXAMINE, .proc/on_other_examine)
if(isstructure(parent))
RegisterSignal(parent, COMSIG_ATOM_ATTACK_HAND, .proc/on_attack_hand)
if(isitem(parent))
RegisterSignal(parent, COMSIG_ITEM_ATTACK_SELF, .proc/apply_moodlet)
/datum/component/art/proc/apply_moodlet(mob/M, impress)
M.visible_message("<span class='notice'>[M] stops and looks intently at [parent].</span>", \
"<span class='notice'>You stop to take in [parent].</span>")
switch(impress)
if (0 to BAD_ART)
SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "artbad", /datum/mood_event/artbad)
if (BAD_ART to GOOD_ART)
SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "artok", /datum/mood_event/artok)
if (GOOD_ART to GREAT_ART)
SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "artgood", /datum/mood_event/artgood)
if(GREAT_ART to INFINITY)
SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "artgreat", /datum/mood_event/artgreat)
/datum/component/art/proc/on_other_examine(datum/source, mob/M)
apply_moodlet(M, impressiveness)
/datum/component/art/proc/on_obj_examine(datum/source, mob/M)
var/obj/O = parent
apply_moodlet(M, impressiveness *(O.obj_integrity/O.max_integrity))
/datum/component/art/proc/on_attack_hand(datum/source, mob/M)
to_chat(M, "<span class='notice'>You start examining [parent]...</span>")
if(!do_after(M, 20, target = parent))
return
on_obj_examine(source, M)
/datum/component/art/rev
/datum/component/art/rev/apply_moodlet(mob/M, impress)
M.visible_message("<span class='notice'>[M] stops to inspect [parent].</span>", \
"<span class='notice'>You take in [parent], inspecting the fine craftsmanship of the proletariat.</span>")
if(M.mind && M.mind.has_antag_datum(/datum/antagonist/rev))
SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "artgreat", /datum/mood_event/artgreat)
else
SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "artbad", /datum/mood_event/artbad)
@@ -74,7 +74,7 @@
//////////////////////Lens//////////////////////////
//Six Steps //
//Sells for 1800 cr, takes 15 glass shets //
//Sells for 1600 cr, takes 15 glass shets //
//Usefull for selling and later crafting //
////////////////////////////////////////////////////
@@ -146,14 +146,14 @@
/obj/item/glasswork/glass_base/glass_lens_part5
name = "Unpolished glass lens"
desc = "A small unpolished glass lens. Could be polished with some silk."
desc = "A small unpolished glass lens. Could be polished with some cloth."
icon = 'icons/obj/glass_ware.dmi'
icon_state = "glass_optics"
next_step = /obj/item/glasswork/glass_base/glass_lens_part6
/obj/item/glasswork/glass_base/glass_lens_part5/attackby(obj/item/I, mob/user, params)
..()
if(istype(I, /obj/item/stack/sheet/silk))
if(istype(I, /obj/item/stack/sheet/cloth))
if(do_after(user,10, target = src))
new next_step(user.loc, 1)
qdel(src)
@@ -324,7 +324,7 @@
//////////////////////Tea Plates////////////////////
//Three Steps //
//Sells for 1200 cr, takes 5 glass shets //
//Sells for 1000 cr, takes 5 glass shets //
//Usefull for selling and chemical things //
////////////////////////////////////////////////////
@@ -370,20 +370,20 @@
/obj/item/glasswork/glass_base/tea_plate3
name = "Disk of glass"
desc = "A disk of glass that can be cant be used for much. Needs to be polished with some silk."
desc = "A disk of glass that can be cant be used for much. Needs to be polished with some cloth."
icon_state = "glass_base_half"
next_step = /obj/item/tea_plate
/obj/item/glasswork/glass_base/tea_plate3/attackby(obj/item/I, mob/user, params)
..()
if(istype(I, /obj/item/stack/sheet/silk))
if(istype(I, /obj/item/stack/sheet/cloth))
if(do_after(user,10, target = src))
new next_step(user.loc, 1)
qdel(src)
//////////////////////Tea Cup///////////////////////
//Four Steps //
//Sells for 1800 cr, takes 6 glass shets //
//Sells for 1600 cr, takes 6 glass shets //
//Usefull for selling and chemical things //
////////////////////////////////////////////////////
@@ -429,13 +429,13 @@
/obj/item/glasswork/glass_base/tea_cup3
name = "Disk of glass"
desc = "A bowl of glass that can be cant be used for much. Needs to be polished with some silk."
desc = "A bowl of glass that can be cant be used for much. Needs to be polished with some cloth."
icon_state = "glass_base_half"
next_step = /obj/item/glasswork/glass_base/tea_cup4
/obj/item/glasswork/glass_base/cup3/attackby(obj/item/I, mob/user, params)
..()
if(istype(I, /obj/item/stack/sheet/silk))
if(istype(I, /obj/item/stack/sheet/cloth))
if(do_after(user,10, target = src))
new next_step(user.loc, 1)
qdel(src)
@@ -1,21 +1,20 @@
//Gun crafting parts til they can be moved elsewhere
// PARTS //
/obj/item/weaponcrafting
icon = 'icons/obj/improvised.dmi'
/obj/item/weaponcrafting/receiver
name = "modular receiver"
desc = "A prototype modular receiver and trigger assembly for a firearm."
icon = 'icons/obj/improvised.dmi'
icon_state = "receiver"
/obj/item/weaponcrafting/stock
name = "rifle stock"
desc = "A classic rifle stock that doubles as a grip, roughly carved out of wood."
icon = 'icons/obj/improvised.dmi'
icon_state = "riflestock"
/obj/item/weaponcrafting/silkstring
name = "silkstring"
desc = "A long piece of silk with some resemblance to cable coil."
icon = 'icons/obj/improvised.dmi'
icon_state = "silkstring"
/obj/item/weaponcrafting/durathread_string
name = "durathread string"
desc = "A long piece of durathread with some resemblance to cable coil."
icon_state = "durastring"
@@ -39,14 +39,14 @@
time = 10
reqs = list(/obj/item/paper = 20)
category = CAT_CLOTHING
/datum/crafting_recipe/armwraps
name = "Armwraps"
result = /obj/item/clothing/gloves/fingerless/pugilist
time = 60
tools = list(TOOL_WIRECUTTER)
reqs = list(/obj/item/stack/sheet/cloth = 4,
/obj/item/stack/sheet/silk = 2,
/obj/item/stack/sheet/durathread = 2,
/obj/item/stack/sheet/leather = 2)
category = CAT_CLOTHING
@@ -192,7 +192,7 @@
result = /obj/item/gun/ballistic/bow/pipe
reqs = list(/obj/item/pipe = 5,
/obj/item/stack/sheet/plastic = 15,
/obj/item/weaponcrafting/silkstring = 5)
/obj/item/weaponcrafting/durathread_string = 5)
time = 450
category = CAT_WEAPONRY
subcategory = CAT_WEAPON
@@ -281,7 +281,7 @@
result = /obj/item/ammo_casing/caseless/arrow/wood
time = 30
reqs = list(/obj/item/stack/sheet/mineral/wood = 1,
/obj/item/stack/sheet/silk = 1,
/obj/item/stack/sheet/durathread = 1,
/obj/item/stack/rods = 1) // 1 metal sheet = 2 rods = 2 arrows
category = CAT_WEAPONRY
subcategory = CAT_AMMO
+5 -5
View File
@@ -86,10 +86,10 @@
RegisterSignal(M, COMSIG_MOB_CLIENT_LOGOUT, .proc/on_mob_logout)
RegisterSignal(M, COMSIG_MOB_GET_VISIBLE_MESSAGE, .proc/on_visible_message)
RegisterSignal(M, COMSIG_MOB_EXAMINATE, .proc/on_examinate)
RegisterSignal(M, COMSIG_MOB_VISIBLE_ATOMS, .proc/on_visible_atoms)
RegisterSignal(M, COMSIG_MOB_FOV_VIEW, .proc/on_fov_view)
RegisterSignal(M, COMSIG_MOB_CLIENT_CHANGE_VIEW, .proc/on_change_view)
RegisterSignal(M, COMSIG_MOB_RESET_PERSPECTIVE, .proc/on_reset_perspective)
RegisterSignal(M, COMSIG_MOB_IS_VIEWER, .proc/is_viewer)
RegisterSignal(M, COMSIG_MOB_FOV_VIEWER, .proc/is_viewer)
/datum/component/field_of_vision/UnregisterFromParent()
. = ..()
@@ -109,8 +109,8 @@
UNREGISTER_NESTED_LOCS(nested_locs, COMSIG_MOVABLE_MOVED, 1)
UnregisterSignal(M, list(COMSIG_MOB_CLIENT_LOGIN, COMSIG_MOB_CLIENT_LOGOUT,
COMSIG_MOB_GET_VISIBLE_MESSAGE, COMSIG_MOB_EXAMINATE,
COMSIG_MOB_VISIBLE_ATOMS, COMSIG_MOB_RESET_PERSPECTIVE,
COMSIG_MOB_CLIENT_CHANGE_VIEW, COMSIG_MOB_IS_VIEWER))
COMSIG_MOB_FOV_VIEW, COMSIG_MOB_RESET_PERSPECTIVE,
COMSIG_MOB_CLIENT_CHANGE_VIEW, COMSIG_MOB_FOV_VIEWER))
/**
* Generates the holder and images (if not generated yet) and adds them to client.images.
@@ -296,7 +296,7 @@
if(fov.alpha)
FOV_ANGLE_CHECK(source, target, return, return COMPONENT_NO_VISIBLE_MESSAGE)
/datum/component/field_of_vision/proc/on_visible_atoms(mob/source, list/atoms)
/datum/component/field_of_vision/proc/on_fov_view(mob/source, list/atoms)
if(!fov.alpha)
return
for(var/k in atoms)
+97 -67
View File
@@ -1,26 +1,52 @@
///Footstep component. Plays footsteps at parents location when it is appropriate.
/datum/component/footstep
///How many steps the parent has taken since the last time a footstep was played
var/steps = 0
///volume determines the extra volume of the footstep. This is multiplied by the base volume, should there be one.
var/volume
///e_range stands for extra range - aka how far the sound can be heard. This is added to the base value and ignored if there isn't a base value.
var/e_range
///footstep_type is a define which determines what kind of sounds should get chosen.
var/footstep_type
///This can be a list OR a soundfile OR null. Determines whatever sound gets played.
var/footstep_sounds
/datum/component/footstep/Initialize(volume_ = 0.5, e_range_ = -1)
/datum/component/footstep/Initialize(footstep_type_ = FOOTSTEP_MOB_BAREFOOT, volume_ = 0.5, e_range_ = -1)
if(!isliving(parent))
return COMPONENT_INCOMPATIBLE
volume = volume_
e_range = e_range_
RegisterSignal(parent, list(COMSIG_MOVABLE_MOVED), .proc/play_footstep)
footstep_type = footstep_type_
switch(footstep_type)
if(FOOTSTEP_MOB_HUMAN)
if(!ishuman(parent))
return COMPONENT_INCOMPATIBLE
RegisterSignal(parent, COMSIG_MOVABLE_MOVED, .proc/play_humanstep)
return
if(FOOTSTEP_MOB_CLAW)
footstep_sounds = GLOB.clawfootstep
if(FOOTSTEP_MOB_BAREFOOT)
footstep_sounds = GLOB.barefootstep
if(FOOTSTEP_MOB_HEAVY)
footstep_sounds = GLOB.heavyfootstep
if(FOOTSTEP_MOB_SHOE)
footstep_sounds = GLOB.footstep
if(FOOTSTEP_MOB_SLIME)
footstep_sounds = 'sound/effects/footstep/slime1.ogg'
if(FOOTSTEP_MOB_CRAWL)
footstep_sounds = 'sound/effects/footstep/crawl1.ogg'
RegisterSignal(parent, COMSIG_MOVABLE_MOVED, .proc/play_simplestep) //Note that this doesn't get called for humans.
/datum/component/footstep/proc/play_footstep()
///Prepares a footstep. Determines if it should get played. Returns the turf it should get played on. Note that it is always a /turf/open
/datum/component/footstep/proc/prepare_step()
var/turf/open/T = get_turf(parent)
if(!istype(T))
return
var/mob/living/LM = parent
var/v = volume
var/e = e_range
if(!T.footstep || LM.buckled || !CHECK_MOBILITY(LM, MOBILITY_STAND) || LM.buckled || LM.throwing || (LM.movement_type & (VENTCRAWLING | FLYING)))
if (LM.lying && !LM.buckled && !(!T.footstep || LM.movement_type & (VENTCRAWLING | FLYING))) //play crawling sound if we're lying
playsound(T, 'sound/effects/footstep/crawl1.ogg', 15 * v)
playsound(T, 'sound/effects/footstep/crawl1.ogg', 15 * volume)
return
if(HAS_TRAIT(LM, TRAIT_SILENT_STEP))
@@ -30,79 +56,83 @@
var/mob/living/carbon/C = LM
if(!C.get_bodypart(BODY_ZONE_L_LEG) && !C.get_bodypart(BODY_ZONE_R_LEG))
return
if(ishuman(C) && C.m_intent == MOVE_INTENT_WALK)
v /= 2
e -= 5
if(C.m_intent == MOVE_INTENT_WALK)
return
steps++
if(steps >= 3)
if(steps >= 6)
steps = 0
else
if(steps % 2)
return
if(prob(80) && !LM.has_gravity(T)) // don't need to step as often when you hop around
if(steps != 0 && !LM.has_gravity(T)) // don't need to step as often when you hop around
return
return T
//begin playsound shenanigans//
//for barefooted non-clawed mobs like monkeys
if(isbarefoot(LM))
playsound(T, pick(GLOB.barefootstep[T.barefootstep][1]),
GLOB.barefootstep[T.barefootstep][2] * v,
TRUE,
GLOB.barefootstep[T.barefootstep][3] + e)
/datum/component/footstep/proc/play_simplestep()
var/turf/open/T = prepare_step()
if(!T)
return
//for xenomorphs, dogs, and other clawed mobs
if(isclawfoot(LM))
if(isalienadult(LM)) //xenos are stealthy and get quieter footsteps
v /= 3
e -= 5
playsound(T, pick(GLOB.clawfootstep[T.clawfootstep][1]),
GLOB.clawfootstep[T.clawfootstep][2] * v,
TRUE,
GLOB.clawfootstep[T.clawfootstep][3] + e)
if(isfile(footstep_sounds) || istext(footstep_sounds))
playsound(T, footstep_sounds, volume)
return
//for megafauna and other large and imtimidating mobs such as the bloodminer
if(isheavyfoot(LM))
playsound(T, pick(GLOB.heavyfootstep[T.heavyfootstep][1]),
GLOB.heavyfootstep[T.heavyfootstep][2] * v,
TRUE,
GLOB.heavyfootstep[T.heavyfootstep][3] + e)
var/turf_footstep
switch(footstep_type)
if(FOOTSTEP_MOB_CLAW)
turf_footstep = T.clawfootstep
if(FOOTSTEP_MOB_BAREFOOT)
turf_footstep = T.barefootstep
if(FOOTSTEP_MOB_HEAVY)
turf_footstep = T.heavyfootstep
if(FOOTSTEP_MOB_SHOE)
turf_footstep = T.footstep
if(!turf_footstep)
return
playsound(T, pick(footstep_sounds[turf_footstep][1]), footstep_sounds[turf_footstep][2] * volume, TRUE, footstep_sounds[turf_footstep][3] + e_range)
//for slimes
if(isslime(LM))
playsound(T, 'sound/effects/footstep/slime1.ogg', 15 * v)
/datum/component/footstep/proc/play_humanstep()
var/turf/open/T = prepare_step()
if(!T)
return
//for (simple) humanoid mobs (clowns, russians, pirates, etc.)
if(isshoefoot(LM))
if(!ishuman(LM))
playsound(T, pick(GLOB.footstep[T.footstep][1]),
GLOB.footstep[T.footstep][2] * v,
TRUE,
GLOB.footstep[T.footstep][3] + e)
return
if(ishuman(LM)) //for proper humans, they're special
var/mob/living/carbon/human/H = LM
var/feetCover = (H.wear_suit && (H.wear_suit.body_parts_covered & FEET)) || (H.w_uniform && (H.w_uniform.body_parts_covered & FEET) || (H.shoes && (H.shoes.body_parts_covered & FEET)))
if (H.dna.features["taur"] == "Naga" || H.dna.features["taur"] == "Tentacle") //are we a naga or tentacle taur creature
playsound(T, 'sound/effects/footstep/crawl1.ogg', 15 * v)
var/mob/living/carbon/human/H = parent
var/list/L = GLOB.barefootstep
var/turf_footstep = T.barefootstep
var/special = FALSE
if(H.physiology.footstep_type)
switch(H.physiology.footstep_type)
if(FOOTSTEP_MOB_CLAW)
turf_footstep = T.clawfootstep
L = GLOB.clawfootstep
if(FOOTSTEP_MOB_BAREFOOT)
turf_footstep = T.barefootstep
L = GLOB.barefootstep
if(FOOTSTEP_MOB_HEAVY)
turf_footstep = T.heavyfootstep
L = GLOB.heavyfootstep
if(FOOTSTEP_MOB_SHOE)
turf_footstep = T.footstep
L = GLOB.footstep
if(FOOTSTEP_MOB_SLIME)
playsound(T, 'sound/effects/footstep/slime1.ogg', 50 * volume)
return
if(FOOTSTEP_MOB_CRAWL)
playsound(T, 'sound/effects/footstep/crawl1.ogg', 50 * volume)
return
special = TRUE
else
var/feetCover = (H.wear_suit && (H.wear_suit.body_parts_covered & FEET)) || (H.w_uniform && (H.w_uniform.body_parts_covered & FEET) || (H.shoes && (H.shoes.body_parts_covered & FEET)))
if(feetCover) //are we wearing shoes
playsound(T, pick(GLOB.footstep[T.footstep][1]),
GLOB.footstep[T.footstep][2] * volume,
TRUE,
GLOB.footstep[T.footstep][3] + e_range)
return
if(feetCover) //are we wearing shoes
playsound(T, pick(GLOB.footstep[T.footstep][1]),
GLOB.footstep[T.footstep][2] * v,
TRUE,
GLOB.footstep[T.footstep][3] + e)
if(!feetCover) //are we NOT wearing shoes
playsound(T, pick(GLOB.barefootstep[T.barefootstep][1]),
GLOB.barefootstep[T.barefootstep][2] * v,
TRUE,
GLOB.barefootstep[T.barefootstep][3] + e)
if(!special && H.dna.species.special_step_sounds)
playsound(T, pick(H.dna.species.special_step_sounds), 50, TRUE)
else
playsound(T, pick(L[turf_footstep][1]),
L[turf_footstep][2] * volume,
TRUE,
L[turf_footstep][3] + e_range)
+1 -1
View File
@@ -73,7 +73,7 @@
if(!material_amount)
to_chat(user, "<span class='warning'>[I] does not contain sufficient materials to be accepted by [parent].</span>")
return
if(!has_space(material_amount))
if((!precise_insertion || !GLOB.typecache_stack[I]) && !has_space(material_amount))
to_chat(user, "<span class='warning'>[parent] has not enough space. Please remove materials from [parent] in order to insert more.</span>")
return
user_insert(I, user)
+28 -11
View File
@@ -23,18 +23,12 @@
if(can_user_rotate)
src.can_user_rotate = can_user_rotate
else
src.can_user_rotate = CALLBACK(src,.proc/default_can_user_rotate)
if(can_be_rotated)
src.can_be_rotated = can_be_rotated
else
src.can_be_rotated = CALLBACK(src,.proc/default_can_be_rotated)
if(after_rotation)
src.after_rotation = after_rotation
else
src.after_rotation = CALLBACK(src,.proc/default_after_rotation)
//Try Clockwise,counter,flip in order
if(src.rotation_flags & ROTATION_FLIP)
@@ -103,14 +97,34 @@
examine_list += "<span class='notice'>Alt-click to rotate it clockwise.</span>"
/datum/component/simple_rotation/proc/HandRot(datum/source, mob/user, rotation = default_rotation_direction)
if(!can_be_rotated.Invoke(user, rotation) || !can_user_rotate.Invoke(user, rotation))
return
if(can_be_rotated)
if(!can_be_rotated.Invoke(user, default_rotation_direction))
return
else
if(!default_can_be_rotated(user, default_rotation_direction))
return
if(can_user_rotate)
if(!can_user_rotate.Invoke(user, default_rotation_direction))
return
else
if(!default_can_user_rotate(user, default_rotation_direction))
return
BaseRot(user, rotation)
return TRUE
/datum/component/simple_rotation/proc/WrenchRot(datum/source, obj/item/I, mob/living/user)
if(!can_be_rotated.Invoke(user,default_rotation_direction) || !can_user_rotate.Invoke(user,default_rotation_direction))
return
if(can_be_rotated)
if(!can_be_rotated.Invoke(user, default_rotation_direction))
return
else
if(!default_can_be_rotated(user, default_rotation_direction))
return
if(can_user_rotate)
if(!can_user_rotate.Invoke(user, default_rotation_direction))
return
else
if(!default_can_user_rotate(user, default_rotation_direction))
return
if(istype(I,/obj/item/wrench))
BaseRot(user,default_rotation_direction)
return COMPONENT_NO_AFTERATTACK
@@ -126,7 +140,10 @@
if(ROTATION_FLIP)
rot_degree = 180
AM.setDir(turn(AM.dir,rot_degree))
after_rotation.Invoke(user,rotation_type)
if(after_rotation)
after_rotation.Invoke(user, rotation_type)
else
default_after_rotation(user, rotation_type)
/datum/component/simple_rotation/proc/default_can_user_rotate(mob/living/user, rotation_type)
if(!istype(user) || !user.canUseTopic(parent, BE_CLOSE, NO_DEXTERY))
@@ -136,9 +136,7 @@
var/mob/M = parent.loc
I.dropped(M)
if(new_location)
//Reset the items values
_removal_reset(AM)
AM.forceMove(new_location)
AM.forceMove(new_location) // exited comsig will handle removal reset.
//We don't want to call this if the item is being destroyed
AM.on_exit_storage(src)
else
+2 -2
View File
@@ -351,7 +351,6 @@
return master._removal_reset(thing)
/datum/component/storage/proc/_remove_and_refresh(datum/source, atom/movable/thing)
_removal_reset(thing)
if(LAZYACCESS(ui_item_blocks, thing))
var/obj/screen/storage/volumetric_box/center/C = ui_item_blocks[thing]
for(var/i in can_see_contents()) //runtimes result if mobs can access post deletion.
@@ -359,6 +358,7 @@
M.client?.screen -= C.on_screen_objects()
ui_item_blocks -= thing
qdel(C)
_removal_reset(thing) // THIS NEEDS TO HAPPEN AFTER SO LAYERING DOESN'T BREAK!
refresh_mob_views()
//Call this proc to handle the removal of an item from the storage item. The item will be moved to the new_location target, if that is null it's being deleted
@@ -572,7 +572,7 @@
if(rustle_sound)
playsound(parent, "rustle", 50, 1, -5)
to_chat(user, "<span class='notice'>You put [I] [insert_preposition]to [parent].</span>")
for(var/mob/viewing in get_actual_viewers(world.view, user)-M)
for(var/mob/viewing in fov_viewers(world.view, user)-M)
if(in_range(M, viewing)) //If someone is standing close enough, they can tell what it is...
viewing.show_message("<span class='notice'>[M] puts [I] [insert_preposition]to [parent].</span>", MSG_VISUAL)
else if(I && I.w_class >= 3) //Otherwise they can only see large or normal items from a distance...
+7 -1
View File
@@ -145,4 +145,10 @@
return !is_mouth_covered()
/mob/living/carbon/CanSpreadAirborneDisease()
return !((head && (head.flags_cover & HEADCOVERSMOUTH) && (head.armor.getRating("bio") >= 25)) || (wear_mask && (wear_mask.flags_cover & MASKCOVERSMOUTH) && (wear_mask.armor.getRating("bio") >= 25)))
return !((head && (head.flags_cover & HEADCOVERSMOUTH) && (head.armor.getRating("bio") >= 25)) || (wear_mask && (wear_mask.flags_cover & MASKCOVERSMOUTH) && (wear_mask.armor.getRating("bio") >= 25)))
/mob/living/proc/set_shocked()
flags_1 |= SHOCKED_1
/mob/living/proc/reset_shocked()
flags_1 &= ~ SHOCKED_1
+12 -1
View File
@@ -47,8 +47,8 @@
destination.dna.uni_identity = uni_identity
destination.dna.blood_type = blood_type
destination.dna.skin_tone_override = skin_tone_override
destination.set_species(species.type, icon_update=0)
destination.dna.features = features.Copy()
destination.set_species(species.type, icon_update=0)
destination.dna.real_name = real_name
destination.dna.nameless = nameless
destination.dna.custom_species = custom_species
@@ -246,6 +246,17 @@
construct_block(GLOB.mam_body_markings_list.Find(features["mam_body_markings"]), GLOB.mam_body_markings_list.len)
if(DNA_TAUR_BLOCK)
construct_block(GLOB.taur_list.Find(features["taur"]), GLOB.taur_list.len)
if(species.mutant_bodyparts["taur"] && ishuman(holder))
var/datum/sprite_accessory/taur/T = GLOB.taur_list[features["taur"]]
switch(T?.taur_mode)
if(STYLE_HOOF_TAURIC)
H.physiology.footstep_type = FOOTSTEP_MOB_SHOE
if(STYLE_PAW_TAURIC)
H.physiology.footstep_type = FOOTSTEP_MOB_CLAW
if(STYLE_SNEK_TAURIC)
H.physiology.footstep_type = FOOTSTEP_MOB_CRAWL
else
H.physiology.footstep_type = null
//Please use add_mutation or activate_mutation instead
/datum/dna/proc/force_give(datum/mutation/human/HM)
+42
View File
@@ -0,0 +1,42 @@
#define SHORT 4/5
#define TALL 5/4
///Very similar to squish, but for dwarves and shorties
/datum/element/dwarfism
element_flags = ELEMENT_DETACH|ELEMENT_BESPOKE
id_arg_index = 2
var/comsig
var/list/attached_targets = list()
/datum/element/dwarfism/Attach(datum/target, comsig, comsig_target)
. = ..()
if(!isliving(target))
return ELEMENT_INCOMPATIBLE
src.comsig = comsig
var/mob/living/L = target
if(L.lying != 0)
L.transform = L.transform.Scale(SHORT, 1)
else
L.transform = L.transform.Scale(1, SHORT)
attached_targets[target] = comsig_target
RegisterSignal(target, comsig, .proc/check_loss) //Second arg of the signal will be checked against the comsig_target.
/datum/element/dwarfism/proc/check_loss(mob/living/L, comsig_target)
if(attached_targets[L] == comsig_target)
Detach(L)
/datum/element/dwarfism/Detach(mob/living/L)
. = ..()
if(QDELETED(L))
return
if(L.lying != 0)
L.transform = L.transform.Scale(TALL, 1)
else
L.transform = L.transform.Scale(1, TALL)
UnregisterSignal(L, comsig)
attached_targets -= L
#undef SHORT
#undef TALL
+1 -1
View File
@@ -41,7 +41,7 @@
return
//we want to delay the effect to be displayed after the mob is petted, not before.
switch(user.a_intent)
if(INTENT_HARM, INTENT_DISARM)
if(INTENT_HARM)
addtimer(CALLBACK(src, .proc/kick_the_dog, source, user), 1)
if(INTENT_HELP)
addtimer(CALLBACK(src, .proc/pet_the_dog, source, user), 1)
+11 -7
View File
@@ -5,16 +5,18 @@
var/list/testmerge = list()
/datum/getrev/New()
commit = rustg_git_revparse("HEAD")
if(commit)
date = rustg_git_commit_date(commit)
originmastercommit = rustg_git_revparse("origin/master")
/datum/getrev/proc/load_tgs_info()
testmerge = world.TgsTestMerges()
var/datum/tgs_revision_information/revinfo = world.TgsRevision()
if(revinfo)
commit = revinfo.commit
originmastercommit = revinfo.origin_commit
else
commit = rustg_git_revparse("HEAD")
if(commit)
date = rustg_git_commit_date(commit)
originmastercommit = rustg_git_revparse("origin/master")
date = rustg_git_commit_date(commit)
// goes to DD log and config_error.txt
log_world(get_log_message())
@@ -77,7 +79,9 @@
msg += "No commit information"
if(world.TgsAvailable())
var/datum/tgs_version/version = world.TgsVersion()
msg += "Server tools version: [version.raw_parameter]"
msg += "TGS version: [version.raw_parameter]"
var/datum/tgs_version/api_version = world.TgsApiVersion()
msg += "DMAPI version: [api_version.raw_parameter]"
// Game mode odds
msg += "<br><b>Current Informational Settings:</b>"
@@ -121,4 +125,4 @@
if(probabilities[ctag] > 0)
var/percentage = round(probabilities[ctag] / sum * 100, 0.1)
msg += "[ctag] [percentage]%"
to_chat(src, msg.Join("<br>"))
to_chat(src, msg.Join("<br>"))
@@ -248,7 +248,7 @@
description = "<span class='boldwarning'>Something I recently ate was horrifyingly disgusting.</span>\n"
mood_change = -5
timeout = 5 MINUTES
/datum/mood_event/nanite_sadness
description = "<span class='warning robot'>+++++++HAPPINESS SUPPRESSION+++++++</span>\n"
mood_change = -7
@@ -256,3 +256,7 @@
/datum/mood_event/nanite_sadness/add_effects(message)
description = "<span class='warning robot'>+++++++[message]+++++++</span>\n"
/datum/mood_event/artbad
description = "<span class='warning'>I've produced better art than that from my ass.</span>\n"
mood_change = -2
timeout = 1200
@@ -182,3 +182,17 @@
description = "<span class='nicegreen'>What a peculiar emblem. It makes me feel hopeful for my future.</span>\n"
mood_change = 5
/datum/mood_event/artok
description = "<span class='nicegreen'>It's nice to see people are making art around here.</span>\n"
mood_change = 2
timeout = 2 MINUTES
/datum/mood_event/artgood
description = "<span class='nicegreen'>What a thought-provoking piece of art. I'll remember that for a while.</span>\n"
mood_change = 3
timeout = 3 MINUTES
/datum/mood_event/artgreat
description = "<span class='nicegreen'>That work of art was so great it made me believe in the goodness of humanity. Says a lot in a place like this.</span>\n"
mood_change = 4
timeout = 4 MINUTES
+2 -1
View File
@@ -116,7 +116,8 @@
owner.apply_overlay(layer_used)
if(power)
owner.RemoveSpell(power)
qdel(src)
qdel(power)
SEND_SIGNAL(owner, COMSIG_HUMAN_MUTATION_LOSS, src)
return 0
return 1
+1 -2
View File
@@ -82,7 +82,7 @@
if(..())
return
ADD_TRAIT(owner, TRAIT_DWARF, GENETIC_MUTATION)
owner.transform = owner.transform.Scale(1, 0.8)
owner.AddElement(/datum/element/dwarfism, COMSIG_HUMAN_MUTATION_LOSS, src)
passtable_on(owner, GENETIC_MUTATION)
owner.visible_message("<span class='danger'>[owner] suddenly shrinks!</span>", "<span class='notice'>Everything around you seems to grow..</span>")
@@ -90,7 +90,6 @@
if(..())
return
REMOVE_TRAIT(owner, TRAIT_DWARF, GENETIC_MUTATION)
owner.transform = owner.transform.Scale(1, 1.25)
passtable_off(owner, GENETIC_MUTATION)
owner.visible_message("<span class='danger'>[owner] suddenly grows!</span>", "<span class='notice'>Everything around you seems to shrink..</span>")
+13 -13
View File
@@ -20,18 +20,20 @@ GLOBAL_LIST_INIT_TYPED(skill_datums, /datum/skill, init_skill_datums())
var/desc
/// Color of the name as shown in the html readout
var/name_color = "#F0F0F0" // White on dark surface.
/// Our progression type
/// Our progression type. These are mostly used to skip typechecks overhead, don't go around messing with these.
var/progression_type
/// Abstract type
var/abstract_type = /datum/skill
/// List of max levels. Only used in level skills, but present here for helper macros.
var/max_levels = INFINITY
/// skill threshold used in generic skill competency calculations.
var/list/competency_thresholds = list(0, 0, 0)
/// Multiplier of the difference of the holder skill value and the selected threshold.
var/list/competency_mults = list(0, 0, 0)
/// In which way this skil can affect or be affected through actions and skill modifiers.
var/skill_flags = SKILL_USE_MOOD|SKILL_TRAIN_MOOD
/// skill threshold used in generic skill competency operations.
var/list/competency_thresholds
/// Base multiplier used in skill competency operations.
var/base_multiplier = 1
/// Value added to the base multiplier depending on overall competency compared to maximum value/level.
var/competency_multiplier = 1
/// A list of ways this skill can affect or be affected through actions and skill modifiers.
var/list/skill_traits = list(SKILL_SANITY, SKILL_INTELLIGENCE)
/**
* Ensures what someone's setting as a value for this skill is valid.
@@ -66,8 +68,7 @@ GLOBAL_LIST_INIT_TYPED(skill_datums, /datum/skill, init_skill_datums())
/datum/skill/binary
abstract_type = /datum/skill/binary
progression_type = SKILL_PROGRESSION_BINARY
competency_thresholds = list(FALSE, TRUE, TRUE)
competency_mults = list(0.5, 0.5, 0.5)
competency_thresholds = list(THRESHOLD_COMPETENT = FALSE, THRESHOLD_EXPERT = TRUE, THRESHOLD_MASTER = TRUE)
/datum/skill/binary/sanitize_value(new_value)
return new_value? TRUE : FALSE
@@ -78,6 +79,7 @@ GLOBAL_LIST_INIT_TYPED(skill_datums, /datum/skill, init_skill_datums())
/datum/skill/numerical
abstract_type = /datum/skill/numerical
progression_type = SKILL_PROGRESSION_NUMERICAL
competency_thresholds = list(THRESHOLD_COMPETENT = 25, THRESHOLD_EXPERT = 50, THRESHOLD_MASTER = 75)
/// Max value of this skill
var/max_value = 100
/// Min value of this skill
@@ -180,8 +182,7 @@ GLOBAL_LIST_INIT_TYPED(skill_datums, /datum/skill, init_skill_datums())
/datum/skill/level/job
abstract_type = /datum/skill/level/job
levels = list("Basic", "Trained", "Experienced", "Master")
competency_thresholds = list(JOB_SKILL_TRAINED, JOB_SKILL_EXPERT, JOB_SKILL_MASTER)
competency_mults = list(0.15, 0.1, 0.1)
competency_thresholds = list(THRESHOLD_COMPETENT = JOB_SKILL_TRAINED, THRESHOLD_EXPERT = JOB_SKILL_EXPERT, THRESHOLD_MASTER = JOB_SKILL_MASTER)
associative = TRUE
//quite the reference, no?
@@ -195,7 +196,6 @@ GLOBAL_LIST_INIT_TYPED(skill_datums, /datum/skill, init_skill_datums())
"Proficient", "Talented", "Adept", "Expert",
"Professional", "Accomplished", "Great", "Master",
"High Master", "Grand Master", "Legendary")
competency_thresholds = list(DORF_SKILL_COMPETENT, DORF_SKILL_EXPERT, DORF_SKILL_MASTER)
competency_mults = list(0.15, 0.1, 0.08)
competency_thresholds = list(THRESHOLD_COMPETENT = DORF_SKILL_COMPETENT, THRESHOLD_EXPERT = DORF_SKILL_EXPERT, THRESHOLD_MASTER = DORF_SKILL_MASTER)
associative = TRUE
unskilled_tier = "Dabbling"
+33 -14
View File
@@ -122,16 +122,22 @@
* * modifier_is_multiplier : wheter the modifier is a multiplier or a divisor.
*/
/datum/mind/proc/action_skill_mod(skill, value, threshold, modifier_is_multiplier = TRUE)
var/mod
var/datum/skill/S = GLOB.skill_datums[skill]
if(!S)
return
return value
var/mod = S.base_multiplier
switch(S.progression_type)
if(SKILL_PROGRESSION_LEVEL)
mod = get_skill_level(S.type)
var/datum/skill/level/L = S
var/skill_lvl = get_skill_level(L.type)
mod += skill_lvl/(L.max_levels+max(L.competency_thresholds[threshold]-skill_lvl, 0))*L.competency_multiplier
if(SKILL_PROGRESSION_NUMERICAL)
var/datum/skill/numerical/N = S
var/skill_val = get_skill_value(N.type)
mod += skill_val/(N.max_value+max(N.competency_thresholds[threshold]-skill_val, 0))*N.competency_multiplier
else
mod = get_skill_value(S.type)
mod = (1+(mod-S.competency_thresholds[threshold])*S.competency_mults[threshold])
var/comp_threshold = S.competency_thresholds[threshold]
mod += (comp_threshold ? (get_skill_value(S.type) / comp_threshold) : get_skill_value(S.type))*S.competency_multiplier
. = modifier_is_multiplier ? value*mod : value/mod
/**
@@ -139,29 +145,42 @@
* Args:
* * item/I : the item used in this action. its used_skills list variable contains the skills exercised with it.
* * value : the value to modify, may be a delay, damage, probability.
* * flags : the required flags that each skill (either in I.used_skills or the skill datum skill_flags) must have to influence
* * traits : the required traits each skill (either in I.used_skills or the skill datum skill_traits) must have to influence
* * the value.
* * bad_flags : the opposite of the above, skills that must not be present to impact the value.
* * bad_traits : the opposite of the above.
* * modifier_is_multiplier : wheter the modifier is a multiplier or a divisor.
*/
/datum/mind/proc/item_action_skills_mod(obj/item/I, value, flags = NONE, bad_flags = NONE, modifier_is_multiplier = TRUE)
/datum/mind/proc/item_action_skills_mod(obj/item/I, value, traits, bad_traits, modifier_is_multiplier = TRUE)
. = value
var/sum = 0
var/divisor = 0
var/one_trait = istext(traits)
var/one_bad_trait = istext(bad_traits)
for(var/k in I.used_skills)
var/datum/skill/S = GLOB.skill_datums[k]
if(!S)
continue
var/our_flags = (I.used_skills[k]|S.skill_flags)
if((flags && !(our_flags & flags)) || (bad_flags && our_flags & bad_flags))
var/our_traits = S.skill_traits
our_traits |= I.used_skills[k]
if(traits && !(one_trait ? (traits in our_traits) : length(our_traits & traits)))
continue
var/mod
if(bad_traits && (one_bad_trait ? (bad_traits in our_traits) : length(our_traits & bad_traits)))
continue
var/mod = S.base_multiplier
switch(S.progression_type)
if(SKILL_PROGRESSION_LEVEL)
mod = get_skill_level(S.type)
var/datum/skill/level/L = S
var/skill_lvl = get_skill_level(L.type)
mod += skill_lvl/(L.max_levels+max(L.competency_thresholds[I.skill_difficulty]-skill_lvl, 0))*L.competency_multiplier
if(SKILL_PROGRESSION_NUMERICAL)
var/datum/skill/numerical/N = S
var/skill_val = get_skill_value(N.type)
mod += skill_val/(N.max_value+max(N.competency_thresholds[I.skill_difficulty]-skill_val, 0))*N.competency_multiplier
else
mod = get_skill_value(S.type)
sum += 1+(mod - S.competency_thresholds[I.skill_difficulty])*S.competency_mults[I.skill_difficulty]
var/comp_threshold = S.competency_thresholds[I.skill_difficulty]
mod += (comp_threshold ? (get_skill_value(S.type) / comp_threshold) : get_skill_value(S.type))*S.competency_multiplier
sum += mod
divisor++
if(divisor)
. = modifier_is_multiplier ? value*(sum/divisor) : value/(sum/divisor)
+29 -11
View File
@@ -9,11 +9,13 @@ GLOBAL_LIST_EMPTY(potential_mods_per_skill)
/datum/skill_modifier
/// flags for this skill modifier.
var/modifier_flags = NONE
/// target skills, can be a specific skill typepath or a set of skill flags.
var/target_skills = NONE
/// target skills, can be a specific skill typepath or a list of skill traits.
var/target_skills = /datum/skill
/// the GLOB.potential_skills_per_mod key generated on runtime. You shouldn't be var-editing it.
var/target_skills_key
/// The identifier key this skill modifier is associated with.
var/identifier
/// skill affinity modifier, can be a multiplier or addendum, depending on the modifier_flags flags.
/// skill affinity modifier, can be a multiplier or addendum, depending on the modifier_flags.
var/affinity_mod = 1
/// skill value modifier, see above.
var/value_mod = 1
@@ -38,21 +40,25 @@ GLOBAL_LIST_EMPTY(potential_mods_per_skill)
CRASH("Skill modifier identifier \"[identifier]\" already taken.")
GLOB.skill_modifiers[identifier] = src
if(ispath(target_skills))
target_skills_key = target_skills
var/list/mod_L = GLOB.potential_mods_per_skill[target_skills]
if(!mod_L)
mod_L = GLOB.potential_mods_per_skill[target_skills] = list()
else
BINARY_INSERT(identifier, mod_L, datum/skill_modifier, src, priority, COMPARE_VALUE)
mod_L[identifier] = src
GLOB.potential_skills_per_mod["[target_skills]"] = list(target_skills)
else //Should be a bitfield.
var/list/L = GLOB.potential_skills_per_mod["[target_skills]"]
GLOB.potential_skills_per_mod[target_skills_key] = list(target_skills)
else //Should be a list.
var/list/T = target_skills
T = sortTim(target_skills, /proc/cmp_text_asc) //Sort the list contents alphabetically.
target_skills_key = T.Join("-")
var/list/L = GLOB.potential_skills_per_mod[target_skills_key]
if(!L)
L = list()
for(var/path in GLOB.skill_datums)
if(GLOB.skill_datums[path].skill_flags & target_skills)
if(GLOB.skill_datums[path].skill_traits & target_skills)
L += path
GLOB.potential_skills_per_mod["[target_skills]"] = L
GLOB.potential_skills_per_mod[target_skills_key] = L
for(var/path in L)
var/list/mod_L = GLOB.potential_mods_per_skill[path]
if(!mod_L)
@@ -62,7 +68,7 @@ GLOBAL_LIST_EMPTY(potential_mods_per_skill)
mod_L[identifier] = src
/datum/skill_modifier/Destroy()
for(var/path in GLOB.potential_skills_per_mod["[target_skills]"])
for(var/path in GLOB.potential_skills_per_mod[target_skills_key])
var/mod_L = GLOB.potential_mods_per_skill[path]
mod_L -= identifier
if(!length(mod_L))
@@ -96,7 +102,7 @@ GLOBAL_LIST_EMPTY(potential_mods_per_skill)
LAZYINITLIST(skill_holder.skill_affinity_mods)
if(M.modifier_flags & MODIFIER_SKILL_LEVEL)
LAZYINITLIST(skill_holder.skill_level_mods)
for(var/path in GLOB.potential_skills_per_mod["[M.target_skills]"])
for(var/path in GLOB.potential_skills_per_mod[M.target_skills_key])
if(M.modifier_flags & MODIFIER_SKILL_VALUE)
ADD_MOD_STEP(skill_holder.skill_value_mods, path, skill_holder.original_values, get_skill_value(path, FALSE))
if(M.modifier_flags & MODIFIER_SKILL_AFFINITY)
@@ -127,7 +133,7 @@ GLOBAL_LIST_EMPTY(potential_mods_per_skill)
if(!skill_holder.skill_value_mods && !skill_holder.skill_affinity_mods && !skill_holder.skill_level_mods)
return
for(var/path in GLOB.potential_skills_per_mod["[M.target_skills]"])
for(var/path in GLOB.potential_skills_per_mod[M.target_skills_key])
if(M.modifier_flags & MODIFIER_SKILL_VALUE && skill_holder.skill_value_mods)
REMOVE_MOD_STEP(skill_holder.skill_value_mods, path, skill_holder.original_values)
if(M.modifier_flags & MODIFIER_SKILL_AFFINITY && skill_holder.skill_affinity_mods)
@@ -155,6 +161,18 @@ GLOBAL_LIST_EMPTY(potential_mods_per_skill)
if(MODIFIER_TARGET_AFFINITY)
mod = affinity_mod
if(modifier_flags & MODIFIER_USE_THRESHOLDS && istext(mod))
var/datum/skill/S = GLOB.skill_datums[skillpath]
if(method == MODIFIER_TARGET_VALUE && S.progression_type == SKILL_PROGRESSION_LEVEL)
var/datum/skill/level/L = S
switch(L.level_up_method)
if(STANDARD_LEVEL_UP)
mod = XP_LEVEL(L.standard_xp_lvl_up, L.xp_lvl_multiplier, S.competency_thresholds[mod])
if(DWARFY_LEVEL_UP)
mod = DORF_XP_LEVEL(L.standard_xp_lvl_up, L.xp_lvl_multiplier, S.competency_thresholds[mod])
else
mod = S.competency_thresholds[mod]
var/diff = 0
if(modifier_flags & (MODIFIER_SKILL_VIRTUE|MODIFIER_SKILL_HANDICAP))
if(modifier_flags & MODIFIER_SKILL_VIRTUE)
+1 -2
View File
@@ -2,5 +2,4 @@
name = "Wiring"
desc = "How proficient and knowledged you are at wiring beyond laying cables on the floor."
name_color = COLOR_PALE_ORANGE
competency_thresholds = list(JOB_SKILL_BASIC, JOB_SKILL_EXPERT, JOB_SKILL_MASTER)
skill_flags = SKILL_USE_MOOD|SKILL_TRAIN_MOOD|SKILL_USE_TOOL|SKILL_TRAINING_TOOL
skill_traits = list(SKILL_SANITY, SKILL_INTELLIGENCE, SKILL_USE_TOOL, SKILL_TRAINING_TOOL)
+1 -1
View File
@@ -2,4 +2,4 @@
name = "Surgery"
desc = "How proficient you are at doing surgery."
name_color = COLOR_PALE_BLUE_GRAY
competency_mults = list(0.025, 0.025, 0.025) // 60% surgery speed up at max value of 100.
competency_multiplier = 1.5 // 60% surgery speed up at max value of 100, considering the base multiplier.
+2 -2
View File
@@ -1,8 +1,8 @@
/datum/skill_modifier/bad_mood
modifier_flags = MODIFIER_SKILL_VALUE|MODIFIER_SKILL_LEVEL|MODIFIER_SKILL_MULT|MODIFIER_SKILL_BODYBOUND
target_skills = SKILL_USE_MOOD
target_skills = list(SKILL_SANITY)
/datum/skill_modifier/great_mood
modifier_flags = MODIFIER_SKILL_AFFINITY|MODIFIER_SKILL_MULT|MODIFIER_SKILL_BODYBOUND
target_skills = SKILL_TRAIN_MOOD
target_skills = list(SKILL_SANITY)
affinity_mod = 1.2
+13
View File
@@ -0,0 +1,13 @@
/datum/skill_modifier/brain_damage
target_skills = list(SKILL_INTELLIGENCE)
modifier_flags = MODIFIER_SKILL_VALUE|MODIFIER_SKILL_AFFINITY|MODIFIER_SKILL_LEVEL|MODIFIER_SKILL_MULT|MODIFIER_SKILL_BODYBOUND
value_mod = 0.85
level_mod = 0.85
affinity_mod = 0.85
/datum/skill_modifier/heavy_brain_damage
target_skills = list(SKILL_INTELLIGENCE)
modifier_flags = MODIFIER_SKILL_VALUE|MODIFIER_SKILL_AFFINITY|MODIFIER_SKILL_LEVEL|MODIFIER_SKILL_BODYBOUND|MODIFIER_SKILL_HANDICAP|MODIFIER_USE_THRESHOLDS
priority = MODIFIER_SKILL_PRIORITY_LOW
value_mod = THRESHOLD_COMPETENT
level_mod = THRESHOLD_COMPETENT
+2
View File
@@ -120,11 +120,13 @@
/datum/status_effect/mesmerize/on_creation(mob/living/new_owner, set_duration)
. = ..()
ADD_TRAIT(owner, TRAIT_MUTE, "mesmerize")
ADD_TRAIT(owner, TRAIT_COMBAT_MODE_LOCKED, "mesmerize")
owner.add_movespeed_modifier(/datum/movespeed_modifier/status_effect/mesmerize)
/datum/status_effect/mesmerize/on_remove()
. = ..()
REMOVE_TRAIT(owner, TRAIT_MUTE, "mesmerize")
REMOVE_TRAIT(owner, TRAIT_COMBAT_MODE_LOCKED, "mesmerize")
owner.remove_movespeed_modifier(/datum/movespeed_modifier/status_effect/mesmerize)
/datum/status_effect/mesmerize/on_creation(mob/living/new_owner, set_duration)
+20
View File
@@ -0,0 +1,20 @@
/datum/tgs_event_handler/impl/HandleEvent(event_code, ...)
switch(event_code)
if(TGS_EVENT_REBOOT_MODE_CHANGE)
var/list/reboot_mode_lookup = list ("[TGS_REBOOT_MODE_NORMAL]" = "be normal", "[TGS_REBOOT_MODE_SHUTDOWN]" = "shutdown the server", "[TGS_REBOOT_MODE_RESTART]" = "hard restart the server")
var old_reboot_mode = args[2]
var new_reboot_mode = args[3]
message_admins("TGS: Reboot will no longer [reboot_mode_lookup["[old_reboot_mode]"]], it will instead [reboot_mode_lookup["[new_reboot_mode]"]]")
if(TGS_EVENT_PORT_SWAP)
message_admins("TGS: Changing port from [world.port] to [args[2]]")
if(TGS_EVENT_INSTANCE_RENAMED)
message_admins("TGS: Instance renamed to from [world.TgsInstanceName()] to [args[2]]")
if(TGS_EVENT_COMPILE_START)
message_admins("TGS: Deployment started, new game version incoming...")
if(TGS_EVENT_COMPILE_CANCELLED)
message_admins("TGS: Deployment cancelled!")
if(TGS_EVENT_COMPILE_FAILURE)
message_admins("TGS: Deployment failed!")
if(TGS_EVENT_DEPLOYMENT_COMPLETE)
message_admins("TGS: Deployment complete!")
to_chat(world, "<span class='boldannounce'>Server updated, changes will be applied on the next round...</span>")
+8
View File
@@ -581,6 +581,14 @@
SEND_SIGNAL(src, COMSIG_ATOM_RCD_ACT, user, the_rcd, passed_mode)
return FALSE
/**
* Respond to a electric bolt action on our item
*
* Default behaviour is to return, we define here to allow for cleaner code later on
*/
/atom/proc/zap_act(power, zap_flags, shocked_targets)
return
/atom/proc/storage_contents_dump_act(obj/item/storage/src_object, mob/user)
if(GetComponent(/datum/component/storage))
return component_storage_contents_dump_act(src_object, user)
+7 -4
View File
@@ -37,6 +37,8 @@
var/throwforce = 0
var/datum/component/orbiter/orbiting
var/can_be_z_moved = TRUE
///If we were without gravity and another animation happened, the bouncing will stop, and we need to restart it in next life().
var/floating_need_update = FALSE
var/zfalling = FALSE
@@ -492,15 +494,16 @@
/atom/movable/proc/float(on)
if(throwing)
return
if(on && !(movement_type & FLOATING))
if(on && (!(movement_type & FLOATING) || floating_need_update))
animate(src, pixel_y = pixel_y + 2, time = 10, loop = -1)
sleep(10)
animate(src, pixel_y = pixel_y - 2, time = 10, loop = -1)
setMovetype(movement_type | FLOATING)
else if (!on && (movement_type & FLOATING))
if(!(movement_type & FLOATING))
setMovetype(movement_type | FLOATING)
else if (!on && movement_type & FLOATING)
animate(src, pixel_y = initial(pixel_y), time = 10)
setMovetype(movement_type & ~FLOATING)
floating_need_update = FALSE
/* Language procs
* Unless you are doing something very specific, these are the ones you want to use.
-3
View File
@@ -48,9 +48,6 @@
/obj/machinery/dominator/hulk_damage()
return (max_integrity - integrity_failure) / DOM_HULK_HITS_REQUIRED
/obj/machinery/dominator/tesla_act()
qdel(src)
/obj/machinery/dominator/update_icon()
cut_overlays()
if(stat & BROKEN)
+1 -1
View File
@@ -10,7 +10,7 @@
/obj/effect/decal/cleanable/crayon/gang
icon = 'icons/effects/crayondecal.dmi'
layer = ABOVE_NORMAL_TURF_LAYER //Harder to hide
plane = GAME_PLANE
plane = ABOVE_WALL_PLANE
do_icon_rotate = FALSE //These are designed to always face south, so no rotation please.
var/datum/team/gang/gang
+4 -4
View File
@@ -522,11 +522,11 @@ Class Procs:
/obj/machinery/proc/can_be_overridden()
. = 1
/obj/machinery/tesla_act(power, tesla_flags, shocked_objects)
..()
if(prob(85) && (tesla_flags & TESLA_MACHINE_EXPLOSIVE))
/obj/machinery/zap_act(power, zap_flags, shocked_objects)
. = ..()
if(prob(85) && (zap_flags & ZAP_MACHINE_EXPLOSIVE))
explosion(src, 1, 2, 4, flame_range = 2, adminlog = FALSE, smoke = FALSE)
if(tesla_flags & TESLA_OBJ_DAMAGE)
else if(zap_flags & ZAP_OBJ_DAMAGE)
take_damage(power/2000, BURN, "energy")
if(prob(40))
emp_act(EMP_LIGHT)
+2 -2
View File
@@ -290,8 +290,6 @@
operating = TRUE
do_animate("closing")
layer = closingLayer
if(!safe)
crush()
sleep(5)
density = TRUE
sleep(5)
@@ -303,6 +301,8 @@
update_freelook_sight()
if(safe)
CheckForMobs()
else
crush()
return 1
/obj/machinery/door/proc/CheckForMobs()
+1 -1
View File
@@ -34,7 +34,7 @@ GLOBAL_LIST_EMPTY(network_holopads)
desc = "It's a floor-mounted device for projecting holographic images."
icon_state = "holopad0"
layer = LOW_OBJ_LAYER
plane = FLOOR_PLANE
plane = ABOVE_WALL_PLANE
flags_1 = HEAR_1
use_power = IDLE_POWER_USE
idle_power_usage = 5
+7 -2
View File
@@ -115,8 +115,8 @@
return PROCESS_KILL
/obj/machinery/space_heater/RefreshParts()
var/laser = 0
var/cap = 0
var/laser = 2
var/cap = 1
for(var/obj/item/stock_parts/micro_laser/M in component_parts)
laser += M.rating
for(var/obj/item/stock_parts/capacitor/M in component_parts)
@@ -166,6 +166,11 @@
else
return ..()
/obj/machinery/space_heater/wrench_act(mob/living/user, obj/item/I)
..()
default_unfasten_wrench(user, I, 5)
return TRUE
/obj/machinery/space_heater/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.physical_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
+105 -14
View File
@@ -11,9 +11,6 @@
var/insisting = 0
/obj/machinery/wish_granter/attack_hand(mob/living/carbon/user)
. = ..()
if(.)
return
if(charges <= 0)
to_chat(user, "The Wish Granter lies silent.")
return
@@ -22,22 +19,116 @@
to_chat(user, "You feel a dark stirring inside of the Wish Granter, something you want nothing of. Your instincts are better than any man's.")
return
else if(is_special_character(user))
to_chat(user, "Even to a heart as dark as yours, you know nothing good will come of this. Something instinctual makes you pull away.")
else if (!insisting)
to_chat(user, "Your first touch makes the Wish Granter stir, listening to you. Are you really sure you want to do this?")
insisting++
else
to_chat(user, "You speak. [pick("I want the station to disappear","Humanity is corrupt, mankind must be destroyed","I want to be rich", "I want to rule the world","I want immortality.")]. The Wish Granter answers.")
to_chat(user, "Your head pounds for a moment, before your vision clears. You are the avatar of the Wish Granter, and your power is LIMITLESS! And it's all yours. You need to make sure no one can take it from you. No one can know, first.")
if(is_special_character(user))
to_chat(user, "You speak. [pick("I want power","Humanity is corrupt, mankind must be destroyed", "I want to rule the world","I want immortality")]. The Wish Granter answers.")
to_chat(user, "Your head pounds for a moment, before your vision clears. The Wish Granter, sensing the darkness in your heart, has given you limitless power, and it's all yours!")
user.dna.add_mutation(HULK)
user.dna.add_mutation(XRAY)
user.dna.add_mutation(SPACEMUT)
user.dna.add_mutation(TK)
user.next_move_modifier *= 0.5 //half the delay between attacks!
to_chat(user, "Things around you feel slower!")
charges--
insisting = FALSE
to_chat(user, "You have a very great feeling about this!")
else
to_chat(user, "The Wish Granter awaits your wish.")
var/wish = input("You want...","Wish") as null|anything in list("Power","Wealth","The Station To Disappear","To Kill","Nothing")
switch(wish)
if("Power") //Gives infinite power in exchange for infinite power going off in your face!
if(charges <= 0)
return
to_chat(user, "<B>Your wish is granted, but at a terrible cost...</B>")
to_chat(user, "The Wish Granter punishes you for your selfishness, warping itself into a delaminating supermatter shard!")
var/obj/item/stock_parts/cell/infinite/powah = new /obj/item/stock_parts/cell/infinite(get_turf(user))
if(user.put_in_hands(powah))
to_chat(user, "[powah] materializes into your hands!")
else
to_chat(user, "[powah] materializes onto the floor.")
var/obj/machinery/power/supermatter_crystal/powerwish = new /obj/machinery/power/supermatter_crystal(loc)
powerwish.damage = 700 //right at the emergency threshold
powerwish.produces_gas = FALSE
charges--
insisting = FALSE
if(!charges)
qdel(src)
if("Wealth") //Gives 1 million space bucks in exchange for being turned into gold!
if(charges <= 0)
return
to_chat(user, "<B>Your wish is granted, but at a cost...</B>")
to_chat(user, "The Wish Granter punishes you for your selfishness, warping your body to match the greed in your heart.")
new /obj/structure/closet/crate/trashcart/moneywish(loc)
new /obj/structure/closet/crate/trashcart/moneywish(loc)
user.set_species(/datum/species/golem/gold)
charges--
insisting = FALSE
if(!charges)
qdel(src)
if("The Station To Disappear") //teleports you to the station and makes you blind, making the station disappear for you!
if(charges <= 0)
return
to_chat(user, "<B>Your wish is 'granted', but at a terrible cost...</B>")
to_chat(user, "The Wish Granter punishes you for your selfishness, claiming your soul and warping your eyes to match the darkness in your heart.")
user.dna.add_mutation(BLINDMUT)
var/obj/item/organ/eyes/eyes = user.getorganslot(ORGAN_SLOT_EYES)
if(eyes)
eyes.applyOrganDamage(eyes.maxHealth)
var/list/destinations = list()
for(var/obj/item/beacon/B in GLOB.teleportbeacons)
var/turf/T = get_turf(B)
if(is_station_level(T.z))
destinations += B
var/chosen_beacon = pick(destinations)
var/obj/effect/portal/jaunt_tunnel/J = new (get_turf(src), src, 100, null, FALSE, get_turf(chosen_beacon))
try_move_adjacent(J)
playsound(src,'sound/effects/sparks4.ogg',50,1)
charges--
insisting = FALSE
if(!charges)
qdel(src)
if("To Kill") //Makes you kill things in exchange for rewards!
if(charges <= 0)
return
to_chat(user, "<B>Your wish is granted, but at a terrible cost...</B>")
to_chat(user, "The Wish Granter punishes you for your wickedness, warping itself into a dastardly creature for you to kill! ...but it almost seems to reward you for this.")
var/obj/item/melee/transforming/energy/sword/cx/killreward = new /obj/item/melee/transforming/energy/sword/cx(get_turf(user))
if(user.put_in_hands(killreward))
to_chat(user, "[killreward] materializes into your hands!")
else
to_chat(user, "[killreward] materializes onto the floor.")
user.next_move_modifier *= 0.8 //20% less delay between attacks!
to_chat(user, "Things around you feel slightly slower!")
var/mob/living/simple_animal/hostile/venus_human_trap/killwish = new /mob/living/simple_animal/hostile/venus_human_trap(loc)
killwish.maxHealth = 1500
killwish.health = killwish.maxHealth
killwish.vine_grab_distance = 6
killwish.melee_damage_upper = 30
killwish.loot = list(/obj/item/dualsaber/hypereutactic)
charges--
insisting = FALSE
if(!charges)
qdel(src)
if("Nothing") //Makes the wish granter disappear
if(charges <= 0)
return
to_chat(user, "<B>The Wish Granter vanishes from sight!</B>")
to_chat(user, "You feel as if you just narrowly avoided a terrible fate...")
charges--
insisting = FALSE
qdel(src)
charges--
insisting = 0
//ITEMS THAT IT USES
user.mind.add_antag_datum(/datum/antagonist/wishgranter)
/obj/structure/closet/crate/trashcart/moneywish
desc = "A heavy, metal trashcart with wheels. Filled with cash."
name = "loaded trash cart"
to_chat(user, "You have a very bad feeling about this.")
return
/obj/structure/closet/crate/trashcart/moneywish/PopulateContents() //25*20*1000=500,000
for(var/i in 1 to 25)
var/obj/item/stack/spacecash/c1000/lodsamoney = new /obj/item/stack/spacecash/c1000(src)
lodsamoney.amount = lodsamoney.max_amount
+12 -9
View File
@@ -62,18 +62,21 @@
/obj/mecha/combat/neovgre/process()
..()
if(GLOB.ratvar_awakens) // At this point only timley intervention by lord singulo could hople to stop the superweapon
if(GLOB.ratvar_awakens) // At this point only timley intervention by lord singulo could hope to stop the superweapon
cell.charge = INFINITY
max_integrity = INFINITY
obj_integrity = max_integrity
CHECK_TICK //Just to be on the safe side lag wise
else if(cell.charge < cell.maxcharge)
for(var/obj/effect/clockwork/sigil/transmission/T in range(SIGIL_ACCESS_RANGE, src))
var/delta = min(recharge_rate, cell.maxcharge - cell.charge)
if (get_clockwork_power() <= delta)
cell.charge += delta
adjust_clockwork_power(-delta)
CHECK_TICK
else
if(cell.charge < cell.maxcharge)
for(var/obj/effect/clockwork/sigil/transmission/T in range(SIGIL_ACCESS_RANGE, src))
var/delta = min(recharge_rate, cell.maxcharge - cell.charge)
if (get_clockwork_power() >= delta)
cell.charge += delta
adjust_clockwork_power(-delta)
if(obj_integrity < max_integrity && istype(loc, /turf/open/floor/clockwork))
obj_integrity += min(max_integrity - obj_integrity, max_integrity / 200)
CHECK_TICK
/obj/mecha/combat/neovgre/Initialize()
.=..()
@@ -90,7 +93,7 @@
energy_drain = 30
name = "Aribter Laser Cannon"
desc = "Please re-attach this to neovgre and stop asking questions about why it looks like a normal Nanotrasen issue Solaris laser cannon - Nezbere"
fire_sound = "sound/weapons/neovgre_laser.ogg"
fire_sound = 'sound/weapons/neovgre_laser.ogg'
/obj/item/mecha_parts/mecha_equipment/weapon/energy/laser/heavy/neovgre/can_attach(obj/mecha/combat/neovgre/M)
if(istype(M))
+1 -1
View File
@@ -77,7 +77,7 @@
/obj/mecha/attack_animal(mob/living/simple_animal/user)
mecha_log_message("Attack by simple animal. Attacker - [user].", color="red")
if(!user.melee_damage_upper && !user.obj_damage)
user.emote("custom", message = "[user.friendly] [src].")
user.emote("custom", message = "[user.friendly_verb_continuous] [src].")
return 0
else
var/play_soundeffect = 1
+1 -1
View File
@@ -3,7 +3,7 @@
desc = "Graffiti. Damn kids."
icon = 'icons/effects/crayondecal.dmi'
icon_state = "rune1"
plane = GAME_PLANE //makes the graffiti visible over a wall.
plane = ABOVE_WALL_PLANE //makes the graffiti visible over a wall.
gender = NEUTER
mergeable_decal = FALSE
var/do_icon_rotate = TRUE
@@ -35,6 +35,7 @@
icon = 'icons/turf/decals.dmi'
icon_state = "warningline"
layer = TURF_DECAL_LAYER
plane = ABOVE_WALL_PLANE
/obj/effect/turf_decal/Initialize()
..()
+1
View File
@@ -469,6 +469,7 @@ INITIALIZE_IMMEDIATE(/obj/effect/landmark/start/new_player)
/obj/effect/landmark/stationroom
var/list/templates = list()
layer = BULLET_HOLE_LAYER
plane = ABOVE_WALL_PLANE
/obj/effect/landmark/stationroom/New()
..()
+6 -4
View File
@@ -135,7 +135,7 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
///Skills vars
//list of skill PATHS exercised when using this item. An associated bitfield can be set to indicate additional ways the skill is used by this specific item.
var/list/datum/skill/used_skills
var/skill_difficulty = THRESHOLD_COMPETENT //how difficult it's to use this item in general.
var/skill_difficulty = THRESHOLD_UNTRAINED //how difficult it's to use this item in general.
var/skill_gain = DEF_SKILL_GAIN //base skill value gain from using this item.
/obj/item/Initialize()
@@ -805,7 +805,7 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
if(delay)
if(user.mind && used_skills)
delay = user.mind.item_action_skills_mod(src, delay, skill_difficulty, SKILL_USE_TOOL, NONE, FALSE)
delay = user.mind.item_action_skills_mod(src, delay, skill_difficulty, SKILL_USE_TOOL, null, FALSE)
// Create a callback with checks that would be called every tick by do_after.
var/datum/callback/tool_check = CALLBACK(src, .proc/tool_check_callback, user, amount, extra_checks)
@@ -831,11 +831,13 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
if(delay >= MIN_TOOL_SOUND_DELAY)
play_tool_sound(target, volume)
if(user.mind && used_skills && skill_gain_mult)
var/gain = skill_gain + delay/SKILL_GAIN_DELAY_DIVISOR
for(var/skill in used_skills)
if(!(used_skills[skill] & SKILL_TRAINING_TOOL))
if(!(SKILL_TRAINING_TOOL in used_skills[skill]))
continue
user.mind.auto_gain_experience(skill, skill_gain*skill_gain_mult, GET_STANDARD_LVL(max_level))
user.mind.auto_gain_experience(skill, gain*skill_gain_mult, GET_STANDARD_LVL(max_level))
return TRUE
+1 -1
View File
@@ -143,7 +143,7 @@ RLD
//if user can't be seen from A (only checks surroundings' opaqueness) and can't see A.
//jarring, but it should stop people from targetting atoms they can't see...
//excluding darkness, to allow RLD to be used to light pitch black dark areas.
if(!((user in view(view_range, A)) || (user in get_actual_viewers(view_range, A))))
if(!((user in view(view_range, A)) || (user in fov_viewers(view_range, A))))
to_chat(user, "<span class='warning'>You focus, pointing \the [src] at whatever outside your field of vision in that direction... to no avail.</span>")
return FALSE
return TRUE
+12 -8
View File
@@ -58,18 +58,22 @@
/obj/item/wallframe/proc/after_attach(var/obj/O)
transfer_fingerprints_to(O)
/obj/item/wallframe/attackby(obj/item/W, mob/user, params)
..()
if(istype(W, /obj/item/screwdriver))
// For camera-building borgs
var/turf/T = get_step(get_turf(user), user.dir)
if(iswallturf(T))
T.attackby(src, user, params)
/obj/item/wallframe/screwdriver_act(mob/user, obj/item/I)
. = ..()
if(.)
return
// For camera-building borgs
var/turf/T = get_step(get_turf(user), user.dir)
if(iswallturf(T))
T.attackby(src, user)
/obj/item/wallframe/wrench_act(mob/user, obj/item/I)
if(!custom_materials)
return
var/metal_amt = round(custom_materials[SSmaterials.GetMaterialRef(/datum/material/iron)]/MINERAL_MATERIAL_AMOUNT)
var/glass_amt = round(custom_materials[SSmaterials.GetMaterialRef(/datum/material/glass)]/MINERAL_MATERIAL_AMOUNT)
if(istype(W, /obj/item/wrench) && (metal_amt || glass_amt))
if(metal_amt || glass_amt)
to_chat(user, "<span class='notice'>You dismantle [src].</span>")
if(metal_amt)
new /obj/item/stack/sheet/metal(get_turf(src), metal_amt)
+19 -8
View File
@@ -91,6 +91,11 @@
refill()
/obj/item/toy/crayon/examine(mob/user)
. = ..()
if(can_change_colour)
. += "<span class='notice'>Ctrl-click [src] while it's on your person to quickly recolour it.</span>"
/obj/item/toy/crayon/proc/refill()
if(charges == -1)
charges_left = 100
@@ -160,6 +165,12 @@
update_icon()
return TRUE
/obj/item/toy/crayon/CtrlClick(mob/user)
if(can_change_colour && !isturf(loc) && user.canUseTopic(src, BE_CLOSE, ismonkey(user)))
select_colour(user)
else
return ..()
/obj/item/toy/crayon/proc/staticDrawables()
. = list()
@@ -237,14 +248,7 @@
else
paint_mode = PAINT_NORMAL
if("select_colour")
if(can_change_colour)
var/chosen_colour = input(usr,"","Choose Color",paint_color) as color|null
if (!isnull(chosen_colour))
paint_color = chosen_colour
. = TRUE
else
. = FALSE
. = can_change_colour && select_colour(usr)
if("enter_text")
var/txt = stripped_input(usr,"Choose what to write.",
"Scribbles",default = text_buffer)
@@ -254,6 +258,13 @@
drawtype = "a"
update_icon()
/obj/item/toy/crayon/proc/select_colour(mob/user)
var/chosen_colour = input(user, "", "Choose Color", paint_color) as color|null
if (!isnull(chosen_colour) && user.canUseTopic(src, BE_CLOSE, ismonkey(user)))
paint_color = chosen_colour
return TRUE
return FALSE
/obj/item/toy/crayon/proc/crayon_text_strip(text)
var/static/regex/crayon_r = new /regex(@"[^\w!?,.=%#&+\/\-]")
return replacetext(lowertext(text), crayon_r, "")
+1 -1
View File
@@ -433,7 +433,7 @@
H.visible_message("<span class='danger'>The defibrillator safely discharges the excessive charge into the floor!</span>")
return
var/mob/living/M = H.pulledby
if(M.electrocute_act(30, src))
if(M.electrocute_act(30, H))
M.visible_message("<span class='danger'>[M] is electrocuted by [M.p_their()] contact with [H]!</span>")
M.emote("scream")
@@ -135,7 +135,7 @@
outmsg = "<span class='warning'>You miss the lens of [C] with [src]!</span>"
//catpeople
var/list/viewers = get_actual_viewers(1,targloc)
var/list/viewers = fov_viewers(1,targloc)
for(var/mob/living/carbon/human/H in viewers)
if(!iscatperson(H) || H.incapacitated() || H.eye_blind )
continue
@@ -66,7 +66,7 @@
if(ismob(loc))
attack_self(loc)
else
for(var/mob/M in get_actual_viewers(1, src))
for(var/mob/M in fov_viewers(1, src))
if(M.client)
attack_self(M)
add_fingerprint(usr)
+3 -3
View File
@@ -197,10 +197,10 @@
if(obj_integrity >= max_integrity)
to_chat(user, "<span class='warning'>[src] is already in perfect condition.</span>")
else
var/obj/item/stack/sheet/mineral/titanium/T = W
T.use(1)
var/obj/item/stack/S = W
S.use(1)
obj_integrity = max_integrity
to_chat(user, "<span class='notice'>You repair [src] with [T].</span>")
to_chat(user, "<span class='notice'>You repair [src] with [S].</span>")
else
return ..()
@@ -5,7 +5,6 @@
* Wood
* Bamboo
* Cloth
* Silk
* Durathread
* Cardboard
* Runed Metal (cult)
@@ -268,6 +267,7 @@ GLOBAL_LIST_INIT(wood_recipes, list ( \
new/datum/stack_recipe("apiary", /obj/structure/beebox, 40, time = 50),\
null, \
new/datum/stack_recipe("picture frame", /obj/item/wallframe/picture, 1, time = 10),\
new/datum/stack_recipe("painting frame", /obj/item/wallframe/painting, 1, time = 10),\
new/datum/stack_recipe("mortar", /obj/item/reagent_containers/glass/mortar, 3), \
new/datum/stack_recipe("honey frame", /obj/item/honey_frame, 5, time = 10),\
))
@@ -388,6 +388,9 @@ GLOBAL_LIST_INIT(cloth_recipes, list ( \
null, \
new/datum/stack_recipe("blindfold", /obj/item/clothing/glasses/sunglasses/blindfold, 2), \
null, \
new/datum/stack_recipe("19x19 canvas", /obj/item/canvas/nineteenXnineteen, 3), \
new/datum/stack_recipe("23x19 canvas", /obj/item/canvas/twentythreeXnineteen, 4), \
new/datum/stack_recipe("23x23 canvas", /obj/item/canvas/twentythreeXtwentythree, 5), \
))
/obj/item/stack/sheet/cloth
@@ -401,7 +404,6 @@ GLOBAL_LIST_INIT(cloth_recipes, list ( \
throwforce = 0
pull_effort = 90
is_fabric = TRUE
loom_result = /obj/item/stack/sheet/silk
merge_type = /obj/item/stack/sheet/cloth
/obj/item/stack/sheet/cloth/get_main_recipes()
@@ -414,30 +416,6 @@ GLOBAL_LIST_INIT(cloth_recipes, list ( \
/obj/item/stack/sheet/cloth/thirty
amount = 30
/*
* Silk
*/
GLOBAL_LIST_INIT(silk_recipes, list ( \
new/datum/stack_recipe("white jumpsuit", /obj/item/clothing/under/color/white, 4, time = 40), \
new/datum/stack_recipe("white gloves", /obj/item/clothing/gloves/color/white, 2, time = 40), \
null, \
new/datum/stack_recipe("silk string", /obj/item/weaponcrafting/silkstring, 1, time = 40), \
))
/obj/item/stack/sheet/silk
name = "silk"
desc = "A long, soft material. Made out of refined cotton, instead of relying on the habits of spiders or silkworms."
singular_name = "silk sheet"
icon_state = "sheet-silk"
item_state = "sheet-cloth"
novariants = TRUE
merge_type = /obj/item/stack/sheet/silk
/obj/item/stack/sheet/silk/get_main_recipes()
. = ..()
. += GLOB.silk_recipes
/*
* Durathread
*/
@@ -446,6 +424,7 @@ GLOBAL_LIST_INIT(durathread_recipes, list ( \
new/datum/stack_recipe("durathread beret", /obj/item/clothing/head/beret/durathread, 2, time = 40), \
new/datum/stack_recipe("durathread beanie", /obj/item/clothing/head/beanie/durathread, 2, time = 40), \
new/datum/stack_recipe("durathread bandana", /obj/item/clothing/mask/bandana/durathread, 1, time = 25), \
new/datum/stack_recipe("durathread string", /obj/item/weaponcrafting/durathread_string, 1, time = 40) \
))
/obj/item/stack/sheet/durathread
+1 -1
View File
@@ -61,7 +61,7 @@
switch(contents.len)
if(0)
icon_state = "[initial(icon_state)]"
if(0 to 11)
if(1 to 11)
icon_state = "[initial(icon_state)]1"
if(11 to 20)
icon_state = "[initial(icon_state)]2"
@@ -210,6 +210,7 @@
power = 8
force = 10
precision = 1
total_mass = 0.2
cooling_power = 5
w_class = WEIGHT_CLASS_HUGE
item_flags = ABSTRACT // don't put in storage
+1 -1
View File
@@ -104,7 +104,7 @@
if (ismob(src.loc))
attack_self(src.loc)
else
for(var/mob/M in get_actual_viewers(1, src))
for(var/mob/M in fov_viewers(1, src))
if (M.client)
src.attack_self(M)
return
+14
View File
@@ -478,6 +478,20 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
throw_range = 2
attack_verb = list("busted")
/obj/item/statuebust/attack_self(mob/living/user)
add_fingerprint(user)
user.examinate(src)
/obj/item/statuebust/examine(mob/living/user)
. = ..()
if(.)
return
if (!isliving(user))
return
user.visible_message("[user] stops to admire [src].", \
"<span class='notice'>You take in [src], admiring its fine craftsmanship.</span>")
SEND_SIGNAL(user, COMSIG_ADD_MOOD_EVENT, "artgood", /datum/mood_event/artgood)
/obj/item/tailclub
name = "tail club"
desc = "For the beating to death of lizards with their own tails."
+7 -6
View File
@@ -112,7 +112,7 @@
/obj/attack_animal(mob/living/simple_animal/M)
if(!M.melee_damage_upper && !M.obj_damage)
M.emote("custom", message = "[M.friendly] [src].")
M.emote("custom", message = "[M.friendly_verb_continuous] [src].")
return 0
else
var/play_soundeffect = 1
@@ -232,15 +232,16 @@ GLOBAL_DATUM_INIT(acid_overlay, /mutable_appearance, mutable_appearance('icons/e
cut_overlay(GLOB.fire_overlay, TRUE)
SSfire_burning.processing -= src
/obj/proc/tesla_act(power, tesla_flags, shocked_targets)
/obj/zap_act(power, zap_flags, shocked_targets)
if(QDELETED(src))
return 0
obj_flags |= BEING_SHOCKED
var/power_bounced = power / 2
tesla_zap(src, 3, power_bounced, tesla_flags, shocked_targets)
addtimer(CALLBACK(src, .proc/reset_shocked), 10)
return power / 2
//The surgeon general warns that being buckled to certain objects receiving powerful shocks is greatly hazardous to your health
//Only tesla coils and grounding rods currently call this because mobs are already targeted over all other objects, but this might be useful for more things later.
/obj/proc/tesla_buckle_check(var/strength)
//Only tesla coils, vehicles, and grounding rods currently call this because mobs are already targeted over all other objects, but this might be useful for more things later.
/obj/proc/zap_buckle_check(var/strength)
if(has_buckled_mobs())
for(var/m in buckled_mobs)
var/mob/living/buckled_mob = m
+2 -2
View File
@@ -123,7 +123,7 @@
/obj/proc/updateUsrDialog()
if((obj_flags & IN_USE) && !(obj_flags & USES_TGUI))
var/is_in_use = FALSE
var/list/nearby = get_actual_viewers(1, src)
var/list/nearby = fov_viewers(1, src)
for(var/mob/M in nearby)
if ((M.client && M.machine == src))
is_in_use = TRUE
@@ -152,7 +152,7 @@
if(obj_flags & IN_USE)
var/is_in_use = FALSE
if(update_viewers)
for(var/mob/M in get_actual_viewers(1, src))
for(var/mob/M in fov_viewers(1, src))
if ((M.client && M.machine == src))
is_in_use = TRUE
src.interact(M)
+343 -76
View File
@@ -35,101 +35,368 @@
else
painting = null
//////////////
// CANVASES //
//////////////
#define AMT_OF_CANVASES 4 //Keep this up to date or shit will break.
//To safe memory on making /icons we cache the blanks..
GLOBAL_LIST_INIT(globalBlankCanvases, new(AMT_OF_CANVASES))
/obj/item/canvas
name = "canvas"
desc = "Draw out your soul on this canvas!"
icon = 'icons/obj/artstuff.dmi'
icon_state = "11x11"
resistance_flags = FLAMMABLE
var/whichGlobalBackup = 1 //List index
var/width = 11
var/height = 11
var/list/grid
var/canvas_color = "#ffffff" //empty canvas color
var/ui_x = 400
var/ui_y = 400
var/used = FALSE
var/painting_name //Painting name, this is set after framing.
var/finalized = FALSE //Blocks edits
var/author_ckey
var/icon_generated = FALSE
var/icon/generated_icon
/obj/item/canvas/nineteenXnineteen
icon_state = "19x19"
whichGlobalBackup = 2
// Painting overlay offset when framed
var/framed_offset_x = 11
var/framed_offset_y = 10
/obj/item/canvas/twentythreeXnineteen
icon_state = "23x19"
whichGlobalBackup = 3
pixel_x = 10
pixel_y = 9
/obj/item/canvas/twentythreeXtwentythree
icon_state = "23x23"
whichGlobalBackup = 4
//HEY YOU
//ARE YOU READING THE CODE FOR CANVASES?
//ARE YOU AWARE THEY CRASH HALF THE SERVER WHEN SOMEONE DRAWS ON THEM...
//...AND NOBODY CAN FIGURE OUT WHY?
//THEN GO ON BRAVE TRAVELER
//TRY TO FIX THEM AND REMOVE THIS CODE
/obj/item/canvas/Initialize()
..()
return INITIALIZE_HINT_QDEL //Delete on creation
. = ..()
reset_grid()
//Find the right size blank canvas
/obj/item/canvas/proc/getGlobalBackup()
. = null
if(GLOB.globalBlankCanvases[whichGlobalBackup])
. = GLOB.globalBlankCanvases[whichGlobalBackup]
else
var/icon/I = icon(initial(icon),initial(icon_state))
GLOB.globalBlankCanvases[whichGlobalBackup] = I
. = I
/obj/item/canvas/proc/reset_grid()
grid = new/list(width,height)
for(var/x in 1 to width)
for(var/y in 1 to height)
grid[x][y] = canvas_color
/obj/item/canvas/attack_self(mob/user)
. = ..()
ui_interact(user)
/obj/item/canvas/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
//One pixel increments
/obj/item/canvas/attackby(obj/item/I, mob/user, params)
//Click info
var/list/click_params = params2list(params)
var/pixX = text2num(click_params["icon-x"])
var/pixY = text2num(click_params["icon-y"])
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "canvas", name, ui_x, ui_y, master_ui, state)
ui.set_autoupdate(FALSE)
ui.open()
//Should always be true, otherwise you didn't click the object, but let's check because SS13~
if(!click_params || !click_params["icon-x"] || !click_params["icon-y"])
return
//Cleaning one pixel with a soap or rag
if(istype(I, /obj/item/soap) || istype(I, /obj/item/reagent_containers/rag))
//Pixel info created only when needed
var/icon/masterpiece = icon(icon,icon_state)
var/thePix = masterpiece.GetPixel(pixX,pixY)
var/icon/Ico = getGlobalBackup()
if(!Ico)
qdel(masterpiece)
return
var/theOriginalPix = Ico.GetPixel(pixX,pixY)
if(thePix != theOriginalPix) //colour changed
DrawPixelOn(theOriginalPix,pixX,pixY)
qdel(masterpiece)
//Drawing one pixel with a crayon
else if(istype(I, /obj/item/toy/crayon))
var/obj/item/toy/crayon/C = I
DrawPixelOn(C.paint_color, pixX, pixY)
/obj/item/canvas/attackby(obj/item/I, mob/living/user, params)
if(user.a_intent == INTENT_HELP)
ui_interact(user)
else
return ..()
/obj/item/canvas/ui_data(mob/user)
. = ..()
.["grid"] = grid
.["name"] = painting_name
.["finalized"] = finalized
//Clean the whole canvas
/obj/item/canvas/attack_self(mob/user)
if(!user)
/obj/item/canvas/examine(mob/user)
. = ..()
ui_interact(user)
/obj/item/canvas/ui_act(action, params)
. = ..()
if(. || finalized)
return
var/icon/blank = getGlobalBackup()
if(blank)
//it's basically a giant etch-a-sketch
icon = blank
user.visible_message("<span class='notice'>[user] cleans the canvas.</span>","<span class='notice'>You clean the canvas.</span>")
var/mob/user = usr
switch(action)
if("paint")
var/obj/item/I = user.get_active_held_item()
var/color = get_paint_tool_color(I)
if(!color)
return FALSE
var/x = text2num(params["x"])
var/y = text2num(params["y"])
grid[x][y] = color
used = TRUE
update_icon()
. = TRUE
if("finalize")
. = TRUE
if(!finalized)
finalize(user)
/obj/item/canvas/proc/finalize(mob/user)
finalized = TRUE
author_ckey = user.ckey
generate_proper_overlay()
try_rename(user)
/obj/item/canvas/update_overlays()
. = ..()
if(!icon_generated)
if(used)
var/mutable_appearance/detail = mutable_appearance(icon,"[icon_state]wip")
detail.pixel_x = 1
detail.pixel_y = 1
. += detail
else
var/mutable_appearance/detail = mutable_appearance(generated_icon)
detail.pixel_x = 1
detail.pixel_y = 1
. += detail
/obj/item/canvas/proc/generate_proper_overlay()
if(icon_generated)
return
var/png_filename = "data/paintings/temp_painting.png"
var/result = rustg_dmi_create_png(png_filename,"[width]","[height]",get_data_string())
if(result)
CRASH("Error generating painting png : [result]")
generated_icon = new(png_filename)
icon_generated = TRUE
update_icon()
/obj/item/canvas/proc/get_data_string()
var/list/data = list()
for(var/y in 1 to height)
for(var/x in 1 to width)
data += grid[x][y]
return data.Join("")
//Todo make this element ?
/obj/item/canvas/proc/get_paint_tool_color(obj/item/I)
if(!I)
return
if(istype(I, /obj/item/toy/crayon))
var/obj/item/toy/crayon/C = I
return C.paint_color
else if(istype(I, /obj/item/pen))
var/obj/item/pen/P = I
switch(P.colour)
if("black")
return "#000000"
if("blue")
return "#0000ff"
if("red")
return "#ff0000"
return P.colour
else if(istype(I, /obj/item/soap) || istype(I, /obj/item/reagent_containers/rag))
return canvas_color
/obj/item/canvas/proc/try_rename(mob/user)
var/new_name = stripped_input(user,"What do you want to name the painting?")
if(!painting_name && new_name && user.canUseTopic(src,BE_CLOSE))
painting_name = new_name
SStgui.update_uis(src)
/obj/item/canvas/nineteenXnineteen
icon_state = "19x19"
width = 19
height = 19
ui_x = 600
ui_y = 600
pixel_x = 6
pixel_y = 9
framed_offset_x = 8
framed_offset_y = 9
/obj/item/canvas/twentythreeXnineteen
icon_state = "23x19"
width = 23
height = 19
ui_x = 800
ui_y = 600
pixel_x = 4
pixel_y = 10
framed_offset_x = 6
framed_offset_y = 8
/obj/item/canvas/twentythreeXtwentythree
icon_state = "23x23"
width = 23
height = 23
ui_x = 800
ui_y = 800
pixel_x = 5
pixel_y = 9
framed_offset_x = 5
framed_offset_y = 6
/obj/item/wallframe/painting
name = "painting frame"
desc = "The perfect showcase for your favorite deathtrap memories."
icon = 'icons/obj/decals.dmi'
custom_materials = null
flags_1 = 0
icon_state = "frame-empty"
result_path = /obj/structure/sign/painting
/obj/structure/sign/painting
name = "Painting"
desc = "Art or \"Art\"? You decide."
icon = 'icons/obj/decals.dmi'
icon_state = "frame-empty"
buildable_sign = FALSE
var/obj/item/canvas/C
var/persistence_id
/obj/structure/sign/painting/Initialize(mapload, dir, building)
. = ..()
SSpersistence.painting_frames += src
AddComponent(/datum/component/art, 20)
if(dir)
setDir(dir)
if(building)
pixel_x = (dir & 3)? 0 : (dir == 4 ? -30 : 30)
pixel_y = (dir & 3)? (dir ==1 ? -30 : 30) : 0
/obj/structure/sign/painting/Destroy()
. = ..()
SSpersistence.painting_frames -= src
/obj/structure/sign/painting/attackby(obj/item/I, mob/user, params)
if(!C && istype(I, /obj/item/canvas))
frame_canvas(user,I)
else if(C && !C.painting_name && istype(I,/obj/item/pen))
try_rename(user)
else
return ..()
/obj/structure/sign/painting/examine(mob/user)
. = ..()
if(C)
C.ui_interact(user,state = GLOB.physical_obscured_state)
/obj/structure/sign/painting/wirecutter_act(mob/living/user, obj/item/I)
. = ..()
if(C)
C.forceMove(drop_location())
C = null
to_chat(user, "<span class='notice'>You remove the painting from the frame.</span>")
update_icon()
return TRUE
/obj/structure/sign/painting/proc/frame_canvas(mob/user,obj/item/canvas/new_canvas)
if(user.transferItemToLoc(new_canvas,src))
C = new_canvas
if(!C.finalized)
C.finalize(user)
to_chat(user,"<span class='notice'>You frame [C].</span>")
update_icon()
/obj/structure/sign/painting/proc/try_rename(mob/user)
if(!C.painting_name)
C.try_rename(user)
/obj/structure/sign/painting/update_icon_state()
. = ..()
if(C && C.generated_icon)
icon_state = null
else
icon_state = "frame-empty"
#undef AMT_OF_CANVASES
/obj/structure/sign/painting/update_overlays()
. = ..()
if(C && C.generated_icon)
var/mutable_appearance/MA = mutable_appearance(C.generated_icon)
MA.pixel_x = C.framed_offset_x
MA.pixel_y = C.framed_offset_y
. += MA
var/mutable_appearance/frame = mutable_appearance(C.icon,"[C.icon_state]frame")
frame.pixel_x = C.framed_offset_x - 1
frame.pixel_y = C.framed_offset_y - 1
. += frame
/obj/structure/sign/painting/proc/load_persistent()
if(!persistence_id)
return
if(!SSpersistence.paintings || !SSpersistence.paintings[persistence_id] || !length(SSpersistence.paintings[persistence_id]))
return
var/list/chosen = pick(SSpersistence.paintings[persistence_id])
var/title = chosen["title"]
var/author = chosen["ckey"]
var/png = "data/paintings/[persistence_id]/[chosen["md5"]].png"
if(!fexists(png))
stack_trace("Persistent painting [chosen["md5"]].png was not found in [persistence_id] directory.")
return
var/icon/I = new(png)
var/obj/item/canvas/new_canvas
var/w = I.Width()
var/h = I.Height()
for(var/T in typesof(/obj/item/canvas))
new_canvas = T
if(initial(new_canvas.width) == w && initial(new_canvas.height) == h)
new_canvas = new T(src)
break
new_canvas.fill_grid_from_icon(I)
new_canvas.generated_icon = I
new_canvas.icon_generated = TRUE
new_canvas.finalized = TRUE
new_canvas.painting_name = title
new_canvas.author_ckey = author
C = new_canvas
update_icon()
/obj/structure/sign/painting/proc/save_persistent()
if(!persistence_id || !C)
return
if(sanitize_filename(persistence_id) != persistence_id)
stack_trace("Invalid persistence_id - [persistence_id]")
return
var/data = C.get_data_string()
var/md5 = md5(data)
var/list/current = SSpersistence.paintings[persistence_id]
if(!current)
current = list()
for(var/list/entry in current)
if(entry["md5"] == md5)
return
var/png_directory = "data/paintings/[persistence_id]/"
var/png_path = png_directory + "[md5].png"
var/result = rustg_dmi_create_png(png_path,"[C.width]","[C.height]",data)
if(result)
CRASH("Error saving persistent painting: [result]")
current += list(list("title" = C.painting_name , "md5" = md5, "ckey" = C.author_ckey))
SSpersistence.paintings[persistence_id] = current
/obj/item/canvas/proc/fill_grid_from_icon(icon/I)
var/h = I.Height() + 1
for(var/x in 1 to width)
for(var/y in 1 to height)
grid[x][y] = I.GetPixel(x,h-y)
//Presets for art gallery mapping, for paintings to be shared across stations
/obj/structure/sign/painting/library
persistence_id = "library"
/obj/structure/sign/painting/library_secure
persistence_id = "library_secure"
/obj/structure/sign/painting/library_private // keep your smut away from prying eyes, or non-librarians at least
persistence_id = "library_private"
/obj/structure/sign/painting/vv_get_dropdown()
. = ..()
VV_DROPDOWN_OPTION(VV_HK_REMOVE_PAINTING, "Remove Persistent Painting")
/obj/structure/sign/painting/vv_do_topic(list/href_list)
. = ..()
if(href_list[VV_HK_REMOVE_PAINTING])
if(!check_rights(NONE))
return
var/mob/user = usr
if(!persistence_id || !C)
to_chat(user,"<span class='warning'>This is not a persistent painting.</span>")
return
var/md5 = md5(C.get_data_string())
var/author = C.author_ckey
var/list/current = SSpersistence.paintings[persistence_id]
if(current)
for(var/list/entry in current)
if(entry["md5"] == md5)
current -= entry
var/png = "data/paintings/[persistence_id]/[md5].png"
fdel(png)
for(var/obj/structure/sign/painting/P in SSpersistence.painting_frames)
if(P.C && md5(P.C.get_data_string()) == md5)
QDEL_NULL(P.C)
log_admin("[key_name(user)] has deleted a persistent painting made by [author].")
message_admins("<span class='notice'>[key_name_admin(user)] has deleted persistent painting made by [author].</span>")
@@ -108,7 +108,9 @@
if(!istype(poordude))
return TRUE
user.visible_message("<span class='notice'>[user] pulls [src] out from under [poordude].</span>", "<span class='notice'>You pull [src] out from under [poordude].</span>")
var/C = new item_chair(loc)
var/obj/item/chair/C = new item_chair(loc)
C.set_custom_materials(custom_materials)
TransferComponents(C)
user.put_in_hands(C)
poordude.DefaultCombatKnockdown(20)//rip in peace
user.adjustStaminaLoss(5)
@@ -43,7 +43,7 @@
Snake = L
break
if(Snake)
alerted = get_actual_viewers(world.view,src)
alerted = fov_viewers(world.view,src)
..()
if(LAZYLEN(alerted))
egged = world.time + SNAKE_SPAM_TICKS
+1 -1
View File
@@ -267,7 +267,7 @@
var/obj/structure/cable/C = T.get_cable_node()
if(C)
playsound(src, 'sound/magic/lightningshock.ogg', 100, 1, extrarange = 5)
tesla_zap(src, 3, C.newavail() * 0.01, TESLA_MOB_DAMAGE | TESLA_OBJ_DAMAGE | TESLA_MOB_STUN | TESLA_ALLOW_DUPLICATES) //Zap for 1/100 of the amount of power. At a million watts in the grid, it will be as powerful as a tesla revolver shot.
tesla_zap(src, 3, C.newavail() * 0.01, ZAP_MOB_DAMAGE | ZAP_OBJ_DAMAGE | ZAP_MOB_STUN | ZAP_ALLOW_DUPLICATES) //Zap for 1/100 of the amount of power. At a million watts in the grid, it will be as powerful as a tesla revolver shot.
C.add_delayedload(C.newavail() * 0.0375) // you can gain up to 3.5 via the 4x upgrades power is halved by the pole so thats 2x then 1X then .5X for 3.5x the 3 bounces shock.
return ..()

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