diff --git a/.github/workflows/compile_changelogs.yml b/.github/workflows/compile_changelogs.yml index f8098df66e..4fd396f133 100644 --- a/.github/workflows/compile_changelogs.yml +++ b/.github/workflows/compile_changelogs.yml @@ -9,32 +9,47 @@ jobs: name: "Compile changelogs" runs-on: ubuntu-latest steps: + - name: "Check for CHANGELOG_ENABLER secret and pass true to output if it exists to be checked by later steps" + id: value_holder + env: + CHANGELOG_ENABLER: ${{ secrets.CHANGELOG_ENABLER }} + run: | + unset SECRET_EXISTS + if [-n $CHANGELOG_ENABLER]; then SECRET_EXISTS='true' ; fi + echo ::set-output name=CL_ENABLED::${SECRET_EXISTS} - name: "Setup python" + if: steps.value_holder.outputs.CL_ENABLED uses: actions/setup-python@v1 with: python-version: '3.x' - name: "Install deps" + if: steps.value_holder.outputs.CL_ENABLED run: | python -m pip install --upgrade pip python -m pip install pyyaml sudo apt-get install dos2unix - name: "Checkout" + if: steps.value_holder.outputs.CL_ENABLED uses: actions/checkout@v1 with: fetch-depth: 25 - name: "Compile" + if: steps.value_holder.outputs.CL_ENABLED run: | python tools/ss13_genchangelog.py html/changelog.html html/changelogs - name: "Convert Lineendings" + if: steps.value_holder.outputs.CL_ENABLED run: | unix2dos html/changelogs/.all_changelog.yml - name: Commit + if: steps.value_holder.outputs.CL_ENABLED run: | git config --local user.email "action@github.com" git config --local user.name "Changelogs" git pull origin master git commit -m "Automatic changelog compile [ci skip]" -a || true - name: "Push" + if: steps.value_holder.outputs.CL_ENABLED uses: ad-m/github-push-action@master with: github_token: ${{ secrets.GITHUB_TOKEN }} diff --git a/code/__DEFINES/dcs/signals.dm b/code/__DEFINES/dcs/signals.dm index 02e3fe6f3d..cf669b905a 100644 --- a/code/__DEFINES/dcs/signals.dm +++ b/code/__DEFINES/dcs/signals.dm @@ -5,9 +5,21 @@ // global signals // These are signals which can be listened to by any component on any parent // start global signals with "!", this used to be necessary but now it's just a formatting choice -#define COMSIG_GLOB_NEW_Z "!new_z" //from base of datum/controller/subsystem/mapping/proc/add_new_zlevel(): (list/args) -#define COMSIG_GLOB_VAR_EDIT "!var_edit" //called after a successful var edit somewhere in the world: (list/args) -#define COMSIG_GLOB_LIVING_SAY_SPECIAL "!say_special" //global living say plug - use sparingly: (mob/speaker , message) +/// from base of datum/controller/subsystem/mapping/proc/add_new_zlevel(): (list/args) +#define COMSIG_GLOB_NEW_Z "!new_z" +/// called after a successful var edit somewhere in the world: (list/args) +#define COMSIG_GLOB_VAR_EDIT "!var_edit" +/// called after an explosion happened : (epicenter, devastation_range, heavy_impact_range, light_impact_range, took, orig_dev_range, orig_heavy_range, orig_light_range) +#define COMSIG_GLOB_EXPLOSION "!explosion" +/// mob was created somewhere : (mob) +#define COMSIG_GLOB_MOB_CREATED "!mob_created" +/// mob died somewhere : (mob , gibbed) +#define COMSIG_GLOB_MOB_DEATH "!mob_death" +/// global living say plug - use sparingly: (mob/speaker , message) +#define COMSIG_GLOB_LIVING_SAY_SPECIAL "!say_special" +/// called by datum/cinematic/play() : (datum/cinematic/new_cinematic) +#define COMSIG_GLOB_PLAY_CINEMATIC "!play_cinematic" + #define COMPONENT_GLOB_BLOCK_CINEMATIC 1 // signals from globally accessible objects /// from SSsun when the sun changes position : (azimuth) diff --git a/code/controllers/admin.dm b/code/controllers/admin.dm index 28803f0979..3782d8be94 100644 --- a/code/controllers/admin.dm +++ b/code/controllers/admin.dm @@ -3,7 +3,9 @@ name = "Initializing..." var/target -/obj/effect/statclick/New(loc, text, target) //Don't port this to Initialize it's too critical +INITIALIZE_IMMEDIATE(/obj/effect/statclick) //it's new, but rebranded. + +/obj/effect/statclick/Initialize(mapload, text, target) //Don't port this to Initialize it's too critical . = ..() name = text src.target = target diff --git a/code/controllers/failsafe.dm b/code/controllers/failsafe.dm index 148822cdd1..22f047a297 100644 --- a/code/controllers/failsafe.dm +++ b/code/controllers/failsafe.dm @@ -1,4 +1,4 @@ - /** +/** * Failsafe * * Pretty much pokes the MC to make sure it's still alive. @@ -31,7 +31,7 @@ GLOBAL_REAL(Failsafe, /datum/controller/failsafe) Initialize() /datum/controller/failsafe/Initialize() - set waitfor = 0 + set waitfor = FALSE Failsafe.Loop() if(!QDELETED(src)) qdel(src) //when Loop() returns, we delete ourselves and let the mc recreate us @@ -97,4 +97,4 @@ GLOBAL_REAL(Failsafe, /datum/controller/failsafe) /datum/controller/failsafe/stat_entry(msg) msg = "Defcon: [defcon_pretty()] (Interval: [Failsafe.processing_interval] | Iteration: [Failsafe.master_iteration])" - return msg + return msg \ No newline at end of file diff --git a/code/controllers/globals.dm b/code/controllers/globals.dm index 6b5fb294ea..21f022acfd 100644 --- a/code/controllers/globals.dm +++ b/code/controllers/globals.dm @@ -20,8 +20,9 @@ GLOBAL_REAL(GLOB, /datum/controller/global_vars) Initialize() -/datum/controller/global_vars/Destroy() - //fuck off kevinz +/datum/controller/global_vars/Destroy(force) + // This is done to prevent an exploit where admins can get around protected vars + SHOULD_CALL_PARENT(FALSE) return QDEL_HINT_IWILLGC /datum/controller/global_vars/stat_entry(msg) diff --git a/code/controllers/subsystem.dm b/code/controllers/subsystem.dm index bb8ce951f5..e49da32557 100644 --- a/code/controllers/subsystem.dm +++ b/code/controllers/subsystem.dm @@ -97,9 +97,9 @@ return //This is used so the mc knows when the subsystem sleeps. do not override. -/datum/controller/subsystem/proc/ignite(resumed = 0) +/datum/controller/subsystem/proc/ignite(resumed = FALSE) SHOULD_NOT_OVERRIDE(TRUE) - set waitfor = 0 + set waitfor = FALSE . = SS_SLEEPING fire(resumed) . = state diff --git a/code/datums/browser.dm b/code/datums/browser.dm index dbe60817bd..2057cbb21a 100644 --- a/code/datums/browser.dm +++ b/code/datums/browser.dm @@ -451,7 +451,7 @@ // otherwise, just reset the client mob's machine var. // /client/verb/windowclose(atomref as text) - set hidden = 1 // hide this verb from the user's panel + set hidden = TRUE // hide this verb from the user's panel set name = ".windowclose" // no autocomplete on cmd line if(atomref!="null") // if passed a real atomref diff --git a/code/datums/cinematic.dm b/code/datums/cinematic.dm index df2c15e9c8..7b3081cb33 100644 --- a/code/datums/cinematic.dm +++ b/code/datums/cinematic.dm @@ -1,5 +1,3 @@ -GLOBAL_LIST_EMPTY(cinematics) - // Use to play cinematics. // Watcher can be world,mob, or a list of mobs // Blocks until sequence is done. @@ -18,6 +16,7 @@ GLOBAL_LIST_EMPTY(cinematics) playing.is_global = TRUE watcher = GLOB.mob_list playing.play(watcher) + qdel(playing) /obj/screen/cinematic icon = 'icons/effects/station_explosion.dmi' @@ -25,12 +24,13 @@ GLOBAL_LIST_EMPTY(cinematics) plane = SPLASHSCREEN_PLANE layer = SPLASHSCREEN_LAYER mouse_opacity = MOUSE_OPACITY_TRANSPARENT - screen_loc = "1,1" + screen_loc = "BOTTOM,LEFT+50%" + appearance_flags = APPEARANCE_UI | TILE_BOUND /datum/cinematic var/id = CINEMATIC_DEFAULT var/list/watching = list() //List of clients watching this - var/list/locked = list() //Who had mob_transforming set during the cinematic + var/list/locked = list() //Who had mob_transforming set during the cinematic var/is_global = FALSE //Global cinematics will override mob-specific ones var/obj/screen/cinematic/screen var/datum/callback/special_callback //For special effects synced with animation (explosions after the countdown etc) @@ -38,28 +38,35 @@ GLOBAL_LIST_EMPTY(cinematics) var/stop_ooc = TRUE //Turns off ooc when played globally. /datum/cinematic/New() - GLOB.cinematics += src screen = new(src) /datum/cinematic/Destroy() - GLOB.cinematics -= src + for(var/CC in watching) + if(!CC) + continue + var/client/C = CC + //C.mob.clear_fullscreen("cinematic") + C.screen -= screen + watching = null QDEL_NULL(screen) - for(var/mob/M in locked) - M.mob_transforming = FALSE + QDEL_NULL(special_callback) + for(var/MM in locked) + if(!MM) + continue + var/mob/M = MM + M.mob_transforming = FALSE + locked = null return ..() /datum/cinematic/proc/play(watchers) - //Check if you can actually play it (stop mob cinematics for global ones) and create screen objects - for(var/A in GLOB.cinematics) - var/datum/cinematic/C = A - if(C == src) - continue - if(C.is_global || !is_global) - return //Can't play two global or local cinematics at the same time + //Check if cinematic can actually play (stop mob cinematics for global ones) + if(SEND_GLOBAL_SIGNAL(COMSIG_GLOB_PLAY_CINEMATIC, src) & COMPONENT_GLOB_BLOCK_CINEMATIC) + return - //Close all open windows if global - if(is_global) - SStgui.close_all_uis() + //We are now playing this cinematic + + //Handle what happens when a different cinematic tries to play over us + RegisterSignal(SSdcs, COMSIG_GLOB_PLAY_CINEMATIC, .proc/replacement_cinematic) //Pause OOC var/ooc_toggled = FALSE @@ -67,24 +74,17 @@ GLOBAL_LIST_EMPTY(cinematics) ooc_toggled = TRUE toggle_ooc(FALSE) - - for(var/mob/M in GLOB.mob_list) - if(M in watchers) - M.mob_transforming = TRUE //Should this be done for non-global cinematics or even at all ? - locked += M - //Close watcher ui's - SStgui.close_user_uis(M) - if(M.client) - watching += M.client - M.client.screen += screen - else - if(is_global) - M.mob_transforming = TRUE - locked += M + //Place /obj/screen/cinematic into everyone's screens, prevent them from moving + for(var/MM in watchers) + var/mob/M = MM + show_to(M, M.client) + RegisterSignal(M, COMSIG_MOB_CLIENT_LOGIN, .proc/show_to) + //Close watcher ui's + SStgui.close_user_uis(M) //Actually play it content() - + //Cleanup sleep(cleanup_time) @@ -92,7 +92,17 @@ GLOBAL_LIST_EMPTY(cinematics) if(ooc_toggled) toggle_ooc(TRUE) - qdel(src) +/datum/cinematic/proc/show_to(mob/M, client/C) + //SIGNAL_HANDLER //must not wait. + + if(!M.mob_transforming) + locked += M + M.mob_transforming = TRUE //Should this be done for non-global cinematics or even at all ? + if(!C) + return + watching += C + //M.overlay_fullscreen("cinematic",/obj/screen/fullscreen/cinematic_backdrop) + C.screen += screen //Sound helper /datum/cinematic/proc/cinematic_sound(s) @@ -111,6 +121,13 @@ GLOBAL_LIST_EMPTY(cinematics) /datum/cinematic/proc/content() sleep(50) +/datum/cinematic/proc/replacement_cinematic(datum/source, datum/cinematic/other) + //SIGNAL_HANDLER + + if(!is_global && other.is_global) //Allow it to play if we're local and it's global + return NONE + return COMPONENT_GLOB_BLOCK_CINEMATIC + /datum/cinematic/nuke_win id = CINEMATIC_NUKE_WIN diff --git a/code/datums/datum.dm b/code/datums/datum.dm index 7756cfd906..d11532a883 100644 --- a/code/datums/datum.dm +++ b/code/datums/datum.dm @@ -15,22 +15,32 @@ * If this is non zero then the object has been garbage collected and is awaiting either * a hard del by the GC subsystme, or to be autocollected (if it has no references) */ - var/gc_destroyed //Time when this object was destroyed. + var/gc_destroyed /// Active timers with this datum as the target var/list/active_timers /// Status traits attached to this datum var/list/status_traits - /// Components attached to this datum - /// Lazy associated list in the structure of `type:component/list of components` + + /** + * Components attached to this datum + * + * Lazy associated list in the structure of `type:component/list of components` + */ var/list/datum_components - /// Any datum registered to receive signals from this datum is in this list - /// Lazy associated list in the structure of `signal:registree/list of registrees` - var/list/comp_lookup //it used to be for looking up components which had registered a signal but now anything can register + /** + * Any datum registered to receive signals from this datum is in this list + * + * Lazy associated list in the structure of `signal:registree/list of registrees` + */ + var/list/comp_lookup /// Lazy associated list in the structure of `signals:proctype` that are run when the datum receives that signal var/list/list/datum/callback/signal_procs - /// Is this datum capable of sending signals? - /// Set to true when a signal has been registered + /** + * Is this datum capable of sending signals? + * + * Set to true when a signal has been registered + */ var/signal_enabled = FALSE /// Datum level flags @@ -39,7 +49,12 @@ /// A weak reference to another datum var/datum/weakref/weak_reference - ///Lazy associative list of currently active cooldowns. + /* + * Lazy associative list of currently active cooldowns. + * + * cooldowns [ COOLDOWN_INDEX ] = add_timer() + * add_timer() returns the truthy value of -1 when not stoppable, and else a truthy numeric index + */ var/list/cooldowns #ifdef TESTING @@ -51,23 +66,34 @@ var/list/cached_vars #endif +/** + * Called when a href for this datum is clicked + * + * Sends a [COMSIG_TOPIC] signal + */ +/datum/Topic(href, href_list[]) + ..() + SEND_SIGNAL(src, COMSIG_TOPIC, usr, href_list) + + /** * Default implementation of clean-up code. * * This should be overridden to remove all references pointing to the object being destroyed, if * you do override it, make sure to call the parent and return it's return value by default * - * Return an appropriate QDEL_HINT to modify handling of your deletion; - * in most cases this is QDEL_HINT_QUEUE. + * Return an appropriate [QDEL_HINT][QDEL_HINT_QUEUE] to modify handling of your deletion; + * in most cases this is [QDEL_HINT_QUEUE]. * * The base case is responsible for doing the following * * Erasing timers pointing to this datum * * Erasing compenents on this datum * * Notifying datums listening to signals from this datum that we are going away * - * Returns QDEL_HINT_QUEUE + * Returns [QDEL_HINT_QUEUE] */ /datum/proc/Destroy(force=FALSE, ...) + SHOULD_CALL_PARENT(TRUE) tag = null datum_flags &= ~DF_USE_TAG //In case something tries to REF us weak_reference = null //ensure prompt GCing of weakref. @@ -112,7 +138,7 @@ UnregisterSignal(target, signal_procs[target]) //END: ECS SHIT - SSsounds.free_datum_channels(src) + SSsounds.free_datum_channels(src) //?? (not on tg) return QDEL_HINT_QUEUE @@ -143,15 +169,15 @@ to_chat(target, txt_changed_vars()) #endif -//Return a LIST for serialize_datum to encode! Not the actual json! +///Return a LIST for serialize_datum to encode! Not the actual json! /datum/proc/serialize_list(list/options) CRASH("Attempted to serialize datum [src] of type [type] without serialize_list being implemented!") -//Accepts a LIST from deserialize_datum. Should return src or another datum. +///Accepts a LIST from deserialize_datum. Should return src or another datum. /datum/proc/deserialize_list(json, list/options) CRASH("Attempted to deserialize datum [src] of type [type] without deserialize_list being implemented!") -//Serializes into JSON. Does not encode type. +///Serializes into JSON. Does not encode type. /datum/proc/serialize_json(list/options) . = serialize_list(options) if(!islist(.)) @@ -159,13 +185,14 @@ else . = json_encode(.) -//Deserializes from JSON. Does not parse type. +///Deserializes from JSON. Does not parse type. /datum/proc/deserialize_json(list/input, list/options) var/list/jsonlist = json_decode(input) . = deserialize_list(jsonlist) if(!istype(., /datum)) . = null +///Convert a datum into a json blob /proc/json_serialize_datum(datum/D, list/options) if(!istype(D)) return @@ -174,6 +201,7 @@ jsonlist["DATUM_TYPE"] = D.type return json_encode(jsonlist) +/// Convert a list of json to datum /proc/json_deserialize_datum(list/jsonlist, list/options, target_type, strict_target_type = FALSE) if(!islist(jsonlist)) if(!istext(jsonlist)) diff --git a/code/datums/position_point_vector.dm b/code/datums/position_point_vector.dm index 482e15c57d..b4e483ae2b 100644 --- a/code/datums/position_point_vector.dm +++ b/code/datums/position_point_vector.dm @@ -214,6 +214,7 @@ /datum/point/vector/processed/Destroy() STOP_PROCESSING(SSprojectiles, src) + return ..() /datum/point/vector/processed/proc/start() last_process = world.time diff --git a/code/datums/skills/_skill.dm b/code/datums/skills/_skill.dm index eecf416b1b..a7d7df72e4 100644 --- a/code/datums/skills/_skill.dm +++ b/code/datums/skills/_skill.dm @@ -171,6 +171,7 @@ GLOBAL_LIST_INIT_TYPED(skill_datums, /datum/skill, init_skill_datums()) continue max_assoc = levels[lvl-1] levels["[max_assoc] +[max_assoc_start++]"] = value + continue levels[key] = value /datum/skill/level/sanitize_value(new_value) diff --git a/code/datums/skills/blacksmithing.dm b/code/datums/skills/blacksmithing.dm index 0bddae5562..1f8eae357a 100644 --- a/code/datums/skills/blacksmithing.dm +++ b/code/datums/skills/blacksmithing.dm @@ -1,6 +1,7 @@ -/datum/skill/level/dorfy/blacksmithing +/datum/skill/level/dwarfy/blacksmithing name = "Blacksmithing" desc = "Making metal into fancy shapes using heat and force. Higher levels increase both your working speed at an anvil as well as the quality of your works." name_color = COLOR_FLOORTILE_GRAY skill_traits = list(SKILL_SANITY, SKILL_INTELLIGENCE, SKILL_USE_TOOL, SKILL_TRAINING_TOOL) ui_category = SKILL_UI_CAT_MISC + standard_xp_lvl_up = 100 //Effectively 200xp for level 1 because of how this code works. 300 more for 2, Etc, diff --git a/code/datums/weakrefs.dm b/code/datums/weakrefs.dm index fbe9036ea7..31e0c3501b 100644 --- a/code/datums/weakrefs.dm +++ b/code/datums/weakrefs.dm @@ -16,8 +16,12 @@ /datum/weakref/New(datum/thing) reference = REF(thing) -/datum/weakref/Destroy() - return QDEL_HINT_LETMELIVE //Let BYOND autoGC thiswhen nothing is using it anymore. +/datum/weakref/Destroy(force) + if(!force) + return QDEL_HINT_LETMELIVE //Let BYOND autoGC thiswhen nothing is using it anymore. + var/datum/target = resolve() + target?.weak_reference = null + return ..() /datum/weakref/proc/resolve() var/datum/D = locate(reference) diff --git a/code/datums/wounds/_scars.dm b/code/datums/wounds/_scars.dm index 8cd0d8a047..85589976e6 100644 --- a/code/datums/wounds/_scars.dm +++ b/code/datums/wounds/_scars.dm @@ -79,7 +79,7 @@ /// Used to "load" a persistent scar /datum/scar/proc/load(obj/item/bodypart/BP, version, description, specific_location, severity=WOUND_SEVERITY_SEVERE) - if(!(BP.body_zone in applicable_zones) || !BP.is_organic_limb()) + if(!(BP.body_zone in applicable_zones) || !(BP.is_organic_limb() || BP.render_like_organic)) qdel(src) return diff --git a/code/datums/wounds/_wounds.dm b/code/datums/wounds/_wounds.dm index 29c87b32d4..1ed0d98543 100644 --- a/code/datums/wounds/_wounds.dm +++ b/code/datums/wounds/_wounds.dm @@ -110,7 +110,7 @@ * * smited- If this is a smite, we don't care about this wound for stat tracking purposes (not yet implemented) */ /datum/wound/proc/apply_wound(obj/item/bodypart/L, silent = FALSE, datum/wound/old_wound = null, smited = FALSE) - if(!istype(L) || !L.owner || !(L.body_zone in viable_zones) || isalien(L.owner) || !L.is_organic_limb()) + if(!istype(L) || !L.owner || !(L.body_zone in viable_zones) || isalien(L.owner) || !(L.is_organic_limb() || L.render_like_organic)) qdel(src) return diff --git a/code/game/objects/items/robot/robot_upgrades.dm b/code/game/objects/items/robot/robot_upgrades.dm index 80fd177d84..9f098bc16c 100644 --- a/code/game/objects/items/robot/robot_upgrades.dm +++ b/code/game/objects/items/robot/robot_upgrades.dm @@ -27,6 +27,13 @@ return FALSE return TRUE +/* +This proc gets called by upgrades after installing them. Use this for things that for example need to be moved into a specific borg item, +as performing this in action() will cause the upgrade to end up in the borg instead of its intended location due to forceMove() being called afterwards.. +*/ +/obj/item/borg/upgrade/proc/afterInstall(mob/living/silicon/robot/R, user = usr) + return + /obj/item/borg/upgrade/proc/deactivate(mob/living/silicon/robot/R, user = usr) if (!(src in R.upgrades)) return FALSE diff --git a/code/game/objects/items/stacks/tiles/tile_types.dm b/code/game/objects/items/stacks/tiles/tile_types.dm index 7a33134afd..91ffae9cb1 100644 --- a/code/game/objects/items/stacks/tiles/tile_types.dm +++ b/code/game/objects/items/stacks/tiles/tile_types.dm @@ -211,6 +211,12 @@ turf_type = /turf/open/floor/carpet/black tableVariant = /obj/structure/table/wood/fancy/black +/obj/item/stack/tile/carpet/arcade + name = "arcade carpet" + icon_state = "tile-carpet-arcade" + turf_type = /turf/open/floor + tableVariant = null + /obj/item/stack/tile/carpet/blackred name = "red carpet" icon_state = "tile-carpet-blackred" @@ -297,6 +303,15 @@ /obj/item/stack/tile/carpet/black/fifty amount = 50 +/obj/item/stack/tile/carpet/arcade/ten + amount = 10 + +/obj/item/stack/tile/carpet/arcade/twenty + amount = 20 + +/obj/item/stack/tile/carpet/arcade/fifty + amount = 50 + /obj/item/stack/tile/carpet/blackred/ten amount = 10 diff --git a/code/game/objects/structures/watercloset.dm b/code/game/objects/structures/watercloset.dm index c52249686a..2214f9e4bb 100644 --- a/code/game/objects/structures/watercloset.dm +++ b/code/game/objects/structures/watercloset.dm @@ -131,15 +131,12 @@ return ..() /obj/structure/toilet/secret - var/obj/item/secret var/secret_type = null -/obj/structure/toilet/secret/Initialize(mapload) +/obj/structure/toilet/secret/Initialize() . = ..() if (secret_type) - secret = new secret_type(src) - secret.desc += "" //In case you want to add something to the item that spawns - contents += secret + new secret_type(src) /obj/structure/toilet/secret/LateInitialize() . = ..() diff --git a/code/game/turfs/simulated/floor.dm b/code/game/turfs/simulated/floor.dm index 877d236e84..ddec9750d9 100644 --- a/code/game/turfs/simulated/floor.dm +++ b/code/game/turfs/simulated/floor.dm @@ -46,7 +46,7 @@ "basalt0","basalt1","basalt2","basalt3","basalt4", "basalt5","basalt6","basalt7","basalt8","basalt9","basalt10","basalt11","basalt12", "oldburning","light-on-r","light-on-y","light-on-g","light-on-b", "wood", "carpetsymbol", "carpetstar", - "carpetcorner", "carpetside", "carpet", "ironsand1", "ironsand2", "ironsand3", "ironsand4", "ironsand5", + "carpetcorner", "carpetside", "carpet", "arcade", "ironsand1", "ironsand2", "ironsand3", "ironsand4", "ironsand5", "ironsand6", "ironsand7", "ironsand8", "ironsand9", "ironsand10", "ironsand11", "ironsand12", "ironsand13", "ironsand14", "ironsand15", "snow", "snow0", "snow1", "snow2", "snow3", "snow4", "snow5", "snow6", "snow7", "snow8", "snow9", "snow10", "snow11", "snow12", "snow-ice", "snow_dug", diff --git a/code/game/turfs/simulated/floor/fancy_floor.dm b/code/game/turfs/simulated/floor/fancy_floor.dm index eae45bfd76..3cf6cc7511 100644 --- a/code/game/turfs/simulated/floor/fancy_floor.dm +++ b/code/game/turfs/simulated/floor/fancy_floor.dm @@ -273,6 +273,13 @@ smooth = SMOOTH_MORE canSmoothWith = list(/turf/open/floor/carpet/black, /turf/open/floor/carpet/blackred, /turf/open/floor/carpet/monochrome) +/turf/open/floor/carpet/arcade + icon = 'icons/turf/floors.dmi' + icon_state = "arcade" + floor_tile = /obj/item/stack/tile/carpet/arcade + smooth = SMOOTH_FALSE + canSmoothWith = list() + /turf/open/floor/carpet/blackred icon = 'icons/turf/floors/carpet_blackred.dmi' floor_tile = /obj/item/stack/tile/carpet/blackred diff --git a/code/modules/antagonists/bloodsucker/bloodsucker_powers.dm b/code/modules/antagonists/bloodsucker/bloodsucker_powers.dm index 5c4b1f2b9f..26c8bd5949 100644 --- a/code/modules/antagonists/bloodsucker/bloodsucker_powers.dm +++ b/code/modules/antagonists/bloodsucker/bloodsucker_powers.dm @@ -180,10 +180,12 @@ button.screen_loc = DEFAULT_BLOODSPELLS button.moved = DEFAULT_BLOODSPELLS button.ordered = FALSE + /datum/action/bloodsucker/passive/Destroy() if(owner) Remove(owner) target = null + return ..() /////////////////////////////////// TARGETTED POWERS /////////////////////////////////// diff --git a/code/modules/antagonists/bloodsucker/objects/bloodsucker_crypt.dm b/code/modules/antagonists/bloodsucker/objects/bloodsucker_crypt.dm index 536c07cd62..e8fb82a5d1 100644 --- a/code/modules/antagonists/bloodsucker/objects/bloodsucker_crypt.dm +++ b/code/modules/antagonists/bloodsucker/objects/bloodsucker_crypt.dm @@ -456,6 +456,7 @@ /obj/structure/bloodsucker/candelabrum/Destroy() STOP_PROCESSING(SSobj, src) + return ..() //return a hint /obj/structure/bloodsucker/candelabrum/update_icon_state() icon_state = "candelabrum[lit ? "_lit" : ""]" diff --git a/code/modules/antagonists/revenant/revenant.dm b/code/modules/antagonists/revenant/revenant.dm index ffb3478b24..f5ebcffe35 100644 --- a/code/modules/antagonists/revenant/revenant.dm +++ b/code/modules/antagonists/revenant/revenant.dm @@ -390,7 +390,7 @@ if(old_key) for(var/mob/M in GLOB.dead_mob_list) if(M.client && M.client.key == old_key) //Only recreates the mob if the mob the client is in is dead - M.transfer_ckey(revenant.key, FALSE) + M.transfer_ckey(revenant, FALSE) key_of_revenant = TRUE break if(!key_of_revenant) @@ -403,7 +403,7 @@ visible_message("[src] settles down and seems lifeless.") return var/mob/C = pick(candidates) - C.transfer_ckey(revenant.key, FALSE) + C.transfer_ckey(revenant, FALSE) if(!revenant.key) qdel(revenant) message_admins("No ckey was found for the new revenant. Oh well!") @@ -411,8 +411,8 @@ visible_message("[src] settles down and seems lifeless.") return - message_admins("[key_of_revenant] has been [old_key == revenant.key ? "re":""]made into a revenant by reforming ectoplasm.") - log_game("[key_of_revenant] was [old_key == revenant.key ? "re":""]made as a revenant by reforming ectoplasm.") + message_admins("[revenant.key] has been [old_key == revenant.key ? "re":""]made into a revenant by reforming ectoplasm.") + log_game("[revenant.key] was [old_key == revenant.key ? "re":""]made as a revenant by reforming ectoplasm.") visible_message("[src] suddenly rises into the air before fading away.") revenant.essence = essence diff --git a/code/modules/cargo/packs/misc.dm b/code/modules/cargo/packs/misc.dm index 394b86bb81..9c15e75cd6 100644 --- a/code/modules/cargo/packs/misc.dm +++ b/code/modules/cargo/packs/misc.dm @@ -351,6 +351,10 @@ name = "Black Carpet Single-Pack" contains = list(/obj/item/stack/tile/carpet/black/fifty) +/datum/supply_pack/misc/carpet/arcade + name = "Arcade Carpet Single-Pack" + contains = list(/obj/item/stack/tile/carpet/arcade/fifty) + /datum/supply_pack/misc/carpet/premium name = "Monochrome Carpet Single-Pack" desc = "Exotic carpets for all your decorating needs. This 30 units stack of extra soft carpet will tie any room together." diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index 1435e90193..9eae46c1f3 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -2639,9 +2639,9 @@ GLOBAL_LIST_EMPTY(preferences_datums) //limb stuff, only done when initially spawning in if(initial_spawn) - //delete any existing prosthetic limbs to make sure no remnant prosthetics are left over + //delete any existing prosthetic limbs to make sure no remnant prosthetics are left over - But DO NOT delete those that are species-related for(var/obj/item/bodypart/part in character.bodyparts) - if(part.status == BODYPART_ROBOTIC) + if(part.status == BODYPART_ROBOTIC && !part.render_like_organic) qdel(part) character.regenerate_limbs() //regenerate limbs so now you only have normal limbs for(var/modified_limb in modified_limbs) diff --git a/code/modules/mapping/minimaps.dm b/code/modules/mapping/minimaps.dm index e0eb174cb3..51fde1f8db 100644 --- a/code/modules/mapping/minimaps.dm +++ b/code/modules/mapping/minimaps.dm @@ -134,12 +134,13 @@ return num; } window.onload = function() { - var datas = \[[jointext(datas, ",")]] - if(!window.HTMLCanvasElement){ - //something has gone horribly wrong! + if(!window.HTMLCanvasElement) { + var label = document.getElementById("label-1"); + label.textContent = "

