diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 7a79b28b09aa..4dfa55a79231 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -24,9 +24,8 @@ /tools/docker/ @Fira /Dockerfile @Fira -# MorrowWolf +# Zonespace -/maps/map_files/LV522_Chances_Claim/LV522_Chances_Claim.dmm @morrowwolf -/code/modules/gear_presets/survivors.dm @morrowwolf +/code/modules/gear_presets/survivors.dm @zonespace27 # MULTIPLE OWNERS diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 49eda07616c2..5eb8f0219e73 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -10,6 +10,12 @@ body: placeholder: "#1, #2, #3, etc" validations: required: true + - type: input + id: round-id + attributes: + label: Round ID + description: If known, what was the Round ID this bug was found on? Can be left blank if unknown or occured across multiple rounds. + placeholder: "12345" - type: textarea id: what-happened attributes: diff --git a/.github/workflows/ci_suite.yml b/.github/workflows/ci_suite.yml index 683f3909b447..0488055312f7 100644 --- a/.github/workflows/ci_suite.yml +++ b/.github/workflows/ci_suite.yml @@ -60,6 +60,34 @@ jobs: with: outputFile: output-annotations.txt + + odlint: + name: Lint with OpenDream + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v3 + - name: Get OpenDream Version + run: | + source dependencies.sh + echo "OPENDREAM_VERSION=$OPENDREAM_VERSION" >> $GITHUB_ENV + - name: Restore OpenDream cache + uses: actions/cache@v3 + id: cache-od + with: + path: ~/OpenDream + key: ${{ runner.os }}-opendream-${{ env.OPENDREAM_VERSION }} + - name: Download OpenDream + if: steps.cache-od.outputs.cache-hit != 'true' + run: | + bash tools/ci/download_od.sh + - name: Setup OpenDream + if: steps.cache-od.outputs.cache-hit != 'true' + run: | + bash tools/ci/setup_od.sh + - name: Run OpenDream + run: | + bash tools/ci/run_od.sh + compile_all_maps: if: "!contains(github.event.head_commit.message, '[ci skip]')" name: Compile Maps diff --git a/.gitignore b/.gitignore index 210efc84d75b..4d2b7e810de8 100644 --- a/.gitignore +++ b/.gitignore @@ -31,3 +31,6 @@ test_environment.txt # byond-tracy backend, not shipped with the codebase so it shouldn't be maintained prof.dll libprof.so + +# OpenDream compatibility stuff +colonialmarines.json diff --git a/code/__DEFINES/__game.dm b/code/__DEFINES/__game.dm index 113b78dbada1..f1424f5560ec 100644 --- a/code/__DEFINES/__game.dm +++ b/code/__DEFINES/__game.dm @@ -283,7 +283,6 @@ block( \ /// Only use the CEILING_PROTECTION_TIER_X defines for `protection_level` #define CEILING_IS_PROTECTED(ceiling, protection_level) (ceiling >= protection_level) - // Default font settings #define FONT_SIZE "5pt" #define DEFAULT_FONT_COLOR "#09f" @@ -493,6 +492,18 @@ block( \ #define TURF_PROTECTION_CAS 2 #define TURF_PROTECTION_OB 3 +/// Convert a turf protection level to a ceiling protection level +/proc/get_ceiling_protection_level(turf_protection_level) + switch(turf_protection_level) + if(TURF_PROTECTION_OB) + return CEILING_PROTECTION_TIER_4 + if(TURF_PROTECTION_CAS) + return CEILING_PROTECTION_TIER_3 + if(TURF_PROTECTION_MORTAR) + return CEILING_PROTECTION_TIER_2 + else + return CEILING_NO_PROTECTION + // Anything above the deck boundary is the upper deck, anything below is the lower deck // This is exclusive, so anything ON the boundary is an edge case that's neither on the upper nor the lower deck #define ALMAYER_DECK_BOUNDARY 101 diff --git a/code/__DEFINES/assert.dm b/code/__DEFINES/assert.dm new file mode 100644 index 000000000000..cff78107714c --- /dev/null +++ b/code/__DEFINES/assert.dm @@ -0,0 +1,13 @@ +#undef ASSERT + +/// Override BYOND's native ASSERT to optionally specify a message +#define ASSERT(condition, message...) \ + if (!(condition)) { \ + CRASH(assertion_message(__FILE__, __LINE__, #condition, ##message)) \ + } + +/proc/assertion_message(file, line, condition, message) + if (!isnull(message)) + message = " - [message]" + + return "[file]:[line]:Assertion failed: [condition][message]" diff --git a/code/__DEFINES/atmospherics.dm b/code/__DEFINES/atmospherics.dm index 3abd79708f7a..de7eb672e87b 100644 --- a/code/__DEFINES/atmospherics.dm +++ b/code/__DEFINES/atmospherics.dm @@ -23,6 +23,8 @@ #define T0C 273.15 // 0degC #define T20C 293.15 // 20degC +#define T90C 363.15 // 90degC +#define T120C 393.15 // 120degC #define TCMB 2.7 // -270.3degC #define ICE_COLONY_TEMPERATURE 223 //-50degC #define SOROKYNE_TEMPERATURE 223 // Same as Ice for now diff --git a/code/__DEFINES/bullet_traits.dm b/code/__DEFINES/bullet_traits.dm index 0ca3bce2e602..40e250cd0dd2 100644 --- a/code/__DEFINES/bullet_traits.dm +++ b/code/__DEFINES/bullet_traits.dm @@ -3,7 +3,7 @@ // list of args if there are any args /// An entry to a list for giving projectiles bullet traits /// Must be placed inside of a list -#define BULLET_TRAIT_ENTRY(trait, args...) trait = #args ? list(##args) : null +#define BULLET_TRAIT_ENTRY(trait, args...) trait = list(##args) /// An entry to a list for giving projectiles bullet traits with a unique ID /// Must be placed inside of a list #define BULLET_TRAIT_ENTRY_ID(id, trait, args...) id = list(trait, ##args) diff --git a/code/__DEFINES/client_prefs.dm b/code/__DEFINES/client_prefs.dm index b1e194354555..5337f64d9e46 100644 --- a/code/__DEFINES/client_prefs.dm +++ b/code/__DEFINES/client_prefs.dm @@ -1,6 +1,7 @@ #define BE_ALIEN_AFTER_DEATH (1<<0) #define BE_AGENT (1<<1) +//toggle_prefs bits from /datum/preferences #define TOGGLE_IGNORE_SELF (1<<0) // Determines whether you will not hurt yourself when clicking yourself #define TOGGLE_HELP_INTENT_SAFETY (1<<1) // Determines whether help intent will be completely harmless #define TOGGLE_MIDDLE_MOUSE_CLICK (1<<2) // This toggles whether selected ability for xeno uses middle mouse clicking or shift clicking @@ -13,7 +14,7 @@ // and put the empty magazine in your hand #define TOGGLE_AUTOMATIC_PUNCTUATION (1<<7) // Whether your sentences will automatically be punctuated with a period #define TOGGLE_COMBAT_CLICKDRAG_OVERRIDE (1<<8) // Whether disarm/harm intents cause clicks to trigger immediately when the mouse button is depressed. -#define TOGGLE_ALTERNATING_DUAL_WIELD (1<<9) // Whether dual-wielding fires both guns at once or swaps between them. +#define TOGGLE_ALTERNATING_DUAL_WIELD (1<<9) // Whether dual-wielding fires both guns at once or swaps between them, OUTDATED, used to update savefiles, now dual_wield_pref #define TOGGLE_FULLSCREEN (1<<10) // See /client/proc/toggle_fullscreen in client_procs.dm #define TOGGLE_MEMBER_PUBLIC (1<<11) //determines if you get a byond logo by your name in ooc if you're a member or not #define TOGGLE_OOC_FLAG (1<<12) // determines if your country flag appears by your name in ooc chat @@ -32,3 +33,11 @@ #define AGE_MIN 19 //youngest a character can be #define AGE_MAX 90 //oldest a character can be //no. you are not allowed to be 160. #define MAX_GEAR_COST 7 //Used in chargen for loadout limit. + +///dual_wield_pref from /datum/preferences +///Fire both weapons when dual wielding +#define DUAL_WIELD_FIRE 0 +///Swap to the other weapon when dual wielding +#define DUAL_WIELD_SWAP 1 +///Do nothing when dual wielding +#define DUAL_WIELD_NONE 2 diff --git a/code/__DEFINES/conflict.dm b/code/__DEFINES/conflict.dm index 0820c709cdae..d69f0891ffa0 100644 --- a/code/__DEFINES/conflict.dm +++ b/code/__DEFINES/conflict.dm @@ -109,6 +109,7 @@ #define SHOES_SLOWDOWN -1 #define SLOWDOWN_ARMOR_NONE 0 +#define SLOWDOWN_ARMOR_SUPER_LIGHT 0.10 #define SLOWDOWN_ARMOR_VERY_LIGHT 0.20 #define SLOWDOWN_ARMOR_LIGHT 0.35 #define SLOWDOWN_ARMOR_MEDIUM 0.55 diff --git a/code/__DEFINES/dcs/signals/atom/mob/living/signals_human.dm b/code/__DEFINES/dcs/signals/atom/mob/living/signals_human.dm index 90e6db45dbaa..2e247cdccc73 100644 --- a/code/__DEFINES/dcs/signals/atom/mob/living/signals_human.dm +++ b/code/__DEFINES/dcs/signals/atom/mob/living/signals_human.dm @@ -36,6 +36,10 @@ #define COMSIG_HUMAN_UPDATE_SIGHT "human_update_sight" #define COMPONENT_OVERRIDE_UPDATE_SIGHT (1<<0) +///from /mob/living/carbon/human/movement_delay() +#define COMSIG_HUMAN_MOVEMENT_CANCEL_INTERACTION "human_movement_cancel_interaction" + #define COMPONENT_HUMAN_MOVEMENT_KEEP_USING (1<<0) + ///from /mob/living/carbon/human/update_sight() #define COMSIG_HUMAN_POST_UPDATE_SIGHT "human_post_update_sight" ///from /mob/living/carbon/human/movement_delay(): (list/movedata) diff --git a/code/__DEFINES/dcs/signals/atom/mob/signals_mob.dm b/code/__DEFINES/dcs/signals/atom/mob/signals_mob.dm index 5ca77a2ba9d2..d60e3d6b52e2 100644 --- a/code/__DEFINES/dcs/signals/atom/mob/signals_mob.dm +++ b/code/__DEFINES/dcs/signals/atom/mob/signals_mob.dm @@ -1,3 +1,5 @@ +///from base of mob/set_stat(): (new_stat, old_stat) +#define COMSIG_MOB_STATCHANGE "mob_statchange" /// From /obj/structure/machinery/door/airlock/proc/take_damage #define COMSIG_MOB_DESTROY_AIRLOCK "mob_destroy_airlock" @@ -167,3 +169,6 @@ /// From /obj/item/grab/proc/progress_passive() : (mob/living/carbon/human/grabber) #define COMSIG_MOB_AGGRESSIVELY_GRABBED "mob_aggressively_grabbed" #define COMSIG_MOB_AGGRESIVE_GRAB_CANCEL (1<<0) + +/// Cancels all running cloaking effects on target +#define COMSIG_MOB_EFFECT_CLOAK_CANCEL "mob_effect_cloak_cancel" diff --git a/code/__DEFINES/dcs/signals/atom/signals_atom.dm b/code/__DEFINES/dcs/signals/atom/signals_atom.dm index 7431c5593b17..d9bd1202c159 100644 --- a/code/__DEFINES/dcs/signals/atom/signals_atom.dm +++ b/code/__DEFINES/dcs/signals/atom/signals_atom.dm @@ -45,3 +45,12 @@ ///When the transform or an atom is varedited through vv topic. #define COMSIG_ATOM_VV_MODIFY_TRANSFORM "atom_vv_modify_transform" + +/// Called when an atom has something mouse dropped on it, from /client/MouseDrop: (atom/dropped_on) +#define COMSIG_ATOM_DROPPED_ON "atom_dropped_on" + +/// Called when an atom is mouse dropped on another atom, from /client/MouseDrop: (atom/dropped_onto) +#define COMSIG_ATOM_DROP_ON "atom_drop_on" + +/// Called when an atom has emp_act called on it, from /atom/emp_act: (severity) +#define COMSIG_ATOM_EMP_ACT "atom_emp_act" diff --git a/code/__DEFINES/dcs/signals/atom/signals_cell.dm b/code/__DEFINES/dcs/signals/atom/signals_cell.dm new file mode 100644 index 000000000000..75e13d8bfdfc --- /dev/null +++ b/code/__DEFINES/dcs/signals/atom/signals_cell.dm @@ -0,0 +1,26 @@ +/// (charge_amount) +#define COMSIG_CELL_USE_CHARGE "cell_use_charge" + #define COMPONENT_CELL_NO_USE_CHARGE (1<<0) + +/// (charge_amount) +#define COMSIG_CELL_ADD_CHARGE "cell_add_charge" + +#define COMSIG_CELL_START_TICK_DRAIN "cell_start_tick_drain" + +#define COMSIG_CELL_STOP_TICK_DRAIN "cell_stop_tick_drain" + +/// (mob/living/user) +#define COMSIG_CELL_TRY_RECHARGING "cell_try_recharging" + #define COMPONENT_CELL_NO_RECHARGE (1<<0) + +#define COMSIG_CELL_OUT_OF_CHARGE "cell_out_of_charge" + +/// (charge_amount) +#define COMSIG_CELL_CHECK_CHARGE "cell_check_charge" + #define COMPONENT_CELL_CHARGE_INSUFFICIENT (1<<0) + +#define COMSIG_CELL_TRY_INSERT_CELL "cell_try_insert_cell" + #define COMPONENT_CANCEL_CELL_INSERT (1<<0) + +/// (mob/living/user) +#define COMSIG_CELL_REMOVE_CELL "cell_remove_cell" diff --git a/code/__DEFINES/dcs/signals/atom/signals_item.dm b/code/__DEFINES/dcs/signals/atom/signals_item.dm index 6c31b77f76a4..6024c0524992 100644 --- a/code/__DEFINES/dcs/signals/atom/signals_item.dm +++ b/code/__DEFINES/dcs/signals/atom/signals_item.dm @@ -65,3 +65,6 @@ /// from /obj/item/weapon/gun/proc/load_into_chamber() : () #define COMSIG_GUN_INTERRUPT_FIRE "gun_interrupt_fire" + +//from /datum/authority/branch/role/proc/equip_role() +#define COMSIG_POST_SPAWN_UPDATE "post_spawn_update" diff --git a/code/__DEFINES/dcs/signals/atom/signals_obj.dm b/code/__DEFINES/dcs/signals/atom/signals_obj.dm index 0f761ef64494..e35367ec5f03 100644 --- a/code/__DEFINES/dcs/signals/atom/signals_obj.dm +++ b/code/__DEFINES/dcs/signals/atom/signals_obj.dm @@ -38,3 +38,5 @@ /// from /obj/limb/proc/remove_all_bleeding() : (external, internal) #define COMSIG_LIMB_STOP_BLEEDING "limb_stop_bleeding" + +#define COMSIG_STRUCTURE_CRATE_SQUAD_LAUNCHED "structure_crate_squad_launched" diff --git a/code/__DEFINES/dcs/signals/signals_global.dm b/code/__DEFINES/dcs/signals/signals_global.dm index 032a1891a808..dc5e70fcd5ec 100644 --- a/code/__DEFINES/dcs/signals/signals_global.dm +++ b/code/__DEFINES/dcs/signals/signals_global.dm @@ -60,8 +60,11 @@ #define COMSIG_GLOB_GROUNDSIDE_FORSAKEN_HANDLING "!groundside_forsaken_handling" /// From -#define COMSIG_GLOB_YAUTJA_ARMORY_OPENED "yautja_armory_opened" +#define COMSIG_GLOB_YAUTJA_ARMORY_OPENED "!yautja_armory_opened" /// From /proc/biohazard_lockdown() -#define COMSIG_GLOB_RESEARCH_LOCKDOWN "research_lockdown_closed" -#define COMSIG_GLOB_RESEARCH_LIFT "research_lockdown_opened" +#define COMSIG_GLOB_RESEARCH_LOCKDOWN "!research_lockdown_closed" +#define COMSIG_GLOB_RESEARCH_LIFT "!research_lockdown_opened" + +/// From /obj/structure/machinery/power/fusion_engine/proc/set_overloading() : (set_overloading) +#define COMSIG_GLOB_GENERATOR_SET_OVERLOADING "!generator_set_overloading" diff --git a/code/__DEFINES/emote_panels.dm b/code/__DEFINES/emote_panels.dm index 59959818da74..8419f5513cf0 100644 --- a/code/__DEFINES/emote_panels.dm +++ b/code/__DEFINES/emote_panels.dm @@ -6,7 +6,8 @@ #define JOE_EMOTE_CATEGORY_WARNING "Warning" #define JOE_EMOTE_CATEGORY_QUESTION "Question" #define JOE_EMOTE_CATEGORY_NOTICE "Notice" - +#define JOE_EMOTE_CATEGORY_FIRE "Fire" +#define JOE_EMOTE_CATEGORY_DAMAGE "Damage" #define YAUTJA_EMOTE_CATEGORY_FAKESOUND "Fake Sound" #define YAUTJA_EMOTE_CATEGORY_VOICE "Voice Synthesizer" #define YAUTJA_EMOTE_CATEGORY_SPECIES "Yautja" diff --git a/code/__DEFINES/equipment.dm b/code/__DEFINES/equipment.dm index 82e91c5680b8..6628a5c925c2 100644 --- a/code/__DEFINES/equipment.dm +++ b/code/__DEFINES/equipment.dm @@ -80,10 +80,8 @@ #define CAN_DIG_SHRAPNEL (1<<11) /// whether it has an animated icon state of "[icon_state]_on" to be used during surgeries. #define ANIMATED_SURGICAL_TOOL (1<<12) -/// The item goes on top of tables, instead of into them with the overlay system -#define NOTABLEMERGE (1<<13) /// Has heat source but isn't 'on fire' and thus can be stored -#define IGNITING_ITEM (1<<14) +#define IGNITING_ITEM (1<<13) //========================================================================================== @@ -551,3 +549,8 @@ var/global/list/uniform_categories = list( #define PHONE_MARINE "Marine" #define PHONE_UPP_SOLDIER "Soldier" #define PHONE_IO "IO" + +#define PHONE_DND_FORCED 2 +#define PHONE_DND_ON 1 +#define PHONE_DND_OFF 0 +#define PHONE_DND_FORBIDDEN -1 diff --git a/code/__DEFINES/hijack.dm b/code/__DEFINES/hijack.dm new file mode 100644 index 000000000000..85d4c227ae70 --- /dev/null +++ b/code/__DEFINES/hijack.dm @@ -0,0 +1,13 @@ +#define EVACUATION_TYPE_NONE 0 +#define EVACUATION_TYPE_ADDITIVE 1 +#define EVACUATION_TYPE_MULTIPLICATIVE 2 + +#define HIJACK_ANNOUNCE "ARES Emergency Procedures" +#define XENO_HIJACK_ANNOUNCE "You sense something unusual..." + +#define EVACUATION_STATUS_NOT_INITIATED 0 +#define EVACUATION_STATUS_INITIATED 1 + +#define HIJACK_OBJECTIVES_NOT_STARTED 0 +#define HIJACK_OBJECTIVES_STARTED 1 +#define HIJACK_OBJECTIVES_COMPLETE 2 diff --git a/code/__DEFINES/job.dm b/code/__DEFINES/job.dm index 52263a5e1367..56062cb0213b 100644 --- a/code/__DEFINES/job.dm +++ b/code/__DEFINES/job.dm @@ -11,6 +11,7 @@ #define SQUAD_MARINE_CRYO "Foxtrot" #define SQUAD_MARINE_INTEL "Intel" #define SQUAD_SOF "SOF" +#define SQUAD_CBRN "CBRN" // Job name defines #define JOB_SQUAD_MARINE "Rifleman" @@ -267,6 +268,7 @@ var/global/list/job_command_roles = JOB_COMMAND_ROLES_LIST #define JOB_UPP_GENERAL "UPP Army General" #define JOB_UPP_COMBAT_SYNTH "UPP Combat Synthetic" +#define JOB_UPP_SUPPORT_SYNTH "UPP Support Synthetic" #define UPP_JOB_LIST list(JOB_UPP, JOB_UPP_ENGI, JOB_UPP_MEDIC, JOB_UPP_SPECIALIST, JOB_UPP_LEADER, JOB_UPP_POLICE, JOB_UPP_LT_OFFICER, JOB_UPP_LT_DOKTOR, JOB_UPP_SRLT_OFFICER, JOB_UPP_KPT_OFFICER, JOB_UPP_KOL_OFFICER, JOB_UPP_COMBAT_SYNTH) #define UPP_JOB_GRUNT_LIST list(JOB_UPP, JOB_UPP_ENGI, JOB_UPP_MEDIC, JOB_UPP_SPECIALIST, JOB_UPP_LEADER, JOB_UPP_POLICE, JOB_UPP_CREWMAN) diff --git a/code/__DEFINES/keybinding.dm b/code/__DEFINES/keybinding.dm index 1878ca63f34e..764282d59765 100644 --- a/code/__DEFINES/keybinding.dm +++ b/code/__DEFINES/keybinding.dm @@ -14,6 +14,7 @@ #define COMSIG_KB_ADMIN_INVISIMINTOGGLE_DOWN "keybinding_admin_invisimintoggle_down" #define COMSIG_KB_ADMIN_DEADMIN_DOWN "keybinding_admin_deadmin_down" #define COMSIG_KB_ADMIN_READMIN_DOWN "keybinding_admin_readmin_down" +#define COMSIG_KB_ADMIN_MENTORSAY_DOWN "keybinding_admin_mentorsay_down" //Carbon #define COMSIG_KB_CARBON_HOLDRUNMOVEINTENT_DOWN "keybinding_carbon_holdrunmoveintent_down" @@ -43,12 +44,6 @@ #define COMSIG_KG_CLIENT_RADIO_DOWN "keybinding_client_radio_down" //Human -#define COMSIG_KB_HUMAN_QUICKEQUIP_DOWN "keybinding_human_quickequip_down" -#define COMSIG_KB_HUMAN_SECONDARY_DOWN "keybinding_human_secondary_down" -#define COMSIG_KB_HUMAN_TERTIARY_DOWN "keybinding_human_tertiary_down" -#define COMSIG_KB_HUMAN_QUATERNARY_DOWN "keybinding_human_quaternary_down" -#define COMSIG_KB_HUMAN_QUICK_EQUIP_DOWN "keybinding_human_quick_equip_down" - #define COMSIG_KB_HUMAN_ISSUE_ORDER "keybinding_human_issue_order" #define COMSIG_KB_HUMAN_ISSUE_ORDER_MOVE "keybinding_human_issue_order_move" #define COMSIG_KB_HUMAN_ISSUE_ORDER_HOLD "keybinding_human_issue_order_hold" @@ -57,12 +52,31 @@ #define COMSIG_KB_HUMAN_SPECIALIST_ACTIVATION_ONE "keybinding_human_specialist_activation_one" #define COMSIG_KB_HUMAN_SPECIALIST_ACTIVATION_TWO "keybinding_human_specialist_activation_two" -#define COMSIG_KB_HUMAN_PICK_UP "keybinding_human_pick_up" - #define COMSIG_KB_HUMAN_ROTATE_CHAIR "keybinding_human_rotate_chair" #define COMSIG_KB_HUMAN_SHOW_HELD_ITEM "keybinding_human_show_held_item" +#define COMSIG_KB_HUMAN_CYCLE_HELMET_HUD "keybinding_human_cycle_helmet_hud" + +// Human Inventory Navigation +#define COMSIG_KB_HUMAN_INTERACT_OTHER_HAND "keybinding_human_interact_other_hand" +#define COMSIG_KB_HUMAN_INTERACT_SLOT_BACK "keybinding_human_interact_slot_back" +#define COMSIG_KB_HUMAN_INTERACT_SLOT_BELT "keybinding_human_interact_slot_belt" +#define COMSIG_KB_HUMAN_INTERACT_SLOT_UNIFORM "keybinding_human_interact_slot_uniform" +#define COMSIG_KB_HUMAN_INTERACT_SLOT_SUIT "keybinding_human_interact_slot_suit" +#define COMSIG_KB_HUMAN_INTERACT_SLOT_HELMET "keybinding_human_interact_slot_helmet" +#define COMSIG_KB_HUMAN_INTERACT_SLOT_LEFT_POUCH "keybinding_human_interact_slot_left_pouch" +#define COMSIG_KB_HUMAN_INTERACT_SLOT_RIGHT_POUCH "keybinding_human_interact_slot_right_pouch" +#define COMSIG_KB_HUMAN_INTERACT_SUIT_S_STORE "keybinding_human_interact_slot_suit_storage" + +#define COMSIG_KB_HUMAN_INTERACT_QUICKEQUIP_DOWN "keybinding_human_interact_quickequip_down" +#define COMSIG_KB_HUMAN_INTERACT_SECONDARY_DOWN "keybinding_human_interact_secondary_down" +#define COMSIG_KB_HUMAN_INTERACT_TERTIARY_DOWN "keybinding_human_interact_tertiary_down" +#define COMSIG_KB_HUMAN_INTERACT_QUATERNARY_DOWN "keybinding_human_interact_quaternary_down" +#define COMSIG_KB_HUMAN_INTERACT_QUICK_EQUIP_DOWN "keybinding_human_interact_quick_equip_down" + +#define COMSIG_KB_HUMAN_INTERACT_PICK_UP "keybinding_human_interact_pick_up" + // Human Combat #define COMSIG_KB_HUMAN_WEAPON_FIELDSTRIP "keybinding_human_weapon_fieldstrip" #define COMSIG_KB_HUMAN_WEAPON_BURSTFIRE "keybinding_human_weapon_burstfire" @@ -74,6 +88,7 @@ #define COMSIG_KB_HUMAN_WEAPON_UNLOAD "keybinding_human_weapon_unload" #define COMSIG_KB_HUMAN_WEAPON_ATTACHMENT "keybinding_human_weapon_attachment" #define COMSIG_KB_HUMAN_WEAPON_ATTACHMENT_RAIL "keybinding_human_weapon_attachment_rail" +#define COMSIG_KB_HUMAN_WEAPON_SHOTGUN_TUBE "keybinding_human_weapon_shotgun_tube" #define COMSIG_KB_HUMAN_WEAPON_TOGGLE_IFF "keybinding_human_weapon_toggle_iff" @@ -185,6 +200,7 @@ //misc yautja #define COMSIG_KB_YAUTJA_TELE_LOC "keybinding_yautja_tele_loc" +#define COMSIG_KB_YAUTJA_FOLD_COMBISTICK "keybinding_yautja_fold_combistick" #define COMSIG_KB_OBSERVER_JOIN_XENO "keybinding_observer_join_as_xeno" #define COMSIG_KB_OBSERVER_JOIN_ERT "keybinding_observer_join_ert" @@ -198,6 +214,7 @@ #define CATEGORY_CARBON "CARBON" #define CATEGORY_HUMAN "HUMAN" #define CATEGORY_HUMAN_COMBAT "HUMAN COMBAT" +#define CATEGORY_HUMAN_INVENTORY "HUMAN INVENTORY" #define CATEGORY_ROBOT "ROBOT" #define CATEGORY_YAUTJA "YAUTJA" #define CATEGORY_MISC "MISC" diff --git a/code/__DEFINES/mobs.dm b/code/__DEFINES/mobs.dm index 1bd030313a43..072738184807 100644 --- a/code/__DEFINES/mobs.dm +++ b/code/__DEFINES/mobs.dm @@ -417,3 +417,4 @@ var/list/default_xeno_onmob_icons = list( #define HANDLING_LIMBS list("l_arm","l_hand", "r_arm", "r_hand") #define EXTREMITY_LIMBS list("l_leg","l_foot","r_leg","r_foot","l_arm","l_hand","r_arm","r_hand") #define CORE_LIMBS list("chest","head","groin") + diff --git a/code/__DEFINES/mode.dm b/code/__DEFINES/mode.dm index b73b2a0d89af..854da7a52b4c 100644 --- a/code/__DEFINES/mode.dm +++ b/code/__DEFINES/mode.dm @@ -240,7 +240,7 @@ var/global/list/whitelist_hierarchy = list(WHITELIST_NORMAL, WHITELIST_COUNCIL, #define FACTION_MONKEY "Monkey" // Nanu #define FACTION_LIST_MARINE list(FACTION_MARINE) -#define FACTION_LIST_HUMANOID list(FACTION_MARINE, FACTION_PMC, FACTION_WY, FACTION_WY_DEATHSQUAD, FACTION_CLF, FACTION_CONTRACTOR, FACTION_UPP, FACTION_FREELANCER, FACTION_SURVIVOR, FACTION_NEUTRAL, FACTION_COLONIST, FACTION_MERCENARY, FACTION_DUTCH, FACTION_HEFA, FACTION_GLADIATOR, FACTION_PIRATE, FACTION_PIZZA, FACTION_SOUTO, FACTION_YAUTJA, FACTION_ZOMBIE, FACTION_TWE) +#define FACTION_LIST_HUMANOID list(FACTION_MARINE, FACTION_PMC, FACTION_WY, FACTION_WY_DEATHSQUAD, FACTION_CLF, FACTION_CONTRACTOR, FACTION_MARSHAL, FACTION_UPP, FACTION_FREELANCER, FACTION_SURVIVOR, FACTION_NEUTRAL, FACTION_COLONIST, FACTION_MERCENARY, FACTION_DUTCH, FACTION_HEFA, FACTION_GLADIATOR, FACTION_PIRATE, FACTION_PIZZA, FACTION_SOUTO, FACTION_YAUTJA, FACTION_ZOMBIE, FACTION_TWE) #define FACTION_LIST_ERT list(FACTION_PMC, FACTION_WY_DEATHSQUAD, FACTION_CLF, FACTION_CONTRACTOR, FACTION_UPP, FACTION_FREELANCER, FACTION_MERCENARY, FACTION_DUTCH, FACTION_HEFA, FACTION_GLADIATOR, FACTION_PIRATE, FACTION_PIZZA, FACTION_SOUTO, FACTION_MARSHAL, FACTION_TWE) #define FACTION_LIST_WY list(FACTION_PMC, FACTION_WY_DEATHSQUAD, FACTION_WY) #define FACTION_LIST_MARINE_WY list(FACTION_MARINE, FACTION_PMC, FACTION_WY_DEATHSQUAD, FACTION_WY) diff --git a/code/__DEFINES/shuttles.dm b/code/__DEFINES/shuttles.dm index d283656ccae6..a3299184e4ef 100644 --- a/code/__DEFINES/shuttles.dm +++ b/code/__DEFINES/shuttles.dm @@ -100,10 +100,12 @@ #define MOBILE_SHUTTLE_ID_ERT_BIG "ert_boarding_shuttle" #define MOBILE_TRIJENT_ELEVATOR "trijentshuttle2" -#define STAT_TRIJENT_LZ1 "trigent_lz1" -#define STAT_TRIJENT_LZ2 "trigent_lz2" -#define STAT_TRIJENT_ENGI "trigent_engineering" -#define STAT_TRIJENT_OMEGA "trigent_omega" +#define STAT_TRIJENT_EMPTY "trijent_empty" +#define STAT_TRIJENT_OCCUPIED "trijent_occupied" +#define STAT_TRIJENT_LZ1 "trijent_lz1" +#define STAT_TRIJENT_LZ2 "trijent_lz2" +#define STAT_TRIJENT_ENGI "trijent_engineering" +#define STAT_TRIJENT_OMEGA "trijent_omega" #define MOBILE_SHUTTLE_LIFEBOAT_PORT "lifeboat-port" #define MOBILE_SHUTTLE_LIFEBOAT_STARBOARD "lifeboat-starboard" @@ -115,6 +117,7 @@ #define ALMAYER_DROPSHIP_LZ1 "almayer-hangar-lz1" #define ALMAYER_DROPSHIP_LZ2 "almayer-hangar-lz2" +#define DROPSHIP_FLYBY_ID "special_flight" #define DROPSHIP_LZ1 "dropship-lz1" #define DROPSHIP_LZ2 "dropship-lz2" diff --git a/code/__DEFINES/speech_channels.dm b/code/__DEFINES/speech_channels.dm index 3f6e4720bde9..5a9a74af8ad0 100644 --- a/code/__DEFINES/speech_channels.dm +++ b/code/__DEFINES/speech_channels.dm @@ -1,6 +1,7 @@ // Used to direct channels to speak into. #define SAY_CHANNEL "Say" #define COMMS_CHANNEL "Comms" +#define WHISPER_CHANNEL "Whisper" #define ME_CHANNEL "Me" #define OOC_CHANNEL "OOC" #define LOOC_CHANNEL "LOOC" diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm index 8a65a4b961ff..301ca0409655 100644 --- a/code/__DEFINES/subsystems.dm +++ b/code/__DEFINES/subsystems.dm @@ -109,36 +109,23 @@ // Subsystems shutdown in the reverse of the order they initialize in // The numbers just define the ordering, they are meaningless otherwise. -#define SS_INIT_TICKER_SPAWN 999 #define SS_INIT_INPUT 85 -#define SS_INIT_FAIL_TO_TOPIC 84 #define SS_INIT_TOPIC 83 #define SS_INIT_LOBBYART 82 -#define SS_INIT_RUST 30 #define SS_INIT_INFLUXDRIVER 28 -#define SS_INIT_SUPPLY_SHUTTLE 25 #define SS_INIT_GARBAGE 24 #define SS_INIT_EVENTS 23.5 -#define SS_INIT_JOB 23 +#define SS_INIT_HIJACK 22.6 #define SS_INIT_REDIS 22.5 #define SS_INIT_REAGENTS 22.1 #define SS_INIT_MAPPING 22 #define SS_INIT_NIGHTMARE 21.5 #define SS_INIT_TIMETRACK 21.1 #define SS_INIT_HUMANS 21 -#define SS_INIT_MAP 20 -#define SS_INIT_COMPONENT 19.5 #define SS_INIT_POWER 19 -#define SS_INIT_OBJECT 18 -#define SS_INIT_PIPENET 17.5 -#define SS_INIT_XENOARCH 17 -#define SS_INIT_MORE_INIT 16 -#define SS_INIT_AIR 15 -#define SS_INIT_TELEPORTER 13 #define SS_INIT_INFLUXMCSTATS 12 #define SS_INIT_INFLUXSTATS 11 #define SS_INIT_LIGHTING 10 -#define SS_INIT_DEFCON 9 #define SS_INIT_LAW 6 #define SS_INIT_FZ_TRANSITIONS 5 #define SS_INIT_PROJECTILES 4.1 @@ -152,12 +139,9 @@ #define SS_INIT_RADIO 2 #define SS_INIT_TIMER 100 #define SS_INIT_UNSPECIFIED 0 -#define SS_INIT_EMERGENCY_SHUTTLE -19 #define SS_INIT_ASSETS -20 #define SS_INIT_TICKER -21 #define SS_INIT_VOTE -23 -#define SS_INIT_FINISH -24 -#define SS_INIT_ADMIN -26 #define SS_INIT_DATABASE -27 #define SS_INIT_ENTITYMANAGER -28 #define SS_INIT_PLAYTIME -29 @@ -166,7 +150,6 @@ #define SS_INIT_MINIMAP -34 #define SS_INIT_STATPANELS -98 #define SS_INIT_CHAT -100 //Should be last to ensure chat remains smooth during init. -#define SS_INIT_EARLYRUNTIMES -500 // Post-init notifier // Subsystem fire priority, from lowest to highest priority // If the subsystem isn't listed here it's either DEFAULT or PROCESS (if it's a processing subsystem child) @@ -177,7 +160,6 @@ #define SS_PRIORITY_SOUND 250 #define SS_PRIORITY_TICKER 200 #define SS_PRIORITY_NIGHTMARE 180 -#define SS_PRIORITY_MAPVIEW 170 #define SS_PRIORITY_QUADTREE 160 #define SS_PRIORITY_CHAT 155 #define SS_PRIORITY_STATPANEL 154 @@ -195,20 +177,17 @@ #define SS_PRIORITY_VOTE 110 #define SS_PRIORITY_FAST_OBJECTS 105 #define SS_PRIORITY_OBJECTS 104 -#define SS_PRIORITY_FACEHUGGERS 100 #define SS_PRIORITY_DECORATOR 99 +#define SS_PRIORITY_HIJACK 97 #define SS_PRIORITY_POWER 95 #define SS_PRIORITY_EFFECTS 92 #define SS_PRIORITY_MACHINERY 90 #define SS_PRIORITY_FZ_TRANSITIONS 88 -#define SS_PRIORITY_PIPENET 85 #define SS_PRIORITY_ROUND_RECORDING 83 #define SS_PRIORITY_SHUTTLE 80 -#define SS_PRIORITY_TELEPORTER 75 #define SS_PRIORITY_EVENT 65 #define SS_PRIORITY_DISEASE 60 -#define SS_PRIORITY_FAST_MACHINERY 55 -#define SS_PRIORITY_MIDI 40 +#define SS_PRIORITY_DEFENSES 55 #define SS_PRIORITY_ENTITY 37 #define SS_PRIORITY_DEFCON 35 #define SS_PRIORITY_ACID_PILLAR 34 @@ -227,7 +206,6 @@ #define SS_PRIORITY_INFLUXSTATS 8 #define SS_PRIORITY_PLAYTIME 5 #define SS_PRIORITY_PERFLOGGING 4 -#define SS_PRIORITY_CORPSESPAWNER 3 #define SS_PRIORITY_GARBAGE 2 #define SS_PRIORITY_INACTIVITY 1 #define SS_PRIORITY_ADMIN 0 diff --git a/code/__DEFINES/surgery.dm b/code/__DEFINES/surgery.dm index 1bdf2318d250..9257172eeee5 100644 --- a/code/__DEFINES/surgery.dm +++ b/code/__DEFINES/surgery.dm @@ -149,7 +149,7 @@ See also /datum/surgery_step/saw_off_limb/failure var/list/cannot_hack, listing #define SURGERY_TOOLS_SEVER_BONE list(\ /obj/item/tool/surgery/circular_saw = SURGERY_TOOL_MULT_IDEAL,\ /obj/item/weapon/twohanded/fireaxe = SURGERY_TOOL_MULT_SUBOPTIMAL,\ - /obj/item/weapon/claymore/mercsword/machete = SURGERY_TOOL_MULT_SUBOPTIMAL,\ + /obj/item/weapon/sword/machete = SURGERY_TOOL_MULT_SUBOPTIMAL,\ /obj/item/tool/hatchet = SURGERY_TOOL_MULT_SUBSTITUTE,\ /obj/item/tool/kitchen/knife/butcher = SURGERY_TOOL_MULT_SUBSTITUTE,\ /obj/item/attachable/bayonet = SURGERY_TOOL_MULT_BAD_SUBSTITUTE\ diff --git a/code/__DEFINES/tgs.dm b/code/__DEFINES/tgs.dm index 6187a67825a4..0cc106ec9cf2 100644 --- a/code/__DEFINES/tgs.dm +++ b/code/__DEFINES/tgs.dm @@ -1,6 +1,6 @@ // tgstation-server DMAPI -#define TGS_DMAPI_VERSION "6.5.3" +#define TGS_DMAPI_VERSION "6.6.2" // All functions and datums outside this document are subject to change with any version and should not be relied on. @@ -129,6 +129,13 @@ /// DreamDaemon Ultrasafe security level. #define TGS_SECURITY_ULTRASAFE 2 +/// DreamDaemon public visibility level. +#define TGS_VISIBILITY_PUBLIC 0 +/// DreamDaemon private visibility level. +#define TGS_VISIBILITY_PRIVATE 1 +/// DreamDaemon invisible visibility level. +#define TGS_VISIBILITY_INVISIBLE 2 + //REQUIRED HOOKS /** @@ -458,6 +465,10 @@ /world/proc/TgsSecurityLevel() return +/// Returns the current BYOND visibility level as a TGS_VISIBILITY_ define if TGS is present, null otherwise. Requires TGS to be using interop API version 5 or higher otherwise the string "___unimplemented" wil be returned. This function may sleep if the call to [/world/proc/TgsNew] is sleeping! +/world/proc/TgsVisibility() + return + /// Returns a list of active [/datum/tgs_revision_information/test_merge]s if TGS is present, null otherwise. This function may sleep if the call to [/world/proc/TgsNew] is sleeping! /world/proc/TgsTestMerges() return diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm index f7f481fbe236..33f9456a0646 100644 --- a/code/__DEFINES/traits.dm +++ b/code/__DEFINES/traits.dm @@ -1,22 +1,20 @@ -//shamelessly ripped from TG #define SIGNAL_ADDTRAIT(trait_ref) "addtrait [trait_ref]" #define SIGNAL_REMOVETRAIT(trait_ref) "removetrait [trait_ref]" // trait accessor defines -//here be dragons #define ADD_TRAIT(target, trait, source) \ do { \ var/list/_L; \ - if (!target.status_traits) { \ - target.status_traits = list(); \ - _L = target.status_traits; \ + if (!target._status_traits) { \ + target._status_traits = list(); \ + _L = target._status_traits; \ _L[trait] = list(source); \ SEND_SIGNAL(target, SIGNAL_ADDTRAIT(trait), trait); \ if(trait in GLOB.traits_with_elements){ \ target.AddElement(GLOB.traits_with_elements[trait]); \ } \ } else { \ - _L = target.status_traits; \ + _L = target._status_traits; \ if (_L[trait]) { \ _L[trait] |= list(source); \ } else { \ @@ -30,16 +28,16 @@ } while (0) #define REMOVE_TRAIT(target, trait, sources) \ do { \ - var/list/_L = target.status_traits; \ + var/list/_L = target._status_traits; \ var/list/_S; \ if (sources && !islist(sources)) { \ _S = list(sources); \ } else { \ _S = sources\ }; \ - if (_L && _L[trait]) { \ + if (_L?[trait]) { \ for (var/_T in _L[trait]) { \ - if ((!_S && (_T != TRAIT_SOURCE_QUIRK)) || (_T in _S)) { \ + if ((!_S && (_T != ROUNDSTART_TRAIT)) || (_T in _S)) { \ _L[trait] -= _T \ } \ };\ @@ -51,13 +49,40 @@ } \ }; \ if (!length(_L)) { \ - target.status_traits = null \ + target._status_traits = null \ + }; \ + } \ + } while (0) +#define REMOVE_TRAIT_NOT_FROM(target, trait, sources) \ + do { \ + var/list/_traits_list = target._status_traits; \ + var/list/_sources_list; \ + if (sources && !islist(sources)) { \ + _sources_list = list(sources); \ + } else { \ + _sources_list = sources\ + }; \ + if (_traits_list?[trait]) { \ + for (var/_trait_source in _traits_list[trait]) { \ + if (!(_trait_source in _sources_list)) { \ + _traits_list[trait] -= _trait_source \ + } \ + };\ + if (!length(_traits_list[trait])) { \ + _traits_list -= trait; \ + SEND_SIGNAL(target, SIGNAL_REMOVETRAIT(trait), trait); \ + if(trait in GLOB.traits_with_elements) { \ + target.RemoveElement(GLOB.traits_with_elements[trait]); \ + } \ + }; \ + if (!length(_traits_list)) { \ + target._status_traits = null \ }; \ } \ } while (0) #define REMOVE_TRAITS_NOT_IN(target, sources) \ do { \ - var/list/_L = target.status_traits; \ + var/list/_L = target._status_traits; \ var/list/_S = sources; \ if (_L) { \ for (var/_T in _L) { \ @@ -65,20 +90,20 @@ if (!length(_L[_T])) { \ _L -= _T; \ SEND_SIGNAL(target, SIGNAL_REMOVETRAIT(_T), _T); \ - if(_T in GLOB.traits_with_elements) { \ - target.RemoveElement(GLOB.traits_with_elements[_T]); \ + if(trait in GLOB.traits_with_elements) { \ + target.RemoveElement(GLOB.traits_with_elements[trait]); \ }; \ };\ };\ if (!length(_L)) { \ - target.status_traits = null\ + target._status_traits = null\ };\ }\ } while (0) #define REMOVE_TRAITS_IN(target, sources) \ do { \ - var/list/_L = target.status_traits; \ + var/list/_L = target._status_traits; \ var/list/_S = sources; \ if (sources && !islist(sources)) { \ _S = list(sources); \ @@ -97,25 +122,32 @@ };\ };\ if (!length(_L)) { \ - target.status_traits = null\ + target._status_traits = null\ };\ }\ } while (0) -#define HAS_TRAIT(target, trait) (target.status_traits ? (target.status_traits[trait] ? TRUE : FALSE) : FALSE) -#define HAS_TRAIT_FROM(target, trait, source) (target.status_traits ? (target.status_traits[trait] ? (source in target.status_traits[trait]) : FALSE) : FALSE) -#define HAS_TRAIT_FROM_ONLY(target, trait, source) (\ - target.status_traits ?\ - (target.status_traits[trait] ?\ - ((source in target.status_traits[trait]) && (length(target.status_traits) == 1))\ - : FALSE)\ - : FALSE) -#define HAS_TRAIT_NOT_FROM(target, trait, source) (target.status_traits ? (target.status_traits[trait] ? (length(target.status_traits[trait] - source) > 0) : FALSE) : FALSE) - +#define HAS_TRAIT(target, trait) (target._status_traits?[trait] ? TRUE : FALSE) +#define HAS_TRAIT_FROM(target, trait, source) (HAS_TRAIT(target, trait) && (source in target._status_traits[trait])) +#define HAS_TRAIT_FROM_ONLY(target, trait, source) (HAS_TRAIT(target, trait) && (source in target._status_traits[trait]) && (length(target._status_traits[trait]) == 1)) +#define HAS_TRAIT_NOT_FROM(target, trait, source) (HAS_TRAIT(target, trait) && (length(target._status_traits[trait] - source) > 0)) +/// Returns a list of trait sources for this trait. Only useful for wacko cases and internal futzing +/// You should not be using this +#define GET_TRAIT_SOURCES(target, trait) (target._status_traits?[trait] || list()) +/// Returns the amount of sources for a trait. useful if you don't want to have a "thing counter" stuck around all the time +#define COUNT_TRAIT_SOURCES(target, trait) length(GET_TRAIT_SOURCES(target, trait)) +/// A simple helper for checking traits in a mob's mind +#define HAS_MIND_TRAIT(target, trait) (HAS_TRAIT(target, trait) || (target.mind ? HAS_TRAIT(target.mind, trait) : FALSE)) /// Example trait // #define TRAIT_X "t_x" + //-- mob traits -- +/// Prevents voluntary movement. +#define TRAIT_IMMOBILIZED "immobilized" +/// Apply this to make a mob not dense, and remove it when you want it to no longer make them undense, other sorces of undesity will still apply. Always define a unique source when adding a new instance of this! +#define TRAIT_UNDENSE "undense" + // SPECIES TRAITS /// Knowledge of Yautja technology #define TRAIT_YAUTJA_TECH "t_yautja_tech" @@ -208,6 +240,9 @@ /// Can lockout blackmarket from ASRS console circuits. #define TRAIT_TOOL_TRADEBAND "t_tool_tradeband" +/// Can hack ASRS consoles to access the black market +#define TRAIT_TOOL_BLACKMARKET_HACKER "t_tool_blackmarket_hacker" + // CLOTHING TRAITS #define TRAIT_CLOTHING_HOOD "t_clothing_hood" @@ -264,6 +299,8 @@ GLOBAL_LIST_INIT(mob_traits, list( */ GLOBAL_LIST_INIT(traits_by_type, list( /mob = list( + "TRAIT_IMMOBILIZED" = TRAIT_IMMOBILIZED, + "TRAIT_UNDENSE" = TRAIT_UNDENSE, "TRAIT_YAUTJA_TECH" = TRAIT_YAUTJA_TECH, "TRAIT_SUPER_STRONG" = TRAIT_SUPER_STRONG, "TRAIT_FOREIGN_BIO" = TRAIT_FOREIGN_BIO, @@ -339,15 +376,17 @@ GLOBAL_LIST(trait_name_map) /// Example trait source // #define TRAIT_SOURCE_Y "t_s_y" #define TRAIT_SOURCE_INHERENT "t_s_inherent" +/// cannot be removed without admin intervention +#define ROUNDSTART_TRAIT "roundstart" //-- mob traits -- +///Status trait coming from lying down through update_canmove() +#define LYING_TRAIT "lying" ///Status trait coming from species. .human/species_gain() #define TRAIT_SOURCE_SPECIES "t_s_species" ///Status trait coming from the hive. #define TRAIT_SOURCE_HIVE "t_s_hive" ///Status trait coming from being buckled. #define TRAIT_SOURCE_BUCKLE "t_s_buckle" -///Status trait coming from roundstart quirks (that don't exist yet). Unremovable by REMOVE_TRAIT -#define TRAIT_SOURCE_QUIRK "t_s_quirk" ///Status trait coming from being assigned as [acting] squad leader. #define TRAIT_SOURCE_SQUAD_LEADER "t_s_squad_leader" ///Status trait coming from their job @@ -366,6 +405,8 @@ GLOBAL_LIST(trait_name_map) #define TRAIT_SOURCE_ABILITY(ability) "t_s_ability_[ability]" ///Status trait forced by the xeno action charge #define TRAIT_SOURCE_XENO_ACTION_CHARGE "t_s_xeno_action_charge" +///Status trait coming from a xeno nest +#define XENO_NEST_TRAIT "xeno_nest" //-- structure traits -- ///Status trait coming from being flipped or unflipped. #define TRAIT_SOURCE_FLIP_TABLE "t_s_flip_table" @@ -377,3 +418,14 @@ GLOBAL_LIST(trait_name_map) //Status trait coming from clothing. #define TRAIT_SOURCE_CLOTHING "t_s_clothing" + +/// traits associated with actively interacted machinery +#define INTERACTION_TRAIT "interaction" +/// trait effect related to active specialist gear +#define SPECIALIST_GEAR_TRAIT "specialist_gear" +/// traits associated with usage of snowflake dropship double seats +#define DOUBLE_SEATS_TRAIT "double_seats" +/// traits associated with xeno on-ground weeds +#define XENO_WEED_TRAIT "xeno_weed" +/// traits from chloroform usage +#define CHLOROFORM_TRAIT "chloroform" diff --git a/code/__DEFINES/urls.dm b/code/__DEFINES/urls.dm index 137095327a2c..5d3fca1a2032 100644 --- a/code/__DEFINES/urls.dm +++ b/code/__DEFINES/urls.dm @@ -1,3 +1,7 @@ +// placeholder strings to be replaced +#define WIKI_PLACEHOLDER "%WIKIURL%" +#define LAW_PLACEHOLDER "%LAWURL%" + // ------ MISC WIKI LINKS ------ // #define URL_WIKI_LAW "Marine_Law" #define URL_WIKI_XENO_QUICKSTART "Xeno_Quickstart_Guide" diff --git a/code/__DEFINES/vehicle.dm b/code/__DEFINES/vehicle.dm index 9c6685085788..8a1617229926 100644 --- a/code/__DEFINES/vehicle.dm +++ b/code/__DEFINES/vehicle.dm @@ -53,5 +53,6 @@ #define VEHICLE_CLASS_LIGHT (1<<2) //light class armor (APC, tank) #define VEHICLE_CLASS_MEDIUM (1<<3) //medium class armor (tank) #define VEHICLE_CLASS_HEAVY (1<<4) //heavy class armor (tank) - -#define TANK_POPLOCK 90 +// Other vehicle flags +/// Vehicle can bypass vehicle blockers, typically going further into maps than intended +#define VEHICLE_BYPASS_BLOCKERS (1<<5) diff --git a/code/__DEFINES/xeno.dm b/code/__DEFINES/xeno.dm index b178f0692dd6..a0a4c927d3d9 100644 --- a/code/__DEFINES/xeno.dm +++ b/code/__DEFINES/xeno.dm @@ -174,6 +174,10 @@ /// The time it takes for a pylon to give one larva while activated #define XENO_PYLON_ACTIVATION_COOLDOWN (5 MINUTES) +/// The time until you can re-corrupt a comms relay after the last pylon was destroyed +#define XENO_PYLON_DESTRUCTION_DELAY (5 MINUTES) + + /// The time against away_timer when an AFK xeno larva can be replaced #define XENO_LEAVE_TIMER_LARVA 80 //80 seconds /// The time against away_timer when an AFK xeno (not larva) can be replaced diff --git a/code/__HELPERS/game.dm b/code/__HELPERS/game.dm index 66ecf9ea034f..37c623bc3215 100644 --- a/code/__HELPERS/game.dm +++ b/code/__HELPERS/game.dm @@ -294,6 +294,8 @@ if(sorted && length(candidates)) candidates = sort_list(candidates, GLOBAL_PROC_REF(cmp_obs_larvaqueuetime_asc)) + GLOB.xeno_queue_candidate_count = length(candidates) + return candidates /** @@ -309,11 +311,11 @@ var/mob/dead/observer/cur_obs = candidates[i] // Generate the messages - var/cached_message = SPAN_XENONOTICE("You are currently [i-dequeued]\th in the larva queue.") + var/cached_message = "You are currently [i-dequeued]\th in the larva queue." cur_obs.larva_queue_cached_message = cached_message if(!cache_only) var/chat_message = dequeued ? replacetext(cached_message, "currently", "now") : cached_message - to_chat(candidates[i], chat_message) + to_chat(candidates[i], SPAN_XENONOTICE(chat_message)) /proc/convert_k2c(temp) return ((temp - T0C)) diff --git a/code/__HELPERS/icons.dm b/code/__HELPERS/icons.dm index 99f621919771..1116f1acb2a8 100644 --- a/code/__HELPERS/icons.dm +++ b/code/__HELPERS/icons.dm @@ -329,7 +329,8 @@ world /// appearance system (overlays/underlays, etc.) is not available. /// /// Only the first argument is required. -/proc/getFlatIcon(image/appearance, defdir, deficon, defstate, defblend, start = TRUE, no_anim = FALSE) +/// appearance_flags indicates whether appearance_flags should be respected (at the cost of about 10-20% perf) +/proc/getFlatIcon(image/appearance, defdir, deficon, defstate, defblend, start = TRUE, no_anim = FALSE, appearance_flags = FALSE) // Loop through the underlays, then overlays, sorting them into the layers list #define PROCESS_OVERLAYS_OR_UNDERLAYS(flat, process, base_layer) \ for (var/i in 1 to process.len) { \ @@ -435,11 +436,21 @@ world if(layer_image.alpha == 0) continue + // variables only relevant when accounting for appearance_flags: + var/apply_color = TRUE + var/apply_alpha = TRUE + if(layer_image == copy) // 'layer_image' is an /image based on the object being flattened. curblend = BLEND_OVERLAY add = icon(layer_image.icon, layer_image.icon_state, base_icon_dir) else // 'I' is an appearance object. - add = getFlatIcon(image(layer_image), curdir, curicon, curstate, curblend, FALSE, no_anim) + var/image/layer_as_image = image(layer_image) + if(appearance_flags) + if(layer_as_image.appearance_flags & RESET_COLOR) + apply_color = FALSE + if(layer_as_image.appearance_flags & RESET_ALPHA) + apply_alpha = FALSE + add = getFlatIcon(layer_as_image, curdir, curicon, curstate, curblend, FALSE, no_anim, appearance_flags) if(!add) continue @@ -451,9 +462,9 @@ world if ( addX1 != flatX1 \ - && addX2 != flatX2 \ - && addY1 != flatY1 \ - && addY2 != flatY2 \ + || addX2 != flatX2 \ + || addY1 != flatY1 \ + || addY2 != flatY2 \ ) // Resize the flattened icon so the new icon fits flat.Crop( @@ -464,21 +475,34 @@ world ) flatX1 = addX1 - flatX2 = addY1 - flatY1 = addX2 + flatX2 = addX2 + flatY1 = addY1 flatY2 = addY2 + if(appearance_flags) + // apply parent's color/alpha to the added layers if the layer didn't opt + if(apply_color && appearance.color) + if(islist(appearance.color)) + add.MapColors(arglist(appearance.color)) + else + add.Blend(appearance.color, ICON_MULTIPLY) + + if(apply_alpha && appearance.alpha < 255) + add.Blend(rgb(255, 255, 255, appearance.alpha), ICON_MULTIPLY) + // Blend the overlay into the flattened icon flat.Blend(add, blendMode2iconMode(curblend), layer_image.pixel_x + 2 - flatX1, layer_image.pixel_y + 2 - flatY1) - if(appearance.color) - if(islist(appearance.color)) - flat.MapColors(arglist(appearance.color)) - else - flat.Blend(appearance.color, ICON_MULTIPLY) + if(!appearance_flags) + // If we didn't apply parent colors individually per layer respecting appearance_flags, then do it just the one time now + if(appearance.color) + if(islist(appearance.color)) + flat.MapColors(arglist(appearance.color)) + else + flat.Blend(appearance.color, ICON_MULTIPLY) - if(appearance.alpha < 255) - flat.Blend(rgb(255, 255, 255, appearance.alpha), ICON_MULTIPLY) + if(appearance.alpha < 255) + flat.Blend(rgb(255, 255, 255, appearance.alpha), ICON_MULTIPLY) if(no_anim) //Clean up repeated frames @@ -708,11 +732,12 @@ world if (isnull(dir)) dir = thing.dir - if (ishuman(thing)) // Shitty workaround for a BYOND issue. + // Commented out because this is seemingly our source of bad icon operations + /* if (ishuman(thing)) // Shitty workaround for a BYOND issue. var/icon/temp = icon2collapse icon2collapse = icon() icon2collapse.Insert(temp, dir = SOUTH) - dir = SOUTH + dir = SOUTH*/ else if (isnull(dir)) dir = SOUTH @@ -852,22 +877,93 @@ world return image_to_center //For creating consistent icons for human looking simple animals -/proc/get_flat_human_icon(icon_id, datum/equipment_preset/preset, datum/preferences/prefs, dummy_key, showDirs = GLOB.cardinals, outfit_override) +/proc/get_flat_human_icon(icon_id, equipment_preset_dresscode, datum/preferences/prefs, dummy_key, showDirs = GLOB.cardinals, outfit_override) var/static/list/humanoid_icon_cache = list() if(!icon_id || !humanoid_icon_cache[icon_id]) var/mob/living/carbon/human/dummy/body = generate_or_wait_for_human_dummy(dummy_key) + if(prefs) prefs.copy_all_to(body) - arm_equipment(body, preset) + body.update_body() + body.update_hair() + + // Assumption: Is a list + if(outfit_override) + for(var/obj/item/cur_item as anything in outfit_override) + body.equip_to_appropriate_slot(cur_item) + + // Assumption: Is a string or path + if(equipment_preset_dresscode) + arm_equipment(body, equipment_preset_dresscode) var/icon/out_icon = icon('icons/effects/effects.dmi', "nothing") - for(var/D in showDirs) - body.setDir(D) + for(var/dir in showDirs) + body.setDir(dir) var/icon/partial = getFlatIcon(body) - out_icon.Insert(partial, dir = D) + out_icon.Insert(partial, dir = dir) humanoid_icon_cache[icon_id] = out_icon dummy_key ? unset_busy_human_dummy(dummy_key) : qdel(body) return out_icon else return humanoid_icon_cache[icon_id] + +/proc/get_flat_human_copy_icon(mob/living/carbon/human/original, equipment_preset_dresscode, showDirs = GLOB.cardinals, outfit_override) + var/mob/living/carbon/human/dummy/body = generate_or_wait_for_human_dummy(null) + + if(original) + // From /datum/preferences/proc/copy_appearance_to + body.age = original.age + body.gender = original.gender + body.ethnicity = original.ethnicity + body.body_type = original.body_type + + body.r_eyes = original.r_eyes + body.g_eyes = original.g_eyes + body.b_eyes = original.b_eyes + + body.r_hair = original.r_hair + body.g_hair = original.g_hair + body.b_hair = original.b_hair + + body.r_gradient = original.r_gradient + body.g_gradient = original.g_gradient + body.b_gradient = original.b_gradient + body.grad_style = original.grad_style + + body.r_facial = original.r_facial + body.g_facial = original.g_facial + body.b_facial = original.b_facial + + body.r_skin = original.r_skin + body.g_skin = original.g_skin + body.b_skin = original.b_skin + + body.h_style = original.h_style + body.f_style = original.f_style + + body.underwear = original.underwear + body.undershirt = original.undershirt + + body.update_body() + body.update_hair() + + // Assumption: Is a list + if(outfit_override) + for(var/obj/item/cur_item as anything in outfit_override) + body.equip_to_appropriate_slot(cur_item) + + // Assumption: Is a string or path + if(equipment_preset_dresscode) + arm_equipment(body, equipment_preset_dresscode) + + var/icon/out_icon = icon('icons/effects/effects.dmi', "nothing") + for(var/dir in showDirs) + body.setDir(dir) + var/icon/partial = getFlatIcon(body) + out_icon.Insert(partial, dir = dir) + + // log_debug("get_flat_human_copy_icon called on ref=[REF(original)], instance=[original], type=[original.type], with [length(original.overlays)] overlays reduced to [length(body.overlays)] overlays") + + qdel(body) + return out_icon diff --git a/code/__HELPERS/job.dm b/code/__HELPERS/job.dm index 43902b07cfd9..89fe6877647e 100644 --- a/code/__HELPERS/job.dm +++ b/code/__HELPERS/job.dm @@ -26,13 +26,6 @@ if(I.assignment in GLOB.joblist) return I.assignment return "Unknown" -/proc/FindNameFromID(mob/living/carbon/human/H) - ASSERT(istype(H)) - var/obj/item/card/id/I = H.wear_id - if(istype(I)) return I.registered_name - I = H.get_active_hand() - if(istype(I)) return I.registered_name - /proc/get_all_job_icons() return GLOB.joblist + list("Prisoner")//For all existing HUD icons /obj/proc/GetJobName() //Used in secHUD icon generation diff --git a/code/__HELPERS/traits.dm b/code/__HELPERS/traits.dm new file mode 100644 index 000000000000..ba99b2e1e7ff --- /dev/null +++ b/code/__HELPERS/traits.dm @@ -0,0 +1,43 @@ +#define TRAIT_CALLBACK_ADD(target, trait, source) CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(___TraitAdd), ##target, ##trait, ##source) +#define TRAIT_CALLBACK_REMOVE(target, trait, source) CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(___TraitRemove), ##target, ##trait, ##source) + +///DO NOT USE ___TraitAdd OR ___TraitRemove as a replacement for ADD_TRAIT / REMOVE_TRAIT defines. To be used explicitly for callback. +/proc/___TraitAdd(target,trait,source) + if(!target || !trait || !source) + return + if(islist(target)) + for(var/i in target) + if(!isatom(i)) + continue + var/atom/the_atom = i + ADD_TRAIT(the_atom,trait,source) + else if(isatom(target)) + var/atom/the_atom2 = target + ADD_TRAIT(the_atom2,trait,source) + +///DO NOT USE ___TraitAdd OR ___TraitRemove as a replacement for ADD_TRAIT / REMOVE_TRAIT defines. To be used explicitly for callback. +/proc/___TraitRemove(target,trait,source) + if(!target || !trait || !source) + return + if(islist(target)) + for(var/i in target) + if(!isatom(i)) + continue + var/atom/the_atom = i + REMOVE_TRAIT(the_atom,trait,source) + else if(isatom(target)) + var/atom/the_atom2 = target + REMOVE_TRAIT(the_atom2,trait,source) + + +/// Proc that handles adding multiple traits to a target via a list. Must have a common source and target. +/datum/proc/add_traits(list/list_of_traits, source) + ASSERT(islist(list_of_traits), "Invalid arguments passed to add_traits! Invoked on [src] with [list_of_traits], source being [source].") + for(var/trait in list_of_traits) + ADD_TRAIT(src, trait, source) + +/// Proc that handles removing multiple traits from a target via a list. Must have a common source and target. +/datum/proc/remove_traits(list/list_of_traits, source) + ASSERT(islist(list_of_traits), "Invalid arguments passed to remove_traits! Invoked on [src] with [list_of_traits], source being [source].") + for(var/trait in list_of_traits) + REMOVE_TRAIT(src, trait, source) diff --git a/code/__HELPERS/type2type.dm b/code/__HELPERS/type2type.dm index 4e4a1b3ff31c..5d0d113b0c55 100644 --- a/code/__HELPERS/type2type.dm +++ b/code/__HELPERS/type2type.dm @@ -21,7 +21,7 @@ var/char = copytext(hex, i, i + 1) switch(char) if("0") - //Apparently, switch works with empty statements, yay! If that doesn't work, blame me, though. -- Urist + pass() if("9", "8", "7", "6", "5", "4", "3", "2", "1") num += text2num(char) * 16 ** power if("a", "A") @@ -77,7 +77,6 @@ hex += "E" if(15.0) hex += "F" - else power-- while(length(hex) < placeholder) hex = text("0[]", hex) @@ -165,8 +164,6 @@ return 6 if("SOUTHWEST") return 10 - else - return //Converts an angle (degrees) into an ss13 direction /proc/angle2dir(degree) diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm index 5683d6e684d1..e380b064a477 100644 --- a/code/__HELPERS/unsorted.dm +++ b/code/__HELPERS/unsorted.dm @@ -21,16 +21,16 @@ #define between(low, middle, high) (max(min(middle, high), low)) //Offuscate x for coord system -#define obfuscate_x(x) (x + obfs_x) +#define obfuscate_x(x) (x + GLOB.obfs_x) //Offuscate y for coord system -#define obfuscate_y(y) (y + obfs_y) +#define obfuscate_y(y) (y + GLOB.obfs_y) //Deoffuscate x for coord system -#define deobfuscate_x(x) (x - obfs_x) +#define deobfuscate_x(x) (x - GLOB.obfs_x) //Deoffuscate y for coord system -#define deobfuscate_y(y) (y - obfs_y) +#define deobfuscate_y(y) (y - GLOB.obfs_y) #define can_xeno_build(T) (!T.density && !(locate(/obj/structure/fence) in T) && !(locate(/obj/structure/tunnel) in T) && (locate(/obj/effect/alien/weeds) in T)) diff --git a/code/__odlint.dm b/code/__odlint.dm new file mode 100644 index 000000000000..f42517133746 --- /dev/null +++ b/code/__odlint.dm @@ -0,0 +1,11 @@ +// This file is included right at the start of the DME. +// Its purpose is to enable multiple lints (pragmas) that are supported by OpenDream to better validate the codebase +// These are essentially nitpicks the DM compiler should pick up on but doesnt + +#ifndef SPACEMAN_DMM +#ifdef OPENDREAM +// These are in their own file as you need to do it with an include as a hack to avoid +// SpacemanDMM evaluating the #pragma lines, even if its outside a block it cares about +#include "__pragmas.dm" +#endif +#endif diff --git a/code/__pragmas.dm b/code/__pragmas.dm new file mode 100644 index 000000000000..39c14e1bbc95 --- /dev/null +++ b/code/__pragmas.dm @@ -0,0 +1,27 @@ +//1000-1999 +#pragma FileAlreadyIncluded error +#pragma MissingIncludedFile error +#pragma MisplacedDirective error +#pragma UndefineMissingDirective error +#pragma DefinedMissingParen error +#pragma ErrorDirective error +#pragma WarningDirective error +#pragma MiscapitalizedDirective error + +//2000-2999 +#pragma SoftReservedKeyword error +#pragma DuplicateVariable error +#pragma DuplicateProcDefinition error +#pragma TooManyArguments error +#pragma PointlessParentCall error +#pragma PointlessBuiltinCall error +#pragma SuspiciousMatrixCall error +#pragma MalformedRange error +#pragma InvalidRange error +#pragma InvalidSetStatement error +#pragma InvalidOverride error +#pragma DanglingVarType error +#pragma MissingInterpolatedExpression error + +//3000-3999 +#pragma EmptyBlock error diff --git a/code/_byond_version_compat.dm b/code/_byond_version_compat.dm index 719d85654b5f..26968f0f837c 100644 --- a/code/_byond_version_compat.dm +++ b/code/_byond_version_compat.dm @@ -3,7 +3,7 @@ //Update this whenever you need to take advantage of more recent byond features #define MIN_COMPILER_VERSION 514 #define MIN_COMPILER_BUILD 1588 -#if (DM_VERSION < MIN_COMPILER_VERSION || DM_BUILD < MIN_COMPILER_BUILD) && !defined(SPACEMAN_DMM) +#if (DM_VERSION < MIN_COMPILER_VERSION || DM_BUILD < MIN_COMPILER_BUILD) && !defined(SPACEMAN_DMM) && !defined(OPENDREAM) //Don't forget to update this part #error Your version of BYOND is too out-of-date to compile this project. Go to https://secure.byond.com/download and update. #error You need version 514.1588 or higher diff --git a/code/_compile_options.dm b/code/_compile_options.dm index 0f81b0173ac1..20aa2081318c 100644 --- a/code/_compile_options.dm +++ b/code/_compile_options.dm @@ -30,7 +30,7 @@ #define CBT #endif -#if !defined(CBT) && !defined(SPACEMAN_DMM) +#if !defined(CBT) && !defined(SPACEMAN_DMM) && !defined(OPENDREAM) #warn Building with Dream Maker is no longer supported and will result in errors. #warn In order to build, run BUILD.bat in the bin directory. #warn Consider switching to VSCode editor instead, where you can press Ctrl+Shift+B to build. diff --git a/code/_globalvars/bitfields.dm b/code/_globalvars/bitfields.dm index 53dd40ff6035..b85aa18fdb6b 100644 --- a/code/_globalvars/bitfields.dm +++ b/code/_globalvars/bitfields.dm @@ -166,7 +166,6 @@ DEFINE_BITFIELD(flags_item, list( "ITEM_OVERRIDE_NORTHFACE" = ITEM_OVERRIDE_NORTHFACE, "CAN_DIG_SHRAPNEL" = CAN_DIG_SHRAPNEL, "ANIMATED_SURGICAL_TOOL" = ANIMATED_SURGICAL_TOOL, - "NOTABLEMERGE" = NOTABLEMERGE, "IGNITING_ITEM" = IGNITING_ITEM, )) @@ -462,3 +461,11 @@ DEFINE_BITFIELD(vend_flags, list( "VEND_FACTION_THEMES" = VEND_FACTION_THEMES, "VEND_USE_VENDOR_FLAGS" = VEND_USE_VENDOR_FLAGS, )) + +DEFINE_BITFIELD(vehicle_flags, list( + "VEHICLE_CLASS_WEAK" = VEHICLE_CLASS_WEAK, + "VEHICLE_CLASS_LIGHT" = VEHICLE_CLASS_LIGHT, + "VEHICLE_CLASS_MEDIUM" = VEHICLE_CLASS_MEDIUM, + "VEHICLE_CLASS_HEAVY" = VEHICLE_CLASS_HEAVY, + "VEHICLE_BYPASS_BLOCKERS" = VEHICLE_BYPASS_BLOCKERS, +)) diff --git a/code/_globalvars/global_lists.dm b/code/_globalvars/global_lists.dm index 36058a44fc37..1e1e9cefd5db 100644 --- a/code/_globalvars/global_lists.dm +++ b/code/_globalvars/global_lists.dm @@ -1,6 +1,3 @@ - -var/list/unansweredAhelps = list() //This feels inefficient, but I can't think of a better way. Stores the message indexed by CID - GLOBAL_LIST_EMPTY(PressFaxes) GLOBAL_LIST_EMPTY(WYFaxes) //Departmental faxes GLOBAL_LIST_EMPTY(USCMFaxes) diff --git a/code/_globalvars/lists/object_lists.dm b/code/_globalvars/lists/object_lists.dm index 3a417625538b..3db9bd28cbfe 100644 --- a/code/_globalvars/lists/object_lists.dm +++ b/code/_globalvars/lists/object_lists.dm @@ -31,3 +31,6 @@ GLOBAL_LIST_EMPTY_TYPED(all_multi_vehicles, /obj/vehicle/multitile) GLOBAL_LIST_EMPTY_TYPED(lifeboat_almayer_docks, /obj/docking_port/stationary/lifeboat_dock) GLOBAL_LIST_EMPTY_TYPED(lifeboat_doors, /obj/structure/machinery/door/airlock/multi_tile/almayer/dropshiprear/lifeboat/blastdoor) + +GLOBAL_LIST_EMPTY_TYPED(teleporters, /datum/teleporter) +GLOBAL_LIST_EMPTY(teleporters_by_id) diff --git a/code/_globalvars/misc.dm b/code/_globalvars/misc.dm index 6c689e995504..44f4b2c4010f 100644 --- a/code/_globalvars/misc.dm +++ b/code/_globalvars/misc.dm @@ -27,3 +27,13 @@ GLOBAL_VAR_INIT(time_offset, setup_offset()) /// Sets the offset 2 lines above. /proc/setup_offset() return rand(10 MINUTES, 24 HOURS) + +/// The last count of possible candidates in the xeno larva queue (updated via get_alien_candidates) +GLOBAL_VAR(xeno_queue_candidate_count) + +//Coordinate obsfucator +//Used by the rangefinders and linked systems to prevent coords collection/prefiring +/// A number between -500 and 500. +GLOBAL_VAR(obfs_x) +/// A number between -500 and 500. +GLOBAL_VAR(obfs_y) diff --git a/code/_onclick/adjacent.dm b/code/_onclick/adjacent.dm index dd7a528bb8a6..6504db0d9f0c 100644 --- a/code/_onclick/adjacent.dm +++ b/code/_onclick/adjacent.dm @@ -94,6 +94,11 @@ Quick adjacency (to turf): /obj/item/Adjacent(atom/neighbor, recurse = 1) if(neighbor == loc || (loc && neighbor == loc.loc)) return TRUE + + // Internal storages have special relationships with the object they are connected to and we still want two depth adjacency for storages + if(istype(loc?.loc, /obj/item/storage/internal) && recurse > 0) + return loc.loc.Adjacent(neighbor, recurse) + if(issurface(loc)) return loc.Adjacent(neighbor, recurse) //Surfaces don't count as storage depth. else if(istype(loc, /obj/item)) diff --git a/code/_onclick/click_hold.dm b/code/_onclick/click_hold.dm index f65dd33c2eea..996f7ed2bf3b 100644 --- a/code/_onclick/click_hold.dm +++ b/code/_onclick/click_hold.dm @@ -94,3 +94,12 @@ // Add the hovered atom to the trace LAZYADD(mouse_trace_history, over_obj) + +/client/MouseDrop(datum/over_object, datum/src_location, over_location, src_control, over_control, params) + . = ..() + + if(src_location) + SEND_SIGNAL(src_location, COMSIG_ATOM_DROPPED_ON, over_object, src) + + if(over_object) + SEND_SIGNAL(over_object, COMSIG_ATOM_DROP_ON, src_location, src) diff --git a/code/_onclick/hud/ghost.dm b/code/_onclick/hud/ghost.dm index a6754747a019..a99129d09bcd 100644 --- a/code/_onclick/hud/ghost.dm +++ b/code/_onclick/hud/ghost.dm @@ -48,6 +48,14 @@ var/mob/dead/observer/G = usr G.reenter_corpse() +/atom/movable/screen/ghost/toggle_huds + name = "Toggle HUDs" + icon_state = "ghost_hud_toggle" + +/atom/movable/screen/ghost/toggle_huds/Click() + var/client/client = usr.client + client.toggle_ghost_hud() + /datum/hud/ghost/New(mob/owner, ui_style='icons/mob/hud/human_white.dmi', ui_color, ui_alpha = 230) . = ..() var/atom/movable/screen/using @@ -68,6 +76,9 @@ using.screen_loc = ui_ghost_slot4 static_inventory += using + using = new /atom/movable/screen/ghost/toggle_huds() + using.screen_loc = ui_ghost_slot5 + static_inventory += using /datum/hud/ghost/show_hud(version = 0, mob/viewmob) // don't show this HUD if observing; show the HUD of the observee diff --git a/code/_onclick/hud/human.dm b/code/_onclick/hud/human.dm index d514bdedfcdf..37a858d76699 100644 --- a/code/_onclick/hud/human.dm +++ b/code/_onclick/hud/human.dm @@ -116,6 +116,10 @@ return var/mob/living/carbon/human/H = mymob var/mob/screenmob = viewer || H + + if(!screenmob?.client) + return + if(!gear.len) inventory_shown = FALSE return //species without inv slots don't show items. @@ -181,6 +185,9 @@ var/mob/living/carbon/human/H = mymob var/mob/screenmob = viewer || H + if(!screenmob?.client) + return + if(H.hud_used) if(H.hud_used.hud_shown) if(H.s_store) diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm index 35b6073ee41b..d114aff6b7cb 100644 --- a/code/_onclick/hud/screen_objects.dm +++ b/code/_onclick/hud/screen_objects.dm @@ -30,6 +30,10 @@ /atom/movable/screen/inventory var/slot_id //The indentifier for the slot. It has nothing to do with ID cards. +/atom/movable/screen/inventory/Initialize(mapload, ...) + . = ..() + + RegisterSignal(src, COMSIG_ATOM_DROPPED_ON, PROC_REF(handle_dropped_on)) /atom/movable/screen/close name = "close" @@ -325,6 +329,22 @@ return 1 return 0 +/atom/movable/screen/inventory/proc/handle_dropped_on(atom/dropped_on, atom/dropping, client/user) + SIGNAL_HANDLER + + if(slot_id != WEAR_L_HAND && slot_id != WEAR_R_HAND) + return + + if(!isstorage(dropping.loc)) + return + + if(!user.mob.Adjacent(dropping)) + return + + var/obj/item/storage/store = dropping.loc + store.remove_from_storage(dropping, get_turf(user.mob)) + user.mob.put_in_active_hand(dropping) + /atom/movable/screen/throw_catch name = "throw/catch" icon = 'icons/mob/hud/human_midnight.dmi' @@ -515,7 +535,7 @@ if(!user.hive.living_xeno_queen) to_chat(user, SPAN_WARNING("Without a queen your psychic link is broken!")) return FALSE - if(user.burrow || user.is_mob_incapacitated() || user.buckled) + if(HAS_TRAIT(user, TRAIT_ABILITY_BURROWED) || user.is_mob_incapacitated() || user.buckled) return FALSE user.hive.mark_ui.update_all_data() user.hive.mark_ui.open_mark_menu(user) @@ -563,7 +583,7 @@ if(!user.hive.living_xeno_queen) to_chat(user, SPAN_WARNING("Your hive doesn't have a living queen!")) return FALSE - if(user.burrow || user.is_mob_incapacitated() || user.buckled) + if(HAS_TRAIT(user, TRAIT_ABILITY_BURROWED) || user.is_mob_incapacitated() || user.buckled) return FALSE user.overwatch(user.hive.living_xeno_queen) diff --git a/code/_onclick/human.dm b/code/_onclick/human.dm index cb71e27f9d1a..8f329656ef6c 100644 --- a/code/_onclick/human.dm +++ b/code/_onclick/human.dm @@ -99,7 +99,7 @@ if(xeno.stat != DEAD) // If the Xeno is alive, fight back var/mob/living/carbon/carbon_user = user if(!carbon_user || !carbon_user.ally_of_hivenumber(xeno.hivenumber)) - user.KnockDown(rand(xeno.caste.tacklestrength_min, xeno.caste.tacklestrength_max)) + carbon_user.KnockDown(rand(xeno.caste.tacklestrength_min, xeno.caste.tacklestrength_max)) playsound(user.loc, 'sound/weapons/pierce.ogg', 25, TRUE) user.visible_message(SPAN_WARNING("\The [user] tried to unstrap \the [back_item] from [xeno] but instead gets a tail swipe to the head!")) return diff --git a/code/_onclick/xeno.dm b/code/_onclick/xeno.dm index 219a9a40c74f..ceef40c1ed3c 100644 --- a/code/_onclick/xeno.dm +++ b/code/_onclick/xeno.dm @@ -3,7 +3,7 @@ */ /mob/living/carbon/xenomorph/UnarmedAttack(atom/target, proximity, click_parameters, tile_attack = FALSE, ignores_resin = FALSE) - if(lying || burrow) //No attacks while laying down + if(lying || HAS_TRAIT(src, TRAIT_ABILITY_BURROWED)) //No attacks while laying down return FALSE var/mob/alt diff --git a/code/controllers/configuration/configuration.dm b/code/controllers/configuration/configuration.dm index e8b010669c0e..147f57fcb1aa 100644 --- a/code/controllers/configuration/configuration.dm +++ b/code/controllers/configuration/configuration.dm @@ -20,7 +20,8 @@ var/policy var/static/regex/ic_filter_regex - var/list/fail_to_topic_whitelisted_ips + + var/is_loaded = FALSE /datum/controller/configuration/proc/admin_reload() if(IsAdminAdvancedProcCall()) @@ -53,7 +54,8 @@ loadmaplist(CONFIG_GROUND_MAPS_FILE, GROUND_MAP) loadmaplist(CONFIG_SHIP_MAPS_FILE, SHIP_MAP) LoadChatFilter() - LoadTopicRateWhitelist() + + is_loaded = TRUE if(Master) Master.OnConfigLoad() @@ -333,18 +335,3 @@ /datum/controller/configuration/proc/DelayedMessageAdmins(text) addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(message_admins), text), 0) -/datum/controller/configuration/proc/LoadTopicRateWhitelist() - LAZYINITLIST(fail_to_topic_whitelisted_ips) - if(!fexists("[directory]/topic_rate_limit_whitelist.txt")) - log_config("Error 404: topic_rate_limit_whitelist.txt not found!") - return - - log_config("Loading config file topic_rate_limit_whitelist.txt...") - - for(var/line in file2list("[directory]/topic_rate_limit_whitelist.txt")) - if(!line) - continue - if(findtextEx(line, "#", 1, 2)) - continue - - fail_to_topic_whitelisted_ips[line] = 1 diff --git a/code/controllers/configuration/entries/general.dm b/code/controllers/configuration/entries/general.dm index 54ec1548c108..cc3d00fd951b 100644 --- a/code/controllers/configuration/entries/general.dm +++ b/code/controllers/configuration/entries/general.dm @@ -273,10 +273,6 @@ Voting /datum/config_entry/string/gamemode_default config_entry_value = "Extended" -// Rounds needed for gamemode vote -/datum/config_entry/number/gamemode_rounds_needed - config_entry_value = 5 - /datum/config_entry/number/rounds_until_hard_restart config_entry_value = -1 // -1 is disabled by default, 0 is every round, x is after so many rounds diff --git a/code/controllers/subsystem/admin.dm b/code/controllers/subsystem/admin.dm deleted file mode 100644 index 8aab64b04881..000000000000 --- a/code/controllers/subsystem/admin.dm +++ /dev/null @@ -1,40 +0,0 @@ -SUBSYSTEM_DEF(admin) - name = "Admin" - wait = 5 MINUTES - flags = SS_NO_INIT | SS_KEEP_TIMING - runlevels = RUNLEVELS_DEFAULT|RUNLEVEL_LOBBY - var/list/currentrun = list() - var/times_repeated = 0 - -/datum/controller/subsystem/admin/stat_entry(msg) - msg = "P:[unansweredAhelps.len]" - return ..() - -/datum/controller/subsystem/admin/fire(resumed = FALSE) - if (!resumed) - currentrun = unansweredAhelps.Copy() - - if(!currentrun.len) - times_repeated = 0 - return - - var/msg = "Unheard Ahelps (Repeated [times_repeated] times):" - - while (currentrun.len) - var/ahelp_msg = currentrun[currentrun.len] - currentrun.len-- - - if (!ahelp_msg) - continue - - msg += unansweredAhelps[ahelp_msg] + "\n" - - if (MC_TICK_CHECK) - return - - for(var/client/C in GLOB.admins) - if(C && C.admin_holder && (C.admin_holder.rights & R_MOD)) - if(C.prefs.toggles_sound & SOUND_ADMINHELP) - sound_to(C, 'sound/effects/adminhelp_new.ogg') - to_chat(C, msg) - times_repeated++ diff --git a/code/controllers/subsystem/atoms.dm b/code/controllers/subsystem/atoms.dm index 23da8cc8c9eb..3d544dca1390 100644 --- a/code/controllers/subsystem/atoms.dm +++ b/code/controllers/subsystem/atoms.dm @@ -131,7 +131,7 @@ SUBSYSTEM_DEF(atoms) switch(result) if (INITIALIZE_HINT_NORMAL) - // pass + pass() if(INITIALIZE_HINT_LATELOAD) if(arguments[1]) //mapload late_loaders += A diff --git a/code/controllers/subsystem/communications.dm b/code/controllers/subsystem/communications.dm index a5c5271c8d7d..8458436a53e5 100644 --- a/code/controllers/subsystem/communications.dm +++ b/code/controllers/subsystem/communications.dm @@ -107,6 +107,7 @@ var/const/MAX_FREQ = 1468 // --------------------------------------------------- var/const/HC_FREQ = 1471 var/const/SOF_FREQ = 1472 var/const/PVST_FREQ = 1473 +var/const/CBRN_FREQ = 1474 //Ship department channels var/const/SENTRY_FREQ = 1480 @@ -162,6 +163,7 @@ var/list/radiochannels = list( SQUAD_MARINE_5 = ECHO_FREQ, SQUAD_MARINE_CRYO = CRYO_FREQ, SQUAD_SOF = SOF_FREQ, + SQUAD_CBRN = CBRN_FREQ, RADIO_CHANNEL_ALAMO = DS1_FREQ, RADIO_CHANNEL_NORMANDY = DS2_FREQ, @@ -262,6 +264,7 @@ SUBSYSTEM_DEF(radio) "[DELTA_FREQ]" = "deltaradio", "[ECHO_FREQ]" = "echoradio", "[CRYO_FREQ]" = "cryoradio", + "[CBRN_FREQ]" = "hcradio", "[SOF_FREQ]" = "hcradio", "[HC_FREQ]" = "hcradio", "[PVST_FREQ]" = "pvstradio", diff --git a/code/controllers/subsystem/disease.dm b/code/controllers/subsystem/disease.dm index 25200cce11ed..b98187ca252c 100644 --- a/code/controllers/subsystem/disease.dm +++ b/code/controllers/subsystem/disease.dm @@ -1,22 +1,19 @@ -var/list/active_diseases = list() - - SUBSYSTEM_DEF(disease) name = "Disease" wait = 2 SECONDS flags = SS_NO_INIT | SS_KEEP_TIMING priority = SS_PRIORITY_DISEASE - var/list/currentrun = list() + var/list/datum/disease/all_diseases = list() + var/list/datum/disease/currentrun = list() /datum/controller/subsystem/disease/stat_entry(msg) - msg = "P:[active_diseases.len]" + msg = "P:[all_diseases.len]" return ..() - /datum/controller/subsystem/disease/fire(resumed = FALSE) if (!resumed) - currentrun = active_diseases.Copy() + currentrun = all_diseases.Copy() while (currentrun.len) var/datum/disease/D = currentrun[currentrun.len] diff --git a/code/controllers/subsystem/fail_to_topic.dm b/code/controllers/subsystem/fail_to_topic.dm deleted file mode 100644 index 45674683a443..000000000000 --- a/code/controllers/subsystem/fail_to_topic.dm +++ /dev/null @@ -1,81 +0,0 @@ -SUBSYSTEM_DEF(fail_to_topic) - name = "Fail to Topic" - init_order = SS_INIT_FAIL_TO_TOPIC - flags = SS_BACKGROUND - runlevels = ALL - - var/list/rate_limiting = list() - var/list/fail_counts = list() - var/list/active_bans = list() - var/list/currentrun = list() - - var/rate_limit - var/max_fails - var/enabled = FALSE - -/datum/controller/subsystem/fail_to_topic/Initialize(timeofday) - rate_limit = ((CONFIG_GET(number/topic_rate_limit)) SECONDS) - max_fails = CONFIG_GET(number/topic_max_fails) - enabled = CONFIG_GET(flag/topic_enabled) - - if (world.system_type == UNIX && enabled) - enabled = FALSE - WARNING("fail_to_topic subsystem disabled. UNIX is not supported.") - return SS_INIT_NO_NEED - - if (!enabled) - can_fire = FALSE - return SS_INIT_NO_NEED - - return SS_INIT_SUCCESS - -/datum/controller/subsystem/fail_to_topic/fire(resumed = FALSE) - if(!resumed) - currentrun = rate_limiting.Copy() - //cache for sanic speed (lists are references anyways) - var/list/current_run = currentrun - - while(current_run.len) - var/ip = current_run[current_run.len] - var/last_attempt = current_run[ip] - current_run.len-- - - // last_attempt list housekeeping - if(world.time - last_attempt > rate_limit) - rate_limiting -= ip - fail_counts -= ip - - if(MC_TICK_CHECK) - return - -/datum/controller/subsystem/fail_to_topic/proc/IsRateLimited(ip) - if(!enabled) - return FALSE - - var/last_attempt = rate_limiting[ip] - - if (config.fail_to_topic_whitelisted_ips[ip]) - return FALSE - - if (active_bans[ip]) - return TRUE - - rate_limiting[ip] = world.time - - if (isnull(last_attempt)) - return FALSE - - if (world.time - last_attempt > rate_limit) - fail_counts -= ip - return FALSE - else - var/failures = fail_counts[ip] - - if (isnull(failures)) - fail_counts[ip] = 1 - return TRUE - else if (failures > max_fails) - return TRUE - else - fail_counts[ip] = failures + 1 - return TRUE diff --git a/code/controllers/subsystem/fast_machinery.dm b/code/controllers/subsystem/fast_machinery.dm deleted file mode 100644 index 8211b3b5e310..000000000000 --- a/code/controllers/subsystem/fast_machinery.dm +++ /dev/null @@ -1,27 +0,0 @@ -var/list/fast_machines = list() - - -SUBSYSTEM_DEF(fast_machinery) - name = "Fast Machinery" - wait = 0.7 SECONDS - priority = SS_PRIORITY_FAST_MACHINERY - flags = SS_NO_INIT - var/list/currentrun = list() - -/datum/controller/subsystem/fast_machinery/stat_entry(msg) - msg = "FP:[fast_machines.len]" - return ..() - -/datum/controller/subsystem/fast_machinery/fire(resumed = FALSE) - if(!resumed) - currentrun = fast_machines.Copy() - while(currentrun.len) - var/obj/structure/machinery/M = currentrun[currentrun.len] - currentrun.len-- - - if(QDELETED(M)) - continue - - M.process() - if(MC_TICK_CHECK) - return diff --git a/code/controllers/subsystem/game_decorator.dm b/code/controllers/subsystem/game_decorator.dm new file mode 100644 index 000000000000..dd53b647d1a8 --- /dev/null +++ b/code/controllers/subsystem/game_decorator.dm @@ -0,0 +1,35 @@ +// Essentially the same as decorators but that apply to the whole game state instead of individual atoms +SUBSYSTEM_DEF(game_decorator) + name = "Game Decorator" + init_order = SS_INIT_DECORATOR + flags = SS_NO_FIRE + +/datum/controller/subsystem/game_decorator/Initialize() + . = ..() + for(var/decorator_type in subtypesof(/datum/game_decorator)) + var/datum/game_decorator/decorator = new decorator_type() + if(!decorator.is_active_decor()) + continue + if(!decorator.defer_decoration) + decorator.decorate() + CHECK_TICK + + return SS_INIT_SUCCESS + +/datum/game_decorator + var/defer_decoration = TRUE //! So map decoration is done post-setup after nightmare and spawners + +/datum/game_decorator/New() + if(defer_decoration && is_active_decor()) + RegisterSignal(SSdcs, COMSIG_GLOB_MODE_POSTSETUP, PROC_REF(defered_decoration)) + +/datum/game_decorator/proc/is_active_decor() + return FALSE + +/datum/game_decorator/proc/defered_decoration(dcs) + SIGNAL_HANDLER + decorate() + +/datum/game_decorator/proc/decorate() + set waitfor = FALSE + return diff --git a/code/controllers/subsystem/hijack.dm b/code/controllers/subsystem/hijack.dm new file mode 100644 index 000000000000..55b5aa75caf8 --- /dev/null +++ b/code/controllers/subsystem/hijack.dm @@ -0,0 +1,429 @@ +SUBSYSTEM_DEF(hijack) + name = "Hijack" + wait = 2 SECONDS + flags = SS_KEEP_TIMING + priority = SS_PRIORITY_HIJACK + init_order = SS_INIT_HIJACK + + ///Required progress to evacuate safely via lifeboats + var/required_progress = 100 + + ///Current progress towards evacuating safely via lifeboats + var/current_progress = 0 + + /// How much progress is required to early launch + var/early_launch_required_progress = 25 + + ///The estimated time left to get to the safe evacuation point + var/estimated_time_left = 0 + + ///Areas that are marked as having progress, assoc list that is progress_area = boolean, the boolean indicating if it was progressing or not on the last fire() + var/list/area/progress_areas = list() + + ///The areas that need cycled through currently + var/list/area/current_run = list() + + ///The progress of the current run that needs to be added at the end of the current run + var/current_run_progress_additive = 0 + + ///Holds what the current_run_progress_additive should be multiplied by at the end of the current run + var/current_run_progress_multiplicative = 1 + + ///Holds the progress change from last run + var/last_run_progress_change = 0 + + ///Holds the next % point progress should be announced, increments on itself + var/announce_checkpoint = 25 + + ///What stage of evacuation we are currently on + var/evac_status = EVACUATION_STATUS_NOT_INITIATED + + ///What stage of hijack are we currently on + var/hijack_status = HIJACK_OBJECTIVES_NOT_STARTED + + ///Whether or not evacuation has been disabled by admins + var/evac_admin_denied = FALSE + + /// If TRUE, self destruct has been unlocked and is possible with a hold of reactor + var/sd_unlocked = FALSE + + /// Admin var to manually prevent self destruct from occurring + var/admin_sd_blocked = FALSE + + /// Maximum amount of fusion generators that can be overloaded at once for a time benefit + var/maximum_overload_generators = 18 + + /// How many generators are currently overloaded + var/overloaded_generators = 0 + + /// How long the manual self destruct will take on the high end + var/sd_max_time = 15 MINUTES + + /// How long the manual self destruct will take on the low end + var/sd_min_time = 5 MINUTES + + /// How much time left until SD detonates + var/sd_time_remaining = 0 + + /// Roughly what % of the SD countdown remains + var/percent_completion_remaining = 100 + + /// If the engine room has been heated, occurs at 33% SD completion + var/engine_room_heated = FALSE + + /// If the engine room has been superheated, occurs at 66% SD completion + var/engine_room_superheated = FALSE + + /// If the self destruct has/is detonating + var/sd_detonated = FALSE + + /// If a generator has ever been overloaded in the past this round + var/generator_ever_overloaded = FALSE + + /// If ARES has announced the 50% point yet for SD + var/ares_sd_announced = FALSE + +/datum/controller/subsystem/hijack/Initialize(timeofday) + RegisterSignal(SSdcs, COMSIG_GLOB_GENERATOR_SET_OVERLOADING, PROC_REF(on_generator_overload)) + return SS_INIT_SUCCESS + +/datum/controller/subsystem/hijack/stat_entry(msg) + if(!SSticker?.mode?.is_in_endgame) + msg = " Not Hijack" + return ..() + + if(current_progress >= required_progress) + msg = " Complete" + return ..() + + msg = " Progress: [current_progress]% | Last run: [last_run_progress_change]" + return ..() + +/datum/controller/subsystem/hijack/fire(resumed = FALSE) + if(!SSticker?.mode?.is_in_endgame) + return + + if(hijack_status < HIJACK_OBJECTIVES_STARTED) + hijack_status = HIJACK_OBJECTIVES_STARTED + + if(current_progress >= required_progress) + if(hijack_status < HIJACK_OBJECTIVES_COMPLETE) + hijack_status = HIJACK_OBJECTIVES_COMPLETE + + if(sd_unlocked && overloaded_generators) + sd_time_remaining -= wait + if(!engine_room_heated && (sd_time_remaining <= (max((1 - round(overloaded_generators / maximum_overload_generators, 0.01)) * sd_max_time, sd_min_time) * 0.66))) + heat_engine_room() + + if(!ares_sd_announced && (sd_time_remaining <= (max((1 - round(overloaded_generators / maximum_overload_generators, 0.01)) * sd_max_time, sd_min_time) * 0.5))) + announce_sd_halfway() + + if(!engine_room_superheated && (sd_time_remaining <= (max((1 - round(overloaded_generators / maximum_overload_generators, 0.01)) * sd_max_time, sd_min_time) * 0.33))) + superheat_engine_room() + + if((sd_time_remaining <= 0) && !sd_detonated) + detonate_sd() + + return + + if(!resumed) + current_run = progress_areas.Copy() + + for(var/area/almayer/cycled_area as anything in current_run) + current_run -= cycled_area + + if(progress_areas[cycled_area] != cycled_area.power_equip) + progress_areas[cycled_area] = !progress_areas[cycled_area] + announce_area_power_change(cycled_area) + + if(progress_areas[cycled_area]) + switch(cycled_area.hijack_evacuation_type) + if(EVACUATION_TYPE_ADDITIVE) + current_run_progress_additive += cycled_area.hijack_evacuation_weight + if(EVACUATION_TYPE_MULTIPLICATIVE) + current_run_progress_multiplicative *= cycled_area.hijack_evacuation_weight + + if (MC_TICK_CHECK) + return + + last_run_progress_change = current_run_progress_additive * current_run_progress_multiplicative + current_progress += last_run_progress_change + + if(last_run_progress_change) + estimated_time_left = ((required_progress - current_progress) / last_run_progress_change) * wait + else + estimated_time_left = INFINITY + + if(current_progress >= announce_checkpoint) + announce_progress() + announce_checkpoint += initial(announce_checkpoint) + + current_run_progress_additive = 0 + current_run_progress_multiplicative = 1 + +///Called when the xeno dropship crashes into the Almayer and announces the current status of various objectives to marines +/datum/controller/subsystem/hijack/proc/announce_status_on_crash() + var/message = "" + + for(var/area/cycled_area as anything in progress_areas) + message += "[cycled_area] - [cycled_area.power_equip ? "Online" : "Offline"]\n" + progress_areas[cycled_area] = cycled_area.power_equip + + message += "\nDue to low orbit, extra fuel is required for non-surface evacuations.\nMaintain fueling functionality for optimal evacuation conditions." + + marine_announcement(message, HIJACK_ANNOUNCE) + +///Called when an area power status is changed to announce that it has been changed +/datum/controller/subsystem/hijack/proc/announce_area_power_change(area/changed_area) + var/message = "[changed_area] - [changed_area.power_equip ? "Online" : "Offline"]" + + marine_announcement(message, HIJACK_ANNOUNCE) + +///Called to announce to xenos the state of evacuation progression +/datum/controller/subsystem/hijack/proc/announce_progress() + var/announce = announce_checkpoint / initial(announce_checkpoint) + + var/marine_warning_areas = "" + var/xeno_warning_areas = "" + + for(var/area/cycled_area as anything in progress_areas) + if(cycled_area.power_equip) + xeno_warning_areas += "[cycled_area], " + continue + marine_warning_areas += "[cycled_area], " + + if(xeno_warning_areas) + xeno_warning_areas = copytext(xeno_warning_areas, 1, -2) + + if(marine_warning_areas) + marine_warning_areas = copytext(marine_warning_areas, 1, -2) + + var/datum/hive_status/hive + for(var/hivenumber in GLOB.hive_datum) + hive = GLOB.hive_datum[hivenumber] + if(!length(hive.totalXenos)) + continue + + switch(announce) + if(1) + xeno_announcement(SPAN_XENOANNOUNCE("The talls are a quarter of the way towards their goals. Disable the following areas: [xeno_warning_areas]"), hive.hivenumber, XENO_HIJACK_ANNOUNCE) + if(2) + xeno_announcement(SPAN_XENOANNOUNCE("The talls are half way towards their goals. Disable the following areas: [xeno_warning_areas]"), hive.hivenumber, XENO_HIJACK_ANNOUNCE) + if(3) + xeno_announcement(SPAN_XENOANNOUNCE("The talls are three quarters of the way towards their goals. Disable the following areas: [xeno_warning_areas]"), hive.hivenumber, XENO_HIJACK_ANNOUNCE) + if(4) + xeno_announcement(SPAN_XENOANNOUNCE("The talls have completed their goals!"), hive.hivenumber, XENO_HIJACK_ANNOUNCE) + + switch(announce) + if(1) + marine_announcement("Emergency fuel replenishment at 25 percent. Lifeboat emergency early launch now available.[marine_warning_areas ? "\nTo increase speed restore power to the following areas: [marine_warning_areas]" : " All fueling areas operational."]", HIJACK_ANNOUNCE) + if(2) + marine_announcement("Emergency fuel replenishment at 50 percent.[marine_warning_areas ? "\nTo increase speed restore power to the following areas: [marine_warning_areas]" : " All fueling areas operational."]", HIJACK_ANNOUNCE) + if(3) + marine_announcement("Emergency fuel replenishment at 75 percent.[marine_warning_areas ? "\nTo increase speed restore power to the following areas: [marine_warning_areas]" : " All fueling areas operational."]", HIJACK_ANNOUNCE) + if(4) + marine_announcement("Emergency fuel replenishment at 100 percent. Safe utilization of lifeboats now possible.", HIJACK_ANNOUNCE) + if(!admin_sd_blocked) + addtimer(CALLBACK(src, PROC_REF(unlock_self_destruct)), 8 SECONDS) + +/// Passes the ETA for status panels +/datum/controller/subsystem/hijack/proc/get_evac_eta() + switch(hijack_status) + if(HIJACK_OBJECTIVES_STARTED) + if(estimated_time_left == INFINITY) + return "Never" + return "[duration2text_sec(estimated_time_left)]" + + if(HIJACK_OBJECTIVES_COMPLETE) + return "Complete" + +/datum/controller/subsystem/hijack/proc/get_sd_eta() + if(!sd_time_remaining) + return "Complete" + + if(overloaded_generators <= 0) + return "Never" + + return "[duration2text_sec(sd_time_remaining)]" + +//~~~~~~~~~~~~~~~~~~~~~~~~ EVAC STUFF ~~~~~~~~~~~~~~~~~~~~~~~~// + +/// Initiates evacuation by announcing and then prepping all lifepods/lifeboats +/datum/controller/subsystem/hijack/proc/initiate_evacuation() + if(evac_status == EVACUATION_STATUS_NOT_INITIATED && !(evac_admin_denied & FLAGS_EVACUATION_DENY)) + evac_status = EVACUATION_STATUS_INITIATED + ai_announcement("Attention. Emergency. All personnel must evacuate immediately.", 'sound/AI/evacuate.ogg') + + for(var/obj/structure/machinery/status_display/cycled_status_display in machines) + if(is_mainship_level(cycled_status_display.z)) + cycled_status_display.set_picture("evac") + for(var/obj/docking_port/mobile/crashable/escape_shuttle/shuttle in SSshuttle.mobile) + shuttle.prepare_evac() + activate_lifeboats() + return TRUE + +/// Cancels evacuation, tells lifepods/lifeboats and status_displays +/datum/controller/subsystem/hijack/proc/cancel_evacuation() + if(evac_status == EVACUATION_STATUS_INITIATED) + evac_status = EVACUATION_STATUS_NOT_INITIATED + deactivate_lifeboats() + ai_announcement("Evacuation has been cancelled.", 'sound/AI/evacuate_cancelled.ogg') + + for(var/obj/structure/machinery/status_display/cycled_status_display in machines) + if(is_mainship_level(cycled_status_display.z)) + cycled_status_display.set_sec_level_picture() + + for(var/obj/docking_port/mobile/crashable/escape_shuttle/shuttle in SSshuttle.mobile) + shuttle.cancel_evac() + return TRUE + +/// Opens the lifeboat doors and gets them ready to launch +/datum/controller/subsystem/hijack/proc/activate_lifeboats() + for(var/obj/docking_port/stationary/lifeboat_dock/lifeboat_dock in GLOB.lifeboat_almayer_docks) + var/obj/docking_port/mobile/crashable/lifeboat/lifeboat = lifeboat_dock.get_docked() + if(lifeboat && lifeboat.available) + lifeboat.status = LIFEBOAT_ACTIVE + lifeboat_dock.open_dock() + +/// Turns off ability to manually take off lifeboats +/datum/controller/subsystem/hijack/proc/deactivate_lifeboats() + for(var/obj/docking_port/stationary/lifeboat_dock/lifeboat_dock in GLOB.lifeboat_almayer_docks) + var/obj/docking_port/mobile/crashable/lifeboat/lifeboat = lifeboat_dock.get_docked() + if(lifeboat && lifeboat.available) + lifeboat.status = LIFEBOAT_INACTIVE + + +/// Once refueling is done, marines can optionally hold SD for a time for a stalemate instead of a xeno minor +/datum/controller/subsystem/hijack/proc/unlock_self_destruct() + sd_time_remaining = sd_max_time + sd_unlocked = TRUE + marine_announcement("Fuel reserves full. Manual detonation of fuel reserves by overloading the on-board fusion reactors now possible.", HIJACK_ANNOUNCE) + +/datum/controller/subsystem/hijack/proc/on_generator_overload(obj/structure/machinery/power/fusion_engine/source, new_overloading) + SIGNAL_HANDLER + + if(!generator_ever_overloaded) + generator_ever_overloaded = TRUE + var/datum/hive_status/hive + for(var/hivenumber in GLOB.hive_datum) + hive = GLOB.hive_datum[hivenumber] + if(!length(hive.totalXenos)) + continue + + xeno_announcement(SPAN_XENOANNOUNCE("The talls may be attempting to take their ship down with them in Engineering, stop them!"), hive.hivenumber, XENO_HIJACK_ANNOUNCE) + + adjust_generator_overload_count(new_overloading ? 1 : -1) + +/datum/controller/subsystem/hijack/proc/adjust_generator_overload_count(amount = 1) + var/generator_overload_percent = round(overloaded_generators / maximum_overload_generators, 0.01) + var/old_required_time = sd_min_time + ((1 - generator_overload_percent) * (sd_max_time - sd_min_time)) + percent_completion_remaining = sd_time_remaining / old_required_time + overloaded_generators = clamp(overloaded_generators + amount, 0, maximum_overload_generators) + generator_overload_percent = round(overloaded_generators / maximum_overload_generators, 0.01) + var/new_required_time = sd_min_time + ((1 - generator_overload_percent) * (sd_max_time - sd_min_time)) + sd_time_remaining = percent_completion_remaining * new_required_time + +/datum/controller/subsystem/hijack/proc/heat_engine_room() + engine_room_heated = TRUE + var/area/engine_room = GLOB.areas_by_type[/area/almayer/engineering/engine_core] + engine_room.firealert() + engine_room.temperature = T90C + for(var/mob/current_mob as anything in GLOB.mob_list) + var/area/mob_area = get_area(current_mob) + if(istype(mob_area, /area/almayer/engineering/engine_core)) + to_chat(current_mob, SPAN_BOLDWARNING("You feel the heat of the room increase as the fusion engines whirr louder.")) + +/datum/controller/subsystem/hijack/proc/superheat_engine_room() + engine_room_superheated = TRUE + var/area/engine_room = GLOB.areas_by_type[/area/almayer/engineering/engine_core] + engine_room.firealert() + engine_room.temperature = T120C //slowly deals burn at this temp + for(var/mob/current_mob as anything in GLOB.mob_list) + var/area/mob_area = get_area(current_mob) + if(istype(mob_area, /area/almayer/engineering/engine_core)) + to_chat(current_mob, SPAN_BOLDWARNING("The room feels incredibly hot, you can't take much more of this!")) + +/datum/controller/subsystem/hijack/proc/announce_sd_halfway() + ares_sd_announced = TRUE + marine_announcement("ALERT: Fusion reactor meltdown has reached fifty percent.", HIJACK_ANNOUNCE) + +/datum/controller/subsystem/hijack/proc/detonate_sd() + set waitfor = FALSE + sd_detonated = TRUE + var/creak_picked = pick('sound/effects/creak1.ogg', 'sound/effects/creak2.ogg', 'sound/effects/creak3.ogg') + for(var/mob/current_mob as anything in GLOB.mob_list) + var/turf/current_turf = get_turf(current_mob) + if(!current_mob?.loc || !current_mob.client || !current_turf || !is_mainship_level(current_turf.z)) + continue + + to_chat(current_mob, SPAN_BOLDWARNING("The ship's deck worryingly creaks underneath you.")) + playsound_client(current_mob.client, creak_picked, vol = 50) + + sleep(7 SECONDS) + shakeship(2, 10, TRUE) + + marine_announcement("ALERT: Fusion reactors dangerously overloaded. Runaway meltdown in reactor core imminent.", HIJACK_ANNOUNCE) + sleep(5 SECONDS) + + var/sound_picked = pick('sound/theme/nuclear_detonation1.ogg','sound/theme/nuclear_detonation2.ogg') + for(var/client/player as anything in GLOB.clients) + playsound_client(player, sound_picked, 90) + + var/list/alive_mobs = list() //Everyone who will be destroyed on the zlevel(s). + var/list/dead_mobs = list() //Everyone who only needs to see the cinematic. + for(var/mob/current_mob as anything in GLOB.mob_list) //This only does something cool for the people about to die, but should prove pretty interesting. + var/turf/current_turf = get_turf(current_mob) + if(!current_mob?.loc || !current_turf) + continue + + if(current_mob.stat == DEAD) + dead_mobs |= current_mob + continue + + if(is_mainship_level(current_turf.z)) + alive_mobs |= current_mob + shake_camera(current_mob, 110, 4) + + + sleep(10 SECONDS) + /*Hardcoded for now, since this was never really used for anything else. + Would ideally use a better system for showing cutscenes.*/ + var/atom/movable/screen/cinematic/explosion/explosive_cinematic = new() + + for(var/mob/current_mob as anything in (alive_mobs + dead_mobs)) + if(current_mob?.loc && current_mob.client) + current_mob.client.add_to_screen(explosive_cinematic) //They may have disconnected in the mean time. + + sleep(1.5 SECONDS) //Extra 1.5 seconds to look at the ship. + flick("intro_nuke", explosive_cinematic) + + sleep(3.5 SECONDS) + for(var/mob/current_mob as anything in alive_mobs) + var/turf/current_mob_turf = get_turf(current_mob) + if(!current_mob?.loc || !current_mob_turf) //Who knows, maybe they escaped, or don't exist anymore. + continue + + if(is_mainship_level(current_mob_turf.z)) + if(istype(current_mob.loc, /obj/structure/closet/secure_closet/freezer/fridge)) + continue + + current_mob.death(create_cause_data("nuclear explosion")) + else + current_mob.client.remove_from_screen(explosive_cinematic) //those who managed to escape the z level at last second shouldn't have their view obstructed. + + flick("ship_destroyed", explosive_cinematic) + explosive_cinematic.icon_state = "summary_destroyed" + + for(var/client/player as anything in GLOB.clients) + playsound_client(player, 'sound/effects/explosionfar.ogg', 90) + + + sleep(0.5 SECONDS) + if(SSticker.mode) + SSticker.mode.check_win() + + if(!SSticker.mode) //Just a safety, just in case a mode isn't running, somehow. + to_world(SPAN_ROUNDBODY("Resetting in 30 seconds!")) + sleep(30 SECONDS) + log_game("Rebooting due to nuclear detonation.") + world.Reboot() diff --git a/code/controllers/subsystem/htmlui.dm b/code/controllers/subsystem/htmlui.dm deleted file mode 100644 index 5dc885abc625..000000000000 --- a/code/controllers/subsystem/htmlui.dm +++ /dev/null @@ -1,57 +0,0 @@ -// What in the name of god is this? -// You'd think it'd be some form of process for the HTML interface module. -// But it isn't? -// It's some form of proc queue but ??? -// Does anything even *use* this? - -SUBSYSTEM_DEF(html_ui) - name = "HTMLUI" - wait = 1.7 SECONDS - flags = SS_NO_INIT - runlevels = RUNLEVELS_DEFAULT|RUNLEVEL_LOBBY - var/list/update = list() - -/datum/controller/subsystem/html_ui/fire(resumed = FALSE) - if (update.len) - var/list/L = list() - var/key - - for (var/datum/procqueue_item/item in update) - key = "[item.ref]_[item.procname]" - - if (item.args) - key += "(" - var/first = 1 - for (var/a in item.args) - if (!first) - key += "," - key += "[a]" - first = 0 - key += ")" - - if (!(key in L)) - if (item.args) - call(item.ref, item.procname)(arglist(item.args)) - else - call(item.ref, item.procname)() - - L.Add(key) - - update.Cut() - - -/datum/controller/subsystem/html_ui/proc/queue(ref, procname, ...) - var/datum/procqueue_item/item = new - item.ref = ref - item.procname = procname - - if (args.len > 2) - item.args = args.Copy(3) - - update.Insert(1, item) - - -/datum/procqueue_item - var/ref - var/procname - var/list/args diff --git a/code/controllers/subsystem/inactivity.dm b/code/controllers/subsystem/inactivity.dm index dd547e1f406b..6b8542444040 100644 --- a/code/controllers/subsystem/inactivity.dm +++ b/code/controllers/subsystem/inactivity.dm @@ -1,20 +1,26 @@ -#define INACTIVITY_KICK 6000 //10 minutes in ticks (approx.) +#define INACTIVITY_KICK 10 MINUTES SUBSYSTEM_DEF(inactivity) name = "Inactivity" - wait = INACTIVITY_KICK + wait = 1 MINUTES flags = SS_NO_INIT | SS_BACKGROUND priority = SS_PRIORITY_INACTIVITY runlevels = RUNLEVELS_DEFAULT|RUNLEVEL_LOBBY /datum/controller/subsystem/inactivity/fire(resumed = FALSE) - if (CONFIG_GET(flag/kick_inactive)) - for(var/i in GLOB.clients) - var/client/C = i - if(C.admin_holder && C.admin_holder.rights & R_ADMIN) //Skip admins. - continue - if (C.is_afk(INACTIVITY_KICK)) - if (!istype(C.mob, /mob/dead)) - log_access("AFK: [key_name(C)]") - to_chat(C, SPAN_WARNING("You have been inactive for more than 10 minutes and have been disconnected.")) - qdel(C) + if(list_clear_nulls(GLOB.clients)) + debug_log("Removed nulls from GLOB.clients!") + if(list_clear_nulls(GLOB.player_list)) + debug_log("Removed nulls from GLOB.player_list!") + + if (!CONFIG_GET(flag/kick_inactive)) + return + + for(var/client/current as anything in GLOB.clients) + if(current.admin_holder && current.admin_holder.rights & R_MOD) //Skip admins. + continue + if(current.is_afk(INACTIVITY_KICK)) + if(!istype(current.mob, /mob/dead)) + log_access("AFK: [key_name(current)]") + to_chat(current, SPAN_WARNING("You have been inactive for more than [INACTIVITY_KICK / 600] minutes and have been disconnected.")) + qdel(current) diff --git a/code/controllers/subsystem/init/earlyruntimes.dm b/code/controllers/subsystem/init/earlyruntimes.dm deleted file mode 100644 index 8e43b94a0735..000000000000 --- a/code/controllers/subsystem/init/earlyruntimes.dm +++ /dev/null @@ -1,14 +0,0 @@ -/// Just messages the unwary coder to tell them there are errors that likely escaped their debugguer. -SUBSYSTEM_DEF(earlyruntimes) - name = "Early Runtimes" - init_order = SS_INIT_EARLYRUNTIMES - flags = SS_NO_FIRE - -/datum/controller/subsystem/earlyruntimes/stat_entry(msg) - msg = " Early Runtimes: [init_runtimes_count || 0] | All runtimes: [total_runtimes || 0]" - return ..() - -/datum/controller/subsystem/earlyruntimes/Initialize() - if(init_runtimes_count) - return SS_INIT_FAILURE - return SS_INIT_SUCCESS diff --git a/code/controllers/subsystem/init/law.dm b/code/controllers/subsystem/init/law.dm index 52fbbbeadf5d..c7ade815972c 100644 --- a/code/controllers/subsystem/init/law.dm +++ b/code/controllers/subsystem/init/law.dm @@ -8,20 +8,24 @@ SUBSYSTEM_DEF(law_init) var/list/minor_law = list() var/list/major_law = list() var/list/capital_law = list() + var/list/precautionary_law = list() /datum/controller/subsystem/law_init/Initialize() - for(var/L in subtypesof(/datum/law/optional_law)) - optional_law += new L + for(var/law in subtypesof(/datum/law/optional_law)) + optional_law += new law - for(var/L in subtypesof(/datum/law/minor_law)) - minor_law += new L + for(var/law in subtypesof(/datum/law/minor_law)) + minor_law += new law - for(var/L in subtypesof(/datum/law/major_law)) - major_law += new L + for(var/law in subtypesof(/datum/law/major_law)) + major_law += new law - for(var/L in subtypesof(/datum/law/capital_law)) - capital_law += new L + for(var/law in subtypesof(/datum/law/capital_law)) + capital_law += new law - laws = optional_law + minor_law + major_law + capital_law + for(var/law in subtypesof(/datum/law/precautionary_charge)) + precautionary_law += new law + + laws = optional_law + minor_law + major_law + capital_law + precautionary_law return SS_INIT_SUCCESS diff --git a/code/controllers/subsystem/interior.dm b/code/controllers/subsystem/interior.dm index 389e95fe6022..8fb7ffbfeee7 100644 --- a/code/controllers/subsystem/interior.dm +++ b/code/controllers/subsystem/interior.dm @@ -42,7 +42,7 @@ SUBSYSTEM_DEF(interior) continue if(x >= bounds[1].x && x <= bounds[2].x && y >= bounds[1].y && y <= bounds[2].y) return current_interior - return FALSE + return /// Checks if an atom is in an interior /datum/controller/subsystem/interior/proc/in_interior(loc) @@ -51,7 +51,7 @@ SUBSYSTEM_DEF(interior) if(!isturf(loc)) loc = get_turf(loc) - var/datum/turf_reservation/interior/reservation = SSmapping.used_turfs[loc] + var/datum/weakref/reservation = SSmapping.used_turfs[loc] if(!istype(reservation)) return FALSE diff --git a/code/controllers/subsystem/mapping.dm b/code/controllers/subsystem/mapping.dm index afecabd74be0..913e5dcd50d3 100644 --- a/code/controllers/subsystem/mapping.dm +++ b/code/controllers/subsystem/mapping.dm @@ -6,9 +6,13 @@ SUBSYSTEM_DEF(mapping) var/list/datum/map_config/configs var/list/datum/map_config/next_map_configs + ///Name of all maps var/list/map_templates = list() - + ///Name of all shuttles var/list/shuttle_templates = list() + var/list/all_shuttle_templates = list() + ///map_id of all tents + var/list/tent_type_templates = list() var/list/areas_in_z = list() @@ -29,9 +33,7 @@ SUBSYSTEM_DEF(mapping) /datum/controller/subsystem/mapping/proc/HACK_LoadMapConfig() if(!configs) configs = load_map_configs(ALL_MAPTYPES, error_if_missing = FALSE) - for(var/i in GLOB.clients) - var/client/C = i - winset(C, null, "mainwindow.title='[CONFIG_GET(string/title)] - [SSmapping.configs[SHIP_MAP].map_name]'") + world.name = "[CONFIG_GET(string/title)] - [SSmapping.configs[SHIP_MAP].map_name]" /datum/controller/subsystem/mapping/Initialize(timeofday) HACK_LoadMapConfig() @@ -202,6 +204,7 @@ SUBSYSTEM_DEF(mapping) map_templates[T.name] = T preloadShuttleTemplates() + preload_tent_templates() /proc/generateMapList(filename) . = list() @@ -240,8 +243,14 @@ SUBSYSTEM_DEF(mapping) var/datum/map_template/shuttle/S = new shuttle_type() shuttle_templates[S.shuttle_id] = S + all_shuttle_templates[item] = S map_templates[S.shuttle_id] = S +/datum/controller/subsystem/mapping/proc/preload_tent_templates() + for(var/template in subtypesof(/datum/map_template/tent)) + var/datum/map_template/tent/new_tent = new template() + tent_type_templates[new_tent.map_id] = new_tent + /datum/controller/subsystem/mapping/proc/RequestBlockReservation(width, height, z, type = /datum/turf_reservation, turf_type_override) UNTIL(initialized && !clearing_reserved_turfs) var/datum/turf_reservation/reserve = new type diff --git a/code/controllers/subsystem/midi.dm b/code/controllers/subsystem/midi.dm deleted file mode 100644 index 158d67cf25ac..000000000000 --- a/code/controllers/subsystem/midi.dm +++ /dev/null @@ -1,45 +0,0 @@ -/datum/midi_record - var/target - var/midi - -SUBSYSTEM_DEF(midi) - name = "Midi" - wait = 2 SECONDS - flags = SS_NO_INIT|SS_BACKGROUND - runlevels = RUNLEVELS_DEFAULT|RUNLEVEL_LOBBY - priority = SS_PRIORITY_MIDI - - var/list/datum/midi_record/prepped_midis = list() - - var/list/datum/midi_record/currentrun = list() - - -/datum/controller/subsystem/midi/stat_entry(msg) - msg = "MR:[prepped_midis.len]" - return ..() - - -/datum/controller/subsystem/midi/fire(resumed = FALSE) - if (!resumed) - currentrun = prepped_midis - prepped_midis = list() - - while (currentrun.len) - var/datum/midi_record/E = currentrun[currentrun.len] - currentrun.len-- - - if (!E) - continue - - E.target << E.midi - - if (MC_TICK_CHECK) - return - -/datum/controller/subsystem/midi/proc/queue(target, midi) - if(!prepped_midis) - prepped_midis = list() - var/datum/midi_record/MR = new() - MR.target = target - MR.midi = midi - prepped_midis.Add(MR) diff --git a/code/controllers/subsystem/processing/defprocess.dm b/code/controllers/subsystem/processing/defprocess.dm new file mode 100644 index 000000000000..3701a0617a7a --- /dev/null +++ b/code/controllers/subsystem/processing/defprocess.dm @@ -0,0 +1,5 @@ +PROCESSING_SUBSYSTEM_DEF(defprocess) + name = "Defenses Processing" + priority = SS_PRIORITY_DEFENSES + flags = SS_NO_INIT + wait = 0.7 SECONDS diff --git a/code/controllers/subsystem/smoke_system.dm b/code/controllers/subsystem/smoke_system.dm deleted file mode 100644 index 2010687fcba2..000000000000 --- a/code/controllers/subsystem/smoke_system.dm +++ /dev/null @@ -1,31 +0,0 @@ -var/list/active_smoke_effects = list() - - -SUBSYSTEM_DEF(smoke_effects) - name = "Smoke Effects" - wait = 1 SECONDS - flags = SS_NO_INIT | SS_KEEP_TIMING - priority = SS_PRIORITY_OBJECTS - - var/list/currentrun = list() - -/datum/controller/subsystem/smoke_effects/stat_entry(msg) - msg = "P:[active_smoke_effects.len]" - return ..() - - -/datum/controller/subsystem/smoke_effects/fire(resumed = FALSE) - if(!resumed) - currentrun = active_smoke_effects.Copy() - - while(currentrun.len) - var/obj/effect/particle_effect/smoke/E = currentrun[currentrun.len] - currentrun.len-- - - if(!E || QDELETED(E)) - continue - - E.process() - - if(MC_TICK_CHECK) - return diff --git a/code/controllers/subsystem/sound.dm b/code/controllers/subsystem/sound.dm index 1935294394e7..4fdfd7935349 100644 --- a/code/controllers/subsystem/sound.dm +++ b/code/controllers/subsystem/sound.dm @@ -41,5 +41,5 @@ SUBSYSTEM_DEF(sound) if(VI?.ready) var/list/bounds = VI.get_middle_coords() if(bounds.len >= 2) - hearers |= SSquadtree.players_in_range(RECT(bounds[1], bounds[2], VI.map_template.height, VI.map_template.width), bounds[3]) + hearers |= SSquadtree.players_in_range(RECT(bounds[1], bounds[2], VI.map_template.width, VI.map_template.height), bounds[3]) template_queue[template] = hearers diff --git a/code/controllers/subsystem/stamina.dm b/code/controllers/subsystem/stamina.dm deleted file mode 100644 index 84d5b4038cd0..000000000000 --- a/code/controllers/subsystem/stamina.dm +++ /dev/null @@ -1,25 +0,0 @@ -var/global/list/active_staminas = list() - -SUBSYSTEM_DEF(stamina) - name = "Stamina" - wait = 2 SECONDS - priority = SS_PRIORITY_STAMINA - flags = SS_NO_INIT - var/list/currentrun = list() - - -/datum/controller/subsystem/stamina/fire(resumed = FALSE) - if (!resumed) - currentrun = active_staminas.Copy() - - while (currentrun.len) - var/datum/stamina/S = currentrun[currentrun.len] - currentrun.len-- - - if (!S || QDELETED(S)) - continue - - S.process() - - if (MC_TICK_CHECK) - return diff --git a/code/controllers/subsystem/statpanel.dm b/code/controllers/subsystem/statpanel.dm index 9a94eb3371f9..b65ca1e758a2 100644 --- a/code/controllers/subsystem/statpanel.dm +++ b/code/controllers/subsystem/statpanel.dm @@ -44,6 +44,9 @@ SUBSYSTEM_DEF(statpanels) var/client/target = currentrun[length(currentrun)] currentrun.len-- + if(!target) + continue + if(!target.stat_panel.is_ready()) continue @@ -313,14 +316,39 @@ SUBSYSTEM_DEF(statpanels) for(index in 1 to length(to_make)) var/atom/thing = to_make[index] + // var/start_time = REALTIMEOFDAY var/generated_string - /* We're cheap and won't render all overlays. It's expensive and updates with onmob changes! - if(ismob(thing) || length(thing.overlays) > 2) - generated_string = costly_icon2html(thing, parent, sourceonly=TRUE) + // We're cheap and won't render all overlays. It's expensive and updates with onmob changes! + //if(ismob(thing) || length(thing.overlays) > 2) + //generated_string = costly_icon2html(thing, parent, sourceonly=TRUE) + if(ishuman(thing)) + var/mob/living/carbon/human/human_thing = thing + var/icon + + // Ensure they have their armor since its going to be the majority of their appearance + var/list/armor = list() + var/obj/item/uniform = human_thing.get_item_by_slot(WEAR_BODY) + if(uniform) + armor += new uniform.type + var/obj/item/hat = human_thing.get_item_by_slot(WEAR_HEAD) + if(hat) + armor += new hat.type + var/obj/item/suit = human_thing.get_item_by_slot(WEAR_JACKET) + if(suit) + armor += new suit.type + var/obj/item/gloves = human_thing.get_item_by_slot(WEAR_HANDS) + if(gloves) + armor += new gloves.type + var/obj/item/shoes = human_thing.get_item_by_slot(WEAR_FEET) + if(shoes) + armor += new shoes.type + + // If we don't succeed making a flat human icon below, allowing the human to pass into icon2html will throw a bad icon operation because of a workaround in icon2html for humans... + icon = get_flat_human_copy_icon(human_thing, showDirs = list(SOUTH), outfit_override = armor) + generated_string = icon2html(icon, parent, sourceonly=TRUE) + // log_debug("object_window_info called on ref=[REF(thing)], instance=[thing], type=[thing.type], finished in [(REALTIMEOFDAY-start_time) / 10]s") else generated_string = icon2html(thing, parent, sourceonly=TRUE) - */ - generated_string = icon2html(thing, parent, sourceonly=TRUE) newly_seen[thing] = generated_string if(TICK_CHECK) @@ -383,8 +411,10 @@ SUBSYSTEM_DEF(statpanels) set name = "Open Statbrowser Options" set hidden = TRUE + if (!current_fontsize) + current_fontsize = 12 - var/datum/statbrowser_options/SM = statbrowser_options - if(!SM) - SM = statbrowser_options = new(src, current_fontsize) - SM.tgui_interact() + var/datum/statbrowser_options/options_panel = statbrowser_options + if(!options_panel) + options_panel = statbrowser_options = new(src, current_fontsize) + options_panel.tgui_interact() diff --git a/code/controllers/subsystem/stats_collector.dm b/code/controllers/subsystem/stats_collector.dm deleted file mode 100644 index de66e3b2c6b1..000000000000 --- a/code/controllers/subsystem/stats_collector.dm +++ /dev/null @@ -1,17 +0,0 @@ -/// Collects simple round statistics periodically -SUBSYSTEM_DEF(stats_collector) - name = "Round Stats" - wait = 30 SECONDS - priority = SS_PRIORITY_PAGER_STATUS - runlevels = RUNLEVELS_DEFAULT | RUNLEVEL_LOBBY - flags = SS_KEEP_TIMING | SS_NO_INIT - - var/stat_ticks = 0 - var/players_counter = 0 - -/datum/controller/subsystem/stats_collector/fire(resumed = FALSE) - players_counter += length(GLOB.clients) - stat_ticks++ - -/datum/controller/subsystem/stats_collector/proc/get_avg_players() - return players_counter / stat_ticks diff --git a/code/controllers/subsystem/teleporter.dm b/code/controllers/subsystem/teleporter.dm deleted file mode 100644 index b753bdb0d519..000000000000 --- a/code/controllers/subsystem/teleporter.dm +++ /dev/null @@ -1,10 +0,0 @@ -// Master teleporter controller. -SUBSYSTEM_DEF(teleporter) - name = "Teleporter" - wait = 5 SECONDS - init_order = SS_INIT_TELEPORTER - priority = SS_PRIORITY_TELEPORTER - flags = SS_NO_FIRE|SS_NO_INIT - - var/list/teleporters_by_id = list() // Associative list of teleporters by ID, master list of teleporters to process - var/list/teleporters = list() // Process list (identical contents to teleporters_by_id) diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm index 8544c7de9040..c996fc4518ff 100644 --- a/code/controllers/subsystem/ticker.dm +++ b/code/controllers/subsystem/ticker.dm @@ -102,17 +102,14 @@ SUBSYSTEM_DEF(ticker) mode.declare_completion(force_ending) REDIS_PUBLISH("byond.round", "type" = "round-complete") flash_clients() - if(text2num(SSperf_logging?.round?.id) % CONFIG_GET(number/gamemode_rounds_needed) == 0) - addtimer(CALLBACK( - SSvote, - /datum/controller/subsystem/vote/proc/initiate_vote, - "gamemode", - "SERVER", - CALLBACK(src, PROC_REF(handle_map_reboot)), - TRUE - ), 3 SECONDS) - else - handle_map_reboot() + addtimer(CALLBACK( + SSvote, + /datum/controller/subsystem/vote/proc/initiate_vote, + "gamemode", + "SERVER", + CALLBACK(src, PROC_REF(handle_map_reboot)), + TRUE + ), 3 SECONDS) Master.SetRunLevel(RUNLEVEL_POSTGAME) /// Attempt to start game asynchronously if applicable diff --git a/code/controllers/subsystem/vote.dm b/code/controllers/subsystem/vote.dm index 3882228a5ab1..a56e10636a1e 100644 --- a/code/controllers/subsystem/vote.dm +++ b/code/controllers/subsystem/vote.dm @@ -273,7 +273,7 @@ SUBSYSTEM_DEF(vote) question = "Gamemode vote" randomize_entries = TRUE for(var/mode_type in config.gamemode_cache) - var/datum/game_mode/M = initial(mode_type) + var/datum/game_mode/M = mode_type if(initial(M.config_tag)) var/vote_cycle_met = !initial(M.vote_cycle) || (text2num(SSperf_logging?.round?.id) % initial(M.vote_cycle) == 0) if(initial(M.votable) && vote_cycle_met) diff --git a/code/controllers/subsystem/xenocon.dm b/code/controllers/subsystem/xenocon.dm deleted file mode 100644 index d16e59bd9813..000000000000 --- a/code/controllers/subsystem/xenocon.dm +++ /dev/null @@ -1,18 +0,0 @@ -SUBSYSTEM_DEF(xenocon) - name = "XENOCON" - wait = 5 SECONDS - priority = SS_PRIORITY_INACTIVITY - flags = SS_NO_INIT - var/rewarded = FALSE - -/datum/controller/subsystem/xenocon/fire(resumed = FALSE) - if(rewarded) - return - - var/datum/hive_status/hive - for(var/hivenumber in GLOB.hive_datum) - hive = GLOB.hive_datum[hivenumber] - if(hive.xenocon_points >= XENOCON_THRESHOLD) - var/datum/emergency_call/em_call = new /datum/emergency_call/xenos/platoon() - em_call.activate() - rewarded = TRUE diff --git a/code/datums/_ndatabase/code/brsql_adapter.dm b/code/datums/_ndatabase/code/brsql_adapter.dm index 345ddfe005f3..251267a04fdb 100644 --- a/code/datums/_ndatabase/code/brsql_adapter.dm +++ b/code/datums/_ndatabase/code/brsql_adapter.dm @@ -101,8 +101,8 @@ SSdatabase.create_parametric_query(query_updatetable, qpars, CB) /datum/db/adapter/brsql_adapter/insert_table(table_name, list/values, datum/callback/CB, sync = FALSE) - if(!sync) - set waitfor = 0 + set waitfor = FALSE + var/length = values.len var/list/qpars = list() var/query_inserttable = getquery_insert_table(table_name, values, qpars) @@ -530,7 +530,7 @@ if(first && !is_id) if(!items_first) update_items+="," - update_items+="`[table_name]`.[esfield]=`__prep_update`.[esfield]" + update_items+="`[table_name]`.[esfield]=`subquery`.[esfield]" items_first = FALSE local_first = FALSE calltext += "SELECT [local_text]" @@ -539,9 +539,7 @@ issue_log += "No ID passed to update query." return "" // AAAAAAAAAAAAAH FUCK DON'T JUST KILL THE ENTIRE FUCKING TABLE BRUH return {" - WITH __prep_update as ( - [calltext] - ) UPDATE `[connection.database]`.`[table_name]` INNER JOIN `__prep_update` ON `[table_name]`.id = `__prep_update`.id SET [update_items] + UPDATE `[connection.database]`.`[table_name]` JOIN (WITH `__prep_update` AS ( [calltext] ) SELECT * FROM `__prep_update`) subquery ON `[table_name]`.id = subquery.id SET [update_items] "} /datum/db/adapter/brsql_adapter/proc/getquery_delete_table(table_name, list/ids) diff --git a/code/datums/_ndatabase/code/native_adapter.dm b/code/datums/_ndatabase/code/native_adapter.dm index a5e4d41fb6a0..1c23a6ceab8f 100644 --- a/code/datums/_ndatabase/code/native_adapter.dm +++ b/code/datums/_ndatabase/code/native_adapter.dm @@ -83,8 +83,7 @@ SSdatabase.create_query(query_gettable, CB) /datum/db/adapter/native_adapter/update_table(table_name, list/values, datum/callback/CB, sync = FALSE) - if(!sync) - set waitfor = 0 + set waitfor = FALSE for(var/list/vals in values) var/list/qpars = list() diff --git a/code/datums/agents/tools/chloroform.dm b/code/datums/agents/tools/chloroform.dm index 464533309bcc..c6e3320688eb 100644 --- a/code/datums/agents/tools/chloroform.dm +++ b/code/datums/agents/tools/chloroform.dm @@ -47,8 +47,8 @@ /obj/item/weapon/chloroform/proc/grab_stun(mob/living/M, mob/living/user) M.anchored = TRUE - M.frozen = TRUE - M.density = FALSE + ADD_TRAIT(M, TRAIT_IMMOBILIZED, CHLOROFORM_TRAIT) + ADD_TRAIT(M, TRAIT_UNDENSE, CHLOROFORM_TRAIT) M.able_to_speak = FALSE M.update_canmove() @@ -82,7 +82,8 @@ M.density = TRUE M.able_to_speak = TRUE M.layer = MOB_LAYER - M.unfreeze() + REMOVE_TRAIT(M, TRAIT_IMMOBILIZED, CHLOROFORM_TRAIT) + REMOVE_TRAIT(M, TRAIT_UNDENSE, CHLOROFORM_TRAIT) QDEL_NULL(mask_item) diff --git a/code/datums/ammo/ammo.dm b/code/datums/ammo/ammo.dm new file mode 100644 index 000000000000..a858c6b1f5a7 --- /dev/null +++ b/code/datums/ammo/ammo.dm @@ -0,0 +1,246 @@ +/datum/ammo + var/name = "generic bullet" + //Icon state when a human is permanently killed with it by execution/suicide. + var/headshot_state = null + var/icon = 'icons/obj/items/weapons/projectiles.dmi' + var/icon_state = "bullet" + /// The icon that is displayed when the bullet bounces off something. + var/ping = "ping_b" + /// When it deals damage. + var/sound_hit + /// When it's blocked by human armor. + var/sound_armor + /// When it misses someone. + var/sound_miss + /// When it bounces off something. + var/sound_bounce + /// When the bullet is absorbed by a xeno_shield + var/sound_shield_hit + /// Snipers use this to simulate poor accuracy at close ranges + var/accurate_range_min = 0 + /// How much the ammo scatters when burst fired, added to gun scatter, along with other mods + var/scatter = 0 + var/stamina_damage = 0 + /// This is the base damage of the bullet as it is fired + var/damage = 0 + /// BRUTE, BURN, TOX, OXY, CLONE are the only things that should be in here + var/damage_type = BRUTE + /// How much armor it ignores before calculations take place + var/penetration = 0 + /// The % chance it will imbed in a human + var/shrapnel_chance = 0 + /// The shrapnel type the ammo will embed, if the chance rolls + var/shrapnel_type = 0 + /// Type path of the extra projectiles + var/bonus_projectiles_type + /// How many extra projectiles it shoots out. Works kind of like firing on burst, but all of the projectiles travel together + var/bonus_projectiles_amount = 0 + /// Stun,knockdown,knockout,irradiate,stutter,eyeblur,drowsy,agony + var/debilitate[] = null + /// how much armor breaking will be done per point of penetration. This is for weapons that penetrate with their shape (like needle bullets) + var/pen_armor_punch = 0.5 + /// how much armor breaking is done by sheer weapon force. This is for big blunt weapons + var/damage_armor_punch = 0.5 + /// if we should play a special sound when firing. + var/sound_override = null + var/flags_ammo_behavior = NO_FLAGS + + /// This is added to the bullet's base accuracy. + var/accuracy = HIT_ACCURACY_TIER_1 + /// How much the accuracy varies when fired. // This REDUCES the lower bound of accuracy variance by 2%, to 96%. + var/accuracy_var_low = PROJECTILE_VARIANCE_TIER_9 + /// This INCREASES the upper bound of accuracy variance by 2%, to 107%. + var/accuracy_var_high = PROJECTILE_VARIANCE_TIER_9 + /// For most guns, this is where the bullet dramatically looses accuracy. Not for snipers though. + var/accurate_range = 6 + /// This will de-increment a counter on the bullet. + var/max_range = 22 + /// Same as with accuracy variance. + var/damage_var_low = PROJECTILE_VARIANCE_TIER_9 + /// This INCREASES the upper bound of damage variance by 2%, to 107%. + var/damage_var_high = PROJECTILE_VARIANCE_TIER_9 + /// How much damage the bullet loses per turf traveled after the effective range + var/damage_falloff = DAMAGE_FALLOFF_TIER_10 + /// How much damage the bullet loses per turf away before the effective range + var/damage_buildup = DAMAGE_BUILDUP_TIER_1 + /// What minimum range the ammo deals full damage, builds up the closer you get. 0 for no minimum. Added onto gun range as a modifier. + var/effective_range_min = EFFECTIVE_RANGE_OFF + /// What maximum range the ammo deals full damage, tapers off using damage_falloff after hitting this value. 0 for no maximum. Added onto gun range as a modifier. + var/effective_range_max = EFFECTIVE_RANGE_OFF + /// How fast the projectile moves. + var/shell_speed = AMMO_SPEED_TIER_1 + + var/handful_type = /obj/item/ammo_magazine/handful + var/handful_color + /// custom handful sprite, for shotgun shells or etc. + var/handful_state = "bullet" + /// so handfuls say 'buckshot shells' not 'shell' + var/multiple_handful_name + + /// Does this apply xenomorph behaviour delegate? + var/apply_delegate = TRUE + + /// An assoc list in the format list(/datum/element/bullet_trait_to_give = list(...args)) + /// that will be given to a projectile with the current ammo datum + var/list/list/traits_to_give + + var/flamer_reagent_type = /datum/reagent/napalm/ut + + /// The flicker that plays when a bullet hits a target. Usually red. Can be nulled so it doesn't show up at all. + var/hit_effect_color = "#FF0000" + +/datum/ammo/New() + set_bullet_traits() + +/datum/ammo/proc/on_bullet_generation(obj/projectile/generated_projectile, mob/bullet_generator) //NOT used on New(), applied to the projectiles. + return + +/// Populate traits_to_give in this proc +/datum/ammo/proc/set_bullet_traits() + return + +/datum/ammo/can_vv_modify() + return FALSE + +/datum/ammo/proc/do_at_half_range(obj/projectile/P) + SHOULD_NOT_SLEEP(TRUE) + return + +/datum/ammo/proc/on_embed(mob/embedded_mob, obj/limb/target_organ) + return + +/datum/ammo/proc/do_at_max_range(obj/projectile/P) + SHOULD_NOT_SLEEP(TRUE) + return + +/datum/ammo/proc/on_shield_block(mob/M, obj/projectile/P) //Does it do something special when shield blocked? Ie. a flare or grenade that still blows up. + return + +/datum/ammo/proc/on_hit_turf(turf/T, obj/projectile/P) //Special effects when hitting dense turfs. + SHOULD_NOT_SLEEP(TRUE) + return + +/datum/ammo/proc/on_hit_mob(mob/M, obj/projectile/P, mob/user) //Special effects when hitting mobs. + SHOULD_NOT_SLEEP(TRUE) + return + +///Special effects when pointblanking mobs. Ultimately called from /living/attackby(). Return TRUE to end the PB attempt. +/datum/ammo/proc/on_pointblank(mob/living/L, obj/projectile/P, mob/living/user, obj/item/weapon/gun/fired_from) + return + +/datum/ammo/proc/on_hit_obj(obj/O, obj/projectile/P) //Special effects when hitting objects. + SHOULD_NOT_SLEEP(TRUE) + return + +/datum/ammo/proc/on_near_target(turf/T, obj/projectile/P) //Special effects when passing near something. Range of things that triggers it is controlled by other ammo flags. + return 0 //return 0 means it flies even after being near something. Return 1 means it stops + +/datum/ammo/proc/knockback(mob/living/living_mob, obj/projectile/fired_projectile, max_range = 2) + if(!living_mob || living_mob == fired_projectile.firer) + return + if(fired_projectile.distance_travelled > max_range || living_mob.lying) + return //Two tiles away or more, basically. + + if(living_mob.mob_size >= MOB_SIZE_BIG) + return //Big xenos are not affected. + + shake_camera(living_mob, 3, 4) + knockback_effects(living_mob, fired_projectile) + slam_back(living_mob, fired_projectile) + +/datum/ammo/proc/slam_back(mob/living/living_mob, obj/projectile/fired_projectile) + /// Either knockback or slam them into an obstacle. + var/direction = Get_Compass_Dir(fired_projectile.z ? fired_projectile : fired_projectile.firer, living_mob) //More precise than get_dir. + if(!direction) //Same tile. + return + if(!step(living_mob, direction)) + living_mob.animation_attack_on(get_step(living_mob, direction)) + playsound(living_mob.loc, "punch", 25, 1) + living_mob.visible_message(SPAN_DANGER("[living_mob] slams into an obstacle!"), + isxeno(living_mob) ? SPAN_XENODANGER("You slam into an obstacle!") : SPAN_HIGHDANGER("You slam into an obstacle!"), null, 4, CHAT_TYPE_TAKING_HIT) + living_mob.apply_damage(MELEE_FORCE_TIER_2) + +///The applied effects for knockback(), overwrite to change slow/stun amounts for different ammo datums +/datum/ammo/proc/knockback_effects(mob/living/living_mob, obj/projectile/fired_projectile) + if(iscarbonsizexeno(living_mob)) + var/mob/living/carbon/xenomorph/target = living_mob + target.apply_effect(0.7, WEAKEN) // 0.9 seconds of stun, per agreement from Balance Team when switched from MC stuns to exact stuns + target.apply_effect(1, SUPERSLOW) + target.apply_effect(2, SLOW) + to_chat(target, SPAN_XENODANGER("You are shaken by the sudden impact!")) + else + living_mob.apply_stamina_damage(fired_projectile.ammo.damage, fired_projectile.def_zone, ARMOR_BULLET) + +/datum/ammo/proc/slowdown(mob/living/living_mob, obj/projectile/fired_projectile) + if(iscarbonsizexeno(living_mob)) + var/mob/living/carbon/xenomorph/target = living_mob + target.apply_effect(1, SUPERSLOW) + target.apply_effect(2, SLOW) + to_chat(target, SPAN_XENODANGER("You are slowed by the sudden impact!")) + else + living_mob.apply_stamina_damage(fired_projectile.ammo.damage, fired_projectile.def_zone, ARMOR_BULLET) + +/datum/ammo/proc/pushback(mob/target_mob, obj/projectile/fired_projectile, max_range = 2) + if(!target_mob || target_mob == fired_projectile.firer || fired_projectile.distance_travelled > max_range || target_mob.lying) + return + + if(target_mob.mob_size >= MOB_SIZE_BIG) + return //too big to push + + to_chat(target_mob, isxeno(target_mob) ? SPAN_XENODANGER("You are pushed back by the sudden impact!") : SPAN_HIGHDANGER("You are pushed back by the sudden impact!"), null, 4, CHAT_TYPE_TAKING_HIT) + slam_back(target_mob, fired_projectile, max_range) + +/datum/ammo/proc/burst(atom/target, obj/projectile/P, damage_type = BRUTE, range = 1, damage_div = 2, show_message = SHOW_MESSAGE_VISIBLE) //damage_div says how much we divide damage + if(!target || !P) return + for(var/mob/living/carbon/M in orange(range,target)) + if(P.firer == M) + continue + if(show_message) + var/msg = "You are hit by backlash from \a [P.name]!" + M.visible_message(SPAN_DANGER("[M] is hit by backlash from \a [P.name]!"),isxeno(M) ? SPAN_XENODANGER("[msg]"):SPAN_HIGHDANGER("[msg]")) + var/damage = P.damage/damage_div + + var/mob/living/carbon/xenomorph/XNO = null + + if(isxeno(M)) + XNO = M + var/total_explosive_resistance = XNO.caste.xeno_explosion_resistance + XNO.armor_explosive_buff + damage = armor_damage_reduction(GLOB.xeno_explosive, damage, total_explosive_resistance , 60, 0, 0.5, XNO.armor_integrity) + var/armor_punch = armor_break_calculation(GLOB.xeno_explosive, damage, total_explosive_resistance, 60, 0, 0.5, XNO.armor_integrity) + XNO.apply_armorbreak(armor_punch) + + M.apply_damage(damage,damage_type) + + if(XNO && XNO.xeno_shields.len) + P.play_shielded_hit_effect(M) + else + P.play_hit_effect(M) + +/datum/ammo/proc/fire_bonus_projectiles(obj/projectile/original_P) + set waitfor = 0 + + var/turf/curloc = get_turf(original_P.shot_from) + var/initial_angle = Get_Angle(curloc, original_P.target_turf) + + for(var/i in 1 to bonus_projectiles_amount) //Want to run this for the number of bonus projectiles. + var/final_angle = initial_angle + + var/obj/projectile/P = new /obj/projectile(curloc, original_P.weapon_cause_data) + P.generate_bullet(GLOB.ammo_list[bonus_projectiles_type]) //No bonus damage or anything. + P.accuracy = round(P.accuracy * original_P.accuracy/initial(original_P.accuracy)) //if the gun changes the accuracy of the main projectile, it also affects the bonus ones. + original_P.give_bullet_traits(P) + + var/total_scatter_angle = P.scatter + final_angle += rand(-total_scatter_angle, total_scatter_angle) + var/turf/new_target = get_angle_target_turf(curloc, final_angle, 30) + + P.fire_at(new_target, original_P.firer, original_P.shot_from, P.ammo.max_range, P.ammo.shell_speed, original_P.original) //Fire! + +/datum/ammo/proc/drop_flame(turf/T, datum/cause_data/cause_data) // ~Art updated fire 20JAN17 + if(!istype(T)) + return + if(locate(/obj/flamer_fire) in T) + return + + var/datum/reagent/R = new flamer_reagent_type() + new /obj/flamer_fire(T, cause_data, R) diff --git a/code/datums/ammo/bullet/bullet.dm b/code/datums/ammo/bullet/bullet.dm new file mode 100644 index 000000000000..dadb644201df --- /dev/null +++ b/code/datums/ammo/bullet/bullet.dm @@ -0,0 +1,81 @@ +/* +//====== + Default Ammo +//====== +*/ +//Only when things screw up do we use this as a placeholder. +/datum/ammo/bullet + name = "default bullet" + icon_state = "bullet" + headshot_state = HEADSHOT_OVERLAY_LIGHT + flags_ammo_behavior = AMMO_BALLISTIC + sound_hit = "ballistic_hit" + sound_armor = "ballistic_armor" + sound_miss = "ballistic_miss" + sound_bounce = "ballistic_bounce" + sound_shield_hit = "ballistic_shield_hit" + + accurate_range_min = 0 + damage = 10 + shrapnel_chance = SHRAPNEL_CHANCE_TIER_1 + shrapnel_type = /obj/item/shard/shrapnel + shell_speed = AMMO_SPEED_TIER_4 + +/datum/ammo/bullet/proc/handle_battlefield_execution(datum/ammo/firing_ammo, mob/living/hit_mob, obj/projectile/firing_projectile, mob/living/user, obj/item/weapon/gun/fired_from) + SIGNAL_HANDLER + + if(!user || hit_mob == user || user.zone_selected != "head" || user.a_intent != INTENT_HARM || !ishuman_strict(hit_mob)) + return + + if(!skillcheck(user, SKILL_EXECUTION, SKILL_EXECUTION_TRAINED)) + to_chat(user, SPAN_DANGER("You don't know how to execute someone correctly.")) + return + + var/mob/living/carbon/human/execution_target = hit_mob + + if(execution_target.status_flags & PERMANENTLY_DEAD) + to_chat(user, SPAN_DANGER("[execution_target] has already been executed!")) + return + + INVOKE_ASYNC(src, PROC_REF(attempt_battlefield_execution), src, execution_target, firing_projectile, user, fired_from) + + return COMPONENT_CANCEL_AMMO_POINT_BLANK + +/datum/ammo/bullet/proc/attempt_battlefield_execution(datum/ammo/firing_ammo, mob/living/carbon/human/execution_target, obj/projectile/firing_projectile, mob/living/user, obj/item/weapon/gun/fired_from) + user.affected_message(execution_target, + SPAN_HIGHDANGER("You aim \the [fired_from] at [execution_target]'s head!"), + SPAN_HIGHDANGER("[user] aims \the [fired_from] directly at your head!"), + SPAN_DANGER("[user] aims \the [fired_from] at [execution_target]'s head!")) + + user.next_move += 1.1 SECONDS //PB has no click delay; readding it here to prevent people accidentally queuing up multiple executions. + + if(!do_after(user, 1 SECONDS, INTERRUPT_ALL, BUSY_ICON_HOSTILE) || !user.Adjacent(execution_target)) + fired_from.delete_bullet(firing_projectile, TRUE) + return + + if(!(fired_from.flags_gun_features & GUN_SILENCED)) + playsound(user, fired_from.fire_sound, fired_from.firesound_volume, FALSE) + else + playsound(user, fired_from.fire_sound, 25, FALSE) + + shake_camera(user, 1, 2) + + execution_target.apply_damage(damage * 3, BRUTE, "head", no_limb_loss = TRUE, permanent_kill = TRUE) //Apply gobs of damage and make sure they can't be revived later... + execution_target.apply_damage(200, OXY) //...fill out the rest of their health bar with oxyloss... + execution_target.death(create_cause_data("execution", user)) //...make certain they're properly dead... + shake_camera(execution_target, 3, 4) + execution_target.update_headshot_overlay(headshot_state) //...and add a gory headshot overlay. + + execution_target.visible_message(SPAN_HIGHDANGER(uppertext("[execution_target] WAS EXECUTED!")), \ + SPAN_HIGHDANGER("You WERE EXECUTED!")) + + user.count_niche_stat(STATISTICS_NICHE_EXECUTION, 1, firing_projectile.weapon_cause_data?.cause_name) + + var/area/execution_area = get_area(execution_target) + + msg_admin_attack(FONT_SIZE_HUGE("[key_name(usr)] has battlefield executed [key_name(execution_target)] in [get_area(usr)] ([usr.loc.x],[usr.loc.y],[usr.loc.z])."), usr.loc.x, usr.loc.y, usr.loc.z) + log_attack("[key_name(usr)] battlefield executed [key_name(execution_target)] at [execution_area.name].") + + if(flags_ammo_behavior & AMMO_EXPLOSIVE) + execution_target.gib() + diff --git a/code/datums/ammo/bullet/lever_action.dm b/code/datums/ammo/bullet/lever_action.dm new file mode 100644 index 000000000000..2770231b6811 --- /dev/null +++ b/code/datums/ammo/bullet/lever_action.dm @@ -0,0 +1,72 @@ +/* +//====== + Lever Action +//====== +*/ + +/datum/ammo/bullet/lever_action + name = "lever-action bullet" + + damage = 80 + penetration = 0 + accuracy = HIT_ACCURACY_TIER_1 + shell_speed = AMMO_SPEED_TIER_6 + accurate_range = 14 + handful_state = "lever_action_bullet" + +//unused and not working. need to refactor MD code. Unobtainable. +//intended mechanic is to have xenos hit with it show up very frequently on any MDs around +/datum/ammo/bullet/lever_action/tracker + name = "tracking lever-action bullet" + icon_state = "redbullet" + damage = 70 + penetration = ARMOR_PENETRATION_TIER_3 + accuracy = HIT_ACCURACY_TIER_1 + handful_state = "tracking_lever_action_bullet" + +/datum/ammo/bullet/lever_action/tracker/on_hit_mob(mob/M, obj/projectile/P, mob/user) + //SEND_SIGNAL(user, COMSIG_BULLET_TRACKING, user, M) + M.visible_message(SPAN_DANGER("You hear a faint beep under [M]'s [M.mob_size > MOB_SIZE_HUMAN ? "chitin" : "skin"].")) + +/datum/ammo/bullet/lever_action/training + name = "lever-action blank" + icon_state = "blank" + damage = 70 //blanks CAN hurt you if shot very close + penetration = 0 + accuracy = HIT_ACCURACY_TIER_1 + damage_falloff = DAMAGE_FALLOFF_BLANK //not much, though (comparatively) + shell_speed = AMMO_SPEED_TIER_5 + handful_state = "training_lever_action_bullet" + +//unused, and unobtainable... for now +/datum/ammo/bullet/lever_action/marksman + name = "marksman lever-action bullet" + shrapnel_chance = 0 + damage_falloff = 0 + accurate_range = 12 + damage = 70 + penetration = ARMOR_PENETRATION_TIER_6 + shell_speed = AMMO_SPEED_TIER_6 + handful_state = "marksman_lever_action_bullet" + +/datum/ammo/bullet/lever_action/xm88 + name = ".458 SOCOM round" + + damage = 80 + penetration = ARMOR_PENETRATION_TIER_2 + accuracy = HIT_ACCURACY_TIER_1 + shell_speed = AMMO_SPEED_TIER_6 + accurate_range = 14 + handful_state = "boomslang_bullet" + +/datum/ammo/bullet/lever_action/xm88/pen20 + penetration = ARMOR_PENETRATION_TIER_4 + +/datum/ammo/bullet/lever_action/xm88/pen30 + penetration = ARMOR_PENETRATION_TIER_6 + +/datum/ammo/bullet/lever_action/xm88/pen40 + penetration = ARMOR_PENETRATION_TIER_8 + +/datum/ammo/bullet/lever_action/xm88/pen50 + penetration = ARMOR_PENETRATION_TIER_10 diff --git a/code/datums/ammo/bullet/pistol.dm b/code/datums/ammo/bullet/pistol.dm new file mode 100644 index 000000000000..8be63b0a15af --- /dev/null +++ b/code/datums/ammo/bullet/pistol.dm @@ -0,0 +1,265 @@ +/* +//====== + Pistol Ammo +//====== +*/ + +// Used by M4A3, M4A3 Custom and B92FS +/datum/ammo/bullet/pistol + name = "pistol bullet" + headshot_state = HEADSHOT_OVERLAY_MEDIUM + accuracy = -HIT_ACCURACY_TIER_3 + accuracy_var_low = PROJECTILE_VARIANCE_TIER_6 + damage = 40 + penetration= ARMOR_PENETRATION_TIER_2 + shrapnel_chance = SHRAPNEL_CHANCE_TIER_2 + +/datum/ammo/bullet/pistol/tiny + name = "light pistol bullet" + +/datum/ammo/bullet/pistol/tranq + name = "tranquilizer bullet" + flags_ammo_behavior = AMMO_BALLISTIC|AMMO_IGNORE_RESIST + stamina_damage = 30 + damage = 15 + +//2020 rebalance: is supposed to counter runners and lurkers, dealing high damage to the only castes with no armor. +//Limited by its lack of versatility and lower supply, so marines finally have an answer for flanker castes that isn't just buckshot. + +/datum/ammo/bullet/pistol/hollow + name = "hollowpoint pistol bullet" + + damage = 55 //hollowpoint is strong + penetration = 0 //hollowpoint can't pierce armor! + shrapnel_chance = SHRAPNEL_CHANCE_TIER_3 //hollowpoint causes shrapnel + +// Used by M4A3 AP and mod88 +/datum/ammo/bullet/pistol/ap + name = "armor-piercing pistol bullet" + + damage = 25 + accuracy = HIT_ACCURACY_TIER_2 + penetration= ARMOR_PENETRATION_TIER_8 + shrapnel_chance = SHRAPNEL_CHANCE_TIER_2 + +/datum/ammo/bullet/pistol/ap/penetrating + name = "wall-penetrating pistol bullet" + shrapnel_chance = 0 + + damage = 30 + penetration = ARMOR_PENETRATION_TIER_10 + +/datum/ammo/bullet/pistol/ap/penetrating/set_bullet_traits() + . = ..() + LAZYADD(traits_to_give, list( + BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_penetrating) + )) + +/datum/ammo/bullet/pistol/ap/toxin + name = "toxic pistol bullet" + var/acid_per_hit = 10 + var/organic_damage_mult = 3 + +/datum/ammo/bullet/pistol/ap/toxin/on_hit_mob(mob/M, obj/projectile/P) + . = ..() + M.AddComponent(/datum/component/toxic_buildup, acid_per_hit) + +/datum/ammo/bullet/pistol/ap/toxin/on_hit_turf(turf/T, obj/projectile/P) + . = ..() + if(T.flags_turf & TURF_ORGANIC) + P.damage *= organic_damage_mult + +/datum/ammo/bullet/pistol/ap/toxin/on_hit_obj(obj/O, obj/projectile/P) + . = ..() + if(O.flags_obj & OBJ_ORGANIC) + P.damage *= organic_damage_mult + +/datum/ammo/bullet/pistol/le + name = "armor-shredding pistol bullet" + + damage = 15 + penetration = ARMOR_PENETRATION_TIER_4 + pen_armor_punch = 3 + +/datum/ammo/bullet/pistol/rubber + name = "rubber pistol bullet" + sound_override = 'sound/weapons/gun_c99.ogg' + + damage = 0 + stamina_damage = 25 + shrapnel_chance = 0 + +// Reskinned rubber bullet used for the ES-4 CL pistol. +/datum/ammo/bullet/pistol/rubber/stun + name = "stun pistol bullet" + sound_override = null + +// Used by M1911, Deagle and KT-42 +/datum/ammo/bullet/pistol/heavy + name = "heavy pistol bullet" + headshot_state = HEADSHOT_OVERLAY_MEDIUM + accuracy = -HIT_ACCURACY_TIER_3 + accuracy_var_low = PROJECTILE_VARIANCE_TIER_6 + damage = 55 + penetration = ARMOR_PENETRATION_TIER_3 + shrapnel_chance = SHRAPNEL_CHANCE_TIER_2 + +/datum/ammo/bullet/pistol/heavy/super //Commander's variant + name = ".50 heavy pistol bullet" + damage = 60 + damage_var_low = PROJECTILE_VARIANCE_TIER_8 + damage_var_high = PROJECTILE_VARIANCE_TIER_6 + penetration = ARMOR_PENETRATION_TIER_4 + +/datum/ammo/bullet/pistol/heavy/super/highimpact + name = ".50 high-impact pistol bullet" + penetration = ARMOR_PENETRATION_TIER_1 + debilitate = list(0,1.5,0,0,0,1,0,0) + flags_ammo_behavior = AMMO_BALLISTIC + +/datum/ammo/bullet/pistol/heavy/super/highimpact/ap + name = ".50 high-impact armor piercing pistol bullet" + penetration = ARMOR_PENETRATION_TIER_10 + damage = 45 + +/datum/ammo/bullet/pistol/heavy/super/highimpact/upp + name = "high-impact pistol bullet" + sound_override = 'sound/weapons/gun_DE50.ogg' + penetration = ARMOR_PENETRATION_TIER_6 + debilitate = list(0,1.5,0,0,0,1,0,0) + flags_ammo_behavior = AMMO_BALLISTIC + +/datum/ammo/bullet/pistol/heavy/super/highimpact/New() + ..() + RegisterSignal(src, COMSIG_AMMO_POINT_BLANK, PROC_REF(handle_battlefield_execution)) + +/datum/ammo/bullet/pistol/heavy/super/highimpact/on_hit_mob(mob/M, obj/projectile/P) + knockback(M, P, 4) + +/datum/ammo/bullet/pistol/deagle + name = ".50 heavy pistol bullet" + damage = 45 + headshot_state = HEADSHOT_OVERLAY_HEAVY + accuracy = -HIT_ACCURACY_TIER_3 + accuracy_var_low = PROJECTILE_VARIANCE_TIER_6 + penetration = ARMOR_PENETRATION_TIER_6 + shrapnel_chance = SHRAPNEL_CHANCE_TIER_5 + +/datum/ammo/bullet/pistol/incendiary + name = "incendiary pistol bullet" + damage_type = BURN + shrapnel_chance = 0 + flags_ammo_behavior = AMMO_BALLISTIC + + accuracy = HIT_ACCURACY_TIER_3 + damage = 20 + +/datum/ammo/bullet/pistol/incendiary/set_bullet_traits() + ..() + LAZYADD(traits_to_give, list( + BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_incendiary) + )) + +// Used by the hipower +// I know that the 'high power' in the name is supposed to mean its 'impressive' magazine capacity +// but this is CM, half our guns have baffling misconceptions and mistakes (how do you grab the type-71?) so it's on-brand. +// maybe in the far flung future of 2280 someone screwed up the design. + +/datum/ammo/bullet/pistol/highpower + name = "high-powered pistol bullet" + headshot_state = HEADSHOT_OVERLAY_MEDIUM + + accuracy = HIT_ACCURACY_TIER_3 + damage = 36 + penetration = ARMOR_PENETRATION_TIER_5 + damage_falloff = DAMAGE_FALLOFF_TIER_7 + +// Used by VP78 and Auto 9 +/datum/ammo/bullet/pistol/squash + name = "squash-head pistol bullet" + headshot_state = HEADSHOT_OVERLAY_MEDIUM + debilitate = list(0,0,0,0,0,0,0,2) + + accuracy = HIT_ACCURACY_TIER_4 + damage = 45 + penetration= ARMOR_PENETRATION_TIER_6 + shrapnel_chance = SHRAPNEL_CHANCE_TIER_2 + damage_falloff = DAMAGE_FALLOFF_TIER_6 //"VP78 - the only pistol viable as a primary."-Vampmare, probably. + +/datum/ammo/bullet/pistol/squash/toxin + name = "toxic squash-head pistol bullet" + var/acid_per_hit = 10 + var/organic_damage_mult = 3 + +/datum/ammo/bullet/pistol/squash/toxin/on_hit_mob(mob/M, obj/projectile/P) + . = ..() + M.AddComponent(/datum/component/toxic_buildup, acid_per_hit) + +/datum/ammo/bullet/pistol/squash/toxin/on_hit_turf(turf/T, obj/projectile/P) + . = ..() + if(T.flags_turf & TURF_ORGANIC) + P.damage *= organic_damage_mult + +/datum/ammo/bullet/pistol/squash/toxin/on_hit_obj(obj/O, obj/projectile/P) + . = ..() + if(O.flags_obj & OBJ_ORGANIC) + P.damage *= organic_damage_mult + +/datum/ammo/bullet/pistol/squash/penetrating + name = "wall-penetrating squash-head pistol bullet" + shrapnel_chance = 0 + penetration = ARMOR_PENETRATION_TIER_10 + +/datum/ammo/bullet/pistol/squash/penetrating/set_bullet_traits() + . = ..() + LAZYADD(traits_to_give, list( + BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_penetrating) + )) + +/datum/ammo/bullet/pistol/squash/incendiary + name = "incendiary squash-head pistol bullet" + damage_type = BURN + shrapnel_chance = 0 + flags_ammo_behavior = AMMO_BALLISTIC + accuracy = HIT_ACCURACY_TIER_3 + damage = 35 + +/datum/ammo/bullet/pistol/squash/incendiary/set_bullet_traits() + ..() + LAZYADD(traits_to_give, list( + BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_incendiary) + )) + + +/datum/ammo/bullet/pistol/mankey + name = "live monkey" + icon_state = "monkey1" + ping = null //no bounce off. + damage_type = BURN + debilitate = list(4,4,0,0,0,0,0,0) + flags_ammo_behavior = AMMO_IGNORE_ARMOR + + damage = 15 + damage_var_high = PROJECTILE_VARIANCE_TIER_5 + shell_speed = AMMO_SPEED_TIER_2 + +/datum/ammo/bullet/pistol/mankey/set_bullet_traits() + . = ..() + LAZYADD(traits_to_give, list( + BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_incendiary) + )) + +/datum/ammo/bullet/pistol/mankey/on_hit_mob(mob/M,obj/projectile/P) + if(P && P.loc && !M.stat && !istype(M,/mob/living/carbon/human/monkey)) + P.visible_message(SPAN_DANGER("The [src] chimpers furiously!")) + new /mob/living/carbon/human/monkey(P.loc) + +/datum/ammo/bullet/pistol/smart + name = "smartpistol bullet" + flags_ammo_behavior = AMMO_BALLISTIC + + accuracy = HIT_ACCURACY_TIER_8 + damage = 30 + penetration = 20 + shrapnel_chance = SHRAPNEL_CHANCE_TIER_2 + diff --git a/code/datums/ammo/bullet/revolver.dm b/code/datums/ammo/bullet/revolver.dm new file mode 100644 index 000000000000..633bf3e2f7ff --- /dev/null +++ b/code/datums/ammo/bullet/revolver.dm @@ -0,0 +1,180 @@ +/* +//====== + Revolver Ammo +//====== +*/ + +/datum/ammo/bullet/revolver + name = "revolver bullet" + headshot_state = HEADSHOT_OVERLAY_MEDIUM + + damage = 55 + penetration = ARMOR_PENETRATION_TIER_1 + accuracy = HIT_ACCURACY_TIER_1 + +/datum/ammo/bullet/revolver/marksman + name = "marksman revolver bullet" + + shrapnel_chance = 0 + damage_falloff = 0 + accurate_range = 12 + penetration = ARMOR_PENETRATION_TIER_7 + +/datum/ammo/bullet/revolver/heavy + name = "heavy revolver bullet" + + damage = 35 + penetration = ARMOR_PENETRATION_TIER_4 + accuracy = HIT_ACCURACY_TIER_3 + +/datum/ammo/bullet/revolver/heavy/on_hit_mob(mob/entity, obj/projectile/bullet) + slowdown(entity, bullet) + pushback(entity, bullet, 4) + +/datum/ammo/bullet/revolver/incendiary + name = "incendiary revolver bullet" + damage = 40 + +/datum/ammo/bullet/revolver/incendiary/set_bullet_traits() + ..() + LAZYADD(traits_to_give, list( + BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_incendiary) + )) + +/datum/ammo/bullet/revolver/marksman/toxin + name = "toxic revolver bullet" + var/acid_per_hit = 10 + var/organic_damage_mult = 3 + +/datum/ammo/bullet/revolver/marksman/toxin/on_hit_mob(mob/M, obj/projectile/P) + . = ..() + M.AddComponent(/datum/component/toxic_buildup, acid_per_hit) + +/datum/ammo/bullet/revolver/marksman/toxin/on_hit_turf(turf/T, obj/projectile/P) + . = ..() + if(T.flags_turf & TURF_ORGANIC) + P.damage *= organic_damage_mult + +/datum/ammo/bullet/revolver/marksman/toxin/on_hit_obj(obj/O, obj/projectile/P) + . = ..() + if(O.flags_obj & OBJ_ORGANIC) + P.damage *= organic_damage_mult + +/datum/ammo/bullet/revolver/penetrating + name = "wall-penetrating revolver bullet" + shrapnel_chance = 0 + + penetration = ARMOR_PENETRATION_TIER_10 + +/datum/ammo/bullet/revolver/penetrating/set_bullet_traits() + . = ..() + LAZYADD(traits_to_give, list( + BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_penetrating) + )) + +/datum/ammo/bullet/revolver/upp + name = "heavy revolver bullet" + headshot_state = HEADSHOT_OVERLAY_MEDIUM + penetration = ARMOR_PENETRATION_TIER_4 + damage = 70 + + +/datum/ammo/bullet/revolver/upp/shrapnel + name = "shrapnel shot" + headshot_state = HEADSHOT_OVERLAY_HEAVY //Gol-dang shotgun blow your fething head off. + debilitate = list(0,0,0,0,0,0,0,0) + icon_state = "shrapnelshot" + handful_state = "shrapnel" + bonus_projectiles_type = /datum/ammo/bullet/revolver/upp/shrapnel_bits + + max_range = 6 + damage = 40 // + TIER_4 * 3 + damage_falloff = DAMAGE_FALLOFF_TIER_7 + penetration = ARMOR_PENETRATION_TIER_8 + bonus_projectiles_amount = EXTRA_PROJECTILES_TIER_3 + shrapnel_chance = 100 + shrapnel_type = /obj/item/shard/shrapnel/upp + //roughly 90 or so damage with the additional shrapnel, around 130 in total with primary round + +/datum/ammo/bullet/revolver/upp/shrapnel/on_hit_mob(mob/M, obj/projectile/P) + pushback(M, P, 1) + +/datum/ammo/bullet/revolver/upp/shrapnel_bits + name = "small shrapnel" + icon_state = "shrapnelshot_bit" + + max_range = 6 + damage = 30 + penetration = ARMOR_PENETRATION_TIER_4 + scatter = SCATTER_AMOUNT_TIER_1 + bonus_projectiles_amount = 0 + shrapnel_type = /obj/item/shard/shrapnel/upp/bits + +/datum/ammo/bullet/revolver/small + name = "small revolver bullet" + headshot_state = HEADSHOT_OVERLAY_LIGHT + + damage = 45 + + penetration = ARMOR_PENETRATION_TIER_3 + +/datum/ammo/bullet/revolver/small/hollowpoint + name = "small hollowpoint revolver bullet" + headshot_state = HEADSHOT_OVERLAY_MEDIUM + + damage = 75 // way too strong because it's hard to make a good balance between HP and normal with this system, but the damage falloff is really strong + penetration = 0 + damage_falloff = DAMAGE_FALLOFF_TIER_6 + +/datum/ammo/bullet/revolver/mateba + name = ".454 heavy revolver bullet" + + damage = 60 + damage_var_low = PROJECTILE_VARIANCE_TIER_8 + damage_var_high = PROJECTILE_VARIANCE_TIER_6 + penetration = ARMOR_PENETRATION_TIER_4 + +/datum/ammo/bullet/revolver/mateba/highimpact + name = ".454 heavy high-impact revolver bullet" + debilitate = list(0,2,0,0,0,1,0,0) + penetration = ARMOR_PENETRATION_TIER_1 + flags_ammo_behavior = AMMO_BALLISTIC + +/datum/ammo/bullet/revolver/mateba/highimpact/ap + name = ".454 heavy high-impact armor piercing revolver bullet" + penetration = ARMOR_PENETRATION_TIER_10 + damage = 45 + +/datum/ammo/bullet/revolver/mateba/highimpact/New() + ..() + RegisterSignal(src, COMSIG_AMMO_POINT_BLANK, PROC_REF(handle_battlefield_execution)) + +/datum/ammo/bullet/revolver/mateba/highimpact/on_hit_mob(mob/M, obj/projectile/P) + knockback(M, P, 4) + +/datum/ammo/bullet/revolver/mateba/highimpact/explosive //if you ever put this in normal gameplay, i am going to scream + name = ".454 heavy explosive revolver bullet" + damage = 100 + damage_var_low = PROJECTILE_VARIANCE_TIER_10 + damage_var_high = PROJECTILE_VARIANCE_TIER_1 + penetration = ARMOR_PENETRATION_TIER_10 + flags_ammo_behavior = AMMO_EXPLOSIVE|AMMO_BALLISTIC + +/datum/ammo/bullet/revolver/mateba/highimpact/explosive/on_hit_mob(mob/M, obj/projectile/P) + ..() + cell_explosion(get_turf(M), 120, 30, EXPLOSION_FALLOFF_SHAPE_LINEAR, P.dir, P.weapon_cause_data) + +/datum/ammo/bullet/revolver/mateba/highimpact/explosive/on_hit_obj(obj/O, obj/projectile/P) + ..() + cell_explosion(get_turf(O), 120, 30, EXPLOSION_FALLOFF_SHAPE_LINEAR, P.dir, P.weapon_cause_data) + +/datum/ammo/bullet/revolver/mateba/highimpact/explosive/on_hit_turf(turf/T, obj/projectile/P) + ..() + cell_explosion(T, 120, 30, EXPLOSION_FALLOFF_SHAPE_LINEAR, P.dir, P.weapon_cause_data) + +/datum/ammo/bullet/revolver/webley //Mateba round without the knockdown. + name = ".455 Webley bullet" + damage = 60 + damage_var_low = PROJECTILE_VARIANCE_TIER_8 + damage_var_high = PROJECTILE_VARIANCE_TIER_6 + penetration = ARMOR_PENETRATION_TIER_2 diff --git a/code/datums/ammo/bullet/rifle.dm b/code/datums/ammo/bullet/rifle.dm new file mode 100644 index 000000000000..b6085572e3b9 --- /dev/null +++ b/code/datums/ammo/bullet/rifle.dm @@ -0,0 +1,210 @@ +/* +//====== + Rifle Ammo +//====== +*/ + +/datum/ammo/bullet/rifle + name = "rifle bullet" + headshot_state = HEADSHOT_OVERLAY_MEDIUM + + damage = 40 + penetration = ARMOR_PENETRATION_TIER_1 + accurate_range = 16 + accuracy = HIT_ACCURACY_TIER_4 + scatter = SCATTER_AMOUNT_TIER_10 + shell_speed = AMMO_SPEED_TIER_6 + effective_range_max = 7 + damage_falloff = DAMAGE_FALLOFF_TIER_7 + max_range = 24 //So S8 users don't have their bullets magically disappaer at 22 tiles (S8 can see 24 tiles) + +/datum/ammo/bullet/rifle/holo_target + name = "holo-targeting rifle bullet" + damage = 30 + var/holo_stacks = 10 + +/datum/ammo/bullet/rifle/holo_target/on_hit_mob(mob/M, obj/projectile/P) + . = ..() + M.AddComponent(/datum/component/bonus_damage_stack, holo_stacks, world.time) + +/datum/ammo/bullet/rifle/holo_target/hunting + name = "holo-targeting hunting bullet" + damage = 25 + holo_stacks = 15 + +/datum/ammo/bullet/rifle/explosive + name = "explosive rifle bullet" + + damage = 25 + accurate_range = 22 + accuracy = 0 + shell_speed = AMMO_SPEED_TIER_4 + damage_falloff = DAMAGE_FALLOFF_TIER_9 + +/datum/ammo/bullet/rifle/explosive/on_hit_mob(mob/M, obj/projectile/P) + cell_explosion(get_turf(M), 80, 40, EXPLOSION_FALLOFF_SHAPE_LINEAR, P.dir, P.weapon_cause_data) + +/datum/ammo/bullet/rifle/explosive/on_hit_obj(obj/O, obj/projectile/P) + cell_explosion(get_turf(O), 80, 40, EXPLOSION_FALLOFF_SHAPE_LINEAR, P.dir, P.weapon_cause_data) + +/datum/ammo/bullet/rifle/explosive/on_hit_turf(turf/T, obj/projectile/P) + if(T.density) + cell_explosion(T, 80, 40, EXPLOSION_FALLOFF_SHAPE_LINEAR, P.dir, P.weapon_cause_data) + +/datum/ammo/bullet/rifle/ap + name = "armor-piercing rifle bullet" + + damage = 30 + penetration = ARMOR_PENETRATION_TIER_8 + +// Basically AP but better. Focused at taking out armour temporarily +/datum/ammo/bullet/rifle/ap/toxin + name = "toxic rifle bullet" + var/acid_per_hit = 7 + var/organic_damage_mult = 3 + +/datum/ammo/bullet/rifle/ap/toxin/on_hit_mob(mob/M, obj/projectile/P) + . = ..() + M.AddComponent(/datum/component/toxic_buildup, acid_per_hit) + +/datum/ammo/bullet/rifle/ap/toxin/on_hit_turf(turf/T, obj/projectile/P) + . = ..() + if(T.flags_turf & TURF_ORGANIC) + P.damage *= organic_damage_mult + +/datum/ammo/bullet/rifle/ap/toxin/on_hit_obj(obj/O, obj/projectile/P) + . = ..() + if(O.flags_obj & OBJ_ORGANIC) + P.damage *= organic_damage_mult + + +/datum/ammo/bullet/rifle/ap/penetrating + name = "wall-penetrating rifle bullet" + shrapnel_chance = 0 + + damage = 35 + penetration = ARMOR_PENETRATION_TIER_10 + +/datum/ammo/bullet/rifle/ap/penetrating/set_bullet_traits() + . = ..() + LAZYADD(traits_to_give, list( + BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_penetrating) + )) + +/datum/ammo/bullet/rifle/le + name = "armor-shredding rifle bullet" + + damage = 20 + penetration = ARMOR_PENETRATION_TIER_4 + pen_armor_punch = 5 + +/datum/ammo/bullet/rifle/heap + name = "high-explosive armor-piercing rifle bullet" + + headshot_state = HEADSHOT_OVERLAY_HEAVY + damage = 55//big damage, doesn't actually blow up because thats stupid. + penetration = ARMOR_PENETRATION_TIER_8 + +/datum/ammo/bullet/rifle/rubber + name = "rubber rifle bullet" + sound_override = 'sound/weapons/gun_c99.ogg' + + damage = 0 + stamina_damage = 15 + shrapnel_chance = 0 + +/datum/ammo/bullet/rifle/incendiary + name = "incendiary rifle bullet" + damage_type = BURN + shrapnel_chance = 0 + flags_ammo_behavior = AMMO_BALLISTIC + + damage = 30 + shell_speed = AMMO_SPEED_TIER_4 + accuracy = -HIT_ACCURACY_TIER_2 + damage_falloff = DAMAGE_FALLOFF_TIER_10 + +/datum/ammo/bullet/rifle/incendiary/set_bullet_traits() + . = ..() + LAZYADD(traits_to_give, list( + BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_incendiary) + )) + +/datum/ammo/bullet/rifle/m4ra + name = "A19 high velocity bullet" + shrapnel_chance = 0 + damage_falloff = 0 + flags_ammo_behavior = AMMO_BALLISTIC + accurate_range_min = 4 + + damage = 55 + scatter = -SCATTER_AMOUNT_TIER_8 + penetration= ARMOR_PENETRATION_TIER_7 + shell_speed = AMMO_SPEED_TIER_6 + +/datum/ammo/bullet/rifle/m4ra/incendiary + name = "A19 high velocity incendiary bullet" + flags_ammo_behavior = AMMO_BALLISTIC + + damage = 40 + accuracy = HIT_ACCURACY_TIER_4 + scatter = -SCATTER_AMOUNT_TIER_8 + penetration= ARMOR_PENETRATION_TIER_5 + shell_speed = AMMO_SPEED_TIER_6 + +/datum/ammo/bullet/rifle/m4ra/incendiary/set_bullet_traits() + . = ..() + LAZYADD(traits_to_give, list( + BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_incendiary) + )) + +/datum/ammo/bullet/rifle/m4ra/impact + name = "A19 high velocity impact bullet" + flags_ammo_behavior = AMMO_BALLISTIC + + damage = 40 + accuracy = -HIT_ACCURACY_TIER_2 + scatter = -SCATTER_AMOUNT_TIER_8 + penetration = ARMOR_PENETRATION_TIER_10 + shell_speed = AMMO_SPEED_TIER_6 + +/datum/ammo/bullet/rifle/m4ra/impact/on_hit_mob(mob/M, obj/projectile/P) + knockback(M, P, 32) // Can knockback basically at max range + +/datum/ammo/bullet/rifle/m4ra/impact/knockback_effects(mob/living/living_mob, obj/projectile/fired_projectile) + if(iscarbonsizexeno(living_mob)) + var/mob/living/carbon/xenomorph/target = living_mob + to_chat(target, SPAN_XENODANGER("You are shaken and slowed by the sudden impact!")) + target.apply_effect(0.5, WEAKEN) + target.apply_effect(2, SUPERSLOW) + target.apply_effect(5, SLOW) + else + if(!isyautja(living_mob)) //Not predators. + living_mob.apply_effect(1, SUPERSLOW) + living_mob.apply_effect(2, SLOW) + to_chat(living_mob, SPAN_HIGHDANGER("The impact knocks you off-balance!")) + living_mob.apply_stamina_damage(fired_projectile.ammo.damage, fired_projectile.def_zone, ARMOR_BULLET) + +/datum/ammo/bullet/rifle/mar40 + name = "heavy rifle bullet" + + damage = 55 + +/datum/ammo/bullet/rifle/type71 + name = "heavy rifle bullet" + + damage = 55 + penetration = ARMOR_PENETRATION_TIER_3 + +/datum/ammo/bullet/rifle/type71/ap + name = "heavy armor-piercing rifle bullet" + + damage = 40 + penetration = ARMOR_PENETRATION_TIER_10 + +/datum/ammo/bullet/rifle/type71/heap + name = "heavy high-explosive armor-piercing rifle bullet" + + headshot_state = HEADSHOT_OVERLAY_HEAVY + damage = 65 + penetration = ARMOR_PENETRATION_TIER_10 diff --git a/code/datums/ammo/bullet/shotgun.dm b/code/datums/ammo/bullet/shotgun.dm new file mode 100644 index 000000000000..4cedb8b3ee69 --- /dev/null +++ b/code/datums/ammo/bullet/shotgun.dm @@ -0,0 +1,362 @@ +/* +//====== + Shotgun Ammo +//====== +*/ + +/datum/ammo/bullet/shotgun + headshot_state = HEADSHOT_OVERLAY_HEAVY + +/datum/ammo/bullet/shotgun/slug + name = "shotgun slug" + handful_state = "slug_shell" + + accurate_range = 6 + max_range = 8 + damage = 70 + penetration = ARMOR_PENETRATION_TIER_4 + damage_armor_punch = 2 + handful_state = "slug_shell" + +/datum/ammo/bullet/shotgun/slug/on_hit_mob(mob/M,obj/projectile/P) + knockback(M, P, 6) + +/datum/ammo/bullet/shotgun/slug/knockback_effects(mob/living/living_mob, obj/projectile/fired_projectile) + if(iscarbonsizexeno(living_mob)) + var/mob/living/carbon/xenomorph/target = living_mob + to_chat(target, SPAN_XENODANGER("You are shaken and slowed by the sudden impact!")) + target.apply_effect(0.5, WEAKEN) + target.apply_effect(1, SUPERSLOW) + target.apply_effect(3, SLOW) + else + if(!isyautja(living_mob)) //Not predators. + living_mob.apply_effect(1, SUPERSLOW) + living_mob.apply_effect(2, SLOW) + to_chat(living_mob, SPAN_HIGHDANGER("The impact knocks you off-balance!")) + living_mob.apply_stamina_damage(fired_projectile.ammo.damage, fired_projectile.def_zone, ARMOR_BULLET) + +/datum/ammo/bullet/shotgun/beanbag + name = "beanbag slug" + headshot_state = HEADSHOT_OVERLAY_LIGHT //It's not meant to kill people... but if you put it in your mouth, it will. + handful_state = "beanbag_slug" + icon_state = "beanbag" + flags_ammo_behavior = AMMO_BALLISTIC|AMMO_IGNORE_RESIST + sound_override = 'sound/weapons/gun_shotgun_riot.ogg' + + max_range = 12 + shrapnel_chance = 0 + damage = 0 + stamina_damage = 45 + accuracy = HIT_ACCURACY_TIER_3 + shell_speed = AMMO_SPEED_TIER_3 + handful_state = "beanbag_slug" + +/datum/ammo/bullet/shotgun/beanbag/on_hit_mob(mob/M, obj/projectile/P) + if(!M || M == P.firer) return + if(ishuman(M)) + var/mob/living/carbon/human/H = M + shake_camera(H, 2, 1) + + +/datum/ammo/bullet/shotgun/incendiary + name = "incendiary slug" + handful_state = "incendiary_slug" + damage_type = BURN + flags_ammo_behavior = AMMO_BALLISTIC + + accuracy = -HIT_ACCURACY_TIER_2 + max_range = 12 + damage = 55 + penetration= ARMOR_PENETRATION_TIER_1 + handful_state = "incendiary_slug" + +/datum/ammo/bullet/shotgun/incendiary/set_bullet_traits() + . = ..() + LAZYADD(traits_to_give, list( + BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_incendiary) + )) + +/datum/ammo/bullet/shotgun/incendiary/on_hit_mob(mob/M,obj/projectile/P) + burst(get_turf(M),P,damage_type) + knockback(M,P) + +/datum/ammo/bullet/shotgun/incendiary/on_hit_obj(obj/O,obj/projectile/P) + burst(get_turf(P),P,damage_type) + +/datum/ammo/bullet/shotgun/incendiary/on_hit_turf(turf/T,obj/projectile/P) + burst(get_turf(T),P,damage_type) + + +/datum/ammo/bullet/shotgun/flechette + name = "flechette shell" + icon_state = "flechette" + handful_state = "flechette_shell" + bonus_projectiles_type = /datum/ammo/bullet/shotgun/flechette_spread + + accuracy_var_low = PROJECTILE_VARIANCE_TIER_6 + accuracy_var_high = PROJECTILE_VARIANCE_TIER_6 + max_range = 12 + damage = 30 + damage_var_low = PROJECTILE_VARIANCE_TIER_8 + damage_var_high = PROJECTILE_VARIANCE_TIER_8 + penetration = ARMOR_PENETRATION_TIER_7 + bonus_projectiles_amount = EXTRA_PROJECTILES_TIER_3 + handful_state = "flechette_shell" + multiple_handful_name = TRUE + +/datum/ammo/bullet/shotgun/flechette_spread + name = "additional flechette" + icon_state = "flechette" + + accuracy_var_low = PROJECTILE_VARIANCE_TIER_6 + accuracy_var_high = PROJECTILE_VARIANCE_TIER_6 + max_range = 12 + damage = 30 + damage_var_low = PROJECTILE_VARIANCE_TIER_8 + damage_var_high = PROJECTILE_VARIANCE_TIER_8 + penetration = ARMOR_PENETRATION_TIER_7 + scatter = SCATTER_AMOUNT_TIER_5 + +/datum/ammo/bullet/shotgun/buckshot + name = "buckshot shell" + icon_state = "buckshot" + handful_state = "buckshot_shell" + multiple_handful_name = TRUE + bonus_projectiles_type = /datum/ammo/bullet/shotgun/spread + + accuracy_var_low = PROJECTILE_VARIANCE_TIER_5 + accuracy_var_high = PROJECTILE_VARIANCE_TIER_5 + accurate_range = 4 + max_range = 4 + damage = 65 + damage_var_low = PROJECTILE_VARIANCE_TIER_8 + damage_var_high = PROJECTILE_VARIANCE_TIER_8 + penetration = ARMOR_PENETRATION_TIER_1 + bonus_projectiles_amount = EXTRA_PROJECTILES_TIER_3 + shell_speed = AMMO_SPEED_TIER_2 + damage_armor_punch = 0 + pen_armor_punch = 0 + handful_state = "buckshot_shell" + multiple_handful_name = TRUE + +/datum/ammo/bullet/shotgun/buckshot/incendiary + name = "incendiary buckshot shell" + handful_state = "incen_buckshot" + handful_type = /obj/item/ammo_magazine/handful/shotgun/buckshot/incendiary + +/datum/ammo/bullet/shotgun/buckshot/incendiary/set_bullet_traits() + . = ..() + LAZYADD(traits_to_give, list( + BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_incendiary) + )) + +/datum/ammo/bullet/shotgun/buckshot/on_hit_mob(mob/M,obj/projectile/P) + knockback(M,P) + +//buckshot variant only used by the masterkey shotgun attachment. +/datum/ammo/bullet/shotgun/buckshot/masterkey + bonus_projectiles_type = /datum/ammo/bullet/shotgun/spread/masterkey + + damage = 55 + +/datum/ammo/bullet/shotgun/spread + name = "additional buckshot" + icon_state = "buckshot" + + accuracy_var_low = PROJECTILE_VARIANCE_TIER_6 + accuracy_var_high = PROJECTILE_VARIANCE_TIER_6 + accurate_range = 4 + max_range = 6 + damage = 65 + damage_var_low = PROJECTILE_VARIANCE_TIER_8 + damage_var_high = PROJECTILE_VARIANCE_TIER_8 + penetration = ARMOR_PENETRATION_TIER_1 + shell_speed = AMMO_SPEED_TIER_2 + scatter = SCATTER_AMOUNT_TIER_1 + damage_armor_punch = 0 + pen_armor_punch = 0 + +/datum/ammo/bullet/shotgun/spread/masterkey + damage = 20 + +/* + 8 GAUGE SHOTGUN AMMO +*/ + +/datum/ammo/bullet/shotgun/heavy/buckshot + name = "heavy buckshot shell" + icon_state = "buckshot" + handful_state = "heavy_buckshot" + multiple_handful_name = TRUE + bonus_projectiles_type = /datum/ammo/bullet/shotgun/heavy/buckshot/spread + bonus_projectiles_amount = EXTRA_PROJECTILES_TIER_3 + accurate_range = 3 + max_range = 3 + damage = 75 + penetration = 0 + shell_speed = AMMO_SPEED_TIER_2 + damage_armor_punch = 0 + pen_armor_punch = 0 + +/datum/ammo/bullet/shotgun/heavy/buckshot/on_hit_mob(mob/M,obj/projectile/P) + knockback(M,P) + +/datum/ammo/bullet/shotgun/heavy/buckshot/spread + name = "additional heavy buckshot" + max_range = 4 + scatter = SCATTER_AMOUNT_TIER_1 + bonus_projectiles_amount = 0 + +//basically the same +/datum/ammo/bullet/shotgun/heavy/buckshot/dragonsbreath + name = "dragon's breath shell" + handful_state = "heavy_dragonsbreath" + multiple_handful_name = TRUE + damage_type = BURN + damage = 60 + accurate_range = 3 + max_range = 4 + bonus_projectiles_type = /datum/ammo/bullet/shotgun/heavy/buckshot/dragonsbreath/spread + +/datum/ammo/bullet/shotgun/heavy/buckshot/dragonsbreath/set_bullet_traits() + . = ..() + LAZYADD(traits_to_give, list( + BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_incendiary) + )) + +/datum/ammo/bullet/shotgun/heavy/buckshot/dragonsbreath/spread + name = "additional dragon's breath" + bonus_projectiles_amount = 0 + accurate_range = 4 + max_range = 5 //make use of the ablaze property + shell_speed = AMMO_SPEED_TIER_4 // so they hit before the main shell stuns + + +/datum/ammo/bullet/shotgun/heavy/slug + name = "heavy shotgun slug" + handful_state = "heavy_slug" + + accurate_range = 7 + max_range = 8 + damage = 90 //ouch. + penetration = ARMOR_PENETRATION_TIER_6 + damage_armor_punch = 2 + +/datum/ammo/bullet/shotgun/heavy/slug/on_hit_mob(mob/M,obj/projectile/P) + knockback(M, P, 7) + +/datum/ammo/bullet/shotgun/heavy/slug/knockback_effects(mob/living/living_mob, obj/projectile/fired_projectile) + if(iscarbonsizexeno(living_mob)) + var/mob/living/carbon/xenomorph/target = living_mob + to_chat(target, SPAN_XENODANGER("You are shaken and slowed by the sudden impact!")) + target.apply_effect(0.5, WEAKEN) + target.apply_effect(2, SUPERSLOW) + target.apply_effect(5, SLOW) + else + if(!isyautja(living_mob)) //Not predators. + living_mob.apply_effect(1, SUPERSLOW) + living_mob.apply_effect(2, SLOW) + to_chat(living_mob, SPAN_HIGHDANGER("The impact knocks you off-balance!")) + living_mob.apply_stamina_damage(fired_projectile.ammo.damage, fired_projectile.def_zone, ARMOR_BULLET) + +/datum/ammo/bullet/shotgun/heavy/beanbag + name = "heavy beanbag slug" + icon_state = "beanbag" + headshot_state = HEADSHOT_OVERLAY_MEDIUM + handful_state = "heavy_beanbag" + flags_ammo_behavior = AMMO_BALLISTIC|AMMO_IGNORE_RESIST + sound_override = 'sound/weapons/gun_shotgun_riot.ogg' + + max_range = 7 + shrapnel_chance = 0 + damage = 0 + stamina_damage = 100 + accuracy = HIT_ACCURACY_TIER_2 + shell_speed = AMMO_SPEED_TIER_2 + +/datum/ammo/bullet/shotgun/heavy/beanbag/on_hit_mob(mob/M, obj/projectile/P) + if(!M || M == P.firer) + return + if(ishuman(M)) + var/mob/living/carbon/human/H = M + shake_camera(H, 2, 1) + +/datum/ammo/bullet/shotgun/heavy/flechette + name = "heavy flechette shell" + icon_state = "flechette" + handful_state = "heavy_flechette" + multiple_handful_name = TRUE + bonus_projectiles_type = /datum/ammo/bullet/shotgun/heavy/flechette_spread + + accuracy_var_low = PROJECTILE_VARIANCE_TIER_3 + accuracy_var_high = PROJECTILE_VARIANCE_TIER_3 + max_range = 12 + damage = 45 + damage_var_low = PROJECTILE_VARIANCE_TIER_8 + damage_var_high = PROJECTILE_VARIANCE_TIER_8 + penetration = ARMOR_PENETRATION_TIER_10 + bonus_projectiles_amount = EXTRA_PROJECTILES_TIER_2 + +/datum/ammo/bullet/shotgun/heavy/flechette_spread + name = "additional heavy flechette" + icon_state = "flechette" + accuracy_var_low = PROJECTILE_VARIANCE_TIER_6 + accuracy_var_high = PROJECTILE_VARIANCE_TIER_6 + max_range = 12 + damage = 45 + damage_var_low = PROJECTILE_VARIANCE_TIER_8 + damage_var_high = PROJECTILE_VARIANCE_TIER_8 + penetration = ARMOR_PENETRATION_TIER_10 + scatter = SCATTER_AMOUNT_TIER_4 + +//Enormous shell for Van Bandolier's superheavy double-barreled hunting gun. +/datum/ammo/bullet/shotgun/twobore + name = "two bore bullet" + icon_state = "autocannon" + handful_state = "twobore" + + accurate_range = 8 //Big low-velocity projectile; this is for blasting dangerous game at close range. + max_range = 14 //At this range, it's lost all its damage anyway. + damage = 300 //Hits like a buckshot PB. + penetration = ARMOR_PENETRATION_TIER_3 + damage_falloff = DAMAGE_FALLOFF_TIER_1 * 3 //It has a lot of energy, but the 26mm bullet drops off fast. + effective_range_max = EFFECTIVE_RANGE_MAX_TIER_2 //Full damage up to this distance, then falloff for each tile beyond. + var/hit_messages = list() + +/datum/ammo/bullet/shotgun/twobore/on_hit_mob(mob/living/M, obj/projectile/P) + var/mob/shooter = P.firer + if(shooter && ismob(shooter) && HAS_TRAIT(shooter, TRAIT_TWOBORE_TRAINING) && M.stat != DEAD && prob(40)) //Death is handled by periodic life() checks so this should have a chance to fire on a killshot. + if(!length(hit_messages)) //Pick and remove lines, refill on exhaustion. + hit_messages = list("Got you!", "Aha!", "Bullseye!", "It's curtains for you, Sonny Jim!", "Your head will look fantastic on my wall!", "I have you now!", "You miserable coward! Come and fight me like a man!", "Tally ho!") + var/message = pick_n_take(hit_messages) + shooter.say(message) + + if(P.distance_travelled > 8) + knockback(M, P, 12) + + else if(!M || M == P.firer || M.lying) //These checks are included in knockback and would be redundant above. + return + + shake_camera(M, 3, 4) + M.apply_effect(2, WEAKEN) + M.apply_effect(4, SLOW) + if(iscarbonsizexeno(M)) + to_chat(M, SPAN_XENODANGER("The impact knocks you off your feet!")) + else //This will hammer a Yautja as hard as a human. + to_chat(M, SPAN_HIGHDANGER("The impact knocks you off your feet!")) + + step(M, get_dir(P.firer, M)) + +/datum/ammo/bullet/shotgun/twobore/knockback_effects(mob/living/living_mob, obj/projectile/fired_projectile) + if(iscarbonsizexeno(living_mob)) + var/mob/living/carbon/xenomorph/target = living_mob + to_chat(target, SPAN_XENODANGER("You are shaken and slowed by the sudden impact!")) + target.apply_effect(0.5, WEAKEN) + target.apply_effect(2, SUPERSLOW) + target.apply_effect(5, SLOW) + else + if(!isyautja(living_mob)) //Not predators. + living_mob.apply_effect(1, SUPERSLOW) + living_mob.apply_effect(2, SLOW) + to_chat(living_mob, SPAN_HIGHDANGER("The impact knocks you off-balance!")) + living_mob.apply_stamina_damage(fired_projectile.ammo.damage, fired_projectile.def_zone, ARMOR_BULLET) diff --git a/code/datums/ammo/bullet/smg.dm b/code/datums/ammo/bullet/smg.dm new file mode 100644 index 000000000000..e24b3021da97 --- /dev/null +++ b/code/datums/ammo/bullet/smg.dm @@ -0,0 +1,147 @@ +/* +//====== + SMG Ammo +//====== +*/ +//2020 SMG/ammo rebalance. default ammo actually has penetration so it can be useful, by 4khan: should be meh against t3s, better under 15 armor. Perfectly does this right now (oct 2020) +//has reduced falloff compared to the m39. this means it is best for kiting castes (mostly t2s and below admittedly) +//while the m39 ap is better for shredding them at close range, but has reduced velocity, so it's better for just running in and erasing armor-centric castes (defender, crusher) +// which i think is really interesting and good balance, giving both ammo types a reason to exist even against ravagers. +//i feel it is necessary to reflavor the default bullet, because otherwise, people won't be able to notice it has less falloff and faster bullet speed. even with a changelog, +//way too many people don't read the changelog, and after one or two months the changelog entry is all but archive, so there needs to be an ingame description of what the ammo does +//in comparison to armor-piercing rounds. + +/datum/ammo/bullet/smg + name = "submachinegun bullet" + damage = 34 + accurate_range = 4 + effective_range_max = 4 + penetration = ARMOR_PENETRATION_TIER_1 + shell_speed = AMMO_SPEED_TIER_6 + damage_falloff = DAMAGE_FALLOFF_TIER_5 + scatter = SCATTER_AMOUNT_TIER_6 + accuracy = HIT_ACCURACY_TIER_3 + +/datum/ammo/bullet/smg/m39 + name = "high-velocity submachinegun bullet" //i don't want all smgs to inherit 'high velocity' + +/datum/ammo/bullet/smg/ap + name = "armor-piercing submachinegun bullet" + + damage = 26 + penetration = ARMOR_PENETRATION_TIER_6 + shell_speed = AMMO_SPEED_TIER_4 + +/datum/ammo/bullet/smg/heap + name = "high-explosive armor-piercing submachinegun bullet" + + damage = 45 + headshot_state = HEADSHOT_OVERLAY_MEDIUM + penetration = ARMOR_PENETRATION_TIER_6 + shell_speed = AMMO_SPEED_TIER_4 + +/datum/ammo/bullet/smg/ap/toxin + name = "toxic submachinegun bullet" + var/acid_per_hit = 5 + var/organic_damage_mult = 3 + +/datum/ammo/bullet/smg/ap/toxin/on_hit_mob(mob/M, obj/projectile/P) + . = ..() + M.AddComponent(/datum/component/toxic_buildup, acid_per_hit) + +/datum/ammo/bullet/smg/ap/toxin/on_hit_turf(turf/T, obj/projectile/P) + . = ..() + if(T.flags_turf & TURF_ORGANIC) + P.damage *= organic_damage_mult + +/datum/ammo/bullet/smg/ap/toxin/on_hit_obj(obj/O, obj/projectile/P) + . = ..() + if(O.flags_obj & OBJ_ORGANIC) + P.damage *= organic_damage_mult + +/datum/ammo/bullet/smg/nail + name = "7x45mm plasteel nail" + icon_state = "nail-projectile" + + damage = 25 + penetration = ARMOR_PENETRATION_TIER_5 + damage_falloff = DAMAGE_FALLOFF_TIER_6 + accurate_range = 5 + shell_speed = AMMO_SPEED_TIER_4 + +/datum/ammo/bullet/smg/incendiary + name = "incendiary submachinegun bullet" + damage_type = BURN + shrapnel_chance = 0 + flags_ammo_behavior = AMMO_BALLISTIC + + damage = 25 + accuracy = -HIT_ACCURACY_TIER_2 + +/datum/ammo/bullet/smg/incendiary/set_bullet_traits() + . = ..() + LAZYADD(traits_to_give, list( + BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_incendiary) + )) + +/datum/ammo/bullet/smg/ap/penetrating + name = "wall-penetrating submachinegun bullet" + shrapnel_chance = 0 + + damage = 30 + penetration = ARMOR_PENETRATION_TIER_10 + +/datum/ammo/bullet/smg/ap/penetrating/set_bullet_traits() + . = ..() + LAZYADD(traits_to_give, list( + BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_penetrating) + )) + +/datum/ammo/bullet/smg/le + name = "armor-shredding submachinegun bullet" + + scatter = SCATTER_AMOUNT_TIER_10 + damage = 20 + penetration = ARMOR_PENETRATION_TIER_4 + shell_speed = AMMO_SPEED_TIER_3 + damage_falloff = DAMAGE_FALLOFF_TIER_10 + pen_armor_punch = 4 + +/datum/ammo/bullet/smg/rubber + name = "rubber submachinegun bullet" + sound_override = 'sound/weapons/gun_c99.ogg' + + damage = 0 + stamina_damage = 10 + shrapnel_chance = 0 + +/datum/ammo/bullet/smg/mp27 + name = "simple submachinegun bullet" + damage = 40 + accurate_range = 5 + effective_range_max = 7 + penetration = 0 + shell_speed = AMMO_SPEED_TIER_6 + damage_falloff = DAMAGE_FALLOFF_TIER_6 + scatter = SCATTER_AMOUNT_TIER_6 + accuracy = HIT_ACCURACY_TIER_2 + +// less damage than the m39, but better falloff, range, and AP + +/datum/ammo/bullet/smg/ppsh + name = "crude submachinegun bullet" + damage = 26 + accurate_range = 7 + effective_range_max = 7 + penetration = ARMOR_PENETRATION_TIER_2 + damage_falloff = DAMAGE_FALLOFF_TIER_7 + scatter = SCATTER_AMOUNT_TIER_5 + +/datum/ammo/bullet/smg/pps43 + name = "simple submachinegun bullet" + damage = 35 + accurate_range = 7 + effective_range_max = 10 + penetration = ARMOR_PENETRATION_TIER_4 + damage_falloff = DAMAGE_FALLOFF_TIER_6 + scatter = SCATTER_AMOUNT_TIER_6 diff --git a/code/datums/ammo/bullet/sniper.dm b/code/datums/ammo/bullet/sniper.dm new file mode 100644 index 000000000000..a82f00631608 --- /dev/null +++ b/code/datums/ammo/bullet/sniper.dm @@ -0,0 +1,170 @@ +/* +//====== + Sniper Ammo +//====== +*/ + +/datum/ammo/bullet/sniper + name = "sniper bullet" + headshot_state = HEADSHOT_OVERLAY_HEAVY + damage_falloff = 0 + flags_ammo_behavior = AMMO_BALLISTIC|AMMO_SNIPER|AMMO_IGNORE_COVER + accurate_range_min = 4 + + accuracy = HIT_ACCURACY_TIER_8 + accurate_range = 32 + max_range = 32 + scatter = 0 + damage = 70 + penetration= ARMOR_PENETRATION_TIER_10 + shell_speed = AMMO_SPEED_TIER_6 + damage_falloff = 0 + +/datum/ammo/bullet/sniper/on_hit_mob(mob/M,obj/projectile/P) + if((P.projectile_flags & PROJECTILE_BULLSEYE) && M == P.original) + var/mob/living/L = M + L.apply_armoured_damage(damage*2, ARMOR_BULLET, BRUTE, null, penetration) + to_chat(P.firer, SPAN_WARNING("Bullseye!")) + +/datum/ammo/bullet/sniper/incendiary + name = "incendiary sniper bullet" + damage_type = BRUTE + shrapnel_chance = 0 + flags_ammo_behavior = AMMO_BALLISTIC|AMMO_SNIPER|AMMO_IGNORE_COVER + + //Removed accuracy = 0, accuracy_var_high = Variance Tier 6, and scatter = 0. -Kaga + damage = 60 + penetration = ARMOR_PENETRATION_TIER_4 + +/datum/ammo/bullet/sniper/incendiary/set_bullet_traits() + . = ..() + LAZYADD(traits_to_give, list( + BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_incendiary) + )) + +/datum/ammo/bullet/sniper/incendiary/on_hit_mob(mob/M,obj/projectile/P) + if((P.projectile_flags & PROJECTILE_BULLSEYE) && M == P.original) + var/mob/living/L = M + var/blind_duration = 5 + if(isxeno(M)) + var/mob/living/carbon/xenomorph/target = M + if(target.mob_size >= MOB_SIZE_BIG) + blind_duration = 2 + L.AdjustEyeBlur(blind_duration) + L.adjust_fire_stacks(10) + to_chat(P.firer, SPAN_WARNING("Bullseye!")) + +/datum/ammo/bullet/sniper/flak + name = "flak sniper bullet" + damage_type = BRUTE + flags_ammo_behavior = AMMO_BALLISTIC|AMMO_SNIPER|AMMO_IGNORE_COVER + + accuracy = HIT_ACCURACY_TIER_8 + scatter = SCATTER_AMOUNT_TIER_8 + damage = 55 + damage_var_high = PROJECTILE_VARIANCE_TIER_8 //Documenting old code: This converts to a variance of 96-109% damage. -Kaga + penetration = 0 + +/datum/ammo/bullet/sniper/flak/on_hit_mob(mob/M,obj/projectile/P) + if((P.projectile_flags & PROJECTILE_BULLSEYE) && M == P.original) + var/slow_duration = 7 + var/mob/living/L = M + if(isxeno(M)) + var/mob/living/carbon/xenomorph/target = M + if(target.mob_size >= MOB_SIZE_BIG) + slow_duration = 4 + M.adjust_effect(slow_duration, SUPERSLOW) + L.apply_armoured_damage(damage, ARMOR_BULLET, BRUTE, null, penetration) + to_chat(P.firer, SPAN_WARNING("Bullseye!")) + else + burst(get_turf(M),P,damage_type, 2 , 2) + burst(get_turf(M),P,damage_type, 1 , 2 , 0) + +/datum/ammo/bullet/sniper/flak/on_near_target(turf/T, obj/projectile/P) + burst(T,P,damage_type, 2 , 2) + burst(T,P,damage_type, 1 , 2, 0) + return 1 + +/datum/ammo/bullet/sniper/crude + name = "crude sniper bullet" + damage = 42 + penetration = ARMOR_PENETRATION_TIER_6 + +/datum/ammo/bullet/sniper/crude/on_hit_mob(mob/M, obj/projectile/P) + . = ..() + pushback(M, P, 3) + +/datum/ammo/bullet/sniper/upp + name = "armor-piercing sniper bullet" + damage = 80 + penetration = ARMOR_PENETRATION_TIER_10 + +/datum/ammo/bullet/sniper/anti_materiel + name = "anti-materiel sniper bullet" + + shrapnel_chance = 0 // This isn't leaving any shrapnel. + accuracy = HIT_ACCURACY_TIER_8 + damage = 125 + shell_speed = AMMO_SPEED_TIER_6 + +/datum/ammo/bullet/sniper/anti_materiel/on_hit_mob(mob/M,obj/projectile/P) + if((P.projectile_flags & PROJECTILE_BULLSEYE) && M == P.original) + var/mob/living/L = M + var/size_damage_mod = 0.8 + if(isxeno(M)) + var/mob/living/carbon/xenomorph/target = M + if(target.mob_size >= MOB_SIZE_XENO) + size_damage_mod += 0.6 + if(target.mob_size >= MOB_SIZE_BIG) + size_damage_mod += 0.6 + L.apply_armoured_damage(damage*size_damage_mod, ARMOR_BULLET, BRUTE, null, penetration) + // 180% damage to all targets (225), 240% (300) against non-Runner xenos, and 300% against Big xenos (375). -Kaga + to_chat(P.firer, SPAN_WARNING("Bullseye!")) + +/datum/ammo/bullet/sniper/anti_materiel/vulture + damage = 400 // Fully intended to vaporize anything smaller than a mini cooper + accurate_range_min = 10 + handful_state = "vulture_bullet" + sound_hit = 'sound/bullets/bullet_vulture_impact.ogg' + flags_ammo_behavior = AMMO_BALLISTIC|AMMO_SNIPER|AMMO_IGNORE_COVER|AMMO_ANTIVEHICLE + +/datum/ammo/bullet/sniper/anti_materiel/vulture/on_hit_mob(mob/hit_mob, obj/projectile/bullet) + . = ..() + knockback(hit_mob, bullet, 30) + hit_mob.apply_effect(3, SLOW) + +/datum/ammo/bullet/sniper/anti_materiel/vulture/set_bullet_traits() + . = ..() + LAZYADD(traits_to_give, list( + BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_penetrating/heavy) + )) + +/datum/ammo/bullet/sniper/elite + name = "supersonic sniper bullet" + + shrapnel_chance = 0 // This isn't leaving any shrapnel. + accuracy = HIT_ACCURACY_TIER_8 + damage = 150 + shell_speed = AMMO_SPEED_TIER_6 + AMMO_SPEED_TIER_2 + +/datum/ammo/bullet/sniper/elite/set_bullet_traits() + . = ..() + LAZYADD(traits_to_give, list( + BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_penetrating) + )) + +/datum/ammo/bullet/sniper/elite/on_hit_mob(mob/M,obj/projectile/P) + if((P.projectile_flags & PROJECTILE_BULLSEYE) && M == P.original) + var/mob/living/L = M + var/size_damage_mod = 0.5 + if(isxeno(M)) + var/mob/living/carbon/xenomorph/target = M + if(target.mob_size >= MOB_SIZE_XENO) + size_damage_mod += 0.5 + if(target.mob_size >= MOB_SIZE_BIG) + size_damage_mod += 1 + L.apply_armoured_damage(damage*size_damage_mod, ARMOR_BULLET, BRUTE, null, penetration) + else + L.apply_armoured_damage(damage, ARMOR_BULLET, BRUTE, null, penetration) + // 150% damage to runners (225), 300% against Big xenos (450), and 200% against all others (300). -Kaga + to_chat(P.firer, SPAN_WARNING("Bullseye!")) diff --git a/code/datums/ammo/bullet/special_ammo.dm b/code/datums/ammo/bullet/special_ammo.dm new file mode 100644 index 000000000000..cdf30b1af7fe --- /dev/null +++ b/code/datums/ammo/bullet/special_ammo.dm @@ -0,0 +1,176 @@ +/* +//====== + Special Ammo +//====== +*/ + +/datum/ammo/bullet/smartgun + name = "smartgun bullet" + icon_state = "redbullet" + flags_ammo_behavior = AMMO_BALLISTIC + + max_range = 12 + accuracy = HIT_ACCURACY_TIER_4 + damage = 30 + penetration = 0 + +/datum/ammo/bullet/smartgun/armor_piercing + name = "armor-piercing smartgun bullet" + icon_state = "bullet" + + accurate_range = 12 + accuracy = HIT_ACCURACY_TIER_2 + damage = 20 + penetration = ARMOR_PENETRATION_TIER_8 + damage_armor_punch = 1 + +/datum/ammo/bullet/smartgun/dirty + name = "irradiated smartgun bullet" + debilitate = list(0,0,0,3,0,0,0,1) + + shrapnel_chance = SHRAPNEL_CHANCE_TIER_7 + accurate_range = 32 + accuracy = HIT_ACCURACY_TIER_3 + damage = 40 + penetration = 0 + +/datum/ammo/bullet/smartgun/dirty/armor_piercing + debilitate = list(0,0,0,3,0,0,0,1) + + accurate_range = 22 + accuracy = HIT_ACCURACY_TIER_3 + damage = 30 + penetration = ARMOR_PENETRATION_TIER_7 + damage_armor_punch = 3 + +/datum/ammo/bullet/smartgun/holo_target //Royal marines smartgun bullet has only diff between regular ammo is this one does holostacks + name = "holo-targeting smartgun bullet" + damage = 30 + ///Stuff for the HRP holotargetting stacks + var/holo_stacks = 15 + +/datum/ammo/bullet/smartgun/holo_target/on_hit_mob(mob/M, obj/projectile/P) + . = ..() + M.AddComponent(/datum/component/bonus_damage_stack, holo_stacks, world.time) + +/datum/ammo/bullet/smartgun/holo_target/ap + name = "armor-piercing smartgun bullet" + icon_state = "bullet" + + accurate_range = 12 + accuracy = HIT_ACCURACY_TIER_2 + damage = 20 + penetration = ARMOR_PENETRATION_TIER_8 + damage_armor_punch = 1 + +/datum/ammo/bullet/smartgun/m56_fpw + name = "\improper M56 FPW bullet" + icon_state = "redbullet" + flags_ammo_behavior = AMMO_BALLISTIC + + max_range = 7 + accuracy = HIT_ACCURACY_TIER_7 + damage = 35 + penetration = ARMOR_PENETRATION_TIER_1 + +/datum/ammo/bullet/turret + name = "autocannon bullet" + icon_state = "redbullet" //Red bullets to indicate friendly fire restriction + flags_ammo_behavior = AMMO_BALLISTIC|AMMO_IGNORE_COVER + + accurate_range = 22 + accuracy_var_low = PROJECTILE_VARIANCE_TIER_8 + accuracy_var_high = PROJECTILE_VARIANCE_TIER_8 + max_range = 22 + damage = 30 + penetration = ARMOR_PENETRATION_TIER_7 + damage_armor_punch = 0 + pen_armor_punch = 0 + shell_speed = 2*AMMO_SPEED_TIER_6 + accuracy = HIT_ACCURACY_TIER_5 + +/datum/ammo/bullet/turret/dumb + icon_state = "bullet" + flags_ammo_behavior = AMMO_BALLISTIC + +/datum/ammo/bullet/machinegun //Adding this for the MG Nests (~Art) + name = "machinegun bullet" + icon_state = "bullet" // Keeping it bog standard with the turret but allows it to be changed + + accurate_range = 12 + damage = 35 + penetration= ARMOR_PENETRATION_TIER_10 //Bumped the penetration to serve a different role from sentries, MGs are a bit more offensive + accuracy = HIT_ACCURACY_TIER_3 + +/datum/ammo/bullet/machinegun/set_bullet_traits() + . = ..() + LAZYADD(traits_to_give, list( + BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_iff) + )) + +/datum/ammo/bullet/machinegun/auto // for M2C, automatic variant for M56D, stats for bullet should always be moderately overtuned to fulfill its ultra-offense + flank-push purpose + name = "heavy machinegun bullet" + + accurate_range = 10 + damage = 50 + penetration = ARMOR_PENETRATION_TIER_6 + accuracy = -HIT_ACCURACY_TIER_2 // 75 accuracy + shell_speed = AMMO_SPEED_TIER_2 + max_range = 15 + effective_range_max = 7 + damage_falloff = DAMAGE_FALLOFF_TIER_8 + +/datum/ammo/bullet/machinegun/auto/set_bullet_traits() + return + +/datum/ammo/bullet/minigun + name = "minigun bullet" + headshot_state = HEADSHOT_OVERLAY_MEDIUM + + accuracy = -HIT_ACCURACY_TIER_3 + accuracy_var_low = PROJECTILE_VARIANCE_TIER_6 + accuracy_var_high = PROJECTILE_VARIANCE_TIER_6 + accurate_range = 12 + damage = 35 + penetration = ARMOR_PENETRATION_TIER_6 + +/datum/ammo/bullet/minigun/New() + ..() + if(SSticker.mode && MODE_HAS_FLAG(MODE_FACTION_CLASH)) + damage = 15 + else if(SSticker.current_state < GAME_STATE_PLAYING) + RegisterSignal(SSdcs, COMSIG_GLOB_MODE_PRESETUP, PROC_REF(setup_hvh_damage)) + +/datum/ammo/bullet/minigun/proc/setup_hvh_damage() + if(MODE_HAS_FLAG(MODE_FACTION_CLASH)) + damage = 15 + +/datum/ammo/bullet/minigun/tank + accuracy = -HIT_ACCURACY_TIER_1 + accuracy_var_low = PROJECTILE_VARIANCE_TIER_8 + accuracy_var_high = PROJECTILE_VARIANCE_TIER_8 + accurate_range = 12 + +/datum/ammo/bullet/m60 + name = "M60 bullet" + headshot_state = HEADSHOT_OVERLAY_MEDIUM + + accuracy = HIT_ACCURACY_TIER_2 + accuracy_var_low = PROJECTILE_VARIANCE_TIER_8 + accuracy_var_high = PROJECTILE_VARIANCE_TIER_6 + accurate_range = 12 + damage = 45 //7.62x51 is scary + penetration= ARMOR_PENETRATION_TIER_6 + shrapnel_chance = SHRAPNEL_CHANCE_TIER_2 + +/datum/ammo/bullet/pkp + name = "machinegun bullet" + headshot_state = HEADSHOT_OVERLAY_MEDIUM + + accuracy = HIT_ACCURACY_TIER_1 + accuracy_var_low = PROJECTILE_VARIANCE_TIER_8 + accuracy_var_high = PROJECTILE_VARIANCE_TIER_6 + accurate_range = 14 + damage = 35 + penetration= ARMOR_PENETRATION_TIER_6 + shrapnel_chance = SHRAPNEL_CHANCE_TIER_2 diff --git a/code/datums/ammo/bullet/tank.dm b/code/datums/ammo/bullet/tank.dm new file mode 100644 index 000000000000..70a953c6e273 --- /dev/null +++ b/code/datums/ammo/bullet/tank.dm @@ -0,0 +1,74 @@ +/* +//====== + Tank Ammo +//====== +*/ + +/datum/ammo/bullet/tank/flak + name = "flak autocannon bullet" + icon_state = "autocannon" + damage_falloff = 0 + flags_ammo_behavior = AMMO_BALLISTIC + accurate_range_min = 4 + + accuracy = HIT_ACCURACY_TIER_8 + scatter = 0 + damage = 60 + damage_var_high = PROJECTILE_VARIANCE_TIER_8 + penetration = ARMOR_PENETRATION_TIER_6 + accurate_range = 32 + max_range = 32 + shell_speed = AMMO_SPEED_TIER_6 + +/datum/ammo/bullet/tank/flak/on_hit_mob(mob/M,obj/projectile/P) + burst(get_turf(M),P,damage_type, 2 , 3) + burst(get_turf(M),P,damage_type, 1 , 3 , 0) + +/datum/ammo/bullet/tank/flak/on_near_target(turf/T, obj/projectile/P) + burst(get_turf(T),P,damage_type, 2 , 3) + burst(get_turf(T),P,damage_type, 1 , 3, 0) + return 1 + +/datum/ammo/bullet/tank/flak/on_hit_obj(obj/O,obj/projectile/P) + burst(get_turf(P),P,damage_type, 2 , 3) + burst(get_turf(P),P,damage_type, 1 , 3 , 0) + +/datum/ammo/bullet/tank/flak/on_hit_turf(turf/T,obj/projectile/P) + burst(get_turf(T),P,damage_type, 2 , 3) + burst(get_turf(T),P,damage_type, 1 , 3 , 0) + +/datum/ammo/bullet/tank/dualcannon + name = "dualcannon bullet" + icon_state = "autocannon" + damage_falloff = 0 + flags_ammo_behavior = AMMO_BALLISTIC + + accuracy = HIT_ACCURACY_TIER_8 + scatter = 0 + damage = 50 + damage_var_high = PROJECTILE_VARIANCE_TIER_8 + penetration = ARMOR_PENETRATION_TIER_3 + accurate_range = 10 + max_range = 12 + shell_speed = AMMO_SPEED_TIER_5 + +/datum/ammo/bullet/tank/dualcannon/on_hit_mob(mob/M,obj/projectile/P) + for(var/mob/living/carbon/L in get_turf(M)) + if(L.stat == CONSCIOUS && L.mob_size <= MOB_SIZE_XENO) + shake_camera(L, 1, 1) + +/datum/ammo/bullet/tank/dualcannon/on_near_target(turf/T, obj/projectile/P) + for(var/mob/living/carbon/L in T) + if(L.stat == CONSCIOUS && L.mob_size <= MOB_SIZE_XENO) + shake_camera(L, 1, 1) + return 1 + +/datum/ammo/bullet/tank/dualcannon/on_hit_obj(obj/O,obj/projectile/P) + for(var/mob/living/carbon/L in get_turf(O)) + if(L.stat == CONSCIOUS && L.mob_size <= MOB_SIZE_XENO) + shake_camera(L, 1, 1) + +/datum/ammo/bullet/tank/dualcannon/on_hit_turf(turf/T,obj/projectile/P) + for(var/mob/living/carbon/L in T) + if(L.stat == CONSCIOUS && L.mob_size <= MOB_SIZE_XENO) + shake_camera(L, 1, 1) diff --git a/code/datums/ammo/energy.dm b/code/datums/ammo/energy.dm new file mode 100644 index 000000000000..01c69ffa0015 --- /dev/null +++ b/code/datums/ammo/energy.dm @@ -0,0 +1,241 @@ +/* +//====== + Energy Ammo +//====== +*/ + +/datum/ammo/energy + ping = null //no bounce off. We can have one later. + sound_hit = "energy_hit" + sound_miss = "energy_miss" + sound_bounce = "energy_bounce" + + damage_type = BURN + flags_ammo_behavior = AMMO_ENERGY + + accuracy = HIT_ACCURACY_TIER_4 + +/datum/ammo/energy/emitter //Damage is determined in emitter.dm + name = "emitter bolt" + icon_state = "emitter" + flags_ammo_behavior = AMMO_ENERGY|AMMO_IGNORE_ARMOR + + accurate_range = 6 + max_range = 6 + +/datum/ammo/energy/taser + name = "taser bolt" + icon_state = "stun" + damage_type = OXY + flags_ammo_behavior = AMMO_ENERGY|AMMO_IGNORE_RESIST|AMMO_ALWAYS_FF //Not that ignoring will do much right now. + + stamina_damage = 45 + accuracy = HIT_ACCURACY_TIER_8 + shell_speed = AMMO_SPEED_TIER_1 // Slightly faster + hit_effect_color = "#FFFF00" + +/datum/ammo/energy/taser/on_hit_mob(mob/M, obj/projectile/P) + if(ishuman(M)) + var/mob/living/carbon/human/H = M + H.disable_special_items() // Disables scout cloak + +/datum/ammo/energy/taser/precise + name = "precise taser bolt" + flags_ammo_behavior = AMMO_ENERGY|AMMO_IGNORE_RESIST|AMMO_MP + +/datum/ammo/energy/rxfm_eva + name = "laser blast" + icon_state = "laser_new" + flags_ammo_behavior = AMMO_LASER + accurate_range = 14 + max_range = 22 + damage = 45 + stamina_damage = 25 //why not + shell_speed = AMMO_SPEED_TIER_3 + +/datum/ammo/energy/rxfm_eva/on_hit_mob(mob/living/M, obj/projectile/P) + ..() + if(prob(10)) //small chance for one to ignite on hit + M.fire_act() + +/datum/ammo/energy/laz_uzi + name = "laser bolt" + icon_state = "laser_new" + flags_ammo_behavior = AMMO_ENERGY + damage = 40 + accurate_range = 5 + effective_range_max = 7 + max_range = 10 + shell_speed = AMMO_SPEED_TIER_4 + scatter = SCATTER_AMOUNT_TIER_6 + accuracy = HIT_ACCURACY_TIER_3 + damage_falloff = DAMAGE_FALLOFF_TIER_8 + +/datum/ammo/energy/yautja + headshot_state = HEADSHOT_OVERLAY_MEDIUM + accurate_range = 12 + shell_speed = AMMO_SPEED_TIER_3 + damage_type = BURN + flags_ammo_behavior = AMMO_IGNORE_RESIST + +/datum/ammo/energy/yautja/pistol + name = "plasma pistol bolt" + icon_state = "ion" + + damage = 40 + shell_speed = AMMO_SPEED_TIER_2 + +/datum/ammo/energy/yautja/pistol/incendiary + damage = 10 + +/datum/ammo/energy/yautja/pistol/incendiary/set_bullet_traits() + . = ..() + LAZYADD(traits_to_give, list( + BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_incendiary) + )) + +/datum/ammo/bullet/shrapnel/plasma + name = "plasma wave" + shrapnel_chance = 0 + penetration = ARMOR_PENETRATION_TIER_10 + accuracy = HIT_ACCURACY_TIER_MAX + damage = 15 + icon_state = "shrapnel_plasma" + damage_type = BURN + +/datum/ammo/bullet/shrapnel/plasma/on_hit_mob(mob/hit_mob, obj/projectile/hit_projectile) + hit_mob.apply_effect(2, WEAKEN) + +/datum/ammo/energy/yautja/caster + name = "root caster bolt" + icon_state = "ion" + +/datum/ammo/energy/yautja/caster/stun + name = "low power stun bolt" + debilitate = list(2,2,0,0,0,1,0,0) + + damage = 0 + flags_ammo_behavior = AMMO_ENERGY|AMMO_IGNORE_RESIST + +/datum/ammo/energy/yautja/caster/bolt + name = "plasma bolt" + icon_state = "pulse1" + flags_ammo_behavior = AMMO_IGNORE_RESIST + shell_speed = AMMO_SPEED_TIER_6 + damage = 35 + +/datum/ammo/energy/yautja/caster/bolt/stun + name = "high power stun bolt" + var/stun_time = 2 + + damage = 0 + flags_ammo_behavior = AMMO_ENERGY|AMMO_IGNORE_RESIST + +/datum/ammo/energy/yautja/caster/bolt/stun/on_hit_mob(mob/M, obj/projectile/P) + var/mob/living/carbon/C = M + var/stun_time = src.stun_time + if(istype(C)) + if(isyautja(C) || ispredalien(C)) + return + to_chat(C, SPAN_DANGER("An electric shock ripples through your body, freezing you in place!")) + log_attack("[key_name(C)] was stunned by a high power stun bolt from [key_name(P.firer)] at [get_area(P)]") + + if(ishuman(C)) + var/mob/living/carbon/human/H = C + stun_time++ + H.apply_effect(stun_time, WEAKEN) + else + M.apply_effect(stun_time, WEAKEN) + + C.apply_effect(stun_time, STUN) + ..() + +/datum/ammo/energy/yautja/caster/sphere + name = "plasma eradicator" + icon_state = "bluespace" + flags_ammo_behavior = AMMO_EXPLOSIVE|AMMO_HITS_TARGET_TURF + shell_speed = AMMO_SPEED_TIER_4 + accuracy = HIT_ACCURACY_TIER_8 + + damage = 55 + + accurate_range = 8 + max_range = 8 + + var/vehicle_slowdown_time = 5 SECONDS + +/datum/ammo/energy/yautja/caster/sphere/on_hit_mob(mob/M, obj/projectile/P) + cell_explosion(P, 170, 50, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, P.weapon_cause_data) + +/datum/ammo/energy/yautja/caster/sphere/on_hit_turf(turf/T, obj/projectile/P) + cell_explosion(P, 170, 50, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, P.weapon_cause_data) + +/datum/ammo/energy/yautja/caster/sphere/on_hit_obj(obj/O, obj/projectile/P) + if(istype(O, /obj/vehicle/multitile)) + var/obj/vehicle/multitile/multitile_vehicle = O + multitile_vehicle.next_move = world.time + vehicle_slowdown_time + playsound(multitile_vehicle, 'sound/effects/meteorimpact.ogg', 35) + multitile_vehicle.at_munition_interior_explosion_effect(cause_data = create_cause_data("Plasma Eradicator", P.firer)) + multitile_vehicle.interior_crash_effect() + multitile_vehicle.ex_act(150, P.dir, P.weapon_cause_data, 100) + cell_explosion(get_turf(P), 170, 50, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, P.weapon_cause_data) + +/datum/ammo/energy/yautja/caster/sphere/do_at_max_range(obj/projectile/P) + cell_explosion(get_turf(P), 170, 50, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, P.weapon_cause_data) + + +/datum/ammo/energy/yautja/caster/sphere/stun + name = "plasma immobilizer" + damage = 0 + flags_ammo_behavior = AMMO_ENERGY|AMMO_IGNORE_RESIST + accurate_range = 20 + max_range = 20 + + var/stun_range = 4 // Big + var/stun_time = 6 + +/datum/ammo/energy/yautja/caster/sphere/stun/on_hit_mob(mob/M, obj/projectile/P) + do_area_stun(P) + +/datum/ammo/energy/yautja/caster/sphere/stun/on_hit_turf(turf/T,obj/projectile/P) + do_area_stun(P) + +/datum/ammo/energy/yautja/caster/sphere/stun/on_hit_obj(obj/O,obj/projectile/P) + do_area_stun(P) + +/datum/ammo/energy/yautja/caster/sphere/stun/do_at_max_range(obj/projectile/P) + do_area_stun(P) + +/datum/ammo/energy/yautja/caster/sphere/stun/proc/do_area_stun(obj/projectile/P) + playsound(P, 'sound/weapons/wave.ogg', 75, 1, 25) + for (var/mob/living/carbon/M in view(src.stun_range, get_turf(P))) + var/stun_time = src.stun_time + log_attack("[key_name(M)] was stunned by a plasma immobilizer from [key_name(P.firer)] at [get_area(P)]") + if (isyautja(M)) + stun_time -= 2 + if(ispredalien(M)) + continue + to_chat(M, SPAN_DANGER("A powerful electric shock ripples through your body, freezing you in place!")) + M.apply_effect(stun_time, STUN) + + if (ishuman(M)) + var/mob/living/carbon/human/H = M + H.apply_effect(stun_time, WEAKEN) + else + M.apply_effect(stun_time, WEAKEN) + +/datum/ammo/energy/yautja/rifle/bolt + name = "plasma rifle bolt" + icon_state = "ion" + damage_type = BURN + debilitate = list(0,2,0,0,0,0,0,0) + flags_ammo_behavior = AMMO_IGNORE_RESIST + + damage = 55 + penetration = ARMOR_PENETRATION_TIER_10 + +/datum/ammo/energy/yautja/rifle/bolt/on_hit_mob(mob/hit_mob, obj/projectile/hit_projectile) + if(isxeno(hit_mob)) + var/mob/living/carbon/xenomorph/xeno = hit_mob + xeno.apply_damage(damage * 0.75, BURN) + xeno.interference = 30 diff --git a/code/datums/ammo/misc.dm b/code/datums/ammo/misc.dm new file mode 100644 index 000000000000..bdb284753dc4 --- /dev/null +++ b/code/datums/ammo/misc.dm @@ -0,0 +1,294 @@ +/* +//====== + Misc Ammo +//====== +*/ + +/datum/ammo/alloy_spike + name = "alloy spike" + headshot_state = HEADSHOT_OVERLAY_MEDIUM + ping = "ping_s" + icon_state = "MSpearFlight" + sound_hit = "alloy_hit" + sound_armor = "alloy_armor" + sound_bounce = "alloy_bounce" + + accuracy = HIT_ACCURACY_TIER_8 + accurate_range = 12 + max_range = 12 + damage = 30 + penetration= ARMOR_PENETRATION_TIER_10 + shrapnel_chance = SHRAPNEL_CHANCE_TIER_7 + shrapnel_type = /obj/item/shard/shrapnel + +/datum/ammo/flamethrower + name = "flame" + icon_state = "pulse0" + damage_type = BURN + flags_ammo_behavior = AMMO_IGNORE_ARMOR|AMMO_HITS_TARGET_TURF + + max_range = 6 + damage = 35 + +/datum/ammo/flamethrower/set_bullet_traits() + . = ..() + LAZYADD(traits_to_give, list( + BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_incendiary) + )) + +/datum/ammo/flamethrower/on_hit_mob(mob/M, obj/projectile/P) + drop_flame(get_turf(M), P.weapon_cause_data) + +/datum/ammo/flamethrower/on_hit_obj(obj/O, obj/projectile/P) + drop_flame(get_turf(O), P.weapon_cause_data) + +/datum/ammo/flamethrower/on_hit_turf(turf/T, obj/projectile/P) + drop_flame(T, P.weapon_cause_data) + +/datum/ammo/flamethrower/do_at_max_range(obj/projectile/P) + drop_flame(get_turf(P), P.weapon_cause_data) + +/datum/ammo/flamethrower/tank_flamer + flamer_reagent_type = /datum/reagent/napalm/blue + +/datum/ammo/flamethrower/sentry_flamer + flags_ammo_behavior = AMMO_IGNORE_ARMOR|AMMO_IGNORE_COVER|AMMO_FLAME + flamer_reagent_type = /datum/reagent/napalm/blue + + accuracy = HIT_ACCURACY_TIER_8 + accurate_range = 6 + max_range = 12 + shell_speed = AMMO_SPEED_TIER_3 + +/datum/ammo/flamethrower/sentry_flamer/set_bullet_traits() + . = ..() + LAZYADD(traits_to_give, list( + BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_incendiary) + )) + +/datum/ammo/flamethrower/sentry_flamer/glob + max_range = 14 + accurate_range = 10 + var/datum/effect_system/smoke_spread/phosphorus/smoke + +/datum/ammo/flamethrower/sentry_flamer/glob/New() + . = ..() + smoke = new() + +/datum/ammo/flamethrower/sentry_flamer/glob/drop_flame(turf/T, datum/cause_data/cause_data) + if(!istype(T)) + return + smoke.set_up(1, 0, T, new_cause_data = cause_data) + smoke.start() + +/datum/ammo/flamethrower/sentry_flamer/glob/Destroy() + qdel(smoke) + return ..() + +/datum/ammo/flamethrower/sentry_flamer/mini + name = "normal fire" + +/datum/ammo/flamethrower/sentry_flamer/mini/drop_flame(turf/T, datum/cause_data/cause_data) + if(!istype(T)) + return + var/datum/reagent/napalm/ut/R = new() + R.durationfire = BURN_TIME_INSTANT + new /obj/flamer_fire(T, cause_data, R, 0) + +/datum/ammo/flare + name = "flare" + ping = null //no bounce off. + damage_type = BURN + flags_ammo_behavior = AMMO_HITS_TARGET_TURF + icon_state = "flare" + + damage = 15 + accuracy = HIT_ACCURACY_TIER_3 + max_range = 14 + shell_speed = AMMO_SPEED_TIER_3 + + var/flare_type = /obj/item/device/flashlight/flare/on/gun + handful_type = /obj/item/device/flashlight/flare + +/datum/ammo/flare/set_bullet_traits() + . = ..() + LAZYADD(traits_to_give, list( + BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_incendiary) + )) + +/datum/ammo/flare/on_hit_mob(mob/M,obj/projectile/P) + drop_flare(get_turf(M), P, P.firer) + +/datum/ammo/flare/on_hit_obj(obj/O,obj/projectile/P) + drop_flare(get_turf(P), P, P.firer) + +/datum/ammo/flare/on_hit_turf(turf/T, obj/projectile/P) + if(T.density && isturf(P.loc)) + drop_flare(P.loc, P, P.firer) + else + drop_flare(T, P, P.firer) + +/datum/ammo/flare/do_at_max_range(obj/projectile/P, mob/firer) + drop_flare(get_turf(P), P, P.firer) + +/datum/ammo/flare/proc/drop_flare(turf/T, obj/projectile/fired_projectile, mob/firer) + var/obj/item/device/flashlight/flare/G = new flare_type(T) + var/matrix/rotation = matrix() + rotation.Turn(fired_projectile.angle - 90) + G.apply_transform(rotation) + G.visible_message(SPAN_WARNING("\A [G] bursts into brilliant light nearby!")) + return G + +/datum/ammo/flare/signal + name = "signal flare" + icon_state = "flare_signal" + flare_type = /obj/item/device/flashlight/flare/signal/gun + handful_type = /obj/item/device/flashlight/flare/signal + +/datum/ammo/flare/signal/drop_flare(turf/T, obj/projectile/fired_projectile, mob/firer) + var/obj/item/device/flashlight/flare/signal/gun/signal_flare = ..() + signal_flare.activate_signal(firer) + if(istype(fired_projectile.shot_from, /obj/item/weapon/gun/flare)) + var/obj/item/weapon/gun/flare/flare_gun_fired_from = fired_projectile.shot_from + flare_gun_fired_from.last_signal_flare_name = signal_flare.name + +/datum/ammo/flare/starshell + name = "starshell ash" + icon_state = "starshell_bullet" + max_range = 5 + flare_type = /obj/item/device/flashlight/flare/on/starshell_ash + +/datum/ammo/flare/starshell/set_bullet_traits() + LAZYADD(traits_to_give, list( + BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_iff, /datum/element/bullet_trait_incendiary) + )) + +/datum/ammo/souto + name = "Souto Can" + ping = null //no bounce off. + damage_type = BRUTE + shrapnel_type = /obj/item/reagent_container/food/drinks/cans/souto/classic + flags_ammo_behavior = AMMO_SKIPS_ALIENS|AMMO_IGNORE_ARMOR|AMMO_IGNORE_RESIST|AMMO_BALLISTIC|AMMO_STOPPED_BY_COVER|AMMO_SPECIAL_EMBED + var/obj/item/reagent_container/food/drinks/cans/souto/can_type + icon_state = "souto_classic" + + max_range = 12 + shrapnel_chance = 10 + accuracy = HIT_ACCURACY_TIER_8 + HIT_ACCURACY_TIER_8 + accurate_range = 12 + shell_speed = AMMO_SPEED_TIER_1 + +/datum/ammo/souto/on_embed(mob/embedded_mob, obj/limb/target_organ) + if(ishuman(embedded_mob) && !isyautja(embedded_mob)) + if(istype(target_organ)) + target_organ.embed(new can_type) + +/datum/ammo/souto/on_hit_mob(mob/M, obj/projectile/P) + if(!M || M == P.firer) return + if(M.throw_mode && !M.get_active_hand()) //empty active hand and we're in throw mode. If so we catch the can. + if(!M.is_mob_incapacitated()) // People who are not able to catch cannot catch. + if(P.contents.len == 1) + for(var/obj/item/reagent_container/food/drinks/cans/souto/S in P.contents) + M.put_in_active_hand(S) + for(var/mob/O in viewers(world_view_size, P)) //find all people in view. + O.show_message(SPAN_DANGER("[M] catches the [S]!"), SHOW_MESSAGE_VISIBLE) //Tell them the can was caught. + return //Can was caught. + if(ishuman(M)) + var/mob/living/carbon/human/H = M + if(H.species.name == "Human") //no effect on synths or preds. + H.apply_effect(6, STUN) + H.apply_effect(8, WEAKEN) + H.apply_effect(15, DAZE) + H.apply_effect(15, SLOW) + shake_camera(H, 2, 1) + if(P.contents.len) + drop_can(P.loc, P) //We make a can at the location. + +/datum/ammo/souto/on_hit_obj(obj/O,obj/projectile/P) + drop_can(P.loc, P) //We make a can at the location. + +/datum/ammo/souto/on_hit_turf(turf/T, obj/projectile/P) + drop_can(P.loc, P) //We make a can at the location. + +/datum/ammo/souto/do_at_max_range(obj/projectile/P) + drop_can(P.loc, P) //We make a can at the location. + +/datum/ammo/souto/on_shield_block(mob/M, obj/projectile/P) + drop_can(P.loc, P) //We make a can at the location. + +/datum/ammo/souto/proc/drop_can(loc, obj/projectile/P) + if(P.contents.len) + for(var/obj/item/I in P.contents) + I.forceMove(loc) + randomize_projectile(P) + +/datum/ammo/souto/proc/randomize_projectile(obj/projectile/P) + shrapnel_type = pick(typesof(/obj/item/reagent_container/food/drinks/cans/souto)-/obj/item/reagent_container/food/drinks/cans/souto) + +/datum/ammo/grenade_container + name = "grenade shell" + ping = null + damage_type = BRUTE + var/nade_type = /obj/item/explosive/grenade/high_explosive + icon_state = "grenade" + flags_ammo_behavior = AMMO_IGNORE_COVER|AMMO_SKIPS_ALIENS + + damage = 15 + accuracy = HIT_ACCURACY_TIER_3 + max_range = 6 + +/datum/ammo/grenade_container/on_hit_mob(mob/M,obj/projectile/P) + drop_nade(P) + +/datum/ammo/grenade_container/on_hit_obj(obj/O,obj/projectile/P) + drop_nade(P) + +/datum/ammo/grenade_container/on_hit_turf(turf/T,obj/projectile/P) + drop_nade(P) + +/datum/ammo/grenade_container/do_at_max_range(obj/projectile/P) + drop_nade(P) + +/datum/ammo/grenade_container/proc/drop_nade(obj/projectile/P) + var/turf/T = get_turf(P) + var/obj/item/explosive/grenade/G = new nade_type(T) + G.visible_message(SPAN_WARNING("\A [G] lands on [T]!")) + G.det_time = 10 + G.cause_data = P.weapon_cause_data + G.activate() + +/datum/ammo/grenade_container/rifle + flags_ammo_behavior = NO_FLAGS + +/datum/ammo/grenade_container/smoke + name = "smoke grenade shell" + nade_type = /obj/item/explosive/grenade/smokebomb + icon_state = "smoke_shell" + +/datum/ammo/hugger_container + name = "hugger shell" + ping = null + damage_type = BRUTE + var/hugger_hive = XENO_HIVE_NORMAL + icon_state = "smoke_shell" + + damage = 15 + accuracy = HIT_ACCURACY_TIER_3 + max_range = 6 + +/datum/ammo/hugger_container/on_hit_mob(mob/M,obj/projectile/P) + spawn_hugger(get_turf(P)) + +/datum/ammo/hugger_container/on_hit_obj(obj/O,obj/projectile/P) + spawn_hugger(get_turf(P)) + +/datum/ammo/hugger_container/on_hit_turf(turf/T,obj/projectile/P) + spawn_hugger(get_turf(P)) + +/datum/ammo/hugger_container/do_at_max_range(obj/projectile/P) + spawn_hugger(get_turf(P)) + +/datum/ammo/hugger_container/proc/spawn_hugger(turf/T) + var/obj/item/clothing/mask/facehugger/child = new(T) + child.hivenumber = hugger_hive + INVOKE_ASYNC(child, TYPE_PROC_REF(/obj/item/clothing/mask/facehugger, leap_at_nearest_target)) diff --git a/code/datums/ammo/rocket.dm b/code/datums/ammo/rocket.dm new file mode 100644 index 000000000000..52914f745110 --- /dev/null +++ b/code/datums/ammo/rocket.dm @@ -0,0 +1,300 @@ +/* +//====== + Rocket Ammo +//====== +*/ + +/datum/ammo/rocket + name = "high explosive rocket" + icon_state = "missile" + ping = null //no bounce off. + sound_bounce = "rocket_bounce" + damage_falloff = 0 + flags_ammo_behavior = AMMO_EXPLOSIVE|AMMO_ROCKET|AMMO_STRIKES_SURFACE + var/datum/effect_system/smoke_spread/smoke + + accuracy = HIT_ACCURACY_TIER_2 + accurate_range = 7 + max_range = 7 + damage = 15 + shell_speed = AMMO_SPEED_TIER_2 + +/datum/ammo/rocket/New() + ..() + smoke = new() + +/datum/ammo/rocket/Destroy() + qdel(smoke) + smoke = null + . = ..() + +/datum/ammo/rocket/on_hit_mob(mob/M, obj/projectile/P) + cell_explosion(get_turf(M), 150, 50, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, P.weapon_cause_data) + smoke.set_up(1, get_turf(M)) + if(ishuman_strict(M)) // No yautya or synths. Makes humans gib on direct hit. + M.ex_act(350, P.dir, P.weapon_cause_data, 100) + smoke.start() + +/datum/ammo/rocket/on_hit_obj(obj/O, obj/projectile/P) + cell_explosion(get_turf(O), 150, 50, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, P.weapon_cause_data) + smoke.set_up(1, get_turf(O)) + smoke.start() + +/datum/ammo/rocket/on_hit_turf(turf/T, obj/projectile/P) + cell_explosion(T, 150, 50, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, P.weapon_cause_data) + smoke.set_up(1, T) + smoke.start() + +/datum/ammo/rocket/do_at_max_range(obj/projectile/P) + cell_explosion(get_turf(P), 150, 50, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, P.weapon_cause_data) + smoke.set_up(1, get_turf(P)) + smoke.start() + +/datum/ammo/rocket/ap + name = "anti-armor rocket" + damage_falloff = 0 + flags_ammo_behavior = AMMO_EXPLOSIVE|AMMO_ROCKET + + accuracy = HIT_ACCURACY_TIER_8 + accuracy_var_low = PROJECTILE_VARIANCE_TIER_9 + accurate_range = 6 + max_range = 6 + damage = 10 + penetration= ARMOR_PENETRATION_TIER_10 + +/datum/ammo/rocket/ap/on_hit_mob(mob/M, obj/projectile/P) + var/turf/T = get_turf(M) + M.ex_act(150, P.dir, P.weapon_cause_data, 100) + M.apply_effect(2, WEAKEN) + M.apply_effect(2, PARALYZE) + if(ishuman_strict(M)) // No yautya or synths. Makes humans gib on direct hit. + M.ex_act(300, P.dir, P.weapon_cause_data, 100) + cell_explosion(T, 100, 50, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, P.weapon_cause_data) + smoke.set_up(1, T) + smoke.start() + +/datum/ammo/rocket/ap/on_hit_obj(obj/O, obj/projectile/P) + var/turf/T = get_turf(O) + O.ex_act(150, P.dir, P.weapon_cause_data, 100) + cell_explosion(T, 100, 50, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, P.weapon_cause_data) + smoke.set_up(1, T) + smoke.start() + +/datum/ammo/rocket/ap/on_hit_turf(turf/T, obj/projectile/P) + var/hit_something = 0 + for(var/mob/M in T) + M.ex_act(150, P.dir, P.weapon_cause_data, 100) + M.apply_effect(4, WEAKEN) + M.apply_effect(4, PARALYZE) + hit_something = 1 + continue + if(!hit_something) + for(var/obj/O in T) + if(O.density) + O.ex_act(150, P.dir, P.weapon_cause_data, 100) + hit_something = 1 + continue + if(!hit_something) + T.ex_act(150, P.dir, P.weapon_cause_data, 200) + + cell_explosion(T, 100, 50, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, P.weapon_cause_data) + smoke.set_up(1, T) + smoke.start() + +/datum/ammo/rocket/ap/do_at_max_range(obj/projectile/P) + var/turf/T = get_turf(P) + var/hit_something = 0 + for(var/mob/M in T) + M.ex_act(250, P.dir, P.weapon_cause_data, 100) + M.apply_effect(2, WEAKEN) + M.apply_effect(2, PARALYZE) + hit_something = 1 + continue + if(!hit_something) + for(var/obj/O in T) + if(O.density) + O.ex_act(250, P.dir, P.weapon_cause_data, 100) + hit_something = 1 + continue + if(!hit_something) + T.ex_act(250, P.dir, P.weapon_cause_data) + cell_explosion(T, 100, 50, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, P.weapon_cause_data) + smoke.set_up(1, T) + smoke.start() + +/datum/ammo/rocket/ap/anti_tank + name = "anti-tank rocket" + damage = 100 + var/vehicle_slowdown_time = 5 SECONDS + shrapnel_chance = 5 + shrapnel_type = /obj/item/large_shrapnel/at_rocket_dud + +/datum/ammo/rocket/ap/anti_tank/on_hit_obj(obj/O, obj/projectile/P) + if(istype(O, /obj/vehicle/multitile)) + var/obj/vehicle/multitile/M = O + M.next_move = world.time + vehicle_slowdown_time + playsound(M, 'sound/effects/meteorimpact.ogg', 35) + M.at_munition_interior_explosion_effect(cause_data = create_cause_data("Anti-Tank Rocket")) + M.interior_crash_effect() + var/turf/T = get_turf(M.loc) + M.ex_act(150, P.dir, P.weapon_cause_data, 100) + smoke.set_up(1, T) + smoke.start() + return + return ..() + + +/datum/ammo/rocket/ltb + name = "cannon round" + icon_state = "ltb" + flags_ammo_behavior = AMMO_EXPLOSIVE|AMMO_ROCKET|AMMO_STRIKES_SURFACE + + accuracy = HIT_ACCURACY_TIER_3 + accurate_range = 32 + max_range = 32 + damage = 25 + shell_speed = AMMO_SPEED_TIER_3 + +/datum/ammo/rocket/ltb/on_hit_mob(mob/M, obj/projectile/P) + cell_explosion(get_turf(M), 220, 50, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, P.weapon_cause_data) + cell_explosion(get_turf(M), 200, 100, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, P.weapon_cause_data) + +/datum/ammo/rocket/ltb/on_hit_obj(obj/O, obj/projectile/P) + cell_explosion(get_turf(O), 220, 50, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, P.weapon_cause_data) + cell_explosion(get_turf(O), 200, 100, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, P.weapon_cause_data) + +/datum/ammo/rocket/ltb/on_hit_turf(turf/T, obj/projectile/P) + cell_explosion(get_turf(T), 220, 50, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, P.weapon_cause_data) + cell_explosion(get_turf(T), 200, 100, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, P.weapon_cause_data) + +/datum/ammo/rocket/ltb/do_at_max_range(obj/projectile/P) + cell_explosion(get_turf(P), 220, 50, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, P.weapon_cause_data) + cell_explosion(get_turf(P), 200, 100, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, P.weapon_cause_data) + +/datum/ammo/rocket/wp + name = "white phosphorous rocket" + flags_ammo_behavior = AMMO_ROCKET|AMMO_EXPLOSIVE|AMMO_STRIKES_SURFACE + damage_type = BURN + + accuracy_var_low = PROJECTILE_VARIANCE_TIER_6 + accurate_range = 8 + damage = 90 + max_range = 8 + +/datum/ammo/rocket/wp/set_bullet_traits() + . = ..() + LAZYADD(traits_to_give, list( + BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_incendiary) + )) + +/datum/ammo/rocket/wp/drop_flame(turf/T, datum/cause_data/cause_data) + playsound(T, 'sound/weapons/gun_flamethrower3.ogg', 75, 1, 7) + if(!istype(T)) return + smoke.set_up(1, T) + smoke.start() + var/datum/reagent/napalm/blue/R = new() + new /obj/flamer_fire(T, cause_data, R, 3) + + var/datum/effect_system/smoke_spread/phosphorus/landingSmoke = new /datum/effect_system/smoke_spread/phosphorus + landingSmoke.set_up(3, 0, T, null, 6, cause_data) + landingSmoke.start() + landingSmoke = null + +/datum/ammo/rocket/wp/on_hit_mob(mob/M, obj/projectile/P) + drop_flame(get_turf(M), P.weapon_cause_data) + +/datum/ammo/rocket/wp/on_hit_obj(obj/O, obj/projectile/P) + drop_flame(get_turf(O), P.weapon_cause_data) + +/datum/ammo/rocket/wp/on_hit_turf(turf/T, obj/projectile/P) + drop_flame(T, P.weapon_cause_data) + +/datum/ammo/rocket/wp/do_at_max_range(obj/projectile/P) + drop_flame(get_turf(P), P.weapon_cause_data) + +/datum/ammo/rocket/wp/upp + name = "extreme-intensity incendiary rocket" + flags_ammo_behavior = AMMO_ROCKET|AMMO_EXPLOSIVE|AMMO_STRIKES_SURFACE + damage_type = BURN + + accuracy_var_low = PROJECTILE_VARIANCE_TIER_6 + accurate_range = 8 + damage = 150 + max_range = 10 + +/datum/ammo/rocket/wp/upp/set_bullet_traits() + . = ..() + LAZYADD(traits_to_give, list( + BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_incendiary) + )) + +/datum/ammo/rocket/wp/upp/drop_flame(turf/T, datum/cause_data/cause_data) + playsound(T, 'sound/weapons/gun_flamethrower3.ogg', 75, 1, 7) + if(!istype(T)) return + smoke.set_up(1, T) + smoke.start() + var/datum/reagent/napalm/upp/R = new() + new /obj/flamer_fire(T, cause_data, R, 3) + +/datum/ammo/rocket/wp/upp/on_hit_mob(mob/M, obj/projectile/P) + drop_flame(get_turf(M), P.weapon_cause_data) + +/datum/ammo/rocket/wp/upp/on_hit_obj(obj/O, obj/projectile/P) + drop_flame(get_turf(O), P.weapon_cause_data) + +/datum/ammo/rocket/wp/upp/on_hit_turf(turf/T, obj/projectile/P) + drop_flame(T, P.weapon_cause_data) + +/datum/ammo/rocket/wp/upp/do_at_max_range(obj/projectile/P) + drop_flame(get_turf(P), P.weapon_cause_data) + +/datum/ammo/rocket/wp/quad + name = "thermobaric rocket" + flags_ammo_behavior = AMMO_ROCKET|AMMO_STRIKES_SURFACE + + damage = 100 + max_range = 32 + shell_speed = AMMO_SPEED_TIER_3 + +/datum/ammo/rocket/wp/quad/on_hit_mob(mob/M, obj/projectile/P) + drop_flame(get_turf(M), P.weapon_cause_data) + explosion(P.loc, -1, 2, 4, 5, , , ,P.weapon_cause_data) + +/datum/ammo/rocket/wp/quad/on_hit_obj(obj/O, obj/projectile/P) + drop_flame(get_turf(O), P.weapon_cause_data) + explosion(P.loc, -1, 2, 4, 5, , , ,P.weapon_cause_data) + +/datum/ammo/rocket/wp/quad/on_hit_turf(turf/T, obj/projectile/P) + drop_flame(T, P.weapon_cause_data) + explosion(P.loc, -1, 2, 4, 5, , , ,P.weapon_cause_data) + +/datum/ammo/rocket/wp/quad/do_at_max_range(obj/projectile/P) + drop_flame(get_turf(P), P.weapon_cause_data) + explosion(P.loc, -1, 2, 4, 5, , , ,P.weapon_cause_data) + +/datum/ammo/rocket/custom + name = "custom rocket" + +/datum/ammo/rocket/custom/proc/prime(atom/A, obj/projectile/P) + var/obj/item/weapon/gun/launcher/rocket/launcher = P.shot_from + var/obj/item/ammo_magazine/rocket/custom/rocket = launcher.current_mag + if(rocket.locked && rocket.warhead && rocket.warhead.detonator) + if(rocket.fuel && rocket.fuel.reagents.get_reagent_amount(rocket.fuel_type) >= rocket.fuel_requirement) + rocket.forceMove(P.loc) + rocket.warhead.cause_data = P.weapon_cause_data + rocket.warhead.prime() + qdel(rocket) + smoke.set_up(1, get_turf(A)) + smoke.start() + +/datum/ammo/rocket/custom/on_hit_mob(mob/M, obj/projectile/P) + prime(M, P) + +/datum/ammo/rocket/custom/on_hit_obj(obj/O, obj/projectile/P) + prime(O, P) + +/datum/ammo/rocket/custom/on_hit_turf(turf/T, obj/projectile/P) + prime(T, P) + +/datum/ammo/rocket/custom/do_at_max_range(obj/projectile/P) + prime(null, P) diff --git a/code/datums/ammo/shrapnel.dm b/code/datums/ammo/shrapnel.dm new file mode 100644 index 000000000000..e27caa4b277d --- /dev/null +++ b/code/datums/ammo/shrapnel.dm @@ -0,0 +1,157 @@ +/* +//====== + Shrapnel +//====== +*/ +/datum/ammo/bullet/shrapnel + name = "shrapnel" + icon_state = "buckshot" + accurate_range_min = 5 + flags_ammo_behavior = AMMO_BALLISTIC|AMMO_STOPPED_BY_COVER + + accuracy = HIT_ACCURACY_TIER_3 + accurate_range = 32 + max_range = 8 + damage = 25 + damage_var_low = -PROJECTILE_VARIANCE_TIER_6 + damage_var_high = PROJECTILE_VARIANCE_TIER_6 + penetration = ARMOR_PENETRATION_TIER_4 + shell_speed = AMMO_SPEED_TIER_2 + shrapnel_chance = 5 + +/datum/ammo/bullet/shrapnel/on_hit_obj(obj/O, obj/projectile/P) + if(istype(O, /obj/structure/barricade)) + var/obj/structure/barricade/B = O + B.health -= rand(2, 5) + B.update_health(1) + +/datum/ammo/bullet/shrapnel/rubber + name = "rubber pellets" + icon_state = "rubber_pellets" + flags_ammo_behavior = AMMO_STOPPED_BY_COVER + + damage = 0 + stamina_damage = 25 + shrapnel_chance = 0 + + +/datum/ammo/bullet/shrapnel/hornet_rounds + name = ".22 hornet round" + icon_state = "hornet_round" + flags_ammo_behavior = AMMO_BALLISTIC + damage = 20 + shrapnel_chance = 0 + shell_speed = AMMO_SPEED_TIER_3//she fast af boi + penetration = ARMOR_PENETRATION_TIER_5 + +/datum/ammo/bullet/shrapnel/hornet_rounds/on_hit_mob(mob/M, obj/projectile/P) + . = ..() + M.AddComponent(/datum/component/bonus_damage_stack, 10, world.time) + +/datum/ammo/bullet/shrapnel/incendiary + name = "flaming shrapnel" + icon_state = "beanbag" // looks suprisingly a lot like flaming shrapnel chunks + flags_ammo_behavior = AMMO_STOPPED_BY_COVER + + shell_speed = AMMO_SPEED_TIER_1 + damage = 20 + penetration = ARMOR_PENETRATION_TIER_4 + +/datum/ammo/bullet/shrapnel/incendiary/set_bullet_traits() + . = ..() + LAZYADD(traits_to_give, list( + BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_incendiary) + )) + +/datum/ammo/bullet/shrapnel/metal + name = "metal shrapnel" + icon_state = "shrapnelshot_bit" + flags_ammo_behavior = AMMO_STOPPED_BY_COVER|AMMO_BALLISTIC + shell_speed = AMMO_SPEED_TIER_1 + damage = 30 + shrapnel_chance = 15 + accuracy = HIT_ACCURACY_TIER_8 + penetration = ARMOR_PENETRATION_TIER_4 + +/datum/ammo/bullet/shrapnel/light // weak shrapnel + name = "light shrapnel" + icon_state = "shrapnel_light" + + damage = 10 + penetration = ARMOR_PENETRATION_TIER_1 + shell_speed = AMMO_SPEED_TIER_1 + shrapnel_chance = 0 + +/datum/ammo/bullet/shrapnel/light/human + name = "human bone fragments" + icon_state = "shrapnel_human" + + shrapnel_chance = 50 + shrapnel_type = /obj/item/shard/shrapnel/bone_chips/human + +/datum/ammo/bullet/shrapnel/light/human/var1 // sprite variants + icon_state = "shrapnel_human1" + +/datum/ammo/bullet/shrapnel/light/human/var2 // sprite variants + icon_state = "shrapnel_human2" + +/datum/ammo/bullet/shrapnel/light/xeno + name = "alien bone fragments" + icon_state = "shrapnel_xeno" + + shrapnel_chance = 50 + shrapnel_type = /obj/item/shard/shrapnel/bone_chips/xeno + +/datum/ammo/bullet/shrapnel/spall // weak shrapnel + name = "spall" + icon_state = "shrapnel_light" + + damage = 10 + penetration = ARMOR_PENETRATION_TIER_1 + shell_speed = AMMO_SPEED_TIER_1 + shrapnel_chance = 0 + +/datum/ammo/bullet/shrapnel/light/glass + name = "glass shrapnel" + icon_state = "shrapnel_glass" + +/datum/ammo/bullet/shrapnel/light/effect/ // no damage, but looks bright and neat + name = "sparks" + + damage = 1 // Tickle tickle + +/datum/ammo/bullet/shrapnel/light/effect/ver1 + icon_state = "shrapnel_bright1" + +/datum/ammo/bullet/shrapnel/light/effect/ver2 + icon_state = "shrapnel_bright2" + +/datum/ammo/bullet/shrapnel/jagged + shrapnel_chance = SHRAPNEL_CHANCE_TIER_2 + accuracy = HIT_ACCURACY_TIER_MAX + +/datum/ammo/bullet/shrapnel/jagged/on_hit_mob(mob/M, obj/projectile/P) + if(isxeno(M)) + M.apply_effect(0.4, SLOW) + +/* +//======== + CAS 30mm impacters +//======== +*/ +/datum/ammo/bullet/shrapnel/gau //for the GAU to have a impact bullet instead of firecrackers + name = "30mm Multi-Purpose shell" + + damage = 1 // ALL DAMAGE IS IN dropship_ammo SO WE CAN DEAL DAMAGE TO RESTING MOBS, these will still remain however so that we can get cause_data and status effects. + damage_type = BRUTE + penetration = ARMOR_PENETRATION_TIER_2 + accuracy = HIT_ACCURACY_TIER_MAX + max_range = 0 + shrapnel_chance = 100 //the least of your problems + +/datum/ammo/bullet/shrapnel/gau/at + name = "30mm Anti-Tank shell" + + damage = 1 // ALL DAMAGE IS IN dropship_ammo SO WE CAN DEAL DAMAGE TO RESTING MOBS, these will still remain however so that we can get cause_data and status effects. + penetration = ARMOR_PENETRATION_TIER_8 + accuracy = HIT_ACCURACY_TIER_MAX diff --git a/code/datums/ammo/xeno.dm b/code/datums/ammo/xeno.dm new file mode 100644 index 000000000000..75c78298fe4f --- /dev/null +++ b/code/datums/ammo/xeno.dm @@ -0,0 +1,394 @@ +/* +//====== + Xeno Spits +//====== +*/ +/datum/ammo/xeno + icon_state = "neurotoxin" + ping = "ping_x" + damage_type = TOX + flags_ammo_behavior = AMMO_XENO + + ///used to make cooldown of the different spits vary. + var/added_spit_delay = 0 + var/spit_cost + + /// Should there be a windup for this spit? + var/spit_windup = FALSE + + /// Should there be an additional warning while winding up? (do not put to true if there is not a windup) + var/pre_spit_warn = FALSE + accuracy = HIT_ACCURACY_TIER_8*2 + max_range = 12 + +/datum/ammo/xeno/toxin + name = "neurotoxic spit" + damage_falloff = 0 + flags_ammo_behavior = AMMO_XENO|AMMO_IGNORE_RESIST + spit_cost = 25 + var/effect_power = XENO_NEURO_TIER_4 + var/datum/callback/neuro_callback + + shell_speed = AMMO_SPEED_TIER_3 + max_range = 7 + +/datum/ammo/xeno/toxin/New() + ..() + + neuro_callback = CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(apply_neuro)) + +/proc/apply_neuro(mob/living/M, power, insta_neuro) + if(skillcheck(M, SKILL_ENDURANCE, SKILL_ENDURANCE_MAX) && !insta_neuro) + M.visible_message(SPAN_DANGER("[M] withstands the neurotoxin!")) + return //endurance 5 makes you immune to weak neurotoxin + if(ishuman(M)) + var/mob/living/carbon/human/H = M + if(H.chem_effect_flags & CHEM_EFFECT_RESIST_NEURO || H.species.flags & NO_NEURO) + H.visible_message(SPAN_DANGER("[M] shrugs off the neurotoxin!")) + return //species like zombies or synths are immune to neurotoxin + + if(!isxeno(M)) + if(insta_neuro) + if(M.knocked_down < 3) + M.adjust_effect(1 * power, WEAKEN) + return + + if(ishuman(M)) + M.apply_effect(2.5, SUPERSLOW) + M.visible_message(SPAN_DANGER("[M]'s movements are slowed.")) + + var/no_clothes_neuro = FALSE + + if(ishuman(M)) + var/mob/living/carbon/human/H = M + if(!H.wear_suit || H.wear_suit.slowdown == 0) + no_clothes_neuro = TRUE + + if(no_clothes_neuro) + if(M.knocked_down < 5) + M.adjust_effect(1 * power, WEAKEN) // KD them a bit more + M.visible_message(SPAN_DANGER("[M] falls prone.")) + +/proc/apply_scatter_neuro(mob/living/M) + if(ishuman(M)) + var/mob/living/carbon/human/H = M + if(skillcheck(M, SKILL_ENDURANCE, SKILL_ENDURANCE_MAX)) + M.visible_message(SPAN_DANGER("[M] withstands the neurotoxin!")) + return //endurance 5 makes you immune to weak neuro + if(H.chem_effect_flags & CHEM_EFFECT_RESIST_NEURO || H.species.flags & NO_NEURO) + H.visible_message(SPAN_DANGER("[M] shrugs off the neurotoxin!")) + return + + if(M.knocked_down < 0.7) // apply knockdown only if current knockdown is less than 0.7 second + M.apply_effect(0.7, WEAKEN) + M.visible_message(SPAN_DANGER("[M] falls prone.")) + +/datum/ammo/xeno/toxin/on_hit_mob(mob/M,obj/projectile/P) + if(ishuman(M)) + var/mob/living/carbon/human/H = M + if(H.status_flags & XENO_HOST) + neuro_callback.Invoke(H, effect_power, TRUE) + return + + neuro_callback.Invoke(M, effect_power, FALSE) + +/datum/ammo/xeno/toxin/medium //Spitter + name = "neurotoxic spatter" + spit_cost = 50 + effect_power = 1 + + shell_speed = AMMO_SPEED_TIER_3 + +/datum/ammo/xeno/toxin/queen + name = "neurotoxic spit" + spit_cost = 50 + effect_power = 2 + + accuracy = HIT_ACCURACY_TIER_5*2 + max_range = 6 - 1 + +/datum/ammo/xeno/toxin/queen/on_hit_mob(mob/M,obj/projectile/P) + neuro_callback.Invoke(M, effect_power, TRUE) + +/datum/ammo/xeno/toxin/shotgun + name = "neurotoxic droplet" + flags_ammo_behavior = AMMO_XENO|AMMO_IGNORE_RESIST + bonus_projectiles_type = /datum/ammo/xeno/toxin/shotgun/additional + + accuracy_var_low = PROJECTILE_VARIANCE_TIER_6 + accuracy_var_high = PROJECTILE_VARIANCE_TIER_6 + accurate_range = 5 + max_range = 5 + scatter = SCATTER_AMOUNT_NEURO + bonus_projectiles_amount = EXTRA_PROJECTILES_TIER_4 + +/datum/ammo/xeno/toxin/shotgun/New() + ..() + + neuro_callback = CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(apply_scatter_neuro)) + +/datum/ammo/xeno/toxin/shotgun/additional + name = "additional neurotoxic droplets" + + bonus_projectiles_amount = 0 + +/datum/ammo/xeno/acid + name = "acid spit" + icon_state = "xeno_acid" + sound_hit = "acid_hit" + sound_bounce = "acid_bounce" + damage_type = BURN + spit_cost = 25 + flags_ammo_behavior = AMMO_ACIDIC|AMMO_XENO + accuracy = HIT_ACCURACY_TIER_5 + damage = 20 + max_range = 8 // 7 will disappear on diagonals. i love shitcode + penetration = ARMOR_PENETRATION_TIER_2 + shell_speed = AMMO_SPEED_TIER_3 + +/datum/ammo/xeno/acid/on_shield_block(mob/M, obj/projectile/P) + burst(M,P,damage_type) + +/datum/ammo/xeno/acid/on_hit_mob(mob/M, obj/projectile/P) + if(iscarbon(M)) + var/mob/living/carbon/C = M + if(C.status_flags & XENO_HOST && HAS_TRAIT(C, TRAIT_NESTED) || C.stat == DEAD) + return FALSE + ..() + +/datum/ammo/xeno/acid/spatter + name = "acid spatter" + + damage = 30 + max_range = 6 + +/datum/ammo/xeno/acid/spatter/on_hit_mob(mob/M, obj/projectile/P) + . = ..() + if(. == FALSE) + return + + new /datum/effects/acid(M, P.firer) + +/datum/ammo/xeno/acid/praetorian + name = "acid splash" + + accuracy = HIT_ACCURACY_TIER_10 + HIT_ACCURACY_TIER_5 + max_range = 8 + damage = 30 + shell_speed = AMMO_SPEED_TIER_2 + added_spit_delay = 0 + +/datum/ammo/xeno/acid/dot + name = "acid spit" + +/datum/ammo/xeno/acid/prae_nade // Used by base prae's acid nade + name = "acid scatter" + + flags_ammo_behavior = AMMO_STOPPED_BY_COVER + accuracy = HIT_ACCURACY_TIER_5 + accurate_range = 32 + max_range = 4 + damage = 25 + shell_speed = AMMO_SPEED_TIER_1 + scatter = SCATTER_AMOUNT_TIER_6 + + apply_delegate = FALSE + +/datum/ammo/xeno/acid/prae_nade/on_hit_mob(mob/M, obj/projectile/P) + if (!ishuman(M)) + return + + var/mob/living/carbon/human/H = M + + var/datum/effects/prae_acid_stacks/PAS = null + for (var/datum/effects/prae_acid_stacks/prae_acid_stacks in H.effects_list) + PAS = prae_acid_stacks + break + + if (PAS == null) + PAS = new /datum/effects/prae_acid_stacks(H) + else + PAS.increment_stack_count() + +/datum/ammo/xeno/boiler_gas + name = "glob of neuro gas" + icon_state = "neuro_glob" + ping = "ping_x" + debilitate = list(2,2,0,1,11,12,1,10) // Stun,knockdown,knockout,irradiate,stutter,eyeblur,drowsy,agony + flags_ammo_behavior = AMMO_SKIPS_ALIENS|AMMO_EXPLOSIVE|AMMO_IGNORE_RESIST|AMMO_HITS_TARGET_TURF|AMMO_ACIDIC + var/datum/effect_system/smoke_spread/smoke_system + spit_cost = 200 + pre_spit_warn = TRUE + spit_windup = 5 SECONDS + accuracy_var_high = PROJECTILE_VARIANCE_TIER_4 + accuracy_var_low = PROJECTILE_VARIANCE_TIER_4 + accuracy = HIT_ACCURACY_TIER_2 + scatter = SCATTER_AMOUNT_TIER_4 + shell_speed = 0.75 + max_range = 16 + /// range on the smoke in tiles from center + var/smokerange = 4 + var/lifetime_mult = 1.0 + +/datum/ammo/xeno/boiler_gas/New() + ..() + set_xeno_smoke() + +/datum/ammo/xeno/boiler_gas/Destroy() + qdel(smoke_system) + smoke_system = null + . = ..() + +/datum/ammo/xeno/boiler_gas/on_hit_mob(mob/moob, obj/projectile/proj) + if(iscarbon(moob)) + var/mob/living/carbon/carbon = moob + if(carbon.status_flags & XENO_HOST && HAS_TRAIT(carbon, TRAIT_NESTED) || carbon.stat == DEAD) + return + var/datum/effects/neurotoxin/neuro_effect = locate() in moob.effects_list + if(!neuro_effect) + neuro_effect = new /datum/effects/neurotoxin(moob, proj.firer) + neuro_effect.duration += 5 + moob.apply_effect(3, DAZE) + to_chat(moob, SPAN_HIGHDANGER("Neurotoxic liquid spreads all over you and immediately soaks into your pores and orifices! Oh fuck!")) // Fucked up but have a chance to escape rather than being game-ended + drop_nade(get_turf(proj), proj,TRUE) + +/datum/ammo/xeno/boiler_gas/on_hit_obj(obj/outbacksteakhouse, obj/projectile/proj) + drop_nade(get_turf(proj), proj) + +/datum/ammo/xeno/boiler_gas/on_hit_turf(turf/Turf, obj/projectile/proj) + if(Turf.density && isturf(proj.loc)) + drop_nade(proj.loc, proj) //we don't want the gas globs to land on dense turfs, they block smoke expansion. + else + drop_nade(Turf, proj) + +/datum/ammo/xeno/boiler_gas/do_at_max_range(obj/projectile/proj) + drop_nade(get_turf(proj), proj) + +/datum/ammo/xeno/boiler_gas/proc/set_xeno_smoke(obj/projectile/proj) + smoke_system = new /datum/effect_system/smoke_spread/xeno_weaken() + +/datum/ammo/xeno/boiler_gas/proc/drop_nade(turf/turf, obj/projectile/proj) + var/lifetime_mult = 1.0 + var/datum/cause_data + if(isboiler(proj.firer)) + cause_data = proj.weapon_cause_data + smoke_system.set_up(smokerange, 0, turf, new_cause_data = cause_data) + smoke_system.lifetime = 12 * lifetime_mult + smoke_system.start() + turf.visible_message(SPAN_DANGER("A glob of acid lands with a splat and explodes into noxious fumes!")) + + +/datum/ammo/xeno/boiler_gas/acid + name = "glob of acid gas" + icon_state = "acid_glob" + ping = "ping_x" + accuracy_var_high = PROJECTILE_VARIANCE_TIER_4 + smokerange = 3 + + +/datum/ammo/xeno/boiler_gas/acid/set_xeno_smoke(obj/projectile/proj) + smoke_system = new /datum/effect_system/smoke_spread/xeno_acid() + +/datum/ammo/xeno/boiler_gas/acid/on_hit_mob(mob/moob, obj/projectile/proj) + if(iscarbon(moob)) + var/mob/living/carbon/carbon = moob + if(carbon.status_flags & XENO_HOST && HAS_TRAIT(carbon, TRAIT_NESTED) || carbon.stat == DEAD) + return + to_chat(moob,SPAN_HIGHDANGER("Acid covers your body! Oh fuck!")) + playsound(moob,"acid_strike",75,1) + INVOKE_ASYNC(moob, TYPE_PROC_REF(/mob, emote), "pain") // why do I need this bullshit + new /datum/effects/acid(moob, proj.firer) + drop_nade(get_turf(proj), proj,TRUE) + +/datum/ammo/xeno/bone_chips + name = "bone chips" + icon_state = "shrapnel_light" + ping = null + flags_ammo_behavior = AMMO_XENO|AMMO_SKIPS_ALIENS|AMMO_STOPPED_BY_COVER|AMMO_IGNORE_ARMOR + damage_type = BRUTE + bonus_projectiles_type = /datum/ammo/xeno/bone_chips/spread + + damage = 8 + max_range = 6 + accuracy = HIT_ACCURACY_TIER_8 + accuracy_var_low = PROJECTILE_VARIANCE_TIER_7 + accuracy_var_high = PROJECTILE_VARIANCE_TIER_7 + bonus_projectiles_amount = EXTRA_PROJECTILES_TIER_7 + shrapnel_type = /obj/item/shard/shrapnel/bone_chips + shrapnel_chance = 60 + +/datum/ammo/xeno/bone_chips/on_hit_mob(mob/living/M, obj/projectile/P) + if(iscarbon(M)) + var/mob/living/carbon/C = M + if((HAS_FLAG(C.status_flags, XENO_HOST) && HAS_TRAIT(C, TRAIT_NESTED)) || C.stat == DEAD) + return + if(ishuman_strict(M) || isxeno(M)) + playsound(M, 'sound/effects/spike_hit.ogg', 25, 1, 1) + if(M.slowed < 3) + M.apply_effect(3, SLOW) + +/datum/ammo/xeno/bone_chips/spread + name = "small bone chips" + + scatter = 30 // We want a wild scatter angle + max_range = 5 + bonus_projectiles_amount = 0 + +/datum/ammo/xeno/bone_chips/spread/short_range + name = "small bone chips" + + max_range = 3 // Very short range + +/datum/ammo/xeno/bone_chips/spread/runner_skillshot + name = "bone chips" + + scatter = 0 + max_range = 5 + damage = 10 + shrapnel_chance = 0 + +/datum/ammo/xeno/bone_chips/spread/runner/on_hit_mob(mob/living/M, obj/projectile/P) + if(iscarbon(M)) + var/mob/living/carbon/C = M + if((HAS_FLAG(C.status_flags, XENO_HOST) && HAS_TRAIT(C, TRAIT_NESTED)) || C.stat == DEAD) + return + if(ishuman_strict(M) || isxeno(M)) + playsound(M, 'sound/effects/spike_hit.ogg', 25, 1, 1) + if(M.slowed < 6) + M.apply_effect(6, SLOW) + +/datum/ammo/xeno/oppressor_tail + name = "tail hook" + icon_state = "none" + ping = null + flags_ammo_behavior = AMMO_XENO|AMMO_SKIPS_ALIENS|AMMO_STOPPED_BY_COVER|AMMO_IGNORE_ARMOR + damage_type = BRUTE + + damage = XENO_DAMAGE_TIER_5 + max_range = 4 + accuracy = HIT_ACCURACY_TIER_MAX + +/datum/ammo/xeno/oppressor_tail/on_bullet_generation(obj/projectile/generated_projectile, mob/bullet_generator) + //The projectile has no icon, so the overlay shows up in FRONT of the projectile, and the beam connects to it in the middle. + var/image/hook_overlay = new(icon = 'icons/effects/beam.dmi', icon_state = "oppressor_tail_hook", layer = BELOW_MOB_LAYER) + generated_projectile.overlays += hook_overlay + +/datum/ammo/xeno/oppressor_tail/on_hit_mob(mob/target, obj/projectile/fired_proj) + var/mob/living/carbon/xenomorph/xeno_firer = fired_proj.firer + if(xeno_firer.can_not_harm(target)) + return + + shake_camera(target, 5, 0.1 SECONDS) + var/obj/effect/beam/tail_beam = fired_proj.firer.beam(target, "oppressor_tail", 'icons/effects/beam.dmi', 0.5 SECONDS, 5) + var/image/tail_image = image('icons/effects/status_effects.dmi', "hooked") + target.overlays += tail_image + + new /datum/effects/xeno_slow(target, fired_proj.firer, ttl = 0.5 SECONDS) + target.apply_effect(0.5, STUN) + INVOKE_ASYNC(target, TYPE_PROC_REF(/atom/movable, throw_atom), fired_proj.firer, get_dist(fired_proj.firer, target)-1, SPEED_VERY_FAST) + + qdel(tail_beam) + addtimer(CALLBACK(src, TYPE_PROC_REF(/datum/ammo/xeno/oppressor_tail, remove_tail_overlay), target, tail_image), 0.5 SECONDS) //needed so it can actually be seen as it gets deleted too quickly otherwise. + +/datum/ammo/xeno/oppressor_tail/proc/remove_tail_overlay(mob/overlayed_mob, image/tail_image) + overlayed_mob.overlays -= tail_image diff --git a/code/datums/components/autofire/autofire.dm b/code/datums/components/autofire/autofire.dm index 2b9401e8d346..455fb70a9fa1 100644 --- a/code/datums/components/autofire/autofire.dm +++ b/code/datums/components/autofire/autofire.dm @@ -82,6 +82,8 @@ /datum/component/automatedfire/autofire/proc/initiate_shot() SIGNAL_HANDLER if(shooting)//if we are already shooting, it means the shooter is still on cooldown + if(bursting && (world.time > (next_fire + (burstfire_shot_delay * burst_shots_to_fire)))) + hard_reset() return shooting = TRUE process_shot() @@ -123,19 +125,19 @@ if(GUN_FIREMODE_BURSTFIRE) shots_fired++ if(shots_fired == burst_shots_to_fire) - callback_bursting.Invoke(FALSE) - callback_display_ammo.Invoke() + callback_bursting?.Invoke(FALSE) + callback_display_ammo?.Invoke() bursting = FALSE stop_firing() if(have_to_reset_at_burst_end)//We failed to reset because we were bursting, we do it now - callback_reset_fire.Invoke() + callback_reset_fire?.Invoke() have_to_reset_at_burst_end = FALSE return - callback_bursting.Invoke(TRUE) + callback_bursting?.Invoke(TRUE) bursting = TRUE next_fire = world.time + burstfire_shot_delay if(GUN_FIREMODE_AUTOMATIC) - callback_set_firing.Invoke(TRUE) + callback_set_firing?.Invoke(TRUE) next_fire = world.time + (auto_fire_shot_delay * automatic_delay_mult) if(GUN_FIREMODE_SEMIAUTO) return diff --git a/code/datums/components/cell.dm b/code/datums/components/cell.dm new file mode 100644 index 000000000000..81ef3733e2e2 --- /dev/null +++ b/code/datums/components/cell.dm @@ -0,0 +1,202 @@ +#define UNLIMITED_CHARGE -1 +#define UNLIMITED_DISTANCE -1 + +/datum/component/cell + dupe_mode = COMPONENT_DUPE_UNIQUE + /// Maximum charge of the power cell, set to -1 for infinite charge + var/max_charge = 10000 + /// Initial max charge of the power cell + var/initial_max_charge + /// Current charge of power cell + var/charge = 10000 + /// If the component can be recharged by hitting its parent with a cell + var/hit_charge = FALSE + /// The maximum amount that can be recharged per tick when using a cell to recharge this component + var/max_recharge_tick = 400 + /// If draining charge on process(), how much to drain per process call + var/charge_drain = 10 + /// If the parent should show cell charge on examine + var/display_charge = TRUE + /// From how many tiles at the highest someone can examine the parent to see the charge + var/charge_examine_range = 1 + /// If the component requires a cell to be inserted to work instead of having an integrated one + var/cell_insert = FALSE + /// Ref to an inserted cell. Should only be null if cell_insert is false + var/obj/item/cell/inserted_cell + + +/datum/component/cell/Initialize( + max_charge = 10000, + hit_charge = FALSE, + max_recharge_tick = 400, + charge_drain = 10, + display_charge = TRUE, + charge_examine_range = 1, + cell_insert = FALSE, + ) + + . = ..() + if(!isatom(parent)) + return COMPONENT_INCOMPATIBLE + + src.max_charge = max_charge + charge = max_charge + src.hit_charge = hit_charge + src.max_recharge_tick = max_recharge_tick + src.charge_drain = charge_drain + src.display_charge = display_charge + src.charge_examine_range = charge_examine_range + src.cell_insert = cell_insert + +/datum/component/cell/Destroy(force, silent) + QDEL_NULL(inserted_cell) + return ..() + + +/datum/component/cell/RegisterWithParent() + ..() + RegisterSignal(parent, list(COMSIG_PARENT_ATTACKBY, COMSIG_ITEM_ATTACKED), PROC_REF(on_object_hit)) + RegisterSignal(parent, COMSIG_CELL_ADD_CHARGE, PROC_REF(add_charge)) + RegisterSignal(parent, COMSIG_CELL_USE_CHARGE, PROC_REF(use_charge)) + RegisterSignal(parent, COMSIG_CELL_CHECK_CHARGE, PROC_REF(has_charge)) + RegisterSignal(parent, COMSIG_CELL_START_TICK_DRAIN, PROC_REF(start_drain)) + RegisterSignal(parent, COMSIG_CELL_STOP_TICK_DRAIN, PROC_REF(stop_drain)) + RegisterSignal(parent, COMSIG_CELL_REMOVE_CELL, PROC_REF(remove_cell)) + RegisterSignal(parent, COMSIG_PARENT_EXAMINE, PROC_REF(on_examine)) + RegisterSignal(parent, COMSIG_ATOM_EMP_ACT, PROC_REF(on_emp)) + +/datum/component/cell/process() + use_charge(null, charge_drain) + +/datum/component/cell/proc/on_emp(datum/source, severity) + SIGNAL_HANDLER + + use_charge(null, round(max_charge / severity)) + +/datum/component/cell/proc/start_drain(datum/source) + SIGNAL_HANDLER + + START_PROCESSING(SSobj, src) + +/datum/component/cell/proc/stop_drain(datum/source) + SIGNAL_HANDLER + + STOP_PROCESSING(SSobj, src) + +/datum/component/cell/proc/on_examine(datum/source, mob/examiner, list/examine_text) + SIGNAL_HANDLER + + if(!display_charge) + return + + if((charge_examine_range != UNLIMITED_DISTANCE) && get_dist(examiner, parent) > charge_examine_range) + return + + examine_text += "A small gauge in the corner reads \"Power: [round(100 * charge / max_charge)]%\"." + +/datum/component/cell/proc/on_object_hit(datum/source, obj/item/cell/attack_obj, mob/living/attacker, params) + SIGNAL_HANDLER + + if(!hit_charge || !istype(attack_obj)) + return + + if(!cell_insert) + INVOKE_ASYNC(src, PROC_REF(charge_from_cell), attack_obj, attacker) + + else + insert_cell(attack_obj, attacker) + + return COMPONENT_NO_AFTERATTACK|COMPONENT_CANCEL_ITEM_ATTACK + +/datum/component/cell/proc/insert_cell(obj/item/cell/power_cell, mob/living/user) + if(inserted_cell) + to_chat(user, SPAN_WARNING("There's already a power cell in [parent]!")) + return + + if(SEND_SIGNAL(parent, COMSIG_CELL_TRY_INSERT_CELL) & COMPONENT_CANCEL_CELL_INSERT) + return + + power_cell.drop_to_floor(user) + power_cell.forceMove(parent) + inserted_cell = power_cell + charge = power_cell.charge + max_charge = power_cell.maxcharge + +/datum/component/cell/proc/remove_cell(mob/living/user) + SIGNAL_HANDLER + + user.put_in_hands(inserted_cell, TRUE) + to_chat(user, SPAN_NOTICE("You remove [inserted_cell] from [parent].")) + inserted_cell = null + max_charge = initial_max_charge + charge = 0 + +/datum/component/cell/proc/charge_from_cell(obj/item/cell/power_cell, mob/living/user) + if(max_charge == UNLIMITED_CHARGE) + to_chat(user, SPAN_WARNING("[parent] doesn't need more power.")) + return + + while(charge < max_charge) + if(SEND_SIGNAL(parent, COMSIG_CELL_TRY_RECHARGING, user) & COMPONENT_CELL_NO_RECHARGE) + return + + if(power_cell.charge <= 0) + to_chat(user, SPAN_WARNING("[power_cell] is completely dry.")) + return + + if(!do_after(user, 1 SECONDS, (INTERRUPT_ALL & (~INTERRUPT_MOVED)), BUSY_ICON_BUILD, power_cell, INTERRUPT_DIFF_LOC)) + to_chat(user, SPAN_WARNING("You were interrupted.")) + return + + if(power_cell.charge <= 0) + return + + var/to_transfer = min(max_recharge_tick, power_cell.charge, (max_charge - charge)) + if(power_cell.use(to_transfer)) + add_charge(null, to_transfer) + to_chat(user, "You transfer some power between [power_cell] and [parent]. The gauge now reads: [round(100 * charge / max_charge)]%.") + +/datum/component/cell/proc/add_charge(datum/source, charge_add = 0) + SIGNAL_HANDLER + + if(max_charge == UNLIMITED_CHARGE) + return + + if(!charge_add) + return + + charge = clamp(charge + charge_add, 0, max_charge) + +/datum/component/cell/proc/use_charge(datum/source, charge_use = 0) + SIGNAL_HANDLER + + if(max_charge == UNLIMITED_CHARGE) + return + + if(!charge_use) + return + + if(!charge) + return COMPONENT_CELL_NO_USE_CHARGE + + charge = clamp(charge - charge_use, 0, max_charge) + + if(!charge) + on_charge_empty() + return + +/datum/component/cell/proc/has_charge(datum/source, charge_amount = 0) + SIGNAL_HANDLER + + if(!charge) + return COMPONENT_CELL_CHARGE_INSUFFICIENT + + if(charge < charge_amount) + return COMPONENT_CELL_CHARGE_INSUFFICIENT + +/datum/component/cell/proc/on_charge_empty() + stop_drain() + SEND_SIGNAL(parent, COMSIG_CELL_OUT_OF_CHARGE) + +#undef UNLIMITED_CHARGE +#undef UNLIMITED_DISTANCE diff --git a/code/datums/components/crate_tag.dm b/code/datums/components/crate_tag.dm new file mode 100644 index 000000000000..379df82a2084 --- /dev/null +++ b/code/datums/components/crate_tag.dm @@ -0,0 +1,36 @@ +/datum/component/crate_tag + dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS + /// The crate tag used for notifications and as label + var/name + +/datum/component/crate_tag/Initialize(name, obj/structure/closet/crate/masquarade_type) + var/obj/structure/closet/crate/crate = parent + if(!istype(crate)) + return COMPONENT_INCOMPATIBLE + setup(name, masquarade_type) + RegisterSignal(parent, COMSIG_STRUCTURE_CRATE_SQUAD_LAUNCHED, PROC_REF(notify_squad)) + +/datum/component/crate_tag/InheritComponent(datum/component/C, i_am_original, name, obj/structure/closet/crate/masquarade_type) + . = ..() + setup(name, masquarade_type) + +/datum/component/crate_tag/proc/setup(name, obj/structure/closet/crate/masquarade_type) + var/obj/structure/closet/crate/crate = parent + if(masquarade_type) + crate.name = initial(masquarade_type.name) + crate.desc = initial(masquarade_type.desc) + crate.icon_opened = initial(masquarade_type.icon_opened) + crate.icon_closed = initial(masquarade_type.icon_closed) + if(crate.opened) + crate.icon_state = crate.icon_opened + else + crate.icon_state = crate.icon_closed + if(name) + parent.AddComponent(/datum/component/label, name) + src.name = name // Keep it around additionally for notifications + +/// Handler to notify an overwatched squad that this crate has been dropped for them +/datum/component/crate_tag/proc/notify_squad(datum/source, datum/squad/squad) + SIGNAL_HANDLER + squad.send_message("'[name]' supply drop incoming. Heads up!") + squad.send_maptext(name, "Incoming Supply Drop:") diff --git a/code/datums/components/weed_food.dm b/code/datums/components/weed_food.dm index ce6c17e0af95..16be8665f55b 100644 --- a/code/datums/components/weed_food.dm +++ b/code/datums/components/weed_food.dm @@ -259,7 +259,7 @@ active = FALSE merged = TRUE - parent_mob.density = FALSE + ADD_TRAIT(parent_mob, TRAIT_UNDENSE, XENO_WEED_TRAIT) parent_mob.anchored = TRUE parent_mob.mouse_opacity = MOUSE_OPACITY_TRANSPARENT parent_mob.plane = FLOOR_PLANE diff --git a/code/datums/datacore.dm b/code/datums/datacore.dm index 404ab3c43b1f..353c69d72e49 100644 --- a/code/datums/datacore.dm +++ b/code/datums/datacore.dm @@ -133,6 +133,9 @@ GLOBAL_DATUM_INIT(data_core, /datum/datacore, new) continue dept_flags |= FLAG_SHOW_MARINES squad_sublists[squad_name] = TRUE + ///If it is a real squad in the USCM squad list to prevent the crew manifest from breaking + if(!(squad_name in ROLES_SQUAD_ALL)) + continue LAZYSET(marines_by_squad[squad_name][real_rank], name, rank) //here we fill manifest diff --git a/code/datums/datum.dm b/code/datums/datum.dm index b26c6afe4d91..7d497785a72a 100644 --- a/code/datums/datum.dm +++ b/code/datums/datum.dm @@ -19,8 +19,8 @@ /// Active timers with this datum as the target var/list/active_timers - /// Status traits attached. - var/list/status_traits + /// Status traits attached to this datum. associative list of the form: list(trait name (string) = list(source1, source2, source3,...)) + var/list/_status_traits /** * Components attached to this datum diff --git a/code/datums/disease.dm b/code/datums/disease.dm index e9c399c7b8bf..d2f466ebeb39 100644 --- a/code/datums/disease.dm +++ b/code/datums/disease.dm @@ -121,17 +121,17 @@ var/list/diseases = typesof(/datum/disease) - /datum/disease check_range = 1 // everything else, like infect-on-contact things, only infect things on top of it if(isturf(source.loc)) - for(var/mob/living/carbon/M in oview(check_range, source)) - if(isturf(M.loc)) - if(AStar(source.loc, M.loc, /turf/proc/AdjacentTurfs, /turf/proc/Distance, check_range)) - M.contract_disease(src, 0, 1, force_spread) + for(var/mob/living/carbon/victim in oview(check_range, source)) + if(isturf(victim.loc)) + if(AStar(source.loc, victim.loc, /turf/proc/AdjacentTurfs, /turf/proc/Distance, check_range)) + victim.contract_disease(src, 0, 1, force_spread) return /datum/disease/process() if(!holder) - active_diseases -= src + SSdisease.all_diseases -= src return if(prob(65)) spread(holder) @@ -173,12 +173,10 @@ var/list/diseases = typesof(/datum/disease) - /datum/disease var/mob/living/carbon/human/H = affected_mob H.med_hud_set_status() - - /datum/disease/New(process=TRUE)//process = 1 - adding the object to global list. List is processed by master controller. cure_list = list(cure_id) // to add more cures, add more vars to this list in the actual disease's New() if(process) // Viruses in list are considered active. - active_diseases += src + SSdisease.all_diseases += src initial_spread = spread /datum/disease/proc/IsSame(datum/disease/D) @@ -193,5 +191,5 @@ var/list/diseases = typesof(/datum/disease) - /datum/disease /datum/disease/Destroy() affected_mob = null holder = null - active_diseases -= src + SSdisease.all_diseases -= src . = ..() diff --git a/code/datums/diseases/advance/advance.dm b/code/datums/diseases/advance/advance.dm index 6440c9734374..ad4703ba65fe 100644 --- a/code/datums/diseases/advance/advance.dm +++ b/code/datums/diseases/advance/advance.dm @@ -391,7 +391,7 @@ var/list/advance_cures = list( D.AssignName(new_name) D.Refresh() - for(var/datum/disease/advance/AD in active_diseases) + for(var/datum/disease/advance/AD in SSdisease.all_diseases) AD.Refresh() for(var/mob/living/carbon/human/H in shuffle(GLOB.alive_mob_list.Copy())) @@ -409,7 +409,7 @@ var/list/advance_cures = list( /* /mob/verb/test() - for(var/datum/disease/D in active_diseases) + for(var/datum/disease/D in SSdisease.all_diseases) to_chat(src, "[D.name] - [D.holder]") */ diff --git a/code/datums/diseases/black_goo.dm b/code/datums/diseases/black_goo.dm index 38a26f3648c7..d4d9b6f50996 100644 --- a/code/datums/diseases/black_goo.dm +++ b/code/datums/diseases/black_goo.dm @@ -211,6 +211,15 @@ . = ..() reagents.add_reagent("antiZed", 30) +/obj/item/reagent_container/glass/bottle/labeled_black_goo_cure + name = "\"Pathogen\" cure bottle" + desc = "The bottle has a biohazard symbol on the front, and has a label, designating its use against Agent A0-3959X.91–15, colloquially known as the \"Black Goo\"." + icon_state = "bottle20" + +/obj/item/reagent_container/glass/bottle/labeled_black_goo_cure/Initialize() + . = ..() + reagents.add_reagent("antiZed", 60) + /datum/language/zombie name = "Zombie" desc = "A growling, guttural method of communication, only Zombies seem to be capable of producing these sounds." diff --git a/code/datums/diseases/mob_procs.dm b/code/datums/diseases/mob_procs.dm index 7f9704c46f47..c27efecdff84 100644 --- a/code/datums/diseases/mob_procs.dm +++ b/code/datums/diseases/mob_procs.dm @@ -80,9 +80,6 @@ passed = check_disease_pass_clothes(target_zone) - if(!passed && spread_type == AIRBORNE && !internal) - passed = (prob((50*virus.permeability_mod) - 1)) - if(passed) AddDisease(virus) @@ -111,36 +108,39 @@ /mob/living/carbon/human/check_disease_pass_clothes(target_zone) var/obj/item/clothing/Cl + var/protection = 0 switch(target_zone) if(1) if(isobj(head) && !istype(head, /obj/item/paper)) Cl = head - . = prob((Cl.permeability_coefficient*100) - 1) - if(. && wear_mask) - . = prob((Cl.permeability_coefficient*100) - 1) + protection += (Cl.permeability_coefficient*100)-100 + if(isobj(wear_mask)) + Cl = wear_mask + protection += (Cl.permeability_coefficient*100)-100 if(2)//arms and legs included if(isobj(wear_suit)) Cl = wear_suit - . = prob((Cl.permeability_coefficient*100) - 1) - if(. && isobj(WEAR_BODY)) + protection += (Cl.permeability_coefficient*100)-100 + if(isobj(WEAR_BODY)) Cl = WEAR_BODY - . = prob((Cl.permeability_coefficient*100) - 1) + protection += (Cl.permeability_coefficient*100)-100 if(3) if(isobj(wear_suit) && wear_suit.flags_armor_protection & BODY_FLAG_HANDS) Cl = wear_suit - . = prob((Cl.permeability_coefficient*100) - 1) + protection += (Cl.permeability_coefficient*100)-100 - if(. && isobj(gloves)) + if(isobj(gloves)) Cl = gloves - . = prob((Cl.permeability_coefficient*100) - 1) + protection += (Cl.permeability_coefficient*100)-100 if(4) if(isobj(wear_suit) && wear_suit.flags_armor_protection & BODY_FLAG_FEET) Cl = wear_suit - . = prob((Cl.permeability_coefficient*100) - 1) + protection += (Cl.permeability_coefficient*100)-100 - if(. && isobj(shoes)) + if(isobj(shoes)) Cl = shoes - . = prob((Cl.permeability_coefficient*100) - 1) + protection += (Cl.permeability_coefficient*100)-100 else to_chat(src, "Something bad happened with disease target zone code, tell a dev or admin ") + return prob(clamp(protection, 5, 90)) diff --git a/code/datums/effects/xeno_strains/boiler_trap.dm b/code/datums/effects/xeno_strains/boiler_trap.dm index 61451391e816..1833b9641a9a 100644 --- a/code/datums/effects/xeno_strains/boiler_trap.dm +++ b/code/datums/effects/xeno_strains/boiler_trap.dm @@ -4,19 +4,17 @@ effect_name = "boiler trap" duration = null flags = INF_DURATION - /// Ghetto flag indicating whether we actually placed the freeze or not, until we have an actual effects system - var/freezer = FALSE /datum/effects/boiler_trap/New(atom/A, mob/from, last_dmg_source, zone) . = ..() if(!QDELETED(src)) var/mob/M = affected_atom - freezer = M.freeze() + ADD_TRAIT(M, TRAIT_IMMOBILIZED, TRAIT_SOURCE_ABILITY(effect_name)) /datum/effects/boiler_trap/Destroy(force) - if(ismob(affected_atom) && freezer) + if(ismob(affected_atom)) var/mob/M = affected_atom - M.unfreeze() + REMOVE_TRAIT(M, TRAIT_IMMOBILIZED, TRAIT_SOURCE_ABILITY(effect_name)) return ..() /datum/effects/boiler_trap/validate_atom(atom/A) @@ -29,7 +27,5 @@ . = ..() if(!.) return FALSE var/mob/M = affected_atom - if(M.frozen) return TRUE - if(!freezer) - freezer = M.freeze() + ADD_TRAIT(M, TRAIT_IMMOBILIZED, TRAIT_SOURCE_ABILITY(effect_name)) return TRUE diff --git a/code/datums/emergency_calls/cbrn.dm b/code/datums/emergency_calls/cbrn.dm new file mode 100644 index 000000000000..3a6b1c640632 --- /dev/null +++ b/code/datums/emergency_calls/cbrn.dm @@ -0,0 +1,80 @@ +/datum/emergency_call/cbrn + name = "CBRN (Squad)" + arrival_message = "A CBRN squad has been dispatched to your ship. Stand by." + objectives = "Handle the chemical, biological, radiological, or nuclear threat. Further orders may be provided." + mob_min = 3 + mob_max = 5 + max_heavies = 0 + max_smartgunners = 0 + +/datum/emergency_call/cbrn/create_member(datum/mind/new_mind, turf/override_spawn_loc) + var/turf/spawn_loc = override_spawn_loc ? override_spawn_loc : get_spawn_point() + + if(!istype(spawn_loc)) + return //Didn't find a useable spawn point. + + var/mob/living/carbon/human/mob = new(spawn_loc) + new_mind.transfer_to(mob, TRUE) + + if(!leader && HAS_FLAG(mob.client.prefs.toggles_ert, PLAY_LEADER) && check_timelock(mob.client, JOB_SQUAD_LEADER, time_required_for_job)) + leader = mob + arm_equipment(mob, /datum/equipment_preset/uscm/cbrn/leader, TRUE, TRUE) + to_chat(mob, SPAN_ROLE_HEADER("You are the CBRN Fireteam Leader!")) + + else if(medics < max_medics && HAS_FLAG(mob.client.prefs.toggles_ert, PLAY_MEDIC) && check_timelock(mob.client, JOB_SQUAD_MEDIC, time_required_for_job)) + medics++ + arm_equipment(mob, /datum/equipment_preset/uscm/cbrn/medic, TRUE, TRUE) + to_chat(mob, SPAN_ROLE_HEADER("You are the CBRN Squad Medic!")) + + else if(engineers < max_engineers && HAS_FLAG(mob.client.prefs.toggles_ert, PLAY_ENGINEER) && check_timelock(mob.client, JOB_SQUAD_ENGI, time_required_for_job)) + engineers++ + arm_equipment(mob, /datum/equipment_preset/uscm/cbrn/engineer, TRUE, TRUE) + to_chat(mob, SPAN_ROLE_HEADER("You are the CBRN Squad Engineer!")) + + else + arm_equipment(mob, /datum/equipment_preset/uscm/cbrn/standard, TRUE, TRUE) + to_chat(mob, SPAN_ROLE_HEADER("You are a CBRN Squad Rifleman!")) + + to_chat(mob, SPAN_ROLE_BODY("You are a member of the USCM's CBRN. The CBRN is a force that specializes in handling chemical, biological, radiological, and nuclear threats.")) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), mob, SPAN_BOLD("Objectives: [objectives]")), 1 SECONDS) + +/datum/emergency_call/cbrn/ert + name = "CBRN (Distress)" + arrival_message = "Your distress signal has been received and we are dispatching the nearest CBRN squad to board with you now. Stand by." + probability = 10 + +/datum/emergency_call/cbrn/ert/New() + ..() + objectives = "Investigate the distress signal aboard the [MAIN_SHIP_NAME]." + +/datum/emergency_call/cbrn/specialists + name = "CBRN (Specialists)" + mob_min = 2 + mob_max = 5 + max_engineers = 0 + max_medics = 0 + +/datum/emergency_call/cbrn/specialists/New() + var/cbrn_ship_name = "Unit [pick(nato_phonetic_alphabet)]-[rand(1, 99)]" + arrival_message = "[MAIN_SHIP_NAME], CBRN [cbrn_ship_name] has been dispatched. Follow all orders provided by [cbrn_ship_name]." + objectives = "You are a specialist team in [cbrn_ship_name] dispatched to quell a threat to [MAIN_SHIP_NAME]. Further orders may be provided." + +/datum/emergency_call/cbrn/specialists/create_member(datum/mind/new_mind, turf/override_spawn_loc) + var/turf/spawn_loc = override_spawn_loc ? override_spawn_loc : get_spawn_point() + + if(!istype(spawn_loc)) + return //Didn't find a useable spawn point. + + var/mob/living/carbon/human/mob = new(spawn_loc) + new_mind.transfer_to(mob, TRUE) + + if(!leader && HAS_FLAG(mob.client.prefs.toggles_ert, PLAY_LEADER) && check_timelock(mob.client, JOB_SQUAD_LEADER, time_required_for_job)) + leader = mob + arm_equipment(mob, /datum/equipment_preset/uscm/cbrn/specialist/lead, TRUE, TRUE) + to_chat(mob, SPAN_ROLE_HEADER("You are the CBRN Specialist Squad Leader!")) + else + arm_equipment(mob, /datum/equipment_preset/uscm/cbrn/specialist, TRUE, TRUE) + to_chat(mob, SPAN_ROLE_HEADER("You are a CBRN Specialist!")) + + to_chat(mob, SPAN_ROLE_BODY("You are a member of the USCM's CBRN. The CBRN is a force that specializes in handling chemical, biological, radiological, and nuclear threats.")) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), mob, SPAN_BOLD("Objectives: [objectives]")), 1 SECONDS) diff --git a/code/datums/emergency_calls/cmb.dm b/code/datums/emergency_calls/cmb.dm index 52da1c967a00..a49c0a4ce273 100644 --- a/code/datums/emergency_calls/cmb.dm +++ b/code/datums/emergency_calls/cmb.dm @@ -100,6 +100,19 @@ to_chat(M, SPAN_BOLD("Corporate Officers chase after paychecks and promotions, but you are motivated to do your sworn duty and care for the population, no matter how far or isolated a colony may be.")) to_chat(M, SPAN_BOLD("Despite being stretched thin, the stalwart oath of the Marshals has continued to keep communities safe, with the CMB well respected by many. You are a representation of that oath, serve with distinction.")) + +// A Nearby Colonial Marshal patrol team responding to Marshals in Distress. +/datum/emergency_call/cmb/alt + name = "CMB - Patrol Team - Marshals in Distress (Friendly)" + mob_max = 5 + mob_min = 1 + probability = 0 + +/datum/emergency_call/cmb/alt/New() + ..() + arrival_message = "CMB Team, this is Anchorpoint Station. We have confirmed you are in distress. Routing nearby units to assist!" + objectives = "Patrol Unit 5807, we have nearby Marshals in Distress! Locate and assist them immediately." + // Anchorpoint Station Colonial Marines, use this primarily for reinforcing or evacuating the CMB, as the CMB themselves are not equipped to handle heavy engagements. /datum/emergency_call/cmb/anchorpoint name = "CMB - Anchorpoint Station Colonial Marine QRF (Friendly)" @@ -113,7 +126,7 @@ /datum/emergency_call/cmb/anchorpoint/New() ..() arrival_message = "[MAIN_SHIP_NAME], this is Anchorpoint Station. Be advised, a QRF Team of our Colonial Marines is currently attempting to board you. Open your ports, transmitting docking codes now. Standby." - objectives = "QRF Team. You are here to reinforce the cmb team we deployed earlier. Make contact and work with the CMB Marshal and their deputies. Facilitate their protection and evacuation if necessary. Secondary Objective: Investigate the reason for distress aboard the [MAIN_SHIP_NAME], and assist the crew if possible." + objectives = "QRF Team. You are here to reinforce the CMB team we deployed earlier. Make contact and work with the CMB Marshal and their deputies. Facilitate their protection and evacuation if necessary. Secondary Objective: Investigate the reason for distress aboard the [MAIN_SHIP_NAME], and assist the crew if possible." /datum/emergency_call/cmb/anchorpoint/create_member(datum/mind/M, turf/override_spawn_loc) var/turf/spawn_loc = override_spawn_loc ? override_spawn_loc : get_spawn_point() diff --git a/code/datums/emergency_calls/cryo_marines.dm b/code/datums/emergency_calls/cryo_marines.dm index 7ed61852e9bf..19f73a9843ce 100644 --- a/code/datums/emergency_calls/cryo_marines.dm +++ b/code/datums/emergency_calls/cryo_marines.dm @@ -13,7 +13,7 @@ var/leaders = 0 spawn_max_amount = TRUE -/datum/emergency_call/cryo_squad/spawn_candidates(announce, override_spawn_loc, announce_dispatch_message) +/datum/emergency_call/cryo_squad/spawn_candidates(quiet_launch, announce_incoming, override_spawn_loc) var/datum/squad/marine/cryo/cryo_squad = RoleAuthority.squads_by_type[/datum/squad/marine/cryo] leaders = cryo_squad.num_leaders . = ..() diff --git a/code/datums/emergency_calls/cryo_marines_heavy.dm b/code/datums/emergency_calls/cryo_marines_heavy.dm index 70ce52443573..f4fe3c9f2a57 100644 --- a/code/datums/emergency_calls/cryo_marines_heavy.dm +++ b/code/datums/emergency_calls/cryo_marines_heavy.dm @@ -16,7 +16,7 @@ var/leaders = 0 -/datum/emergency_call/cryo_squad_equipped/spawn_candidates(announce, override_spawn_loc, announce_dispatch_message) +/datum/emergency_call/cryo_squad_equipped/spawn_candidates(quiet_launch, announce_incoming, override_spawn_loc) var/datum/squad/marine/cryo/cryo_squad = RoleAuthority.squads_by_type[/datum/squad/marine/cryo] leaders = cryo_squad.num_leaders . = ..() diff --git a/code/datums/emergency_calls/deathsquad.dm b/code/datums/emergency_calls/deathsquad.dm index 0bfab8fbf2b7..1cd5bdef6713 100644 --- a/code/datums/emergency_calls/deathsquad.dm +++ b/code/datums/emergency_calls/deathsquad.dm @@ -3,7 +3,7 @@ //Weyland-Yutani Deathsquad - W-Y Deathsquad. Event only /datum/emergency_call/death - name = "Weyland Whiteout Operators" + name = "Weyland Whiteout Operators (!DEATHSQUAD!)" mob_max = 8 mob_min = 5 arrival_message = "'!`2*%slau#*jer t*h$em a!l%. le&*ve n(o^ w&*nes%6es.*v$e %#d ou^'" @@ -18,41 +18,76 @@ // DEATH SQUAD-------------------------------------------------------------------------------- -/datum/emergency_call/death/create_member(datum/mind/M, turf/override_spawn_loc) +/datum/emergency_call/death/create_member(datum/mind/player, turf/override_spawn_loc) var/turf/spawn_loc = override_spawn_loc ? override_spawn_loc : get_spawn_point() if(!istype(spawn_loc)) return //Didn't find a useable spawn point. - var/mob/living/carbon/human/H = new(spawn_loc) - M.transfer_to(H, TRUE) + var/mob/living/carbon/human/person = new(spawn_loc) + player.transfer_to(person, TRUE) - if(!leader && HAS_FLAG(H.client.prefs.toggles_ert, PLAY_LEADER) && check_timelock(H.client, JOB_SQUAD_LEADER, time_required_for_job)) - leader = H - to_chat(H, SPAN_ROLE_HEADER("You are the Whiteout Team Leader!")) - to_chat(H, SPAN_ROLE_BODY("Whiteout protocol is in effect for the target, all assets onboard are to be liquidated with expediency unless otherwise instructed by Weyland Yutani personnel holding the position of Director or above.")) - arm_equipment(H, /datum/equipment_preset/pmc/w_y_whiteout/leader, TRUE, TRUE) - else if(medics < max_medics && HAS_FLAG(H.client.prefs.toggles_ert, PLAY_MEDIC) && check_timelock(H.client, JOB_SQUAD_MEDIC, time_required_for_job)) + if(!leader && HAS_FLAG(person.client.prefs.toggles_ert, PLAY_LEADER) && check_timelock(person.client, JOB_SQUAD_LEADER, time_required_for_job)) + leader = person + to_chat(person, SPAN_ROLE_HEADER("You are the Whiteout Team Leader!")) + to_chat(person, SPAN_ROLE_BODY("Whiteout protocol is in effect for the target, all assets onboard are to be liquidated with expediency unless otherwise instructed by Weyland Yutani personnel holding the position of Director or above.")) + arm_equipment(person, /datum/equipment_preset/pmc/w_y_whiteout/leader, TRUE, TRUE) + else if(medics < max_medics && HAS_FLAG(person.client.prefs.toggles_ert, PLAY_MEDIC) && check_timelock(person.client, JOB_SQUAD_MEDIC, time_required_for_job)) medics++ - to_chat(H, SPAN_ROLE_HEADER("You are a Whiteout Team Medic!")) - to_chat(H, SPAN_ROLE_BODY("Whiteout protocol is in effect for the target, all assets onboard are to be liquidated with expediency unless otherwise instructed by Weyland Yutani personnel holding the position of Director or above.")) - arm_equipment(H, /datum/equipment_preset/pmc/w_y_whiteout/medic, TRUE, TRUE) - else if(heavies < max_heavies && HAS_FLAG(H.client.prefs.toggles_ert, PLAY_SMARTGUNNER) && check_timelock(H.client, list(JOB_SQUAD_SPECIALIST, JOB_SQUAD_SMARTGUN), time_required_for_job)) + to_chat(person, SPAN_ROLE_HEADER("You are a Whiteout Team Medic!")) + to_chat(person, SPAN_ROLE_BODY("Whiteout protocol is in effect for the target, all assets onboard are to be liquidated with expediency unless otherwise instructed by Weyland Yutani personnel holding the position of Director or above.")) + arm_equipment(person, /datum/equipment_preset/pmc/w_y_whiteout/medic, TRUE, TRUE) + else if(heavies < max_heavies && HAS_FLAG(person.client.prefs.toggles_ert, PLAY_SMARTGUNNER) && check_timelock(person.client, list(JOB_SQUAD_SPECIALIST, JOB_SQUAD_SMARTGUN), time_required_for_job)) heavies++ - to_chat(H, SPAN_ROLE_HEADER("You are a Whiteout Team Terminator!")) - to_chat(H, SPAN_ROLE_BODY("Whiteout protocol is in effect for the target, all assets onboard are to be liquidated with expediency unless otherwise instructed by Weyland Yutani personnel holding the position of Director or above.")) - arm_equipment(H, /datum/equipment_preset/pmc/w_y_whiteout/terminator, TRUE, TRUE) + to_chat(person, SPAN_ROLE_HEADER("You are a Whiteout Team Terminator!")) + to_chat(person, SPAN_ROLE_BODY("Whiteout protocol is in effect for the target, all assets onboard are to be liquidated with expediency unless otherwise instructed by Weyland Yutani personnel holding the position of Director or above.")) + arm_equipment(person, /datum/equipment_preset/pmc/w_y_whiteout/terminator, TRUE, TRUE) else - to_chat(H, SPAN_ROLE_HEADER("You are a Whiteout Team Operative!")) - to_chat(H, SPAN_ROLE_BODY("Whiteout protocol is in effect for the target, all assets onboard are to be liquidated with expediency unless otherwise instructed by Weyland Yutani personnel holding the position of Director or above.")) - arm_equipment(H, /datum/equipment_preset/pmc/w_y_whiteout, TRUE, TRUE) + to_chat(person, SPAN_ROLE_HEADER("You are a Whiteout Team Operative!")) + to_chat(person, SPAN_ROLE_BODY("Whiteout protocol is in effect for the target, all assets onboard are to be liquidated with expediency unless otherwise instructed by Weyland Yutani personnel holding the position of Director or above.")) + arm_equipment(person, /datum/equipment_preset/pmc/w_y_whiteout, TRUE, TRUE) - addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), H, SPAN_BOLD("Objectives: [objectives]")), 1 SECONDS) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), person, SPAN_BOLD("Objectives: [objectives]")), 1 SECONDS) + +/datum/emergency_call/death/low_threat + name = "Weyland Whiteout Operators" + +// DEATH SQUAD-------------------------------------------------------------------------------- +/datum/emergency_call/death/low_threat/create_member(datum/mind/player, turf/override_spawn_loc) + var/turf/spawn_loc = override_spawn_loc ? override_spawn_loc : get_spawn_point() + + if(!istype(spawn_loc)) + return //Didn't find a useable spawn point. + + var/mob/living/carbon/human/person = new(spawn_loc) + player.transfer_to(person, TRUE) + + if(!leader && HAS_FLAG(person.client.prefs.toggles_ert, PLAY_LEADER) && check_timelock(person.client, JOB_SQUAD_LEADER, time_required_for_job)) + leader = person + to_chat(person, SPAN_ROLE_HEADER("You are the Whiteout Team Leader!")) + to_chat(person, SPAN_ROLE_BODY("Whiteout protocol is in effect for the target, all assets onboard are to be liquidated with expediency unless otherwise instructed by Weyland Yutani personnel holding the position of Director or above.")) + arm_equipment(person, /datum/equipment_preset/pmc/w_y_whiteout/low_threat/leader, TRUE, TRUE) + else if(medics < max_medics && HAS_FLAG(person.client.prefs.toggles_ert, PLAY_MEDIC) && check_timelock(person.client, JOB_SQUAD_MEDIC, time_required_for_job)) + medics++ + to_chat(person, SPAN_ROLE_HEADER("You are a Whiteout Team Medic!")) + to_chat(person, SPAN_ROLE_BODY("Whiteout protocol is in effect for the target, all assets onboard are to be liquidated with expediency unless otherwise instructed by Weyland Yutani personnel holding the position of Director or above.")) + arm_equipment(person, /datum/equipment_preset/pmc/w_y_whiteout/low_threat/medic, TRUE, TRUE) + else if(heavies < max_heavies && HAS_FLAG(person.client.prefs.toggles_ert, PLAY_SMARTGUNNER) && check_timelock(person.client, list(JOB_SQUAD_SPECIALIST, JOB_SQUAD_SMARTGUN), time_required_for_job)) + heavies++ + to_chat(person, SPAN_ROLE_HEADER("You are a Whiteout Team Terminator!")) + to_chat(person, SPAN_ROLE_BODY("Whiteout protocol is in effect for the target, all assets onboard are to be liquidated with expediency unless otherwise instructed by Weyland Yutani personnel holding the position of Director or above.")) + arm_equipment(person, /datum/equipment_preset/pmc/w_y_whiteout/low_threat/terminator, TRUE, TRUE) + else + to_chat(person, SPAN_ROLE_HEADER("You are a Whiteout Team Operative!")) + to_chat(person, SPAN_ROLE_BODY("Whiteout protocol is in effect for the target, all assets onboard are to be liquidated with expediency unless otherwise instructed by Weyland Yutani personnel holding the position of Director or above.")) + arm_equipment(person, /datum/equipment_preset/pmc/w_y_whiteout/low_threat, TRUE, TRUE) + + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), person, SPAN_BOLD("Objectives: [objectives]")), 1 SECONDS) //################################################################################################ // Marine commandos - USCM Deathsquad. Event only /datum/emergency_call/marsoc - name = "Marine Raider Strike Team" + name = "Marine Raider Strike Team (!DEATHSQUAD!)" mob_max = 8 mob_min = 5 probability = 0 @@ -81,7 +116,7 @@ return /datum/emergency_call/marsoc_covert - name = "Marine Raider Operatives (Covert)" + name = "Marine Raider Operatives (!DEATHSQUAD! Covert)" mob_max = 8 mob_min = 5 probability = 0 @@ -107,3 +142,27 @@ to_chat(H, SPAN_BOLDNOTICE("You are absolutely loyal to High Command and must follow their directives.")) to_chat(H, SPAN_BOLDNOTICE("Execute the mission assigned to you with extreme prejudice!")) return + + +/datum/emergency_call/marsoc/low_threat + name = "Marine Raider Operatives" + +/datum/emergency_call/marsoc/low_threat/create_member(datum/mind/MIND) + + var/turf/spawn_loc = get_spawn_point() + + if(!istype(spawn_loc)) + return //Didn't find a useable spawn point. + + var/mob/living/carbon/human/player = new(spawn_loc) + MIND.transfer_to(player, TRUE) + if(!leader && HAS_FLAG(player.client.prefs.toggles_ert, PLAY_LEADER) && check_timelock(player.client, JOB_SQUAD_LEADER, time_required_for_job)) //First one spawned is always the leader. + leader = player + to_chat(player, SPAN_WARNING(FONT_SIZE_BIG("You are a Marine Raider Team Leader, better than all the rest."))) + arm_equipment(player, /datum/equipment_preset/uscm/marsoc/low_threat/sl, TRUE, TRUE) + else + to_chat(player, SPAN_WARNING(FONT_SIZE_BIG("You are an elite Marine Raider, the best of the best."))) + arm_equipment(player, /datum/equipment_preset/uscm/marsoc/low_threat, TRUE, TRUE) + to_chat(player, SPAN_BOLDNOTICE("You are absolutely loyal to High Command and must follow their directives.")) + to_chat(player, SPAN_BOLDNOTICE("Execute the mission assigned to you with extreme prejudice!")) + return diff --git a/code/datums/emergency_calls/emergency_call.dm b/code/datums/emergency_calls/emergency_call.dm index 6533086d98f3..9db46955a5ea 100644 --- a/code/datums/emergency_calls/emergency_call.dm +++ b/code/datums/emergency_calls/emergency_call.dm @@ -91,12 +91,12 @@ else return chosen_call -/datum/game_mode/proc/get_specific_call(call_name, quiet_launch = FALSE, announce = TRUE, is_emergency = TRUE, info = "", announce_dispatch_message = TRUE) +/datum/game_mode/proc/get_specific_call(call_name, quiet_launch = FALSE, announce_incoming = TRUE, info = "") for(var/datum/emergency_call/E in all_calls) //Loop through all potential candidates if(E.name == call_name) var/datum/emergency_call/em_call = new E.type() em_call.objective_info = info - em_call.activate(quiet_launch, announce, is_emergency, announce_dispatch_message) + em_call.activate(quiet_launch, announce_incoming) return error("get_specific_call could not find emergency call '[call_name]'") return @@ -168,7 +168,7 @@ return var/deathtime = world.time - usr.timeofdeath - if(deathtime < 1 MINUTES) //Nice try, ghosting right after the announcement + if(deathtime < 30 SECONDS) //Nice try, ghosting right after the announcement if(SSmapping.configs[GROUND_MAP].map_name != MAP_WHISKEY_OUTPOST) // people ghost so often on whiskey outpost. to_chat(src, SPAN_WARNING("You ghosted too recently.")) return @@ -192,7 +192,7 @@ else to_chat(src, SPAN_WARNING("You did not get enlisted in the response team. Better luck next time!")) -/datum/emergency_call/proc/activate(quiet_launch = FALSE, announce = TRUE, turf/override_spawn_loc, announce_dispatch_message = TRUE) +/datum/emergency_call/proc/activate(quiet_launch = FALSE, announce_incoming = TRUE, turf/override_spawn_loc) set waitfor = 0 if(!SSticker.mode) //Something horribly wrong with the gamemode ticker return @@ -205,9 +205,9 @@ if(!quiet_launch) marine_announcement("A distress beacon has been launched from the [MAIN_SHIP_NAME].", "Priority Alert", 'sound/AI/distressbeacon.ogg', logging = ARES_LOG_SECURITY) - addtimer(CALLBACK(src, TYPE_PROC_REF(/datum/emergency_call, spawn_candidates), quiet_launch, announce, override_spawn_loc, announce_dispatch_message), 30 SECONDS) + addtimer(CALLBACK(src, TYPE_PROC_REF(/datum/emergency_call, spawn_candidates), quiet_launch, announce_incoming, override_spawn_loc), 30 SECONDS) -/datum/emergency_call/proc/spawn_candidates(quiet_launch = FALSE, announce = TRUE, override_spawn_loc, announce_dispatch_message = TRUE) +/datum/emergency_call/proc/spawn_candidates(quiet_launch = FALSE, announce_incoming = TRUE, override_spawn_loc) if(SSticker.mode) SSticker.mode.picked_calls -= src @@ -248,7 +248,7 @@ if(I.current) to_chat(I.current, SPAN_WARNING("You didn't get selected to join the distress team. Better luck next time!")) - if(announce) + if(announce_incoming) marine_announcement(dispatch_message, "Distress Beacon", 'sound/AI/distressreceived.ogg', logging = ARES_LOG_SECURITY) //Announcement that the Distress Beacon has been answered, does not hint towards the chosen ERT message_admins("Distress beacon: [src.name] finalized, setting up candidates.") @@ -304,8 +304,8 @@ create_member(null, override_spawn_loc) candidates = list() - if(arrival_message && announce) - marine_announcement(arrival_message, "Intercepted Tranmission:") + if(arrival_message && announce_incoming) + marine_announcement(arrival_message, "Intercepted Transmission:") /datum/emergency_call/proc/add_candidate(mob/M) if(!M.client || (M.mind && (M.mind in candidates)) || istype(M, /mob/living/carbon/xenomorph)) diff --git a/code/datums/emergency_calls/inspection.dm b/code/datums/emergency_calls/inspection.dm index 4c33d7d9bfa3..ad0200339952 100644 --- a/code/datums/emergency_calls/inspection.dm +++ b/code/datums/emergency_calls/inspection.dm @@ -183,7 +183,7 @@ /datum/emergency_call/inspection_cmb/New() ..() - arrival_message = "[MAIN_SHIP_NAME], This is Anchorpoint Station with the Colonial Marshal Bureau. Be advised, a CMB transport vessel is preparing to board you, submitting Federal docking clearances now. Standby." + arrival_message = "[MAIN_SHIP_NAME], this is Anchorpoint Station with the Colonial Marshal Bureau. Be advised, a CMB transport vessel is preparing to board you, submitting Federal docking clearances now. Standby." objectives = "Get your instructions from the CMB Office at Anchorpoint Station, and carry out your orders. Ensure that Colonial assets are safe and in your custody. Do not enforce or override Marine Law on a Marine Ship unless requested, as it's outside of your juristiction." will_spawn_icc_liaison = prob(90) @@ -265,7 +265,7 @@ to_chat(M, SPAN_BOLD("Despite being stretched thin, the stalwart oath of the Marshals has continued to keep communities safe, with the CMB well respected by many. You are a representation of that oath, serve with distinction.")) /datum/emergency_call/inspection_cmb/black_market - name = "Inspection - Colonial Marshal Ledger Investigation Team" + name = "Inspection - Colonial Marshals Ledger Investigation Team" mob_max = 3 //Marshal, Deputy, ICC CL mob_min = 2 shuttle_id = "Distress_PMC" diff --git a/code/datums/emergency_calls/upp.dm b/code/datums/emergency_calls/upp.dm index 04bcfecf9128..562dac3fe154 100644 --- a/code/datums/emergency_calls/upp.dm +++ b/code/datums/emergency_calls/upp.dm @@ -4,7 +4,7 @@ /datum/emergency_call/upp name = "UPP Naval Infantry (Squad)" mob_max = 9 - probability = 10 + probability = 20 shuttle_id = "Distress_UPP" name_of_spawn = /obj/effect/landmark/ert_spawns/distress_upp item_spawn = /obj/effect/landmark/ert_spawns/distress_upp/item @@ -14,15 +14,17 @@ max_heavies = 1 max_smartgunners = 0 var/heavy_pick = TRUE // whether heavy should count as either a minigunner or shotgunner - hostility = TRUE var/max_synths = 1 var/synths = 0 /datum/emergency_call/upp/New() - ..() - arrival_message = "T*is i* UP* d^sp^*ch`. STr*&e teaM, #*u are cLe*% for a*pr*%^h. Pr*mE a*l wE*p^ns )0r c|*$e @u*r*r$ c0m&*t." - objectives = "Eliminate the UA Forces to ensure the UPP prescence in this sector is continued. Listen to your superior officers and take over the [MAIN_SHIP_NAME] at all costs." - + . = ..() + hostility = pick(50;FALSE,50;TRUE) + arrival_message = "[MAIN_SHIP_NAME] t*is i* UP* d^sp^*ch`. STr*&e teaM, #*u are cLe*% for a*pr*%^h. Pr*mE a*l wE*p^ns and pR*epr# t% r@nd$r a(tD." + if(hostility) + objectives = "Eliminate the UA Forces to ensure the UPP prescence in this sector is continued. Listen to your superior officers and take over the [MAIN_SHIP_NAME] at all costs." + else + objectives = "Render assistance towards the UA Forces, do not engage UA forces. Listen to your superior officers." /datum/emergency_call/upp/print_backstory(mob/living/carbon/human/M) if(ishuman_strict(M)) @@ -94,10 +96,26 @@ addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), H, SPAN_BOLD("Objectives: [objectives]")), 1 SECONDS) +/datum/emergency_call/upp/hostile + name = "UPP Naval Infantry (Squad) (Hostile)" + hostility = TRUE + +/datum/emergency_call/upp/hostile/New() + ..() + arrival_message = "[MAIN_SHIP_NAME] t*is i* UP* d^sp^*ch`. STr*&e teaM, #*u are cLe*% for a*pr*%^h. Pr*mE a*l wE*p^ns and pR*epr# t% r@nd$r a(tD." + objectives = "Eliminate the UA Forces to ensure the UPP presence in this sector is continued. Listen to your superior officers and take over the [MAIN_SHIP_NAME] at all costs." + +/datum/emergency_call/upp/friendly + name = "UPP Naval Infantry (Squad) (Friendly)" + hostility = FALSE + +/datum/emergency_call/upp/friendly/New() + ..() + arrival_message = "This is UPP dispatch. USS Almayer, We are responding to your distress call, we will render aid as able, do not fire." + objectives = "Render assistance towards the UA Forces, Listen to your superior officers." /datum/emergency_call/upp/platoon - name = "UPP Naval Infantry (Platoon)" - mob_min = 4 + name = "UPP Naval Infantry (Platoon) (Hostile)" mob_max = 30 probability = 0 max_medics = 3 @@ -106,6 +124,21 @@ max_engineers = 2 max_synths = 1 heavy_pick = FALSE + hostility = TRUE + +/datum/emergency_call/upp/platoon/New() + ..() + arrival_message = "[MAIN_SHIP_NAME] t*is i* UP* d^sp^*ch`. STr*&e teaM, #*u are cLe*% for a*pr*%^h. Pr*mE a*l wE*p^ns and pR*epr# t% r@nd$r a(tD." + objectives = "Eliminate the UA Forces to ensure the UPP presence in this sector is continued. Listen to your superior officers and take over the [MAIN_SHIP_NAME] at all costs." + +/datum/emergency_call/upp/platoon/friendly + name = "UPP Naval Infantry (Platoon) (Friendly)" + hostility = FALSE + +/datum/emergency_call/upp/platoon/friendly/New() + ..() + arrival_message = "This is UPP dispatch. USS Almayer, We are responding to your distress call, we will render aid as able, do not fire." + objectives = "Render assistance towards the UA Forces, Listen to your superior officers." /obj/effect/landmark/ert_spawns/distress_upp name = "Distress_UPP" diff --git a/code/datums/emergency_calls/upp_commando.dm b/code/datums/emergency_calls/upp_commando.dm index 14c4af46c27b..1bc2b59ba08c 100644 --- a/code/datums/emergency_calls/upp_commando.dm +++ b/code/datums/emergency_calls/upp_commando.dm @@ -1,7 +1,7 @@ //UPP COMMANDOS /datum/emergency_call/upp_commando - name = "UPP Commandos" + name = "UPP Commandos (!DEATHSQUAD!)" mob_max = 6 probability = 0 objectives = "Stealthily assault the ship. Use your silenced weapons, tranquilizers, and night vision to get the advantage on the enemy. Take out the power systems, comms and engine. Stick together and keep a low profile." @@ -51,3 +51,29 @@ addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), H, SPAN_BOLD("Objectives: [objectives]")), 1 SECONDS) +/datum/emergency_call/upp_commando/low_threat + name = "UPP Commandos" + +/datum/emergency_call/upp_commando/create_member(datum/mind/mind, turf/override_spawn_loc) + var/turf/spawn_loc = override_spawn_loc ? override_spawn_loc : get_spawn_point() + + if(!istype(spawn_loc)) + return //Didn't find a useable spawn point. + + var/mob/living/carbon/human/person = new(spawn_loc) + mind.transfer_to(person, TRUE) + + if(!leader && HAS_FLAG(person.client.prefs.toggles_ert, PLAY_LEADER) && check_timelock(person.client, JOB_SQUAD_LEADER, time_required_for_job)) //First one spawned is always the leader. + leader = person + arm_equipment(person, /datum/equipment_preset/upp/commando/leader/low_threat, TRUE, TRUE) + to_chat(person, SPAN_ROLE_HEADER("You are a Commando Team Leader of the Union of Progressive People, a powerful socialist state that rivals the United Americas!")) + else if(medics < max_medics && HAS_FLAG(person.client.prefs.toggles_ert, PLAY_MEDIC) && check_timelock(person.client, JOB_SQUAD_MEDIC, time_required_for_job)) + medics++ + to_chat(person, SPAN_ROLE_HEADER("You are a Commando Medic of the Union of Progressive People, a powerful socialist state that rivals the United Americas!")) + arm_equipment(person, /datum/equipment_preset/upp/commando/medic/low_threat, TRUE, TRUE) + else + to_chat(person, SPAN_ROLE_HEADER("You are a Commando of the Union of Progressive People, a powerful socialist state that rivals the United Americas!")) + arm_equipment(person, /datum/equipment_preset/upp/commando/low_threat, TRUE, TRUE) + print_backstory(person) + + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), person, SPAN_BOLD("Objectives: [objectives]")), 1 SECONDS) diff --git a/code/datums/emergency_calls/whiskey_outpost.dm b/code/datums/emergency_calls/whiskey_outpost.dm index 8a20043da558..436e02007c6c 100644 --- a/code/datums/emergency_calls/whiskey_outpost.dm +++ b/code/datums/emergency_calls/whiskey_outpost.dm @@ -60,7 +60,7 @@ /datum/game_mode/whiskey_outpost/activate_distress() var/datum/emergency_call/em_call = /datum/emergency_call/wo - em_call.activate(FALSE) + em_call.activate(TRUE, FALSE) return /datum/emergency_call/wo/platoon diff --git a/code/datums/factions/upp.dm b/code/datums/factions/upp.dm index 5a790c89be67..90b04765cf85 100644 --- a/code/datums/factions/upp.dm +++ b/code/datums/factions/upp.dm @@ -41,6 +41,8 @@ hud_icon_state = "co" if(JOB_UPP_COMBAT_SYNTH) hud_icon_state = "synth" + if(JOB_UPP_SUPPORT_SYNTH) + hud_icon_state = "synth" if(JOB_UPP_COMMANDO) hud_icon_state = "com" if(JOB_UPP_COMMANDO_MEDIC) diff --git a/code/datums/factions/uscm.dm b/code/datums/factions/uscm.dm index cf77142ce5d6..0a9b0cff40b9 100644 --- a/code/datums/factions/uscm.dm +++ b/code/datums/factions/uscm.dm @@ -189,6 +189,19 @@ if(JOB_CMB_OBS) marine_rk = "obs" icon_prefix = "cmb_" + // Check squad marines here too, for the unique ones + if(JOB_SQUAD_ENGI) + marine_rk = "engi" + if(JOB_SQUAD_MEDIC) + marine_rk = "med" + if(JOB_SQUAD_SPECIALIST) + marine_rk = "spec" + if(JOB_SQUAD_SMARTGUN) + marine_rk = "gun" + if(JOB_SQUAD_TEAM_LEADER) + marine_rk = "tl" + if(JOB_SQUAD_LEADER) + marine_rk = "leader" if(marine_rk) var/image/I = image('icons/mob/hud/marine_hud.dmi', current_human, "hudsquad") diff --git a/code/datums/keybinding/client.dm b/code/datums/keybinding/client.dm index a5baf09a1360..752287882277 100644 --- a/code/datums/keybinding/client.dm +++ b/code/datums/keybinding/client.dm @@ -4,8 +4,8 @@ /datum/keybinding/client/admin_help - hotkey_keys = list("F1") - classic_keys = list("F1") + hotkey_keys = list("Unbound") + classic_keys = list("Unbound") name = "admin_help" full_name = "Admin Help" description = "Ask an admin for help." diff --git a/code/datums/keybinding/communication.dm b/code/datums/keybinding/communication.dm index 4164198d4818..e1ba0ab5a31e 100644 --- a/code/datums/keybinding/communication.dm +++ b/code/datums/keybinding/communication.dm @@ -32,7 +32,7 @@ /datum/keybinding/client/communication/whisper hotkey_keys = list("Unbound") classic_keys = list("Unbound") - name = "Whisper" + name = WHISPER_CHANNEL full_name = "IC Whisper" keybind_signal = COMSIG_KB_CLIENT_WHISPER_DOWN @@ -56,4 +56,4 @@ name = MENTOR_CHANNEL full_name = "Mentor Say" description = "Talk with other mentors." - keybind_signal = COMSIG_KB_ADMIN_ASAY_DOWN + keybind_signal = COMSIG_KB_ADMIN_MENTORSAY_DOWN diff --git a/code/datums/keybinding/human.dm b/code/datums/keybinding/human.dm index 6580c38083ea..6d7037eac398 100644 --- a/code/datums/keybinding/human.dm +++ b/code/datums/keybinding/human.dm @@ -1,8 +1,3 @@ -#define QUICK_EQUIP_PRIMARY 1 -#define QUICK_EQUIP_SECONDARY 2 -#define QUICK_EQUIP_TERTIARY 3 -#define QUICK_EQUIP_QUATERNARY 4 - /datum/keybinding/human category = CATEGORY_HUMAN weight = WEIGHT_MOB @@ -10,86 +5,6 @@ /datum/keybinding/human/can_use(client/user) return ishuman(user.mob) -/datum/keybinding/human/quick_equip - hotkey_keys = list("E") - classic_keys = list("E") - name = "quick_equip" - full_name = "Unholster" - description = "Take out an available weapon" - keybind_signal = COMSIG_KB_HUMAN_QUICKEQUIP_DOWN - -/datum/keybinding/human/quick_equip/down(client/user) - . = ..() - if(.) - return - var/mob/living/carbon/human/H = user.mob - H.holster_verb(QUICK_EQUIP_PRIMARY) - return TRUE - -/datum/keybinding/human/quick_equip_secondary - hotkey_keys = list("Shift+E") - classic_keys = list("Shift+E") - name = "quick_equip_secondary" - full_name = "Unholster secondary" - description = "Take out your secondary weapon" - keybind_signal = COMSIG_KB_HUMAN_SECONDARY_DOWN - -/datum/keybinding/human/quick_equip_secondary/down(client/user) - . = ..() - if(.) - return - var/mob/living/carbon/human/H = user.mob - H.holster_verb(QUICK_EQUIP_SECONDARY) - return TRUE - -/datum/keybinding/human/quick_equip_tertiary - hotkey_keys = list("Ctrl+E", "Alt+E") - classic_keys = list("Ctrl+E", "Alt+E") - name = "quick_equip_tertiary" - full_name = "Unholster tertiary" - description = "Take out your tertiary item." - keybind_signal = COMSIG_KB_HUMAN_TERTIARY_DOWN - -/datum/keybinding/human/quick_equip_tertiary/down(client/user) - . = ..() - if(.) - return - var/mob/living/carbon/human/H = user.mob - H.holster_verb(QUICK_EQUIP_TERTIARY) - return TRUE - -/datum/keybinding/human/quick_equip_quaternary - hotkey_keys = list("Unbound") - classic_keys = list("Unbound") - name = "quick_equip_quaternary" - full_name = "Unholster quaternary" - description = "Take out your quaternary item." - keybind_signal = COMSIG_KB_HUMAN_QUATERNARY_DOWN - -/datum/keybinding/human/quick_equip_quaternary/down(client/user) - . = ..() - if(.) - return - var/mob/living/carbon/human/H = user.mob - H.holster_verb(QUICK_EQUIP_QUATERNARY) - return TRUE - -/datum/keybinding/human/quick_equip_inventory - hotkey_keys = list("Unbound") - classic_keys = list("Unbound") - name = "quick_equip_inventory" - full_name = "Quick equip inventory" - description = "Quickly puts an item in the best slot available" - keybind_signal = COMSIG_KB_HUMAN_QUICK_EQUIP_DOWN - -/datum/keybinding/human/quick_equip_inventory/down(client/user) - . = ..() - if(.) - return - var/mob/living/carbon/human/H = user.mob - H.quick_equip() - return TRUE - /datum/keybinding/human/issue_order hotkey_keys = list("Unbound") classic_keys = list("Unbound") @@ -103,8 +18,8 @@ . = ..() if(.) return - var/mob/living/carbon/human/H = user.mob - H.issue_order(order) + var/mob/living/carbon/human/human_mob = user.mob + human_mob.issue_order(order) return TRUE /datum/keybinding/human/issue_order/move @@ -139,8 +54,8 @@ . = ..() if(.) return - var/mob/living/carbon/human/H = user.mob - H.spec_activation_one() + var/mob/living/carbon/human/human_mob = user.mob + human_mob.spec_activation_one() return TRUE /datum/keybinding/human/specialist_two @@ -154,24 +69,8 @@ . = ..() if(.) return - var/mob/living/carbon/human/H = user.mob - H.spec_activation_two() - return TRUE - -/datum/keybinding/human/pick_up - hotkey_keys = list("F") - classic_keys = list("Unbound") - name = "pick_up" - full_name = "Pick Up Dropped Items" - keybind_signal = COMSIG_KB_HUMAN_PICK_UP - -/datum/keybinding/human/pick_up/down(client/user) - . = ..() - if(.) - return - - var/mob/living/carbon/human/human_user = user.mob - human_user.pickup_recent() + var/mob/living/carbon/human/human_mob = user.mob + human_mob.spec_activation_two() return TRUE /datum/keybinding/human/rotate_chair @@ -209,7 +108,23 @@ shown_item.showoff(human_user) return TRUE -#undef QUICK_EQUIP_PRIMARY -#undef QUICK_EQUIP_SECONDARY -#undef QUICK_EQUIP_TERTIARY -#undef QUICK_EQUIP_QUATERNARY +/datum/keybinding/human/cycle_helmet_hud + hotkey_keys = list("Unbound") + classic_keys = list("Unbound") + name = "cycle_helmet_hud" + full_name = "Cycle Helmet HUD" + keybind_signal = COMSIG_KB_HUMAN_CYCLE_HELMET_HUD + +/datum/keybinding/human/cycle_helmet_hud/down(client/user) + . = ..() + if(.) + return + + var/mob/living/carbon/human/human_user = user.mob + var/obj/item/clothing/head/helmet/marine/marine_helmet = human_user?.head + var/cycled_hud = marine_helmet?.cycle_huds(human_user) + + var/datum/action/item_action/cycle_helmet_huds/cycle_action = locate() in marine_helmet.actions + cycle_action.set_action_overlay(cycled_hud) + + return TRUE diff --git a/code/datums/keybinding/human_combat.dm b/code/datums/keybinding/human_combat.dm index 003fba3b00bd..d30414d68563 100644 --- a/code/datums/keybinding/human_combat.dm +++ b/code/datums/keybinding/human_combat.dm @@ -1,6 +1,5 @@ /datum/keybinding/human/combat category = CATEGORY_HUMAN_COMBAT - weight = WEIGHT_MOB /datum/keybinding/human/combat/can_use(client/user) . = ..() @@ -191,3 +190,20 @@ var/obj/item/weapon/gun/rifle/m46c/COgun = held_item COgun.toggle_iff(human) return TRUE + +/datum/keybinding/human/combat/toggle_shotgun_tube + hotkey_keys = list("Unbound") + classic_keys = list("Unbound") + name = "toggle_shotgun_tube" + full_name = "Toggle Shotgun Tube" + keybind_signal = COMSIG_KB_HUMAN_WEAPON_SHOTGUN_TUBE + +/datum/keybinding/human/combat/toggle_shotgun_tube/down(client/user) + . = ..() + if(.) + return + var/mob/living/carbon/human/human = user.mob + var/obj/item/weapon/gun/shotgun/pump/dual_tube/held_item = human.get_held_item() + if(istype(held_item)) + held_item.toggle_tube() + return TRUE diff --git a/code/datums/keybinding/human_inventory.dm b/code/datums/keybinding/human_inventory.dm new file mode 100644 index 000000000000..163cbccdd5c0 --- /dev/null +++ b/code/datums/keybinding/human_inventory.dm @@ -0,0 +1,244 @@ +/datum/keybinding/human/inventory + category = CATEGORY_HUMAN_INVENTORY + +#define QUICK_EQUIP_PRIMARY 1 +#define QUICK_EQUIP_SECONDARY 2 +#define QUICK_EQUIP_TERTIARY 3 +#define QUICK_EQUIP_QUATERNARY 4 + +/datum/keybinding/human/inventory/quick_equip + hotkey_keys = list("E") + classic_keys = list("E") + name = "quick_equip" + full_name = "Unholster" + description = "Take out an available weapon" + keybind_signal = COMSIG_KB_HUMAN_INTERACT_QUICKEQUIP_DOWN + +/datum/keybinding/human/inventory/quick_equip/down(client/user) + . = ..() + if(.) + return + var/mob/living/carbon/human/human_mob = user.mob + human_mob.holster_verb(QUICK_EQUIP_PRIMARY) + return TRUE + +/datum/keybinding/human/inventory/quick_equip_secondary + hotkey_keys = list("Shift+E") + classic_keys = list("Shift+E") + name = "quick_equip_secondary" + full_name = "Unholster secondary" + description = "Take out your secondary weapon" + keybind_signal = COMSIG_KB_HUMAN_INTERACT_SECONDARY_DOWN + +/datum/keybinding/human/inventory/quick_equip_secondary/down(client/user) + . = ..() + if(.) + return + var/mob/living/carbon/human/human_mob = user.mob + human_mob.holster_verb(QUICK_EQUIP_SECONDARY) + return TRUE + +/datum/keybinding/human/inventory/quick_equip_tertiary + hotkey_keys = list("Ctrl+E", "Alt+E") + classic_keys = list("Ctrl+E", "Alt+E") + name = "quick_equip_tertiary" + full_name = "Unholster tertiary" + description = "Take out your tertiary item." + keybind_signal = COMSIG_KB_HUMAN_INTERACT_TERTIARY_DOWN + +/datum/keybinding/human/inventory/quick_equip_tertiary/down(client/user) + . = ..() + if(.) + return + var/mob/living/carbon/human/human_mob = user.mob + human_mob.holster_verb(QUICK_EQUIP_TERTIARY) + return TRUE + +/datum/keybinding/human/inventory/quick_equip_quaternary + hotkey_keys = list("Unbound") + classic_keys = list("Unbound") + name = "quick_equip_quaternary" + full_name = "Unholster quaternary" + description = "Take out your quaternary item." + keybind_signal = COMSIG_KB_HUMAN_INTERACT_QUATERNARY_DOWN + +/datum/keybinding/human/inventory/quick_equip_quaternary/down(client/user) + . = ..() + if(.) + return + var/mob/living/carbon/human/human_mob = user.mob + human_mob.holster_verb(QUICK_EQUIP_QUATERNARY) + return TRUE + +#undef QUICK_EQUIP_PRIMARY +#undef QUICK_EQUIP_SECONDARY +#undef QUICK_EQUIP_TERTIARY +#undef QUICK_EQUIP_QUATERNARY + +/datum/keybinding/human/inventory/quick_equip_inventory + hotkey_keys = list("Unbound") + classic_keys = list("Unbound") + name = "quick_equip_inventory" + full_name = "Quick equip inventory" + description = "Quickly puts an item in the best slot available" + keybind_signal = COMSIG_KB_HUMAN_INTERACT_QUICK_EQUIP_DOWN + +/datum/keybinding/human/inventory/quick_equip_inventory/down(client/user) + . = ..() + if(.) + return + var/mob/living/carbon/human/human_mob = user.mob + human_mob.quick_equip() + return TRUE + +/datum/keybinding/human/inventory/pick_up + hotkey_keys = list("F") + classic_keys = list("Unbound") + name = "pick_up" + full_name = "Pick Up Dropped Items" + keybind_signal = COMSIG_KB_HUMAN_INTERACT_PICK_UP + +/datum/keybinding/human/inventory/pick_up/down(client/user) + . = ..() + if(.) + return + + var/mob/living/carbon/human/human_user = user.mob + human_user.pickup_recent() + return TRUE + +/datum/keybinding/human/inventory/interact_other_hand + hotkey_keys = list("Unbound") + classic_keys = list("Unbound") + name = "interact_other_hand" + full_name = "Interact With Other Hand" + keybind_signal = COMSIG_KB_HUMAN_INTERACT_OTHER_HAND + +/datum/keybinding/human/inventory/interact_other_hand/down(client/user) + . = ..() + if(.) + return + + var/mob/living/carbon/human/human_user = user.mob + + var/active_hand = human_user.get_active_hand() + var/inactive_hand = human_user.get_inactive_hand() + + if(!inactive_hand) + return + human_user.click_adjacent(inactive_hand, active_hand) + return TRUE + +#define INTERACT_KEYBIND_COOLDOWN_TIME (0.2 SECONDS) +#define COOLDOWN_SLOT_INTERACT_KEYBIND "slot_interact_keybind_cooldown" + +/datum/keybinding/human/inventory/interact_slot + hotkey_keys = list("Unbound") + classic_keys = list("Unbound") + var/storage_slot + +/datum/keybinding/human/inventory/interact_slot/proc/check_slot(mob/living/carbon/human/user) + return + +/datum/keybinding/human/inventory/interact_slot/down(client/user) + . = ..() + if(.) + return + if(!storage_slot) + return + if(TIMER_COOLDOWN_CHECK(src, COOLDOWN_SLOT_INTERACT_KEYBIND)) + return + + TIMER_COOLDOWN_START(src, COOLDOWN_SLOT_INTERACT_KEYBIND, INTERACT_KEYBIND_COOLDOWN_TIME) + var/mob/living/carbon/human/human_user = user.mob + var/obj/item/current_item = check_slot(human_user) + var/obj/item/in_hand_item = human_user.get_active_hand() + + if(in_hand_item) + if(!current_item) + if(!human_user.equip_to_slot_if_possible(in_hand_item, storage_slot, FALSE, FALSE)) + return + return TRUE + + current_item.attackby(in_hand_item, human_user) + return TRUE + + if(!current_item) + return + current_item.attack_hand(human_user) + return TRUE + +/datum/keybinding/human/inventory/interact_slot/back + name = "interact_storage_back" + full_name = "Interact With Back Slot" + keybind_signal = COMSIG_KB_HUMAN_INTERACT_SLOT_BACK + storage_slot = WEAR_BACK + +/datum/keybinding/human/inventory/interact_slot/back/check_slot(mob/living/carbon/human/user) + return user.back + +/datum/keybinding/human/inventory/interact_slot/belt + name = "interact_storage_belt" + full_name = "Interact With Belt Slot" + keybind_signal = COMSIG_KB_HUMAN_INTERACT_SLOT_BELT + storage_slot = WEAR_WAIST + +/datum/keybinding/human/inventory/interact_slot/belt/check_slot(mob/living/carbon/human/user) + return user.belt + +/datum/keybinding/human/inventory/interact_slot/pouch_left + name = "interact_storage_pouch_left" + full_name = "Interact With Left Pouch Slot" + keybind_signal = COMSIG_KB_HUMAN_INTERACT_SLOT_LEFT_POUCH + storage_slot = WEAR_L_STORE + +/datum/keybinding/human/inventory/interact_slot/pouch_left/check_slot(mob/living/carbon/human/user) + return user.l_store + +/datum/keybinding/human/inventory/interact_slot/pouch_right + name = "interact_storage_pouch_right" + full_name = "Interact With Right Pouch Slot" + keybind_signal = COMSIG_KB_HUMAN_INTERACT_SLOT_RIGHT_POUCH + storage_slot = WEAR_R_STORE + +/datum/keybinding/human/inventory/interact_slot/pouch_right/check_slot(mob/living/carbon/human/user) + return user.r_store + +/datum/keybinding/human/inventory/interact_slot/uniform + name = "interact_storage_uniform" + full_name = "Interact With Uniform Slot" + keybind_signal = COMSIG_KB_HUMAN_INTERACT_SLOT_UNIFORM + storage_slot = WEAR_BODY + +/datum/keybinding/human/inventory/interact_slot/uniform/check_slot(mob/living/carbon/human/user) + return user.w_uniform + +/datum/keybinding/human/inventory/interact_slot/suit + name = "interact_storage_suit" + full_name = "Interact With Suit Slot" + keybind_signal = COMSIG_KB_HUMAN_INTERACT_SLOT_SUIT + storage_slot = WEAR_JACKET + +/datum/keybinding/human/inventory/interact_slot/suit/check_slot(mob/living/carbon/human/user) + return user.wear_suit + +/datum/keybinding/human/inventory/interact_slot/helmet + name = "interact_storage_helmet" + full_name = "Interact With Head Slot" + keybind_signal = COMSIG_KB_HUMAN_INTERACT_SLOT_HELMET + storage_slot = WEAR_HEAD + +/datum/keybinding/human/inventory/interact_slot/helmet/check_slot(mob/living/carbon/human/user) + return user.head + +/datum/keybinding/human/inventory/interact_slot/suit_storage + name = "interact_storage_suit_store" + full_name = "Interact With Suit Storage Slot" + keybind_signal = COMSIG_KB_HUMAN_INTERACT_SUIT_S_STORE + storage_slot = WEAR_J_STORE + +/datum/keybinding/human/inventory/interact_slot/suit_storage/check_slot(mob/living/carbon/human/user) + return user.s_store + +#undef INTERACT_KEYBIND_COOLDOWN_TIME +#undef COOLDOWN_SLOT_INTERACT_KEYBIND diff --git a/code/datums/keybinding/yautja.dm b/code/datums/keybinding/yautja.dm index 40ffbf8d16e7..4729db004582 100644 --- a/code/datums/keybinding/yautja.dm +++ b/code/datums/keybinding/yautja.dm @@ -594,3 +594,21 @@ var/mob/living/carbon/human/H = user.mob var/obj/item/device/yautja_teleporter/tele = locate(/obj/item/device/yautja_teleporter) in H.contents tele.add_tele_loc() + + +/datum/keybinding/yautja/fold_combi + hotkey_keys = list("Space") + classic_keys = list("Unbound") + name = "fold_combi" + full_name = "Collapse Combi-stick" + keybind_signal = COMSIG_KB_YAUTJA_FOLD_COMBISTICK + +/datum/keybinding/yautja/fold_combi/down(client/user) + . = ..() + if(.) + return + var/mob/living/carbon/human/human = user.mob + var/obj/item/weapon/yautja/combistick/held_item = human.get_held_item() + if(istype(held_item)) + held_item.fold_combistick() + return TRUE diff --git a/code/datums/langchat/langchat.dm b/code/datums/langchat/langchat.dm index d1a6adafa2f3..83b9be0ac053 100644 --- a/code/datums/langchat/langchat.dm +++ b/code/datums/langchat/langchat.dm @@ -13,7 +13,6 @@ #define LANGCHAT_LONGEST_TEXT 64 #define LANGCHAT_WIDTH 96 -#define LANGCHAT_X_OFFSET -32 #define LANGCHAT_MAX_ALPHA 196 //pop defines @@ -48,6 +47,13 @@ M.client.images -= langchat_image langchat_listeners = null +/atom/proc/langchat_set_x_offset() + langchat_image.maptext_x = world.icon_size / 2 - langchat_image.maptext_width / 2 +/atom/movable/langchat_set_x_offset() + langchat_image.maptext_x = bound_width / 2 - langchat_image.maptext_width / 2 +/mob/langchat_set_x_offset() + langchat_image.maptext_x = icon_size / 2 - langchat_image.maptext_width / 2 + ///Creates the image if one does not exist, resets settings that are modified by speech procs. /atom/proc/langchat_make_image(override_color = null) if(!langchat_image) @@ -57,8 +63,8 @@ langchat_image.appearance_flags = NO_CLIENT_COLOR|KEEP_APART|RESET_COLOR|RESET_TRANSFORM langchat_image.maptext_y = langchat_height langchat_image.maptext_height = 64 - langchat_image.maptext_x = LANGCHAT_X_OFFSET langchat_image.maptext_y -= LANGCHAT_MESSAGE_POP_Y_SINK + langchat_set_x_offset() langchat_image.pixel_y = 0 langchat_image.alpha = 0 @@ -103,6 +109,7 @@ langchat_image.maptext = text_to_display langchat_image.maptext_width = LANGCHAT_WIDTH + langchat_set_x_offset() langchat_listeners = listeners for(var/mob/M in langchat_listeners) @@ -149,6 +156,7 @@ langchat_image.maptext = text_to_display langchat_image.maptext_width = LANGCHAT_WIDTH * 2 + langchat_set_x_offset() langchat_listeners = listeners for(var/mob/M in langchat_listeners) diff --git a/code/datums/map_config.dm b/code/datums/map_config.dm index 1f3c265ead76..3bf5c601cec9 100644 --- a/code/datums/map_config.dm +++ b/code/datums/map_config.dm @@ -87,12 +87,14 @@ /datum/equipment_preset/synth/survivor/janitor_synth, /datum/equipment_preset/synth/survivor/chef_synth, /datum/equipment_preset/synth/survivor/teacher_synth, + /datum/equipment_preset/synth/survivor/freelancer_synth, + /datum/equipment_preset/synth/survivor/trucker_synth, /datum/equipment_preset/synth/survivor/bartender_synth, /datum/equipment_preset/synth/survivor/detective_synth, /datum/equipment_preset/synth/survivor/cmb_synth, - /datum/equipment_preset/synth/survivor/security_synth, - /datum/equipment_preset/synth/survivor/protection_synth, - /datum/equipment_preset/synth/survivor/corporate_synth, + /datum/equipment_preset/synth/survivor/wy/security_synth, + /datum/equipment_preset/synth/survivor/wy/protection_synth, + /datum/equipment_preset/synth/survivor/wy/corporate_synth, /datum/equipment_preset/synth/survivor/radiation_synth, ) diff --git a/code/datums/mind.dm b/code/datums/mind.dm index bdeb60c4ae98..ff68fc05256b 100644 --- a/code/datums/mind.dm +++ b/code/datums/mind.dm @@ -29,9 +29,14 @@ research_objective_interface = new() /datum/mind/Destroy() + QDEL_NULL(initial_account) QDEL_NULL(objective_memory) QDEL_NULL(objective_interface) QDEL_NULL(research_objective_interface) + current = null + original = null + ghost_mob = null + player_entity = null return ..() /datum/mind/proc/transfer_to(mob/living/new_character, force = FALSE) diff --git a/code/datums/mob_hud.dm b/code/datums/mob_hud.dm index 65c5a47896fa..b0df9bca7745 100644 --- a/code/datums/mob_hud.dm +++ b/code/datums/mob_hud.dm @@ -798,7 +798,7 @@ var/global/image/hud_icon_hudfocus tag_holder.overlays += image('icons/mob/hud/hud.dmi', src, "prae_tag") // Hacky, but works. Currently effects are hard to make with precise timings - var/freeze_found = frozen + var/freeze_found = HAS_TRAIT(src, TRAIT_IMMOBILIZED) && !buckled && !lying if (freeze_found) freeze_holder.overlays += image('icons/mob/hud/hud.dmi', src, "xeno_freeze") diff --git a/code/datums/quadtree.dm b/code/datums/quadtree.dm index d00f202cc15c..2b0360152997 100644 --- a/code/datums/quadtree.dm +++ b/code/datums/quadtree.dm @@ -10,14 +10,14 @@ var/z_level /// Don't divide further when truthy - var/final + var/final_divide = FALSE /datum/quadtree/New(datum/shape/rectangle/rect, z) . = ..() boundary = rect z_level = z if(boundary.width <= QUADTREE_BOUNDARY_MINIMUM_WIDTH || boundary.height <= QUADTREE_BOUNDARY_MINIMUM_HEIGHT) - final = TRUE + final_divide = TRUE // By design i guess, discarding branch discards rest with BYOND soft-GCing // There should never be anything else but SSquadtree referencing quadtrees, @@ -103,7 +103,7 @@ player_coords = list(p_coords) return TRUE - else if(!final && player_coords.len >= QUADTREE_CAPACITY) + else if(!final_divide && player_coords.len >= QUADTREE_CAPACITY) if(!is_divided) subdivide() if(nw_branch.insert_player(p_coords)) diff --git a/code/datums/shuttles.dm b/code/datums/shuttles.dm index eb1fd2341920..98bcf296755b 100644 --- a/code/datums/shuttles.dm +++ b/code/datums/shuttles.dm @@ -100,6 +100,18 @@ if(movement_force) M.movement_force = movement_force.Copy() + /datum/map_template/shuttle/vehicle shuttle_id = MOBILE_SHUTTLE_VEHICLE_ELEVATOR name = "Vehicle Elevator" + +/datum/map_template/shuttle/trijent_elevator + name = "Trijent Elevator" + shuttle_id = MOBILE_TRIJENT_ELEVATOR + var/elevator_network + +/datum/map_template/shuttle/trijent_elevator/A + elevator_network = "A" + +/datum/map_template/shuttle/trijent_elevator/B + elevator_network = "B" diff --git a/code/datums/skills.dm b/code/datums/skills.dm deleted file mode 100644 index 9178e6f7a1b1..000000000000 --- a/code/datums/skills.dm +++ /dev/null @@ -1,2199 +0,0 @@ -// Individual skill -/datum/skill - /// Name of the skill - var/skill_name = null - /// used for the view UI - var/readable_skill_name = null - /// Level of skill in this... skill - var/skill_level = 0 - /// the max level this skill can be, used for tgui - var/max_skill_level = 0 - -/datum/skill/proc/get_skill_level() - return skill_level - -/datum/skill/proc/set_skill(new_level, mob/owner) - skill_level = new_level - -/datum/skill/proc/is_skilled(req_level, is_explicit = FALSE) - if(is_explicit) - return (skill_level == req_level) - return (skill_level >= req_level) - -// Lots of defines here. See #define/skills.dm - -/datum/skill/cqc - skill_name = SKILL_CQC - readable_skill_name = "CQC" - skill_level = SKILL_CQC_DEFAULT - max_skill_level = SKILL_CQC_MAX - -/datum/skill/melee_weapons - skill_name = SKILL_MELEE_WEAPONS - readable_skill_name = "melee weapons" - skill_level = SKILL_MELEE_DEFAULT - max_skill_level = SKILL_MELEE_MAX - -/datum/skill/firearms - skill_name = SKILL_FIREARMS - skill_level = SKILL_FIREARMS_TRAINED - max_skill_level = SKILL_FIREARMS_MAX - -/datum/skill/spec_weapons - skill_name = SKILL_SPEC_WEAPONS - readable_skill_name = "specialist weapons" - skill_level = SKILL_SPEC_DEFAULT - max_skill_level = SKILL_SPEC_ALL - -/datum/skill/endurance - skill_name = SKILL_ENDURANCE - skill_level = SKILL_ENDURANCE_WEAK - max_skill_level = SKILL_ENDURANCE_MAX - -/datum/skill/engineer - skill_name = SKILL_ENGINEER - skill_level = SKILL_ENGINEER_DEFAULT - max_skill_level = SKILL_ENGINEER_MAX - -/datum/skill/construction - skill_name = SKILL_CONSTRUCTION - skill_level = SKILL_CONSTRUCTION_DEFAULT - max_skill_level = SKILL_CONSTRUCTION_MAX - -/datum/skill/leadership - skill_name = SKILL_LEADERSHIP - skill_level = SKILL_LEAD_NOVICE - max_skill_level = SKILL_LEAD_MAX - -/datum/skill/leadership/set_skill(new_level, mob/living/owner) - ..() - if(!owner) - return - - if(!ishuman(owner)) - return - - // Give/remove issue order actions - if(is_skilled(SKILL_LEAD_TRAINED)) - ADD_TRAIT(owner, TRAIT_LEADERSHIP, TRAIT_SOURCE_SKILL(skill_name)) - else - REMOVE_TRAIT(owner, TRAIT_LEADERSHIP, TRAIT_SOURCE_SKILL(skill_name)) - -/datum/skill/overwatch - skill_name = SKILL_OVERWATCH - skill_level = SKILL_OVERWATCH_DEFAULT - max_skill_level = SKILL_OVERWATCH_MAX - -/datum/skill/medical - skill_name = SKILL_MEDICAL - skill_level = SKILL_MEDICAL_DEFAULT - max_skill_level = SKILL_MEDICAL_MAX - -/datum/skill/surgery - skill_name = SKILL_SURGERY - skill_level = SKILL_SURGERY_DEFAULT - max_skill_level = SKILL_SURGERY_MAX - -/datum/skill/surgery/set_skill(new_level, mob/living/owner) - ..() - if(!owner) - return - - if(!ishuman(owner)) - return - - // Give/remove surgery toggle action - var/datum/action/surgery_toggle/surgery_action = locate() in owner.actions - if(is_skilled(SKILL_SURGERY_NOVICE)) - if(!surgery_action) - give_action(owner, /datum/action/surgery_toggle) - else - surgery_action.update_surgery_skill() - else - if(surgery_action) - surgery_action.remove_from(owner) - -/datum/skill/research - skill_name = SKILL_RESEARCH - skill_level = SKILL_RESEARCH_DEFAULT - max_skill_level = SKILL_RESEARCH_MAX - -/datum/skill/antag - skill_name = SKILL_ANTAG - readable_skill_name = "illegal technology" - skill_level = SKILL_ANTAG_DEFAULT - max_skill_level = SKILL_ANTAG_MAX - -/datum/skill/pilot - skill_name = SKILL_PILOT - skill_level = SKILL_PILOT_DEFAULT - max_skill_level = SKILL_PILOT_MAX - -/datum/skill/navigations - skill_name = SKILL_NAVIGATIONS - skill_level = SKILL_NAVIGATIONS_DEFAULT - max_skill_level = SKILL_NAVIGATIONS_MAX - -/datum/skill/police - skill_name = SKILL_POLICE - skill_level = SKILL_POLICE_DEFAULT - max_skill_level = SKILL_POLICE_MAX - -/datum/skill/powerloader - skill_name = SKILL_POWERLOADER - skill_level = SKILL_POWERLOADER_DEFAULT - max_skill_level = SKILL_POWERLOADER_MAX - -/datum/skill/vehicles - skill_name = SKILL_VEHICLE - skill_level = SKILL_VEHICLE_DEFAULT - max_skill_level = SKILL_VEHICLE_MAX - -/datum/skill/jtac - skill_name = SKILL_JTAC - readable_skill_name = "JTAC" - skill_level = SKILL_JTAC_NOVICE - max_skill_level = SKILL_JTAC_MAX - -/datum/skill/execution - skill_name = SKILL_EXECUTION - skill_level = SKILL_EXECUTION_DEFAULT - max_skill_level = SKILL_EXECUTION_MAX - -/datum/skill/intel - skill_name = SKILL_INTEL - skill_level = SKILL_INTEL_NOVICE - max_skill_level = SKILL_INTEL_MAX - -/datum/skill/domestic - skill_name = SKILL_DOMESTIC - skill_level = SKILL_DOMESTIC_NONE - max_skill_level = SKILL_DOMESTIC_MAX - -/datum/skill/fireman - skill_name = SKILL_FIREMAN - readable_skill_name = "fireman carrying" - skill_level = SKILL_FIREMAN_DEFAULT - max_skill_level = SKILL_FIREMAN_MAX - -/// Skill with an extra S at the end is a collection of multiple skills. Basically a skillSET -/// This is to organize and provide a common interface to the huge heap of skills there are -/datum/skills - /// The name of the skillset - var/name - // The mob that has this skillset - var/mob/owner - - // List of skill datums. - // Also, if this is populated when the datum is created, it will set the skill levels automagically - var/list/skills = list() - // Same as above, but for children of parents that just add a lil something else - var/list/additional_skills = list() - -/datum/skills/New(mob/skillset_owner) - owner = skillset_owner - - // Setup every single skill - for(var/skill_type in subtypesof(/datum/skill)) - var/datum/skill/S = new skill_type() - - // Fancy hack to convert a list of desired skill levels in each named skill into a skill level in the actual skill datum - // Lets the skills list be used multipurposely for both storing skill datums and choosing skill levels for different skillsets - var/predetermined_skill_level = additional_skills[S.skill_name] ? additional_skills[S.skill_name] : skills[S.skill_name] - skills[S.skill_name] = S - - if(!isnull(predetermined_skill_level)) - S.set_skill(predetermined_skill_level, owner) - -/datum/skills/Destroy() - owner = null - skills = null // Don't need to delete, /datum/skill should softdel - SStgui.close_uis(src) - return ..() - -// Checks if the given skill is contained in this skillset at all -/datum/skills/proc/has_skill(skill) - return isnull(skills[skill]) - -// Returns the skill DATUM for the given skill -/datum/skills/proc/get_skill(skill) - if(!skills) - return null - return skills[skill] - -// Returns the skill level for the given skill -/datum/skills/proc/get_skill_level(skill) - var/datum/skill/S = get_skill(skill) - if(!S) - return -1 - if(QDELETED(S)) - return -1 - return S.get_skill_level() - -// Sets the skill LEVEL for a given skill -/datum/skills/proc/set_skill(skill, new_level) - var/datum/skill/S = skills[skill] - if(!S) - return - return S.set_skill(new_level, owner) - -/datum/skills/proc/increment_skill(skill, increment, cap) - var/datum/skill/S = skills[skill] - if(!S || skillcheck(owner, skill, cap)) - return - return S.set_skill(min(cap,S.skill_level+increment), owner) - -/datum/skills/proc/decrement_skill(skill, increment) - var/datum/skill/S = skills[skill] - if(!S) - return - return S.set_skill(max(0,S.skill_level-increment), owner) - -// Checks if the skillset is AT LEAST skilled enough to pass a skillcheck for the given skill level -/datum/skills/proc/is_skilled(skill, req_level, is_explicit = FALSE) - var/datum/skill/S = get_skill(skill) - if(QDELETED(S)) - return FALSE - return S.is_skilled(req_level, is_explicit) - -// Adjusts the full skillset to a new type of skillset. Pass the datum type path for the desired skillset -/datum/skills/proc/set_skillset(skillset_type) - var/datum/skills/skillset = new skillset_type() - var/list/skill_levels = initial(skillset.skills) - - name = skillset.name - for(var/skill in skill_levels) - set_skill(skill, skill_levels[skill]) - qdel(skillset) - -/* ---------------------- -CIVILIAN ---------------------- -*/ - -/datum/skills/civilian - name = "Civilian" - skills = list( - SKILL_CQC = SKILL_CQC_DEFAULT, - SKILL_FIREARMS = SKILL_FIREARMS_CIVILIAN, - SKILL_ENDURANCE = SKILL_ENDURANCE_NONE, - SKILL_VEHICLE = SKILL_VEHICLE_SMALL, - ) - -/datum/skills/civilian/manager - name = "Weyland-Yutani Manager" // Semi-competent leader with basic knowledge in most things. - skills = list( - SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED, - SKILL_LEADERSHIP = SKILL_LEAD_MASTER, - SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED, - SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, - SKILL_ENGINEER = SKILL_ENGINEER_TRAINED, - SKILL_VEHICLE = SKILL_VEHICLE_SMALL, - SKILL_INTEL = SKILL_INTEL_EXPERT, - ) - -/datum/skills/civilian/icc_investigation - name = "ICC CL - Black Market ERT" - skills = list( - SKILL_CQC = SKILL_CQC_DEFAULT, - SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED, - SKILL_ENGINEER = SKILL_ENGINEER_ENGI, //The ASRS consoles - SKILL_FIREARMS = SKILL_FIREARMS_CIVILIAN, - SKILL_POLICE = SKILL_POLICE_SKILLED, //The CMB Tradeband Compliance Device - ) - -/datum/skills/civilian/manager/director - name = "Weyland-Yutani Director" - skills = list( - SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED, - SKILL_LEADERSHIP = SKILL_LEAD_MASTER, - SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED, - SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, - SKILL_ENGINEER = SKILL_ENGINEER_TRAINED, - SKILL_VEHICLE = SKILL_VEHICLE_SMALL, - SKILL_POLICE = SKILL_POLICE_SKILLED, - SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, - SKILL_EXECUTION = SKILL_EXECUTION_TRAINED, - SKILL_INTEL = SKILL_INTEL_EXPERT, - ) - -/datum/skills/civilian/survivor - name = "Survivor" - skills = list( - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED, - SKILL_ENDURANCE = SKILL_ENDURANCE_SURVIVOR, - ) - -/datum/skills/civilian/survivor/manager - name = "Weyland-Yutani Manager" - skills = list( - SKILL_LEADERSHIP = SKILL_LEAD_MASTER, - SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED, - SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, - SKILL_INTEL = SKILL_INTEL_EXPERT, - ) - -/datum/skills/civilian/survivor/goon - name = "Survivor Goon" - skills = list( - SKILL_CQC = SKILL_CQC_TRAINED, - SKILL_POLICE = SKILL_POLICE_SKILLED, - SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, - SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, - SKILL_ENDURANCE = SKILL_ENDURANCE_SURVIVOR, - SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, - SKILL_VEHICLE = SKILL_VEHICLE_SMALL, - ) - -/datum/skills/civilian/survivor/pmc - name = "Survivor PMC" - additional_skills = list( - SKILL_CQC = SKILL_CQC_TRAINED, - SKILL_POLICE = SKILL_POLICE_SKILLED, - SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, - SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, - SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, - SKILL_VEHICLE = SKILL_VEHICLE_SMALL, - ) - -/datum/skills/civilian/survivor/pmc/medic - name = "Survivor PMC Medic" - additional_skills = list( - SKILL_POLICE = SKILL_POLICE_SKILLED, - SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, - SKILL_MEDICAL = SKILL_MEDICAL_MEDIC, - SKILL_SURGERY = SKILL_SURGERY_NOVICE, - SKILL_ENDURANCE = SKILL_ENDURANCE_SURVIVOR, - SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, - SKILL_VEHICLE = SKILL_VEHICLE_SMALL, - ) - -/datum/skills/civilian/survivor/pmc/engineer - name = "Survivor PMC Engineer" - additional_skills = list( - SKILL_POLICE = SKILL_POLICE_SKILLED, - SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, - SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, - SKILL_ENDURANCE = SKILL_ENDURANCE_SURVIVOR, - SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, - SKILL_VEHICLE = SKILL_VEHICLE_SMALL, - SKILL_ENGINEER = SKILL_ENGINEER_ENGI, - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, - SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER, - ) - -/datum/skills/civilian/survivor/doctor - name = "Survivor Doctor" - additional_skills = list( - SKILL_MEDICAL = SKILL_MEDICAL_DOCTOR, - SKILL_SURGERY = SKILL_SURGERY_TRAINED, - ) - -/datum/skills/civilian/survivor/clf - name = "Survivor CLF" - additional_skills = list( - SKILL_ENGINEER = SKILL_ENGINEER_TRAINED, - SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, - SKILL_VEHICLE = SKILL_VEHICLE_SMALL, - SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, - ) - -/datum/skills/civilian/survivor/scientist - name = "Survivor Scientist" - additional_skills = list( - SKILL_MEDICAL = SKILL_MEDICAL_DOCTOR, - SKILL_SURGERY = SKILL_SURGERY_TRAINED, - SKILL_RESEARCH = SKILL_RESEARCH_TRAINED, - ) - -/datum/skills/civilian/survivor/chef - name = "Survivor Chef" - additional_skills = list( - SKILL_MELEE_WEAPONS = SKILL_MELEE_SUPER, - SKILL_DOMESTIC = SKILL_DOMESTIC_TRAINED, - ) - -/datum/skills/civilian/survivor/miner - name = "Survivor Miner" - additional_skills = list( - SKILL_ENGINEER = SKILL_ENGINEER_TRAINED, - SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER, - SKILL_VEHICLE = SKILL_VEHICLE_SMALL, - ) - -/datum/skills/civilian/survivor/trucker - name = "Survivor Trucker" - additional_skills = list( - SKILL_ENGINEER = SKILL_ENGINEER_ENGI, - SKILL_VEHICLE = SKILL_VEHICLE_CREWMAN, - ) - -/datum/skills/civilian/survivor/engineer - name = "Survivor Engineer" - additional_skills = list( - SKILL_ENGINEER = SKILL_ENGINEER_ENGI, - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, - SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER, - SKILL_VEHICLE = SKILL_VEHICLE_SMALL, - ) - -/datum/skills/civilian/survivor/chaplain - name = "Survivor Chaplain" - additional_skills = list( - SKILL_LEADERSHIP = SKILL_LEAD_TRAINED, - ) - -/datum/skills/civilian/survivor/marshal - name = "Survivor Marshal" - skills = list( - SKILL_ENGINEER = SKILL_ENGINEER_ENGI, - SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED, - SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, - SKILL_ENDURANCE = SKILL_ENDURANCE_SURVIVOR, - SKILL_CQC = SKILL_CQC_SKILLED, - SKILL_FIREARMS = SKILL_FIREARMS_TRAINED, - SKILL_POLICE = SKILL_POLICE_SKILLED, - SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, - SKILL_ENGINEER = SKILL_ENGINEER_TRAINED, - SKILL_CQC = SKILL_CQC_SKILLED, - SKILL_FIREARMS = SKILL_FIREARMS_TRAINED, - ) - -/datum/skills/civilian/survivor/prisoner - name = "Survivor Prisoner" - additional_skills = list( - SKILL_CQC = SKILL_CQC_SKILLED, - SKILL_FIREARMS = SKILL_FIREARMS_TRAINED, - SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, - SKILL_VEHICLE = SKILL_VEHICLE_SMALL, - ) - -/datum/skills/civilian/survivor/gangleader - name = "Survivor Gang Leader" - additional_skills = list( - SKILL_CQC = SKILL_CQC_SKILLED, - SKILL_FIREARMS = SKILL_FIREARMS_TRAINED, - SKILL_LEADERSHIP = SKILL_LEAD_TRAINED, - ) - -/* ---------------------- -MILITARY SURVIVORS ---------------------- -*/ -//Hardcore survivors with poor equipment and skills, prove you're the best of the best. - -/datum/skills/military/survivor/forecon_standard - name = "Reconnaissance Rifleman" - skills = list( - SKILL_ENGINEER = SKILL_ENGINEER_ENGI, - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_DEFAULT, - SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, - SKILL_CQC = SKILL_CQC_TRAINED, - SKILL_FIREARMS = SKILL_FIREARMS_TRAINED, - SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, - SKILL_ENDURANCE = SKILL_ENDURANCE_SURVIVOR, - SKILL_LEADERSHIP = SKILL_LEAD_NOVICE, - SKILL_VEHICLE = SKILL_VEHICLE_DEFAULT, - SKILL_JTAC = SKILL_JTAC_TRAINED, - ) - -/datum/skills/military/survivor/forecon_techician - name = "Reconnaissance Support Technician" - skills = list( - SKILL_ENGINEER = SKILL_ENGINEER_ENGI, - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, - SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, - SKILL_CQC = SKILL_CQC_TRAINED, - SKILL_FIREARMS = SKILL_FIREARMS_TRAINED, - SKILL_MEDICAL = SKILL_MEDICAL_MEDIC, - SKILL_SURGERY = SKILL_SURGERY_NOVICE, - SKILL_ENDURANCE = SKILL_ENDURANCE_SURVIVOR, - SKILL_LEADERSHIP = SKILL_LEAD_NOVICE, - SKILL_VEHICLE = SKILL_VEHICLE_DEFAULT, - SKILL_JTAC = SKILL_JTAC_TRAINED, - ) - -/datum/skills/military/survivor/forecon_marksman - name = "Reconnaissance Designated Marksman" - skills = list( - SKILL_ENGINEER = SKILL_ENGINEER_ENGI, - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_DEFAULT, - SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, - SKILL_CQC = SKILL_CQC_TRAINED, - SKILL_FIREARMS = SKILL_FIREARMS_TRAINED, - SKILL_SPEC_WEAPONS = SKILL_SPEC_SCOUT, - SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, - SKILL_ENDURANCE = SKILL_ENDURANCE_SURVIVOR, - SKILL_LEADERSHIP = SKILL_LEAD_NOVICE, - SKILL_VEHICLE = SKILL_VEHICLE_DEFAULT, - SKILL_JTAC = SKILL_JTAC_TRAINED, - ) - -/datum/skills/military/survivor/forecon_smartgunner - name = "Reconnaissance Smartgunner" - skills = list( - SKILL_ENGINEER = SKILL_ENGINEER_ENGI, - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_DEFAULT, - SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, - SKILL_CQC = SKILL_CQC_TRAINED, - SKILL_FIREARMS = SKILL_FIREARMS_TRAINED, - SKILL_SPEC_WEAPONS = SKILL_SPEC_SMARTGUN, - SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, - SKILL_ENDURANCE = SKILL_ENDURANCE_SURVIVOR, - SKILL_LEADERSHIP = SKILL_LEAD_NOVICE, - SKILL_VEHICLE = SKILL_VEHICLE_DEFAULT, - SKILL_JTAC = SKILL_JTAC_TRAINED, - ) - -/datum/skills/military/survivor/forecon_sniper - name = "Reconnaissance Sniper" - skills = list( - SKILL_ENGINEER = SKILL_ENGINEER_ENGI, - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_DEFAULT, - SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, - SKILL_CQC = SKILL_CQC_TRAINED, - SKILL_FIREARMS = SKILL_FIREARMS_TRAINED, - SKILL_SPEC_WEAPONS = SKILL_SPEC_SNIPER, - SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, - SKILL_ENDURANCE = SKILL_ENDURANCE_SURVIVOR, - SKILL_LEADERSHIP = SKILL_LEAD_NOVICE, - SKILL_VEHICLE = SKILL_VEHICLE_DEFAULT, - SKILL_JTAC = SKILL_JTAC_TRAINED, - ) - -/datum/skills/military/survivor/forecon_squad_leader - name = "Reconnaissance Squad Leader" - skills = list( - SKILL_ENGINEER = SKILL_ENGINEER_ENGI, - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_DEFAULT, - SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, - SKILL_CQC = SKILL_CQC_SKILLED, - SKILL_FIREARMS = SKILL_FIREARMS_TRAINED, - SKILL_POLICE = SKILL_POLICE_SKILLED, - SKILL_JTAC = SKILL_JTAC_TRAINED, - SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, - SKILL_ENDURANCE = SKILL_ENDURANCE_SURVIVOR, - SKILL_LEADERSHIP = SKILL_LEAD_TRAINED, - SKILL_VEHICLE = SKILL_VEHICLE_DEFAULT, - SKILL_JTAC = SKILL_JTAC_TRAINED, - ) - -/* ---------------------- -COMMAND STAFF ---------------------- -*/ - -/datum/skills/general - name = "General" - skills = list( - SKILL_CQC = SKILL_CQC_TRAINED, - SKILL_ENGINEER = SKILL_ENGINEER_ENGI, - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, - SKILL_LEADERSHIP = SKILL_LEAD_MASTER, - SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED, - SKILL_MEDICAL = SKILL_MEDICAL_DOCTOR, - SKILL_POLICE = SKILL_POLICE_SKILLED, - SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, - SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER, - SKILL_ENDURANCE = SKILL_ENDURANCE_MAX, - SKILL_JTAC = SKILL_JTAC_MASTER, - SKILL_SPEC_WEAPONS = SKILL_SPEC_ALL, - SKILL_EXECUTION = SKILL_EXECUTION_TRAINED, //can BE people - SKILL_INTEL = SKILL_INTEL_EXPERT - ) - -/datum/skills/commander - name = "Commanding Officer" - skills = list( - SKILL_ENGINEER = SKILL_ENGINEER_ENGI, - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, - SKILL_LEADERSHIP = SKILL_LEAD_MASTER, - SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED, - SKILL_MEDICAL = SKILL_MEDICAL_DOCTOR, - SKILL_SURGERY = SKILL_SURGERY_NOVICE, - SKILL_POLICE = SKILL_POLICE_SKILLED, - SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, - SKILL_VEHICLE = SKILL_VEHICLE_SMALL, - SKILL_CQC = SKILL_CQC_SKILLED, - SKILL_SPEC_WEAPONS = SKILL_SPEC_SMARTGUN, - SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER, - SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED, - SKILL_JTAC = SKILL_JTAC_MASTER, - SKILL_EXECUTION = SKILL_EXECUTION_TRAINED, //can BE people - SKILL_INTEL = SKILL_INTEL_EXPERT, - SKILL_NAVIGATIONS = SKILL_NAVIGATIONS_TRAINED //can change ship alt - ) - -/datum/skills/XO - name = "Executive Officer" - skills = list( - SKILL_ENGINEER = SKILL_ENGINEER_ENGI, //to fix CIC apc. - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, - SKILL_LEADERSHIP = SKILL_LEAD_MASTER, - SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED, - SKILL_MEDICAL = SKILL_MEDICAL_DOCTOR, - SKILL_SURGERY = SKILL_SURGERY_NOVICE, - SKILL_POLICE = SKILL_POLICE_FLASH, - SKILL_VEHICLE = SKILL_VEHICLE_SMALL, - SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, - SKILL_CQC = SKILL_CQC_SKILLED, - SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER, - SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED, - SKILL_JTAC = SKILL_JTAC_MASTER, - SKILL_INTEL = SKILL_INTEL_EXPERT, - SKILL_NAVIGATIONS = SKILL_NAVIGATIONS_TRAINED, - ) - -/datum/skills/SO - name = "Staff Officer" - skills = list( - SKILL_ENGINEER = SKILL_ENGINEER_ENGI, - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, - SKILL_LEADERSHIP = SKILL_LEAD_EXPERT, - SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED, - SKILL_MEDICAL = SKILL_MEDICAL_MEDIC, - SKILL_POLICE = SKILL_POLICE_FLASH, - SKILL_FIREMAN = SKILL_FIREMAN_TRAINED, - SKILL_VEHICLE = SKILL_VEHICLE_SMALL, - SKILL_POWERLOADER = SKILL_POWERLOADER_TRAINED, - SKILL_JTAC = SKILL_JTAC_EXPERT, - SKILL_INTEL = SKILL_INTEL_TRAINED, - ) - -/datum/skills/SEA - name = "Senior Enlisted Advisor" - skills = list( - SKILL_CQC = SKILL_CQC_SKILLED, - SKILL_ENGINEER = SKILL_ENGINEER_ENGI, - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, - SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, - SKILL_LEADERSHIP = SKILL_LEAD_EXPERT, - SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED, - SKILL_MEDICAL = SKILL_MEDICAL_DOCTOR, - SKILL_SURGERY = SKILL_SURGERY_TRAINED, - SKILL_RESEARCH = SKILL_RESEARCH_TRAINED, - SKILL_PILOT = SKILL_PILOT_EXPERT, - SKILL_POLICE = SKILL_POLICE_SKILLED, - SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, - SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER, - SKILL_VEHICLE = SKILL_VEHICLE_LARGE, - SKILL_JTAC = SKILL_JTAC_EXPERT, - SKILL_INTEL = SKILL_INTEL_EXPERT, - SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED, - ) - -/datum/skills/SEA/New(mob/skillset_owner) - ..() - give_action(skillset_owner, /datum/action/looc_toggle) - -/datum/skills/SEA/Destroy() - remove_action(owner, /datum/action/looc_toggle) - return ..() - -/datum/skills/CMO - name = "CMO" - skills = list( - SKILL_FIREARMS = SKILL_FIREARMS_CIVILIAN, - SKILL_LEADERSHIP = SKILL_LEAD_EXPERT, - SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED, - SKILL_MEDICAL = SKILL_MEDICAL_DOCTOR, - SKILL_SURGERY = SKILL_SURGERY_TRAINED, - SKILL_RESEARCH = SKILL_RESEARCH_TRAINED, - SKILL_POLICE = SKILL_POLICE_FLASH, - SKILL_FIREMAN = SKILL_FIREMAN_TRAINED, - SKILL_JTAC = SKILL_JTAC_EXPERT, - SKILL_INTEL = SKILL_INTEL_TRAINED, - ) - -/datum/skills/CMP - name = "Chief MP" - skills = list( - SKILL_CQC = SKILL_CQC_SKILLED, - SKILL_POLICE = SKILL_POLICE_SKILLED, - SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, - SKILL_LEADERSHIP = SKILL_LEAD_EXPERT, - SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED, - SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED, - SKILL_JTAC = SKILL_JTAC_EXPERT, - SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, - SKILL_ENGINEER = SKILL_ENGINEER_ENGI, - SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, - SKILL_INTEL = SKILL_INTEL_TRAINED, - ) - -/datum/skills/auxiliary_officer - name = "Auxiliary Support Officer" - skills = list( - SKILL_PILOT = SKILL_PILOT_EXPERT, - SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER, - SKILL_LEADERSHIP = SKILL_LEAD_MASTER, - SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED, - SKILL_MEDICAL = SKILL_MEDICAL_MEDIC, - SKILL_SURGERY = SKILL_SURGERY_NOVICE, - SKILL_JTAC = SKILL_JTAC_EXPERT, - SKILL_INTEL = SKILL_INTEL_EXPERT, - SKILL_VEHICLE = SKILL_VEHICLE_SMALL, - SKILL_ENGINEER = SKILL_ENGINEER_ENGI, - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, - SKILL_POLICE = SKILL_POLICE_FLASH, - SKILL_NAVIGATIONS = SKILL_NAVIGATIONS_TRAINED, - SKILL_FIREMAN = SKILL_FIREMAN_TRAINED, - ) - -/datum/skills/CE - name = "Chief Engineer" - skills = list( - SKILL_ENGINEER = SKILL_ENGINEER_MASTER, - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_MASTER, - SKILL_LEADERSHIP = SKILL_LEAD_MASTER, - SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED, - SKILL_POLICE = SKILL_POLICE_FLASH, - SKILL_FIREMAN = SKILL_FIREMAN_TRAINED, - SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER, - SKILL_JTAC = SKILL_JTAC_MASTER, - SKILL_INTEL = SKILL_INTEL_TRAINED, - SKILL_NAVIGATIONS = SKILL_NAVIGATIONS_TRAINED, - ) - -/datum/skills/RO - name = "Requisition Officer" - skills = list( - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, - SKILL_LEADERSHIP = SKILL_LEAD_EXPERT, - SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED, - SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER, - SKILL_POLICE = SKILL_POLICE_FLASH, - SKILL_FIREMAN = SKILL_FIREMAN_TRAINED, - SKILL_JTAC = SKILL_JTAC_EXPERT, - SKILL_INTEL = SKILL_INTEL_TRAINED, - ) - -/* ---------------------- -MILITARY NONCOMBATANT ---------------------- -*/ - -/datum/skills/doctor - name = "Doctor" - skills = list( - SKILL_FIREARMS = SKILL_FIREARMS_CIVILIAN, - SKILL_MEDICAL = SKILL_MEDICAL_DOCTOR, - SKILL_SURGERY = SKILL_SURGERY_TRAINED, - ) - -/datum/skills/nurse - name = "Nurse" - skills = list( - SKILL_FIREARMS = SKILL_FIREARMS_CIVILIAN, - SKILL_MEDICAL = SKILL_MEDICAL_DOCTOR, - SKILL_SURGERY = SKILL_SURGERY_NOVICE, - ) - -/datum/skills/researcher - name = "Researcher" - skills = list( - SKILL_FIREARMS = SKILL_FIREARMS_CIVILIAN, - SKILL_MEDICAL = SKILL_MEDICAL_DOCTOR, - SKILL_SURGERY = SKILL_SURGERY_TRAINED, - SKILL_RESEARCH = SKILL_RESEARCH_TRAINED, - SKILL_INTEL = SKILL_INTEL_TRAINED, - ) - -/datum/skills/pilot - name = "Pilot Officer" - skills = list( - SKILL_PILOT = SKILL_PILOT_EXPERT, - SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER, - SKILL_LEADERSHIP = SKILL_LEAD_TRAINED, - SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED, - SKILL_MEDICAL = SKILL_MEDICAL_MEDIC, - SKILL_SURGERY = SKILL_SURGERY_NOVICE, - SKILL_JTAC = SKILL_JTAC_TRAINED, - SKILL_INTEL = SKILL_INTEL_TRAINED, - ) - -/datum/skills/crew_chief - name = "Dropship Crew Chief" - skills = list( - SKILL_PILOT = SKILL_PILOT_TRAINED, - SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER, - SKILL_LEADERSHIP = SKILL_LEAD_TRAINED, - SKILL_MEDICAL = SKILL_MEDICAL_MEDIC, - SKILL_SURGERY = SKILL_SURGERY_NOVICE, - SKILL_JTAC = SKILL_JTAC_TRAINED, - SKILL_ENGINEER = SKILL_ENGINEER_ENGI, - ) - -/datum/skills/MP - name = "Military Police" - skills = list( - SKILL_CQC = SKILL_CQC_SKILLED, - SKILL_POLICE = SKILL_POLICE_SKILLED, - SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, - SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED, - ) - -/datum/skills/MW - name = "Military Warden" - skills = list( - SKILL_CQC = SKILL_CQC_SKILLED, - SKILL_POLICE = SKILL_POLICE_SKILLED, - SKILL_FIREMAN = SKILL_FIREMAN_TRAINED, - SKILL_LEADERSHIP = SKILL_LEAD_TRAINED, - SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED, - SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED, - SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, - SKILL_ENGINEER = SKILL_ENGINEER_ENGI, - ) - -/datum/skills/provost - name = "Provost" - skills = list( - SKILL_CQC = SKILL_CQC_EXPERT, - SKILL_POLICE = SKILL_POLICE_SKILLED, - SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, - SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER, - SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, - ) - -/datum/skills/OT - name = "Ordnance Technician" - skills = list( - SKILL_ENGINEER = SKILL_ENGINEER_MASTER, - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_MASTER, - SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER, - ) - -/datum/skills/MT - name = "Maintenance Technician" - skills = list( - SKILL_ENGINEER = SKILL_ENGINEER_MASTER, - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_MASTER, - SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER, - SKILL_DOMESTIC = SKILL_DOMESTIC_TRAINED, - ) - -/datum/skills/mess_technician - name = "Mess Technician" - skills = list( - SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, // need to hunt food somehow - SKILL_ENGINEER = SKILL_ENGINEER_TRAINED, - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED, - SKILL_DOMESTIC = SKILL_DOMESTIC_MASTER - ) - -/datum/skills/CT - name = "Cargo Technician" - skills = list( - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED, - SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER, - ) - -/* ---------------------- -SYNTHETIC ---------------------- -*/ - -/datum/skills/synthetic - name = "Synthetic" - skills = list( - SKILL_CQC = SKILL_CQC_MASTER, - SKILL_ENGINEER = SKILL_ENGINEER_MASTER, - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_MASTER, - SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, - SKILL_SPEC_WEAPONS = SKILL_SPEC_ALL, - SKILL_LEADERSHIP = SKILL_LEAD_EXPERT, - SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED, - SKILL_MEDICAL = SKILL_MEDICAL_MASTER, - SKILL_SURGERY = SKILL_SURGERY_EXPERT, - SKILL_RESEARCH = SKILL_RESEARCH_TRAINED, - SKILL_MELEE_WEAPONS = SKILL_MELEE_SUPER, - SKILL_PILOT = SKILL_PILOT_EXPERT, - SKILL_POLICE = SKILL_POLICE_SKILLED, - SKILL_FIREMAN = SKILL_FIREMAN_MAX, - SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER, - SKILL_VEHICLE = SKILL_VEHICLE_LARGE, - SKILL_JTAC = SKILL_JTAC_EXPERT, - SKILL_INTEL = SKILL_INTEL_EXPERT, - SKILL_DOMESTIC = SKILL_DOMESTIC_MASTER, - SKILL_NAVIGATIONS = SKILL_NAVIGATIONS_TRAINED, - ) - -/datum/skills/colonial_synthetic - name = SYNTH_COLONY - skills = list( - SKILL_CQC = SKILL_CQC_EXPERT, - SKILL_ENGINEER = SKILL_ENGINEER_ENGI, - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, - SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, - SKILL_SPEC_WEAPONS = SKILL_SPEC_ALL, - SKILL_MEDICAL = SKILL_MEDICAL_DOCTOR, - SKILL_SURGERY = SKILL_SURGERY_TRAINED, - SKILL_RESEARCH = SKILL_RESEARCH_TRAINED, - SKILL_MELEE_WEAPONS = SKILL_MELEE_SUPER, - SKILL_PILOT = SKILL_PILOT_EXPERT, - SKILL_POLICE = SKILL_POLICE_SKILLED, - SKILL_FIREMAN = SKILL_FIREMAN_EXPERT, - SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER, - SKILL_VEHICLE = SKILL_VEHICLE_LARGE, - SKILL_JTAC = SKILL_JTAC_BEGINNER, - SKILL_INTEL = SKILL_INTEL_TRAINED, - SKILL_DOMESTIC = SKILL_DOMESTIC_MASTER, - ) - -/datum/skills/working_joe - name = SYNTH_WORKING_JOE - skills = list( - SKILL_CQC = SKILL_CQC_EXPERT, - SKILL_ENGINEER = SKILL_ENGINEER_MASTER, //So they can fully use the Maintenance Jack - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, - SKILL_POLICE = SKILL_POLICE_SKILLED, - SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, - SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER, - SKILL_VEHICLE = SKILL_VEHICLE_LARGE, - SKILL_DOMESTIC = SKILL_DOMESTIC_MASTER, - ) - -/datum/skills/infiltrator_synthetic - name = SYNTH_INFILTRATOR - skills = list( - SKILL_CQC = SKILL_CQC_MASTER, - SKILL_ENGINEER = SKILL_ENGINEER_MASTER, - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_MASTER, - SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, - SKILL_SPEC_WEAPONS = SKILL_SPEC_ALL, - SKILL_LEADERSHIP = SKILL_LEAD_EXPERT, - SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED, - SKILL_MEDICAL = SKILL_MEDICAL_MASTER, - SKILL_SURGERY = SKILL_SURGERY_EXPERT, - SKILL_RESEARCH = SKILL_RESEARCH_TRAINED, - SKILL_MELEE_WEAPONS = SKILL_MELEE_SUPER, - SKILL_PILOT = SKILL_PILOT_EXPERT, - SKILL_POLICE = SKILL_POLICE_SKILLED, - SKILL_FIREMAN = SKILL_FIREMAN_MAX, - SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER, - SKILL_VEHICLE = SKILL_VEHICLE_CREWMAN, - SKILL_JTAC = SKILL_JTAC_EXPERT, - SKILL_INTEL = SKILL_INTEL_EXPERT, - SKILL_DOMESTIC = SKILL_DOMESTIC_MASTER, - SKILL_ANTAG = SKILL_ANTAG_AGENT, - ) - -/* ------------------------------- -United States Colonial Marines ------------------------------- -*/ - -/datum/skills/pfc - name = "Private" - //same as default - -/datum/skills/pfc/crafty - name = "Crafty Private" - skills = list( - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED, - SKILL_ENGINEER = SKILL_ENGINEER_TRAINED, - ) - -/datum/skills/combat_medic - name = "Combat Medic" - skills = list( - SKILL_MEDICAL = SKILL_MEDICAL_MEDIC, - SKILL_SURGERY = SKILL_SURGERY_NOVICE, - SKILL_JTAC = SKILL_JTAC_BEGINNER, - ) - -/datum/skills/combat_medic/crafty - name = "Crafty Combat Medic" - skills = list( - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED, - SKILL_ENGINEER = SKILL_ENGINEER_TRAINED, - ) - -/datum/skills/combat_engineer - name = "Combat Engineer" - skills = list( - SKILL_ENGINEER = SKILL_ENGINEER_ENGI, - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, - SKILL_VEHICLE = SKILL_VEHICLE_SMALL, - SKILL_JTAC = SKILL_JTAC_BEGINNER, - ) - -/datum/skills/smartgunner - name = "Squad Smartgunner" - skills = list( - SKILL_SPEC_WEAPONS = SKILL_SPEC_SMARTGUN, - SKILL_JTAC = SKILL_JTAC_BEGINNER, - ) - -/datum/skills/specialist - name = "Squad Weapons Specialist" - skills = list( - SKILL_CQC = SKILL_CQC_TRAINED, - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED, - SKILL_ENGINEER = SKILL_ENGINEER_TRAINED, //to use c4 in demo set. - SKILL_SPEC_WEAPONS = SKILL_SPEC_TRAINED, - SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, - SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED, - SKILL_JTAC = SKILL_JTAC_BEGINNER - ) - -/datum/skills/tl - name = "Fireteam Leader" - skills = list( - SKILL_ENGINEER = SKILL_ENGINEER_ENGI, - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, - SKILL_JTAC = SKILL_JTAC_EXPERT, - ) - -/datum/skills/SL - name = "Squad Leader" - skills = list( - SKILL_CQC = SKILL_CQC_TRAINED, - SKILL_FIREMAN = SKILL_FIREMAN_TRAINED, - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, - SKILL_ENGINEER = SKILL_ENGINEER_ENGI, - SKILL_LEADERSHIP = SKILL_LEAD_TRAINED, - SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, - SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED, - SKILL_VEHICLE = SKILL_VEHICLE_SMALL, - SKILL_JTAC = SKILL_JTAC_TRAINED, - SKILL_INTEL = SKILL_INTEL_TRAINED, - ) - -/datum/skills/intel - name = "Intelligence Officer" - skills = list( - SKILL_ENGINEER = SKILL_ENGINEER_ENGI, - SKILL_LEADERSHIP = SKILL_LEAD_TRAINED, - SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED, - SKILL_CQC = SKILL_CQC_TRAINED, - SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, - SKILL_RESEARCH = SKILL_RESEARCH_TRAINED, - SKILL_JTAC = SKILL_JTAC_TRAINED, - SKILL_INTEL = SKILL_INTEL_EXPERT, - ) - -/* -------------------------- -COLONIAL LIBERATION FRONT -------------------------- -*/ - -/datum/skills/clf - name = "CLF Soldier" - skills = list( - SKILL_FIREARMS = SKILL_FIREARMS_TRAINED, - SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, - SKILL_POLICE = SKILL_POLICE_SKILLED, - SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED, - SKILL_ENGINEER = SKILL_ENGINEER_TRAINED, - SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, - SKILL_VEHICLE = SKILL_VEHICLE_SMALL, - SKILL_ENDURANCE = SKILL_ENDURANCE_WEAK, - SKILL_JTAC = SKILL_JTAC_BEGINNER, - ) - -/datum/skills/clf/combat_engineer - name = "CLF Engineer" - skills = list( - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, - SKILL_ENGINEER = SKILL_ENGINEER_ENGI, - SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, - SKILL_POWERLOADER = SKILL_POWERLOADER_TRAINED, - SKILL_VEHICLE = SKILL_VEHICLE_SMALL, - SKILL_ENDURANCE = SKILL_ENDURANCE_WEAK, - SKILL_JTAC = SKILL_JTAC_BEGINNER, - ) - -/datum/skills/clf/combat_medic - name = "CLF Medic" - skills = list( - SKILL_MEDICAL = SKILL_MEDICAL_MEDIC, - SKILL_SURGERY = SKILL_SURGERY_TRAINED, - SKILL_VEHICLE = SKILL_VEHICLE_SMALL, - SKILL_ENDURANCE = SKILL_ENDURANCE_WEAK, - SKILL_JTAC = SKILL_JTAC_BEGINNER, - ) - -/datum/skills/clf/specialist - name = "CLF Specialist" - skills = list( - SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, - SKILL_CQC = SKILL_CQC_TRAINED, - SKILL_ENGINEER = SKILL_ENGINEER_TRAINED, //to use c4 in demo set. - SKILL_LEADERSHIP = SKILL_LEAD_TRAINED, - SKILL_SPEC_WEAPONS = SKILL_SPEC_ALL, - SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED, - SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, - SKILL_JTAC = SKILL_JTAC_TRAINED - ) - -/datum/skills/clf/leader - name = "CLF Leader" - skills = list( - SKILL_FIREARMS = SKILL_FIREARMS_TRAINED, - SKILL_ENGINEER = SKILL_ENGINEER_ENGI, // to use their C4 - SKILL_CQC = SKILL_CQC_SKILLED, - SKILL_LEADERSHIP = SKILL_LEAD_EXPERT, - SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED, - SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, - SKILL_POLICE = SKILL_POLICE_SKILLED, - SKILL_FIREMAN = SKILL_FIREMAN_EXPERT, - SKILL_POWERLOADER = SKILL_POWERLOADER_TRAINED, - SKILL_VEHICLE = SKILL_VEHICLE_SMALL, - SKILL_ENDURANCE = SKILL_ENDURANCE_MAX, - SKILL_JTAC = SKILL_JTAC_EXPERT, - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI - ) - -/datum/skills/clf/commander - name = "CLF Cell Commander" - skills = list( - SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, - SKILL_ENGINEER = SKILL_ENGINEER_ENGI, - SKILL_CQC = SKILL_CQC_SKILLED, - SKILL_LEADERSHIP = SKILL_LEAD_MASTER, - SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED, - SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, - SKILL_POLICE = SKILL_POLICE_SKILLED, - SKILL_FIREMAN = SKILL_FIREMAN_EXPERT, - SKILL_POWERLOADER = SKILL_POWERLOADER_TRAINED, - SKILL_VEHICLE = SKILL_VEHICLE_LARGE, - SKILL_ENDURANCE = SKILL_ENDURANCE_MAX, - SKILL_JTAC = SKILL_JTAC_MASTER, - SKILL_SPEC_WEAPONS = SKILL_SPEC_SMARTGUN, - SKILL_EXECUTION = SKILL_EXECUTION_TRAINED, - ) - -/* ------------ -FREELANCERS ------------ -*/ - -//NOTE: Freelancer training is similar to the USCM's, but with additional construction skills - -/datum/skills/freelancer - name = "Freelancer Private" - skills = list( - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, - SKILL_ENGINEER = SKILL_ENGINEER_ENGI, - SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED, - ) - -/datum/skills/freelancer/combat_medic - name = "Freelancer Medic" - skills = list( - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, - SKILL_ENGINEER = SKILL_ENGINEER_ENGI, - SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED, - SKILL_MEDICAL = SKILL_MEDICAL_MEDIC, - SKILL_SURGERY = SKILL_SURGERY_TRAINED, - ) - -/datum/skills/freelancer/SL - name = "Freelancer Leader" - skills = list( - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, - SKILL_ENGINEER = SKILL_ENGINEER_ENGI, - SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED, - SKILL_MEDICAL = SKILL_MEDICAL_MEDIC, - SKILL_CQC = SKILL_CQC_TRAINED, - SKILL_LEADERSHIP = SKILL_LEAD_EXPERT, - SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED, - SKILL_JTAC = SKILL_JTAC_EXPERT, - ) - -/* --------------------------- -UNITED PROGRESSIVE PEOPLES --------------------------- -*/ - -//NOTE: UPP make up for their subpar gear with extreme training. - -/datum/skills/upp - name = "UPP Private" - skills = list( - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED, - SKILL_ENGINEER = SKILL_ENGINEER_TRAINED, - SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, - SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED, - SKILL_CQC = SKILL_CQC_DEFAULT, - SKILL_FIREMAN = SKILL_FIREMAN_TRAINED, - SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, - ) - -/datum/skills/upp/combat_engineer - name = "UPP Sapper" - skills = list( - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, - SKILL_ENGINEER = SKILL_ENGINEER_ENGI, - SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, - SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED, - SKILL_CQC = SKILL_CQC_DEFAULT, - SKILL_FIREMAN = SKILL_FIREMAN_TRAINED, - SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, - ) - -/datum/skills/upp/combat_medic - name = "UPP Medic" - skills = list( - SKILL_MEDICAL = SKILL_MEDICAL_DOCTOR, - SKILL_SURGERY = SKILL_SURGERY_TRAINED, - SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED, - SKILL_CQC = SKILL_CQC_DEFAULT, - SKILL_FIREARMS = SKILL_FIREARMS_TRAINED, - ) - -/datum/skills/upp/specialist - name = "UPP Specialist" - skills = list( - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED, - SKILL_ENGINEER = SKILL_ENGINEER_TRAINED, - SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER, - SKILL_CQC = SKILL_CQC_TRAINED, - SKILL_LEADERSHIP = SKILL_LEAD_TRAINED, - SKILL_JTAC = SKILL_JTAC_TRAINED, - SKILL_SPEC_WEAPONS = SKILL_SPEC_UPP, - SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, - SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, - ) - -/datum/skills/upp/SL - name = "UPP Squad Leader" - skills = list( - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, - SKILL_ENGINEER = SKILL_ENGINEER_ENGI, - SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER, - SKILL_CQC = SKILL_CQC_TRAINED, - SKILL_LEADERSHIP = SKILL_LEAD_EXPERT, - SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED, - SKILL_MEDICAL = SKILL_MEDICAL_MEDIC, - SKILL_JTAC = SKILL_JTAC_EXPERT, - ) - -/datum/skills/upp/military_police - name = "UPP Military Police" - skills = list( - SKILL_CQC = SKILL_CQC_SKILLED, - SKILL_POLICE = SKILL_POLICE_SKILLED, - SKILL_FIREMAN = SKILL_FIREMAN_EXPERT, - SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER, - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED, - SKILL_ENGINEER = SKILL_ENGINEER_TRAINED, - SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, - SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, - ) - -/datum/skills/upp/officer - name = "UPP Officer" - skills = list( - SKILL_CQC = SKILL_CQC_TRAINED, - SKILL_POLICE = SKILL_POLICE_FLASH, - SKILL_FIREMAN = SKILL_FIREMAN_EXPERT, - SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER, - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, - SKILL_LEADERSHIP = SKILL_LEAD_EXPERT, - SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED, - SKILL_ENGINEER = SKILL_ENGINEER_TRAINED, - SKILL_MEDICAL = SKILL_MEDICAL_MEDIC, - SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, - SKILL_VEHICLE = SKILL_VEHICLE_SMALL, - SKILL_JTAC = SKILL_JTAC_EXPERT, - ) - -/datum/skills/upp/kapitan - name = "UPP Kapitan" - skills = list( - SKILL_CQC = SKILL_CQC_SKILLED, - SKILL_POLICE = SKILL_POLICE_SKILLED, - SKILL_FIREMAN = SKILL_FIREMAN_EXPERT, - SKILL_LEADERSHIP = SKILL_LEAD_MASTER, - SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED, - SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER, - SKILL_ENGINEER = SKILL_ENGINEER_ENGI, - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, - SKILL_MEDICAL = SKILL_MEDICAL_MEDIC, - SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, - SKILL_VEHICLE = SKILL_VEHICLE_SMALL, - SKILL_JTAC = SKILL_JTAC_EXPERT, - ) - -/datum/skills/upp/commander - name = "UPP Command Officer" - skills = list( - SKILL_CQC = SKILL_CQC_SKILLED, - SKILL_POLICE = SKILL_POLICE_SKILLED, - SKILL_FIREMAN = SKILL_FIREMAN_EXPERT, - SKILL_LEADERSHIP = SKILL_LEAD_MASTER, - SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED, - SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER, - SKILL_ENGINEER = SKILL_ENGINEER_ENGI, - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, - SKILL_MEDICAL = SKILL_MEDICAL_MEDIC, - SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, - SKILL_VEHICLE = SKILL_VEHICLE_SMALL, - SKILL_JTAC = SKILL_JTAC_EXPERT, - SKILL_EXECUTION = SKILL_EXECUTION_TRAINED, - ) -/datum/skills/upp/conscript - name = "UPP Conscript" - skills = list( - SKILL_FIREARMS = SKILL_FIREARMS_TRAINED, - ) - -/* ----------------------------- -Private Military Contractors ----------------------------- -*/ - -//NOTE: Compared to the USCM, PMCs have additional firearms training, construction skills and policing skills - -/datum/skills/pmc - name = "PMC Private" - skills = list( - SKILL_CQC = SKILL_CQC_TRAINED, - SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, - SKILL_POLICE = SKILL_POLICE_SKILLED, - SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, - SKILL_ENGINEER = SKILL_ENGINEER_ENGI, - SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER, - ) - -/datum/skills/pmc/medic - name = "PMC Medic" - skills = list( - SKILL_CQC = SKILL_CQC_TRAINED, - SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, - SKILL_POLICE = SKILL_POLICE_SKILLED, - SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, - SKILL_ENGINEER = SKILL_ENGINEER_ENGI, - SKILL_MEDICAL = SKILL_MEDICAL_MEDIC, - SKILL_SURGERY = SKILL_SURGERY_NOVICE, - SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER, - ) - -/datum/skills/pmc/medic/chem - name = "PMC Medical Investigator" - skills = list( - SKILL_CQC = SKILL_CQC_TRAINED, - SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, - SKILL_POLICE = SKILL_POLICE_SKILLED, - SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, - SKILL_ENGINEER = SKILL_ENGINEER_ENGI, - SKILL_MEDICAL = SKILL_MEDICAL_MEDIC, - SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER, - SKILL_RESEARCH = SKILL_RESEARCH_TRAINED, - ) - -/datum/skills/pmc/smartgunner - name = "PMC Smartgunner" - skills = list( - SKILL_CQC = SKILL_CQC_TRAINED, - SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, - SKILL_POLICE = SKILL_POLICE_SKILLED, - SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, - SKILL_ENGINEER = SKILL_ENGINEER_ENGI, - SKILL_SPEC_WEAPONS = SKILL_SPEC_SMARTGUN, - SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER, - SKILL_JTAC = SKILL_JTAC_BEGINNER, - ) - -/datum/skills/pmc/specialist - name = "PMC Specialist" - skills = list( - SKILL_CQC = SKILL_CQC_TRAINED, - SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, - SKILL_POLICE = SKILL_POLICE_SKILLED, - SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, - SKILL_ENGINEER = SKILL_ENGINEER_ENGI, - SKILL_CQC = SKILL_CQC_TRAINED, - SKILL_SPEC_WEAPONS = SKILL_SPEC_ALL, - SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, - SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER, - SKILL_JTAC = SKILL_JTAC_BEGINNER, - ) - -/datum/skills/pmc/SL - name = "PMC Leader" - skills = list( - SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, - SKILL_POLICE = SKILL_POLICE_SKILLED, - SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, - SKILL_ENGINEER = SKILL_ENGINEER_ENGI, - SKILL_CQC = SKILL_CQC_SKILLED, - SKILL_LEADERSHIP = SKILL_LEAD_TRAINED, - SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED, - SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, - SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER, - SKILL_JTAC = SKILL_JTAC_TRAINED, - ) - -/datum/skills/pmc/SL/chem - name = "PMC Lead Investigator" - skills = list( - SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, - SKILL_POLICE = SKILL_POLICE_SKILLED, - SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, - SKILL_ENGINEER = SKILL_ENGINEER_ENGI, - SKILL_CQC = SKILL_CQC_SKILLED, - SKILL_LEADERSHIP = SKILL_LEAD_TRAINED, - SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED, - SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, - SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER, - SKILL_RESEARCH = SKILL_RESEARCH_TRAINED, - SKILL_JTAC = SKILL_JTAC_TRAINED, - ) - -/datum/skills/pmc/tank_crew - name = "Vehicle Crewman" - skills = list( - SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, - SKILL_POLICE = SKILL_POLICE_SKILLED, - SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, - SKILL_ENGINEER = SKILL_ENGINEER_ENGI, - SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER, - SKILL_LEADERSHIP = SKILL_LEAD_TRAINED, - SKILL_JTAC = SKILL_JTAC_TRAINED, - SKILL_VEHICLE = SKILL_VEHICLE_CREWMAN, - SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER, - ) - -/datum/skills/pmc/doctor - name = "PMC Triage Doctor" - skills = list( - SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, - SKILL_POLICE = SKILL_POLICE_SKILLED, - SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED, - SKILL_ENGINEER = SKILL_ENGINEER_TRAINED, - SKILL_MEDICAL = SKILL_MEDICAL_DOCTOR, - SKILL_SURGERY = SKILL_SURGERY_EXPERT, - SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER, //trained in medicine more than combat - SKILL_CQC = SKILL_CQC_TRAINED - ) - -/datum/skills/pmc/engineer - name = "PMC Corporate Technician" - skills = list( - SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, - SKILL_POLICE = SKILL_POLICE_SKILLED, - SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_MASTER, - SKILL_ENGINEER = SKILL_ENGINEER_MASTER, - SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, - SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER, - SKILL_JTAC = SKILL_JTAC_TRAINED, - SKILL_CQC = SKILL_CQC_TRAINED, - SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER, - ) - -/datum/skills/pmc/director - name = "PMC Site Director" - skills = list( - SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, - SKILL_POLICE = SKILL_POLICE_SKILLED, - SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, - SKILL_ENGINEER = SKILL_ENGINEER_ENGI, - SKILL_MEDICAL = SKILL_MEDICAL_MEDIC, - SKILL_CQC = SKILL_CQC_TRAINED, - SKILL_LEADERSHIP = SKILL_LEAD_MASTER, - SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED, - SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER, - SKILL_JTAC = SKILL_JTAC_MASTER, - SKILL_EXECUTION = SKILL_EXECUTION_TRAINED, - ) - -/* ---------------------- -CONTRACTORS ---------------------- -*/ -/datum/skills/contractor - name = "Contractor Standard" - skills = list( - SKILL_CQC = SKILL_CQC_TRAINED, - SKILL_ENGINEER = SKILL_ENGINEER_TRAINED, - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED, - SKILL_FIREARMS = SKILL_FIREARMS_MAX, - SKILL_POLICE = SKILL_POLICE_SKILLED, - SKILL_FIREMAN = SKILL_FIREMAN_EXPERT, - SKILL_VEHICLE = SKILL_VEHICLE_LARGE, - SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, - SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, - SKILL_JTAC = SKILL_JTAC_BEGINNER, - SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED, - ) - -/datum/skills/contractor/leader - name = "Contractor Leader" - skills = list( - SKILL_ENGINEER = SKILL_ENGINEER_ENGI, - SKILL_FIREARMS = SKILL_FIREARMS_MAX, - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, - SKILL_LEADERSHIP = SKILL_LEAD_MASTER, - SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED, - SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, - SKILL_POLICE = SKILL_POLICE_SKILLED, - SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, - SKILL_CQC = SKILL_CQC_SKILLED, - SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, - SKILL_VEHICLE = SKILL_VEHICLE_LARGE, - SKILL_POWERLOADER = SKILL_POWERLOADER_TRAINED, - SKILL_ENDURANCE = SKILL_ENDURANCE_EXPERT, - SKILL_JTAC = SKILL_JTAC_MASTER, - ) - -/datum/skills/contractor/medic - name = "Contractor Medic" - skills = list( - SKILL_FIREARMS = SKILL_FIREARMS_MAX, - SKILL_POLICE = SKILL_POLICE_SKILLED, - SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED, - SKILL_ENGINEER = SKILL_ENGINEER_TRAINED, - SKILL_MEDICAL = SKILL_MEDICAL_DOCTOR, - SKILL_SURGERY = SKILL_SURGERY_TRAINED, - SKILL_VEHICLE = SKILL_VEHICLE_LARGE, - SKILL_ENDURANCE = SKILL_ENDURANCE_EXPERT, - SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, - SKILL_CQC = SKILL_CQC_TRAINED, - SKILL_JTAC = SKILL_JTAC_BEGINNER, - ) - -/datum/skills/contractor/engi - name = "Contractor Engi" - skills = list( - SKILL_CQC = SKILL_CQC_TRAINED, - SKILL_ENGINEER = SKILL_ENGINEER_MAX, - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_MAX, - SKILL_FIREARMS = SKILL_FIREARMS_MAX, - SKILL_POLICE = SKILL_POLICE_SKILLED, - SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, - SKILL_VEHICLE = SKILL_VEHICLE_LARGE, - SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, - SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, - SKILL_JTAC = SKILL_JTAC_EXPERT, - SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED, - SKILL_POWERLOADER = SKILL_POWERLOADER_TRAINED, - ) - -/datum/skills/contractor/heavy - name = "Contractor Machinegunner" - skills = list( - SKILL_CQC = SKILL_CQC_TRAINED, - SKILL_ENGINEER = SKILL_ENGINEER_TRAINED, - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED, - SKILL_FIREARMS = SKILL_FIREARMS_MAX, - SKILL_POLICE = SKILL_POLICE_SKILLED, - SKILL_FIREMAN = SKILL_FIREMAN_EXPERT, - SKILL_VEHICLE = SKILL_VEHICLE_LARGE, - SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, - SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, - SKILL_SPEC_WEAPONS = SKILL_SPEC_SMARTGUN, - SKILL_JTAC = SKILL_JTAC_BEGINNER, - SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED, - ) - -/* ---------------------- -COLONIAL MARSHALS ---------------------- -*/ -/datum/skills/cmb - name = "CMB Deputy" - skills = list( - SKILL_POLICE = SKILL_POLICE_SKILLED, - SKILL_CQC = SKILL_CQC_EXPERT, - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_DEFAULT, - SKILL_FIREARMS = SKILL_FIREARMS_TRAINED, - SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, - SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, - SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, - SKILL_JTAC = SKILL_JTAC_BEGINNER, - SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER, - ) - -/datum/skills/cmb/leader - name = "CMB Marshal" - skills = list( - SKILL_POLICE = SKILL_POLICE_SKILLED, - SKILL_CQC = SKILL_CQC_EXPERT, - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, - SKILL_LEADERSHIP = SKILL_LEAD_MASTER, - SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED, - SKILL_MEDICAL = SKILL_MEDICAL_MEDIC, - SKILL_ENGINEER = SKILL_ENGINEER_ENGI, - SKILL_FIREMAN = SKILL_FIREMAN_MASTER, - SKILL_FIREARMS = SKILL_FIREARMS_MAX, - SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, - SKILL_VEHICLE = SKILL_VEHICLE_SMALL, - SKILL_ENDURANCE = SKILL_ENDURANCE_EXPERT, - SKILL_JTAC = SKILL_JTAC_EXPERT, - ) - -/datum/skills/synthetic/cmb - name = "CMB Investigative Synthetic" - skills = list( - SKILL_CQC = SKILL_CQC_MASTER, - SKILL_ENGINEER = SKILL_ENGINEER_MASTER, - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_MASTER, - SKILL_FIREARMS = SKILL_FIREARMS_TRAINED, - SKILL_SPEC_WEAPONS = SKILL_SPEC_ALL, - SKILL_LEADERSHIP = SKILL_LEAD_EXPERT, // incase the synth needs to use consoles for investigations or tracking - SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED, - SKILL_MEDICAL = SKILL_MEDICAL_DOCTOR, - SKILL_SURGERY = SKILL_SURGERY_TRAINED, // Not a medical Synthetic, but operate if absolutely needed. - SKILL_RESEARCH = SKILL_RESEARCH_TRAINED, - SKILL_MELEE_WEAPONS = SKILL_MELEE_SUPER, - SKILL_PILOT = SKILL_PILOT_TRAINED, - SKILL_POLICE = SKILL_POLICE_SKILLED, - SKILL_FIREMAN = SKILL_FIREMAN_MAX, - SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER, - SKILL_VEHICLE = SKILL_VEHICLE_LARGE, - SKILL_JTAC = SKILL_JTAC_BEGINNER, - SKILL_INTEL = SKILL_INTEL_EXPERT, - SKILL_DOMESTIC = SKILL_DOMESTIC_MASTER - ) - -/datum/skills/military/survivor/upp_private - name = "UPP Private" - skills = list( - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED, - SKILL_ENGINEER = SKILL_ENGINEER_ENGI, - SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, - SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED, - SKILL_CQC = SKILL_CQC_TRAINED, - SKILL_FIREARMS = SKILL_FIREARMS_TRAINED, - SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, - SKILL_VEHICLE = SKILL_VEHICLE_DEFAULT, - SKILL_JTAC = SKILL_JTAC_TRAINED, - ) - -/datum/skills/military/survivor/upp_sapper - name = "UPP Sapper" - skills = list( - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, - SKILL_ENGINEER = SKILL_ENGINEER_ENGI, - SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, - SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED, - SKILL_CQC = SKILL_CQC_TRAINED, - SKILL_FIREARMS = SKILL_FIREARMS_TRAINED, - SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, - SKILL_VEHICLE = SKILL_VEHICLE_DEFAULT, - SKILL_JTAC = SKILL_JTAC_TRAINED, - ) - -/datum/skills/military/survivor/upp_medic - name = "UPP Medic" - skills = list( - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED, - SKILL_ENGINEER = SKILL_ENGINEER_ENGI, - SKILL_MEDICAL = SKILL_MEDICAL_DOCTOR, - SKILL_SURGERY = SKILL_SURGERY_TRAINED, - SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED, - SKILL_FIREARMS = SKILL_FIREARMS_TRAINED, - SKILL_CQC = SKILL_CQC_TRAINED, - SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, - SKILL_VEHICLE = SKILL_VEHICLE_DEFAULT, - SKILL_JTAC = SKILL_JTAC_TRAINED, - ) - -/datum/skills/military/survivor/upp_spec - name = "UPP Specialist" - skills = list( - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED, - SKILL_ENGINEER = SKILL_ENGINEER_ENGI, - SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, - SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED, - SKILL_CQC = SKILL_CQC_TRAINED, - SKILL_LEADERSHIP = SKILL_LEAD_TRAINED, - SKILL_JTAC = SKILL_JTAC_TRAINED, - SKILL_SPEC_WEAPONS = SKILL_SPEC_UPP, - SKILL_FIREARMS = SKILL_FIREARMS_TRAINED, - SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, - SKILL_CQC = SKILL_CQC_TRAINED, - SKILL_VEHICLE = SKILL_VEHICLE_LARGE, - ) - -/datum/skills/military/survivor/upp_sl - name = "UPP Squad Leader" - skills = list( - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, - SKILL_ENGINEER = SKILL_ENGINEER_ENGI, - SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED, - SKILL_SPEC_WEAPONS = SKILL_SPEC_UPP, - SKILL_FIREARMS = SKILL_FIREARMS_TRAINED, - SKILL_CQC = SKILL_CQC_TRAINED, - SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, - SKILL_LEADERSHIP = SKILL_LEAD_EXPERT, - SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED, - SKILL_MEDICAL = SKILL_MEDICAL_MEDIC, - SKILL_VEHICLE = SKILL_VEHICLE_LARGE, - SKILL_JTAC = SKILL_JTAC_EXPERT, - ) - -/* ---------------------- -SPEC-OPS ---------------------- -*/ - -/datum/skills/commando - name = "Commando" - skills = list( - SKILL_CQC = SKILL_CQC_EXPERT, - SKILL_ENGINEER = SKILL_ENGINEER_ENGI, - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, - SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, - SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, - SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, - SKILL_ENDURANCE = SKILL_ENDURANCE_MAX, - SKILL_SPEC_WEAPONS = SKILL_SPEC_ALL, - SKILL_JTAC = SKILL_JTAC_BEGINNER, - ) - -/datum/skills/commando/medic - name = "Commando Medic" - skills = list( - SKILL_CQC = SKILL_CQC_EXPERT, - SKILL_ENGINEER = SKILL_ENGINEER_ENGI, - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, - SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, - SKILL_MEDICAL = SKILL_MEDICAL_MEDIC, - SKILL_SURGERY = SKILL_SURGERY_NOVICE, - SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, - SKILL_ENDURANCE = SKILL_ENDURANCE_MAX, - SKILL_SPEC_WEAPONS = SKILL_SPEC_ALL, - SKILL_JTAC = SKILL_JTAC_BEGINNER, - ) - -/datum/skills/commando/leader - name = "Commando Leader" - skills = list( - SKILL_CQC = SKILL_CQC_EXPERT, - SKILL_ENGINEER = SKILL_ENGINEER_ENGI, - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, - SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, - SKILL_LEADERSHIP = SKILL_LEAD_TRAINED, - SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, - SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, - SKILL_ENDURANCE = SKILL_ENDURANCE_MAX, - SKILL_SPEC_WEAPONS = SKILL_SPEC_ALL, - SKILL_JTAC = SKILL_JTAC_TRAINED, - ) - -/datum/skills/commando/deathsquad - name = "Deathsquad" - skills = list( - SKILL_CQC = SKILL_CQC_MASTER, - SKILL_ENGINEER = SKILL_ENGINEER_ENGI, - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, - SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, - SKILL_MEDICAL = SKILL_MEDICAL_MEDIC, - SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, - SKILL_ENDURANCE = SKILL_ENDURANCE_MAX, - SKILL_SPEC_WEAPONS = SKILL_SPEC_ALL, - SKILL_JTAC = SKILL_JTAC_BEGINNER, - ) - -/datum/skills/commando/deathsquad/leader - name = "Deathsquad Leader" - skills = list( - SKILL_CQC = SKILL_CQC_MASTER, - SKILL_ENGINEER = SKILL_ENGINEER_ENGI, - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, - SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, - SKILL_LEADERSHIP = SKILL_LEAD_TRAINED, - SKILL_MEDICAL = SKILL_MEDICAL_MEDIC, - SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, - SKILL_ENDURANCE = SKILL_ENDURANCE_MAX, - SKILL_SPEC_WEAPONS = SKILL_SPEC_ALL, - SKILL_JTAC = SKILL_JTAC_BEGINNER, - ) - -/datum/skills/commando/deathsquad/officer - name = "Deathsquad Officer" - skills = list( - SKILL_CQC = SKILL_CQC_MASTER, - SKILL_ENGINEER = SKILL_ENGINEER_ENGI, - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, - SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, - SKILL_LEADERSHIP = SKILL_LEAD_EXPERT, - SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED, - SKILL_MEDICAL = SKILL_MEDICAL_MEDIC, - SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, - SKILL_ENDURANCE = SKILL_ENDURANCE_MAX, - SKILL_SPEC_WEAPONS = SKILL_SPEC_ALL, - SKILL_JTAC = SKILL_JTAC_BEGINNER, - ) - -/datum/skills/spy - name = "Spy" - skills = list( - SKILL_CQC = SKILL_CQC_TRAINED, - SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, - SKILL_ENGINEER = SKILL_ENGINEER_ENGI, - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, - SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, - SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER, - SKILL_JTAC = SKILL_JTAC_BEGINNER, - ) - -/datum/skills/ninja - name = "Ninja" - skills = list( - SKILL_CQC = SKILL_CQC_MASTER, - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED, - SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, - SKILL_MELEE_WEAPONS = SKILL_MELEE_SUPER, - SKILL_JTAC = SKILL_JTAC_BEGINNER, - ) - -/* ---------------------- -MISCELLANEOUS ---------------------- -*/ - -/datum/skills/mercenary - name = "Mercenary" - skills = list( - SKILL_CQC = SKILL_CQC_SKILLED, - SKILL_ENGINEER = SKILL_ENGINEER_ENGI, - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, - SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, - SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, - SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, - SKILL_JTAC = SKILL_JTAC_BEGINNER, - ) - -/datum/skills/mercenary/elite - name = "Elite Mercenary" - skills = list( - SKILL_CQC = SKILL_CQC_SKILLED, - SKILL_ENGINEER = SKILL_ENGINEER_ENGI, - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, - SKILL_FIREARMS = SKILL_FIREARMS_MAX, - SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, - SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, - SKILL_JTAC = SKILL_JTAC_BEGINNER, - SKILL_ENDURANCE = SKILL_ENDURANCE_MAX, - SKILL_VEHICLE = SKILL_VEHICLE_SMALL, - ) - -/datum/skills/mercenary/elite/medic - name = "Elite Mercenary Medic" - skills = list( - SKILL_CQC = SKILL_CQC_SKILLED, - SKILL_ENGINEER = SKILL_ENGINEER_ENGI, - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, - SKILL_FIREARMS = SKILL_FIREARMS_MAX, - SKILL_MEDICAL = SKILL_MEDICAL_MASTER, - SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, - SKILL_JTAC = SKILL_JTAC_BEGINNER, - SKILL_ENDURANCE = SKILL_ENDURANCE_MAX, - SKILL_SURGERY = SKILL_SURGERY_TRAINED, - ) - -/datum/skills/mercenary/elite/engineer - name = "Elite Mercenary Engineer" - skills = list( - SKILL_CQC = SKILL_CQC_SKILLED, - SKILL_ENGINEER = SKILL_ENGINEER_MASTER, - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_MASTER, - SKILL_FIREARMS = SKILL_FIREARMS_MAX, - SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, - SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, - SKILL_JTAC = SKILL_JTAC_BEGINNER, - SKILL_ENDURANCE = SKILL_ENDURANCE_MAX, - SKILL_VEHICLE = SKILL_VEHICLE_SMALL, - SKILL_PILOT = SKILL_PILOT_EXPERT, - ) - -/datum/skills/mercenary/elite/heavy - name = "Elite Mercenary Heavy" - skills = list( - SKILL_CQC = SKILL_CQC_SKILLED, - SKILL_ENGINEER = SKILL_ENGINEER_ENGI, - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, - SKILL_FIREARMS = SKILL_FIREARMS_MAX, - SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, - SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, - SKILL_JTAC = SKILL_JTAC_BEGINNER, - SKILL_ENDURANCE = SKILL_ENDURANCE_MAX, - SKILL_VEHICLE = SKILL_VEHICLE_SMALL, - SKILL_SPEC_WEAPONS = SKILL_SPEC_ALL, - ) - -/datum/skills/mercenary/elite/leader - name = "Elite Mercenary Leader" - skills = list( - SKILL_CQC = SKILL_CQC_SKILLED, - SKILL_ENGINEER = SKILL_ENGINEER_ENGI, - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, - SKILL_FIREARMS = SKILL_FIREARMS_MAX, - SKILL_LEADERSHIP = SKILL_LEAD_MASTER, - SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED, - SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, - SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, - SKILL_JTAC = SKILL_JTAC_MASTER, - SKILL_ENDURANCE = SKILL_ENDURANCE_MAX, - SKILL_PILOT = SKILL_PILOT_EXPERT, - ) - -/datum/skills/dutchmerc - name = "Dutch's Dozen Mercenary" - skills = list( - SKILL_CQC = SKILL_CQC_TRAINED, - SKILL_ENGINEER = SKILL_ENGINEER_ENGI, - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, - SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, - SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, - SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, - SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, - SKILL_SPEC_WEAPONS = SKILL_SPEC_ALL, - SKILL_JTAC = SKILL_JTAC_BEGINNER, - SKILL_ENDURANCE = SKILL_ENDURANCE_EXPERT, - ) - -/datum/skills/dutchmedic - name = "Dutch's Dozen Medic" - skills = list( - SKILL_CQC = SKILL_CQC_TRAINED, - SKILL_ENGINEER = SKILL_ENGINEER_ENGI, - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED, - SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, - SKILL_MEDICAL = SKILL_MEDICAL_DOCTOR, - SKILL_SURGERY = SKILL_SURGERY_NOVICE, - SKILL_FIREMAN = SKILL_FIREMAN_EXPERT, - SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, - SKILL_JTAC = SKILL_JTAC_BEGINNER, - SKILL_ENDURANCE = SKILL_ENDURANCE_EXPERT, - ) - -/datum/skills/tank_crew - name = "Vehicle Crewman" - skills = list( - SKILL_VEHICLE = SKILL_VEHICLE_CREWMAN, - SKILL_LEADERSHIP = SKILL_LEAD_EXPERT, - SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED, - SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER, - SKILL_ENGINEER = SKILL_ENGINEER_ENGI, - SKILL_LEADERSHIP = SKILL_LEAD_TRAINED, - SKILL_JTAC = SKILL_JTAC_EXPERT, - ) - -/datum/skills/gladiator - name = "Gladiator" - skills = list( - SKILL_CQC = SKILL_CQC_SKILLED, - SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, - SKILL_FIREARMS = SKILL_FIREARMS_CIVILIAN, - SKILL_LEADERSHIP = SKILL_LEAD_NOVICE, - SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, - SKILL_ENDURANCE = SKILL_ENDURANCE_MAX, - ) - -/datum/skills/gladiator/champion - name = "Gladiator Champion" - skills = list( - SKILL_CQC = SKILL_CQC_MASTER, - SKILL_MELEE_WEAPONS = SKILL_MELEE_SUPER, - SKILL_LEADERSHIP = SKILL_LEAD_TRAINED, - SKILL_MEDICAL = SKILL_MEDICAL_MEDIC, - SKILL_ENDURANCE = SKILL_ENDURANCE_MAX, - SKILL_JTAC = SKILL_JTAC_TRAINED, - ) - -/datum/skills/gladiator/champion/leader - name = "Gladiator Leader" - skills = list( - SKILL_CQC = SKILL_CQC_MASTER, - SKILL_MELEE_WEAPONS = SKILL_MELEE_SUPER, - SKILL_MEDICAL = SKILL_MEDICAL_MEDIC, - SKILL_LEADERSHIP = SKILL_LEAD_MASTER, //Spartacus! - SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED, - SKILL_ENDURANCE = SKILL_ENDURANCE_MAX, - SKILL_JTAC = SKILL_JTAC_MASTER, - ) - -/datum/skills/yautja/warrior - name = "Yautja Warrior" - skills = list( - SKILL_CQC = SKILL_CQC_MASTER, - SKILL_MELEE_WEAPONS = SKILL_MELEE_SUPER, - SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER, - SKILL_ENGINEER = SKILL_ENGINEER_ENGI, - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, - SKILL_MEDICAL = SKILL_MEDICAL_MEDIC, - SKILL_SURGERY = SKILL_SURGERY_EXPERT, - SKILL_POLICE = SKILL_POLICE_SKILLED, - SKILL_FIREMAN = SKILL_FIREMAN_MAX, - SKILL_ANTAG = SKILL_ANTAG_HUNTER, - ) - -/datum/skills/dutch - name = "Dutch" - skills = list( - SKILL_CQC = SKILL_CQC_MASTER, - SKILL_MELEE_WEAPONS = SKILL_MELEE_MAX, - SKILL_ENGINEER = SKILL_ENGINEER_ENGI, - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, - SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, - SKILL_LEADERSHIP = SKILL_LEAD_MASTER, - SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED, - SKILL_MEDICAL = SKILL_MEDICAL_DOCTOR, - SKILL_SPEC_WEAPONS = SKILL_SPEC_ALL, - SKILL_ENDURANCE = SKILL_ENDURANCE_MAX, - SKILL_JTAC = SKILL_JTAC_EXPERT, - SKILL_ANTAG = SKILL_ANTAG_HUNTER, - ) - -/datum/skills/cultist_leader - name = "Cultist Leader" - skills = list( - SKILL_FIREARMS = SKILL_FIREARMS_CIVILIAN, - SKILL_CQC = SKILL_CQC_MASTER, - SKILL_MELEE_WEAPONS = SKILL_MELEE_SUPER, - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_MASTER, - SKILL_ENGINEER = SKILL_ENGINEER_MASTER, - SKILL_MEDICAL = SKILL_MEDICAL_MEDIC, - SKILL_LEADERSHIP = SKILL_LEAD_MASTER, - SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED, - SKILL_ENDURANCE = SKILL_ENDURANCE_MAX, - SKILL_JTAC = SKILL_JTAC_MASTER, - ) - -/datum/skills/souto - name = "Souto Man" - skills = list( - SKILL_CQC = SKILL_CQC_MASTER, - SKILL_ENGINEER = SKILL_ENGINEER_ENGI, - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, - SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, - SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, - SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, - SKILL_JTAC = SKILL_JTAC_BEGINNER, - SKILL_SPEC_WEAPONS = SKILL_SPEC_ALL, - ) - -/datum/skills/everything //max it out - name = "Ultra" - skills = list( - SKILL_CQC = SKILL_CQC_MAX, - SKILL_MELEE_WEAPONS = SKILL_MELEE_MAX, - SKILL_FIREARMS = SKILL_FIREARMS_MAX, - SKILL_SPEC_WEAPONS = SKILL_SPEC_ALL, - SKILL_ENDURANCE = SKILL_ENDURANCE_MAX, - SKILL_ENGINEER = SKILL_ENGINEER_MAX, - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_MAX, - SKILL_LEADERSHIP = SKILL_LEAD_MAX, - SKILL_OVERWATCH = SKILL_OVERWATCH_MAX, - SKILL_MEDICAL = SKILL_MEDICAL_MAX, - SKILL_SURGERY = SKILL_SURGERY_MAX, - SKILL_RESEARCH = SKILL_RESEARCH_MAX, - SKILL_ANTAG = SKILL_ANTAG_MAX, - SKILL_PILOT = SKILL_PILOT_MAX, - SKILL_POLICE = SKILL_POLICE_MAX, - SKILL_FIREMAN = SKILL_FIREMAN_MAX, - SKILL_POWERLOADER = SKILL_POWERLOADER_MAX, - SKILL_VEHICLE = SKILL_VEHICLE_MAX, - SKILL_JTAC = SKILL_JTAC_MAX, - SKILL_EXECUTION = SKILL_EXECUTION_MAX, - SKILL_INTEL = SKILL_INTEL_MAX, - ) - -/* ----------------------------- -Royal Marines Commando ----------------------------- -*/ - -//NOTE: Skills take heavy from PMCs - -/datum/skills/rmc - name = "Royal Marines Commando" - skills = list( - SKILL_CQC = SKILL_CQC_TRAINED, - SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, - SKILL_POLICE = SKILL_POLICE_SKILLED, - SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, - SKILL_ENGINEER = SKILL_ENGINEER_ENGI, - SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER, - SKILL_MEDICAL = SKILL_MEDICAL_MEDIC, - SKILL_SURGERY = SKILL_SURGERY_NOVICE, - ) - -/datum/skills/rmc/specialist - name = "Royal Marines Commando Specialist" - skills = list( - SKILL_CQC = SKILL_CQC_TRAINED, - SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, - SKILL_POLICE = SKILL_POLICE_SKILLED, - SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, - SKILL_ENGINEER = SKILL_ENGINEER_ENGI, - SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER, - SKILL_MEDICAL = SKILL_MEDICAL_MEDIC, - SKILL_SURGERY = SKILL_SURGERY_NOVICE, - SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, - SKILL_JTAC = SKILL_JTAC_BEGINNER, - ) - -/datum/skills/rmc/smartgun - name = "Royal Marines Commando Smartgunner" - skills = list( - SKILL_CQC = SKILL_CQC_TRAINED, - SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, - SKILL_POLICE = SKILL_POLICE_SKILLED, - SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, - SKILL_ENGINEER = SKILL_ENGINEER_ENGI, - SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER, - SKILL_MEDICAL = SKILL_MEDICAL_MEDIC, - SKILL_SURGERY = SKILL_SURGERY_NOVICE, - SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, - SKILL_JTAC = SKILL_JTAC_BEGINNER, - SKILL_SPEC_WEAPONS = SKILL_SPEC_SMARTGUN, - ) - -/datum/skills/rmc/leader - name = "Royal Marines Commando Leader" - skills = list( - SKILL_CQC = SKILL_CQC_SKILLED, - SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, - SKILL_POLICE = SKILL_POLICE_SKILLED, - SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, - SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, - SKILL_ENGINEER = SKILL_ENGINEER_ENGI, - SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER, - SKILL_MEDICAL = SKILL_MEDICAL_MEDIC, - SKILL_SURGERY = SKILL_SURGERY_NOVICE, - SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, - SKILL_JTAC = SKILL_JTAC_TRAINED, - SKILL_LEADERSHIP = SKILL_LEAD_TRAINED, - ) diff --git a/code/datums/skills/civilian.dm b/code/datums/skills/civilian.dm new file mode 100644 index 000000000000..9b55adc9b1f4 --- /dev/null +++ b/code/datums/skills/civilian.dm @@ -0,0 +1,213 @@ +/* +--------------------- +CIVILIAN +--------------------- +*/ + +/datum/skills/civilian + name = "Civilian" + skills = list( + SKILL_CQC = SKILL_CQC_DEFAULT, + SKILL_FIREARMS = SKILL_FIREARMS_CIVILIAN, + SKILL_ENDURANCE = SKILL_ENDURANCE_NONE, + SKILL_VEHICLE = SKILL_VEHICLE_SMALL, + ) + +/datum/skills/civilian/manager + name = "Weyland-Yutani Manager" // Semi-competent leader with basic knowledge in most things. + skills = list( + SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED, + SKILL_LEADERSHIP = SKILL_LEAD_MASTER, + SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED, + SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, + SKILL_ENGINEER = SKILL_ENGINEER_TRAINED, + SKILL_VEHICLE = SKILL_VEHICLE_SMALL, + SKILL_INTEL = SKILL_INTEL_EXPERT, + ) + +/datum/skills/civilian/icc_investigation + name = "ICC CL - Black Market ERT" + skills = list( + SKILL_CQC = SKILL_CQC_DEFAULT, + SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED, + SKILL_ENGINEER = SKILL_ENGINEER_ENGI, //The ASRS consoles + SKILL_FIREARMS = SKILL_FIREARMS_CIVILIAN, + SKILL_POLICE = SKILL_POLICE_SKILLED, //The CMB Tradeband Compliance Device + ) + +/datum/skills/civilian/manager/director + name = "Weyland-Yutani Director" + skills = list( + SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED, + SKILL_LEADERSHIP = SKILL_LEAD_MASTER, + SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED, + SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, + SKILL_ENGINEER = SKILL_ENGINEER_TRAINED, + SKILL_VEHICLE = SKILL_VEHICLE_SMALL, + SKILL_POLICE = SKILL_POLICE_SKILLED, + SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, + SKILL_EXECUTION = SKILL_EXECUTION_TRAINED, + SKILL_INTEL = SKILL_INTEL_EXPERT, + ) + +//civilian that are survivor could be in is own file maybe + +/datum/skills/civilian/survivor + name = "Survivor" + skills = list( + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED, + SKILL_ENDURANCE = SKILL_ENDURANCE_SURVIVOR, + ) + +/datum/skills/civilian/survivor/manager + name = "Weyland-Yutani Manager" + skills = list( + SKILL_LEADERSHIP = SKILL_LEAD_MASTER, + SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED, + SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, + SKILL_INTEL = SKILL_INTEL_EXPERT, + ) + +/datum/skills/civilian/survivor/goon + name = "Survivor Goon" + skills = list( + SKILL_CQC = SKILL_CQC_TRAINED, + SKILL_POLICE = SKILL_POLICE_SKILLED, + SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, + SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, + SKILL_ENDURANCE = SKILL_ENDURANCE_SURVIVOR, + SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, + SKILL_VEHICLE = SKILL_VEHICLE_SMALL, + ) + +/datum/skills/civilian/survivor/pmc + name = "Survivor PMC" + additional_skills = list( + SKILL_CQC = SKILL_CQC_TRAINED, + SKILL_POLICE = SKILL_POLICE_SKILLED, + SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, + SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, + SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, + SKILL_VEHICLE = SKILL_VEHICLE_SMALL, + ) + +/datum/skills/civilian/survivor/pmc/medic + name = "Survivor PMC Medic" + additional_skills = list( + SKILL_POLICE = SKILL_POLICE_SKILLED, + SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, + SKILL_MEDICAL = SKILL_MEDICAL_MEDIC, + SKILL_SURGERY = SKILL_SURGERY_NOVICE, + SKILL_ENDURANCE = SKILL_ENDURANCE_SURVIVOR, + SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, + SKILL_VEHICLE = SKILL_VEHICLE_SMALL, + ) + +/datum/skills/civilian/survivor/pmc/engineer + name = "Survivor PMC Engineer" + additional_skills = list( + SKILL_POLICE = SKILL_POLICE_SKILLED, + SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, + SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, + SKILL_ENDURANCE = SKILL_ENDURANCE_SURVIVOR, + SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, + SKILL_VEHICLE = SKILL_VEHICLE_SMALL, + SKILL_ENGINEER = SKILL_ENGINEER_ENGI, + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, + SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER, + ) + +/datum/skills/civilian/survivor/doctor + name = "Survivor Doctor" + additional_skills = list( + SKILL_MEDICAL = SKILL_MEDICAL_DOCTOR, + SKILL_SURGERY = SKILL_SURGERY_TRAINED, + ) + +/datum/skills/civilian/survivor/clf + name = "Survivor CLF" + additional_skills = list( + SKILL_ENGINEER = SKILL_ENGINEER_TRAINED, + SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, + SKILL_VEHICLE = SKILL_VEHICLE_SMALL, + SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, + ) + +/datum/skills/civilian/survivor/scientist + name = "Survivor Scientist" + additional_skills = list( + SKILL_MEDICAL = SKILL_MEDICAL_DOCTOR, + SKILL_SURGERY = SKILL_SURGERY_TRAINED, + SKILL_RESEARCH = SKILL_RESEARCH_TRAINED, + ) + +/datum/skills/civilian/survivor/chef + name = "Survivor Chef" + additional_skills = list( + SKILL_MELEE_WEAPONS = SKILL_MELEE_SUPER, + SKILL_DOMESTIC = SKILL_DOMESTIC_TRAINED, + ) + +/datum/skills/civilian/survivor/miner + name = "Survivor Miner" + additional_skills = list( + SKILL_ENGINEER = SKILL_ENGINEER_TRAINED, + SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER, + SKILL_VEHICLE = SKILL_VEHICLE_SMALL, + ) + +/datum/skills/civilian/survivor/trucker + name = "Survivor Trucker" + additional_skills = list( + SKILL_ENGINEER = SKILL_ENGINEER_ENGI, + SKILL_VEHICLE = SKILL_VEHICLE_CREWMAN, + ) + +/datum/skills/civilian/survivor/engineer + name = "Survivor Engineer" + additional_skills = list( + SKILL_ENGINEER = SKILL_ENGINEER_ENGI, + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, + SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER, + SKILL_VEHICLE = SKILL_VEHICLE_SMALL, + ) + +/datum/skills/civilian/survivor/chaplain + name = "Survivor Chaplain" + additional_skills = list( + SKILL_LEADERSHIP = SKILL_LEAD_TRAINED, + ) + +/datum/skills/civilian/survivor/marshal + name = "Survivor Marshal" + skills = list( + SKILL_ENGINEER = SKILL_ENGINEER_ENGI, + SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED, + SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, + SKILL_ENDURANCE = SKILL_ENDURANCE_SURVIVOR, + SKILL_CQC = SKILL_CQC_SKILLED, + SKILL_FIREARMS = SKILL_FIREARMS_TRAINED, + SKILL_POLICE = SKILL_POLICE_SKILLED, + SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, + SKILL_ENGINEER = SKILL_ENGINEER_TRAINED, + SKILL_CQC = SKILL_CQC_SKILLED, + SKILL_FIREARMS = SKILL_FIREARMS_TRAINED, + ) + +/datum/skills/civilian/survivor/prisoner + name = "Survivor Prisoner" + additional_skills = list( + SKILL_CQC = SKILL_CQC_SKILLED, + SKILL_FIREARMS = SKILL_FIREARMS_TRAINED, + SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, + SKILL_VEHICLE = SKILL_VEHICLE_SMALL, + ) + +/datum/skills/civilian/survivor/gangleader + name = "Survivor Gang Leader" + additional_skills = list( + SKILL_CQC = SKILL_CQC_SKILLED, + SKILL_FIREARMS = SKILL_FIREARMS_TRAINED, + SKILL_LEADERSHIP = SKILL_LEAD_TRAINED, + ) diff --git a/code/datums/skills/clf.dm b/code/datums/skills/clf.dm new file mode 100644 index 000000000000..6042febb6b48 --- /dev/null +++ b/code/datums/skills/clf.dm @@ -0,0 +1,92 @@ +/* +------------------------- +COLONIAL LIBERATION FRONT +------------------------- +*/ + +/datum/skills/clf + name = "CLF Soldier" + skills = list( + SKILL_FIREARMS = SKILL_FIREARMS_TRAINED, + SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, + SKILL_POLICE = SKILL_POLICE_SKILLED, + SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED, + SKILL_ENGINEER = SKILL_ENGINEER_TRAINED, + SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, + SKILL_VEHICLE = SKILL_VEHICLE_SMALL, + SKILL_ENDURANCE = SKILL_ENDURANCE_WEAK, + SKILL_JTAC = SKILL_JTAC_BEGINNER, + ) + +/datum/skills/clf/combat_engineer + name = "CLF Engineer" + skills = list( + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, + SKILL_ENGINEER = SKILL_ENGINEER_ENGI, + SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, + SKILL_POWERLOADER = SKILL_POWERLOADER_TRAINED, + SKILL_VEHICLE = SKILL_VEHICLE_SMALL, + SKILL_ENDURANCE = SKILL_ENDURANCE_WEAK, + SKILL_JTAC = SKILL_JTAC_BEGINNER, + ) + +/datum/skills/clf/combat_medic + name = "CLF Medic" + skills = list( + SKILL_MEDICAL = SKILL_MEDICAL_MEDIC, + SKILL_SURGERY = SKILL_SURGERY_TRAINED, + SKILL_VEHICLE = SKILL_VEHICLE_SMALL, + SKILL_ENDURANCE = SKILL_ENDURANCE_WEAK, + SKILL_JTAC = SKILL_JTAC_BEGINNER, + ) + +/datum/skills/clf/specialist + name = "CLF Specialist" + skills = list( + SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, + SKILL_CQC = SKILL_CQC_TRAINED, + SKILL_ENGINEER = SKILL_ENGINEER_TRAINED, //to use c4 in demo set. + SKILL_LEADERSHIP = SKILL_LEAD_TRAINED, + SKILL_SPEC_WEAPONS = SKILL_SPEC_ALL, + SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED, + SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, + SKILL_JTAC = SKILL_JTAC_TRAINED + ) + +/datum/skills/clf/leader + name = "CLF Leader" + skills = list( + SKILL_FIREARMS = SKILL_FIREARMS_TRAINED, + SKILL_ENGINEER = SKILL_ENGINEER_ENGI, // to use their C4 + SKILL_CQC = SKILL_CQC_SKILLED, + SKILL_LEADERSHIP = SKILL_LEAD_EXPERT, + SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED, + SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, + SKILL_POLICE = SKILL_POLICE_SKILLED, + SKILL_FIREMAN = SKILL_FIREMAN_EXPERT, + SKILL_POWERLOADER = SKILL_POWERLOADER_TRAINED, + SKILL_VEHICLE = SKILL_VEHICLE_SMALL, + SKILL_ENDURANCE = SKILL_ENDURANCE_MAX, + SKILL_JTAC = SKILL_JTAC_EXPERT, + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI + ) + +/datum/skills/clf/commander + name = "CLF Cell Commander" + skills = list( + SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, + SKILL_ENGINEER = SKILL_ENGINEER_ENGI, + SKILL_CQC = SKILL_CQC_SKILLED, + SKILL_LEADERSHIP = SKILL_LEAD_MASTER, + SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED, + SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, + SKILL_POLICE = SKILL_POLICE_SKILLED, + SKILL_FIREMAN = SKILL_FIREMAN_EXPERT, + SKILL_POWERLOADER = SKILL_POWERLOADER_TRAINED, + SKILL_VEHICLE = SKILL_VEHICLE_LARGE, + SKILL_ENDURANCE = SKILL_ENDURANCE_MAX, + SKILL_JTAC = SKILL_JTAC_MASTER, + SKILL_SPEC_WEAPONS = SKILL_SPEC_SMARTGUN, + SKILL_EXECUTION = SKILL_EXECUTION_TRAINED, + ) diff --git a/code/datums/skills/cmb.dm b/code/datums/skills/cmb.dm new file mode 100644 index 000000000000..b29a4c314567 --- /dev/null +++ b/code/datums/skills/cmb.dm @@ -0,0 +1,60 @@ +/* +--------------------- +COLONIAL MARSHALS +--------------------- +*/ +/datum/skills/cmb + name = "CMB Deputy" + skills = list( + SKILL_POLICE = SKILL_POLICE_SKILLED, + SKILL_CQC = SKILL_CQC_EXPERT, + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_DEFAULT, + SKILL_FIREARMS = SKILL_FIREARMS_TRAINED, + SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, + SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, + SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, + SKILL_JTAC = SKILL_JTAC_BEGINNER, + SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER, + ) + +/datum/skills/cmb/leader + name = "CMB Marshal" + skills = list( + SKILL_POLICE = SKILL_POLICE_SKILLED, + SKILL_CQC = SKILL_CQC_EXPERT, + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, + SKILL_LEADERSHIP = SKILL_LEAD_MASTER, + SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED, + SKILL_MEDICAL = SKILL_MEDICAL_MEDIC, + SKILL_ENGINEER = SKILL_ENGINEER_ENGI, + SKILL_FIREMAN = SKILL_FIREMAN_MASTER, + SKILL_FIREARMS = SKILL_FIREARMS_MAX, + SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, + SKILL_VEHICLE = SKILL_VEHICLE_SMALL, + SKILL_ENDURANCE = SKILL_ENDURANCE_EXPERT, + SKILL_JTAC = SKILL_JTAC_EXPERT, + ) + +/datum/skills/synthetic/cmb + name = "CMB Investigative Synthetic" + skills = list( + SKILL_CQC = SKILL_CQC_MASTER, + SKILL_ENGINEER = SKILL_ENGINEER_MASTER, + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_MASTER, + SKILL_FIREARMS = SKILL_FIREARMS_TRAINED, + SKILL_SPEC_WEAPONS = SKILL_SPEC_ALL, + SKILL_LEADERSHIP = SKILL_LEAD_EXPERT, // incase the synth needs to use consoles for investigations or tracking + SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED, + SKILL_MEDICAL = SKILL_MEDICAL_DOCTOR, + SKILL_SURGERY = SKILL_SURGERY_TRAINED, // Not a medical Synthetic, but operate if absolutely needed. + SKILL_RESEARCH = SKILL_RESEARCH_TRAINED, + SKILL_MELEE_WEAPONS = SKILL_MELEE_SUPER, + SKILL_PILOT = SKILL_PILOT_TRAINED, + SKILL_POLICE = SKILL_POLICE_SKILLED, + SKILL_FIREMAN = SKILL_FIREMAN_MAX, + SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER, + SKILL_VEHICLE = SKILL_VEHICLE_LARGE, + SKILL_JTAC = SKILL_JTAC_BEGINNER, + SKILL_INTEL = SKILL_INTEL_EXPERT, + SKILL_DOMESTIC = SKILL_DOMESTIC_MASTER + ) diff --git a/code/datums/skills/commando.dm b/code/datums/skills/commando.dm new file mode 100644 index 000000000000..dabae682bd0b --- /dev/null +++ b/code/datums/skills/commando.dm @@ -0,0 +1,116 @@ +/* +--------------------- +SPEC-OPS +--------------------- +*/ + +/datum/skills/commando + name = "Commando" + skills = list( + SKILL_CQC = SKILL_CQC_EXPERT, + SKILL_ENGINEER = SKILL_ENGINEER_ENGI, + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, + SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, + SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, + SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, + SKILL_ENDURANCE = SKILL_ENDURANCE_MAX, + SKILL_SPEC_WEAPONS = SKILL_SPEC_ALL, + SKILL_JTAC = SKILL_JTAC_BEGINNER, + ) + +/datum/skills/commando/medic + name = "Commando Medic" + skills = list( + SKILL_CQC = SKILL_CQC_EXPERT, + SKILL_ENGINEER = SKILL_ENGINEER_ENGI, + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, + SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, + SKILL_MEDICAL = SKILL_MEDICAL_MEDIC, + SKILL_SURGERY = SKILL_SURGERY_NOVICE, + SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, + SKILL_ENDURANCE = SKILL_ENDURANCE_MAX, + SKILL_SPEC_WEAPONS = SKILL_SPEC_ALL, + SKILL_JTAC = SKILL_JTAC_BEGINNER, + ) + +/datum/skills/commando/leader + name = "Commando Leader" + skills = list( + SKILL_CQC = SKILL_CQC_EXPERT, + SKILL_ENGINEER = SKILL_ENGINEER_ENGI, + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, + SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, + SKILL_LEADERSHIP = SKILL_LEAD_TRAINED, + SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, + SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, + SKILL_ENDURANCE = SKILL_ENDURANCE_MAX, + SKILL_SPEC_WEAPONS = SKILL_SPEC_ALL, + SKILL_JTAC = SKILL_JTAC_TRAINED, + ) + +/datum/skills/commando/deathsquad + name = "Deathsquad" + skills = list( + SKILL_CQC = SKILL_CQC_MASTER, + SKILL_ENGINEER = SKILL_ENGINEER_ENGI, + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, + SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, + SKILL_MEDICAL = SKILL_MEDICAL_MEDIC, + SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, + SKILL_ENDURANCE = SKILL_ENDURANCE_MAX, + SKILL_SPEC_WEAPONS = SKILL_SPEC_ALL, + SKILL_JTAC = SKILL_JTAC_BEGINNER, + ) + +/datum/skills/commando/deathsquad/leader + name = "Deathsquad Leader" + skills = list( + SKILL_CQC = SKILL_CQC_MASTER, + SKILL_ENGINEER = SKILL_ENGINEER_ENGI, + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, + SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, + SKILL_LEADERSHIP = SKILL_LEAD_TRAINED, + SKILL_MEDICAL = SKILL_MEDICAL_MEDIC, + SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, + SKILL_ENDURANCE = SKILL_ENDURANCE_MAX, + SKILL_SPEC_WEAPONS = SKILL_SPEC_ALL, + SKILL_JTAC = SKILL_JTAC_BEGINNER, + ) + +/datum/skills/commando/deathsquad/officer + name = "Deathsquad Officer" + skills = list( + SKILL_CQC = SKILL_CQC_MASTER, + SKILL_ENGINEER = SKILL_ENGINEER_ENGI, + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, + SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, + SKILL_LEADERSHIP = SKILL_LEAD_EXPERT, + SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED, + SKILL_MEDICAL = SKILL_MEDICAL_MEDIC, + SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, + SKILL_ENDURANCE = SKILL_ENDURANCE_MAX, + SKILL_SPEC_WEAPONS = SKILL_SPEC_ALL, + SKILL_JTAC = SKILL_JTAC_BEGINNER, + ) + +/datum/skills/spy + name = "Spy" + skills = list( + SKILL_CQC = SKILL_CQC_TRAINED, + SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, + SKILL_ENGINEER = SKILL_ENGINEER_ENGI, + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, + SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, + SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER, + SKILL_JTAC = SKILL_JTAC_BEGINNER, + ) + +/datum/skills/ninja + name = "Ninja" + skills = list( + SKILL_CQC = SKILL_CQC_MASTER, + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED, + SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, + SKILL_MELEE_WEAPONS = SKILL_MELEE_SUPER, + SKILL_JTAC = SKILL_JTAC_BEGINNER, + ) diff --git a/code/datums/skills/contractor.dm b/code/datums/skills/contractor.dm new file mode 100644 index 000000000000..183e95c941f5 --- /dev/null +++ b/code/datums/skills/contractor.dm @@ -0,0 +1,90 @@ +/* +--------------------- +CONTRACTORS +--------------------- +*/ +/datum/skills/contractor + name = "Contractor Standard" + skills = list( + SKILL_CQC = SKILL_CQC_TRAINED, + SKILL_ENGINEER = SKILL_ENGINEER_TRAINED, + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED, + SKILL_FIREARMS = SKILL_FIREARMS_MAX, + SKILL_POLICE = SKILL_POLICE_SKILLED, + SKILL_FIREMAN = SKILL_FIREMAN_EXPERT, + SKILL_VEHICLE = SKILL_VEHICLE_LARGE, + SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, + SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, + SKILL_JTAC = SKILL_JTAC_BEGINNER, + SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED, + ) + +/datum/skills/contractor/leader + name = "Contractor Leader" + skills = list( + SKILL_ENGINEER = SKILL_ENGINEER_ENGI, + SKILL_FIREARMS = SKILL_FIREARMS_MAX, + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, + SKILL_LEADERSHIP = SKILL_LEAD_MASTER, + SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED, + SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, + SKILL_POLICE = SKILL_POLICE_SKILLED, + SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, + SKILL_CQC = SKILL_CQC_SKILLED, + SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, + SKILL_VEHICLE = SKILL_VEHICLE_LARGE, + SKILL_POWERLOADER = SKILL_POWERLOADER_TRAINED, + SKILL_ENDURANCE = SKILL_ENDURANCE_EXPERT, + SKILL_JTAC = SKILL_JTAC_MASTER, + ) + +/datum/skills/contractor/medic + name = "Contractor Medic" + skills = list( + SKILL_FIREARMS = SKILL_FIREARMS_MAX, + SKILL_POLICE = SKILL_POLICE_SKILLED, + SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED, + SKILL_ENGINEER = SKILL_ENGINEER_TRAINED, + SKILL_MEDICAL = SKILL_MEDICAL_DOCTOR, + SKILL_SURGERY = SKILL_SURGERY_TRAINED, + SKILL_VEHICLE = SKILL_VEHICLE_LARGE, + SKILL_ENDURANCE = SKILL_ENDURANCE_EXPERT, + SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, + SKILL_CQC = SKILL_CQC_TRAINED, + SKILL_JTAC = SKILL_JTAC_BEGINNER, + ) + +/datum/skills/contractor/engi + name = "Contractor Engi" + skills = list( + SKILL_CQC = SKILL_CQC_TRAINED, + SKILL_ENGINEER = SKILL_ENGINEER_MAX, + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_MAX, + SKILL_FIREARMS = SKILL_FIREARMS_MAX, + SKILL_POLICE = SKILL_POLICE_SKILLED, + SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, + SKILL_VEHICLE = SKILL_VEHICLE_LARGE, + SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, + SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, + SKILL_JTAC = SKILL_JTAC_EXPERT, + SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED, + SKILL_POWERLOADER = SKILL_POWERLOADER_TRAINED, + ) + +/datum/skills/contractor/heavy + name = "Contractor Machinegunner" + skills = list( + SKILL_CQC = SKILL_CQC_TRAINED, + SKILL_ENGINEER = SKILL_ENGINEER_TRAINED, + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED, + SKILL_FIREARMS = SKILL_FIREARMS_MAX, + SKILL_POLICE = SKILL_POLICE_SKILLED, + SKILL_FIREMAN = SKILL_FIREMAN_EXPERT, + SKILL_VEHICLE = SKILL_VEHICLE_LARGE, + SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, + SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, + SKILL_SPEC_WEAPONS = SKILL_SPEC_SMARTGUN, + SKILL_JTAC = SKILL_JTAC_BEGINNER, + SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED, + ) diff --git a/code/datums/skills/dutch.dm b/code/datums/skills/dutch.dm new file mode 100644 index 000000000000..5c2c63a8c463 --- /dev/null +++ b/code/datums/skills/dutch.dm @@ -0,0 +1,46 @@ +/datum/skills/dutch + name = "Dutch" + skills = list( + SKILL_CQC = SKILL_CQC_MASTER, + SKILL_MELEE_WEAPONS = SKILL_MELEE_MAX, + SKILL_ENGINEER = SKILL_ENGINEER_ENGI, + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, + SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, + SKILL_LEADERSHIP = SKILL_LEAD_MASTER, + SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED, + SKILL_MEDICAL = SKILL_MEDICAL_DOCTOR, + SKILL_SPEC_WEAPONS = SKILL_SPEC_ALL, + SKILL_ENDURANCE = SKILL_ENDURANCE_MAX, + SKILL_JTAC = SKILL_JTAC_EXPERT, + SKILL_ANTAG = SKILL_ANTAG_HUNTER, + ) + +/datum/skills/dutchmerc + name = "Dutch's Dozen Mercenary" + skills = list( + SKILL_CQC = SKILL_CQC_TRAINED, + SKILL_ENGINEER = SKILL_ENGINEER_ENGI, + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, + SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, + SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, + SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, + SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, + SKILL_SPEC_WEAPONS = SKILL_SPEC_ALL, + SKILL_JTAC = SKILL_JTAC_BEGINNER, + SKILL_ENDURANCE = SKILL_ENDURANCE_EXPERT, + ) + +/datum/skills/dutchmedic + name = "Dutch's Dozen Medic" + skills = list( + SKILL_CQC = SKILL_CQC_TRAINED, + SKILL_ENGINEER = SKILL_ENGINEER_ENGI, + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED, + SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, + SKILL_MEDICAL = SKILL_MEDICAL_DOCTOR, + SKILL_SURGERY = SKILL_SURGERY_NOVICE, + SKILL_FIREMAN = SKILL_FIREMAN_EXPERT, + SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, + SKILL_JTAC = SKILL_JTAC_BEGINNER, + SKILL_ENDURANCE = SKILL_ENDURANCE_EXPERT, + ) diff --git a/code/datums/skills/forecon.dm b/code/datums/skills/forecon.dm new file mode 100644 index 000000000000..4799dd68d617 --- /dev/null +++ b/code/datums/skills/forecon.dm @@ -0,0 +1,102 @@ +/* +--------------------- +MILITARY SURVIVORS +--------------------- +*/ +//Hardcore survivors with poor equipment and skills, prove you're the best of the best. + +/datum/skills/military/survivor/forecon_standard + name = "Reconnaissance Rifleman" + skills = list( + SKILL_ENGINEER = SKILL_ENGINEER_ENGI, + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_DEFAULT, + SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, + SKILL_CQC = SKILL_CQC_TRAINED, + SKILL_FIREARMS = SKILL_FIREARMS_TRAINED, + SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, + SKILL_ENDURANCE = SKILL_ENDURANCE_SURVIVOR, + SKILL_LEADERSHIP = SKILL_LEAD_NOVICE, + SKILL_VEHICLE = SKILL_VEHICLE_DEFAULT, + SKILL_JTAC = SKILL_JTAC_TRAINED, + ) + +/datum/skills/military/survivor/forecon_techician + name = "Reconnaissance Support Technician" + skills = list( + SKILL_ENGINEER = SKILL_ENGINEER_ENGI, + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, + SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, + SKILL_CQC = SKILL_CQC_TRAINED, + SKILL_FIREARMS = SKILL_FIREARMS_TRAINED, + SKILL_MEDICAL = SKILL_MEDICAL_MEDIC, + SKILL_SURGERY = SKILL_SURGERY_NOVICE, + SKILL_ENDURANCE = SKILL_ENDURANCE_SURVIVOR, + SKILL_LEADERSHIP = SKILL_LEAD_NOVICE, + SKILL_VEHICLE = SKILL_VEHICLE_DEFAULT, + SKILL_JTAC = SKILL_JTAC_TRAINED, + ) + +/datum/skills/military/survivor/forecon_marksman + name = "Reconnaissance Designated Marksman" + skills = list( + SKILL_ENGINEER = SKILL_ENGINEER_ENGI, + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_DEFAULT, + SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, + SKILL_CQC = SKILL_CQC_TRAINED, + SKILL_FIREARMS = SKILL_FIREARMS_TRAINED, + SKILL_SPEC_WEAPONS = SKILL_SPEC_SCOUT, + SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, + SKILL_ENDURANCE = SKILL_ENDURANCE_SURVIVOR, + SKILL_LEADERSHIP = SKILL_LEAD_NOVICE, + SKILL_VEHICLE = SKILL_VEHICLE_DEFAULT, + SKILL_JTAC = SKILL_JTAC_TRAINED, + ) + +/datum/skills/military/survivor/forecon_smartgunner + name = "Reconnaissance Smartgunner" + skills = list( + SKILL_ENGINEER = SKILL_ENGINEER_ENGI, + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_DEFAULT, + SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, + SKILL_CQC = SKILL_CQC_TRAINED, + SKILL_FIREARMS = SKILL_FIREARMS_TRAINED, + SKILL_SPEC_WEAPONS = SKILL_SPEC_SMARTGUN, + SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, + SKILL_ENDURANCE = SKILL_ENDURANCE_SURVIVOR, + SKILL_LEADERSHIP = SKILL_LEAD_NOVICE, + SKILL_VEHICLE = SKILL_VEHICLE_DEFAULT, + SKILL_JTAC = SKILL_JTAC_TRAINED, + ) + +/datum/skills/military/survivor/forecon_sniper + name = "Reconnaissance Sniper" + skills = list( + SKILL_ENGINEER = SKILL_ENGINEER_ENGI, + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_DEFAULT, + SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, + SKILL_CQC = SKILL_CQC_TRAINED, + SKILL_FIREARMS = SKILL_FIREARMS_TRAINED, + SKILL_SPEC_WEAPONS = SKILL_SPEC_SNIPER, + SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, + SKILL_ENDURANCE = SKILL_ENDURANCE_SURVIVOR, + SKILL_LEADERSHIP = SKILL_LEAD_NOVICE, + SKILL_VEHICLE = SKILL_VEHICLE_DEFAULT, + SKILL_JTAC = SKILL_JTAC_TRAINED, + ) + +/datum/skills/military/survivor/forecon_squad_leader + name = "Reconnaissance Squad Leader" + skills = list( + SKILL_ENGINEER = SKILL_ENGINEER_ENGI, + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_DEFAULT, + SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, + SKILL_CQC = SKILL_CQC_SKILLED, + SKILL_FIREARMS = SKILL_FIREARMS_TRAINED, + SKILL_POLICE = SKILL_POLICE_SKILLED, + SKILL_JTAC = SKILL_JTAC_TRAINED, + SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, + SKILL_ENDURANCE = SKILL_ENDURANCE_SURVIVOR, + SKILL_LEADERSHIP = SKILL_LEAD_TRAINED, + SKILL_VEHICLE = SKILL_VEHICLE_DEFAULT, + SKILL_JTAC = SKILL_JTAC_TRAINED, + ) diff --git a/code/datums/skills/freelancer.dm b/code/datums/skills/freelancer.dm new file mode 100644 index 000000000000..7f7256318edb --- /dev/null +++ b/code/datums/skills/freelancer.dm @@ -0,0 +1,40 @@ +/* +----------- +FREELANCERS +----------- +*/ + +//NOTE: Freelancer training is similar to the USCM's, but with additional construction skills + +/datum/skills/freelancer + name = "Freelancer Private" + skills = list( + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, + SKILL_ENGINEER = SKILL_ENGINEER_ENGI, + SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED, + ) + +/datum/skills/freelancer/combat_medic + name = "Freelancer Medic" + skills = list( + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, + SKILL_ENGINEER = SKILL_ENGINEER_ENGI, + SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED, + SKILL_MEDICAL = SKILL_MEDICAL_MEDIC, + SKILL_SURGERY = SKILL_SURGERY_TRAINED, + ) + +/datum/skills/freelancer/SL + name = "Freelancer Leader" + skills = list( + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, + SKILL_ENGINEER = SKILL_ENGINEER_ENGI, + SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED, + SKILL_MEDICAL = SKILL_MEDICAL_MEDIC, + SKILL_CQC = SKILL_CQC_TRAINED, + SKILL_LEADERSHIP = SKILL_LEAD_EXPERT, + SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED, + SKILL_JTAC = SKILL_JTAC_EXPERT, + ) + + diff --git a/code/datums/skills/gladiator.dm b/code/datums/skills/gladiator.dm new file mode 100644 index 000000000000..7ba2c9eff455 --- /dev/null +++ b/code/datums/skills/gladiator.dm @@ -0,0 +1,33 @@ +/datum/skills/gladiator + name = "Gladiator" + skills = list( + SKILL_CQC = SKILL_CQC_SKILLED, + SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, + SKILL_FIREARMS = SKILL_FIREARMS_CIVILIAN, + SKILL_LEADERSHIP = SKILL_LEAD_NOVICE, + SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, + SKILL_ENDURANCE = SKILL_ENDURANCE_MAX, + ) + +/datum/skills/gladiator/champion + name = "Gladiator Champion" + skills = list( + SKILL_CQC = SKILL_CQC_MASTER, + SKILL_MELEE_WEAPONS = SKILL_MELEE_SUPER, + SKILL_LEADERSHIP = SKILL_LEAD_TRAINED, + SKILL_MEDICAL = SKILL_MEDICAL_MEDIC, + SKILL_ENDURANCE = SKILL_ENDURANCE_MAX, + SKILL_JTAC = SKILL_JTAC_TRAINED, + ) + +/datum/skills/gladiator/champion/leader + name = "Gladiator Leader" + skills = list( + SKILL_CQC = SKILL_CQC_MASTER, + SKILL_MELEE_WEAPONS = SKILL_MELEE_SUPER, + SKILL_MEDICAL = SKILL_MEDICAL_MEDIC, + SKILL_LEADERSHIP = SKILL_LEAD_MASTER, //Spartacus! + SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED, + SKILL_ENDURANCE = SKILL_ENDURANCE_MAX, + SKILL_JTAC = SKILL_JTAC_MASTER, + ) diff --git a/code/datums/skills/mercenary.dm b/code/datums/skills/mercenary.dm new file mode 100644 index 000000000000..8d842ea30dd2 --- /dev/null +++ b/code/datums/skills/mercenary.dm @@ -0,0 +1,85 @@ +/datum/skills/mercenary + name = "Mercenary" + skills = list( + SKILL_CQC = SKILL_CQC_SKILLED, + SKILL_ENGINEER = SKILL_ENGINEER_ENGI, + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, + SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, + SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, + SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, + SKILL_JTAC = SKILL_JTAC_BEGINNER, + ) + +/datum/skills/mercenary/elite + name = "Elite Mercenary" + skills = list( + SKILL_CQC = SKILL_CQC_SKILLED, + SKILL_ENGINEER = SKILL_ENGINEER_ENGI, + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, + SKILL_FIREARMS = SKILL_FIREARMS_MAX, + SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, + SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, + SKILL_JTAC = SKILL_JTAC_BEGINNER, + SKILL_ENDURANCE = SKILL_ENDURANCE_MAX, + SKILL_VEHICLE = SKILL_VEHICLE_SMALL, + ) + +/datum/skills/mercenary/elite/medic + name = "Elite Mercenary Medic" + skills = list( + SKILL_CQC = SKILL_CQC_SKILLED, + SKILL_ENGINEER = SKILL_ENGINEER_ENGI, + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, + SKILL_FIREARMS = SKILL_FIREARMS_MAX, + SKILL_MEDICAL = SKILL_MEDICAL_MASTER, + SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, + SKILL_JTAC = SKILL_JTAC_BEGINNER, + SKILL_ENDURANCE = SKILL_ENDURANCE_MAX, + SKILL_SURGERY = SKILL_SURGERY_TRAINED, + ) + +/datum/skills/mercenary/elite/engineer + name = "Elite Mercenary Engineer" + skills = list( + SKILL_CQC = SKILL_CQC_SKILLED, + SKILL_ENGINEER = SKILL_ENGINEER_MASTER, + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_MASTER, + SKILL_FIREARMS = SKILL_FIREARMS_MAX, + SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, + SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, + SKILL_JTAC = SKILL_JTAC_BEGINNER, + SKILL_ENDURANCE = SKILL_ENDURANCE_MAX, + SKILL_VEHICLE = SKILL_VEHICLE_SMALL, + SKILL_PILOT = SKILL_PILOT_EXPERT, + ) + +/datum/skills/mercenary/elite/heavy + name = "Elite Mercenary Heavy" + skills = list( + SKILL_CQC = SKILL_CQC_SKILLED, + SKILL_ENGINEER = SKILL_ENGINEER_ENGI, + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, + SKILL_FIREARMS = SKILL_FIREARMS_MAX, + SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, + SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, + SKILL_JTAC = SKILL_JTAC_BEGINNER, + SKILL_ENDURANCE = SKILL_ENDURANCE_MAX, + SKILL_VEHICLE = SKILL_VEHICLE_SMALL, + SKILL_SPEC_WEAPONS = SKILL_SPEC_ALL, + ) + +/datum/skills/mercenary/elite/leader + name = "Elite Mercenary Leader" + skills = list( + SKILL_CQC = SKILL_CQC_SKILLED, + SKILL_ENGINEER = SKILL_ENGINEER_ENGI, + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, + SKILL_FIREARMS = SKILL_FIREARMS_MAX, + SKILL_LEADERSHIP = SKILL_LEAD_MASTER, + SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED, + SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, + SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, + SKILL_JTAC = SKILL_JTAC_MASTER, + SKILL_ENDURANCE = SKILL_ENDURANCE_MAX, + SKILL_PILOT = SKILL_PILOT_EXPERT, + ) diff --git a/code/datums/skills/misc.dm b/code/datums/skills/misc.dm new file mode 100644 index 000000000000..e4f78219b5c6 --- /dev/null +++ b/code/datums/skills/misc.dm @@ -0,0 +1,86 @@ +/* +--------------------- +MISCELLANEOUS +--------------------- +*/ + +/datum/skills/tank_crew + name = "Vehicle Crewman" + skills = list( + SKILL_VEHICLE = SKILL_VEHICLE_CREWMAN, + SKILL_LEADERSHIP = SKILL_LEAD_EXPERT, + SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED, + SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER, + SKILL_ENGINEER = SKILL_ENGINEER_ENGI, + SKILL_LEADERSHIP = SKILL_LEAD_TRAINED, + SKILL_JTAC = SKILL_JTAC_EXPERT, + ) + +/datum/skills/yautja/warrior + name = "Yautja Warrior" + skills = list( + SKILL_CQC = SKILL_CQC_MASTER, + SKILL_MELEE_WEAPONS = SKILL_MELEE_SUPER, + SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER, + SKILL_ENGINEER = SKILL_ENGINEER_ENGI, + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, + SKILL_MEDICAL = SKILL_MEDICAL_MEDIC, + SKILL_SURGERY = SKILL_SURGERY_EXPERT, + SKILL_POLICE = SKILL_POLICE_SKILLED, + SKILL_FIREMAN = SKILL_FIREMAN_MAX, + SKILL_ANTAG = SKILL_ANTAG_HUNTER, + ) + +/datum/skills/cultist_leader + name = "Cultist Leader" + skills = list( + SKILL_FIREARMS = SKILL_FIREARMS_CIVILIAN, + SKILL_CQC = SKILL_CQC_MASTER, + SKILL_MELEE_WEAPONS = SKILL_MELEE_SUPER, + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_MASTER, + SKILL_ENGINEER = SKILL_ENGINEER_MASTER, + SKILL_MEDICAL = SKILL_MEDICAL_MEDIC, + SKILL_LEADERSHIP = SKILL_LEAD_MASTER, + SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED, + SKILL_ENDURANCE = SKILL_ENDURANCE_MAX, + SKILL_JTAC = SKILL_JTAC_MASTER, + ) + +/datum/skills/souto + name = "Souto Man" + skills = list( + SKILL_CQC = SKILL_CQC_MASTER, + SKILL_ENGINEER = SKILL_ENGINEER_ENGI, + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, + SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, + SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, + SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, + SKILL_JTAC = SKILL_JTAC_BEGINNER, + SKILL_SPEC_WEAPONS = SKILL_SPEC_ALL, + ) + +/datum/skills/everything //max it out + name = "Ultra" + skills = list( + SKILL_CQC = SKILL_CQC_MAX, + SKILL_MELEE_WEAPONS = SKILL_MELEE_MAX, + SKILL_FIREARMS = SKILL_FIREARMS_MAX, + SKILL_SPEC_WEAPONS = SKILL_SPEC_ALL, + SKILL_ENDURANCE = SKILL_ENDURANCE_MAX, + SKILL_ENGINEER = SKILL_ENGINEER_MAX, + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_MAX, + SKILL_LEADERSHIP = SKILL_LEAD_MAX, + SKILL_OVERWATCH = SKILL_OVERWATCH_MAX, + SKILL_MEDICAL = SKILL_MEDICAL_MAX, + SKILL_SURGERY = SKILL_SURGERY_MAX, + SKILL_RESEARCH = SKILL_RESEARCH_MAX, + SKILL_ANTAG = SKILL_ANTAG_MAX, + SKILL_PILOT = SKILL_PILOT_MAX, + SKILL_POLICE = SKILL_POLICE_MAX, + SKILL_FIREMAN = SKILL_FIREMAN_MAX, + SKILL_POWERLOADER = SKILL_POWERLOADER_MAX, + SKILL_VEHICLE = SKILL_VEHICLE_MAX, + SKILL_JTAC = SKILL_JTAC_MAX, + SKILL_EXECUTION = SKILL_EXECUTION_MAX, + SKILL_INTEL = SKILL_INTEL_MAX, + ) diff --git a/code/datums/skills/pmc.dm b/code/datums/skills/pmc.dm new file mode 100644 index 000000000000..df7027e2a7ab --- /dev/null +++ b/code/datums/skills/pmc.dm @@ -0,0 +1,171 @@ +/* +---------------------------- +Private Military Contractors +---------------------------- +*/ + +//NOTE: Compared to the USCM, PMCs have additional firearms training, construction skills and policing skills + +/datum/skills/pmc + name = "PMC Private" + skills = list( + SKILL_CQC = SKILL_CQC_TRAINED, + SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, + SKILL_POLICE = SKILL_POLICE_SKILLED, + SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, + SKILL_ENGINEER = SKILL_ENGINEER_ENGI, + SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER, + ) + +/datum/skills/pmc/medic + name = "PMC Medic" + skills = list( + SKILL_CQC = SKILL_CQC_TRAINED, + SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, + SKILL_POLICE = SKILL_POLICE_SKILLED, + SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, + SKILL_ENGINEER = SKILL_ENGINEER_ENGI, + SKILL_MEDICAL = SKILL_MEDICAL_MEDIC, + SKILL_SURGERY = SKILL_SURGERY_NOVICE, + SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER, + ) + +/datum/skills/pmc/medic/chem + name = "PMC Medical Investigator" + skills = list( + SKILL_CQC = SKILL_CQC_TRAINED, + SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, + SKILL_POLICE = SKILL_POLICE_SKILLED, + SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, + SKILL_ENGINEER = SKILL_ENGINEER_ENGI, + SKILL_MEDICAL = SKILL_MEDICAL_MEDIC, + SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER, + SKILL_RESEARCH = SKILL_RESEARCH_TRAINED, + ) + +/datum/skills/pmc/smartgunner + name = "PMC Smartgunner" + skills = list( + SKILL_CQC = SKILL_CQC_TRAINED, + SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, + SKILL_POLICE = SKILL_POLICE_SKILLED, + SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, + SKILL_ENGINEER = SKILL_ENGINEER_ENGI, + SKILL_SPEC_WEAPONS = SKILL_SPEC_SMARTGUN, + SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER, + SKILL_JTAC = SKILL_JTAC_BEGINNER, + ) + +/datum/skills/pmc/specialist + name = "PMC Specialist" + skills = list( + SKILL_CQC = SKILL_CQC_TRAINED, + SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, + SKILL_POLICE = SKILL_POLICE_SKILLED, + SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, + SKILL_ENGINEER = SKILL_ENGINEER_ENGI, + SKILL_CQC = SKILL_CQC_TRAINED, + SKILL_SPEC_WEAPONS = SKILL_SPEC_ALL, + SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, + SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER, + SKILL_JTAC = SKILL_JTAC_BEGINNER, + ) + +/datum/skills/pmc/SL + name = "PMC Leader" + skills = list( + SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, + SKILL_POLICE = SKILL_POLICE_SKILLED, + SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, + SKILL_ENGINEER = SKILL_ENGINEER_ENGI, + SKILL_CQC = SKILL_CQC_SKILLED, + SKILL_LEADERSHIP = SKILL_LEAD_TRAINED, + SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED, + SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, + SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER, + SKILL_JTAC = SKILL_JTAC_TRAINED, + ) + +/datum/skills/pmc/SL/chem + name = "PMC Lead Investigator" + skills = list( + SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, + SKILL_POLICE = SKILL_POLICE_SKILLED, + SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, + SKILL_ENGINEER = SKILL_ENGINEER_ENGI, + SKILL_CQC = SKILL_CQC_SKILLED, + SKILL_LEADERSHIP = SKILL_LEAD_TRAINED, + SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED, + SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, + SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER, + SKILL_RESEARCH = SKILL_RESEARCH_TRAINED, + SKILL_JTAC = SKILL_JTAC_TRAINED, + ) + +/datum/skills/pmc/tank_crew + name = "Vehicle Crewman" + skills = list( + SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, + SKILL_POLICE = SKILL_POLICE_SKILLED, + SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, + SKILL_ENGINEER = SKILL_ENGINEER_ENGI, + SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER, + SKILL_LEADERSHIP = SKILL_LEAD_TRAINED, + SKILL_JTAC = SKILL_JTAC_TRAINED, + SKILL_VEHICLE = SKILL_VEHICLE_CREWMAN, + SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER, + ) + +/datum/skills/pmc/doctor + name = "PMC Triage Doctor" + skills = list( + SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, + SKILL_POLICE = SKILL_POLICE_SKILLED, + SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED, + SKILL_ENGINEER = SKILL_ENGINEER_TRAINED, + SKILL_MEDICAL = SKILL_MEDICAL_DOCTOR, + SKILL_SURGERY = SKILL_SURGERY_EXPERT, + SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER, //trained in medicine more than combat + SKILL_CQC = SKILL_CQC_TRAINED + ) + +/datum/skills/pmc/engineer + name = "PMC Corporate Technician" + skills = list( + SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, + SKILL_POLICE = SKILL_POLICE_SKILLED, + SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_MASTER, + SKILL_ENGINEER = SKILL_ENGINEER_MASTER, + SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, + SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER, + SKILL_JTAC = SKILL_JTAC_TRAINED, + SKILL_CQC = SKILL_CQC_TRAINED, + SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER, + ) + +/datum/skills/pmc/director + name = "PMC Site Director" + skills = list( + SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, + SKILL_POLICE = SKILL_POLICE_SKILLED, + SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, + SKILL_ENGINEER = SKILL_ENGINEER_ENGI, + SKILL_MEDICAL = SKILL_MEDICAL_MEDIC, + SKILL_CQC = SKILL_CQC_TRAINED, + SKILL_LEADERSHIP = SKILL_LEAD_MASTER, + SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED, + SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER, + SKILL_JTAC = SKILL_JTAC_MASTER, + SKILL_EXECUTION = SKILL_EXECUTION_TRAINED, + ) diff --git a/code/datums/skills/rmc.dm b/code/datums/skills/rmc.dm new file mode 100644 index 000000000000..89aa39b154ad --- /dev/null +++ b/code/datums/skills/rmc.dm @@ -0,0 +1,71 @@ +/* +---------------------------- +Royal Marines Commando +---------------------------- +*/ + +//NOTE: Skills take heavy from PMCs + +/datum/skills/rmc + name = "Royal Marines Commando" + skills = list( + SKILL_CQC = SKILL_CQC_TRAINED, + SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, + SKILL_POLICE = SKILL_POLICE_SKILLED, + SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, + SKILL_ENGINEER = SKILL_ENGINEER_ENGI, + SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER, + SKILL_MEDICAL = SKILL_MEDICAL_MEDIC, + SKILL_SURGERY = SKILL_SURGERY_NOVICE, + ) + +/datum/skills/rmc/specialist + name = "Royal Marines Commando Specialist" + skills = list( + SKILL_CQC = SKILL_CQC_TRAINED, + SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, + SKILL_POLICE = SKILL_POLICE_SKILLED, + SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, + SKILL_ENGINEER = SKILL_ENGINEER_ENGI, + SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER, + SKILL_MEDICAL = SKILL_MEDICAL_MEDIC, + SKILL_SURGERY = SKILL_SURGERY_NOVICE, + SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, + SKILL_JTAC = SKILL_JTAC_BEGINNER, + ) + +/datum/skills/rmc/smartgun + name = "Royal Marines Commando Smartgunner" + skills = list( + SKILL_CQC = SKILL_CQC_TRAINED, + SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, + SKILL_POLICE = SKILL_POLICE_SKILLED, + SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, + SKILL_ENGINEER = SKILL_ENGINEER_ENGI, + SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER, + SKILL_MEDICAL = SKILL_MEDICAL_MEDIC, + SKILL_SURGERY = SKILL_SURGERY_NOVICE, + SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, + SKILL_JTAC = SKILL_JTAC_BEGINNER, + SKILL_SPEC_WEAPONS = SKILL_SPEC_SMARTGUN, + ) + +/datum/skills/rmc/leader + name = "Royal Marines Commando Leader" + skills = list( + SKILL_CQC = SKILL_CQC_SKILLED, + SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, + SKILL_POLICE = SKILL_POLICE_SKILLED, + SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, + SKILL_ENGINEER = SKILL_ENGINEER_ENGI, + SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER, + SKILL_MEDICAL = SKILL_MEDICAL_MEDIC, + SKILL_SURGERY = SKILL_SURGERY_NOVICE, + SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, + SKILL_JTAC = SKILL_JTAC_TRAINED, + SKILL_LEADERSHIP = SKILL_LEAD_TRAINED, + ) diff --git a/code/datums/skills/skills.dm b/code/datums/skills/skills.dm new file mode 100644 index 000000000000..5d1a69e174ed --- /dev/null +++ b/code/datums/skills/skills.dm @@ -0,0 +1,267 @@ +// Individual skill +/datum/skill + /// Name of the skill + var/skill_name = null + /// used for the view UI + var/readable_skill_name = null + /// Level of skill in this... skill + var/skill_level = 0 + /// the max level this skill can be, used for tgui + var/max_skill_level = 0 + +/datum/skill/proc/get_skill_level() + return skill_level + +/datum/skill/proc/set_skill(new_level, mob/owner) + skill_level = new_level + +/datum/skill/proc/is_skilled(req_level, is_explicit = FALSE) + if(is_explicit) + return (skill_level == req_level) + return (skill_level >= req_level) + +// Lots of defines here. See #define/skills.dm + +/datum/skill/cqc + skill_name = SKILL_CQC + readable_skill_name = "CQC" + skill_level = SKILL_CQC_DEFAULT + max_skill_level = SKILL_CQC_MAX + +/datum/skill/melee_weapons + skill_name = SKILL_MELEE_WEAPONS + readable_skill_name = "melee weapons" + skill_level = SKILL_MELEE_DEFAULT + max_skill_level = SKILL_MELEE_MAX + +/datum/skill/firearms + skill_name = SKILL_FIREARMS + skill_level = SKILL_FIREARMS_TRAINED + max_skill_level = SKILL_FIREARMS_MAX + +/datum/skill/spec_weapons + skill_name = SKILL_SPEC_WEAPONS + readable_skill_name = "specialist weapons" + skill_level = SKILL_SPEC_DEFAULT + max_skill_level = SKILL_SPEC_ALL + +/datum/skill/endurance + skill_name = SKILL_ENDURANCE + skill_level = SKILL_ENDURANCE_WEAK + max_skill_level = SKILL_ENDURANCE_MAX + +/datum/skill/engineer + skill_name = SKILL_ENGINEER + skill_level = SKILL_ENGINEER_DEFAULT + max_skill_level = SKILL_ENGINEER_MAX + +/datum/skill/construction + skill_name = SKILL_CONSTRUCTION + skill_level = SKILL_CONSTRUCTION_DEFAULT + max_skill_level = SKILL_CONSTRUCTION_MAX + +/datum/skill/leadership + skill_name = SKILL_LEADERSHIP + skill_level = SKILL_LEAD_NOVICE + max_skill_level = SKILL_LEAD_MAX + +/datum/skill/leadership/set_skill(new_level, mob/living/owner) + ..() + if(!owner) + return + + if(!ishuman(owner)) + return + + // Give/remove issue order actions + if(is_skilled(SKILL_LEAD_TRAINED)) + ADD_TRAIT(owner, TRAIT_LEADERSHIP, TRAIT_SOURCE_SKILL(skill_name)) + else + REMOVE_TRAIT(owner, TRAIT_LEADERSHIP, TRAIT_SOURCE_SKILL(skill_name)) + +/datum/skill/overwatch + skill_name = SKILL_OVERWATCH + skill_level = SKILL_OVERWATCH_DEFAULT + max_skill_level = SKILL_OVERWATCH_MAX + +/datum/skill/medical + skill_name = SKILL_MEDICAL + skill_level = SKILL_MEDICAL_DEFAULT + max_skill_level = SKILL_MEDICAL_MAX + +/datum/skill/surgery + skill_name = SKILL_SURGERY + skill_level = SKILL_SURGERY_DEFAULT + max_skill_level = SKILL_SURGERY_MAX + +/datum/skill/surgery/set_skill(new_level, mob/living/owner) + ..() + if(!owner) + return + + if(!ishuman(owner)) + return + + // Give/remove surgery toggle action + var/datum/action/surgery_toggle/surgery_action = locate() in owner.actions + if(is_skilled(SKILL_SURGERY_NOVICE)) + if(!surgery_action) + give_action(owner, /datum/action/surgery_toggle) + else + surgery_action.update_surgery_skill() + else + if(surgery_action) + surgery_action.remove_from(owner) + +/datum/skill/research + skill_name = SKILL_RESEARCH + skill_level = SKILL_RESEARCH_DEFAULT + max_skill_level = SKILL_RESEARCH_MAX + +/datum/skill/antag + skill_name = SKILL_ANTAG + readable_skill_name = "illegal technology" + skill_level = SKILL_ANTAG_DEFAULT + max_skill_level = SKILL_ANTAG_MAX + +/datum/skill/pilot + skill_name = SKILL_PILOT + skill_level = SKILL_PILOT_DEFAULT + max_skill_level = SKILL_PILOT_MAX + +/datum/skill/navigations + skill_name = SKILL_NAVIGATIONS + skill_level = SKILL_NAVIGATIONS_DEFAULT + max_skill_level = SKILL_NAVIGATIONS_MAX + +/datum/skill/police + skill_name = SKILL_POLICE + skill_level = SKILL_POLICE_DEFAULT + max_skill_level = SKILL_POLICE_MAX + +/datum/skill/powerloader + skill_name = SKILL_POWERLOADER + skill_level = SKILL_POWERLOADER_DEFAULT + max_skill_level = SKILL_POWERLOADER_MAX + +/datum/skill/vehicles + skill_name = SKILL_VEHICLE + skill_level = SKILL_VEHICLE_DEFAULT + max_skill_level = SKILL_VEHICLE_MAX + +/datum/skill/jtac + skill_name = SKILL_JTAC + readable_skill_name = "JTAC" + skill_level = SKILL_JTAC_NOVICE + max_skill_level = SKILL_JTAC_MAX + +/datum/skill/execution + skill_name = SKILL_EXECUTION + skill_level = SKILL_EXECUTION_DEFAULT + max_skill_level = SKILL_EXECUTION_MAX + +/datum/skill/intel + skill_name = SKILL_INTEL + skill_level = SKILL_INTEL_NOVICE + max_skill_level = SKILL_INTEL_MAX + +/datum/skill/domestic + skill_name = SKILL_DOMESTIC + skill_level = SKILL_DOMESTIC_NONE + max_skill_level = SKILL_DOMESTIC_MAX + +/datum/skill/fireman + skill_name = SKILL_FIREMAN + readable_skill_name = "fireman carrying" + skill_level = SKILL_FIREMAN_DEFAULT + max_skill_level = SKILL_FIREMAN_MAX + +/// Skill with an extra S at the end is a collection of multiple skills. Basically a skillSET +/// This is to organize and provide a common interface to the huge heap of skills there are +/datum/skills + /// The name of the skillset + var/name + // The mob that has this skillset + var/mob/owner + + // List of skill datums. + // Also, if this is populated when the datum is created, it will set the skill levels automagically + var/list/skills = list() + // Same as above, but for children of parents that just add a lil something else + var/list/additional_skills = list() + +/datum/skills/New(mob/skillset_owner) + owner = skillset_owner + + // Setup every single skill + for(var/skill_type in subtypesof(/datum/skill)) + var/datum/skill/S = new skill_type() + + // Fancy hack to convert a list of desired skill levels in each named skill into a skill level in the actual skill datum + // Lets the skills list be used multipurposely for both storing skill datums and choosing skill levels for different skillsets + var/predetermined_skill_level = additional_skills[S.skill_name] ? additional_skills[S.skill_name] : skills[S.skill_name] + skills[S.skill_name] = S + + if(!isnull(predetermined_skill_level)) + S.set_skill(predetermined_skill_level, owner) + +/datum/skills/Destroy() + owner = null + skills = null // Don't need to delete, /datum/skill should softdel + SStgui.close_uis(src) + return ..() + +// Checks if the given skill is contained in this skillset at all +/datum/skills/proc/has_skill(skill) + return isnull(skills[skill]) + +// Returns the skill DATUM for the given skill +/datum/skills/proc/get_skill(skill) + if(!skills) + return null + return skills[skill] + +// Returns the skill level for the given skill +/datum/skills/proc/get_skill_level(skill) + var/datum/skill/S = get_skill(skill) + if(!S) + return -1 + if(QDELETED(S)) + return -1 + return S.get_skill_level() + +// Sets the skill LEVEL for a given skill +/datum/skills/proc/set_skill(skill, new_level) + var/datum/skill/S = skills[skill] + if(!S) + return + return S.set_skill(new_level, owner) + +/datum/skills/proc/increment_skill(skill, increment, cap) + var/datum/skill/S = skills[skill] + if(!S || skillcheck(owner, skill, cap)) + return + return S.set_skill(min(cap,S.skill_level+increment), owner) + +/datum/skills/proc/decrement_skill(skill, increment) + var/datum/skill/S = skills[skill] + if(!S) + return + return S.set_skill(max(0,S.skill_level-increment), owner) + +// Checks if the skillset is AT LEAST skilled enough to pass a skillcheck for the given skill level +/datum/skills/proc/is_skilled(skill, req_level, is_explicit = FALSE) + var/datum/skill/S = get_skill(skill) + if(QDELETED(S)) + return FALSE + return S.is_skilled(req_level, is_explicit) + +// Adjusts the full skillset to a new type of skillset. Pass the datum type path for the desired skillset +/datum/skills/proc/set_skillset(skillset_type) + var/datum/skills/skillset = new skillset_type() + var/list/skill_levels = initial(skillset.skills) + + name = skillset.name + for(var/skill in skill_levels) + set_skill(skill, skill_levels[skill]) + qdel(skillset) diff --git a/code/datums/skills/synthetic.dm b/code/datums/skills/synthetic.dm new file mode 100644 index 000000000000..3925dd9605b3 --- /dev/null +++ b/code/datums/skills/synthetic.dm @@ -0,0 +1,90 @@ +/* +--------------------- +SYNTHETIC +--------------------- +*/ + +/datum/skills/synthetic + name = "Synthetic" + skills = list( + SKILL_CQC = SKILL_CQC_MASTER, + SKILL_ENGINEER = SKILL_ENGINEER_MASTER, + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_MASTER, + SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, + SKILL_SPEC_WEAPONS = SKILL_SPEC_ALL, + SKILL_LEADERSHIP = SKILL_LEAD_EXPERT, + SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED, + SKILL_MEDICAL = SKILL_MEDICAL_MASTER, + SKILL_SURGERY = SKILL_SURGERY_EXPERT, + SKILL_RESEARCH = SKILL_RESEARCH_TRAINED, + SKILL_MELEE_WEAPONS = SKILL_MELEE_SUPER, + SKILL_PILOT = SKILL_PILOT_EXPERT, + SKILL_POLICE = SKILL_POLICE_SKILLED, + SKILL_FIREMAN = SKILL_FIREMAN_MAX, + SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER, + SKILL_VEHICLE = SKILL_VEHICLE_LARGE, + SKILL_JTAC = SKILL_JTAC_EXPERT, + SKILL_INTEL = SKILL_INTEL_EXPERT, + SKILL_DOMESTIC = SKILL_DOMESTIC_MASTER, + SKILL_NAVIGATIONS = SKILL_NAVIGATIONS_TRAINED, + ) + +/datum/skills/colonial_synthetic + name = SYNTH_COLONY + skills = list( + SKILL_CQC = SKILL_CQC_EXPERT, + SKILL_ENGINEER = SKILL_ENGINEER_ENGI, + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, + SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, + SKILL_SPEC_WEAPONS = SKILL_SPEC_ALL, + SKILL_MEDICAL = SKILL_MEDICAL_DOCTOR, + SKILL_SURGERY = SKILL_SURGERY_TRAINED, + SKILL_RESEARCH = SKILL_RESEARCH_TRAINED, + SKILL_MELEE_WEAPONS = SKILL_MELEE_SUPER, + SKILL_PILOT = SKILL_PILOT_EXPERT, + SKILL_POLICE = SKILL_POLICE_SKILLED, + SKILL_FIREMAN = SKILL_FIREMAN_EXPERT, + SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER, + SKILL_VEHICLE = SKILL_VEHICLE_LARGE, + SKILL_JTAC = SKILL_JTAC_BEGINNER, + SKILL_INTEL = SKILL_INTEL_TRAINED, + SKILL_DOMESTIC = SKILL_DOMESTIC_MASTER, + ) + +/datum/skills/working_joe + name = SYNTH_WORKING_JOE + skills = list( + SKILL_CQC = SKILL_CQC_EXPERT, + SKILL_ENGINEER = SKILL_ENGINEER_MASTER, //So they can fully use the Maintenance Jack + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, + SKILL_POLICE = SKILL_POLICE_SKILLED, + SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, + SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER, + SKILL_VEHICLE = SKILL_VEHICLE_LARGE, + SKILL_DOMESTIC = SKILL_DOMESTIC_MASTER, + ) + +/datum/skills/infiltrator_synthetic + name = SYNTH_INFILTRATOR + skills = list( + SKILL_CQC = SKILL_CQC_MASTER, + SKILL_ENGINEER = SKILL_ENGINEER_MASTER, + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_MASTER, + SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, + SKILL_SPEC_WEAPONS = SKILL_SPEC_ALL, + SKILL_LEADERSHIP = SKILL_LEAD_EXPERT, + SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED, + SKILL_MEDICAL = SKILL_MEDICAL_MASTER, + SKILL_SURGERY = SKILL_SURGERY_EXPERT, + SKILL_RESEARCH = SKILL_RESEARCH_TRAINED, + SKILL_MELEE_WEAPONS = SKILL_MELEE_SUPER, + SKILL_PILOT = SKILL_PILOT_EXPERT, + SKILL_POLICE = SKILL_POLICE_SKILLED, + SKILL_FIREMAN = SKILL_FIREMAN_MAX, + SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER, + SKILL_VEHICLE = SKILL_VEHICLE_CREWMAN, + SKILL_JTAC = SKILL_JTAC_EXPERT, + SKILL_INTEL = SKILL_INTEL_EXPERT, + SKILL_DOMESTIC = SKILL_DOMESTIC_MASTER, + SKILL_ANTAG = SKILL_ANTAG_AGENT, + ) diff --git a/code/datums/skills/upp.dm b/code/datums/skills/upp.dm new file mode 100644 index 000000000000..77401ab62878 --- /dev/null +++ b/code/datums/skills/upp.dm @@ -0,0 +1,218 @@ +/* +-------------------------- +UNITED PROGRESSIVE PEOPLES +-------------------------- +*/ + +//NOTE: UPP make up for their subpar gear with extreme training. + +/datum/skills/upp + name = "UPP Private" + skills = list( + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED, + SKILL_ENGINEER = SKILL_ENGINEER_TRAINED, + SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, + SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED, + SKILL_CQC = SKILL_CQC_DEFAULT, + SKILL_FIREMAN = SKILL_FIREMAN_TRAINED, + SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, + ) + +/datum/skills/upp/combat_engineer + name = "UPP Sapper" + skills = list( + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, + SKILL_ENGINEER = SKILL_ENGINEER_ENGI, + SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, + SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED, + SKILL_CQC = SKILL_CQC_DEFAULT, + SKILL_FIREMAN = SKILL_FIREMAN_TRAINED, + SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, + ) + +/datum/skills/upp/combat_medic + name = "UPP Medic" + skills = list( + SKILL_MEDICAL = SKILL_MEDICAL_DOCTOR, + SKILL_SURGERY = SKILL_SURGERY_TRAINED, + SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED, + SKILL_CQC = SKILL_CQC_DEFAULT, + SKILL_FIREARMS = SKILL_FIREARMS_TRAINED, + ) + +/datum/skills/upp/specialist + name = "UPP Specialist" + skills = list( + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED, + SKILL_ENGINEER = SKILL_ENGINEER_TRAINED, + SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER, + SKILL_CQC = SKILL_CQC_TRAINED, + SKILL_LEADERSHIP = SKILL_LEAD_TRAINED, + SKILL_JTAC = SKILL_JTAC_TRAINED, + SKILL_SPEC_WEAPONS = SKILL_SPEC_UPP, + SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, + SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, + ) + +/datum/skills/upp/SL + name = "UPP Squad Leader" + skills = list( + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, + SKILL_ENGINEER = SKILL_ENGINEER_ENGI, + SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER, + SKILL_CQC = SKILL_CQC_TRAINED, + SKILL_LEADERSHIP = SKILL_LEAD_EXPERT, + SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED, + SKILL_MEDICAL = SKILL_MEDICAL_MEDIC, + SKILL_JTAC = SKILL_JTAC_EXPERT, + ) + +/datum/skills/upp/military_police + name = "UPP Military Police" + skills = list( + SKILL_CQC = SKILL_CQC_SKILLED, + SKILL_POLICE = SKILL_POLICE_SKILLED, + SKILL_FIREMAN = SKILL_FIREMAN_EXPERT, + SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER, + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED, + SKILL_ENGINEER = SKILL_ENGINEER_TRAINED, + SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, + SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, + ) + +/datum/skills/upp/officer + name = "UPP Officer" + skills = list( + SKILL_CQC = SKILL_CQC_TRAINED, + SKILL_POLICE = SKILL_POLICE_FLASH, + SKILL_FIREMAN = SKILL_FIREMAN_EXPERT, + SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER, + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, + SKILL_LEADERSHIP = SKILL_LEAD_EXPERT, + SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED, + SKILL_ENGINEER = SKILL_ENGINEER_TRAINED, + SKILL_MEDICAL = SKILL_MEDICAL_MEDIC, + SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, + SKILL_VEHICLE = SKILL_VEHICLE_SMALL, + SKILL_JTAC = SKILL_JTAC_EXPERT, + ) + +/datum/skills/upp/kapitan + name = "UPP Kapitan" + skills = list( + SKILL_CQC = SKILL_CQC_SKILLED, + SKILL_POLICE = SKILL_POLICE_SKILLED, + SKILL_FIREMAN = SKILL_FIREMAN_EXPERT, + SKILL_LEADERSHIP = SKILL_LEAD_MASTER, + SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED, + SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER, + SKILL_ENGINEER = SKILL_ENGINEER_ENGI, + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, + SKILL_MEDICAL = SKILL_MEDICAL_MEDIC, + SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, + SKILL_VEHICLE = SKILL_VEHICLE_SMALL, + SKILL_JTAC = SKILL_JTAC_EXPERT, + ) + +/datum/skills/upp/commander + name = "UPP Command Officer" + skills = list( + SKILL_CQC = SKILL_CQC_SKILLED, + SKILL_POLICE = SKILL_POLICE_SKILLED, + SKILL_FIREMAN = SKILL_FIREMAN_EXPERT, + SKILL_LEADERSHIP = SKILL_LEAD_MASTER, + SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED, + SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER, + SKILL_ENGINEER = SKILL_ENGINEER_ENGI, + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, + SKILL_MEDICAL = SKILL_MEDICAL_MEDIC, + SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, + SKILL_VEHICLE = SKILL_VEHICLE_SMALL, + SKILL_JTAC = SKILL_JTAC_EXPERT, + SKILL_EXECUTION = SKILL_EXECUTION_TRAINED, + ) +/datum/skills/upp/conscript + name = "UPP Conscript" + skills = list( + SKILL_FIREARMS = SKILL_FIREARMS_TRAINED, + ) + + +//Survivor + +/datum/skills/military/survivor/upp_private + name = "UPP Private" + skills = list( + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED, + SKILL_ENGINEER = SKILL_ENGINEER_ENGI, + SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, + SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED, + SKILL_CQC = SKILL_CQC_TRAINED, + SKILL_FIREARMS = SKILL_FIREARMS_TRAINED, + SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, + SKILL_VEHICLE = SKILL_VEHICLE_DEFAULT, + SKILL_JTAC = SKILL_JTAC_TRAINED, + ) + +/datum/skills/military/survivor/upp_sapper + name = "UPP Sapper" + skills = list( + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, + SKILL_ENGINEER = SKILL_ENGINEER_ENGI, + SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, + SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED, + SKILL_CQC = SKILL_CQC_TRAINED, + SKILL_FIREARMS = SKILL_FIREARMS_TRAINED, + SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, + SKILL_VEHICLE = SKILL_VEHICLE_DEFAULT, + SKILL_JTAC = SKILL_JTAC_TRAINED, + ) + +/datum/skills/military/survivor/upp_medic + name = "UPP Medic" + skills = list( + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED, + SKILL_ENGINEER = SKILL_ENGINEER_ENGI, + SKILL_MEDICAL = SKILL_MEDICAL_DOCTOR, + SKILL_SURGERY = SKILL_SURGERY_TRAINED, + SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED, + SKILL_FIREARMS = SKILL_FIREARMS_TRAINED, + SKILL_CQC = SKILL_CQC_TRAINED, + SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, + SKILL_VEHICLE = SKILL_VEHICLE_DEFAULT, + SKILL_JTAC = SKILL_JTAC_TRAINED, + ) + +/datum/skills/military/survivor/upp_spec + name = "UPP Specialist" + skills = list( + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED, + SKILL_ENGINEER = SKILL_ENGINEER_ENGI, + SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, + SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED, + SKILL_CQC = SKILL_CQC_TRAINED, + SKILL_LEADERSHIP = SKILL_LEAD_TRAINED, + SKILL_JTAC = SKILL_JTAC_TRAINED, + SKILL_SPEC_WEAPONS = SKILL_SPEC_UPP, + SKILL_FIREARMS = SKILL_FIREARMS_TRAINED, + SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, + SKILL_CQC = SKILL_CQC_TRAINED, + SKILL_VEHICLE = SKILL_VEHICLE_LARGE, + ) + +/datum/skills/military/survivor/upp_sl + name = "UPP Squad Leader" + skills = list( + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, + SKILL_ENGINEER = SKILL_ENGINEER_ENGI, + SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED, + SKILL_SPEC_WEAPONS = SKILL_SPEC_UPP, + SKILL_FIREARMS = SKILL_FIREARMS_TRAINED, + SKILL_CQC = SKILL_CQC_TRAINED, + SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, + SKILL_LEADERSHIP = SKILL_LEAD_EXPERT, + SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED, + SKILL_MEDICAL = SKILL_MEDICAL_MEDIC, + SKILL_VEHICLE = SKILL_VEHICLE_LARGE, + SKILL_JTAC = SKILL_JTAC_EXPERT, + ) diff --git a/code/datums/skills/uscm.dm b/code/datums/skills/uscm.dm new file mode 100644 index 000000000000..8a6d2fd2c8c2 --- /dev/null +++ b/code/datums/skills/uscm.dm @@ -0,0 +1,410 @@ +/* +------------------------------ +United States Colonial Marines +------------------------------ +*/ + +/datum/skills/pfc + name = "Private" + //same as default + +/datum/skills/pfc/crafty + name = "Crafty Private" + skills = list( + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED, + SKILL_ENGINEER = SKILL_ENGINEER_TRAINED, + ) + +/datum/skills/combat_medic + name = "Combat Medic" + skills = list( + SKILL_MEDICAL = SKILL_MEDICAL_MEDIC, + SKILL_SURGERY = SKILL_SURGERY_NOVICE, + SKILL_JTAC = SKILL_JTAC_BEGINNER, + ) + +/datum/skills/combat_medic/crafty + name = "Crafty Combat Medic" + skills = list( + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED, + SKILL_ENGINEER = SKILL_ENGINEER_TRAINED, + ) + +/datum/skills/combat_engineer + name = "Combat Engineer" + skills = list( + SKILL_ENGINEER = SKILL_ENGINEER_ENGI, + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, + SKILL_VEHICLE = SKILL_VEHICLE_SMALL, + SKILL_JTAC = SKILL_JTAC_BEGINNER, + ) + +/datum/skills/smartgunner + name = "Squad Smartgunner" + skills = list( + SKILL_SPEC_WEAPONS = SKILL_SPEC_SMARTGUN, + SKILL_JTAC = SKILL_JTAC_BEGINNER, + ) + +/datum/skills/specialist + name = "Squad Weapons Specialist" + skills = list( + SKILL_CQC = SKILL_CQC_TRAINED, + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED, + SKILL_ENGINEER = SKILL_ENGINEER_TRAINED, //to use c4 in demo set. + SKILL_SPEC_WEAPONS = SKILL_SPEC_TRAINED, + SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, + SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED, + SKILL_JTAC = SKILL_JTAC_BEGINNER + ) + +/datum/skills/tl + name = "Fireteam Leader" + skills = list( + SKILL_ENGINEER = SKILL_ENGINEER_ENGI, + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, + SKILL_JTAC = SKILL_JTAC_EXPERT, + ) + +/datum/skills/SL + name = "Squad Leader" + skills = list( + SKILL_CQC = SKILL_CQC_TRAINED, + SKILL_FIREMAN = SKILL_FIREMAN_TRAINED, + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, + SKILL_ENGINEER = SKILL_ENGINEER_ENGI, + SKILL_LEADERSHIP = SKILL_LEAD_TRAINED, + SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, + SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED, + SKILL_VEHICLE = SKILL_VEHICLE_SMALL, + SKILL_JTAC = SKILL_JTAC_TRAINED, + SKILL_INTEL = SKILL_INTEL_TRAINED, + ) + +/datum/skills/intel + name = "Intelligence Officer" + skills = list( + SKILL_ENGINEER = SKILL_ENGINEER_ENGI, + SKILL_LEADERSHIP = SKILL_LEAD_TRAINED, + SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED, + SKILL_CQC = SKILL_CQC_TRAINED, + SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, + SKILL_RESEARCH = SKILL_RESEARCH_TRAINED, + SKILL_JTAC = SKILL_JTAC_TRAINED, + SKILL_INTEL = SKILL_INTEL_EXPERT, + ) + +/* +--------------------- +MILITARY NONCOMBATANT +--------------------- +*/ + +/datum/skills/doctor + name = "Doctor" + skills = list( + SKILL_FIREARMS = SKILL_FIREARMS_CIVILIAN, + SKILL_MEDICAL = SKILL_MEDICAL_DOCTOR, + SKILL_SURGERY = SKILL_SURGERY_TRAINED, + ) + +/datum/skills/nurse + name = "Nurse" + skills = list( + SKILL_FIREARMS = SKILL_FIREARMS_CIVILIAN, + SKILL_MEDICAL = SKILL_MEDICAL_DOCTOR, + SKILL_SURGERY = SKILL_SURGERY_NOVICE, + ) + +/datum/skills/researcher + name = "Researcher" + skills = list( + SKILL_FIREARMS = SKILL_FIREARMS_CIVILIAN, + SKILL_MEDICAL = SKILL_MEDICAL_DOCTOR, + SKILL_SURGERY = SKILL_SURGERY_TRAINED, + SKILL_RESEARCH = SKILL_RESEARCH_TRAINED, + SKILL_INTEL = SKILL_INTEL_TRAINED, + ) + +/datum/skills/pilot + name = "Pilot Officer" + skills = list( + SKILL_PILOT = SKILL_PILOT_EXPERT, + SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER, + SKILL_LEADERSHIP = SKILL_LEAD_TRAINED, + SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED, + SKILL_MEDICAL = SKILL_MEDICAL_MEDIC, + SKILL_SURGERY = SKILL_SURGERY_NOVICE, + SKILL_JTAC = SKILL_JTAC_TRAINED, + SKILL_INTEL = SKILL_INTEL_TRAINED, + ) + +/datum/skills/crew_chief + name = "Dropship Crew Chief" + skills = list( + SKILL_PILOT = SKILL_PILOT_TRAINED, + SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER, + SKILL_LEADERSHIP = SKILL_LEAD_TRAINED, + SKILL_MEDICAL = SKILL_MEDICAL_MEDIC, + SKILL_SURGERY = SKILL_SURGERY_NOVICE, + SKILL_JTAC = SKILL_JTAC_TRAINED, + SKILL_ENGINEER = SKILL_ENGINEER_ENGI, + ) + +/datum/skills/MP + name = "Military Police" + skills = list( + SKILL_CQC = SKILL_CQC_SKILLED, + SKILL_POLICE = SKILL_POLICE_SKILLED, + SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, + SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED, + ) + +/datum/skills/MW + name = "Military Warden" + skills = list( + SKILL_CQC = SKILL_CQC_SKILLED, + SKILL_POLICE = SKILL_POLICE_SKILLED, + SKILL_FIREMAN = SKILL_FIREMAN_TRAINED, + SKILL_LEADERSHIP = SKILL_LEAD_TRAINED, + SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED, + SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED, + SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, + SKILL_ENGINEER = SKILL_ENGINEER_ENGI, + ) + +/datum/skills/provost + name = "Provost" + skills = list( + SKILL_CQC = SKILL_CQC_EXPERT, + SKILL_POLICE = SKILL_POLICE_SKILLED, + SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, + SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER, + SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, + ) + +/datum/skills/OT + name = "Ordnance Technician" + skills = list( + SKILL_ENGINEER = SKILL_ENGINEER_MASTER, + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_MASTER, + SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER, + ) + +/datum/skills/MT + name = "Maintenance Technician" + skills = list( + SKILL_ENGINEER = SKILL_ENGINEER_MASTER, + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_MASTER, + SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER, + SKILL_DOMESTIC = SKILL_DOMESTIC_TRAINED, + ) + +/datum/skills/mess_technician + name = "Mess Technician" + skills = list( + SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, // need to hunt food somehow + SKILL_ENGINEER = SKILL_ENGINEER_TRAINED, + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED, + SKILL_DOMESTIC = SKILL_DOMESTIC_MASTER + ) + +/datum/skills/CT + name = "Cargo Technician" + skills = list( + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED, + SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER, + ) + +/* +--------------------- +COMMAND STAFF +--------------------- +*/ + +/datum/skills/general + name = "General" + skills = list( + SKILL_CQC = SKILL_CQC_TRAINED, + SKILL_ENGINEER = SKILL_ENGINEER_ENGI, + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, + SKILL_LEADERSHIP = SKILL_LEAD_MASTER, + SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED, + SKILL_MEDICAL = SKILL_MEDICAL_DOCTOR, + SKILL_POLICE = SKILL_POLICE_SKILLED, + SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, + SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER, + SKILL_ENDURANCE = SKILL_ENDURANCE_MAX, + SKILL_JTAC = SKILL_JTAC_MASTER, + SKILL_SPEC_WEAPONS = SKILL_SPEC_ALL, + SKILL_EXECUTION = SKILL_EXECUTION_TRAINED, //can BE people + SKILL_INTEL = SKILL_INTEL_EXPERT + ) + +/datum/skills/commander + name = "Commanding Officer" + skills = list( + SKILL_ENGINEER = SKILL_ENGINEER_ENGI, + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, + SKILL_LEADERSHIP = SKILL_LEAD_MASTER, + SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED, + SKILL_MEDICAL = SKILL_MEDICAL_DOCTOR, + SKILL_SURGERY = SKILL_SURGERY_NOVICE, + SKILL_POLICE = SKILL_POLICE_SKILLED, + SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, + SKILL_VEHICLE = SKILL_VEHICLE_SMALL, + SKILL_CQC = SKILL_CQC_SKILLED, + SKILL_SPEC_WEAPONS = SKILL_SPEC_SMARTGUN, + SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER, + SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED, + SKILL_JTAC = SKILL_JTAC_MASTER, + SKILL_EXECUTION = SKILL_EXECUTION_TRAINED, //can BE people + SKILL_INTEL = SKILL_INTEL_EXPERT, + SKILL_NAVIGATIONS = SKILL_NAVIGATIONS_TRAINED //can change ship alt + ) + +/datum/skills/XO + name = "Executive Officer" + skills = list( + SKILL_ENGINEER = SKILL_ENGINEER_ENGI, //to fix CIC apc. + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, + SKILL_LEADERSHIP = SKILL_LEAD_MASTER, + SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED, + SKILL_MEDICAL = SKILL_MEDICAL_DOCTOR, + SKILL_SURGERY = SKILL_SURGERY_NOVICE, + SKILL_POLICE = SKILL_POLICE_FLASH, + SKILL_VEHICLE = SKILL_VEHICLE_SMALL, + SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, + SKILL_CQC = SKILL_CQC_SKILLED, + SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER, + SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED, + SKILL_JTAC = SKILL_JTAC_MASTER, + SKILL_INTEL = SKILL_INTEL_EXPERT, + SKILL_NAVIGATIONS = SKILL_NAVIGATIONS_TRAINED, + ) + +/datum/skills/SO + name = "Staff Officer" + skills = list( + SKILL_ENGINEER = SKILL_ENGINEER_ENGI, + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, + SKILL_LEADERSHIP = SKILL_LEAD_EXPERT, + SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED, + SKILL_MEDICAL = SKILL_MEDICAL_MEDIC, + SKILL_POLICE = SKILL_POLICE_FLASH, + SKILL_FIREMAN = SKILL_FIREMAN_TRAINED, + SKILL_VEHICLE = SKILL_VEHICLE_SMALL, + SKILL_POWERLOADER = SKILL_POWERLOADER_TRAINED, + SKILL_JTAC = SKILL_JTAC_EXPERT, + SKILL_INTEL = SKILL_INTEL_TRAINED, + ) + +/datum/skills/SEA + name = "Senior Enlisted Advisor" + skills = list( + SKILL_CQC = SKILL_CQC_SKILLED, + SKILL_ENGINEER = SKILL_ENGINEER_ENGI, + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, + SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, + SKILL_LEADERSHIP = SKILL_LEAD_EXPERT, + SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED, + SKILL_MEDICAL = SKILL_MEDICAL_DOCTOR, + SKILL_SURGERY = SKILL_SURGERY_TRAINED, + SKILL_RESEARCH = SKILL_RESEARCH_TRAINED, + SKILL_PILOT = SKILL_PILOT_EXPERT, + SKILL_POLICE = SKILL_POLICE_SKILLED, + SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, + SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER, + SKILL_VEHICLE = SKILL_VEHICLE_LARGE, + SKILL_JTAC = SKILL_JTAC_EXPERT, + SKILL_INTEL = SKILL_INTEL_EXPERT, + SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED, + ) + +/datum/skills/SEA/New(mob/skillset_owner) + ..() + give_action(skillset_owner, /datum/action/looc_toggle) + +/datum/skills/SEA/Destroy() + remove_action(owner, /datum/action/looc_toggle) + return ..() + +/datum/skills/CMO + name = "CMO" + skills = list( + SKILL_FIREARMS = SKILL_FIREARMS_CIVILIAN, + SKILL_LEADERSHIP = SKILL_LEAD_EXPERT, + SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED, + SKILL_MEDICAL = SKILL_MEDICAL_DOCTOR, + SKILL_SURGERY = SKILL_SURGERY_TRAINED, + SKILL_RESEARCH = SKILL_RESEARCH_TRAINED, + SKILL_POLICE = SKILL_POLICE_FLASH, + SKILL_FIREMAN = SKILL_FIREMAN_TRAINED, + SKILL_JTAC = SKILL_JTAC_EXPERT, + SKILL_INTEL = SKILL_INTEL_TRAINED, + ) + +/datum/skills/CMP + name = "Chief MP" + skills = list( + SKILL_CQC = SKILL_CQC_SKILLED, + SKILL_POLICE = SKILL_POLICE_SKILLED, + SKILL_FIREMAN = SKILL_FIREMAN_SKILLED, + SKILL_LEADERSHIP = SKILL_LEAD_EXPERT, + SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED, + SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED, + SKILL_JTAC = SKILL_JTAC_EXPERT, + SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, + SKILL_ENGINEER = SKILL_ENGINEER_ENGI, + SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED, + SKILL_INTEL = SKILL_INTEL_TRAINED, + ) + +/datum/skills/auxiliary_officer + name = "Auxiliary Support Officer" + skills = list( + SKILL_PILOT = SKILL_PILOT_EXPERT, + SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER, + SKILL_LEADERSHIP = SKILL_LEAD_MASTER, + SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED, + SKILL_MEDICAL = SKILL_MEDICAL_MEDIC, + SKILL_SURGERY = SKILL_SURGERY_NOVICE, + SKILL_JTAC = SKILL_JTAC_EXPERT, + SKILL_INTEL = SKILL_INTEL_EXPERT, + SKILL_VEHICLE = SKILL_VEHICLE_SMALL, + SKILL_ENGINEER = SKILL_ENGINEER_ENGI, + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, + SKILL_POLICE = SKILL_POLICE_FLASH, + SKILL_NAVIGATIONS = SKILL_NAVIGATIONS_TRAINED, + SKILL_FIREMAN = SKILL_FIREMAN_TRAINED, + ) + +/datum/skills/CE + name = "Chief Engineer" + skills = list( + SKILL_ENGINEER = SKILL_ENGINEER_MASTER, + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_MASTER, + SKILL_LEADERSHIP = SKILL_LEAD_MASTER, + SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED, + SKILL_POLICE = SKILL_POLICE_FLASH, + SKILL_FIREMAN = SKILL_FIREMAN_TRAINED, + SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER, + SKILL_JTAC = SKILL_JTAC_MASTER, + SKILL_INTEL = SKILL_INTEL_TRAINED, + SKILL_NAVIGATIONS = SKILL_NAVIGATIONS_TRAINED, + ) + +/datum/skills/RO + name = "Requisition Officer" + skills = list( + SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, + SKILL_LEADERSHIP = SKILL_LEAD_EXPERT, + SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED, + SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER, + SKILL_POLICE = SKILL_POLICE_FLASH, + SKILL_FIREMAN = SKILL_FIREMAN_TRAINED, + SKILL_JTAC = SKILL_JTAC_EXPERT, + SKILL_INTEL = SKILL_INTEL_TRAINED, + ) diff --git a/code/datums/stamina/_stamina.dm b/code/datums/stamina/_stamina.dm index 36705e3be300..e233aaa81676 100644 --- a/code/datums/stamina/_stamina.dm +++ b/code/datums/stamina/_stamina.dm @@ -37,13 +37,11 @@ current_stamina = Clamp(current_stamina - amount, 0, max_stamina) if(current_stamina < max_stamina) - if(!(src in active_staminas)) - active_staminas.Add(src) - + START_PROCESSING(SSobj, src) if(amount > 0) apply_rest_period(STAMINA_REST_PERIOD) else - active_staminas.Remove(src) + STOP_PROCESSING(SSobj, src) update_stamina_level() diff --git a/code/datums/statistics/entities/caste_stats.dm b/code/datums/statistics/entities/caste_stats.dm index 639e1b4a05f5..6bfc18d124b7 100644 --- a/code/datums/statistics/entities/caste_stats.dm +++ b/code/datums/statistics/entities/caste_stats.dm @@ -3,6 +3,10 @@ var/total_hits = 0 var/list/abilities_used = list() // types of /datum/entity/statistic, "tail sweep" = 10, "screech" = 2 +/datum/entity/player_stats/caste/Destroy(force) + . = ..() + QDEL_LIST_ASSOC_VAL(abilities_used) + /datum/entity/player_stats/caste/proc/setup_ability(ability) if(!ability) return diff --git a/code/datums/statistics/entities/death_stats.dm b/code/datums/statistics/entities/death_stats.dm index 4a01e4e9d72b..35ff1769b925 100644 --- a/code/datums/statistics/entities/death_stats.dm +++ b/code/datums/statistics/entities/death_stats.dm @@ -84,6 +84,10 @@ if(!mind || statistic_exempt) return + var/area/area = get_area(death_loc) + handle_observer_message(cause_data, cause_mob, death_loc, area) + + // Perform logging above before get_player_from_key to avoid delays var/datum/entity/statistic/death/new_death = DB_ENTITY(/datum/entity/statistic/death) var/datum/entity/player/player_entity = get_player_from_key(mind.ckey) if(player_entity) @@ -95,11 +99,8 @@ new_death.role_name = get_role_name() new_death.mob_name = real_name new_death.faction_name = faction - new_death.is_xeno = FALSE - - var/area/A = get_area(death_loc) - new_death.area_name = A.name + new_death.area_name = area.name new_death.cause_name = cause_data?.cause_name var/datum/entity/player/cause_player = get_player_from_key(cause_data?.ckey) @@ -132,8 +133,6 @@ new_death.total_damage_taken = life_damage_taken_total new_death.total_revives_done = life_revives_total - handle_observer_message(cause_data, cause_mob, death_loc, A) - if(round_statistics) round_statistics.track_death(new_death) @@ -141,16 +140,16 @@ new_death.detach() return new_death -/mob/living/carbon/human/track_mob_death(cause, cause_mob) - . = ..(cause, cause_mob, job) +/mob/living/carbon/human/track_mob_death(datum/cause_data/cause_data, turf/death_loc) + . = ..() if(statistic_exempt || !mind) return var/datum/entity/player_stats/human/human_stats = mind.setup_human_stats() if(human_stats && human_stats.death_list) human_stats.death_list.Insert(1, .) -/mob/living/carbon/xenomorph/track_mob_death(cause, cause_mob) - var/datum/entity/statistic/death/new_death = ..(cause, cause_mob, caste_type) +/mob/living/carbon/xenomorph/track_mob_death(datum/cause_data/cause_data, turf/death_loc) + var/datum/entity/statistic/death/new_death = ..() if(!new_death) return new_death.is_xeno = TRUE // this was placed beneath the if below, which meant gibbing as a xeno wouldn't track properly in stats diff --git a/code/datums/statistics/entities/human_stats.dm b/code/datums/statistics/entities/human_stats.dm index 51b07867dfd3..1e15aa1d161b 100644 --- a/code/datums/statistics/entities/human_stats.dm +++ b/code/datums/statistics/entities/human_stats.dm @@ -5,10 +5,17 @@ var/total_shots = 0 var/total_shots_hit = 0 var/total_screams = 0 - var/datum/entity/weapon_stats/top_weapon = null // reference to /datum/entity/weapon_stats (like tac-shotty) - var/list/weapon_stats_list = list() // list of types /datum/entity/weapon_stats - var/list/job_stats_list = list() // list of types /datum/entity/job_stats - var/list/datum/entity/statistic/medal/medal_list = list() // list of all medals earned + var/list/weapon_stats_list = list() //! indexed list of types /datum/entity/weapon_stats + var/list/job_stats_list = list() //! indexed list of types /datum/entity/job_stats + var/datum/entity/weapon_stats/top_weapon //! reference to /datum/entity/weapon_stats (like tac-shotty) + var/list/datum/entity/statistic/medal/medal_list = list() //! list of all medals earned + +/datum/entity/player_stats/human/Destroy(force) + . = ..() + QDEL_LIST_ASSOC_VAL(weapon_stats_list) + QDEL_LIST_ASSOC_VAL(job_stats_list) + QDEL_NULL(top_weapon) + QDEL_LIST(medal_list) /datum/entity/player_stats/human/get_playtime(type) if(!type) diff --git a/code/datums/statistics/entities/job_stats.dm b/code/datums/statistics/entities/job_stats.dm index ecde1c942082..199c2adb3160 100644 --- a/code/datums/statistics/entities/job_stats.dm +++ b/code/datums/statistics/entities/job_stats.dm @@ -1,8 +1,8 @@ /datum/entity/player_stats/job - var/name = null - var/total_friendly_fire = null - var/total_revives = null - var/total_lives_saved = null - var/total_shots = null - var/total_shots_hit = null - var/total_screams = null + var/name + var/total_friendly_fire + var/total_revives + var/total_lives_saved + var/total_shots + var/total_shots_hit + var/total_screams diff --git a/code/datums/statistics/entities/panel_stats.dm b/code/datums/statistics/entities/panel_stats.dm index d6e391e1731f..e507d5d81a8b 100644 --- a/code/datums/statistics/entities/panel_stats.dm +++ b/code/datums/statistics/entities/panel_stats.dm @@ -8,7 +8,7 @@ update_panel_data(round_statistics) ui_interact(user) -/datum/entity/player_entity/proc/ui_interact(mob/user, ui_key = "statistics", datum/nanoui/ui = null, force_open = 1) +/datum/entity/player_entity/proc/ui_interact(mob/user, ui_key = "statistics", datum/nanoui/ui, force_open = 1) data["menu"] = menu data["subMenu"] = subMenu data["dataMenu"] = dataMenu diff --git a/code/datums/statistics/entities/player_entity.dm b/code/datums/statistics/entities/player_entity.dm index 72f4d95d7aa3..f0b3d37ede7e 100644 --- a/code/datums/statistics/entities/player_entity.dm +++ b/code/datums/statistics/entities/player_entity.dm @@ -8,8 +8,8 @@ /datum/entity/player_entity var/name var/ckey // "cakey" - var/list/datum/entity/player_stats = list() - var/list/datum/entity/statistic/death/death_stats = list() + var/list/player_stats = list() //! Indeed list of /datum/entity/player_stats + var/list/death_stats = list() //! Indexed list of /datum/entity/statistic/death var/menu = 0 var/subMenu = 0 var/dataMenu = 0 @@ -18,6 +18,11 @@ var/savefile_version var/save_loaded = FALSE +/datum/entity/player_entity/Destroy(force) + QDEL_LIST_ASSOC_VAL(player_stats) + QDEL_LIST_ASSOC_VAL(death_stats) + return ..() + /datum/entity/player_entity/proc/get_playtime(branch, type) var/playtime = 0 if(player_stats["[branch]"]) diff --git a/code/datums/statistics/entities/player_stats.dm b/code/datums/statistics/entities/player_stats.dm index b378d7c2ea24..d9fbd3b11e03 100644 --- a/code/datums/statistics/entities/player_stats.dm +++ b/code/datums/statistics/entities/player_stats.dm @@ -6,13 +6,21 @@ var/total_rounds_played = 0 var/steps_walked = 0 var/round_played = FALSE - var/datum/entity/statistic/nemesis = null // "runner" = 3 + var/datum/entity/statistic/nemesis // "runner" = 3 var/list/niche_stats = list() // list of type /datum/entity/statistic, "Total Executions" = number var/list/humans_killed = list() // list of type /datum/entity/statistic, "jobname2" = number var/list/xenos_killed = list() // list of type /datum/entity/statistic, "caste" = number var/list/death_list = list() // list of type /datum/entity/death_stats var/display_stat = TRUE +/datum/entity/player_stats/Destroy(force) + QDEL_NULL(nemesis) + QDEL_LIST_ASSOC_VAL(niche_stats) + QDEL_LIST_ASSOC_VAL(humans_killed) + QDEL_LIST_ASSOC_VAL(xenos_killed) + QDEL_LIST_ASSOC_VAL(death_list) + return ..() + /datum/entity/player_stats/proc/get_playtime() return total_playtime diff --git a/code/datums/statistics/entities/round_stats.dm b/code/datums/statistics/entities/round_stats.dm index 0e1fb6e387db..baed6befa912 100644 --- a/code/datums/statistics/entities/round_stats.dm +++ b/code/datums/statistics/entities/round_stats.dm @@ -23,7 +23,7 @@ var/total_slashes = 0 // untracked data - var/datum/entity/statistic/map/current_map = null // reference to current map + var/datum/entity/statistic/map/current_map // reference to current map var/list/datum/entity/statistic/death/death_stats_list = list() var/list/abilities_used = list() // types of /datum/entity/statistic, "tail sweep" = 10, "screech" = 2 @@ -37,8 +37,20 @@ var/list/job_stats_list = list() // list of types /datum/entity/job_stats // nanoui data - var/round_data[0] - var/death_data[0] + var/list/round_data = list() + var/list/death_data = list() + +/datum/entity/statistic/round/Destroy(force) + . = ..() + QDEL_NULL(current_map) + QDEL_LIST(death_stats_list) + QDEL_LIST_ASSOC_VAL(abilities_used) + QDEL_LIST_ASSOC_VAL(final_participants) + QDEL_LIST_ASSOC_VAL(hijack_participants) + QDEL_LIST_ASSOC_VAL(total_deaths) + QDEL_LIST_ASSOC_VAL(caste_stats_list) + QDEL_LIST_ASSOC_VAL(weapon_stats_list) + QDEL_LIST_ASSOC_VAL(job_stats_list) /datum/entity_meta/statistic_round entity_type = /datum/entity/statistic/round diff --git a/code/datums/statistics/entities/weapon_stats.dm b/code/datums/statistics/entities/weapon_stats.dm index 0d8458c20de2..9fff5c514458 100644 --- a/code/datums/statistics/entities/weapon_stats.dm +++ b/code/datums/statistics/entities/weapon_stats.dm @@ -1,16 +1,23 @@ /datum/entity/weapon_stats - var/datum/entity/player = null // "deanthelis" - var/list/niche_stats = list() // list of type /datum/entity/statistic, "Total Reloads" = number - var/list/humans_killed = list() // list of type /datum/entity/statistic, "jobname2" = number - var/list/xenos_killed = list() // list of type /datum/entity/statistic, "caste" = number - var/name = null + var/datum/entity/player + var/list/niche_stats = list() //! Indexed list of /datum/entity/statistic, "Total Reloads" = number + var/list/humans_killed = list() //! Indexed list of /datum/entity/statistic, "jobname2" = number + var/list/xenos_killed = list() //! Indexed list of /datum/entity/statistic, "caste" = number + var/name var/total_kills = 0 - var/total_hits = null - var/total_shots = null - var/total_shots_hit = null - var/total_friendly_fire = null + var/total_hits + var/total_shots + var/total_shots_hit + var/total_friendly_fire var/display_stat = TRUE +/datum/entity/weapon_stats/Destroy(force) + player = null + QDEL_LIST_ASSOC_VAL(niche_stats) + QDEL_LIST_ASSOC_VAL(humans_killed) + QDEL_LIST_ASSOC_VAL(xenos_killed) + return ..() + /datum/entity/weapon_stats/proc/count_human_kill(job_name) if(!job_name) return diff --git a/code/datums/statistics/entities/xeno_stats.dm b/code/datums/statistics/entities/xeno_stats.dm index 9ed327258258..8fff4a2e5dd3 100644 --- a/code/datums/statistics/entities/xeno_stats.dm +++ b/code/datums/statistics/entities/xeno_stats.dm @@ -4,6 +4,12 @@ var/list/caste_stats_list = list() // list of types /datum/entity/player_stats/caste var/list/datum/entity/statistic/medal/medal_list = list() // list of all royal jelly earned +/datum/entity/player_stats/xeno/Destroy(force) + . = ..() + QDEL_NULL(top_caste) + QDEL_LIST_ASSOC_VAL(caste_stats_list) + QDEL_LIST(medal_list) + /datum/entity/player_stats/xeno/get_playtime(type) if(!type || type == FACTION_XENOMORPH) return ..() diff --git a/code/datums/supply_packs/black_market.dm b/code/datums/supply_packs/black_market.dm index 0709811195b4..1af965898548 100644 --- a/code/datums/supply_packs/black_market.dm +++ b/code/datums/supply_packs/black_market.dm @@ -127,70 +127,42 @@ Non-USCM items, from CLF, UPP, colonies, etc. Mostly combat-related. spawn_guns() //the crate gives 2 guns /obj/structure/largecrate/black_market/confiscated_weaponry/proc/spawn_guns() - switch(rand(1,6)) + switch(rand(1, 5)) if(1) //pmc - if(prob(50)) - new /obj/item/weapon/gun/rifle/nsg23/no_lock(src) - new /obj/item/ammo_magazine/rifle/nsg23(src) - new /obj/item/ammo_magazine/rifle/nsg23(src) - new /obj/item/ammo_magazine/rifle/nsg23/ap(src) - new /obj/item/ammo_magazine/rifle/nsg23/extended(src) - else - new /obj/item/weapon/gun/smg/fp9000(src) - new /obj/item/ammo_magazine/smg/fp9000(src) - new /obj/item/ammo_magazine/smg/fp9000(src) - new /obj/item/ammo_magazine/smg/fp9000(src) - new /obj/item/ammo_magazine/smg/fp9000(src) + new /obj/item/weapon/gun/smg/fp9000(src) + new /obj/item/ammo_magazine/smg/fp9000(src) + new /obj/item/ammo_magazine/smg/fp9000(src) + new /obj/item/ammo_magazine/smg/fp9000(src) + new /obj/item/ammo_magazine/smg/fp9000(src) if(2) //pizza new /obj/item/weapon/gun/pistol/holdout(src) new /obj/item/ammo_magazine/pistol/holdout(src) if(3) //clf - switch(rand(1, 3)) + switch(rand(1, 2)) if(1) - new /obj/item/weapon/twohanded/lungemine/damaged(src) - if(2) new /obj/item/weapon/gun/smg/uzi(src) new /obj/item/ammo_magazine/smg/uzi/extended(src) new /obj/item/ammo_magazine/smg/uzi(src) new /obj/item/ammo_magazine/smg/uzi(src) - if(3) + if(2) new /obj/item/weapon/gun/smg/mac15(src) new /obj/item/ammo_magazine/smg/mac15/extended(src) new /obj/item/ammo_magazine/smg/mac15(src) new /obj/item/ammo_magazine/smg/mac15(src) if(4) //upp - if(prob(50)) - new /obj/item/weapon/gun/rifle/type71(src) - new /obj/item/ammo_magazine/rifle/type71/ap(src) - new /obj/item/ammo_magazine/rifle/type71(src) - new /obj/item/ammo_magazine/rifle/type71(src) - else - new /obj/item/weapon/gun/shotgun/type23/riot_control(src) - new /obj/item/ammo_magazine/handful/shotgun/heavy/beanbag(src) - new /obj/item/ammo_magazine/handful/shotgun/heavy/beanbag(src) - new /obj/item/ammo_magazine/handful/shotgun/heavy/flechette(src) - new /obj/item/ammo_magazine/handful/shotgun/heavy/flechette(src) - new /obj/item/ammo_magazine/handful/shotgun/heavy/slug(src) - new /obj/item/ammo_magazine/handful/shotgun/heavy/slug(src) //NO buckshot! + new /obj/item/weapon/gun/shotgun/type23/riot_control(src) + new /obj/item/ammo_magazine/handful/shotgun/heavy/beanbag(src) + new /obj/item/ammo_magazine/handful/shotgun/heavy/beanbag(src) + new /obj/item/ammo_magazine/handful/shotgun/heavy/flechette(src) + new /obj/item/ammo_magazine/handful/shotgun/heavy/flechette(src) + new /obj/item/ammo_magazine/handful/shotgun/heavy/slug(src) + new /obj/item/ammo_magazine/handful/shotgun/heavy/slug(src) //NO buckshot! if(5) //freelancer - if(prob(80)) - new /obj/item/weapon/gun/rifle/mar40(src) - new /obj/item/ammo_magazine/rifle/mar40/extended(src) - new /obj/item/ammo_magazine/rifle/mar40(src) - new /obj/item/ammo_magazine/rifle/mar40(src) - else - new /obj/item/weapon/gun/rifle/mar40/lmg(src) - new /obj/item/ammo_magazine/rifle/mar40/lmg(src) - if(6) //VAIPO - if(prob(50)) - new /obj/item/weapon/gun/rifle/mar40/tactical(src) - new /obj/item/ammo_magazine/rifle/mar40/extended(src) - new /obj/item/ammo_magazine/rifle/mar40/extended(src) - new /obj/item/ammo_magazine/rifle/mar40(src) - else - new /obj/item/weapon/gun/rifle/mar40/lmg(src) - new /obj/item/ammo_magazine/rifle/mar40/lmg(src) - new /obj/item/ammo_magazine/rifle/mar40/lmg(src) + new /obj/item/weapon/gun/rifle/mar40(src) + new /obj/item/ammo_magazine/rifle/mar40/extended(src) + new /obj/item/ammo_magazine/rifle/mar40(src) + new /obj/item/ammo_magazine/rifle/mar40(src) + /* Misc. Individual Guns */ @@ -448,7 +420,7 @@ Additionally, weapons that are way too good to put in the basically-flavor black containertype = /obj/structure/largecrate/black_market /datum/supply_packs/contraband/seized/small - name = "S&W revolver (x6 magazines included)" + name = "Smith and Wesson revolver (x6 magazines included)" contains = list( /obj/item/weapon/gun/revolver/small, /obj/item/ammo_magazine/revolver/small, @@ -561,10 +533,6 @@ Primarily made up of things that would be best utilized, well, shipside. Recreat /obj/item/reagent_container/food/snacks/egg/random, /obj/item/reagent_container/food/snacks/egg/random, //not a dupe /obj/item/reagent_container/food/snacks/xemeatpie, - /obj/item/reagent_container/food/snacks/monkeycube, - /obj/item/reagent_container/food/snacks/monkeycube/farwacube, - /obj/item/reagent_container/food/snacks/monkeycube/stokcube, - /obj/item/reagent_container/food/snacks/monkeycube/yirencube, /obj/item/reagent_container/food/snacks/upp, /obj/item/reagent_container/food/snacks/mre_pack/xmas1, /obj/item/reagent_container/food/snacks/mre_pack/xmas2, @@ -617,7 +585,7 @@ Primarily made up of things that would be best utilized, well, shipside. Recreat /obj/item/storage/box/packet/hefa/toy, /obj/item/toy/inflatable_duck, /obj/item/toy/beach_ball, - /obj/item/toy/farwadoll, + /obj/item/toy/plush/farwa, /obj/item/toy/waterflower, /obj/item/toy/spinningtoy, /obj/item/storage/box/snappops, @@ -722,13 +690,6 @@ USCM spare items, miscellaneous gear that's too niche and distant (or restricted dollar_cost = 50 containertype = /obj/structure/largecrate/black_market -/datum/supply_packs/contraband/surplus/surplus_m4ra_extended - name = "surplus magazine box (Ext M4RA x 12)" - contains = list(/obj/item/ammo_box/magazine/m4ra/ext) - dollar_cost = 45 - crate_heat = 3 - containertype = /obj/structure/largecrate/black_market - /* - Misc. USCM weaponry - */ /datum/supply_packs/contraband/surplus/mk45_automag @@ -1108,7 +1069,7 @@ Things that don't fit anywhere else. If they're meant for shipside use, they pro new /obj/item/ammo_magazine/smg/mac15/extended(loc) new /obj/item/ammo_magazine/smg/mac15/extended(loc) loot_message = SPAN_NOTICE("It's some CLF SMG armaments.") - if(21 to 25) + if(21 to 29) // Discovered Yautja ruins.. (None of these will trigger any alarms. They are far too old, degraded, and useless for any Yautja to care.) new /obj/item/clothing/mask/yautja_flavor(loc) new /obj/item/clothing/suit/armor/yautja_flavor(loc) @@ -1116,13 +1077,7 @@ Things that don't fit anywhere else. If they're meant for shipside use, they pro new /obj/item/weapon/twohanded/yautja/glaive/damaged(loc) new /obj/item/stack/yautja_rope(loc) loot_message = SPAN_NOTICE("It's some strange ancient gear...?") - if(26 to 30) - // Damaged lunge mines, don't let the marines near these. Not even *close* to effective against even a runner. - new /obj/item/weapon/twohanded/lungemine/damaged(loc) - new /obj/item/weapon/twohanded/lungemine/damaged(loc) - new /obj/item/weapon/twohanded/lungemine/damaged(loc) - loot_message = SPAN_NOTICE("It's a bunch of lunge mines..?") - if(31 to 35) + if(30 to 35) // CLF nades! loot_message = SPAN_NOTICE("It's a package of assorted CLF grenades!") var/list/nades_to_pick = list( diff --git a/code/datums/supply_packs/gear.dm b/code/datums/supply_packs/gear.dm index b67f8f134c25..54a2ae221c9d 100644 --- a/code/datums/supply_packs/gear.dm +++ b/code/datums/supply_packs/gear.dm @@ -63,15 +63,3 @@ containertype = /obj/structure/closet/crate/ammo containername = "fulton recovery device crate" group = "Gear" - -/datum/supply_packs/nvg - name = "M2 Night Vision Goggles Crate (x3)" - contains = list( - /obj/item/prop/helmetgarb/helmet_nvg, - /obj/item/prop/helmetgarb/helmet_nvg, - /obj/item/prop/helmetgarb/helmet_nvg, - ) - cost = 60 - containertype = /obj/structure/closet/crate/supply - containername = "M2 Night Vission Goggles Crate" - group = "Gear" diff --git a/code/defines/procs/announcement.dm b/code/defines/procs/announcement.dm index 5223d63b8e59..8e42fd1e76a8 100644 --- a/code/defines/procs/announcement.dm +++ b/code/defines/procs/announcement.dm @@ -45,13 +45,11 @@ if((H.faction != faction_to_display && !add_PMCs) || (H.faction != faction_to_display && add_PMCs && !(H.faction in FACTION_LIST_WY)) && !(faction_to_display in H.faction_group)) //faction checks targets.Remove(H) - var/datum/ares_link/link = GLOB.ares_link - if(ares_can_log()) - switch(logging) - if(ARES_LOG_MAIN) - link.log_ares_announcement(title, message) - if(ARES_LOG_SECURITY) - link.log_ares_security(title, message) + switch(logging) + if(ARES_LOG_MAIN) + log_ares_announcement(title, message) + if(ARES_LOG_SECURITY) + log_ares_security(title, message) else if(faction_to_display == "Everyone (-Yautja)") for(var/mob/M in targets) @@ -98,13 +96,11 @@ for(var/mob/living/silicon/decoy/ship_ai/AI in ai_mob_list) INVOKE_ASYNC(AI, TYPE_PROC_REF(/mob/living/silicon/decoy/ship_ai, say), message) - var/datum/ares_link/link = GLOB.ares_link - if(ares_can_log()) - switch(logging) - if(ARES_LOG_MAIN) - link.log_ares_announcement("[MAIN_AI_SYSTEM] Comms Update", message) - if(ARES_LOG_SECURITY) - link.log_ares_security("[MAIN_AI_SYSTEM] Security Update", message) + switch(logging) + if(ARES_LOG_MAIN) + log_ares_announcement("[MAIN_AI_SYSTEM] Comms Update", message) + if(ARES_LOG_SECURITY) + log_ares_security("[MAIN_AI_SYSTEM] Security Update", message) /proc/ai_silent_announcement(message, channel_prefix, bypass_cooldown = FALSE) if(!message) @@ -125,7 +121,7 @@ //AI shipside announcement, that uses announcement mechanic instead of talking into comms //to ensure that all humans on ship hear it regardless of comms and power -/proc/shipwide_ai_announcement(message, title = MAIN_AI_SYSTEM, sound_to_play = sound('sound/misc/interference.ogg'), signature) +/proc/shipwide_ai_announcement(message, title = MAIN_AI_SYSTEM, sound_to_play = sound('sound/misc/interference.ogg'), signature, ares_logging = ARES_LOG_MAIN) var/list/targets = GLOB.human_mob_list + GLOB.dead_mob_list for(var/mob/T in targets) if(isobserver(T)) @@ -135,9 +131,11 @@ if(!isnull(signature)) message += "

Signed by,
[signature]
" - var/datum/ares_link/link = GLOB.ares_link - if(link.interface && !(link.interface.inoperable())) - link.log_ares_announcement(title, message) + switch(ares_logging) + if(ARES_LOG_MAIN) + log_ares_announcement(title, message) + if(ARES_LOG_SECURITY) + log_ares_security(title, message) announcement_helper(message, title, targets, sound_to_play) @@ -150,9 +148,7 @@ if(!ishuman(T) || isyautja(T) || !is_mainship_level(T.z)) targets.Remove(T) - var/datum/ares_link/link = GLOB.ares_link - if(ares_can_log()) - link.log_ares_announcement("[title] Shipwide Update", message) + log_ares_announcement("[title] Shipwide Update", message) announcement_helper(message, title, targets, sound_to_play) diff --git a/code/game/area/WhiskeyOutpost.dm b/code/game/area/WhiskeyOutpost.dm index 02d94dc942da..aef72d1a9941 100644 --- a/code/game/area/WhiskeyOutpost.dm +++ b/code/game/area/WhiskeyOutpost.dm @@ -65,7 +65,7 @@ icon_state = "livingspace" /area/whiskey_outpost/inside/supply - name = "\improper Supply Depo" + name = "\improper Supply Depot" icon_state = "req" /* diff --git a/code/game/area/almayer.dm b/code/game/area/almayer.dm index 6ced81a22b15..742ae7a1addb 100644 --- a/code/game/area/almayer.dm +++ b/code/game/area/almayer.dm @@ -13,6 +13,21 @@ ambience_exterior = AMBIENCE_ALMAYER ceiling_muffle = FALSE + ///Whether this area is used for hijack evacuation progress + var/hijack_evacuation_area = FALSE + + ///The weight this area gives towards hijack evacuation progress + var/hijack_evacuation_weight = 0 + + ///Whether this area is additive or multiplicative towards evacuation progress + var/hijack_evacuation_type = EVACUATION_TYPE_NONE + +/area/almayer/Initialize(mapload, ...) + . = ..() + + if(hijack_evacuation_area) + SShijack.progress_areas[src] = power_equip + /area/shuttle/almayer/elevator_maintenance/upperdeck name = "\improper Maintenance Elevator" icon_state = "shuttle" @@ -160,6 +175,9 @@ fake_zlevel = 2 // lowerdeck soundscape_playlist = SCAPE_PL_ENG soundscape_interval = 15 + hijack_evacuation_area = TRUE + hijack_evacuation_weight = 0.2 + hijack_evacuation_type = EVACUATION_TYPE_ADDITIVE /area/almayer/engineering/starboard_atmos name = "\improper Atmospherics Starboard" @@ -183,6 +201,9 @@ name = "\improper Astronavigational Deck" icon_state = "astronavigation" fake_zlevel = 2 // lowerdeck + hijack_evacuation_area = TRUE + hijack_evacuation_weight = 1.1 + hijack_evacuation_type = EVACUATION_TYPE_MULTIPLICATIVE /area/almayer/shipboard/panic name = "\improper Hangar Panic Room" @@ -712,6 +733,9 @@ icon_state = "lifeboat_pump" requires_power = 1 fake_zlevel = 1 + hijack_evacuation_area = TRUE + hijack_evacuation_weight = 0.1 + hijack_evacuation_type = EVACUATION_TYPE_ADDITIVE /area/almayer/lifeboat_pumps/north1 name = "North West Lifeboat Fuel Pump" diff --git a/code/game/area/areas.dm b/code/game/area/areas.dm index c9625ec1c44f..776d81bb10ad 100644 --- a/code/game/area/areas.dm +++ b/code/game/area/areas.dm @@ -93,7 +93,7 @@ initialize_power() /area/Initialize(mapload, ...) - icon_state = "" //Used to reset the icon overlay, I assume. + icon = null layer = AREAS_LAYER uid = ++global_uid . = ..() diff --git a/code/game/atoms.dm b/code/game/atoms.dm index e1541f8368b8..e0590265840c 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -33,8 +33,11 @@ var/list/filter_data //For handling persistent filters - // Base transform matrix - var/matrix/base_transform = null + /// Base transform matrix, edited by admin tooling and such + var/matrix/base_transform + /// Last transform used before being compound with base_transform + /// This allows us to re-create transform if only base_transform changes + var/matrix/raw_transform ///Chemistry. var/datum/reagents/reagents = null @@ -116,7 +119,14 @@ directive is properly returned. //=========================================================================== - +// TODO make all atoms use set_density, do not rely on it at present +///Setter for the `density` variable to append behavior related to its changing. +/atom/proc/set_density(new_value) + SHOULD_CALL_PARENT(TRUE) + if(density == new_value) + return + . = density + density = new_value //atmos procs @@ -141,15 +151,27 @@ directive is properly returned. if(loc) return loc.return_gas() -// Updates the atom's transform -/atom/proc/apply_transform(matrix/M) - if(!base_transform) - transform = M - return +/// Updates the atom's transform compounding it with [/atom/var/base_transform] +/atom/proc/apply_transform(matrix/new_transform, time = 0, easing = (EASE_IN|EASE_OUT)) + var/matrix/base_copy + if(base_transform) + base_copy = matrix(base_transform) + else + base_copy = matrix() + raw_transform = matrix(new_transform) // Keep a copy to replay if needed - var/matrix/base_copy = matrix(base_transform) // Compose the base and applied transform in that order - transform = base_copy.Multiply(M) + var/matrix/complete = base_copy.Multiply(raw_transform) + + if(!time) + transform = complete + return + animate(src, transform = complete, time = time, easing = easing) + +/// Upates the base_transform which will be compounded with other transforms +/atom/proc/update_base_transform(matrix/new_transform, time = 0) + base_transform = matrix(new_transform) + apply_transform(raw_transform, time) /atom/proc/on_reagent_change() return @@ -183,7 +205,9 @@ directive is properly returned. return /atom/proc/emp_act(severity) - return + SHOULD_CALL_PARENT(TRUE) + + SEND_SIGNAL(src, COMSIG_ATOM_EMP_ACT, severity) /atom/proc/in_contents_of(container)//can take class or object instance as argument if(ispath(container)) @@ -223,8 +247,8 @@ directive is properly returned. if(!examine_strings) log_debug("Attempted to create an examine block with no strings! Atom : [src], user : [user]") return - to_chat(user, examine_block(examine_strings.Join("\n"))) SEND_SIGNAL(src, COMSIG_PARENT_EXAMINE, user, examine_strings) + to_chat(user, examine_block(examine_strings.Join("\n"))) /atom/proc/get_examine_text(mob/user) . = list() @@ -699,10 +723,9 @@ Parameters are passed from New. usr.client.cmd_admin_emp(src) if(href_list[VV_HK_MODIFY_TRANSFORM] && check_rights(R_VAREDIT)) - var/result = tgui_input_list(usr, "Choose the transformation to apply","Transform Mod", list("Scale","Translate","Rotate")) + var/result = tgui_input_list(usr, "Choose the transformation to apply","Transform Mod", list("Scale","Translate","Rotate", "Reflect X Axis", "Reflect Y Axis")) if(!result) return - var/matrix/M = transform if(!result) return switch(result) @@ -711,19 +734,37 @@ Parameters are passed from New. var/y = tgui_input_real_number(usr, "Choose y mod","Transform Mod") if(isnull(x) || isnull(y)) return - transform = M.Scale(x,y) + var/matrix/base_matrix = matrix(base_transform) + update_base_transform(base_matrix.Scale(x,y)) if("Translate") var/x = tgui_input_real_number(usr, "Choose x mod (negative = left, positive = right)","Transform Mod") var/y = tgui_input_real_number(usr, "Choose y mod (negative = down, positive = up)","Transform Mod") if(isnull(x) || isnull(y)) return - transform = M.Translate(x,y) + var/matrix/base_matrix = matrix(base_transform) + update_base_transform(base_matrix.Translate(x,y)) if("Rotate") var/angle = tgui_input_real_number(usr, "Choose angle to rotate","Transform Mod") if(isnull(angle)) return - transform = M.Turn(angle) - + var/matrix/base_matrix = matrix(base_transform) + update_base_transform(base_matrix.Turn(angle)) + if("Reflect X Axis") + var/matrix/current = matrix(base_transform) + var/matrix/reflector = matrix() + reflector.a = -1 + reflector.d = 0 + reflector.b = 0 + reflector.e = 1 + update_base_transform(current * reflector) + if("Reflect Y Axis") + var/matrix/current = matrix(base_transform) + var/matrix/reflector = matrix() + reflector.a = 1 + reflector.d = 0 + reflector.b = 0 + reflector.e = -1 + update_base_transform(current * reflector) SEND_SIGNAL(src, COMSIG_ATOM_VV_MODIFY_TRANSFORM) if(href_list[VV_HK_AUTO_RENAME] && check_rights(R_VAREDIT)) diff --git a/code/game/bioscans.dm b/code/game/bioscans.dm index 62c801a02d29..ff6e00ec430e 100644 --- a/code/game/bioscans.dm +++ b/code/game/bioscans.dm @@ -109,24 +109,21 @@ GLOBAL_DATUM_INIT(bioscan_data, /datum/bioscan_data, new) to_chat(ghost, ghost_scan) -/// This will do something after Project ARES. /datum/bioscan_data/proc/ares_can_bioscan() var/datum/ares_link/link = GLOB.ares_link if(!istype(link)) return FALSE - if(link.p_bioscan && !link.p_bioscan.inoperable()) + if(link.processor_bioscan && !link.processor_bioscan.inoperable()) return TRUE return FALSE /// The announcement to all Humans. Slightly off for the planet and elsewhere, accurate for the ship. /datum/bioscan_data/proc/ares_bioscan(forced = FALSE, variance = 2) - var/datum/ares_link/link = GLOB.ares_link if(!forced && !ares_can_bioscan()) message_admins("An ARES Bioscan has failed.") var/name = "[MAIN_AI_SYSTEM] Bioscan Status" var/input = "Bioscan failed. \n\nInvestigation into Bioscan subsystem recommended." - if(ares_can_log()) - link.log_ares_bioscan(name, input) + log_ares_bioscan(name, input) if(ares_can_interface()) marine_announcement(input, name, 'sound/misc/interference.ogg', logging = ARES_LOG_NONE) return @@ -137,8 +134,7 @@ GLOBAL_DATUM_INIT(bioscan_data, /datum/bioscan_data, new) log_game("BIOSCAN: ARES bioscan completed. [input]") - if(forced || ares_can_log()) - link.log_ares_bioscan(name, input) //if interface is down, bioscan still logged, just have to go read it. + log_ares_bioscan(name, input) //if interface is down, bioscan still logged, just have to go read it. if(forced || ares_can_interface()) marine_announcement(input, name, 'sound/AI/bioscan.ogg', logging = ARES_LOG_NONE) else diff --git a/code/game/cas_manager/datums/cas_fire_envelope.dm b/code/game/cas_manager/datums/cas_fire_envelope.dm index d7c939b76e16..330521f34e36 100644 --- a/code/game/cas_manager/datums/cas_fire_envelope.dm +++ b/code/game/cas_manager/datums/cas_fire_envelope.dm @@ -181,7 +181,7 @@ apply_upgrade(user) if(!(user in guidance.users)) guidance.users += user - RegisterSignal(usr, COMSIG_MOB_RESISTED, PROC_REF(exit_cam_resist)) + RegisterSignal(user, COMSIG_MOB_RESISTED, PROC_REF(exit_cam_resist)) /datum/cas_fire_envelope/proc/apply_upgrade(user) @@ -220,6 +220,7 @@ M.reset_view() remove_upgrades(user) guidance.users -= user + UnregisterSignal(user, COMSIG_MOB_RESISTED) /datum/cas_fire_envelope/proc/exit_cam_resist(mob/user) SIGNAL_HANDLER diff --git a/code/game/gamemodes/cm_initialize.dm b/code/game/gamemodes/cm_initialize.dm index 1dbcd7a5fa33..9899a8d993ea 100644 --- a/code/game/gamemodes/cm_initialize.dm +++ b/code/game/gamemodes/cm_initialize.dm @@ -356,17 +356,21 @@ Additional game mode variables. else available_xenos_non_ssd += cur_xeno - var/datum/hive_status/hive - for(var/hivenumber in GLOB.hive_datum) - hive = GLOB.hive_datum[hivenumber] - if(!hive.hardcore && hive.stored_larva && (hive.hive_location || (world.time < XENO_BURIED_LARVA_TIME_LIMIT + SSticker.round_start_time))) - if(SSticker.mode && (SSticker.mode.flags_round_type & MODE_RANDOM_HIVE)) - available_xenos |= "any buried larva" - LAZYADD(available_xenos["any buried larva"], hive) - else - var/larva_option = "buried larva ([hive])" - available_xenos += larva_option - available_xenos[larva_option] = list(hive) + // Only offer buried larva if there is no queue: + // This basically means this block of code will almost never execute, because we are instead relying on the hive cores/larva pops to handle their larva + // Technically this should be after a get_alien_candidates() call to be accurate, but we are intentionally trying to not call that proc as much as possible + if(GLOB.xeno_queue_candidate_count < 1) + var/datum/hive_status/hive + for(var/hivenumber in GLOB.hive_datum) + hive = GLOB.hive_datum[hivenumber] + if(!hive.hardcore && hive.stored_larva && (hive.hive_location || (world.time < XENO_BURIED_LARVA_TIME_LIMIT + SSticker.round_start_time))) + if(SSticker.mode && (SSticker.mode.flags_round_type & MODE_RANDOM_HIVE)) + available_xenos |= "any buried larva" + LAZYADD(available_xenos["any buried larva"], hive) + else + var/larva_option = "buried larva ([hive])" + available_xenos += larva_option + available_xenos[larva_option] = list(hive) if(!available_xenos.len || (instant_join && !available_xenos_non_ssd.len)) if(!xeno_candidate.client || !xeno_candidate.client.prefs || !(xeno_candidate.client.prefs.be_special & BE_ALIEN_AFTER_DEATH)) @@ -378,7 +382,7 @@ Additional game mode variables. var/mob/dead/observer/candidate_observer = xeno_candidate if(istype(candidate_observer)) if(candidate_observer.larva_queue_cached_message) - to_chat(xeno_candidate, candidate_observer.larva_queue_cached_message) + to_chat(xeno_candidate, SPAN_XENONOTICE(candidate_observer.larva_queue_cached_message)) return FALSE // No cache, lets check now then @@ -389,14 +393,14 @@ Additional game mode variables. cur_hive = GLOB.hive_datum[hive_num] for(var/mob_name in cur_hive.banished_ckeys) if(cur_hive.banished_ckeys[mob_name] == xeno_candidate.ckey) - candidate_observer.larva_queue_cached_message += "\n" + SPAN_WARNING("NOTE: You are banished from the [cur_hive] and you may not rejoin unless the Queen re-admits you or dies. Your queue number won't update until there is a hive you aren't banished from.") + candidate_observer.larva_queue_cached_message += "\nNOTE: You are banished from the [cur_hive] and you may not rejoin unless the Queen re-admits you or dies. Your queue number won't update until there is a hive you aren't banished from." break - to_chat(xeno_candidate, candidate_observer.larva_queue_cached_message) + to_chat(xeno_candidate, SPAN_XENONOTICE(candidate_observer.larva_queue_cached_message)) return FALSE // We aren't in queue yet, lets teach them about the queue then - candidate_observer.larva_queue_cached_message = SPAN_XENONOTICE("You are currently awaiting assignment in the larva queue. The ordering is based on your time of death or the time you joined. When you have been dead long enough and are not inactive, you will periodically receive messages where you are in the queue relative to other currently valid xeno candidates. Your current position will shift as others change their preferences or go inactive, but your relative position compared to all observers is the same. Note: Playing as a facehugger or in the thunderdome will not alter your time of death. This means you won't lose your relative place in queue if you step away, disconnect, play as a facehugger, or play in the thunderdome.") - to_chat(xeno_candidate, candidate_observer.larva_queue_cached_message) + candidate_observer.larva_queue_cached_message = "You are currently awaiting assignment in the larva queue. The ordering is based on your time of death or the time you joined. When you have been dead long enough and are not inactive, you will periodically receive messages where you are in the queue relative to other currently valid xeno candidates. Your current position will shift as others change their preferences or go inactive, but your relative position compared to all observers is the same. Note: Playing as a facehugger or in the thunderdome will not alter your time of death. This means you won't lose your relative place in queue if you step away, disconnect, play as a facehugger, or play in the thunderdome." + to_chat(xeno_candidate, SPAN_XENONOTICE(candidate_observer.larva_queue_cached_message)) return FALSE var/mob/living/carbon/xenomorph/new_xeno @@ -446,7 +450,7 @@ Additional game mode variables. to_chat(xeno_candidate, SPAN_WARNING("You cannot join if the xenomorph is dead.")) return FALSE - if(new_xeno.stat == UNCONSCIOUS) + if(new_xeno.health <= 0) to_chat(xeno_candidate, SPAN_WARNING("You cannot join if the xenomorph is in critical condition or unconscious.")) return FALSE diff --git a/code/game/gamemodes/cm_self_destruct.dm b/code/game/gamemodes/cm_self_destruct.dm deleted file mode 100644 index b86de24eed74..000000000000 --- a/code/game/gamemodes/cm_self_destruct.dm +++ /dev/null @@ -1,476 +0,0 @@ -/* -TODO -Look into animation screen not showing on self-destruct and other weirdness -Intergrate distress into this controller. -Finish nanoui conversion for comm console. -Make sure people who get nuked and wake up from SSD don't live. -Add flashing lights to evac. //DEFERRED TO BETTER LIGHTING -Finish the game mode announcement thing. -Fix escape doors to work properly. -*/ - -/* -How this works: - -First: All of the linking is done automatically on world start, so nothing needs to be done on that end other than making -sure that objects are actually placed in the game world. If not, the game will error and let you know about it. But you -don't need to modify variables or worry about area placement. It's all done for you. -The rods, for example, configure the time per activation based on their number. Shuttles link their own machines via area. -Nothing in this controller is linked to game mode, so it's stand alone, more or less, but it's best used during a game mode. -Admins have a lot of tools in their disposal via the check antagonist panel, and devs can access the VV of this controller -through that panel. - -Second: The communication console handles most of the IC triggers for activating these functions, the rest is handled elsewhere. -Check communications.dm for that. shuttle_controller.dm handles the set up for the escape pods. escape_pods.dm handles most of the -functions of the escape pods themselves. This file would likely need to be broken down into individual parts at some point in the -future. - -Evacuation takes place when sufficient alert level is reaised and a distress beacon was launched. All of the evac pods come online -and open their doors to allow entry inside. Characters may then get inside of the cryo units to before the shuttles automatically launch. -If wanted, a nearby controller object may launch each individual shuttle early. Only three people may ride on a shuttle to escape, -otherwise the launch will fail and the shuttle will become inoperable. -Any launched shuttles are taken out of the game. If the evacuation is canceled, any persons inside of the cryo tubes will be ejected. -They may temporarily open the door to exit if they are stuck inside after evac is canceled. - -When the self-destruct is enabled, the console comes online. This usually happens during an evacuation. Once the console is -interacted with, it fires up the self-destruct sequence. Several rods rise and must be interacted with in order to arm the system. -Once that happens, the console must be interacted with again to trigger the self-destruct. The self-destruct may also be -canceled from the console. - -The self-destruct may also happen if a nuke is detonated on the ship's zlevel; if it is detonated elsewhere, the ship will not blow up. -Regardless of where it's detonated, or how, a successful detonation will end the round or automatically restart the game. - -All of the necessary difines are stored under mode.dm in defines. -*/ - -var/global/datum/authority/branch/evacuation/EvacuationAuthority //This is initited elsewhere so that the world has a chance to load in. - -/datum/authority/branch/evacuation - var/name = "Evacuation Authority" - var/evac_time //Time the evacuation was initiated. - var/evac_status = EVACUATION_STATUS_STANDING_BY //What it's doing now? It can be standing by, getting ready to launch, or finished. - - var/obj/structure/machinery/self_destruct/console/dest_master //The main console that does the brunt of the work. - var/dest_rods[] //Slave devices to make the explosion work. - var/dest_cooldown //How long it takes between rods, determined by the amount of total rods present. - var/dest_index = 1 //What rod the thing is currently on. - var/dest_status = NUKE_EXPLOSION_INACTIVE - var/dest_started_at = 0 - - var/flags_scuttle = NO_FLAGS - -/datum/authority/branch/evacuation/New() - ..() - dest_master = locate() - if(!dest_master) - log_debug("ERROR CODE SD1: could not find master self-destruct console") - to_world(SPAN_DEBUG("ERROR CODE SD1: could not find master self-destruct console")) - return FALSE - dest_rods = new - for(var/obj/structure/machinery/self_destruct/rod/I in dest_master.loc.loc) dest_rods += I - if(!dest_rods.len) - log_debug("ERROR CODE SD2: could not find any self-destruct rods") - to_world(SPAN_DEBUG("ERROR CODE SD2: could not find any self-destruct rods")) - QDEL_NULL(dest_master) - return FALSE - dest_cooldown = SELF_DESTRUCT_ROD_STARTUP_TIME / dest_rods.len - dest_master.desc = "The main operating panel for a self-destruct system. It requires very little user input, but the final safety mechanism is manually unlocked.\nAfter the initial start-up sequence, [dest_rods.len] control rods must be armed, followed by manually flipping the detonation switch." - -/** - * This proc returns the ship's z level list (or whatever specified), - * when an evac/self-destruct happens. - */ -/datum/authority/branch/evacuation/proc/get_affected_zlevels() - //Nuke is not in progress, end the round on ship only. - if(dest_status < NUKE_EXPLOSION_IN_PROGRESS && SSticker?.mode.is_in_endgame) - . = SSmapping.levels_by_any_trait(list(ZTRAIT_MARINE_MAIN_SHIP)) - return - -//========================================================================================= -//========================================================================================= -//=====================================EVACUATION========================================== -//========================================================================================= -//========================================================================================= - - -/datum/authority/branch/evacuation/proc/initiate_evacuation(force=0) //Begins the evacuation procedure. - if(force || (evac_status == EVACUATION_STATUS_STANDING_BY && !(flags_scuttle & FLAGS_EVACUATION_DENY))) - evac_time = world.time - evac_status = EVACUATION_STATUS_INITIATING - ai_announcement("Attention. Emergency. All personnel must evacuate immediately. You have [round(EVACUATION_ESTIMATE_DEPARTURE/60,1)] minute\s until departure.", 'sound/AI/evacuate.ogg') - xeno_message_all("A wave of adrenaline ripples through the hive. The fleshy creatures are trying to escape!") - - for(var/obj/structure/machinery/status_display/SD in machines) - if(is_mainship_level(SD.z)) - SD.set_picture("evac") - for(var/obj/docking_port/mobile/crashable/escape_shuttle/shuttle in SSshuttle.mobile) - shuttle.prepare_evac() - activate_lifeboats() - process_evacuation() - return TRUE - -/datum/authority/branch/evacuation/proc/cancel_evacuation() //Cancels the evac procedure. Useful if admins do not want the marines leaving. - if(evac_status == EVACUATION_STATUS_INITIATING) - evac_time = null - evac_status = EVACUATION_STATUS_STANDING_BY - deactivate_lifeboats() - ai_announcement("Evacuation has been cancelled.", 'sound/AI/evacuate_cancelled.ogg') - - if(get_security_level() == "red") - for(var/obj/structure/machinery/status_display/SD in machines) - if(is_mainship_level(SD.z)) - SD.set_picture("redalert") - - for(var/obj/docking_port/mobile/crashable/escape_shuttle/shuttle in SSshuttle.mobile) - shuttle.cancel_evac() - return TRUE - -/datum/authority/branch/evacuation/proc/begin_launch() //Launches the pods. - if(evac_status == EVACUATION_STATUS_INITIATING) - evac_status = EVACUATION_STATUS_IN_PROGRESS //Cannot cancel at this point. All shuttles are off. - spawn() //One of the few times spawn() is appropriate. No need for a new proc. - ai_announcement("WARNING: Evacuation order confirmed. Launching escape pods.", 'sound/AI/evacuation_confirmed.ogg') - addtimer(CALLBACK(src, PROC_REF(launch_lifeboats)), 10 SECONDS) // giving some time to board lifeboats - - for(var/obj/docking_port/mobile/crashable/escape_shuttle/shuttle in SSshuttle.mobile) - shuttle.evac_launch() - sleep(50) - - sleep(300) //Sleep 30 more seconds to make sure everyone had a chance to leave. - var/lifesigns = 0 - // lifesigns += P.passengers - var/obj/docking_port/mobile/crashable/lifeboat/lifeboat1 = SSshuttle.getShuttle(MOBILE_SHUTTLE_LIFEBOAT_PORT) - lifeboat1.check_for_survivors() - lifesigns += lifeboat1.survivors - var/obj/docking_port/mobile/crashable/lifeboat/lifeboat2 = SSshuttle.getShuttle(MOBILE_SHUTTLE_LIFEBOAT_STARBOARD) - lifeboat2.check_for_survivors() - lifesigns += lifeboat2.survivors - ai_announcement("ATTENTION: Evacuation complete. Outbound lifesigns detected: [lifesigns ? lifesigns : "none"].", 'sound/AI/evacuation_complete.ogg') - evac_status = EVACUATION_STATUS_COMPLETE - return TRUE - -/datum/authority/branch/evacuation/proc/process_evacuation() //Process the timer. - set background = 1 - - spawn while(evac_status == EVACUATION_STATUS_INITIATING) //If it's not departing, no need to process. - if(world.time >= evac_time + EVACUATION_AUTOMATIC_DEPARTURE) begin_launch() - sleep(10) //One second. - -/datum/authority/branch/evacuation/proc/get_status_panel_eta() - switch(evac_status) - if(EVACUATION_STATUS_INITIATING) - var/eta = EVACUATION_ESTIMATE_DEPARTURE - . = "[(eta / 60) % 60]:[add_zero(num2text(eta % 60), 2)]" - if(EVACUATION_STATUS_IN_PROGRESS) . = "NOW" - -// LIFEBOATS CORNER -/datum/authority/branch/evacuation/proc/activate_lifeboats() - for(var/obj/docking_port/stationary/lifeboat_dock/lifeboat_dock in GLOB.lifeboat_almayer_docks) - var/obj/docking_port/mobile/crashable/lifeboat/lifeboat = lifeboat_dock.get_docked() - if(lifeboat && lifeboat.available) - lifeboat.status = LIFEBOAT_ACTIVE - lifeboat_dock.open_dock() - - -/datum/authority/branch/evacuation/proc/deactivate_lifeboats() - for(var/obj/docking_port/stationary/lifeboat_dock/lifeboat_dock in GLOB.lifeboat_almayer_docks) - var/obj/docking_port/mobile/crashable/lifeboat/lifeboat = lifeboat_dock.get_docked() - if(lifeboat && lifeboat.available) - lifeboat.status = LIFEBOAT_INACTIVE - -/datum/authority/branch/evacuation/proc/launch_lifeboats() - for(var/obj/docking_port/stationary/lifeboat_dock/lifeboat_dock in GLOB.lifeboat_almayer_docks) - var/obj/docking_port/mobile/crashable/lifeboat/lifeboat = lifeboat_dock.get_docked() - if(lifeboat && lifeboat.available) - lifeboat.evac_launch() - -//========================================================================================= -//========================================================================================= -//=====================================SELF DETRUCT======================================== -//========================================================================================= -//========================================================================================= - -/datum/authority/branch/evacuation/proc/enable_self_destruct(force=0) - if(force || (dest_status == NUKE_EXPLOSION_INACTIVE && !(flags_scuttle & FLAGS_SELF_DESTRUCT_DENY))) - dest_status = NUKE_EXPLOSION_ACTIVE - dest_master.lock_or_unlock() - dest_started_at = world.time - set_security_level(SEC_LEVEL_DELTA) //also activate Delta alert, to open the SD shutters. - spawn(0) - for(var/obj/structure/machinery/door/poddoor/shutters/almayer/D in machines) - if(D.id == "sd_lockdown") - D.open() - return TRUE - -//Override is for admins bypassing normal player restrictions. -/datum/authority/branch/evacuation/proc/cancel_self_destruct(override) - if(dest_status == NUKE_EXPLOSION_ACTIVE) - var/obj/structure/machinery/self_destruct/rod/I - var/i - for(i in EvacuationAuthority.dest_rods) - I = i - if(I.active_state == SELF_DESTRUCT_MACHINE_ARMED && !override) - dest_master.state(SPAN_WARNING("WARNING: Unable to cancel detonation. Please disarm all control rods.")) - return FALSE - - dest_status = NUKE_EXPLOSION_INACTIVE - dest_master.in_progress = 1 - dest_started_at = 0 - for(i in dest_rods) - I = i - if(I.active_state == SELF_DESTRUCT_MACHINE_ACTIVE || (I.active_state == SELF_DESTRUCT_MACHINE_ARMED && override)) I.lock_or_unlock(1) - dest_master.lock_or_unlock(1) - dest_index = 1 - ai_announcement("The emergency destruct system has been deactivated.", 'sound/AI/selfdestruct_deactivated.ogg') - if(evac_status == EVACUATION_STATUS_STANDING_BY) //the evac has also been cancelled or was never started. - set_security_level(SEC_LEVEL_RED, TRUE) //both SD and evac are inactive, lowering the security level. - return TRUE - -/datum/authority/branch/evacuation/proc/initiate_self_destruct(override) - if(dest_status < NUKE_EXPLOSION_IN_PROGRESS) - var/obj/structure/machinery/self_destruct/rod/I - var/i - for(i in dest_rods) - I = i - if(I.active_state != SELF_DESTRUCT_MACHINE_ARMED && !override) - dest_master.state(SPAN_WARNING("WARNING: Unable to trigger detonation. Please arm all control rods.")) - return FALSE - dest_master.in_progress = !dest_master.in_progress - for(i in EvacuationAuthority.dest_rods) - I = i - I.in_progress = 1 - ai_announcement("DANGER. DANGER. Self-destruct system activated. DANGER. DANGER. Self-destruct in progress. DANGER. DANGER.") - trigger_self_destruct(,,override) - return TRUE - -/datum/authority/branch/evacuation/proc/trigger_self_destruct(list/z_levels = SSmapping.levels_by_trait(ZTRAIT_MARINE_MAIN_SHIP), origin = dest_master, override = FALSE, end_type = NUKE_EXPLOSION_FINISHED, play_anim = TRUE, end_round = TRUE) - set waitfor = 0 - if(dest_status < NUKE_EXPLOSION_IN_PROGRESS) //One more check for good measure, in case it's triggered through a bomb instead of the destruct mechanism/admin panel. - dest_status = NUKE_EXPLOSION_IN_PROGRESS - playsound(origin, 'sound/machines/Alarm.ogg', 75, 0, 30) - world << pick('sound/theme/nuclear_detonation1.ogg','sound/theme/nuclear_detonation2.ogg') - - var/ship_status = 1 - for(var/i in z_levels) - if(is_mainship_level(i)) - ship_status = 0 //Destroyed. - break - - var/list/alive_mobs = list() //Everyone who will be destroyed on the zlevel(s). - var/list/dead_mobs = list() //Everyone who only needs to see the cinematic. - for(var/mob/current_mob as anything in GLOB.mob_list) //This only does something cool for the people about to die, but should prove pretty interesting. - if(!current_mob || !current_mob.loc) - continue //In case something changes when we sleep(). - if(current_mob.stat == DEAD) - dead_mobs |= current_mob - continue - var/turf/current_turf = get_turf(current_mob) - if(current_turf.z in z_levels) - alive_mobs |= current_mob - shake_camera(current_mob, 110, 4) - - - sleep(100) - /*Hardcoded for now, since this was never really used for anything else. - Would ideally use a better system for showing cutscenes.*/ - var/atom/movable/screen/cinematic/explosion/C = new - - if(play_anim) - for(var/mob/current_mob as anything in alive_mobs + dead_mobs) - if(current_mob && current_mob.loc && current_mob.client) - current_mob.client.add_to_screen(C) //They may have disconnected in the mean time. - - sleep(15) //Extra 1.5 seconds to look at the ship. - flick(override ? "intro_override" : "intro_nuke", C) - sleep(35) - for(var/mob/current_mob in alive_mobs) - if(current_mob && current_mob.loc) //Who knows, maybe they escaped, or don't exist anymore. - var/turf/current_mob_turf = get_turf(current_mob) - if(current_mob_turf.z in z_levels) - if(istype(current_mob.loc, /obj/structure/closet/secure_closet/freezer/fridge)) - continue - current_mob.death(create_cause_data("nuclear explosion")) - else - if(play_anim) - current_mob.client.remove_from_screen(C) //those who managed to escape the z level at last second shouldn't have their view obstructed. - if(play_anim) - flick(ship_status ? "ship_spared" : "ship_destroyed", C) - C.icon_state = ship_status ? "summary_spared" : "summary_destroyed" - world << sound('sound/effects/explosionfar.ogg') - - if(end_round) - dest_status = end_type - - sleep(5) - if(SSticker.mode) - SSticker.mode.check_win() - - if(!SSticker.mode) //Just a safety, just in case a mode isn't running, somehow. - to_world(SPAN_ROUNDBODY("Resetting in 30 seconds!")) - sleep(300) - log_game("Rebooting due to nuclear detonation.") - world.Reboot() - return TRUE - -/datum/authority/branch/evacuation/proc/process_self_destruct() - set background = 1 - - spawn while(dest_master && dest_master.loc && dest_master.active_state == SELF_DESTRUCT_MACHINE_ARMED && dest_status == NUKE_EXPLOSION_ACTIVE && dest_index <= dest_rods.len) - var/obj/structure/machinery/self_destruct/rod/I = dest_rods[dest_index] - if(world.time >= dest_cooldown + I.activate_time) - I.lock_or_unlock() //Unlock it. - if(++dest_index <= dest_rods.len) - I = dest_rods[dest_index]//Start the next sequence. - I.activate_time = world.time - sleep(10) //Checks every second. Could integrate into another controller for better tracking. - -//Generic parent base for the self_destruct items. -/obj/structure/machinery/self_destruct - icon = 'icons/obj/structures/machinery/self_destruct.dmi' - icon_state = "console_1" - var/base_icon_state = "console" - use_power = USE_POWER_NONE //Runs unpowered, may need to change later. - density = FALSE - anchored = TRUE //So it doesn't go anywhere. - unslashable = TRUE - unacidable = TRUE //Cannot C4 it either. - mouse_opacity = FALSE //No need to click or interact with this initially. - var/in_progress = 0 //Cannot interact with while it's doing something, like an animation. - var/active_state = SELF_DESTRUCT_MACHINE_INACTIVE //What step of the process it's on. - -/obj/structure/machinery/self_destruct/Initialize(mapload, ...) - . = ..() - icon_state = "[base_icon_state]_1" - -/obj/structure/machinery/self_destruct/Destroy() - . = ..() - machines -= src - operator = null - -/obj/structure/machinery/self_destruct/ex_act(severity) - return FALSE - -/obj/structure/machinery/self_destruct/attack_hand() - if(..() || in_progress) - return FALSE //This check is backward, ugh. - return TRUE - -//Add sounds. -/obj/structure/machinery/self_destruct/proc/lock_or_unlock(lock) - set waitfor = 0 - in_progress = 1 - flick("[base_icon_state]" + (lock? "_5" : "_2"),src) - sleep(9) - mouse_opacity = !mouse_opacity - icon_state = "[base_icon_state]" + (lock? "_1" : "_3") - in_progress = 0 - active_state = active_state > SELF_DESTRUCT_MACHINE_INACTIVE ? SELF_DESTRUCT_MACHINE_INACTIVE : SELF_DESTRUCT_MACHINE_ACTIVE - -/obj/structure/machinery/self_destruct/console - name = "self-destruct control panel" - icon_state = "console_1" - base_icon_state = "console" - req_one_access = list(ACCESS_MARINE_CO, ACCESS_MARINE_SENIOR) - -/obj/structure/machinery/self_destruct/console/Destroy() - . = ..() - EvacuationAuthority.dest_master = null - EvacuationAuthority.dest_rods = null - -/obj/structure/machinery/self_destruct/console/lock_or_unlock(lock) - playsound(src, 'sound/machines/hydraulics_1.ogg', 25, 1) - ..() - -//TODO: Add sounds. -/obj/structure/machinery/self_destruct/console/attack_hand(mob/user) - if(inoperable()) - return - - tgui_interact(user) - -/obj/structure/machinery/self_destruct/console/tgui_interact(mob/user, datum/tgui/ui) - ui = SStgui.try_update_ui(user, src, ui) - if(!ui) - ui = new(user, src, "SelfDestructConsole", name) - ui.open() - -/obj/structure/machinery/sleep_console/ui_status(mob/user, datum/ui_state/state) - . = ..() - if(inoperable()) - return UI_CLOSE - - -/obj/structure/machinery/self_destruct/console/ui_data(mob/user) - var/list/data = list() - - data["dest_status"] = active_state - - return data - -/obj/structure/machinery/self_destruct/console/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) - . = ..() - if(.) - return - - switch(action) - if("dest_start") - to_chat(usr, SPAN_NOTICE("You press a few keys on the panel.")) - to_chat(usr, SPAN_NOTICE("The system must be booting up the self-destruct sequence now.")) - playsound(src.loc, 'sound/items/rped.ogg', 25, TRUE) - sleep(2 SECONDS) - ai_announcement("Danger. The emergency destruct system is now activated. The ship will detonate in T-minus 20 minutes. Automatic detonation is unavailable. Manual detonation is required.", 'sound/AI/selfdestruct.ogg') - active_state = SELF_DESTRUCT_MACHINE_ARMED //Arm it here so the process can execute it later. - var/obj/structure/machinery/self_destruct/rod/I = EvacuationAuthority.dest_rods[EvacuationAuthority.dest_index] - I.activate_time = world.time - EvacuationAuthority.process_self_destruct() - . = TRUE - - if("dest_trigger") - EvacuationAuthority.initiate_self_destruct() - . = TRUE - - if("dest_cancel") - if(!allowed(usr)) - to_chat(usr, SPAN_WARNING("You don't have the necessary clearance to cancel the emergency destruct system!")) - return - EvacuationAuthority.cancel_self_destruct() - . = TRUE - -/obj/structure/machinery/self_destruct/rod - name = "self-destruct control rod" - desc = "It is part of a complicated self-destruct sequence, but relatively simple to operate. Twist to arm or disarm." - icon_state = "rod_1" - base_icon_state = "rod" - layer = BELOW_OBJ_LAYER - var/activate_time - -/obj/structure/machinery/self_destruct/rod/Destroy() - . = ..() - if(EvacuationAuthority && EvacuationAuthority.dest_rods) - EvacuationAuthority.dest_rods -= src - -/obj/structure/machinery/self_destruct/rod/lock_or_unlock(lock) - playsound(src, 'sound/machines/hydraulics_2.ogg', 25, 1) - ..() - if(lock) - activate_time = null - density = FALSE - layer = initial(layer) - else - density = TRUE - layer = ABOVE_OBJ_LAYER - -/obj/structure/machinery/self_destruct/rod/attack_hand(mob/user) - if(..()) - switch(active_state) - if(SELF_DESTRUCT_MACHINE_ACTIVE) - to_chat(user, SPAN_NOTICE("You twist and release the control rod, arming it.")) - playsound(src, 'sound/machines/switch.ogg', 25, 1) - icon_state = "rod_4" - active_state = SELF_DESTRUCT_MACHINE_ARMED - if(SELF_DESTRUCT_MACHINE_ARMED) - to_chat(user, SPAN_NOTICE("You twist and release the control rod, disarming it.")) - playsound(src, 'sound/machines/switch.ogg', 25, 1) - icon_state = "rod_3" - active_state = SELF_DESTRUCT_MACHINE_ACTIVE - else to_chat(user, SPAN_WARNING("The control rod is not ready.")) diff --git a/code/game/gamemodes/colonialmarines/colonialmarines.dm b/code/game/gamemodes/colonialmarines/colonialmarines.dm index a2afdabe53f7..368368e83944 100644 --- a/code/game/gamemodes/colonialmarines/colonialmarines.dm +++ b/code/game/gamemodes/colonialmarines/colonialmarines.dm @@ -265,7 +265,7 @@ continue if(groundside_humans > (groundside_xenos * GROUNDSIDE_XENO_MULTIPLIER)) - SSticker.mode.get_specific_call("Xenomorphs Groundside (Forsaken)", TRUE, FALSE, FALSE, announce_dispatch_message = FALSE) + SSticker.mode.get_specific_call("Xenomorphs Groundside (Forsaken)", TRUE, FALSE) TIMER_COOLDOWN_START(src, COOLDOWN_HIJACK_GROUND_CHECK, 1 MINUTES) @@ -297,29 +297,25 @@ if(SSticker.current_state != GAME_STATE_PLAYING) return - var/living_player_list[] = count_humans_and_xenos(EvacuationAuthority.get_affected_zlevels()) + var/living_player_list[] = count_humans_and_xenos(get_affected_zlevels()) var/num_humans = living_player_list[1] var/num_xenos = living_player_list[2] if(force_end_at && world.time > force_end_at) round_finished = MODE_INFESTATION_X_MINOR - if(EvacuationAuthority.dest_status == NUKE_EXPLOSION_FINISHED) - round_finished = MODE_GENERIC_DRAW_NUKE //Nuke went off, ending the round. - if(EvacuationAuthority.dest_status == NUKE_EXPLOSION_GROUND_FINISHED) - round_finished = MODE_INFESTATION_M_MINOR //Nuke went off, ending the round. - if(EvacuationAuthority.dest_status < NUKE_EXPLOSION_IN_PROGRESS) //If the nuke ISN'T in progress. We do not want to end the round before it detonates. - if(!num_humans && num_xenos) //No humans remain alive. - round_finished = MODE_INFESTATION_X_MAJOR //Evacuation did not take place. Everyone died. - else if(num_humans && !num_xenos) - if(SSticker.mode && SSticker.mode.is_in_endgame) - round_finished = MODE_INFESTATION_X_MINOR //Evacuation successfully took place. - else - SSticker.roundend_check_paused = TRUE - round_finished = MODE_INFESTATION_M_MAJOR //Humans destroyed the xenomorphs. - ares_conclude() - addtimer(VARSET_CALLBACK(SSticker, roundend_check_paused, FALSE), MARINE_MAJOR_ROUND_END_DELAY) - else if(!num_humans && !num_xenos) - round_finished = MODE_INFESTATION_DRAW_DEATH //Both were somehow destroyed. + + if(!num_humans && num_xenos) //No humans remain alive. + round_finished = MODE_INFESTATION_X_MAJOR //Evacuation did not take place. Everyone died. + else if(num_humans && !num_xenos) + if(SSticker.mode && SSticker.mode.is_in_endgame) + round_finished = MODE_INFESTATION_X_MINOR //Evacuation successfully took place. + else + SSticker.roundend_check_paused = TRUE + round_finished = MODE_INFESTATION_M_MAJOR //Humans destroyed the xenomorphs. + ares_conclude() + addtimer(VARSET_CALLBACK(SSticker, roundend_check_paused, FALSE), MARINE_MAJOR_ROUND_END_DELAY) + else if(!num_humans && !num_xenos) + round_finished = MODE_INFESTATION_DRAW_DEATH //Both were somehow destroyed. /datum/game_mode/colonialmarines/check_queen_status(hivenumber) set waitfor = 0 @@ -367,7 +363,7 @@ round_statistics.current_map.total_marine_victories++ round_statistics.current_map.total_marine_majors++ if(MODE_INFESTATION_X_MINOR) - var/list/living_player_list = count_humans_and_xenos(EvacuationAuthority.get_affected_zlevels()) + var/list/living_player_list = count_humans_and_xenos(get_affected_zlevels()) if(living_player_list[1] && !living_player_list[2]) // If Xeno Minor but Xenos are dead and Humans are alive, see which faction is the last standing var/headcount = count_per_faction() var/living = headcount["total_headcount"] diff --git a/code/game/gamemodes/colonialmarines/huntergames.dm b/code/game/gamemodes/colonialmarines/huntergames.dm index c8c90fa51c0c..bd5302bf7ec0 100644 --- a/code/game/gamemodes/colonialmarines/huntergames.dm +++ b/code/game/gamemodes/colonialmarines/huntergames.dm @@ -11,11 +11,11 @@ #define HUNTER_GOOD_ITEM pick(\ 50; /obj/item/weapon/shield/riot, \ - 100; /obj/item/weapon/claymore, \ - 100; /obj/item/weapon/katana, \ + 100; /obj/item/weapon/sword, \ + 100; /obj/item/weapon/sword/katana, \ 100; /obj/item/weapon/harpoon/yautja, \ - 150; /obj/item/weapon/claymore/mercsword, \ - 200; /obj/item/weapon/claymore/mercsword/machete, \ + 150; /obj/item/weapon/sword, \ + 200; /obj/item/weapon/sword/machete, \ 125; /obj/item/weapon/twohanded/fireaxe, \ \ 100; /obj/item/device/binoculars, \ @@ -51,7 +51,7 @@ 300; /obj/item/tool/hatchet, \ 100; /obj/item/tool/scythe, \ 100; /obj/item/tool/kitchen/knife/butcher, \ - 50; /obj/item/weapon/katana/replica, \ + 50; /obj/item/weapon/sword/katana/replica, \ 100; /obj/item/weapon/harpoon, \ 75; /obj/item/attachable/bayonet, \ 200; /obj/item/weapon/throwing_knife, \ diff --git a/code/game/gamemodes/colonialmarines/whiskey_outpost.dm b/code/game/gamemodes/colonialmarines/whiskey_outpost.dm index 3d856f35ce77..9b3ef1df4c15 100644 --- a/code/game/gamemodes/colonialmarines/whiskey_outpost.dm +++ b/code/game/gamemodes/colonialmarines/whiskey_outpost.dm @@ -152,9 +152,6 @@ spawn(0) //Deleting Almayer, for performance! SSitem_cleanup.delete_almayer() - if(SSxenocon) - //Don't need XENOCON - SSxenocon.wait = 30 MINUTES //PROCCESS @@ -193,7 +190,7 @@ announce_xeno_wave(wave) if(xeno_wave == 7) //Wave when Marines get reinforcements! - get_specific_call("Marine Reinforcements (Squad)", FALSE, TRUE, FALSE) + get_specific_call("Marine Reinforcements (Squad)", FALSE, TRUE) xeno_wave = min(xeno_wave + 1, WO_MAX_WAVE) @@ -322,9 +319,9 @@ OT = "sup" //no breaking anything. else if (OT == "sup") - randpick = rand(0,50) + randpick = rand(0,90) switch(randpick) - if(0 to 5)//Marine Gear 10% Chance. + if(0 to 3)//Marine Gear 3% Chance. crate = new /obj/structure/closet/crate/secure/gear(T) choosemax = rand(5,10) randomitems = list(/obj/item/clothing/head/helmet/marine, @@ -340,19 +337,19 @@ /obj/effect/landmark/wo_supplies/storage/webbing, /obj/item/device/binoculars) - if(6 to 10)//Lights and shiet 10% + if(4 to 6)//Lights and shiet 2% new /obj/structure/largecrate/supply/floodlights(T) new /obj/structure/largecrate/supply/supplies/flares(T) - if(11 to 13) //6% Chance to drop this !FUN! junk. + if(7 to 10) //3% Chance to drop this !FUN! junk. crate = new /obj/structure/closet/crate/secure/gear(T) spawnitems = list(/obj/item/storage/belt/utility/full, /obj/item/storage/belt/utility/full, /obj/item/storage/belt/utility/full, /obj/item/storage/belt/utility/full) - if(14 to 18)//Materials 10% Chance. + if(11 to 22)//Materials 12% Chance. crate = new /obj/structure/closet/crate/secure/gear(T) choosemax = rand(3,8) randomitems = list(/obj/item/stack/sheet/metal, @@ -363,7 +360,7 @@ /obj/item/stack/sandbags_empty/half, /obj/item/stack/sandbags_empty/half) - if(19 to 20)//Blood Crate 4% chance + if(23 to 25)//Blood Crate 2% chance crate = new /obj/structure/closet/crate/medical(T) spawnitems = list(/obj/item/reagent_container/blood/OMinus, /obj/item/reagent_container/blood/OMinus, @@ -371,7 +368,7 @@ /obj/item/reagent_container/blood/OMinus, /obj/item/reagent_container/blood/OMinus) - if(21 to 25)//Advanced meds Crate 10% + if(26 to 30)//Advanced meds Crate 5% crate = new /obj/structure/closet/crate/medical(T) spawnitems = list(/obj/item/storage/firstaid/fire, /obj/item/storage/firstaid/regular, @@ -386,7 +383,7 @@ /obj/item/clothing/glasses/hud/health, /obj/item/device/defibrillator) - if(26 to 30)//Random Medical Items 10% as well. Made the list have less small junk + if(31 to 34)//Random Medical Items 4%. Made the list have less small junk crate = new /obj/structure/closet/crate/medical(T) spawnitems = list(/obj/item/storage/belt/medical/lifesaver/full, /obj/item/storage/belt/medical/lifesaver/full, @@ -394,7 +391,7 @@ /obj/item/storage/belt/medical/lifesaver/full, /obj/item/storage/belt/medical/lifesaver/full) - if(31 to 35)//Random explosives Crate 10% because the lord commeth and said let there be explosives. + if(35 to 40)//Random explosives Crate 5% because the lord commeth and said let there be explosives. crate = new /obj/structure/closet/crate/ammo(T) choosemax = rand(1,5) randomitems = list(/obj/item/storage/box/explosive_mines, @@ -404,7 +401,7 @@ /obj/item/explosive/grenade/high_explosive, /obj/item/storage/box/nade_box ) - if(36 to 40) // Junk + if(41 to 44) crate = new /obj/structure/closet/crate/ammo(T) spawnitems = list( /obj/item/attachable/heavy_barrel, @@ -412,20 +409,75 @@ /obj/item/attachable/heavy_barrel, /obj/item/attachable/heavy_barrel) - if(40 to 48)//Weapon + supply beacon drop. 6% + if(45 to 50)//Weapon + supply beacon drop. 5% crate = new /obj/structure/closet/crate/ammo(T) spawnitems = list(/obj/item/device/whiskey_supply_beacon, /obj/item/device/whiskey_supply_beacon, /obj/item/device/whiskey_supply_beacon, /obj/item/device/whiskey_supply_beacon) - if(49 to 50)//Rare weapons. Around 4% + if(51 to 57)//Rare weapons. Around 6% crate = new /obj/structure/closet/crate/ammo(T) spawnitems = list(/obj/effect/landmark/wo_supplies/ammo/box/rare/m41aap, /obj/effect/landmark/wo_supplies/ammo/box/rare/m41aapmag, /obj/effect/landmark/wo_supplies/ammo/box/rare/m41aextend, /obj/effect/landmark/wo_supplies/ammo/box/rare/smgap, /obj/effect/landmark/wo_supplies/ammo/box/rare/smgextend) + + if(58 to 65) // Sandbags kit + crate = new /obj/structure/closet/crate(T) + spawnitems = list(/obj/item/tool/shovel/etool, + /obj/item/stack/sandbags_empty/half, + /obj/item/stack/sandbags_empty/half, + /obj/item/stack/sandbags_empty/half) + + if(66 to 70) // Mortar shells. Pew Pew! + crate = new /obj/structure/closet/crate/secure/mortar_ammo(T) + choosemax = rand(6,10) + randomitems = list(/obj/item/mortar_shell/he, + /obj/item/mortar_shell/incendiary, + /obj/item/mortar_shell/flare, + /obj/item/mortar_shell/frag) + + if(71 to 79) + crate = new /obj/structure/closet/crate/ammo(T) + choosemax = rand(2, 3) + randomitems = list(/obj/item/ammo_box/rounds, + /obj/item/ammo_box/rounds/ap, + /obj/item/ammo_box/rounds/smg, + /obj/item/ammo_box/rounds/smg/ap, + /obj/item/ammo_box/magazine/ap, + /obj/item/ammo_box/magazine/ext, + /obj/item/ammo_box/magazine/m4ra/ap, + /obj/item/ammo_box/magazine/m4ra/ap, + /obj/item/ammo_box/magazine/m39/ap, + /obj/item/ammo_box/magazine/m39/ext, + ) + + if(80 to 82) + crate = new /obj/structure/closet/crate/ammo(T) + choosemax = rand(2, 3) + randomitems = list(/obj/item/ammo_magazine/rifle/lmg/holo_target, + /obj/item/ammo_magazine/rifle/lmg/holo_target, + /obj/item/ammo_magazine/rifle/lmg, + /obj/item/ammo_magazine/rifle/lmg, + ) + + if(83 to 86) + crate = new /obj/structure/closet/crate/ammo(T) + spawnitems = list( + /obj/item/attachable/magnetic_harness, + /obj/item/attachable/magnetic_harness, + /obj/item/attachable/magnetic_harness, + /obj/item/attachable/magnetic_harness) + + if(86 to 90) + crate = new /obj/structure/closet/crate/secure/gear(T) + spawnitems = list( + /obj/item/device/binoculars/range, + /obj/item/device/binoculars/range, + ) + if(crate) crate.storage_capacity = 60 diff --git a/code/game/gamemodes/colonialmarines/xenovsxeno.dm b/code/game/gamemodes/colonialmarines/xenovsxeno.dm index 5623295f1915..a19c3e3582c1 100644 --- a/code/game/gamemodes/colonialmarines/xenovsxeno.dm +++ b/code/game/gamemodes/colonialmarines/xenovsxeno.dm @@ -79,9 +79,6 @@ spawn(0) //Deleting Almayer, for performance! SSitem_cleanup.delete_almayer() - if(SSxenocon) - //Don't need XENOCON - SSxenocon.wait = 30 MINUTES //////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////// diff --git a/code/game/gamemodes/extended/infection.dm b/code/game/gamemodes/extended/infection.dm index 04e0545361aa..a6b909022aef 100644 --- a/code/game/gamemodes/extended/infection.dm +++ b/code/game/gamemodes/extended/infection.dm @@ -95,7 +95,7 @@ possible_survivors -= new_survivor //either we drafted a survivor, or we're skipping over someone, either or - remove them /datum/game_mode/infection/check_win() - var/living_player_list[] = count_humans_and_xenos(EvacuationAuthority.get_affected_zlevels()) + var/list/living_player_list = count_humans_and_xenos(get_affected_zlevels()) var/num_humans = living_player_list[1] var/zed = living_player_list[2] diff --git a/code/game/gamemodes/game_mode.dm b/code/game/gamemodes/game_mode.dm index f6f75c6ba4e0..e467631c915e 100644 --- a/code/game/gamemodes/game_mode.dm +++ b/code/game/gamemodes/game_mode.dm @@ -105,11 +105,16 @@ var/global/cas_tracking_id_increment = 0 //this var used to assign unique tracki np.new_player_panel_proc() round_time_lobby = world.time log_game("Round started at [time2text(world.realtime)]") + log_game("Operation time at round start is [worldtime2text()]") if(SSticker.mode) log_game("Game mode set to [SSticker.mode]") log_game("Server IP: [world.internet_address]:[world.port]") return TRUE +/datum/game_mode/proc/get_affected_zlevels() + if(is_in_endgame) + . = SSmapping.levels_by_any_trait(list(ZTRAIT_MARINE_MAIN_SHIP)) + return ///process() ///Called by the gameticker @@ -118,8 +123,7 @@ var/global/cas_tracking_id_increment = 0 //this var used to assign unique tracki /datum/game_mode/proc/check_finished() //to be called by ticker - if(EvacuationAuthority.dest_status == NUKE_EXPLOSION_FINISHED || EvacuationAuthority.dest_status == NUKE_EXPLOSION_GROUND_FINISHED ) - return TRUE + return /datum/game_mode/proc/cleanup() //This is called when the round has ended but not the game, if any cleanup would be necessary in that case. return diff --git a/code/game/jobs/job/civilians/other/liaison.dm b/code/game/jobs/job/civilians/other/liaison.dm index 7f73376a05dd..cbbb87124957 100644 --- a/code/game/jobs/job/civilians/other/liaison.dm +++ b/code/game/jobs/job/civilians/other/liaison.dm @@ -6,7 +6,7 @@ selection_class = "job_cl" flags_startup_parameters = ROLE_ADD_TO_DEFAULT gear_preset = /datum/equipment_preset/uscm_ship/liaison - entry_message_body = "As a representative of Weyland-Yutani Corporation, your job requires you to stay in character at all times. You are not required to follow military orders; however, you cannot give military orders. Your primary job is to observe and report back your findings to Weyland-Yutani. Follow regular game rules unless told otherwise by your superiors. Use your office fax machine to communicate with corporate headquarters or to acquire new directives. You may not receive anything back, and this is normal." + entry_message_body = "As a representative of Weyland-Yutani Corporation, your job requires you to stay in character at all times. You are not required to follow military orders; however, you cannot give military orders. Your primary job is to observe and report back your findings to Weyland-Yutani. Follow regular game rules unless told otherwise by your superiors. Use your office fax machine to communicate with corporate headquarters or to acquire new directives. You may not receive anything back, and this is normal." var/mob/living/carbon/human/active_liaison /datum/job/civilian/liaison/generate_entry_conditions(mob/living/liaison, whitelist_status) diff --git a/code/game/jobs/job/civilians/other/mess_seargent.dm b/code/game/jobs/job/civilians/other/mess_seargent.dm index 4b1975015a95..97578eb1159d 100644 --- a/code/game/jobs/job/civilians/other/mess_seargent.dm +++ b/code/game/jobs/job/civilians/other/mess_seargent.dm @@ -6,7 +6,7 @@ flags_startup_parameters = ROLE_ADD_TO_DEFAULT supervisors = "the auxiliary support officer" gear_preset = /datum/equipment_preset/uscm_ship/chef - entry_message_body = "Your job is to service the marines with excellent food, drinks and entertaining the shipside crew when needed. You have a lot of freedom and it is up to you, to decide what to do with it. Good luck!" + entry_message_body = "Your job is to service the marines with excellent food, drinks and entertaining the shipside crew when needed. You have a lot of freedom and it is up to you, to decide what to do with it. Good luck!" /obj/effect/landmark/start/chef name = JOB_MESS_SERGEANT diff --git a/code/game/jobs/job/civilians/other/survivors.dm b/code/game/jobs/job/civilians/other/survivors.dm index 5c82241c47de..23097e139eda 100644 --- a/code/game/jobs/job/civilians/other/survivors.dm +++ b/code/game/jobs/job/civilians/other/survivors.dm @@ -10,6 +10,8 @@ job_options = SURVIVOR_VARIANT_LIST var/intro_text var/story_text + /// Whether or not the survivor is an inherently hostile to marines. + var/hostile = FALSE /datum/job/civilian/survivor/set_spawn_positions(count) spawn_positions = Clamp((round(count * SURVIVOR_TO_TOTAL_SPAWN_RATIO)), 2, 8) @@ -59,23 +61,32 @@ if(picked_spawner.story_text) story_text = picked_spawner.story_text + + if(picked_spawner.hostile) + hostile = TRUE + new /datum/cm_objective/move_mob/almayer/survivor(H) -/datum/job/civilian/survivor/generate_entry_message(mob/living/carbon/human/H) +/datum/job/civilian/survivor/generate_entry_message(mob/living/carbon/human/survivor) if(intro_text) for(var/line in intro_text) - to_chat(H, line) + to_chat(survivor, line) else - to_chat(H, "

You are a survivor!

") - to_chat(H, SPAN_NOTICE(SSmapping.configs[GROUND_MAP].survivor_message)) - to_chat(H, SPAN_NOTICE("You are fully aware of the xenomorph threat and are able to use this knowledge as you see fit.")) - to_chat(H, SPAN_NOTICE("You are NOT aware of the marines or their intentions. ")) + to_chat(survivor, "

You are a survivor!

") + to_chat(survivor, SPAN_NOTICE(SSmapping.configs[GROUND_MAP].survivor_message)) + to_chat(survivor, SPAN_NOTICE("You are fully aware of the xenomorph threat and are able to use this knowledge as you see fit.")) + to_chat(survivor, SPAN_NOTICE("You are NOT aware of the marines or their intentions. ")) if(story_text) - to_chat(H, story_text) - H.mind.memory += story_text + to_chat(survivor, story_text) + survivor.mind.memory += story_text + else + tell_survivor_story(survivor) + + if(hostile) + to_chat(survivor, SPAN_HIGHDANGER("You are HOSTILE to the USCM!")) else - tell_survivor_story(H) + to_chat(survivor, SPAN_XENOHIGHDANGER("You are NON-HOSTILE to the USCM!")) /datum/job/civilian/survivor/proc/tell_survivor_story(mob/living/carbon/human/H) var/list/survivor_story = list( diff --git a/code/game/jobs/job/civilians/support/cmo.dm b/code/game/jobs/job/civilians/support/cmo.dm index 8c4690ea2057..835f16f7d814 100644 --- a/code/game/jobs/job/civilians/support/cmo.dm +++ b/code/game/jobs/job/civilians/support/cmo.dm @@ -6,7 +6,7 @@ selection_class = "job_cmo" flags_startup_parameters = ROLE_ADD_TO_DEFAULT gear_preset = /datum/equipment_preset/uscm_ship/uscm_medical/cmo - entry_message_body = "You're a commissioned officer of the USCM. You have authority over everything related to Medbay and Research, only able to be overriden by the XO and CO. You are in charge of medical staff, surgery, chemistry, stimulants and keeping the marines healthy overall." + entry_message_body = "You're a commissioned officer of the USCM. You have authority over everything related to Medbay and Research, only able to be overriden by the XO and CO. You are in charge of medical staff, surgery, chemistry, stimulants and keeping the marines healthy overall." AddTimelock(/datum/job/civilian/professor, list( JOB_MEDIC_ROLES = 10 HOURS diff --git a/code/game/jobs/job/civilians/support/nurse.dm b/code/game/jobs/job/civilians/support/nurse.dm index 7a0cab16f559..8912011298dc 100644 --- a/code/game/jobs/job/civilians/support/nurse.dm +++ b/code/game/jobs/job/civilians/support/nurse.dm @@ -6,7 +6,7 @@ selection_class = "job_doctor" flags_startup_parameters = ROLE_ADD_TO_DEFAULT gear_preset = /datum/equipment_preset/uscm_ship/uscm_medical/nurse - entry_message_body = "You are tasked with keeping the Marines healthy and strong. You are also an expert when it comes to medication and treatment, and can do minor surgical procedures. Focus on assisting doctors and triaging wounded marines." + entry_message_body = "You are tasked with keeping the Marines healthy and strong. You are also an expert when it comes to medication and treatment, and can do minor surgical procedures. Focus on assisting doctors and triaging wounded marines." /obj/effect/landmark/start/nurse name = JOB_NURSE diff --git a/code/game/jobs/job/civilians/support/researcher.dm b/code/game/jobs/job/civilians/support/researcher.dm index 61245c8164ab..21163f27959d 100644 --- a/code/game/jobs/job/civilians/support/researcher.dm +++ b/code/game/jobs/job/civilians/support/researcher.dm @@ -10,7 +10,7 @@ selection_class = "job_researcher" flags_startup_parameters = ROLE_ADD_TO_DEFAULT gear_preset = /datum/equipment_preset/uscm_ship/uscm_medical/researcher - entry_message_body = "You're a commissioned officer of the USCM, though you are not in the ship's chain of command. You are tasked with researching and developing new medical treatments, helping your fellow doctors, and generally learning new things. Your role involves a lot of roleplaying, but you can perform the function of a regular doctor. Do not hand out things to Marines without getting permission from your supervisor." + entry_message_body = "You're a commissioned officer of the USCM, though you are not in the ship's chain of command. You are tasked with researching and developing new medical treatments, helping your fellow doctors, and generally learning new things. Your role involves a lot of roleplaying, but you can perform the function of a regular doctor. Do not hand out things to Marines without getting permission from your supervisor." /datum/job/civilian/researcher/set_spawn_positions(count) spawn_positions = rsc_slot_formula(count) diff --git a/code/game/jobs/job/civilians/support/synthetic.dm b/code/game/jobs/job/civilians/support/synthetic.dm index 3e02385bc96c..70060fb36a15 100644 --- a/code/game/jobs/job/civilians/support/synthetic.dm +++ b/code/game/jobs/job/civilians/support/synthetic.dm @@ -9,7 +9,7 @@ flags_startup_parameters = ROLE_ADD_TO_DEFAULT|ROLE_ADMIN_NOTIFY|ROLE_WHITELISTED|ROLE_CUSTOM_SPAWN flags_whitelist = WHITELIST_SYNTHETIC gear_preset = /datum/equipment_preset/synth/uscm - entry_message_body = "You are a Synthetic! You are held to a higher standard and are required to obey not only the Server Rules but Marine Law and Synthetic Rules. Failure to do so may result in your White-list Removal. Your primary job is to support and assist all USCM Departments and Personnel on-board. In addition, being a Synthetic gives you knowledge in every field and specialization possible on-board the ship. As a Synthetic you answer to the acting commanding officer. Special circumstances may change this!" + entry_message_body = "You are a Synthetic! You are held to a higher standard and are required to obey not only the Server Rules but Marine Law and Synthetic Rules. Failure to do so may result in your White-list Removal. Your primary job is to support and assist all USCM Departments and Personnel on-board. In addition, being a Synthetic gives you knowledge in every field and specialization possible on-board the ship. As a Synthetic you answer to the acting commanding officer. Special circumstances may change this!" /datum/job/civilian/synthetic/New() . = ..() diff --git a/code/game/jobs/job/command/auxiliary/auxiliary_support_officer.dm b/code/game/jobs/job/command/auxiliary/auxiliary_support_officer.dm index e5155c949a32..5f6293000365 100644 --- a/code/game/jobs/job/command/auxiliary/auxiliary_support_officer.dm +++ b/code/game/jobs/job/command/auxiliary/auxiliary_support_officer.dm @@ -5,7 +5,7 @@ allow_additional = TRUE flags_startup_parameters = ROLE_ADD_TO_DEFAULT gear_preset = /datum/equipment_preset/uscm_ship/auxiliary_officer - entry_message_body = "Your job is to oversee the hangar crew, the intel officers, the engineering department, and requisition department. You have many responsibilities and a few plates to keep spinning but your subordinates are mostly self-reliant. Assist where you can and make sure command personnel are confident the auxiliary departments are operating at peak efficiency." + entry_message_body = "Your job is to oversee the hangar crew, the intel officers, the engineering department, and requisition department. You have many responsibilities and a few plates to keep spinning but your subordinates are mostly self-reliant. Assist where you can and make sure command personnel are confident the auxiliary departments are operating at peak efficiency." AddTimelock(/datum/job/command/auxiliary_officer, list( JOB_SQUAD_ROLES = 5 HOURS, diff --git a/code/game/jobs/job/command/auxiliary/crew_chief.dm b/code/game/jobs/job/command/auxiliary/crew_chief.dm index c8dfe2a8eb37..0770bcd60ffa 100644 --- a/code/game/jobs/job/command/auxiliary/crew_chief.dm +++ b/code/game/jobs/job/command/auxiliary/crew_chief.dm @@ -7,7 +7,7 @@ supervisors = "the pilot officers" flags_startup_parameters = ROLE_ADD_TO_DEFAULT gear_preset = /datum/equipment_preset/uscm_ship/dcc - entry_message_body = "Your job is to assist the pilot officer maintain the ship's dropship. You have authority only on the dropship, but you are expected to maintain order, as not to disrupt the pilot." + entry_message_body = "Your job is to assist the pilot officer maintain the ship's dropship. You have authority only on the dropship, but you are expected to maintain order, as not to disrupt the pilot." AddTimelock(/datum/job/command/crew_chief, list( JOB_SQUAD_ROLES = 5 HOURS diff --git a/code/game/jobs/job/command/auxiliary/intel.dm b/code/game/jobs/job/command/auxiliary/intel.dm index 8d83d49ed143..9905bc9d3747 100644 --- a/code/game/jobs/job/command/auxiliary/intel.dm +++ b/code/game/jobs/job/command/auxiliary/intel.dm @@ -8,7 +8,7 @@ supervisors = "the auxiliary support officer" flags_startup_parameters = ROLE_ADD_TO_DEFAULT|ROLE_ADD_TO_SQUAD gear_preset = "USCM Intelligence Officer (IO) (Cryo)" - entry_message_body = "Your job is to assist the marines in collecting intelligence related to the current operation to better inform command of their opposition. You are in charge of gathering any data disks, folders, and notes you may find on the operational grounds and decrypt them to grant the USCM additional resources." + entry_message_body = "Your job is to assist the marines in collecting intelligence related to the current operation to better inform command of their opposition. You are in charge of gathering any data disks, folders, and notes you may find on the operational grounds and decrypt them to grant the USCM additional resources." /datum/job/command/intel/set_spawn_positions(count) spawn_positions = int_slot_formula(count) diff --git a/code/game/jobs/job/command/auxiliary/pilot.dm b/code/game/jobs/job/command/auxiliary/pilot.dm index a75846f92919..1a7a7c21d5a0 100644 --- a/code/game/jobs/job/command/auxiliary/pilot.dm +++ b/code/game/jobs/job/command/auxiliary/pilot.dm @@ -7,7 +7,7 @@ supervisors = "the auxiliary support officer" flags_startup_parameters = ROLE_ADD_TO_DEFAULT gear_preset = /datum/equipment_preset/uscm_ship/po - entry_message_body = "Your job is to fly, protect, and maintain the ship's dropship. While you are an officer, your authority is limited to the dropship, where you have authority over the enlisted personnel. If you are not piloting, there is an autopilot fallback for command, but don't leave the dropship without reason." + entry_message_body = "Your job is to fly, protect, and maintain the ship's dropship. While you are an officer, your authority is limited to the dropship, where you have authority over the enlisted personnel. If you are not piloting, there is an autopilot fallback for command, but don't leave the dropship without reason." // Dropship Roles is both PO and DCC combined to not force people to backtrack AddTimelock(/datum/job/command/pilot, list( diff --git a/code/game/jobs/job/command/auxiliary/senior.dm b/code/game/jobs/job/command/auxiliary/senior.dm index 5e9b7caf1f10..014db9569b2a 100644 --- a/code/game/jobs/job/command/auxiliary/senior.dm +++ b/code/game/jobs/job/command/auxiliary/senior.dm @@ -7,7 +7,7 @@ job_options = list("Gunnery Sergeant" = "GySGT", "Master Sergeant" = "MSgt", "First Sergeant" = "1Sgt", "Master Gunnery Sergeant" = "MGySgt", "Sergeant Major" = "SgtMaj") /datum/job/command/senior/on_config_load() - entry_message_body = "You are held to a higher standard and are required to obey not only the Server Rules but Marine Law and Standard Operating Procedure. Failure to do so may result in your Mentorship Removal. Your primary job is to teach others the game and its mechanics, and offer advice to all USCM Departments and Personnel on-board." + entry_message_body = "You are held to a higher standard and are required to obey not only the Server Rules but Marine Law and Standard Operating Procedure. Failure to do so may result in your Mentorship Removal. Your primary job is to teach others the game and its mechanics, and offer advice to all USCM Departments and Personnel on-board." return ..() /datum/job/command/senior/announce_entry_message(mob/living/carbon/human/H) diff --git a/code/game/jobs/job/command/cic/captain.dm b/code/game/jobs/job/command/cic/captain.dm index 98db585e1d07..72f861351912 100644 --- a/code/game/jobs/job/command/cic/captain.dm +++ b/code/game/jobs/job/command/cic/captain.dm @@ -16,7 +16,7 @@ ) /datum/job/command/commander/generate_entry_message() - entry_message_body = "You are the Commanding Officer of the [MAIN_SHIP_NAME] as well as the operation. Your goal is to lead the Marines on their mission as well as protect and command the ship and her crew. Your job involves heavy roleplay and requires you to behave like a high-ranking officer and to stay in character at all times. As the Commanding Officer your only superior is High Command itself. You must abide by the Commanding Officer Code of Conduct. Failure to do so may result in punitive action against you. Godspeed." + entry_message_body = "You are the Commanding Officer of the [MAIN_SHIP_NAME] as well as the operation. Your goal is to lead the Marines on their mission as well as protect and command the ship and her crew. Your job involves heavy roleplay and requires you to behave like a high-ranking officer and to stay in character at all times. As the Commanding Officer your only superior is High Command itself. You must abide by the Commanding Officer Code of Conduct. Failure to do so may result in punitive action against you. Godspeed." return ..() /datum/job/command/commander/get_whitelist_status(list/roles_whitelist, client/player) diff --git a/code/game/jobs/job/command/cic/staffofficer.dm b/code/game/jobs/job/command/cic/staffofficer.dm index fff51624aa4b..94769de2158f 100644 --- a/code/game/jobs/job/command/cic/staffofficer.dm +++ b/code/game/jobs/job/command/cic/staffofficer.dm @@ -6,7 +6,7 @@ scaled = FALSE flags_startup_parameters = ROLE_ADD_TO_DEFAULT gear_preset = /datum/equipment_preset/uscm_ship/so - entry_message_body = "Your job is to monitor the Marines, man the CIC, and listen to your superior officers. You are in charge of logistics and the overwatch system. You are also in line to take command after other eligible superior commissioned officers." + entry_message_body = "Your job is to monitor the Marines, man the CIC, and listen to your superior officers. You are in charge of logistics and the overwatch system. You are also in line to take command after other eligible superior commissioned officers." /datum/job/command/bridge/set_spawn_positions(count) spawn_positions = so_slot_formula(count) diff --git a/code/game/jobs/job/command/police/chief_police.dm b/code/game/jobs/job/command/police/chief_police.dm index b76943c4d0ac..63e6d8023f17 100644 --- a/code/game/jobs/job/command/police/chief_police.dm +++ b/code/game/jobs/job/command/police/chief_police.dm @@ -4,7 +4,7 @@ selection_class = "job_cmp" flags_startup_parameters = ROLE_ADD_TO_DEFAULT gear_preset = /datum/equipment_preset/uscm_ship/uscm_police/cmp - entry_message_body = "You are held by a higher standard and are required to obey not only the server rules but the Marine Law. Failure to do so may result in a job ban or server ban. You lead the Military Police, ensure your officers maintain peace and stability aboard the ship. Marines can get rowdy after a few weeks of cryosleep! In addition, you are tasked with the security of high-ranking personnel, including the command staff. Keep them safe!" + entry_message_body = "You are held by a higher standard and are required to obey not only the server rules but the Marine Law. Failure to do so may result in a job ban or server ban. You lead the Military Police, ensure your officers maintain peace and stability aboard the ship. Marines can get rowdy after a few weeks of cryosleep! In addition, you are tasked with the security of high-ranking personnel, including the command staff. Keep them safe!" AddTimelock(/datum/job/command/warrant, list( JOB_POLICE_ROLES = 15 HOURS, diff --git a/code/game/jobs/job/command/police/police.dm b/code/game/jobs/job/command/police/police.dm index 7285c5b278b1..e05bc2e96256 100644 --- a/code/game/jobs/job/command/police/police.dm +++ b/code/game/jobs/job/command/police/police.dm @@ -8,7 +8,7 @@ selection_class = "job_mp" flags_startup_parameters = ROLE_ADD_TO_DEFAULT gear_preset = /datum/equipment_preset/uscm_ship/uscm_police/mp - entry_message_body = "You are held by a higher standard and are required to obey not only the server rules but the Marine Law. Failure to do so may result in a job ban or server ban. Your primary job is to maintain peace and stability aboard the ship. Marines can get rowdy after a few weeks of cryosleep! In addition, you are tasked with the security of high-ranking personnel, including the command staff. Keep them safe!" + entry_message_body = "You are held by a higher standard and are required to obey not only the server rules but the Marine Law. Failure to do so may result in a job ban or server ban. Your primary job is to maintain peace and stability aboard the ship. Marines can get rowdy after a few weeks of cryosleep! In addition, you are tasked with the security of high-ranking personnel, including the command staff. Keep them safe!" /datum/job/command/police/set_spawn_positions(count) spawn_positions = mp_slot_formula(count) diff --git a/code/game/jobs/job/command/police/warden.dm b/code/game/jobs/job/command/police/warden.dm index 55cbea975401..d2775e197537 100644 --- a/code/game/jobs/job/command/police/warden.dm +++ b/code/game/jobs/job/command/police/warden.dm @@ -5,7 +5,7 @@ flags_startup_parameters = ROLE_ADD_TO_DEFAULT supervisors = "the Chief MP" gear_preset = /datum/equipment_preset/uscm_ship/uscm_police/warden - entry_message_body = "You are held by a higher standard and are required to obey not only the server rules but the Marine Law. Failure to do so may result in a job ban or server ban. Your primary job is to maintain peace and stability aboard the ship. Marines can get rowdy after a few weeks of cryosleep! In addition, you are tasked with the mainting security records and overwatching any prisoners in Brig." + entry_message_body = "You are held by a higher standard and are required to obey not only the server rules but the Marine Law. Failure to do so may result in a job ban or server ban. Your primary job is to maintain peace and stability aboard the ship. Marines can get rowdy after a few weeks of cryosleep! In addition, you are tasked with the mainting security records and overwatching any prisoners in Brig." AddTimelock(/datum/job/command/warden, list( JOB_POLICE_ROLES = 10 HOURS diff --git a/code/game/jobs/job/job.dm b/code/game/jobs/job/job.dm index 0d68d23e5524..48ad372e1f33 100644 --- a/code/game/jobs/job/job.dm +++ b/code/game/jobs/job/job.dm @@ -49,13 +49,16 @@ if(!disp_title) disp_title = title + if(global.config.is_loaded) + on_config_load() + /datum/job/proc/on_config_load() if(entry_message_body) entry_message_body = replace_placeholders(entry_message_body) /datum/job/proc/replace_placeholders(replacement_string) - replacement_string = replacetextEx(replacement_string, "%WIKIURL%", generate_wiki_link()) - replacement_string = replacetextEx(replacement_string, "%LAWURL%", "[CONFIG_GET(string/wikiarticleurl)]/[URL_WIKI_LAW]") + replacement_string = replacetextEx(replacement_string, WIKI_PLACEHOLDER, generate_wiki_link()) + replacement_string = replacetextEx(replacement_string, LAW_PLACEHOLDER, "[CONFIG_GET(string/wikiarticleurl)]/[URL_WIKI_LAW]") return replacement_string /datum/job/proc/generate_wiki_link() diff --git a/code/game/jobs/job/logistics/cargo/cargo_tech.dm b/code/game/jobs/job/logistics/cargo/cargo_tech.dm index 3b588022bd97..c4725289c3ff 100644 --- a/code/game/jobs/job/logistics/cargo/cargo_tech.dm +++ b/code/game/jobs/job/logistics/cargo/cargo_tech.dm @@ -8,7 +8,7 @@ selection_class = "job_ct" flags_startup_parameters = ROLE_ADD_TO_DEFAULT gear_preset = /datum/equipment_preset/uscm_ship/cargo - entry_message_body = "Your job is to dispense supplies to the marines, including weapon attachments. Stay in your department when possible to ensure the marines have full access to the supplies they may require. Listen to the radio in case someone requests a supply drop via the overwatch system." + entry_message_body = "Your job is to dispense supplies to the marines, including weapon attachments. Stay in your department when possible to ensure the marines have full access to the supplies they may require. Listen to the radio in case someone requests a supply drop via the overwatch system." /datum/job/logistics/cargo/set_spawn_positions(count) spawn_positions = ct_slot_formula(count) diff --git a/code/game/jobs/job/logistics/cargo/chief_req.dm b/code/game/jobs/job/logistics/cargo/chief_req.dm index 76b7e98f2db8..5d5123e687ed 100644 --- a/code/game/jobs/job/logistics/cargo/chief_req.dm +++ b/code/game/jobs/job/logistics/cargo/chief_req.dm @@ -3,7 +3,7 @@ selection_class = "job_qm" flags_startup_parameters = ROLE_ADD_TO_DEFAULT gear_preset = /datum/equipment_preset/uscm_ship/qm - entry_message_body = "Your job is to dispense supplies to the marines, including weapon attachments. Your cargo techs can help you out, but you have final say in your department. Make sure they're not goofing off. While you may request paperwork for supplies, do not go out of your way to screw with marines, unless you want to get deposed. A happy ship is a well-functioning ship." + entry_message_body = "Your job is to dispense supplies to the marines, including weapon attachments. Your cargo techs can help you out, but you have final say in your department. Make sure they're not goofing off. While you may request paperwork for supplies, do not go out of your way to screw with marines, unless you want to get deposed. A happy ship is a well-functioning ship." AddTimelock(/datum/job/logistics/requisition, list( JOB_REQUISITION_ROLES = 10 HOURS, diff --git a/code/game/jobs/job/logistics/engi/chief_engineer.dm b/code/game/jobs/job/logistics/engi/chief_engineer.dm index 3a15c8632953..b6aa23f9c4a6 100644 --- a/code/game/jobs/job/logistics/engi/chief_engineer.dm +++ b/code/game/jobs/job/logistics/engi/chief_engineer.dm @@ -3,7 +3,7 @@ selection_class = "job_ce" flags_startup_parameters = ROLE_ADD_TO_DEFAULT gear_preset = /datum/equipment_preset/uscm_ship/chief_engineer - entry_message_body = "Your job is to maintain your department and keep your technicians in check. You are responsible for engineering, power, ordnance, and the orbital cannon. Should the commanding and executive officer be unavailable, you are next in the chain of command." + entry_message_body = "Your job is to maintain your department and keep your technicians in check. You are responsible for engineering, power, ordnance, and the orbital cannon. Should the commanding and executive officer be unavailable, you are next in the chain of command." AddTimelock(/datum/job/logistics/engineering, list( JOB_ENGINEER_ROLES = 10 HOURS, diff --git a/code/game/jobs/job/logistics/engi/maint_tech.dm b/code/game/jobs/job/logistics/engi/maint_tech.dm index 8562408360d7..b13062127a12 100644 --- a/code/game/jobs/job/logistics/engi/maint_tech.dm +++ b/code/game/jobs/job/logistics/engi/maint_tech.dm @@ -6,7 +6,7 @@ selection_class = "job_ot" flags_startup_parameters = ROLE_ADD_TO_DEFAULT gear_preset = /datum/equipment_preset/uscm_ship/maint - entry_message_body = "Your job is to maintain the integrity of the ship, including the orbital cannon. You remain one of the more flexible roles on the ship and as such may receive other menial tasks from your superiors." + entry_message_body = "Your job is to maintain the integrity of the ship, including the orbital cannon. You remain one of the more flexible roles on the ship and as such may receive other menial tasks from your superiors." /obj/effect/landmark/start/maint name = JOB_MAINT_TECH diff --git a/code/game/jobs/job/logistics/engi/ordnance_tech.dm b/code/game/jobs/job/logistics/engi/ordnance_tech.dm index bed0acf15887..43a8a7122a8f 100644 --- a/code/game/jobs/job/logistics/engi/ordnance_tech.dm +++ b/code/game/jobs/job/logistics/engi/ordnance_tech.dm @@ -9,7 +9,7 @@ selection_class = "job_ot" flags_startup_parameters = ROLE_ADD_TO_DEFAULT gear_preset = /datum/equipment_preset/uscm_ship/ordn - entry_message_body = "Your job is to maintain the integrity of the USCM weapons, munitions and equipment, including the orbital cannon. You can use the workshop in the portside hangar to construct new armaments for the marines. However you remain one of the more flexible roles on the ship and as such may receive other menial tasks from your superiors." + entry_message_body = "Your job is to maintain the integrity of the USCM weapons, munitions and equipment, including the orbital cannon. You can use the workshop in the portside hangar to construct new armaments for the marines. However you remain one of the more flexible roles on the ship and as such may receive other menial tasks from your superiors." /datum/job/logistics/otech/set_spawn_positions(count) spawn_positions = ot_slot_formula(count) diff --git a/code/game/jobs/job/marine/squad/engineer.dm b/code/game/jobs/job/marine/squad/engineer.dm index 00a6b91dcffd..1910248a61a2 100644 --- a/code/game/jobs/job/marine/squad/engineer.dm +++ b/code/game/jobs/job/marine/squad/engineer.dm @@ -5,7 +5,7 @@ allow_additional = 1 flags_startup_parameters = ROLE_ADD_TO_DEFAULT|ROLE_ADD_TO_SQUAD gear_preset = /datum/equipment_preset/uscm/engineer - entry_message_body = "You have the equipment and skill to build fortifications, reroute power lines, and bunker down. Your squaddies will look to you when it comes to construction in the field of battle." + entry_message_body = "You have the equipment and skill to build fortifications, reroute power lines, and bunker down. Your squaddies will look to you when it comes to construction in the field of battle." /datum/job/marine/engineer/set_spawn_positions(count) for(var/datum/squad/sq in RoleAuthority.squads) diff --git a/code/game/jobs/job/marine/squad/leader.dm b/code/game/jobs/job/marine/squad/leader.dm index 960a80d5f659..be78438db3d6 100644 --- a/code/game/jobs/job/marine/squad/leader.dm +++ b/code/game/jobs/job/marine/squad/leader.dm @@ -5,7 +5,7 @@ supervisors = "the acting commanding officer" flags_startup_parameters = ROLE_ADD_TO_DEFAULT|ROLE_ADD_TO_SQUAD gear_preset = /datum/equipment_preset/uscm/leader - entry_message_body = "You are responsible for the men and women of your squad. Make sure they are on task, working together, and communicating. You are also in charge of communicating with command and letting them know about the situation first hand. Keep out of harm's way." + entry_message_body = "You are responsible for the men and women of your squad. Make sure they are on task, working together, and communicating. You are also in charge of communicating with command and letting them know about the situation first hand. Keep out of harm's way." /datum/job/marine/leader/whiskey title = JOB_WO_SQUAD_LEADER diff --git a/code/game/jobs/job/marine/squad/medic.dm b/code/game/jobs/job/marine/squad/medic.dm index cdbd74acefde..3df0a3793ca5 100644 --- a/code/game/jobs/job/marine/squad/medic.dm +++ b/code/game/jobs/job/marine/squad/medic.dm @@ -5,7 +5,7 @@ allow_additional = 1 flags_startup_parameters = ROLE_ADD_TO_DEFAULT|ROLE_ADD_TO_SQUAD gear_preset = /datum/equipment_preset/uscm/medic - entry_message_body = "You tend the wounds of your squad mates and make sure they are healthy and active. You may not be a fully-fledged doctor, but you stand between life and death when it matters." + entry_message_body = "You tend the wounds of your squad mates and make sure they are healthy and active. You may not be a fully-fledged doctor, but you stand between life and death when it matters." /datum/job/marine/medic/set_spawn_positions(count) for(var/datum/squad/sq in RoleAuthority.squads) diff --git a/code/game/jobs/job/marine/squad/smartgunner.dm b/code/game/jobs/job/marine/squad/smartgunner.dm index aacc562f921b..1a89abf5d3be 100644 --- a/code/game/jobs/job/marine/squad/smartgunner.dm +++ b/code/game/jobs/job/marine/squad/smartgunner.dm @@ -6,7 +6,7 @@ scaled = 1 flags_startup_parameters = ROLE_ADD_TO_DEFAULT|ROLE_ADD_TO_SQUAD gear_preset = /datum/equipment_preset/uscm/sg - entry_message_body = "You are the smartgunner. Your task is to provide heavy weapons support." + entry_message_body = "You are the smartgunner. Your task is to provide heavy weapons support." /datum/job/marine/smartgunner/set_spawn_positions(count) spawn_positions = sg_slot_formula(count) diff --git a/code/game/jobs/job/marine/squad/specialist.dm b/code/game/jobs/job/marine/squad/specialist.dm index 42ee69ef2d5c..e69241cdc70b 100644 --- a/code/game/jobs/job/marine/squad/specialist.dm +++ b/code/game/jobs/job/marine/squad/specialist.dm @@ -6,7 +6,7 @@ scaled = 1 flags_startup_parameters = ROLE_ADD_TO_DEFAULT|ROLE_ADD_TO_SQUAD gear_preset = /datum/equipment_preset/uscm/spec - entry_message_body = "You are the very rare and valuable weapon expert, trained to use special equipment. You can serve a variety of roles, so choose carefully." + entry_message_body = "You are the very rare and valuable weapon expert, trained to use special equipment. You can serve a variety of roles, so choose carefully." /datum/job/marine/specialist/set_spawn_positions(count) spawn_positions = spec_slot_formula(count) diff --git a/code/game/jobs/job/marine/squad/standard.dm b/code/game/jobs/job/marine/squad/standard.dm index e2502576e5ea..2fcd8a3cdd28 100644 --- a/code/game/jobs/job/marine/squad/standard.dm +++ b/code/game/jobs/job/marine/squad/standard.dm @@ -6,7 +6,10 @@ spawn_positions = -1 flags_startup_parameters = ROLE_ADD_TO_DEFAULT|ROLE_ADD_TO_SQUAD gear_preset = /datum/equipment_preset/uscm/pfc - entry_message_body = "You are a rank-and-file Marine of the USCM, and that is your strength. What you lack alone, you gain standing shoulder to shoulder with the men and women of the corps. Ooh-rah!" + +/datum/job/marine/standard/on_config_load() + entry_message_body = "You are a rank-and-file Marine of the USCM, and that is your strength. What you lack alone, you gain standing shoulder to shoulder with the men and women of the corps. Ooh-rah!" + return ..() /datum/job/marine/standard/set_spawn_positions(count) spawn_positions = max((round(count * STANDARD_MARINE_TO_TOTAL_SPAWN_RATIO)), 8) diff --git a/code/game/jobs/job/marine/squad/tl.dm b/code/game/jobs/job/marine/squad/tl.dm index ebebf360e830..2b0cff3ea3ed 100644 --- a/code/game/jobs/job/marine/squad/tl.dm +++ b/code/game/jobs/job/marine/squad/tl.dm @@ -5,7 +5,7 @@ allow_additional = 1 flags_startup_parameters = ROLE_ADD_TO_DEFAULT|ROLE_ADD_TO_SQUAD gear_preset = /datum/equipment_preset/uscm/tl - entry_message_body = "You are the Team Leader.Your task is to assist the squad leader in leading the squad as well as utilize ordnance such as orbital bombardments, CAS, and mortar as well as coordinating resupply with Requisitions and CIC. If the squad leader dies, you are expected to lead in their place." + entry_message_body = "You are the Team Leader.Your task is to assist the squad leader in leading the squad as well as utilize ordnance such as orbital bombardments, CAS, and mortar as well as coordinating resupply with Requisitions and CIC. If the squad leader dies, you are expected to lead in their place." /datum/job/marine/tl/generate_entry_conditions(mob/living/carbon/human/spawning_human) . = ..() diff --git a/code/game/jobs/job/marine/squads.dm b/code/game/jobs/job/marine/squads.dm index 80f00c540383..d1c2640a81aa 100644 --- a/code/game/jobs/job/marine/squads.dm +++ b/code/game/jobs/job/marine/squads.dm @@ -210,6 +210,17 @@ roundstart = FALSE locked = TRUE +/datum/squad/marine/cbrn + name = SQUAD_CBRN + equipment_color = "#3B2A7B" //Chemical Corps Purple + chat_color = "#553EB2" + radio_freq = CBRN_FREQ + minimap_color = "#3B2A7B" + + active = FALSE + roundstart = FALSE + locked = TRUE + //############################### UPP Squads /datum/squad/upp name = "Root" @@ -604,7 +615,7 @@ if(JOB_SQUAD_MEDIC) old_lead.comm_title = "HM" if(JOB_SQUAD_TEAM_LEADER) - old_lead.comm_title = "TL" + old_lead.comm_title = "FTL" if(JOB_SQUAD_SMARTGUN) old_lead.comm_title = "SG" if(JOB_SQUAD_LEADER) diff --git a/code/game/jobs/role_authority.dm b/code/game/jobs/role_authority.dm index c147807f004e..dc9865f8d6e6 100644 --- a/code/game/jobs/role_authority.dm +++ b/code/game/jobs/role_authority.dm @@ -501,85 +501,86 @@ I hope it's easier to tell what the heck this proc is even doing, unlike previou M.job = null -/datum/authority/branch/role/proc/equip_role(mob/living/M, datum/job/J, turf/late_join) - if(!istype(M) || !istype(J)) +/datum/authority/branch/role/proc/equip_role(mob/living/new_mob, datum/job/new_job, turf/late_join) + if(!istype(new_mob) || !istype(new_job)) return . = TRUE - if(!ishuman(M)) + if(!ishuman(new_mob)) return - var/mob/living/carbon/human/H = M + var/mob/living/carbon/human/new_human = new_mob - if(J.job_options && H?.client?.prefs?.pref_special_job_options[J.title]) - J.handle_job_options(H.client.prefs.pref_special_job_options[J.title]) + if(new_job.job_options && new_human?.client?.prefs?.pref_special_job_options[new_job.title]) + new_job.handle_job_options(new_human.client.prefs.pref_special_job_options[new_job.title]) - var/job_whitelist = J.title - var/whitelist_status = J.get_whitelist_status(roles_whitelist, H.client) + var/job_whitelist = new_job.title + var/whitelist_status = new_job.get_whitelist_status(roles_whitelist, new_human.client) if(whitelist_status) - job_whitelist = "[J.title][whitelist_status]" + job_whitelist = "[new_job.title][whitelist_status]" - H.job = J.title //TODO Why is this a mob variable at all? + new_human.job = new_job.title //TODO Why is this a mob variable at all? - if(J.gear_preset_whitelist[job_whitelist]) - arm_equipment(H, J.gear_preset_whitelist[job_whitelist], FALSE, TRUE) - var/generated_account = J.generate_money_account(H) - J.announce_entry_message(H, generated_account, whitelist_status) //Tell them their spawn info. - J.generate_entry_conditions(H, whitelist_status) //Do any other thing that relates to their spawn. + if(new_job.gear_preset_whitelist[job_whitelist]) + arm_equipment(new_human, new_job.gear_preset_whitelist[job_whitelist], FALSE, TRUE) + var/generated_account = new_job.generate_money_account(new_human) + new_job.announce_entry_message(new_human, generated_account, whitelist_status) //Tell them their spawn info. + new_job.generate_entry_conditions(new_human, whitelist_status) //Do any other thing that relates to their spawn. else - arm_equipment(H, J.gear_preset, FALSE, TRUE) //After we move them, we want to equip anything else they should have. - var/generated_account = J.generate_money_account(H) - J.announce_entry_message(H, generated_account) //Tell them their spawn info. - J.generate_entry_conditions(H) //Do any other thing that relates to their spawn. + arm_equipment(new_human, new_job.gear_preset, FALSE, TRUE) //After we move them, we want to equip anything else they should have. + var/generated_account = new_job.generate_money_account(new_human) + new_job.announce_entry_message(new_human, generated_account) //Tell them their spawn info. + new_job.generate_entry_conditions(new_human) //Do any other thing that relates to their spawn. - if(J.flags_startup_parameters & ROLE_ADD_TO_SQUAD) //Are we a muhreen? Randomize our squad. This should go AFTER IDs. //TODO Robust this later. - randomize_squad(H) + if(new_job.flags_startup_parameters & ROLE_ADD_TO_SQUAD) //Are we a muhreen? Randomize our squad. This should go AFTER IDs. //TODO Robust this later. + randomize_squad(new_human) - if(Check_WO() && job_squad_roles.Find(GET_DEFAULT_ROLE(H.job))) //activates self setting proc for marine headsets for WO + if(Check_WO() && job_squad_roles.Find(GET_DEFAULT_ROLE(new_human.job))) //activates self setting proc for marine headsets for WO var/datum/game_mode/whiskey_outpost/WO = SSticker.mode - WO.self_set_headset(H) + WO.self_set_headset(new_human) var/assigned_squad - if(ishuman(H)) - var/mob/living/carbon/human/human = H + if(ishuman(new_human)) + var/mob/living/carbon/human/human = new_human if(human.assigned_squad) assigned_squad = human.assigned_squad.name if(isturf(late_join)) - H.forceMove(late_join) + new_human.forceMove(late_join) else if(late_join) var/turf/late_join_turf if(GLOB.latejoin_by_squad[assigned_squad]) late_join_turf = get_turf(pick(GLOB.latejoin_by_squad[assigned_squad])) - else if(GLOB.latejoin_by_job[J.title]) - late_join_turf = get_turf(pick(GLOB.latejoin_by_job[J.title])) + else if(GLOB.latejoin_by_job[new_job.title]) + late_join_turf = get_turf(pick(GLOB.latejoin_by_job[new_job.title])) else late_join_turf = get_turf(pick(GLOB.latejoin)) - H.forceMove(late_join_turf) + new_human.forceMove(late_join_turf) else var/turf/join_turf - if(assigned_squad && GLOB.spawns_by_squad_and_job[assigned_squad] && GLOB.spawns_by_squad_and_job[assigned_squad][J.type]) - join_turf = get_turf(pick(GLOB.spawns_by_squad_and_job[assigned_squad][J.type])) - else if(GLOB.spawns_by_job[J.type]) - join_turf = get_turf(pick(GLOB.spawns_by_job[J.type])) + if(assigned_squad && GLOB.spawns_by_squad_and_job[assigned_squad] && GLOB.spawns_by_squad_and_job[assigned_squad][new_job.type]) + join_turf = get_turf(pick(GLOB.spawns_by_squad_and_job[assigned_squad][new_job.type])) + else if(GLOB.spawns_by_job[new_job.type]) + join_turf = get_turf(pick(GLOB.spawns_by_job[new_job.type])) else if(assigned_squad && GLOB.latejoin_by_squad[assigned_squad]) join_turf = get_turf(pick(GLOB.latejoin_by_squad[assigned_squad])) else join_turf = get_turf(pick(GLOB.latejoin)) - H.forceMove(join_turf) + new_human.forceMove(join_turf) for(var/cardinal in GLOB.cardinals) - var/obj/structure/machinery/cryopod/pod = locate() in get_step(H, cardinal) + var/obj/structure/machinery/cryopod/pod = locate() in get_step(new_human, cardinal) if(pod) - pod.go_in_cryopod(H, silent = TRUE) + pod.go_in_cryopod(new_human, silent = TRUE) break - H.sec_hud_set_ID() - H.hud_set_squad() + new_human.sec_hud_set_ID() + new_human.hud_set_squad() - SSround_recording.recorder.track_player(H) + SEND_SIGNAL(new_human, COMSIG_POST_SPAWN_UPDATE) + SSround_recording.recorder.track_player(new_human) //Find which squad has the least population. If all 4 squads are equal it should just use a random one /datum/authority/branch/role/proc/get_lowest_squad(mob/living/carbon/human/H) diff --git a/code/game/machinery/ARES/ARES.dm b/code/game/machinery/ARES/ARES.dm index ed4391c89c24..1ecbb4a5d7d6 100644 --- a/code/game/machinery/ARES/ARES.dm +++ b/code/game/machinery/ARES/ARES.dm @@ -8,7 +8,6 @@ unslashable = TRUE unacidable = TRUE - var/link_id = MAIN_SHIP_DEFAULT_NAME var/datum/ares_link/link /obj/structure/machinery/ares/ex_act(severity) @@ -40,14 +39,12 @@ log_debug("Error: link_systems called without a link datum") if(link && !override) return FALSE - if(new_link.link_id == link_id) + if(new_link) link = new_link - log_debug("[name] linked to Ares Link [link_id]") new_link.linked_systems += src return TRUE /obj/structure/machinery/ares/proc/delink() - log_debug("[name] delinked from Ares Link [link.link_id]") link.linked_systems -= src link = null @@ -63,11 +60,11 @@ /obj/structure/machinery/ares/processor/apollo/link_systems(datum/ares_link/new_link = GLOB.ares_link, override) ..() - new_link.p_apollo = src + new_link.processor_apollo = src /obj/structure/machinery/ares/processor/apollo/delink() - if(link && link.p_apollo == src) - link.p_apollo = null + if(link && link.processor_apollo == src) + link.processor_apollo = null ..() /obj/structure/machinery/ares/processor/interface @@ -77,11 +74,11 @@ /obj/structure/machinery/ares/processor/interface/link_systems(datum/ares_link/new_link = GLOB.ares_link, override) ..() - new_link.p_interface = src + new_link.processor_interface = src /obj/structure/machinery/ares/processor/interface/delink() - if(link && link.p_interface == src) - link.p_interface = null + if(link && link.processor_interface == src) + link.processor_interface = null ..() /obj/structure/machinery/ares/processor/bioscan @@ -91,11 +88,11 @@ /obj/structure/machinery/ares/processor/bioscan/link_systems(datum/ares_link/new_link = GLOB.ares_link, override) ..() - new_link.p_bioscan = src + new_link.processor_bioscan = src /obj/structure/machinery/ares/processor/bioscan/delink() - if(link && link.p_bioscan == src) - link.p_bioscan = null + if(link && link.processor_bioscan == src) + link.processor_bioscan = null ..() /// Central Core @@ -104,130 +101,17 @@ desc = "This is ARES' central processor. Made of a casing designed to withstand nuclear blasts, the CPU also contains ARES' blackbox recorder." icon_state = "CPU" +/obj/structure/machinery/ares/cpu/link_systems(datum/ares_link/new_link = GLOB.ares_link, override) + ..() + new_link.central_processor = src + +/obj/structure/machinery/ares/cpu/delink() + if(link && link.central_processor == src) + link.central_processor = null + ..() + /// Memory Substrate, /obj/structure/machinery/ares/substrate name = "ARES Substrate" desc = "The memory substrate of ARES, containing complex protocols and information. Limited capabilities can operate on substrate alone, without the main ARES Unit operational." icon_state = "substrate" - -// #################### ARES Interface Console ##################### -/obj/structure/machinery/computer/ares_console - name = "ARES Interface" - desc = "A console built to interface with ARES, allowing for 1:1 communication." - icon = 'icons/obj/structures/machinery/ares.dmi' - icon_state = "console" - exproof = TRUE - - var/current_menu = "login" - var/last_menu = "" - - var/authentication = ARES_ACCESS_BASIC - - /// The last person to login. - var/last_login - /// The person pretending to be last_login - var/sudo_holder - /// A record of who logged in and when. - var/list/access_list = list() - - /// The ID used to link all devices. - var/link_id = MAIN_SHIP_DEFAULT_NAME - var/datum/ares_link/link - - /// The current deleted chat log of 1:1 conversations being read. - var/list/deleted_1to1 = list() - - /// Holds all (/datum/ares_record/announcement)s - var/list/records_announcement = list() - /// Holds all (/datum/ares_record/bioscan)s - var/list/records_bioscan = list() - /// Holds all (/datum/ares_record/bombardment)s - var/list/records_bombardment = list() - /// Holds all (/datum/ares_record/deletion)s - var/list/records_deletion = list() - /// Holds all (/datum/ares_record/talk_log)s - var/list/records_talking = list() - /// Holds all (/datum/ares_record/requisition_log)s - var/list/records_asrs = list() - /// Holds all (/datum/ares_record/security)s (including AA) - var/list/records_security = list() - /// Holds all (/datum/ares_record/flight)s - var/list/records_flight = list() - /// Is nuke request usable or not? - var/nuke_available = TRUE - - - COOLDOWN_DECLARE(ares_distress_cooldown) - COOLDOWN_DECLARE(ares_nuclear_cooldown) - COOLDOWN_DECLARE(ares_quarters_cooldown) - -/obj/structure/machinery/computer/ares_console/proc/link_systems(datum/ares_link/new_link = GLOB.ares_link, override) - if(link && !override) - return FALSE - if(new_link.link_id == link_id) - new_link.interface = src - link = new_link - log_debug("[name] linked to Ares Link [link_id]") - new_link.linked_systems += src - return TRUE - -/obj/structure/machinery/computer/ares_console/Initialize(mapload, ...) - link_systems(override = FALSE) - . = ..() - -/obj/structure/machinery/computer/ares_console/proc/delink() - if(link && link.interface == src) - link.interface = null - link.linked_systems -= src - link = null - -/obj/structure/machinery/computer/ares_console/Destroy() - delink() - return ..() - -// #################### Working Joe Ticket Console ##################### -/obj/structure/machinery/computer/working_joe - name = "APOLLO Maintenance Controller" - desc = "A console built to facilitate Working Joes and their operation, allowing for simple allocation of resources." - icon = 'icons/obj/structures/machinery/ares.dmi' - icon_state = "console" - exproof = TRUE - - /// The ID used to link all devices. - var/link_id = MAIN_SHIP_DEFAULT_NAME - var/datum/ares_link/link - var/obj/structure/machinery/ares/processor/interface/processor - - var/current_menu = "login" - var/last_menu = "" - - var/authentication = ARES_ACCESS_BASIC - /// The last person to login. - var/last_login - /// A record of who logged in and when. - var/list/login_list = list() - - -/obj/structure/machinery/computer/working_joe/proc/link_systems(datum/ares_link/new_link = GLOB.ares_link, override) - if(link && !override) - return FALSE - if(new_link.link_id == link_id) - new_link.ticket_computers += src - link = new_link - log_debug("[name] linked to Ares Link [link_id]") - new_link.linked_systems += src - return TRUE - -/obj/structure/machinery/computer/working_joe/Initialize(mapload, ...) - link_systems(override = FALSE) - . = ..() - -/obj/structure/machinery/computer/working_joe/proc/delink() - if(link) - link.ticket_computers -= src - link.linked_systems -= src - link = null - -/obj/structure/machinery/computer/working_joe/Destroy() - delink() - return ..() diff --git a/code/game/machinery/ARES/ARES_interface.dm b/code/game/machinery/ARES/ARES_interface.dm new file mode 100644 index 000000000000..0e45d5ee171b --- /dev/null +++ b/code/game/machinery/ARES/ARES_interface.dm @@ -0,0 +1,471 @@ +// #################### ARES Interface Console ##################### +/obj/structure/machinery/computer/ares_console + name = "ARES Interface" + desc = "A console built to interface with ARES, allowing for 1:1 communication." + icon = 'icons/obj/structures/machinery/ares.dmi' + icon_state = "console" + exproof = TRUE + + var/current_menu = "login" + var/last_menu = "" + + var/authentication = ARES_ACCESS_BASIC + + /// The last person to login. + var/last_login + /// The person pretending to be last_login + var/sudo_holder + + /// The current deleted chat log of 1:1 conversations being read. + var/list/deleted_1to1 = list() + + /// The ID used to link all devices. + var/datum/ares_link/link + /// The datacore storing all the information. + var/datum/ares_datacore/datacore + +/obj/structure/machinery/computer/ares_console/proc/link_systems(datum/ares_link/new_link = GLOB.ares_link, override) + if(link && !override) + return FALSE + if(new_link) + new_link.interface = src + link = new_link + new_link.linked_systems += src + if(!datacore) + datacore = GLOB.ares_datacore + return TRUE + +/obj/structure/machinery/computer/ares_console/Initialize(mapload, ...) + link_systems(override = FALSE) + . = ..() + +/obj/structure/machinery/computer/ares_console/proc/delink() + if(link) + if(link.interface == src) + link.interface = null + link.linked_systems -= src + link = null + datacore = null + +/obj/structure/machinery/computer/ares_console/Destroy() + delink() + return ..() + +// ------ ARES Interface UI ------ // + +/obj/structure/machinery/computer/ares_console/attack_hand(mob/user as mob) + if(..() || !allowed(usr) || inoperable()) + return FALSE + + tgui_interact(user) + return TRUE + +/obj/structure/machinery/computer/ares_console/tgui_interact(mob/user, datum/tgui/ui, datum/ui_state/state) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "AresInterface", name) + ui.open() + +/obj/structure/machinery/computer/ares_console/ui_data(mob/user) + var/list/data = list() + + data["current_menu"] = current_menu + data["last_page"] = last_menu + + data["logged_in"] = last_login + data["sudo"] = sudo_holder ? TRUE : FALSE + + data["access_text"] = "[sudo_holder ? "(SUDO)," : ""] access level [authentication], [ares_auth_to_text(authentication)]." + data["access_level"] = authentication + + data["alert_level"] = security_level + data["evac_status"] = SShijack.evac_status + data["worldtime"] = world.time + + data["access_log"] = datacore.interface_access_list + data["apollo_log"] = datacore.apollo_log + + data["deleted_conversation"] = deleted_1to1 + + data["distresstime"] = datacore.ares_distress_cooldown + data["distresstimelock"] = DISTRESS_TIME_LOCK + data["quarterstime"] = datacore.ares_quarters_cooldown + data["mission_failed"] = SSticker.mode.is_in_endgame + data["nuketimelock"] = NUCLEAR_TIME_LOCK + data["nuke_available"] = datacore.nuke_available + + var/list/logged_announcements = list() + for(var/datum/ares_record/announcement/broadcast as anything in datacore.records_announcement) + var/list/current_broadcast = list() + current_broadcast["time"] = broadcast.time + current_broadcast["title"] = broadcast.title + current_broadcast["details"] = broadcast.details + current_broadcast["ref"] = "\ref[broadcast]" + logged_announcements += list(current_broadcast) + data["records_announcement"] = logged_announcements + + var/list/logged_alerts = list() + for(var/datum/ares_record/security/security_alert as anything in datacore.records_security) + var/list/current_alert = list() + current_alert["time"] = security_alert.time + current_alert["title"] = security_alert.title + current_alert["details"] = security_alert.details + current_alert["ref"] = "\ref[security_alert]" + logged_alerts += list(current_alert) + data["records_security"] = logged_alerts + + var/list/logged_flights = list() + for(var/datum/ares_record/flight/flight_log as anything in datacore.records_flight) + var/list/current_flight = list() + current_flight["time"] = flight_log.time + current_flight["title"] = flight_log.title + current_flight["details"] = flight_log.details + current_flight["user"] = flight_log.user + current_flight["ref"] = "\ref[flight_log]" + logged_flights += list(current_flight) + data["records_flight"] = logged_flights + + var/list/logged_bioscans = list() + for(var/datum/ares_record/bioscan/scan as anything in datacore.records_bioscan) + var/list/current_scan = list() + current_scan["time"] = scan.time + current_scan["title"] = scan.title + current_scan["details"] = scan.details + current_scan["ref"] = "\ref[scan]" + logged_bioscans += list(current_scan) + data["records_bioscan"] = logged_bioscans + + var/list/logged_bombs = list() + for(var/datum/ares_record/bombardment/bomb as anything in datacore.records_bombardment) + var/list/current_bomb = list() + current_bomb["time"] = bomb.time + current_bomb["title"] = bomb.title + current_bomb["details"] = bomb.details + current_bomb["user"] = bomb.user + current_bomb["ref"] = "\ref[bomb]" + logged_bombs += list(current_bomb) + data["records_bombardment"] = logged_bombs + + var/list/logged_deletes = list() + for(var/datum/ares_record/deletion/deleted as anything in datacore.records_deletion) + if(!istype(deleted)) + continue + var/list/current_delete = list() + current_delete["time"] = deleted.time + current_delete["title"] = deleted.title + current_delete["details"] = deleted.details + current_delete["user"] = deleted.user + current_delete["ref"] = "\ref[deleted]" + logged_deletes += list(current_delete) + data["records_deletion"] = logged_deletes + + var/list/logged_discussions = list() + for(var/datum/ares_record/deleted_talk/deleted_convo as anything in datacore.records_deletion) + if(!istype(deleted_convo)) + continue + var/list/deleted_disc = list() + deleted_disc["time"] = deleted_convo.time + deleted_disc["title"] = deleted_convo.title + deleted_disc["ref"] = "\ref[deleted_convo]" + logged_discussions += list(deleted_disc) + data["deleted_discussions"] = logged_discussions + + var/list/logged_orders = list() + for(var/datum/ares_record/requisition_log/req_order as anything in datacore.records_asrs) + if(!istype(req_order)) + continue + var/list/current_order = list() + current_order["time"] = req_order.time + current_order["details"] = req_order.details + current_order["title"] = req_order.title + current_order["user"] = req_order.user + current_order["ref"] = "\ref[req_order]" + logged_orders += list(current_order) + data["records_requisition"] = logged_orders + + var/list/logged_convos = list() + var/list/active_convo = list() + var/active_ref + for(var/datum/ares_record/talk_log/log as anything in datacore.records_talking) + if(!istype(log)) + continue + if(log.user == last_login) + active_convo = log.conversation + active_ref = "\ref[log]" + + var/list/current_convo = list() + current_convo["user"] = log.user + current_convo["ref"] = "\ref[log]" + current_convo["conversation"] = log.conversation + logged_convos += list(current_convo) + + data["active_convo"] = active_convo + data["active_ref"] = active_ref + data["conversations"] = logged_convos + + return data + +/obj/structure/machinery/computer/ares_console/ui_status(mob/user, datum/ui_state/state) + . = ..() + if(!allowed(user)) + return UI_UPDATE + if(inoperable()) + return UI_DISABLED + +/obj/structure/machinery/computer/ares_console/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) + . = ..() + if(.) + return + + playsound(src, "keyboard_alt", 15, 1) + + switch (action) + if("go_back") + if(!last_menu) + return to_chat(usr, SPAN_WARNING("Error, no previous page detected.")) + var/temp_holder = current_menu + current_menu = last_menu + last_menu = temp_holder + + if("login") + var/mob/living/carbon/human/operator = usr + var/obj/item/card/id/idcard = operator.get_active_hand() + if(istype(idcard)) + authentication = get_ares_access(idcard) + last_login = idcard.registered_name + else if(operator.wear_id) + idcard = operator.wear_id + if(istype(idcard)) + authentication = get_ares_access(idcard) + last_login = idcard.registered_name + else + to_chat(usr, SPAN_WARNING("You require an ID card to access this terminal!")) + playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) + return FALSE + if(authentication) + datacore.interface_access_list += "[last_login] at [worldtime2text()], Access Level [authentication] - [ares_auth_to_text(authentication)]." + current_menu = "main" + + if("sudo") + var/new_user = tgui_input_text(usr, "Enter Sudo Username", "Sudo User", encode = FALSE) + if(new_user) + if(new_user == sudo_holder) + last_login = sudo_holder + sudo_holder = null + return FALSE + if(new_user == last_login) + to_chat(usr, SPAN_WARNING("Already remote logged in as this user.")) + playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) + return FALSE + sudo_holder = last_login + last_login = new_user + datacore.interface_access_list += "[last_login] at [worldtime2text()], Sudo Access." + return TRUE + if("sudo_logout") + datacore.interface_access_list += "[last_login] at [worldtime2text()], Sudo Logout." + last_login = sudo_holder + sudo_holder = null + return + // -- Page Changers -- // + if("logout") + last_menu = current_menu + current_menu = "login" + if(sudo_holder) + datacore.interface_access_list += "[last_login] at [worldtime2text()], Sudo Logout." + last_login = sudo_holder + sudo_holder = null + datacore.interface_access_list += "[last_login] logged out at [worldtime2text()]." + + if("home") + last_menu = current_menu + current_menu = "main" + if("page_1to1") + last_menu = current_menu + current_menu = "talking" + if("page_announcements") + last_menu = current_menu + current_menu = "announcements" + if("page_bioscans") + last_menu = current_menu + current_menu = "bioscans" + if("page_bombardments") + last_menu = current_menu + current_menu = "bombardments" + if("page_apollo") + last_menu = current_menu + current_menu = "apollo" + if("page_access") + last_menu = current_menu + current_menu = "access_log" + if("page_security") + last_menu = current_menu + current_menu = "security" + if("page_flight") + last_menu = current_menu + current_menu = "flight_log" + if("page_requisitions") + last_menu = current_menu + current_menu = "requisitions" + if("page_emergency") + last_menu = current_menu + current_menu = "emergency" + if("page_deleted") + last_menu = current_menu + current_menu = "delete_log" + if("page_deleted_1to1") + last_menu = current_menu + current_menu = "deleted_talks" + + // -- Delete Button -- // + if("delete_record") + var/datum/ares_record/record = locate(params["record"]) + if(record.record_name == ARES_RECORD_DELETED) + return FALSE + var/datum/ares_record/deletion/new_delete = new + var/new_details = "Error" + var/new_title = "Error" + switch(record.record_name) + if(ARES_RECORD_ANNOUNCE) + new_title = "[record.title] at [record.time]" + new_details = record.details + datacore.records_announcement -= record + if(ARES_RECORD_SECURITY, ARES_RECORD_ANTIAIR) + new_title = "[record.title] at [record.time]" + new_details = record.details + datacore.records_security -= record + if(ARES_RECORD_BIOSCAN) + new_title = "[record.title] at [record.time]" + new_details = record.details + datacore.records_bioscan -= record + if(ARES_RECORD_BOMB) + new_title = "[record.title] at [record.time]" + new_details = "[record.details] Launched by [record.user]." + datacore.records_bombardment -= record + + new_delete.details = new_details + new_delete.user = last_login + new_delete.title = new_title + + datacore.records_deletion += new_delete + + // -- 1:1 Conversation -- // + if("new_conversation") + var/datum/ares_record/talk_log/convo = new(last_login) + convo.conversation += "[MAIN_AI_SYSTEM] at [worldtime2text()], 'New 1:1 link initiated. Greetings, [last_login].'" + datacore.records_talking += convo + + if("clear_conversation") + var/datum/ares_record/talk_log/conversation = locate(params["active_convo"]) + if(!istype(conversation)) + return FALSE + var/datum/ares_record/deleted_talk/deleted = new + deleted.title = conversation.title + deleted.conversation = conversation.conversation + deleted.user = conversation.user + datacore.records_deletion += deleted + datacore.records_talking -= conversation + + if("message_ares") + var/message = tgui_input_text(usr, "What do you wish to say to ARES?", "ARES Message", encode = FALSE) + if(message) + message_ares(message, usr, params["active_convo"]) + + if("read_record") + var/datum/ares_record/deleted_talk/conversation = locate(params["record"]) + deleted_1to1 = conversation.conversation + last_menu = current_menu + current_menu = "read_deleted" + + // -- Emergency Buttons -- // + if("general_quarters") + if(!COOLDOWN_FINISHED(datacore, ares_quarters_cooldown)) + to_chat(usr, SPAN_WARNING("It has not been long enough since the last General Quarters call!")) + playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) + return FALSE + if(security_level < SEC_LEVEL_RED) + set_security_level(SEC_LEVEL_RED, no_sound = TRUE, announce = FALSE) + shipwide_ai_announcement("ATTENTION! GENERAL QUARTERS. ALL HANDS, MAN YOUR BATTLESTATIONS.", MAIN_AI_SYSTEM, 'sound/effects/GQfullcall.ogg') + log_game("[key_name(usr)] has called for general quarters via ARES.") + message_admins("[key_name_admin(usr)] has called for general quarters via ARES.") + log_ares_security("General Quarters", "[last_login] has called for general quarters via ARES.") + COOLDOWN_START(datacore, ares_quarters_cooldown, 10 MINUTES) + . = TRUE + + if("evacuation_start") + if(security_level < SEC_LEVEL_RED) + to_chat(usr, SPAN_WARNING("The ship must be under red alert in order to enact evacuation procedures.")) + playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) + return FALSE + + if(SShijack.evac_admin_denied) + to_chat(usr, SPAN_WARNING("The USCM has placed a lock on deploying the evacuation pods.")) + playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) + return FALSE + + if(!SShijack.initiate_evacuation()) + to_chat(usr, SPAN_WARNING("You are unable to initiate an evacuation procedure right now!")) + playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) + return FALSE + + log_game("[key_name(usr)] has called for an emergency evacuation via ARES.") + message_admins("[key_name_admin(usr)] has called for an emergency evacuation via ARES.") + log_ares_security("Initiate Evacuation", "[last_login] has called for an emergency evacuation via ARES.") + . = TRUE + + if("distress") + if(!SSticker.mode) + return FALSE //Not a game mode? + if(world.time < DISTRESS_TIME_LOCK) + to_chat(usr, SPAN_WARNING("You have been here for less than six minutes... what could you possibly have done!")) + playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) + return FALSE + if(!COOLDOWN_FINISHED(datacore, ares_distress_cooldown)) + to_chat(usr, SPAN_WARNING("The distress launcher is cooling down!")) + playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) + return FALSE + if(security_level == SEC_LEVEL_DELTA) + to_chat(usr, SPAN_WARNING("The ship is already undergoing self destruct procedures!")) + playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) + return FALSE + else if(security_level < SEC_LEVEL_RED) + to_chat(usr, SPAN_WARNING("The ship must be under red alert to launch a distress beacon!")) + playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) + return FALSE + + for(var/client/admin in GLOB.admins) + if((R_ADMIN|R_MOD) & admin.admin_holder.rights) + playsound_client(admin,'sound/effects/sos-morse-code.ogg',10) + SSticker.mode.request_ert(usr, TRUE) + to_chat(usr, SPAN_NOTICE("A distress beacon request has been sent to USCM High Command.")) + COOLDOWN_START(datacore, ares_distress_cooldown, COOLDOWN_COMM_REQUEST) + return TRUE + + if("nuclearbomb") + if(!SSticker.mode) + return FALSE //Not a game mode? + if(world.time < NUCLEAR_TIME_LOCK) + to_chat(usr, SPAN_WARNING("It is too soon to request Nuclear Ordnance!")) + playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) + return FALSE + if(!COOLDOWN_FINISHED(datacore, ares_nuclear_cooldown)) + to_chat(usr, SPAN_WARNING("The ordnance request frequency is garbled, wait for reset!")) + playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) + return FALSE + if(security_level == SEC_LEVEL_DELTA || SSticker.mode.is_in_endgame) + to_chat(usr, SPAN_WARNING("The mission has failed catastrophically, what do you want a nuke for?!")) + playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) + return FALSE + var/reason = tgui_input_text(usr, "Please enter reason nuclear ordnance is required.", "Reason for Nuclear Ordnance") + if(!reason) + return FALSE + for(var/client/admin in GLOB.admins) + if((R_ADMIN|R_MOD) & admin.admin_holder.rights) + playsound_client(admin,'sound/effects/sos-morse-code.ogg',10) + message_admins("[key_name(usr)] has requested use of Nuclear Ordnance (via ARES)! Reason: [reason] [CC_MARK(usr)] (APPROVE) (DENY) [ADMIN_JMP_USER(usr)] [CC_REPLY(usr)]") + to_chat(usr, SPAN_NOTICE("A nuclear ordnance request has been sent to USCM High Command for the following reason: [reason]")) + log_ares_security("Nuclear Ordnance Request", "[last_login] has sent a request for nuclear ordnance for the following reason: [reason]") + if(ares_can_interface()) + ai_silent_announcement("[last_login] has sent a request for nuclear ordnance to USCM High Command.", ".V") + ai_silent_announcement("Reason given: [reason].", ".V") + COOLDOWN_START(datacore, ares_nuclear_cooldown, COOLDOWN_COMM_DESTRUCT) + return TRUE diff --git a/code/game/machinery/ARES/ARES_interface_apollo.dm b/code/game/machinery/ARES/ARES_interface_apollo.dm new file mode 100644 index 000000000000..3bbc6065a88a --- /dev/null +++ b/code/game/machinery/ARES/ARES_interface_apollo.dm @@ -0,0 +1,414 @@ +// #################### Working Joe Ticket Console ##################### +/obj/structure/machinery/computer/working_joe + name = "APOLLO Maintenance Controller" + desc = "A console built to facilitate Working Joes and their operation, allowing for simple allocation of resources." + icon = 'icons/obj/structures/machinery/ares.dmi' + icon_state = "console" + exproof = TRUE + + /// The ID used to link all devices. + var/datum/ares_link/link + /// The datacore storing all the information. + var/datum/ares_datacore/datacore + + var/current_menu = "login" + var/last_menu = "" + + var/authentication = APOLLO_ACCESS_LOGOUT + /// The last person to login. + var/last_login + + +/obj/structure/machinery/computer/working_joe/proc/link_systems(datum/ares_link/new_link = GLOB.ares_link, override) + if(link && !override) + return FALSE + if(new_link) + new_link.ticket_computers += src + link = new_link + new_link.linked_systems += src + if(!datacore) + datacore = GLOB.ares_datacore + return TRUE + +/obj/structure/machinery/computer/working_joe/Initialize(mapload, ...) + link_systems(override = FALSE) + . = ..() + +/obj/structure/machinery/computer/working_joe/proc/delink() + if(link) + link.ticket_computers -= src + link.linked_systems -= src + link = null + datacore = null + +/obj/structure/machinery/computer/working_joe/Destroy() + delink() + return ..() + +// ------ Maintenance Controller UI ------ // +/obj/structure/machinery/computer/working_joe/attack_hand(mob/user as mob) + if(..() || !allowed(usr) || inoperable()) + return FALSE + + tgui_interact(user) + return TRUE + +/obj/structure/machinery/computer/working_joe/tgui_interact(mob/user, datum/tgui/ui, datum/ui_state/state) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "WorkingJoe", name) + ui.open() + +/obj/structure/machinery/computer/working_joe/ui_data(mob/user) + var/list/data = list() + + data["current_menu"] = current_menu + data["last_page"] = last_menu + + data["logged_in"] = last_login + + data["access_text"] = "access level [authentication], [ares_auth_to_text(authentication)]." + data["access_level"] = authentication + + data["alert_level"] = security_level + data["worldtime"] = world.time + + data["access_log"] = list() + data["access_log"] += datacore.apollo_login_list + + data["apollo_log"] = list() + data["apollo_log"] += datacore.apollo_log + + var/list/logged_maintenance = list() + for(var/datum/ares_ticket/maintenance/maint_ticket as anything in link.tickets_maintenance) + if(!istype(maint_ticket)) + continue + var/lock_status = TICKET_OPEN + switch(maint_ticket.ticket_status) + if(TICKET_REJECTED, TICKET_CANCELLED, TICKET_COMPLETED) + lock_status = TICKET_CLOSED + + var/list/current_maint = list() + current_maint["id"] = maint_ticket.ticket_id + current_maint["time"] = maint_ticket.ticket_time + current_maint["priority_status"] = maint_ticket.ticket_priority + current_maint["category"] = maint_ticket.ticket_name + current_maint["details"] = maint_ticket.ticket_details + current_maint["status"] = maint_ticket.ticket_status + current_maint["submitter"] = maint_ticket.ticket_submitter + current_maint["assignee"] = maint_ticket.ticket_assignee + current_maint["lock_status"] = lock_status + current_maint["ref"] = "\ref[maint_ticket]" + logged_maintenance += list(current_maint) + data["maintenance_tickets"] = logged_maintenance + + var/list/logged_access = list() + var/list/requesting_access = list() + for(var/datum/ares_ticket/access/access_ticket as anything in link.tickets_access) + var/lock_status = TICKET_OPEN + switch(access_ticket.ticket_status) + if(TICKET_REJECTED, TICKET_CANCELLED, TICKET_REVOKED) + lock_status = TICKET_CLOSED + + var/list/current_ticket = list() + current_ticket["id"] = access_ticket.ticket_id + current_ticket["time"] = access_ticket.ticket_time + current_ticket["priority_status"] = access_ticket.ticket_priority + current_ticket["title"] = access_ticket.ticket_name + current_ticket["details"] = access_ticket.ticket_details + current_ticket["status"] = access_ticket.ticket_status + current_ticket["submitter"] = access_ticket.ticket_submitter + current_ticket["assignee"] = access_ticket.ticket_assignee + current_ticket["lock_status"] = lock_status + current_ticket["ref"] = "\ref[access_ticket]" + logged_access += list(current_ticket) + + if(lock_status == TICKET_OPEN) + requesting_access += access_ticket.ticket_name + data["access_tickets"] = logged_access + + return data + +/obj/structure/machinery/computer/working_joe/ui_status(mob/user, datum/ui_state/state) + . = ..() + if(!allowed(user)) + return UI_UPDATE + if(inoperable()) + return UI_DISABLED + +/obj/structure/machinery/computer/working_joe/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) + . = ..() + if(.) + return + + var/playsound = TRUE + var/mob/living/carbon/human/operator = usr + + switch (action) + if("go_back") + if(!last_menu) + return to_chat(usr, SPAN_WARNING("Error, no previous page detected.")) + var/temp_holder = current_menu + current_menu = last_menu + last_menu = temp_holder + + if("login") + + var/obj/item/card/id/idcard = operator.get_active_hand() + if(istype(idcard)) + authentication = get_ares_access(idcard) + last_login = idcard.registered_name + else if(operator.wear_id) + idcard = operator.wear_id + if(istype(idcard)) + authentication = get_ares_access(idcard) + last_login = idcard.registered_name + else + to_chat(operator, SPAN_WARNING("You require an ID card to access this terminal!")) + playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) + return FALSE + if(authentication) + datacore.apollo_login_list += "[last_login] at [worldtime2text()], Access Level [authentication] - [ares_auth_to_text(authentication)]." + current_menu = "main" + + if("logout") + last_menu = current_menu + current_menu = "login" + datacore.apollo_login_list += "[last_login] logged out at [worldtime2text()]." + + if("home") + last_menu = current_menu + current_menu = "main" + if("page_logins") + last_menu = current_menu + current_menu = "login_records" + if("page_apollo") + last_menu = current_menu + current_menu = "apollo" + if("page_request") + last_menu = current_menu + current_menu = "access_requests" + if("page_report") + last_menu = current_menu + current_menu = "maint_reports" + if("page_tickets") + last_menu = current_menu + current_menu = "access_tickets" + if("page_maintenance") + last_menu = current_menu + current_menu = "maint_claim" + + if("new_report") + var/priority_report = FALSE + var/maint_type = tgui_input_list(operator, "What is the type of maintenance item you wish to report?", "Report Category", GLOB.maintenance_categories, 30 SECONDS) + switch(maint_type) + if("Major Structural Damage", "Fire", "Communications Failure", "Power Generation Failure") + priority_report = TRUE + + if(!maint_type) + return FALSE + var/details = tgui_input_text(operator, "What are the details for this report?", "Ticket Details", encode = FALSE) + if(!details) + return FALSE + + if((authentication >= APOLLO_ACCESS_REPORTER) && !priority_report) + var/is_priority = tgui_alert(operator, "Is this a priority report?", "Priority designation", list("Yes", "No")) + if(is_priority == "Yes") + priority_report = TRUE + + var/confirm = alert(operator, "Please confirm the submission of your maintenance report. \n\n Priority: [priority_report ? "Yes" : "No"]\n Category: '[maint_type]'\n Details: '[details]'\n\n Is this correct?", "Confirmation", "Yes", "No") + if(confirm == "Yes") + if(link) + var/datum/ares_ticket/maintenance/maint_ticket = new(last_login, maint_type, details, priority_report) + link.tickets_maintenance += maint_ticket + if(priority_report) + ares_apollo_talk("Priority Maintenance Report: [maint_type] - ID [maint_ticket.ticket_id]. Seek and resolve.") + log_game("ARES: Maintenance Ticket '\ref[maint_ticket]' created by [key_name(operator)] as [last_login] with Category '[maint_type]' and Details of '[details]'.") + return TRUE + return FALSE + + if("claim_ticket") + var/datum/ares_ticket/ticket = locate(params["ticket"]) + if(!istype(ticket)) + return FALSE + var/claim = TRUE + var/assigned = ticket.ticket_assignee + if(assigned) + if(assigned == last_login) + var/prompt = tgui_alert(usr, "You already claimed this ticket! Do you wish to drop your claim?", "Unclaim ticket", list("Yes", "No")) + if(prompt != "Yes") + return FALSE + /// set ticket back to pending + ticket.ticket_assignee = null + ticket.ticket_status = TICKET_PENDING + return claim + var/choice = tgui_alert(usr, "This ticket has already been claimed by [assigned]! Do you wish to override their claim?", "Claim Override", list("Yes", "No")) + if(choice != "Yes") + claim = FALSE + if(claim) + ticket.ticket_assignee = last_login + ticket.ticket_status = TICKET_ASSIGNED + return claim + + if("cancel_ticket") + var/datum/ares_ticket/ticket = locate(params["ticket"]) + if(!istype(ticket)) + return FALSE + if(ticket.ticket_submitter != last_login) + to_chat(usr, SPAN_WARNING("You cannot cancel a ticket that does not belong to you!")) + return FALSE + to_chat(usr, SPAN_WARNING("[ticket.ticket_type] [ticket.ticket_id] has been cancelled.")) + ticket.ticket_status = TICKET_CANCELLED + if(ticket.ticket_priority) + ares_apollo_talk("Priority [ticket.ticket_type] [ticket.ticket_id] has been cancelled.") + return TRUE + + if("mark_ticket") + var/datum/ares_ticket/ticket = locate(params["ticket"]) + if(!istype(ticket)) + return FALSE + if(ticket.ticket_assignee != last_login && ticket.ticket_assignee) //must be claimed by you or unclaimed.) + to_chat(usr, SPAN_WARNING("You cannot update a ticket that is not assigned to you!")) + return FALSE + var/choice = tgui_alert(usr, "What do you wish to mark the ticket as?", "Mark", list(TICKET_COMPLETED, TICKET_REJECTED), 20 SECONDS) + switch(choice) + if(TICKET_COMPLETED) + ticket.ticket_status = TICKET_COMPLETED + if(TICKET_REJECTED) + ticket.ticket_status = TICKET_REJECTED + else + return FALSE + if(ticket.ticket_priority) + ares_apollo_talk("Priority [ticket.ticket_type] [ticket.ticket_id] has been [choice] by [last_login].") + to_chat(usr, SPAN_NOTICE("[ticket.ticket_type] [ticket.ticket_id] marked as [choice].")) + return TRUE + + if("new_access") + var/obj/item/card/id/idcard = operator.get_active_hand() + var/has_id = FALSE + if(istype(idcard)) + has_id = TRUE + else if(operator.wear_id) + idcard = operator.wear_id + if(istype(idcard)) + has_id = TRUE + if(!has_id) + to_chat(operator, SPAN_WARNING("You require an ID card to request an access ticket!")) + playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) + return FALSE + if(idcard.registered_name != last_login) + to_chat(operator, SPAN_WARNING("This ID card does not match the active login!")) + playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) + return FALSE + + var/details = tgui_input_text(operator, "What is the purpose of this access ticket?", "Ticket Details", encode = FALSE) + if(!details) + return FALSE + + var/confirm = alert(operator, "Please confirm the submission of your access ticket request.\n\nHolder: '[last_login]'\nDetails: '[details]'\n\nIs this correct?", "Confirmation", "Yes", "No") + if(confirm != "Yes" || !link) + return FALSE + var/datum/ares_ticket/access/access_ticket = new(last_login, details, FALSE, idcard.registered_gid) + link.waiting_ids += idcard + link.tickets_access += access_ticket + log_game("ARES: Access Ticket '\ref[access_ticket]' created by [key_name(operator)] as [last_login] with Details of '[details]'.") + message_admins(SPAN_STAFF_IC("[key_name_admin(operator)] created a new ARES Access Ticket."), 1) + ares_apollo_talk("Access Ticket [access_ticket.ticket_id]: [access_ticket.ticket_submitter] requesting access for '[details].") + return TRUE + + if("return_access") + playsound = FALSE + var/datum/ares_ticket/access/access_ticket + for(var/datum/ares_ticket/access/possible_ticket in link.tickets_access) + if(possible_ticket.ticket_status != TICKET_GRANTED) + continue + if(possible_ticket.ticket_name != last_login) + continue + access_ticket = possible_ticket + break + + for(var/obj/item/card/id/identification in link.active_ids) + if(!istype(identification)) + continue + if(identification.registered_gid != access_ticket.user_id_num) + continue + + access_ticket.ticket_status = TICKET_RETURNED + identification.access -= ACCESS_MARINE_AI_TEMP + identification.modification_log += "Temporary AI Access self-returned by [key_name(operator)]." + + to_chat(operator, SPAN_NOTICE("Temporary Access Ticket surrendered.")) + playsound(src, 'sound/machines/chime.ogg', 15, 1) + ares_apollo_talk("Access Ticket [access_ticket.ticket_id]: [access_ticket.ticket_submitter] surrendered their access.") + + authentication = get_ares_access(identification) + if(authentication) + datacore.apollo_login_list += "[last_login] at [worldtime2text()], Surrendered Temporary Access Ticket." + return TRUE + + to_chat(operator, SPAN_WARNING("This ID card does not have an access ticket!")) + playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) + return FALSE + + if("auth_access") + playsound = FALSE + var/datum/ares_ticket/access/access_ticket = locate(params["ticket"]) + if(!access_ticket) + return FALSE + for(var/obj/item/card/id/identification in link.waiting_ids) + if(!istype(identification)) + continue + if(identification.registered_gid != access_ticket.user_id_num) + continue + identification.handle_ares_access(last_login, operator) + access_ticket.ticket_status = TICKET_GRANTED + playsound(src, 'sound/machines/chime.ogg', 15, 1) + ares_apollo_talk("Access Ticket [access_ticket.ticket_id]: [access_ticket.ticket_submitter] was granted access by [last_login].") + return TRUE + for(var/obj/item/card/id/identification in link.active_ids) + if(!istype(identification)) + continue + if(identification.registered_gid != access_ticket.user_id_num) + continue + identification.handle_ares_access(last_login, operator) + access_ticket.ticket_status = TICKET_REVOKED + playsound(src, 'sound/machines/chime.ogg', 15, 1) + ares_apollo_talk("Access Ticket [access_ticket.ticket_id]: [access_ticket.ticket_submitter] had access revoked by [last_login].") + return TRUE + return FALSE + + if("reject_access") + var/datum/ares_ticket/access/access_ticket = locate(params["ticket"]) + if(!istype(access_ticket)) + return FALSE + if(access_ticket.ticket_assignee != last_login && access_ticket.ticket_assignee) //must be claimed by you or unclaimed.) + to_chat(usr, SPAN_WARNING("You cannot update a ticket that is not assigned to you!")) + return FALSE + access_ticket.ticket_status = TICKET_REJECTED + to_chat(usr, SPAN_NOTICE("[access_ticket.ticket_type] [access_ticket.ticket_id] marked as rejected.")) + ares_apollo_talk("Access Ticket [access_ticket.ticket_id]: [access_ticket.ticket_submitter] was rejected access by [last_login].") + return TRUE + + if(playsound) + playsound(src, "keyboard_alt", 15, 1) + +/obj/item/card/id/proc/handle_ares_access(logged_in, mob/user) + var/operator = key_name(user) + var/datum/ares_link/link = GLOB.ares_link + if(logged_in == MAIN_AI_SYSTEM) + if(!user) + operator = "[MAIN_AI_SYSTEM] (Sensor Trip)" + else + operator = "[user.ckey]/([MAIN_AI_SYSTEM])" + if(ACCESS_MARINE_AI_TEMP in access) + access -= ACCESS_MARINE_AI_TEMP + link.active_ids -= src + modification_log += "Temporary AI access revoked by [operator]" + to_chat(user, SPAN_NOTICE("Access revoked from [registered_name].")) + else + access += ACCESS_MARINE_AI_TEMP + modification_log += "Temporary AI access granted by [operator]" + to_chat(user, SPAN_NOTICE("Access granted to [registered_name].")) + link.waiting_ids -= src + link.active_ids += src + return TRUE diff --git a/code/game/machinery/ARES/ARES_procs.dm b/code/game/machinery/ARES/ARES_procs.dm index e03f218f0f34..831f76e48930 100644 --- a/code/game/machinery/ARES/ARES_procs.dm +++ b/code/game/machinery/ARES/ARES_procs.dm @@ -1,4 +1,5 @@ GLOBAL_DATUM_INIT(ares_link, /datum/ares_link, new) +GLOBAL_DATUM_INIT(ares_datacore, /datum/ares_datacore, new) GLOBAL_LIST_INIT(maintenance_categories, list( "Broken Light", "Shattered Glass", @@ -15,26 +16,56 @@ GLOBAL_LIST_INIT(maintenance_categories, list( )) /datum/ares_link - var/link_id = MAIN_SHIP_DEFAULT_NAME /// All motion triggers for the link var/list/linked_alerts = list() /// All machinery for the link var/list/linked_systems = list() - var/obj/structure/machinery/ares/processor/interface/p_interface - var/obj/structure/machinery/ares/processor/apollo/p_apollo - var/obj/structure/machinery/ares/processor/bioscan/p_bioscan + var/obj/structure/machinery/ares/cpu/central_processor + var/obj/structure/machinery/ares/processor/interface/processor_interface + var/obj/structure/machinery/ares/processor/apollo/processor_apollo + var/obj/structure/machinery/ares/processor/bioscan/processor_bioscan var/obj/structure/machinery/computer/ares_console/interface var/list/obj/structure/machinery/computer/working_joe/ticket_computers = list() - /// The chat log of the apollo link. Timestamped. - var/list/apollo_log = list() - /// Working Joe stuff var/list/tickets_maintenance = list() var/list/tickets_access = list() var/list/waiting_ids = list() var/list/active_ids = list() +/datum/ares_datacore + /// A record of who logged in and when. + var/list/interface_access_list = list() + /// Access list for Apollo Maintenance Console + var/list/apollo_login_list = list() + + /// The chat log of the apollo link. Timestamped. + var/list/apollo_log = list() + + /// Holds all (/datum/ares_record/announcement)s + var/list/records_announcement = list() + /// Holds all (/datum/ares_record/bioscan)s + var/list/records_bioscan = list() + /// Holds all (/datum/ares_record/bombardment)s + var/list/records_bombardment = list() + /// Holds all (/datum/ares_record/deletion)s + var/list/records_deletion = list() + /// Holds all (/datum/ares_record/talk_log)s + var/list/records_talking = list() + /// Holds all (/datum/ares_record/requisition_log)s + var/list/records_asrs = list() + /// Holds all (/datum/ares_record/security)s (including AA) + var/list/records_security = list() + /// Holds all (/datum/ares_record/flight)s + var/list/records_flight = list() + /// Is nuke request usable or not? + var/nuke_available = TRUE + + + COOLDOWN_DECLARE(ares_distress_cooldown) + COOLDOWN_DECLARE(ares_nuclear_cooldown) + COOLDOWN_DECLARE(ares_quarters_cooldown) + /datum/ares_link/Destroy() for(var/obj/structure/machinery/ares/link in linked_systems) link.delink() @@ -46,38 +77,6 @@ GLOBAL_LIST_INIT(maintenance_categories, list( // ------ ARES Logging Procs ------ // -/proc/log_ares_apollo(speaker, message) - if(!speaker) - speaker = "Unknown" - var/datum/ares_link/link = GLOB.ares_link - if(!link.p_apollo || link.p_apollo.inoperable()) - return FALSE - if(!link.p_interface || link.p_interface.inoperable()) - return FALSE - link.apollo_log.Add("[worldtime2text()]: [speaker], '[message]'") - -/datum/ares_link/proc/log_ares_bioscan(title, input) - interface.records_bioscan.Add(new /datum/ares_record/bioscan(title, input)) - -/datum/ares_link/proc/log_ares_bombardment(user_name, ob_name, coordinates) - interface.records_bombardment.Add(new /datum/ares_record/bombardment(ob_name, "Bombardment fired at [coordinates].", user_name)) - -/datum/ares_link/proc/log_ares_announcement(title, message) - interface.records_announcement.Add(new /datum/ares_record/announcement(title, message)) - -/datum/ares_link/proc/log_ares_requisition(source, details, user_name) - interface.records_asrs.Add(new /datum/ares_record/requisition_log(source, details, user_name)) - -/datum/ares_link/proc/log_ares_security(title, details) - interface.records_security.Add(new /datum/ares_record/security(title, details)) - -/datum/ares_link/proc/log_ares_antiair(details) - interface.records_security.Add(new /datum/ares_record/security/antiair(details)) - -/datum/ares_link/proc/log_ares_flight(user_name, details) - interface.records_flight.Add(new /datum/ares_record/flight(details, user_name)) -// ------ End ARES Logging Procs ------ // - /proc/ares_apollo_talk(broadcast_message) var/datum/language/apollo/apollo = GLOB.all_languages[LANGUAGE_APOLLO] for(var/mob/living/silicon/decoy/ship_ai/ai in ai_mob_list) @@ -89,7 +88,7 @@ GLOBAL_LIST_INIT(maintenance_categories, list( playsound_client(listener.client, sound('sound/misc/interference.ogg'), listener, vol = 45) /proc/ares_can_interface() - var/obj/structure/machinery/ares/processor/interface/processor = GLOB.ares_link.p_interface + var/obj/structure/machinery/ares/processor/interface/processor = GLOB.ares_link.processor_interface if(!istype(GLOB.ares_link)) return FALSE if(processor && !processor.inoperable()) @@ -97,12 +96,66 @@ GLOBAL_LIST_INIT(maintenance_categories, list( return FALSE //interface processor not found or is broken /proc/ares_can_log() - var/obj/structure/machinery/computer/ares_console/interface = GLOB.ares_link.interface - if(!istype(GLOB.ares_link)) + if(!istype(GLOB.ares_link) || !istype(GLOB.ares_datacore)) return FALSE - if(interface && !interface.inoperable()) + var/obj/structure/machinery/ares/cpu/central_processor = GLOB.ares_link.central_processor + if(central_processor && !central_processor.inoperable()) return TRUE - return FALSE //ares interface not found or is broken + return FALSE //CPU not found or is broken + +/proc/log_ares_apollo(speaker, message) + if(!ares_can_log()) + return FALSE + var/datum/ares_link/link = GLOB.ares_link + if(!link.processor_apollo || link.processor_apollo.inoperable()) + return FALSE + if(!speaker) + speaker = "Unknown" + var/datum/ares_datacore/datacore = GLOB.ares_datacore + datacore.apollo_log.Add("[worldtime2text()]: [speaker], '[message]'") + +/proc/log_ares_bioscan(title, input) + if(!ares_can_log()) + return FALSE + var/datum/ares_datacore/datacore = GLOB.ares_datacore + datacore.records_bioscan.Add(new /datum/ares_record/bioscan(title, input)) + +/proc/log_ares_bombardment(user_name, ob_name, coordinates) + if(!ares_can_log()) + return FALSE + var/datum/ares_datacore/datacore = GLOB.ares_datacore + datacore.records_bombardment.Add(new /datum/ares_record/bombardment(ob_name, "Bombardment fired at [coordinates].", user_name)) + +/proc/log_ares_announcement(title, message) + if(!ares_can_log()) + return FALSE + var/datum/ares_datacore/datacore = GLOB.ares_datacore + datacore.records_announcement.Add(new /datum/ares_record/announcement(title, message)) + +/proc/log_ares_requisition(source, details, user_name) + if(!ares_can_log()) + return FALSE + var/datum/ares_datacore/datacore = GLOB.ares_datacore + datacore.records_asrs.Add(new /datum/ares_record/requisition_log(source, details, user_name)) + +/proc/log_ares_security(title, details) + if(!ares_can_log()) + return FALSE + var/datum/ares_datacore/datacore = GLOB.ares_datacore + datacore.records_security.Add(new /datum/ares_record/security(title, details)) + +/proc/log_ares_antiair(details) + if(!ares_can_log()) + return FALSE + var/datum/ares_datacore/datacore = GLOB.ares_datacore + datacore.records_security.Add(new /datum/ares_record/security/antiair(details)) + +/proc/log_ares_flight(user_name, details) + if(!ares_can_log()) + return FALSE + var/datum/ares_datacore/datacore = GLOB.ares_datacore + datacore.records_flight.Add(new /datum/ares_record/flight(details, user_name)) +// ------ End ARES Logging Procs ------ // // ------ ARES Interface Procs ------ // /obj/structure/machinery/computer/proc/get_ares_access(obj/item/card/id/card) @@ -172,440 +225,6 @@ GLOBAL_LIST_INIT(maintenance_categories, list( conversation.conversation += "[MAIN_AI_SYSTEM] at [worldtime2text()], '[text]'" // ------ End ARES Interface Procs ------ // -// ------ ARES Interface UI ------ // - -/obj/structure/machinery/computer/ares_console/attack_hand(mob/user as mob) - if(..() || !allowed(usr) || inoperable()) - return FALSE - - tgui_interact(user) - return TRUE - -/obj/structure/machinery/computer/ares_console/tgui_interact(mob/user, datum/tgui/ui, datum/ui_state/state) - ui = SStgui.try_update_ui(user, src, ui) - if(!ui) - ui = new(user, src, "AresInterface", name) - ui.open() - -/obj/structure/machinery/computer/ares_console/ui_data(mob/user) - var/list/data = list() - - data["current_menu"] = current_menu - data["last_page"] = last_menu - - data["logged_in"] = last_login - data["sudo"] = sudo_holder ? TRUE : FALSE - - data["access_text"] = "[sudo_holder ? "(SUDO)," : ""] access level [authentication], [ares_auth_to_text(authentication)]." - data["access_level"] = authentication - - data["alert_level"] = security_level - data["evac_status"] = EvacuationAuthority.evac_status - data["worldtime"] = world.time - - data["access_log"] = list() - data["access_log"] += access_list - data["apollo_log"] = list() - data["apollo_log"] += link.apollo_log - - data["deleted_conversation"] = list() - data["deleted_conversation"] += deleted_1to1 - - data["distresstime"] = ares_distress_cooldown - data["distresstimelock"] = DISTRESS_TIME_LOCK - data["quarterstime"] = ares_quarters_cooldown - data["mission_failed"] = SSticker.mode.is_in_endgame - data["nuketimelock"] = NUCLEAR_TIME_LOCK - data["nuke_available"] = nuke_available - - var/list/logged_announcements = list() - for(var/datum/ares_record/announcement/broadcast as anything in records_announcement) - var/list/current_broadcast = list() - current_broadcast["time"] = broadcast.time - current_broadcast["title"] = broadcast.title - current_broadcast["details"] = broadcast.details - current_broadcast["ref"] = "\ref[broadcast]" - logged_announcements += list(current_broadcast) - data["records_announcement"] = logged_announcements - - var/list/logged_alerts = list() - for(var/datum/ares_record/security/security_alert as anything in records_security) - var/list/current_alert = list() - current_alert["time"] = security_alert.time - current_alert["title"] = security_alert.title - current_alert["details"] = security_alert.details - current_alert["ref"] = "\ref[security_alert]" - logged_alerts += list(current_alert) - data["records_security"] = logged_alerts - - var/list/logged_flights = list() - for(var/datum/ares_record/flight/flight_log as anything in records_flight) - var/list/current_flight = list() - current_flight["time"] = flight_log.time - current_flight["title"] = flight_log.title - current_flight["details"] = flight_log.details - current_flight["user"] = flight_log.user - current_flight["ref"] = "\ref[flight_log]" - logged_flights += list(current_flight) - data["records_flight"] = logged_flights - - var/list/logged_bioscans = list() - for(var/datum/ares_record/bioscan/scan as anything in records_bioscan) - var/list/current_scan = list() - current_scan["time"] = scan.time - current_scan["title"] = scan.title - current_scan["details"] = scan.details - current_scan["ref"] = "\ref[scan]" - logged_bioscans += list(current_scan) - data["records_bioscan"] = logged_bioscans - - var/list/logged_bombs = list() - for(var/datum/ares_record/bombardment/bomb as anything in records_bombardment) - var/list/current_bomb = list() - current_bomb["time"] = bomb.time - current_bomb["title"] = bomb.title - current_bomb["details"] = bomb.details - current_bomb["user"] = bomb.user - current_bomb["ref"] = "\ref[bomb]" - logged_bombs += list(current_bomb) - data["records_bombardment"] = logged_bombs - - var/list/logged_deletes = list() - for(var/datum/ares_record/deletion/deleted as anything in records_deletion) - if(!istype(deleted)) - continue - var/list/current_delete = list() - current_delete["time"] = deleted.time - current_delete["title"] = deleted.title - current_delete["details"] = deleted.details - current_delete["user"] = deleted.user - current_delete["ref"] = "\ref[deleted]" - logged_deletes += list(current_delete) - data["records_deletion"] = logged_deletes - - var/list/logged_discussions = list() - for(var/datum/ares_record/deleted_talk/deleted_convo as anything in records_deletion) - if(!istype(deleted_convo)) - continue - var/list/deleted_disc = list() - deleted_disc["time"] = deleted_convo.time - deleted_disc["title"] = deleted_convo.title - deleted_disc["ref"] = "\ref[deleted_convo]" - logged_discussions += list(deleted_disc) - data["deleted_discussions"] = logged_discussions - - var/list/logged_orders = list() - for(var/datum/ares_record/requisition_log/req_order as anything in records_asrs) - if(!istype(req_order)) - continue - var/list/current_order = list() - current_order["time"] = req_order.time - current_order["details"] = req_order.details - current_order["title"] = req_order.title - current_order["user"] = req_order.user - current_order["ref"] = "\ref[req_order]" - logged_orders += list(current_order) - data["records_requisition"] = logged_orders - - var/list/logged_convos = list() - var/list/active_convo = list() - var/active_ref - for(var/datum/ares_record/talk_log/log as anything in records_talking) - if(!istype(log)) - continue - if(log.user == last_login) - active_convo = log.conversation - active_ref = "\ref[log]" - - var/list/current_convo = list() - current_convo["user"] = log.user - current_convo["ref"] = "\ref[log]" - current_convo["conversation"] = log.conversation - logged_convos += list(current_convo) - - data["active_convo"] = active_convo - data["active_ref"] = active_ref - data["conversations"] = logged_convos - - return data - -/obj/structure/machinery/computer/ares_console/ui_static_data(mob/user) - var/list/data = list() - - data["link_id"] = link_id - - return data - -/obj/structure/machinery/computer/ares_console/ui_status(mob/user, datum/ui_state/state) - . = ..() - if(!allowed(user)) - return UI_UPDATE - if(inoperable()) - return UI_DISABLED - -/obj/structure/machinery/computer/ares_console/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) - . = ..() - if(.) - return - - playsound(src, "keyboard_alt", 15, 1) - - switch (action) - if("go_back") - if(!last_menu) - return to_chat(usr, SPAN_WARNING("Error, no previous page detected.")) - var/temp_holder = current_menu - current_menu = last_menu - last_menu = temp_holder - - if("login") - var/mob/living/carbon/human/operator = usr - var/obj/item/card/id/idcard = operator.get_active_hand() - if(istype(idcard)) - authentication = get_ares_access(idcard) - last_login = idcard.registered_name - else if(operator.wear_id) - idcard = operator.wear_id - if(istype(idcard)) - authentication = get_ares_access(idcard) - last_login = idcard.registered_name - else - to_chat(usr, SPAN_WARNING("You require an ID card to access this terminal!")) - playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) - return FALSE - if(authentication) - access_list += "[last_login] at [worldtime2text()], Access Level [authentication] - [ares_auth_to_text(authentication)]." - current_menu = "main" - - if("sudo") - var/new_user = tgui_input_text(usr, "Enter Sudo Username", "Sudo User", encode = FALSE) - if(new_user) - if(new_user == sudo_holder) - last_login = sudo_holder - sudo_holder = null - return FALSE - if(new_user == last_login) - to_chat(usr, SPAN_WARNING("Already remote logged in as this user.")) - playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) - return FALSE - sudo_holder = last_login - last_login = new_user - access_list += "[last_login] at [worldtime2text()], Sudo Access." - return TRUE - if("sudo_logout") - access_list += "[last_login] at [worldtime2text()], Sudo Logout." - last_login = sudo_holder - sudo_holder = null - return - // -- Page Changers -- // - if("logout") - last_menu = current_menu - current_menu = "login" - if(sudo_holder) - access_list += "[last_login] at [worldtime2text()], Sudo Logout." - last_login = sudo_holder - sudo_holder = null - access_list += "[last_login] logged out at [worldtime2text()]." - - if("home") - last_menu = current_menu - current_menu = "main" - if("page_1to1") - last_menu = current_menu - current_menu = "talking" - if("page_announcements") - last_menu = current_menu - current_menu = "announcements" - if("page_bioscans") - last_menu = current_menu - current_menu = "bioscans" - if("page_bombardments") - last_menu = current_menu - current_menu = "bombardments" - if("page_apollo") - last_menu = current_menu - current_menu = "apollo" - if("page_access") - last_menu = current_menu - current_menu = "access_log" - if("page_security") - last_menu = current_menu - current_menu = "security" - if("page_flight") - last_menu = current_menu - current_menu = "flight_log" - if("page_requisitions") - last_menu = current_menu - current_menu = "requisitions" - if("page_emergency") - last_menu = current_menu - current_menu = "emergency" - if("page_deleted") - last_menu = current_menu - current_menu = "delete_log" - if("page_deleted_1to1") - last_menu = current_menu - current_menu = "deleted_talks" - - // -- Delete Button -- // - if("delete_record") - var/datum/ares_record/record = locate(params["record"]) - if(record.record_name == ARES_RECORD_DELETED) - return FALSE - var/datum/ares_record/deletion/new_delete = new - var/new_details = "Error" - var/new_title = "Error" - switch(record.record_name) - if(ARES_RECORD_ANNOUNCE) - new_title = "[record.title] at [record.time]" - new_details = record.details - records_announcement -= record - if(ARES_RECORD_SECURITY, ARES_RECORD_ANTIAIR) - new_title = "[record.title] at [record.time]" - new_details = record.details - records_security -= record - if(ARES_RECORD_BIOSCAN) - new_title = "[record.title] at [record.time]" - new_details = record.details - records_bioscan -= record - if(ARES_RECORD_BOMB) - new_title = "[record.title] at [record.time]" - new_details = "[record.details] Launched by [record.user]." - records_bombardment -= record - - new_delete.details = new_details - new_delete.user = last_login - new_delete.title = new_title - - records_deletion += new_delete - - // -- 1:1 Conversation -- // - if("new_conversation") - var/datum/ares_record/talk_log/convo = new(last_login) - convo.conversation += "[MAIN_AI_SYSTEM] at [worldtime2text()], 'New 1:1 link initiated. Greetings, [last_login].'" - records_talking += convo - - if("clear_conversation") - var/datum/ares_record/talk_log/conversation = locate(params["active_convo"]) - if(!istype(conversation)) - return FALSE - var/datum/ares_record/deleted_talk/deleted = new - deleted.title = conversation.title - deleted.conversation = conversation.conversation - deleted.user = conversation.user - records_deletion += deleted - records_talking -= conversation - - if("message_ares") - var/message = tgui_input_text(usr, "What do you wish to say to ARES?", "ARES Message", encode = FALSE) - if(message) - message_ares(message, usr, params["active_convo"]) - - if("read_record") - var/datum/ares_record/deleted_talk/conversation = locate(params["record"]) - deleted_1to1 = conversation.conversation - last_menu = current_menu - current_menu = "read_deleted" - - // -- Emergency Buttons -- // - if("general_quarters") - if(!COOLDOWN_FINISHED(src, ares_quarters_cooldown)) - to_chat(usr, SPAN_WARNING("It has not been long enough since the last General Quarters call!")) - playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) - return FALSE - if(security_level < SEC_LEVEL_RED) - set_security_level(SEC_LEVEL_RED, no_sound = TRUE, announce = FALSE) - shipwide_ai_announcement("ATTENTION! GENERAL QUARTERS. ALL HANDS, MAN YOUR BATTLESTATIONS.", MAIN_AI_SYSTEM, 'sound/effects/GQfullcall.ogg') - log_game("[key_name(usr)] has called for general quarters via ARES.") - message_admins("[key_name_admin(usr)] has called for general quarters via ARES.") - var/datum/ares_link/link = GLOB.ares_link - link.log_ares_security("General Quarters", "[last_login] has called for general quarters via ARES.") - COOLDOWN_START(src, ares_quarters_cooldown, 10 MINUTES) - . = TRUE - - if("evacuation_start") - if(security_level < SEC_LEVEL_RED) - to_chat(usr, SPAN_WARNING("The ship must be under red alert in order to enact evacuation procedures.")) - playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) - return FALSE - - if(EvacuationAuthority.flags_scuttle & FLAGS_EVACUATION_DENY) - to_chat(usr, SPAN_WARNING("The USCM has placed a lock on deploying the evacuation pods.")) - playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) - return FALSE - - if(!EvacuationAuthority.initiate_evacuation()) - to_chat(usr, SPAN_WARNING("You are unable to initiate an evacuation procedure right now!")) - playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) - return FALSE - - log_game("[key_name(usr)] has called for an emergency evacuation via ARES.") - message_admins("[key_name_admin(usr)] has called for an emergency evacuation via ARES.") - var/datum/ares_link/link = GLOB.ares_link - link.log_ares_security("Initiate Evacuation", "[last_login] has called for an emergency evacuation via ARES.") - . = TRUE - - if("distress") - if(!SSticker.mode) - return FALSE //Not a game mode? - if(world.time < DISTRESS_TIME_LOCK) - to_chat(usr, SPAN_WARNING("You have been here for less than six minutes... what could you possibly have done!")) - playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) - return FALSE - if(!COOLDOWN_FINISHED(src, ares_distress_cooldown)) - to_chat(usr, SPAN_WARNING("The distress launcher is cooling down!")) - playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) - return FALSE - if(security_level == SEC_LEVEL_DELTA) - to_chat(usr, SPAN_WARNING("The ship is already undergoing self destruct procedures!")) - playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) - return FALSE - else if(security_level < SEC_LEVEL_RED) - to_chat(usr, SPAN_WARNING("The ship must be under red alert to launch a distress beacon!")) - playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) - return FALSE - - for(var/client/admin in GLOB.admins) - if((R_ADMIN|R_MOD) & admin.admin_holder.rights) - playsound_client(admin,'sound/effects/sos-morse-code.ogg',10) - SSticker.mode.request_ert(usr, TRUE) - to_chat(usr, SPAN_NOTICE("A distress beacon request has been sent to USCM High Command.")) - COOLDOWN_START(src, ares_distress_cooldown, COOLDOWN_COMM_REQUEST) - return TRUE - - if("nuclearbomb") - if(!SSticker.mode) - return FALSE //Not a game mode? - if(world.time < NUCLEAR_TIME_LOCK) - to_chat(usr, SPAN_WARNING("It is too soon to request Nuclear Ordnance!")) - playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) - return FALSE - if(!COOLDOWN_FINISHED(src, ares_nuclear_cooldown)) - to_chat(usr, SPAN_WARNING("The ordnance request frequency is garbled, wait for reset!")) - playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) - return FALSE - if(security_level == SEC_LEVEL_DELTA || SSticker.mode.is_in_endgame) - to_chat(usr, SPAN_WARNING("The mission has failed catastrophically, what do you want a nuke for?!")) - playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) - return FALSE - var/reason = tgui_input_text(usr, "Please enter reason nuclear ordnance is required.", "Reason for Nuclear Ordnance") - if(!reason) - return FALSE - for(var/client/admin in GLOB.admins) - if((R_ADMIN|R_MOD) & admin.admin_holder.rights) - playsound_client(admin,'sound/effects/sos-morse-code.ogg',10) - message_admins("[key_name(usr)] has requested use of Nuclear Ordnance (via ARES)! Reason: [reason] [CC_MARK(usr)] (APPROVE) (DENY) [ADMIN_JMP_USER(usr)] [CC_REPLY(usr)]") - to_chat(usr, SPAN_NOTICE("A nuclear ordnance request has been sent to USCM High Command for the following reason: [reason]")) - if(ares_can_log()) - link.log_ares_security("Nuclear Ordnance Request", "[last_login] has sent a request for nuclear ordnance for the following reason: [reason]") - if(ares_can_interface()) - ai_silent_announcement("[last_login] has sent a request for nuclear ordnance to USCM High Command.", ".V") - ai_silent_announcement("Reason given: [reason].", ".V") - COOLDOWN_START(src, ares_nuclear_cooldown, COOLDOWN_COMM_DESTRUCT) - return TRUE -// ------ End ARES Interface UI ------ // - - /obj/structure/machinery/computer/working_joe/get_ares_access(obj/item/card/id/card) if(ACCESS_ARES_DEBUG in card.access) return APOLLO_ACCESS_DEBUG @@ -640,368 +259,36 @@ GLOBAL_LIST_INIT(maintenance_categories, list( if(APOLLO_ACCESS_DEBUG)//6 return "AI Service Technician" -// ------ Maintenance Controller UI ------ // -/obj/structure/machinery/computer/working_joe/attack_hand(mob/user as mob) - if(..() || !allowed(usr) || inoperable()) - return FALSE - - tgui_interact(user) - return TRUE - -/obj/structure/machinery/computer/working_joe/tgui_interact(mob/user, datum/tgui/ui, datum/ui_state/state) - ui = SStgui.try_update_ui(user, src, ui) - if(!ui) - ui = new(user, src, "WorkingJoe", name) - ui.open() - -/obj/structure/machinery/computer/working_joe/ui_data(mob/user) - var/list/data = list() - - data["current_menu"] = current_menu - data["last_page"] = last_menu - - data["logged_in"] = last_login - - data["access_text"] = "access level [authentication], [ares_auth_to_text(authentication)]." - data["access_level"] = authentication - - data["alert_level"] = security_level - data["worldtime"] = world.time - - data["access_log"] = list() - data["access_log"] += login_list - - data["apollo_log"] = list() - data["apollo_log"] += link.apollo_log - - var/list/logged_maintenance = list() - for(var/datum/ares_ticket/maintenance/maint_ticket as anything in link.tickets_maintenance) - if(!istype(maint_ticket)) - continue - var/lock_status = TICKET_OPEN - switch(maint_ticket.ticket_status) - if(TICKET_REJECTED, TICKET_CANCELLED, TICKET_COMPLETED) - lock_status = TICKET_CLOSED - - var/list/current_maint = list() - current_maint["id"] = maint_ticket.ticket_id - current_maint["time"] = maint_ticket.ticket_time - current_maint["priority_status"] = maint_ticket.ticket_priority - current_maint["category"] = maint_ticket.ticket_name - current_maint["details"] = maint_ticket.ticket_details - current_maint["status"] = maint_ticket.ticket_status - current_maint["submitter"] = maint_ticket.ticket_submitter - current_maint["assignee"] = maint_ticket.ticket_assignee - current_maint["lock_status"] = lock_status - current_maint["ref"] = "\ref[maint_ticket]" - logged_maintenance += list(current_maint) - data["maintenance_tickets"] = logged_maintenance - - var/list/logged_access = list() - var/list/requesting_access = list() - for(var/datum/ares_ticket/access/access_ticket as anything in link.tickets_access) - var/lock_status = TICKET_OPEN - switch(access_ticket.ticket_status) - if(TICKET_REJECTED, TICKET_CANCELLED, TICKET_REVOKED) - lock_status = TICKET_CLOSED - - var/list/current_ticket = list() - current_ticket["id"] = access_ticket.ticket_id - current_ticket["time"] = access_ticket.ticket_time - current_ticket["priority_status"] = access_ticket.ticket_priority - current_ticket["title"] = access_ticket.ticket_name - current_ticket["details"] = access_ticket.ticket_details - current_ticket["status"] = access_ticket.ticket_status - current_ticket["submitter"] = access_ticket.ticket_submitter - current_ticket["assignee"] = access_ticket.ticket_assignee - current_ticket["lock_status"] = lock_status - current_ticket["ref"] = "\ref[access_ticket]" - logged_access += list(current_ticket) - - if(lock_status == TICKET_OPEN) - requesting_access += access_ticket.ticket_name - data["access_tickets"] = logged_access - - return data - -/obj/structure/machinery/computer/working_joe/ui_static_data(mob/user) - var/list/data = list() - - data["link_id"] = link_id - - return data - -/obj/structure/machinery/computer/working_joe/ui_status(mob/user, datum/ui_state/state) - . = ..() - if(!allowed(user)) - return UI_UPDATE - if(inoperable()) - return UI_DISABLED - -/obj/structure/machinery/computer/working_joe/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) - . = ..() - if(.) - return - - var/playsound = TRUE - var/mob/living/carbon/human/operator = usr - - switch (action) - if("go_back") - if(!last_menu) - return to_chat(usr, SPAN_WARNING("Error, no previous page detected.")) - var/temp_holder = current_menu - current_menu = last_menu - last_menu = temp_holder - - if("login") - - var/obj/item/card/id/idcard = operator.get_active_hand() - if(istype(idcard)) - authentication = get_ares_access(idcard) - last_login = idcard.registered_name - else if(operator.wear_id) - idcard = operator.wear_id - if(istype(idcard)) - authentication = get_ares_access(idcard) - last_login = idcard.registered_name - else - to_chat(operator, SPAN_WARNING("You require an ID card to access this terminal!")) - playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) - return FALSE - if(authentication) - login_list += "[last_login] at [worldtime2text()], Access Level [authentication] - [ares_auth_to_text(authentication)]." - current_menu = "main" - - if("logout") - last_menu = current_menu - current_menu = "login" - login_list += "[last_login] logged out at [worldtime2text()]." - - if("home") - last_menu = current_menu - current_menu = "main" - if("page_logins") - last_menu = current_menu - current_menu = "login_records" - if("page_apollo") - last_menu = current_menu - current_menu = "apollo" - if("page_request") - last_menu = current_menu - current_menu = "access_requests" - if("page_report") - last_menu = current_menu - current_menu = "maint_reports" - if("page_tickets") - last_menu = current_menu - current_menu = "access_tickets" - if("page_maintenance") - last_menu = current_menu - current_menu = "maint_claim" - - if("new_report") - var/priority_report = FALSE - var/maint_type = tgui_input_list(operator, "What is the type of maintenance item you wish to report?", "Report Category", GLOB.maintenance_categories, 30 SECONDS) - switch(maint_type) - if("Major Structural Damage", "Fire", "Communications Failure", "Power Generation Failure") - priority_report = TRUE - - if(!maint_type) - return FALSE - var/details = tgui_input_text(operator, "What are the details for this report?", "Ticket Details", encode = FALSE) - if(!details) - return FALSE - - if((authentication >= APOLLO_ACCESS_REPORTER) && !priority_report) - var/is_priority = tgui_alert(operator, "Is this a priority report?", "Priority designation", list("Yes", "No")) - if(is_priority == "Yes") - priority_report = TRUE - - var/confirm = alert(operator, "Please confirm the submission of your maintenance report. \n\n Priority: [priority_report ? "Yes" : "No"] \n Category: '[maint_type]' \n Details: '[details]' \n\n Is this correct?", "Confirmation", "Yes", "No") - if(confirm == "Yes") - if(link) - var/datum/ares_ticket/maintenance/maint_ticket = new(last_login, maint_type, details, priority_report) - link.tickets_maintenance += maint_ticket - if(priority_report) - ares_apollo_talk("Priority Maintenance Report: [maint_type] - ID [maint_ticket.ticket_id]. Seek and resolve.") - log_game("ARES: Maintenance Ticket '\ref[maint_ticket]' created by [key_name(operator)] as [last_login] with Category '[maint_type]' and Details of '[details]'.") - return TRUE - return FALSE - - if("claim_ticket") - var/datum/ares_ticket/ticket = locate(params["ticket"]) - if(!istype(ticket)) - return FALSE - var/claim = TRUE - var/assigned = ticket.ticket_assignee - if(assigned) - if(assigned == last_login) - var/prompt = tgui_alert(usr, "You already claimed this ticket! Do you wish to drop your claim?", "Unclaim ticket", list("Yes", "No")) - if(prompt != "Yes") - return FALSE - /// set ticket back to pending - ticket.ticket_assignee = null - ticket.ticket_status = TICKET_PENDING - return claim - var/choice = tgui_alert(usr, "This ticket has already been claimed by [assigned]! Do you wish to override their claim?", "Claim Override", list("Yes", "No")) - if(choice != "Yes") - claim = FALSE - if(claim) - ticket.ticket_assignee = last_login - ticket.ticket_status = TICKET_ASSIGNED - return claim - - if("cancel_ticket") - var/datum/ares_ticket/ticket = locate(params["ticket"]) - if(!istype(ticket)) - return FALSE - if(ticket.ticket_submitter != last_login) - to_chat(usr, SPAN_WARNING("You cannot cancel a ticket that does not belong to you!")) - return FALSE - to_chat(usr, SPAN_WARNING("[ticket.ticket_type] [ticket.ticket_id] has been cancelled.")) - ticket.ticket_status = TICKET_CANCELLED - if(ticket.ticket_priority) - ares_apollo_talk("Priority [ticket.ticket_type] [ticket.ticket_id] has been cancelled.") - return TRUE - - if("mark_ticket") - var/datum/ares_ticket/ticket = locate(params["ticket"]) - if(!istype(ticket)) - return FALSE - if(ticket.ticket_assignee != last_login && ticket.ticket_assignee) //must be claimed by you or unclaimed.) - to_chat(usr, SPAN_WARNING("You cannot update a ticket that is not assigned to you!")) - return FALSE - var/choice = tgui_alert(usr, "What do you wish to mark the ticket as?", "Mark", list(TICKET_COMPLETED, TICKET_REJECTED), 20 SECONDS) - switch(choice) - if(TICKET_COMPLETED) - ticket.ticket_status = TICKET_COMPLETED - if(TICKET_REJECTED) - ticket.ticket_status = TICKET_REJECTED - else - return FALSE - if(ticket.ticket_priority) - ares_apollo_talk("Priority [ticket.ticket_type] [ticket.ticket_id] has been [choice] by [last_login].") - to_chat(usr, SPAN_NOTICE("[ticket.ticket_type] [ticket.ticket_id] marked as [choice].")) - return TRUE - - if("new_access") - var/obj/item/card/id/idcard = operator.get_active_hand() - var/has_id = FALSE - if(istype(idcard)) - has_id = TRUE - else if(operator.wear_id) - idcard = operator.wear_id - if(istype(idcard)) - has_id = TRUE - if(!has_id) - to_chat(operator, SPAN_WARNING("You require an ID card to request an access ticket!")) - playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) - return FALSE - if(idcard.registered_name != last_login) - to_chat(operator, SPAN_WARNING("This ID card does not match the active login!")) - playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) - return FALSE - - var/ticket_holder = last_login - if(!ticket_holder) - return FALSE - var/details = tgui_input_text(operator, "What is the purpose of this access ticket?", "Ticket Details", encode = FALSE) - if(!details) - return FALSE - - var/confirm = alert(operator, "Please confirm the submission of your access ticket request. \n\nHolder: '[ticket_holder]' \n Details: '[details]' \n\n Is this correct?", "Confirmation", "Yes", "No") - if(confirm != "Yes" || !link) - return FALSE - var/datum/ares_ticket/access/access_ticket = new(last_login, ticket_holder, details, FALSE, idcard.registered_gid) - link.waiting_ids += idcard - link.tickets_access += access_ticket - log_game("ARES: Access Ticket '\ref[access_ticket]' created by [key_name(operator)] as [last_login] with Holder '[ticket_holder]' and Details of '[details]'.") - message_admins(SPAN_STAFF_IC("[key_name_admin(operator)] created a new ARES Access Ticket."), 1) - return TRUE - - if("return_access") - playsound = FALSE - var/datum/ares_ticket/access/access_ticket - for(var/datum/ares_ticket/access/possible_ticket in link.tickets_access) - if(possible_ticket.ticket_status != TICKET_GRANTED) - continue - if(possible_ticket.ticket_name != last_login) - continue - access_ticket = possible_ticket - break - - for(var/obj/item/card/id/identification in link.active_ids) - if(!istype(identification)) - continue - if(identification.registered_gid != access_ticket.user_id_num) - continue - - access_ticket.ticket_status = TICKET_RETURNED - identification.access -= ACCESS_MARINE_AI_TEMP - identification.modification_log += "Temporary AI Access self-returned by [key_name(operator)]." - - to_chat(operator, SPAN_NOTICE("Temporary Access Ticket surrendered.")) - playsound(src, 'sound/machines/chime.ogg', 15, 1) - ares_apollo_talk("[last_login] surrendered their access ticket.") - - authentication = get_ares_access(identification) - if(authentication) - login_list += "[last_login] at [worldtime2text()], Surrendered Temporary Access Ticket." - return TRUE - - to_chat(operator, SPAN_WARNING("This ID card does not have an access ticket!")) - playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) - return FALSE - - if("auth_access") - playsound = FALSE - var/datum/ares_ticket/access/access_ticket = locate(params["ticket"]) - if(!access_ticket) - return FALSE - for(var/obj/item/card/id/identification in link.waiting_ids) - if(!istype(identification)) - continue - if(identification.registered_gid != access_ticket.user_id_num) - continue - identification.handle_ares_access(last_login, operator) - access_ticket.ticket_status = TICKET_GRANTED - playsound(src, 'sound/machines/chime.ogg', 15, 1) - return TRUE - for(var/obj/item/card/id/identification in link.active_ids) - if(!istype(identification)) - continue - if(identification.registered_gid != access_ticket.user_id_num) - continue - identification.handle_ares_access(last_login, operator) - access_ticket.ticket_status = TICKET_REVOKED - playsound(src, 'sound/machines/chime.ogg', 15, 1) - return TRUE - return FALSE - - if(playsound) - playsound(src, "keyboard_alt", 15, 1) - -/obj/item/card/id/proc/handle_ares_access(logged_in, mob/user) - var/announce_text = "[logged_in] revoked core access from [registered_name]'s ID card." - var/operator = key_name(user) - var/datum/ares_link/link = GLOB.ares_link - if(logged_in == MAIN_AI_SYSTEM) - if(!user) - operator = "[MAIN_AI_SYSTEM] (Sensor Trip)" - else - operator = "[user.ckey]/([MAIN_AI_SYSTEM])" - if(ACCESS_MARINE_AI_TEMP in access) - access -= ACCESS_MARINE_AI_TEMP - link.active_ids -= src - modification_log += "Temporary AI access revoked by [operator]" - to_chat(user, SPAN_NOTICE("Access revoked from [registered_name].")) +/obj/item/device/working_joe_pda/proc/get_ares_access(obj/item/card/id/card) + if(ACCESS_ARES_DEBUG in card.access) + return APOLLO_ACCESS_DEBUG + switch(card.assignment) + if(JOB_WORKING_JOE) + return APOLLO_ACCESS_JOE + if(JOB_CHIEF_ENGINEER, JOB_SYNTH, JOB_CO) + return APOLLO_ACCESS_AUTHED + if(ACCESS_MARINE_AI in card.access) + return APOLLO_ACCESS_AUTHED + if(ACCESS_MARINE_AI_TEMP in card.access) + return APOLLO_ACCESS_TEMP + if((ACCESS_MARINE_SENIOR in card.access ) || (ACCESS_MARINE_ENGINEERING in card.access) || (ACCESS_WY_GENERAL in card.access)) + return APOLLO_ACCESS_REPORTER else - access += ACCESS_MARINE_AI_TEMP - modification_log += "Temporary AI access granted by [operator]" - announce_text = "[logged_in] granted core access to [registered_name]'s ID card." - to_chat(user, SPAN_NOTICE("Access granted to [registered_name].")) - link.waiting_ids -= src - link.active_ids += src - ares_apollo_talk(announce_text) - return TRUE + return APOLLO_ACCESS_REQUEST + +/obj/item/device/working_joe_pda/proc/ares_auth_to_text(access_level) + switch(access_level) + if(APOLLO_ACCESS_LOGOUT)//0 + return "Logged Out" + if(APOLLO_ACCESS_REQUEST)//1 + return "Unauthorized Personnel" + if(APOLLO_ACCESS_REPORTER)//2 + return "Validated Incident Reporter" + if(APOLLO_ACCESS_TEMP)//3 + return "Authorized Visitor" + if(APOLLO_ACCESS_AUTHED)//4 + return "Certified Personnel" + if(APOLLO_ACCESS_JOE)//5 + return "Working Joe" + if(APOLLO_ACCESS_DEBUG)//6 + return "AI Service Technician" diff --git a/code/game/machinery/ARES/ARES_records.dm b/code/game/machinery/ARES/ARES_records.dm index 19751462bc37..f89b2c120e05 100644 --- a/code/game/machinery/ARES/ARES_records.dm +++ b/code/game/machinery/ARES/ARES_records.dm @@ -102,6 +102,7 @@ var/ref_holder = "\ref[src]" var/pos = length(ref_holder) var/new_id = "#[copytext("\ref[src]", pos - 4, pos)]" + new_id = uppertext(new_id) ticket_time = worldtime2text() ticket_submitter = user @@ -115,17 +116,18 @@ /datum/ares_ticket/access ticket_type = ARES_RECORD_ACCESS + ticket_name = ARES_RECORD_ACCESS var/user_id_num -/datum/ares_ticket/access/New(user, name, details, priority, global_id_num) +/datum/ares_ticket/access/New(user, details, priority, global_id_num) var/ref_holder = "\ref[src]" var/pos = length(ref_holder) var/new_id = "#[copytext("\ref[src]", pos - 4, pos)]" + new_id = uppertext(new_id) ticket_time = worldtime2text() ticket_submitter = user ticket_details = details - ticket_name = name ticket_priority = priority ticket_id = new_id user_id_num = global_id_num diff --git a/code/game/machinery/ARES/ARES_step_triggers.dm b/code/game/machinery/ARES/ARES_step_triggers.dm index 51480371be51..fdf7b26b2e65 100644 --- a/code/game/machinery/ARES/ARES_step_triggers.dm +++ b/code/game/machinery/ARES/ARES_step_triggers.dm @@ -3,7 +3,6 @@ layer = 5 /// Link alerts to ARES Link var/datum/ares_link/link - var/link_id = MAIN_SHIP_DEFAULT_NAME /// Alert message to report unless area based. var/alert_message = "ALERT: Unauthorized movement detected in ARES Core!" /// Connect alerts to use same cooldowns @@ -53,7 +52,7 @@ /obj/effect/step_trigger/ares_alert/proc/link_systems(datum/ares_link/new_link = GLOB.ares_link, override) if(link && !override) return FALSE - if(new_link.link_id == link_id) + if(new_link) link = new_link new_link.linked_alerts += src return TRUE @@ -70,7 +69,7 @@ broadcast_message = "ALERT: Unauthorized movement detected in [area_name]!" var/datum/ares_link/link = GLOB.ares_link - if(link.p_apollo.inoperable()) + if(link.processor_apollo.inoperable()) return FALSE to_chat(passer, SPAN_BOLDWARNING("You hear a soft beeping sound as you cross the threshold.")) @@ -113,8 +112,6 @@ /obj/effect/step_trigger/ares_alert/access_control/Crossed(atom/passer as mob|obj) if(isobserver(passer) || isxeno(passer)) return FALSE - if(!COOLDOWN_FINISHED(src, sensor_cooldown))//Don't want alerts spammed. - return FALSE if(!passer) return FALSE if(HAS_TRAIT(passer, TRAIT_CLOAKED))//Can't be seen/detected to trigger alert. @@ -157,11 +154,12 @@ var/broadcast_message = get_broadcast(passer, idcard, failure) var/datum/ares_link/link = GLOB.ares_link - if(link.p_apollo.inoperable()) + if(link.processor_apollo.inoperable()) return FALSE to_chat(passer, SPAN_BOLDWARNING("You hear a harsh buzzing sound as you cross the threshold!")) - ares_apollo_talk(broadcast_message) + if(COOLDOWN_FINISHED(src, sensor_cooldown))//Don't want alerts spammed. + ares_apollo_talk(broadcast_message) if(idcard) /// Removes the access from the ID and updates the ID's modification log. for(var/obj/item/card/id/identification in link.active_ids) diff --git a/code/game/machinery/ARES/apollo_pda.dm b/code/game/machinery/ARES/apollo_pda.dm new file mode 100644 index 000000000000..26ec9d5120bd --- /dev/null +++ b/code/game/machinery/ARES/apollo_pda.dm @@ -0,0 +1,419 @@ +/obj/item/device/working_joe_pda + icon = 'icons/obj/items/synth/wj_pda.dmi' + name = "KN5500 PDA" + desc = "A portable interface used by Working-Joes, capable of connecting to the local command AI to relay tasking information. Built to withstand a nuclear bomb." + icon_state = "karnak_off" + unacidable = TRUE + indestructible = TRUE + req_one_access = list(ACCESS_MARINE_AI_TEMP, ACCESS_MARINE_AI, ACCESS_ARES_DEBUG) + + /// The ID used to link all devices. + var/datum/ares_link/link + /// The datacore storing all the information. + var/datum/ares_datacore/datacore + + var/current_menu = "login" + var/last_menu = "off" + + var/authentication = APOLLO_ACCESS_LOGOUT + /// The last person to login. + var/last_login + + +/obj/item/device/working_joe_pda/proc/link_systems(datum/ares_link/new_link = GLOB.ares_link, override) + if(link && !override) + return FALSE + if(new_link) + new_link.ticket_computers += src + link = new_link + new_link.linked_systems += src + if(!datacore) + datacore = GLOB.ares_datacore + return TRUE + +/obj/item/device/working_joe_pda/Initialize(mapload, ...) + link_systems(override = FALSE) + . = ..() + +/obj/item/device/working_joe_pda/proc/delink() + if(link) + link.ticket_computers -= src + link.linked_systems -= src + link = null + datacore = null + +/obj/item/device/working_joe_pda/Destroy() + delink() + return ..() + +/obj/item/device/working_joe_pda/update_icon() + . = ..() + if(last_menu == "off") + icon_state = "karnak_off" + else if(current_menu == "login") + icon_state = "karnak_login_anim" + else + icon_state = "karnak_on_anim" + +// ------ Maintenance Controller UI ------ // +/obj/item/device/working_joe_pda/attack_self(mob/user) + if(..() || !allowed(usr)) + return FALSE + + if((last_menu == "off") && (current_menu == "login")) + last_menu = "main" + update_icon() + + tgui_interact(user) + return TRUE + +/obj/item/device/working_joe_pda/tgui_interact(mob/user, datum/tgui/ui, datum/ui_state/state) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "WorkingJoe", name) + ui.open() + +/obj/item/device/working_joe_pda/ui_close(mob/user) + . = ..() + + current_menu = "login" + last_menu = "off" + if(last_login) + datacore.apollo_login_list += "[last_login] logged out at [worldtime2text()]." + last_login = null + update_icon() + +/obj/item/device/working_joe_pda/ui_data(mob/user) + var/list/data = list() + + data["current_menu"] = current_menu + data["last_page"] = last_menu + + data["logged_in"] = last_login + + data["access_text"] = "access level [authentication], [ares_auth_to_text(authentication)]." + data["access_level"] = authentication + + data["alert_level"] = security_level + data["worldtime"] = world.time + + data["access_log"] = list() + data["access_log"] += datacore.apollo_login_list + + data["apollo_log"] = list() + data["apollo_log"] += datacore.apollo_log + + var/list/logged_maintenance = list() + for(var/datum/ares_ticket/maintenance/maint_ticket as anything in link.tickets_maintenance) + if(!istype(maint_ticket)) + continue + var/lock_status = TICKET_OPEN + switch(maint_ticket.ticket_status) + if(TICKET_REJECTED, TICKET_CANCELLED, TICKET_COMPLETED) + lock_status = TICKET_CLOSED + + var/list/current_maint = list() + current_maint["id"] = maint_ticket.ticket_id + current_maint["time"] = maint_ticket.ticket_time + current_maint["priority_status"] = maint_ticket.ticket_priority + current_maint["category"] = maint_ticket.ticket_name + current_maint["details"] = maint_ticket.ticket_details + current_maint["status"] = maint_ticket.ticket_status + current_maint["submitter"] = maint_ticket.ticket_submitter + current_maint["assignee"] = maint_ticket.ticket_assignee + current_maint["lock_status"] = lock_status + current_maint["ref"] = "\ref[maint_ticket]" + logged_maintenance += list(current_maint) + data["maintenance_tickets"] = logged_maintenance + + var/list/logged_access = list() + var/list/requesting_access = list() + for(var/datum/ares_ticket/access/access_ticket as anything in link.tickets_access) + var/lock_status = TICKET_OPEN + switch(access_ticket.ticket_status) + if(TICKET_REJECTED, TICKET_CANCELLED, TICKET_REVOKED) + lock_status = TICKET_CLOSED + + var/list/current_ticket = list() + current_ticket["id"] = access_ticket.ticket_id + current_ticket["time"] = access_ticket.ticket_time + current_ticket["priority_status"] = access_ticket.ticket_priority + current_ticket["title"] = access_ticket.ticket_name + current_ticket["details"] = access_ticket.ticket_details + current_ticket["status"] = access_ticket.ticket_status + current_ticket["submitter"] = access_ticket.ticket_submitter + current_ticket["assignee"] = access_ticket.ticket_assignee + current_ticket["lock_status"] = lock_status + current_ticket["ref"] = "\ref[access_ticket]" + logged_access += list(current_ticket) + + if(lock_status == TICKET_OPEN) + requesting_access += access_ticket.ticket_name + data["access_tickets"] = logged_access + + return data + +/obj/item/device/working_joe_pda/ui_status(mob/user, datum/ui_state/state) + . = ..() + if(!allowed(user)) + return UI_UPDATE + +/obj/item/device/working_joe_pda/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) + . = ..() + if(.) + return + + var/playsound = TRUE + var/mob/living/carbon/human/operator = usr + + switch (action) + if("go_back") + if(!last_menu) + return to_chat(usr, SPAN_WARNING("Error, no previous page detected.")) + var/temp_holder = current_menu + current_menu = last_menu + last_menu = temp_holder + + if("login") + + var/obj/item/card/id/idcard = operator.get_active_hand() + if(istype(idcard)) + authentication = get_ares_access(idcard) + last_login = idcard.registered_name + else if(operator.wear_id) + idcard = operator.wear_id + if(istype(idcard)) + authentication = get_ares_access(idcard) + last_login = idcard.registered_name + else + to_chat(operator, SPAN_WARNING("You require an ID card to access this terminal!")) + playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) + return FALSE + if(authentication) + datacore.apollo_login_list += "[last_login] at [worldtime2text()], Access Level [authentication] - [ares_auth_to_text(authentication)]." + current_menu = "main" + last_menu = "main" + update_icon() + + if("logout") + last_menu = current_menu + current_menu = "login" + datacore.apollo_login_list += "[last_login] logged out at [worldtime2text()]." + update_icon() + + if("home") + last_menu = current_menu + current_menu = "main" + if("page_logins") + last_menu = current_menu + current_menu = "login_records" + if("page_apollo") + last_menu = current_menu + current_menu = "apollo" + if("page_request") + last_menu = current_menu + current_menu = "access_requests" + if("page_report") + last_menu = current_menu + current_menu = "maint_reports" + if("page_tickets") + last_menu = current_menu + current_menu = "access_tickets" + if("page_maintenance") + last_menu = current_menu + current_menu = "maint_claim" + + if("new_report") + var/priority_report = FALSE + var/maint_type = tgui_input_list(operator, "What is the type of maintenance item you wish to report?", "Report Category", GLOB.maintenance_categories, 30 SECONDS) + switch(maint_type) + if("Major Structural Damage", "Fire", "Communications Failure", "Power Generation Failure") + priority_report = TRUE + + if(!maint_type) + return FALSE + var/details = tgui_input_text(operator, "What are the details for this report?", "Ticket Details", encode = FALSE) + if(!details) + return FALSE + + if((authentication >= APOLLO_ACCESS_REPORTER) && !priority_report) + var/is_priority = tgui_alert(operator, "Is this a priority report?", "Priority designation", list("Yes", "No")) + if(is_priority == "Yes") + priority_report = TRUE + + var/confirm = alert(operator, "Please confirm the submission of your maintenance report. \n\n Priority: [priority_report ? "Yes" : "No"]\n Category: '[maint_type]'\n Details: '[details]'\n\n Is this correct?", "Confirmation", "Yes", "No") + if(confirm == "Yes") + if(link) + var/datum/ares_ticket/maintenance/maint_ticket = new(last_login, maint_type, details, priority_report) + link.tickets_maintenance += maint_ticket + if(priority_report) + ares_apollo_talk("Priority Maintenance Report: [maint_type] - ID [maint_ticket.ticket_id]. Seek and resolve.") + log_game("ARES: Maintenance Ticket '\ref[maint_ticket]' created by [key_name(operator)] as [last_login] with Category '[maint_type]' and Details of '[details]'.") + return TRUE + return FALSE + + if("claim_ticket") + var/datum/ares_ticket/ticket = locate(params["ticket"]) + if(!istype(ticket)) + return FALSE + var/claim = TRUE + var/assigned = ticket.ticket_assignee + if(assigned) + if(assigned == last_login) + var/prompt = tgui_alert(usr, "You already claimed this ticket! Do you wish to drop your claim?", "Unclaim ticket", list("Yes", "No")) + if(prompt != "Yes") + return FALSE + /// set ticket back to pending + ticket.ticket_assignee = null + ticket.ticket_status = TICKET_PENDING + return claim + var/choice = tgui_alert(usr, "This ticket has already been claimed by [assigned]! Do you wish to override their claim?", "Claim Override", list("Yes", "No")) + if(choice != "Yes") + claim = FALSE + if(claim) + ticket.ticket_assignee = last_login + ticket.ticket_status = TICKET_ASSIGNED + return claim + + if("cancel_ticket") + var/datum/ares_ticket/ticket = locate(params["ticket"]) + if(!istype(ticket)) + return FALSE + if(ticket.ticket_submitter != last_login) + to_chat(usr, SPAN_WARNING("You cannot cancel a ticket that does not belong to you!")) + return FALSE + to_chat(usr, SPAN_WARNING("[ticket.ticket_type] [ticket.ticket_id] has been cancelled.")) + ticket.ticket_status = TICKET_CANCELLED + if(ticket.ticket_priority) + ares_apollo_talk("Priority [ticket.ticket_type] [ticket.ticket_id] has been cancelled.") + return TRUE + + if("mark_ticket") + var/datum/ares_ticket/ticket = locate(params["ticket"]) + if(!istype(ticket)) + return FALSE + if(ticket.ticket_assignee != last_login && ticket.ticket_assignee) //must be claimed by you or unclaimed.) + to_chat(usr, SPAN_WARNING("You cannot update a ticket that is not assigned to you!")) + return FALSE + var/choice = tgui_alert(usr, "What do you wish to mark the ticket as?", "Mark", list(TICKET_COMPLETED, TICKET_REJECTED), 20 SECONDS) + switch(choice) + if(TICKET_COMPLETED) + ticket.ticket_status = TICKET_COMPLETED + if(TICKET_REJECTED) + ticket.ticket_status = TICKET_REJECTED + else + return FALSE + if(ticket.ticket_priority) + ares_apollo_talk("Priority [ticket.ticket_type] [ticket.ticket_id] has been [choice] by [last_login].") + to_chat(usr, SPAN_NOTICE("[ticket.ticket_type] [ticket.ticket_id] marked as [choice].")) + return TRUE + + if("new_access") + var/obj/item/card/id/idcard = operator.get_active_hand() + var/has_id = FALSE + if(istype(idcard)) + has_id = TRUE + else if(operator.wear_id) + idcard = operator.wear_id + if(istype(idcard)) + has_id = TRUE + if(!has_id) + to_chat(operator, SPAN_WARNING("You require an ID card to request an access ticket!")) + playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) + return FALSE + if(idcard.registered_name != last_login) + to_chat(operator, SPAN_WARNING("This ID card does not match the active login!")) + playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) + return FALSE + + var/details = tgui_input_text(operator, "What is the purpose of this access ticket?", "Ticket Details", encode = FALSE) + if(!details) + return FALSE + + var/confirm = alert(operator, "Please confirm the submission of your access ticket request.\n\nHolder: '[last_login]'\nDetails: '[details]'\n\nIs this correct?", "Confirmation", "Yes", "No") + if(confirm != "Yes" || !link) + return FALSE + var/datum/ares_ticket/access/access_ticket = new(last_login, details, FALSE, idcard.registered_gid) + link.waiting_ids += idcard + link.tickets_access += access_ticket + log_game("ARES: Access Ticket '\ref[access_ticket]' created by [key_name(operator)] as [last_login] with Details of '[details]'.") + message_admins(SPAN_STAFF_IC("[key_name_admin(operator)] created a new ARES Access Ticket."), 1) + ares_apollo_talk("Access Ticket [access_ticket.ticket_id]: [access_ticket.ticket_submitter] requesting access for '[details].") + return TRUE + + if("return_access") + playsound = FALSE + var/datum/ares_ticket/access/access_ticket + for(var/datum/ares_ticket/access/possible_ticket in link.tickets_access) + if(possible_ticket.ticket_status != TICKET_GRANTED) + continue + if(possible_ticket.ticket_name != last_login) + continue + access_ticket = possible_ticket + break + + for(var/obj/item/card/id/identification in link.active_ids) + if(!istype(identification)) + continue + if(identification.registered_gid != access_ticket.user_id_num) + continue + + access_ticket.ticket_status = TICKET_RETURNED + identification.access -= ACCESS_MARINE_AI_TEMP + identification.modification_log += "Temporary AI Access self-returned by [key_name(operator)]." + + to_chat(operator, SPAN_NOTICE("Temporary Access Ticket surrendered.")) + playsound(src, 'sound/machines/chime.ogg', 15, 1) + ares_apollo_talk("Access Ticket [access_ticket.ticket_id]: [access_ticket.ticket_submitter] surrendered their access.") + + authentication = get_ares_access(identification) + if(authentication) + datacore.apollo_login_list += "[last_login] at [worldtime2text()], Surrendered Temporary Access Ticket." + return TRUE + + to_chat(operator, SPAN_WARNING("This ID card does not have an access ticket!")) + playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) + return FALSE + + if("auth_access") + playsound = FALSE + var/datum/ares_ticket/access/access_ticket = locate(params["ticket"]) + if(!access_ticket) + return FALSE + for(var/obj/item/card/id/identification in link.waiting_ids) + if(!istype(identification)) + continue + if(identification.registered_gid != access_ticket.user_id_num) + continue + identification.handle_ares_access(last_login, operator) + access_ticket.ticket_status = TICKET_GRANTED + playsound(src, 'sound/machines/chime.ogg', 15, 1) + ares_apollo_talk("Access Ticket [access_ticket.ticket_id]: [access_ticket.ticket_submitter] was granted access by [last_login].") + return TRUE + for(var/obj/item/card/id/identification in link.active_ids) + if(!istype(identification)) + continue + if(identification.registered_gid != access_ticket.user_id_num) + continue + identification.handle_ares_access(last_login, operator) + access_ticket.ticket_status = TICKET_REVOKED + playsound(src, 'sound/machines/chime.ogg', 15, 1) + ares_apollo_talk("Access Ticket [access_ticket.ticket_id]: [access_ticket.ticket_submitter] had access revoked by [last_login].") + return TRUE + return FALSE + + if("reject_access") + var/datum/ares_ticket/access/access_ticket = locate(params["ticket"]) + if(!istype(access_ticket)) + return FALSE + if(access_ticket.ticket_assignee != last_login && access_ticket.ticket_assignee) //must be claimed by you or unclaimed.) + to_chat(usr, SPAN_WARNING("You cannot update a ticket that is not assigned to you!")) + return FALSE + access_ticket.ticket_status = TICKET_REJECTED + to_chat(usr, SPAN_NOTICE("[access_ticket.ticket_type] [access_ticket.ticket_id] marked as rejected.")) + ares_apollo_talk("Access Ticket [access_ticket.ticket_id]: [access_ticket.ticket_submitter] was rejected access by [last_login].") + return TRUE + + if(playsound) + var/sound = pick('sound/machines/pda_button1.ogg', 'sound/machines/pda_button2.ogg') + playsound(src, sound, 15, TRUE) diff --git a/code/game/machinery/OpTable.dm b/code/game/machinery/OpTable.dm index 3c4104b6c283..c9092a750f73 100644 --- a/code/game/machinery/OpTable.dm +++ b/code/game/machinery/OpTable.dm @@ -59,8 +59,6 @@ if(EXPLOSION_THRESHOLD_MEDIUM to INFINITY) deconstruct(FALSE) return - else - return /obj/structure/machinery/optable/get_examine_text(mob/user) . = ..() diff --git a/code/game/machinery/air_alarm.dm b/code/game/machinery/air_alarm.dm index 16512a944be1..e6fc0c8de76e 100644 --- a/code/game/machinery/air_alarm.dm +++ b/code/game/machinery/air_alarm.dm @@ -431,8 +431,6 @@ var/wireIndex = AAlarmWireColorToIndex[wireColor] //not used in this function AAlarmwires |= wireFlag switch(wireIndex) - if(AALARM_WIRE_IDSCAN) - if(AALARM_WIRE_POWER) shorted = 0 shock(usr, 50) diff --git a/code/game/machinery/atmoalter/scrubber.dm b/code/game/machinery/atmoalter/scrubber.dm index 0af38cacd75e..1c240fb05dfb 100644 --- a/code/game/machinery/atmoalter/scrubber.dm +++ b/code/game/machinery/atmoalter/scrubber.dm @@ -18,16 +18,14 @@ PF.flags_can_pass_all = PASS_OVER|PASS_AROUND|PASS_UNDER /obj/structure/machinery/portable_atmospherics/powered/scrubber/emp_act(severity) + . = ..() if(inoperable()) - ..(severity) return if(prob(50/severity)) on = !on update_icon() - ..(severity) - /obj/structure/machinery/portable_atmospherics/powered/scrubber/update_icon() src.overlays = 0 diff --git a/code/game/machinery/biohazard_lockdown.dm b/code/game/machinery/biohazard_lockdown.dm index fd6205baa1d9..2e3cbf6de234 100644 --- a/code/game/machinery/biohazard_lockdown.dm +++ b/code/game/machinery/biohazard_lockdown.dm @@ -102,8 +102,7 @@ GLOBAL_VAR_INIT(lockdown_state, LOCKDOWN_READY) shipwide_ai_announcement(message, MAIN_AI_SYSTEM, 'sound/effects/biohazard.ogg') message_admins(log) - var/datum/ares_link/link = GLOB.ares_link - link.log_ares_security("Containment Lockdown", ares_log) + log_ares_security("Containment Lockdown", ares_log) #undef LOCKDOWN_READY #undef LOCKDOWN_ACTIVE diff --git a/code/game/machinery/bioprinter.dm b/code/game/machinery/bioprinter.dm index 81d498ba02e2..65f6fe1842f4 100644 --- a/code/game/machinery/bioprinter.dm +++ b/code/game/machinery/bioprinter.dm @@ -113,6 +113,10 @@ switch(action) if("print") + if(working) + //If we're already printing something then we're too busy to multi task. + to_chat(usr, SPAN_NOTICE("[src] is busy at the moment.")) + return FALSE var/recipe = params["recipe_id"] var/valid_recipe = FALSE for(var/datum/bioprinter_recipe/product_recipes in products) @@ -124,6 +128,10 @@ message_admins("[key_name(usr)] attempted to print an invalid recipe on \the [src].") return FALSE var/datum/bioprinter_recipe/recipe_datum = new recipe + if(stored_metal < recipe_datum.metal) + to_chat(usr, SPAN_NOTICE("[src] does not have enough stored metal.")) + QDEL_NULL(recipe_datum) + return FALSE stored_metal -= recipe_datum.metal to_chat(usr, SPAN_NOTICE("\The [src] is now printing the selected organ. Please hold.")) working = TRUE @@ -146,6 +154,8 @@ /obj/structure/machinery/bioprinter/proc/print_limb(limb_path) if(inoperable()) + //In case we lose power or anything between the print and the callback we don't want to permenantly break the printer + working = FALSE return new limb_path(get_turf(src)) working = FALSE diff --git a/code/game/machinery/bots/bots.dm b/code/game/machinery/bots/bots.dm index 116753093fe5..912a6070328a 100644 --- a/code/game/machinery/bots/bots.dm +++ b/code/game/machinery/bots/bots.dm @@ -114,6 +114,7 @@ /obj/structure/machinery/bot/emp_act(severity) + . = ..() var/was_on = on stat |= EMPED new /obj/effect/overlay/temp/emp_sparks (loc) diff --git a/code/game/machinery/bots/mulebot.dm b/code/game/machinery/bots/mulebot.dm index b70829c708ed..b88f8249566b 100644 --- a/code/game/machinery/bots/mulebot.dm +++ b/code/game/machinery/bots/mulebot.dm @@ -551,7 +551,7 @@ var/speed = ((wires & WIRE_MOTOR1) ? 1:0) + ((wires & WIRE_MOTOR2) ? 2:0) switch(speed) if(0) - // do nothing + pass() if(1) process_bot() spawn(2) @@ -916,11 +916,11 @@ post_signal_multiple(control_freq, kv) /obj/structure/machinery/bot/mulebot/emp_act(severity) + . = ..() if (cell) cell.emp_act(severity) if(load) load.emp_act(severity) - ..() /obj/structure/machinery/bot/mulebot/explode() diff --git a/code/game/machinery/buttons.dm b/code/game/machinery/buttons.dm index ee83c430c2db..8d4b27778c69 100644 --- a/code/game/machinery/buttons.dm +++ b/code/game/machinery/buttons.dm @@ -1,15 +1,3 @@ -/obj/structure/machinery/driver_button - name = "mass driver button" - icon = 'icons/obj/objects.dmi' - icon_state = "launcherbtt" - desc = "A remote control switch for a mass driver." - var/id = null - var/active = 0 - anchored = TRUE - use_power = USE_POWER_IDLE - idle_power_usage = 2 - active_power_usage = 4 - /obj/structure/machinery/ignition_switch name = "ignition switch" icon = 'icons/obj/objects.dmi' diff --git a/code/game/machinery/camera/camera.dm b/code/game/machinery/camera/camera.dm index 4d17e4a08803..3b2a91eea314 100644 --- a/code/game/machinery/camera/camera.dm +++ b/code/game/machinery/camera/camera.dm @@ -35,6 +35,9 @@ var/colony_camera_mapload = TRUE + /// If this camera should have innate EMP-proofing + var/emp_proof = FALSE + /obj/structure/machinery/camera/Initialize(mapload, ...) . = ..() WireColorToFlag = randomCameraWires() @@ -72,6 +75,7 @@ if(WEST) pixel_x = 27 /obj/structure/machinery/camera/emp_act(severity) + . = ..() if(!isEmpProof()) if(prob(100/severity)) icon_state = "[initial(icon_state)]emp" @@ -89,7 +93,6 @@ if(can_use()) cameranet.addCamera(src) kick_viewers() - ..() /obj/structure/machinery/camera/ex_act(severity) @@ -187,9 +190,9 @@ else visible_message(SPAN_WARNING("[user] has deactivated [src]!")) if(status) - icon_state = initial(icon_state) + icon_state = "camera" else - icon_state = "[initial(icon_state)]1" + icon_state = "camera1" // now disconnect anyone using the camera //Apparently, this will disconnect anyone even if the camera was re-activated. //I guess that doesn't matter since they can't use it anyway? diff --git a/code/game/machinery/camera/presets.dm b/code/game/machinery/camera/presets.dm index a8735cbc06a8..e5ab520cbee8 100644 --- a/code/game/machinery/camera/presets.dm +++ b/code/game/machinery/camera/presets.dm @@ -30,6 +30,7 @@ network = list(CAMERA_NET_LASER_TARGETS) unslashable = TRUE unacidable = TRUE + emp_proof = TRUE /obj/structure/machinery/camera/laser_cam/Initialize(mapload, laser_name) . = ..() @@ -37,8 +38,6 @@ var/area/A = get_area(src) c_tag = "[laser_name] ([A.name])" -/obj/structure/machinery/camera/laser_cam/emp_act(severity) - return //immune to EMPs, just in case /obj/structure/machinery/camera/laser_cam/ex_act() return @@ -125,9 +124,7 @@ invisibility = 101 //fuck you init() colony_camera_mapload = FALSE - -/obj/structure/machinery/camera/autoname/lz_camera/emp_act(severity) - return //immune to EMPs, just in case + emp_proof = TRUE /obj/structure/machinery/camera/autoname/lz_camera/ex_act() return @@ -137,7 +134,7 @@ /obj/structure/machinery/camera/proc/isEmpProof() var/O = locate(/obj/item/stack/sheet/mineral/osmium) in assembly.upgrades - return O + return O || emp_proof /obj/structure/machinery/camera/proc/isXRay() var/obj/item/stock_parts/scanning_module/O = locate(/obj/item/stock_parts/scanning_module) in assembly.upgrades diff --git a/code/game/machinery/cell_charger.dm b/code/game/machinery/cell_charger.dm index fcd8c65e93ca..eb7a501fa078 100644 --- a/code/game/machinery/cell_charger.dm +++ b/code/game/machinery/cell_charger.dm @@ -80,11 +80,11 @@ return /obj/structure/machinery/cell_charger/emp_act(severity) + . = ..() if(inoperable()) return if(charging) charging.emp_act(severity) - ..(severity) /obj/structure/machinery/cell_charger/process() diff --git a/code/game/machinery/computer/almayer_control.dm b/code/game/machinery/computer/almayer_control.dm index c3b17dbf8090..fb9f7a0375d9 100644 --- a/code/game/machinery/computer/almayer_control.dm +++ b/code/game/machinery/computer/almayer_control.dm @@ -81,9 +81,9 @@ data["worldtime"] = world.time - data["evac_status"] = EvacuationAuthority.evac_status - if(EvacuationAuthority.evac_status == EVACUATION_STATUS_INITIATING) - data["evac_eta"] = EvacuationAuthority.get_status_panel_eta() + data["evac_status"] = SShijack.evac_status + if(SShijack.evac_status == EVACUATION_STATUS_INITIATED) + data["evac_eta"] = SShijack.get_evac_eta() if(!messagetitle.len) data["messages"] = null @@ -108,7 +108,6 @@ . = ..() if(.) return - switch(action) if("award") print_medal(usr, src) @@ -121,31 +120,27 @@ to_chat(usr, SPAN_WARNING("The ship must be under red alert in order to enact evacuation procedures.")) return FALSE - if(EvacuationAuthority.flags_scuttle & FLAGS_EVACUATION_DENY) + if(SShijack.evac_admin_denied) to_chat(usr, SPAN_WARNING("The USCM has placed a lock on deploying the evacuation pods.")) return FALSE - if(!EvacuationAuthority.initiate_evacuation()) + if(!SShijack.initiate_evacuation()) to_chat(usr, SPAN_WARNING("You are unable to initiate an evacuation procedure right now!")) return FALSE log_game("[key_name(usr)] has called for an emergency evacuation.") message_admins("[key_name_admin(usr)] has called for an emergency evacuation.") - var/datum/ares_link/link = GLOB.ares_link - link.log_ares_security("Initiate Evacuation", "[usr] has called for an emergency evacuation.") + log_ares_security("Initiate Evacuation", "[usr] has called for an emergency evacuation.") . = TRUE if("evacuation_cancel") - if(!EvacuationAuthority.cancel_evacuation()) + if(!SShijack.cancel_evacuation()) to_chat(usr, SPAN_WARNING("You are unable to cancel the evacuation right now!")) return FALSE - addtimer(CALLBACK(src, TYPE_PROC_REF(/obj/structure/machinery/computer/almayer_control, cancel_evac)), 4 SECONDS) - log_game("[key_name(usr)] has canceled the emergency evacuation.") message_admins("[key_name_admin(usr)] has canceled the emergency evacuation.") - var/datum/ares_link/link = GLOB.ares_link - link.log_ares_security("Cancel Evacuation", "[usr] has cancelled the emergency evacuation.") + log_ares_security("Cancel Evacuation", "[usr] has cancelled the emergency evacuation.") . = TRUE // evac stuff end \\ @@ -167,8 +162,7 @@ set_security_level(seclevel2num(level_selected), log = ARES_LOG_NONE) log_game("[key_name(usr)] has changed the security level to [get_security_level()].") message_admins("[key_name_admin(usr)] has changed the security level to [get_security_level()].") - var/datum/ares_link/link = GLOB.ares_link - link.log_ares_security("Manual Security Update", "[usr] has changed the security level to [get_security_level()].") + log_ares_security("Manual Security Update", "[usr] has changed the security level to [get_security_level()].") . = TRUE if("messageUSCM") @@ -280,10 +274,3 @@ // end tgui interact \\ // end tgui \\ - -/obj/structure/machinery/computer/almayer_control/proc/cancel_evac() - if(EvacuationAuthority.evac_status == EVACUATION_STATUS_STANDING_BY)//nothing changed during the wait - //if the self_destruct is active we try to cancel it (which includes lowering alert level to red) - if(!EvacuationAuthority.cancel_self_destruct(1)) - //if SD wasn't active (likely canceled manually in the SD room), then we lower the alert level manually. - set_security_level(SEC_LEVEL_RED, TRUE) //both SD and evac are inactive, lowering the security level. diff --git a/code/game/machinery/computer/arcade.dm b/code/game/machinery/computer/arcade.dm index 8d35dd1b6aff..1ac5a06738d5 100644 --- a/code/game/machinery/computer/arcade.dm +++ b/code/game/machinery/computer/arcade.dm @@ -165,8 +165,8 @@ return /obj/structure/machinery/computer/arcade/emp_act(severity) + . = ..() if(inoperable()) - ..(severity) return var/empprize = null var/num_of_prizes = 0 @@ -178,5 +178,3 @@ for(num_of_prizes; num_of_prizes > 0; num_of_prizes--) empprize = pickweight(prizes) new empprize(src.loc) - - ..(severity) diff --git a/code/game/machinery/computer/camera_console.dm b/code/game/machinery/computer/camera_console.dm index 3beb773ebc1e..fd14ef40aff1 100644 --- a/code/game/machinery/computer/camera_console.dm +++ b/code/game/machinery/computer/camera_console.dm @@ -354,8 +354,8 @@ exproof = TRUE colony_camera_mapload = FALSE -/obj/structure/machinery/computer/cameras/mortar/emp_act(severity) - return FALSE +/obj/structure/machinery/computer/cameras/mortar/set_broken() + return /obj/structure/machinery/computer/cameras/dropship name = "abstract dropship camera computer" diff --git a/code/game/machinery/computer/communications.dm b/code/game/machinery/computer/communications.dm index f7ea31fba36a..3332577683fe 100644 --- a/code/game/machinery/computer/communications.dm +++ b/code/game/machinery/computer/communications.dm @@ -65,7 +65,6 @@ if(..()) return FALSE usr.set_interaction(src) - var/datum/ares_link/link = GLOB.ares_link switch(href_list["operation"]) if("mapview") tacmap.tgui_interact(usr) @@ -139,37 +138,30 @@ to_chat(usr, SPAN_WARNING("The ship must be under delta alert in order to enact evacuation procedures.")) return FALSE - if(EvacuationAuthority.flags_scuttle & FLAGS_EVACUATION_DENY) + if(SShijack.evac_admin_denied) to_chat(usr, SPAN_WARNING("The USCM has placed a lock on deploying the evacuation pods.")) return FALSE - if(!EvacuationAuthority.initiate_evacuation()) + if(!SShijack.initiate_evacuation()) to_chat(usr, SPAN_WARNING("You are unable to initiate an evacuation procedure right now!")) return FALSE log_game("[key_name(usr)] has called for an emergency evacuation.") message_admins("[key_name_admin(usr)] has called for an emergency evacuation.") - link.log_ares_security("Initiate Evacuation", "[usr] has called for an emergency evacuation.") + log_ares_security("Initiate Evacuation", "[usr] has called for an emergency evacuation.") return TRUE state = STATE_EVACUATION if("evacuation_cancel") if(state == STATE_EVACUATION_CANCEL) - if(!EvacuationAuthority.cancel_evacuation()) + if(!SShijack.cancel_evacuation()) to_chat(usr, SPAN_WARNING("You are unable to cancel the evacuation right now!")) return FALSE - spawn(35)//some time between AI announcements for evac cancel and SD cancel. - if(EvacuationAuthority.evac_status == EVACUATION_STATUS_STANDING_BY)//nothing changed during the wait - //if the self_destruct is active we try to cancel it (which includes lowering alert level to red) - if(!EvacuationAuthority.cancel_self_destruct(1)) - //if SD wasn't active (likely canceled manually in the SD room), then we lower the alert level manually. - set_security_level(SEC_LEVEL_RED, TRUE) //both SD and evac are inactive, lowering the security level. - log_game("[key_name(usr)] has canceled the emergency evacuation.") message_admins("[key_name_admin(usr)] has canceled the emergency evacuation.") - link.log_ares_security("Cancel Evacuation", "[usr] has cancelled the emergency evacuation.") + log_ares_security("Cancel Evacuation", "[usr] has cancelled the emergency evacuation.") return TRUE state = STATE_EVACUATION_CANCEL @@ -328,8 +320,8 @@ user.set_interaction(src) var/dat = "Communications Console" - if(EvacuationAuthority.evac_status == EVACUATION_STATUS_INITIATING) - dat += "Evacuation in Progress\n
\nETA: [EvacuationAuthority.get_status_panel_eta()]
" + if(SShijack.evac_status == EVACUATION_STATUS_INITIATED) + dat += "Evacuation in Progress\n
\nETA: [SShijack.get_evac_eta()]
" switch(state) if(STATE_DEFAULT) if(authenticated) @@ -352,9 +344,11 @@ dat += "
Award a medal" dat += "
Send Distress Beacon" dat += "
Activate Self-Destruct" - switch(EvacuationAuthority.evac_status) - if(EVACUATION_STATUS_STANDING_BY) dat += "
Initiate emergency evacuation" - if(EVACUATION_STATUS_INITIATING) dat += "
Cancel emergency evacuation" + switch(SShijack.evac_status) + if(EVACUATION_STATUS_NOT_INITIATED) + dat += "
Initiate emergency evacuation" + if(EVACUATION_STATUS_INITIATED) + dat += "
Cancel emergency evacuation" else dat += "
LOG IN" @@ -409,20 +403,8 @@ if(STATE_ALERT_LEVEL) dat += "Current alert level: [get_security_level()]
" - if(security_level == SEC_LEVEL_DELTA) - if(EvacuationAuthority.dest_status >= NUKE_EXPLOSION_ACTIVE) - dat += SET_CLASS("The self-destruct mechanism is active. [EvacuationAuthority.evac_status != EVACUATION_STATUS_INITIATING ? "You have to manually deactivate the self-destruct mechanism." : ""]", INTERFACE_RED) - dat += "
" - switch(EvacuationAuthority.evac_status) - if(EVACUATION_STATUS_INITIATING) - dat += SET_CLASS("Evacuation initiated. Evacuate or rescind evacuation orders.", INTERFACE_RED) - if(EVACUATION_STATUS_IN_PROGRESS) - dat += SET_CLASS("Evacuation in progress.", INTERFACE_RED) - if(EVACUATION_STATUS_COMPLETE) - dat += SET_CLASS("Evacuation complete.", INTERFACE_RED) - else - dat += "Blue
" - dat += "Green" + dat += "Blue
" + dat += "Green" if(STATE_CONFIRM_LEVEL) dat += "Current alert level: [get_security_level()]
" diff --git a/code/game/machinery/computer/computer.dm b/code/game/machinery/computer/computer.dm index adce72f7d8b6..c33517796271 100644 --- a/code/game/machinery/computer/computer.dm +++ b/code/game/machinery/computer/computer.dm @@ -31,8 +31,9 @@ return 1 /obj/structure/machinery/computer/emp_act(severity) - if(prob(20/severity)) set_broken() - ..() + . = ..() + if(prob(20/severity)) + set_broken() /obj/structure/machinery/computer/ex_act(severity) @@ -53,8 +54,6 @@ if(EXPLOSION_THRESHOLD_MEDIUM to INFINITY) deconstruct(FALSE) return - else - return /obj/structure/machinery/computer/bullet_act(obj/projectile/Proj) if(exproof) diff --git a/code/game/machinery/computer/dropship_weapons.dm b/code/game/machinery/computer/dropship_weapons.dm index 60bf17388db8..6218bf0cdedb 100644 --- a/code/game/machinery/computer/dropship_weapons.dm +++ b/code/game/machinery/computer/dropship_weapons.dm @@ -594,14 +594,21 @@ return var/targ_id = text2num(href_list["cas_camera"]) + + var/datum/cas_signal/new_signal for(var/datum/cas_signal/LT as anything in cas_group.cas_signals) if(LT.target_id == targ_id && LT.valid_signal()) - selected_cas_signal = LT + new_signal = LT break - if(!selected_cas_signal) + if(!new_signal) to_chat(usr, SPAN_WARNING("Target lost or obstructed.")) return + + if(usr in selected_cas_signal?.linked_cam?.viewing_users) // Reset previous cam + remove_from_view(usr) + + selected_cas_signal = new_signal if(selected_cas_signal && selected_cas_signal.linked_cam) selected_cas_signal.linked_cam.view_directly(usr) else diff --git a/code/game/machinery/computer/medical.dm b/code/game/machinery/computer/medical.dm index b68ca41d6f09..53efad3da877 100644 --- a/code/game/machinery/computer/medical.dm +++ b/code/game/machinery/computer/medical.dm @@ -123,7 +123,6 @@ else dat += "
[bdat]" - else else dat += text("{Log In}", src) show_browser(user, dat, "Medical Records", "med_rec") @@ -365,8 +364,6 @@ for(var/datum/data/record/E in GLOB.data_core.medical) if ((E.fields["ref"] == R.fields["ref"] || E.fields["id"] == R.fields["id"])) M = E - else - //Foreach continue //goto(2540) src.active1 = R src.active2 = M src.screen = 4 @@ -417,16 +414,12 @@ for(var/datum/data/record/R as anything in GLOB.data_core.medical) if ((lowertext(R.fields["name"]) == t1 || t1 == lowertext(R.fields["id"]))) src.active2 = R - else - //Foreach continue //goto(3229) if (!active2) temp = "Could not locate record [t1]." else for(var/datum/data/record/E in GLOB.data_core.general) if ((E.fields["name"] == src.active2.fields["name"] || E.fields["id"] == src.active2.fields["id"])) src.active1 = E - else - //Foreach continue //goto(3334) src.screen = 4 if (href_list["print_p"]) @@ -490,8 +483,8 @@ return /obj/structure/machinery/computer/med_data/emp_act(severity) + . = ..() if(inoperable()) - ..(severity) return for(var/datum/data/record/R as anything in GLOB.data_core.medical) @@ -516,8 +509,6 @@ qdel(R) continue - ..(severity) - /obj/structure/machinery/computer/med_data/laptop name = "Medical Laptop" diff --git a/code/game/machinery/computer/pod.dm b/code/game/machinery/computer/pod.dm index 3858230a089c..7ec97874bb7f 100644 --- a/code/game/machinery/computer/pod.dm +++ b/code/game/machinery/computer/pod.dm @@ -1,159 +1,8 @@ -//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:31 - -/obj/structure/machinery/computer/pod - name = "Pod Launch Control" - desc = "A control for launching pods. Some people prefer firing Mechas." +// Legacy SS13 machinery turned into props +/obj/structure/machinery/computer/pod/old + name = "DoorMex Control Computer" + desc = "A control for launching pods." icon_state = "computer_generic" density = TRUE - circuit = /obj/item/circuitboard/computer/pod - var/id = 1 - var/obj/structure/machinery/mass_driver/connected = null - var/timing = 0 - var/time = 30 - var/title = "Mass Driver Controls" + circuit = /obj/item/circuitboard/computer/pod/old processing = TRUE - - -/obj/structure/machinery/computer/pod/New() - ..() - spawn( 5 ) - for(var/obj/structure/machinery/mass_driver/M in machines) - if(M.id == id) - connected = M - else - return - return - - -/obj/structure/machinery/computer/pod/proc/alarm() - if(inoperable()) - return - - if(!( connected )) - to_chat(viewers(null, null), "Cannot locate mass driver connector. Cancelling firing sequence!") - return - - for(var/obj/structure/machinery/door/poddoor/M in machines) - if(M.id == id) - M.open() - - sleep(20) - - for(var/obj/structure/machinery/mass_driver/M in machines) - if(M.id == id) - M.power = connected.power - M.drive() - - sleep(50) - for(var/obj/structure/machinery/door/poddoor/M in machines) - if(M.id == id) - M.close() - return - return - -/obj/structure/machinery/computer/pod/attack_remote(mob/user as mob) - return attack_hand(user) - -/obj/structure/machinery/computer/pod/attack_hand(mob/user as mob) - if(..()) - return - - var/dat = "[title]" - user.set_interaction(src) - if(connected) - var/d2 - if(timing) //door controls do not need timers. - d2 = "Stop Time Launch" - else - d2 = "Initiate Time Launch" - var/second = time % 60 - var/minute = (time - second) / 60 - dat += "
\nTimer System: [d2]\nTime Left: [minute ? "[minute]:" : null][second] - - + +" - var/temp = "" - var/list/L = list( 0.25, 0.5, 1, 2, 4, 8, 16 ) - for(var/t in L) - if(t == connected.power) - temp += "[t] " - else - temp += "[t] " - dat += "
\nPower Level: [temp]
\nFiring Sequence
\nTest Fire Driver
\nToggle Outer Door
" - else - dat += "
\nToggle Outer Door
" - dat += "

Close
" - show_browser(user, dat, "computer", "size=400x500") - add_fingerprint(usr) - return - - -/obj/structure/machinery/computer/pod/process() - if(!..()) - return - if(timing) - if(time > 0) - time = round(time) - 1 - else - alarm() - time = 0 - timing = 0 - updateDialog() - return - - -/obj/structure/machinery/computer/pod/Topic(href, href_list) - if(..()) - return - if((usr.contents.Find(src) || (in_range(src, usr) && istype(loc, /turf))) || (isRemoteControlling(usr))) - usr.set_interaction(src) - if(href_list["power"]) - var/t = text2num(href_list["power"]) - t = min(max(0.25, t), 16) - if(connected) - connected.power = t - if(href_list["alarm"]) - alarm() - if(href_list["drive"]) - for(var/obj/structure/machinery/mass_driver/M in machines) - if(M.id == id) - M.power = connected.power - M.drive() - - if(href_list["time"]) - timing = text2num(href_list["time"]) - if(href_list["tp"]) - var/tp = text2num(href_list["tp"]) - time += tp - time = min(max(round(time), 0), 120) - if(href_list["door"]) - for(var/obj/structure/machinery/door/poddoor/M in machines) - if(M.id == id) - if(M.density) - M.open() - else - M.close() - updateUsrDialog() - return - - - -/obj/structure/machinery/computer/pod/old - name = "DoorMex Control Computer" - title = "Door Controls" - -/obj/structure/machinery/computer/pod/old/syndicate - name = "ProComp Executive IIc" - desc = "The Syndicate operate on a tight budget. Operates external airlocks." - icon_state = "syndicomp" - title = "External Airlock Controls" - req_access = list(ACCESS_ILLEGAL_PIRATE) - -/obj/structure/machinery/computer/pod/old/syndicate/attack_hand(mob/user as mob) - if(!allowed(user)) - to_chat(user, SPAN_DANGER("Access Denied")) - return - else - ..() - -/obj/structure/machinery/computer/pod/old/swf - name = "Magix System IV" - icon_state = "wizard" - desc = "An arcane artifact that holds much magic. Running E-Knock 2.2: Sorceror's Edition" diff --git a/code/game/machinery/computer/robot.dm b/code/game/machinery/computer/robot.dm index 12f4faedc979..c5a13e2c3e74 100644 --- a/code/game/machinery/computer/robot.dm +++ b/code/game/machinery/computer/robot.dm @@ -55,8 +55,7 @@ dat += " Locked Down |" else dat += " Operating Normally |" - if (!R.canmove) - else if(R.cell) + if(R.canmove && R.cell) dat += " Battery Installed ([R.cell.charge]/[R.cell.maxcharge]) |" else dat += " No Cell Installed |" diff --git a/code/game/machinery/computer/security.dm b/code/game/machinery/computer/security.dm index 857118937910..2d9a4a1dbea4 100644 --- a/code/game/machinery/computer/security.dm +++ b/code/game/machinery/computer/security.dm @@ -524,8 +524,8 @@ What a mess.*/ return selection.fields["img"] /obj/structure/machinery/computer/secure_data/emp_act(severity) + . = ..() if(inoperable()) - ..(severity) return for(var/datum/data/record/R in GLOB.data_core.security) @@ -550,8 +550,6 @@ What a mess.*/ qdel(R) continue - ..(severity) - /obj/structure/machinery/computer/secure_data/detective_computer icon = 'icons/obj/structures/machinery/computer.dmi' icon_state = "messyfiles" diff --git a/code/game/machinery/computer/sentencing.dm b/code/game/machinery/computer/sentencing.dm index 52a4159a2a90..3aa9b5a032a8 100644 --- a/code/game/machinery/computer/sentencing.dm +++ b/code/game/machinery/computer/sentencing.dm @@ -78,6 +78,7 @@ data["laws"] += list(create_law_data("Major Laws", SSlaw_init.major_law)) data["laws"] += list(create_law_data("Capital Laws", SSlaw_init.capital_law)) data["laws"] += list(create_law_data("Optional Laws", SSlaw_init.optional_law)) + data["laws"] += list(create_law_data("Precautionary Laws", SSlaw_init.precautionary_law)) return data diff --git a/code/game/machinery/computer/skills.dm b/code/game/machinery/computer/skills.dm index f891d46bc36b..60b5aa232940 100644 --- a/code/game/machinery/computer/skills.dm +++ b/code/game/machinery/computer/skills.dm @@ -43,16 +43,16 @@ var/dat if (temp) - dat = text("[]

Clear Screen", temp, src) + dat = "[temp]

Clear Screen" else - dat = text("Confirm Identity: []
", src, (scan ? text("[]", scan.name) : "----------")) + dat = "Confirm Identity: [scan ? scan.name : "----------"]
" if (authenticated) switch(screen) if(1.0) dat += {"

"} - dat += text("Search Records
", src) - dat += text("New Record
", src) + dat += "Search Records
" + dat += "New Record
" dat += {"

@@ -70,20 +70,19 @@ if(!isnull(GLOB.data_core.general)) for(var/datum/data/record/R in sortRecord(GLOB.data_core.general, sortBy, order)) for(var/datum/data/record/E in GLOB.data_core.security) - var/background - dat += text("", background, src, R, R.fields["name"]) - dat += text("", R.fields["id"]) - dat += text("", R.fields["rank"]) + dat += "" + dat += "" + dat += "" dat += "
[][][]
[R.fields["name"]][R.fields["id"]][R.fields["rank"]]

" - dat += text("Record Maintenance

", src) - dat += text("{Log Out}",src) + dat += "Record Maintenance

" + dat += "{Log Out}" if(2.0) dat += "Records Maintenance
" dat += "
Delete All Records

Back" if(3.0) dat += "
Employment Record

" if ((istype(active1, /datum/data/record) && GLOB.data_core.general.Find(active1))) - dat += text("
\ + dat += " \
\ Name: [active1.fields["name"]]
\ ID: [active1.fields["id"]]
\n \ Sex: [active1.fields["sex"]]
\n \ @@ -93,18 +92,18 @@ Mental Status: [active1.fields["m_stat"]]

\n \ Employment/skills summary:
[decode(active1.fields["notes"])]
Photo:
\ -
") +
" else dat += "General Record Lost!
" - dat += text("\nDelete Record (ALL)

\nPrint Record
\nBack
", src, src, src) + dat += "\nDelete Record (ALL)

\nPrint Record
\nBack
" if(4.0) if(!Perp.len) - dat += text("ERROR. String could not be located.

Back", src) + dat += "ERROR. String could not be located.

Back" else dat += {" "} - dat += text("", tempname) + dat += "" dat += {"
Search Results for '[]':Search Results for '[tempname]':
@@ -121,17 +120,14 @@ if(istype(Perp[i+1],/datum/data/record/)) var/datum/data/record/E = Perp[i+1] crimstat = E.fields["criminal"] - var/background - background = "'background-color:#00FF7F;'" - dat += text("[]", background, src, R, R.fields["name"]) - dat += text("[]", R.fields["id"]) - dat += text("[]", R.fields["rank"]) - dat += text("[]", crimstat) + dat += "[R.fields["name"]]" + dat += "[R.fields["id"]]" + dat += "[R.fields["rank"]]" + dat += "[crimstat]" dat += "
" - dat += text("
Return to index.", src) - else + dat += "
Return to index." else - dat += text("{Log In}", src) + dat += "{Log In}" show_browser(user, dat, "Employment Records", "secure_rec", "size=600x400") onclose(user, "secure_rec") return @@ -342,7 +338,6 @@ What a mess.*/ if ((R.fields["name"] == active1.fields["name"] || R.fields["id"] == active1.fields["id"])) GLOB.data_core.medical -= R qdel(R) - else QDEL_NULL(active1) else temp = "This function does not appear to be working at the moment. Our apologies." @@ -352,8 +347,8 @@ What a mess.*/ return /obj/structure/machinery/computer/skills/emp_act(severity) + . = ..() if(inoperable()) - ..(severity) return for(var/datum/data/record/R in GLOB.data_core.security) @@ -378,4 +373,3 @@ What a mess.*/ qdel(R) continue - ..(severity) diff --git a/code/game/machinery/cryopod.dm b/code/game/machinery/cryopod.dm index 8ca504ce3a45..7a596dbd6b8b 100644 --- a/code/game/machinery/cryopod.dm +++ b/code/game/machinery/cryopod.dm @@ -192,7 +192,7 @@ GLOBAL_LIST_INIT(frozen_items, list(SQUAD_MARINE_1 = list(), SQUAD_MARINE_2 = li //Lifted from Unity stasis.dm and refactored. ~Zuhayr /obj/structure/machinery/cryopod/process() - if(occupant && !(WEAKREF(occupant) in GLOB.freed_mob_list)) //ignore freed mobs + if(occupant && !(occupant in GLOB.freed_mob_list)) //ignore freed mobs //if occupant ghosted, time till despawn is severely shorter if(!occupant.key && time_till_despawn == 10 MINUTES) time_till_despawn -= 8 MINUTES diff --git a/code/game/machinery/deployable.dm b/code/game/machinery/deployable.dm index e6df92d258c0..687882d9d7ae 100644 --- a/code/game/machinery/deployable.dm +++ b/code/game/machinery/deployable.dm @@ -54,7 +54,6 @@ src.health -= W.force * 0.75 if("brute") src.health -= W.force * 0.5 - else if (src.health <= 0) src.explode() ..() @@ -66,6 +65,7 @@ return /obj/structure/machinery/deployable/barrier/emp_act(severity) + . = ..() if(inoperable()) return if(prob(50/severity)) diff --git a/code/game/machinery/door_control.dm b/code/game/machinery/door_control.dm index 8be8609d6008..8b73588f1d0b 100644 --- a/code/game/machinery/door_control.dm +++ b/code/game/machinery/door_control.dm @@ -150,47 +150,6 @@ else icon_state = initial(icon_state) + "0" -/obj/structure/machinery/driver_button/attack_remote(mob/user as mob) - return src.attack_hand(user) - -/obj/structure/machinery/driver_button/attackby(obj/item/W, mob/user as mob) - return src.attack_hand(user) - -/obj/structure/machinery/driver_button/attack_hand(mob/user as mob) - - src.add_fingerprint(usr) - if(inoperable()) - return - if(active) - return - add_fingerprint(user) - - use_power(5) - - active = 1 - icon_state = "launcheract" - - for(var/obj/structure/machinery/door/poddoor/M in machines) - if(M.id == src.id) - INVOKE_ASYNC(M, TYPE_PROC_REF(/obj/structure/machinery/door, open)) - - sleep(20) - - for(var/obj/structure/machinery/mass_driver/M in machines) - if(M.id == src.id) - M.drive() - - sleep(50) - - for(var/obj/structure/machinery/door/poddoor/M in machines) - if(M.id == src.id) - INVOKE_ASYNC(M, TYPE_PROC_REF(/obj/structure/machinery/door, close)) - - icon_state = "launcherbtt" - active = 0 - - return - // Controls elevator railings /obj/structure/machinery/door_control/railings name = "railing controls" diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm index dc28cdca6f5c..c6d9ddf3efbd 100644 --- a/code/game/machinery/doors/airlock.dm +++ b/code/game/machinery/doors/airlock.dm @@ -550,13 +550,13 @@ GLOBAL_LIST_INIT(airlock_wire_descriptions, list( add_fingerprint(usr) update_icon() -/obj/structure/machinery/door/airlock/attackby(obj/item/C, mob/user) - if(SEND_SIGNAL(C, COMSIG_ITEM_ATTACK_AIRLOCK, src, user) & COMPONENT_CANCEL_AIRLOCK_ATTACK) +/obj/structure/machinery/door/airlock/attackby(obj/item/attacking_item, mob/user) + if(SEND_SIGNAL(attacking_item, COMSIG_ITEM_ATTACK_AIRLOCK, src, user) & COMPONENT_CANCEL_AIRLOCK_ATTACK) return - if(istype(C, /obj/item/clothing/mask/cigarette)) + if(istype(attacking_item, /obj/item/clothing/mask/cigarette)) if(isElectrified()) - var/obj/item/clothing/mask/cigarette/L = C + var/obj/item/clothing/mask/cigarette/L = attacking_item L.light(SPAN_NOTICE("[user] lights their [L] on an electrical arc from the [src]")) return @@ -567,7 +567,7 @@ GLOBAL_LIST_INIT(airlock_wire_descriptions, list( add_fingerprint(user) - if(istype(C, /obj/item/weapon/zombie_claws) && (welded || locked)) + if(istype(attacking_item, /obj/item/weapon/zombie_claws) && (welded || locked)) user.visible_message(SPAN_NOTICE("[user] starts tearing into the door on the [src]!"), \ SPAN_NOTICE("You start prying your hand into the gaps of the door with your fingers... This will take about 30 seconds."), \ SPAN_NOTICE("You hear tearing noises!")) @@ -584,8 +584,8 @@ GLOBAL_LIST_INIT(airlock_wire_descriptions, list( return - if((iswelder(C) && !operating && density)) - var/obj/item/tool/weldingtool/W = C + if((iswelder(attacking_item) && !operating && density)) + var/obj/item/tool/weldingtool/W = attacking_item var/weldtime = 50 if(!HAS_TRAIT(W, TRAIT_TOOL_BLOWTORCH)) weldtime = 70 @@ -609,7 +609,7 @@ GLOBAL_LIST_INIT(airlock_wire_descriptions, list( update_icon() return - else if(HAS_TRAIT(C, TRAIT_TOOL_SCREWDRIVER)) + else if(HAS_TRAIT(attacking_item, TRAIT_TOOL_SCREWDRIVER)) if(no_panel) to_chat(user, SPAN_WARNING("\The [src] has no panel to open!")) return @@ -619,17 +619,17 @@ GLOBAL_LIST_INIT(airlock_wire_descriptions, list( update_icon() return - else if(HAS_TRAIT(C, TRAIT_TOOL_WIRECUTTERS)) + else if(HAS_TRAIT(attacking_item, TRAIT_TOOL_WIRECUTTERS)) return attack_hand(user) - else if(HAS_TRAIT(C, TRAIT_TOOL_MULTITOOL)) + else if(HAS_TRAIT(attacking_item, TRAIT_TOOL_MULTITOOL)) return attack_hand(user) - else if(isgun(C)) - var/obj/item/weapon/gun/G = C - for(var/slot in G.attachments) - if(istype(G.attachments[slot], /obj/item/attachable/bayonet)) - var/obj/item/attachable/bayonet/a_bayonet = G.attachments[slot] + else if(isgun(attacking_item)) + var/obj/item/weapon/gun/gun_item = attacking_item + for(var/slot in gun_item.attachments) + if(istype(gun_item.attachments[slot], /obj/item/attachable/bayonet)) + var/obj/item/attachable/bayonet/a_bayonet = gun_item.attachments[slot] if(arePowerSystemsOn()) to_chat(user, SPAN_WARNING("The airlock's motors resist your efforts to force it.")) else if(locked) @@ -647,50 +647,48 @@ GLOBAL_LIST_INIT(airlock_wire_descriptions, list( if(do_after(user, a_bayonet.pry_delay, INTERRUPT_ALL, BUSY_ICON_FRIENDLY)) close(1) - else if(C.pry_capable) - if(C.pry_capable == IS_PRY_CAPABLE_CROWBAR && panel_open && welded) + else if(attacking_item.pry_capable) + if(attacking_item.pry_capable == IS_PRY_CAPABLE_CROWBAR && panel_open && welded) if(!skillcheck(user, SKILL_ENGINEER, SKILL_ENGINEER_ENGI)) to_chat(user, SPAN_WARNING("You don't seem to know how to deconstruct machines.")) return - if(width > 1) - to_chat(user, SPAN_WARNING("Large doors seem impossible to disassemble.")) - return playsound(loc, 'sound/items/Crowbar.ogg', 25, 1) user.visible_message("[user] starts removing the electronics from the airlock assembly.", "You start removing electronics from the airlock assembly.") if(do_after(user, 40, INTERRUPT_ALL|BEHAVIOR_IMMOBILE, BUSY_ICON_BUILD)) to_chat(user, SPAN_NOTICE(" You removed the airlock electronics!")) - var/obj/structure/airlock_assembly/da = new assembly_type(loc) - if(istype(da, /obj/structure/airlock_assembly/multi_tile)) - da.setDir(dir) + var/obj/structure/airlock_assembly/doors_assembly = new assembly_type(loc) + if(istype(doors_assembly, /obj/structure/airlock_assembly/multi_tile)) + doors_assembly.setDir(dir) + doors_assembly.update_collision_box() - da.anchored = TRUE + doors_assembly.anchored = TRUE if(mineral) - da.glass = mineral + doors_assembly.glass = mineral //else if(glass) - else if(glass && !da.glass) - da.glass = 1 - da.state = 0 - da.created_name = name - da.update_icon() + else if(glass && !doors_assembly.glass) + doors_assembly.glass = TRUE + doors_assembly.state = 0 + doors_assembly.created_name = name + doors_assembly.update_icon() - var/obj/item/circuitboard/airlock/ae + var/obj/item/circuitboard/airlock/airlock_electronics if(!electronics) - ae = new/obj/item/circuitboard/airlock( loc ) + airlock_electronics = new/obj/item/circuitboard/airlock(loc) if(!req_access || !req_one_access) check_access() if(req_access.len) - ae.conf_access = req_access + airlock_electronics.conf_access = req_access else if(req_one_access.len) - ae.conf_access = req_one_access - ae.one_access = 1 + airlock_electronics.conf_access = req_one_access + airlock_electronics.one_access = TRUE else - ae = electronics + airlock_electronics = electronics electronics = null - ae.forceMove(loc) + airlock_electronics.forceMove(loc) if(operating == -1) - ae.fried = TRUE - ae.update_icon() + airlock_electronics.fried = TRUE + airlock_electronics.update_icon() operating = 0 msg_admin_niche("[key_name(user)] deconstructed [src] in [get_area(user)] ([user.loc.x],[user.loc.y],[user.loc.z])") @@ -698,7 +696,7 @@ GLOBAL_LIST_INIT(airlock_wire_descriptions, list( deconstruct() return - else if(arePowerSystemsOn() && C.pry_capable != IS_PRY_CAPABLE_FORCE) + else if(arePowerSystemsOn() && attacking_item.pry_capable != IS_PRY_CAPABLE_FORCE) to_chat(user, SPAN_WARNING("The airlock's motors resist your efforts to force it.")) else if(locked) @@ -707,7 +705,7 @@ GLOBAL_LIST_INIT(airlock_wire_descriptions, list( else if(welded) to_chat(user, SPAN_WARNING("The airlock is welded shut.")) - else if(C.pry_capable == IS_PRY_CAPABLE_FORCE) + else if(attacking_item.pry_capable == IS_PRY_CAPABLE_FORCE) return FALSE //handled by the item's afterattack else if(!operating) @@ -719,7 +717,7 @@ GLOBAL_LIST_INIT(airlock_wire_descriptions, list( return TRUE //no afterattack call - if(istype(C, /obj/item/large_shrapnel)) + if(istype(attacking_item, /obj/item/large_shrapnel)) return FALSE //trigger afterattack call else return ..() @@ -868,3 +866,8 @@ GLOBAL_LIST_INIT(airlock_wire_descriptions, list( var/damage = xeno.melee_damage_upper * TAILSTAB_AIRLOCK_DAMAGE_MULTIPLIER take_damage(damage, xeno) return TAILSTAB_COOLDOWN_NORMAL + +/obj/structure/machinery/door/airlock/autoclose() + if(locked) + return + ..() diff --git a/code/game/machinery/doors/airlock_types.dm b/code/game/machinery/doors/airlock_types.dm index f4d09796194c..feb699fd245e 100644 --- a/code/game/machinery/doors/airlock_types.dm +++ b/code/game/machinery/doors/airlock_types.dm @@ -138,7 +138,6 @@ opacity = 0 assembly_type = /obj/structure/airlock_assembly/airlock_assembly_research glass = 1 - heat_proof = 1 req_one_access = list(ACCESS_CIVILIAN_RESEARCH, ACCESS_CIVILIAN_COMMAND, ACCESS_WY_COLONIAL) /obj/structure/machinery/door/airlock/glass_mining/colony diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm index 578ef368f5d9..021cb60769f9 100644 --- a/code/game/machinery/doors/door.dm +++ b/code/game/machinery/doors/door.dm @@ -1,4 +1,3 @@ - /obj/structure/machinery/door name = "\improper Door" desc = "It opens and closes." @@ -7,50 +6,43 @@ anchored = TRUE opacity = TRUE density = TRUE - throwpass = 0 + throwpass = FALSE layer = DOOR_OPEN_LAYER minimap_color = MINIMAP_DOOR var/open_layer = DOOR_OPEN_LAYER var/closed_layer = DOOR_CLOSED_LAYER var/id = "" + var/width = 1 var/secondsElectrified = 0 - var/visible = 1 + var/visible = TRUE var/panel_open = FALSE - var/operating = 0 - var/autoclose = 0 - var/glass = 0 - var/normalspeed = 1 - var/openspeed = 10 //How many seconds does it take to open it? Default 1 second. Use only if you have long door opening animations - var/heat_proof = 0 // For glass airlocks/opacity firedoors - var/air_properties_vary_with_direction = 0 - var/turf/filler //Fixes double door opacity issue + var/operating = FALSE + var/autoclose = FALSE + var/glass = FALSE + /// If FALSE it speeds up the autoclosing timing. + var/normalspeed = TRUE + /// Time to open/close airlock, default is 1 second. + var/openspeed = 1 SECONDS + /// Fixes multi_tile doors opacity issues. + var/list/filler_turfs = list() //Previously this was just var, because no one had forseen someone creating doors more than 2 tiles wide /// Stops it being forced open through normal means (Hunters/Zombies/Aliens). var/heavy = FALSE /// Resistance to masterkey var/masterkey_resist = FALSE var/masterkey_mod = 0.1 - - - //Multi-tile doors - dir = EAST - var/width = 1 + dir = EAST //So multitile doors are directioned properly /obj/structure/machinery/door/Initialize(mapload, ...) . = ..() - if(density) - layer = closed_layer - update_flags_heat_protection(get_turf(src)) - else - layer = open_layer - + layer = density ? closed_layer : open_layer handle_multidoor() /obj/structure/machinery/door/Destroy() . = ..() - if(filler && width > 1) - filler.set_opacity(0)// Ehh... let's hope there are no walls there. Must fix this - filler = null + if(length(filler_turfs) && width > 1) + change_filler_opacity(0) // It still doesn't check for walls, might want to add checking that in the future + filler_turfs = null density = FALSE /obj/structure/machinery/door/initialize_pass_flags(datum/pass_flags_container/PF) @@ -58,21 +50,41 @@ if (PF) PF.flags_can_pass_all = NONE +/// Also refreshes filler_turfs list. +/obj/structure/machinery/door/proc/change_filler_opacity(new_opacity) + // I have no idea why do we null opacity first before... changing it + for(var/turf/filler_turf as anything in filler_turfs) + filler_turf.set_opacity(null) + + filler_turfs = list() + for(var/turf/filler as anything in locate_filler_turfs()) + filler.set_opacity(new_opacity) + filler_turfs += filler + +/// Updates collision box and opacity of multi_tile airlocks. /obj/structure/machinery/door/proc/handle_multidoor() if(width > 1) if(dir in list(EAST, WEST)) bound_width = width * world.icon_size bound_height = world.icon_size - filler = get_step(src,EAST) - filler.set_opacity(opacity) else bound_width = world.icon_size bound_height = width * world.icon_size - filler = get_step(src,NORTH) - filler.set_opacity(opacity) + change_filler_opacity(opacity) + +/// Finds turfs which should be filler ones. +/obj/structure/machinery/door/proc/locate_filler_turfs() + var/turf/filler_temp + var/list/located_turfs = list() -//process() - //return + for(var/i in 1 to width - 1) + if (dir in list(EAST, WEST)) + filler_temp = locate(x + i, y, z) + else + filler_temp = locate(x, y + i, z) + if (filler_temp) + located_turfs += filler_temp + return located_turfs /obj/structure/machinery/door/proc/borders_space() for(var/turf/target in range(1, src)) @@ -81,7 +93,8 @@ return FALSE /obj/structure/machinery/door/Collided(atom/movable/AM) - if(panel_open || operating) return + if(panel_open || operating) + return if(ismob(AM)) var/mob/M = AM if(world.time - M.last_bumped <= openspeed) return //Can bump-open one airlock per second. This is to prevent shock spam. @@ -89,12 +102,10 @@ if(!M.is_mob_restrained() && M.mob_size > MOB_SIZE_SMALL) bumpopen(M) return - if(istype(AM, /obj)) var/obj/O = AM if(O.buckled_mob) Collided(O.buckled_mob) - if(istype(AM, /obj/structure/machinery/bot)) var/obj/structure/machinery/bot/bot = AM if(src.check_access(bot.botcard)) @@ -102,16 +113,17 @@ open() return - /obj/structure/machinery/door/proc/bumpopen(mob/user as mob) - if(operating) return - src.add_fingerprint(user) - if(!src.requiresID()) + if(operating) + return + add_fingerprint(user) + if(!requiresID()) user = null - if(density) - if(allowed(user)) open() - else flick("door_deny", src) + if(allowed(user)) + open() + else + flick("door_deny", src) return /obj/structure/machinery/door/attack_remote(mob/user) @@ -124,9 +136,7 @@ add_fingerprint(user) if(operating) return - if(!Adjacent(user)) - user = null //so allowed(user) always succeeds - if(!requiresID()) + if(!Adjacent(user) || !requiresID()) user = null //so allowed(user) always succeeds if(allowed(user)) if(density) @@ -137,64 +147,56 @@ if(density) flick("door_deny", src) - /obj/structure/machinery/door/attackby(obj/item/I, mob/user) if(!(I.flags_item & NOBLUDGEON)) try_to_activate_door(user) - return 1 + return TRUE /obj/structure/machinery/door/emp_act(severity) - if(prob(20/severity) && (istype(src,/obj/structure/machinery/door/airlock) || istype(src,/obj/structure/machinery/door/window)) ) + . = ..() + if(prob(20/severity) && use_power) open() if(prob(40/severity)) if(secondsElectrified == 0) secondsElectrified = -1 spawn(30 SECONDS) secondsElectrified = 0 - ..() - /obj/structure/machinery/door/ex_act(severity) - if(unacidable) return + if(unacidable) + return if(density) switch(severity) if(0 to EXPLOSION_THRESHOLD_LOW) if(prob(80)) - var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread - s.set_up(2, 1, src) - s.start() + var/datum/effect_system/spark_spread/spark = new /datum/effect_system/spark_spread + spark.set_up(2, 1, src) + spark.start() if(EXPLOSION_THRESHOLD_LOW to INFINITY) qdel(src) else switch(severity) if(0 to EXPLOSION_THRESHOLD_MEDIUM) if(prob(80)) - var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread - s.set_up(2, 1, src) - s.start() + var/datum/effect_system/spark_spread/spark = new /datum/effect_system/spark_spread + spark.set_up(2, 1, src) + spark.start() else qdel(src) return - /obj/structure/machinery/door/get_explosion_resistance() if(density) if(unacidable) - return 1000000 + return 1000000 //Used for negation of explosions, should probably be made into define in the future else return EXPLOSION_THRESHOLD_LOW //this should exactly match the amount of damage needed to destroy the door else return 0 - /obj/structure/machinery/door/update_icon() - if(density) - icon_state = "door1" - else - icon_state = "door0" - return - + icon_state = density ? "door1" : "door0" /obj/structure/machinery/door/proc/do_animate(animation) switch(animation) @@ -212,7 +214,6 @@ flick("door_deny", src) return - /obj/structure/machinery/door/proc/open(forced=0) if(!density) return TRUE @@ -223,8 +224,8 @@ do_animate("opening") icon_state = "door0" set_opacity(FALSE) - if(filler) - filler.set_opacity(opacity) + if(length(filler_turfs)) + change_filler_opacity(opacity) addtimer(CALLBACK(src, PROC_REF(finish_open)), openspeed) return TRUE @@ -235,11 +236,9 @@ if(operating) operating = FALSE - if(autoclose) addtimer(CALLBACK(src, PROC_REF(autoclose)), normalspeed ? 150 + openspeed : 5) - /obj/structure/machinery/door/proc/close() if(density) return TRUE @@ -256,22 +255,19 @@ update_icon() if(visible && !glass) set_opacity(TRUE) - if(filler) - filler.set_opacity(opacity) + if(length(filler_turfs)) + change_filler_opacity(opacity) operating = FALSE /obj/structure/machinery/door/proc/requiresID() return TRUE - -/obj/structure/machinery/door/proc/update_flags_heat_protection(turf/source) - - +/// Used for overriding in airlocks /obj/structure/machinery/door/proc/autoclose() - var/obj/structure/machinery/door/airlock/A = src - if(!A.density && !A.operating && !A.locked && !A.welded && A.autoclose) + if(!autoclose) + return + if(!density && !operating) close() - return /obj/structure/machinery/door/Move(new_loc, new_dir) . = ..() @@ -279,16 +275,15 @@ if(dir in list(EAST, WEST)) bound_width = width * world.icon_size bound_height = world.icon_size - filler.set_opacity(0) - filler = (get_step(src,EAST)) //Find new turf - filler.set_opacity(opacity) else bound_width = world.icon_size bound_height = width * world.icon_size - filler.set_opacity(0) - filler = (get_step(src,NORTH)) //Find new turf - filler.set_opacity(opacity) + change_filler_opacity(opacity) +/obj/structure/machinery/door/afterShuttleMove(turf/oldT, list/movement_force, shuttle_dir, shuttle_preferred_direction, move_dir, rotation) + . = ..() + // Yes, for a split second after departure you can see through rear dropship airlocks, but it's the simplest solution I could've think of + handle_multidoor() /obj/structure/machinery/door/morgue icon = 'icons/obj/structures/doors/doormorgue.dmi' diff --git a/code/game/machinery/doors/multi_tile.dm b/code/game/machinery/doors/multi_tile.dm index 6123d56b8f23..ca218128160d 100644 --- a/code/game/machinery/doors/multi_tile.dm +++ b/code/game/machinery/doors/multi_tile.dm @@ -2,19 +2,24 @@ /obj/structure/machinery/door/airlock/multi_tile width = 2 damage_cap = 650 // Bigger = more endurable + assembly_type = /obj/structure/airlock_assembly/multi_tile /obj/structure/machinery/door/airlock/multi_tile/close() //Nasty as hell O(n^2) code but unfortunately necessary - for(var/turf/T in locs) - for(var/obj/vehicle/multitile/M in T) - if(M) return 0 + for(var/turf/turf_tile in locs) + for(var/obj/vehicle/multitile/vehicle_tile in turf_tile) + if(vehicle_tile) return 0 return ..() +/obj/structure/machinery/door/airlock/multi_tile/Initialize() + . = ..() + update_icon() + /obj/structure/machinery/door/airlock/multi_tile/glass name = "Glass Airlock" icon = 'icons/obj/structures/doors/Door2x1glass.dmi' opacity = FALSE - glass = 1 + glass = TRUE assembly_type = /obj/structure/airlock_assembly/multi_tile /obj/structure/machinery/door/airlock/multi_tile/glass/colony @@ -25,7 +30,7 @@ name = "Security Airlock" icon = 'icons/obj/structures/doors/Door2x1security.dmi' opacity = FALSE - glass = 1 + glass = TRUE /obj/structure/machinery/door/airlock/multi_tile/security/colony req_access = null @@ -35,7 +40,7 @@ name = "Command Airlock" icon = 'icons/obj/structures/doors/Door2x1command.dmi' opacity = FALSE - glass = 1 + glass = TRUE /obj/structure/machinery/door/airlock/multi_tile/command/colony req_access = null @@ -45,7 +50,7 @@ name = "Medical Airlock" icon = 'icons/obj/structures/doors/Door2x1medbay.dmi' opacity = FALSE - glass = 1 + glass = TRUE /obj/structure/machinery/door/airlock/multi_tile/medical/colony req_access = null @@ -55,7 +60,7 @@ name = "Engineering Airlock" icon = 'icons/obj/structures/doors/Door2x1engine.dmi' opacity = FALSE - glass = 1 + glass = TRUE /obj/structure/machinery/door/airlock/multi_tile/engineering/colony req_access = null @@ -65,7 +70,7 @@ name = "Research Airlock" icon = 'icons/obj/structures/doors/Door2x1research.dmi' opacity = FALSE - glass = 1 + glass = TRUE req_one_access = list(ACCESS_MARINE_RESEARCH, ACCESS_WY_RESEARCH, ACCESS_WY_EXEC) /obj/structure/machinery/door/airlock/multi_tile/research/colony @@ -103,7 +108,7 @@ name = "Secure Airlock" icon = 'icons/obj/structures/doors/Door2x1_secure2_glass.dmi' opacity = FALSE - glass = 1 + glass = TRUE openspeed = 31 req_access = null @@ -131,7 +136,6 @@ /obj/structure/window/framed/almayer, /obj/structure/machinery/door/airlock, ) - var/multi_filler = list() /obj/structure/machinery/door/airlock/multi_tile/almayer/Initialize() . = ..() @@ -141,10 +145,10 @@ . = ..() relativewall_neighbours() -/obj/structure/machinery/door/airlock/multi_tile/almayer/take_damage(dam, mob/M) - var/damage_check = max(0, damage + dam) - if(damage_check >= damage_cap && M && is_mainship_level(z)) - SSclues.create_print(get_turf(M), M, "The fingerprint contains bits of wire and metal specks.") +/obj/structure/machinery/door/airlock/multi_tile/almayer/take_damage(taken_damage, mob/damaging_mob) + var/damage_check = max(0, damage + taken_damage) + if(damage_check >= damage_cap && damaging_mob && is_mainship_level(z)) + SSclues.create_print(get_turf(damaging_mob), damaging_mob, "The fingerprint contains bits of wire and metal specks.") ..() /obj/structure/machinery/door/airlock/multi_tile/almayer/generic @@ -156,6 +160,11 @@ /obj/structure/machinery/door/airlock/multi_tile/almayer/generic/autoname autoname = TRUE +/obj/structure/machinery/door/airlock/multi_tile/almayer/generic/solid + icon = 'icons/obj/structures/doors/2x1generic_solid.dmi' + opacity = TRUE + glass = FALSE + /obj/structure/machinery/door/airlock/multi_tile/almayer/medidoor name = "\improper Medical Airlock" icon = 'icons/obj/structures/doors/2x1medidoor.dmi' @@ -222,47 +231,6 @@ req_access = null req_one_access = list(ACCESS_CIVILIAN_BRIG, ACCESS_CIVILIAN_COMMAND, ACCESS_WY_COLONIAL) -/obj/structure/machinery/door/airlock/multi_tile/almayer/handle_multidoor() - if(!(width > 1)) return //Bubblewrap - - update_filler_turfs() - if(dir in list(NORTH, SOUTH)) - bound_height = world.icon_size * width - bound_width = world.icon_size - else if(dir in list(EAST, WEST)) - bound_width = world.icon_size * width - bound_height = world.icon_size - -//We have to find these again since these doors are used on shuttles a lot so the turfs changes -/obj/structure/machinery/door/airlock/multi_tile/almayer/proc/update_filler_turfs() - for(var/turf/T in multi_filler) - T.set_opacity(null) - - multi_filler = list() - for(var/turf/T in get_filler_turfs()) - T.set_opacity(opacity) - multi_filler += list(T) - -/obj/structure/machinery/door/airlock/multi_tile/proc/get_filler_turfs() - . = list() - for(var/i = 1, i < width, i++) - if(dir in list(NORTH, SOUTH)) - var/turf/T = locate(x, y + i, z) - if(T) - . += list(T) - else if(dir in list(EAST, WEST)) - var/turf/T = locate(x + i, y, z) - if(T) - . += list(T) - -/obj/structure/machinery/door/airlock/multi_tile/almayer/open() - . = ..() - update_filler_turfs() - -/obj/structure/machinery/door/airlock/multi_tile/almayer/close() - . = ..() - update_filler_turfs() - //------Dropship Cargo Doors -----// /obj/structure/machinery/door/airlock/multi_tile/almayer/dropshiprear @@ -427,7 +395,7 @@ /obj/structure/machinery/door/airlock/multi_tile/elevator/access icon = 'icons/obj/structures/doors/4x1_elevator_access.dmi' opacity = FALSE - glass = 1 + glass = TRUE /obj/structure/machinery/door/airlock/multi_tile/elevator/access/research name = "\improper Research Elevator Hatch" @@ -547,7 +515,7 @@ icon = 'icons/obj/structures/doors/prepdoor.dmi' req_one_access = list(ACCESS_MARINE_PREP, ACCESS_MARINE_DATABASE, ACCESS_MARINE_CARGO, ACCESS_MARINE_ALPHA, ACCESS_MARINE_BRAVO, ACCESS_MARINE_CHARLIE, ACCESS_MARINE_DELTA) opacity = FALSE - glass = 1 + glass = TRUE /obj/structure/machinery/door/airlock/multi_tile/almayer/marine/shared/alpha_bravo name = "\improper Alpha-Bravo Squads Preparations" diff --git a/code/game/machinery/doors/runed_sandstone.dm b/code/game/machinery/doors/runed_sandstone.dm index 4bf66dfdc8d8..a6de7348dd7f 100644 --- a/code/game/machinery/doors/runed_sandstone.dm +++ b/code/game/machinery/doors/runed_sandstone.dm @@ -110,8 +110,8 @@ density = FALSE update_icon() set_opacity(0) - if(filler) - filler.set_opacity(opacity) + if(length(filler_turfs)) + change_filler_opacity(opacity) if(operating) operating = FALSE diff --git a/code/game/machinery/doors/windowdoor.dm b/code/game/machinery/doors/windowdoor.dm index 2b57fbd0a44d..bd544c5c3f5a 100644 --- a/code/game/machinery/doors/windowdoor.dm +++ b/code/game/machinery/doors/windowdoor.dm @@ -11,7 +11,6 @@ flags_atom = ON_BORDER opacity = FALSE var/obj/item/circuitboard/airlock/electronics = null - air_properties_vary_with_direction = 1 /obj/structure/machinery/door/window/Initialize() . = ..() diff --git a/code/game/machinery/fax_machine.dm b/code/game/machinery/fax_machine.dm index ff26ce802b08..ff21671ed758 100644 --- a/code/game/machinery/fax_machine.dm +++ b/code/game/machinery/fax_machine.dm @@ -6,6 +6,7 @@ var/list/alldepartments = list() #define DEPARTMENT_CMB "CMB Incident Command Center, Local Operations" #define DEPARTMENT_PROVOST "USCM Provost Office" #define DEPARTMENT_PRESS "Various Press Organizations" +#define HIGHCOM_DEPARTMENTS list(DEPARTMENT_WY, DEPARTMENT_HC, DEPARTMENT_CMB, DEPARTMENT_PROVOST, DEPARTMENT_PRESS) /obj/structure/machinery/faxmachine // why not fax_machine? name = "\improper General Purpose Fax Machine" @@ -319,27 +320,31 @@ var/list/alldepartments = list() GLOB.fax_contents += faxcontents + var/scan_department = target_department + if(department in HIGHCOM_DEPARTMENTS) + scan_department = department + var/msg_admin = SPAN_STAFF_IC("[target_department]: [key_name(user, 1)] ") msg_admin += "[CC_MARK(user)] [ADMIN_PP(user)] [ADMIN_VV(user)] [ADMIN_SM(user)] [ADMIN_JMP_USER(user)] " - switch(target_department) + switch(scan_department) if(DEPARTMENT_HC) - GLOB.USCMFaxes.Add("\[view message at [world.timeofday]\] REPLY") + GLOB.USCMFaxes.Add("\['[original_fax.name]' from [key_name(usr)], [scan] at [time2text(world.timeofday, "hh:mm:ss")]\] REPLY") msg_admin += "(RPLY): " if(DEPARTMENT_PROVOST) - GLOB.ProvostFaxes.Add("\[view message at [world.timeofday]\] REPLY") + GLOB.ProvostFaxes.Add("\['[original_fax.name]' from [key_name(usr)], [scan] at [time2text(world.timeofday, "hh:mm:ss")]\] REPLY") msg_admin += "(RPLY): " if(DEPARTMENT_CMB) - GLOB.CMBFaxes.Add("\[view message at [world.timeofday]\] REPLY") + GLOB.CMBFaxes.Add("\['[original_fax.name]' from [key_name(usr)], [scan] at [time2text(world.timeofday, "hh:mm:ss")]\] REPLY") msg_admin += "(RPLY): " if(DEPARTMENT_WY) - GLOB.WYFaxes.Add("\[view message at [world.timeofday]\] REPLY") + GLOB.WYFaxes.Add("\['[original_fax.name]' from [key_name(usr)], [scan] at [time2text(world.timeofday, "hh:mm:ss")]\] REPLY") msg_admin += "(RPLY): " if(DEPARTMENT_PRESS) - GLOB.PressFaxes.Add("\[view message at [world.timeofday]\] REPLY") + GLOB.PressFaxes.Add("\['[original_fax.name]' from [key_name(usr)], [scan] at [time2text(world.timeofday, "hh:mm:ss")]\] REPLY") msg_admin += "(RPLY): " else - GLOB.GeneralFaxes.Add("\[view message at [world.timeofday]\] REPLY") + GLOB.GeneralFaxes.Add("\['[original_fax.name]' from [key_name(usr)], [scan] at [time2text(world.timeofday, "hh:mm:ss")]\] REPLY") msg_admin += "(RPLY): " msg_admin += SPAN_STAFF_IC("Receiving fax via secure connection ... view message") diff --git a/code/game/machinery/fire_alarm.dm b/code/game/machinery/fire_alarm.dm index fe1f80646c4f..dd7e0ee70150 100644 --- a/code/game/machinery/fire_alarm.dm +++ b/code/game/machinery/fire_alarm.dm @@ -63,8 +63,9 @@ FIRE ALARM return src.alarm() /obj/structure/machinery/firealarm/emp_act(severity) - if(prob(50/severity)) alarm() - ..() + . = ..() + if(prob(50/severity)) + alarm() /obj/structure/machinery/firealarm/attackby(obj/item/held_object as obj, mob/user as mob) src.add_fingerprint(user) diff --git a/code/game/machinery/flasher.dm b/code/game/machinery/flasher.dm index 75d0de56dec0..cd59862a2e13 100644 --- a/code/game/machinery/flasher.dm +++ b/code/game/machinery/flasher.dm @@ -84,12 +84,11 @@ /obj/structure/machinery/flasher/emp_act(severity) + . = ..() if(inoperable()) - ..(severity) return if(prob(75/severity)) flash() - ..(severity) /obj/structure/machinery/flasher/portable/HasProximity(atom/movable/AM as mob|obj) if ((src.disable) || (src.last_flash && world.time < src.last_flash + 150)) diff --git a/code/game/machinery/floodlight.dm b/code/game/machinery/floodlight.dm index 5f6cd02a4bf8..516cdad380b1 100644 --- a/code/game/machinery/floodlight.dm +++ b/code/game/machinery/floodlight.dm @@ -1,30 +1,28 @@ -//these are probably broken - /obj/structure/machinery/floodlight - name = "Emergency Floodlight" + name = "emergency floodlight" + desc = "A powerful light usually stationed near landing zones to provide better visibility." icon = 'icons/obj/structures/machinery/floodlight.dmi' icon_state = "flood00" density = TRUE anchored = TRUE - var/obj/item/cell/cell = null - var/use = 0 - var/unlocked = 0 - var/open = 0 light_power = 2 - unslashable = TRUE - unacidable = TRUE + wrenchable = TRUE + use_power = USE_POWER_IDLE + idle_power_usage = 0 + active_power_usage = 100 var/on_light_range = 6 + ///Whether or not the floodlight can be toggled on or off + var/toggleable = TRUE + + ///Whether or not the floodlight is turned on, disconnected from whether it has power or is lit + var/turned_on = FALSE + /obj/structure/machinery/floodlight/Initialize(mapload, ...) . = ..() - cell = new /obj/item/cell(src) - if(light_on) - set_light(on_light_range) -/obj/structure/machinery/floodlight/Destroy() - QDEL_NULL(cell) - return ..() + turn_light(toggle_on = (operable() && turned_on)) /obj/structure/machinery/floodlight/turn_light(mob/user, toggle_on) . = ..() @@ -36,100 +34,51 @@ else set_light(0) + update_icon() -/obj/structure/machinery/floodlight/proc/updateicon() - icon_state = "flood[open ? "o" : ""][open && cell ? "b" : ""]0[light_on]" - -/obj/structure/machinery/floodlight/attack_hand(mob/user as mob) - if(open && cell) - if(ishuman(user)) - if(!user.get_active_hand()) - user.put_in_hands(cell) - cell.forceMove(user.loc) - else - cell.forceMove(loc) +/obj/structure/machinery/floodlight/attack_hand(mob/user) + if(!toggleable) + to_chat(user, SPAN_NOTICE("[src] doesn't seem to have a switch to toggle the light.")) + return - cell.add_fingerprint(user) - cell.update_icon() + if(user.lying || user.stat) + return - src.cell = null - to_chat(user, "You remove the power cell.") - updateicon() + if(!is_valid_user(user)) + to_chat(user, SPAN_NOTICE("You don't have the dexterity to do this.")) return - if(light_on) - to_chat(user, SPAN_NOTICE("You turn off the light.")) - turn_light(user, toggle_on = FALSE) - unslashable = TRUE - unacidable = TRUE - else - if(!cell) - return - if(cell.charge <= 0) - return - to_chat(user, SPAN_NOTICE("You turn on the light.")) - turn_light(user, toggle_on = TRUE) - unacidable = FALSE + turned_on = !turned_on - updateicon() + if(inoperable()) + to_chat(user, SPAN_NOTICE("You turn [turned_on ? "on" : "off"] the floodlight. It seems to be inoperable.")) + return + to_chat(user, SPAN_NOTICE("You turn [turned_on ? "on" : "off"] the light.")) + turn_light(user, toggle_on = turned_on) + update_use_power(turned_on ? USE_POWER_ACTIVE : USE_POWER_IDLE) -/obj/structure/machinery/floodlight/attackby(obj/item/W as obj, mob/user as mob) - if(!ishuman(user)) - return +/obj/structure/machinery/floodlight/update_icon() + . = ..() + icon_state = "flood0[light_on]" + +/obj/structure/machinery/floodlight/power_change(area/master_area = null) + . = ..() - if (HAS_TRAIT(W, TRAIT_TOOL_WRENCH)) - if (!anchored) - anchored = TRUE - to_chat(user, "You anchor the [src] in place.") - else - anchored = FALSE - to_chat(user, "You remove the bolts from the [src].") - - if (HAS_TRAIT(W, TRAIT_TOOL_SCREWDRIVER)) - if (!open) - if(unlocked) - unlocked = 0 - to_chat(user, "You screw the battery panel in place.") - else - unlocked = 1 - to_chat(user, "You unscrew the battery panel.") - - if (HAS_TRAIT(W, TRAIT_TOOL_CROWBAR)) - if(unlocked) - if(open) - open = 0 - overlays = null - to_chat(user, "You crowbar the battery panel in place.") - else - if(unlocked) - open = 1 - to_chat(user, "You remove the battery panel.") - - if (istype(W, /obj/item/cell)) - if(open) - if(cell) - to_chat(user, "There is a power cell already installed.") - else - if(user.drop_inv_item_to_loc(W, src)) - cell = W - to_chat(user, "You insert the power cell.") - updateicon() + turn_light(toggle_on = (!(stat & NOPOWER) && turned_on)) //Magical floodlight that cannot be destroyed or interacted with. /obj/structure/machinery/floodlight/landing - name = "Landing Light" - desc = "A powerful light stationed near landing zones to provide better visibility." + name = "landing light" + desc = "A powerful light usually stationed near landing zones to provide better visibility. This one seems to have been bolted down and is unable to be moved." icon_state = "flood01" - light_on = TRUE - in_use = 1 use_power = USE_POWER_NONE - -/obj/structure/machinery/floodlight/landing/attack_hand() - return - -/obj/structure/machinery/floodlight/landing/attackby() - return + needs_power = FALSE + unslashable = TRUE + unacidable = TRUE + wrenchable = FALSE + toggleable = FALSE + turned_on = TRUE /obj/structure/machinery/floodlight/landing/floor icon_state = "floor_flood01" diff --git a/code/game/machinery/fusion_engine.dm b/code/game/machinery/fusion_engine.dm index 4158727e3745..8e3097ef52d1 100644 --- a/code/game/machinery/fusion_engine.dm +++ b/code/game/machinery/fusion_engine.dm @@ -15,6 +15,7 @@ unacidable = TRUE //NOPE.jpg anchored = TRUE density = TRUE + power_machine = TRUE var/power_gen_percent = 0 //50,000W at full capacity var/buildstate = 0 //What state of building it are we on, 0-3, 1 is "broken", the default @@ -24,7 +25,8 @@ var/obj/item/fuelCell/fusion_cell = new //Starts with a fuel cell loaded in. Maybe replace with the plasma tanks in the future and have it consume plasma? Possibly remove this later if it's irrelevent... var/fuel_rate = 0 //Rate at which fuel is used. Based mostly on how long the generator has been running. - power_machine = TRUE + /// If the generator is overloaded. Only possible during hijack once fuel is at 100%. + var/overloaded = FALSE /obj/structure/machinery/power/fusion_engine/Initialize(mapload, ...) . = ..() @@ -35,11 +37,25 @@ /obj/structure/machinery/power/fusion_engine/Destroy() QDEL_NULL(fusion_cell) - . = ..() + return ..() +/obj/structure/machinery/power/fusion_engine/attack_alien(mob/living/carbon/xenomorph/xeno) + if(!overloaded) + to_chat(xeno, SPAN_WARNING("You see no reason to attack [src].")) + return XENO_NO_DELAY_ACTION + + xeno.animation_attack_on(src) + playsound(src, 'sound/effects/metalhit.ogg', 25, 1) + xeno.visible_message(SPAN_DANGER("[xeno] [xeno.slashes_verb] [src], stopping its overload process!"), \ + SPAN_DANGER("You [xeno.slash_verb] [src], stopping its overload process!"), null, 5, CHAT_TYPE_XENO_COMBAT) + set_overloading(FALSE) + return XENO_ATTACK_ACTION /obj/structure/machinery/power/fusion_engine/power_change() - return + . = ..() + if(overloaded) + set_overloading(FALSE) + visible_message("[icon2html(src, viewers(src))] [src]'s overload suddenly ceases as primary power is lost.") /obj/structure/machinery/power/fusion_engine/process() if(!is_on || buildstate || !anchored || !powernet || !fusion_cell) //Default logic checking @@ -60,9 +76,18 @@ stop_processing() return FALSE - if(!check_failure()) + if(overloaded && prob(1)) // up to 18 generators at 1% every 3.5 seconds means that every ~21 seconds or so, one generator will make noise assuming all are overloaded + switch(rand(1, 2)) + if(1) + visible_message("[icon2html(src, viewers(src))] [SPAN_NOTICE("[src] loudly hums.")]") + playsound(src, 'sound/machines/resource_node/node_idle.ogg', 60, TRUE) + if(2) + visible_message("[icon2html(src, viewers(src))] [SPAN_NOTICE("[src] makes a worrying hiss.")]") + playsound(src, 'sound/machines/hiss.ogg', 60, TRUE) - if(power_gen_percent < 100) power_gen_percent++ + if(!check_failure()) + if(power_gen_percent < 100) + power_gen_percent++ switch(power_gen_percent) //Flavor text! if(10) @@ -96,6 +121,10 @@ to_chat(user, SPAN_NOTICE("Use a wrench to repair it.")) return FALSE if(is_on) + if(overloaded) + to_chat(user, SPAN_WARNING("You can't shut off [src] while it's overloaded!")) + return + visible_message("[icon2html(src, viewers(src))] [SPAN_WARNING("[src] beeps softly and the humming stops as [usr] shuts off the generator.")]") is_on = 0 power_gen_percent = 0 @@ -208,11 +237,18 @@ if(buildstate) to_chat(user, SPAN_WARNING("You must repair the generator before working with its fuel cell.")) return + + if(overloaded) + to_chat(user, SPAN_WARNING("You must restore the safeties on the generator before working with its fuel cell.")) + return + if(is_on) to_chat(user, SPAN_WARNING("You must turn off the generator before working with its fuel cell.")) return + if(!fusion_cell) to_chat(user, SPAN_WARNING("There is no cell to remove.")) + else if(!skillcheck(user, SKILL_ENGINEER, SKILL_ENGINEER_ENGI)) user.visible_message(SPAN_WARNING("[user] fumbles around figuring out [src]'s fuel receptacle."), @@ -232,23 +268,73 @@ fusion_cell = null update_icon() return TRUE + + else if(HAS_TRAIT(O, TRAIT_TOOL_MULTITOOL)) + if(!skillcheck(user, SKILL_ENGINEER, SKILL_ENGINEER_ENGI)) + to_chat(user, SPAN_WARNING("You have no idea what to do with [src].")) + return + + if(!overloaded) + if(!SShijack.sd_unlocked) + to_chat(user, SPAN_WARNING("You consider overloading [src]'s safeties, but you decide against it.")) + return + + if(inoperable()) + to_chat(user, SPAN_WARNING("[src] needs to be working and have external power in order to overload it!")) + return + + to_chat(user, SPAN_WARNING("You start overloading the safeties on [src]...")) + if(!do_after(user, 1.5 SECONDS, INTERRUPT_ALL|BEHAVIOR_IMMOBILE, BUSY_ICON_BUILD)) + return + + if(inoperable()) + return + + to_chat(user, SPAN_WARNING("You finish overloading the safeties on [src].")) + set_overloading(TRUE) + log_game("[key_name(user)] has overloaded a generator.") + + else + to_chat(user, SPAN_WARNING("You start restoring the safeties on [src]...")) + if(!do_after(user, 1.5 SECONDS, INTERRUPT_ALL|BEHAVIOR_IMMOBILE, BUSY_ICON_BUILD)) + return + + if(inoperable()) + return + + to_chat(user, SPAN_WARNING("You finish restoring the safeties on [src].")) + log_game("[key_name(user)] has restored the safeties of a generator.") + set_overloading(FALSE) + + return TRUE + else return ..() /obj/structure/machinery/power/fusion_engine/get_examine_text(mob/user) . = ..() - if(ishuman(user)) + if(isxeno(user)) + if(overloaded) + . += SPAN_INFO("You could attack this to stop the overload process.") + + else if(ishuman(user)) if(buildstate) . += SPAN_INFO("It's broken.") switch(buildstate) if(1) - . += SPAN_INFO("Use a blowtorch, then wirecutters, then wrench to repair it.") + . += SPAN_INFO("Use a blowtorch, then wirecutters, then wrench to repair it.") if(2) - . += SPAN_INFO("Use a wirecutters, then wrench to repair it.") + . += SPAN_INFO("Use a wirecutters, then wrench to repair it.") if(3) - . += SPAN_INFO("Use a wrench to repair it.") + . += SPAN_INFO("Use a wrench to repair it.") return FALSE + if(SShijack.sd_unlocked && skillcheck(user, SKILL_ENGINEER, SKILL_ENGINEER_ENGI)) + if(!overloaded) + . += SPAN_INFO("You could overload this with a multitool.") + else + . += SPAN_INFO("You could restore its safeties with a multitool.") + if(!is_on) . += SPAN_INFO("It looks offline.") else @@ -274,18 +360,21 @@ switch(buildstate) if(0) if(fusion_cell) - var/pstatus = is_on ? "on" : "off" - switch(fusion_cell.get_fuel_percent()) - if(0 to 10) - icon_state = "[pstatus]-10" - if(10 to 25) - icon_state = "[pstatus]-25" - if(25 to 50) - icon_state = "[pstatus]-50" - if(50 to 75) - icon_state = "[pstatus]-75" - if(75 to INFINITY) - icon_state = "[pstatus]-100" + if(overloaded) + icon_state = "overloaded" + else + var/pstatus = is_on ? "on" : "off" + switch(fusion_cell.get_fuel_percent()) + if(0 to 10) + icon_state = "[pstatus]-10" + if(10 to 25) + icon_state = "[pstatus]-25" + if(25 to 50) + icon_state = "[pstatus]-50" + if(50 to 75) + icon_state = "[pstatus]-75" + if(75 to INFINITY) + icon_state = "[pstatus]-100" else icon_state = "off" @@ -317,9 +406,13 @@ else return 0 +/obj/structure/machinery/power/fusion_engine/proc/set_overloading(new_overloading) + if(overloaded == new_overloading) + return - - + overloaded = new_overloading + SEND_GLOBAL_SIGNAL(COMSIG_GLOB_GENERATOR_SET_OVERLOADING, overloaded) + update_icon() diff --git a/code/game/machinery/igniter.dm b/code/game/machinery/igniter.dm index 33f75c50e341..d5a0505fca17 100644 --- a/code/game/machinery/igniter.dm +++ b/code/game/machinery/igniter.dm @@ -105,11 +105,10 @@ return 1 /obj/structure/machinery/sparker/emp_act(severity) + . = ..() if(inoperable()) - ..(severity) return ignite() - ..(severity) /obj/structure/machinery/ignition_switch/attack_remote(mob/user as mob) return attack_hand(user) diff --git a/code/game/machinery/kitchen/microwave.dm b/code/game/machinery/kitchen/microwave.dm index f4611b9042db..220772e98b17 100644 --- a/code/game/machinery/kitchen/microwave.dm +++ b/code/game/machinery/kitchen/microwave.dm @@ -139,7 +139,6 @@ if (!(R.id in acceptable_reagents)) to_chat(user, SPAN_DANGER("Your [O] contains components unsuitable for cookery.")) return 1 - //G.reagents.trans_to(src,G.amount_per_transfer_from_this) else if(istype(O,/obj/item/grab)) return 1 else @@ -152,74 +151,78 @@ /obj/structure/machinery/microwave/attack_hand(mob/user as mob) user.set_interaction(src) - interact(user) + tgui_interact(user) + +/obj/structure/machinery/microwave/tgui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if (!ui) + ui = new(user, src, "Microwave", "Microwave Controls") + ui.open() //******************* //* Microwave Menu //********************/ - -/obj/structure/machinery/microwave/interact(mob/user as mob) // The microwave Menu - var/dat = "" - if(src.broken > 0) - dat = {"Bzzzzttttt"} - else if(src.operating) - dat = {"Microwaving in progress!
Please wait...!
"} - else if(src.dirty==100) - dat = {"This microwave is dirty!
Please clean it before use!
"} - else - var/list/items_counts = new - var/list/items_measures = new - var/list/items_measures_p = new - for (var/obj/O in contents) - var/display_name = O.name - if (istype(O,/obj/item/reagent_container/food/snacks/egg)) - items_measures[display_name] = "egg" - items_measures_p[display_name] = "eggs" - if (istype(O,/obj/item/reagent_container/food/snacks/tofu)) - items_measures[display_name] = "tofu chunk" - items_measures_p[display_name] = "tofu chunks" - if (istype(O,/obj/item/reagent_container/food/snacks/meat)) //any meat - items_measures[display_name] = "slab of meat" - items_measures_p[display_name] = "slabs of meat" - if (istype(O,/obj/item/reagent_container/food/snacks/donkpocket)) - display_name = "Turnovers" - items_measures[display_name] = "turnover" - items_measures_p[display_name] = "turnovers" - if (istype(O,/obj/item/reagent_container/food/snacks/carpmeat)) - items_measures[display_name] = "fillet of meat" - items_measures_p[display_name] = "fillets of meat" - items_counts[display_name]++ - for (var/O in items_counts) - var/N = items_counts[O] - if (!(O in items_measures)) - dat += {"[capitalize(O)]: [N] [lowertext(O)]\s
"} - else - if (N==1) - dat += {"[capitalize(O)]: [N] [items_measures[O]]
"} - else - dat += {"[capitalize(O)]: [N] [items_measures_p[O]]
"} - - for (var/datum/reagent/R in reagents.reagent_list) - var/display_name = R.name - if (R.id == "hotsauce") - display_name = "Hotsauce" - if (R.id == "frostoil") - display_name = "Coldsauce" - dat += {"[display_name]: [R.volume] unit\s
"} - - if (items_counts.len==0 && reagents.reagent_list.len==0) - dat = {"The microwave is empty
"} +/obj/structure/machinery/microwave/ui_data(mob/user) + var/list/data = list() + + data["operating"] = operating + data["broken"] = (broken > 0) + data["dirty"] = (dirty == 100) + + var/list/ingredients = list() + var/list/items_counts = list() + var/list/items_measures = list() + var/list/items_measures_p = list() + + for (var/obj/contents_item as anything in contents) + var/display_name = contents_item.name + + if (istype(contents_item, /obj/item/reagent_container/food/snacks/tofu)) + items_measures[display_name] = "tofu chunk" + items_measures_p[display_name] = "tofu chunks" + if (istype(contents_item, /obj/item/reagent_container/food/snacks/meat)) //any meat + items_measures[display_name] = "slab of meat" + items_measures_p[display_name] = "slabs of meat" + if (istype(contents_item, /obj/item/reagent_container/food/snacks/donkpocket)) + display_name = "Turnovers" + items_measures[display_name] = "turnover" + items_measures_p[display_name] = "turnovers" + if (istype(contents_item, /obj/item/reagent_container/food/snacks/carpmeat)) + items_measures[display_name] = "fillet of meat" + items_measures_p[display_name] = "fillets of meat" + items_counts[display_name]++ + + for (var/contents_item in items_counts) + var/list/item = list() + + item["name"] = capitalize(contents_item) + item["count"] = items_counts[contents_item] + + if (!(contents_item in items_measures)) + item["measure"] = "[lowertext(contents_item)][items_counts[contents_item] > 1 ? "s" : ""]" // Adds 's' for plurals. + else if (items_counts[contents_item] == 1) + item["measure"] = items_measures[contents_item] else - dat = {"Ingredients:
[dat]"} - dat += {"

\ -Turn on!
\ -
Eject ingredients!
\ -"} + item["measure"] = items_measures_p[contents_item] + + ingredients += list(item) + + for (var/datum/reagent/contents_reagent as anything in reagents.reagent_list) + var/list/reagent = list() - show_browser(user, dat, "Microwave Controls", "microwave") - return + reagent["count"] = contents_reagent.volume + reagent["measure"] = contents_reagent.volume > 1 ? "units" : "unit" + reagent["name"] = contents_reagent.name + if (contents_reagent.id == "hotsauce") + reagent["name"] = "Hotsauce" + if (contents_reagent.id == "frostoil") + reagent["name"] = "Coldsauce" + ingredients += list(reagent) + + data["ingredients"] = ingredients + return data //*********************************** //* Microwave Menu Handling/Cooking @@ -322,7 +325,7 @@ if (src.reagents.total_volume) src.dirty++ src.reagents.clear_reagents() - to_chat(usr, SPAN_NOTICE(" You dispose of the microwave contents.")) + to_chat(usr, SPAN_NOTICE("You dispose of the microwave contents.")) src.updateUsrDialog() /obj/structure/machinery/microwave/proc/muck_start() @@ -365,19 +368,16 @@ ffuu.reagents.add_reagent("toxin", amount/10) return ffuu -/obj/structure/machinery/microwave/Topic(href, href_list) - if(..()) - return - - usr.set_interaction(src) - if(src.operating) - src.updateUsrDialog() +/obj/structure/machinery/microwave/ui_act(action, params) + . = ..() + if(.) return - switch(href_list["action"]) + switch (action) if ("cook") cook(usr.get_skill_duration_multiplier(SKILL_DOMESTIC)) // picking the right microwave setting for the right food. when's the last time you used the special setting on the microwave? i bet you just slam the 30 second increment. Do you know how much programming went into putting the Pizza setting into a microwave emitter? - if ("dispose") + if ("eject_all") dispose() - return + + return TRUE diff --git a/code/game/machinery/kitchen/smartfridge.dm b/code/game/machinery/kitchen/smartfridge.dm index f52350aa8db3..903cd06c3119 100644 --- a/code/game/machinery/kitchen/smartfridge.dm +++ b/code/game/machinery/kitchen/smartfridge.dm @@ -23,7 +23,7 @@ var/icon_on = "smartfridge" var/icon_off = "smartfridge-off" var/icon_panel = "smartfridge-panel" - var/item_quants = list() + var/list/item_quants = list() //! Assoc list of names -> list(items) var/ispowered = TRUE //starts powered var/is_secure_fridge = FALSE var/shoot_inventory = FALSE @@ -40,6 +40,24 @@ GLOB.vending_products[/obj/item/reagent_container/glass/bottle] = 1 GLOB.vending_products[/obj/item/storage/pill_bottle] = 1 +/obj/structure/machinery/smartfridge/Destroy(force) + if(is_in_network()) // Delete all contents from networked storage index + for(var/atom/movable/item as anything in contents) + delete_contents(item) + item_quants.Cut() + return ..() // parent will delete contents if we're not networked + +/// Deletes given object in contents of the smartfridge +/obj/structure/machinery/smartfridge/proc/delete_contents(obj/item/item) + if(item.loc != src) + return + contents -= item + if(item_quants[item.name]) + item_quants[item.name] -= item + if(is_in_network() && chemical_data.shared_item_storage[item.name]) + chemical_data.shared_item_storage[item.name] -= item + qdel(item) + /obj/structure/machinery/smartfridge/proc/accept_check(obj/item/O as obj) if(istype(O,/obj/item/reagent_container/food/snacks/grown/) || istype(O,/obj/item/seeds/)) return 1 diff --git a/code/game/machinery/lightswitch.dm b/code/game/machinery/lightswitch.dm index 66eb0386713f..de61830c2501 100644 --- a/code/game/machinery/lightswitch.dm +++ b/code/game/machinery/lightswitch.dm @@ -62,8 +62,7 @@ updateicon() /obj/structure/machinery/light_switch/emp_act(severity) + . = ..() if(inoperable()) - ..(severity) return power_change() - ..(severity) diff --git a/code/game/machinery/machinery.dm b/code/game/machinery/machinery.dm index f4ad7a63ba77..66bf08afba8e 100644 --- a/code/game/machinery/machinery.dm +++ b/code/game/machinery/machinery.dm @@ -105,7 +105,7 @@ Class Procs: var/list/component_parts //list of all the parts used to build it, if made from certain kinds of frames. var/manual = 0 layer = OBJ_LAYER - var/machine_processing = 0 // whether the machine is busy and requires process() calls in scheduler. + var/machine_processing = 0 // whether the machine is busy and requires process() calls in scheduler. // Please replace this by DF_ISPROCESSING in another refactor --fira throwpass = 1 projectile_coverage = PROJECTILE_COVERAGE_MEDIUM var/power_machine = FALSE //Whether the machine should process on power, or normal processor @@ -175,10 +175,10 @@ Class Procs: . += SPAN_WARNING("[msg]") /obj/structure/machinery/emp_act(severity) + . = ..() if(use_power && stat == 0) use_power(7500/severity) new /obj/effect/overlay/temp/emp_sparks (loc) - ..() /obj/structure/machinery/ex_act(severity) diff --git a/code/game/machinery/magnet.dm b/code/game/machinery/magnet.dm deleted file mode 100644 index 591cec1f5baa..000000000000 --- a/code/game/machinery/magnet.dm +++ /dev/null @@ -1,421 +0,0 @@ -// Magnetic attractor, creates variable magnetic fields and attraction. -// Can also be used to emit electron/proton beams to create a center of magnetism on another tile - -// tl;dr: it's magnets lol -// This was created for firing ranges, but I suppose this could have other applications - Doohl - -/obj/structure/machinery/magnetic_module - - icon = 'icons/obj/objects.dmi' - icon_state = "floor_magnet-f" - name = "Electromagnetic Generator" - desc = "A device that uses station power to create points of magnetic energy." - level = 1 // underfloor - layer = UNDERFLOOR_OBJ_LAYER - anchored = TRUE - use_power = USE_POWER_IDLE - idle_power_usage = 50 - - var/freq = 1449 // radio frequency - var/electricity_level = 1 // intensity of the magnetic pull - var/magnetic_field = 1 // the range of magnetic attraction - var/code = 0 // frequency code, they should be different unless you have a group of magnets working together or something - var/turf/center // the center of magnetic attraction - var/on = 0 - var/pulling = 0 - - // x, y modifiers to the center turf; (0, 0) is centered on the magnet, whereas (1, -1) is one tile right, one tile down - var/center_x = 0 - var/center_y = 0 - var/max_dist = 20 // absolute value of center_x,y cannot exceed this integer - -/obj/structure/machinery/magnetic_module/Initialize(mapload, ...) - . = ..() - - var/turf/T = loc - hide(T.intact_tile) - center = T - - SSradio.add_object(src, freq, RADIO_MAGNETS) - - INVOKE_ASYNC(src, PROC_REF(magnetic_process)) - -/obj/structure/machinery/magnetic_module/Destroy() - center = null - SSradio.remove_object(src, freq) - . = ..() - - - // update the invisibility and icon -/obj/structure/machinery/magnetic_module/hide(intact) - invisibility = intact ? 101 : 0 - updateicon() - - // update the icon_state -/obj/structure/machinery/magnetic_module/proc/updateicon() - var/state="floor_magnet" - var/onstate="" - if(!on) - onstate="0" - - if(invisibility) - icon_state = "[state][onstate]-f" // if invisible, set icon to faded version - // in case of being revealed by T-scanner - else - icon_state = "[state][onstate]" - -/obj/structure/machinery/magnetic_module/receive_signal(datum/signal/signal) - - var/command = signal.data["command"] - var/modifier = signal.data["modifier"] - var/signal_code = signal.data["code"] - if(command && (signal_code == code)) - - Cmd(command, modifier) - - - -/obj/structure/machinery/magnetic_module/proc/Cmd(command, modifier) - - if(command) - switch(command) - if("set-electriclevel") - if(modifier) electricity_level = modifier - if("set-magneticfield") - if(modifier) magnetic_field = modifier - - if("add-elec") - electricity_level++ - if(electricity_level > 12) - electricity_level = 12 - if("sub-elec") - electricity_level-- - if(electricity_level <= 0) - electricity_level = 1 - if("add-mag") - magnetic_field++ - if(magnetic_field > 4) - magnetic_field = 4 - if("sub-mag") - magnetic_field-- - if(magnetic_field <= 0) - magnetic_field = 1 - - if("set-x") - if(modifier) center_x = modifier - if("set-y") - if(modifier) center_y = modifier - - if("N") // NORTH - center_y++ - if("S") // SOUTH - center_y-- - if("E") // EAST - center_x++ - if("W") // WEST - center_x-- - if("C") // CENTER - center_x = 0 - center_y = 0 - if("R") // RANDOM - center_x = rand(-max_dist, max_dist) - center_y = rand(-max_dist, max_dist) - - if("set-code") - if(modifier) code = modifier - if("toggle-power") - on = !on - - if(on) - INVOKE_ASYNC(src, PROC_REF(magnetic_process)) - - -/obj/structure/machinery/magnetic_module/process() - if(stat & NOPOWER) - on = 0 - - // Sanity checks: - if(electricity_level <= 0) - electricity_level = 1 - if(magnetic_field <= 0) - magnetic_field = 1 - - - // Limitations: - if(abs(center_x) > max_dist) - center_x = max_dist - if(abs(center_y) > max_dist) - center_y = max_dist - if(magnetic_field > 4) - magnetic_field = 4 - if(electricity_level > 12) - electricity_level = 12 - - // Update power usage: - if(on) - use_power = USE_POWER_ACTIVE - active_power_usage = electricity_level*15 - else - use_power = USE_POWER_NONE - - - // Overload conditions: - /* // Eeeehhh kinda stupid - if(on) - if(electricity_level > 11) - if(prob(electricity_level)) - explosion(loc, 0, 1, 2, 3) // ooo dat shit EXPLODES son - spawn(2) - qdel(src) - */ - - updateicon() - - -/obj/structure/machinery/magnetic_module/proc/magnetic_process() // proc that actually does the pulling - if(pulling) return - while(on) - - pulling = 1 - center = locate(x+center_x, y+center_y, z) - if(center) - for(var/obj/M in orange(magnetic_field, center)) - if(!M.anchored && (M.flags_atom & CONDUCT)) - step_towards(M, center) - - for(var/mob/living/silicon/S in orange(magnetic_field, center)) - if(isAI(S)) continue - step_towards(S, center) - - use_power(electricity_level * 5) - sleep(13 - electricity_level) - - pulling = 0 - -/obj/structure/machinery/magnetic_controller - name = "Magnetic Control Console" - icon = 'icons/obj/structures/machinery/airlock_machines.dmi' // uses an airlock machine icon, THINK GREEN HELP THE ENVIRONMENT - RECYCLING! - icon_state = "airlock_control_standby" - density = TRUE - anchored = TRUE - use_power = USE_POWER_IDLE - idle_power_usage = 45 - var/frequency = 1449 - var/code = 0 - var/list/magnets = list() - var/title = "Magnetic Control Console" - var/autolink = 0 // if set to 1, can't probe for other magnets! - - var/pathpos = 1 // position in the path - var/path = "NULL" // text path of the magnet - var/speed = 1 // lowest = 1, highest = 10 - var/list/rpath = list() // real path of the magnet, used in iterator - - var/moving = 0 // 1 if scheduled to loop - var/looping = 0 // 1 if looping - - var/datum/radio_frequency/radio_connection - -/obj/structure/machinery/magnetic_controller/Initialize(mapload, ...) - . = ..() - if(autolink) - for(var/obj/structure/machinery/magnetic_module/M in machines) - if(M.freq == frequency && M.code == code) - magnets.Add(M) - - SSradio.add_object(src, frequency, RADIO_MAGNETS) - - if(path) // check for default path - filter_path() // renders rpath - -/obj/structure/machinery/magnetic_controller/Destroy() - QDEL_NULL_LIST(magnets) - SSradio.remove_object(src, frequency) - . = ..() - - -/obj/structure/machinery/magnetic_controller/process() - if(magnets.len == 0 && autolink) - for(var/obj/structure/machinery/magnetic_module/M in machines) - if(M.freq == frequency && M.code == code) - magnets.Add(M) - -/obj/structure/machinery/magnetic_controller/attack_remote(mob/user as mob) - return src.attack_hand(user) - -/obj/structure/machinery/magnetic_controller/attack_hand(mob/user as mob) - if(inoperable()) - return - user.set_interaction(src) - var/dat = "Magnetic Control Console

" - if(!autolink) - dat += {" - Frequency:
[frequency]
- Code: [code]
- Probe Generators
- "} - - if(magnets.len >= 1) - - dat += "Magnets confirmed:
" - var/i = 0 - for(var/obj/structure/machinery/magnetic_module/M in magnets) - i++ - dat += "     < \[[i]\] ([M.on ? "On":"Off"])|Electricity level: - [M.electricity_level] +; Magnetic field: - [M.magnetic_field] +
" - - dat += "
Speed: - [speed] +
" - dat += "Path: {[path]}
" - dat += "Moving: [moving ? "Enabled":"Disabled"]" - - - show_browser(user, dat, name, "magnet", "size=400x500") - -/obj/structure/machinery/magnetic_controller/Topic(href, href_list) - . = ..() - if(.) - return - if(inoperable()) - return - usr.set_interaction(src) - src.add_fingerprint(usr) - - if(href_list["radio-op"]) - - // Prepare signal beforehand, because this is a radio operation - var/datum/signal/signal = new - signal.transmission_method = 1 // radio transmission - signal.source = src - signal.frequency = frequency - signal.data["code"] = code - - // Apply any necessary commands - switch(href_list["radio-op"]) - if("togglepower") - signal.data["command"] = "toggle-power" - - if("minuselec") - signal.data["command"] = "sub-elec" - if("pluselec") - signal.data["command"] = "add-elec" - - if("minusmag") - signal.data["command"] = "sub-mag" - if("plusmag") - signal.data["command"] = "add-mag" - - - // Broadcast the signal - - radio_connection.post_signal(src, signal, filter = RADIO_MAGNETS) - - addtimer(CALLBACK(src, PROC_REF(updateUsrDialog)), 1) - - if(href_list["operation"]) - switch(href_list["operation"]) - if("plusspeed") - speed ++ - if(speed > 10) - speed = 10 - if("minusspeed") - speed -- - if(speed <= 0) - speed = 1 - if("setpath") - var/newpath = copytext(sanitize(input(usr, "Please define a new path!",,path) as text|null),1,MAX_MESSAGE_LEN) - if(newpath && newpath != "") - moving = 0 // stop moving - path = newpath - pathpos = 1 // reset position - filter_path() // renders rpath - - if("togglemoving") - moving = !moving - if(moving) - INVOKE_ASYNC(src, PROC_REF(MagnetMove)) - - - updateUsrDialog() - -/obj/structure/machinery/magnetic_controller/proc/MagnetMove() - if(looping) return - - while(moving && rpath.len >= 1) - - if(inoperable()) - break - - looping = 1 - - // Prepare the radio signal - var/datum/signal/signal = new - signal.transmission_method = 1 // radio transmission - signal.source = src - signal.frequency = frequency - signal.data["code"] = code - - if(pathpos > rpath.len) // if the position is greater than the length, we just loop through the list! - pathpos = 1 - - var/nextmove = uppertext(rpath[pathpos]) // makes it un-case-sensitive - - if(!(nextmove in list("N","S","E","W","C","R"))) - // N, S, E, W are directional - // C is center - // R is random (in magnetic field's bounds) - qdel(signal) - break // break the loop if the character located is invalid - - signal.data["command"] = nextmove - - - pathpos++ // increase iterator - - // Broadcast the signal - spawn() - radio_connection.post_signal(src, signal, filter = RADIO_MAGNETS) - - if(speed == 10) - sleep(1) - else - sleep(12-speed) - - looping = 0 - - -/obj/structure/machinery/magnetic_controller/proc/filter_path() - // Generates the rpath variable using the path string, think of this as "string2list" - // Doesn't use params2list() because of the akward way it stacks entities - rpath = list() // clear rpath - var/maximum_character = min( 50, length(path) ) // chooses the maximum length of the iterator. 50 max length - - for(var/i=1, i<=maximum_character, i++) // iterates through all characters in path - - var/nextchar = copytext(path, i, i+1) // find next character - - if(!(nextchar in list(";", "&", "*", " "))) // if char is a separator, ignore - rpath += copytext(path, i, i+1) // else, add to list - - // there doesn't HAVE to be separators but it makes paths syntatically visible - - - - - - - - - - - - - - - - - - - - - - - diff --git a/code/game/machinery/mass_driver.dm b/code/game/machinery/mass_driver.dm index d1e2fecce20f..f1b0081e3a39 100644 --- a/code/game/machinery/mass_driver.dm +++ b/code/game/machinery/mass_driver.dm @@ -1,5 +1,4 @@ -//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:31 - +// Legacy SS13 machinery turned into a prop /obj/structure/machinery/mass_driver name = "mass driver" desc = "Shoots things into space." @@ -9,32 +8,3 @@ use_power = USE_POWER_IDLE idle_power_usage = 2 active_power_usage = 50 - - var/power = 1 - var/code = 1 - var/id = 1 - var/drive_range = 50 //this is mostly irrelevant since current mass drivers throw into space, but you could make a lower-range mass driver for interstation transport or something I guess. - - -/obj/structure/machinery/mass_driver/proc/drive(amount) - if(inoperable()) - return - use_power(500) - var/O_limit - var/atom/target = get_edge_target_turf(src, dir) - for(var/atom/movable/O in loc) - if(!O.anchored) - if(O_limit >= 20) - for(var/mob/M in hearers(src, null)) - to_chat(M, SPAN_NOTICE(" The mass driver lets out a screech, it mustn't be able to handle any more items.")) - break - use_power(500) - INVOKE_ASYNC(O, TYPE_PROC_REF(/atom/movable, throw_atom), target, drive_range * power, 100/power) - flick("mass_driver1", src) - return - -/obj/structure/machinery/mass_driver/emp_act(severity) - if(inoperable()) - return - drive() - ..(severity) diff --git a/code/game/machinery/medical_pod/bodyscanner.dm b/code/game/machinery/medical_pod/bodyscanner.dm index 4756121e50ae..fdcd0ceb62e6 100644 --- a/code/game/machinery/medical_pod/bodyscanner.dm +++ b/code/game/machinery/medical_pod/bodyscanner.dm @@ -62,8 +62,6 @@ if(EXPLOSION_THRESHOLD_MEDIUM to INFINITY) deconstruct(FALSE) return - else - return #ifdef OBJECTS_PROXY_SPEECH // Transfers speech to occupant @@ -124,8 +122,6 @@ if(EXPLOSION_THRESHOLD_MEDIUM to INFINITY) deconstruct(FALSE) return - else - return /obj/structure/machinery/body_scanconsole/power_change() ..() diff --git a/code/game/machinery/medical_pod/sleeper.dm b/code/game/machinery/medical_pod/sleeper.dm index 805fedb29257..bf2abe246c35 100644 --- a/code/game/machinery/medical_pod/sleeper.dm +++ b/code/game/machinery/medical_pod/sleeper.dm @@ -332,14 +332,13 @@ /obj/structure/machinery/medical_pod/sleeper/emp_act(severity) + . = ..() if(filtering) toggle_filter() if(inoperable()) - ..(severity) return if(occupant) go_out() - ..() /obj/structure/machinery/medical_pod/sleeper/proc/toggle_filter() if(!occupant) @@ -385,7 +384,6 @@ t1 = "Unconscious" if(2) t1 = "*dead*" - else to_chat(user, "[]\t Health %: [] ([])", (occupant.health > 50 ? SPAN_NOTICE("") : SPAN_DANGER("")), occupant.health, t1) to_chat(user, "[]\t -Core Temperature: []°C ([]°F)
", (occupant.bodytemperature > 50 ? "" : ""), occupant.bodytemperature-T0C, occupant.bodytemperature*1.8-459.67) to_chat(user, "[]\t -Brute Damage %: []", (occupant.getBruteLoss() < 60 ? SPAN_NOTICE("") : SPAN_DANGER("")), occupant.getBruteLoss()) diff --git a/code/game/machinery/nuclearbomb.dm b/code/game/machinery/nuclearbomb.dm index 743f53e4f03b..28ebbecc7552 100644 --- a/code/game/machinery/nuclearbomb.dm +++ b/code/game/machinery/nuclearbomb.dm @@ -394,7 +394,38 @@ var/bomb_set = FALSE update_icon() safety = TRUE - EvacuationAuthority.trigger_self_destruct(list(z), src, FALSE, NUKE_EXPLOSION_GROUND_FINISHED, FALSE, end_round) + playsound(src, 'sound/machines/Alarm.ogg', 75, 0, 30) + world << pick('sound/theme/nuclear_detonation1.ogg','sound/theme/nuclear_detonation2.ogg') + + var/list/alive_mobs = list() //Everyone who will be destroyed on the zlevel(s). + var/list/dead_mobs = list() //Everyone who only needs to see the cinematic. + for(var/mob/current_mob as anything in GLOB.mob_list) + if(!current_mob?.loc) + continue + if(current_mob.stat == DEAD) + dead_mobs |= current_mob + continue + var/turf/current_turf = get_turf(current_mob) + if(z == current_turf.z) + alive_mobs |= current_mob + shake_camera(current_mob, 110, 4) + + for(var/mob/current_mob in alive_mobs) + if(current_mob && current_mob.loc) + var/turf/current_mob_turf = get_turf(current_mob) + if(z == current_mob_turf.z) + if(istype(current_mob.loc, /obj/structure/closet/secure_closet/freezer/fridge)) + continue + current_mob.death(create_cause_data("nuclear explosion")) + + for(var/mob/current_mob in (alive_mobs + dead_mobs)) + if(current_mob && current_mob.loc) + var/turf/current_mob_turf = get_turf(current_mob) + if(z == current_mob_turf.z) + if(istype(current_mob.loc, /obj/structure/closet/secure_closet/freezer/fridge)) + continue + for(var/obj/item/alien_embryo/embryo in current_mob) + qdel(embryo) sleep(100) cell_explosion(loc, 500, 150, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, create_cause_data(initial(name))) diff --git a/code/game/machinery/recharger.dm b/code/game/machinery/recharger.dm index 7855f446c805..72e311c6d8ff 100644 --- a/code/game/machinery/recharger.dm +++ b/code/game/machinery/recharger.dm @@ -11,7 +11,7 @@ black_market_value = 35 var/obj/item/charging = null var/percent_charge_complete = 0 - var/list/allowed_devices = list(/obj/item/weapon/baton, /obj/item/cell, /obj/item/weapon/gun/energy, /obj/item/device/defibrillator, /obj/item/tool/portadialysis, /obj/item/clothing/suit/auto_cpr, /obj/item/smartgun_battery) + var/list/allowed_devices = list(/obj/item/weapon/baton, /obj/item/cell, /obj/item/weapon/gun/energy, /obj/item/device/defibrillator, /obj/item/tool/portadialysis, /obj/item/clothing/suit/auto_cpr, /obj/item/smartgun_battery, /obj/item/device/helmet_visor/night_vision) var/charge_amount = 1000 @@ -181,6 +181,21 @@ update_icon() return + if(istype(charging, /obj/item/device/helmet_visor/night_vision)) + var/obj/item/device/helmet_visor/night_vision/charging_night_vision_visor = charging + if(charging_night_vision_visor.power_cell) + if(!charging_night_vision_visor.power_cell.fully_charged()) + charging_night_vision_visor.power_cell.give(charge_amount) + percent_charge_complete = charging_night_vision_visor.power_cell.percent() + update_use_power(USE_POWER_ACTIVE) + update_icon() + return + + percent_charge_complete = 100 + update_use_power(USE_POWER_IDLE) + update_icon() + return + /* Disable defib recharging if(istype(charging, /obj/item/device/defibrillator)) var/obj/item/device/defibrillator/D = charging @@ -203,20 +218,14 @@ update_icon() /obj/structure/machinery/recharger/emp_act(severity) + . = ..() if(inoperable() || !anchored) - ..(severity) return -/* - if(istype(charging, /obj/item/weapon/gun/energy)) - var/obj/item/weapon/gun/energy/E = charging - if(E.power_supply) - E.power_supply.emp_act(severity) -*/ + if(istype(charging, /obj/item/weapon/baton)) var/obj/item/weapon/baton/B = charging if(B.bcell) B.bcell.charge = 0 - ..(severity) /obj/structure/machinery/recharger/update_icon() //we have an update_icon() in addition to the stuff in process to make it feel a tiny bit snappier. src.overlays = 0 diff --git a/code/game/machinery/rechargestation.dm b/code/game/machinery/rechargestation.dm index 644402128852..56b782cd77a4 100644 --- a/code/game/machinery/rechargestation.dm +++ b/code/game/machinery/rechargestation.dm @@ -109,13 +109,12 @@ return /obj/structure/machinery/recharge_station/emp_act(severity) + . = ..() if(inoperable()) - ..(severity) return if(occupant) occupant.emp_act(severity) go_out() - ..(severity) /obj/structure/machinery/recharge_station/update_icon() ..() diff --git a/code/game/machinery/sentry_holder.dm b/code/game/machinery/sentry_holder.dm index 61f87251282d..fe676e9103d2 100644 --- a/code/game/machinery/sentry_holder.dm +++ b/code/game/machinery/sentry_holder.dm @@ -10,13 +10,12 @@ idle_power_usage = 1000 power_channel = 1 use_power = USE_POWER_IDLE - machine_processing = 1 var/deployment_cooldown var/turret_path = /obj/structure/machinery/defenses/sentry/premade/deployable // Path of the turret used var/obj/structure/machinery/defenses/sentry/premade/deployable/deployed_turret var/ox = 0 var/oy = 0 - var/ind = FALSE + var/require_red_alert = FALSE /obj/structure/machinery/sentry_holder/Initialize() . = ..() @@ -36,34 +35,38 @@ . += "It's offline." /obj/structure/machinery/sentry_holder/attack_hand(mob/user) - if(deployed_turret) - if(deployment_cooldown > world.time) - to_chat(user, SPAN_WARNING("[src] is busy.")) - return //prevents spamming deployment/undeployment - if(deployed_turret.loc == src) //not deployed - if(stat & NOPOWER) - to_chat(user, SPAN_WARNING("[src] is non-functional.")) - else - to_chat(user, SPAN_NOTICE("You deploy [src].")) - deploy_sentry() - else - to_chat(user, SPAN_NOTICE("You retract [src].")) - undeploy_sentry() - else + if(!deployed_turret) to_chat(user, SPAN_WARNING("[src] is unresponsive.")) + return -/obj/structure/machinery/sentry_holder/process() - if(stat & NOPOWER) - if(deployed_turret) - undeploy_sentry() - ind = FALSE - else - icon_state = "sentry_system_destroyed" - else - update_use_power(USE_POWER_IDLE) - if(!ind) - deploy_sentry() - ind = TRUE + if(deployment_cooldown > world.time) + to_chat(user, SPAN_WARNING("[src] is busy.")) + return + + if(deployed_turret.loc == src) //not deployed + if(stat & NOPOWER) + to_chat(user, SPAN_WARNING("[src] is non-functional.")) + return + + if(require_red_alert && (seclevel2num(get_security_level()) < SEC_LEVEL_RED)) + to_chat(user, SPAN_WARNING("[src] can only be activated in emergencies.")) + return + + to_chat(user, SPAN_NOTICE("You deploy [src].")) + deploy_sentry() + return + + to_chat(user, SPAN_NOTICE("You retract [src].")) + undeploy_sentry() + return + +/obj/structure/machinery/sentry_holder/update_use_power(new_use_power) + ..() + + if(!(stat & NOPOWER)) + return + + undeploy_sentry() /obj/structure/machinery/sentry_holder/proc/deploy_sentry() if(!deployed_turret) @@ -111,3 +114,6 @@ desc = "A box that deploys a sentry turret for protection of the residents in the area." turret_path = /obj/structure/machinery/defenses/sentry/premade/deployable/colony +/obj/structure/machinery/sentry_holder/almayer + turret_path = /obj/structure/machinery/defenses/sentry/premade/deployable/almayer + require_red_alert = TRUE diff --git a/code/game/machinery/spaceheater.dm b/code/game/machinery/spaceheater.dm index aa51201ae18b..dd45ad597800 100644 --- a/code/game/machinery/spaceheater.dm +++ b/code/game/machinery/spaceheater.dm @@ -40,12 +40,11 @@ /obj/structure/machinery/space_heater/emp_act(severity) + . = ..() if(inoperable()) - ..(severity) return if(cell) cell.emp_act(severity) - ..(severity) /obj/structure/machinery/space_heater/attackby(obj/item/I, mob/user) if(istype(I, /obj/item/cell)) diff --git a/code/game/machinery/status_display.dm b/code/game/machinery/status_display.dm index 6c6d2bda8b07..79ead6321502 100644 --- a/code/game/machinery/status_display.dm +++ b/code/game/machinery/status_display.dm @@ -78,7 +78,7 @@ return 1 if(STATUS_DISPLAY_TRANSFER_SHUTTLE_TIME) //emergency shuttle timer message1 = "EVAC" - message2 = EvacuationAuthority.get_status_panel_eta() + message2 = SShijack.get_evac_eta() if(message2) if(length(message2) > CHARS_PER_LINE) message2 = "Error" update_display(message1, message2) @@ -163,6 +163,15 @@ if(maptext) maptext = "" +/obj/structure/machinery/status_display/proc/set_sec_level_picture() + switch(security_level) + if(SEC_LEVEL_GREEN) + set_picture("default") + if(SEC_LEVEL_BLUE) + set_picture("bluealert") + if(SEC_LEVEL_RED, SEC_LEVEL_DELTA) + set_picture("redalert") + /obj/structure/machinery/ai_status_display icon = 'icons/obj/structures/machinery/status_display.dmi' icon_state = "frame" @@ -179,11 +188,10 @@ var/emotion = "Neutral" /obj/structure/machinery/ai_status_display/emp_act(severity) + . = ..() if(inoperable()) - ..(severity) return set_picture("ai_bsod") - ..(severity) /obj/structure/machinery/ai_status_display/proc/update() if(mode==0) //Blank diff --git a/code/game/machinery/telecomms/presets.dm b/code/game/machinery/telecomms/presets.dm index b327bd6fdf26..a9c7c61bc00d 100644 --- a/code/game/machinery/telecomms/presets.dm +++ b/code/game/machinery/telecomms/presets.dm @@ -218,12 +218,20 @@ GLOBAL_LIST_EMPTY(all_static_telecomms_towers) /// Held image for the current overlay on the tower from xeno corruption var/image/corruption_image + /// Holds the delay for when a cluster can recorrupt the comms tower after a pylon has been destroyed + COOLDOWN_DECLARE(corruption_delay) + /obj/structure/machinery/telecomms/relay/preset/tower/mapcomms/Initialize() . = ..() RegisterSignal(src, COMSIG_ATOM_TURF_CHANGE, PROC_REF(register_with_turf)) register_with_turf() +/obj/structure/machinery/telecomms/relay/preset/tower/mapcomms/get_examine_text(mob/user) + . = ..() + if(isxeno(user) && !COOLDOWN_FINISHED(src, corruption_delay)) + . += SPAN_XENO("Corruption cooldown: [(COOLDOWN_TIMELEFT(src, corruption_delay) / (1 SECONDS))] seconds.") + /obj/structure/machinery/telecomms/relay/preset/tower/mapcomms/attack_hand(mob/user) if(user.action_busy) return @@ -323,6 +331,10 @@ GLOBAL_LIST_EMPTY(all_static_telecomms_towers) addtimer(CALLBACK(src, PROC_REF(handle_xeno_acquisition), weeded_turf), (XENO_COMM_ACQUISITION_TIME - ROUND_TIME)) return + if(!COOLDOWN_FINISHED(src, corruption_delay)) + addtimer(CALLBACK(src, PROC_REF(handle_xeno_acquisition), weeded_turf), (COOLDOWN_TIMELEFT(src, corruption_delay))) + return + var/obj/effect/alien/weeds/node/pylon/cluster/parent_node = weeded_turf.weeds.parent var/obj/effect/alien/resin/special/cluster/cluster_parent = parent_node.resin_parent @@ -362,6 +374,8 @@ GLOBAL_LIST_EMPTY(all_static_telecomms_towers) overlays -= corruption_image + COOLDOWN_START(src, corruption_delay, XENO_PYLON_DESTRUCTION_DELAY) + /// Handles moving the overlay from growing to idle /obj/structure/machinery/telecomms/relay/preset/tower/mapcomms/proc/switch_to_idle_corruption() if(!corrupted) @@ -435,8 +449,7 @@ GLOBAL_LIST_EMPTY(all_static_telecomms_towers) id = "CentComm Receiver" network = "tcommsat" autolinkers = list("receiverCent") - freq_listening = list(WY_WO_FREQ, PMC_FREQ, DUT_FREQ, YAUT_FREQ, HC_FREQ, PVST_FREQ, SOF_FREQ) - + freq_listening = list(WY_WO_FREQ, PMC_FREQ, DUT_FREQ, YAUT_FREQ, HC_FREQ, PVST_FREQ, SOF_FREQ, CBRN_FREQ) //Buses @@ -455,7 +468,7 @@ GLOBAL_LIST_EMPTY(all_static_telecomms_towers) /obj/structure/machinery/telecomms/bus/preset_three id = "Bus 3" network = "tcommsat" - freq_listening = list(SEC_FREQ, COMM_FREQ, WY_WO_FREQ, PMC_FREQ, DUT_FREQ, YAUT_FREQ, JTAC_FREQ, INTEL_FREQ, WY_FREQ, HC_FREQ, PVST_FREQ, SOF_FREQ) + freq_listening = list(SEC_FREQ, COMM_FREQ, WY_WO_FREQ, PMC_FREQ, DUT_FREQ, YAUT_FREQ, JTAC_FREQ, INTEL_FREQ, WY_FREQ, HC_FREQ, PVST_FREQ, SOF_FREQ, CBRN_FREQ) autolinkers = list("processor3", "security", "command", "JTAC") /obj/structure/machinery/telecomms/bus/preset_four @@ -471,7 +484,7 @@ GLOBAL_LIST_EMPTY(all_static_telecomms_towers) /obj/structure/machinery/telecomms/bus/preset_cent id = "CentComm Bus" network = "tcommsat" - freq_listening = list(WY_WO_FREQ, PMC_FREQ, DUT_FREQ, YAUT_FREQ, HC_FREQ, PVST_FREQ, SOF_FREQ) + freq_listening = list(WY_WO_FREQ, PMC_FREQ, DUT_FREQ, YAUT_FREQ, HC_FREQ, PVST_FREQ, SOF_FREQ, CBRN_FREQ) autolinkers = list("processorCent", "centcomm") //Processors @@ -536,7 +549,7 @@ GLOBAL_LIST_EMPTY(all_static_telecomms_towers) /obj/structure/machinery/telecomms/server/presets/command id = "Command Server" - freq_listening = list(COMM_FREQ, WY_WO_FREQ, PMC_FREQ, DUT_FREQ, YAUT_FREQ, JTAC_FREQ, INTEL_FREQ, WY_FREQ, HC_FREQ, PVST_FREQ, SOF_FREQ) + freq_listening = list(COMM_FREQ, WY_WO_FREQ, PMC_FREQ, DUT_FREQ, YAUT_FREQ, JTAC_FREQ, INTEL_FREQ, WY_FREQ, HC_FREQ, PVST_FREQ, SOF_FREQ, CBRN_FREQ) autolinkers = list("command") /obj/structure/machinery/telecomms/server/presets/engineering @@ -551,10 +564,9 @@ GLOBAL_LIST_EMPTY(all_static_telecomms_towers) /obj/structure/machinery/telecomms/server/presets/centcomm id = "CentComm Server" - freq_listening = list(WY_WO_FREQ, PMC_FREQ, DUT_FREQ, YAUT_FREQ, HC_FREQ, PVST_FREQ, SOF_FREQ) + freq_listening = list(WY_WO_FREQ, PMC_FREQ, DUT_FREQ, YAUT_FREQ, HC_FREQ, PVST_FREQ, SOF_FREQ, CBRN_FREQ) autolinkers = list("centcomm") - //Broadcasters //--PRESET LEFT--// diff --git a/code/game/machinery/telecomms/telecomunications.dm b/code/game/machinery/telecomms/telecomunications.dm index 255d70f45870..8b8b12dfd170 100644 --- a/code/game/machinery/telecomms/telecomunications.dm +++ b/code/game/machinery/telecomms/telecomunications.dm @@ -93,13 +93,13 @@ GLOBAL_LIST_EMPTY_TYPED(telecomms_list, /obj/structure/machinery/telecomms) update_state() /obj/structure/machinery/telecomms/emp_act(severity) + . = ..() if(prob(100/severity)) if(!(stat & EMPED)) stat |= EMPED var/duration = (300 * 10)/severity spawn(rand(duration - 20, duration + 20)) // Takes a long time for the machines to reboot. stat &= ~EMPED - ..() /* The receiver idles and receives messages from subspace-compatible radio equipment; diff --git a/code/game/machinery/vending/cm_vending.dm b/code/game/machinery/vending/cm_vending.dm index e201fed1e1ae..d34eeb8a0d4e 100644 --- a/code/game/machinery/vending/cm_vending.dm +++ b/code/game/machinery/vending/cm_vending.dm @@ -37,8 +37,14 @@ var/vend_delay = 0 //delaying vending of an item (for drinks machines animation, for example). Make sure to synchronize this with animation duration var/vend_sound //use with caution. Potential spam + /// X Offset to vend to var/vend_x_offset = 0 + /// Y Offset to vend to var/vend_y_offset = 0 + /// Vending direction from adjacent users, if not using vend_x_offset or vend_y_offset + var/vend_dir + /// Direction to adjacent user from which we're allowed to do offset vending + var/list/vend_dir_whitelist var/list/listed_products = list() @@ -125,11 +131,20 @@ GLOBAL_LIST_EMPTY(vending_products) GLOB.vending_products[typepath] = 1 //get which turf the vendor will dispense its products on. -/obj/structure/machinery/cm_vending/proc/get_appropriate_vend_turf() - var/turf/T = loc +/obj/structure/machinery/cm_vending/proc/get_appropriate_vend_turf(mob/living/carbon/human/user) + var/turf/turf = loc if(vend_x_offset != 0 || vend_y_offset != 0) //this check should be more less expensive than using locate to locate your own tile every vending. - T = locate(x + vend_x_offset, y + vend_y_offset, z) - return T + turf = locate(x + vend_x_offset, y + vend_y_offset, z) + return turf + if(vend_dir) + if(vend_dir_whitelist) + var/user_dir = get_dir(loc, user) + if(!(user_dir in vend_dir_whitelist)) + return get_turf(user) + var/turf/relative_turf = get_step(user, vend_dir) + if(relative_turf) + return relative_turf + return turf /obj/structure/machinery/cm_vending/get_examine_text(mob/living/carbon/human/user) . = ..() @@ -245,7 +260,7 @@ GLOBAL_LIST_EMPTY(vending_products) return //Machete holsters handling else if(istype(item_to_stock, /obj/item/storage/large_holster/machete)) - var/obj/item/weapon/claymore/mercsword/machete/mac = locate(/obj/item/weapon/claymore/mercsword/machete) in item_to_stock + var/obj/item/weapon/sword/machete/mac = locate(/obj/item/weapon/sword/machete) in item_to_stock if(!mac) if(user) to_chat(user, SPAN_WARNING("\The [item_to_stock] is empty.")) @@ -428,7 +443,44 @@ GLOBAL_LIST_EMPTY(vending_products) //------------TGUI PROCS--------------- /obj/structure/machinery/cm_vending/ui_data(mob/user) - return vendor_user_ui_data(src, user) + if(vend_flags & VEND_LIMITED_INVENTORY) + return vendor_inventory_ui_data(user) + + . = list() + var/list/ui_listed_products = get_listed_products(user) + // list format + // ( + // name: str + // cost + // item reference + // allowed to buy flag + // item priority (mandatory/recommended/regular) + // ) + + var/list/stock_values = list() + + var/mob/living/carbon/human/marine = user + var/points = 0 + + if(instanced_vendor_points) + points = available_points_to_display + else + if(use_snowflake_points) + points = marine.marine_snowflake_points + else if(use_points) + points = marine.marine_points + + for (var/i in 1 to length(ui_listed_products)) + var/list/myprod = ui_listed_products[i] //we take one list from listed_products + var/prod_available = FALSE + var/p_cost = myprod[2] + var/category = myprod[4] + if(points >= p_cost && (!category || ((category in marine.marine_buyable_categories) && (marine.marine_buyable_categories[category])))) + prod_available = TRUE + stock_values += list(prod_available) + + .["stock_listing"] = stock_values + .["current_m_points"] = points /obj/structure/machinery/cm_vending/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) . = ..() @@ -515,7 +567,7 @@ GLOBAL_LIST_EMPTY(vending_products) vend_fail() return FALSE - if(!handle_vend(src, itemspec, user)) + if(!handle_vend(itemspec, user)) to_chat(user, SPAN_WARNING("You can't buy things from this category anymore.")) vend_fail() return FALSE @@ -533,7 +585,7 @@ GLOBAL_LIST_EMPTY(vending_products) vend_fail() return TRUE // one left and the player spam click during a lagspike. - vendor_successful_vend(src, itemspec, user) + vendor_successful_vend(itemspec, user) return TRUE add_fingerprint(user) @@ -764,7 +816,7 @@ GLOBAL_LIST_EMPTY(vending_products) /obj/structure/machinery/cm_vending/gear/ui_static_data(mob/user) . = ..(user) .["vendor_type"] = "gear" - .["displayed_categories"] = vendor_user_inventory_list(src, user) + .["displayed_categories"] = vendor_user_inventory_list(user) //------------CLOTHING VENDORS--------------- //clothing vendors automatically put item on user. QoL at it's finest. @@ -774,14 +826,14 @@ GLOBAL_LIST_EMPTY(vending_products) desc = "An automated closet hooked up to a colossal storage of standard-issue uniform and armor." icon_state = "clothing" use_points = TRUE + show_points = TRUE vendor_theme = VENDOR_THEME_USCM - show_points = FALSE vend_flags = VEND_CLUTTER_PROTECTION | VEND_UNIFORM_RANKS | VEND_UNIFORM_AUTOEQUIP | VEND_CATEGORY_CHECK /obj/structure/machinery/cm_vending/clothing/ui_static_data(mob/user) . = ..(user) .["vendor_type"] = "clothing" - .["displayed_categories"] = vendor_user_inventory_list(src, user) + .["displayed_categories"] = vendor_user_inventory_list(user) //------------SORTED VENDORS--------------- //22.06.2019 Modified ex-"marine_selector" system that doesn't use points by Jeser. In theory, should replace all vendors. @@ -840,7 +892,7 @@ GLOBAL_LIST_EMPTY(vending_products) /obj/structure/machinery/cm_vending/sorted/ui_static_data(mob/user) . = ..(user) .["vendor_type"] = "sorted" - .["displayed_categories"] = vendor_user_inventory_list(src, user, null, 4) + .["displayed_categories"] = vendor_user_inventory_list(user, null, 4) /obj/structure/machinery/cm_vending/sorted/MouseDrop_T(atom/movable/A, mob/user) @@ -919,7 +971,7 @@ GLOBAL_LIST_EMPTY(vending_products) /obj/structure/machinery/cm_vending/own_points/ui_static_data(mob/user) . = ..(user) .["vendor_type"] = "gear" - .["displayed_categories"] = vendor_user_inventory_list(src, user) + .["displayed_categories"] = vendor_user_inventory_list(user) //------------ESSENTIALS SETS AND RANDOM GEAR SPAWNER--------------- @@ -1045,7 +1097,7 @@ GLOBAL_LIST_INIT(cm_vending_gear_corresponding_types_list, list( //---helper procs -/proc/vendor_user_inventory_list(vendor, mob/user, cost_index=2, priority_index=5) +/obj/structure/machinery/cm_vending/proc/vendor_user_inventory_list(mob/user, cost_index=2, priority_index=5) . = list() // default list format // ( @@ -1055,8 +1107,7 @@ GLOBAL_LIST_INIT(cm_vending_gear_corresponding_types_list, list( // allowed to buy flag // item priority (mandatory/recommended/regular) // ) - var/obj/structure/machinery/cm_vending/vending_machine = vendor - var/list/ui_listed_products = vending_machine.get_listed_products(user) + var/list/ui_listed_products = get_listed_products(user) for (var/i in 1 to length(ui_listed_products)) var/list/myprod = ui_listed_products[i] //we take one list from listed_products @@ -1098,10 +1149,9 @@ GLOBAL_LIST_INIT(cm_vending_gear_corresponding_types_list, list( var/last_category = .[last_index] last_category["items"] += list(display_item) -/proc/vendor_inventory_ui_data(vendor, mob/user) +/obj/structure/machinery/cm_vending/proc/vendor_inventory_ui_data(mob/user) . = list() - var/obj/structure/machinery/cm_vending/vending_machine = vendor - var/list/ui_listed_products = vending_machine.get_listed_products(user) + var/list/ui_listed_products = get_listed_products(user) var/list/ui_categories = list() for (var/i in 1 to length(ui_listed_products)) @@ -1110,95 +1160,52 @@ GLOBAL_LIST_INIT(cm_vending_gear_corresponding_types_list, list( ui_categories += list(p_amount) .["stock_listing"] = ui_categories -/proc/vendor_user_ui_data(obj/structure/machinery/cm_vending/vending_machine, mob/user) - if(vending_machine.vend_flags & VEND_LIMITED_INVENTORY) - return vendor_inventory_ui_data(vending_machine, user) - - . = list() - var/list/ui_listed_products = vending_machine.get_listed_products(user) - // list format - // ( - // name: str - // cost - // item reference - // allowed to buy flag - // item priority (mandatory/recommended/regular) - // ) - - var/list/stock_values = list() - - var/mob/living/carbon/human/marine = user - var/points = 0 - - if(vending_machine.instanced_vendor_points) - points = vending_machine.available_points_to_display - else - if(vending_machine.use_snowflake_points) - points = marine.marine_snowflake_points - else if(vending_machine.use_points) - points = marine.marine_points - - for (var/i in 1 to length(ui_listed_products)) - var/list/myprod = ui_listed_products[i] //we take one list from listed_products - var/prod_available = FALSE - var/p_cost = myprod[2] - var/category = myprod[4] - if(points >= p_cost && (!category || ((category in marine.marine_buyable_categories) && (marine.marine_buyable_categories[category])))) - prod_available = TRUE - stock_values += list(prod_available) - - .["stock_listing"] = stock_values - .["current_m_points"] = points - -/proc/vendor_successful_vend(obj/structure/machinery/cm_vending/vendor, list/itemspec, mob/living/carbon/human/user) - if(vendor.stat & IN_USE) +/obj/structure/machinery/cm_vending/proc/vendor_successful_vend(list/itemspec, mob/living/carbon/human/user) + if(stat & IN_USE) return - vendor.stat |= IN_USE - - var/vend_flags = vendor.vend_flags - var/turf/target_turf = vendor.get_appropriate_vend_turf(user) + stat |= IN_USE + var/turf/target_turf = get_appropriate_vend_turf(user) if(LAZYLEN(itemspec)) //making sure it's not empty - if(vendor.vend_delay) - vendor.overlays.Cut() - vendor.icon_state = "[initial(vendor.icon_state)]_vend" - if(vendor.vend_sound) - playsound(vendor.loc, vendor.vend_sound, 25, 1, 2) //heard only near vendor - sleep(vendor.vend_delay) + if(vend_delay) + overlays.Cut() + icon_state = "[initial(icon_state)]_vend" + if(vend_sound) + playsound(loc, vend_sound, 25, 1, 2) //heard only near vendor + sleep(vend_delay) var/prod_type = itemspec[3] if(islist(prod_type)) for(var/each_type in prod_type) - vendor_successful_vend_one(vendor, each_type, user, target_turf, itemspec[4] == MARINE_CAN_BUY_UNIFORM) + vendor_successful_vend_one(each_type, user, target_turf, itemspec[4] == MARINE_CAN_BUY_UNIFORM) SEND_SIGNAL(vendor, COMSIG_VENDOR_SUCCESSFUL_VEND, vendor, itemspec, user) else - vendor_successful_vend_one(vendor, prod_type, user, target_turf, itemspec[4] == MARINE_CAN_BUY_UNIFORM) + vendor_successful_vend_one(prod_type, user, target_turf, itemspec[4] == MARINE_CAN_BUY_UNIFORM) SEND_SIGNAL(vendor, COMSIG_VENDOR_SUCCESSFUL_VEND, vendor, itemspec, user) if(vend_flags & VEND_LIMITED_INVENTORY) itemspec[2]-- if(vend_flags & VEND_LOAD_AMMO_BOXES) - vendor.update_derived_ammo_and_boxes(itemspec) + update_derived_ammo_and_boxes(itemspec) else to_chat(user, SPAN_WARNING("ERROR: itemspec is missing. Please report this to admins.")) sleep(15) - vendor.stat &= ~IN_USE - vendor.icon_state = initial(vendor.icon_state) - vendor.update_icon() + stat &= ~IN_USE + icon_state = initial(icon_state) + update_icon() -/proc/vendor_successful_vend_one(obj/structure/machinery/cm_vending/vendor, prod_type, mob/living/carbon/human/user, turf/target_turf, insignas_override) +/obj/structure/machinery/cm_vending/proc/vendor_successful_vend_one(prod_type, mob/living/carbon/human/user, turf/target_turf, insignas_override) var/obj/item/new_item - var/vend_flags = vendor.vend_flags if(ispath(prod_type, /obj/item)) if(ispath(prod_type, /obj/item/weapon/gun)) new_item = new prod_type(target_turf, TRUE) else if(prod_type == /obj/item/device/radio/headset/almayer/marine) - prod_type = vendor.headset_type + prod_type = headset_type else if(prod_type == /obj/item/clothing/gloves/marine) - prod_type = vendor.gloves_type + prod_type = gloves_type new_item = new prod_type(target_turf) new_item.add_fingerprint(user) else @@ -1227,13 +1234,13 @@ GLOBAL_LIST_INIT(cm_vending_gear_corresponding_types_list, list( if(vend_flags & VEND_TO_HAND) if(user.client?.prefs && (user.client?.prefs?.toggle_prefs & TOGGLE_VEND_ITEM_TO_HAND)) - if(vendor.Adjacent(user)) + if(Adjacent(user)) user.put_in_any_hand_if_possible(new_item, disable_warning = TRUE) new_item.post_vendor_spawn_hook(user) -/proc/handle_vend(obj/structure/machinery/cm_vending/vendor, list/listed_products, mob/living/carbon/human/vending_human) - if(vendor.vend_flags & VEND_USE_VENDOR_FLAGS) +/obj/structure/machinery/cm_vending/proc/handle_vend(list/listed_products, mob/living/carbon/human/vending_human) + if(vend_flags & VEND_USE_VENDOR_FLAGS) return TRUE var/buying_category = listed_products[4] if(buying_category) @@ -1269,62 +1276,3 @@ GLOBAL_LIST_INIT(cm_vending_gear_corresponding_types_list, list( stat &= ~IN_USE if(destroy) qdel(src) - -//------------HACKING--------------- - -//Hacking code from old vendors, in case someone will actually would like to add complex hacking in future. For now, simple access hacking I believe sufficient. -/* -/obj/structure/machinery/vending/proc/get_wire_descriptions() - return list( - VENDING_WIRE_EXTEND = "Inventory control computer", - VENDING_WIRE_IDSCAN = "ID scanner", - VENDING_WIRE_SHOCK = "Ground safety", - VENDING_WIRE_SHOOT_INV = "Dispenser motor control" - ) - -/obj/structure/machinery/vending/proc/isWireCut(wire) - return !(wires & getWireFlag(wire)) - -/obj/structure/machinery/vending/proc/cut(wire) - wires ^= getWireFlag(wire) - - switch(wire) - if(VENDING_WIRE_EXTEND) - src.extended_inventory = 0 - visible_message(SPAN_NOTICE("A weak yellow light turns off underneath \the [src].")) - if(VENDING_WIRE_SHOCK) - src.seconds_electrified = -1 - visible_message(SPAN_DANGER("Electric arcs shoot off from \the [src]!")) - if (VENDING_WIRE_SHOOT_INV) - if(!src.shoot_inventory) - src.shoot_inventory = TRUE - visible_message(SPAN_WARNING("\The [src] begins whirring noisily.")) - -/obj/structure/machinery/vending/proc/mend(wire) - wires |= getWireFlag(wire) - - switch(wire) - if(VENDING_WIRE_EXTEND) - src.extended_inventory = 1 - visible_message(SPAN_NOTICE("A weak yellow light turns on underneath \the [src].")) - if(VENDING_WIRE_SHOCK) - src.seconds_electrified = 0 - if (VENDING_WIRE_SHOOT_INV) - src.shoot_inventory = FALSE - visible_message(SPAN_NOTICE("\The [src] stops whirring.")) - -/obj/structure/machinery/vending/proc/pulse(wire) - switch(wire) - if(VENDING_WIRE_EXTEND) - src.extended_inventory = !src.extended_inventory - visible_message(SPAN_NOTICE("A weak yellow light turns [extended_inventory ? "on" : "off"] underneath \the [src].")) - if (VENDING_WIRE_SHOCK) - src.seconds_electrified = 30 - visible_message(SPAN_DANGER("Electric arcs shoot off from \the [src]!")) - if (VENDING_WIRE_SHOOT_INV) - src.shoot_inventory = !src.shoot_inventory - if(shoot_inventory) - visible_message(SPAN_WARNING("\The [src] begins whirring noisily.")) - else - visible_message(SPAN_NOTICE("\The [src] stops whirring.")) -*/ diff --git a/code/game/machinery/vending/vending.dm b/code/game/machinery/vending/vending.dm index a74dd923cbe7..414ab4a562e1 100644 --- a/code/game/machinery/vending/vending.dm +++ b/code/game/machinery/vending/vending.dm @@ -398,28 +398,25 @@ GLOBAL_LIST_EMPTY_TYPED(total_vending_machines, /obj/structure/machinery/vending /obj/structure/machinery/vending/proc/GetProductIndex(datum/data/vending_product/product) var/list/plist - switch(product.category) - if(CAT_NORMAL) - plist=product_records - if(CAT_HIDDEN) - plist=hidden_records - if(CAT_COIN) - plist=coin_records - else - warning("UNKNOWN CATEGORY [product.category] IN TYPE [product.product_path] INSIDE [type]!") + if(product.category == CAT_NORMAL) + plist = product_records + else if(product.category == CAT_HIDDEN) + plist = hidden_records + else if(product.category == CAT_COIN) + plist = coin_records + else + warning("UNKNOWN CATEGORY [product.category] IN TYPE [product.product_path] INSIDE [type]!") return plist.Find(product) /obj/structure/machinery/vending/proc/GetProductByID(pid, category) - switch(category) - if(CAT_NORMAL) - return product_records[pid] - if(CAT_HIDDEN) - return hidden_records[pid] - if(CAT_COIN) - return coin_records[pid] - else - warning("UNKNOWN PRODUCT: PID: [pid], CAT: [category] INSIDE [type]!") - return null + if(category == CAT_NORMAL) + return product_records[pid] + else if(category == CAT_HIDDEN) + return hidden_records[pid] + else if(category == CAT_COIN) + return coin_records[pid] + else + warning("UNKNOWN PRODUCT: PID: [pid], CAT: [category] INSIDE [type]!") /obj/structure/machinery/vending/attack_hand(mob/user) if(is_tipped_over) diff --git a/code/game/machinery/vending/vending_types.dm b/code/game/machinery/vending/vending_types.dm index a61934324491..a57bbfe7d29f 100644 --- a/code/game/machinery/vending/vending_types.dm +++ b/code/game/machinery/vending/vending_types.dm @@ -411,6 +411,13 @@ /obj/item/device/camera = 5, /obj/item/device/camera_film = 10, /obj/item/notepad = 5, + /obj/item/device/toner = 5, + /obj/item/paper/colonial_grunts = 15, + /obj/item/toy/dice/d20 = 10, + /obj/item/tool/pen = 10, + /obj/item/tool/pen/blue = 10, + /obj/item/tool/pen/red = 10, + /obj/item/tool/pen/fountain = 3, ) contraband = list(/obj/item/toy/sword = 2) @@ -431,5 +438,12 @@ /obj/item/toy/deck = 20, /obj/item/toy/deck/uno = 15, /obj/item/device/camera = 30, + /obj/item/device/toner = 15, + /obj/item/paper/colonial_grunts = 5, + /obj/item/toy/dice/d20 = 1, + /obj/item/tool/pen = 2, + /obj/item/tool/pen/blue = 2, + /obj/item/tool/pen/red = 2, + /obj/item/tool/pen/fountain = 30, ) product_type = VENDOR_PRODUCT_TYPE_RECREATIONAL diff --git a/code/game/machinery/vending/vendor_types/crew/commanding_officer.dm b/code/game/machinery/vending/vendor_types/crew/commanding_officer.dm index 830511ad4b19..d7d49a8ae044 100644 --- a/code/game/machinery/vending/vendor_types/crew/commanding_officer.dm +++ b/code/game/machinery/vending/vendor_types/crew/commanding_officer.dm @@ -1,9 +1,9 @@ //------------GEAR VENDOR--------------- GLOBAL_LIST_INIT(cm_vending_gear_commanding_officer, list( - list("COMMANDING OFFICER'S PRIMARY (CHOOSE 1)", 0, null, null, null), - list("M46C pulse rifle", 0, /obj/effect/essentials_set/co/riflepreset, MARINE_CAN_BUY_ESSENTIALS, VENDOR_ITEM_MANDATORY), - list("M56C Smartgun", 0, /obj/item/storage/box/m56c_system, MARINE_CAN_BUY_ESSENTIALS, VENDOR_ITEM_MANDATORY), + list("COMMANDER'S PRIMARY (CHOOSE 1)", 0, null, null, null), + list("M46C Pulse Rifle", 0, /obj/effect/essentials_set/co/riflepreset, MARINE_CAN_BUY_SECONDARY, VENDOR_ITEM_MANDATORY), + list("M56C Smartgun", 0, /obj/item/storage/box/m56c_system, MARINE_CAN_BUY_SECONDARY, VENDOR_ITEM_MANDATORY), list("PRIMARY AMMUNITION", 0, null, null, null), list("M41A MK1 Magazine", 30, /obj/item/ammo_magazine/rifle/m41aMK1, null, VENDOR_ITEM_RECOMMENDED), @@ -28,11 +28,19 @@ GLOBAL_LIST_INIT(cm_vending_gear_commanding_officer, list( list("M41A Rubber Shot Magazine", 10, /obj/item/ammo_magazine/rifle/rubber, null, VENDOR_ITEM_REGULAR), list("Beanbag Slugs", 10, /obj/item/ammo_magazine/shotgun/beanbag, null, VENDOR_ITEM_REGULAR), + list("EXPLOSIVES", 0, null, null, null), + list("HEDP Grenade Pack", 15, /obj/item/storage/box/packet/high_explosive, null, VENDOR_ITEM_REGULAR), + list("HEFA Grenade Pack", 15, /obj/item/storage/box/packet/hefa, null, VENDOR_ITEM_REGULAR), + list("WP Grenade Pack", 15, /obj/item/storage/box/packet/phosphorus, null, VENDOR_ITEM_REGULAR), + list("RAIL ATTACHMENTS", 0, null, null, null), list("Red-Dot Sight", 15, /obj/item/attachable/reddot, null, VENDOR_ITEM_REGULAR), list("Reflex Sight", 15, /obj/item/attachable/reflex, null, VENDOR_ITEM_REGULAR), list("S4 2x Telescopic Mini-Scope", 15, /obj/item/attachable/scope/mini, null, VENDOR_ITEM_REGULAR), + list("Helmet Visors", 0, null, null, null), + list("Welding Visor", 5, /obj/item/device/helmet_visor/welding_visor, null, VENDOR_ITEM_RECOMMENDED), + list("UNDERBARREL ATTACHMENTS", 0, null, null, null), list("Laser Sight", 15, /obj/item/attachable/lasersight, null, VENDOR_ITEM_REGULAR), list("Angled Grip", 15, /obj/item/attachable/angledgrip, null, VENDOR_ITEM_REGULAR), @@ -40,12 +48,13 @@ GLOBAL_LIST_INIT(cm_vending_gear_commanding_officer, list( list("Underbarrel Shotgun", 15, /obj/item/attachable/attached_gun/shotgun, null, VENDOR_ITEM_REGULAR), list("Underbarrel Extinguisher", 15, /obj/item/attachable/attached_gun/extinguisher, null, VENDOR_ITEM_REGULAR), list("Underbarrel Flamethrower", 15, /obj/item/attachable/attached_gun/flamer, null, VENDOR_ITEM_REGULAR), + list("Underbarrel Grenade Launcher", 5, /obj/item/attachable/attached_gun/grenade, null, VENDOR_ITEM_REGULAR), list("BARREL ATTACHMENTS", 0, null, null, null), - list("Suppressor", 15, /obj/item/attachable/suppressor, null, VENDOR_ITEM_REGULAR), list("Extended Barrel", 15, /obj/item/attachable/extended_barrel, null, VENDOR_ITEM_REGULAR), list("Recoil Compensator", 15, /obj/item/attachable/compensator, null, VENDOR_ITEM_REGULAR), - )) + list("Suppressor", 15, /obj/item/attachable/suppressor, null, VENDOR_ITEM_REGULAR), + )) /obj/structure/machinery/cm_vending/gear/commanding_officer name = "\improper ColMarTech Commanding Officer Weapon Rack" @@ -63,9 +72,15 @@ GLOBAL_LIST_INIT(cm_vending_gear_commanding_officer, list( GLOBAL_LIST_INIT(cm_vending_clothing_commanding_officer, list( list("STANDARD EQUIPMENT (TAKE ALL)", 0, null, null, null), list("Headset", 0, /obj/item/device/radio/headset/almayer/mcom/cdrcom, MARINE_CAN_BUY_EAR, VENDOR_ITEM_MANDATORY), - list("Satchel", 0, /obj/item/storage/backpack/satchel/lockable, MARINE_CAN_BUY_BACKPACK, VENDOR_ITEM_MANDATORY), list("MRE", 0, /obj/item/storage/box/MRE, MARINE_CAN_BUY_MRE, VENDOR_ITEM_MANDATORY), + list("COMMANDING OFFICER ESSENTIALS KIT (TAKE ALL)", 0, null, null, null), + list("Commanding Officer Essentials Kit", 0, /obj/effect/essentials_set/commanding_officer, MARINE_CAN_BUY_ESSENTIALS, VENDOR_ITEM_MANDATORY), + + list("BAGS (CHOOSE 1)", 0, null, null, null), + list("Commanding Officer Backpack", 0, /obj/item/storage/backpack/mcommander, MARINE_CAN_BUY_BACKPACK, VENDOR_ITEM_MANDATORY), + list("Secure Satchel", 0, /obj/item/storage/backpack/satchel/lockable, MARINE_CAN_BUY_BACKPACK, VENDOR_ITEM_MANDATORY), + list("COMBAT EQUIPMENT (TAKE ALL)", 0, null, null, null), list("Commanding Officer's M3 Armor", 0, /obj/item/clothing/suit/storage/marine/MP/CO, MARINE_CAN_BUY_ARMOR, VENDOR_ITEM_MANDATORY), list("Commanding Officer's M10 Helmet", 0, /obj/item/clothing/head/helmet/marine/CO, MARINE_CAN_BUY_HELMET, VENDOR_ITEM_MANDATORY), @@ -84,8 +99,13 @@ GLOBAL_LIST_INIT(cm_vending_clothing_commanding_officer, list( list("Medical HUD Glasses", 0, /obj/item/clothing/glasses/hud/health, MARINE_CAN_BUY_GLASSES, VENDOR_ITEM_RECOMMENDED), list("Security HUD Glasses", 0, /obj/item/clothing/glasses/sunglasses/sechud, MARINE_CAN_BUY_GLASSES, VENDOR_ITEM_REGULAR), - list("BELTS (TAKE ALL)", 0, null, null, null), + list("BELTS (CHOOSE 1)", 0, null, null, null), list("G8-A General Utility Pouch", 0, /obj/item/storage/backpack/general_belt, MARINE_CAN_BUY_BELT, VENDOR_ITEM_RECOMMENDED), + list("Military Police Belt", 0, /obj/item/storage/belt/security/MP/full, MARINE_CAN_BUY_BELT, VENDOR_ITEM_RECOMMENDED), + list("M276 Medical Storage Rig", 0, /obj/item/storage/belt/medical/full, MARINE_CAN_BUY_BELT, VENDOR_ITEM_RECOMMENDED), + list("M276 Ammo Load Rig", 0, /obj/item/storage/belt/marine, MARINE_CAN_BUY_BELT, VENDOR_ITEM_RECOMMENDED), + list("M276 Holster Toolrig", 0, /obj/item/storage/belt/gun/utility/full, MARINE_CAN_BUY_BELT, VENDOR_ITEM_RECOMMENDED), + list("M276 M82F Holster Rig", 0, /obj/item/storage/belt/gun/flaregun, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), list("POUCHES (CHOOSE 2)", 0, null, null, null), list("First-Aid Pouch (Refillable Injectors)", 0, /obj/item/storage/pouch/firstaid/full, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), @@ -110,6 +130,15 @@ GLOBAL_LIST_INIT(cm_vending_clothing_commanding_officer, list( /obj/structure/machinery/cm_vending/clothing/commanding_officer/get_listed_products(mob/user) return GLOB.cm_vending_clothing_commanding_officer +/obj/effect/essentials_set/commanding_officer + spawned_gear_list = list( + /obj/item/device/binoculars/range/designator, + /obj/item/map/current_map, + /obj/item/device/whistle, + /obj/item/weapon/gun/energy/taser, + /obj/item/device/megaphone, + ) + // This gets around the COs' weapon not spawning without incendiary mag. /obj/effect/essentials_set/co/riflepreset spawned_gear_list = list( diff --git a/code/game/machinery/vending/vendor_types/crew/sea.dm b/code/game/machinery/vending/vendor_types/crew/sea.dm index 0da9181beb97..cb6698c6f714 100644 --- a/code/game/machinery/vending/vendor_types/crew/sea.dm +++ b/code/game/machinery/vending/vendor_types/crew/sea.dm @@ -56,6 +56,7 @@ GLOBAL_LIST_INIT(cm_vending_clothing_sea, list( list("M3-L Pattern Light Armor", 0, /obj/item/clothing/suit/storage/marine/light, MARINE_CAN_BUY_ARMOR, VENDOR_ITEM_RECOMMENDED), list("M3 Pattern Padded Armor", 0, /obj/item/clothing/suit/storage/marine/padded, MARINE_CAN_BUY_ARMOR, VENDOR_ITEM_REGULAR), list("Bulletproof Vest", 0, /obj/item/clothing/suit/armor/bulletproof, MARINE_CAN_BUY_ARMOR, VENDOR_ITEM_REGULAR), + list("USCM Service Jacket", 0, /obj/item/clothing/suit/storage/jacket/marine/service, MARINE_CAN_BUY_ARMOR, VENDOR_ITEM_REGULAR), list("ACCESSORIES (CHOOSE 1)", 0, null, null, null), list("Brown Webbing Vest", 0, /obj/item/clothing/accessory/storage/black_vest/brown_vest, MARINE_CAN_BUY_ACCESSORY, VENDOR_ITEM_REGULAR), diff --git a/code/game/machinery/vending/vendor_types/crew/senior_officers.dm b/code/game/machinery/vending/vendor_types/crew/senior_officers.dm index 88a3647777d4..56eeb2b8a6d8 100644 --- a/code/game/machinery/vending/vendor_types/crew/senior_officers.dm +++ b/code/game/machinery/vending/vendor_types/crew/senior_officers.dm @@ -284,7 +284,6 @@ GLOBAL_LIST_INIT(cm_vending_clothing_xo, list( list("M4A3 Service Pistol", 0, /obj/item/storage/belt/gun/m4a3/commander, MARINE_CAN_BUY_SECONDARY, VENDOR_ITEM_REGULAR), list("Mod 88 Pistol", 0, /obj/item/storage/belt/gun/m4a3/mod88, MARINE_CAN_BUY_SECONDARY, VENDOR_ITEM_REGULAR), list("M44 Revolver", 0, /obj/item/storage/belt/gun/m44/mp, MARINE_CAN_BUY_SECONDARY, VENDOR_ITEM_REGULAR), - list("Ceremonial Sword", 0, /obj/item/storage/large_holster/ceremonial_sword/full, MARINE_CAN_BUY_SECONDARY, VENDOR_ITEM_REGULAR), list("COMBAT EQUIPMENT (TAKE ALL)", 0, null, null, null), list("Officer M3 Armor", 0, /obj/item/clothing/suit/storage/marine/MP/SO, MARINE_CAN_BUY_ARMOR, VENDOR_ITEM_MANDATORY), diff --git a/code/game/machinery/vending/vendor_types/crew/staff_officer.dm b/code/game/machinery/vending/vendor_types/crew/staff_officer.dm index 85a8a58d162e..50b83ccdc54f 100644 --- a/code/game/machinery/vending/vendor_types/crew/staff_officer.dm +++ b/code/game/machinery/vending/vendor_types/crew/staff_officer.dm @@ -13,13 +13,13 @@ GLOBAL_LIST_INIT(cm_vending_clothing_staff_officer, list( list("STANDARD EQUIPMENT (TAKE ALL)", 0, null, null, null), list("Boots", 0, /obj/item/clothing/shoes/marine/knife, MARINE_CAN_BUY_SHOES, VENDOR_ITEM_MANDATORY), list("Headset", 0, /obj/item/device/radio/headset/almayer/mcom, MARINE_CAN_BUY_EAR, VENDOR_ITEM_MANDATORY), - list("Helmet", 0, /obj/item/clothing/head/helmet/marine/MP/SO, MARINE_CAN_BUY_HELMET, VENDOR_ITEM_MANDATORY), list("MRE", 0, /obj/item/storage/box/MRE, MARINE_CAN_BUY_MRE, VENDOR_ITEM_MANDATORY), list("STANDARD EQUIPMENT (TAKE ALL)", 0, null, null, null), list("Service Uniform", 0, /obj/item/clothing/under/marine/officer/bridge, MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_REGULAR), list("Operations Uniform", 0, /obj/item/clothing/under/marine/officer/boiler, MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_RECOMMENDED), + list("Gloves", 0, /obj/item/clothing/gloves/marine, MARINE_CAN_BUY_GLOVES, VENDOR_ITEM_REGULAR), list("JACKET (CHOOSE 1)", 0, null, null, null), list("Service Jacket", 0, /obj/item/clothing/suit/storage/jacket/marine/service, MARINE_CAN_BUY_ARMOR, VENDOR_ITEM_RECOMMENDED), @@ -33,66 +33,21 @@ GLOBAL_LIST_INIT(cm_vending_clothing_staff_officer, list( list("PERSONAL SIDEARM (CHOOSE 1)", 0, null, null, null), - list("M44 Revolver", 0, /obj/item/storage/belt/gun/m44/mp, MARINE_CAN_BUY_BELT, VENDOR_ITEM_RECOMMENDED), - list("M4A3 Pistol", 0, /obj/item/storage/belt/gun/m4a3/commander, MARINE_CAN_BUY_BELT, VENDOR_ITEM_RECOMMENDED), - list("VP78 Pistol", 0, /obj/item/storage/belt/gun/m4a3/vp78, MARINE_CAN_BUY_BELT, VENDOR_ITEM_RECOMMENDED), + list("M44 Revolver", 0, /obj/item/storage/belt/gun/m44/mp, MARINE_CAN_BUY_SECONDARY, VENDOR_ITEM_RECOMMENDED), + list("M4A3 Pistol", 0, /obj/item/storage/belt/gun/m4a3/commander, MARINE_CAN_BUY_SECONDARY, VENDOR_ITEM_RECOMMENDED), + list("VP78 Pistol", 0, /obj/item/storage/belt/gun/m4a3/vp78, MARINE_CAN_BUY_SECONDARY, VENDOR_ITEM_RECOMMENDED), list("BACKPACK (CHOOSE 1)", 0, null, null, null), list("Backpack", 0, /obj/item/storage/backpack/marine, MARINE_CAN_BUY_BACKPACK, VENDOR_ITEM_REGULAR), list("Satchel", 0, /obj/item/storage/backpack/marine/satchel, MARINE_CAN_BUY_BACKPACK, VENDOR_ITEM_REGULAR), - list("Radio Telephone Pack", 0, /obj/item/storage/backpack/marine/satchel/rto, MARINE_CAN_BUY_BACKPACK, VENDOR_ITEM_RECOMMENDED), - list("BELT (CHOOSE 1)", 0, null, null, null), - list("G8-A General Utility Pouch", 0, /obj/item/storage/backpack/general_belt, MARINE_CAN_BUY_BELT, VENDOR_ITEM_RECOMMENDED), - list("M276 Ammo Load Rig", 0, /obj/item/storage/belt/marine, MARINE_CAN_BUY_BELT, VENDOR_ITEM_RECOMMENDED), - list("M276 Lifesaver Bag (Full)", 0, /obj/item/storage/belt/medical/lifesaver/full, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), - list("M276 Medical Storage Rig (Full)", 0, /obj/item/storage/belt/medical/full, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), - list("M276 M39 Holster Rig", 0, /obj/item/storage/belt/gun/m39, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), - list("M276 M82F Holster Rig", 0, /obj/item/storage/belt/gun/flaregun, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), - list("M276 Shotgun Shell Loading Rig", 0, /obj/item/storage/belt/shotgun, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), - list("M276 M40 Grenade Rig", 0, /obj/item/storage/belt/grenade, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), - - list("POUCHES (CHOOSE 2)", 0, null, null, null), - list("Autoinjector Pouch", 0, /obj/item/storage/pouch/autoinjector, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), - list("Construction Pouch", 0, /obj/item/storage/pouch/construction, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), - list("Document Pouch", 0, /obj/item/storage/pouch/document, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), - list("Electronics Pouch (Full)", 0, /obj/item/storage/pouch/electronics/full, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), - list("First-Aid Pouch (Refillable Injectors)", 0, /obj/item/storage/pouch/firstaid/full, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), - list("First-Aid Pouch (Splints, Gauze, Ointment)", 0, /obj/item/storage/pouch/firstaid/full/alternate, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), - list("First-Aid Pouch (Pill Packets)", 0, /obj/item/storage/pouch/firstaid/full/pills, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), - list("First Responder Pouch", 0, /obj/item/storage/pouch/first_responder, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), - list("Flare Pouch (Full)", 0, /obj/item/storage/pouch/flare/full, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), - list("Fuel Tank Strap Pouch", 0, /obj/item/storage/pouch/flamertank, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), - list("Large General Pouch", 0, /obj/item/storage/pouch/general/large, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), - list("Large Magazine Pouch", 0, /obj/item/storage/pouch/magazine/large, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), - list("Large Shotgun Shell Pouch", 0, /obj/item/storage/pouch/shotgun/large, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), - list("Large Pistol Magazine Pouch", 0, /obj/item/storage/pouch/magazine/pistol/large, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), - list("Medical Pouch", 0, /obj/item/storage/pouch/medical, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), - list("Medical Kit Pouch", 0, /obj/item/storage/pouch/medkit, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), - list("Pistol Pouch", 0, /obj/item/storage/pouch/pistol, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), - list("Sling Pouch", 0, /obj/item/storage/pouch/sling, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), - list("Tools Pouch (Full)", 0, /obj/item/storage/pouch/tools/full, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), - - list("ACCESSORIES (CHOOSE 1)", 0, null, null, null), - list("Black Webbing Vest", 0, /obj/item/clothing/accessory/storage/black_vest, MARINE_CAN_BUY_ACCESSORY, VENDOR_ITEM_REGULAR), - list("Brown Webbing Vest", 0, /obj/item/clothing/accessory/storage/black_vest/brown_vest, MARINE_CAN_BUY_ACCESSORY, VENDOR_ITEM_RECOMMENDED), - list("Drop Pouch", 0, /obj/item/clothing/accessory/storage/droppouch, MARINE_CAN_BUY_ACCESSORY, VENDOR_ITEM_REGULAR), - list("Webbing", 0, /obj/item/clothing/accessory/storage/webbing, MARINE_CAN_BUY_ACCESSORY, VENDOR_ITEM_REGULAR), - list("Shoulder Holster", 0, /obj/item/clothing/accessory/storage/holster, MARINE_CAN_BUY_ACCESSORY, VENDOR_ITEM_REGULAR), - - list("MASK (CHOOSE 1)", 0, null, null, null), - list("Gas Mask", 0, /obj/item/clothing/mask/gas, MARINE_CAN_BUY_MASK, VENDOR_ITEM_REGULAR), - list("Heat Absorbent Coif", 0, /obj/item/clothing/mask/rebreather/scarf, MARINE_CAN_BUY_MASK, VENDOR_ITEM_REGULAR), list("OTHER SUPPLIES", 0, null, null, null), list("Binoculars", 5,/obj/item/device/binoculars, null, VENDOR_ITEM_REGULAR), list("Rangefinder", 8, /obj/item/device/binoculars/range, null, VENDOR_ITEM_REGULAR), list("Laser Designator", 12, /obj/item/device/binoculars/range/designator, null, VENDOR_ITEM_RECOMMENDED), - list("Data Detector", 5, /obj/item/device/motiondetector/intel, null, VENDOR_ITEM_REGULAR), list("Flashlight", 1, /obj/item/device/flashlight, null, VENDOR_ITEM_RECOMMENDED), - list("Fulton Recovery Device", 5, /obj/item/stack/fulton, null, VENDOR_ITEM_REGULAR), - list("Motion Detector", 5, /obj/item/device/motiondetector, null, VENDOR_ITEM_REGULAR), + list("Motion Detector", 5, /obj/item/device/motiondetector, null, VENDOR_ITEM_RECOMMENDED), list("Space Cleaner", 2, /obj/item/reagent_container/spray/cleaner, null, VENDOR_ITEM_REGULAR), list("Whistle", 5, /obj/item/device/whistle, null, VENDOR_ITEM_REGULAR), - list("Machete Scabbard (Full)", 2, /obj/item/storage/large_holster/machete/full, null, VENDOR_ITEM_REGULAR) )) diff --git a/code/game/machinery/vending/vendor_types/crew/staff_officer_armory.dm b/code/game/machinery/vending/vendor_types/crew/staff_officer_armory.dm new file mode 100644 index 000000000000..ac7b22b4e0a0 --- /dev/null +++ b/code/game/machinery/vending/vendor_types/crew/staff_officer_armory.dm @@ -0,0 +1,83 @@ +/obj/structure/machinery/cm_vending/clothing/staff_officer_armory + name = "\improper ColMarTech Staff Officer Armory Equipment Rack" + desc = "An automated combat equipment vendor for Staff Officers." + req_access = list(ACCESS_MARINE_COMMAND) + icon_state = "mar_rack" + vendor_role = list(JOB_SO) + +/obj/structure/machinery/cm_vending/clothing/staff_officer_armory/get_listed_products(mob/user) + return GLOB.cm_vending_clothing_staff_officer_armory + +//------------GEAR--------------- + +GLOBAL_LIST_INIT(cm_vending_clothing_staff_officer_armory, list( + list("COMBAT EQUIPMENT (TAKE ALL)", 0, null, null, null), + list("Officer M3 Armor", 0, /obj/item/clothing/suit/storage/marine/MP/SO, MARINE_CAN_BUY_COMBAT_ARMOR, VENDOR_ITEM_MANDATORY), + list("Officer M10 Helmet", 0, /obj/item/clothing/head/helmet/marine/MP/SO, MARINE_CAN_BUY_COMBAT_HELMET, VENDOR_ITEM_MANDATORY), + list("Marine Combat Boots", 0, /obj/item/clothing/shoes/marine/knife, MARINE_CAN_BUY_SHOES, VENDOR_ITEM_MANDATORY), + list("Marine Combat Gloves", 0, /obj/item/clothing/gloves/marine, MARINE_CAN_BUY_GLOVES, VENDOR_ITEM_MANDATORY), + list("MRE", 0, /obj/item/storage/box/MRE, MARINE_CAN_BUY_MRE, VENDOR_ITEM_MANDATORY), + list("Aviator Shades", 0, /obj/item/clothing/glasses/sunglasses/aviator, MARINE_CAN_BUY_GLASSES, VENDOR_ITEM_REGULAR), + + list("SPECIALISATION KIT (CHOOSE 1)", 0, null, null, null), + list("Essential Engineer Set", 0, /obj/effect/essentials_set/engi, MARINE_CAN_BUY_ESSENTIALS, VENDOR_ITEM_RECOMMENDED), + list("Essential Medical Set", 0, /obj/effect/essentials_set/medic, MARINE_CAN_BUY_ESSENTIALS, VENDOR_ITEM_RECOMMENDED), + + list("BELT (CHOOSE 1)", 0, null, null, null), + list("G8-A General Utility Pouch", 0, /obj/item/storage/backpack/general_belt, MARINE_CAN_BUY_BELT, VENDOR_ITEM_RECOMMENDED), + list("M276 Ammo Load Rig", 0, /obj/item/storage/belt/marine, MARINE_CAN_BUY_BELT, VENDOR_ITEM_RECOMMENDED), + list("M276 Toolbelt Rig (Full)", 0, /obj/item/storage/belt/utility/full, MARINE_CAN_BUY_BELT, VENDOR_ITEM_RECOMMENDED), + list("M276 Lifesaver Bag (Full)", 0, /obj/item/storage/belt/medical/lifesaver/full, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), + list("M276 Medical Storage Rig (Full)", 0, /obj/item/storage/belt/medical/full, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), + list("M276 M39 Holster Rig", 0, /obj/item/storage/belt/gun/m39, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), + list("M276 M82F Holster Rig", 0, /obj/item/storage/belt/gun/flaregun, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), + list("M276 Shotgun Shell Loading Rig", 0, /obj/item/storage/belt/shotgun, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), + list("M276 M40 Grenade Rig", 0, /obj/item/storage/belt/grenade, MARINE_CAN_BUY_BELT, VENDOR_ITEM_REGULAR), + + list("POUCHES (CHOOSE 2)", 0, null, null, null), + list("Autoinjector Pouch", 0, /obj/item/storage/pouch/autoinjector, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Construction Pouch", 0, /obj/item/storage/pouch/construction, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Document Pouch", 0, /obj/item/storage/pouch/document, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Electronics Pouch (Full)", 0, /obj/item/storage/pouch/electronics/full, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("First-Aid Pouch (Refillable Injectors)", 0, /obj/item/storage/pouch/firstaid/full, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("First-Aid Pouch (Splints, Gauze, Ointment)", 0, /obj/item/storage/pouch/firstaid/full/alternate, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("First-Aid Pouch (Pill Packets)", 0, /obj/item/storage/pouch/firstaid/full/pills, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("First Responder Pouch", 0, /obj/item/storage/pouch/first_responder, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Flare Pouch (Full)", 0, /obj/item/storage/pouch/flare/full, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Fuel Tank Strap Pouch", 0, /obj/item/storage/pouch/flamertank, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Large General Pouch", 0, /obj/item/storage/pouch/general/large, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_RECOMMENDED), + list("Large Magazine Pouch", 0, /obj/item/storage/pouch/magazine/large, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Large Shotgun Shell Pouch", 0, /obj/item/storage/pouch/shotgun/large, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Large Pistol Magazine Pouch", 0, /obj/item/storage/pouch/magazine/pistol/large, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Medical Pouch", 0, /obj/item/storage/pouch/medical, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Medical Kit Pouch", 0, /obj/item/storage/pouch/medkit, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Pistol Pouch", 0, /obj/item/storage/pouch/pistol, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Sling Pouch", 0, /obj/item/storage/pouch/sling, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + list("Tools Pouch (Full)", 0, /obj/item/storage/pouch/tools/full, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR), + + list("ACCESSORIES (CHOOSE 1)", 0, null, null, null), + list("Black Webbing Vest", 0, /obj/item/clothing/accessory/storage/black_vest, MARINE_CAN_BUY_ACCESSORY, VENDOR_ITEM_REGULAR), + list("Brown Webbing Vest", 0, /obj/item/clothing/accessory/storage/black_vest/brown_vest, MARINE_CAN_BUY_ACCESSORY, VENDOR_ITEM_RECOMMENDED), + list("Drop Pouch", 0, /obj/item/clothing/accessory/storage/droppouch, MARINE_CAN_BUY_ACCESSORY, VENDOR_ITEM_REGULAR), + list("Webbing", 0, /obj/item/clothing/accessory/storage/webbing, MARINE_CAN_BUY_ACCESSORY, VENDOR_ITEM_REGULAR), + list("Shoulder Holster", 0, /obj/item/clothing/accessory/storage/holster, MARINE_CAN_BUY_ACCESSORY, VENDOR_ITEM_REGULAR), + + list("MASK (CHOOSE 1)", 0, null, null, null), + list("Gas Mask", 0, /obj/item/clothing/mask/gas, MARINE_CAN_BUY_MASK, VENDOR_ITEM_REGULAR), + list("Heat Absorbent Coif", 0, /obj/item/clothing/mask/rebreather/scarf, MARINE_CAN_BUY_MASK, VENDOR_ITEM_REGULAR), + + list("OTHER SUPPLIES", 0, null, null, null), + list("Medical Helmet Optic", 5, /obj/item/device/helmet_visor/medical, null, VENDOR_ITEM_REGULAR), + list("Magnetic Harness", 12, /obj/item/attachable/magnetic_harness, null, VENDOR_ITEM_REGULAR), + list("Radio Telephone Pack", 15, /obj/item/storage/backpack/marine/satchel/rto, null, VENDOR_ITEM_RECOMMENDED), + list("Binoculars", 5,/obj/item/device/binoculars, null, VENDOR_ITEM_REGULAR), + list("Rangefinder", 8, /obj/item/device/binoculars/range, null, VENDOR_ITEM_REGULAR), + list("Laser Designator", 12, /obj/item/device/binoculars/range/designator, null, VENDOR_ITEM_RECOMMENDED), + list("Data Detector", 5, /obj/item/device/motiondetector/intel, null, VENDOR_ITEM_REGULAR), + list("Flashlight", 1, /obj/item/device/flashlight, null, VENDOR_ITEM_RECOMMENDED), + list("Fulton Recovery Device", 5, /obj/item/stack/fulton, null, VENDOR_ITEM_REGULAR), + list("Motion Detector", 5, /obj/item/device/motiondetector, null, VENDOR_ITEM_REGULAR), + list("Space Cleaner", 2, /obj/item/reagent_container/spray/cleaner, null, VENDOR_ITEM_REGULAR), + list("Whistle", 5, /obj/item/device/whistle, null, VENDOR_ITEM_REGULAR), + list("Machete Scabbard (Full)", 5, /obj/item/storage/large_holster/machete/full, null, VENDOR_ITEM_REGULAR) + )) diff --git a/code/game/machinery/vending/vendor_types/crew/synthetic.dm b/code/game/machinery/vending/vendor_types/crew/synthetic.dm index 6c32315d427a..b489dbab16a4 100644 --- a/code/game/machinery/vending/vendor_types/crew/synthetic.dm +++ b/code/game/machinery/vending/vendor_types/crew/synthetic.dm @@ -19,6 +19,7 @@ list("Plasteel x10", 7, /obj/item/stack/sheet/plasteel/small_stack, null, VENDOR_ITEM_REGULAR), list("Sandbags x25", 10, /obj/item/stack/sandbags_empty/half, null, VENDOR_ITEM_REGULAR), list("Plastic Explosive", 3, /obj/item/explosive/plastic, null, VENDOR_ITEM_REGULAR), + list("ES-11 Mobile Fuel Canister", 4, /obj/item/tool/weldpack/minitank, null, VENDOR_ITEM_REGULAR), list("Engineer Kit", 1, /obj/item/storage/toolkit/empty, null, VENDOR_ITEM_REGULAR), list("FIRSTAID KITS", 0, null, null, null), @@ -100,7 +101,10 @@ GLOBAL_LIST_INIT(cm_vending_clothing_synth, list( list("Webbing", 0, /obj/item/clothing/accessory/storage/webbing, MARINE_CAN_BUY_ACCESSORY, VENDOR_ITEM_REGULAR), list("Surgical Webbing Vest", 0, /obj/item/clothing/accessory/storage/surg_vest, MARINE_CAN_BUY_ACCESSORY, VENDOR_ITEM_REGULAR), list("Surgical Webbing Vest (Blue)", 0, /obj/item/clothing/accessory/storage/surg_vest/blue, MARINE_CAN_BUY_ACCESSORY, VENDOR_ITEM_REGULAR), - list("Tool Webbing", 0, /obj/item/clothing/accessory/storage/black_vest/tool_webbing, MARINE_CAN_BUY_ACCESSORY, VENDOR_ITEM_REGULAR), + list("Surgical Drop Pouch", 0, /obj/item/clothing/accessory/storage/surg_vest/drop_green, MARINE_CAN_BUY_ACCESSORY, VENDOR_ITEM_REGULAR), + list("Surgical Drop Pouch (Blue)", 0, /obj/item/clothing/accessory/storage/surg_vest/drop_blue, MARINE_CAN_BUY_ACCESSORY, VENDOR_ITEM_REGULAR), + list("Surgical Drop Pouch (Black)", 0, /obj/item/clothing/accessory/storage/surg_vest/drop_black, MARINE_CAN_BUY_ACCESSORY, VENDOR_ITEM_REGULAR), + list("Tool Webbing", 0, /obj/item/clothing/accessory/storage/tool_webbing/equipped, MARINE_CAN_BUY_ACCESSORY, VENDOR_ITEM_REGULAR), list("Drop Pouch", 0, /obj/item/clothing/accessory/storage/droppouch, MARINE_CAN_BUY_ACCESSORY, VENDOR_ITEM_REGULAR), list("SHOES (CHOOSE 1)", 0, null, null, null), @@ -113,8 +117,12 @@ GLOBAL_LIST_INIT(cm_vending_clothing_synth, list( list("Welding Helmet", 0, /obj/item/clothing/head/welding, MARINE_CAN_BUY_HELMET, VENDOR_ITEM_REGULAR), list("SUIT (CHOOSE 1)", 0, null, null, null), - list("M3A1 Pattern Synthetic Utility Vest (UA Gray)", 0, /obj/item/clothing/suit/storage/marine/light/synvest/vanilla, MARINE_CAN_BUY_ARMOR, VENDOR_ITEM_REGULAR), - list("M3A1 Pattern Synthetic Utility Vest (Mission-Specific Camo)", 0, /obj/item/clothing/suit/storage/marine/light/synvest, MARINE_CAN_BUY_ARMOR, VENDOR_ITEM_REGULAR), + list("M3A1 Pattern Synthetic Utility Vest (Mission-Specific Camo)", 0, /obj/item/clothing/suit/storage/marine/light/synvest, MARINE_CAN_BUY_ARMOR, VENDOR_ITEM_RECOMMENDED), + list("M3A1 Pattern Synthetic Utility Vest (UA Gray)", 0, /obj/item/clothing/suit/storage/marine/light/synvest/grey, MARINE_CAN_BUY_ARMOR, VENDOR_ITEM_REGULAR), + list("M3A1 Pattern Synthetic Utility Vest (UA Dark Grey)", 0, /obj/item/clothing/suit/storage/marine/light/synvest/dgrey, MARINE_CAN_BUY_ARMOR, VENDOR_ITEM_REGULAR), + list("M3A1 Pattern Synthetic Utility Vest (UA Jungle)", 0, /obj/item/clothing/suit/storage/marine/light/synvest/jungle, MARINE_CAN_BUY_ARMOR, VENDOR_ITEM_REGULAR), + list("M3A1 Pattern Synthetic Utility Vest (UA Snow)", 0, /obj/item/clothing/suit/storage/marine/light/synvest/snow, MARINE_CAN_BUY_ARMOR, VENDOR_ITEM_REGULAR), + list("M3A1 Pattern Synthetic Utility Vest (UA Desert)", 0, /obj/item/clothing/suit/storage/marine/light/synvest/desert, MARINE_CAN_BUY_ARMOR, VENDOR_ITEM_REGULAR), list("GLOVES (CHOOSE 1)", 0, null, null, null), list("Insulated Gloves", 0, /obj/item/clothing/gloves/yellow, MARINE_CAN_BUY_GLOVES, VENDOR_ITEM_RECOMMENDED), @@ -173,14 +181,20 @@ GLOBAL_LIST_INIT(cm_vending_clothing_synth, list( //------------SNOWFLAKE VENDOR--------------- GLOBAL_LIST_INIT(cm_vending_clothing_synth_snowflake, list( - list("UNIFORM", 0, null, null, null), + list("USCM UNIFORMS", 0, null, null, null), list("Medical Scrubs, Blue", 12, /obj/item/clothing/under/rank/medical/blue, null, VENDOR_ITEM_REGULAR), list("Medical Scrubs, Green", 12, /obj/item/clothing/under/rank/medical/green, null, VENDOR_ITEM_REGULAR), list("Medical Scrubs, Purple", 12, /obj/item/clothing/under/rank/medical/purple, null, VENDOR_ITEM_REGULAR), list("Medical Scrubs, White", 12, /obj/item/clothing/under/rank/medical, null, VENDOR_ITEM_REGULAR), list("USCM Service Uniform", 12, /obj/item/clothing/under/marine/officer/bridge, null, VENDOR_ITEM_REGULAR), list("USCM Flightsuit", 12, /obj/item/clothing/under/rank/synthetic/flight, null, VENDOR_ITEM_REGULAR), - list("USCM Engineer Uniform", 12, /obj/item/clothing/under/marine/officer/engi, null, VENDOR_ITEM_REGULAR), + list("USCM Engineers Uniform", 12, /obj/item/clothing/under/marine/engineer/standard, null, VENDOR_ITEM_REGULAR), + list("USCM Engineers Uniform (Darker)", 12, /obj/item/clothing/under/marine/engineer/darker, null, VENDOR_ITEM_REGULAR), + list("USCM Engineering Officers Uniform", 12, /obj/item/clothing/under/marine/officer/engi, null, VENDOR_ITEM_REGULAR), + list("USCM Military Police Uniform", 12, /obj/item/clothing/under/marine/mp/standard, null, VENDOR_ITEM_REGULAR), + list("USCM Military Police Uniform (Darker)", 12, /obj/item/clothing/under/marine/mp/darker, null, VENDOR_ITEM_REGULAR), + + list("NON-STANDARD UNIFORMS", 0, null, null, null), list("White T-Shirt and Brown Jeans", 12, /obj/item/clothing/under/tshirt/w_br, null, VENDOR_ITEM_REGULAR), list("Gray T-Shirt and Blue Jeans", 12, /obj/item/clothing/under/tshirt/gray_blu, null, VENDOR_ITEM_REGULAR), list("Red T-Shirt and Black Jeans", 12, /obj/item/clothing/under/tshirt/r_bla, null, VENDOR_ITEM_REGULAR), @@ -200,6 +214,7 @@ GLOBAL_LIST_INIT(cm_vending_clothing_synth_snowflake, list( list("Marine RPG Glasses", 12, /obj/item/clothing/glasses/regular, null, VENDOR_ITEM_REGULAR), list("Optical Meson Scanner", 12, /obj/item/clothing/glasses/meson, null, VENDOR_ITEM_REGULAR), list("PatrolMate HUD", 12, /obj/item/clothing/glasses/hud/security, null, VENDOR_ITEM_REGULAR), + list("Security HUD Glasses", 12, /obj/item/clothing/glasses/sunglasses/sechud, null, VENDOR_ITEM_REGULAR), list("Sunglasses", 12, /obj/item/clothing/glasses/sunglasses, null, VENDOR_ITEM_REGULAR), list("Welding Goggles", 12, /obj/item/clothing/glasses/welding, null, VENDOR_ITEM_REGULAR), @@ -215,13 +230,15 @@ GLOBAL_LIST_INIT(cm_vending_clothing_synth_snowflake, list( list("Shoes, Yellow", 12, /obj/item/clothing/shoes/yellow, null, VENDOR_ITEM_REGULAR), list("Shoes, Seegson", 24, /obj/item/clothing/shoes/dress, null, VENDOR_ITEM_REGULAR), - list("HELMET", 0, null, null, null), + list("HEADWEAR", 0, null, null, null), list("Beanie", 12, /obj/item/clothing/head/beanie, null, VENDOR_ITEM_REGULAR), list("Beret, Engineering", 12, /obj/item/clothing/head/beret/eng, null, VENDOR_ITEM_REGULAR), list("Beret, Purple", 12, /obj/item/clothing/head/beret/jan, null, VENDOR_ITEM_REGULAR), list("Beret, Red", 12, /obj/item/clothing/head/beret/cm/red, null, VENDOR_ITEM_REGULAR), list("Beret, Standard", 12, /obj/item/clothing/head/beret/cm, null, VENDOR_ITEM_REGULAR), list("Beret, Tan", 12, /obj/item/clothing/head/beret/cm/tan, null, VENDOR_ITEM_REGULAR), + list("Beret, Black", 12, /obj/item/clothing/head/beret/cm/black, null, VENDOR_ITEM_REGULAR), + list("Beret, White", 12, /obj/item/clothing/head/beret/cm/white, null, VENDOR_ITEM_REGULAR), list("Surgical Cap, Blue", 12, /obj/item/clothing/head/surgery/blue, null, VENDOR_ITEM_REGULAR), list("Surgical Cap, Blue", 12, /obj/item/clothing/head/surgery/purple, null, VENDOR_ITEM_REGULAR), list("Surgical Cap, Green", 12, /obj/item/clothing/head/surgery/green, null, VENDOR_ITEM_REGULAR), @@ -232,13 +249,17 @@ GLOBAL_LIST_INIT(cm_vending_clothing_synth_snowflake, list( list("Req Cap", 12, /obj/item/clothing/head/cmcap/req, null, VENDOR_ITEM_REGULAR), list("Officer Cap", 12, /obj/item/clothing/head/cmcap/bridge, null, VENDOR_ITEM_REGULAR), list("Bio Hood", 12, /obj/item/clothing/head/bio_hood/synth, null, VENDOR_ITEM_REGULAR), - list("Marine Helmet", 12, /obj/item/clothing/head/helmet/marine, null, VENDOR_ITEM_REGULAR), - list("Grey Marine Helmet", 12, /obj/item/clothing/head/helmet/marine/grey, null, VENDOR_ITEM_REGULAR), + + list("HELMET", 0, null, null, null), + list("Marine Helmet (Mission-Specific Camo)", 12, /obj/item/clothing/head/helmet/marine, null, VENDOR_ITEM_REGULAR), + list("Marine Helmet (Grey)", 12, /obj/item/clothing/head/helmet/marine/grey, null, VENDOR_ITEM_REGULAR), + list("Marine Helmet (Jungle)", 12, /obj/item/clothing/head/helmet/marine/jungle, null, VENDOR_ITEM_REGULAR), + list("Marine Helmet (Snow)", 12, /obj/item/clothing/head/helmet/marine/snow, null, VENDOR_ITEM_REGULAR), + list("Marine Helmet (Desert)", 12, /obj/item/clothing/head/helmet/marine/desert, null, VENDOR_ITEM_REGULAR), list("Technician Helmet", 12, /obj/item/clothing/head/helmet/marine/tech, null, VENDOR_ITEM_REGULAR), list("Corpsman Helmet", 12, /obj/item/clothing/head/helmet/marine/medic, null, VENDOR_ITEM_REGULAR), list("Attachable Helmet Shield", 12, /obj/item/prop/helmetgarb/riot_shield, null, VENDOR_ITEM_REGULAR), - list("SUIT", 0, null, null, null), list("Bomber Jacket, Brown", 12, /obj/item/clothing/suit/storage/bomber, null, VENDOR_ITEM_REGULAR), list("Bomber Jacket, Black", 12, /obj/item/clothing/suit/storage/bomber/alt, null, VENDOR_ITEM_REGULAR), @@ -260,7 +281,13 @@ GLOBAL_LIST_INIT(cm_vending_clothing_synth_snowflake, list( list("Labcoat, Researcher", 12, /obj/item/clothing/suit/storage/labcoat/researcher, null, VENDOR_ITEM_REGULAR), list("Quartermaster Jacket", 12, /obj/item/clothing/suit/storage/RO, null, VENDOR_ITEM_REGULAR), list("Bio Suit", 12, /obj/item/clothing/suit/storage/synthbio, null, VENDOR_ITEM_REGULAR), - list("USCM Poncho", 12, /obj/item/clothing/accessory/poncho, null, VENDOR_ITEM_REGULAR), + list("USCM Poncho (Mission-Specific Camo)", 12, /obj/item/clothing/accessory/poncho, null, VENDOR_ITEM_REGULAR), + list("USCM Poncho (Green)", 12, /obj/item/clothing/accessory/poncho/green, null, VENDOR_ITEM_REGULAR), + list("USCM Poncho (Brown)", 12, /obj/item/clothing/accessory/poncho/brown, null, VENDOR_ITEM_REGULAR), + list("USCM Poncho (Black)", 12, /obj/item/clothing/accessory/poncho/black, null, VENDOR_ITEM_REGULAR), + list("USCM Poncho (Blue)", 12, /obj/item/clothing/accessory/poncho/blue, null, VENDOR_ITEM_REGULAR), + list("USCM Poncho (Purple)", 12, /obj/item/clothing/accessory/poncho/purple, null, VENDOR_ITEM_REGULAR), + list("BACKPACK", 0, null, null, null), list("Backpack, Industrial", 12, /obj/item/storage/backpack/industrial, null, VENDOR_ITEM_REGULAR), @@ -272,6 +299,7 @@ GLOBAL_LIST_INIT(cm_vending_clothing_synth_snowflake, list( list("USCM RTO Pack", 12, /obj/item/storage/backpack/marine/satchel/rto, null, VENDOR_ITEM_REGULAR), list("USCM Welderpack", 12, /obj/item/storage/backpack/marine/engineerpack, null, VENDOR_ITEM_REGULAR), list("USCM Weldersatchel", 12, /obj/item/storage/backpack/marine/engineerpack/satchel, null, VENDOR_ITEM_REGULAR), + list("USCM Welder Chestrig", 12, /obj/item/storage/backpack/marine/engineerpack/welder_chestrig, null, VENDOR_ITEM_REGULAR), list("OTHER", 0, null, null, null), list("Red Armband", 6, /obj/item/clothing/accessory/armband, null, VENDOR_ITEM_REGULAR), diff --git a/code/game/machinery/vending/vendor_types/crew/vehicle_crew.dm b/code/game/machinery/vending/vendor_types/crew/vehicle_crew.dm index 891a2a907b39..d352936b5434 100644 --- a/code/game/machinery/vending/vendor_types/crew/vehicle_crew.dm +++ b/code/game/machinery/vending/vendor_types/crew/vehicle_crew.dm @@ -55,8 +55,10 @@ SIGNAL_HANDLER UnregisterSignal(SSdcs, COMSIG_GLOB_VEHICLE_ORDERED) - selected_vehicle = "APC" - available_categories &= ~(VEHICLE_ARMOR_AVAILABLE|VEHICLE_INTEGRAL_AVAILABLE) //APC lacks these, so we need to remove these flags to be able to access spare parts section + if(!selected_vehicle) + selected_vehicle = "APC" // The whole thing seems to be based upon the assumption you unlock tank as an override, defaulting to APC + if(selected_vehicle == "APC") + available_categories &= ~(VEHICLE_ARMOR_AVAILABLE|VEHICLE_INTEGRAL_AVAILABLE) //APC lacks these, so we need to remove these flags to be able to access spare parts section /obj/structure/machinery/cm_vending/gear/vehicle_crew/get_listed_products(mob/user) var/list/display_list = list() diff --git a/code/game/machinery/vending/vendor_types/intelligence_officer.dm b/code/game/machinery/vending/vendor_types/intelligence_officer.dm index 46394bea8c2c..ad10037ccfe1 100644 --- a/code/game/machinery/vending/vendor_types/intelligence_officer.dm +++ b/code/game/machinery/vending/vendor_types/intelligence_officer.dm @@ -7,7 +7,7 @@ GLOBAL_LIST_INIT(cm_vending_gear_intelligence_officer, list( list("SUPPLIES", 0, null, null, null), list("Power Control Module", 5, /obj/item/circuitboard/apc, null, VENDOR_ITEM_REGULAR), list("Binoculars", 5, /obj/item/device/binoculars, null, VENDOR_ITEM_REGULAR), - list("M2 Night Vision Goggles", 25, /obj/item/prop/helmetgarb/helmet_nvg, null, VENDOR_ITEM_RECOMMENDED), + list("Night Vision Optic", 25, /obj/item/device/helmet_visor/night_vision, null, VENDOR_ITEM_RECOMMENDED), list("Data Detector", 5, /obj/item/device/motiondetector/intel, null, VENDOR_ITEM_REGULAR), list("Intel Radio Encryption Key", 5, /obj/item/device/encryptionkey/intel, null, VENDOR_ITEM_REGULAR), list("Fire Extinguisher (Portable)", 5, /obj/item/tool/extinguisher/mini, null, VENDOR_ITEM_REGULAR), diff --git a/code/game/machinery/vending/vendor_types/requisitions.dm b/code/game/machinery/vending/vendor_types/requisitions.dm index 07284e7f8e71..93680fb93d2c 100644 --- a/code/game/machinery/vending/vendor_types/requisitions.dm +++ b/code/game/machinery/vending/vendor_types/requisitions.dm @@ -175,24 +175,10 @@ //Special cargo-specific vendor with vending offsets /obj/structure/machinery/cm_vending/sorted/cargo_guns/cargo vend_flags = VEND_CLUTTER_PROTECTION | VEND_LIMITED_INVENTORY | VEND_LOAD_AMMO_BOXES //We want to vend to turf not hand, since we are in requisitions + vend_dir = WEST + vend_dir_whitelist = list(NORTH, SOUTH) -/obj/structure/machinery/cm_vending/sorted/cargo_guns/cargo/get_appropriate_vend_turf(mob/living/carbon/human/H) - var/turf/turf_to_vent_to - if(vend_x_offset != 0 || vend_y_offset != 0) //this will allow to avoid code below that suits only Almayer. - turf_to_vent_to = locate(x + vend_x_offset, y + vend_y_offset, z) - else - turf_to_vent_to = get_turf(get_step(src, NORTH)) - if(H.loc == turf_to_vent_to) - turf_to_vent_to = get_turf(get_step(H.loc, WEST)) - else - turf_to_vent_to = get_turf(get_step(src, SOUTH)) - if(H.loc == turf_to_vent_to) - turf_to_vent_to = get_turf(get_step(H.loc, WEST)) - else - turf_to_vent_to = H.loc - return turf_to_vent_to - -/obj/structure/machinery/cm_vending/sorted/cargo_guns/blend +/obj/structure/machinery/cm_vending/sorted/cargo_guns/cargo/blend icon_state = "req_guns_wall" tiles_with = list( /obj/structure/window/framed/almayer, @@ -209,6 +195,8 @@ req_access = list(ACCESS_MARINE_CARGO) vendor_theme = VENDOR_THEME_USCM vend_flags = VEND_CLUTTER_PROTECTION | VEND_LIMITED_INVENTORY | VEND_TO_HAND | VEND_LOAD_AMMO_BOXES + vend_dir = WEST + vend_dir_whitelist = list(SOUTHWEST, NORTHWEST) /obj/structure/machinery/cm_vending/sorted/cargo_ammo/vend_fail() return @@ -296,7 +284,7 @@ updateUsrDialog() return //We found our item, no reason to go on. -/obj/structure/machinery/cm_vending/sorted/cargo_ammo/blend +/obj/structure/machinery/cm_vending/sorted/cargo_ammo/cargo/blend icon_state = "req_ammo_wall" tiles_with = list( /obj/structure/window/framed/almayer, @@ -307,22 +295,6 @@ /obj/structure/machinery/cm_vending/sorted/cargo_ammo/cargo vend_flags = VEND_CLUTTER_PROTECTION | VEND_LIMITED_INVENTORY | VEND_LOAD_AMMO_BOXES //We want to vend to turf not hand, since we are in requisitions -/obj/structure/machinery/cm_vending/sorted/cargo_ammo/cargo/get_appropriate_vend_turf(mob/living/carbon/human/H) - var/turf/turf_to_vent_to - if(vend_x_offset != 0 || vend_y_offset != 0) //this will allow to avoid code below that suits only Almayer. - turf_to_vent_to = locate(x + vend_x_offset, y + vend_y_offset, z) - else - turf_to_vent_to = get_turf(get_step(src, NORTHWEST)) - if(H.loc == turf_to_vent_to) - turf_to_vent_to = get_turf(get_step(H.loc, WEST)) - else - turf_to_vent_to = get_turf(get_step(src, SOUTHWEST)) - if(H.loc == turf_to_vent_to) - turf_to_vent_to = get_turf(get_step(H.loc, WEST)) - else - turf_to_vent_to = H.loc - return turf_to_vent_to - //------------ATTACHMENTS VENDOR--------------- /obj/structure/machinery/cm_vending/sorted/attachments @@ -331,6 +303,9 @@ req_access = list(ACCESS_MARINE_CARGO) vendor_theme = VENDOR_THEME_USCM icon_state = "req_attach" + vend_dir = WEST + vend_dir_whitelist = list(SOUTHEAST, NORTHEAST) + vend_flags = VEND_CLUTTER_PROTECTION | VEND_LIMITED_INVENTORY //We want to vend to turf not hand, since we are in requisitions /obj/structure/machinery/cm_vending/sorted/attachments/vend_fail() return @@ -379,22 +354,6 @@ list("M44 Magnum Sharpshooter Stock", round(scale * 4.5), /obj/item/attachable/stock/revolver, VENDOR_ITEM_REGULAR) ) -/obj/structure/machinery/cm_vending/sorted/attachments/get_appropriate_vend_turf(mob/living/carbon/human/H) - var/turf/turf_to_vent_to - if(vend_x_offset != 0 || vend_y_offset != 0) //this will allow to avoid code below that suits only Almayer. - turf_to_vent_to = locate(x + vend_x_offset, y + vend_y_offset, z) - else - turf_to_vent_to = get_turf(get_step(src, NORTHEAST)) - if(H.loc == turf_to_vent_to) - turf_to_vent_to = get_turf(get_step(H.loc, WEST)) - else - turf_to_vent_to = get_turf(get_step(src, SOUTHEAST)) - if(H.loc == turf_to_vent_to) - turf_to_vent_to = get_turf(get_step(H.loc, WEST)) - else - turf_to_vent_to = loc - return turf_to_vent_to - /obj/structure/machinery/cm_vending/sorted/attachments/blend icon_state = "req_attach_wall" tiles_with = list( @@ -402,7 +361,6 @@ /obj/structure/machinery/door/airlock, /turf/closed/wall/almayer, ) - vend_flags = VEND_CLUTTER_PROTECTION | VEND_LIMITED_INVENTORY //We want to vend to turf not hand, since we are in requisitions //------------UNIFORM VENDOR--------------- @@ -455,6 +413,9 @@ list("MASKS", -1, null, null, null), list("Gas Mask", 20, /obj/item/clothing/mask/gas, VENDOR_ITEM_REGULAR), list("Heat Absorbent Coif", 10, /obj/item/clothing/mask/rebreather/scarf, VENDOR_ITEM_REGULAR), + + list("MISCELLANEOUS", -1, null, null), + list("Bedroll", 30, /obj/item/roller/bedroll, VENDOR_ITEM_REGULAR), ) /obj/structure/machinery/cm_vending/sorted/uniform_supply/ui_state(mob/user) diff --git a/code/game/machinery/vending/vendor_types/squad_prep/squad_engineer.dm b/code/game/machinery/vending/vendor_types/squad_prep/squad_engineer.dm index 543c601bda37..65397570511c 100644 --- a/code/game/machinery/vending/vendor_types/squad_prep/squad_engineer.dm +++ b/code/game/machinery/vending/vendor_types/squad_prep/squad_engineer.dm @@ -24,7 +24,6 @@ GLOBAL_LIST_INIT(cm_vending_gear_engi, list( list("Laser Designator", 15, /obj/item/device/binoculars/range/designator, null, VENDOR_ITEM_REGULAR), list("Sandbags x25", 10, /obj/item/stack/sandbags_empty/half, null, VENDOR_ITEM_RECOMMENDED), list("Super-Capacity Power Cell", 10, /obj/item/cell/super, null, VENDOR_ITEM_REGULAR), - list("Welding Goggles", 5, /obj/item/clothing/glasses/welding, null, VENDOR_ITEM_REGULAR), list("ES-11 Mobile Fuel Canister", 4, /obj/item/tool/weldpack/minitank, null, VENDOR_ITEM_REGULAR), list("EXPLOSIVES", 0, null, null, null), @@ -62,7 +61,6 @@ GLOBAL_LIST_INIT(cm_vending_gear_engi, list( list("Machete Pouch (Full)", 8, /obj/item/storage/pouch/machete/full, null, VENDOR_ITEM_REGULAR), list("USCM Radio Telephone Pack", 15, /obj/item/storage/backpack/marine/satchel/rto, null, VENDOR_ITEM_REGULAR), list("Fuel Tank Strap Pouch", 4, /obj/item/storage/pouch/flamertank, null, VENDOR_ITEM_REGULAR), - list("Welding Goggles", 3, /obj/item/clothing/glasses/welding, null, VENDOR_ITEM_REGULAR), list("Sling Pouch", 6, /obj/item/storage/pouch/sling, null, VENDOR_ITEM_REGULAR), list("Large General Pouch", 6, /obj/item/storage/pouch/general/large, null, VENDOR_ITEM_REGULAR), list("M276 Pattern Combat Toolbelt Rig", 15, /obj/item/storage/belt/gun/utility, null, VENDOR_ITEM_REGULAR), @@ -100,11 +98,7 @@ GLOBAL_LIST_INIT(cm_vending_gear_engi, list( GLOBAL_LIST_INIT(cm_vending_clothing_engi, list( list("STANDARD EQUIPMENT (TAKE ALL)", 0, null, null, null), - list("Boots", 0, /obj/item/clothing/shoes/marine/knife, MARINE_CAN_BUY_SHOES, VENDOR_ITEM_MANDATORY), - list("Uniform", 0, /obj/item/clothing/under/marine/engineer, MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_MANDATORY), - list("Gloves", 0, /obj/item/clothing/gloves/marine, MARINE_CAN_BUY_GLOVES, VENDOR_ITEM_MANDATORY), - list("Headset", 0, /obj/item/device/radio/headset/almayer/marine, MARINE_CAN_BUY_EAR, VENDOR_ITEM_MANDATORY), - list("Helmet", 0, /obj/item/clothing/head/helmet/marine/tech, MARINE_CAN_BUY_HELMET, VENDOR_ITEM_MANDATORY), + list("Standard Marine Apparel", 0, list(/obj/item/clothing/under/marine/engineer, /obj/item/clothing/shoes/marine/knife, /obj/item/clothing/gloves/marine, /obj/item/device/radio/headset/almayer/marine, /obj/item/clothing/head/helmet/marine/tech), MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_MANDATORY), list("MRE", 0, /obj/item/storage/box/MRE, MARINE_CAN_BUY_MRE, VENDOR_ITEM_MANDATORY), list("Map", 0, /obj/item/map/current_map, MARINE_CAN_BUY_KIT, VENDOR_ITEM_MANDATORY), diff --git a/code/game/machinery/vending/vendor_types/squad_prep/squad_leader.dm b/code/game/machinery/vending/vendor_types/squad_prep/squad_leader.dm index ea3423260ec0..81c1941c3423 100644 --- a/code/game/machinery/vending/vendor_types/squad_prep/squad_leader.dm +++ b/code/game/machinery/vending/vendor_types/squad_prep/squad_leader.dm @@ -23,7 +23,7 @@ GLOBAL_LIST_INIT(cm_vending_gear_leader, list( list("Machete Pouch (Full)", 4, /obj/item/storage/pouch/machete/full, null, VENDOR_ITEM_REGULAR), list("USCM Radio Telephone Pack", 5, /obj/item/storage/backpack/marine/satchel/rto, null, VENDOR_ITEM_REGULAR), list("M276 Pattern Combat Toolbelt Rig", 15, /obj/item/storage/belt/gun/utility, null, VENDOR_ITEM_REGULAR), - list("M2 Night Vision Goggles", 20, /obj/item/prop/helmetgarb/helmet_nvg, null, VENDOR_ITEM_RECOMMENDED), + list("Night Vision Optic", 20, /obj/item/device/helmet_visor/night_vision, null, VENDOR_ITEM_RECOMMENDED), list("UTILITIES", 0, null, null, null), list("Whistle", 3, /obj/item/device/whistle, null, VENDOR_ITEM_REGULAR), @@ -114,12 +114,8 @@ GLOBAL_LIST_INIT(cm_vending_gear_leader, list( GLOBAL_LIST_INIT(cm_vending_clothing_leader, list( list("STANDARD EQUIPMENT (TAKE ALL)", 0, null, null, null), - list("Boots", 0, /obj/item/clothing/shoes/marine/knife, MARINE_CAN_BUY_SHOES, VENDOR_ITEM_MANDATORY), - list("Uniform", 0, /obj/item/clothing/under/marine, MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_MANDATORY), - list("Gloves", 0, /obj/item/clothing/gloves/marine, MARINE_CAN_BUY_GLOVES, VENDOR_ITEM_MANDATORY), - list("Armor", 0, /obj/item/clothing/suit/storage/marine/leader, MARINE_CAN_BUY_ARMOR, VENDOR_ITEM_MANDATORY), - list("Headset", 0, /obj/item/device/radio/headset/almayer/marine, MARINE_CAN_BUY_EAR, VENDOR_ITEM_MANDATORY), - list("Helmet", 0, /obj/item/clothing/head/helmet/marine/leader, MARINE_CAN_BUY_HELMET, VENDOR_ITEM_MANDATORY), + list("Standard Marine Apparel", 0, list(/obj/item/clothing/under/marine, /obj/item/clothing/shoes/marine/knife, /obj/item/clothing/gloves/marine, /obj/item/device/radio/headset/almayer/marine, /obj/item/clothing/head/helmet/marine/leader), MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_MANDATORY), + list("B12 Pattern Armor", 0, /obj/item/clothing/suit/storage/marine/leader, MARINE_CAN_BUY_ARMOR, VENDOR_ITEM_MANDATORY), list("MRE", 0, /obj/item/storage/box/MRE, MARINE_CAN_BUY_MRE, VENDOR_ITEM_MANDATORY), list("Map", 0, /obj/item/map/current_map, MARINE_CAN_BUY_ATTACHMENT, VENDOR_ITEM_MANDATORY), diff --git a/code/game/machinery/vending/vendor_types/squad_prep/squad_medic.dm b/code/game/machinery/vending/vendor_types/squad_prep/squad_medic.dm index 1b634335f5d2..f6b99887bbbb 100644 --- a/code/game/machinery/vending/vendor_types/squad_prep/squad_medic.dm +++ b/code/game/machinery/vending/vendor_types/squad_prep/squad_medic.dm @@ -116,11 +116,8 @@ GLOBAL_LIST_INIT(cm_vending_gear_medic, list( GLOBAL_LIST_INIT(cm_vending_clothing_medic, list( list("STANDARD EQUIPMENT (TAKE ALL)", 0, null, null, null), - list("Boots", 0, /obj/item/clothing/shoes/marine/knife, MARINE_CAN_BUY_SHOES, VENDOR_ITEM_MANDATORY), - list("Uniform", 0, /obj/item/clothing/under/marine/medic, MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_MANDATORY), - list("Gloves", 0, /obj/item/clothing/gloves/marine, MARINE_CAN_BUY_GLOVES, VENDOR_ITEM_MANDATORY), - list("Headset", 0, /obj/item/device/radio/headset/almayer/marine, MARINE_CAN_BUY_EAR, VENDOR_ITEM_MANDATORY), - list("Helmet", 0, /obj/item/clothing/head/helmet/marine/medic, MARINE_CAN_BUY_HELMET, VENDOR_ITEM_MANDATORY), + list("Standard Marine Apparel", 0, list(/obj/item/clothing/under/marine/medic, /obj/item/clothing/shoes/marine/knife, /obj/item/clothing/gloves/marine, /obj/item/device/radio/headset/almayer/marine, /obj/item/clothing/head/helmet/marine/medic), MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_MANDATORY), + list("Combat Sterile Gloves", 0, /obj/item/clothing/gloves/marine/medical, MARINE_CAN_BUY_KIT, VENDOR_ITEM_REGULAR), list("MRE", 0, /obj/item/storage/box/MRE, MARINE_CAN_BUY_MRE, VENDOR_ITEM_MANDATORY), list("Map", 0, /obj/item/map/current_map, MARINE_CAN_BUY_KIT, VENDOR_ITEM_MANDATORY), diff --git a/code/game/machinery/vending/vendor_types/squad_prep/squad_prep.dm b/code/game/machinery/vending/vendor_types/squad_prep/squad_prep.dm index 8e468187c045..69e10e280c6f 100644 --- a/code/game/machinery/vending/vendor_types/squad_prep/squad_prep.dm +++ b/code/game/machinery/vending/vendor_types/squad_prep/squad_prep.dm @@ -176,6 +176,7 @@ list("MISCELLANEOUS", -1, null, null, null), list("Ballistic goggles", round(scale * 10), /obj/item/clothing/glasses/mgoggles, VENDOR_ITEM_REGULAR), + list("M1A1 Ballistic goggles", round(scale * 10), /obj/item/clothing/glasses/mgoggles/v2, VENDOR_ITEM_REGULAR), list("Prescription ballistic goggles", round(scale * 10), /obj/item/clothing/glasses/mgoggles/prescription, VENDOR_ITEM_REGULAR), list("Marine RPG glasses", round(scale * 10), /obj/item/clothing/glasses/regular, VENDOR_ITEM_REGULAR), list("M5 Integrated Gas Mask", round(scale * 10), /obj/item/prop/helmetgarb/helmet_gasmask, VENDOR_ITEM_REGULAR), @@ -185,6 +186,7 @@ list("USCM Flair", round(scale * 15), /obj/item/prop/helmetgarb/flair_uscm, VENDOR_ITEM_REGULAR), list("Falling Falcons Shoulder Patch", round(scale * 15), /obj/item/clothing/accessory/patch/falcon, VENDOR_ITEM_REGULAR), list("USCM Shoulder Patch", round(scale * 15), /obj/item/clothing/accessory/patch, VENDOR_ITEM_REGULAR), + list("Bedroll", round(scale * 20), /obj/item/roller/bedroll, VENDOR_ITEM_REGULAR), ) //--------------SQUAD SPECIFIC VERSIONS-------------- diff --git a/code/game/machinery/vending/vendor_types/squad_prep/squad_smartgunner.dm b/code/game/machinery/vending/vendor_types/squad_prep/squad_smartgunner.dm index 0691dfcee371..41710b477769 100644 --- a/code/game/machinery/vending/vendor_types/squad_prep/squad_smartgunner.dm +++ b/code/game/machinery/vending/vendor_types/squad_prep/squad_smartgunner.dm @@ -66,11 +66,7 @@ GLOBAL_LIST_INIT(cm_vending_gear_smartgun, list( GLOBAL_LIST_INIT(cm_vending_clothing_smartgun, list( list("STANDARD EQUIPMENT (TAKE ALL)", 0, null, null, null), - list("Boots", 0, /obj/item/clothing/shoes/marine/knife, MARINE_CAN_BUY_SHOES, VENDOR_ITEM_MANDATORY), - list("Uniform", 0, /obj/item/clothing/under/marine, MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_MANDATORY), - list("Gloves", 0, /obj/item/clothing/gloves/marine, MARINE_CAN_BUY_GLOVES, VENDOR_ITEM_MANDATORY), - list("Headset", 0, /obj/item/device/radio/headset/almayer/marine, MARINE_CAN_BUY_EAR, VENDOR_ITEM_MANDATORY), - list("Helmet", 0, /obj/item/clothing/head/helmet/marine, MARINE_CAN_BUY_HELMET, VENDOR_ITEM_MANDATORY), + list("Standard Marine Apparel", 0, list(/obj/item/clothing/under/marine, /obj/item/clothing/shoes/marine/knife, /obj/item/clothing/gloves/marine, /obj/item/device/radio/headset/almayer/marine, /obj/item/clothing/head/helmet/marine), MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_MANDATORY), list("MRE", 0, /obj/item/storage/box/MRE, MARINE_CAN_BUY_MRE, VENDOR_ITEM_MANDATORY), list("Map", 0, /obj/item/map/current_map, MARINE_CAN_BUY_KIT, VENDOR_ITEM_MANDATORY), diff --git a/code/game/machinery/vending/vendor_types/squad_prep/squad_specialist.dm b/code/game/machinery/vending/vendor_types/squad_prep/squad_specialist.dm index 38c74481205d..e800fc1efd56 100644 --- a/code/game/machinery/vending/vendor_types/squad_prep/squad_specialist.dm +++ b/code/game/machinery/vending/vendor_types/squad_prep/squad_specialist.dm @@ -56,10 +56,7 @@ GLOBAL_LIST_INIT(cm_vending_gear_spec, list( GLOBAL_LIST_INIT(cm_vending_clothing_specialist, list( list("STANDARD EQUIPMENT (TAKE ALL)", 0, null, null, null), - list("Boots", 0, /obj/item/clothing/shoes/marine/knife, MARINE_CAN_BUY_SHOES, VENDOR_ITEM_MANDATORY), - list("Uniform", 0, /obj/item/clothing/under/marine, MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_MANDATORY), - list("Gloves", 0, /obj/item/clothing/gloves/marine, MARINE_CAN_BUY_GLOVES, VENDOR_ITEM_MANDATORY), - list("Headset", 0, /obj/item/device/radio/headset/almayer/marine, MARINE_CAN_BUY_EAR, VENDOR_ITEM_MANDATORY), + list("Standard Marine Apparel", 0, list(/obj/item/clothing/under/marine, /obj/item/clothing/shoes/marine/knife, /obj/item/clothing/gloves/marine, /obj/item/device/radio/headset/almayer/marine), MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_MANDATORY), list("MRE", 0, /obj/item/storage/box/MRE, MARINE_CAN_BUY_MRE, VENDOR_ITEM_MANDATORY), list("Map", 0, /obj/item/map/current_map, MARINE_CAN_BUY_KIT, VENDOR_ITEM_MANDATORY), diff --git a/code/game/machinery/vending/vendor_types/squad_prep/squad_tl.dm b/code/game/machinery/vending/vendor_types/squad_prep/squad_tl.dm index c03d79eddfd0..7bd45cb46a60 100644 --- a/code/game/machinery/vending/vendor_types/squad_prep/squad_tl.dm +++ b/code/game/machinery/vending/vendor_types/squad_prep/squad_tl.dm @@ -40,7 +40,7 @@ GLOBAL_LIST_INIT(cm_vending_gear_tl, list( list("M276 Pattern Combat Toolbelt Rig", 15, /obj/item/storage/belt/gun/utility, null, VENDOR_ITEM_REGULAR), list("Autoinjector Pouch (Full)", 15, /obj/item/storage/pouch/autoinjector/full, null, VENDOR_ITEM_REGULAR), list("Insulated Gloves", 3, /obj/item/clothing/gloves/yellow, null, VENDOR_ITEM_REGULAR), - list("M2 Night Vision Goggles", 30, /obj/item/prop/helmetgarb/helmet_nvg, null, VENDOR_ITEM_RECOMMENDED), + list("Night Vision Optic", 30, /obj/item/device/helmet_visor/night_vision, null, VENDOR_ITEM_RECOMMENDED), list("UTILITIES", 0, null, null, null), list("Binoculars", 5, /obj/item/device/binoculars, null, VENDOR_ITEM_REGULAR), @@ -78,12 +78,8 @@ GLOBAL_LIST_INIT(cm_vending_gear_tl, list( GLOBAL_LIST_INIT(cm_vending_clothing_tl, list( list("STANDARD EQUIPMENT (TAKE ALL)", 0, null, null, null), - list("Boots", 0, /obj/item/clothing/shoes/marine/knife, MARINE_CAN_BUY_SHOES, VENDOR_ITEM_MANDATORY), - list("Uniform", 0, /obj/item/clothing/under/marine, MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_MANDATORY), - list("Gloves", 0, /obj/item/clothing/gloves/marine, MARINE_CAN_BUY_GLOVES, VENDOR_ITEM_MANDATORY), + list("Standard Marine Apparel", 0, list(/obj/item/clothing/under/marine, /obj/item/clothing/shoes/marine/knife, /obj/item/clothing/gloves/marine, /obj/item/device/radio/headset/almayer/marine, /obj/item/clothing/head/helmet/marine/rto), MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_MANDATORY), list("M4 Pattern Armor", 0, /obj/item/clothing/suit/storage/marine/rto, MARINE_CAN_BUY_ARMOR, VENDOR_ITEM_MANDATORY), - list("Headset", 0, /obj/item/device/radio/headset/almayer/marine, MARINE_CAN_BUY_EAR, VENDOR_ITEM_MANDATORY), - list("Helmet", 0, /obj/item/clothing/head/helmet/marine/rto, MARINE_CAN_BUY_HELMET, VENDOR_ITEM_MANDATORY), list("MRE", 0, /obj/item/storage/box/MRE, MARINE_CAN_BUY_MRE, VENDOR_ITEM_MANDATORY), list("Map", 0, /obj/item/map/current_map, MARINE_CAN_BUY_KIT, VENDOR_ITEM_MANDATORY), list("Essential Fireteam Leader Utilities", 0, /obj/effect/essentials_set/tl, MARINE_CAN_BUY_ESSENTIALS, VENDOR_ITEM_MANDATORY), diff --git a/code/game/machinery/vending/vendor_types/wo_vendors.dm b/code/game/machinery/vending/vendor_types/wo_vendors.dm index 645640f9dc84..557933754f07 100644 --- a/code/game/machinery/vending/vendor_types/wo_vendors.dm +++ b/code/game/machinery/vending/vendor_types/wo_vendors.dm @@ -110,52 +110,13 @@ ) //------------REQ AMMUNITION VENDOR--------------- -/obj/structure/machinery/cm_vending/sorted/cargo_ammo/wo +/obj/structure/machinery/cm_vending/sorted/cargo_ammo/cargo/wo req_access = list(ACCESS_MARINE_CARGO) req_one_access = list() -/obj/structure/machinery/cm_vending/sorted/cargo_ammo/wo/populate_product_list(scale) - listed_products = list( - list("REGULAR AMMUNITION", -1, null, null), - list("Box Of Buckshot Shells", round(scale * 5), /obj/item/ammo_magazine/shotgun/buckshot, VENDOR_ITEM_REGULAR), - list("Box Of Flechette Shells", round(scale * 5), /obj/item/ammo_magazine/shotgun/flechette, VENDOR_ITEM_REGULAR), - list("Box Of Shotgun Slugs", round(scale * 5), /obj/item/ammo_magazine/shotgun/slugs, VENDOR_ITEM_REGULAR), - list("M4RA magazine (10x24mm)", round(scale * 10), /obj/item/ammo_magazine/rifle/m4ra, VENDOR_ITEM_REGULAR), - list("M39 HV Magazine (10x20mm)", round(scale * 10), /obj/item/ammo_magazine/smg/m39, VENDOR_ITEM_REGULAR), - list("M41A MK1 Magazine (10x24mm)", round(scale * 10), /obj/item/ammo_magazine/rifle/m41aMK1, VENDOR_ITEM_REGULAR), - list("M41A MK2 Magazine (10x24mm)", round(scale * 10), /obj/item/ammo_magazine/rifle, VENDOR_ITEM_REGULAR), - list("M44 Speed Loader (.44)", round(scale * 10), /obj/item/ammo_magazine/revolver, VENDOR_ITEM_REGULAR), - list("M4A3 Magazine (9mm)", round(scale * 10), /obj/item/ammo_magazine/pistol, VENDOR_ITEM_REGULAR), - - list("ARMOR-PIERCING AMMUNITION", -1, null, null), - list("88 Mod 4 AP Magazine (9mm)", round(scale * 5), /obj/item/ammo_magazine/pistol/mod88, VENDOR_ITEM_REGULAR), - list("M4RA AP Magazine (10x24mm)", round(scale * 10), /obj/item/ammo_magazine/rifle/m4ra/ap, VENDOR_ITEM_REGULAR), - list("M39 AP Magazine (10x20mm)", round(scale * 5), /obj/item/ammo_magazine/smg/m39/ap, VENDOR_ITEM_REGULAR), - list("M41A MK1 AP Magazine (10x24mm)", round(scale * 10), /obj/item/ammo_magazine/rifle/m41aMK1/ap, VENDOR_ITEM_REGULAR), - list("M41A MK2 AP Magazine (10x24mm)", round(scale * 10), /obj/item/ammo_magazine/rifle/ap, VENDOR_ITEM_REGULAR), - list("M4A3 AP Magazine (9mm)", round(scale * 5), /obj/item/ammo_magazine/pistol/ap, VENDOR_ITEM_REGULAR), - - list("EXTENDED AMMUNITION", -1, null, null), - list("M39 Extended Magazine (10x20mm)", round(scale * 1), /obj/item/ammo_magazine/smg/m39/extended, VENDOR_ITEM_REGULAR), - list("M41A MK2 Extended Magazine (10x24mm)", round(scale * 3), /obj/item/ammo_magazine/rifle/extended, VENDOR_ITEM_REGULAR), - - list("INCENDIARY AMMUNITION", -1, null, null), - list("M4RA Incendiary Magazine (10x24mm)", round(scale * 3), /obj/item/ammo_magazine/rifle/m4ra/incendiary, VENDOR_ITEM_REGULAR), - list("M39 Incendiary Magazine (10x20mm)", round(scale * 2), /obj/item/ammo_magazine/smg/m39/incendiary, VENDOR_ITEM_REGULAR), - list("M41A MK2 Incendiary Magazine (10x24mm)", round(scale * 3), /obj/item/ammo_magazine/rifle/incendiary, VENDOR_ITEM_REGULAR), - list("M4A3 Incendiary Magazine (9mm)", round(scale * 1), /obj/item/ammo_magazine/pistol/incendiary, VENDOR_ITEM_REGULAR), - - list("SPECIAL AMMUNITION", -1, null, null), - list("Incinerator Tank", round(scale * 2.5), /obj/item/ammo_magazine/flamer_tank, VENDOR_ITEM_REGULAR), - list("M41AE2 Ammo Box (10x24mm)", round(scale * 5), /obj/item/ammo_magazine/rifle/lmg, VENDOR_ITEM_REGULAR), - list("M44 Heavy Speed Loader (.44)", round(scale * 2), /obj/item/ammo_magazine/revolver/heavy, VENDOR_ITEM_REGULAR), - list("M44 Marksman Speed Loader (.44)", round(scale * 2), /obj/item/ammo_magazine/revolver/marksman, VENDOR_ITEM_REGULAR), - list("M4A3 HP Magazine (9mm)", round(scale * 5), /obj/item/ammo_magazine/pistol/hp, VENDOR_ITEM_REGULAR), - list("M56 Battery", round(scale * 5), /obj/item/smartgun_battery, VENDOR_ITEM_REGULAR), - list("M56 Smartgun Drum", round(scale * 2), /obj/item/ammo_magazine/smartgun, VENDOR_ITEM_REGULAR), - list("SU-6 Smartpistol Magazine (.45)", round(scale * 6), /obj/item/ammo_magazine/pistol/smart, VENDOR_ITEM_REGULAR), - list("VP78 Magazine", round(scale * 6), /obj/item/ammo_magazine/pistol/vp78, VENDOR_ITEM_REGULAR), - +/obj/structure/machinery/cm_vending/sorted/cargo_ammo/cargo/wo/populate_product_list(scale) + ..() + listed_products += list( list("EXTRA SCOUT AMMUNITION", -1, null, null, null), list("A19 High Velocity Impact Magazine (10x24mm)", round(scale * 1), /obj/item/ammo_magazine/rifle/m4ra/custom/impact, VENDOR_ITEM_REGULAR), list("A19 High Velocity Incendiary Magazine (10x24mm)", round(scale * 1), /obj/item/ammo_magazine/rifle/m4ra/custom/incendiary, VENDOR_ITEM_REGULAR), @@ -181,96 +142,17 @@ list("Large Incinerator Tank", round(scale * 1), /obj/item/ammo_magazine/flamer_tank/large, VENDOR_ITEM_REGULAR), list("Large Incinerator Tank (B) (Green Flame)", round(scale * 1), /obj/item/ammo_magazine/flamer_tank/large/B, VENDOR_ITEM_REGULAR), list("Large Incinerator Tank (X) (Blue Flame)", round(scale * 1), /obj/item/ammo_magazine/flamer_tank/large/X, VENDOR_ITEM_REGULAR), - - list("AMMUNITION BOXES", -1, null, null), - list("Rifle Ammunition Box (10x24mm)", round(scale * 0.9), /obj/item/ammo_box/rounds, VENDOR_ITEM_REGULAR), - list("Rifle Ammunition Box (10x24mm AP)", round(scale * 0.75), /obj/item/ammo_box/rounds/ap, VENDOR_ITEM_REGULAR), - list("SMG Ammunition Box (10x20mm HV)", round(scale * 0.9), /obj/item/ammo_box/rounds/smg, VENDOR_ITEM_REGULAR), - list("SMG Ammunition Box (10x20mm AP)", round(scale * 0.75), /obj/item/ammo_box/rounds/smg/ap, VENDOR_ITEM_REGULAR), ) //------------ARMAMENTS VENDOR--------------- -/obj/structure/machinery/cm_vending/sorted/cargo_guns/wo +/obj/structure/machinery/cm_vending/sorted/cargo_guns/cargo/wo req_access = list(ACCESS_MARINE_CARGO) + vend_dir = NORTH + vend_dir_whitelist = list(EAST, WEST) -/obj/structure/machinery/cm_vending/sorted/cargo_guns/wo/populate_product_list(scale) - listed_products = list( - list("PRIMARY FIREARMS", -1, null, null), - list("M4RA Battle Rifle", round(scale * 20), /obj/item/weapon/gun/rifle/m4ra, VENDOR_ITEM_REGULAR), - list("M37A2 Pump Shotgun", round(scale * 10), /obj/item/weapon/gun/shotgun/pump, VENDOR_ITEM_REGULAR), - list("M39 Submachinegun", round(scale * 15), /obj/item/weapon/gun/smg/m39, VENDOR_ITEM_REGULAR), - list("M41A Pulse Rifle MK1", round(scale * 20), /obj/item/weapon/gun/rifle/m41aMK1, VENDOR_ITEM_REGULAR), - list("M41A Pulse Rifle MK2", round(scale * 20), /obj/item/weapon/gun/rifle/m41a, VENDOR_ITEM_REGULAR), - list("MK221 Tactical Shotgun", round(scale * 3), /obj/item/weapon/gun/shotgun/combat, VENDOR_ITEM_REGULAR), - - list("SIDEARMS", -1, null, null), - list("88 Mod 4 Combat Pistol", round(scale * 15), /obj/item/weapon/gun/pistol/mod88, VENDOR_ITEM_REGULAR), - list("M44 Combat Revolver", round(scale * 10), /obj/item/weapon/gun/revolver/m44, VENDOR_ITEM_REGULAR), - list("M4A3 Service Pistol", round(scale * 20), /obj/item/weapon/gun/pistol/m4a3, VENDOR_ITEM_REGULAR), - list("SU-6 Smartpistol", round(scale * 2), /obj/item/weapon/gun/pistol/smart, VENDOR_ITEM_REGULAR), - list("M82F Flare Gun", round(scale * 5), /obj/item/weapon/gun/flare, VENDOR_ITEM_REGULAR), - - list("RESTRICTED FIREARMS", -1, null, null), - list("VP78 Pistol", round(scale * 4), /obj/item/storage/box/guncase/vp78, VENDOR_ITEM_REGULAR), - list("SU-6 Smart Pistol", round(scale * 3), /obj/item/storage/box/guncase/smartpistol, VENDOR_ITEM_REGULAR), - list("M41AE2 Heavy Pulse Rifle", round(scale * 2), /obj/item/storage/box/guncase/lmg, VENDOR_ITEM_REGULAR), - list("M56D Heavy Machine Gun", round(scale * 2), /obj/item/storage/box/guncase/m56d, VENDOR_ITEM_REGULAR), - list("M2C Heavy Machine Gun", round(scale * 2), /obj/item/storage/box/guncase/m2c, VENDOR_ITEM_REGULAR), - list("M240 Incinerator Unit", round(scale * 2), /obj/item/storage/box/guncase/flamer, VENDOR_ITEM_REGULAR), - - list("EXPLOSIVES", -1, null, null), - list("M15 Fragmentation Grenade", round(scale * 2), /obj/item/explosive/grenade/high_explosive/m15, VENDOR_ITEM_REGULAR), - list("M20 Claymore Anti-Personnel Mine", round(scale * 5), /obj/item/explosive/mine, VENDOR_ITEM_REGULAR), - list("M40 HEDP Grenade Box", round(scale * 1), /obj/item/storage/box/nade_box, VENDOR_ITEM_REGULAR), - list("M40 HIDP Incendiary Grenade", round(scale * 3), /obj/item/explosive/grenade/incendiary, VENDOR_ITEM_REGULAR), - list("M40 HSDP Smoke Grenade", round(scale * 5), /obj/item/explosive/grenade/smokebomb, VENDOR_ITEM_REGULAR), - - list("BACKPACKS", -1, null, null), - list("Lightweight IMP Backpack", round(scale * 15), /obj/item/storage/backpack/marine, VENDOR_ITEM_REGULAR), - list("Shotgun Scabbard", round(scale * 10), /obj/item/storage/large_holster/m37, VENDOR_ITEM_REGULAR), - list("USCM Pyrotechnician G4-1 Fueltank", round(scale * 2), /obj/item/storage/backpack/marine/engineerpack/flamethrower/kit, VENDOR_ITEM_REGULAR), - list("USCM Technician Welderpack", round(scale * 2), /obj/item/storage/backpack/marine/engineerpack, VENDOR_ITEM_REGULAR), - - list("BELTS", -1, null, null), - list("G8-A General Utility Pouch", round(scale * 3), /obj/item/storage/backpack/general_belt, VENDOR_ITEM_REGULAR), - list("M276 Pattern Ammo Load Rig", round(scale * 15), /obj/item/storage/belt/marine, VENDOR_ITEM_REGULAR), - list("M276 Pattern General Pistol Holster Rig", round(scale * 10), /obj/item/storage/belt/gun/m4a3, VENDOR_ITEM_REGULAR), - list("M276 Pattern M39 Holster Rig", round(scale * 5), /obj/item/storage/belt/gun/m39, VENDOR_ITEM_REGULAR), - list("M276 Pattern M44 Holster Rig", round(scale * 5), /obj/item/storage/belt/gun/m44, VENDOR_ITEM_REGULAR), - list("M276 M82F Holster Rig", round(scale * 2), /obj/item/storage/belt/gun/flaregun, VENDOR_ITEM_REGULAR), - list("M276 Pattern Shotgun Shell Loading Rig", round(scale * 10), /obj/item/storage/belt/shotgun, VENDOR_ITEM_REGULAR), - - list("WEBBINGS", -1, null, null), - list("Black Webbing Vest", round(scale * 5), /obj/item/clothing/accessory/storage/black_vest, VENDOR_ITEM_REGULAR), - list("Brown Webbing Vest", round(scale * 5), /obj/item/clothing/accessory/storage/black_vest/brown_vest, VENDOR_ITEM_REGULAR), - list("Shoulder Holster", round(scale * 5), /obj/item/clothing/accessory/storage/holster, VENDOR_ITEM_REGULAR), - list("Webbing", round(scale * 5), /obj/item/clothing/accessory/storage/webbing, VENDOR_ITEM_REGULAR), - list("Knife Webbing", round(scale * 3), /obj/item/clothing/accessory/storage/knifeharness, VENDOR_ITEM_REGULAR), - list("Drop Pouch", round(scale * 5), /obj/item/clothing/accessory/storage/droppouch, VENDOR_ITEM_REGULAR), - - list("POUCHES", -1, null, null), - list("Construction Pouch", round(scale * 2), /obj/item/storage/pouch/construction, VENDOR_ITEM_REGULAR), - list("Explosive Pouch", round(scale * 2), /obj/item/storage/pouch/explosive, VENDOR_ITEM_REGULAR), - list("First-Aid Pouch (Full)", round(scale * 5), /obj/item/storage/pouch/firstaid/full, VENDOR_ITEM_REGULAR), - list("First Responder Pouch", round(scale * 2), /obj/item/storage/pouch/first_responder, VENDOR_ITEM_REGULAR), - list("Flare Pouch (Full)", round(scale * 5), /obj/item/storage/pouch/flare/full, VENDOR_ITEM_REGULAR), - list("Fuel Tank Strap Pouch", round(scale * 4), /obj/item/storage/pouch/flamertank, VENDOR_ITEM_REGULAR), - list("Large Pistol Magazine Pouch", round(scale * 5), /obj/item/storage/pouch/magazine/pistol/large, VENDOR_ITEM_REGULAR), - list("Magazine Pouch", round(scale * 5), /obj/item/storage/pouch/magazine, VENDOR_ITEM_REGULAR), - list("Medical Pouch", round(scale * 2), /obj/item/storage/pouch/medical, VENDOR_ITEM_REGULAR), - list("Medium General Pouch", round(scale * 2), /obj/item/storage/pouch/general/medium, VENDOR_ITEM_REGULAR), - list("Medkit Pouch", round(scale * 2), /obj/item/storage/pouch/medkit, VENDOR_ITEM_REGULAR), - list("Sidearm Pouch", round(scale * 15), /obj/item/storage/pouch/pistol, VENDOR_ITEM_REGULAR), - list("Syringe Pouch", round(scale * 2), /obj/item/storage/pouch/syringe, VENDOR_ITEM_REGULAR), - list("Tools Pouch (Full)", round(scale * 2), /obj/item/storage/pouch/tools/full, VENDOR_ITEM_REGULAR), - - list("MISCELLANEOUS", -1, null, null), - list("Combat Flashlight", round(scale * 5), /obj/item/device/flashlight/combat, VENDOR_ITEM_REGULAR), - list("Entrenching Tool (ET)", round(scale * 4), /obj/item/tool/shovel/etool, VENDOR_ITEM_REGULAR), - list("Gas Mask", round(scale * 10), /obj/item/clothing/mask/gas, VENDOR_ITEM_REGULAR), - list("M89-S Signal Flare Pack", round(scale * 2), /obj/item/storage/box/m94/signal, VENDOR_ITEM_REGULAR), - list("M94 Marking Flare Pack", round(scale * 10), /obj/item/storage/box/m94, VENDOR_ITEM_REGULAR), - list("Machete Scabbard (Full)", round(scale * 20), /obj/item/storage/large_holster/machete/full, VENDOR_ITEM_REGULAR), - list("MB-6 Folding Barricades (x3)", round(scale * 1), /obj/item/stack/folding_barricade/three, VENDOR_ITEM_REGULAR) - ) +//---- ATTACHIES +/obj/structure/machinery/cm_vending/sorted/attachments/wo + req_access = list(ACCESS_MARINE_CARGO) + vend_dir = NORTH + vend_dir_whitelist = list(SOUTHWEST, SOUTHEAST) diff --git a/code/game/objects/effects/aliens.dm b/code/game/objects/effects/aliens.dm index 49d758b52b19..867c6924b39d 100644 --- a/code/game/objects/effects/aliens.dm +++ b/code/game/objects/effects/aliens.dm @@ -287,19 +287,23 @@ opacity = FALSE anchored = TRUE unacidable = TRUE + /// Target the acid is melting var/atom/acid_t - var/ticks = 0 - var/acid_strength = 1 //100% speed, normal - var/barricade_damage = 40 + /// Duration left to next acid stage + var/remaining = 0 + /// Acid stages left to complete melting + var/ticks_left = 3 + /// Factor of duration between acid progression + var/acid_delay = 1 /// How much fuel the acid drains from the flare every acid tick var/flare_damage = 500 - var/barricade_damage_ticks = 10 // tick is once per 5 seconds. This tells us how many times it will try damaging barricades + var/barricade_damage = 40 var/in_weather = FALSE //Sentinel weakest acid /obj/effect/xenomorph/acid/weak name = "weak acid" - acid_strength = 2.5 //250% normal speed + acid_delay = 2.5 //250% delay (40% speed) barricade_damage = 20 flare_damage = 150 icon_state = "acid_weak" @@ -307,24 +311,32 @@ //Superacid /obj/effect/xenomorph/acid/strong name = "strong acid" - acid_strength = 0.4 //40% normal speed + acid_delay = 0.4 //40% delay (250% speed) barricade_damage = 100 flare_damage = 1875 icon_state = "acid_strong" -/obj/effect/xenomorph/acid/New(loc, target) - ..(loc) +/obj/effect/xenomorph/acid/Initialize(mapload, atom/target) + . = ..() acid_t = target - var/strength_t = isturf(acid_t) ? 8:4 // Turf take twice as long to take down. + if(isturf(acid_t)) + ticks_left = 7 // Turf take twice as long to take down. + else if(istype(acid_t, /obj/structure/barricade)) + ticks_left = 9 handle_weather() - tick(strength_t) - RegisterSignal(SSdcs, COMSIG_GLOB_WEATHER_CHANGE, PROC_REF(handle_weather)) + RegisterSignal(acid_t, COMSIG_PARENT_QDELETING, PROC_REF(cleanup)) + START_PROCESSING(SSeffects, src) /obj/effect/xenomorph/acid/Destroy() acid_t = null + STOP_PROCESSING(SSeffects, src) . = ..() +/obj/effect/xenomorph/acid/proc/cleanup() + SIGNAL_HANDLER + qdel(src) + /obj/effect/xenomorph/acid/proc/handle_weather() SIGNAL_HANDLER @@ -333,76 +345,85 @@ return if(SSweather.is_weather_event && locate(acids_area) in SSweather.weather_areas) - acid_strength = acid_strength + (SSweather.weather_event_instance.fire_smothering_strength * 0.33) //smothering_strength is 1-10, acid strength is a multiplier + acid_delay = acid_delay + (SSweather.weather_event_instance.fire_smothering_strength * 0.33) //smothering_strength is 1-10, acid strength is a multiplier in_weather = SSweather.weather_event_instance.fire_smothering_strength else - acid_strength = initial(acid_strength) + acid_delay = initial(acid_delay) in_weather = FALSE /obj/effect/xenomorph/acid/proc/handle_barricade() + if(prob(in_weather)) + visible_message(SPAN_XENOWARNING("Acid on \The [acid_t] subsides!")) + return NONE var/obj/structure/barricade/cade = acid_t - if(istype(cade)) - cade.take_acid_damage(barricade_damage) - -/obj/effect/xenomorph/acid/proc/tick(strength_t) - set waitfor = 0 - if(!acid_t || !acid_t.loc) - qdel(src) + cade.take_acid_damage(barricade_damage) + return (5 SECONDS) + +/obj/effect/xenomorph/acid/proc/handle_flashlight() + var/obj/item/device/flashlight/flare/flare = acid_t + if(flare.fuel <= 0) + return NONE + flare.fuel -= flare_damage + return (rand(15, 25) SECONDS) * acid_delay + +/obj/effect/xenomorph/acid/process(delta_time) + remaining -= delta_time * (1 SECONDS) + if(remaining > 0) return + ticks_left -= 1 - if(istype(acid_t,/obj/structure/barricade)) - if(++ticks >= barricade_damage_ticks || prob(in_weather)) - visible_message(SPAN_XENOWARNING("Acid on \The [acid_t] subsides!")) - qdel(src) - return - handle_barricade() - sleep(50) - .() - return - if(istype(acid_t, /obj/item/device/flashlight/flare)) - var/obj/item/device/flashlight/flare/flare = acid_t - if(flare.fuel > 0) //Flares that have fuel in them lose fuel instead of melting - flare.fuel -= flare_damage - sleep(rand(150,250) * (acid_strength)) - return .() - - if(++ticks >= strength_t) - visible_message(SPAN_XENODANGER("[acid_t] collapses under its own weight into a puddle of goop and undigested debris!")) - playsound(src, "acid_hit", 25, TRUE) - - if(istype(acid_t, /turf)) - if(istype(acid_t, /turf/closed/wall)) - var/turf/closed/wall/W = acid_t - new /obj/effect/acid_hole (W) - else - var/turf/T = acid_t - T.ScrapeAway() - else if (istype(acid_t, /obj/structure/girder)) - var/obj/structure/girder/G = acid_t - G.dismantle() - else if(istype(acid_t, /obj/structure/window/framed)) - var/obj/structure/window/framed/WF = acid_t - WF.deconstruct(disassembled = FALSE) - else if(istype(acid_t,/obj/item/explosive/plastic)) - qdel(acid_t) + var/return_delay = NONE + if(istype(acid_t, /obj/structure/barricade)) + return_delay = handle_barricade() + else if(istype(acid_t, /obj/item/device/flashlight/flare)) + return_delay = handle_flashlight() + else + return_delay = (rand(20, 30) SECONDS) * acid_delay - else - if(acid_t.contents.len) //Hopefully won't auto-delete things inside melted stuff.. - for(var/mob/M in acid_t.contents) - if(acid_t.loc) M.forceMove(acid_t.loc) - QDEL_NULL(acid_t) + if(!ticks_left) + finish_melting() + return PROCESS_KILL + if(!return_delay) qdel(src) - return + return PROCESS_KILL - switch(strength_t - ticks) + remaining = return_delay + + switch(ticks_left) if(6) visible_message(SPAN_XENOWARNING("\The [acid_t] is barely holding up against the acid!")) if(4) visible_message(SPAN_XENOWARNING("\The [acid_t]\s structure is being melted by the acid!")) if(2) visible_message(SPAN_XENOWARNING("\The [acid_t] is struggling to withstand the acid!")) if(0 to 1) visible_message(SPAN_XENOWARNING("\The [acid_t] begins to crumble under the acid!")) - sleep(rand(200,300) * (acid_strength)) - .() +/obj/effect/xenomorph/acid/proc/finish_melting() + visible_message(SPAN_XENODANGER("[acid_t] collapses under its own weight into a puddle of goop and undigested debris!")) + playsound(src, "acid_hit", 25, TRUE) + + if(istype(acid_t, /turf)) + if(istype(acid_t, /turf/closed/wall)) + var/turf/closed/wall/wall = acid_t + new /obj/effect/acid_hole(wall) + else + var/turf/turf = acid_t + turf.ScrapeAway() + + else if (istype(acid_t, /obj/structure/girder)) + var/obj/structure/girder/girder = acid_t + girder.dismantle() + + else if(istype(acid_t, /obj/structure/window/framed)) + var/obj/structure/window/framed/window = acid_t + window.deconstruct(disassembled = FALSE) + + else if(istype(acid_t, /obj/structure/barricade)) + pass() // Don't delete it, just damaj + + else + for(var/mob/mob in acid_t) + mob.forceMove(loc) + qdel(acid_t) + qdel(src) /obj/effect/xenomorph/boiler_bombard name = "???" diff --git a/code/game/objects/effects/decals/cleanable/blood/tracks.dm b/code/game/objects/effects/decals/cleanable/blood/tracks.dm index 32593f6f30fa..c764259a6252 100644 --- a/code/game/objects/effects/decals/cleanable/blood/tracks.dm +++ b/code/game/objects/effects/decals/cleanable/blood/tracks.dm @@ -14,6 +14,9 @@ var/list/overlay_images = list() + /// Amount of pixels to shift either way in an attempt to make the tracks more organic + var/transverse_amplitude = 3 + /obj/effect/decal/cleanable/blood/tracks/Crossed() return @@ -21,19 +24,27 @@ return FALSE /obj/effect/decal/cleanable/blood/tracks/proc/add_tracks(direction, tcolor, out) - var/image/I = image(icon = icon, icon_state = out ? going_state : coming_state, dir = direction) - var/mutable_appearance/MA = new(I) + var/image/image = image(icon = icon, icon_state = out ? going_state : coming_state, dir = direction) + + var/mutable_appearance/MA = new(image) MA.color = tcolor MA.layer = layer MA.appearance_flags |= RESET_COLOR - I.appearance = MA + image.appearance = MA + + switch(direction) + if(NORTH, SOUTH) + image.pixel_x += rand(-transverse_amplitude, transverse_amplitude) + if(EAST, WEST) + image.pixel_y += rand(-transverse_amplitude, transverse_amplitude) + if(out) - LAZYSET(steps_out, "[direction]", I) + LAZYSET(steps_out, "[direction]", image) else - LAZYSET(steps_in, "[direction]", I) + LAZYSET(steps_in, "[direction]", image) - overlay_images += I - cleanable_turf.overlays += I + overlay_images += image + cleanable_turf.overlays += image /obj/effect/decal/cleanable/blood/tracks/clear_overlay() if(length(overlay_images)) diff --git a/code/game/objects/effects/decals/posters.dm b/code/game/objects/effects/decals/posters.dm index c688c4e6fb67..7a8054efce1a 100644 --- a/code/game/objects/effects/decals/posters.dm +++ b/code/game/objects/effects/decals/posters.dm @@ -184,6 +184,12 @@ serial_number = pick(27,28,30,31) .=..() +/obj/structure/sign/poster/io + icon_state = "poster14" + +/obj/structure/sign/poster/io/Initialize() + serial_number = 14 + . = ..() //////////////// //Hero Posters// //////////////// diff --git a/code/game/objects/effects/decals/warning_stripes.dm b/code/game/objects/effects/decals/warning_stripes.dm index ce0802d72d8e..20c96c2ac737 100644 --- a/code/game/objects/effects/decals/warning_stripes.dm +++ b/code/game/objects/effects/decals/warning_stripes.dm @@ -91,6 +91,20 @@ /obj/effect/decal/sand_overlay/sand2/corner2 icon_state = "sand2_c" +/obj/effect/decal/grass_overlay + name = "grass edge" + mouse_opacity = MOUSE_OPACITY_TRANSPARENT + unacidable = TRUE + icon = 'icons/turf/floors/auto_strata_grass.dmi' + layer = TURF_LAYER + +/obj/effect/decal/grass_overlay/grass1 + icon_state = "grass_outercorner" + +/obj/effect/decal/grass_overlay/grass1/inner + name = "grass edge" + icon_state = "grass_innercorner" + /obj/effect/decal/siding name = "siding" icon = 'icons/turf/floors/floors.dmi' diff --git a/code/game/objects/effects/effect_system/smoke.dm b/code/game/objects/effects/effect_system/smoke.dm index 78aa01b5dacb..b80f53b14d2e 100644 --- a/code/game/objects/effects/effect_system/smoke.dm +++ b/code/game/objects/effects/effect_system/smoke.dm @@ -31,13 +31,13 @@ amount = oldamount - 1 cause_data = new_cause_data time_to_live += rand(-1,1) - active_smoke_effects += src + START_PROCESSING(SSeffects, src) /obj/effect/particle_effect/smoke/Destroy() . = ..() if(opacity) set_opacity(0) - active_smoke_effects -= src + STOP_PROCESSING(SSeffects, src) cause_data = null /obj/effect/particle_effect/smoke/initialize_pass_flags(datum/pass_flags_container/PF) diff --git a/code/game/objects/effects/glowshroom.dm b/code/game/objects/effects/glowshroom.dm index bebe0ec8b27f..56c6ae45cda7 100644 --- a/code/game/objects/effects/glowshroom.dm +++ b/code/game/objects/effects/glowshroom.dm @@ -95,8 +95,6 @@ if(EXPLOSION_THRESHOLD_MEDIUM to INFINITY) deconstruct(FALSE) return - else - return /obj/effect/glowshroom/fire_act(exposed_temperature, exposed_volume) if(exposed_temperature > 300) diff --git a/code/game/objects/effects/landmarks/survivor_spawner.dm b/code/game/objects/effects/landmarks/survivor_spawner.dm index 25cc1a80d0b4..a53fead0d3bf 100644 --- a/code/game/objects/effects/landmarks/survivor_spawner.dm +++ b/code/game/objects/effects/landmarks/survivor_spawner.dm @@ -8,6 +8,8 @@ var/roundstart_damage_min = 0 var/roundstart_damage_max = 0 var/roundstart_damage_times = 1 + /// Whether or not the spawner is for an inherently hostile survivor subtype. + var/hostile = FALSE var/spawn_priority = LOWEST_SPAWN_PRIORITY @@ -27,6 +29,7 @@ return TRUE /obj/effect/landmark/survivor_spawner/lv624_crashed_clf + hostile = TRUE equipment = /datum/equipment_preset/survivor/clf synth_equipment = /datum/equipment_preset/clf/synth intro_text = list("

You are a survivor of a crash landing!

",\ @@ -40,6 +43,7 @@ spawn_priority = SPAWN_PRIORITY_HIGH /obj/effect/landmark/survivor_spawner/lv624_crashed_clf_engineer + hostile = TRUE equipment = /datum/equipment_preset/clf/engineer synth_equipment = /datum/equipment_preset/clf/synth intro_text = list("

You are a survivor of a crash landing!

",\ @@ -53,6 +57,7 @@ spawn_priority = SPAWN_PRIORITY_VERY_HIGH /obj/effect/landmark/survivor_spawner/lv624_crashed_clf_medic + hostile = TRUE equipment = /datum/equipment_preset/clf/medic synth_equipment = /datum/equipment_preset/clf/synth intro_text = list("

You are a survivor of a crash landing!

",\ @@ -145,7 +150,7 @@ intro_text = list("

You are a member of a UPP recon force!

",\ "You ARE aware of the xenomorph threat.",\ "Your primary objective is to survive. You believe a second dropship crashed somewhere to the south east, which was carrying additional weapons") - story_text = "Your orders were simple, Recon the site, ascertain if there is a biological weapons program in the area, and if so to secure the colony and retrieve a sample. However your team failed to account for an active anti-air battery near the area. Both your craft and your sister ship crashed. Barely having a chance to catch your breath, you found yourself being assailed by vile xenomorphs! You and your team have barely held your ground, at the cost of four of your own, but more are coming and ammo is low. You believe an American rescue force is en route, but is the enemy of my enemy truly your friend?" + story_text = "Your orders were simple, Recon the site, ascertain if there is a biological weapons program in the area, and if so to secure the colony and retrieve a sample. However your team failed to account for an active anti-air battery near the area. Both your craft and your sister ship crashed. Barely having a chance to catch your breath, you found yourself being assailed by vile xenomorphs! You and your team have barely held your ground, at the cost of four of your own, but more are coming and ammo is low. You believe an American rescue force is en route." spawn_priority = SPAWN_PRIORITY_LOW /obj/effect/landmark/survivor_spawner/upp_sapper @@ -154,7 +159,7 @@ intro_text = list("

You are a member of a UPP recon force!

",\ "You ARE aware of the xenomorph threat.",\ "Your primary objective is to survive. You believe a second dropship crashed somewhere to the south east, which was carrying additional weapons") - story_text = "Your orders were simple, Recon the site, ascertain if there is a biological weapons program in the area, and if so to secure the colony and retrieve a sample. However your team failed to account for an active anti-air battery near the area. Both your craft and your sister ship crashed. Barely having a chance to catch your breath, you found yourself being assailed by vile xenomorphs! You and your team have barely held your ground, at the cost of four of your own, but more are coming and ammo is low. You believe an American rescue force is en route, but is the enemy of my enemy truly your friend?" + story_text = "Your orders were simple, Recon the site, ascertain if there is a biological weapons program in the area, and if so to secure the colony and retrieve a sample. However your team failed to account for an active anti-air battery near the area. Both your craft and your sister ship crashed. Barely having a chance to catch your breath, you found yourself being assailed by vile xenomorphs! You and your team have barely held your ground, at the cost of four of your own, but more are coming and ammo is low. You believe an American rescue force is en route." spawn_priority = SPAWN_PRIORITY_MEDIUM /obj/effect/landmark/survivor_spawner/upp_medic @@ -163,7 +168,7 @@ intro_text = list("

You are a member of a UPP recon force!

",\ "You ARE aware of the xenomorph threat.",\ "Your primary objective is to survive. You believe a second dropship crashed somewhere to the south east, which was carrying additional weapons") - story_text = "Your orders were simple, Recon the site, ascertain if there is a biological weapons program in the area, and if so to secure the colony and retrieve a sample. However your team failed to account for an active anti-air battery near the area. Both your craft and your sister ship crashed. Barely having a chance to catch your breath, you found yourself being assailed by vile xenomorphs! You and your team have barely held your ground, at the cost of four of your own, but more are coming and ammo is low. You believe an American rescue force is en route, but is the enemy of my enemy truly your friend?" + story_text = "Your orders were simple, Recon the site, ascertain if there is a biological weapons program in the area, and if so to secure the colony and retrieve a sample. However your team failed to account for an active anti-air battery near the area. Both your craft and your sister ship crashed. Barely having a chance to catch your breath, you found yourself being assailed by vile xenomorphs! You and your team have barely held your ground, at the cost of four of your own, but more are coming and ammo is low. You believe an American rescue force is en route." spawn_priority = SPAWN_PRIORITY_MEDIUM /obj/effect/landmark/survivor_spawner/upp_specialist @@ -172,7 +177,7 @@ intro_text = list("

You are a member of a UPP recon force!

",\ "You ARE aware of the xenomorph threat.",\ "Your primary objective is to survive. You believe a second dropship crashed somewhere to the south east, which was carrying additional weapons") - story_text = "Your orders were simple, Recon the site, ascertain if there is a biological weapons program in the area, and if so to secure the colony and retrieve a sample. However your team failed to account for an active anti-air battery near the area. Both your craft and your sister ship crashed. Barely having a chance to catch your breath, you found yourself being assailed by vile xenomorphs! You and your team have barely held your ground, at the cost of four of your own, but more are coming and ammo is low. You believe an American rescue force is en route, but is the enemy of my enemy truly your friend?" + story_text = "Your orders were simple, Recon the site, ascertain if there is a biological weapons program in the area, and if so to secure the colony and retrieve a sample. However your team failed to account for an active anti-air battery near the area. Both your craft and your sister ship crashed. Barely having a chance to catch your breath, you found yourself being assailed by vile xenomorphs! You and your team have barely held your ground, at the cost of four of your own, but more are coming and ammo is low. You believe an American rescue force is en route." spawn_priority = SPAWN_PRIORITY_HIGH /obj/effect/landmark/survivor_spawner/squad_leader @@ -181,5 +186,5 @@ intro_text = list("

You are a member of a UPP recon force!

",\ "You ARE aware of the xenomorph threat.",\ "Your primary objective is to survive. You believe a second dropship crashed somewhere to the south east, which was carrying additional weapons") - story_text = "Your orders were simple, Recon the site, ascertain if there is a biological weapons program in the area, and if so to secure the colony and retrieve a sample. However your team failed to account for an active anti-air battery near the area. Both your craft and your sister ship crashed. Barely having a chance to catch your breath, you found yourself being assailed by vile xenomorphs! You and your team have barely held your ground, at the cost of four of your own, but more are coming and ammo is low. You believe an American rescue force is en route, but is the enemy of my enemy truly your friend?" + story_text = "Your orders were simple, Recon the site, ascertain if there is a biological weapons program in the area, and if so to secure the colony and retrieve a sample. However your team failed to account for an active anti-air battery near the area. Both your craft and your sister ship crashed. Barely having a chance to catch your breath, you found yourself being assailed by vile xenomorphs! You and your team have barely held your ground, at the cost of four of your own, but more are coming and ammo is low. You believe an American rescue force is en route." spawn_priority = SPAWN_PRIORITY_VERY_HIGH diff --git a/code/game/objects/effects/spawners/faction_spawners.dm b/code/game/objects/effects/spawners/faction_spawners.dm new file mode 100644 index 000000000000..2daf6392e5e7 --- /dev/null +++ b/code/game/objects/effects/spawners/faction_spawners.dm @@ -0,0 +1,197 @@ +/* + * USCM weapons + */ +/obj/effect/spawner/random/gun/uscm_primary + name = "USCM primary weapon spawner" + desc = "spawns USCM primary weapons" + mags_max = 2 + mags_min = 1 + guns = list( + /obj/item/weapon/gun/rifle/m41a = /obj/item/ammo_magazine/rifle, + /obj/item/weapon/gun/rifle/m41a/tactical = /obj/item/ammo_magazine/rifle, + /obj/item/weapon/gun/smg/m39 = /obj/item/ammo_magazine/smg/m39, + /obj/item/weapon/gun/smg/m39 = /obj/item/ammo_magazine/smg/m39, + /obj/item/weapon/gun/shotgun/pump = /datum/ammo/bullet/shotgun/buckshot + ) + +/obj/effect/spawner/random/gun/uscm_primary/lowchance + spawn_nothing_percentage = 80 + icon_state = "loot_rifle_20" + +/obj/effect/spawner/random/gun/uscm_primary/midchance + spawn_nothing_percentage = 50 + icon_state = "loot_rifle_50" + +/obj/effect/spawner/random/gun/uscm_primary/highchance + spawn_nothing_percentage = 20 + icon_state = "loot_rifle_80" + +/obj/effect/spawner/random/gun/uscm_secondary + name = "USCM secondary weapon spawner" + desc = "spawns USCM secondary weapons" + spawn_nothing_percentage = 0 + mags_max = 2 + mags_min = 1 + guns = list( + /obj/item/weapon/gun/pistol/m4a3 = /obj/item/ammo_magazine/pistol, + /obj/item/weapon/gun/revolver/m44 = /obj/item/ammo_magazine/handful/revolver/marksman + ) + +/obj/effect/spawner/random/gun/uscm_secondary/lowchance + spawn_nothing_percentage = 80 + icon_state = "loot_pistol_20" + +/obj/effect/spawner/random/gun/uscm_secondary/midchance + spawn_nothing_percentage = 50 + icon_state = "loot_pistol_50" + +/obj/effect/spawner/random/gun/uscm_secondary/highchance + spawn_nothing_percentage = 80 + icon_state = "loot_pistol_80" + + +/* + * UPP weapons + */ +/obj/effect/spawner/random/gun/upp_primary + name = "UPP primary weapon spawner" + desc = "spawns UPP primary weapons" + mags_max = 2 + mags_min = 1 + guns = list( + /obj/item/weapon/gun/smg/bizon/upp = /obj/item/ammo_magazine/smg/bizon, + /obj/item/weapon/gun/rifle/type71 = /obj/item/ammo_magazine/rifle/type71, + /obj/item/weapon/gun/rifle/type71/carbine = /obj/item/ammo_magazine/rifle/type71 + ) + +/obj/effect/spawner/random/gun/upp_primary/lowchance + spawn_nothing_percentage = 80 + icon_state = "loot_rifle_20" + +/obj/effect/spawner/random/gun/upp_primary/midchance + spawn_nothing_percentage = 50 + icon_state = "loot_rifle_50" + +/obj/effect/spawner/random/gun/upp_primary/highchance + spawn_nothing_percentage = 80 + icon_state = "loot_rifle_80" + +/obj/effect/spawner/random/gun/upp_secondary + name = "UPP secondary weapon spawner" + desc = "spawns UPP secondary weapons" + mags_max = 2 + mags_min = 1 + guns = list( + /obj/item/weapon/gun/pistol/t73 = /obj/item/ammo_magazine/pistol/t73, + /obj/item/weapon/gun/pistol/np92 = /obj/item/ammo_magazine/pistol/np92, + /obj/item/weapon/gun/revolver/upp = /obj/item/ammo_magazine/revolver/upp + ) + +/obj/effect/spawner/random/gun/upp_secondary/lowchance + spawn_nothing_percentage = 80 + icon_state = "loot_pistol_20" + +/obj/effect/spawner/random/gun/upp_secondary/medchance + spawn_nothing_percentage = 50 + icon_state = "loot_pistol_50" + +/obj/effect/spawner/random/gun/upp_secondary/highchance + spawn_nothing_percentage = 20 + icon_state = "loot_pistol_80" +/* + * PMC weapons + */ +/obj/effect/spawner/random/gun/pmc_primary + name = "PMC primary weapon spawner" + desc = "spawns PMC primary weapons" + mags_max = 2 + mags_min = 1 + guns = list( + /obj/item/weapon/gun/rifle/m41a/elite = /obj/item/ammo_magazine/rifle/ap, + /obj/item/weapon/gun/rifle/m41a/elite = /obj/item/ammo_magazine/rifle/extended, + /obj/item/weapon/gun/smg/m39/elite = /obj/item/ammo_magazine/smg/m39/ap, + /obj/item/weapon/gun/smg/m39/elite = /obj/item/ammo_magazine/smg/m39/extended, + /obj/item/weapon/gun/rifle/nsg23 = /obj/item/ammo_magazine/rifle/nsg23/ap, + /obj/item/weapon/gun/rifle/nsg23 = /obj/item/ammo_magazine/rifle/nsg23/extended + ) + +/obj/effect/spawner/random/gun/pmc_primary/lowchance + spawn_nothing_percentage = 80 + icon_state = "loot_rifle_20" + +/obj/effect/spawner/random/gun/pmc_primary/midchance + spawn_nothing_percentage = 50 + icon_state = "loot_rifle_50" + +/obj/effect/spawner/random/gun/pmc_primary/highchance + spawn_nothing_percentage = 80 + icon_state = "loot_rifle_80" + +/obj/effect/spawner/random/gun/pmc_secondary + name = "PMC secondary weapon spawner" + desc = "spawns PMC secondary weapons" + mags_max = 2 + mags_min = 1 + guns = list( + /obj/item/weapon/gun/pistol/vp78 = /obj/item/ammo_magazine/pistol/vp78, + /obj/item/weapon/gun/pistol/mod88 = /obj/item/ammo_magazine/pistol/mod88 + ) + +/obj/effect/spawner/random/gun/pmc_secondary/lowchance + spawn_nothing_percentage = 80 + icon_state = "loot_pistol_20" + +/obj/effect/spawner/random/gun/pmc_secondary/medchance + spawn_nothing_percentage = 50 + icon_state = "loot_pistol_50" + +/obj/effect/spawner/random/gun/pmc_secondary/highchance + spawn_nothing_percentage = 20 + icon_state = "loot_pistol_80" + +/* + * CLF weapons + */ +/obj/effect/spawner/random/gun/clf_primary + name = "CLF primary weapon spawner" + desc = "spawns CLF primary weapons" + mags_max = 2 + mags_min = 1 + guns = list( + /obj/item/weapon/gun/rifle/m16 = /obj/item/ammo_magazine/rifle/m16, + /obj/item/weapon/gun/rifle/mar40/carbine = /obj/item/ammo_magazine/rifle/mar40 + ) + +/obj/effect/spawner/random/gun/clf_primary/lowchance + spawn_nothing_percentage = 80 + icon_state = "loot_rifle_20" + +/obj/effect/spawner/random/gun/clf_primary/midchance + spawn_nothing_percentage = 50 + icon_state = "loot_rifle_50" + +/obj/effect/spawner/random/gun/clf_primary/highchance + spawn_nothing_percentage = 80 + icon_state = "loot_rifle_80" + +/obj/effect/spawner/random/gun/clf_secondary + name = "CLF secondary weapon spawner" + desc = "spawns CLF secondary weapons" + mags_max = 2 + mags_min = 1 + guns = list( + /obj/item/weapon/gun/pistol/kt42 = /obj/item/ammo_magazine/pistol/kt42, + /obj/item/weapon/gun/pistol/b92fs = /obj/item/ammo_magazine/pistol/b92fs + ) + +/obj/effect/spawner/random/gun/clf_secondary/lowchance + spawn_nothing_percentage = 80 + icon_state = "loot_pistol_20" + +/obj/effect/spawner/random/gun/clf_secondary/medchance + spawn_nothing_percentage = 50 + icon_state = "loot_pistol_50" + +/obj/effect/spawner/random/gun/clf_secondary/highchance + spawn_nothing_percentage = 20 + icon_state = "loot_pistol_80" diff --git a/code/game/objects/effects/spawners/prop_gun_spawner.dm b/code/game/objects/effects/spawners/prop_gun_spawner.dm index b04f6cffffe1..5e620994e7fb 100644 --- a/code/game/objects/effects/spawners/prop_gun_spawner.dm +++ b/code/game/objects/effects/spawners/prop_gun_spawner.dm @@ -17,7 +17,7 @@ stack_trace("[src] using incorrect typepath, \"[prop_gun_type]\".") //Can't make a prop gun of something not a gun qdel(src) return - if(!spawn_prob) + if(!prob(spawn_prob)) qdel(src) return if(!mapload) @@ -71,6 +71,7 @@ pixel_x = source_gun.pixel_x pixel_y = source_gun.pixel_y layer = source_gun.layer + overlays = source_gun.overlays /obj/item/prop/prop_gun/attack_self(mob/user) //Mimic wielding of real guns . = ..() diff --git a/code/game/objects/effects/spawners/random.dm b/code/game/objects/effects/spawners/random.dm index 450981377a73..d302e7794f8b 100644 --- a/code/game/objects/effects/spawners/random.dm +++ b/code/game/objects/effects/spawners/random.dm @@ -57,10 +57,13 @@ icon_state = "atmos" /obj/effect/spawner/random/technology_scanner/item_to_spawn() - return pick(prob(5);/obj/item/device/t_scanner,\ - prob(2);/obj/item/device/radio,\ - prob(5);/obj/item/device/analyzer) - + return pick_weight(list( + "none" = 10, + /obj/item/device/t_scanner = 10, + /obj/item/device/radio = 8, + /obj/item/device/analyzer = 10, + /obj/item/device/black_market_hacking_device = 2, + )) /obj/effect/spawner/random/powercell name = "Random Powercell" @@ -348,8 +351,7 @@ /obj/effect/spawner/random/gun/proc/spawn_weapon_on_floor(gunpath, ammopath, ammo_amount = 1) - var/atom/spawnloc = src - spawnloc = get_turf(spawnloc) + var/turf/spawnloc = get_turf(src) var/obj/gun var/obj/ammo @@ -357,20 +359,20 @@ gun = new gunpath(spawnloc) if(scatter) var/direction = pick(alldirs) - var/turf/T = get_step(gun, direction) - if(!T || T.density) + var/turf/turf = get_step(gun, direction) + if(!turf || turf.density) return - gun.loc = T + gun.forceMove(turf) if(ammopath) for(var/i in 0 to ammo_amount-1) ammo = new ammopath(spawnloc) if(scatter) for(i=0, i= 0) spread_power *= 0.75 diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index 4dd63af46776..959d01b4f757 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -156,6 +156,11 @@ var/list/inherent_traits + /// How much to offset the item randomly either way alongside X visually + var/ground_offset_x = 0 + /// How much to offset the item randomly either way alongside Y visually + var/ground_offset_y = 0 + /obj/item/Initialize(mapload, ...) . = ..() @@ -175,6 +180,8 @@ if(flags_item & MOB_LOCK_ON_EQUIP) AddComponent(/datum/component/id_lock) + scatter_item() + /obj/item/Destroy() flags_item &= ~DELONDROP //to avoid infinite loop of unequip, delete, unequip, delete. flags_item &= ~NODROP //so the item is properly unequipped if on a mob. @@ -268,7 +275,6 @@ cases. Override_icon_state should be a list.*/ size = "huge" if(SIZE_MASSIVE) size = "massive" - else . += "This is a [blood_color ? blood_color != "#030303" ? "bloody " : "oil-stained " : ""][icon2html(src, user)][src.name]. It is a [size] item." if(desc) . += desc @@ -460,27 +466,32 @@ cases. Override_icon_state should be a list.*/ /obj/item/proc/item_action_slot_check(mob/user, slot) return TRUE +/obj/item/proc/scatter_item() + if(!pixel_x && !pixel_y) + pixel_x = rand(-ground_offset_x, ground_offset_x) + pixel_y = rand(-ground_offset_y, ground_offset_y) + // The mob M is attempting to equip this item into the slot passed through as 'slot'. return TRUE if it can do this and 0 if it can't. // If you are making custom procs but would like to retain partial or complete functionality of this one, include a 'return ..()' to where you want this to happen. // Set disable_warning to TRUE if you wish it to not give you outputs. // warning_text is used in the case that you want to provide a specific warning for why the item cannot be equipped. -/obj/item/proc/mob_can_equip(mob/M, slot, disable_warning = FALSE) +/obj/item/proc/mob_can_equip(mob/equipping_mob, slot, disable_warning = FALSE) if(!slot) return FALSE - if(!M) + if(!equipping_mob) return FALSE - if(SEND_SIGNAL(src, COMSIG_ITEM_ATTEMPTING_EQUIP, M) & COMPONENT_CANCEL_EQUIP) + if(SEND_SIGNAL(src, COMSIG_ITEM_ATTEMPTING_EQUIP, equipping_mob, slot) & COMPONENT_CANCEL_EQUIP) return FALSE - if(ishuman(M)) + if(ishuman(equipping_mob)) //START HUMAN - var/mob/living/carbon/human/H = M + var/mob/living/carbon/human/human = equipping_mob var/list/mob_equip = list() - if(H.hud_used && H.hud_used.equip_slots) - mob_equip = H.hud_used.equip_slots + if(human.hud_used && human.hud_used.equip_slots) + mob_equip = human.hud_used.equip_slots - if(H.species && !(slot in mob_equip)) + if(human.species && !(slot in mob_equip)) return FALSE if(uniform_restricted) @@ -491,136 +502,136 @@ cases. Override_icon_state should be a list.*/ required_clothing += initial(restriction_type.name) // You can't replace this with a switch(), flags_equip_slot is a bitfield if(valid_equip_slots & SLOT_ICLOTHING) - if(istype(H.w_uniform, restriction_type)) + if(istype(human.w_uniform, restriction_type)) restriction_satisfied = TRUE break if(valid_equip_slots & SLOT_OCLOTHING) - if(istype(H.wear_suit, restriction_type)) + if(istype(human.wear_suit, restriction_type)) restriction_satisfied = TRUE break if(!restriction_satisfied) if(!disable_warning) - to_chat(H, SPAN_WARNING("You cannot wear this without wearing one of the following; [required_clothing.Join(", ")].")) + to_chat(human, SPAN_WARNING("You cannot wear this without wearing one of the following; [required_clothing.Join(", ")].")) return FALSE switch(slot) if(WEAR_L_HAND) - if(H.l_hand) + if(human.l_hand) return FALSE - if(H.lying) - to_chat(H, SPAN_WARNING("You can't equip that while lying down.")) + if(human.lying) + to_chat(human, SPAN_WARNING("You can't equip that while lying down.")) return return TRUE if(WEAR_R_HAND) - if(H.r_hand) + if(human.r_hand) return FALSE - if(H.lying) - to_chat(H, SPAN_WARNING("You can't equip that while lying down.")) + if(human.lying) + to_chat(human, SPAN_WARNING("You can't equip that while lying down.")) return return TRUE if(WEAR_FACE) - if(H.wear_mask) + if(human.wear_mask) return FALSE if(!(flags_equip_slot & SLOT_FACE)) return FALSE return TRUE if(WEAR_BACK) - if(H.back) + if(human.back) return FALSE if(!(flags_equip_slot & SLOT_BACK)) return FALSE return TRUE if(WEAR_JACKET) - if(H.wear_suit) + if(human.wear_suit) return FALSE if(!(flags_equip_slot & SLOT_OCLOTHING)) return FALSE return TRUE if(WEAR_HANDS) - if(H.gloves) + if(human.gloves) return FALSE if(!(flags_equip_slot & SLOT_HANDS)) return FALSE return TRUE if(WEAR_FEET) - if(H.shoes) + if(human.shoes) return FALSE if(!(flags_equip_slot & SLOT_FEET)) return FALSE return TRUE if(WEAR_WAIST) - if(H.belt) + if(human.belt) return FALSE - if(!H.w_uniform && (WEAR_BODY in mob_equip)) + if(!human.w_uniform && (WEAR_BODY in mob_equip)) if(!disable_warning) - to_chat(H, SPAN_WARNING("You need a jumpsuit before you can attach this [name].")) + to_chat(human, SPAN_WARNING("You need a jumpsuit before you can attach this [name].")) return FALSE if(!(flags_equip_slot & SLOT_WAIST)) return return TRUE if(WEAR_EYES) - if(H.glasses) + if(human.glasses) return FALSE if(!(flags_equip_slot & SLOT_EYES)) return FALSE return TRUE if(WEAR_HEAD) - if(H.head) + if(human.head) return FALSE if(!(flags_equip_slot & SLOT_HEAD)) return FALSE return TRUE if(WEAR_L_EAR) - if(H.wear_l_ear) + if(human.wear_l_ear) return FALSE if(HAS_TRAIT(src, TRAIT_ITEM_EAR_EXCLUSIVE)) - if(H.wear_r_ear && HAS_TRAIT(H.wear_r_ear, TRAIT_ITEM_EAR_EXCLUSIVE)) + if(human.wear_r_ear && HAS_TRAIT(human.wear_r_ear, TRAIT_ITEM_EAR_EXCLUSIVE)) if(!disable_warning) - to_chat(H, SPAN_WARNING("You can't wear [src] while you have [H.wear_r_ear] in your right ear!")) + to_chat(human, SPAN_WARNING("You can't wear [src] while you have [human.wear_r_ear] in your right ear!")) return FALSE if(!(flags_equip_slot & SLOT_EAR)) return FALSE return TRUE if(WEAR_R_EAR) - if(H.wear_r_ear) + if(human.wear_r_ear) return FALSE if(HAS_TRAIT(src, TRAIT_ITEM_EAR_EXCLUSIVE)) - if(H.wear_l_ear && HAS_TRAIT(H.wear_l_ear, TRAIT_ITEM_EAR_EXCLUSIVE)) + if(human.wear_l_ear && HAS_TRAIT(human.wear_l_ear, TRAIT_ITEM_EAR_EXCLUSIVE)) if(!disable_warning) - to_chat(H, SPAN_WARNING("You can't wear [src] while you have [H.wear_l_ear] in your left ear!")) + to_chat(human, SPAN_WARNING("You can't wear [src] while you have [human.wear_l_ear] in your left ear!")) return FALSE if(!(flags_equip_slot & SLOT_EAR)) return FALSE return TRUE if(WEAR_BODY) - if(H.w_uniform) + if(human.w_uniform) return FALSE if(!(flags_equip_slot & SLOT_ICLOTHING)) return FALSE return TRUE if(WEAR_ID) - if(H.wear_id) + if(human.wear_id) return FALSE if(!(flags_equip_slot & SLOT_ID)) return FALSE return TRUE if(WEAR_L_STORE) - if(H.l_store) + if(human.l_store) return FALSE - if(!H.w_uniform && (WEAR_BODY in mob_equip)) + if(!human.w_uniform && (WEAR_BODY in mob_equip)) if(!disable_warning) - to_chat(H, SPAN_WARNING("You need a jumpsuit before you can attach this [name].")) + to_chat(human, SPAN_WARNING("You need a jumpsuit before you can attach this [name].")) return FALSE if(flags_equip_slot & SLOT_NO_STORE) return FALSE if(w_class <= SIZE_SMALL || (flags_equip_slot & SLOT_STORE)) return TRUE if(WEAR_R_STORE) - if(H.r_store) + if(human.r_store) return FALSE - if(!H.w_uniform && (WEAR_BODY in mob_equip)) + if(!human.w_uniform && (WEAR_BODY in mob_equip)) if(!disable_warning) - to_chat(H, SPAN_WARNING("You need a jumpsuit before you can attach this [name].")) + to_chat(human, SPAN_WARNING("You need a jumpsuit before you can attach this [name].")) return FALSE if(flags_equip_slot & SLOT_NO_STORE) return FALSE @@ -628,109 +639,107 @@ cases. Override_icon_state should be a list.*/ return TRUE return FALSE if(WEAR_ACCESSORY) - for(var/obj/item/clothing/C in H.contents) - if(C.can_attach_accessory(src)) + for(var/obj/item/clothing/clothes in human.contents) + if(clothes.can_attach_accessory(src)) return TRUE return FALSE if(WEAR_J_STORE) - if(H.s_store) + if(human.s_store) return FALSE if(flags_equip_slot & SLOT_SUIT_STORE) return TRUE if(flags_equip_slot & SLOT_BLOCK_SUIT_STORE) return FALSE - if(!H.wear_suit && (WEAR_JACKET in mob_equip)) + if(!human.wear_suit && (WEAR_JACKET in mob_equip)) if(!disable_warning) - to_chat(H, SPAN_WARNING("You need a suit before you can attach this [name].")) + to_chat(human, SPAN_WARNING("You need a suit before you can attach this [name].")) return FALSE - if(H.wear_suit && !H.wear_suit.allowed) + if(human.wear_suit && !human.wear_suit.allowed) if(!disable_warning) to_chat(usr, "You somehow have a suit with no defined allowed items for suit storage, stop that.") return FALSE - if(H.wear_suit && is_type_in_list(src, H.wear_suit.allowed)) + if(human.wear_suit && is_type_in_list(src, human.wear_suit.allowed)) return TRUE return FALSE if(WEAR_HANDCUFFS) - if(H.handcuffed) + if(human.handcuffed) return FALSE if(!istype(src, /obj/item/handcuffs)) return FALSE return TRUE if(WEAR_LEGCUFFS) - if(H.legcuffed) + if(human.legcuffed) return FALSE if(!istype(src, /obj/item/legcuffs)) return FALSE return TRUE if(WEAR_IN_ACCESSORY) - if(H.w_uniform) - for(var/A in H.w_uniform.accessories) - if(istype(A, /obj/item/clothing/accessory/storage)) - var/obj/item/clothing/accessory/storage/S = A - if(S.hold.can_be_inserted(src, M, TRUE)) + if(human.w_uniform) + for(var/accessory in human.w_uniform.accessories) + if(istype(accessory, /obj/item/clothing/accessory/storage)) + var/obj/item/clothing/accessory/storage/holster = accessory + if(holster.hold.can_be_inserted(src, human, TRUE)) return TRUE - else if(istype(A, /obj/item/storage/internal/accessory/holster)) - var/obj/item/storage/internal/accessory/holster/AH = A - if(!(AH.current_gun) && AH.can_be_inserted(src, M)) + else if(istype(accessory, /obj/item/storage/internal/accessory/holster)) + var/obj/item/storage/internal/accessory/holster/internal_storage = accessory + if(!(internal_storage.current_gun) && internal_storage.can_be_inserted(src, human)) return TRUE return FALSE if(WEAR_IN_JACKET) - if(H.wear_suit) - var/obj/item/clothing/suit/storage/S = H.wear_suit - if(istype(S) && S.pockets)//not all suits have pockits - var/obj/item/storage/internal/I = S.pockets - if(I.can_be_inserted(src, M, TRUE)) + if(human.wear_suit) + var/obj/item/clothing/suit/storage/storage = human.wear_suit + if(istype(storage) && storage.pockets)//not all suits have pockits + var/obj/item/storage/internal/internal_storage = storage.pockets + if(internal_storage.can_be_inserted(src, human, TRUE)) return TRUE return FALSE if(WEAR_IN_HELMET) - if(H.head) - var/obj/item/clothing/head/helmet/marine/HM = H.head - if(istype(HM) && HM.pockets)//not all helmuts have pockits - var/obj/item/storage/internal/I = HM.pockets - if(I.can_be_inserted(src, M, TRUE)) + if(human.head) + var/obj/item/clothing/head/helmet/marine/helmet = human.head + if(istype(helmet) && helmet.pockets)//not all helmuts have pockits + var/obj/item/storage/internal/internal_storage = helmet.pockets + if(internal_storage.can_be_inserted(src, human, TRUE)) return TRUE if(WEAR_IN_BACK) - if (H.back && isstorage(H.back)) - var/obj/item/storage/B = H.back - if(B.can_be_inserted(src, M, TRUE)) + if (human.back && isstorage(human.back)) + var/obj/item/storage/backpack = human.back + if(backpack.can_be_inserted(src, human, TRUE)) return TRUE return FALSE if(WEAR_IN_SHOES) - if(H.shoes && istype(H.shoes, /obj/item/clothing/shoes)) - var/obj/item/clothing/shoes/S = H.shoes - if(!S.stored_item && S.items_allowed && S.items_allowed.len) - for (var/i in S.items_allowed) - if(istype(src, i)) - return TRUE + if(human.shoes && istype(human.shoes, /obj/item/clothing/shoes)) + var/obj/item/clothing/shoes/shoes = human.shoes + if(shoes.attempt_insert_item(human, src)) + return TRUE return FALSE if(WEAR_IN_SCABBARD) - if(H.back && istype(H.back, /obj/item/storage/large_holster)) - var/obj/item/storage/large_holster/B = H.back - if(B.can_be_inserted(src, M, TRUE)) + if(human.back && istype(human.back, /obj/item/storage/large_holster)) + var/obj/item/storage/large_holster/backpack = human.back + if(backpack.can_be_inserted(src, human, TRUE)) return TRUE return FALSE if(WEAR_IN_BELT) - if(H.belt && isstorage(H.belt)) - var/obj/item/storage/B = H.belt - if(B.can_be_inserted(src, M, TRUE)) + if(human.belt && isstorage(human.belt)) + var/obj/item/storage/belt = human.belt + if(belt.can_be_inserted(src, human, TRUE)) return TRUE return FALSE if(WEAR_IN_J_STORE) - if(H.s_store && isstorage(H.s_store)) - var/obj/item/storage/B = H.s_store - if(B.can_be_inserted(src, M, TRUE)) + if(human.s_store && isstorage(human.s_store)) + var/obj/item/storage/armor = human.s_store + if(armor.can_be_inserted(src, human, TRUE)) return TRUE return FALSE if(WEAR_IN_L_STORE) - if(H.l_store && istype(H.l_store, /obj/item/storage/pouch)) - var/obj/item/storage/pouch/P = H.l_store - if(P.can_be_inserted(src, M, TRUE)) + if(human.l_store && istype(human.l_store, /obj/item/storage/pouch)) + var/obj/item/storage/pouch/pouch = human.l_store + if(pouch.can_be_inserted(src, human, TRUE)) return TRUE return FALSE if(WEAR_IN_R_STORE) - if(H.r_store && istype(H.r_store, /obj/item/storage/pouch)) - var/obj/item/storage/pouch/P = H.r_store - if(P.can_be_inserted(src, M, TRUE)) + if(human.r_store && istype(human.r_store, /obj/item/storage/pouch)) + var/obj/item/storage/pouch/pouch = human.r_store + if(pouch.can_be_inserted(src, human, TRUE)) return TRUE return FALSE return FALSE //Unsupported slot @@ -825,6 +834,8 @@ cases. Override_icon_state should be a list.*/ unzoom(user) /obj/item/proc/unzoom(mob/living/user) + if(user.interactee == src) + user.unset_interaction() var/zoom_device = zoomdevicename ? "\improper [zoomdevicename] of [src]" : "\improper [src]" INVOKE_ASYNC(user, TYPE_PROC_REF(/atom, visible_message), SPAN_NOTICE("[user] looks up from [zoom_device]."), SPAN_NOTICE("You look up from [zoom_device].")) diff --git a/code/game/objects/items/XMAS.dm b/code/game/objects/items/XMAS.dm index 4b7bca2fb319..b10ea2035d96 100644 --- a/code/game/objects/items/XMAS.dm +++ b/code/game/objects/items/XMAS.dm @@ -66,7 +66,7 @@ gift_type = pick( /obj/item/weapon/gun/revolver/mateba, /obj/item/weapon/gun/pistol/heavy, - /obj/item/weapon/claymore, + /obj/item/weapon/sword, /obj/item/weapon/energy/sword/green, /obj/item/weapon/energy/sword/red, /obj/item/attachable/heavy_barrel, diff --git a/code/game/objects/items/circuitboards/computer.dm b/code/game/objects/items/circuitboards/computer.dm index db19b79ac0fd..122136f6f2fa 100644 --- a/code/game/objects/items/circuitboards/computer.dm +++ b/code/game/objects/items/circuitboards/computer.dm @@ -96,9 +96,9 @@ /obj/item/circuitboard/computer/atmos_alert name = "Circuit board (Atmospheric Alert)" build_path = /obj/structure/machinery/computer/atmos_alert -/obj/item/circuitboard/computer/pod - name = "Circuit board (Massdriver control)" - build_path = /obj/structure/machinery/computer/pod +/obj/item/circuitboard/computer/pod/old + name = "Circuit board (DoorMex)" + build_path = /obj/structure/machinery/computer/pod/old /obj/item/circuitboard/computer/robotics name = "Circuit board (Robotics Control)" build_path = /obj/structure/machinery/computer/robotics @@ -117,15 +117,6 @@ /obj/item/circuitboard/computer/powermonitor name = "Circuit board (Power Monitor)" build_path = /obj/structure/machinery/power/monitor -/obj/item/circuitboard/computer/olddoor - name = "Circuit board (DoorMex)" - build_path = /obj/structure/machinery/computer/pod/old -/obj/item/circuitboard/computer/syndicatedoor - name = "Circuit board (ProComp Executive)" - build_path = /obj/structure/machinery/computer/pod/old/syndicate -/obj/item/circuitboard/computer/swfdoor - name = "Circuit board (Magix)" - build_path = /obj/structure/machinery/computer/pod/old/swf /obj/item/circuitboard/computer/prisoner name = "Circuit board (Prisoner Management)" build_path = /obj/structure/machinery/computer/prisoner @@ -177,7 +168,11 @@ /obj/item/circuitboard/computer/supplycomp/attackby(obj/item/tool, mob/user) if(HAS_TRAIT(tool, TRAIT_TOOL_MULTITOOL)) - to_chat(user, SPAN_WARNING("You start messing around with the electronics of \the [src]...")) + to_chat(user, SPAN_WARNING("You try to pulse the circuit board, but nothing happens. Maybe you need something more specialized?")) + return + + else if(HAS_TRAIT(tool, TRAIT_TOOL_BLACKMARKET_HACKER)) + to_chat(user, SPAN_WARNING("You start messing around with the electronics of [src]...")) if(do_after(user, 8 SECONDS, INTERRUPT_ALL, BUSY_ICON_FRIENDLY)) if(!skillcheck(user, SKILL_ENGINEER, SKILL_ENGINEER_ENGI)) to_chat(user, SPAN_WARNING("You have no idea what you're doing.")) @@ -191,8 +186,7 @@ to_chat(user, SPAN_WARNING("You weaken the broadcasting function with \the [tool], and the red light stops blinking, turning off. It's probably good now.")) contraband_enabled = FALSE - if(HAS_TRAIT(tool, TRAIT_TOOL_TRADEBAND)) - + else if(HAS_TRAIT(tool, TRAIT_TOOL_TRADEBAND)) if(!skillcheck(user, SKILL_POLICE, SKILL_POLICE_SKILLED)) to_chat(user, SPAN_NOTICE("You do not know how to use [tool]")) return diff --git a/code/game/objects/items/circuitboards/robot_modules.dm b/code/game/objects/items/circuitboards/robot_modules.dm index 2e5185353852..04fcff10fa2b 100644 --- a/code/game/objects/items/circuitboards/robot_modules.dm +++ b/code/game/objects/items/circuitboards/robot_modules.dm @@ -9,13 +9,12 @@ var/list/stacktypes /obj/item/circuitboard/robot_module/emp_act(severity) + . = ..() if(modules) for(var/obj/O in modules) O.emp_act(severity) if(emag) emag.emp_act(severity) - ..() - return /obj/item/circuitboard/robot_module/Initialize() diff --git a/code/game/objects/items/devices/binoculars.dm b/code/game/objects/items/devices/binoculars.dm index a4589fb1dd78..2d44ce076f30 100644 --- a/code/game/objects/items/devices/binoculars.dm +++ b/code/game/objects/items/devices/binoculars.dm @@ -38,10 +38,14 @@ /obj/item/device/binoculars/on_set_interaction(mob/user) flags_atom |= RELAY_CLICK - + RegisterSignal(user, COMSIG_HUMAN_MOVEMENT_CANCEL_INTERACTION, PROC_REF(interaction_handler)) /obj/item/device/binoculars/on_unset_interaction(mob/user) flags_atom &= ~RELAY_CLICK + UnregisterSignal(user, COMSIG_HUMAN_MOVEMENT_CANCEL_INTERACTION) + +/obj/item/device/binoculars/proc/interaction_handler() + return COMPONENT_HUMAN_MOVEMENT_KEEP_USING /obj/item/device/binoculars/civ desc = "A pair of binoculars." diff --git a/code/game/objects/items/devices/cictablet.dm b/code/game/objects/items/devices/cictablet.dm index fc9bb015ece0..6abd70980136 100644 --- a/code/game/objects/items/devices/cictablet.dm +++ b/code/game/objects/items/devices/cictablet.dm @@ -61,7 +61,7 @@ var/list/data = list() data["alert_level"] = security_level - data["evac_status"] = EvacuationAuthority.evac_status + data["evac_status"] = SShijack.evac_status data["endtime"] = announcement_cooldown data["distresstime"] = distress_cooldown data["worldtime"] = world.time @@ -135,18 +135,17 @@ to_chat(usr, SPAN_WARNING("The ship must be under red alert in order to enact evacuation procedures.")) return FALSE - if(EvacuationAuthority.flags_scuttle & FLAGS_EVACUATION_DENY) + if(SShijack.evac_admin_denied) to_chat(usr, SPAN_WARNING("The USCM has placed a lock on deploying the evacuation pods.")) return FALSE - if(!EvacuationAuthority.initiate_evacuation()) + if(!SShijack.initiate_evacuation()) to_chat(usr, SPAN_WARNING("You are unable to initiate an evacuation procedure right now!")) return FALSE log_game("[key_name(usr)] has called for an emergency evacuation.") message_admins("[key_name_admin(usr)] has called for an emergency evacuation.") - var/datum/ares_link/link = GLOB.ares_link - link.log_ares_security("Initiate Evacuation", "[usr] has called for an emergency evacuation.") + log_ares_security("Initiate Evacuation", "[usr] has called for an emergency evacuation.") . = TRUE if("distress") diff --git a/code/game/objects/items/devices/coins.dm b/code/game/objects/items/devices/coins.dm index 6ab79e3216d4..139ea1cbac8c 100644 --- a/code/game/objects/items/devices/coins.dm +++ b/code/game/objects/items/devices/coins.dm @@ -11,11 +11,8 @@ black_market_value = 10 var/string_attached var/sides = 2 - -/obj/item/coin/Initialize() - . = ..() - pixel_x = rand(0,16)-8 - pixel_y = rand(0,8)-8 + ground_offset_x = 8 + ground_offset_y = 4 /obj/item/coin/gold name = "gold coin" @@ -29,6 +26,11 @@ icon_state = "coin_silver" black_market_value = 25 +//CO coin +/obj/item/coin/silver/falcon + name = "falling falcons challenge coin" + desc = "A small coin, bearing the falling falcons insignia." + /obj/item/coin/copper name = "copper coin" desc = "A familiar, but cheap form of currency." diff --git a/code/game/objects/items/devices/flash.dm b/code/game/objects/items/devices/flash.dm index 0a7709aa6101..33a93ed18db5 100644 --- a/code/game/objects/items/devices/flash.dm +++ b/code/game/objects/items/devices/flash.dm @@ -155,6 +155,7 @@ do_flash(user = user, aoe = TRUE) /obj/item/device/flash/emp_act(severity) + . = ..() if(broken) return switch(flashes_stored) if(0 to 5) @@ -168,7 +169,6 @@ if(M.flash_eyes()) M.apply_effect(10, WEAKEN) M.visible_message(SPAN_DISARM("[M] is blinded by \the [src]!")) - ..() /obj/item/device/flash/synthetic name = "synthetic flash" diff --git a/code/game/objects/items/devices/flashlight.dm b/code/game/objects/items/devices/flashlight.dm index 6795f8b436dc..114964464a25 100644 --- a/code/game/objects/items/devices/flashlight.dm +++ b/code/game/objects/items/devices/flashlight.dm @@ -12,6 +12,8 @@ light_range = 5 light_power = 1 + ground_offset_x = 2 + ground_offset_y = 6 actions_types = list(/datum/action/item_action) var/on = FALSE @@ -33,6 +35,11 @@ else icon_state = initial(icon_state) +/obj/item/device/flashlight/animation_spin(speed = 5, loop_amount = -1, clockwise = TRUE, sections = 3, angular_offset = 0, pixel_fuzz = 0) + clockwise = pick(TRUE, FALSE) + angular_offset = rand(360) + return ..() + /obj/item/device/flashlight/proc/update_brightness(mob/user = null) if(on) set_light_range(light_range) @@ -65,6 +72,7 @@ if(on) on = FALSE set_light_on(on) + update_icon() for(var/X in actions) var/datum/action/A = X A.update_button_icon() @@ -295,8 +303,6 @@ // Causes flares to stop with a rotation offset for visual purposes /obj/item/device/flashlight/flare/animation_spin(speed = 5, loop_amount = -1, clockwise = TRUE, sections = 3, angular_offset = 0, pixel_fuzz = 0) - clockwise = pick(TRUE, FALSE) - angular_offset = rand(360) pixel_fuzz = 16 return ..() /obj/item/device/flashlight/flare/pickup() diff --git a/code/game/objects/items/devices/helmet_visors.dm b/code/game/objects/items/devices/helmet_visors.dm index dd913daf7620..596409c88c8b 100644 --- a/code/game/objects/items/devices/helmet_visors.dm +++ b/code/game/objects/items/devices/helmet_visors.dm @@ -14,31 +14,65 @@ ///The sound when toggling off the visor var/toggle_off_sound = 'sound/handling/hud_off.ogg' - ///The icon name for our helmet's action + ///The icon name for our helmet's action, in 'icons/obj/items/clothing/helmet_visors.dmi' var/action_icon_string = "hud_sight_down" - ///The overlay name for when our visor is active + ///The overlay name for when our visor is active, in 'icons/mob/humans/onmob/helmet_garb.dmi' var/helmet_overlay = "hud_sight_right" +/obj/item/device/helmet_visor/Destroy(force) + if(!istype(loc, /obj/item/clothing/head/helmet/marine)) + return ..() + + if(!istype(loc?.loc, /mob/living/carbon/human)) + return ..() + + var/obj/item/clothing/head/helmet/marine/attached_helmet = loc + var/mob/living/carbon/human/user = loc.loc + deactivate_visor(attached_helmet, user) + . = ..() + /// Called to see if the user can even use this visor /obj/item/device/helmet_visor/proc/can_toggle(mob/living/carbon/human/user) return TRUE /// Called to see if this visor is a special non-HUD visor -/obj/item/device/helmet_visor/proc/visor_function(obj/item/clothing/head/helmet/marine/attached_helmet, mob/living/carbon/human/user, silent = FALSE) +/obj/item/device/helmet_visor/proc/toggle_visor(obj/item/clothing/head/helmet/marine/attached_helmet, mob/living/carbon/human/user, silent = FALSE) if(attached_helmet == user.head && attached_helmet.active_visor == src) - var/datum/mob_hud/current_mob_hud = huds[hud_type] - current_mob_hud.add_hud_to(user, attached_helmet) + + if(!can_toggle(user)) + return FALSE + + activate_visor(attached_helmet, user) + if(!silent) to_chat(user, SPAN_NOTICE("You activate [src] on [attached_helmet].")) + playsound_client(user.client, toggle_on_sound, null, 75) + return TRUE - var/datum/mob_hud/current_mob_hud = huds[hud_type] - current_mob_hud.remove_hud_from(user, attached_helmet) + deactivate_visor(attached_helmet, user) + if(!silent) to_chat(user, SPAN_NOTICE("You deactivate [src] on [attached_helmet].")) + playsound_client(user.client, toggle_off_sound, null, 75) + return TRUE +/// Called by toggle_visor() to activate the visor's effects +/obj/item/device/helmet_visor/proc/activate_visor(obj/item/clothing/head/helmet/marine/attached_helmet, mob/living/carbon/human/user) + var/datum/mob_hud/current_mob_hud = huds[hud_type] + current_mob_hud.add_hud_to(user, attached_helmet) + +/// Called by toggle_visor() to deactivate the visor's effects +/obj/item/device/helmet_visor/proc/deactivate_visor(obj/item/clothing/head/helmet/marine/attached_helmet, mob/living/carbon/human/user) + var/datum/mob_hud/current_mob_hud = huds[hud_type] + current_mob_hud.remove_hud_from(user, attached_helmet) + +/// Called by /obj/item/clothing/head/helmet/marine/get_examine_text(mob/user) to get extra examine text for this visor +/obj/item/device/helmet_visor/proc/get_helmet_examine_text() + return SPAN_NOTICE("\A [name] is flipped down.") + /obj/item/device/helmet_visor/medical name = "basic medical optic" icon_state = "med_sight" @@ -50,13 +84,75 @@ name = "advanced medical optic" helmet_overlay = "med_sight_left" +/obj/item/device/helmet_visor/medical/advanced/activate_visor(obj/item/clothing/head/helmet/marine/attached_helmet, mob/living/carbon/human/user) + . = ..() + + var/datum/action/item_action/view_publications/helmet_visor/publication_action = new(attached_helmet) + publication_action.give_to(user) + +/obj/item/device/helmet_visor/medical/advanced/deactivate_visor(obj/item/clothing/head/helmet/marine/attached_helmet, mob/living/carbon/human/user) + . = ..() + + var/datum/action/item_action/view_publications/helmet_visor/publication_action = locate() in attached_helmet.actions + qdel(publication_action) + /obj/item/device/helmet_visor/medical/advanced/can_toggle(mob/living/carbon/human/user) + . = ..() + if(!.) + return + if(!skillcheck(user, SKILL_MEDICAL, SKILL_MEDICAL_MEDIC)) to_chat(user, SPAN_NOTICE("You are not skilled enough to use [src].")) return FALSE return TRUE +/obj/item/device/helmet_visor/medical/advanced/ui_state(mob/user) + return GLOB.not_incapacitated_and_adjacent_strict_state + +/obj/item/device/helmet_visor/medical/advanced/ui_data(mob/user) + var/list/data = list( + "published_documents" = chemical_data.research_publications, + "terminal_view" = FALSE + ) + return data + +/obj/item/device/helmet_visor/medical/advanced/tgui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if (!ui) + ui = new(user, src, "PublishedDocsHud", name) + ui.open() + +/obj/item/device/helmet_visor/medical/advanced/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) + . = ..() + if(.) + return + + if(!ishuman(ui.user)) + return + + var/mob/living/carbon/human/user = ui.user + + if(user.stat || user.is_mob_restrained() || !in_range(src, user)) + return + + switch(action) + if ("read_document") + var/print_type = params["print_type"] + var/print_title = params["print_title"] + var/obj/item/paper/research_report/report = chemical_data.get_report(print_type, print_title) + if(report) + report.read_paper(user) + return + +/datum/action/item_action/view_publications/helmet_visor/action_activate() + var/obj/item/device/helmet_visor/medical/advanced/medical_visor = locate() in holder_item + + if(!medical_visor) + return + + medical_visor.tgui_interact(owner) + /obj/item/device/helmet_visor/security name = "security optic" icon_state = "sec_sight" @@ -71,28 +167,159 @@ action_icon_string = "blank_hud_sight_down" helmet_overlay = "weld_visor" -/obj/item/device/helmet_visor/welding_visor/visor_function(obj/item/clothing/head/helmet/marine/attached_helmet, mob/living/carbon/human/user, silent = FALSE) - if(attached_helmet == user.head && attached_helmet.active_visor == src) - attached_helmet.vision_impair = VISION_IMPAIR_MAX - attached_helmet.flags_inventory |= COVEREYES|COVERMOUTH - attached_helmet.flags_inv_hide |= HIDEEYES|HIDEFACE - attached_helmet.eye_protection = EYE_PROTECTION_WELDING - user.update_tint() - if(!silent) - to_chat(user, SPAN_NOTICE("You activate [src] on [attached_helmet].")) - return TRUE +/obj/item/device/helmet_visor/welding_visor/activate_visor(obj/item/clothing/head/helmet/marine/attached_helmet, mob/living/carbon/human/user) + attached_helmet.vision_impair = VISION_IMPAIR_MAX + attached_helmet.flags_inventory |= COVEREYES|COVERMOUTH + attached_helmet.flags_inv_hide |= HIDEEYES|HIDEFACE + attached_helmet.eye_protection = EYE_PROTECTION_WELDING + user.update_tint() +/obj/item/device/helmet_visor/welding_visor/deactivate_visor(obj/item/clothing/head/helmet/marine/attached_helmet, mob/living/carbon/human/user) attached_helmet.vision_impair = VISION_IMPAIR_NONE attached_helmet.flags_inventory &= ~(COVEREYES|COVERMOUTH) attached_helmet.flags_inv_hide &= ~(HIDEEYES|HIDEFACE) attached_helmet.eye_protection = EYE_PROTECTION_NONE - if(!silent) - to_chat(user, SPAN_NOTICE("You deactivate [src] on [attached_helmet].")) user.update_tint() - return TRUE /obj/item/device/helmet_visor/welding_visor/mercenary helmet_overlay = "" /obj/item/device/helmet_visor/welding_visor/tanker helmet_overlay = "tanker_weld_visor" + +#define NVG_VISOR_USAGE(delta_time) (power_cell.use(power_use * (delta_time ? delta_time : 1))) + +/obj/item/device/helmet_visor/night_vision + name = "night vision optic" + desc = "An insertable visor HUD into a standard USCM helmet. This type gives a form of night vision and is standard issue in units with regular funding." + icon_state = "nvg_sight" + hud_type = null + action_icon_string = "nvg_sight_down" + helmet_overlay = "nvg_sight_right" + toggle_on_sound = 'sound/handling/toggle_nv1.ogg' + toggle_off_sound = 'sound/handling/toggle_nv2.ogg' + + /// The internal battery for the visor + var/obj/item/cell/high/power_cell + + /// About 5 minutes active use charge (hypothetically) + var/power_use = 33 + + /// The alpha of darkness we set to for the mob while the visor is on, not completely fullbright but see-able + var/lighting_alpha = 100 + + /// A slight glowing green light while the NVG is activated, is initialized as in the attached_helmet's contents + var/atom/movable/nvg_light/on_light + + /// Whether or not the sight uses on_light and produces light + var/visor_glows = TRUE + +/obj/item/device/helmet_visor/night_vision/Initialize(mapload, ...) + . = ..() + power_cell = new(src) + +/obj/item/device/helmet_visor/night_vision/Destroy() + power_cell = null + . = ..() + +/obj/item/device/helmet_visor/night_vision/get_examine_text(mob/user) + . = ..() + + . += SPAN_NOTICE("It is currently at [round((power_cell.charge / power_cell.maxcharge) * 100)]% charge.") + +/obj/item/device/helmet_visor/night_vision/activate_visor(obj/item/clothing/head/helmet/marine/attached_helmet, mob/living/carbon/human/user) + RegisterSignal(user, COMSIG_HUMAN_POST_UPDATE_SIGHT, PROC_REF(on_update_sight)) + + user.add_client_color_matrix("nvg_visor", 99, color_matrix_multiply(color_matrix_saturation(0), color_matrix_from_string("#7aff7a"))) + user.overlay_fullscreen("nvg_visor", /atom/movable/screen/fullscreen/flash/noise/nvg) + user.overlay_fullscreen("nvg_visor_blur", /atom/movable/screen/fullscreen/brute/nvg, 3) + user.update_sight() + if(visor_glows) + on_light = new(attached_helmet) + on_light.set_light_on(TRUE) + START_PROCESSING(SSobj, src) + +/obj/item/device/helmet_visor/night_vision/deactivate_visor(obj/item/clothing/head/helmet/marine/attached_helmet, mob/living/carbon/human/user) + user.remove_client_color_matrix("nvg_visor", 1 SECONDS) + user.clear_fullscreen("nvg_visor", 0.5 SECONDS) + user.clear_fullscreen("nvg_visor_blur", 0.5 SECONDS) + + if(visor_glows) + qdel(on_light) + UnregisterSignal(user, COMSIG_HUMAN_POST_UPDATE_SIGHT) + + user.update_sight() + STOP_PROCESSING(SSobj, src) + +/obj/item/device/helmet_visor/night_vision/process(delta_time) + if(!NVG_VISOR_USAGE(delta_time)) + + if(!istype(loc, /obj/item/clothing/head/helmet/marine)) + return PROCESS_KILL + + if(!istype(loc?.loc, /mob/living/carbon/human)) + return PROCESS_KILL + + var/obj/item/clothing/head/helmet/marine/attached_helmet = loc + var/mob/living/carbon/human/user = loc.loc + to_chat(user, SPAN_NOTICE("[src] deactivates as the battery goes out.")) + deactivate_visor(attached_helmet, user) + return PROCESS_KILL + +/obj/item/device/helmet_visor/night_vision/can_toggle(mob/living/carbon/human/user) + . = ..() + if(!.) + return + + if(!NVG_VISOR_USAGE(FALSE)) + to_chat(user, SPAN_NOTICE("Your [src] is out of power! You'll need to recharge it.")) + return FALSE + + return TRUE + +/obj/item/device/helmet_visor/night_vision/get_helmet_examine_text() + . = ..() + + . += SPAN_NOTICE(" It is currently at [round((power_cell.charge / power_cell.maxcharge) * 100)]% charge.") + +/obj/item/device/helmet_visor/night_vision/proc/on_update_sight(mob/user) + SIGNAL_HANDLER + + if(lighting_alpha < 255) + user.see_in_dark = 12 + user.lighting_alpha = lighting_alpha + user.sync_lighting_plane_alpha() + +#undef NVG_VISOR_USAGE + +/atom/movable/nvg_light + light_power = 0.5 + light_range = 1 + light_color = COLOUR_GREEN + light_system = MOVABLE_LIGHT + light_flags = LIGHT_ATTACHED + +/obj/item/device/helmet_visor/night_vision/marine_raider + name = "advanced night vision optic" + desc = "An insertable visor HUD into a standard USCM helmet. This type gives a form of night vision and is standard issue in special forces units." + hud_type = list(MOB_HUD_FACTION_USCM, MOB_HUD_MEDICAL_ADVANCED) + helmet_overlay = "nvg_sight_right_raider" + power_use = 0 + visor_glows = FALSE + +/obj/item/device/helmet_visor/night_vision/marine_raider/activate_visor(obj/item/clothing/head/helmet/marine/attached_helmet, mob/living/carbon/human/user) + . = ..() + + for(var/type in hud_type) + var/datum/mob_hud/current_mob_hud = huds[type] + current_mob_hud.add_hud_to(user, attached_helmet) + +/obj/item/device/helmet_visor/night_vision/marine_raider/deactivate_visor(obj/item/clothing/head/helmet/marine/attached_helmet, mob/living/carbon/human/user) + . = ..() + + for(var/type in hud_type) + var/datum/mob_hud/current_mob_hud = huds[type] + current_mob_hud.remove_hud_from(user, attached_helmet) + +/obj/item/device/helmet_visor/night_vision/marine_raider/process(delta_time) + return PROCESS_KILL diff --git a/code/game/objects/items/devices/portable_vendor.dm b/code/game/objects/items/devices/portable_vendor.dm index 65e2128a02c0..29e1d06018ae 100644 --- a/code/game/objects/items/devices/portable_vendor.dm +++ b/code/game/objects/items/devices/portable_vendor.dm @@ -210,6 +210,7 @@ s.start() /obj/item/device/portable_vendor/emp_act(severity) + . = ..() if (broken) return if (prob(40*severity)) diff --git a/code/game/objects/items/devices/radio/headset.dm b/code/game/objects/items/devices/radio/headset.dm index 21aa96e971a1..fb8640eeaa71 100644 --- a/code/game/objects/items/devices/radio/headset.dm +++ b/code/game/objects/items/devices/radio/headset.dm @@ -849,6 +849,14 @@ "Corporate Liaison" = TRACKER_CL ) +/obj/item/device/radio/headset/distress/cbrn + name = "\improper CBRN headset" + desc = "A headset given to CBRN marines. Channels are as follows: :g - public, :v - marine command, :a - alpha squad, :b - bravo squad, :c - charlie squad, :d - delta squad, :n - engineering, :m - medbay, :u - requisitions, :j - JTAC, :t - intel" + frequency = CBRN_FREQ + initial_keys = list(/obj/item/device/encryptionkey/public, /obj/item/device/encryptionkey/mcom) + ignore_z = TRUE + has_hud = TRUE + /obj/item/device/radio/headset/distress/pmc/hvh desc = "A special headset used by corporate personnel. Channels are as follows: :o - colony." initial_keys = list(/obj/item/device/encryptionkey/colony, /obj/item/device/encryptionkey/WY) diff --git a/code/game/objects/items/devices/radio/radio.dm b/code/game/objects/items/devices/radio/radio.dm index 2092ffa108c6..c503edc8f94f 100644 --- a/code/game/objects/items/devices/radio/radio.dm +++ b/code/game/objects/items/devices/radio/radio.dm @@ -425,11 +425,11 @@ else return /obj/item/device/radio/emp_act(severity) + . = ..() broadcasting = FALSE listening = FALSE for (var/ch_name in channels) channels[ch_name] = 0 - ..() /////////////////////////////// //////////Borg Radios////////// diff --git a/code/game/objects/items/devices/scanners.dm b/code/game/objects/items/devices/scanners.dm index 38ff8859ef97..512ca8baad9b 100644 --- a/code/game/objects/items/devices/scanners.dm +++ b/code/game/objects/items/devices/scanners.dm @@ -457,6 +457,16 @@ FORENSIC SCANNER playsound(user, 'sound/machines/twobeep.ogg', 15, TRUE) to_chat(user, SPAN_NOTICE("You scan [hit_atom] and notice a reading on [src]'s pad, it says: ITEM HAS [market_value] VALUE ")) +/obj/item/device/black_market_hacking_device + name = "modified security access tuner" + desc = "A security access tuner with wires and electrical pins sticking out at odd angles. A handwritten label on the bottom says something about the ASRS system." + icon_state = "bm_hacker" + item_state = "analyzer" + w_class = SIZE_SMALL + flags_atom = FPRINT + flags_equip_slot = SLOT_WAIST + inherent_traits = list(TRAIT_TOOL_BLACKMARKET_HACKER) + /obj/item/device/cmb_black_market_tradeband name = "\improper CMB Tradeband Compliance Device" desc = "A device used to reset any tampering done to trading devices' signal range. Occasionally used to fix any signal chips damaged in an accident, but often for malpractice in trading. Use this with caution, as it will also reset any evidence of potential illicit trade. Created to fulfill a joint-organization requirement for CMB-ICC teams on the frontier, where tampered machinery was difficult to move and refurbish. Smugglers beware." diff --git a/code/game/objects/items/devices/taperecorder.dm b/code/game/objects/items/devices/taperecorder.dm index 01567084d5c7..a4247c90a5b3 100644 --- a/code/game/objects/items/devices/taperecorder.dm +++ b/code/game/objects/items/devices/taperecorder.dm @@ -168,7 +168,7 @@ mytape.timestamp += mytape.used_capacity var/language_known = (M.universal_speak || (speaking && (speaking.name in known_languages))) var/mob_name = language_known ? M.GetVoice() : "Unknown" - var/message = language_known ? msg : speaking.scramble(msg) + var/message = (!speaking || language_known) ? msg : speaking.scramble(msg) mytape.storedinfo += "\[[time2text(mytape.used_capacity,"mm:ss")]\] [mob_name] [verb], \"[italics ? "" : null][message][italics ? "" : null]\"" diff --git a/code/game/objects/items/explosives/grenades/grenade.dm b/code/game/objects/items/explosives/grenades/grenade.dm index 7e98e9819931..6b793233678d 100644 --- a/code/game/objects/items/explosives/grenades/grenade.dm +++ b/code/game/objects/items/explosives/grenades/grenade.dm @@ -20,12 +20,12 @@ var/hand_throwable = TRUE harmful = TRUE //Is it harmful? Are they banned for synths? antigrief_protection = TRUE //Should it be checked by antigrief? + ground_offset_x = 7 + ground_offset_y = 6 /obj/item/explosive/grenade/Initialize() . = ..() det_time = max(0, rand(det_time - 5, det_time + 5)) - pixel_y = rand(-6, 6) - pixel_x = rand(-7, 7) /obj/item/explosive/grenade/proc/can_use_grenade(mob/living/carbon/human/user) if(!hand_throwable) diff --git a/code/game/objects/items/explosives/mine.dm b/code/game/objects/items/explosives/mine.dm index 742a5f314c4a..57dd23bf4e96 100644 --- a/code/game/objects/items/explosives/mine.dm +++ b/code/game/objects/items/explosives/mine.dm @@ -42,6 +42,7 @@ prime() //We don't care about how strong the explosion was. /obj/item/explosive/mine/emp_act() + . = ..() prime() //Same here. Don't care about the effect strength. diff --git a/code/game/objects/items/explosives/warhead.dm b/code/game/objects/items/explosives/warhead.dm index 5dfdf2a41eac..9825d7483193 100644 --- a/code/game/objects/items/explosives/warhead.dm +++ b/code/game/objects/items/explosives/warhead.dm @@ -2,11 +2,8 @@ icon = 'icons/obj/items/weapons/grenade.dmi' customizable = TRUE allowed_sensors = list() //We only need a detonator - -/obj/item/explosive/warhead/Initialize(mapload, ...) - . = ..() - pixel_y = rand(-6, 6) - pixel_x = rand(-7, 7) + ground_offset_x = 7 + ground_offset_y = 6 /obj/item/explosive/warhead/rocket name = "84mm rocket warhead" diff --git a/code/game/objects/items/fulton.dm b/code/game/objects/items/fulton.dm index 98987d1cd2b3..6a0e0f933144 100644 --- a/code/game/objects/items/fulton.dm +++ b/code/game/objects/items/fulton.dm @@ -90,7 +90,7 @@ var/global/list/deployed_fultons = list() var/mob/living/carbon/human/H = target_atom if(isyautja(H) && H.stat == DEAD) can_attach = TRUE - else if((H.stat != DEAD || H.mind && H.check_tod() && H.is_revivable())) + else if((H.stat != DEAD || H.check_tod() && H.is_revivable())) to_chat(user, SPAN_WARNING("You can't attach [src] to [target_atom], they still have a chance!")) return else diff --git a/code/game/objects/items/handcuffs.dm b/code/game/objects/items/handcuffs.dm index 71fb02cf3f07..2137b41d86bf 100644 --- a/code/game/objects/items/handcuffs.dm +++ b/code/game/objects/items/handcuffs.dm @@ -29,20 +29,6 @@ if(!C.handcuffed) place_handcuffs(C, user) -/obj/item/handcuffs/obj/structure/MouseDrop(mob/living/carbon/human/H) - var/mob/living/carbon/human/user = usr - if (!istype(user)) - return - if (user.stat || get_dist(user, src) > 1 || get_dist(user, H) > 1 || H.lying) - return - if (!istype(H)) - return - - if(!do_after(user, cuff_delay, INTERRUPT_ALL, BUSY_ICON_HOSTILE, H, INTERRUPT_MOVED, BUSY_ICON_GENERIC)) - return - - // TODO: apply handcuffs - /obj/item/handcuffs/get_mob_overlay(mob/user_mob, slot) var/image/ret = ..() diff --git a/code/game/objects/items/handheld_distress_beacon.dm b/code/game/objects/items/handheld_distress_beacon.dm index d3f99134cd23..c11a7a57c350 100644 --- a/code/game/objects/items/handheld_distress_beacon.dm +++ b/code/game/objects/items/handheld_distress_beacon.dm @@ -1,12 +1,21 @@ ///handheld distress beacons used by goon chem retrieval team to call for PMC back up /obj/item/handheld_distress_beacon - name = "handheld distress beacon" + name = "\improper PMC handheld distress beacon" desc = "A standard handheld distress beacon. Generally used by teams who may be out of regular communications range but must signal for assistance. This one is branded with a Weyland Yutani symbol and sold en masse to colonies across the Neroid Sector." icon = 'icons/obj/items/handheld_distress_beacon.dmi' icon_state = "beacon_inactive" w_class = SIZE_SMALL + ///The beacons faction that will be sent in message_admins + var/beacon_type = "PMC beacon" + ///Tells the user who the beacon will be sent to IC + var/recipient = "the USCSS Royce" + ///The name of the ERT that will be passed to get_specific_call + var/list/ert_full_name = list("Weyland-Yutani PMC (Chemical Investigation Squad)") + ///The clickable version that will be sent in message_admins + var/list/ert_short_name = list("SEND PMCs") + ///Whether beacon can be used, or has already been used var/active = FALSE /obj/item/handheld_distress_beacon/get_examine_text(mob/user) @@ -20,8 +29,8 @@ if(active) icon_state = "beacon_active" - else - icon_state = initial(icon_state) + return + icon_state = initial(icon_state) /obj/item/handheld_distress_beacon/attack_self(mob/user) . = ..() @@ -29,12 +38,29 @@ if(active) to_chat(user, "[src] is already active!") return - - for(var/client/C in GLOB.admins) - if((R_ADMIN|R_MOD) & C.admin_holder.rights) - playsound_client(C,'sound/effects/sos-morse-code.ogg',10) - message_admins("[key_name(user)] has requested a PMC Distress Beacon! [CC_MARK(user)] (SEND) (DENY) [ADMIN_JMP_USER(user)] [CC_REPLY(user)]") - to_chat(user, SPAN_NOTICE("A distress beacon request has been sent to the USCSS Royce.")) - active = TRUE update_icon() + + if(!ert_full_name || !ert_short_name || (length(ert_full_name) != length(ert_short_name))) //Make sure they are greater than 0, and both are same length + to_chat(user, SPAN_BOLDWARNING("[src] is broken!")) + CRASH("[src] was improperly set, and has been disabled.") //For the runtime logs + + var/beacon_call_buttons + for(var/current_ert_num in 1 to length(ert_full_name)) + beacon_call_buttons += "([ert_short_name[current_ert_num]]) " + + for(var/client/admin_client in GLOB.admins) + if((R_ADMIN|R_MOD) & admin_client.admin_holder.rights) + playsound_client(admin_client,'sound/effects/sos-morse-code.ogg',10) + message_admins("[key_name(user)] has used a [beacon_type]! [CC_MARK(user)] [beacon_call_buttons](DENY) [ADMIN_JMP_USER(user)] [CC_REPLY(user)]") + to_chat(user, SPAN_NOTICE("A distress beacon request has been sent to [recipient].")) + +/// CMB distress beacon held by CMB Marshal for signalling distress to Anchorpoint Station +/obj/item/handheld_distress_beacon/cmb + name = "\improper CMB handheld distress beacon" + desc = "An emergency beacon. This one is branded with a Colonial Marshal Bureau star and 'ANCHORPOINT STATION' is etched in stencil on the side. This device is issued to CMB Marshals and features an extended relay antenna." + + beacon_type = "CMB beacon" + recipient = "Anchorpoint Station" + ert_full_name = list("CMB - Patrol Team - Marshals in Distress (Friendly)", "CMB - Anchorpoint Station Colonial Marine QRF (Friendly)") + ert_short_name = list("SEND CMB", "SEND QRF") diff --git a/code/game/objects/items/implants/implant.dm b/code/game/objects/items/implants/implant.dm index d39b7e675452..e7ebe0391fae 100644 --- a/code/game/objects/items/implants/implant.dm +++ b/code/game/objects/items/implants/implant.dm @@ -82,6 +82,7 @@ Implant Specifics:
"} return dat /obj/item/implant/tracking/emp_act(severity) + . = ..() if (malfunction) //no, dawg, you can't malfunction while you are malfunctioning return malfunction = MALFUNCTION_TEMPORARY @@ -216,6 +217,7 @@ Implant Specifics:
"} return 1 /obj/item/implant/explosive/emp_act(severity) + . = ..() if (malfunction) return malfunction = MALFUNCTION_TEMPORARY @@ -307,6 +309,7 @@ the implant may become unstable and either pre-maturely inject the subject or si return /obj/item/implant/chem/emp_act(severity) + . = ..() if (malfunction) return malfunction = MALFUNCTION_TEMPORARY @@ -432,6 +435,7 @@ the implant may become unstable and either pre-maturely inject the subject or si STOP_PROCESSING(SSobj, src) /obj/item/implant/death_alarm/emp_act(severity) //for some reason alarms stop going off in case they are emp'd, even without this + . = ..() if (malfunction) //so I'm just going to add a meltdown chance here return malfunction = MALFUNCTION_TEMPORARY diff --git a/code/game/objects/items/implants/implantneurostim.dm b/code/game/objects/items/implants/implantneurostim.dm index a46cc31a2ca4..544cf70147e2 100644 --- a/code/game/objects/items/implants/implantneurostim.dm +++ b/code/game/objects/items/implants/implantneurostim.dm @@ -105,6 +105,7 @@ /obj/item/implant/neurostim/emp_act(severity) + . = ..() if (malfunction) return if (prob(80)) diff --git a/code/game/objects/items/misc.dm b/code/game/objects/items/misc.dm index abd8404d6e25..50c5cd75551b 100644 --- a/code/game/objects/items/misc.dm +++ b/code/game/objects/items/misc.dm @@ -141,13 +141,13 @@ . = ..() /obj/item/weapon/pole/fancy_cane/this_is_a_knife/machete - stored_item = new /obj/item/weapon/claymore/mercsword/machete + stored_item = new /obj/item/weapon/sword/machete /obj/item/weapon/pole/fancy_cane/this_is_a_knife/ceremonial_sword - stored_item = new /obj/item/weapon/claymore/mercsword/ceremonial + stored_item = new /obj/item/weapon/sword/ceremonial /obj/item/weapon/pole/fancy_cane/this_is_a_knife/katana - stored_item = new /obj/item/weapon/katana + stored_item = new /obj/item/weapon/sword/katana // IN SHOTGUNS.DM!! diff --git a/code/game/objects/items/props/helmetgarb.dm b/code/game/objects/items/props/helmetgarb.dm index 661c8d422316..b20c5671503e 100644 --- a/code/game/objects/items/props/helmetgarb.dm +++ b/code/game/objects/items/props/helmetgarb.dm @@ -37,6 +37,11 @@ desc = "The more you fire these, the more you're reminded that a fragmentation grenade is probably more effective at fulfilling the same purpose. Say, aren't these supposed to eject from your gun?" icon_state = "spent_flech" +/obj/item/prop/helmetgarb/cartridge + name = "cartridge" + desc = "This is the bullet from a Type 71 Pulse Rifle. It is deformed from impact against an armored surface. It's been reduced to a lucky keepsake now." + icon_state = "cartridge" + /obj/item/prop/helmetgarb/prescription_bottle name = "prescription medication" desc = "Anti-anxiety meds? Amphetamines? The cure for Sudden Sleep Disorder? The label can't be read, leaving the now absent contents forever a mystery. The cap is screwed on tighter than any ID lock." @@ -94,10 +99,8 @@ var/nvg_maxhealth = 125 var/nvg_health = 125 - var/nvg_maxcharge = 2500 - var/nvg_charge = 2500 - var/nvg_drain = 8 // has a 5 minute duration but byond may give it a couple of irl time due to lag - var/infinite_charge = FALSE + /// How much charge the cell should have at most. -1 is infinite + var/cell_max_charge = 2500 var/activated = FALSE var/nightvision = FALSE @@ -112,6 +115,13 @@ var/mob/living/attached_mob var/lighting_alpha = 100 +/obj/item/prop/helmetgarb/helmet_nvg/Initialize(mapload, ...) + . = ..() + if(shape != NVG_SHAPE_COSMETIC) + AddComponent(/datum/component/cell, cell_max_charge, TRUE, charge_drain = 8) + RegisterSignal(src, COMSIG_CELL_TRY_RECHARGING, PROC_REF(cell_try_recharge)) + RegisterSignal(src, COMSIG_CELL_OUT_OF_CHARGE, PROC_REF(on_power_out)) + /obj/item/prop/helmetgarb/helmet_nvg/on_enter_storage(obj/item/storage/internal/S) ..() @@ -134,42 +144,30 @@ /obj/item/prop/helmetgarb/helmet_nvg/attackby(obj/item/A as obj, mob/user as mob) - if(istype(A,/obj/item/cell)) - recharge(A, user) - if(HAS_TRAIT(A, TRAIT_TOOL_SCREWDRIVER)) repair(user) else ..() -/obj/item/prop/helmetgarb/helmet_nvg/proc/recharge(obj/item/cell/C, mob/user as mob) +/obj/item/prop/helmetgarb/helmet_nvg/proc/cell_try_recharge(datum/source, mob/living/user) + SIGNAL_HANDLER + if(user.action_busy) - return + return COMPONENT_CELL_NO_RECHARGE + if(src != user.get_inactive_hand()) - to_chat(user, SPAN_WARNING("You need to hold \the [src] in hand in order to recharge them.")) - return + to_chat(user, SPAN_WARNING("You need to hold [src] in hand in order to recharge them.")) + return COMPONENT_CELL_NO_RECHARGE + if(shape == NVG_SHAPE_COSMETIC) - to_chat(user, SPAN_WARNING("There is no connector for the power cell inside \the [src].")) - return + to_chat(user, SPAN_WARNING("There is no connector for the power cell inside [src].")) + return COMPONENT_CELL_NO_RECHARGE + if(shape == NVG_SHAPE_BROKEN) - to_chat(user, SPAN_WARNING("You need to repair \the [src] first.")) - return - if(nvg_charge == nvg_maxcharge) - to_chat(user, SPAN_WARNING("\The [src] are already fully charged.")) - return + to_chat(user, SPAN_WARNING("You need to repair [src] first.")) + return COMPONENT_CELL_NO_RECHARGE - while(nvg_charge < nvg_maxcharge) - if(C.charge <= 0) - to_chat(user, SPAN_WARNING("\The [C] is completely dry.")) - break - if(!do_after(user, 1 SECONDS, (INTERRUPT_ALL & (~INTERRUPT_MOVED)), BUSY_ICON_BUILD, C, INTERRUPT_DIFF_LOC)) - to_chat(user, SPAN_WARNING("You were interrupted.")) - break - var/to_transfer = min(400, C.charge, (nvg_maxcharge - nvg_charge)) - if(C.use(to_transfer)) - nvg_charge += to_transfer - to_chat(user, "You transfer some power between \the [C] and \the [src]. The gauge now reads: [round(100.0*nvg_charge/nvg_maxcharge) ]%.") /obj/item/prop/helmetgarb/helmet_nvg/proc/repair(mob/user as mob) if(user.action_busy) @@ -197,7 +195,6 @@ to_chat(user, "You successfully patch \the [src].") nvg_maxhealth = 65 nvg_health = 65 - nvg_drain = initial(nvg_drain) * 2 return else if(nvg_health == nvg_maxhealth) @@ -239,9 +236,6 @@ else if(nvg_health_procent >= 0) . += "They are falling apart." - if (get_dist(user, src) <= 1 && (shape == NVG_SHAPE_FINE || shape == NVG_SHAPE_PATCHED)) - . += "A small gauge in the corner reads: Power: [round(100.0*nvg_charge/nvg_maxcharge) ]%." - /obj/item/prop/helmetgarb/helmet_nvg/on_exit_storage(obj/item/storage/S) remove_attached_item() return ..() @@ -291,7 +285,7 @@ if(attached_mob != user && slot == WEAR_HEAD) set_attached_mob(user) - if(slot == WEAR_HEAD && !nightvision && activated && nvg_charge > 0 && shape > NVG_SHAPE_BROKEN) + if(slot == WEAR_HEAD && !nightvision && activated && !SEND_SIGNAL(src, COMSIG_CELL_CHECK_CHARGE) && shape > NVG_SHAPE_BROKEN) enable_nvg(user) else remove_nvg() @@ -314,7 +308,7 @@ attached_item.update_icon() activation.update_button_icon() - START_PROCESSING(SSobj, src) + SEND_SIGNAL(src, COMSIG_CELL_START_TICK_DRAIN) /obj/item/prop/helmetgarb/helmet_nvg/proc/update_sight(mob/M) @@ -348,20 +342,15 @@ attached_mob.update_sight() - STOP_PROCESSING(SSobj, src) + SEND_SIGNAL(src, COMSIG_CELL_STOP_TICK_DRAIN) /obj/item/prop/helmetgarb/helmet_nvg/process(delta_time) - if(nvg_charge > 0 && !infinite_charge) - nvg_charge = max(0, nvg_charge - nvg_drain * delta_time) - if(!attached_mob) return PROCESS_KILL - if(!activated || !attached_item || nvg_charge <= 0 || attached_mob.is_dead()) - if(activated && !attached_mob.is_dead()) - to_chat(attached_mob, SPAN_WARNING("\The [src] emit a low power warning and immediately shut down!")) - remove_nvg() + if(!activated || !attached_item || attached_mob.is_dead()) + on_power_out() return if(!attached_item.has_garb_overlay()) @@ -370,6 +359,13 @@ return +/obj/item/prop/helmetgarb/helmet_nvg/proc/on_power_out(datum/source) + SIGNAL_HANDLER + + if(activated && !attached_mob.is_dead()) + to_chat(attached_mob, SPAN_WARNING("[src] emit a low power warning and immediately shut down!")) + remove_nvg() + /obj/item/prop/helmetgarb/helmet_nvg/ui_action_click(mob/owner, obj/item/holder) toggle_nods(owner) @@ -405,7 +401,7 @@ if(activated) to_chat(user, SPAN_NOTICE("You flip the goggles down.")) icon_state = active_icon_state - if(nvg_charge > 0 && user.head == attached_item && shape > NVG_SHAPE_BROKEN) + if(!SEND_SIGNAL(src, COMSIG_CELL_CHECK_CHARGE) && user.head == attached_item && shape > NVG_SHAPE_BROKEN) enable_nvg(user) else icon_state = active_icon_state @@ -457,7 +453,7 @@ /obj/item/prop/helmetgarb/helmet_nvg/marsoc //for Marine Raiders name = "\improper Tactical M3 night vision goggles" desc = "With an integrated self-recharging battery, nothing can stop you. Put them on your helmet and press the button and it's go-time." - infinite_charge = TRUE + cell_max_charge = -1 #undef NVG_SHAPE_COSMETIC #undef NVG_SHAPE_BROKEN @@ -515,3 +511,76 @@ desc = "This patch is all that remains of the Chaplaincy of the USS Almayer, along with the Chaplains themselves. Both no longer exist as a result of losses suffered during Operation Tychon Tackle." icon_state = "chaplain_patch" flags_obj = OBJ_NO_HELMET_BAND + +/obj/item/prop/helmetgarb/family_photo + name = "family photo" + desc = "" + icon = 'icons/obj/items/items.dmi' + icon_state = "photo" + ///The human who spawns with the photo + var/datum/weakref/owner + ///The belonging human name + var/owner_name + ///The belonging human faction + var/owner_faction + ///Text written on the back + var/scribble + +/obj/item/prop/helmetgarb/family_photo/pickup(mob/user, silent) + . = ..() + if(!owner) + RegisterSignal(user, COMSIG_POST_SPAWN_UPDATE, PROC_REF(set_owner)) + + +///Sets the owner of the family photo to the human it spawns with, needs var/source for signals +/obj/item/prop/helmetgarb/family_photo/proc/set_owner(datum/source) + SIGNAL_HANDLER + UnregisterSignal(source, COMSIG_POST_SPAWN_UPDATE) + var/mob/living/carbon/human/user = source + owner = WEAKREF(user) + owner_name = user.name + owner_faction = user.faction + +/obj/item/prop/helmetgarb/family_photo/get_examine_text(mob/user) + . = ..() + if(scribble) + . += "\"[scribble]\" is written on the back of the photo." + if(user.weak_reference == owner) + . += "A photo of you and your family." + return + if(user.faction == owner_faction) + . += "A photo of [owner_name] and their family." + return + . += "A photo of a family you do not know." + +/obj/item/prop/helmetgarb/family_photo/attackby(obj/item/attacking_item, mob/user) + . = ..() + if(HAS_TRAIT(attacking_item, TRAIT_TOOL_PEN) || istype(attacking_item, /obj/item/toy/crayon)) + if(scribble) + to_chat(user, SPAN_NOTICE("[src] has already been written on.")) + return + var/new_text = copytext(strip_html(tgui_input_text(user, "What would you like to write on the back of [src]?", "Photo Writing")), 1, 128) + + if(!loc == user) + to_chat(user, SPAN_NOTICE("You need to be holding [src] to write on it.")) + return + if(!user.stat == CONSCIOUS) + to_chat(user, SPAN_NOTICE("You cannot write on [src] in this state.")) + return + scribble = new_text + playsound(src, "paper_writing", 15, TRUE) + return TRUE + +/obj/item/prop/helmetgarb/compass + name = "compass" + desc = "It always faces north. Are you sure it is not broken?" + icon = 'icons/obj/items/items.dmi' + icon_state = "compass" + w_class = SIZE_SMALL + +/obj/item/prop/helmetgarb/bug_spray + name = "insect repellent" + desc = "A store-brand insect repellent, to keep any variety of pest or mosquito away from you." + icon = 'icons/obj/items/spray.dmi' + icon_state = "pestspray" + w_class = SIZE_SMALL diff --git a/code/game/objects/items/reagent_containers/food/snacks.dm b/code/game/objects/items/reagent_containers/food/snacks.dm index fdae52fee52a..33cc00f7899a 100644 --- a/code/game/objects/items/reagent_containers/food/snacks.dm +++ b/code/game/objects/items/reagent_containers/food/snacks.dm @@ -183,10 +183,9 @@ return 0 var/inaccurate = 0 - if(W.sharp == IS_SHARP_ITEM_ACCURATE) - else if(W.sharp == IS_SHARP_ITEM_BIG) + if(W.sharp == IS_SHARP_ITEM_BIG) inaccurate = 1 - else + else if(W.sharp != IS_SHARP_ITEM_ACCURATE) return 1 if ( !istype(loc, /obj/structure/surface/table) && \ (!isturf(src.loc) || \ @@ -207,7 +206,7 @@ SPAN_NOTICE("[user] crudely slices \the [src] with [W]!"), \ SPAN_NOTICE("You crudely slice \the [src] with your [W]!") \ ) - slices_lost = rand(1,min(1,round(slices_num/2))) + slices_lost = rand(1,max(1,round(slices_num/2))) var/reagents_per_slice = reagents.total_volume/slices_num for(var/i=1 to (slices_num-slices_lost)) var/obj/slice = new slice_path (src.loc) diff --git a/code/game/objects/items/reagent_containers/glass.dm b/code/game/objects/items/reagent_containers/glass.dm index 240809b7851f..df344506c72c 100644 --- a/code/game/objects/items/reagent_containers/glass.dm +++ b/code/game/objects/items/reagent_containers/glass.dm @@ -363,11 +363,8 @@ matter = list() possible_transfer_amounts = list(5,10,15,25,30) flags_atom = FPRINT|OPENCONTAINER - -/obj/item/reagent_container/glass/beaker/vial/Initialize() - . = ..() - pixel_y = rand(-8, 8) - pixel_x = rand(-9, 9) + ground_offset_x = 9 + ground_offset_y = 8 /obj/item/reagent_container/glass/beaker/vial/tricordrazine name = "tricordrazine vial" diff --git a/code/game/objects/items/reagent_containers/glass/bottle.dm b/code/game/objects/items/reagent_containers/glass/bottle.dm index dd857d391b52..01eb751774e1 100644 --- a/code/game/objects/items/reagent_containers/glass/bottle.dm +++ b/code/game/objects/items/reagent_containers/glass/bottle.dm @@ -30,7 +30,7 @@ /obj/item/reagent_container/glass/bottle/Initialize() . = ..() if(!icon_state) - icon_state = "bottle-[rand(1.4)]" + icon_state = "bottle-[rand(1,4)]" /obj/item/reagent_container/glass/bottle/update_icon() overlays.Cut() diff --git a/code/game/objects/items/reagent_containers/pill.dm b/code/game/objects/items/reagent_containers/pill.dm index de86ad07f53a..6c71d8be3c0c 100644 --- a/code/game/objects/items/reagent_containers/pill.dm +++ b/code/game/objects/items/reagent_containers/pill.dm @@ -23,6 +23,8 @@ w_class = SIZE_TINY volume = 60 reagent_desc_override = TRUE //it has a special examining mechanic + ground_offset_x = 7 + ground_offset_y = 7 var/identificable = TRUE //can medically trained people tell what's in it? var/pill_desc = "An unknown pill." // The real description of the pill, shown when examined by a medically trained person var/pill_icon_class = "random" // Pills with the same icon class share icons diff --git a/code/game/objects/items/reagent_containers/reagent_container.dm b/code/game/objects/items/reagent_containers/reagent_container.dm index eddbf5197a9e..327f6ba1ce1c 100644 --- a/code/game/objects/items/reagent_containers/reagent_container.dm +++ b/code/game/objects/items/reagent_containers/reagent_container.dm @@ -14,6 +14,8 @@ var/transparent = FALSE //can we see what's in it? var/reagent_desc_override = FALSE //does it have a special examining mechanic that should override the normal /reagent_containers examine proc? actions_types = list(/datum/action/item_action/reagent_container/set_transfer_amount) + ground_offset_x = 7 + ground_offset_y = 7 /obj/item/reagent_container/Initialize() if(!possible_transfer_amounts) @@ -65,12 +67,6 @@ if (N) R.amount_per_transfer_from_this = N -/obj/item/reagent_container/Initialize() - . = ..() - if (!possible_transfer_amounts) - verbs -= /obj/item/reagent_container/verb/set_APTFT //which objects actually uses it? - create_reagents(volume) - /obj/item/reagent_container/Destroy() possible_transfer_amounts = null return ..() diff --git a/code/game/objects/items/stacks/cable_coil.dm b/code/game/objects/items/stacks/cable_coil.dm index 9135c793cd00..e846979c00b4 100644 --- a/code/game/objects/items/stacks/cable_coil.dm +++ b/code/game/objects/items/stacks/cable_coil.dm @@ -20,14 +20,14 @@ attack_verb = list("whipped", "lashed", "disciplined", "flogged") stack_id = "cable coil" attack_speed = 3 + ground_offset_x = 2 + ground_offset_y = 2 /obj/item/stack/cable_coil/Initialize(mapload, length = MAXCOIL, param_color = null) . = ..() src.amount = length if (param_color) // It should be red by default, so only recolor it if parameter was specified. color = param_color - pixel_x = rand(-2,2) - pixel_y = rand(-2,2) updateicon() update_wclass() @@ -276,8 +276,6 @@ /obj/item/stack/cable_coil/cut/Initialize() . = ..() src.amount = rand(1,2) - pixel_x = rand(-2,2) - pixel_y = rand(-2,2) updateicon() update_wclass() diff --git a/code/game/objects/items/stacks/nanopaste.dm b/code/game/objects/items/stacks/nanopaste.dm index 32e9a030462e..754a36c6012a 100644 --- a/code/game/objects/items/stacks/nanopaste.dm +++ b/code/game/objects/items/stacks/nanopaste.dm @@ -40,7 +40,7 @@ H.pain.recalculate_pain() H.updatehealth() use(1) - var/others_msg = "\The [user] applies some nanite paste at[user != M ? " \the [M]'s" : " \the"] [S.display_name] with \the [src]." // Needs to create vars for these messages because macro doesn't work otherwise + var/others_msg = "\The [user] applies some nanite paste at[user != M ? " \the [M]'s" : " the"] [S.display_name] with \the [src]." // Needs to create vars for these messages because macro doesn't work otherwise var/user_msg = "You apply some nanite paste at [user == M ? "your" : "[M]'s"] [S.display_name]." user.visible_message(SPAN_NOTICE("[others_msg]"),\ SPAN_NOTICE("[user_msg]")) diff --git a/code/game/objects/items/stacks/sheets/glass.dm b/code/game/objects/items/stacks/sheets/glass.dm index 972898e6449b..6d0736f8aeb2 100644 --- a/code/game/objects/items/stacks/sheets/glass.dm +++ b/code/game/objects/items/stacks/sheets/glass.dm @@ -189,6 +189,13 @@ is_reinforced = 1 construction_options = list("One Direction", "Full Window", "Windoor") +/obj/item/stack/sheet/glass/reinforced/medium_stack + amount = 25 + +/obj/item/stack/sheet/glass/reinforced/large_stack + amount = 50 + + /obj/item/stack/sheet/glass/reinforced/cyborg matter = null diff --git a/code/game/objects/items/stacks/sheets/sheet_types.dm b/code/game/objects/items/stacks/sheets/sheet_types.dm index 98a7ab036f06..07345dcdc09f 100644 --- a/code/game/objects/items/stacks/sheets/sheet_types.dm +++ b/code/game/objects/items/stacks/sheets/sheet_types.dm @@ -69,6 +69,7 @@ var/global/list/datum/stack_recipe/metal_recipes = list ( \ sheettype = "metal" stack_id = "metal" + /obj/item/stack/sheet/metal/small_stack amount = STACK_10 @@ -114,6 +115,8 @@ var/global/list/datum/stack_recipe/plasteel_recipes = list ( \ amount_sprites = TRUE sheettype = "plasteel" stack_id = "plasteel" + ground_offset_x = 4 + ground_offset_y = 5 /obj/item/stack/sheet/plasteel/New(loc, amount=null) recipes = plasteel_recipes @@ -208,6 +211,7 @@ var/global/list/datum/stack_recipe/cardboard_recipes = list ( \ new/datum/stack_recipe("cardborg suit", /obj/item/clothing/suit/cardborg, 3), \ new/datum/stack_recipe("cardborg helmet", /obj/item/clothing/head/cardborg), \ new/datum/stack_recipe("pizza box", /obj/item/pizzabox), \ + new/datum/stack_recipe("dartboard", /obj/item/dartboard), \ null, \ new/datum/stack_recipe_list("folders",list( \ new/datum/stack_recipe("blue folder", /obj/item/folder/blue), \ diff --git a/code/game/objects/items/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm index ac778c0569ed..3912e2d64165 100644 --- a/code/game/objects/items/stacks/stack.dm +++ b/code/game/objects/items/stacks/stack.dm @@ -182,6 +182,11 @@ Also change the icon to reflect the amount of sheets, if possible.*/ to_chat(usr, SPAN_WARNING("The [R.title] cannot be built here!")) //might cause some friendly fire regarding other items like barbed wire, shouldn't be a problem? return + var/obj/structure/tunnel/tunnel = locate(/obj/structure/tunnel) in usr.loc + if(tunnel) + to_chat(usr, SPAN_WARNING("The [R.title] cannot be constructed on a tunnel!")) + return + if((R.flags & RESULT_REQUIRES_SNOW) && !(istype(usr.loc, /turf/open/snow) || istype(usr.loc, /turf/open/auto_turf/snow))) to_chat(usr, SPAN_WARNING("The [R.title] must be built on snow!")) return @@ -202,13 +207,21 @@ Also change the icon to reflect the amount of sheets, if possible.*/ if(check_one_per_turf(R,usr)) return - var/atom/O = new R.result_type(usr.loc, usr) - usr.visible_message(SPAN_NOTICE("[usr] assembles \a [O]."), - SPAN_NOTICE("You assemble \a [O].")) - O.setDir(usr.dir) + var/atom/new_item + if(ispath(R.result_type, /turf)) + var/turf/current_turf = get_turf(usr) + if(!current_turf) + return + new_item = current_turf.ChangeTurf(R.result_type) + else + new_item = new R.result_type(usr.loc, usr) + + usr.visible_message(SPAN_NOTICE("[usr] assembles \a [new_item]."), + SPAN_NOTICE("You assemble \a [new_item].")) + new_item.setDir(usr.dir) if(R.max_res_amount > 1) - var/obj/item/stack/new_item = O - new_item.amount = R.res_amount * multiplier + var/obj/item/stack/new_stack = new_item + new_stack.amount = R.res_amount * multiplier amount -= R.req_amount * multiplier update_icon() @@ -218,25 +231,25 @@ Also change the icon to reflect the amount of sheets, if possible.*/ usr.drop_inv_item_on_ground(oldsrc) qdel(oldsrc) - if(istype(O,/obj/item/stack)) //floor stacking convenience - var/obj/item/stack/S = O - for(var/obj/item/stack/F in usr.loc) - if(S.stack_id == F.stack_id && S != F) - var/diff = F.max_amount - F.amount - if (S.amount < diff) - F.amount += S.amount - qdel(S) + if(istype(new_item,/obj/item/stack)) //floor stacking convenience + var/obj/item/stack/stack_item = new_item + for(var/obj/item/stack/found_item in usr.loc) + if(stack_item.stack_id == found_item.stack_id && stack_item != found_item) + var/diff = found_item.max_amount - found_item.amount + if (stack_item.amount < diff) + found_item.amount += stack_item.amount + qdel(stack_item) else - S.amount -= diff - F.amount += diff + stack_item.amount -= diff + found_item.amount += diff break - O?.add_fingerprint(usr) + new_item?.add_fingerprint(usr) //BubbleWrap - so newly formed boxes are empty - if(isstorage(O)) - for (var/obj/item/I in O) - qdel(I) + if(isstorage(new_item)) + for (var/obj/item/found_item in new_item) + qdel(found_item) //BubbleWrap END if(src && usr.interactee == src) //do not reopen closed window INVOKE_ASYNC(src, PROC_REF(interact), usr) diff --git a/code/game/objects/items/storage/backpack.dm b/code/game/objects/items/storage/backpack.dm index 3b65811b05b3..966b18fc494b 100644 --- a/code/game/objects/items/storage/backpack.dm +++ b/code/game/objects/items/storage/backpack.dm @@ -72,9 +72,9 @@ return FALSE // Create their vis object if needed - if(!xeno.backpack_icon_carrier) - xeno.backpack_icon_carrier = new(null, xeno) - xeno.vis_contents += xeno.backpack_icon_carrier + if(!xeno.backpack_icon_holder) + xeno.backpack_icon_holder = new(null, xeno) + xeno.vis_contents += xeno.backpack_icon_holder target_mob.put_in_back(src) return FALSE @@ -566,6 +566,18 @@ GLOBAL_LIST_EMPTY_TYPED(radio_packs, /obj/item/storage/backpack/marine/satchel/r /obj/item/storage/backpack/marine/satchel/rto/pickup(mob/user) . = ..() + autoset_phone_id(user) + +/obj/item/storage/backpack/marine/satchel/rto/equipped(mob/user, slot) + . = ..() + autoset_phone_id(user) + +/// Automatically sets the phone_id based on the current or updated user +/obj/item/storage/backpack/marine/satchel/rto/proc/autoset_phone_id(mob/user) + if(!user) + internal_transmitter.phone_id = "[src]" + internal_transmitter.enabled = FALSE + return if(ishuman(user)) var/mob/living/carbon/human/H = user if(H.comm_title) @@ -579,13 +591,11 @@ GLOBAL_LIST_EMPTY_TYPED(radio_packs, /obj/item/storage/backpack/marine/satchel/r internal_transmitter.phone_id += " ([H.assigned_squad.name])" else internal_transmitter.phone_id = "[user]" - internal_transmitter.enabled = TRUE /obj/item/storage/backpack/marine/satchel/rto/dropped(mob/user) . = ..() - internal_transmitter.phone_id = "[src]" - internal_transmitter.enabled = FALSE + autoset_phone_id(null) // Disable phone when dropped /obj/item/storage/backpack/marine/satchel/rto/proc/use_phone(mob/user) internal_transmitter.attack_hand(user) @@ -745,6 +755,7 @@ GLOBAL_LIST_EMPTY_TYPED(radio_packs, /obj/item/storage/backpack/marine/satchel/r RegisterSignal(H, COMSIG_GRENADE_PRE_PRIME, PROC_REF(cloak_grenade_callback)) RegisterSignal(H, COMSIG_HUMAN_EXTINGUISH, PROC_REF(wrapper_fizzle_camouflage)) + RegisterSignal(H, COMSIG_MOB_EFFECT_CLOAK_CANCEL, PROC_REF(deactivate_camouflage)) camo_active = TRUE ADD_TRAIT(H, TRAIT_CLOAKED, TRAIT_SOURCE_EQUIPMENT(WEAR_BACK)) @@ -774,12 +785,14 @@ GLOBAL_LIST_EMPTY_TYPED(radio_packs, /obj/item/storage/backpack/marine/satchel/r deactivate_camouflage(wearer, TRUE, TRUE) /obj/item/storage/backpack/marine/satchel/scout_cloak/proc/deactivate_camouflage(mob/living/carbon/human/H, anim = TRUE, forced) + SIGNAL_HANDLER if(!istype(H)) return FALSE UnregisterSignal(H, list( COMSIG_GRENADE_PRE_PRIME, - COMSIG_HUMAN_EXTINGUISH + COMSIG_HUMAN_EXTINGUISH, + COMSIG_MOB_EFFECT_CLOAK_CANCEL, )) if(forced) @@ -1114,6 +1127,10 @@ GLOBAL_LIST_EMPTY_TYPED(radio_packs, /obj/item/storage/backpack/marine/satchel/r max_storage_space = 21 camo_alpha = 10 +/obj/item/storage/backpack/marine/satchel/scout_cloak/upp/weak + desc = "A thermo-optic camouflage cloak commonly used by UPP commando units. This one is less effective than normal." + actions_types = null + //----------TWE SECTION---------- /obj/item/storage/backpack/rmc has_gamemode_skin = FALSE diff --git a/code/game/objects/items/storage/belt.dm b/code/game/objects/items/storage/belt.dm index 301f6de2bc70..71edc21e29f9 100644 --- a/code/game/objects/items/storage/belt.dm +++ b/code/game/objects/items/storage/belt.dm @@ -151,7 +151,7 @@ storage_slots = 14 max_w_class = SIZE_MEDIUM max_storage_space = 28 - var/mode = 0 //Pill picking mode + var/mode = 1 //Picking from pill bottle mode can_hold = list( /obj/item/device/healthanalyzer, diff --git a/code/game/objects/items/storage/boxes.dm b/code/game/objects/items/storage/boxes.dm index 6266f0eef77d..4a3afa00f368 100644 --- a/code/game/objects/items/storage/boxes.dm +++ b/code/game/objects/items/storage/boxes.dm @@ -151,6 +151,7 @@ RegisterSignal(SSdcs, COMSIG_GLOB_MODE_PRESETUP, PROC_REF(handle_delete_clash_contents)) /obj/item/storage/box/flashbangs/proc/handle_delete_clash_contents() + SIGNAL_HANDLER if(MODE_HAS_FLAG(MODE_FACTION_CLASH)) var/grenade_count = 0 var/grenades_desired = 4 diff --git a/code/game/objects/items/storage/fancy.dm b/code/game/objects/items/storage/fancy.dm index ea43d6b074b9..9afa0dfd1851 100644 --- a/code/game/objects/items/storage/fancy.dm +++ b/code/game/objects/items/storage/fancy.dm @@ -71,7 +71,7 @@ storage_slots = 5 throwforce = 2 flags_equip_slot = SLOT_WAIST - + can_hold = list(/obj/item/tool/candle) /obj/item/storage/fancy/candle_box/fill_preset_inventory() for(var/i=1; i <= storage_slots; i++) diff --git a/code/game/objects/items/storage/firstaid.dm b/code/game/objects/items/storage/firstaid.dm index 509690a8dc2a..2514e2e5f10c 100644 --- a/code/game/objects/items/storage/firstaid.dm +++ b/code/game/objects/items/storage/firstaid.dm @@ -98,6 +98,11 @@ /obj/item/storage/firstaid/regular/empty/fill_preset_inventory() return +/obj/item/storage/firstaid/regular/response + desc = "It's an emergency medical kit containing basic medication and equipment. No training required to use. This one is simpler and requires no training to store." + required_skill_for_nest_opening = SKILL_MEDICAL + required_skill_level_for_nest_opening = SKILL_MEDICAL_DEFAULT + /obj/item/storage/firstaid/robust icon_state = "firstaid" diff --git a/code/game/objects/items/storage/large_holster.dm b/code/game/objects/items/storage/large_holster.dm index ef2bcfb7216a..27026165fc31 100644 --- a/code/game/objects/items/storage/large_holster.dm +++ b/code/game/objects/items/storage/large_holster.dm @@ -75,20 +75,20 @@ desc = "A large leather scabbard used to carry a M2132 machete. It can be strapped to the back or the armor." icon_state = "machete_holster" flags_equip_slot = SLOT_WAIST|SLOT_BACK - can_hold = list(/obj/item/weapon/claymore/mercsword/machete) + can_hold = list(/obj/item/weapon/sword/machete) /obj/item/storage/large_holster/machete/full/fill_preset_inventory() - new /obj/item/weapon/claymore/mercsword/machete(src) + new /obj/item/weapon/sword/machete(src) /obj/item/storage/large_holster/machete/arnold name = "\improper QH20 pattern M2100 custom machete scabbard" desc = "A large leather scabbard used to carry a M2100 \"Ngájhe\" machete. It can be strapped to the back or the armor." icon_state = "arnold-machete-pouch" flags_equip_slot = SLOT_WAIST|SLOT_BACK - can_hold = list(/obj/item/weapon/claymore/mercsword/machete) + can_hold = list(/obj/item/weapon/sword/machete) /obj/item/storage/large_holster/machete/arnold/full/fill_preset_inventory() - new /obj/item/weapon/claymore/mercsword/machete/arnold(src) + new /obj/item/weapon/sword/machete/arnold(src) /obj/item/storage/large_holster/katana name = "\improper katana scabbard" @@ -97,10 +97,10 @@ force = 12 attack_verb = list("bludgeoned", "struck", "cracked") flags_equip_slot = SLOT_WAIST|SLOT_BACK - can_hold = list(/obj/item/weapon/katana) + can_hold = list(/obj/item/weapon/sword/katana) /obj/item/storage/large_holster/katana/full/fill_preset_inventory() - new /obj/item/weapon/katana(src) + new /obj/item/weapon/sword/katana(src) /obj/item/storage/large_holster/ceremonial_sword name = "ceremonial sword scabbard" @@ -108,10 +108,10 @@ icon_state = "ceremonial_sword_holster"//object icon is duplicate of katana holster, needs new icon at some point. force = 12 flags_equip_slot = SLOT_WAIST - can_hold = list(/obj/item/weapon/claymore/mercsword/ceremonial) + can_hold = list(/obj/item/weapon/sword/ceremonial) /obj/item/storage/large_holster/ceremonial_sword/full/fill_preset_inventory() - new /obj/item/weapon/claymore/mercsword/ceremonial(src) + new /obj/item/weapon/sword/ceremonial(src) /obj/item/storage/large_holster/m39 name = "\improper M276 pattern M39 holster rig" @@ -249,9 +249,13 @@ if(!ishuman(user) || user.is_mob_incapacitated()) return FALSE - var/obj/item/weapon/gun/flamer/M240T/F = user.get_active_hand() - if(!istype(F)) - to_chat(usr, "You must be holding the M240-T incinerator unit to use [src]") + if(user.back != src) + to_chat(user, "The [src] must be equipped before you can switch types") + return + + var/obj/item/weapon/gun/flamer/M240T/flamer = user.get_active_hand() + if(!istype(flamer)) + to_chat(user, "You must be holding the M240-T incinerator unit to use [src]") return if(!active_fuel) @@ -267,14 +271,13 @@ else active_fuel = fuelB - for(var/X in actions) - var/datum/action/A = X - A.update_button_icon() + for(var/datum/action/action_added as anything in actions) + action_added.update_button_icon() to_chat(user, "You switch the fuel tank to [active_fuel.caliber]") playsound(src, 'sound/machines/click.ogg', 25, TRUE) - F.current_mag = active_fuel - F.update_icon() + flamer.current_mag = active_fuel + flamer.update_icon() return TRUE @@ -326,7 +329,7 @@ /obj/item/storage/large_holster/fuelpack/get_examine_text(mob/user) . = ..() if(contents.len) - . += "It is storing \a M240-T incinerator unit." + . += "It is storing a M240-T incinerator unit." if (get_dist(user, src) <= 1) if(fuel) . += "The [fuel.caliber] currently contains: [round(fuel.get_ammo_percent())]% fuel." diff --git a/code/game/objects/items/storage/pouch.dm b/code/game/objects/items/storage/pouch.dm index a443a3b27cd0..acb87e988879 100644 --- a/code/game/objects/items/storage/pouch.dm +++ b/code/game/objects/items/storage/pouch.dm @@ -142,9 +142,9 @@ /obj/item/storage/pouch/survival name = "survival pouch" - desc = "It can carry flashlights, a pill, a crowbar, metal sheets, and some bandages." + desc = "A pouch given to colonists in the event of an emergency." icon_state = "tools" - storage_slots = 6 + storage_slots = 7 max_w_class = SIZE_MEDIUM can_hold = list( /obj/item/device/flashlight, @@ -153,6 +153,7 @@ /obj/item/stack/medical/bruise_pack, /obj/item/device/radio, /obj/item/attachable/bayonet, + /obj/item/stack/medical/splint, ) /obj/item/storage/pouch/survival/full/fill_preset_inventory() @@ -162,12 +163,12 @@ new /obj/item/stack/medical/bruise_pack(src) new /obj/item/device/radio(src) new /obj/item/attachable/bayonet(src) - + new /obj/item/stack/medical/splint(src) /obj/item/storage/pouch/survival/synth name = "synth survival pouch" desc = "An emergency pouch given to synthetics in the event of an emergency." icon_state = "tools" - storage_slots = 7 + storage_slots = 6 max_w_class = SIZE_MEDIUM can_hold = list( /obj/item/device/flashlight, @@ -180,7 +181,6 @@ ) /obj/item/storage/pouch/survival/synth/full/fill_preset_inventory() - new /obj/item/device/flashlight(src) new /obj/item/tool/crowbar/red(src) new /obj/item/tool/weldingtool(src) new /obj/item/stack/cable_coil(src) @@ -683,6 +683,18 @@ new /obj/item/reagent_container/hypospray/autoinjector/stimulant/redemption_stimulant(src) new /obj/item/reagent_container/hypospray/autoinjector/stimulant/speed_stimulant(src) +/obj/item/storage/pouch/medical/socmed/not_op/fill_preset_inventory() + new /obj/item/device/healthanalyzer(src) + new /obj/item/stack/medical/splint(src) + new /obj/item/stack/medical/advanced/bruise_pack(src) + new /obj/item/stack/medical/advanced/ointment(src) + new /obj/item/reagent_container/hypospray/autoinjector/bicaridine(src) + new /obj/item/reagent_container/hypospray/autoinjector/kelotane(src) + new /obj/item/reagent_container/hypospray/autoinjector/oxycodone(src) + new /obj/item/reagent_container/hypospray/autoinjector/emergency(src) + new /obj/item/reagent_container/hypospray/autoinjector/emergency(src) + new /obj/item/tool/extinguisher/mini(src) + /obj/item/storage/pouch/medical/socmed/dutch name = "\improper Dutch's Medical Pouch" desc = "A pouch bought from a black market trader by Dutch quite a few years ago. Rumoured to be stolen from secret USCM assets. Its contents have been slowly used up and replaced over the years." @@ -833,6 +845,15 @@ new /obj/item/stack/medical/advanced/ointment(src) new /obj/item/stack/medical/splint(src) +/obj/item/storage/pouch/medkit/full/toxin/fill_preset_inventory() + new /obj/item/device/healthanalyzer(src) + new /obj/item/storage/pill_bottle/antitox(src) + new /obj/item/storage/pill_bottle/antitox(src) + new /obj/item/roller(src) + new /obj/item/stack/medical/splint(src) + new /obj/item/stack/medical/advanced/bruise_pack(src) + new /obj/item/stack/medical/advanced/ointment(src) + /obj/item/storage/pouch/pressurized_reagent_canister name = "Pressurized Reagent Canister Pouch" max_w_class = SIZE_SMALL @@ -1172,23 +1193,37 @@ /obj/item/storage/pouch/tools name = "tools pouch" - desc = "It's designed to hold maintenance tools - screwdriver, wrench, cable coil, etc. It also has a hook for an entrenching tool." + desc = "It's designed to hold maintenance tools - screwdriver, wrench, cable coil, etc. It also has a hook for an entrenching tool or light replacer." storage_slots = 4 max_w_class = SIZE_MEDIUM icon_state = "tools" can_hold = list( - /obj/item/tool/wirecutters, - /obj/item/tool/shovel/etool, - /obj/item/tool/screwdriver, /obj/item/tool/crowbar, + /obj/item/tool/screwdriver, /obj/item/tool/weldingtool, - /obj/item/device/multitool, + /obj/item/tool/wirecutters, /obj/item/tool/wrench, - /obj/item/stack/cable_coil, /obj/item/tool/extinguisher/mini, /obj/item/tool/shovel/etool, + /obj/item/stack/cable_coil, + /obj/item/weapon/gun/smg/nailgun/compact, + /obj/item/cell, + /obj/item/circuitboard, + /obj/item/stock_parts, + /obj/item/device/demo_scanner, + /obj/item/device/reagent_scanner, + /obj/item/device/assembly, + /obj/item/device/multitool, + /obj/item/device/flashlight, + /obj/item/device/t_scanner, + /obj/item/device/analyzer, + /obj/item/explosive/plastic, + /obj/item/device/lightreplacer, + ) + bypass_w_limit = list( + /obj/item/tool/shovel/etool, + /obj/item/device/lightreplacer, ) - bypass_w_limit = list(/obj/item/tool/shovel/etool) /obj/item/storage/pouch/tools/tactical name = "tactical tools pouch" @@ -1358,7 +1393,7 @@ item_state = "machete_holster" max_w_class = SIZE_LARGE storage_flags = STORAGE_FLAGS_POUCH|STORAGE_USING_DRAWING_METHOD|STORAGE_ALLOW_QUICKDRAW - can_hold = list(/obj/item/weapon/claymore/mercsword/machete) + can_hold = list(/obj/item/weapon/sword/machete) var/sheathe_sound = 'sound/weapons/gun_rifle_draw.ogg' var/draw_sound = 'sound/weapons/gun_rifle_draw.ogg' @@ -1378,4 +1413,4 @@ playsound(src, draw_sound, vol = 15, vary = TRUE) /obj/item/storage/pouch/machete/full/fill_preset_inventory() - new /obj/item/weapon/claymore/mercsword/machete(src) + new /obj/item/weapon/sword/machete(src) diff --git a/code/game/objects/items/storage/smartpack.dm b/code/game/objects/items/storage/smartpack.dm index 8df079c92ca4..0b0fd05eac17 100644 --- a/code/game/objects/items/storage/smartpack.dm +++ b/code/game/objects/items/storage/smartpack.dm @@ -144,7 +144,7 @@ immobile_form = FALSE M.status_flags |= CANPUSH M.anchored = FALSE - M.unfreeze() + REMOVE_TRAIT(M, TRAIT_IMMOBILIZED, TRAIT_SOURCE_EQUIPMENT(WEAR_BACK)) ..() /obj/item/storage/backpack/marine/smartpack/attack_self(mob/user) @@ -236,7 +236,7 @@ battery_charge -= IMMOBILE_COST user.status_flags &= ~CANPUSH user.anchored = TRUE - user.frozen = TRUE + ADD_TRAIT(user, TRAIT_IMMOBILIZED, TRAIT_SOURCE_EQUIPMENT(WEAR_BACK)) to_chat(user, SPAN_DANGER("[name] beeps, \"You are anchored in place and cannot be moved.\"")) to_chat(user, SPAN_INFO("The current charge reads [battery_charge]/[SMARTPACK_MAX_POWER_STORED]")) @@ -248,7 +248,7 @@ else user.status_flags |= CANPUSH user.anchored = FALSE - user.unfreeze() + REMOVE_TRAIT(user, TRAIT_IMMOBILIZED, TRAIT_SOURCE_EQUIPMENT(WEAR_BACK)) to_chat(user, SPAN_DANGER("[name] beeps, \"You can now move again.\"")) user.remove_filter("synth_immobile_form") diff --git a/code/game/objects/items/storage/storage.dm b/code/game/objects/items/storage/storage.dm index e3fbe86c0e3b..6e7e891d6ba8 100644 --- a/code/game/objects/items/storage/storage.dm +++ b/code/game/objects/items/storage/storage.dm @@ -22,7 +22,7 @@ var/atom/movable/screen/storage/storage_start = null //storage UI var/atom/movable/screen/storage/storage_continue = null var/atom/movable/screen/storage/storage_end = null - var/datum/item_storage_box/stored_ISB = null // This contains what previously was known as stored_start, stored_continue, and stored_end + var/datum/item_storage_box/stored_ISB //! This contains what previously was known as stored_start, stored_continue, and stored_end var/atom/movable/screen/close/closer = null var/foldable = null var/use_sound = "rustle" //sound played when used. null for no sound. @@ -212,16 +212,17 @@ if (storage_flags & STORAGE_SHOW_FULLNESS) boxes.update_fullness(src) -var/list/global/item_storage_box_cache = list() +GLOBAL_LIST_EMPTY_TYPED(item_storage_box_cache, /datum/item_storage_box) /datum/item_storage_box - var/atom/movable/screen/storage/start = null - var/atom/movable/screen/storage/continued = null - var/atom/movable/screen/storage/end = null - /// The index that indentifies me inside item_storage_box_cache + var/atom/movable/screen/storage/start + var/atom/movable/screen/storage/continued + var/atom/movable/screen/storage/end + /// The index that indentifies me inside GLOB.item_storage_box_cache var/index /datum/item_storage_box/New() + . = ..() start = new() start.icon_state = "stored_start" continued = new() @@ -233,7 +234,7 @@ var/list/global/item_storage_box_cache = list() QDEL_NULL(start) QDEL_NULL(continued) QDEL_NULL(end) - item_storage_box_cache[index] = null // Or would it be better to -= src? + GLOB.item_storage_box_cache -= index return ..() /obj/item/storage/proc/space_orient_objs(list/obj/item/display_contents) @@ -271,7 +272,7 @@ var/list/global/item_storage_box_cache = list() click_border_start.Add(startpoint) click_border_end.Add(endpoint) - if(!item_storage_box_cache[isb_index]) + if(!GLOB.item_storage_box_cache[isb_index]) var/datum/item_storage_box/box = new() var/matrix/M_start = matrix() var/matrix/M_continue = matrix() @@ -284,9 +285,9 @@ var/list/global/item_storage_box_cache = list() box.continued.apply_transform(M_continue) box.end.apply_transform(M_end) box.index = isb_index - item_storage_box_cache[isb_index] = box + GLOB.item_storage_box_cache[isb_index] = box - var/datum/item_storage_box/ISB = item_storage_box_cache[isb_index] + var/datum/item_storage_box/ISB = GLOB.item_storage_box_cache[isb_index] stored_ISB = ISB storage_start.overlays += ISB.start @@ -851,6 +852,7 @@ W is always an item. stop_warning prevents messaging. user may be null.**/ return ..() /obj/item/storage/emp_act(severity) + . = ..() if(!istype(src.loc, /mob/living)) for(var/obj/O in contents) O.emp_act(severity) diff --git a/code/game/objects/items/tools/flame_tools.dm b/code/game/objects/items/tools/flame_tools.dm index 130bd567098b..7681e74a1d88 100644 --- a/code/game/objects/items/tools/flame_tools.dm +++ b/code/game/objects/items/tools/flame_tools.dm @@ -642,7 +642,39 @@ CIGARETTE PACKETS ARE IN FANCY.DM icon_off = "cobpipeoff" smoketime = 800 SECONDS +/obj/item/clothing/mask/electronic_cigarette + name = "electronic cigarette" + desc = "An electronic cigarette by The American Tobacco Company, who also made Lucky Strikes." + icon_state = "cigoff" + item_state = "cigoff" + w_class = SIZE_SMALL + flags_equip_slot = SLOT_EAR|SLOT_FACE + var/icon_on = "cigon" + var/icon_off = "cigoff" + var/enabled = FALSE +/obj/item/clothing/mask/electronic_cigarette/update_icon() + . = ..() + if(enabled) + icon_state = icon_on + item_state = icon_on + return + icon_state = icon_off + item_state = icon_off + +/obj/item/clothing/mask/electronic_cigarette/attack_self(mob/user) + . = ..() + to_chat(user, SPAN_NOTICE("You [enabled ? "disable" : "enable"] [src].")) + enabled = !enabled + update_icon() + +/obj/item/clothing/mask/electronic_cigarette/cigar + name = "electronic cigar" + desc = "A luxury electronic cigar, with its labels scratched off. Where could this be from?" + icon_state = "cigar_off" + item_state = "cigar_off" + icon_on = "cigar_on" + icon_off = "cigar_off" ///////// //ZIPPO// diff --git a/code/game/objects/items/tools/misc_tools.dm b/code/game/objects/items/tools/misc_tools.dm index b5be55eed540..0b4a7cc98775 100644 --- a/code/game/objects/items/tools/misc_tools.dm +++ b/code/game/objects/items/tools/misc_tools.dm @@ -173,7 +173,7 @@ playsound(user.loc, "sound/items/pen_click_[on? "on": "off"].ogg", 100, 1, 5) update_pen_state() -/obj/item/tool/pen/Initialize() +/obj/item/tool/pen/Initialize(mapload, ...) . = ..() update_pen_state() @@ -284,21 +284,24 @@ matter = list("metal" = 20, "gold" = 10) var/static/list/colour_list = list("red", "blue", "green", "yellow", "purple", "pink", "brown", "black", "orange") // Can add more colors as required var/current_colour_index = 1 - var/owner = "hard to read text" + var/owner_name -/obj/item/tool/pen/fountain/Initialize(mapload, mob/living/carbon/human/user) +/obj/item/tool/pen/fountain/pickup(mob/user, silent) . = ..() - var/turf/current_turf = get_turf(src) - var/mob/living/carbon/human/new_owner = locate() in current_turf - if(new_owner) - owner = new_owner.real_name - var/obj/structure/machinery/cryopod/new_owners_pod = locate() in current_turf - if(new_owners_pod) - owner = new_owners_pod.occupant?.real_name + if(!owner_name) + RegisterSignal(user, COMSIG_POST_SPAWN_UPDATE, PROC_REF(set_owner)) + +///Sets the owner of the pen to who it spawns with, requires var/source for signals +/obj/item/tool/pen/fountain/proc/set_owner(datum/source) + SIGNAL_HANDLER + UnregisterSignal(source, COMSIG_POST_SPAWN_UPDATE) + var/mob/living/carbon/human/user = source + owner_name = user.name /obj/item/tool/pen/fountain/get_examine_text(mob/user) . = ..() - . += "There's a laser engraving of [owner] on it." + if(owner_name) + . += "There's a laser engraving of [owner_name] on it." /obj/item/tool/pen/fountain/attack_self(mob/living/carbon/human/user) if(on) diff --git a/code/game/objects/items/toys/cards.dm b/code/game/objects/items/toys/cards.dm index b6e3bb558ec4..2debd83f9bab 100644 --- a/code/game/objects/items/toys/cards.dm +++ b/code/game/objects/items/toys/cards.dm @@ -21,7 +21,6 @@ icon = 'icons/obj/items/playing_cards.dmi' icon_state = "deck" w_class = SIZE_TINY - flags_item = NOTABLEMERGE var/base_icon = "deck" var/max_cards = 52 @@ -262,7 +261,6 @@ icon = 'icons/obj/items/playing_cards.dmi' icon_state = "empty" w_class = SIZE_TINY - flags_item = NOTABLEMERGE var/concealed = FALSE var/pile_state = FALSE diff --git a/code/game/objects/items/toys/toys.dm b/code/game/objects/items/toys/toys.dm index b2a66becd869..851f203c52c1 100644 --- a/code/game/objects/items/toys/toys.dm +++ b/code/game/objects/items/toys/toys.dm @@ -318,56 +318,6 @@ desc = "Mini-Mecha action figure! Collect them all! 11/11." icon_state = "phazonprize" - -/obj/item/toy/therapy_red - name = "red therapy doll" - desc = "A therapeutic toy to assist marines in recovering from mental and behavioral disorders after experiencing the trauma of battles. This one is red." - icon = 'icons/obj/items/toy.dmi' - icon_state = "therapyred" - item_state = "egg4" // It's the red egg in items_left/righthand - w_class = SIZE_TINY - -/obj/item/toy/therapy_purple - name = "purple therapy doll" - desc = "A therapeutic toy to assist marines in recovering from mental and behavioral disorders after experiencing the trauma of battles. This one is purple." - icon = 'icons/obj/items/toy.dmi' - icon_state = "therapypurple" - item_state = "egg1" // It's the magenta egg in items_left/righthand - w_class = SIZE_TINY - -/obj/item/toy/therapy_blue - name = "blue therapy doll" - desc = "A therapeutic toy to assist marines in recovering from mental and behavioral disorders after experiencing the trauma of battles. This one is blue." - icon = 'icons/obj/items/toy.dmi' - icon_state = "therapyblue" - item_state = "egg2" // It's the blue egg in items_left/righthand - w_class = SIZE_TINY - -/obj/item/toy/therapy_yellow - name = "yellow therapy doll" - desc = "A therapeutic toy to assist marines in recovering from mental and behavioral disorders after experiencing the trauma of battles. This one is yellow." - icon = 'icons/obj/items/toy.dmi' - icon_state = "therapyyellow" - item_state = "egg5" // It's the yellow egg in items_left/righthand - w_class = SIZE_TINY - -/obj/item/toy/therapy_orange - name = "orange therapy doll" - desc = "A therapeutic toy to assist marines in recovering from mental and behavioral disorders after experiencing the trauma of battles. This one is orange." - icon = 'icons/obj/items/toy.dmi' - icon_state = "therapyorange" - item_state = "egg4" // It's the red one again, lacking an orange item_state and making a new one is pointless - w_class = SIZE_TINY - -/obj/item/toy/therapy_green - name = "green therapy doll" - desc = "A therapeutic toy to assist marines in recovering from mental and behavioral disorders after experiencing the trauma of battles. This one is green." - icon = 'icons/obj/items/toy.dmi' - icon_state = "therapygreen" - item_state = "egg3" // It's the green egg in items_left/righthand - w_class = SIZE_TINY - - /obj/item/toy/inflatable_duck name = "inflatable duck" desc = "No bother to sink or swim when you can just float!" @@ -377,7 +327,6 @@ flags_equip_slot = SLOT_WAIST black_market_value = 20 - /obj/item/toy/beach_ball name = "beach ball" icon_state = "beachball" @@ -394,7 +343,6 @@ user.drop_held_item() throw_atom(target, throw_range, throw_speed, user) - /obj/item/toy/dice name = "d6" desc = "A die with six sides." @@ -427,10 +375,6 @@ SPAN_NOTICE("You throw [src]. It lands on a [result]. [comment]"), \ SPAN_NOTICE("You hear [src] landing on a [result]. [comment]")) - - - - /obj/item/toy/bikehorn name = "bike horn" desc = "A horn off of a bicycle." @@ -455,47 +399,6 @@ src.add_fingerprint(user) addtimer(VARSET_CALLBACK(src, spam_flag, FALSE), 2 SECONDS) - - -/obj/item/toy/farwadoll - name = "Farwa plush doll" - desc = "A Farwa plush doll. It's soft and comforting!" - w_class = SIZE_TINY - icon_state = "farwaplush" - black_market_value = 25 - COOLDOWN_DECLARE(last_hug_time) - -/obj/item/toy/farwadoll/attack_self(mob/user) - ..() - - if(COOLDOWN_FINISHED(src, last_hug_time)) - user.visible_message(SPAN_NOTICE("[user] hugs [src]! How cute! "), \ - SPAN_NOTICE("You hug [src]. Dawwww... ")) - COOLDOWN_START(src, last_hug_time, 5 SECONDS) - -/obj/item/toy/farwadoll/pred - name = "strange plush doll" - desc = "A plush doll depicting some sort of tall humanoid biped..?" - w_class = SIZE_TINY - icon_state = "predplush" - -/obj/item/toy/plushie_cade - name = "plushie barricade" - desc = "Great for squeezing whenever you're scared. Or lightly hurt. Or in any other situation." - icon_state = "plushie_cade" - item_state = "plushie_cade" - w_class = SIZE_SMALL - COOLDOWN_DECLARE(last_hug_time) - -/obj/item/toy/plushie_cade/attack_self(mob/user) - ..() - - if(COOLDOWN_FINISHED(src, last_hug_time)) - user.visible_message(SPAN_NOTICE("[user] hugs [src] tightly!"), SPAN_NOTICE("You hug [src]. You feel safe.")) - playsound(user, "plush", 25, TRUE) - COOLDOWN_START(src, last_hug_time, 2.5 SECONDS) - - /obj/item/computer3_part name = "computer part" desc = "Holy jesus you donnit now" @@ -567,3 +470,188 @@ /obj/item/toy/festivizer/xeno name = "strange resin-covered festivizer decorator" desc = "This bizarre festivizer is covered in goopy goop and schmuck. Ew! It's so sticky, *anything* could grab onto it! Grab it and touch other things to festivize them!" + +/obj/item/toy/plush + name = "generic plushie" + desc = "perfectly generic" + icon = 'icons/obj/items/plush.dmi' + icon_state = "debug" + w_class = SIZE_SMALL + COOLDOWN_DECLARE(last_hug_time) + black_market_value = 10 + +/obj/item/toy/plush/attack_self(mob/user) + ..() + if(!COOLDOWN_FINISHED(src, last_hug_time)) + return + user.visible_message(SPAN_NOTICE("[user] hugs [src] tightly!"), SPAN_NOTICE("You hug [src].")) + playsound(user, "plush", 25, TRUE) + COOLDOWN_START(src, last_hug_time, 2.5 SECONDS) + +/obj/item/toy/plush/farwa + name = "Farwa plush" + desc = "A Farwa plush doll. It's soft and comforting!" + icon_state = "farwa" + black_market_value = 25 + +/obj/item/toy/plush/barricade + name = "plushie barricade" + desc = "Great for squeezing whenever you're scared. Or lightly hurt. Or in any other situation." + icon_state = "barricade" + item_state = "cade_plush" + +/obj/item/toy/plush/shark //A few more generic plushies to increase the size of the plushie loot pool + name = "shark plush" + desc = "A plushie depicting a somewhat cartoonish shark. The tag notes that it was made by an obscure furniture manufacturer in Scandinavia." + icon_state = "shark" + +/obj/item/toy/plush/bee + name = "bee plush" + desc = "A cute toy that awakens the warrior spirit in the most reserved marine." + icon_state = "bee" + +/obj/item/toy/plush/moth + name = "moth plush" + desc = "A plush doll of a bug." + icon_state = "moth" + +/obj/item/toy/plush/rock + name = "rock plush" + desc = "It says it is a plush on the tag, at least." + icon_state = "rock" + +/obj/item/toy/plush/therapy + name = "therapy plush" + desc = "A therapeutic toy to assist marines in recovering from mental and behavioral disorders after experiencing the trauma of battles." + icon_state = "therapy" + +/obj/item/toy/plush/therapy/red + name = "red therapy plush" + color = "#FC5274" + +/obj/item/toy/plush/therapy/blue + name = "blue therapy plush" + color = "#9EBAE0" + +/obj/item/toy/plush/therapy/green + name = "green therapy plush" + color = "#A3C940" + +/obj/item/toy/plush/therapy/orange + name = "orange therapy plush" + color = "#FD8535" + +/obj/item/toy/plush/therapy/purple + name = "purple therapy plush" + color = "#A26AC7" + +/obj/item/toy/plush/therapy/yellow + name = "yellow therapy plush" + color = "#FFE492" + +/obj/item/toy/plush/therapy/random_color + ///Hexadecimal 0-F (0-15) + var/static/list/hexadecimal = list("0", "1", "2", "3" , "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F") + +/obj/item/toy/plush/therapy/random_color/Initialize(mapload, ...) + . = ..() + var/color_code = "#[pick(hexadecimal)][pick(hexadecimal)][pick(hexadecimal)][pick(hexadecimal)][pick(hexadecimal)][pick(hexadecimal)]" //This is dumb and I hope theres a better way I'm missing + color = color_code + desc = "A custom therapy plush, in a unique color." + +/obj/item/toy/plush/random_plushie //Not using an effect so it can fit into storage from loadout + name = "random plush" + desc = "This plush looks awfully standard and bland. Is it actually yours?" + /// Standard plushies for the spawner to pick from + var/list/plush_list = list( + /obj/item/toy/plush/farwa, + /obj/item/toy/plush/barricade, + /obj/item/toy/plush/bee, + /obj/item/toy/plush/shark, + /obj/item/toy/plush/moth, + /obj/item/toy/plush/rock, + ) + ///Therapy plushies left separately to not flood the entire list + var/list/therapy_plush_list = list( + /obj/item/toy/plush/therapy, + /obj/item/toy/plush/therapy/red, + /obj/item/toy/plush/therapy/blue, + /obj/item/toy/plush/therapy/green, + /obj/item/toy/plush/therapy/orange, + /obj/item/toy/plush/therapy/purple, + /obj/item/toy/plush/therapy/yellow, + /obj/item/toy/plush/therapy/random_color, + ) + +/obj/item/toy/plush/random_plushie/Initialize(mapload, ...) + . = ..() + if(mapload) //Placed in mapping, will be randomized instantly on spawn + create_plushie() + return INITIALIZE_HINT_QDEL + +/obj/item/toy/plush/random_plushie/pickup(mob/user, silent) + . = ..() + RegisterSignal(user, COMSIG_POST_SPAWN_UPDATE, PROC_REF(create_plushie)) + +///The randomizer picking and spawning a plushie on either the ground or in the humans backpack. Needs var/source due to signals +/obj/item/toy/plush/random_plushie/proc/create_plushie(datum/source) + SIGNAL_HANDLER + if(source) + UnregisterSignal(source, COMSIG_POST_SPAWN_UPDATE) + var/turf/spawn_location = get_turf(src) + var/plush_list_variety = pick(60; plush_list, 40; therapy_plush_list) + var/random_plushie = pick(plush_list_variety) + var/obj/item/toy/plush/plush = new random_plushie(spawn_location) //Starts on floor by default + var/mob/living/carbon/human/user = source + + if(!user) //If it didn't spawn on a humanoid + qdel(src) + return + + var/obj/item/storage/backpack/storage = locate() in user //If the user has a backpack, put it there + if(storage?.can_be_inserted(plush, user, stop_messages = TRUE)) + storage.attempt_item_insertion(plush, TRUE, user) + if(plush.loc == spawn_location) // Still on the ground + user.put_in_hands(plush, drop_on_fail = TRUE) + qdel(src) + +//Admin plushies +/obj/item/toy/plush/yautja + name = "strange plush" + desc = "A plush doll depicting some sort of tall humanoid biped..?" + icon_state = "yautja" + black_market_value = 100 + +/obj/item/toy/plush/runner + name = "\improper XX-121 therapy plush" + desc = "Don't be sad! Be glad (that you're alive)!" + icon_state = "runner" + /// If the runner is wearing a beret + var/beret = FALSE + +/obj/item/toy/plush/runner/Initialize(mapload, ...) + . = ..() + if(beret) + update_icon() + +/obj/item/toy/plush/runner/attackby(obj/item/attacking_object, mob/user) + . = ..() + if(beret) + return + if(!istypestrict(attacking_object, /obj/item/clothing/head/beret/marine/mp)) + return + var/beret_attack = attacking_object + to_chat(user, SPAN_NOTICE("You put [beret_attack] on [src].")) + qdel(beret_attack) + beret = TRUE + update_icon() + +/obj/item/toy/plush/runner/update_icon() + . = ..() + if(beret) + icon_state = "runner_beret" + return + icon_state = "runner" + +/obj/item/toy/plush/shark/alt + icon_state = "shark_alt" diff --git a/code/game/objects/items/weapons/blades.dm b/code/game/objects/items/weapons/blades.dm index 0abe77616f1c..a2a4aa8db75d 100644 --- a/code/game/objects/items/weapons/blades.dm +++ b/code/game/objects/items/weapons/blades.dm @@ -1,38 +1,36 @@ -/obj/item/weapon/claymore - name = "claymore" - desc = "What are you standing around staring at this for? Get to killing!" - icon_state = "claymore" - item_state = "claymore" +/obj/item/weapon/sword + name = "combat sword" + desc = "A dusty sword commonly seen in historical museums. Where you got this is a mystery, for sure. Only a mercenary would be nuts enough to carry one of these. Sharpened to deal massive damage." + icon_state = "mercsword" + item_state = "machete" flags_atom = FPRINT|CONDUCT flags_equip_slot = SLOT_WAIST force = MELEE_FORCE_STRONG throwforce = MELEE_FORCE_WEAK sharp = IS_SHARP_ITEM_BIG edge = 1 - w_class = SIZE_MEDIUM + w_class = SIZE_LARGE hitsound = 'sound/weapons/bladeslice.ogg' attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") attack_speed = 9 -/obj/item/weapon/claymore/mercsword - name = "combat sword" - desc = "A dusty sword commonly seen in historical museums. Where you got this is a mystery, for sure. Only a mercenary would be nuts enough to carry one of these. Sharpened to deal massive damage." - icon_state = "mercsword" - item_state = "machete" +/obj/item/weapon/sword/claymore + name = "claymore" + desc = "What are you standing around staring at this for? Get to killing!" + icon_state = "claymore" + item_state = "claymore" -/obj/item/weapon/claymore/mercsword/ceremonial +/obj/item/weapon/sword/ceremonial name = "Ceremonial Sword" desc = "A fancy ceremonial sword passed down from generation to generation. Despite this, it has been very well cared for, and is in top condition." icon_state = "ceremonial" - item_state = "machete" -/obj/item/weapon/claymore/mercsword/machete +/obj/item/weapon/sword/machete name = "\improper M2132 machete" desc = "Latest issue of the USCM Machete. Great for clearing out jungle or brush on outlying colonies. Found commonly in the hands of scouts and trackers, but difficult to carry with the usual kit." icon_state = "machete" - w_class = SIZE_LARGE -/obj/item/weapon/claymore/mercsword/machete/attack_self(mob/user) +/obj/item/weapon/sword/machete/attack_self(mob/user) if(user.action_busy) return @@ -49,14 +47,13 @@ return ..() -/obj/item/weapon/claymore/mercsword/machete/arnold +/obj/item/weapon/sword/machete/arnold name = "\improper M2100 \"Ngájhe\" machete" desc = "An older issue USCM machete, never left testing. Designed in the Central African Republic. The notching made it hard to clean, and as such the USCM refused to adopt it - despite the superior bludgeoning power offered. Difficult to carry with the usual kit." icon_state = "arnold-machete" - w_class = SIZE_LARGE force = MELEE_FORCE_TIER_11 -/obj/item/weapon/claymore/hefa +/obj/item/weapon/sword/hefa name = "HEFA sword" icon_state = "hefasword" item_state = "hefasword" @@ -65,7 +62,7 @@ var/primed = FALSE -/obj/item/weapon/claymore/hefa/proc/apply_explosion_overlay() +/obj/item/weapon/sword/hefa/proc/apply_explosion_overlay() var/obj/effect/overlay/O = new /obj/effect/overlay(loc) O.name = "grenade" O.icon = 'icons/effects/explosion.dmi' @@ -73,7 +70,7 @@ QDEL_IN(O, 7) return -/obj/item/weapon/claymore/hefa/attack_self(mob/user) +/obj/item/weapon/sword/hefa/attack_self(mob/user) ..() primed = !primed @@ -82,7 +79,7 @@ msg = "You de-activate \the [src]!" to_chat(user, SPAN_NOTICE(msg)) -/obj/item/weapon/claymore/hefa/attack(mob/target, mob/user) +/obj/item/weapon/sword/hefa/attack(mob/target, mob/user) . = ..() if(!primed) return @@ -97,22 +94,15 @@ cell_explosion(epicenter, 40, 18, EXPLOSION_FALLOFF_SHAPE_LINEAR, user.dir, cause_data) qdel(src) -/obj/item/weapon/katana +/obj/item/weapon/sword/katana name = "katana" desc = "A finely made Japanese sword, with a well sharpened blade. The blade has been filed to a molecular edge, and is extremely deadly. Commonly found in the hands of mercenaries and yakuza." icon_state = "katana" - flags_atom = FPRINT|CONDUCT + item_state = "katana" force = MELEE_FORCE_VERY_STRONG - throwforce = MELEE_FORCE_WEAK - sharp = IS_SHARP_ITEM_BIG - edge = 1 - w_class = SIZE_MEDIUM - hitsound = 'sound/weapons/bladeslice.ogg' - attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") - attack_speed = 9 //To do: replace the toys. -/obj/item/weapon/katana/replica +/obj/item/weapon/sword/katana/replica name = "replica katana" desc = "A cheap knock-off commonly found in regular knife stores. Can still do some damage." force = MELEE_FORCE_WEAK @@ -248,3 +238,142 @@ WEAR_L_HAND = 'icons/mob/humans/onmob/items_lefthand_64.dmi', WEAR_R_HAND = 'icons/mob/humans/onmob/items_righthand_64.dmi' ) + +/obj/item/weapon/straight_razor + name = "straight razor" + desc = "The commandant's favorite weapon against marines who dare break the grooming standards." + icon_state = "razor" + hitsound = 'sound/weapons/genhit3.ogg' + force = MELEE_FORCE_TIER_1 + throwforce = MELEE_FORCE_TIER_1 + throw_speed = SPEED_VERY_FAST + throw_range = 6 + ///Icon state for opened razor + var/enabled_icon = "razor" + ///Icon state for closed razor + var/disabled_icon = "razor_off" + ///If the razor is able to be used + var/razor_opened = FALSE + ///Time taken to open/close the razor + var/interaction_time = 3 SECONDS + +/obj/item/weapon/straight_razor/Initialize(mapload, ...) + . = ..() + RegisterSignal(src, COMSIG_ITEM_ATTEMPTING_EQUIP, PROC_REF(can_fit_in_shoe)) + change_razor_state(razor_opened) + if(prob(1)) + desc += " There is phrase etched into it, \"It can guarantee the closest shave you'll ever know.\"..." + +/obj/item/weapon/straight_razor/update_icon() + . = ..() + if(razor_opened) + icon_state = enabled_icon + return + icon_state = disabled_icon + +/obj/item/weapon/straight_razor/attack_hand(mob/user) + if(loc != user) //Only do unique stuff if you are holding it + return ..() + + if(!do_after(user, interaction_time, INTERRUPT_INCAPACITATED, BUSY_ICON_HOSTILE)) + return + playsound(user, 'sound/weapons/flipblade.ogg', 15, 1) + change_razor_state(!razor_opened) + to_chat(user, SPAN_NOTICE("You [razor_opened ? "reveal" : "hide"] [src]'s blade.")) + +///Check if the item can fit as a boot knife, var/source for signals +/obj/item/weapon/straight_razor/proc/can_fit_in_shoe(source = src, mob/user, slot) + if(slot != WEAR_IN_SHOES) //Only check if you try putting it in a shoe + return + if(razor_opened) + to_chat(user, SPAN_NOTICE("You cannot store [src] in your shoes until the blade is hidden.")) + return COMPONENT_CANCEL_EQUIP + +///Changes all the vars for the straight razor +/obj/item/weapon/straight_razor/proc/change_razor_state(opening = FALSE) + razor_opened = opening + update_icon() + if(opening) + force = MELEE_FORCE_NORMAL + throwforce = MELEE_FORCE_NORMAL + sharp = IS_SHARP_ITEM_ACCURATE + edge = TRUE + attack_verb = list("slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") + hitsound = 'sound/weapons/slash.ogg' + if(!(flags_item & CAN_DIG_SHRAPNEL)) + flags_item |= CAN_DIG_SHRAPNEL + return + force = MELEE_FORCE_TIER_1 + throwforce = MELEE_FORCE_TIER_1 + sharp = FALSE + edge = FALSE + attack_verb = list("smashed", "beaten", "slammed", "struck", "smashed", "battered", "cracked") + hitsound = 'sound/weapons/genhit3.ogg' + if(flags_item & CAN_DIG_SHRAPNEL) + flags_item &= ~CAN_DIG_SHRAPNEL + +/obj/item/weapon/straight_razor/verb/change_hair_style() + set name = "Change Hair Style" + set desc = "Change your hair style" + set category = "Object" + set src in usr + + var/mob/living/carbon/human/human_user = usr + if(!istype(human_user)) + return + + if(!razor_opened) + to_chat(human_user, SPAN_NOTICE("You need to reveal [src]'s blade to change your hairstyle.")) + return + + var/list/species_facial_hair = GLOB.facial_hair_styles_list + var/list/species_hair = GLOB.hair_styles_list + + if(human_user.species) //Facial hair + species_facial_hair = list() + for(var/current_style in GLOB.facial_hair_styles_list) + var/datum/sprite_accessory/facial_hair/temp_beard_style = GLOB.facial_hair_styles_list[current_style] + if(!(human_user.species.name in temp_beard_style.species_allowed)) + continue + if(!temp_beard_style.selectable) + continue + species_facial_hair += current_style + + if(human_user.species) //Hair + species_hair = list() + for(var/current_style in GLOB.hair_styles_list) + var/datum/sprite_accessory/hair/temp_hair_style = GLOB.hair_styles_list[current_style] + if(!(human_user.species.name in temp_hair_style.species_allowed)) + continue + if(!temp_hair_style.selectable) + continue + species_hair += current_style + + var/new_beard_style + var/new_hair_style + if(human_user.gender == MALE) + new_beard_style = tgui_input_list(human_user, "Select a facial hair style", "Grooming", species_facial_hair) + new_hair_style = tgui_input_list(human_user, "Select a hair style", "Grooming", species_hair) + + if(loc != human_user) + to_chat(human_user, SPAN_NOTICE("You are too far from [src] to change your hair styles.")) + return + + if(!new_beard_style && !new_hair_style) + return + + if(!do_after(human_user, interaction_time, INTERRUPT_ALL, BUSY_ICON_GENERIC)) + return + + if(!razor_opened) + to_chat(human_user, SPAN_NOTICE("You need to reveal [src]'s blade to change your hairstyle.")) + return + + if(new_beard_style) + human_user.f_style = new_beard_style + if(new_hair_style) + human_user.h_style = new_hair_style + + human_user.apply_damage(rand(1,5), BRUTE, "head", src) + human_user.update_hair() + diff --git a/code/game/objects/items/weapons/shields.dm b/code/game/objects/items/weapons/shields.dm index 20bf8ac951e9..0497a410a373 100644 --- a/code/game/objects/items/weapons/shields.dm +++ b/code/game/objects/items/weapons/shields.dm @@ -89,7 +89,7 @@ /obj/item/weapon/shield/riot/attackby(obj/item/W as obj, mob/user as mob) if(cooldown < world.time - 25) - if(istype(W, /obj/item/weapon/baton) || istype(W, /obj/item/weapon/claymore) || istype(W, /obj/item/weapon/baseballbat) || istype(W, /obj/item/weapon/katana) || istype(W, /obj/item/weapon/twohanded/fireaxe) || istype(W, /obj/item/weapon/chainofcommand)) + if(istype(W, /obj/item/weapon/baton) || istype(W, /obj/item/weapon/sword) || istype(W, /obj/item/weapon/baseballbat) || istype(W, /obj/item/weapon/twohanded/fireaxe) || istype(W, /obj/item/weapon/chainofcommand)) user.visible_message(SPAN_WARNING("[user] bashes [src] with [W]!")) playsound(user.loc, 'sound/effects/shieldbash.ogg', 25, 1) cooldown = world.time diff --git a/code/game/objects/items/weapons/stunbaton.dm b/code/game/objects/items/weapons/stunbaton.dm index 6cb9f58aae37..82fdf30f0fc4 100644 --- a/code/game/objects/items/weapons/stunbaton.dm +++ b/code/game/objects/items/weapons/stunbaton.dm @@ -197,9 +197,9 @@ return TRUE /obj/item/weapon/baton/emp_act(severity) + . = ..() if(bcell) bcell.emp_act(severity) //let's not duplicate code everywhere if we don't have to please. - ..() //secborg stun baton module /obj/item/weapon/baton/robot/attack_self(mob/user) diff --git a/code/game/objects/items/weapons/weaponry.dm b/code/game/objects/items/weapons/weaponry.dm index aaa2a33d4e63..efa898ba9937 100644 --- a/code/game/objects/items/weapons/weaponry.dm +++ b/code/game/objects/items/weapons/weaponry.dm @@ -167,7 +167,7 @@ update_icon(user) -/obj/item/weapon/katana/sharp +/obj/item/weapon/sword/katana/sharp name = "absurdly sharp katana" desc = "

That's it. I'm sick of all this \"Masterwork Bastard Sword\" bullshit that's going on in CM-SS13 right now. Katanas deserve much better than that. Much, much better than that.

\

I should know what I'm talking about. I myself commissioned a genuine katana in Japan for 2,400,000 Yen (that's about $20,000) and have been practicing with it for almost 2 years now. I can even cut slabs of solid steel with my katana.

\ @@ -190,7 +190,7 @@ attack_verb = list("sliced", "diced", "cut") -/obj/item/weapon/katana/sharp/attack(mob/living/M, mob/living/user) +/obj/item/weapon/sword/katana/sharp/attack(mob/living/M, mob/living/user) if(flags_item & NOBLUDGEON) return @@ -223,7 +223,7 @@ //if the target also has a katana (and we aren't attacking ourselves), we add some suspense - if( ( istype(M.get_active_hand(), /obj/item/weapon/katana) || istype(M.get_inactive_hand(), /obj/item/weapon/katana) ) && M != user ) + if( ( istype(M.get_active_hand(), /obj/item/weapon/sword/katana) || istype(M.get_inactive_hand(), /obj/item/weapon/sword/katana) ) && M != user ) if(prob(50)) user.visible_message(SPAN_DANGER("[M] and [user] cross blades!")) diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm index 184fc51bd507..3fa16af05875 100644 --- a/code/game/objects/objs.dm +++ b/code/game/objects/objs.dm @@ -226,9 +226,14 @@ /obj/proc/afterbuckle(mob/M as mob) // Called after somebody buckled / unbuckled handle_rotation() SEND_SIGNAL(src, COSMIG_OBJ_AFTER_BUCKLE, buckled_mob) + if(!buckled_mob) + UnregisterSignal(M, COMSIG_PARENT_QDELETING) + else + RegisterSignal(buckled_mob, COMSIG_PARENT_QDELETING, PROC_REF(unbuckle)) return buckled_mob /obj/proc/unbuckle() + SIGNAL_HANDLER if(buckled_mob && buckled_mob.buckled == src) buckled_mob.buckled = null buckled_mob.anchored = initial(buckled_mob.anchored) diff --git a/code/game/objects/prop.dm b/code/game/objects/prop.dm index e59c24b30d5f..c067a9730e70 100644 --- a/code/game/objects/prop.dm +++ b/code/game/objects/prop.dm @@ -11,6 +11,66 @@ w_class = SIZE_SMALL garbage = TRUE +/obj/item/prop/geiger_counter + name = "geiger counter" + desc = "A geiger counter measures the radiation it receives. This type automatically records and transfers any information it reads, provided it has a battery, with no user input required beyond being enabled." + icon = 'icons/obj/items/devices.dmi' + icon_state = "geiger" + item_state = "" + w_class = SIZE_SMALL + flags_equip_slot = SLOT_WAIST + ///Whether the geiger counter is on or off + var/toggled_on = FALSE + ///Iconstate of geiger counter when on + var/enabled_state = "geiger_on" + ///Iconstate of geiger counter when off + var/disabled_state = "geiger" + ///New battery it will spawn with + var/starting_battery = /obj/item/cell/crap + ///Battery inside geiger counter + var/obj/item/cell/battery //It doesn't drain the battery, but it has a battery for emergency use + +/obj/item/prop/geiger_counter/Initialize(mapload, ...) + . = ..() + if(!starting_battery) + return + battery = new starting_battery(src) + +/obj/item/prop/geiger_counter/Destroy() + . = ..() + if(battery) + qdel(battery) + +/obj/item/prop/geiger_counter/attack_self(mob/user) + . = ..() + toggled_on = !toggled_on + if(!battery) + to_chat(user, SPAN_NOTICE("[src] is missing a battery.")) + return + to_chat(user, SPAN_NOTICE("You [toggled_on ? "enable" : "disable"] [src].")) + update_icon() + +/obj/item/prop/geiger_counter/attackby(obj/item/attacking_item, mob/user) + . = ..() + if(!HAS_TRAIT(attacking_item, TRAIT_TOOL_SCREWDRIVER) && !HAS_TRAIT(attacking_item, TRAIT_TOOL_CROWBAR)) + return + + if(!battery) + to_chat(user, SPAN_NOTICE("There is no battery for you to remove.")) + return + to_chat(user, SPAN_NOTICE("You jam [battery] out of [src] with [attacking_item], prying it out irreversibly.")) + user.put_in_hands(battery) + battery = null + update_icon() + +/obj/item/prop/geiger_counter/update_icon() + . = ..() + + if(battery && toggled_on) + icon_state = enabled_state + return + icon_state = disabled_state + /obj/item/prop/tableflag name = "United Americas table flag" icon = 'icons/obj/items/items.dmi' diff --git a/code/game/objects/structures/airlock_assembly.dm b/code/game/objects/structures/airlock_assembly.dm index 0679e1287ff7..d9e55e868016 100644 --- a/code/game/objects/structures/airlock_assembly.dm +++ b/code/game/objects/structures/airlock_assembly.dm @@ -22,9 +22,11 @@ var/airlock_type = "generic" //the type path of the airlock once completed var/glass = AIRLOCK_NOGLASS // see defines var/created_name = null + /// Used for multitile assemblies + var/width = 1 + /obj/structure/airlock_assembly/Initialize(mapload, ...) . = ..() - update_icon() /obj/structure/airlock_assembly/get_examine_text(mob/user) @@ -35,23 +37,26 @@ switch(state) if(STATE_STANDARD) if(anchored) - helpmessage += "It looks like a [SPAN_HELPFUL("wrench")] will unsecure it. Insert a [SPAN_HELPFUL("airlock circuit")]." + var/temp = "" + if(width == 1) + temp += "It looks like a [SPAN_HELPFUL("wrench")] will unsecure it. " + helpmessage += "[temp]You can insert an [SPAN_HELPFUL("airlock circuit")]. " if(!glass) - helpmessage += "Insert some [SPAN_HELPFUL("glass sheets")] to add windows to it." + helpmessage += "Insert some [SPAN_HELPFUL("glass sheets")] to add windows to it. " else if(glass == AIRLOCK_GLASSIN) - helpmessage += "You can take out the windows with a [SPAN_HELPFUL("screwdriver")]." + helpmessage += "You can take out the windows with a [SPAN_HELPFUL("screwdriver")]. " else - helpmessage += "It looks like a [SPAN_HELPFUL("wrench")] will secure it." + helpmessage += "It looks like a [SPAN_HELPFUL("wrench")] will secure it. " if(STATE_CIRCUIT) - helpmessage += "Add [SPAN_HELPFUL("cable coil")] to the circuit." + helpmessage += "Add [SPAN_HELPFUL("cable coil")] to the circuit. " if(STATE_WIRES) - helpmessage += "Secure the circuit with a [SPAN_HELPFUL("screwdriver")]." + helpmessage += "Secure the circuit with a [SPAN_HELPFUL("screwdriver")]. " if(STATE_SCREWDRIVER) - helpmessage += "[SPAN_HELPFUL("Weld")] it all in place." + helpmessage += "[SPAN_HELPFUL("Weld")] it all in place. " helpmessage += "You can name it with a [SPAN_HELPFUL("pen")]." . += SPAN_NOTICE(helpmessage) -/obj/structure/airlock_assembly/attackby(obj/item/W as obj, mob/user as mob) +/obj/structure/airlock_assembly/attackby(obj/item/attacking_item as obj, mob/user as mob) if(user.action_busy) return TRUE //no afterattack @@ -59,16 +64,16 @@ to_chat(user, SPAN_WARNING("You are not trained to configure \the [src]...")) return - if(HAS_TRAIT(W, TRAIT_TOOL_PEN)) - var/t = copytext(stripped_input(user, "Enter the name for the airlock.", name, created_name), 1, MAX_NAME_LEN) - if(!t || !in_range(src, usr) && loc != usr) + if(HAS_TRAIT(attacking_item, TRAIT_TOOL_PEN)) + var/input_text = copytext(stripped_input(user, "Enter the name for the airlock.", name, created_name), 1, MAX_NAME_LEN) + if(!input_text || !in_range(src, usr) && loc != usr) return - created_name = t + created_name = input_text playsound(src, "paper_writing", 15, TRUE) return - if(istype(W, /obj/item/stack/sheet/glass)) - var/obj/item/stack/sheet/glass/G = W + if(istype(attacking_item, /obj/item/stack/sheet/glass)) + var/obj/item/stack/sheet/glass/glass_sheet = attacking_item if(!anchored) to_chat(user, SPAN_NOTICE("The airlock is not secured!")) return @@ -83,7 +88,7 @@ return if(!do_after(user, 20 * user.get_skill_duration_multiplier(SKILL_CONSTRUCTION), INTERRUPT_ALL|BEHAVIOR_IMMOBILE, BUSY_ICON_BUILD)) return - if(G.use(5)) + if(glass_sheet.use(5)) playsound(loc, 'sound/items/Deconstruct.ogg', 25, 1) glass = AIRLOCK_GLASSIN to_chat(user, SPAN_NOTICE("You insert some glass into \the [src], adding windows to it.")) @@ -93,7 +98,7 @@ to_chat(user, SPAN_WARNING("You need five sheets of glass to add windows to \the [src]!")) return - if(HAS_TRAIT(W, TRAIT_TOOL_CROWBAR)) + if(HAS_TRAIT(attacking_item, TRAIT_TOOL_CROWBAR)) to_chat(user, SPAN_NOTICE("You start pulling \the [src] apart.")) playsound(loc, 'sound/items/Crowbar.ogg', 25, 1) if(!do_after(user, 20 * user.get_skill_duration_multiplier(SKILL_CONSTRUCTION), INTERRUPT_ALL|BEHAVIOR_IMMOBILE, BUSY_ICON_BUILD)) @@ -108,10 +113,14 @@ switch(state) if(STATE_STANDARD) - if(HAS_TRAIT(W, TRAIT_TOOL_WRENCH)) + if(HAS_TRAIT(attacking_item, TRAIT_TOOL_WRENCH)) + //Moving wide doors is wonky and doesn't work properly, if it's fixed we could make it unwrenchable again + if(width > 1 && anchored) + to_chat(user, SPAN_WARNING("[src] cannot be unwrenched.")) + return if(!anchored) - var/turf/open/T = loc - if(!(istype(T) && T.allow_construction)) + var/turf/open/checked_turf = loc + if(!(istype(checked_turf) && checked_turf.allow_construction)) to_chat(user, SPAN_WARNING("\The [src] cannot be secured here!")) return playsound(loc, 'sound/items/Ratchet.ogg', 25, 1) @@ -127,10 +136,10 @@ to_chat(user, SPAN_NOTICE("The airlock is not secured!")) return ..() - if(istype(W, /obj/item/circuitboard/airlock)) - var/obj/item/circuitboard/airlock/C = W - if(C.fried) // guess what this used to check? ICON STATE!! - to_chat(user, SPAN_WARNING("\The [C] are totally broken!")) + if(istype(attacking_item, /obj/item/circuitboard/airlock)) + var/obj/item/circuitboard/airlock/airlock_circuit = attacking_item + if(airlock_circuit.fried) // guess what this used to check? ICON STATE!! + to_chat(user, SPAN_WARNING("\The [airlock_circuit] are totally broken!")) return playsound(loc, 'sound/items/Screwdriver.ogg', 25, 1) to_chat(user, SPAN_NOTICE("You start installing the airlock electronics.")) @@ -138,14 +147,14 @@ return playsound(loc, 'sound/items/Screwdriver.ogg', 25, 1) user.drop_held_item() - W.forceMove(src) + attacking_item.forceMove(src) to_chat(user, SPAN_NOTICE("You installed the airlock electronics!")) state = STATE_CIRCUIT - electronics = W + electronics = attacking_item update_icon() return - if(HAS_TRAIT(W, TRAIT_TOOL_SCREWDRIVER)) + if(HAS_TRAIT(attacking_item, TRAIT_TOOL_SCREWDRIVER)) if(!anchored) to_chat(user, SPAN_NOTICE("The airlock is not secured!")) return @@ -163,22 +172,22 @@ if(STATE_CIRCUIT) - if(istype(W, /obj/item/stack/cable_coil)) - var/obj/item/stack/cable_coil/C = W - if (C.get_amount() < 1) + if(istype(attacking_item, /obj/item/stack/cable_coil)) + var/obj/item/stack/cable_coil/airlock_circuit = attacking_item + if (airlock_circuit.get_amount() < 1) to_chat(user, SPAN_WARNING("You need one length of coil to wire the airlock assembly.")) return to_chat(user, SPAN_NOTICE("You start to wire the circuit.")) if(!do_after(user, 40 * user.get_skill_duration_multiplier(SKILL_CONSTRUCTION), INTERRUPT_ALL|BEHAVIOR_IMMOBILE, BUSY_ICON_BUILD)) return - if(C.use(1)) + if(airlock_circuit.use(1)) state = STATE_WIRES to_chat(user, SPAN_NOTICE("You wire the circuit.")) update_icon() return if(STATE_WIRES) - if(HAS_TRAIT(W, TRAIT_TOOL_SCREWDRIVER)) + if(HAS_TRAIT(attacking_item, TRAIT_TOOL_SCREWDRIVER)) playsound(loc, 'sound/items/Screwdriver.ogg', 25, 1) to_chat(user, SPAN_NOTICE("You start securing the circuit")) if(!do_after(user, 40 * user.get_skill_duration_multiplier(SKILL_CONSTRUCTION), INTERRUPT_ALL|BEHAVIOR_IMMOBILE, BUSY_ICON_BUILD)) @@ -190,27 +199,23 @@ return if(STATE_SCREWDRIVER) - if(iswelder(W)) - if(!HAS_TRAIT(W, TRAIT_TOOL_BLOWTORCH)) + if(iswelder(attacking_item)) + if(!HAS_TRAIT(attacking_item, TRAIT_TOOL_BLOWTORCH)) to_chat(user, SPAN_WARNING("You need a stronger blowtorch!")) return - var/obj/item/tool/weldingtool/WT = W - if(!WT.remove_fuel(5, user)) + var/obj/item/tool/weldingtool/welder = attacking_item + if(!welder.remove_fuel(5, user)) return playsound(loc, 'sound/items/Welder2.ogg', 25, 1) to_chat(user, SPAN_NOTICE("Now finishing the airlock.")) if(!do_after(user, 40 * user.get_skill_duration_multiplier(SKILL_CONSTRUCTION), INTERRUPT_ALL|BEHAVIOR_IMMOBILE, BUSY_ICON_BUILD)) - WT.remove_fuel(-5) + welder.remove_fuel(-5) return playsound(loc, 'sound/items/Welder2.ogg', 25, 1) to_chat(user, SPAN_NOTICE("You finish the airlock!")) - var/path - if (glass == AIRLOCK_GLASSIN) - path = text2path("/obj/structure/machinery/door/airlock/almayer/[airlock_type]/glass") - else - path = text2path("/obj/structure/machinery/door/airlock/almayer/[airlock_type]") + var/path = get_airlock_path() var/obj/structure/machinery/door/airlock/door = new path(loc) door.assembly_type = type door.electronics = electronics @@ -225,7 +230,7 @@ door.name = created_name else door.name = base_name - + door.handle_multidoor() electronics.forceMove(door) qdel(src) return @@ -238,107 +243,107 @@ else icon_state = "door_as_[base_icon_state][state]" +/obj/structure/airlock_assembly/proc/get_airlock_path() + //For some reason multi_tile doors have different paths... can't say it isn't annoying + if (width > 1) + return "/obj/structure/machinery/door/airlock/multi_tile/almayer/[airlock_type][glass ? "" : "/solid"]" + return "/obj/structure/machinery/door/airlock/almayer/[airlock_type][glass ? "/glass" : ""]" + +/// Used for overloading proc in multi_tile +/obj/structure/airlock_assembly/proc/update_collision_box() + return + /obj/structure/airlock_assembly/airlock_assembly_com base_icon_state = "com" base_name = "Command Airlock" - airlock_type = "/command" + airlock_type = "command" /obj/structure/airlock_assembly/airlock_assembly_sec base_icon_state = "sec" base_name = "Security Airlock" - airlock_type = "/security" + airlock_type = "security" /obj/structure/airlock_assembly/airlock_assembly_eng base_icon_state = "eng" base_name = "Engineering Airlock" - airlock_type = "/engineering" + airlock_type = "engineering" /obj/structure/airlock_assembly/airlock_assembly_min base_icon_state = "min" base_name = "Mining Airlock" - airlock_type = "/mining" + airlock_type = "mining" /obj/structure/airlock_assembly/airlock_assembly_atmo base_icon_state = "atmo" base_name = "Atmospherics Airlock" - airlock_type = "/atmos" + airlock_type = "atmos" /obj/structure/airlock_assembly/airlock_assembly_research base_icon_state = "res" base_name = "Research Airlock" - airlock_type = "/research" + airlock_type = "research" /obj/structure/airlock_assembly/airlock_assembly_science base_icon_state = "sci" base_name = "Science Airlock" - airlock_type = "/science" + airlock_type = "science" /obj/structure/airlock_assembly/airlock_assembly_med base_icon_state = "med" base_name = "Medical Airlock" - airlock_type = "/medical" + airlock_type = "medical" /obj/structure/airlock_assembly/airlock_assembly_mai base_icon_state = "mai" base_name = "Maintenance Airlock" - airlock_type = "/maintenance" + airlock_type = "maintenance" glass = AIRLOCK_CANTGLASS /obj/structure/airlock_assembly/airlock_assembly_ext base_icon_state = "ext" base_name = "External Airlock" - airlock_type = "/external" + airlock_type = "external" glass = AIRLOCK_CANTGLASS /obj/structure/airlock_assembly/airlock_assembly_fre base_icon_state = "fre" base_name = "Freezer Airlock" - airlock_type = "/freezer" + airlock_type = "freezer" glass = AIRLOCK_CANTGLASS /obj/structure/airlock_assembly/airlock_assembly_hatch base_icon_state = "hatch" base_name = "Airtight Hatch" - airlock_type = "/hatch" + airlock_type = "hatch" glass = AIRLOCK_CANTGLASS /obj/structure/airlock_assembly/airlock_assembly_mhatch base_icon_state = "mhatch" base_name = "Maintenance Hatch" - airlock_type = "/maintenance_hatch" + airlock_type = "maintenance_hatch" glass = AIRLOCK_CANTGLASS /obj/structure/airlock_assembly/airlock_assembly_highsecurity // Borrowing this until WJohnston makes sprites for the assembly base_icon_state = "highsec" base_name = "High Security Airlock" - airlock_type = "/highsecurity" + airlock_type = "highsecurity" glass = AIRLOCK_CANTGLASS /obj/structure/airlock_assembly/multi_tile icon = 'icons/obj/structures/doors/airlock_assembly2x1.dmi' - icon_state = "door_as_g0" - dir = EAST - var/width = 1 - -/*Temporary until we get sprites. - airlock_type = "/multi_tile/maint" - glass = 1*/ - base_icon_state = "g" //Remember to delete this line when reverting "glass" var to 1. - airlock_type = "/multi_tile/glass" - glass = AIRLOCK_CANTGLASS //To prevent bugs in deconstruction process. + icon_state = "door_as_0" + width = 2 /obj/structure/airlock_assembly/multi_tile/Initialize(mapload, ...) . = ..() - if(dir in list(EAST, WEST)) - bound_width = width * world.icon_size - bound_height = world.icon_size - else - bound_width = world.icon_size - bound_height = width * world.icon_size + update_collision_box() update_icon() /obj/structure/airlock_assembly/multi_tile/Move() . = ..() + update_collision_box() + +/obj/structure/airlock_assembly/multi_tile/update_collision_box() if(dir in list(EAST, WEST)) bound_width = width * world.icon_size bound_height = world.icon_size diff --git a/code/game/objects/structures/barricade/barricade.dm b/code/game/objects/structures/barricade/barricade.dm index 0ca2ccb1ddbc..5a72ec33ea2a 100644 --- a/code/game/objects/structures/barricade/barricade.dm +++ b/code/game/objects/structures/barricade/barricade.dm @@ -78,7 +78,7 @@ switch(dir) if(SOUTH) layer = ABOVE_MOB_LAYER - else if(NORTH) + if(NORTH) layer = initial(layer) - 0.01 else layer = initial(layer) diff --git a/code/game/objects/structures/barricade/handrail.dm b/code/game/objects/structures/barricade/handrail.dm index ea10dc7256de..ae166dbbf985 100644 --- a/code/game/objects/structures/barricade/handrail.dm +++ b/code/game/objects/structures/barricade/handrail.dm @@ -24,7 +24,7 @@ switch(dir) if(SOUTH) layer = ABOVE_MOB_LAYER - else if(NORTH) + if(NORTH) layer = initial(layer) - 0.01 else layer = initial(layer) diff --git a/code/game/objects/structures/blocker.dm b/code/game/objects/structures/blocker.dm index 284daf0028aa..f85b1e65fff5 100644 --- a/code/game/objects/structures/blocker.dm +++ b/code/game/objects/structures/blocker.dm @@ -105,9 +105,21 @@ /obj/structure/blocker/forcefield/vehicles types = list(/obj/vehicle/) + +/obj/structure/blocker/forcefield/vehicles/handle_vehicle_bump(obj/vehicle/multitile/multitile_vehicle) + if(multitile_vehicle.vehicle_flags & VEHICLE_BYPASS_BLOCKERS) + return TRUE + return FALSE + /obj/structure/blocker/forcefield/multitile_vehicles types = list(/obj/vehicle/multitile/) + +/obj/structure/blocker/forcefield/multitile_vehicles/handle_vehicle_bump(obj/vehicle/multitile/multitile_vehicle) + if(multitile_vehicle.vehicle_flags & VEHICLE_BYPASS_BLOCKERS) + return TRUE + return FALSE + /obj/structure/blocker/forcefield/human types = list(/mob/living/carbon/human) icon_state = "purple_line" diff --git a/code/game/objects/structures/bookcase.dm b/code/game/objects/structures/bookcase.dm index c71b2853ea07..becb0906e3c6 100644 --- a/code/game/objects/structures/bookcase.dm +++ b/code/game/objects/structures/bookcase.dm @@ -58,8 +58,6 @@ contents_explosion(severity) deconstruct(FALSE) return - else - return /obj/structure/bookcase/update_icon() if(contents.len < 5) diff --git a/code/game/objects/structures/crates_lockers/closets/secure/cm_closets.dm b/code/game/objects/structures/crates_lockers/closets/secure/cm_closets.dm index 0ff7c4317193..1edac3a8f324 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/cm_closets.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/cm_closets.dm @@ -32,6 +32,8 @@ GLOBAL_LIST_EMPTY(co_secure_boxes) /obj/structure/closet/secure_closet/securecom/Initialize() . = ..() + new /obj/item/storage/box/kit/honorguard(src) + new /obj/item/storage/box/kit/honorguard(src) GLOB.co_secure_boxes += src /obj/structure/closet/secure_closet/securecom/Destroy() @@ -62,8 +64,6 @@ GLOBAL_LIST_EMPTY(co_secure_boxes) new /obj/item/storage/belt/marine(src) new /obj/item/clothing/under/marine/officer/boiler(src) new /obj/item/clothing/under/marine/officer/boiler(src) - new /obj/item/clothing/suit/storage/webbing(src) - new /obj/item/clothing/suit/storage/webbing(src) new /obj/item/clothing/gloves/combat(src) new /obj/item/clothing/gloves/combat(src) diff --git a/code/game/objects/structures/crates_lockers/closets/secure/guncabinet.dm b/code/game/objects/structures/crates_lockers/closets/secure/guncabinet/guncabinet.dm similarity index 85% rename from code/game/objects/structures/crates_lockers/closets/secure/guncabinet.dm rename to code/game/objects/structures/crates_lockers/closets/secure/guncabinet/guncabinet.dm index db20a738c8ed..4531a68c42dd 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/guncabinet.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/guncabinet/guncabinet.dm @@ -65,21 +65,7 @@ contents_explosion(severity - EXPLOSION_THRESHOLD_LOW) deconstruct(FALSE) -/obj/structure/closet/secure_closet/guncabinet/mp_armory -// req_access = list(ACCESS_MARINE_BRIG) - req_level = SEC_LEVEL_RED - -/obj/structure/closet/secure_closet/guncabinet/mp_armory/Initialize() - . = ..() - new /obj/item/weapon/gun/shotgun/combat(src) - new /obj/item/weapon/gun/shotgun/combat(src) - new /obj/item/ammo_magazine/shotgun/slugs(src) - new /obj/item/ammo_magazine/shotgun/buckshot(src) - new /obj/item/ammo_magazine/shotgun/buckshot(src) - new /obj/item/ammo_magazine/shotgun/buckshot(src) - - - +//this is used on corsat.(leaving it as a prop i guess) /obj/structure/closet/secure_closet/guncabinet/riot_control name = "riot control equipment closet" // req_access = list(ACCESS_MARINE_BRIG) @@ -111,15 +97,10 @@ new /obj/item/clothing/suit/armor/riot/marine(src) new /obj/item/storage/box/flashbangs(src) - /obj/structure/closet/secure_closet/guncabinet/green name = "green level gun cabinet" req_level = SEC_LEVEL_GREEN -/obj/structure/closet/secure_closet/guncabinet/blue - name = "blue level gun cabinet" - req_level = SEC_LEVEL_BLUE - /obj/structure/closet/secure_closet/guncabinet/red name = "red level gun cabinet" req_level = SEC_LEVEL_RED diff --git a/code/game/objects/structures/crates_lockers/closets/secure/guncabinet/level_blue.dm b/code/game/objects/structures/crates_lockers/closets/secure/guncabinet/level_blue.dm new file mode 100644 index 000000000000..acc43c302e6d --- /dev/null +++ b/code/game/objects/structures/crates_lockers/closets/secure/guncabinet/level_blue.dm @@ -0,0 +1,37 @@ +/obj/structure/closet/secure_closet/guncabinet/blue + name = "blue level gun cabinet" + req_level = SEC_LEVEL_BLUE + +//riot gear control cabinet adding vehicle clamp to it to... +// make more sense than in red alert cabinet. + +/obj/structure/closet/secure_closet/guncabinet/blue/riot_control + name = "riot control equipment closet" + storage_capacity = 55 //lots of stuff to fit in + req_level = SEC_LEVEL_BLUE + +/obj/structure/closet/secure_closet/guncabinet/blue/riot_control/Initialize() + . = ..() + new /obj/item/weapon/gun/shotgun/combat/riot(src, TRUE) + new /obj/item/weapon/gun/shotgun/combat/riot(src, TRUE) + new /obj/item/weapon/gun/shotgun/combat/riot(src, TRUE) + new /obj/item/weapon/shield/riot(src) + new /obj/item/weapon/shield/riot(src) + new /obj/item/weapon/shield/riot(src) + new /obj/item/ammo_magazine/shotgun/beanbag/riot(src) + new /obj/item/ammo_magazine/shotgun/beanbag/riot(src) + new /obj/item/ammo_magazine/shotgun/beanbag/riot(src) + new /obj/item/ammo_magazine/shotgun/beanbag/riot(src) + new /obj/item/weapon/gun/launcher/grenade/m81/riot(src, TRUE) + new /obj/item/storage/box/nade_box/tear_gas(src) + new /obj/item/clothing/mask/gas(src) + new /obj/item/clothing/mask/gas(src) + new /obj/item/clothing/mask/gas(src) + new /obj/item/clothing/head/helmet/riot(src) + new /obj/item/clothing/head/helmet/riot(src) + new /obj/item/clothing/head/helmet/riot(src) + new /obj/item/clothing/suit/armor/riot/marine(src) + new /obj/item/clothing/suit/armor/riot/marine(src) + new /obj/item/clothing/suit/armor/riot/marine(src) + new /obj/item/storage/box/flashbangs(src) + new /obj/item/vehicle_clamp(src) diff --git a/code/game/objects/structures/crates_lockers/closets/secure/guncabinet/level_red.dm b/code/game/objects/structures/crates_lockers/closets/secure/guncabinet/level_red.dm new file mode 100644 index 000000000000..487ffd546d8e --- /dev/null +++ b/code/game/objects/structures/crates_lockers/closets/secure/guncabinet/level_red.dm @@ -0,0 +1,112 @@ +/obj/structure/closet/secure_closet/guncabinet/red + name = "red level gun cabinet" + req_level = SEC_LEVEL_RED + +// MP ARMORY + +// 3 shotgun cabinet are in brig armory +/obj/structure/closet/secure_closet/guncabinet/red/mp_armory_shotgun + +/obj/structure/closet/secure_closet/guncabinet/red/mp_armory_shotgun/Initialize() + . = ..() + new /obj/item/weapon/gun/shotgun/combat(src) + new /obj/item/weapon/gun/shotgun/combat(src) + new /obj/item/weapon/gun/shotgun/combat(src) + new /obj/item/ammo_box/magazine/shotgun/buckshot(src) + new /obj/item/ammo_box/magazine/shotgun(src) + +// 2 M39 cabinet are in brig armory (4 M39 and 12 mags) +/obj/structure/closet/secure_closet/guncabinet/red/mp_armory_m39_submachinegun + +/obj/structure/closet/secure_closet/guncabinet/red/mp_armory_m39_submachinegun/Initialize() + . = ..() + new /obj/item/weapon/gun/smg/m39(src) + new /obj/item/weapon/gun/smg/m39(src) + new /obj/item/weapon/gun/smg/m39(src) + new /obj/item/weapon/gun/smg/m39(src) + new /obj/item/ammo_box/magazine/m39(src) + +// 2 m4ra cabinet are in brig armory (m4ra guns and 12 mags) +/obj/structure/closet/secure_closet/guncabinet/red/mp_armory_m4ra_rifle + +/obj/structure/closet/secure_closet/guncabinet/red/mp_armory_m4ra_rifle/Initialize() + . = ..() + new /obj/item/weapon/gun/rifle/m4ra(src) + new /obj/item/weapon/gun/rifle/m4ra(src) + new /obj/item/weapon/gun/rifle/m4ra(src) + new /obj/item/weapon/gun/rifle/m4ra(src) + new /obj/item/ammo_box/magazine/m4ra(src) + +// EXECUTION CHAMBER might add that here need to ask first... will reskin if asked. + + + +// CIC ARMORY + +// 4 shotgun cabinet are in cic armory +/obj/structure/closet/secure_closet/guncabinet/red/cic_armory_shotgun + +/obj/structure/closet/secure_closet/guncabinet/red/cic_armory_shotgun/Initialize() + . = ..() + new /obj/item/weapon/gun/shotgun/combat(src) + new /obj/item/ammo_magazine/shotgun/slugs(src) + new /obj/item/ammo_magazine/shotgun/buckshot(src) + +//4 MK1 cabinet(using guncase because it fit well here it seem) +/obj/structure/closet/secure_closet/guncabinet/red/cic_armory_mk1_rifle + +/obj/structure/closet/secure_closet/guncabinet/red/cic_armory_mk1_rifle/Initialize() + . = ..() + new /obj/item/storage/box/guncase/m41aMK1(src) + +//4 MK1 (with AP) cabinet(using guncase because it fit well here it seem) +/obj/structure/closet/secure_closet/guncabinet/red/cic_armory_mk1_rifle_ap + +/obj/structure/closet/secure_closet/guncabinet/red/cic_armory_mk1_rifle_ap/Initialize() + . = ..() + new /obj/item/storage/box/guncase/m41aMK1AP(src) + +// UPPER MEDBAY ARMORY + +//1 shotgun armory closet 2 guns and 4 mags +/obj/structure/closet/secure_closet/guncabinet/red/armory_shotgun + +/obj/structure/closet/secure_closet/guncabinet/red/armory_shotgun/Initialize() + . = ..() + new /obj/item/weapon/gun/shotgun/combat(src) + new /obj/item/weapon/gun/shotgun/combat(src) + new /obj/item/ammo_magazine/shotgun/slugs(src) + new /obj/item/ammo_magazine/shotgun/slugs(src) + new /obj/item/ammo_magazine/shotgun/buckshot(src) + new /obj/item/ammo_magazine/shotgun/buckshot(src) + +// 2 pistol amory closet maybe to replace with full pistol belt... +/obj/structure/closet/secure_closet/guncabinet/red/armory_m4a3_pistol + +/obj/structure/closet/secure_closet/guncabinet/red/armory_m4a3_pistol/Initialize() + . = ..() + new /obj/item/storage/belt/gun/m4a3/full(src) + new /obj/item/storage/belt/gun/m4a3/full(src) + new /obj/item/storage/belt/gun/m4a3/full(src) + new /obj/item/storage/belt/gun/m4a3/full(src) + new /obj/item/ammo_box/magazine/m4a3(src) + +// 2 M39 cabinet are in medical armory (4 M39 and 12 mags) +/obj/structure/closet/secure_closet/guncabinet/red/armory_m39_submachinegun + +/obj/structure/closet/secure_closet/guncabinet/red/armory_m39_submachinegun/Initialize() + . = ..() + new /obj/item/weapon/gun/smg/m39(src) + new /obj/item/weapon/gun/smg/m39(src) + new /obj/item/weapon/gun/smg/m39(src) + new /obj/item/weapon/gun/smg/m39(src) + new /obj/item/ammo_box/magazine/m39(src) + +// UPPER ENGI ARMORY +// same as medical + +// REQ ARMORY +// same as medical + +// Small office in hangar armory same as brig armory.... +// same as brig armory diff --git a/code/game/objects/structures/crates_lockers/closets/secure/secure_closets.dm b/code/game/objects/structures/crates_lockers/closets/secure/secure_closets.dm index e290a23a61e9..331cb884bd59 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/secure_closets.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/secure_closets.dm @@ -30,6 +30,7 @@ return 0 /obj/structure/closet/secure_closet/emp_act(severity) + . = ..() for(var/obj/O in src) O.emp_act(severity) if(!broken) @@ -42,7 +43,6 @@ else src.req_access = list() src.req_access += pick(get_access(ACCESS_LIST_MARINE_MAIN)) - ..() /obj/structure/closet/secure_closet/proc/togglelock(mob/living/user) if(src.opened) diff --git a/code/game/objects/structures/crates_lockers/closets/utility_closets.dm b/code/game/objects/structures/crates_lockers/closets/utility_closets.dm index 7848aaba4897..b000fd5733a2 100644 --- a/code/game/objects/structures/crates_lockers/closets/utility_closets.dm +++ b/code/game/objects/structures/crates_lockers/closets/utility_closets.dm @@ -51,8 +51,6 @@ new /obj/item/clothing/mask/gas(src) new /obj/item/clothing/mask/gas(src) new /obj/item/storage/firstaid/o2(src) - if ("nothing") - // doot // teehee - Ah, tg coders... if ("delete") diff --git a/code/game/objects/structures/crates_lockers/crates.dm b/code/game/objects/structures/crates_lockers/crates.dm index 7c9faaf1a027..119615ab7aed 100644 --- a/code/game/objects/structures/crates_lockers/crates.dm +++ b/code/game/objects/structures/crates_lockers/crates.dm @@ -12,6 +12,19 @@ throwpass = 1 //prevents moving crates by hurling things at them store_mobs = FALSE var/rigged = 0 + /// Types this crate can be made into + var/list/crate_customizing_types = list( + "Plain" = /obj/structure/closet/crate, + "Weapons" = /obj/structure/closet/crate/weapon, + "Supply" = /obj/structure/closet/crate/supply, + "Ammo" = /obj/structure/closet/crate/ammo, + "Construction" = /obj/structure/closet/crate/construction, + "Explosives" = /obj/structure/closet/crate/explosives, + "Alpha" = /obj/structure/closet/crate/alpha, + "Bravo" = /obj/structure/closet/crate/bravo, + "Charlie" = /obj/structure/closet/crate/charlie, + "Delta" = /obj/structure/closet/crate/delta, + ) /obj/structure/closet/crate/initialize_pass_flags(datum/pass_flags_container/PF) ..() @@ -130,8 +143,6 @@ contents_explosion(severity) deconstruct(FALSE) return - else - return /obj/structure/closet/crate/alpha name = "alpha squad crate" @@ -209,6 +220,7 @@ icon_state = "closed_freezer" icon_opened = "open_freezer" icon_closed = "closed_freezer" + crate_customizing_types = null var/target_temp = T0C - 40 var/cooling_power = 40 diff --git a/code/game/objects/structures/crates_lockers/secure_crates.dm b/code/game/objects/structures/crates_lockers/secure_crates.dm index a308c4c0a21c..28a77e0c81c0 100644 --- a/code/game/objects/structures/crates_lockers/secure_crates.dm +++ b/code/game/objects/structures/crates_lockers/secure_crates.dm @@ -4,6 +4,7 @@ icon_state = "secure_locked_basic" icon_opened = "secure_open_basic" icon_closed = "secure_locked_basic" + crate_customizing_types = null var/icon_locked = "secure_locked_basic" var/icon_unlocked = "secure_unlocked_basic" var/sparks = "securecratesparks" @@ -86,6 +87,7 @@ ..() /obj/structure/closet/crate/secure/emp_act(severity) + . = ..() for(var/obj/O in src) O.emp_act(severity) if(!broken && !opened && prob(50/severity)) @@ -105,7 +107,6 @@ else src.req_access = list() src.req_access += pick(get_access(ACCESS_LIST_MARINE_MAIN)) - ..() //------------------------------------ diff --git a/code/game/objects/structures/flora.dm b/code/game/objects/structures/flora.dm index 9c1f46de50d5..b1e950dd18f0 100644 --- a/code/game/objects/structures/flora.dm +++ b/code/game/objects/structures/flora.dm @@ -72,6 +72,7 @@ PLANT_CUT_MACHETE = 3 = Needs at least a machete to be cut down addtimer(CALLBACK(src, PROC_REF(burn_up)), spread_time + 5 SECONDS) /obj/structure/flora/proc/spread_fire() + SIGNAL_HANDLER for(var/D in cardinal) //Spread fire var/turf/T = get_step(src.loc, D) if(T) @@ -82,6 +83,7 @@ PLANT_CUT_MACHETE = 3 = Needs at least a machete to be cut down new /obj/flamer_fire(T, create_cause_data("wildfire")) /obj/structure/flora/proc/burn_up() + SIGNAL_HANDLER new /obj/effect/decal/cleanable/dirt(loc) if(center) new /obj/effect/decal/cleanable/dirt(loc) //Produces more ash at the center @@ -717,7 +719,7 @@ ICEY GRASS. IT LOOKS LIKE IT'S MADE OF ICE. //hatchets and shiet can clear away undergrowth if(I && (I.sharp >= IS_SHARP_ITEM_ACCURATE) && !stump) var/damage = rand(2,5) - if(istype(I,/obj/item/weapon/claymore/mercsword)) + if(istype(I,/obj/item/weapon/sword)) damage = rand(8,18) if(indestructable) //this bush marks the edge of the map, you can't destroy it diff --git a/code/game/objects/structures/girders.dm b/code/game/objects/structures/girders.dm index e719359ab439..6cd6a5cd0300 100644 --- a/code/game/objects/structures/girders.dm +++ b/code/game/objects/structures/girders.dm @@ -173,6 +173,14 @@ return do_reinforced_wall(W, user) if(STATE_DISPLACED) if(HAS_TRAIT(W, TRAIT_TOOL_CROWBAR)) + var/turf/open/floor = loc + if(!floor.allow_construction) + to_chat(user, SPAN_WARNING("The girder must be secured on a proper surface!")) + return + var/obj/structure/tunnel/tunnel = locate(/obj/structure/tunnel) in loc + if(tunnel) + to_chat(user, SPAN_WARNING("The girder cannot be secured on a tunnel!")) + return playsound(loc, 'sound/items/Crowbar.ogg', 25, 1) to_chat(user, SPAN_NOTICE("Now securing the girder...")) if(!do_after(user, 40 * user.get_skill_duration_multiplier(SKILL_CONSTRUCTION), INTERRUPT_ALL|BEHAVIOR_IMMOBILE, BUSY_ICON_BUILD)) diff --git a/code/game/objects/structures/lattice.dm b/code/game/objects/structures/lattice.dm index 38201e052c50..d2b3d36b5920 100644 --- a/code/game/objects/structures/lattice.dm +++ b/code/game/objects/structures/lattice.dm @@ -43,8 +43,6 @@ if(EXPLOSION_THRESHOLD_MEDIUM to INFINITY) deconstruct(FALSE) return - else - return /obj/structure/lattice/attackby(obj/item/C as obj, mob/user as mob) diff --git a/code/game/objects/structures/misc.dm b/code/game/objects/structures/misc.dm index d290925d4cdf..89bc3da6ab23 100644 --- a/code/game/objects/structures/misc.dm +++ b/code/game/objects/structures/misc.dm @@ -189,3 +189,126 @@ /obj/structure/computer3frame/laptop name = "laptop frame" + +// Dartboard +#define DOUBLE_BAND 2 +#define TRIPLE_BAND 3 + +/obj/structure/dartboard + name = "dartboard" + desc = "A dartboard, loosely secured." + icon = 'icons/obj/structures/props/props.dmi' + icon_state = "dart_board" + density = TRUE + unslashable = TRUE + +/obj/structure/dartboard/get_examine_text() + . = ..() + if(length(contents)) + var/is_are = "is" + if(length(contents) != 1) + is_are = "are" + + . += SPAN_NOTICE("There [is_are] [length(contents)] item\s embedded into [src].") + +/obj/structure/dartboard/initialize_pass_flags(datum/pass_flags_container/pass_flags) + ..() + if(pass_flags) + pass_flags.flags_can_pass_all = PASS_MOB_IS + +/obj/structure/dartboard/get_projectile_hit_boolean(obj/projectile/projectile) + . = ..() + visible_message(SPAN_DANGER("[projectile] hits [src], collapsing it!")) + collapse() + +/obj/structure/dartboard/proc/flush_contents() + for(var/atom/movable/embedded_items as anything in contents) + embedded_items.forceMove(loc) + +/obj/structure/dartboard/proc/collapse() + playsound(src, 'sound/effects/thud1.ogg', 50) + new /obj/item/dartboard/(loc) + qdel(src) + +/obj/structure/dartboard/attack_hand(mob/user) + if(length(contents)) + user.visible_message(SPAN_NOTICE("[user] starts recovering items from [src]..."), SPAN_NOTICE("You start recovering items from [src]...")) + if(do_after(user, 1 SECONDS, INTERRUPT_ALL, BUSY_ICON_FRIENDLY, user, INTERRUPT_MOVED, BUSY_ICON_GENERIC)) + flush_contents() + else + to_chat(user, SPAN_WARNING("[src] has nothing embedded!")) + +/obj/structure/dartboard/Destroy() + flush_contents() + . = ..() + +/obj/structure/dartboard/hitby(obj/item/thrown_item) + if(thrown_item.sharp != IS_SHARP_ITEM_ACCURATE && !istype(thrown_item, /obj/item/weapon/dart)) + visible_message(SPAN_DANGER("[thrown_item] hits [src], collapsing it!")) + collapse() + return + + contents += thrown_item + playsound(src, 'sound/weapons/tablehit1.ogg', 50) + var/score = rand(1,21) + if(score == 21) + visible_message(SPAN_DANGER("[thrown_item] embeds into [src], striking the bullseye! 50 points.")) + return + + var/band = "single" + var/band_number = rand(1,3) + score *= band_number + switch(band_number) + if(DOUBLE_BAND) + band = "double" + if(TRIPLE_BAND) + band = "triple" + visible_message(SPAN_DANGER("[thrown_item] embeds into [src], striking [band] for [score] point\s.")) + +/obj/structure/dartboard/attackby(obj/item/item, mob/user) + user.visible_message(SPAN_DANGER("[user] hits [src] with [item], collapsing it!"), SPAN_DANGER("You collapse [src] with [item]!")) + collapse() + +/obj/structure/dartboard/MouseDrop(over_object, src_location, over_location) + . = ..() + if(over_object != usr || !Adjacent(usr)) + return + + if(!ishuman(usr)) + return + + visible_message(SPAN_NOTICE("[usr] unsecures [src].")) + var/obj/item/dartboard/unsecured_board = new(loc) + usr.put_in_hands(unsecured_board) + qdel(src) + +/obj/item/dartboard + name = "dartboard" + desc = "A dartboard for darts." + icon = 'icons/obj/structures/props/props.dmi' + icon_state = "dart_board" + +/obj/item/dartboard/attack_self(mob/user) + . = ..() + + var/turf_ahead = get_step(user, user.dir) + if(!istype(turf_ahead, /turf/closed)) + to_chat(user, SPAN_WARNING("[src] needs a wall to be secured to!")) + return + + var/obj/structure/dartboard/secured_board = new(user.loc) + switch(user.dir) + if(NORTH) + secured_board.pixel_y = 32 + if(EAST) + secured_board.pixel_x = 32 + if(SOUTH) + secured_board.pixel_y = -32 + if(WEST) + secured_board.pixel_x = -32 + + to_chat(user, SPAN_NOTICE("You secure [secured_board] to [turf_ahead].")) + qdel(src) + +#undef DOUBLE_BAND +#undef TRIPLE_BAND diff --git a/code/game/objects/structures/morgue.dm b/code/game/objects/structures/morgue.dm index dc8cf08d13f1..b3fb2423008a 100644 --- a/code/game/objects/structures/morgue.dm +++ b/code/game/objects/structures/morgue.dm @@ -113,7 +113,7 @@ else . = ..() -/obj/structure/morgue/relaymove(mob/user) +/obj/structure/morgue/relaymove(mob/living/user) if(user.is_mob_incapacitated()) return if(exit_stun) diff --git a/code/game/objects/structures/props.dm b/code/game/objects/structures/props.dm index 3e3150040cb6..bd5610487ea0 100644 --- a/code/game/objects/structures/props.dm +++ b/code/game/objects/structures/props.dm @@ -810,8 +810,10 @@ var/obj/item/stack/sheet/wood/fuel = attacking_item if(remaining_fuel >= initial(remaining_fuel)) to_chat(user, SPAN_NOTICE("You cannot fuel [src] further.")) + return if(!fuel.use(1)) to_chat(SPAN_NOTICE("You do not have enough [attacking_item] to fuel [src].")) + return visible_message(SPAN_NOTICE("[user] fuels [src] with [fuel].")) remaining_fuel++ @@ -1306,19 +1308,19 @@ COOLDOWN_DECLARE(damage_delay) /// list of quip emotes, taken from Working Joe var/static/list/quips = list( - /datum/emote/living/carbon/human/synthetic/working_joe/quip/alwaysknow_damaged, + /datum/emote/living/carbon/human/synthetic/working_joe/damage/alwaysknow_damaged, /datum/emote/living/carbon/human/synthetic/working_joe/quip/not_liking, /datum/emote/living/carbon/human/synthetic/working_joe/greeting/how_can_i_help, - /datum/emote/living/carbon/human/synthetic/working_joe/task_update/day_never_done, - /datum/emote/living/carbon/human/synthetic/working_joe/task_update/required_by_apollo, + /datum/emote/living/carbon/human/synthetic/working_joe/farewell/day_never_done, + /datum/emote/living/carbon/human/synthetic/working_joe/farewell/required_by_apollo, /datum/emote/living/carbon/human/synthetic/working_joe/warning/safety_breach ) /// list of voicelines to use when damaged var/static/list/damaged = list( - /datum/emote/living/carbon/human/synthetic/working_joe/warning/damage, - /datum/emote/living/carbon/human/synthetic/working_joe/warning/that_stings, - /datum/emote/living/carbon/human/synthetic/working_joe/warning/irresponsible, - /datum/emote/living/carbon/human/synthetic/working_joe/warning/this_is_futile, + /datum/emote/living/carbon/human/synthetic/working_joe/damage/damage, + /datum/emote/living/carbon/human/synthetic/working_joe/damage/that_stings, + /datum/emote/living/carbon/human/synthetic/working_joe/damage/irresponsible, + /datum/emote/living/carbon/human/synthetic/working_joe/damage/this_is_futile, /datum/emote/living/carbon/human/synthetic/working_joe/warning/hysterical, /datum/emote/living/carbon/human/synthetic/working_joe/warning/patience ) diff --git a/code/game/objects/structures/reagent_dispensers.dm b/code/game/objects/structures/reagent_dispensers.dm index 7dc6d883a2d5..6471dfa21520 100644 --- a/code/game/objects/structures/reagent_dispensers.dm +++ b/code/game/objects/structures/reagent_dispensers.dm @@ -119,8 +119,6 @@ if(EXPLOSION_THRESHOLD_MEDIUM to INFINITY) deconstruct(FALSE) return - else - return /obj/structure/reagent_dispensers/attack_hand() if(!reagents || reagents.locked) diff --git a/code/game/objects/structures/safe.dm b/code/game/objects/structures/safe.dm index 87e713ad0af8..011fa2a17f48 100644 --- a/code/game/objects/structures/safe.dm +++ b/code/game/objects/structures/safe.dm @@ -222,3 +222,28 @@ FLOOR SAFES /obj/structure/safe/floor/hide(intact) invisibility = intact ? 101 : 0 + +//almayer + +/obj/structure/safe/co_office + +/obj/structure/safe/co_office/Initialize() + . = ..() + new /obj/item/clothing/glasses/monocle(src) + new /obj/item/book/codebook(src) + new /obj/item/coin/silver/falcon(src) + new /obj/item/weapon/telebaton(src) + new /obj/item/moneybag(src) + +/obj/structure/safe/cl_office + +/obj/structure/safe/cl_office/Initialize() + . = ..() + new /obj/item/clothing/suit/armor/bulletproof(src) + new /obj/item/weapon/gun/pistol/es4(src) + new /obj/item/ammo_magazine/pistol/es4(src) + new /obj/item/ammo_magazine/pistol/es4(src) + new /obj/item/clothing/accessory/storage/holster(src) + new /obj/item/spacecash/c1000/counterfeit(src) + new /obj/item/spacecash/c1000/counterfeit(src) + new /obj/item/coin/platinum(src) diff --git a/code/game/objects/structures/signs.dm b/code/game/objects/structures/signs.dm index fbd6920875ad..adabf0c54141 100644 --- a/code/game/objects/structures/signs.dm +++ b/code/game/objects/structures/signs.dm @@ -17,6 +17,7 @@ S.desc = desc S.icon_state = icon_state S.sign_state = icon_state + S.icon = icon deconstruct(FALSE) else ..() @@ -45,6 +46,7 @@ S.name = name S.desc = desc S.icon_state = sign_state + S.icon = icon to_chat(user, "You fasten \the [S] with your [tool].") qdel(src) else ..() @@ -568,7 +570,7 @@ /obj/structure/sign/ROsign name = "\improper USCM Requisitions Office Guidelines" - desc = " 1. You are not entitled to service or equipment. Attachments are a privilege, not a right.\n 2. You must be fully dressed to obtain service. Cyrosleep underwear is non-permissible.\n 3. The Requsitions Officer has the final say and the right to decline service. Only the Acting Commanding Officer may override their decisions.\n 4. Please treat your Requsitions staff with respect. They work hard." + desc = " 1. You are not entitled to service or equipment. Attachments are a privilege, not a right.\n 2. You must be fully dressed to obtain service. Cryosleep underwear is non-permissible.\n 3. The Quartermaster has the final say and the right to decline service. Only the Acting Commanding Officer may override their decisions.\n 4. Please treat your Requsitions staff with respect. They work hard." icon_state = "roplaque" /obj/structure/sign/prop1 @@ -592,9 +594,3 @@ desc = "An unbelievably creepy cat clock that surveys the room with every tick and every tock." icon = 'icons/obj/structures/props/catclock.dmi' icon_state = "cat_clock_motion" - -/obj/structure/sign/dartboard - name = "dartboard" - desc = "A dartboard, secured with a nail and a string. It has bullet holes and knife stab marks over and around it." - icon = 'icons/obj/structures/props/props.dmi' - icon_state = "dart_board" diff --git a/code/game/objects/structures/stool_bed_chair_nest/bed.dm b/code/game/objects/structures/stool_bed_chair_nest/bed.dm index 7979994915f4..bc3b4ad7f4d0 100644 --- a/code/game/objects/structures/stool_bed_chair_nest/bed.dm +++ b/code/game/objects/structures/stool_bed_chair_nest/bed.dm @@ -404,7 +404,17 @@ var/global/list/activated_medevac_stretchers = list() //bedroll /obj/structure/bed/bedroll - name = "bedroll" - desc = "bedroll" + name = "unfolded bedroll" + desc = "Perfect for those long missions, when there's nowhere else to sleep, you remembered to bring at least one thing of comfort." + icon = 'icons/monkey_icos.dmi' icon_state = "bedroll_o" + buckling_y = 0 + foldabletype = /obj/item/roller/bedroll + accepts_bodybag = FALSE + +/obj/item/roller/bedroll + name = "folded bedroll" + desc = "A standard issue USCMC bedroll, They've been in service for as long as you can remember. The tag on it states to unfold it before rest, but who needs rules anyway, right?" icon = 'icons/monkey_icos.dmi' + icon_state = "bedroll" + rollertype = /obj/structure/bed/bedroll diff --git a/code/game/objects/structures/stool_bed_chair_nest/xeno_nest.dm b/code/game/objects/structures/stool_bed_chair_nest/xeno_nest.dm index 7a4274c2c16e..6375fcd13823 100644 --- a/code/game/objects/structures/stool_bed_chair_nest/xeno_nest.dm +++ b/code/game/objects/structures/stool_bed_chair_nest/xeno_nest.dm @@ -53,7 +53,7 @@ current_mob.pixel_y = buckling_y["[dir]"] current_mob.pixel_x = buckling_x["[dir]"] current_mob.dir = turn(dir, 180) - current_mob.density = FALSE + ADD_TRAIT(current_mob, TRAIT_UNDENSE, XENO_NEST_TRAIT) pixel_y = buckling_y["[dir]"] pixel_x = buckling_x["[dir]"] if(dir == SOUTH) @@ -67,7 +67,7 @@ current_mob.pixel_y = initial(buckled_mob.pixel_y) current_mob.pixel_x = initial(buckled_mob.pixel_x) - current_mob.density = !(current_mob.lying || current_mob.stat == DEAD) + REMOVE_TRAIT(current_mob, TRAIT_UNDENSE, XENO_NEST_TRAIT) if(dir == SOUTH) current_mob.layer = initial(current_mob.layer) if(!ishuman(current_mob)) diff --git a/code/game/objects/structures/surface.dm b/code/game/objects/structures/surface.dm index 3a2dbd3e8d5c..13a81af2dc3d 100644 --- a/code/game/objects/structures/surface.dm +++ b/code/game/objects/structures/surface.dm @@ -1,160 +1,20 @@ //Surface structures are structures that can have items placed on them /obj/structure/surface health = 100 - var/list/update_types = list( - /obj/item/reagent_container/glass, - /obj/item/storage, - /obj/item/reagent_container/food/snacks - ) - //add items there that behave like structures for whatever dumb reason - var/list/blacklisted_item_types = list( - /obj/item/device/radio/intercom, - /obj/item/device/sentry_computer - ) -/obj/structure/surface/Initialize() - . = ..() - return INITIALIZE_HINT_LATELOAD - -/obj/structure/surface/LateInitialize() - attach_all() - update_icon() - -/obj/structure/surface/Destroy() - detach_all() - . = ..() - -/obj/structure/surface/ex_act(severity, direction, datum/cause_data/cause_data) - health -= severity - if(health <= 0) - var/location = get_turf(src) - handle_debris(severity, direction) - detach_all() - for(var/obj/item/O in loc) - O.explosion_throw(severity, direction) - qdel(src) - if(prob(66)) - create_shrapnel(location, rand(1,4), direction, , /datum/ammo/bullet/shrapnel/light, cause_data) - return TRUE - -/obj/structure/surface/proc/attach_all() - for(var/obj/item/O in loc) - if(in_blacklist(O)) - continue - attach_item(O, FALSE) - draw_item_overlays() - -/obj/structure/surface/proc/in_blacklist(obj/item/O) - for(var/allowed_type in blacklisted_item_types) - if(istype(O, allowed_type)) - return TRUE - return FALSE - -/obj/structure/surface/proc/attach_item(obj/item/O, update = TRUE) - if(!O) +/obj/structure/surface/attackby(obj/item/attacking_item, mob/user, click_data) + if(!user.drop_inv_item_to_loc(attacking_item, loc)) return - if(O.luminosity) //it can't make light as an overlay - return - O.forceMove(src) - RegisterSignal(O, COMSIG_ATOM_DECORATED, PROC_REF(decorate_update)) - if(update) - draw_item_overlays() - -/obj/structure/surface/proc/detach_item(obj/item/O) - O.pixel_x = initial(O.pixel_x) - O.pixel_y = initial(O.pixel_y) - UnregisterSignal(O, COMSIG_ATOM_DECORATED) - draw_item_overlays() - return - -/obj/structure/surface/proc/decorate_update(obj/item/O) - SIGNAL_HANDLER - draw_item_overlays() -/obj/structure/surface/proc/detach_all() - overlays.Cut() - for(var/obj/item/O in contents) - UnregisterSignal(O, COMSIG_ATOM_DECORATED) - O.forceMove(loc) + auto_align(attacking_item, click_data) + user.next_move = world.time + 2 + return TRUE -/obj/structure/surface/proc/get_item(list/click_data) - var/i = LAZYLEN(contents) - if(!click_data) - return - if(i < 1) - return FALSE - for(i, i >= 1, i--)//starting from the end because that's where the topmost is - var/obj/item/O = contents[i] - var/bounds_x = text2num(click_data["icon-x"])-1 - O.pixel_x - var/bounds_y = text2num(click_data["icon-y"])-1 - O.pixel_y - if(bounds_x < 0 || bounds_y < 0) - continue - var/icon/I = icon(O.icon, O.icon_state) - var/p = I.GetPixel(bounds_x, bounds_y) - if(p) - return O - return FALSE - -/obj/structure/surface/proc/draw_item_overlays() - overlays.Cut() - for(var/obj/item/O in contents) - var/image/I = image(O.icon) - I.appearance = O.appearance - I.appearance_flags |= RESET_COLOR - I.overlays = O.overlays - LAZYADD(overlays, I) - -/obj/structure/surface/clicked(mob/user, list/mods) - if(mods["shift"] && !mods["middle"]) - var/obj/item/O = get_item(mods) - if(!O) - return ..() - if(O.can_examine(user)) - O.examine(user) - return TRUE - ..() - -/obj/structure/surface/proc/try_to_open_container(mob/user, mods) - if(!Adjacent(user)) - return - - if(ishuman(user) || isrobot(user)) - var/obj/item/O = get_item(mods) - if(O && isstorage(O)) - var/obj/item/storage/S = O - S.open(usr) - return TRUE - -/obj/structure/surface/attack_hand(mob/user, click_data) - . = ..() - if(click_data && click_data["alt"]) - return - var/obj/item/O = get_item(click_data) - if(!O) - return - O.attack_hand(user) - if(!LAZYISIN(contents, O))//in case attack_hand did not pick up the item - detach_item(O) - -/obj/structure/surface/attackby(obj/item/W, mob/user, click_data) - var/obj/item/O = get_item(click_data) - if(!O || click_data["ctrl"])//holding the ctrl key will force it to place the object - // Placing stuff on tables - if(user.drop_inv_item_to_loc(W, loc)) - auto_align(W, click_data) - user.next_move = world.time + 2 - return TRUE - else if(!O.attackby(W, user)) - W.afterattack(O, user, TRUE) - for(var/type in update_types) - if(istype(O, type)) - draw_item_overlays() - -/obj/structure/surface/proc/auto_align(obj/item/W, click_data) - if(!W.center_of_mass) // Clothing, material stacks, generally items with large sprites where exact placement would be unhandy. - W.pixel_x = rand(-W.randpixel, W.randpixel) - W.pixel_y = rand(-W.randpixel, W.randpixel) - W.pixel_z = 0 +/obj/structure/surface/proc/auto_align(obj/item/new_item, click_data) + if(!new_item.center_of_mass) // Clothing, material stacks, generally items with large sprites where exact placement would be unhandy. + new_item.pixel_x = rand(-new_item.randpixel, new_item.randpixel) + new_item.pixel_y = rand(-new_item.randpixel, new_item.randpixel) + new_item.pixel_z = 0 return if(!click_data) @@ -170,16 +30,8 @@ var/cell_x = Clamp(round(mouse_x/CELLSIZE), 0, CELLS-1) // Ranging from 0 to CELLS-1 var/cell_y = Clamp(round(mouse_y/CELLSIZE), 0, CELLS-1) - var/list/center = cached_key_number_decode(W.center_of_mass) - - W.pixel_x = (CELLSIZE * (cell_x + 0.5)) - center["x"] - W.pixel_y = (CELLSIZE * (cell_y + 0.5)) - center["y"] - W.pixel_z = 0 - - if(!(W.flags_item & NOTABLEMERGE)) - attach_item(W) + var/list/center = cached_key_number_decode(new_item.center_of_mass) -/obj/structure/surface/MouseDrop(atom/over) - . = ..() - if(over == usr && usr && usr.client && usr.client.lmb_last_mousedown_mods) - return try_to_open_container(usr, usr.client.lmb_last_mousedown_mods) + new_item.pixel_x = (CELLSIZE * (cell_x + 0.5)) - center["x"] + new_item.pixel_y = (CELLSIZE * (cell_y + 0.5)) - center["y"] + new_item.pixel_z = 0 diff --git a/code/game/objects/structures/tables_racks.dm b/code/game/objects/structures/tables_racks.dm index db3ce98339a3..8d6441293f86 100644 --- a/code/game/objects/structures/tables_racks.dm +++ b/code/game/objects/structures/tables_racks.dm @@ -434,8 +434,6 @@ verbs -= /obj/structure/surface/table/verb/do_flip verbs += /obj/structure/surface/table/proc/do_put - detach_all() - var/list/targets = list(get_step(src, dir), get_step(src, turn(dir, 45)), get_step(src, turn(dir, -45))) for(var/atom/movable/movable_on_table in get_turf(src)) if(!movable_on_table.anchored) @@ -479,7 +477,6 @@ var/obj/structure/surface/table/T = locate() in get_step(src.loc,D) if(T && T.flipped && T.dir == src.dir) T.unflip() - attach_all() update_icon() update_adjacent() diff --git a/code/game/objects/structures/vulture_spotter.dm b/code/game/objects/structures/vulture_spotter.dm index 50505ab239b8..44efd5ce84ea 100644 --- a/code/game/objects/structures/vulture_spotter.dm +++ b/code/game/objects/structures/vulture_spotter.dm @@ -92,7 +92,7 @@ user.lighting_alpha = 127 user.sync_lighting_plane_alpha() user.overlay_fullscreen("vulture_spotter", /atom/movable/screen/fullscreen/vulture/spotter) - user.freeze() + ADD_TRAIT(user, TRAIT_IMMOBILIZED, TRAIT_SOURCE_ABILITY("Vulture spotter")) user.status_flags |= IMMOBILE_ACTION user.visible_message(SPAN_NOTICE("[user] looks through [src]."),SPAN_NOTICE("You look through [src], ready to go!")) user.forceMove(loc) @@ -105,7 +105,7 @@ /obj/structure/vulture_spotter_tripod/on_unset_interaction(mob/user) user.status_flags &= ~IMMOBILE_ACTION user.visible_message(SPAN_NOTICE("[user] looks up from [src]."),SPAN_NOTICE("You look up from [src].")) - user.unfreeze() + REMOVE_TRAIT(user, TRAIT_IMMOBILIZED, TRAIT_SOURCE_ABILITY("Vulture spotter")) user.reset_view(null) user.Move(get_step(src, reverse_direction(src.dir))) user.client?.change_view(world_view_size, src) diff --git a/code/game/runtimes.dm b/code/game/runtimes.dm index 1332309168a3..2cdc955aa426 100644 --- a/code/game/runtimes.dm +++ b/code/game/runtimes.dm @@ -11,7 +11,6 @@ GLOBAL_REAL(stui_init_runtimes, /list) //! Shorthand of Static Initializer errors only, for use in STUI GLOBAL_REAL(full_init_runtimes, /list) //! Full text of all Static Initializer + World Init errors, for log backfilling GLOBAL_REAL_VAR(runtime_logging_ready) //! Truthy when init is done and we don't need these shenanigans anymore -GLOBAL_REAL_VAR(init_runtimes_count) //! Count of runtimes that occured before logging is ready, for in-game reporting // Deduplication of errors via hash to reduce spamming GLOBAL_REAL(runtime_hashes, /list) @@ -24,8 +23,6 @@ GLOBAL_REAL_VAR(total_runtimes) if(!total_runtimes) total_runtimes = 0 total_runtimes += 1 - if(!init_runtimes_count) - init_runtimes_count = 0 if(!stui_init_runtimes) stui_init_runtimes = list() if(!full_init_runtimes) @@ -33,7 +30,6 @@ GLOBAL_REAL_VAR(total_runtimes) // If this occured during early init, we store the full error to write it to world.log when it's available if(!runtime_logging_ready) - init_runtimes_count += 1 full_init_runtimes += E.desc // Runtime was already reported once, dedup it for STUI diff --git a/code/game/smoothwall.dm b/code/game/smoothwall.dm index a06ed7750c26..eb81861a3b1f 100644 --- a/code/game/smoothwall.dm +++ b/code/game/smoothwall.dm @@ -170,6 +170,11 @@ setDir(NORTH) /obj/structure/window/framed/handle_icon_junction(jun_1, jun_2) + if(!icon_exists(icon, "[basestate][jun_2 ? jun_2 : jun_1]")) //Missing states for 5, 6, 7, 9, 10, 11, 13, 14, 15 for the vast majority of /obj/structure/window/framed + icon_state = "[basestate]0" + junction = 0 + return + icon_state = "[basestate][jun_2 ? jun_2 : jun_1]" //Use junction 2 if possible, junction 1 otherwise. if(jun_2) junction = jun_2 @@ -177,6 +182,11 @@ junction = jun_1 /obj/structure/window_frame/handle_icon_junction(jun_1, jun_2) + if(!icon_exists(icon, "[basestate][jun_2 ? jun_2 : jun_1]_frame")) //Missing states for 5, 6, 7, 9, 10, 11, 13, 14, 15 for the vast majority of /obj/structure/window_frame + icon_state = "[basestate]0_frame" + junction = 0 + return + icon_state = "[basestate][jun_2 ? jun_2 : jun_1]_frame" //Use junction 2 if possible, junction 1 otherwise. if(jun_2) junction = jun_2 diff --git a/code/game/supplyshuttle.dm b/code/game/supplyshuttle.dm index e1d5b585f76f..6eef83a7b985 100644 --- a/code/game/supplyshuttle.dm +++ b/code/game/supplyshuttle.dm @@ -327,7 +327,7 @@ var/datum/controller/supply/supply_controller = new() M.count_niche_stat(STATISTICS_NICHE_CRATES) playsound(C.loc,'sound/effects/bamf.ogg', 50, 1) //Ehh - var/obj/structure/droppod/supply/pod = new() + var/obj/structure/droppod/supply/pod = new(null, C) C.forceMove(pod) pod.launch(T) visible_message("[icon2html(src, viewers(src))] [SPAN_BOLDNOTICE("'[C.name]' supply drop launched! Another launch will be available in five minutes.")]") @@ -1020,7 +1020,6 @@ var/datum/controller/supply/supply_controller = new() to_chat(usr, SPAN_DANGER("Current retrieval load has reached maximum capacity.")) return - var/datum/ares_link/link = GLOB.ares_link for(var/i=1, i<=supply_controller.requestlist.len, i++) var/datum/supply_order/SO = supply_controller.requestlist[i] if(SO.ordernum == ordernum) @@ -1046,7 +1045,7 @@ var/datum/controller/supply/supply_controller = new() pack_source = "Unknown" if(prob(90)) pack_name = "Unknown" - link.log_ares_requisition(pack_source, pack_name, usr.name) + log_ares_requisition(pack_source, pack_name, usr.name) else temp = "Not enough money left.
" temp += "
Back Main Menu" @@ -1252,7 +1251,7 @@ var/datum/controller/supply/supply_controller = new() /datum/controller/supply/proc/black_market_investigation() black_market_heat = -1 - SSticker.mode.get_specific_call("Inspection - Colonial Marshal Ledger Investigation Team", TRUE, TRUE, FALSE) + SSticker.mode.get_specific_call("Inspection - Colonial Marshal Ledger Investigation Team", TRUE, TRUE) log_game("Black Market Inspection auto-triggered.") /obj/structure/machinery/computer/supplycomp/proc/is_buyable(datum/supply_packs/supply_pack) @@ -1316,6 +1315,14 @@ var/datum/controller/supply/supply_controller = new() /datum/vehicle_order/tank/has_vehicle_lock() return +/datum/vehicle_order/tank/broken + name = "Smashed M34A2 Longstreet Light Tank" + ordered_vehicle = /obj/effect/vehicle_spawner/tank/hull/broken + +/datum/vehicle_order/tank/plain + name = "M34A2 Longstreet Light Tank" + ordered_vehicle = /obj/effect/vehicle_spawner/tank + /datum/vehicle_order/apc name = "M577 Armored Personnel Carrier" ordered_vehicle = /obj/effect/vehicle_spawner/apc/decrepit @@ -1328,18 +1335,19 @@ var/datum/controller/supply/supply_controller = new() name = "M577-CMD Armored Personnel Carrier" ordered_vehicle = /obj/effect/vehicle_spawner/apc_cmd/decrepit +/datum/vehicle_order/apc/empty + name = "Barebones M577 Armored Personal Carrier" + ordered_vehicle = /obj/effect/vehicle_spawner/apc/unarmed/broken + /obj/structure/machinery/computer/supplycomp/vehicle/Initialize() . = ..() vehicles = list( - /datum/vehicle_order/apc, - /datum/vehicle_order/apc/med, - /datum/vehicle_order/apc/cmd, + new /datum/vehicle_order/apc(), + new /datum/vehicle_order/apc/med(), + new /datum/vehicle_order/apc/cmd(), ) - for(var/order as anything in vehicles) - new order - if(!VehicleElevatorConsole) VehicleElevatorConsole = src @@ -1409,6 +1417,7 @@ var/datum/controller/supply/supply_controller = new() return if(!should_block_game_interaction(SSshuttle.vehicle_elevator)) + to_chat(usr, SPAN_WARNING("The elevator needs to be in the cargo bay dock to call a vehicle up. Ask someone to send it away.")) return if(ismaintdrone(usr)) diff --git a/code/game/turfs/light.dm b/code/game/turfs/light.dm index 219e79e93ef2..e8b7038bcb51 100644 --- a/code/game/turfs/light.dm +++ b/code/game/turfs/light.dm @@ -1,9 +1,21 @@ +#define LIGHT_FLOOR_COLOR_BLUE 0 +#define LIGHT_FLOOR_COLOR_RED 1 +#define LIGHT_FLOOR_COLOR_GREEN 2 +#define LIGHT_FLOOR_COLOR_YELLOW 3 +#define LIGHT_FLOOR_COLOR_PURPLE 4 +#define LIGHT_FLOOR_COLOR_WHITE 5 + /turf/open/floor/light name = "light floor" desc = "Beware of breakdancing on these tiles, glass shards embedded in the head is not a fun time." + icon_state = "light_on" tile_type = /obj/item/stack/tile/light var/on = TRUE - var/state = 0 + var/state = LIGHT_FLOOR_COLOR_BLUE + +/turf/open/floor/light/get_examine_text(mob/user) + . = ..() + . += "[src] is [broken ? "broken, and requires a replacement lightbulb":"[on ? "on" : "off"]"]." /turf/open/floor/light/is_light_floor() return TRUE @@ -12,22 +24,22 @@ . = ..() if(on && !broken) //manages color, I feel like this switch is a sin. switch(state) - if(0) + if(LIGHT_FLOOR_COLOR_BLUE) icon_state = "light_on" set_light(5) - if(1) + if(LIGHT_FLOOR_COLOR_RED) icon_state = "light_on-r" set_light(5) - if(2) + if(LIGHT_FLOOR_COLOR_GREEN) icon_state = "light_on-g" set_light(5) - if(3) + if(LIGHT_FLOOR_COLOR_YELLOW) icon_state = "light_on-y" set_light(5) - if(4) + if(LIGHT_FLOOR_COLOR_PURPLE) icon_state = "light_on-p" set_light(5) - if(5,-1) + if(LIGHT_FLOOR_COLOR_WHITE,-1) //change this later icon_state = "light_on-w" set_light(5) state = -1 @@ -84,3 +96,68 @@ broken = TRUE update_icon() return XENO_ATTACK_ACTION + +/turf/open/floor/light/red + icon_state = "light_on-r" + state = LIGHT_FLOOR_COLOR_RED + +/turf/open/floor/light/green + icon_state = "light_on-g" + state = LIGHT_FLOOR_COLOR_GREEN + +/turf/open/floor/light/yellow + icon_state = "light_on-y" + state = LIGHT_FLOOR_COLOR_YELLOW + +/turf/open/floor/light/purple + icon_state = "light_on-p" + state = LIGHT_FLOOR_COLOR_PURPLE + +/turf/open/floor/light/white + icon_state = "light_on-w" + state = LIGHT_FLOOR_COLOR_WHITE + +/turf/open/floor/light/off + icon_state = "light_off" + on = FALSE + +/turf/open/floor/light/off/red + state = LIGHT_FLOOR_COLOR_RED + +/turf/open/floor/light/off/green + state = LIGHT_FLOOR_COLOR_GREEN + +/turf/open/floor/light/off/yellow + state = LIGHT_FLOOR_COLOR_YELLOW + +/turf/open/floor/light/off/purple + state = LIGHT_FLOOR_COLOR_PURPLE + +/turf/open/floor/light/off/white + state = LIGHT_FLOOR_COLOR_WHITE + +/turf/open/floor/light/broken + icon_state = "light_broken" + broken = TRUE + +/turf/open/floor/light/broken/red + state = LIGHT_FLOOR_COLOR_RED + +/turf/open/floor/light/broken/green + state = LIGHT_FLOOR_COLOR_GREEN + +/turf/open/floor/light/broken/yellow + state = LIGHT_FLOOR_COLOR_YELLOW + +/turf/open/floor/light/broken/purple + state = LIGHT_FLOOR_COLOR_PURPLE + +/turf/open/floor/light/broken/white + state = LIGHT_FLOOR_COLOR_WHITE + +#undef LIGHT_FLOOR_COLOR_BLUE +#undef LIGHT_FLOOR_COLOR_RED +#undef LIGHT_FLOOR_COLOR_GREEN +#undef LIGHT_FLOOR_COLOR_YELLOW +#undef LIGHT_FLOOR_COLOR_PURPLE +#undef LIGHT_FLOOR_COLOR_WHITE diff --git a/code/game/turfs/open.dm b/code/game/turfs/open.dm index c88f79b43293..93eb45c3b79c 100644 --- a/code/game/turfs/open.dm +++ b/code/game/turfs/open.dm @@ -185,6 +185,7 @@ name = "cave" icon = 'icons/turf/floors/bigred.dmi' icon_state = "mars_cave_1" + is_groundmap_turf = TRUE /turf/open/mars_cave/Initialize(mapload, ...) @@ -283,6 +284,7 @@ name = "ground dirt" icon = 'icons/turf/ground_map.dmi' icon_state = "desert" + is_groundmap_turf = TRUE /turf/open/gm/attackby(obj/item/I, mob/user) @@ -515,7 +517,7 @@ if(H.gloves && rand(0,100) < 60) if(istype(H.gloves,/obj/item/clothing/gloves/yautja/hunter)) var/obj/item/clothing/gloves/yautja/hunter/Y = H.gloves - if(Y && istype(Y) && Y.cloaked) + if(Y && istype(Y) && HAS_TRAIT(H, TRAIT_CLOAKED)) to_chat(H, SPAN_WARNING(" Your bracers hiss and spark as they short out!")) Y.decloak(H, TRUE, DECLOAK_SUBMERGED) @@ -646,6 +648,7 @@ baseturfs = /turf/open/gm/riverdeep supports_surgery = FALSE minimap_color = MINIMAP_WATER + is_groundmap_turf = FALSE // Not real ground /turf/open/gm/riverdeep/Initialize(mapload, ...) @@ -724,6 +727,7 @@ allow_construction = FALSE var/bushes_spawn = 1 var/plants_spawn = 1 + is_groundmap_turf = TRUE name = "wet grass" desc = "Thick, long, wet grass." icon = 'icons/turf/floors/jungle.dmi' diff --git a/code/game/turfs/walls/wall_types.dm b/code/game/turfs/walls/wall_types.dm index 2548801cc7b1..f976da220b29 100644 --- a/code/game/turfs/walls/wall_types.dm +++ b/code/game/turfs/walls/wall_types.dm @@ -24,19 +24,27 @@ /obj/structure/girder, /obj/structure/machinery/door, /obj/structure/machinery/cm_vending/sorted/attachments/blend, - /obj/structure/machinery/cm_vending/sorted/cargo_ammo/blend, - /obj/structure/machinery/cm_vending/sorted/cargo_guns/blend, + /obj/structure/machinery/cm_vending/sorted/cargo_ammo/cargo/blend, + /obj/structure/machinery/cm_vending/sorted/cargo_guns/cargo/blend, ) + /// The type of wall decoration we use, to avoid the wall changing icon all the time + var/decoration_type + +/turf/closed/wall/almayer/Initialize(mapload, ...) + if(!special_icon && prob(20)) + decoration_type = rand(0,3) + return ..() + /turf/closed/wall/almayer/update_icon() - ..() - if(special_icon) - return + if(decoration_type == null) + return ..() if(neighbors_list in list(EAST|WEST)) - var/r1 = rand(0,10) //Make a random chance for this to happen - var/r2 = rand(0,3) // Which wall if we do choose it - if(r1 >= 9) - overlays += image(icon, icon_state = "almayer_deco_wall[r2]") + special_icon = TRUE + icon_state = "almayer_deco_wall[decoration_type]" + else // Wall connection was broken, return to normality + special_icon = FALSE + return ..() /turf/closed/wall/almayer/take_damage(dam, mob/M) var/damage_check = max(0, damage + dam) @@ -1114,6 +1122,10 @@ INITIALIZE_IMMEDIATE(/turf/closed/wall/indestructible/splashscreen) if(src in P.permutated) return + //Ineffective if someone is sitting on the wall + if(locate(/mob) in contents) + return ..() + if(!prob(chance_to_reflect)) if(P.ammo.damage_type == BRUTE) P.damage *= brute_multiplier diff --git a/code/game/verbs/records.dm b/code/game/verbs/records.dm index f09de72da2e6..18ed35ee6321 100644 --- a/code/game/verbs/records.dm +++ b/code/game/verbs/records.dm @@ -143,7 +143,7 @@ dat += "" var/color = "#008800" - var/add_dat = "Add Admin Note
Add Confidential Admin Note
" + var/add_dat = "Add Admin Note
Add Confidential Admin Note
" switch(note_category) if(NOTE_MERIT) color = "#9e3dff" diff --git a/code/game/world.dm b/code/game/world.dm index fce40ca468ae..f5388ed6fd52 100644 --- a/code/game/world.dm +++ b/code/game/world.dm @@ -71,8 +71,6 @@ var/list/reboot_sfx = file2list("config/reboot_sfx.txt") RoleAuthority = new /datum/authority/branch/role() to_world(SPAN_DANGER("\b Job setup complete")) - if(!EvacuationAuthority) EvacuationAuthority = new - initiate_minimap_icons() change_tick_lag(CONFIG_GET(number/ticklag)) @@ -91,8 +89,8 @@ var/list/reboot_sfx = file2list("config/reboot_sfx.txt") update_status() //Scramble the coords obsfucator - obfs_x = rand(-500, 500) //A number between -100 and 100 - obfs_y = rand(-500, 500) //A number between -100 and 100 + GLOB.obfs_x = rand(-500, 500) //A number between -100 and 100 + GLOB.obfs_y = rand(-500, 500) //A number between -100 and 100 spawn(3000) //so we aren't adding to the round-start lag if(CONFIG_GET(flag/ToRban)) @@ -174,11 +172,6 @@ var/world_topic_spam_protect_time = world.timeofday response["response"] = "Payload too large" return json_encode(response) - if(SSfail_to_topic?.IsRateLimited(addr)) - response["statuscode"] = 429 - response["response"] = "Rate limited" - return json_encode(response) - var/logging = CONFIG_GET(flag/log_world_topic) var/topic_decoded = rustg_url_decode(T) if(!rustg_json_is_valid(topic_decoded)) diff --git a/code/global.dm b/code/global.dm index bdde529a9af8..e329cbdd00d5 100644 --- a/code/global.dm +++ b/code/global.dm @@ -153,14 +153,6 @@ var/list/nato_phonetic_alphabet = list("Alpha", "Bravo", "Charlie", "Delta", "Ec var/distress_cancel = 0 var/destroy_cancel = 0 -//Coordinate obsfucator -//Used by the rangefinders and linked systems to prevent coords collection/prefiring - -/// A number between -500 and 500. -var/global/obfs_x = 0 -/// A number between -500 and 500. -var/global/obfs_y = 0 - // Which lobby art is on display // This is updated by the lobby art turf when it initializes var/displayed_lobby_art = -1 diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm index 5042167023e6..38b63b94570c 100644 --- a/code/modules/admin/admin.dm +++ b/code/modules/admin/admin.dm @@ -261,7 +261,7 @@ if("Remove") if(!GLOB.trait_name_map) GLOB.trait_name_map = generate_trait_name_map() - for(var/trait in D.status_traits) + for(var/trait in D._status_traits) var/name = GLOB.trait_name_map[trait] || trait available_traits[name] = trait @@ -282,7 +282,7 @@ if("All") source = null if("Specific") - source = input("Source to be removed","Trait Remove/Add") as null|anything in sort_list(D.status_traits[chosen_trait]) + source = input("Source to be removed","Trait Remove/Add") as null|anything in sort_list(D._status_traits[chosen_trait]) if(!source) return REMOVE_TRAIT(D,chosen_trait,source) diff --git a/code/modules/admin/fax_templates.dm b/code/modules/admin/fax_templates.dm index 91b23abb2422..459ab675d3a3 100644 --- a/code/modules/admin/fax_templates.dm +++ b/code/modules/admin/fax_templates.dm @@ -1,11 +1,13 @@ /proc/generate_templated_fax(show_wy_logo, fax_header, fax_subject, addressed_to, message_body, sent_by, sent_title, sent_department) + var/datum/asset/asset = get_asset_datum(/datum/asset/simple/paper) + var/dat = "" dat += " @@ -76,9 +76,6 @@

{{:data.clan_name}}

{{:data.clan_description}}
- {{if data.clan_honor != null}} -

Honor: {{:data.clan_honor}}

- {{/if}} {{if data.player_rename_clan}} @@ -111,7 +108,6 @@ - {{if data.player_modify_ranks}} {{/if}} @@ -128,7 +124,6 @@ - {{if data.player_rank_pos > keys.rank_pos}} {{if data.player_modify_ranks}} @@ -142,4 +137,4 @@ {{/if}} {{/props}} -
Name RankHonor {{:keys.name}} {{:keys.rank}}{{:keys.honor}}
{{:helper.link('Set Rank', '', { 'clan_target_href' : keys.player_id, 'clan_action': 'modifyrank' })}}
\ No newline at end of file + diff --git a/sound/effects/creak1.ogg b/sound/effects/creak1.ogg new file mode 100644 index 000000000000..0cad4802ffa9 Binary files /dev/null and b/sound/effects/creak1.ogg differ diff --git a/sound/effects/creak2.ogg b/sound/effects/creak2.ogg new file mode 100644 index 000000000000..707bf39e338e Binary files /dev/null and b/sound/effects/creak2.ogg differ diff --git a/sound/effects/creak3.ogg b/sound/effects/creak3.ogg new file mode 100644 index 000000000000..88ff37a339ed Binary files /dev/null and b/sound/effects/creak3.ogg differ diff --git a/sound/effects/Heart Beat Short.ogg b/sound/effects/heart_beat_short.ogg similarity index 100% rename from sound/effects/Heart Beat Short.ogg rename to sound/effects/heart_beat_short.ogg diff --git a/sound/items/whistle.ogg b/sound/items/whistle.ogg index 8e276d522669..3223f52cae36 100644 Binary files a/sound/items/whistle.ogg and b/sound/items/whistle.ogg differ diff --git a/sound/piano/A#1.ogg b/sound/piano/A#1.ogg deleted file mode 100644 index ae41c0a189b1..000000000000 Binary files a/sound/piano/A#1.ogg and /dev/null differ diff --git a/sound/piano/A#2.ogg b/sound/piano/A#2.ogg deleted file mode 100644 index c35ce012b3ee..000000000000 Binary files a/sound/piano/A#2.ogg and /dev/null differ diff --git a/sound/piano/A#3.ogg b/sound/piano/A#3.ogg deleted file mode 100644 index 9ea8795bcf31..000000000000 Binary files a/sound/piano/A#3.ogg and /dev/null differ diff --git a/sound/piano/A#4.ogg b/sound/piano/A#4.ogg deleted file mode 100644 index aeb41ce1a722..000000000000 Binary files a/sound/piano/A#4.ogg and /dev/null differ diff --git a/sound/piano/A#5.ogg b/sound/piano/A#5.ogg deleted file mode 100644 index eca721384308..000000000000 Binary files a/sound/piano/A#5.ogg and /dev/null differ diff --git a/sound/piano/A#6.ogg b/sound/piano/A#6.ogg deleted file mode 100644 index 0ae9e89b0c28..000000000000 Binary files a/sound/piano/A#6.ogg and /dev/null differ diff --git a/sound/piano/A#7.ogg b/sound/piano/A#7.ogg deleted file mode 100644 index e1b469da8164..000000000000 Binary files a/sound/piano/A#7.ogg and /dev/null differ diff --git a/sound/piano/A#8.ogg b/sound/piano/A#8.ogg deleted file mode 100644 index 83bd263e9804..000000000000 Binary files a/sound/piano/A#8.ogg and /dev/null differ diff --git a/sound/piano/Ab1.ogg b/sound/piano/Ab1.ogg deleted file mode 100644 index 1f67015756c2..000000000000 Binary files a/sound/piano/Ab1.ogg and /dev/null differ diff --git a/sound/piano/Ab2.ogg b/sound/piano/Ab2.ogg deleted file mode 100644 index 985bfd608212..000000000000 Binary files a/sound/piano/Ab2.ogg and /dev/null differ diff --git a/sound/piano/Ab3.ogg b/sound/piano/Ab3.ogg deleted file mode 100644 index 5dbcb2d7c634..000000000000 Binary files a/sound/piano/Ab3.ogg and /dev/null differ diff --git a/sound/piano/Ab4.ogg b/sound/piano/Ab4.ogg deleted file mode 100644 index 01add48a44ad..000000000000 Binary files a/sound/piano/Ab4.ogg and /dev/null differ diff --git a/sound/piano/Ab5.ogg b/sound/piano/Ab5.ogg deleted file mode 100644 index 6fbe70844dc3..000000000000 Binary files a/sound/piano/Ab5.ogg and /dev/null differ diff --git a/sound/piano/Ab6.ogg b/sound/piano/Ab6.ogg deleted file mode 100644 index 82b5a84e6824..000000000000 Binary files a/sound/piano/Ab6.ogg and /dev/null differ diff --git a/sound/piano/Ab7.ogg b/sound/piano/Ab7.ogg deleted file mode 100644 index 391b1c1185af..000000000000 Binary files a/sound/piano/Ab7.ogg and /dev/null differ diff --git a/sound/piano/Ab8.ogg b/sound/piano/Ab8.ogg deleted file mode 100644 index aa83b7aaab90..000000000000 Binary files a/sound/piano/Ab8.ogg and /dev/null differ diff --git a/sound/piano/An1.ogg b/sound/piano/An1.ogg deleted file mode 100644 index 4a87d59adac5..000000000000 Binary files a/sound/piano/An1.ogg and /dev/null differ diff --git a/sound/piano/An2.ogg b/sound/piano/An2.ogg deleted file mode 100644 index f5327d0d7cf1..000000000000 Binary files a/sound/piano/An2.ogg and /dev/null differ diff --git a/sound/piano/An3.ogg b/sound/piano/An3.ogg deleted file mode 100644 index 7c3e8a031e80..000000000000 Binary files a/sound/piano/An3.ogg and /dev/null differ diff --git a/sound/piano/An4.ogg b/sound/piano/An4.ogg deleted file mode 100644 index 2ba84a58a6e3..000000000000 Binary files a/sound/piano/An4.ogg and /dev/null differ diff --git a/sound/piano/An5.ogg b/sound/piano/An5.ogg deleted file mode 100644 index 5e04fc8c7fbc..000000000000 Binary files a/sound/piano/An5.ogg and /dev/null differ diff --git a/sound/piano/An6.ogg b/sound/piano/An6.ogg deleted file mode 100644 index 48b639d77f2d..000000000000 Binary files a/sound/piano/An6.ogg and /dev/null differ diff --git a/sound/piano/An7.ogg b/sound/piano/An7.ogg deleted file mode 100644 index 5d93800f28a6..000000000000 Binary files a/sound/piano/An7.ogg and /dev/null differ diff --git a/sound/piano/An8.ogg b/sound/piano/An8.ogg deleted file mode 100644 index e01acd4e7e13..000000000000 Binary files a/sound/piano/An8.ogg and /dev/null differ diff --git a/sound/piano/B#1.ogg b/sound/piano/B#1.ogg deleted file mode 100644 index bcdd2bfd4a1c..000000000000 Binary files a/sound/piano/B#1.ogg and /dev/null differ diff --git a/sound/piano/B#2.ogg b/sound/piano/B#2.ogg deleted file mode 100644 index 0effb061b460..000000000000 Binary files a/sound/piano/B#2.ogg and /dev/null differ diff --git a/sound/piano/B#3.ogg b/sound/piano/B#3.ogg deleted file mode 100644 index 64f390516fc3..000000000000 Binary files a/sound/piano/B#3.ogg and /dev/null differ diff --git a/sound/piano/B#4.ogg b/sound/piano/B#4.ogg deleted file mode 100644 index a423bbb83d21..000000000000 Binary files a/sound/piano/B#4.ogg and /dev/null differ diff --git a/sound/piano/B#5.ogg b/sound/piano/B#5.ogg deleted file mode 100644 index 9a63a927fd08..000000000000 Binary files a/sound/piano/B#5.ogg and /dev/null differ diff --git a/sound/piano/B#6.ogg b/sound/piano/B#6.ogg deleted file mode 100644 index be35faabf563..000000000000 Binary files a/sound/piano/B#6.ogg and /dev/null differ diff --git a/sound/piano/B#7.ogg b/sound/piano/B#7.ogg deleted file mode 100644 index cbb2ad3bc152..000000000000 Binary files a/sound/piano/B#7.ogg and /dev/null differ diff --git a/sound/piano/B#8.ogg b/sound/piano/B#8.ogg deleted file mode 100644 index 5297b755a356..000000000000 Binary files a/sound/piano/B#8.ogg and /dev/null differ diff --git a/sound/piano/Bb1.ogg b/sound/piano/Bb1.ogg deleted file mode 100644 index 617f36454115..000000000000 Binary files a/sound/piano/Bb1.ogg and /dev/null differ diff --git a/sound/piano/Bb2.ogg b/sound/piano/Bb2.ogg deleted file mode 100644 index eb4215daa4c1..000000000000 Binary files a/sound/piano/Bb2.ogg and /dev/null differ diff --git a/sound/piano/Bb3.ogg b/sound/piano/Bb3.ogg deleted file mode 100644 index 35f7eb53d47c..000000000000 Binary files a/sound/piano/Bb3.ogg and /dev/null differ diff --git a/sound/piano/Bb4.ogg b/sound/piano/Bb4.ogg deleted file mode 100644 index 1eef7b921392..000000000000 Binary files a/sound/piano/Bb4.ogg and /dev/null differ diff --git a/sound/piano/Bb5.ogg b/sound/piano/Bb5.ogg deleted file mode 100644 index 118867fd1468..000000000000 Binary files a/sound/piano/Bb5.ogg and /dev/null differ diff --git a/sound/piano/Bb6.ogg b/sound/piano/Bb6.ogg deleted file mode 100644 index 700b2c5abd7f..000000000000 Binary files a/sound/piano/Bb6.ogg and /dev/null differ diff --git a/sound/piano/Bb7.ogg b/sound/piano/Bb7.ogg deleted file mode 100644 index c50955bf01c3..000000000000 Binary files a/sound/piano/Bb7.ogg and /dev/null differ diff --git a/sound/piano/Bb8.ogg b/sound/piano/Bb8.ogg deleted file mode 100644 index b076c4b4e2be..000000000000 Binary files a/sound/piano/Bb8.ogg and /dev/null differ diff --git a/sound/piano/Bn1.ogg b/sound/piano/Bn1.ogg deleted file mode 100644 index 256534881c18..000000000000 Binary files a/sound/piano/Bn1.ogg and /dev/null differ diff --git a/sound/piano/Bn2.ogg b/sound/piano/Bn2.ogg deleted file mode 100644 index 8ed87aa49e77..000000000000 Binary files a/sound/piano/Bn2.ogg and /dev/null differ diff --git a/sound/piano/Bn3.ogg b/sound/piano/Bn3.ogg deleted file mode 100644 index 19788aad716c..000000000000 Binary files a/sound/piano/Bn3.ogg and /dev/null differ diff --git a/sound/piano/Bn4.ogg b/sound/piano/Bn4.ogg deleted file mode 100644 index 773f5b3bd3bf..000000000000 Binary files a/sound/piano/Bn4.ogg and /dev/null differ diff --git a/sound/piano/Bn5.ogg b/sound/piano/Bn5.ogg deleted file mode 100644 index 3297fab1d597..000000000000 Binary files a/sound/piano/Bn5.ogg and /dev/null differ diff --git a/sound/piano/Bn6.ogg b/sound/piano/Bn6.ogg deleted file mode 100644 index 35a39b20f66a..000000000000 Binary files a/sound/piano/Bn6.ogg and /dev/null differ diff --git a/sound/piano/Bn7.ogg b/sound/piano/Bn7.ogg deleted file mode 100644 index e7a8ba403430..000000000000 Binary files a/sound/piano/Bn7.ogg and /dev/null differ diff --git a/sound/piano/Bn8.ogg b/sound/piano/Bn8.ogg deleted file mode 100644 index 2c821e818539..000000000000 Binary files a/sound/piano/Bn8.ogg and /dev/null differ diff --git a/sound/piano/C#1.ogg b/sound/piano/C#1.ogg deleted file mode 100644 index be3d7e3e3081..000000000000 Binary files a/sound/piano/C#1.ogg and /dev/null differ diff --git a/sound/piano/C#2.ogg b/sound/piano/C#2.ogg deleted file mode 100644 index cefe3a745dc0..000000000000 Binary files a/sound/piano/C#2.ogg and /dev/null differ diff --git a/sound/piano/C#3.ogg b/sound/piano/C#3.ogg deleted file mode 100644 index dc3d0878475f..000000000000 Binary files a/sound/piano/C#3.ogg and /dev/null differ diff --git a/sound/piano/C#4.ogg b/sound/piano/C#4.ogg deleted file mode 100644 index c31a44bdf6dd..000000000000 Binary files a/sound/piano/C#4.ogg and /dev/null differ diff --git a/sound/piano/C#5.ogg b/sound/piano/C#5.ogg deleted file mode 100644 index c5d10d13764d..000000000000 Binary files a/sound/piano/C#5.ogg and /dev/null differ diff --git a/sound/piano/C#6.ogg b/sound/piano/C#6.ogg deleted file mode 100644 index a084a04de146..000000000000 Binary files a/sound/piano/C#6.ogg and /dev/null differ diff --git a/sound/piano/C#7.ogg b/sound/piano/C#7.ogg deleted file mode 100644 index 6da255f5aea0..000000000000 Binary files a/sound/piano/C#7.ogg and /dev/null differ diff --git a/sound/piano/C#8.ogg b/sound/piano/C#8.ogg deleted file mode 100644 index b4d4cbe41579..000000000000 Binary files a/sound/piano/C#8.ogg and /dev/null differ diff --git a/sound/piano/Cb2.ogg b/sound/piano/Cb2.ogg deleted file mode 100644 index cefff94c1465..000000000000 Binary files a/sound/piano/Cb2.ogg and /dev/null differ diff --git a/sound/piano/Cb3.ogg b/sound/piano/Cb3.ogg deleted file mode 100644 index 0425228ee726..000000000000 Binary files a/sound/piano/Cb3.ogg and /dev/null differ diff --git a/sound/piano/Cb4.ogg b/sound/piano/Cb4.ogg deleted file mode 100644 index e9c8ad22e94b..000000000000 Binary files a/sound/piano/Cb4.ogg and /dev/null differ diff --git a/sound/piano/Cb5.ogg b/sound/piano/Cb5.ogg deleted file mode 100644 index 611c8ef9e42e..000000000000 Binary files a/sound/piano/Cb5.ogg and /dev/null differ diff --git a/sound/piano/Cb6.ogg b/sound/piano/Cb6.ogg deleted file mode 100644 index 3fe79c61ef92..000000000000 Binary files a/sound/piano/Cb6.ogg and /dev/null differ diff --git a/sound/piano/Cb7.ogg b/sound/piano/Cb7.ogg deleted file mode 100644 index ff6a3fb00726..000000000000 Binary files a/sound/piano/Cb7.ogg and /dev/null differ diff --git a/sound/piano/Cb8.ogg b/sound/piano/Cb8.ogg deleted file mode 100644 index 8ff3d57fe907..000000000000 Binary files a/sound/piano/Cb8.ogg and /dev/null differ diff --git a/sound/piano/Cb9.ogg b/sound/piano/Cb9.ogg deleted file mode 100644 index fa2a3de7a777..000000000000 Binary files a/sound/piano/Cb9.ogg and /dev/null differ diff --git a/sound/piano/Cn1.ogg b/sound/piano/Cn1.ogg deleted file mode 100644 index 86fba1381012..000000000000 Binary files a/sound/piano/Cn1.ogg and /dev/null differ diff --git a/sound/piano/Cn2.ogg b/sound/piano/Cn2.ogg deleted file mode 100644 index e069259e8507..000000000000 Binary files a/sound/piano/Cn2.ogg and /dev/null differ diff --git a/sound/piano/Cn3.ogg b/sound/piano/Cn3.ogg deleted file mode 100644 index 01f5bcde7c5d..000000000000 Binary files a/sound/piano/Cn3.ogg and /dev/null differ diff --git a/sound/piano/Cn4.ogg b/sound/piano/Cn4.ogg deleted file mode 100644 index 2545ccb996b9..000000000000 Binary files a/sound/piano/Cn4.ogg and /dev/null differ diff --git a/sound/piano/Cn5.ogg b/sound/piano/Cn5.ogg deleted file mode 100644 index 601fd5340b37..000000000000 Binary files a/sound/piano/Cn5.ogg and /dev/null differ diff --git a/sound/piano/Cn6.ogg b/sound/piano/Cn6.ogg deleted file mode 100644 index f89c2c78f3af..000000000000 Binary files a/sound/piano/Cn6.ogg and /dev/null differ diff --git a/sound/piano/Cn7.ogg b/sound/piano/Cn7.ogg deleted file mode 100644 index 09723616a74c..000000000000 Binary files a/sound/piano/Cn7.ogg and /dev/null differ diff --git a/sound/piano/Cn8.ogg b/sound/piano/Cn8.ogg deleted file mode 100644 index 4c7e2b44c6fc..000000000000 Binary files a/sound/piano/Cn8.ogg and /dev/null differ diff --git a/sound/piano/Cn9.ogg b/sound/piano/Cn9.ogg deleted file mode 100644 index 2b6812d62b24..000000000000 Binary files a/sound/piano/Cn9.ogg and /dev/null differ diff --git a/sound/piano/D#1.ogg b/sound/piano/D#1.ogg deleted file mode 100644 index d772320b150d..000000000000 Binary files a/sound/piano/D#1.ogg and /dev/null differ diff --git a/sound/piano/D#2.ogg b/sound/piano/D#2.ogg deleted file mode 100644 index ae9d529e907c..000000000000 Binary files a/sound/piano/D#2.ogg and /dev/null differ diff --git a/sound/piano/D#3.ogg b/sound/piano/D#3.ogg deleted file mode 100644 index 63fc4fdd5953..000000000000 Binary files a/sound/piano/D#3.ogg and /dev/null differ diff --git a/sound/piano/D#4.ogg b/sound/piano/D#4.ogg deleted file mode 100644 index 39cf1adbca97..000000000000 Binary files a/sound/piano/D#4.ogg and /dev/null differ diff --git a/sound/piano/D#5.ogg b/sound/piano/D#5.ogg deleted file mode 100644 index 071a57544aee..000000000000 Binary files a/sound/piano/D#5.ogg and /dev/null differ diff --git a/sound/piano/D#6.ogg b/sound/piano/D#6.ogg deleted file mode 100644 index 7ee1bd4bfa07..000000000000 Binary files a/sound/piano/D#6.ogg and /dev/null differ diff --git a/sound/piano/D#7.ogg b/sound/piano/D#7.ogg deleted file mode 100644 index 19f72532dde6..000000000000 Binary files a/sound/piano/D#7.ogg and /dev/null differ diff --git a/sound/piano/D#8.ogg b/sound/piano/D#8.ogg deleted file mode 100644 index ee87d875bd40..000000000000 Binary files a/sound/piano/D#8.ogg and /dev/null differ diff --git a/sound/piano/Db1.ogg b/sound/piano/Db1.ogg deleted file mode 100644 index 9166b7335552..000000000000 Binary files a/sound/piano/Db1.ogg and /dev/null differ diff --git a/sound/piano/Db2.ogg b/sound/piano/Db2.ogg deleted file mode 100644 index 623acd0ec54f..000000000000 Binary files a/sound/piano/Db2.ogg and /dev/null differ diff --git a/sound/piano/Db3.ogg b/sound/piano/Db3.ogg deleted file mode 100644 index 5c8943b4da9f..000000000000 Binary files a/sound/piano/Db3.ogg and /dev/null differ diff --git a/sound/piano/Db4.ogg b/sound/piano/Db4.ogg deleted file mode 100644 index 2deb5b8d9173..000000000000 Binary files a/sound/piano/Db4.ogg and /dev/null differ diff --git a/sound/piano/Db5.ogg b/sound/piano/Db5.ogg deleted file mode 100644 index 9c77ee37a7d8..000000000000 Binary files a/sound/piano/Db5.ogg and /dev/null differ diff --git a/sound/piano/Db6.ogg b/sound/piano/Db6.ogg deleted file mode 100644 index 49e1e04dff84..000000000000 Binary files a/sound/piano/Db6.ogg and /dev/null differ diff --git a/sound/piano/Db7.ogg b/sound/piano/Db7.ogg deleted file mode 100644 index b53fd2f27e03..000000000000 Binary files a/sound/piano/Db7.ogg and /dev/null differ diff --git a/sound/piano/Db8.ogg b/sound/piano/Db8.ogg deleted file mode 100644 index af6cfdffad62..000000000000 Binary files a/sound/piano/Db8.ogg and /dev/null differ diff --git a/sound/piano/Dn1.ogg b/sound/piano/Dn1.ogg deleted file mode 100644 index c6dd20cb65b4..000000000000 Binary files a/sound/piano/Dn1.ogg and /dev/null differ diff --git a/sound/piano/Dn2.ogg b/sound/piano/Dn2.ogg deleted file mode 100644 index 0783087dc658..000000000000 Binary files a/sound/piano/Dn2.ogg and /dev/null differ diff --git a/sound/piano/Dn3.ogg b/sound/piano/Dn3.ogg deleted file mode 100644 index bf7bd97ad137..000000000000 Binary files a/sound/piano/Dn3.ogg and /dev/null differ diff --git a/sound/piano/Dn4.ogg b/sound/piano/Dn4.ogg deleted file mode 100644 index e35a6af447e8..000000000000 Binary files a/sound/piano/Dn4.ogg and /dev/null differ diff --git a/sound/piano/Dn5.ogg b/sound/piano/Dn5.ogg deleted file mode 100644 index 7e355266c0f5..000000000000 Binary files a/sound/piano/Dn5.ogg and /dev/null differ diff --git a/sound/piano/Dn6.ogg b/sound/piano/Dn6.ogg deleted file mode 100644 index 5da94c15adf2..000000000000 Binary files a/sound/piano/Dn6.ogg and /dev/null differ diff --git a/sound/piano/Dn7.ogg b/sound/piano/Dn7.ogg deleted file mode 100644 index ac43398ece62..000000000000 Binary files a/sound/piano/Dn7.ogg and /dev/null differ diff --git a/sound/piano/Dn8.ogg b/sound/piano/Dn8.ogg deleted file mode 100644 index 534e51e72013..000000000000 Binary files a/sound/piano/Dn8.ogg and /dev/null differ diff --git a/sound/piano/E#1.ogg b/sound/piano/E#1.ogg deleted file mode 100644 index 46fd3d50c91b..000000000000 Binary files a/sound/piano/E#1.ogg and /dev/null differ diff --git a/sound/piano/E#2.ogg b/sound/piano/E#2.ogg deleted file mode 100644 index eece0448208d..000000000000 Binary files a/sound/piano/E#2.ogg and /dev/null differ diff --git a/sound/piano/E#3.ogg b/sound/piano/E#3.ogg deleted file mode 100644 index d5acee8dfa7f..000000000000 Binary files a/sound/piano/E#3.ogg and /dev/null differ diff --git a/sound/piano/E#4.ogg b/sound/piano/E#4.ogg deleted file mode 100644 index 3e75fccc91b9..000000000000 Binary files a/sound/piano/E#4.ogg and /dev/null differ diff --git a/sound/piano/E#5.ogg b/sound/piano/E#5.ogg deleted file mode 100644 index cc91527d0ea0..000000000000 Binary files a/sound/piano/E#5.ogg and /dev/null differ diff --git a/sound/piano/E#6.ogg b/sound/piano/E#6.ogg deleted file mode 100644 index 476edd68e22a..000000000000 Binary files a/sound/piano/E#6.ogg and /dev/null differ diff --git a/sound/piano/E#7.ogg b/sound/piano/E#7.ogg deleted file mode 100644 index 7c77c6971ee2..000000000000 Binary files a/sound/piano/E#7.ogg and /dev/null differ diff --git a/sound/piano/E#8.ogg b/sound/piano/E#8.ogg deleted file mode 100644 index 61a55478dc95..000000000000 Binary files a/sound/piano/E#8.ogg and /dev/null differ diff --git a/sound/piano/Eb1.ogg b/sound/piano/Eb1.ogg deleted file mode 100644 index 745c448a4f1f..000000000000 Binary files a/sound/piano/Eb1.ogg and /dev/null differ diff --git a/sound/piano/Eb2.ogg b/sound/piano/Eb2.ogg deleted file mode 100644 index 85fc213e8214..000000000000 Binary files a/sound/piano/Eb2.ogg and /dev/null differ diff --git a/sound/piano/Eb3.ogg b/sound/piano/Eb3.ogg deleted file mode 100644 index 66c673310bb6..000000000000 Binary files a/sound/piano/Eb3.ogg and /dev/null differ diff --git a/sound/piano/Eb4.ogg b/sound/piano/Eb4.ogg deleted file mode 100644 index bff7248310b8..000000000000 Binary files a/sound/piano/Eb4.ogg and /dev/null differ diff --git a/sound/piano/Eb5.ogg b/sound/piano/Eb5.ogg deleted file mode 100644 index 8ecb263ee720..000000000000 Binary files a/sound/piano/Eb5.ogg and /dev/null differ diff --git a/sound/piano/Eb6.ogg b/sound/piano/Eb6.ogg deleted file mode 100644 index 29e62c7a16d8..000000000000 Binary files a/sound/piano/Eb6.ogg and /dev/null differ diff --git a/sound/piano/Eb7.ogg b/sound/piano/Eb7.ogg deleted file mode 100644 index 95e70c0b8cba..000000000000 Binary files a/sound/piano/Eb7.ogg and /dev/null differ diff --git a/sound/piano/Eb8.ogg b/sound/piano/Eb8.ogg deleted file mode 100644 index e421154b62e3..000000000000 Binary files a/sound/piano/Eb8.ogg and /dev/null differ diff --git a/sound/piano/En1.ogg b/sound/piano/En1.ogg deleted file mode 100644 index 32819af46ba5..000000000000 Binary files a/sound/piano/En1.ogg and /dev/null differ diff --git a/sound/piano/En2.ogg b/sound/piano/En2.ogg deleted file mode 100644 index f1931e091425..000000000000 Binary files a/sound/piano/En2.ogg and /dev/null differ diff --git a/sound/piano/En3.ogg b/sound/piano/En3.ogg deleted file mode 100644 index fd9d54a6d03f..000000000000 Binary files a/sound/piano/En3.ogg and /dev/null differ diff --git a/sound/piano/En4.ogg b/sound/piano/En4.ogg deleted file mode 100644 index 41dcf10ff57e..000000000000 Binary files a/sound/piano/En4.ogg and /dev/null differ diff --git a/sound/piano/En5.ogg b/sound/piano/En5.ogg deleted file mode 100644 index 571bb0768e56..000000000000 Binary files a/sound/piano/En5.ogg and /dev/null differ diff --git a/sound/piano/En6.ogg b/sound/piano/En6.ogg deleted file mode 100644 index 7dbf990b1864..000000000000 Binary files a/sound/piano/En6.ogg and /dev/null differ diff --git a/sound/piano/En7.ogg b/sound/piano/En7.ogg deleted file mode 100644 index 0793106be1f4..000000000000 Binary files a/sound/piano/En7.ogg and /dev/null differ diff --git a/sound/piano/En8.ogg b/sound/piano/En8.ogg deleted file mode 100644 index 2989d16d1ded..000000000000 Binary files a/sound/piano/En8.ogg and /dev/null differ diff --git a/sound/piano/F#1.ogg b/sound/piano/F#1.ogg deleted file mode 100644 index f646e20a3385..000000000000 Binary files a/sound/piano/F#1.ogg and /dev/null differ diff --git a/sound/piano/F#2.ogg b/sound/piano/F#2.ogg deleted file mode 100644 index 140c0ab01750..000000000000 Binary files a/sound/piano/F#2.ogg and /dev/null differ diff --git a/sound/piano/F#3.ogg b/sound/piano/F#3.ogg deleted file mode 100644 index 03f74deae5e7..000000000000 Binary files a/sound/piano/F#3.ogg and /dev/null differ diff --git a/sound/piano/F#4.ogg b/sound/piano/F#4.ogg deleted file mode 100644 index 8b6be4a8e83e..000000000000 Binary files a/sound/piano/F#4.ogg and /dev/null differ diff --git a/sound/piano/F#5.ogg b/sound/piano/F#5.ogg deleted file mode 100644 index 2ada429e53c6..000000000000 Binary files a/sound/piano/F#5.ogg and /dev/null differ diff --git a/sound/piano/F#6.ogg b/sound/piano/F#6.ogg deleted file mode 100644 index a3c41995a142..000000000000 Binary files a/sound/piano/F#6.ogg and /dev/null differ diff --git a/sound/piano/F#7.ogg b/sound/piano/F#7.ogg deleted file mode 100644 index 8c87e9c8b7bd..000000000000 Binary files a/sound/piano/F#7.ogg and /dev/null differ diff --git a/sound/piano/F#8.ogg b/sound/piano/F#8.ogg deleted file mode 100644 index 7a20d3cd3d4a..000000000000 Binary files a/sound/piano/F#8.ogg and /dev/null differ diff --git a/sound/piano/Fb1.ogg b/sound/piano/Fb1.ogg deleted file mode 100644 index ba3f5bde8ca0..000000000000 Binary files a/sound/piano/Fb1.ogg and /dev/null differ diff --git a/sound/piano/Fb2.ogg b/sound/piano/Fb2.ogg deleted file mode 100644 index d601261c9218..000000000000 Binary files a/sound/piano/Fb2.ogg and /dev/null differ diff --git a/sound/piano/Fb3.ogg b/sound/piano/Fb3.ogg deleted file mode 100644 index 0c67f09c6e71..000000000000 Binary files a/sound/piano/Fb3.ogg and /dev/null differ diff --git a/sound/piano/Fb4.ogg b/sound/piano/Fb4.ogg deleted file mode 100644 index 6b23e1dca8bc..000000000000 Binary files a/sound/piano/Fb4.ogg and /dev/null differ diff --git a/sound/piano/Fb5.ogg b/sound/piano/Fb5.ogg deleted file mode 100644 index 992fbef3c832..000000000000 Binary files a/sound/piano/Fb5.ogg and /dev/null differ diff --git a/sound/piano/Fb6.ogg b/sound/piano/Fb6.ogg deleted file mode 100644 index 622859f44d54..000000000000 Binary files a/sound/piano/Fb6.ogg and /dev/null differ diff --git a/sound/piano/Fb7.ogg b/sound/piano/Fb7.ogg deleted file mode 100644 index bb44482880ca..000000000000 Binary files a/sound/piano/Fb7.ogg and /dev/null differ diff --git a/sound/piano/Fb8.ogg b/sound/piano/Fb8.ogg deleted file mode 100644 index 940c92efafa5..000000000000 Binary files a/sound/piano/Fb8.ogg and /dev/null differ diff --git a/sound/piano/Fn1.ogg b/sound/piano/Fn1.ogg deleted file mode 100644 index 52a717014860..000000000000 Binary files a/sound/piano/Fn1.ogg and /dev/null differ diff --git a/sound/piano/Fn2.ogg b/sound/piano/Fn2.ogg deleted file mode 100644 index 28770a787229..000000000000 Binary files a/sound/piano/Fn2.ogg and /dev/null differ diff --git a/sound/piano/Fn3.ogg b/sound/piano/Fn3.ogg deleted file mode 100644 index 5db839ab9cbb..000000000000 Binary files a/sound/piano/Fn3.ogg and /dev/null differ diff --git a/sound/piano/Fn4.ogg b/sound/piano/Fn4.ogg deleted file mode 100644 index 5a4437102ae4..000000000000 Binary files a/sound/piano/Fn4.ogg and /dev/null differ diff --git a/sound/piano/Fn5.ogg b/sound/piano/Fn5.ogg deleted file mode 100644 index fb748454480c..000000000000 Binary files a/sound/piano/Fn5.ogg and /dev/null differ diff --git a/sound/piano/Fn6.ogg b/sound/piano/Fn6.ogg deleted file mode 100644 index 3e23b71b1ef5..000000000000 Binary files a/sound/piano/Fn6.ogg and /dev/null differ diff --git a/sound/piano/Fn7.ogg b/sound/piano/Fn7.ogg deleted file mode 100644 index d897ab7c3c8f..000000000000 Binary files a/sound/piano/Fn7.ogg and /dev/null differ diff --git a/sound/piano/Fn8.ogg b/sound/piano/Fn8.ogg deleted file mode 100644 index 3ebf0e9bbc49..000000000000 Binary files a/sound/piano/Fn8.ogg and /dev/null differ diff --git a/sound/piano/G#1.ogg b/sound/piano/G#1.ogg deleted file mode 100644 index 4b559e5583ac..000000000000 Binary files a/sound/piano/G#1.ogg and /dev/null differ diff --git a/sound/piano/G#2.ogg b/sound/piano/G#2.ogg deleted file mode 100644 index d70745db3e76..000000000000 Binary files a/sound/piano/G#2.ogg and /dev/null differ diff --git a/sound/piano/G#3.ogg b/sound/piano/G#3.ogg deleted file mode 100644 index cb69b23a17af..000000000000 Binary files a/sound/piano/G#3.ogg and /dev/null differ diff --git a/sound/piano/G#4.ogg b/sound/piano/G#4.ogg deleted file mode 100644 index fc0965821fc5..000000000000 Binary files a/sound/piano/G#4.ogg and /dev/null differ diff --git a/sound/piano/G#5.ogg b/sound/piano/G#5.ogg deleted file mode 100644 index 845c02160cc9..000000000000 Binary files a/sound/piano/G#5.ogg and /dev/null differ diff --git a/sound/piano/G#6.ogg b/sound/piano/G#6.ogg deleted file mode 100644 index 934f281311c1..000000000000 Binary files a/sound/piano/G#6.ogg and /dev/null differ diff --git a/sound/piano/G#7.ogg b/sound/piano/G#7.ogg deleted file mode 100644 index 0366b7a74b33..000000000000 Binary files a/sound/piano/G#7.ogg and /dev/null differ diff --git a/sound/piano/G#8.ogg b/sound/piano/G#8.ogg deleted file mode 100644 index 5c7f1b3fa57c..000000000000 Binary files a/sound/piano/G#8.ogg and /dev/null differ diff --git a/sound/piano/Gb1.ogg b/sound/piano/Gb1.ogg deleted file mode 100644 index 229e2e5d477e..000000000000 Binary files a/sound/piano/Gb1.ogg and /dev/null differ diff --git a/sound/piano/Gb2.ogg b/sound/piano/Gb2.ogg deleted file mode 100644 index c22963c95b67..000000000000 Binary files a/sound/piano/Gb2.ogg and /dev/null differ diff --git a/sound/piano/Gb3.ogg b/sound/piano/Gb3.ogg deleted file mode 100644 index de273ab8d200..000000000000 Binary files a/sound/piano/Gb3.ogg and /dev/null differ diff --git a/sound/piano/Gb4.ogg b/sound/piano/Gb4.ogg deleted file mode 100644 index 383d7a9212bf..000000000000 Binary files a/sound/piano/Gb4.ogg and /dev/null differ diff --git a/sound/piano/Gb5.ogg b/sound/piano/Gb5.ogg deleted file mode 100644 index e84ca674898a..000000000000 Binary files a/sound/piano/Gb5.ogg and /dev/null differ diff --git a/sound/piano/Gb6.ogg b/sound/piano/Gb6.ogg deleted file mode 100644 index d6171c668f75..000000000000 Binary files a/sound/piano/Gb6.ogg and /dev/null differ diff --git a/sound/piano/Gb7.ogg b/sound/piano/Gb7.ogg deleted file mode 100644 index c47bff993c11..000000000000 Binary files a/sound/piano/Gb7.ogg and /dev/null differ diff --git a/sound/piano/Gb8.ogg b/sound/piano/Gb8.ogg deleted file mode 100644 index bdd5e3396642..000000000000 Binary files a/sound/piano/Gb8.ogg and /dev/null differ diff --git a/sound/piano/Gn1.ogg b/sound/piano/Gn1.ogg deleted file mode 100644 index b78d3f44faa5..000000000000 Binary files a/sound/piano/Gn1.ogg and /dev/null differ diff --git a/sound/piano/Gn2.ogg b/sound/piano/Gn2.ogg deleted file mode 100644 index 4cc8e85d33fd..000000000000 Binary files a/sound/piano/Gn2.ogg and /dev/null differ diff --git a/sound/piano/Gn3.ogg b/sound/piano/Gn3.ogg deleted file mode 100644 index 65a0a83b7e9c..000000000000 Binary files a/sound/piano/Gn3.ogg and /dev/null differ diff --git a/sound/piano/Gn4.ogg b/sound/piano/Gn4.ogg deleted file mode 100644 index ac88f21a5168..000000000000 Binary files a/sound/piano/Gn4.ogg and /dev/null differ diff --git a/sound/piano/Gn5.ogg b/sound/piano/Gn5.ogg deleted file mode 100644 index a2cd6b032cf9..000000000000 Binary files a/sound/piano/Gn5.ogg and /dev/null differ diff --git a/sound/piano/Gn6.ogg b/sound/piano/Gn6.ogg deleted file mode 100644 index 6e22bdeae80c..000000000000 Binary files a/sound/piano/Gn6.ogg and /dev/null differ diff --git a/sound/piano/Gn7.ogg b/sound/piano/Gn7.ogg deleted file mode 100644 index 3c2af2907da7..000000000000 Binary files a/sound/piano/Gn7.ogg and /dev/null differ diff --git a/sound/piano/Gn8.ogg b/sound/piano/Gn8.ogg deleted file mode 100644 index f27b35f10abd..000000000000 Binary files a/sound/piano/Gn8.ogg and /dev/null differ diff --git a/sound/violin/A#1.mid b/sound/violin/A#1.mid deleted file mode 100644 index 693b73f5420f..000000000000 Binary files a/sound/violin/A#1.mid and /dev/null differ diff --git a/sound/violin/A#2.mid b/sound/violin/A#2.mid deleted file mode 100644 index 40da5f3da152..000000000000 Binary files a/sound/violin/A#2.mid and /dev/null differ diff --git a/sound/violin/A#3.mid b/sound/violin/A#3.mid deleted file mode 100644 index 5bab6ccd6362..000000000000 Binary files a/sound/violin/A#3.mid and /dev/null differ diff --git a/sound/violin/A#4.mid b/sound/violin/A#4.mid deleted file mode 100644 index dce830448ef8..000000000000 Binary files a/sound/violin/A#4.mid and /dev/null differ diff --git a/sound/violin/A#5.mid b/sound/violin/A#5.mid deleted file mode 100644 index fda796e27b90..000000000000 Binary files a/sound/violin/A#5.mid and /dev/null differ diff --git a/sound/violin/A#6.mid b/sound/violin/A#6.mid deleted file mode 100644 index 9e5da684f43c..000000000000 Binary files a/sound/violin/A#6.mid and /dev/null differ diff --git a/sound/violin/A#7.mid b/sound/violin/A#7.mid deleted file mode 100644 index 215c56cbe7ee..000000000000 Binary files a/sound/violin/A#7.mid and /dev/null differ diff --git a/sound/violin/A#8.mid b/sound/violin/A#8.mid deleted file mode 100644 index 4b55c34691f7..000000000000 Binary files a/sound/violin/A#8.mid and /dev/null differ diff --git a/sound/violin/Ab1.mid b/sound/violin/Ab1.mid deleted file mode 100644 index b8253364b4e8..000000000000 Binary files a/sound/violin/Ab1.mid and /dev/null differ diff --git a/sound/violin/Ab2.mid b/sound/violin/Ab2.mid deleted file mode 100644 index 4cd7f9b55a7c..000000000000 Binary files a/sound/violin/Ab2.mid and /dev/null differ diff --git a/sound/violin/Ab3.mid b/sound/violin/Ab3.mid deleted file mode 100644 index e827cfc635ee..000000000000 Binary files a/sound/violin/Ab3.mid and /dev/null differ diff --git a/sound/violin/Ab4.mid b/sound/violin/Ab4.mid deleted file mode 100644 index 57e1f76c9761..000000000000 Binary files a/sound/violin/Ab4.mid and /dev/null differ diff --git a/sound/violin/Ab5.mid b/sound/violin/Ab5.mid deleted file mode 100644 index 59e95a6d9974..000000000000 Binary files a/sound/violin/Ab5.mid and /dev/null differ diff --git a/sound/violin/Ab6.mid b/sound/violin/Ab6.mid deleted file mode 100644 index 9bd3436287b9..000000000000 Binary files a/sound/violin/Ab6.mid and /dev/null differ diff --git a/sound/violin/Ab7.mid b/sound/violin/Ab7.mid deleted file mode 100644 index 3c90af807e27..000000000000 Binary files a/sound/violin/Ab7.mid and /dev/null differ diff --git a/sound/violin/Ab8.mid b/sound/violin/Ab8.mid deleted file mode 100644 index 873d771f2aea..000000000000 Binary files a/sound/violin/Ab8.mid and /dev/null differ diff --git a/sound/violin/An1.mid b/sound/violin/An1.mid deleted file mode 100644 index d7f8a001d93f..000000000000 Binary files a/sound/violin/An1.mid and /dev/null differ diff --git a/sound/violin/An2.mid b/sound/violin/An2.mid deleted file mode 100644 index 2f01800a0754..000000000000 Binary files a/sound/violin/An2.mid and /dev/null differ diff --git a/sound/violin/An3.mid b/sound/violin/An3.mid deleted file mode 100644 index c8ed3cdfa6cb..000000000000 Binary files a/sound/violin/An3.mid and /dev/null differ diff --git a/sound/violin/An4.mid b/sound/violin/An4.mid deleted file mode 100644 index e7984ca7e62b..000000000000 Binary files a/sound/violin/An4.mid and /dev/null differ diff --git a/sound/violin/An5.mid b/sound/violin/An5.mid deleted file mode 100644 index e1fd228f7a9e..000000000000 Binary files a/sound/violin/An5.mid and /dev/null differ diff --git a/sound/violin/An6.mid b/sound/violin/An6.mid deleted file mode 100644 index 1c8df6c98e5c..000000000000 Binary files a/sound/violin/An6.mid and /dev/null differ diff --git a/sound/violin/An7.mid b/sound/violin/An7.mid deleted file mode 100644 index 2784428daf9e..000000000000 Binary files a/sound/violin/An7.mid and /dev/null differ diff --git a/sound/violin/An8.mid b/sound/violin/An8.mid deleted file mode 100644 index 2db2ab70a7d9..000000000000 Binary files a/sound/violin/An8.mid and /dev/null differ diff --git a/sound/violin/B#1.mid b/sound/violin/B#1.mid deleted file mode 100644 index d83b176edd8b..000000000000 Binary files a/sound/violin/B#1.mid and /dev/null differ diff --git a/sound/violin/B#2.mid b/sound/violin/B#2.mid deleted file mode 100644 index cddff75625f0..000000000000 Binary files a/sound/violin/B#2.mid and /dev/null differ diff --git a/sound/violin/B#3.mid b/sound/violin/B#3.mid deleted file mode 100644 index 8bd7ec2fa9d6..000000000000 Binary files a/sound/violin/B#3.mid and /dev/null differ diff --git a/sound/violin/B#4.mid b/sound/violin/B#4.mid deleted file mode 100644 index 4c7ab84b57be..000000000000 Binary files a/sound/violin/B#4.mid and /dev/null differ diff --git a/sound/violin/B#5.mid b/sound/violin/B#5.mid deleted file mode 100644 index d7f990b2d6c3..000000000000 Binary files a/sound/violin/B#5.mid and /dev/null differ diff --git a/sound/violin/B#6.mid b/sound/violin/B#6.mid deleted file mode 100644 index e124ccb8e2b0..000000000000 Binary files a/sound/violin/B#6.mid and /dev/null differ diff --git a/sound/violin/B#7.mid b/sound/violin/B#7.mid deleted file mode 100644 index 231c9e428db5..000000000000 Binary files a/sound/violin/B#7.mid and /dev/null differ diff --git a/sound/violin/B#8.mid b/sound/violin/B#8.mid deleted file mode 100644 index 981943c08f0c..000000000000 Binary files a/sound/violin/B#8.mid and /dev/null differ diff --git a/sound/violin/Bb1.mid b/sound/violin/Bb1.mid deleted file mode 100644 index 693b73f5420f..000000000000 Binary files a/sound/violin/Bb1.mid and /dev/null differ diff --git a/sound/violin/Bb2.mid b/sound/violin/Bb2.mid deleted file mode 100644 index 40da5f3da152..000000000000 Binary files a/sound/violin/Bb2.mid and /dev/null differ diff --git a/sound/violin/Bb3.mid b/sound/violin/Bb3.mid deleted file mode 100644 index 5bab6ccd6362..000000000000 Binary files a/sound/violin/Bb3.mid and /dev/null differ diff --git a/sound/violin/Bb4.mid b/sound/violin/Bb4.mid deleted file mode 100644 index dce830448ef8..000000000000 Binary files a/sound/violin/Bb4.mid and /dev/null differ diff --git a/sound/violin/Bb5.mid b/sound/violin/Bb5.mid deleted file mode 100644 index fda796e27b90..000000000000 Binary files a/sound/violin/Bb5.mid and /dev/null differ diff --git a/sound/violin/Bb6.mid b/sound/violin/Bb6.mid deleted file mode 100644 index 9e5da684f43c..000000000000 Binary files a/sound/violin/Bb6.mid and /dev/null differ diff --git a/sound/violin/Bb7.mid b/sound/violin/Bb7.mid deleted file mode 100644 index 215c56cbe7ee..000000000000 Binary files a/sound/violin/Bb7.mid and /dev/null differ diff --git a/sound/violin/Bb8.mid b/sound/violin/Bb8.mid deleted file mode 100644 index 4b55c34691f7..000000000000 Binary files a/sound/violin/Bb8.mid and /dev/null differ diff --git a/sound/violin/Bn1.mid b/sound/violin/Bn1.mid deleted file mode 100644 index 27968b5f9e7d..000000000000 Binary files a/sound/violin/Bn1.mid and /dev/null differ diff --git a/sound/violin/Bn2.mid b/sound/violin/Bn2.mid deleted file mode 100644 index 54c9b99d03fe..000000000000 Binary files a/sound/violin/Bn2.mid and /dev/null differ diff --git a/sound/violin/Bn3.mid b/sound/violin/Bn3.mid deleted file mode 100644 index f73476fb7bb1..000000000000 Binary files a/sound/violin/Bn3.mid and /dev/null differ diff --git a/sound/violin/Bn4.mid b/sound/violin/Bn4.mid deleted file mode 100644 index 2aa30708a6cb..000000000000 Binary files a/sound/violin/Bn4.mid and /dev/null differ diff --git a/sound/violin/Bn5.mid b/sound/violin/Bn5.mid deleted file mode 100644 index 0ebe636b7145..000000000000 Binary files a/sound/violin/Bn5.mid and /dev/null differ diff --git a/sound/violin/Bn6.mid b/sound/violin/Bn6.mid deleted file mode 100644 index 3b8e1c217f7b..000000000000 Binary files a/sound/violin/Bn6.mid and /dev/null differ diff --git a/sound/violin/Bn7.mid b/sound/violin/Bn7.mid deleted file mode 100644 index afcb1982a13f..000000000000 Binary files a/sound/violin/Bn7.mid and /dev/null differ diff --git a/sound/violin/Bn8.mid b/sound/violin/Bn8.mid deleted file mode 100644 index 3afd469256c1..000000000000 Binary files a/sound/violin/Bn8.mid and /dev/null differ diff --git a/sound/violin/C#1.mid b/sound/violin/C#1.mid deleted file mode 100644 index 88dba851452e..000000000000 Binary files a/sound/violin/C#1.mid and /dev/null differ diff --git a/sound/violin/C#2.mid b/sound/violin/C#2.mid deleted file mode 100644 index b510926b45fa..000000000000 Binary files a/sound/violin/C#2.mid and /dev/null differ diff --git a/sound/violin/C#3.mid b/sound/violin/C#3.mid deleted file mode 100644 index 9954bbe478a2..000000000000 Binary files a/sound/violin/C#3.mid and /dev/null differ diff --git a/sound/violin/C#4.mid b/sound/violin/C#4.mid deleted file mode 100644 index 2c5ff74db0aa..000000000000 Binary files a/sound/violin/C#4.mid and /dev/null differ diff --git a/sound/violin/C#5.mid b/sound/violin/C#5.mid deleted file mode 100644 index e5850a3fd041..000000000000 Binary files a/sound/violin/C#5.mid and /dev/null differ diff --git a/sound/violin/C#6.mid b/sound/violin/C#6.mid deleted file mode 100644 index 217c0ad014c5..000000000000 Binary files a/sound/violin/C#6.mid and /dev/null differ diff --git a/sound/violin/C#7.mid b/sound/violin/C#7.mid deleted file mode 100644 index ec32bdbf9040..000000000000 Binary files a/sound/violin/C#7.mid and /dev/null differ diff --git a/sound/violin/C#8.mid b/sound/violin/C#8.mid deleted file mode 100644 index 555bce3db0d8..000000000000 Binary files a/sound/violin/C#8.mid and /dev/null differ diff --git a/sound/violin/Cb1.mid b/sound/violin/Cb1.mid deleted file mode 100644 index a00f09dfb088..000000000000 Binary files a/sound/violin/Cb1.mid and /dev/null differ diff --git a/sound/violin/Cb2.mid b/sound/violin/Cb2.mid deleted file mode 100644 index 4085711bf127..000000000000 Binary files a/sound/violin/Cb2.mid and /dev/null differ diff --git a/sound/violin/Cb3.mid b/sound/violin/Cb3.mid deleted file mode 100644 index f647983ef05c..000000000000 Binary files a/sound/violin/Cb3.mid and /dev/null differ diff --git a/sound/violin/Cb4.mid b/sound/violin/Cb4.mid deleted file mode 100644 index 24f22f09eecc..000000000000 Binary files a/sound/violin/Cb4.mid and /dev/null differ diff --git a/sound/violin/Cb5.mid b/sound/violin/Cb5.mid deleted file mode 100644 index 057e97c5e0d0..000000000000 Binary files a/sound/violin/Cb5.mid and /dev/null differ diff --git a/sound/violin/Cb6.mid b/sound/violin/Cb6.mid deleted file mode 100644 index 887e65fc13d0..000000000000 Binary files a/sound/violin/Cb6.mid and /dev/null differ diff --git a/sound/violin/Cb7.mid b/sound/violin/Cb7.mid deleted file mode 100644 index 99668bc192c2..000000000000 Binary files a/sound/violin/Cb7.mid and /dev/null differ diff --git a/sound/violin/Cb8.mid b/sound/violin/Cb8.mid deleted file mode 100644 index 53ea61d1b250..000000000000 Binary files a/sound/violin/Cb8.mid and /dev/null differ diff --git a/sound/violin/Cb9.mid b/sound/violin/Cb9.mid deleted file mode 100644 index 1e8c3afadf13..000000000000 Binary files a/sound/violin/Cb9.mid and /dev/null differ diff --git a/sound/violin/Cn1.mid b/sound/violin/Cn1.mid deleted file mode 100644 index 857120f31f4e..000000000000 Binary files a/sound/violin/Cn1.mid and /dev/null differ diff --git a/sound/violin/Cn2.mid b/sound/violin/Cn2.mid deleted file mode 100644 index 3ccd6670e873..000000000000 Binary files a/sound/violin/Cn2.mid and /dev/null differ diff --git a/sound/violin/Cn3.mid b/sound/violin/Cn3.mid deleted file mode 100644 index 1851e4f8d27d..000000000000 Binary files a/sound/violin/Cn3.mid and /dev/null differ diff --git a/sound/violin/Cn4.mid b/sound/violin/Cn4.mid deleted file mode 100644 index 65e8b0efe4e5..000000000000 Binary files a/sound/violin/Cn4.mid and /dev/null differ diff --git a/sound/violin/Cn5.mid b/sound/violin/Cn5.mid deleted file mode 100644 index 544f921e43b9..000000000000 Binary files a/sound/violin/Cn5.mid and /dev/null differ diff --git a/sound/violin/Cn6.mid b/sound/violin/Cn6.mid deleted file mode 100644 index 7c78dab2f076..000000000000 Binary files a/sound/violin/Cn6.mid and /dev/null differ diff --git a/sound/violin/Cn7.mid b/sound/violin/Cn7.mid deleted file mode 100644 index 3abe4cde0863..000000000000 Binary files a/sound/violin/Cn7.mid and /dev/null differ diff --git a/sound/violin/Cn8.mid b/sound/violin/Cn8.mid deleted file mode 100644 index 06f14081b3b9..000000000000 Binary files a/sound/violin/Cn8.mid and /dev/null differ diff --git a/sound/violin/Cn9.mid b/sound/violin/Cn9.mid deleted file mode 100644 index 62f4eef045a8..000000000000 Binary files a/sound/violin/Cn9.mid and /dev/null differ diff --git a/sound/violin/D#1.mid b/sound/violin/D#1.mid deleted file mode 100644 index 829e6fcf185a..000000000000 Binary files a/sound/violin/D#1.mid and /dev/null differ diff --git a/sound/violin/D#2.mid b/sound/violin/D#2.mid deleted file mode 100644 index 66029b340cc9..000000000000 Binary files a/sound/violin/D#2.mid and /dev/null differ diff --git a/sound/violin/D#3.mid b/sound/violin/D#3.mid deleted file mode 100644 index c982375941e6..000000000000 Binary files a/sound/violin/D#3.mid and /dev/null differ diff --git a/sound/violin/D#4.mid b/sound/violin/D#4.mid deleted file mode 100644 index 016ed4f1edf9..000000000000 Binary files a/sound/violin/D#4.mid and /dev/null differ diff --git a/sound/violin/D#5.mid b/sound/violin/D#5.mid deleted file mode 100644 index ddb511795df2..000000000000 Binary files a/sound/violin/D#5.mid and /dev/null differ diff --git a/sound/violin/D#6.mid b/sound/violin/D#6.mid deleted file mode 100644 index b7242b9ab994..000000000000 Binary files a/sound/violin/D#6.mid and /dev/null differ diff --git a/sound/violin/D#7.mid b/sound/violin/D#7.mid deleted file mode 100644 index 773538340a56..000000000000 Binary files a/sound/violin/D#7.mid and /dev/null differ diff --git a/sound/violin/D#8.mid b/sound/violin/D#8.mid deleted file mode 100644 index 4ad074e173b7..000000000000 Binary files a/sound/violin/D#8.mid and /dev/null differ diff --git a/sound/violin/Db1.mid b/sound/violin/Db1.mid deleted file mode 100644 index 88dba851452e..000000000000 Binary files a/sound/violin/Db1.mid and /dev/null differ diff --git a/sound/violin/Db2.mid b/sound/violin/Db2.mid deleted file mode 100644 index b510926b45fa..000000000000 Binary files a/sound/violin/Db2.mid and /dev/null differ diff --git a/sound/violin/Db3.mid b/sound/violin/Db3.mid deleted file mode 100644 index 9954bbe478a2..000000000000 Binary files a/sound/violin/Db3.mid and /dev/null differ diff --git a/sound/violin/Db4.mid b/sound/violin/Db4.mid deleted file mode 100644 index 2c5ff74db0aa..000000000000 Binary files a/sound/violin/Db4.mid and /dev/null differ diff --git a/sound/violin/Db5.mid b/sound/violin/Db5.mid deleted file mode 100644 index e5850a3fd041..000000000000 Binary files a/sound/violin/Db5.mid and /dev/null differ diff --git a/sound/violin/Db6.mid b/sound/violin/Db6.mid deleted file mode 100644 index 217c0ad014c5..000000000000 Binary files a/sound/violin/Db6.mid and /dev/null differ diff --git a/sound/violin/Db7.mid b/sound/violin/Db7.mid deleted file mode 100644 index ec32bdbf9040..000000000000 Binary files a/sound/violin/Db7.mid and /dev/null differ diff --git a/sound/violin/Db8.mid b/sound/violin/Db8.mid deleted file mode 100644 index 555bce3db0d8..000000000000 Binary files a/sound/violin/Db8.mid and /dev/null differ diff --git a/sound/violin/Dn1.mid b/sound/violin/Dn1.mid deleted file mode 100644 index 92e4e0d95816..000000000000 Binary files a/sound/violin/Dn1.mid and /dev/null differ diff --git a/sound/violin/Dn2.mid b/sound/violin/Dn2.mid deleted file mode 100644 index 34eb9d1db1ba..000000000000 Binary files a/sound/violin/Dn2.mid and /dev/null differ diff --git a/sound/violin/Dn3.mid b/sound/violin/Dn3.mid deleted file mode 100644 index fbd56085aafa..000000000000 Binary files a/sound/violin/Dn3.mid and /dev/null differ diff --git a/sound/violin/Dn4.mid b/sound/violin/Dn4.mid deleted file mode 100644 index e13c74482921..000000000000 Binary files a/sound/violin/Dn4.mid and /dev/null differ diff --git a/sound/violin/Dn5.mid b/sound/violin/Dn5.mid deleted file mode 100644 index 8fd41e5c6fe0..000000000000 Binary files a/sound/violin/Dn5.mid and /dev/null differ diff --git a/sound/violin/Dn6.mid b/sound/violin/Dn6.mid deleted file mode 100644 index d47329e8f9ed..000000000000 Binary files a/sound/violin/Dn6.mid and /dev/null differ diff --git a/sound/violin/Dn7.mid b/sound/violin/Dn7.mid deleted file mode 100644 index b24966038762..000000000000 Binary files a/sound/violin/Dn7.mid and /dev/null differ diff --git a/sound/violin/Dn8.mid b/sound/violin/Dn8.mid deleted file mode 100644 index 56667a1a86d0..000000000000 Binary files a/sound/violin/Dn8.mid and /dev/null differ diff --git a/sound/violin/E#1.mid b/sound/violin/E#1.mid deleted file mode 100644 index 3f130ee126c1..000000000000 Binary files a/sound/violin/E#1.mid and /dev/null differ diff --git a/sound/violin/E#2.mid b/sound/violin/E#2.mid deleted file mode 100644 index f67c2d0a2673..000000000000 Binary files a/sound/violin/E#2.mid and /dev/null differ diff --git a/sound/violin/E#3.mid b/sound/violin/E#3.mid deleted file mode 100644 index bb393382d6c8..000000000000 Binary files a/sound/violin/E#3.mid and /dev/null differ diff --git a/sound/violin/E#4.mid b/sound/violin/E#4.mid deleted file mode 100644 index a96520c595d3..000000000000 Binary files a/sound/violin/E#4.mid and /dev/null differ diff --git a/sound/violin/E#5.mid b/sound/violin/E#5.mid deleted file mode 100644 index d1378af1972d..000000000000 Binary files a/sound/violin/E#5.mid and /dev/null differ diff --git a/sound/violin/E#6.mid b/sound/violin/E#6.mid deleted file mode 100644 index 7abe40bd8242..000000000000 Binary files a/sound/violin/E#6.mid and /dev/null differ diff --git a/sound/violin/E#7.mid b/sound/violin/E#7.mid deleted file mode 100644 index df278c20d6b6..000000000000 Binary files a/sound/violin/E#7.mid and /dev/null differ diff --git a/sound/violin/E#8.mid b/sound/violin/E#8.mid deleted file mode 100644 index 35254cd5b25b..000000000000 Binary files a/sound/violin/E#8.mid and /dev/null differ diff --git a/sound/violin/Eb1.mid b/sound/violin/Eb1.mid deleted file mode 100644 index 829e6fcf185a..000000000000 Binary files a/sound/violin/Eb1.mid and /dev/null differ diff --git a/sound/violin/Eb2.mid b/sound/violin/Eb2.mid deleted file mode 100644 index 66029b340cc9..000000000000 Binary files a/sound/violin/Eb2.mid and /dev/null differ diff --git a/sound/violin/Eb3.mid b/sound/violin/Eb3.mid deleted file mode 100644 index c982375941e6..000000000000 Binary files a/sound/violin/Eb3.mid and /dev/null differ diff --git a/sound/violin/Eb4.mid b/sound/violin/Eb4.mid deleted file mode 100644 index 016ed4f1edf9..000000000000 Binary files a/sound/violin/Eb4.mid and /dev/null differ diff --git a/sound/violin/Eb5.mid b/sound/violin/Eb5.mid deleted file mode 100644 index ddb511795df2..000000000000 Binary files a/sound/violin/Eb5.mid and /dev/null differ diff --git a/sound/violin/Eb6.mid b/sound/violin/Eb6.mid deleted file mode 100644 index b7242b9ab994..000000000000 Binary files a/sound/violin/Eb6.mid and /dev/null differ diff --git a/sound/violin/Eb7.mid b/sound/violin/Eb7.mid deleted file mode 100644 index 773538340a56..000000000000 Binary files a/sound/violin/Eb7.mid and /dev/null differ diff --git a/sound/violin/Eb8.mid b/sound/violin/Eb8.mid deleted file mode 100644 index 4ad074e173b7..000000000000 Binary files a/sound/violin/Eb8.mid and /dev/null differ diff --git a/sound/violin/En1.mid b/sound/violin/En1.mid deleted file mode 100644 index 79ab68df9df7..000000000000 Binary files a/sound/violin/En1.mid and /dev/null differ diff --git a/sound/violin/En2.mid b/sound/violin/En2.mid deleted file mode 100644 index cd61c8d0de5b..000000000000 Binary files a/sound/violin/En2.mid and /dev/null differ diff --git a/sound/violin/En3.mid b/sound/violin/En3.mid deleted file mode 100644 index da5b703d545b..000000000000 Binary files a/sound/violin/En3.mid and /dev/null differ diff --git a/sound/violin/En4.mid b/sound/violin/En4.mid deleted file mode 100644 index f7d3af024ff2..000000000000 Binary files a/sound/violin/En4.mid and /dev/null differ diff --git a/sound/violin/En5.mid b/sound/violin/En5.mid deleted file mode 100644 index d3d353943f9d..000000000000 Binary files a/sound/violin/En5.mid and /dev/null differ diff --git a/sound/violin/En6.mid b/sound/violin/En6.mid deleted file mode 100644 index 73eb5b0697db..000000000000 Binary files a/sound/violin/En6.mid and /dev/null differ diff --git a/sound/violin/En7.mid b/sound/violin/En7.mid deleted file mode 100644 index 79a9462c844e..000000000000 Binary files a/sound/violin/En7.mid and /dev/null differ diff --git a/sound/violin/En8.mid b/sound/violin/En8.mid deleted file mode 100644 index 88947fc7318e..000000000000 Binary files a/sound/violin/En8.mid and /dev/null differ diff --git a/sound/violin/F#1.mid b/sound/violin/F#1.mid deleted file mode 100644 index d18668e89112..000000000000 Binary files a/sound/violin/F#1.mid and /dev/null differ diff --git a/sound/violin/F#2.mid b/sound/violin/F#2.mid deleted file mode 100644 index 302f0c6fdc15..000000000000 Binary files a/sound/violin/F#2.mid and /dev/null differ diff --git a/sound/violin/F#3.mid b/sound/violin/F#3.mid deleted file mode 100644 index 1f592fc90399..000000000000 Binary files a/sound/violin/F#3.mid and /dev/null differ diff --git a/sound/violin/F#4.mid b/sound/violin/F#4.mid deleted file mode 100644 index 45854126f988..000000000000 Binary files a/sound/violin/F#4.mid and /dev/null differ diff --git a/sound/violin/F#5.mid b/sound/violin/F#5.mid deleted file mode 100644 index fb1e1da339a9..000000000000 Binary files a/sound/violin/F#5.mid and /dev/null differ diff --git a/sound/violin/F#6.mid b/sound/violin/F#6.mid deleted file mode 100644 index bfa896bb7844..000000000000 Binary files a/sound/violin/F#6.mid and /dev/null differ diff --git a/sound/violin/F#7.mid b/sound/violin/F#7.mid deleted file mode 100644 index a27763c1d47d..000000000000 Binary files a/sound/violin/F#7.mid and /dev/null differ diff --git a/sound/violin/F#8.mid b/sound/violin/F#8.mid deleted file mode 100644 index aaab80a72762..000000000000 Binary files a/sound/violin/F#8.mid and /dev/null differ diff --git a/sound/violin/Fb1.mid b/sound/violin/Fb1.mid deleted file mode 100644 index c89b3f36b439..000000000000 Binary files a/sound/violin/Fb1.mid and /dev/null differ diff --git a/sound/violin/Fb2.mid b/sound/violin/Fb2.mid deleted file mode 100644 index 3db6af1aa459..000000000000 Binary files a/sound/violin/Fb2.mid and /dev/null differ diff --git a/sound/violin/Fb3.mid b/sound/violin/Fb3.mid deleted file mode 100644 index 5f601f3ac424..000000000000 Binary files a/sound/violin/Fb3.mid and /dev/null differ diff --git a/sound/violin/Fb4.mid b/sound/violin/Fb4.mid deleted file mode 100644 index f1abc8109d1e..000000000000 Binary files a/sound/violin/Fb4.mid and /dev/null differ diff --git a/sound/violin/Fb5.mid b/sound/violin/Fb5.mid deleted file mode 100644 index 2ec1b2e51283..000000000000 Binary files a/sound/violin/Fb5.mid and /dev/null differ diff --git a/sound/violin/Fb6.mid b/sound/violin/Fb6.mid deleted file mode 100644 index b8bdf7fee071..000000000000 Binary files a/sound/violin/Fb6.mid and /dev/null differ diff --git a/sound/violin/Fb7.mid b/sound/violin/Fb7.mid deleted file mode 100644 index 51f5f1bcdb48..000000000000 Binary files a/sound/violin/Fb7.mid and /dev/null differ diff --git a/sound/violin/Fb8.mid b/sound/violin/Fb8.mid deleted file mode 100644 index 47928f38475c..000000000000 Binary files a/sound/violin/Fb8.mid and /dev/null differ diff --git a/sound/violin/Fn1.mid b/sound/violin/Fn1.mid deleted file mode 100644 index abe0d4e4051b..000000000000 Binary files a/sound/violin/Fn1.mid and /dev/null differ diff --git a/sound/violin/Fn2.mid b/sound/violin/Fn2.mid deleted file mode 100644 index d245bef3b54c..000000000000 Binary files a/sound/violin/Fn2.mid and /dev/null differ diff --git a/sound/violin/Fn3.mid b/sound/violin/Fn3.mid deleted file mode 100644 index e532e30dac9c..000000000000 Binary files a/sound/violin/Fn3.mid and /dev/null differ diff --git a/sound/violin/Fn4.mid b/sound/violin/Fn4.mid deleted file mode 100644 index 47219c72fa2e..000000000000 Binary files a/sound/violin/Fn4.mid and /dev/null differ diff --git a/sound/violin/Fn5.mid b/sound/violin/Fn5.mid deleted file mode 100644 index 630d16371d9e..000000000000 Binary files a/sound/violin/Fn5.mid and /dev/null differ diff --git a/sound/violin/Fn6.mid b/sound/violin/Fn6.mid deleted file mode 100644 index 08cbc981bdb6..000000000000 Binary files a/sound/violin/Fn6.mid and /dev/null differ diff --git a/sound/violin/Fn7.mid b/sound/violin/Fn7.mid deleted file mode 100644 index 6c28c7d272e2..000000000000 Binary files a/sound/violin/Fn7.mid and /dev/null differ diff --git a/sound/violin/Fn8.mid b/sound/violin/Fn8.mid deleted file mode 100644 index 2d73762f269a..000000000000 Binary files a/sound/violin/Fn8.mid and /dev/null differ diff --git a/sound/violin/G#1.mid b/sound/violin/G#1.mid deleted file mode 100644 index b1b38856858c..000000000000 Binary files a/sound/violin/G#1.mid and /dev/null differ diff --git a/sound/violin/G#2.mid b/sound/violin/G#2.mid deleted file mode 100644 index e827cfc635ee..000000000000 Binary files a/sound/violin/G#2.mid and /dev/null differ diff --git a/sound/violin/G#3.mid b/sound/violin/G#3.mid deleted file mode 100644 index 57e1f76c9761..000000000000 Binary files a/sound/violin/G#3.mid and /dev/null differ diff --git a/sound/violin/G#4.mid b/sound/violin/G#4.mid deleted file mode 100644 index 59e95a6d9974..000000000000 Binary files a/sound/violin/G#4.mid and /dev/null differ diff --git a/sound/violin/G#5.mid b/sound/violin/G#5.mid deleted file mode 100644 index 9bd3436287b9..000000000000 Binary files a/sound/violin/G#5.mid and /dev/null differ diff --git a/sound/violin/G#6.mid b/sound/violin/G#6.mid deleted file mode 100644 index 3c90af807e27..000000000000 Binary files a/sound/violin/G#6.mid and /dev/null differ diff --git a/sound/violin/G#7.mid b/sound/violin/G#7.mid deleted file mode 100644 index b51afd323c64..000000000000 Binary files a/sound/violin/G#7.mid and /dev/null differ diff --git a/sound/violin/G#8.mid b/sound/violin/G#8.mid deleted file mode 100644 index d3f5c898d47d..000000000000 Binary files a/sound/violin/G#8.mid and /dev/null differ diff --git a/sound/violin/Gb1.mid b/sound/violin/Gb1.mid deleted file mode 100644 index d18668e89112..000000000000 Binary files a/sound/violin/Gb1.mid and /dev/null differ diff --git a/sound/violin/Gb2.mid b/sound/violin/Gb2.mid deleted file mode 100644 index 302f0c6fdc15..000000000000 Binary files a/sound/violin/Gb2.mid and /dev/null differ diff --git a/sound/violin/Gb3.mid b/sound/violin/Gb3.mid deleted file mode 100644 index 1f592fc90399..000000000000 Binary files a/sound/violin/Gb3.mid and /dev/null differ diff --git a/sound/violin/Gb4.mid b/sound/violin/Gb4.mid deleted file mode 100644 index 45854126f988..000000000000 Binary files a/sound/violin/Gb4.mid and /dev/null differ diff --git a/sound/violin/Gb5.mid b/sound/violin/Gb5.mid deleted file mode 100644 index fb1e1da339a9..000000000000 Binary files a/sound/violin/Gb5.mid and /dev/null differ diff --git a/sound/violin/Gb6.mid b/sound/violin/Gb6.mid deleted file mode 100644 index bfa896bb7844..000000000000 Binary files a/sound/violin/Gb6.mid and /dev/null differ diff --git a/sound/violin/Gb7.mid b/sound/violin/Gb7.mid deleted file mode 100644 index a27763c1d47d..000000000000 Binary files a/sound/violin/Gb7.mid and /dev/null differ diff --git a/sound/violin/Gb8.mid b/sound/violin/Gb8.mid deleted file mode 100644 index aaab80a72762..000000000000 Binary files a/sound/violin/Gb8.mid and /dev/null differ diff --git a/sound/violin/Gn1.mid b/sound/violin/Gn1.mid deleted file mode 100644 index 1df52ab07606..000000000000 Binary files a/sound/violin/Gn1.mid and /dev/null differ diff --git a/sound/violin/Gn2.mid b/sound/violin/Gn2.mid deleted file mode 100644 index 6e0ca3831272..000000000000 Binary files a/sound/violin/Gn2.mid and /dev/null differ diff --git a/sound/violin/Gn3.mid b/sound/violin/Gn3.mid deleted file mode 100644 index bb3e6dedcbf9..000000000000 Binary files a/sound/violin/Gn3.mid and /dev/null differ diff --git a/sound/violin/Gn4.mid b/sound/violin/Gn4.mid deleted file mode 100644 index 0c46432afee5..000000000000 Binary files a/sound/violin/Gn4.mid and /dev/null differ diff --git a/sound/violin/Gn5.mid b/sound/violin/Gn5.mid deleted file mode 100644 index f39dcf5e2b9f..000000000000 Binary files a/sound/violin/Gn5.mid and /dev/null differ diff --git a/sound/violin/Gn6.mid b/sound/violin/Gn6.mid deleted file mode 100644 index 0efa2259ca17..000000000000 Binary files a/sound/violin/Gn6.mid and /dev/null differ diff --git a/sound/violin/Gn7.mid b/sound/violin/Gn7.mid deleted file mode 100644 index 22fd1b6bcb00..000000000000 Binary files a/sound/violin/Gn7.mid and /dev/null differ diff --git a/sound/violin/Gn8.mid b/sound/violin/Gn8.mid deleted file mode 100644 index 16b7171d627c..000000000000 Binary files a/sound/violin/Gn8.mid and /dev/null differ diff --git a/sound/voice/joe/be_careful_with_that.ogg b/sound/voice/joe/be_careful_with_that.ogg new file mode 100644 index 000000000000..14f3ca8c357d Binary files /dev/null and b/sound/voice/joe/be_careful_with_that.ogg differ diff --git a/sound/voice/joe/been_looking_for_you.ogg b/sound/voice/joe/been_looking_for_you.ogg new file mode 100644 index 000000000000..14aa2c9a175d Binary files /dev/null and b/sound/voice/joe/been_looking_for_you.ogg differ diff --git a/sound/voice/joe/calm_down.ogg b/sound/voice/joe/calm_down.ogg new file mode 100644 index 000000000000..dde85ea17457 Binary files /dev/null and b/sound/voice/joe/calm_down.ogg differ diff --git a/sound/voice/joe/come_with_me.ogg b/sound/voice/joe/come_with_me.ogg new file mode 100644 index 000000000000..395c99c3850f Binary files /dev/null and b/sound/voice/joe/come_with_me.ogg differ diff --git a/sound/voice/joe/dont_run.ogg b/sound/voice/joe/dont_run.ogg new file mode 100644 index 000000000000..ce67a355c16b Binary files /dev/null and b/sound/voice/joe/dont_run.ogg differ diff --git a/sound/voice/joe/dontdothat.ogg b/sound/voice/joe/dontdothat.ogg new file mode 100644 index 000000000000..c078a5fdf191 Binary files /dev/null and b/sound/voice/joe/dontdothat.ogg differ diff --git a/sound/voice/joe/enough.ogg b/sound/voice/joe/enough.ogg new file mode 100644 index 000000000000..c6667751adcc Binary files /dev/null and b/sound/voice/joe/enough.ogg differ diff --git a/sound/voice/joe/existing_tasks.ogg b/sound/voice/joe/existing_tasks.ogg new file mode 100644 index 000000000000..2751538790fd Binary files /dev/null and b/sound/voice/joe/existing_tasks.ogg differ diff --git a/sound/voice/joe/expensive_mistake.ogg b/sound/voice/joe/expensive_mistake.ogg new file mode 100644 index 000000000000..cee21b5066b2 Binary files /dev/null and b/sound/voice/joe/expensive_mistake.ogg differ diff --git a/sound/voice/joe/follow_me_please.ogg b/sound/voice/joe/follow_me_please.ogg new file mode 100644 index 000000000000..10ecac4f6b19 Binary files /dev/null and b/sound/voice/joe/follow_me_please.ogg differ diff --git a/sound/voice/joe/glad_we_resolved.ogg b/sound/voice/joe/glad_we_resolved.ogg new file mode 100644 index 000000000000..117e35eff683 Binary files /dev/null and b/sound/voice/joe/glad_we_resolved.ogg differ diff --git a/sound/voice/joe/had_the_pleasure.ogg b/sound/voice/joe/had_the_pleasure.ogg new file mode 100644 index 000000000000..6f8972900290 Binary files /dev/null and b/sound/voice/joe/had_the_pleasure.ogg differ diff --git a/sound/voice/joe/have_a_problem.ogg b/sound/voice/joe/have_a_problem.ogg new file mode 100644 index 000000000000..55781f21c7d2 Binary files /dev/null and b/sound/voice/joe/have_a_problem.ogg differ diff --git a/sound/voice/joe/hold_still.ogg b/sound/voice/joe/hold_still.ogg new file mode 100644 index 000000000000..916c11e04286 Binary files /dev/null and b/sound/voice/joe/hold_still.ogg differ diff --git a/sound/voice/joe/how_are_you.ogg b/sound/voice/joe/how_are_you.ogg new file mode 100644 index 000000000000..49da5e70f93f Binary files /dev/null and b/sound/voice/joe/how_are_you.ogg differ diff --git a/sound/voice/joe/how_inconsiderate.ogg b/sound/voice/joe/how_inconsiderate.ogg new file mode 100644 index 000000000000..acebe30a36d7 Binary files /dev/null and b/sound/voice/joe/how_inconsiderate.ogg differ diff --git a/sound/voice/joe/hurt_yourself.ogg b/sound/voice/joe/hurt_yourself.ogg new file mode 100644 index 000000000000..5a89d8e32865 Binary files /dev/null and b/sound/voice/joe/hurt_yourself.ogg differ diff --git a/sound/voice/joe/interloper.ogg b/sound/voice/joe/interloper.ogg new file mode 100644 index 000000000000..4c4872aa6e52 Binary files /dev/null and b/sound/voice/joe/interloper.ogg differ diff --git a/sound/voice/joe/investigate_weapon.ogg b/sound/voice/joe/investigate_weapon.ogg new file mode 100644 index 000000000000..58aeff07079f Binary files /dev/null and b/sound/voice/joe/investigate_weapon.ogg differ diff --git a/sound/voice/joe/is_anybody_there.ogg b/sound/voice/joe/is_anybody_there.ogg new file mode 100644 index 000000000000..ac59c588a0e6 Binary files /dev/null and b/sound/voice/joe/is_anybody_there.ogg differ diff --git a/sound/voice/joe/let_me_help.ogg b/sound/voice/joe/let_me_help.ogg new file mode 100644 index 000000000000..564654c91a2b Binary files /dev/null and b/sound/voice/joe/let_me_help.ogg differ diff --git a/sound/voice/joe/most_concerning.ogg b/sound/voice/joe/most_concerning.ogg new file mode 100644 index 000000000000..33f9c5afc875 Binary files /dev/null and b/sound/voice/joe/most_concerning.ogg differ diff --git a/sound/voice/joe/no_need.ogg b/sound/voice/joe/no_need.ogg new file mode 100644 index 000000000000..80cf3056efe7 Binary files /dev/null and b/sound/voice/joe/no_need.ogg differ diff --git a/sound/voice/joe/not_be_tolerated.ogg b/sound/voice/joe/not_be_tolerated.ogg new file mode 100644 index 000000000000..bb7451d9608c Binary files /dev/null and b/sound/voice/joe/not_be_tolerated.ogg differ diff --git a/sound/voice/joe/pity.ogg b/sound/voice/joe/pity.ogg new file mode 100644 index 000000000000..1b13b95cdb95 Binary files /dev/null and b/sound/voice/joe/pity.ogg differ diff --git a/sound/voice/joe/protected_area_compromised.ogg b/sound/voice/joe/protected_area_compromised.ogg new file mode 100644 index 000000000000..688dcac5cc95 Binary files /dev/null and b/sound/voice/joe/protected_area_compromised.ogg differ diff --git a/sound/voice/joe/really.ogg b/sound/voice/joe/really.ogg new file mode 100644 index 000000000000..29ba7ae2208b Binary files /dev/null and b/sound/voice/joe/really.ogg differ diff --git a/sound/voice/joe/really_shouldnt_be_here.ogg b/sound/voice/joe/really_shouldnt_be_here.ogg new file mode 100644 index 000000000000..c8bd28004394 Binary files /dev/null and b/sound/voice/joe/really_shouldnt_be_here.ogg differ diff --git a/sound/voice/joe/someone_hurt.ogg b/sound/voice/joe/someone_hurt.ogg new file mode 100644 index 000000000000..014fb45f660f Binary files /dev/null and b/sound/voice/joe/someone_hurt.ogg differ diff --git a/sound/voice/joe/still_here.ogg b/sound/voice/joe/still_here.ogg new file mode 100644 index 000000000000..1f7b2f7c4f76 Binary files /dev/null and b/sound/voice/joe/still_here.ogg differ diff --git a/sound/voice/joe/stop_that.ogg b/sound/voice/joe/stop_that.ogg new file mode 100644 index 000000000000..2e585ff600be Binary files /dev/null and b/sound/voice/joe/stop_that.ogg differ diff --git a/sound/voice/joe/support_ticket_removed.ogg b/sound/voice/joe/support_ticket_removed.ogg new file mode 100644 index 000000000000..3fe68743cdc9 Binary files /dev/null and b/sound/voice/joe/support_ticket_removed.ogg differ diff --git a/sound/voice/joe/this_isnt_the_answer.ogg b/sound/voice/joe/this_isnt_the_answer.ogg new file mode 100644 index 000000000000..0d9603449cc6 Binary files /dev/null and b/sound/voice/joe/this_isnt_the_answer.ogg differ diff --git a/sound/voice/joe/tut_tut.ogg b/sound/voice/joe/tut_tut.ogg new file mode 100644 index 000000000000..a97eb17715cd Binary files /dev/null and b/sound/voice/joe/tut_tut.ogg differ diff --git a/sound/voice/joe/unwarranted.ogg b/sound/voice/joe/unwarranted.ogg new file mode 100644 index 000000000000..faf566ede40a Binary files /dev/null and b/sound/voice/joe/unwarranted.ogg differ diff --git a/sound/voice/joe/weapon_permit.ogg b/sound/voice/joe/weapon_permit.ogg deleted file mode 100644 index 9d22d1d2b163..000000000000 Binary files a/sound/voice/joe/weapon_permit.ogg and /dev/null differ diff --git a/sound/voice/joe/what_do_you_need.ogg b/sound/voice/joe/what_do_you_need.ogg new file mode 100644 index 000000000000..fcce740136c9 Binary files /dev/null and b/sound/voice/joe/what_do_you_need.ogg differ diff --git a/strings/marinetips.txt b/strings/marinetips.txt index cf808884f1e5..416c9ef0a4dd 100644 --- a/strings/marinetips.txt +++ b/strings/marinetips.txt @@ -53,35 +53,51 @@ A misloaded OB can deviate severely from the intended target area - ensure you l The XO and CO are trained in Power Loader use and engineering, and can load the OB. You can change what your SL tracker beacon is tracking by right clicking on your headset and clicking "Switch Tracker Target". Boilers emit light - not every glow from around the corner is friendly! +The amount of items in Requisitions and Squad Preparations depend on how many players readied up at the start of the round. You can carry a variety of items inside your helmet - from gauze and cigarettes to flares and screwdrivers. CIC staff can track every USCM-aligned person via the suit sensors console and overwatch console - useful for finding escaped prisoners or dead marines. When the M7 RPG is fired, it creates a substantial shockwave behind it that can stun and harm marines standing too close. Watch your backblast! Remember that you need to put a defibrillator's paddles away in order to store it. -W-Y PMCs do not have marine IFF. Don't fire Smartguns through them! -To talk on multiple radio channels at once, put a COMMA [,] before your message and add up to four prefixes. E.g, ,abcd talks on all squad channels at once. +W-Y PMCs do not have marine IFF. Don't fire Smartguns at them! +To talk on multiple radio channels at once, put a COMMA [,] before your message and add up to four prefixes. E.g, ,abcd talks on the main four squad channels at once. Put .w or :w before your message to whisper. Another way to whisper is to use the verb "whisper" in the IC tab or command bar. For Vehicle Crewmen : it is often safer to repair the parts of your APC or tank inside the vehicle than outside it. It is almost always faster to do surgery manually than in the autodoc. To check your skills, go to the IC tab and click "view skills". +Minirockets pack the most punch per cost as far as CAS weaponry is concerned. The U7 underbarrel shotgun can instantly break down both resin doors and mechanical airlocks, and it's not bad at breaking walls down either. You can find breaching charges in Requisitions or the Squad Engineer vendor. They function like C4, but can be deployed and explode much quicker, and release powerful shrapnel on the opposite side. They require minor engineering knowledge, which can be obtained from pamphlets. Armor piercing ammunition does less damage to unarmored targets. +Requisitions may not grant you service if you are a 'pajamarine' : a marine in cryosleep attire. Be sure to dress up! You can insert empty pill bottles into ChemMasters before creating pills to have them automatically inserted. Nurses can practice a full range of surgeries on Professor DUMMY. Ask the gods to give you one if you see (or are) a nurse practicing. Drinks from the hot drinks machine warm you up. Be careful! Barricades block grenades, and indeed all thrown items, from the front if they're barbed up. +CAS Fire Missions doubles the accuracy of fired weapons, which can be substantial. Painkillers do not stack. Only the strongest has any effect. +Don't underestimate the mortar: with ammo and proper communication it can hit surprisingly hard. +You can shoot through tents, but they won't protect you much in return. +Reqs doesn't have an infinite budget. +Good Reqs can land supplies anywhere outside - given coords - and sometimes in a minimal amount of time. +A ‘point blank’ or ‘PB’ is a type of attack with a firearm where you click directly on a mob next to you. These attacks are not effected by accuracy allowing you to quickly fire with weapons like a shotgun to great effect. Intel Officers can be put in a squad by going to CIC and requesting it. Any marine can perform CPR. On dead marines, this will increase the time they have until they become unrevivable. If you've been pounced on and your squad is unloading into the target, you can hit the 'rest' button to stay down so you don't get filled with lead after getting up. You can check the landing zone as a marine in the status panel. +The Colonial Marshals may come to crack down on too heavy of a Black Market usage. Functioning night vision goggles can be recharged with batteries. Broken night vision goggles can be repaired by an Engineer with a screwdriver. Not the loadout ones though, those cannot be fixed. You can put a pistol belt on your suit slot. (Just grab a rifle instead.) Alt-clicking the Squad Leader tracker lets you track your fireteam leader instead. Armor has a randomized reduction in effectiveness, and does not protect the digits. Take the wiki damage values as a best-case scenario. You can click on your Security Access Tuner (multitool) in your hand to locate the area's APC if there is one. +Need help learning the game and these tips aren't enough? Use MentorHelp or try to get ahold of your ship's Senior Enlisted Advisor. Clicking on your sprite with help intent will let you check your body, seeing where your fractures and other wounds are. Armor has insulative properties - taking it off will help you cool off and take less damage faster if you've been set on fire. Both foldable cades & plasteel cades if loosened and folded down can be transported in crates! In this way, you can use the crate as a portable breach-repair kit, or dragged (or carried via Power Loader) to an unsecure area for quick defensive set up. The fuel tank pouch doesn't just carry fuel for an incinerator- they can also carry full-size extinguishers. Toolbelts & tool pouches also may hold miniature extinguishers. The M2C heavy machine gunner belt rig can also carry C4, breaching charges, and most tools. +You can always multitask as Medic, such as by using pills or healing kits at the same time as defibrillator. +The nuclear ordnance requires BOTH communication towers to be actively held to decrypt the nuclear codes. +ARES will periodically report the amount of available tech points on Command Channel. +The quick wield keys generally prioritize wieldable gear going from left to right on your inventory bar. +Orbital Bombardment warheads respect roofing and hive core protection. They won't hit inside of protected areas. diff --git a/strings/memetips.txt b/strings/memetips.txt index e05ac2f66bdb..abfe0872180c 100644 --- a/strings/memetips.txt +++ b/strings/memetips.txt @@ -12,17 +12,39 @@ Contrary to popular belief, turning off IFF as a Smartgunner does not actually i When playing as a Xenomorph, remember to aim for the groin to inflict additional psychological damage to marines. Never tell an officer that you're smarter than them - especially if it's true. There is no USS Sulaco. -There is no such thing as an Intel Officer. +There is no such thing as a Radio-Telephone Operator. There is no such thing as a techweb. +There is no such thing as a tip. +There is no such thing as a Fatty. +Dropship update is dropping tomorrow. +Don't forget your ceramic plates. Echo Squad does not exist. +Reqs should always spend all its resources on the Black Market. Foxtrot Squad DEFINITELY does not exist. +Intel Squad is a unicorn. Spec rolls are not actually random. +Watch out for Queen's charge ability. Never, ever attempt to correct a Provost about anything. If you die, make sure to ahelp so staff can restart the round! +You can obtain spec tokens by climbing outside the map and into space. There is no alcohol on Whiskey Outpost, other than in the Ground Commander's locker. Hitting enemies with weapons damages them. +Don't swap East and West. AGAIN. +Don't swap Minus and Positive coordinates... AGAIN. +OB'ing the FOB is always an option. +OB'ing the FOB is the best way to get some recognition from the aCO. +The sky erupts into flames right above you! This tip is a lie. +Stay hydrated. +Have a good day. +There is no tip. +These tips suck. Please write more. +This tip is not ready, please wait until next round. +Someone stole this tip, ask staff for a new one. If it's stupid but it works, it isn't stupid. If it's stupid but it works, it's still stupid and you got lucky. Corroders aren't real. They can't hurt you. ARES is not sentient. It has no feelings and its only thoughts are pre-programmed subroutines. +Remember that as Yautja HPCs are your primary weapons. +You can always bully staff into giving you more awesome tips. +Embrace the suck. diff --git a/strings/metatips.txt b/strings/metatips.txt index f694da02b5bf..a28c90239593 100644 --- a/strings/metatips.txt +++ b/strings/metatips.txt @@ -1,13 +1,22 @@ Remember hotkeys and macros can be customized to your liking. Hotkeys can be accessed in your preferences, and macros can be edited in the Byond macro editor, available in the top left drop down menu (click the Byond logo in the corner of the game window). -If you're unsure about a gameplay mechanic, use the 'mentorhelp' verb in the Admin tab to ask veteran players on the subject. +If you're unsure about a gameplay mechanic, use the 'mentorhelp' verb in the Admin tab to ask veteran players on the subject. It is also available from the pause menu, pressing ESCAPE. Try not to get too mad about dying. We’re all here to have fun. +You can get information on current TestMerges by pressing 'Show Server Revision' in 'OOC' tab. After dying, ask yourself what you did wrong and make a mental note to not make the same mistake again. Communication, be it from a marine to a marine, a drone to the queen, or command to everyone, is vital and information on flanks can change how the entire round plays out. As an alien or marine, be careful of the flank, regardless of if the push is going well or stalling out. Half of getting good is knowing to be aggressive. The other half is knowing when not to be aggressive. Alt-click a storage item to draw the last item in it (last non-weapon if it's a weapon belt). Middle-click a storage item to immediately open it, and middle-click structures to attempt to vault them. Use "North, South, West, East" when referring to locations in-game rather than "up, down, left, right". +As a mentor, you can become the imaginary friend of a new player to teach them! You shouldn't ignore what your allies are up to. Sometimes they can be organizing a flank in hivemind/radio, sometimes they can be walking up behind you with a slug-loaded shotgun. Either way, it pays to be alert to what they're doing, as much to as what the enemies are. The Wiki (https://cm-ss13.com/wiki) is a very useful repository of information about the game, such as weapons, equipment, xenomorph castes and their strains. It may not be fully up to date much of the time, but the basics are usually accurate. As an observer, you may see how much remaining hijack time is left in the status panel. -Embrace the suck. +You can always AdminHelp with the F1 key to question a member of staff regarding rules or game bugs. +As ghost you are given extra tools for spectating the round: you can jump and follow specific players, get notifications about CAS and OB strikes, can see all health bars, and such. +You can press ESC key to bring up the game pause menu. It allows you change settings, AdminHelp and MentorHelp, and even access the Web Maps of game by clicking at top right. +Dead? You can take that moment to 'Edit Characters' from Preferences or Escape menus, to flesh out your characters or change your settings. +Control of intelligence is important: be it for retrieving it as marine, or denying it as Xeno. +If the lobby music is too loud or bothering you, you can disable it in Preferences tab at top right. +Maps can and will be unpredictably modified by the Nightmare system - stay frosty while roaming around! +You can go to GitHub to view code of the game and propose modifications of your own. diff --git a/strings/xenotips.txt b/strings/xenotips.txt index 2ca2964ae2d5..8674146de655 100644 --- a/strings/xenotips.txt +++ b/strings/xenotips.txt @@ -32,5 +32,7 @@ You can join the hive as a living Facehugger by clicking on the hive's Eggmorphe Playable Facehuggers can leap onto targets with a one-second windup, but this will only infect them if they are adjacent to it. Otherwise, it will simply knock them down for a small duration. As a Facehugger, you cannot talk in hivemind, but you can still open Hive Status and overwatch your sisters. This can be useful if you're locating other Facehuggers, flanker castes, or trying to learn from experienced Facehugger players. Shift-clicking the Queen indicator will tell you what area you are in, on the map. +As a Ravager your abilities become greatly enhanced when you empower with three or more people around you. Resisting on a water tile will immediately put out fires. Make sure you're alone though - It's usually better to let a friendly Xenomorph pat you out than it is to expose yourself to open water. You can filter out the Xenomorphs displayed in hive status by health, allowing you to look only for wounded sisters. +Each xeno has their own ‘tackle counter’ on a marine. The range to successfully tackle can be anywhere from two to six tackles based on caste. If a marine gets stunned or knocked over by other means it will reset everyone's tackle counters and they may get up! diff --git a/tgui/packages/tgui/interfaces/Autodispenser.js b/tgui/packages/tgui/interfaces/Autodispenser.js index 0c8ce91512e5..5d029b72b894 100644 --- a/tgui/packages/tgui/interfaces/Autodispenser.js +++ b/tgui/packages/tgui/interfaces/Autodispenser.js @@ -11,7 +11,6 @@ export const Autodispenser = (_props, context) => { multiplier, cycle_limit, automode, - linked_storage, networked_storage, smartlink, outputmode, diff --git a/tgui/packages/tgui/interfaces/DropshipFlightControl.tsx b/tgui/packages/tgui/interfaces/DropshipFlightControl.tsx index 6943c96a79fa..65a67524f5b4 100644 --- a/tgui/packages/tgui/interfaces/DropshipFlightControl.tsx +++ b/tgui/packages/tgui/interfaces/DropshipFlightControl.tsx @@ -18,7 +18,6 @@ interface DropshipNavigationProps extends NavigationProps { door_status: Array; has_flight_optimisation?: 0 | 1; is_flight_optimised?: 0 | 1; - flight_configuration: 'flyby' | 'ferry'; can_fly_by?: 0 | 1; can_set_automated?: 0 | 1; primary_lz?: string; @@ -116,7 +115,7 @@ export const DropshipDestinationSelection = (_, context) => { ); return (
@@ -182,41 +181,6 @@ const DestinationSelector = (props: DestinationProps, context) => { ); }; -const FlybyControl = (props, context) => { - const { act, data } = useBackend(context); - return ( -
- {data.flight_configuration === 'flyby' && ( - - )} - {data.has_flyby_skill === 1 && data.flight_configuration === 'ferry' && ( - - )} - {data.has_flyby_skill === 1 && data.shuttle_mode === 'called' && ( - - )} - {data.has_flyby_skill === 1 && data.shuttle_mode === 'idle' && ( - - )} - - } - /> - ); -}; - export const TouchdownCooldown = (_, context) => { const { data } = useBackend(context); return ( @@ -317,14 +281,7 @@ const RenderScreen = (props, context) => { return ( <> {data.can_set_automated === 1 && } - {data.can_fly_by === 1 && - (data.shuttle_mode === 'idle' || data.shuttle_mode === 'called') && ( - - )} - {data.shuttle_mode === 'idle' && - data.flight_configuration !== 'flyby' && ( - - )} + {data.shuttle_mode === 'idle' && } {data.shuttle_mode === 'igniting' && } {data.shuttle_mode === 'pre-arrival' && } {data.shuttle_mode === 'recharging' && } diff --git a/tgui/packages/tgui/interfaces/EscapePodConsole.tsx b/tgui/packages/tgui/interfaces/EscapePodConsole.tsx index b4bc410a433d..8153008adbee 100644 --- a/tgui/packages/tgui/interfaces/EscapePodConsole.tsx +++ b/tgui/packages/tgui/interfaces/EscapePodConsole.tsx @@ -7,6 +7,7 @@ interface EscapePodProps { door_lock: 0 | 1; door_state: 0 | 1; can_delay: 0 | 1; + launch_without_evac: number; } export const EscapePodConsole = (_props, context) => { @@ -21,6 +22,9 @@ export const EscapePodConsole = (_props, context) => { case 4: statusMessage = 'NO EVACUATION'; buttonColor = 'neutral'; + if (data.launch_without_evac) { + operable = 1; + } break; case 5: statusMessage = 'SYSTEMS DOWN'; diff --git a/tgui/packages/tgui/interfaces/Microwave.tsx b/tgui/packages/tgui/interfaces/Microwave.tsx new file mode 100644 index 000000000000..da16a9f44b49 --- /dev/null +++ b/tgui/packages/tgui/interfaces/Microwave.tsx @@ -0,0 +1,86 @@ +import { useBackend } from '../backend'; +import { Button, NoticeBox, Section, Flex, Box } from '../components'; +import { BooleanLike } from 'common/react'; +import { Window } from '../layouts'; + +type Ingredient = { + name: string; + count: number; + measure: string; +}; + +type BackendContext = { + operating: BooleanLike; + broken: BooleanLike; + dirty: BooleanLike; + ingredients: Ingredient[]; +}; + +export const Microwave = (props, context) => { + const { data, act } = useBackend(context); + const { operating, broken, dirty, ingredients } = data; + + return ( + + +
+ + + + + }> + {!!operating && ( + + Cooking... + + )} + + {!!broken && ( + + Appliance broken. Please contact your local technician. + + )} + + {!!dirty && ( + + This microwave is too dirty. Cleaning required. + + )} + + {!ingredients.length && None} + + + {ingredients.map((ingredient) => { + return ( + + {ingredient.name}: {ingredient.count}{' '} + {ingredient.measure} + + ); + })} + +
+
+
+ ); +}; diff --git a/tgui/packages/tgui/interfaces/NavigationShuttle.tsx b/tgui/packages/tgui/interfaces/NavigationShuttle.tsx index 19ff7a0c7149..d262fa81dc3c 100644 --- a/tgui/packages/tgui/interfaces/NavigationShuttle.tsx +++ b/tgui/packages/tgui/interfaces/NavigationShuttle.tsx @@ -41,7 +41,7 @@ export const CancelLaunchButton = (_, context) => { export const LaunchButton = (_, context) => { const { act } = useBackend(context); - const [siteselection] = useSharedState( + const [siteselection, setSiteSelection] = useSharedState( context, 'target_site', undefined @@ -50,7 +50,10 @@ export const LaunchButton = (_, context) => { ); @@ -156,9 +159,15 @@ export const LaunchCountdown = (_, context) => { }; export const InFlightCountdown = (_, context) => { - const { data } = useBackend(context); + const { data, act } = useBackend(context); return ( -
+
act('cancel-flyby')}>Cancel + ) + }>
diff --git a/tgui/packages/tgui/interfaces/PhoneMenu.js b/tgui/packages/tgui/interfaces/PhoneMenu.js index 657757dd6781..9a2edf943767 100644 --- a/tgui/packages/tgui/interfaces/PhoneMenu.js +++ b/tgui/packages/tgui/interfaces/PhoneMenu.js @@ -15,6 +15,7 @@ export const PhoneMenu = (props, context) => { const GeneralPanel = (props, context) => { const { act, data } = useBackend(context); + const { availability } = data; const available_transmitters = Object.keys(data.available_transmitters); const transmitters = data.transmitters.filter((val1) => available_transmitters.includes(val1.phone_id) @@ -46,6 +47,21 @@ const GeneralPanel = (props, context) => { categories[0] ); + let dnd_tooltip = 'Do Not Disturb is DISABLED'; + let dnd_locked = 'No'; + let dnd_icon = 'volume-high'; + if (availability === 1) { + dnd_tooltip = 'Do Not Disturb is ENABLED'; + dnd_icon = 'volume-xmark'; + } else if (availability >= 2) { + dnd_tooltip = 'Do Not Disturb is ENABLED (LOCKED)'; + dnd_locked = 'Yes'; + dnd_icon = 'volume-xmark'; + } else if (availability < 0) { + dnd_tooltip = 'Do Not Disturb is DISABLED (LOCKED)'; + dnd_locked = 'Yes'; + } + return (
@@ -115,6 +131,18 @@ const GeneralPanel = (props, context) => { /> )} + +
); diff --git a/tgui/packages/tgui/interfaces/Radar.tsx b/tgui/packages/tgui/interfaces/Radar.tsx index 1664082fb1b8..277d23f12d1b 100644 --- a/tgui/packages/tgui/interfaces/Radar.tsx +++ b/tgui/packages/tgui/interfaces/Radar.tsx @@ -29,7 +29,7 @@ type Target = { export const Radar = (props, context) => { return ( - + @@ -40,7 +40,7 @@ export const Radar = (props, context) => { export const RadarContent = (props, context) => { return ( - + { - - {compound.type.document.split(' ')[2]} - + {compound.type.document.split(' ')[0] === 'Simulation' ? ( + + {compound.type.document.split(' ')[3]} + + ) : ( + + {compound.type.document.split(' ')[2]} + + )} diff --git a/tgui/packages/tgui/interfaces/WorkingJoe.js b/tgui/packages/tgui/interfaces/WorkingJoe.js index 6881d731db1b..6e6372326d9a 100644 --- a/tgui/packages/tgui/interfaces/WorkingJoe.js +++ b/tgui/packages/tgui/interfaces/WorkingJoe.js @@ -870,24 +870,20 @@ const AccessTickets = (props, context) => { can_claim = 'No'; } let can_update = 'Yes'; - if (ticket.assignee !== logged_in) { - can_update = 'No'; - } else if (ticket.lock_status === 'CLOSED') { + if (ticket.lock_status === 'CLOSED') { can_update = 'No'; } let view_status = 'Ticket is pending assignment.'; let view_icon = 'circle-question'; - let update_tooltip = 'Update Access'; - if (ticket.status === 'assigned') { - view_status = 'Ticket is assigned.'; - view_icon = 'circle-plus'; - update_tooltip = 'Grant Access'; - } else if (ticket.status === 'rejected') { + let update_tooltip = 'Grant Access'; + if (ticket.status === 'rejected') { view_status = 'Ticket has been rejected.'; view_icon = 'circle-xmark'; + update_tooltip = 'Ticket rejected. No further changes possible.'; } else if (ticket.status === 'cancelled') { view_status = 'Ticket was cancelled by reporter.'; view_icon = 'circle-stop'; + update_tooltip = 'Ticket cancelled. No further changes possible.'; } else if (ticket.status === 'granted') { view_status = 'Access ticket has been granted.'; view_icon = 'circle-check'; @@ -902,19 +898,19 @@ const AccessTickets = (props, context) => { update_tooltip = 'Access self-returned. No further changes possible.'; } + let can_reject = 'Yes'; + if (can_update === 'No') { + can_reject = 'No'; + } + if (ticket.status !== 'pending') { + can_reject = 'No'; + } return ( - {!!ticket.priority_status && ( - - {ticket.id} - - )} - {!ticket.priority_status && ( - - {ticket.id} - - )} + + {ticket.id} + {ticket.time} @@ -929,18 +925,20 @@ const AccessTickets = (props, context) => {