WARNING! HTMLCanvasElement not found!

" return false } - for(var i = 0; i < [length(minimaps)]; i++){ + var datas = \[[jointext(datas, ",")]] + for(var i = 0; i < [length(minimaps)]; i++) { //the fuck is this wrapped? var data = datas\[i]; var img = document.getElementById("map-" + (i + 1)); @@ -160,13 +161,16 @@ ctx.drawImage(document.getElementById("map-" + (i+1) + "-meta"), 0, 0); var imagedata = ctx.getImageData(0, 0, img.width, img.height); - var label = document.getElementById("label-" + (i+1)); + canvas.onmousemove = function(e){ var rect = canvas.getBoundingClientRect(); var x = Math.floor(e.offsetX * img.width / rect.width); var y = Math.floor(e.offsetY * img.height / rect.height); + var color_idx = x * 4 + (y * 4 * imagedata.width); var color = "#" + hexify(imagedata.data\[color_idx]) + hexify(imagedata.data\[color_idx+1]) + hexify(imagedata.data\[color_idx+2]); + var label = document.getElementById("label-" + (i+1)); //label-String(n) + label.textContent = data\[color]; canvas.title = data\[color]; } diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index 6143bde602..1eb308af00 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -454,10 +454,12 @@ if(U.action(src)) to_chat(user, "You apply the upgrade to [src].") if(U.one_use) + U.afterInstall(src) qdel(U) else U.forceMove(src) upgrades += U + U.afterInstall(src) else to_chat(user, "Upgrade error.") U.forceMove(drop_location()) diff --git a/code/modules/projectiles/guns/energy/kinetic_accelerator.dm b/code/modules/projectiles/guns/energy/kinetic_accelerator.dm index c1f47ccd1a..438c000a1e 100644 --- a/code/modules/projectiles/guns/energy/kinetic_accelerator.dm +++ b/code/modules/projectiles/guns/energy/kinetic_accelerator.dm @@ -105,10 +105,20 @@ holds_charge = TRUE unique_frequency = TRUE +/obj/item/gun/energy/kinetic_accelerator/cyborg/Destroy() + for(var/obj/item/borg/upgrade/modkit/M in modkits) + M.uninstall(src) + return ..() + /obj/item/gun/energy/kinetic_accelerator/premiumka/cyborg holds_charge = TRUE unique_frequency = TRUE +/obj/item/gun/energy/kinetic_accelerator/premiumka/cyborg/Destroy() + for(var/obj/item/borg/upgrade/modkit/M in modkits) + M.uninstall(src) + return ..() + /obj/item/gun/energy/kinetic_accelerator/minebot trigger_guard = TRIGGER_GUARD_ALLOW_ALL overheat_time = 20 @@ -284,11 +294,11 @@ else ..() -/obj/item/borg/upgrade/modkit/action(mob/living/silicon/robot/R) - . = ..() - if (.) - for(var/obj/item/gun/energy/kinetic_accelerator/cyborg/H in R.module.modules) - return install(H, usr) +/obj/item/borg/upgrade/modkit/afterInstall(mob/living/silicon/robot/R) + for(var/obj/item/gun/energy/kinetic_accelerator/H in R.module.modules) + if(install(H, R)) //It worked + return + to_chat(R, "Upgrade error - Aborting Kinetic Accelerator linking.") //No applicable KA found, insufficient capacity, or some other problem. /obj/item/borg/upgrade/modkit/proc/install(obj/item/gun/energy/kinetic_accelerator/KA, mob/user) . = TRUE @@ -323,12 +333,6 @@ to_chat(user, "You don't have room([KA.get_remaining_mod_capacity()]% remaining, [cost]% needed) to install this modkit. Use a crowbar to remove existing modkits.") . = FALSE -/obj/item/borg/upgrade/modkit/deactivate(mob/living/silicon/robot/R, user = usr) - . = ..() - if (.) - for(var/obj/item/gun/energy/kinetic_accelerator/cyborg/KA in R.module.modules) - uninstall(KA) - /obj/item/borg/upgrade/modkit/proc/uninstall(obj/item/gun/energy/kinetic_accelerator/KA, forcemove = TRUE) KA.modkits -= src if(forcemove) diff --git a/code/modules/reagents/chemistry/reagents/other_reagents.dm b/code/modules/reagents/chemistry/reagents/other_reagents.dm index 0d3e9a4139..0021a49e51 100644 --- a/code/modules/reagents/chemistry/reagents/other_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/other_reagents.dm @@ -1978,6 +1978,11 @@ color = "#363636" carpet_type = /turf/open/floor/carpet/black +/datum/reagent/carpet/arcade + name = "Liquid Arcade Carpet" + color = "#b51d05" + carpet_type = /turf/open/floor/carpet/arcade + /datum/reagent/carpet/blackred name = "Liquid Red Black Carpet" color = "#342125" diff --git a/code/modules/reagents/chemistry/recipes/others.dm b/code/modules/reagents/chemistry/recipes/others.dm index 92861a94ed..0ab8a69aa0 100644 --- a/code/modules/reagents/chemistry/recipes/others.dm +++ b/code/modules/reagents/chemistry/recipes/others.dm @@ -757,6 +757,12 @@ results = list(/datum/reagent/carpet/black = 2) required_reagents = list(/datum/reagent/carpet = 1, /datum/reagent/carbon = 1) +/datum/chemical_reaction/carpet/arcade + name = "liquid arcade carpet" + id = /datum/reagent/carpet/arcade + results = list(/datum/reagent/carpet/arcade = 2) + required_reagents = list(/datum/reagent/carpet = 1, /datum/reagent/consumable/pwr_game = 1) + /datum/chemical_reaction/carpet/blackred name = "liquid red black carpet" id = /datum/reagent/carpet/blackred diff --git a/code/modules/smithing/anvil.dm b/code/modules/smithing/anvil.dm index 19d48119e6..b796edabbf 100644 --- a/code/modules/smithing/anvil.dm +++ b/code/modules/smithing/anvil.dm @@ -36,6 +36,7 @@ icon_state = "anvil" density = TRUE anchored = TRUE + var/busy = FALSE //If someone is already interacting with this anvil var/workpiece_state = FALSE var/datum/material/workpiece_material var/anvilquality = 0 @@ -84,7 +85,7 @@ currentquality = anvilquality var/skillmod = 0 if(user.mind.skill_holder) - skillmod = user.mind.get_skill_level(/datum/skill/level/dorfy/blacksmithing)/2 + skillmod = user.mind.get_skill_level(/datum/skill/level/dwarfy/blacksmithing)/2 currentquality += skillmod qdel(notsword) else @@ -93,12 +94,14 @@ return else if(istype(I, /obj/item/melee/smith/hammer)) var/obj/item/melee/smith/hammer/hammertime = I - if(workpiece_state == WORKPIECE_PRESENT || workpiece_state == WORKPIECE_INPROGRESS) - do_shaping(user, hammertime.qualitymod) - return - else - to_chat(user, "You can't work an empty anvil!") - return FALSE + if(!(workpiece_state == WORKPIECE_PRESENT || workpiece_state == WORKPIECE_INPROGRESS)) + to_chat(user, "You can't work an empty anvil!") + return FALSE + if(busy) + to_chat(user, "This anvil is already being worked!") + return FALSE + do_shaping(user, hammertime.qualitymod) + return return ..() /obj/structure/anvil/wrench_act(mob/living/user, obj/item/I) @@ -108,16 +111,18 @@ /obj/structure/anvil/proc/do_shaping(mob/user, var/qualitychange) + busy = TRUE currentquality += qualitychange var/list/shapingsteps = list("weak hit", "strong hit", "heavy hit", "fold", "draw", "shrink", "bend", "punch", "upset") //weak/strong/heavy hit affect strength. All the other steps shape. workpiece_state = WORKPIECE_INPROGRESS var/stepdone = input(user, "How would you like to work the metal?") in shapingsteps var/steptime = 50 if(user.mind.skill_holder) - var/skillmod = user.mind.get_skill_level(/datum/skill/level/dorfy/blacksmithing)/10 + 1 + var/skillmod = user.mind.get_skill_level(/datum/skill/level/dwarfy/blacksmithing)/10 + 1 steptime = 50 / skillmod playsound(src, 'sound/effects/clang2.ogg',40, 2) if(!do_after(user, steptime, target = src)) + busy = FALSE return FALSE switch(stepdone) if("weak hit") @@ -162,16 +167,17 @@ addtimer(CALLBACK(GLOBAL_PROC, .proc/playsound, src, 'sound/effects/clang2.ogg', 40, 2), 15) if(length(stepsdone) >= 3) tryfinish(user) + busy = FALSE /obj/structure/anvil/proc/tryfinish(mob/user) var/artifactchance = 0 if(!artifactrolled) - artifactchance = (1+(user.mind.get_skill_level(/datum/skill/level/dorfy/blacksmithing)/4))/2500 + artifactchance = (1+(user.mind.get_skill_level(/datum/skill/level/dwarfy/blacksmithing)/4))/2500 artifactrolled = TRUE var/artifact = max(prob(artifactchance), debug) var/finalfailchance = outrightfailchance if(user.mind.skill_holder) - var/skillmod = user.mind.get_skill_level(/datum/skill/level/dorfy/blacksmithing)/10 + 1 + var/skillmod = user.mind.get_skill_level(/datum/skill/level/dwarfy/blacksmithing)/10 + 1 finalfailchance = max(0, finalfailchance / skillmod) //lv 2 gives 20% less to fail, 3 30%, etc if((currentsteps > 10 || (rng && prob(finalfailchance))) && !artifact) to_chat(user, "You overwork the metal, causing it to turn into useless slag!") @@ -184,7 +190,7 @@ outrightfailchance = 1 artifactrolled = FALSE if(user.mind.skill_holder) - user.mind.auto_gain_experience(/datum/skill/level/dorfy/blacksmithing, 25, 400, silent = FALSE) + user.mind.auto_gain_experience(/datum/skill/level/dwarfy/blacksmithing, 25, 400, silent = FALSE) for(var/i in smithrecipes) if(i == stepsdone) var/turf/T = get_turf(user) @@ -217,7 +223,7 @@ outrightfailchance = 1 artifactrolled = FALSE if(user.mind.skill_holder) - user.mind.auto_gain_experience(/datum/skill/level/dorfy/blacksmithing, 50, 10000000, silent = FALSE) + user.mind.auto_gain_experience(/datum/skill/level/dwarfy/blacksmithing, 50, 10000000, silent = FALSE) break /obj/structure/anvil/debugsuper diff --git a/code/modules/smithing/smithed_items.dm b/code/modules/smithing/smithed_items.dm index 6d10d33a75..e514fd5c9a 100644 --- a/code/modules/smithing/smithed_items.dm +++ b/code/modules/smithing/smithed_items.dm @@ -35,7 +35,7 @@ if(G.max_heat_protection_temperature) prot = (G.max_heat_protection_temperature > 360) else - prot = 1 + prot = 0 if(prot > 0 || HAS_TRAIT(user, TRAIT_RESISTHEAT) || HAS_TRAIT(user, TRAIT_RESISTHEATHANDS)) to_chat(user, "You pick up the [src].") return ..() diff --git a/code/modules/surgery/bodyparts/_bodyparts.dm b/code/modules/surgery/bodyparts/_bodyparts.dm index 77eb5c654f..90f2185ce6 100644 --- a/code/modules/surgery/bodyparts/_bodyparts.dm +++ b/code/modules/surgery/bodyparts/_bodyparts.dm @@ -581,7 +581,7 @@ C = owner no_update = FALSE - if(HAS_TRAIT(C, TRAIT_HUSK) && is_organic_limb()) + if(HAS_TRAIT(C, TRAIT_HUSK) && (is_organic_limb() || render_like_organic)) species_id = "husk" //overrides species_id dmg_overlay_type = "" //no damage overlay shown when husked should_draw_gender = FALSE diff --git a/code/modules/surgery/bodyparts/dismemberment.dm b/code/modules/surgery/bodyparts/dismemberment.dm index fa003e3f3c..3038e32733 100644 --- a/code/modules/surgery/bodyparts/dismemberment.dm +++ b/code/modules/surgery/bodyparts/dismemberment.dm @@ -434,5 +434,8 @@ var/datum/scar/scaries = new var/datum/wound/loss/phantom_loss = new // stolen valor, really scaries.generate(L, phantom_loss) + if(HAS_TRAIT(src, ROBOTIC_LIMBS)) //Snowflake trait moment, but needed. + L.render_like_organic = TRUE + L.change_bodypart_status(BODYPART_ROBOTIC, FALSE, TRUE) //Haha what if IPC-lings actually regenerated the right limbs instead of organic ones? That'd be pretty cool, right? L.attach_limb(src, 1) return TRUE diff --git a/code/modules/vending/_vending.dm b/code/modules/vending/_vending.dm index a115300085..26bee38f7b 100644 --- a/code/modules/vending/_vending.dm +++ b/code/modules/vending/_vending.dm @@ -529,7 +529,7 @@ GLOBAL_LIST_EMPTY(vending_products) if(5) // limb squish! for(var/i in C.bodyparts) var/obj/item/bodypart/squish_part = i - if(squish_part.is_organic_limb()) + if(squish_part.is_organic_limb() || squish_part.render_like_organic) var/type_wound = pick(list(/datum/wound/blunt/critical, /datum/wound/blunt/severe, /datum/wound/blunt/moderate)) squish_part.force_wound_upwards(type_wound) else diff --git a/code/modules/vore/eating/vorepanel.dm b/code/modules/vore/eating/vorepanel.dm index 1adf5ef6e7..9cb46d011d 100644 --- a/code/modules/vore/eating/vorepanel.dm +++ b/code/modules/vore/eating/vorepanel.dm @@ -46,6 +46,7 @@ /datum/vore_look/Destroy() loop = null selected = null + ..() //this is a must return QDEL_HINT_HARDDEL /datum/vore_look/Topic(href,href_list[]) diff --git a/html/changelog.html b/html/changelog.html index 13ae860cb3..0de57ebe79 100644 --- a/html/changelog.html +++ b/html/changelog.html @@ -53,6 +53,11 @@

04 October 2020

DeltaFire15 updated: