From ecaf6fd21b5668fe37f6f02a2c0b2084ecc2be35 Mon Sep 17 00:00:00 2001 From: spaghetti <48985748+definitelynotspaghetti@users.noreply.github.com> Date: Tue, 18 Jun 2024 10:05:44 +0300 Subject: [PATCH] predators (#437) * init * huntership * upd * upd * upd * upd * upd * upd * upd * upd * upd * upd * upd * upd * upd * smartdisc * upd... * upd? * hellhound * caster fix * translator * map fixes * map fixes * translator * falcon fix * hair fix * radio fix * upd * upd * pre equip dupe fix * caster buff * upd * balance * orbit * equip * fixes * upd * upd * data_huds * hud * surgery * scanner fix * item verbs * upd * config issues * surgery * Update _radio.dm * Update mobs.dm * Update flavor_misc.dm * Update emote.dm * Update human_defines.dm * Update dbcore.dm * hugger_egg * abilities * facehuggers.dm * surgery * Update yaut_items.dm * Update sentries.dm * Update hive_threat.dm * Update _game_mode.dm * Update facehuggers.dm * Update yautja.dm * Update human_attackhand.dm * heal_pack * Update xenomorph.dm * constructions * Update minimaps.dm * Update yautja.dm * Update includes.dm * Update yautja.dm * unused proc * cryo * Revert "cryo" This reverts commit ff4dba897746ba3d5f737106db7cb6bd3e98daed. * cryo * human defines * Update yautja_rope.dm * Update yaut_weapons.dm * Update yaut_weapons.dm * text * Update yaut_mask.dm * upd * damage_mod * Update attack_alien.dm * Update apc.dm * Update matrices.dm * Update unsorted.dm * proc * Update data_huds.dm * Revert "proc" This reverts commit ccac8f7b5601f314de421c8af63a14769ef4ccce. * proc * Update new_player.dm * Update maintenance_tools.dm * multitool * tiles * Update sheet_types.dm --------- Co-authored-by: Blundir <100090741+Blundir@users.noreply.github.com> --- SQL/tgmc-schema.sql | 19 + _maps/~RUTGMC/predship/huntership.dmm | 7870 +++++++++++++++++ code/__DEFINES/_radio.dm | 7 +- code/__DEFINES/conflict.dm | 2 +- code/__DEFINES/is_helpers.dm | 3 +- code/__DEFINES/minimap.dm | 2 +- code/__DEFINES/mobs.dm | 6 +- code/__DEFINES/preferences.dm | 3 +- .../~RUtgmc_defines/_defines_include.dm | 4 + code/__DEFINES/~RUtgmc_defines/atom_hud.dm | 8 + code/__DEFINES/~RUtgmc_defines/conflict.dm | 6 + code/__DEFINES/~RUtgmc_defines/dsc/signals.dm | 20 + code/__DEFINES/~RUtgmc_defines/equipment.dm | 2 + code/__DEFINES/~RUtgmc_defines/footsteps.dm | 61 + code/__DEFINES/~RUtgmc_defines/is_helpers.dm | 11 + code/__DEFINES/~RUtgmc_defines/minimap.dm | 1 + code/__DEFINES/~RUtgmc_defines/mobs.dm | 10 + code/__DEFINES/~RUtgmc_defines/mode.dm | 37 + code/__DEFINES/~RUtgmc_defines/predators.dm | 165 + code/__DEFINES/~RUtgmc_defines/preferences.dm | 8 + code/__DEFINES/~RUtgmc_defines/span.dm | 11 + code/__DEFINES/~RUtgmc_defines/traits.dm | 7 + code/__HELPERS/mobs.dm | 3 +- code/_globalvars/lists/flavor_misc.dm | 3 +- code/_onclick/item_attack.dm | 2 + code/controllers/subsystem/dbcore.dm | 2 +- code/datums/actions/observer_action.dm | 2 +- code/datums/atom_hud.dm | 4 + code/datums/components/bump_attack.dm | 2 +- code/datums/elements/footstep.dm | 4 + code/datums/gamemodes/_game_mode.dm | 4 +- code/datums/jobs/job/job.dm | 19 +- code/datums/jobs/job/xenomorph.dm | 4 +- code/datums/outfit.dm | 4 +- code/datums/quick_load_outfits.dm | 4 +- .../datums/weather/weather_types/acid_rain.dm | 21 +- code/game/atoms_movable.dm | 3 +- code/game/communications.dm | 4 + code/game/data_huds.dm | 1 - code/game/objects/effects/step_triggers.dm | 10 +- code/game/objects/effects/weeds.dm | 10 + code/game/objects/items/motion_detector.dm | 4 + code/game/objects/items/scanners.dm | 5 + code/game/objects/items/stacks/medical.dm | 6 +- .../objects/items/tools/maintenance_tools.dm | 2 +- .../machinery/telecomms/machines/bus.dm | 2 +- .../machinery/telecomms/machines/receiver.dm | 2 +- .../machinery/telecomms/machines/server.dm | 4 +- .../stool_bed_chair_nest/xeno_nest.dm | 6 +- code/game/say.dm | 1 + code/game/sound.dm | 20 + code/game/turfs/walls/walls.dm | 6 + code/modules/admin/topic.dm | 24 +- code/modules/animations/animation_library.dm | 33 + code/modules/client/client_procs.dm | 4 + code/modules/client/preferences_savefile.dm | 81 + code/modules/client/preferences_ui.dm | 167 +- .../modular_armor/attachments/storage.dm | 3 + code/modules/events/hive_threat.dm | 2 +- code/modules/mob/dead/observer/login.dm | 4 + code/modules/mob/dead/observer/orbit.dm | 27 + code/modules/mob/death.dm | 9 + code/modules/mob/living/blood.dm | 5 + .../mob/living/carbon/carbon_defines.dm | 4 + code/modules/mob/living/carbon/human/death.dm | 3 + code/modules/mob/living/carbon/human/emote.dm | 6 +- .../mob/living/carbon/human/examine.dm | 20 + code/modules/mob/living/carbon/human/human.dm | 7 +- .../living/carbon/human/human_attackhand.dm | 3 +- .../mob/living/carbon/human/human_damage.dm | 9 +- .../mob/living/carbon/human/human_defense.dm | 18 +- .../mob/living/carbon/human/human_helpers.dm | 2 +- .../mob/living/carbon/human/inventory.dm | 4 +- .../mob/living/carbon/human/species.dm | 5 + .../mob/living/carbon/human/update_icons.dm | 12 +- .../living/carbon/xenomorph/attack_alien.dm | 21 + .../castes/hunter/abilities_hunter.dm | 7 +- .../xenomorph/castes/king/abilities_king.dm | 4 + .../castes/runner/abilities_runner.dm | 10 + .../living/carbon/xenomorph/damage_procs.dm | 4 + .../mob/living/carbon/xenomorph/embryo.dm | 9 +- .../mob/living/carbon/xenomorph/emote.dm | 11 + .../living/carbon/xenomorph/facehuggers.dm | 16 +- .../mob/living/carbon/xenomorph/life.dm | 3 + .../mob/living/carbon/xenomorph/say.dm | 5 + .../living/carbon/xenomorph/update_icons.dm | 3 +- .../mob/living/carbon/xenomorph/xenomorph.dm | 2 +- .../mob/living/carbon/xenomorph/xenoprocs.dm | 6 + code/modules/mob/living/damage_procs.dm | 4 + code/modules/mob/living/living_movement.dm | 4 + code/modules/mob/login.dm | 7 + code/modules/mob/mob.dm | 14 + code/modules/mob/mob_movement.dm | 4 + code/modules/mob/new_player/ethnicity.dm | 80 +- code/modules/mob/new_player/new_player.dm | 10 + code/modules/organs/limbs.dm | 6 + code/modules/organs/wound.dm | 3 +- code/modules/power/apc.dm | 47 + code/modules/projectiles/sentries.dm | 2 +- code/modules/reagents/reagents/toxin.dm | 5 +- code/modules/surgery/surgery.dm | 4 +- config/role_whitelist.txt | 21 + html/browser/banpanel.css | 3 + interface/stylesheet.dm | 5 + modular_RUtgmc/code/__HELPERS/matrices.dm | 107 + modular_RUtgmc/code/__HELPERS/unsorted.dm | 95 + .../code/_globalvars/lists/flavor_misc.dm | 29 + modular_RUtgmc/code/_globalvars/lists/mobs.dm | 3 + modular_RUtgmc/code/_onclick/hud/defines.dm | 18 + modular_RUtgmc/code/_onclick/hud/yautja.dm | 18 + .../code/controllers/configuration/entries.dm | 9 + .../code/controllers/subsystem/dbcore.dm | 2 + .../code/controllers/subsystem/hunt_system.dm | 73 + .../code/controllers/subsystem/job.dm | 2 +- .../code/controllers/subsystem/minimaps.dm | 56 + .../code/controllers/subsystem/predships.dm | 477 + .../code/datums/actions/observer_action.dm | 33 + .../datums/elements/yautja_tracked_item.dm | 44 + modular_RUtgmc/code/datums/flaying.dm | 111 + .../code/datums/gamemodes/_game_mode.dm | 112 + .../code/datums/gamemodes/distress.dm | 1 + modular_RUtgmc/code/datums/jobs/job/job.dm | 8 + modular_RUtgmc/code/datums/jobs/job/pred.dm | 246 + modular_RUtgmc/code/datums/keybinding/xeno.dm | 18 + modular_RUtgmc/code/datums/skills.dm | 15 + .../code/datums/status_effects/xeno_buffs.dm | 50 + modular_RUtgmc/code/game/atoms.dm | 5 + modular_RUtgmc/code/game/data_huds.dm | 24 +- .../game/objects/effects/step_triggers.dm | 23 + .../code/game/objects/items/card_ids.dm | 6 + .../items/reagent_containers/autoinjectors.dm | 26 + .../items/reagent_containers/snacks.dm | 10 + .../code/game/objects/items/scanners.dm | 11 + .../code/game/objects/items/stacks/leather.dm | 4 + .../code/game/objects/items/stacks/medical.dm | 39 + .../objects/items/stacks/sheets/mineral.dm | 3 + .../items/{ => stacks}/sheets/sheet_types.dm | 11 + .../objects/items/stacks/tiles/tile_types.dm | 9 + .../game/objects/items/weapons/weapons.dm | 3 + .../code/game/objects/machinery/OpTable.dm | 4 + .../code/game/objects/machinery/adv_med.dm | 5 + .../code/game/objects/machinery/autodoc.dm | 9 + .../game/objects/machinery/computer/crew.dm | 4 + .../game/objects/machinery/kitchen/gibber.dm | 3 + .../code/game/objects/machinery/sleeper.dm | 4 + .../code/game/objects/structures/barricade.dm | 7 + .../game/objects/structures/bedsheet_bin.dm | 5 + .../structures/crates_lockers/closets.dm | 4 + .../crates_lockers/secure/freezer.dm | 15 + .../code/game/objects/structures/misc.dm | 16 + .../objects/structures/reagent_dispensers.dm | 8 + .../structures/stool_bed_chair_nest/bed.dm | 7 + .../structures/stool_bed_chair_nest/chairs.dm | 3 + .../code/game/objects/structures/window.dm | 10 + .../code/game/objects/yautja_misc.dm | 100 + modular_RUtgmc/code/game/turfs/floor_types.dm | 25 + .../code/game/turfs/walls/wall_types.dm | 32 + .../code/modules/admin/admin_verbs.dm | 43 + modular_RUtgmc/code/modules/admin/holder.dm | 93 + .../code/modules/admin/panels/player_panel.dm | 12 +- .../components/unary_devices/thermomachine.dm | 4 + .../machinery/portable/canister.dm | 5 + modular_RUtgmc/code/modules/clans/clan.dm | 4 + modular_RUtgmc/code/modules/clans/client.dm | 181 + modular_RUtgmc/code/modules/clans/rank.dm | 44 + modular_RUtgmc/code/modules/clans/ship.dm | 7 + .../code/modules/client/preferences.dm | 23 + .../code/modules/clothing/glasses/meson.dm | 33 + .../code/modules/clothing/glasses/night.dm | 33 + .../code/modules/clothing/glasses/thermal.dm | 31 + .../modular_armor/attachments/modules.dm | 2 + .../code/modules/cm_preds/_yaut_defines.dm | 22 + .../code/modules/cm_preds/falcon.dm | 117 + .../code/modules/cm_preds/huntdata.dm | 159 + .../code/modules/cm_preds/keybinds.dm | 82 + .../code/modules/cm_preds/landmakrs.dm | 20 + .../code/modules/cm_preds/predator_action.dm | 315 + .../code/modules/cm_preds/smartdisc.dm | 278 + .../code/modules/cm_preds/thrall_items.dm | 60 + .../code/modules/cm_preds/thrall_procs.dm | 186 + .../code/modules/cm_preds/yaut_bracers.dm | 1314 +++ .../code/modules/cm_preds/yaut_chems.dm | 63 + .../code/modules/cm_preds/yaut_hudprocs.dm | 390 + .../code/modules/cm_preds/yaut_items.dm | 1219 +++ .../code/modules/cm_preds/yaut_machines.dm | 171 + .../code/modules/cm_preds/yaut_mask.dm | 270 + .../code/modules/cm_preds/yaut_procs.dm | 227 + .../code/modules/cm_preds/yaut_shield.dm | 125 + .../code/modules/cm_preds/yautja_rope.dm | 111 + .../cm_preds/yautja_weapons/misc_weapons.dm | 127 + .../cm_preds/yautja_weapons/one_handed.dm | 482 + .../modules/cm_preds/yautja_weapons/ranged.dm | 579 ++ .../cm_preds/yautja_weapons/two_handed.dm | 82 + .../code/modules/language/hellhound.dm | 7 + .../code/modules/language/yautja.dm | 20 + .../code/modules/mining/money_bag.dm | 6 + .../code/modules/mob/dead/observer.dm | 52 + modular_RUtgmc/code/modules/mob/hologram.dm | 80 + .../mob/living/carbon/carbon_defense.dm | 22 + .../mob/living/carbon/human/emote-yautja.dm | 170 + .../mob/living/carbon/human/human_defense.dm | 51 + .../mob/living/carbon/human/human_defines.dm | 3 + .../mob/living/carbon/human/update_icons.dm | 44 + .../modules/mob/living/carbon/human/yautja.dm | 295 + .../mob/living/carbon/xenomorph/abilities.dm | 4 + .../carbon/xenomorph/castes/beetle/beetle.dm | 3 + .../xenomorph/castes/defiler/defiler.dm | 2 + .../xenomorph/castes/facehugger/facehugger.dm | 3 + .../xenomorph/castes/hellhound/hellhound.dm | 2 +- .../carbon/xenomorph/castes/larva/larva.dm | 108 +- .../carbon/xenomorph/castes/mantis/mantis.dm | 3 + .../castes/predalien/abilities_predalien.dm | 9 +- .../castes/predalien/castedatum_predalien.dm | 3 - .../xenomorph/castes/predalien/predalien.dm | 4 +- .../xenomorph/castes/scorpion/scorpion.dm | 3 + .../mob/living/carbon/xenomorph/egg.dm | 6 + .../mob/living/carbon/xenomorph/evolution.dm | 6 + .../mob/living/carbon/xenomorph/hive_datum.dm | 23 +- .../living/carbon/xenomorph/hive_upgrades.dm | 16 + .../mob/living/carbon/xenomorph/life.dm | 7 + .../living/carbon/xenomorph/update_icons.dm | 6 + .../living/carbon/xenomorph/xeno_defines.dm | 3 +- modular_RUtgmc/code/modules/mob/mob.dm | 30 + .../modules/mob/mob_transformation_simple.dm | 29 + .../mob/new_player/preferences_setup.dm | 30 + .../modules/mob/new_player/yautja_hair.dm | 40 + .../code/modules/organs/limb_objects.dm | 31 + .../code/modules/projectiles/ammo_datums.dm | 189 + .../code/modules/projectiles/gun_helpers.dm | 6 + .../reagents/machinery/chem_dispenser.dm | 12 + .../reagents/machinery/reagentgrinder.dm | 3 + .../modules/requisitions/supply_export.dm | 3 + .../code/modules/shuttle/marine_dropship.dm | 24 +- .../code/modules/surgery/mcomp_tendwounds.dm | 169 + .../code/modules/surgery/surgery_tools.dm | 114 + .../code/modules/xenomorph/xeno_structures.dm | 67 + .../Xeno/castes/predalien_praetorian.dmi | Bin 0 -> 13488 bytes .../{predalien.dmi => predalien_warrior.dmi} | Bin modular_RUtgmc/icons/Xeno/nest.dmi | Bin 0 -> 966 bytes modular_RUtgmc/icons/mob/screen/yautja.dmi | Bin 0 -> 2461 bytes modular_RUtgmc/icons/obj/hunter/chair.dmi | Bin 0 -> 1734 bytes modular_RUtgmc/icons/obj/stack_objects.dmi | Bin 1445 -> 1515 bytes .../icons/obj/structures/closet.dmi | Bin 0 -> 372 bytes modular_RUtgmc/icons/obj/structures/torch.dmi | Bin 0 -> 1219 bytes modular_RUtgmc/icons/turf/corsat.dmi | Bin 0 -> 60477 bytes modular_RUtgmc/icons/turf/sandstone.dmi | Bin 0 -> 18354 bytes modular_RUtgmc/icons/turf/strata_floor.dmi | Bin 0 -> 6132 bytes modular_RUtgmc/includes.dm | 84 +- .../footstep/alien_footstep_medium1.ogg | Bin 0 -> 25788 bytes .../footstep/alien_footstep_medium2.ogg | Bin 0 -> 29640 bytes .../footstep/alien_footstep_medium3.ogg | Bin 0 -> 31168 bytes tgui/packages/tgui-panel/chat/constants.js | 2 +- .../tgui-panel/styles/tgchat/chat-dark.scss | 67 + .../tgui-panel/styles/tgchat/chat-light.scss | 67 + tgui/packages/tgui/constants.ts | 1 + tgui/packages/tgui/interfaces/ClanMenu.js | 202 + tgui/packages/tgui/interfaces/Orbit/index.tsx | 5 +- tgui/packages/tgui/interfaces/Orbit/types.ts | 1 + .../PlayerPreferences/KeybindSettings.tsx | 6 + .../interfaces/PlayerPreferences/Types.tsx | 25 + .../PlayerPreferences/YautjaCustomization.tsx | 199 + .../interfaces/PlayerPreferences/index.tsx | 30 +- tgui/packages/tgui/styles/colors.scss | 2 + .../tgui/styles/interfaces/ClanMenu.scss | 48 + tgui/packages/tgui/styles/main.scss | 1 + 265 files changed, 20380 insertions(+), 143 deletions(-) create mode 100644 _maps/~RUTGMC/predship/huntership.dmm create mode 100644 code/__DEFINES/~RUtgmc_defines/equipment.dm create mode 100644 code/__DEFINES/~RUtgmc_defines/minimap.dm create mode 100644 code/__DEFINES/~RUtgmc_defines/predators.dm create mode 100644 code/__DEFINES/~RUtgmc_defines/span.dm create mode 100644 config/role_whitelist.txt create mode 100644 modular_RUtgmc/code/__HELPERS/matrices.dm create mode 100644 modular_RUtgmc/code/_onclick/hud/defines.dm create mode 100644 modular_RUtgmc/code/_onclick/hud/yautja.dm create mode 100644 modular_RUtgmc/code/controllers/configuration/entries.dm create mode 100644 modular_RUtgmc/code/controllers/subsystem/dbcore.dm create mode 100644 modular_RUtgmc/code/controllers/subsystem/hunt_system.dm create mode 100644 modular_RUtgmc/code/controllers/subsystem/predships.dm create mode 100644 modular_RUtgmc/code/datums/elements/yautja_tracked_item.dm create mode 100644 modular_RUtgmc/code/datums/flaying.dm create mode 100644 modular_RUtgmc/code/datums/jobs/job/job.dm create mode 100644 modular_RUtgmc/code/datums/jobs/job/pred.dm create mode 100644 modular_RUtgmc/code/game/objects/effects/step_triggers.dm create mode 100644 modular_RUtgmc/code/game/objects/items/card_ids.dm create mode 100644 modular_RUtgmc/code/game/objects/items/reagent_containers/autoinjectors.dm create mode 100644 modular_RUtgmc/code/game/objects/items/reagent_containers/snacks.dm create mode 100644 modular_RUtgmc/code/game/objects/items/stacks/leather.dm create mode 100644 modular_RUtgmc/code/game/objects/items/stacks/sheets/mineral.dm rename modular_RUtgmc/code/game/objects/items/{ => stacks}/sheets/sheet_types.dm (90%) create mode 100644 modular_RUtgmc/code/game/objects/items/stacks/tiles/tile_types.dm create mode 100644 modular_RUtgmc/code/game/objects/items/weapons/weapons.dm create mode 100644 modular_RUtgmc/code/game/objects/machinery/computer/crew.dm create mode 100644 modular_RUtgmc/code/game/objects/machinery/kitchen/gibber.dm create mode 100644 modular_RUtgmc/code/game/objects/structures/bedsheet_bin.dm create mode 100644 modular_RUtgmc/code/game/objects/structures/crates_lockers/secure/freezer.dm create mode 100644 modular_RUtgmc/code/game/objects/structures/stool_bed_chair_nest/chairs.dm create mode 100644 modular_RUtgmc/code/game/objects/yautja_misc.dm create mode 100644 modular_RUtgmc/code/modules/atmospherics/machinery/components/unary_devices/thermomachine.dm create mode 100644 modular_RUtgmc/code/modules/atmospherics/machinery/portable/canister.dm create mode 100644 modular_RUtgmc/code/modules/clans/clan.dm create mode 100644 modular_RUtgmc/code/modules/clans/client.dm create mode 100644 modular_RUtgmc/code/modules/clans/rank.dm create mode 100644 modular_RUtgmc/code/modules/clans/ship.dm create mode 100644 modular_RUtgmc/code/modules/client/preferences.dm create mode 100644 modular_RUtgmc/code/modules/clothing/glasses/meson.dm create mode 100644 modular_RUtgmc/code/modules/clothing/glasses/thermal.dm create mode 100644 modular_RUtgmc/code/modules/cm_preds/_yaut_defines.dm create mode 100644 modular_RUtgmc/code/modules/cm_preds/falcon.dm create mode 100644 modular_RUtgmc/code/modules/cm_preds/huntdata.dm create mode 100644 modular_RUtgmc/code/modules/cm_preds/keybinds.dm create mode 100644 modular_RUtgmc/code/modules/cm_preds/landmakrs.dm create mode 100644 modular_RUtgmc/code/modules/cm_preds/predator_action.dm create mode 100644 modular_RUtgmc/code/modules/cm_preds/smartdisc.dm create mode 100644 modular_RUtgmc/code/modules/cm_preds/thrall_items.dm create mode 100644 modular_RUtgmc/code/modules/cm_preds/thrall_procs.dm create mode 100644 modular_RUtgmc/code/modules/cm_preds/yaut_bracers.dm create mode 100644 modular_RUtgmc/code/modules/cm_preds/yaut_chems.dm create mode 100644 modular_RUtgmc/code/modules/cm_preds/yaut_hudprocs.dm create mode 100644 modular_RUtgmc/code/modules/cm_preds/yaut_items.dm create mode 100644 modular_RUtgmc/code/modules/cm_preds/yaut_machines.dm create mode 100644 modular_RUtgmc/code/modules/cm_preds/yaut_mask.dm create mode 100644 modular_RUtgmc/code/modules/cm_preds/yaut_procs.dm create mode 100644 modular_RUtgmc/code/modules/cm_preds/yaut_shield.dm create mode 100644 modular_RUtgmc/code/modules/cm_preds/yautja_rope.dm create mode 100644 modular_RUtgmc/code/modules/cm_preds/yautja_weapons/misc_weapons.dm create mode 100644 modular_RUtgmc/code/modules/cm_preds/yautja_weapons/one_handed.dm create mode 100644 modular_RUtgmc/code/modules/cm_preds/yautja_weapons/ranged.dm create mode 100644 modular_RUtgmc/code/modules/cm_preds/yautja_weapons/two_handed.dm create mode 100644 modular_RUtgmc/code/modules/language/hellhound.dm create mode 100644 modular_RUtgmc/code/modules/language/yautja.dm create mode 100644 modular_RUtgmc/code/modules/mining/money_bag.dm create mode 100644 modular_RUtgmc/code/modules/mob/dead/observer.dm create mode 100644 modular_RUtgmc/code/modules/mob/hologram.dm create mode 100644 modular_RUtgmc/code/modules/mob/living/carbon/human/emote-yautja.dm create mode 100644 modular_RUtgmc/code/modules/mob/living/carbon/human/update_icons.dm create mode 100644 modular_RUtgmc/code/modules/mob/living/carbon/human/yautja.dm create mode 100644 modular_RUtgmc/code/modules/mob/living/carbon/xenomorph/castes/beetle/beetle.dm create mode 100644 modular_RUtgmc/code/modules/mob/living/carbon/xenomorph/castes/mantis/mantis.dm create mode 100644 modular_RUtgmc/code/modules/mob/living/carbon/xenomorph/castes/scorpion/scorpion.dm create mode 100644 modular_RUtgmc/code/modules/mob/living/carbon/xenomorph/update_icons.dm create mode 100644 modular_RUtgmc/code/modules/mob/mob.dm create mode 100644 modular_RUtgmc/code/modules/mob/mob_transformation_simple.dm create mode 100644 modular_RUtgmc/code/modules/mob/new_player/preferences_setup.dm create mode 100644 modular_RUtgmc/code/modules/mob/new_player/yautja_hair.dm create mode 100644 modular_RUtgmc/code/modules/projectiles/gun_helpers.dm create mode 100644 modular_RUtgmc/code/modules/reagents/machinery/reagentgrinder.dm create mode 100644 modular_RUtgmc/code/modules/surgery/mcomp_tendwounds.dm create mode 100644 modular_RUtgmc/code/modules/surgery/surgery_tools.dm create mode 100644 modular_RUtgmc/icons/Xeno/castes/predalien_praetorian.dmi rename modular_RUtgmc/icons/Xeno/castes/{predalien.dmi => predalien_warrior.dmi} (100%) create mode 100644 modular_RUtgmc/icons/Xeno/nest.dmi create mode 100644 modular_RUtgmc/icons/mob/screen/yautja.dmi create mode 100644 modular_RUtgmc/icons/obj/hunter/chair.dmi create mode 100644 modular_RUtgmc/icons/obj/structures/closet.dmi create mode 100644 modular_RUtgmc/icons/obj/structures/torch.dmi create mode 100644 modular_RUtgmc/icons/turf/corsat.dmi create mode 100644 modular_RUtgmc/icons/turf/sandstone.dmi create mode 100644 modular_RUtgmc/icons/turf/strata_floor.dmi create mode 100644 modular_RUtgmc/sound/effects/footstep/alien_footstep_medium1.ogg create mode 100644 modular_RUtgmc/sound/effects/footstep/alien_footstep_medium2.ogg create mode 100644 modular_RUtgmc/sound/effects/footstep/alien_footstep_medium3.ogg create mode 100644 tgui/packages/tgui/interfaces/ClanMenu.js create mode 100644 tgui/packages/tgui/interfaces/PlayerPreferences/YautjaCustomization.tsx create mode 100644 tgui/packages/tgui/styles/interfaces/ClanMenu.scss diff --git a/SQL/tgmc-schema.sql b/SQL/tgmc-schema.sql index 1885ba0c574cd..235fc63be13e4 100644 --- a/SQL/tgmc-schema.sql +++ b/SQL/tgmc-schema.sql @@ -88,6 +88,25 @@ CREATE TABLE IF NOT EXISTS `connection_log` ( PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; +CREATE TABLE IF NOT EXISTS `clan` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(32) DEFAULT NULL, + `description` varchar(2048) NOT NULL, + `honor` int(11) DEFAULT 0, + `color` varchar(32) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +CREATE TABLE IF NOT EXISTS `clan_player` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `byond_ckey` varchar(32) DEFAULT NULL, + `clan_rank` int(11) DEFAULT 1, + `permissions` int(11) DEFAULT 1, + `clan_id` int(11) DEFAULT 0, + `honor` int(11) DEFAULT 0, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + -- Data exporting was unselected. -- Dumping structure for table feedback.death CREATE TABLE IF NOT EXISTS `death` ( diff --git a/_maps/~RUTGMC/predship/huntership.dmm b/_maps/~RUTGMC/predship/huntership.dmm new file mode 100644 index 0000000000000..68df5cbdcd62d --- /dev/null +++ b/_maps/~RUTGMC/predship/huntership.dmm @@ -0,0 +1,7870 @@ +//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +"aa" = ( +/turf/open/space, +/area/space) +"ab" = ( +/obj/item/skull/king{ + anchored = 1 + }, +/obj/structure/table/reinforced/prison{ + color = "#6b675e"; + resistance_flags = 1 + }, +/turf/open/floor/corsat, +/area/yautja) +"ac" = ( +/obj/structure/shuttle/engine/propulsion/burst/right{ + color = "#aba9a9"; + dir = 1 + }, +/turf/open/space, +/area/yautja) +"ad" = ( +/obj/structure/shuttle/engine/propulsion/burst/left{ + color = "#aba9a9"; + dir = 1 + }, +/turf/open/space, +/area/yautja) +"ae" = ( +/obj/structure/shuttle/engine/propulsion{ + color = "#aba9a9"; + dir = 1 + }, +/turf/open/space, +/area/yautja) +"af" = ( +/turf/closed/wall/cult, +/area/yautja) +"ag" = ( +/turf/open/floor/plating/ground/dirtgrassborder, +/area/yautja) +"ah" = ( +/obj/item/clothing/shoes/marine/yautja/hunter, +/obj/item/clothing/suit/armor/yautja/hunter, +/obj/item/clothing/mask/gas/yautja/hunter, +/obj/machinery/door/window/right{ + dir = 2 + }, +/obj/structure/table/reinforced/prison, +/obj/structure/window/reinforced{ + dir = 4 + }, +/turf/open/floor/sandstone/runed, +/area/yautja) +"ai" = ( +/obj/item/clothing/shoes/marine/yautja/hunter, +/obj/item/clothing/suit/armor/yautja/hunter, +/obj/item/clothing/mask/gas/yautja/hunter, +/obj/machinery/door/window/right{ + dir = 2 + }, +/obj/structure/table/reinforced/prison, +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/structure/window/reinforced{ + dir = 8 + }, +/turf/open/floor/sandstone/runed, +/area/yautja) +"aj" = ( +/obj/item/clothing/shoes/marine/yautja/hunter, +/obj/item/clothing/suit/armor/yautja/hunter, +/obj/item/clothing/mask/gas/yautja/hunter, +/obj/machinery/door/window/right{ + dir = 2 + }, +/obj/structure/table/reinforced/prison, +/obj/structure/window/reinforced{ + dir = 8 + }, +/turf/open/floor/sandstone/runed, +/area/yautja) +"ak" = ( +/obj/machinery/door/window/right{ + dir = 2 + }, +/obj/item/clothing/shoes/marine/yautja/hunter, +/obj/item/clothing/suit/armor/yautja/hunter, +/obj/item/clothing/mask/gas/yautja/hunter, +/obj/structure/table/reinforced/prison, +/obj/structure/window/reinforced{ + dir = 4 + }, +/turf/open/floor/sandstone/runed, +/area/yautja) +"al" = ( +/obj/machinery/door/window/right{ + dir = 2 + }, +/obj/item/clothing/shoes/marine/yautja/hunter, +/obj/item/clothing/suit/armor/yautja/hunter, +/obj/item/clothing/mask/gas/yautja/hunter, +/obj/structure/table/reinforced/prison, +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/structure/window/reinforced{ + dir = 4 + }, +/turf/open/floor/sandstone/runed, +/area/yautja) +"am" = ( +/obj/machinery/door/window/right{ + dir = 2 + }, +/obj/item/clothing/shoes/marine/yautja/hunter, +/obj/item/clothing/suit/armor/yautja/hunter, +/obj/item/clothing/mask/gas/yautja/hunter, +/obj/structure/table/reinforced/prison, +/obj/structure/window/reinforced{ + dir = 8 + }, +/turf/open/floor/sandstone/runed, +/area/yautja) +"an" = ( +/obj/machinery/autodoc/yautja{ + dir = 4 + }, +/turf/open/floor/corsat, +/area/yautja) +"ao" = ( +/obj/item/clothing/yautja_cape/ceremonial{ + anchored = 1; + color = "#292b29"; + pixel_x = 2; + pixel_y = 32 + }, +/obj/item/clothing/shoes/marine/yautja/hunter/pred{ + pixel_y = 29 + }, +/obj/item/clothing/suit/armor/yautja/hunter/pred{ + pixel_y = 30 + }, +/obj/item/clothing/mask/gas/yautja/hunter/pred{ + pixel_y = 29 + }, +/turf/open/floor/corsat, +/area/yautja) +"ap" = ( +/obj/structure/stairs{ + color = "#b29082" + }, +/turf/open/shuttle/dropship/fourteen, +/area/yautja) +"aq" = ( +/obj/item/clothing/yautja_cape/ceremonial{ + anchored = 1; + color = "#292b29"; + pixel_x = 2; + pixel_y = 32 + }, +/obj/item/clothing/shoes/marine/yautja/hunter/pred{ + pixel_y = 30 + }, +/obj/item/clothing/suit/armor/yautja/hunter/pred{ + pixel_y = 30 + }, +/obj/item/clothing/mask/gas/yautja/hunter/pred{ + pixel_y = 30 + }, +/turf/open/floor/corsat, +/area/yautja) +"ar" = ( +/obj/machinery/door/airlock/yautja{ + dir = 1; + name = "\improper Wargear Storage" + }, +/turf/open/shuttle/dropship/fourteen, +/area/yautja) +"at" = ( +/obj/machinery/atmospherics/components/unary/cryo_cell{ + resistance_flags = 1 + }, +/turf/open/floor/corsat, +/area/yautja) +"au" = ( +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/structure/table/reinforced/prison{ + color = "#6b675e"; + resistance_flags = 1 + }, +/turf/open/floor/corsat, +/area/yautja) +"av" = ( +/obj/structure/table/mainship{ + color = "#6b675e"; + resistance_flags = 1 + }, +/obj/item/flashlight/lamp, +/turf/open/floor/corsat, +/area/yautja) +"aw" = ( +/obj/structure/curtain/temple, +/turf/open/shuttle/dropship/fourteen, +/area/yautja) +"ay" = ( +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/machinery/door/window/right{ + dir = 2 + }, +/obj/item/clothing/suit/armor/yautja/thrall, +/obj/item/clothing/mask/gas/yautja/thrall, +/obj/item/clothing/shoes/marine/yautja/thrall, +/obj/item/clothing/under/chainshirt/thrall, +/obj/structure/table/reinforced/prison, +/turf/open/floor/sandstone/runed, +/area/yautja) +"az" = ( +/obj/structure/window/phoronreinforced/pred{ + dir = 10 + }, +/turf/open/floor/light, +/area/yautja) +"aA" = ( +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/machinery/door/window/right{ + dir = 2 + }, +/obj/item/clothing/suit/armor/yautja/thrall, +/obj/item/clothing/mask/gas/yautja/thrall, +/obj/item/clothing/shoes/marine/yautja/thrall, +/obj/item/clothing/under/chainshirt/thrall, +/obj/structure/table/reinforced/prison, +/turf/open/floor/sandstone/runed, +/area/yautja) +"aB" = ( +/obj/effect/decal/cleanable/blood, +/obj/structure/closet/crate{ + color = "#6b675e" + }, +/turf/open/floor/strata/multi_tiles, +/area/yautja) +"aC" = ( +/obj/structure/rack{ + color = "#6b675e"; + layer = 2.79; + resistance_flags = 1 + }, +/obj/item/hunting_trap, +/obj/item/hunting_trap, +/obj/item/hunting_trap, +/obj/item/hunting_trap, +/obj/item/hunting_trap, +/obj/item/hunting_trap, +/obj/item/hunting_trap, +/obj/item/hunting_trap, +/turf/open/floor/corsat, +/area/yautja) +"aD" = ( +/obj/structure/xenoautopsy/tank/hugger/yautja, +/turf/open/floor/corsat, +/area/yautja) +"aE" = ( +/obj/structure/table/reinforced/prison{ + color = "#6b675e"; + resistance_flags = 1 + }, +/obj/item/tool/surgery/cautery/predatorcautery, +/obj/item/tool/surgery/circular_saw/predatorbonesaw, +/obj/item/tool/surgery/hemostat/predatorhemostat, +/obj/item/tool/surgery/retractor/predatorretractor, +/obj/item/tool/surgery/scalpel/predatorscalpel, +/turf/open/floor/corsat, +/area/yautja) +"aF" = ( +/obj/item/clothing/gloves/yautja/hunter{ + anchored = 1; + charge = 1; + charge_max = 1; + color = "#a8a7a5"; + density = 1; + desc = "The ship's on-board self destruct system, let's hope you never have to use it."; + name = "Self Destruct System" + }, +/turf/open/floor/strata/multi_tiles, +/area/yautja) +"aG" = ( +/obj/machinery/power/smes/magical{ + capacity = 9e+008; + charge = 9e+008; + dir = 4; + name = "plasma power generator" + }, +/turf/open/floor/corsat, +/area/yautja) +"aI" = ( +/obj/structure/shuttle/engine/heater{ + dir = 1 + }, +/obj/item/flashlight/slime, +/obj/structure/window/phoronreinforced{ + resistance_flags = 1 + }, +/obj/structure/window/phoronreinforced/pred{ + dir = 8 + }, +/turf/open/floor/corsat, +/area/yautja) +"aK" = ( +/obj/structure/shuttle/engine/heater{ + dir = 1 + }, +/obj/item/flashlight/slime, +/obj/structure/window/phoronreinforced{ + resistance_flags = 1 + }, +/obj/structure/window/phoronreinforced/pred{ + dir = 4 + }, +/turf/open/floor/corsat, +/area/yautja) +"aL" = ( +/obj/machinery/power/terminal{ + dir = 1 + }, +/turf/open/floor/corsat, +/area/yautja) +"aP" = ( +/obj/machinery/door/airlock/yautja{ + dir = 1; + name = "\improper Trophy Room" + }, +/turf/open/shuttle/dropship/fourteen, +/area/yautja) +"aQ" = ( +/obj/structure/table/reinforced/prison{ + color = "#6b675e"; + resistance_flags = 1 + }, +/obj/item/tool/surgery/FixOVein/predatorFixOVein, +/obj/item/tool/surgery/bonegel/predatorbonegel, +/obj/item/tool/surgery/bonesetter/predatorbonesetter, +/obj/item/tool/surgery/surgicaldrill/predatorsurgicaldrill, +/turf/open/floor/corsat, +/area/yautja) +"aT" = ( +/obj/machinery/door/airlock/yautja{ + name = "\improper Operation Room" + }, +/turf/open/shuttle/dropship/fourteen, +/area/yautja) +"aV" = ( +/obj/structure/rack{ + color = "#6b675e"; + layer = 2.79; + resistance_flags = 1 + }, +/obj/item/weapon/yautja/knife, +/turf/open/floor/corsat, +/area/yautja) +"aW" = ( +/obj/machinery/optable/yautja, +/turf/open/floor/corsat, +/area/yautja) +"aX" = ( +/obj/structure/table/reinforced/prison{ + color = "#6b675e"; + resistance_flags = 1 + }, +/obj/effect/decal/remains/xeno{ + pixel_x = -31 + }, +/obj/structure/showcase/yautja{ + dir = 8; + pixel_x = -1 + }, +/turf/open/floor/strata/multi_tiles, +/area/yautja) +"aY" = ( +/obj/machinery/portable_atmospherics/canister/oxygen/pred, +/turf/open/floor/corsat, +/area/yautja) +"bc" = ( +/obj/machinery/cryopod{ + dir = 1 + }, +/turf/open/floor/strata/multi_tiles, +/area/yautja) +"bd" = ( +/obj/effect/step_trigger/teleporter/yautja_ship, +/turf/open/floor/light, +/area/yautja) +"bg" = ( +/obj/structure/rack{ + color = "#6b675e"; + layer = 2.79; + resistance_flags = 1 + }, +/obj/item/stack/sheet/mineral/sandstone{ + amount = 50 + }, +/obj/item/stack/sheet/mineral/sandstone{ + amount = 50 + }, +/obj/item/stack/sheet/mineral/sandstone{ + amount = 50 + }, +/obj/item/stack/sheet/mineral/sandstone{ + amount = 50 + }, +/obj/item/stack/sheet/mineral/sandstone{ + amount = 50 + }, +/turf/open/floor/corsat, +/area/yautja) +"bj" = ( +/turf/closed/wall/huntership, +/area/yautja) +"bl" = ( +/obj/machinery/door/airlock/yautja{ + name = "\improper Starboard Wing" + }, +/turf/open/shuttle/dropship/fourteen, +/area/yautja) +"bm" = ( +/obj/machinery/door/airlock/yautja{ + name = "\improper Port Wing" + }, +/turf/open/shuttle/dropship/fourteen, +/area/yautja) +"bn" = ( +/obj/structure/rack{ + color = "#6b675e"; + layer = 2.79; + resistance_flags = 1 + }, +/obj/item/weapon/harpoon/yautja, +/obj/item/weapon/harpoon/yautja, +/obj/item/weapon/harpoon/yautja, +/obj/item/weapon/harpoon/yautja, +/turf/open/floor/corsat, +/area/yautja) +"bp" = ( +/obj/machinery/door/airlock/yautja{ + dir = 1; + name = "\improper Research Chamber" + }, +/turf/open/shuttle/dropship/fourteen, +/area/yautja) +"bq" = ( +/obj/structure/table/mainship{ + color = "#6b675e"; + resistance_flags = 1 + }, +/turf/open/floor/corsat, +/area/yautja) +"br" = ( +/obj/item/stool, +/turf/open/shuttle/dropship/fourteen, +/area/yautja) +"bs" = ( +/obj/machinery/bodyscanner{ + dir = 1; + resistance_flags = 1 + }, +/turf/open/floor/corsat, +/area/yautja) +"bu" = ( +/obj/machinery/door/airlock/yautja/secure{ + dir = 2; + name = "\improper Burial Room" + }, +/turf/open/shuttle/dropship/fourteen, +/area/yautja) +"bv" = ( +/obj/structure/closet/coffin/predator, +/turf/open/floor/corsat, +/area/yautja) +"bx" = ( +/obj/machinery/door/airlock/yautja{ + dir = 1; + name = "\improper Storage Chamber" + }, +/turf/open/shuttle/dropship/fourteen, +/area/yautja) +"by" = ( +/obj/effect/decal/remains/human, +/obj/alien/egg/hugger/forsaken, +/turf/open/floor/strata/multi_tiles, +/area/yautja) +"bz" = ( +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/structure/window/reinforced, +/obj/structure/table/reinforced/prison{ + color = "#6b675e"; + resistance_flags = 1 + }, +/turf/open/floor/corsat, +/area/yautja) +"bA" = ( +/obj/machinery/chem_dispenser/pred, +/turf/open/floor/corsat, +/area/yautja) +"bD" = ( +/obj/machinery/door/airlock/yautja/secure{ + dir = 2; + name = "\improper Heavy Armory" + }, +/obj/machinery/door/poddoor/shutters/almayer/yautja{ + name = "Yautja Armory"; + dir = 2 + }, +/turf/open/shuttle/dropship/fourteen, +/area/yautja) +"bE" = ( +/obj/structure/stairs/seamless{ + color = "#6b675e"; + resistance_flags = 1 + }, +/turf/open/floor/corsat, +/area/yautja) +"bG" = ( +/obj/machinery/door/airlock/yautja{ + name = "\improper Cooler Room" + }, +/turf/open/shuttle/dropship/fourteen, +/area/yautja) +"bI" = ( +/obj/structure/stairs/seamless{ + dir = 1; + color = "#6b675e"; + resistance_flags = 1 + }, +/turf/open/floor/corsat, +/area/yautja) +"bL" = ( +/turf/open/floor/corsat, +/area/yautja) +"bM" = ( +/obj/structure/table/mainship{ + color = "#6b675e"; + resistance_flags = 1 + }, +/obj/machinery/processor/yautja{ + pixel_y = 4 + }, +/turf/open/floor/strata/multi_tiles, +/area/yautja) +"bN" = ( +/obj/structure/rack{ + color = "#6b675e"; + layer = 2.79; + resistance_flags = 1 + }, +/obj/item/weapon/gun/energy/yautja/plasmapistol{ + pixel_y = -7 + }, +/obj/item/weapon/gun/energy/yautja/plasmapistol, +/obj/item/weapon/gun/energy/yautja/plasmapistol{ + pixel_y = 7 + }, +/turf/open/floor/strata/multi_tiles, +/area/yautja) +"bO" = ( +/obj/structure/bed/pred/alt, +/turf/open/floor/corsat, +/area/yautja) +"bR" = ( +/obj/structure/table/reinforced/prison{ + color = "#6b675e"; + resistance_flags = 1 + }, +/obj/item/reagent_containers/glass/beaker/noreact{ + pixel_y = -16; + pixel_x = 6 + }, +/obj/item/reagent_containers/glass/beaker/large{ + pixel_y = 4 + }, +/turf/open/floor/corsat, +/area/yautja) +"bU" = ( +/obj/structure/closet/secure_closet/freezer/kitchen/yautja, +/turf/open/floor/tile/dark/red2{ + dir = 4 + }, +/area/yautja) +"bV" = ( +/obj/effect/turf_decal/lvsanddecal/full, +/obj/effect/turf_decal/lvsanddecal/full, +/obj/effect/turf_decal/lvsanddecal/full, +/obj/effect/turf_decal/lvsanddecal/full, +/obj/effect/turf_decal/lvsanddecal/full, +/turf/open/beach/sand, +/area/yautja) +"bW" = ( +/obj/machinery/door/poddoor/shutters/almayer/yautja{ + dir = 4; + id = "Cell Lockdown 1"; + name = "\improper Cell Shutters" + }, +/obj/machinery/door/airlock/yautja{ + name = "\improper Prisoner Cell 1"; + opacity = 0 + }, +/turf/open/shuttle/dropship/fourteen, +/area/yautja) +"bX" = ( +/obj/machinery/door/poddoor/shutters/almayer/yautja{ + dir = 4; + id = "Cell Lockdown 4"; + name = "\improper Cell Shutters" + }, +/obj/machinery/door/airlock/yautja{ + name = "\improper Prisoner Cell 4"; + opacity = 0 + }, +/turf/open/shuttle/dropship/fourteen, +/area/yautja) +"bY" = ( +/obj/structure/table/reinforced/prison{ + color = "#6b675e"; + resistance_flags = 1 + }, +/obj/item/stack/sheet/xenochitin{ + pixel_y = -17; + pixel_x = -7 + }, +/obj/item/stack/sheet/xenochitin{ + pixel_y = -13 + }, +/obj/structure/xenoautopsy{ + pixel_y = 10 + }, +/turf/open/floor/corsat, +/area/yautja) +"cb" = ( +/obj/structure/table/mainship{ + color = "#6b675e"; + resistance_flags = 1 + }, +/obj/item/storage/box/drinkingglasses{ + pixel_y = 6; + pixel_x = -9 + }, +/obj/item/book/manual/barman_recipes{ + pixel_x = 9; + pixel_y = 7 + }, +/turf/open/floor/strata/multi_tiles, +/area/yautja) +"ce" = ( +/obj/machinery/door/poddoor/shutters/almayer/yautja{ + dir = 4; + id = "Cell Lockdown 2"; + name = "\improper Cell Shutters" + }, +/obj/machinery/door/airlock/yautja{ + name = "\improper Prisoner Cell 2"; + opacity = 0 + }, +/turf/open/shuttle/dropship/fourteen, +/area/yautja) +"cf" = ( +/obj/machinery/door/poddoor/shutters/almayer/yautja{ + dir = 4; + id = "Cell Lockdown 5"; + name = "\improper Cell Shutters" + }, +/obj/machinery/door/airlock/yautja{ + name = "\improper Prisoner Cell 5"; + opacity = 0 + }, +/turf/open/shuttle/dropship/fourteen, +/area/yautja) +"cg" = ( +/obj/machinery/door_control{ + id = "Cell Lockdown 6"; + name = "Cell Lockdown 6"; + pixel_x = -7; + pixel_y = 9; + dir = 8 + }, +/turf/open/floor/strata/multi_tiles, +/area/yautja) +"cj" = ( +/obj/machinery/sleeper{ + resistance_flags = 1 + }, +/turf/open/floor/corsat, +/area/yautja) +"cl" = ( +/obj/structure/table/reinforced/prison{ + color = "#6b675e"; + resistance_flags = 1 + }, +/obj/item/alienjar, +/turf/open/floor/corsat, +/area/yautja) +"cm" = ( +/obj/machinery/door/poddoor/shutters/almayer/yautja{ + dir = 4; + id = "Cell Lockdown 3"; + name = "\improper Cell Shutters" + }, +/obj/machinery/door/airlock/yautja{ + name = "\improper Prisoner Cell 3"; + opacity = 0 + }, +/turf/open/shuttle/dropship/fourteen, +/area/yautja) +"cn" = ( +/obj/machinery/door/poddoor/shutters/almayer/yautja{ + dir = 4; + id = "Cell Lockdown 6"; + name = "\improper Cell Shutters" + }, +/obj/machinery/door/airlock/yautja{ + name = "\improper Prisoner Cell 6"; + opacity = 0 + }, +/turf/open/shuttle/dropship/fourteen, +/area/yautja) +"cr" = ( +/obj/structure/table/mainship{ + color = "#6b675e"; + resistance_flags = 1 + }, +/obj/machinery/chem_dispenser/soda/pred{ + dir = 8; + pixel_y = 7 + }, +/turf/open/floor/strata/multi_tiles, +/area/yautja) +"ct" = ( +/obj/machinery/door/airlock/yautja{ + dir = 1; + name = "\improper Fore Rooms" + }, +/turf/open/shuttle/dropship/fourteen, +/area/yautja) +"cu" = ( +/obj/structure/closet/secure_closet/freezer/meat/yautja, +/obj/item/reagent_containers/food/snacks/rawmeatball, +/obj/item/reagent_containers/food/snacks/rawmeatball, +/obj/item/reagent_containers/food/snacks/rawmeatball, +/obj/item/reagent_containers/food/snacks/rawmeatball, +/obj/item/reagent_containers/food/snacks/rawmeatball, +/obj/item/reagent_containers/food/snacks/rawmeatball, +/obj/item/reagent_containers/food/snacks/rawmeatball, +/turf/open/floor/tile/dark/red2{ + dir = 10 + }, +/area/yautja) +"cv" = ( +/obj/structure/table/mainship{ + color = "#6b675e"; + resistance_flags = 1 + }, +/obj/item/tool/kitchen/rollingpin{ + pixel_y = 10 + }, +/obj/item/tool/kitchen/knife{ + pixel_x = -5 + }, +/obj/item/reagent_containers/food/condiment/saltshaker, +/obj/item/reagent_containers/food/condiment/peppermill{ + pixel_y = 11; + pixel_x = 9 + }, +/turf/open/floor/strata/multi_tiles, +/area/yautja) +"cw" = ( +/obj/structure/table/reinforced/prison{ + color = "#6b675e"; + resistance_flags = 1 + }, +/obj/item/clothing/mask/muzzle, +/obj/item/clothing/mask/muzzle, +/obj/item/clothing/mask/muzzle, +/obj/item/clothing/mask/muzzle, +/obj/item/clothing/mask/muzzle, +/obj/item/clothing/mask/muzzle, +/obj/item/restraints/handcuffs/cable{ + pixel_x = 14 + }, +/turf/open/shuttle/dropship/fourteen, +/area/yautja) +"cz" = ( +/obj/item/skull/deacon{ + pixel_y = -1; + anchored = 1 + }, +/obj/structure/table/reinforced/prison{ + color = "#6b675e"; + resistance_flags = 1 + }, +/turf/open/floor/corsat, +/area/yautja) +"cA" = ( +/obj/machinery/door/airlock/yautja{ + name = "\improper Elder Teleporter" + }, +/turf/open/floor/corsat, +/area/yautja) +"cB" = ( +/obj/machinery/door/airlock/yautja{ + dir = 1; + name = "\improper Navigation Chamber" + }, +/turf/open/shuttle/dropship/fourteen, +/area/yautja) +"cC" = ( +/obj/machinery/vending/engivend/yautja, +/turf/open/floor/corsat, +/area/yautja) +"cF" = ( +/obj/machinery/door/airlock/yautja{ + dir = 1; + name = "\improper Engine Room" + }, +/turf/open/shuttle/dropship/fourteen, +/area/yautja) +"cG" = ( +/obj/structure/stairs/seamless/pred{ + dir = 8; + resistance_flags = 1 + }, +/turf/open/floor/strata/multi_tiles, +/area/yautja) +"cJ" = ( +/obj/structure/table/mainship{ + color = "#6b675e"; + resistance_flags = 1 + }, +/obj/machinery/reagentgrinder/yautja{ + pixel_y = 6 + }, +/turf/open/floor/strata/multi_tiles, +/area/yautja) +"cK" = ( +/obj/structure/rack{ + color = "#6b675e"; + layer = 2.79; + resistance_flags = 1 + }, +/obj/item/weapon/claymore/mercsword{ + attack_speed = 12; + force = 25; + pixel_x = 12 + }, +/obj/item/weapon/claymore/mercsword{ + attack_speed = 12; + force = 25; + pixel_x = 8 + }, +/obj/item/weapon/claymore/mercsword{ + attack_speed = 12; + force = 25; + pixel_x = 4 + }, +/obj/item/weapon/claymore/mercsword{ + attack_speed = 12; + force = 25; + pixel_x = -4 + }, +/obj/item/weapon/claymore/mercsword{ + attack_speed = 12; + force = 25; + pixel_x = -12 + }, +/obj/item/weapon/claymore/mercsword{ + attack_speed = 12; + force = 25 + }, +/obj/item/weapon/claymore/mercsword{ + attack_speed = 12; + force = 25; + pixel_x = -8 + }, +/turf/open/shuttle/dropship/fourteen, +/area/yautja) +"cN" = ( +/obj/structure/cryofeed, +/turf/open/floor/corsat, +/area/yautja) +"cO" = ( +/obj/structure/cryofeed/right, +/turf/open/floor/corsat, +/area/yautja) +"cP" = ( +/turf/open/shuttle/dropship/fourteen, +/area/yautja) +"cQ" = ( +/obj/structure/rack{ + color = "#6b675e"; + layer = 2.79; + resistance_flags = 1 + }, +/obj/item/stack/sheet/mineral/sandstone/runed{ + amount = 50 + }, +/obj/item/stack/sheet/mineral/sandstone/runed{ + amount = 50 + }, +/obj/item/stack/sheet/mineral/sandstone/runed{ + amount = 50 + }, +/obj/item/stack/sheet/mineral/sandstone/runed{ + amount = 50 + }, +/obj/item/stack/sheet/mineral/sandstone/runed{ + amount = 50 + }, +/turf/open/floor/corsat, +/area/yautja) +"cR" = ( +/obj/structure/table/reinforced/prison{ + color = "#6b675e"; + resistance_flags = 1 + }, +/obj/effect/decal/remains/xeno{ + pixel_x = 33 + }, +/obj/structure/showcase/yautja{ + dir = 4 + }, +/turf/open/floor/strata/multi_tiles, +/area/yautja) +"cS" = ( +/obj/structure/table/reinforced/prison{ + color = "#6b675e"; + resistance_flags = 1 + }, +/obj/item/clothing/shoes/combat, +/obj/item/clothing/under/chainshirt/hunter, +/obj/item/clothing/gloves/combat, +/obj/item/clothing/head/helmet/gladiator, +/obj/item/clothing/under/gladiator, +/turf/open/floor/corsat, +/area/yautja) +"cT" = ( +/obj/structure/rack{ + color = "#6b675e"; + layer = 2.79; + resistance_flags = 1 + }, +/obj/item/tool/pickaxe, +/turf/open/floor/corsat, +/area/yautja) +"cU" = ( +/obj/structure/rack{ + color = "#6b675e"; + layer = 2.79; + resistance_flags = 1 + }, +/obj/item/tool/extinguisher, +/turf/open/floor/corsat, +/area/yautja) +"cV" = ( +/obj/structure/table/mainship{ + color = "#6b675e"; + resistance_flags = 1 + }, +/obj/item/tool/weldingtool/yautja{ + pixel_y = 5 + }, +/turf/open/floor/corsat, +/area/yautja) +"cW" = ( +/obj/structure/table/mainship{ + color = "#6b675e"; + resistance_flags = 1 + }, +/obj/item/stack/cable_coil, +/obj/item/tool/screwdriver/yautja{ + pixel_y = 10; + pixel_x = -9 + }, +/turf/open/floor/corsat, +/area/yautja) +"cX" = ( +/obj/item/flashlight/lantern, +/obj/item/flashlight/lantern, +/obj/item/flashlight/lantern, +/obj/item/flashlight/lantern, +/obj/item/flashlight/lantern, +/obj/item/clothing/under/chainshirt/hunter, +/obj/item/clothing/under/chainshirt/hunter, +/obj/item/clothing/under/chainshirt/hunter, +/obj/structure/rack{ + color = "#6b675e"; + layer = 2.79; + resistance_flags = 1 + }, +/obj/item/storage/belt/yautja, +/obj/item/storage/belt/yautja, +/obj/item/storage/belt/yautja, +/obj/item/storage/belt/yautja, +/turf/open/floor/corsat, +/area/yautja) +"cY" = ( +/obj/item/tool/kitchen/tray{ + pixel_y = -3 + }, +/obj/effect/decal/cleanable/blood, +/turf/open/floor/strata/multi_tiles, +/area/yautja) +"cZ" = ( +/obj/structure/table/reinforced/prison{ + color = "#6b675e"; + resistance_flags = 1 + }, +/obj/item/weapon/claymore/mercsword/machete/arnold, +/turf/open/floor/corsat, +/area/yautja) +"da" = ( +/obj/structure/table/mainship{ + color = "#6b675e"; + resistance_flags = 1 + }, +/obj/machinery/microwave/yautja, +/turf/open/floor/strata/multi_tiles, +/area/yautja) +"db" = ( +/obj/structure/rack{ + color = "#6b675e"; + layer = 2.79; + resistance_flags = 1 + }, +/obj/item/tool/pickaxe/jackhammer, +/turf/open/floor/corsat, +/area/yautja) +"dc" = ( +/obj/machinery/door/airlock/yautja{ + dir = 1; + name = "\improper Research Containment" + }, +/turf/open/floor/strata/multi_tiles, +/area/yautja) +"de" = ( +/obj/structure/kitchenspike, +/obj/item/reagent_containers/food/snacks/meat/xenomeat{ + pixel_y = -3 + }, +/obj/item/reagent_containers/food/snacks/meat/xenomeat{ + pixel_y = 8; + pixel_x = 5 + }, +/obj/item/reagent_containers/food/snacks/meat/xenomeat{ + pixel_y = 8; + pixel_x = -3 + }, +/turf/open/floor/tile/dark/red2{ + dir = 5 + }, +/area/yautja) +"df" = ( +/obj/structure/table/mainship{ + color = "#6b675e"; + resistance_flags = 1 + }, +/obj/item/flashlight/lantern{ + pixel_y = 6 + }, +/turf/open/floor/corsat, +/area/yautja) +"di" = ( +/obj/item/storage/fancy/egg_box, +/obj/item/storage/fancy/egg_box, +/obj/structure/closet/secure_closet/freezer/fridge/yautja, +/turf/open/floor/tile/dark/red2{ + dir = 1 + }, +/area/yautja) +"dk" = ( +/obj/structure/stairs/seamless/pred{ + dir = 1 + }, +/turf/open/floor/strata/multi_tiles, +/area/yautja) +"dl" = ( +/obj/structure/stairs/seamless{ + color = "#6b675e" + }, +/turf/open/floor/strata/multi_tiles, +/area/yautja) +"dm" = ( +/obj/effect/turf_decal/lvsanddecal/full, +/obj/effect/turf_decal/lvsanddecal/full, +/obj/effect/turf_decal/lvsanddecal/full, +/obj/effect/turf_decal/lvsanddecal/full, +/turf/open/beach/sand, +/area/yautja) +"dI" = ( +/turf/open/space/basic, +/area/space) +"dP" = ( +/obj/item/explosive/grenade/spawnergrenade/hellhound, +/obj/item/explosive/grenade/spawnergrenade/hellhound, +/obj/item/explosive/grenade/spawnergrenade/hellhound, +/obj/item/explosive/grenade/spawnergrenade/hellhound, +/obj/structure/closet/crate/secure{ + color = "#6b675e"; + name = "Secure Yautja crate"; + req_one_access = list(252) + }, +/turf/open/floor/strata/multi_tiles, +/area/yautja) +"eg" = ( +/obj/effect/turf_decal/lvsanddecal/full, +/obj/effect/turf_decal/lvsanddecal/full, +/turf/open/beach/sand, +/area/yautja) +"er" = ( +/obj/structure/stairs/seamless/pred{ + dir = 8; + resistance_flags = 1 + }, +/turf/open/floor/corsat, +/area/yautja) +"eA" = ( +/obj/structure/table/reinforced/prison{ + color = "#6b675e"; + resistance_flags = 1 + }, +/obj/item/xenos_claw{ + pixel_y = 4; + anchored = 1 + }, +/turf/open/floor/corsat, +/area/yautja) +"eS" = ( +/obj/item/skull/warrior{ + pixel_y = 33; + anchored = 1 + }, +/turf/open/shuttle/dropship/fourteen, +/area/yautja) +"eT" = ( +/obj/structure/stairs/seamless/pred{ + dir = 4; + resistance_flags = 1 + }, +/turf/open/floor/corsat, +/area/yautja) +"eY" = ( +/obj/structure/bed/chair/comfy/black/pred, +/turf/open/shuttle/dropship/fourteen, +/area/yautja) +"fb" = ( +/turf/open/floor/tile/dark/red2{ + dir = 4 + }, +/area/yautja) +"fg" = ( +/obj/structure/prop/brazier/torch{ + pixel_y = 33 + }, +/turf/open/shuttle/dropship/fourteen, +/area/yautja) +"fj" = ( +/obj/machinery/cryopod, +/turf/open/shuttle/dropship/fourteen, +/area/yautja) +"fk" = ( +/obj/structure/table/reinforced/prison{ + color = "#6b675e"; + resistance_flags = 1 + }, +/obj/item/weapon/twohanded/rocketsledge{ + anchored = 1; + pixel_x = 2; + pixel_y = 4 + }, +/turf/open/floor/corsat, +/area/yautja) +"fq" = ( +/obj/structure/window/framed/colony/reinforced/hull/pred, +/turf/open/shuttle/dropship/fourteen, +/area/yautja) +"fv" = ( +/obj/structure/table/reinforced/prison{ + color = "#6b675e"; + resistance_flags = 1 + }, +/turf/open/floor/strata/multi_tiles, +/area/yautja) +"fx" = ( +/obj/machinery/computer/crew/pred{ + pixel_y = 28; + density = 0; + resistance_flags = 1 + }, +/turf/open/floor/corsat, +/area/yautja) +"fF" = ( +/obj/structure/rack{ + color = "#6b675e"; + layer = 2.79; + resistance_flags = 1 + }, +/obj/item/tool/hatchet{ + attack_speed = 12; + name = "duelling hatchet"; + pixel_x = -7; + pixel_y = -1 + }, +/obj/item/tool/hatchet{ + attack_speed = 12; + name = "duelling hatchet"; + pixel_x = -3; + pixel_y = 2 + }, +/obj/item/tool/hatchet{ + attack_speed = 12; + name = "duelling hatchet"; + pixel_x = 2; + pixel_y = 5 + }, +/obj/item/tool/hatchet{ + attack_speed = 12; + name = "duelling hatchet"; + pixel_x = 6; + pixel_y = 7 + }, +/turf/open/floor/strata/multi_tiles, +/area/yautja) +"gb" = ( +/obj/structure/closet/crate{ + color = "#6b675e" + }, +/obj/item/stack/medical/heal_pack/advanced/bruise_pack/predator{ + pixel_x = 6 + }, +/obj/item/stack/medical/heal_pack/ointment/predator{ + pixel_x = -6 + }, +/obj/item/stack/medical/heal_pack/ointment/predator{ + pixel_x = -6 + }, +/obj/item/stack/medical/heal_pack/ointment/predator{ + pixel_x = -6 + }, +/obj/item/stack/medical/heal_pack/ointment/predator{ + pixel_x = -6 + }, +/obj/item/stack/medical/heal_pack/ointment/predator{ + pixel_x = -6 + }, +/obj/item/stack/medical/heal_pack/ointment/predator{ + pixel_x = -6 + }, +/obj/item/stack/medical/heal_pack/ointment/predator{ + pixel_x = -6 + }, +/obj/item/stack/medical/heal_pack/ointment/predator{ + pixel_x = -6 + }, +/obj/item/stack/medical/heal_pack/advanced/bruise_pack/predator{ + pixel_x = 6 + }, +/obj/item/stack/medical/heal_pack/advanced/bruise_pack/predator{ + pixel_x = 6 + }, +/obj/item/stack/medical/heal_pack/advanced/bruise_pack/predator{ + pixel_x = 6 + }, +/obj/item/stack/medical/heal_pack/advanced/bruise_pack/predator{ + pixel_x = 6 + }, +/obj/item/stack/medical/heal_pack/advanced/bruise_pack/predator{ + pixel_x = 6 + }, +/obj/item/stack/medical/heal_pack/advanced/bruise_pack/predator{ + pixel_x = 6 + }, +/turf/open/floor/strata/multi_tiles, +/area/yautja) +"ge" = ( +/obj/machinery/door_control{ + id = "Cell Lockdown 4"; + name = "Cell Lockdown 4"; + pixel_x = -7; + pixel_y = 9; + dir = 8 + }, +/turf/open/floor/strata/multi_tiles, +/area/yautja) +"gp" = ( +/obj/structure/bed/chair/comfy/black/pred, +/turf/open/floor/corsat, +/area/yautja) +"gG" = ( +/obj/machinery/door_control/mainship{ + dir = 4; + id = "Yautja Armory"; + name = "Yautja Armory"; + req_one_access = list(252); + pixel_x = -7; + pixel_y = 11 + }, +/turf/open/floor/corsat, +/area/yautja) +"hI" = ( +/obj/structure/shuttle/window{ + color = "#6b675e" + }, +/turf/open/floor/tile/dark2, +/area/yautja) +"hR" = ( +/obj/machinery/computer/autodoc_console/pred, +/turf/open/floor/corsat, +/area/yautja) +"hV" = ( +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/structure/table/reinforced/prison{ + color = "#6b675e"; + resistance_flags = 1 + }, +/obj/item/reagent_containers/glass/rag/polishing_rag, +/turf/open/floor/corsat, +/area/yautja) +"il" = ( +/obj/machinery/door/window/right{ + dir = 2 + }, +/obj/item/clothing/suit/armor/yautja/thrall, +/obj/item/clothing/mask/gas/yautja/thrall, +/obj/item/clothing/shoes/marine/yautja/thrall, +/obj/item/clothing/under/chainshirt/thrall, +/obj/structure/table/reinforced/prison, +/obj/structure/window/reinforced{ + dir = 4 + }, +/turf/open/floor/sandstone/runed, +/area/yautja) +"is" = ( +/obj/structure/kitchenspike, +/obj/item/reagent_containers/food/snacks/bearmeat{ + pixel_y = 8; + pixel_x = -3 + }, +/obj/item/clothing/head/ushanka, +/obj/item/clothing/glasses/sunglasses/fake, +/obj/item/reagent_containers/food/snacks/bearmeat{ + pixel_y = 1; + pixel_x = -2 + }, +/obj/item/reagent_containers/food/snacks/bearmeat{ + pixel_y = 8; + pixel_x = -3 + }, +/obj/item/reagent_containers/food/snacks/bearmeat{ + pixel_y = 4; + pixel_x = 4 + }, +/obj/item/reagent_containers/food/snacks/bearmeat{ + pixel_y = -5 + }, +/obj/item/reagent_containers/hypospray/autoinjector/medicalnanites{ + layer = 2 + }, +/turf/open/floor/tile/dark/red2{ + dir = 8 + }, +/area/yautja) +"iV" = ( +/obj/structure/table/mainship{ + color = "#6b675e"; + resistance_flags = 1 + }, +/obj/item/trash/tray, +/obj/item/tool/kitchen/utensil/fork{ + pixel_x = 10; + pixel_y = 3 + }, +/turf/open/floor/corsat, +/area/yautja) +"ja" = ( +/obj/structure/barricade/metal/handrail{ + dir = 8 + }, +/turf/open/floor/plating/ground/dirtgrassborder{ + dir = 4 + }, +/area/yautja) +"jl" = ( +/obj/structure/table/reinforced/prison{ + color = "#6b675e"; + resistance_flags = 1 + }, +/obj/structure/window/reinforced, +/turf/open/floor/corsat, +/area/yautja) +"jy" = ( +/obj/structure/table/reinforced/prison{ + color = "#6b675e"; + resistance_flags = 1 + }, +/obj/item/flashlight/lantern{ + pixel_y = 6 + }, +/turf/open/floor/corsat, +/area/yautja) +"jP" = ( +/obj/structure/rack{ + color = "#6b675e"; + layer = 2.79; + resistance_flags = 1 + }, +/obj/item/weapon/claymore{ + attack_speed = 12; + force = 25; + name = "duelling claymore" + }, +/obj/item/weapon/claymore{ + attack_speed = 12; + force = 25; + name = "duelling claymore"; + pixel_x = -5 + }, +/obj/item/weapon/claymore{ + attack_speed = 12; + force = 25; + name = "duelling claymore"; + pixel_x = 5 + }, +/obj/item/weapon/claymore{ + attack_speed = 12; + force = 25; + name = "duelling claymore"; + pixel_x = 10 + }, +/turf/open/floor/strata/multi_tiles, +/area/yautja) +"kA" = ( +/obj/item/weapon/twohanded/dualsaber{ + force_wielded = 20; + anchored = 1 + }, +/obj/structure/table/reinforced/prison{ + color = "#6b675e"; + resistance_flags = 1 + }, +/turf/open/floor/corsat, +/area/yautja) +"kF" = ( +/obj/structure/table/reinforced/prison{ + color = "#6b675e"; + resistance_flags = 1 + }, +/obj/item/research_resource/xeno/tier_three, +/turf/open/floor/strata/multi_tiles, +/area/yautja) +"lr" = ( +/obj/structure/table/mainship{ + color = "#6b675e"; + resistance_flags = 1 + }, +/obj/item/book/manual/chef_recipes{ + pixel_y = 10; + pixel_x = 6 + }, +/obj/item/reagent_containers/spray/cleaner{ + pixel_x = -9; + pixel_y = 6 + }, +/turf/open/shuttle/dropship/fourteen, +/area/yautja) +"lu" = ( +/obj/structure/barricade/metal/handrail{ + dir = 8 + }, +/obj/structure/barricade/metal/handrail, +/turf/open/floor/plating/ground/dirtgrassborder/corner{ + dir = 8 + }, +/area/yautja) +"ly" = ( +/obj/structure/table/reinforced/prison{ + color = "#6b675e"; + resistance_flags = 1 + }, +/turf/open/floor/corsat, +/area/yautja) +"mb" = ( +/obj/machinery/door_control{ + id = "Cell Lockdown 3"; + name = "Cell Lockdown 3"; + pixel_y = 9; + pixel_x = 7; + dir = 4 + }, +/turf/open/floor/strata/multi_tiles, +/area/yautja) +"mj" = ( +/obj/structure/barricade/metal/handrail{ + dir = 4 + }, +/obj/structure/barricade/metal/handrail, +/turf/open/ground/grass, +/area/yautja) +"mv" = ( +/obj/item/weapon/katana{ + anchored = 1 + }, +/obj/structure/table/reinforced/prison{ + color = "#6b675e"; + resistance_flags = 1 + }, +/turf/open/floor/corsat, +/area/yautja) +"nh" = ( +/obj/item/storage/box/bracer{ + pixel_y = 16 + }, +/obj/item/storage/box/bracer{ + pixel_y = 8 + }, +/obj/item/storage/box/bracer, +/obj/structure/rack{ + color = "#6b675e"; + layer = 2.79; + resistance_flags = 1 + }, +/turf/open/floor/corsat, +/area/yautja) +"nv" = ( +/obj/structure/rack{ + color = "#6b675e"; + layer = 2.79; + resistance_flags = 1 + }, +/obj/item/weapon/twohanded/yautja/spear, +/obj/item/weapon/twohanded/yautja/spear, +/obj/item/weapon/twohanded/yautja/spear, +/obj/item/weapon/twohanded/yautja/spear, +/turf/open/floor/strata/multi_tiles, +/area/yautja) +"ny" = ( +/obj/structure/barricade/metal/handrail{ + dir = 1 + }, +/obj/structure/barricade/metal/handrail{ + dir = 4 + }, +/turf/open/ground/grass, +/area/yautja) +"nC" = ( +/obj/machinery/telecomms/relay/preset/telecomms, +/turf/open/floor/strata/multi_tiles, +/area/yautja) +"nT" = ( +/obj/structure/table/reinforced/prison{ + color = "#6b675e"; + resistance_flags = 1 + }, +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/machinery/door/window/right{ + dir = 2 + }, +/turf/open/floor/corsat, +/area/yautja) +"ob" = ( +/obj/structure/table/reinforced/prison{ + color = "#6b675e"; + resistance_flags = 1 + }, +/obj/effect/decal/remains/human{ + pixel_y = -25 + }, +/turf/open/floor/strata/multi_tiles, +/area/yautja) +"oe" = ( +/obj/structure/closet/pred, +/turf/open/floor/corsat, +/area/yautja) +"ov" = ( +/obj/structure/rack{ + color = "#6b675e"; + layer = 2.79; + resistance_flags = 1 + }, +/obj/item/stack/yautja_rope{ + pixel_y = 10 + }, +/obj/item/storage/belt/utility/pred/full, +/obj/item/storage/belt/utility/pred/full, +/obj/item/storage/belt/utility/pred/full, +/obj/item/storage/belt/utility/pred/full, +/obj/item/storage/belt/utility/pred/full, +/turf/open/floor/corsat, +/area/yautja) +"oO" = ( +/obj/item/weapon/yautja/chain{ + anchored = 1; + name = "Houndmaster's Discipline Whip"; + pixel_x = -3; + pixel_y = 29 + }, +/turf/open/floor/strata/multi_tiles, +/area/yautja) +"pA" = ( +/obj/machinery/door_control{ + id = "Cell Lockdown 1"; + name = "Cell Lockdown 1"; + pixel_y = 9; + pixel_x = 7; + dir = 4 + }, +/turf/open/floor/strata/multi_tiles, +/area/yautja) +"pJ" = ( +/obj/structure/barricade/metal/handrail{ + dir = 1 + }, +/obj/structure/barricade/metal/handrail{ + dir = 8 + }, +/turf/open/floor/plating/ground/dirtgrassborder/corner, +/area/yautja) +"qj" = ( +/obj/structure/rack{ + color = "#6b675e"; + layer = 2.79; + resistance_flags = 1 + }, +/obj/item/tool/crowbar/yautja, +/turf/open/floor/corsat, +/area/yautja) +"qS" = ( +/obj/structure/table/mainship{ + color = "#6b675e"; + resistance_flags = 1 + }, +/obj/item/tool/kitchen/utensil/fork{ + pixel_x = 10; + pixel_y = 3 + }, +/turf/open/floor/corsat, +/area/yautja) +"qY" = ( +/obj/machinery/computer/body_scanconsole/pred, +/turf/open/floor/corsat, +/area/yautja) +"rt" = ( +/obj/structure/table/reinforced/prison{ + color = "#6b675e"; + resistance_flags = 1 + }, +/obj/item/storage/medicomp/full, +/turf/open/floor/corsat, +/area/yautja) +"rH" = ( +/obj/structure/shuttle/window{ + color = "#6b675e" + }, +/turf/open/floor/corsat, +/area/yautja) +"rY" = ( +/obj/structure/rack{ + color = "#6b675e"; + layer = 2.79; + resistance_flags = 1 + }, +/obj/item/stack/medical/splint{ + name = "splints" + }, +/obj/item/stack/medical/splint{ + name = "splints" + }, +/obj/item/stack/medical/splint{ + name = "splints" + }, +/obj/item/stack/medical/splint{ + name = "splints" + }, +/obj/item/stack/medical/splint{ + name = "splints" + }, +/obj/item/stack/medical/splint{ + name = "splints" + }, +/obj/item/stack/medical/splint{ + name = "splints" + }, +/obj/item/stack/medical/splint{ + name = "splints" + }, +/obj/item/stack/medical/splint{ + name = "splints" + }, +/obj/item/stack/medical/splint{ + name = "splints" + }, +/turf/open/floor/strata/multi_tiles, +/area/yautja) +"sx" = ( +/obj/structure/window/framed/colony/reinforced/hull/pred, +/turf/open/floor/strata/multi_tiles, +/area/yautja) +"sV" = ( +/obj/machinery/door/airlock/yautja{ + dir = 1; + name = "\improper Feed Hall" + }, +/turf/open/shuttle/dropship/fourteen, +/area/yautja) +"tc" = ( +/obj/machinery/door_control{ + id = "Cell Lockdown 2"; + name = "Cell Lockdown 2"; + pixel_y = 9; + pixel_x = 7; + dir = 4 + }, +/turf/open/floor/strata/multi_tiles, +/area/yautja) +"tf" = ( +/obj/structure/showcase/yautja/alt{ + dir = 4 + }, +/obj/item/clothing/mask/gas/yautja/hunter{ + anchored = 1; + pixel_y = 20 + }, +/turf/open/floor/corsat, +/area/yautja) +"ti" = ( +/obj/structure/shuttle/window{ + color = "#6b675e" + }, +/turf/open/floor/strata/multi_tiles, +/area/yautja) +"tn" = ( +/obj/structure/table/reinforced/prison{ + color = "#6b675e"; + resistance_flags = 1 + }, +/obj/item/flashlight/lamp, +/turf/open/floor/strata/multi_tiles, +/area/yautja) +"tD" = ( +/obj/structure/rack{ + color = "#6b675e"; + layer = 2.79; + resistance_flags = 1 + }, +/obj/item/stack/sheet/plasteel{ + amount = 30 + }, +/obj/item/stack/sheet/plasteel{ + amount = 30 + }, +/obj/item/stack/sheet/plasteel{ + amount = 30 + }, +/obj/item/stack/sheet/plasteel{ + amount = 30 + }, +/obj/item/stack/sheet/plasteel{ + amount = 30 + }, +/turf/open/floor/corsat, +/area/yautja) +"ua" = ( +/obj/alien/egg/hugger/forsaken, +/turf/open/floor/strata/multi_tiles, +/area/yautja) +"uO" = ( +/obj/structure/bed/chair/hunter{ + dir = 4 + }, +/turf/open/floor/corsat, +/area/yautja) +"uU" = ( +/obj/machinery/door/window/right{ + dir = 2 + }, +/obj/item/clothing/suit/armor/yautja/thrall, +/obj/item/clothing/mask/gas/yautja/thrall, +/obj/item/clothing/shoes/marine/yautja/thrall, +/obj/item/clothing/under/chainshirt/thrall, +/obj/structure/table/reinforced/prison, +/obj/structure/window/reinforced{ + dir = 8 + }, +/turf/open/floor/sandstone/runed, +/area/yautja) +"uZ" = ( +/obj/structure/table/reinforced/prison{ + color = "#6b675e"; + resistance_flags = 1 + }, +/obj/item/weapon/claymore/mercsword{ + anchored = 1 + }, +/turf/open/floor/corsat, +/area/yautja) +"vE" = ( +/obj/structure/stairs/seamless/pred{ + color = "#6b675e"; + dir = 1; + resistance_flags = 1 + }, +/turf/open/floor/strata/multi_tiles, +/area/yautja) +"vI" = ( +/obj/structure/closet/secure_closet/freezer/meat/yautja, +/turf/open/floor/tile/dark/red2{ + dir = 4 + }, +/area/yautja) +"vO" = ( +/obj/machinery/shower{ + dir = 4 + }, +/obj/structure/window/reinforced, +/turf/open/floor/strata/multi_tiles, +/area/yautja) +"wu" = ( +/obj/machinery/cic_maptable/yautja{ + resistance_flags = 1 + }, +/turf/open/floor/strata/multi_tiles, +/area/yautja) +"wH" = ( +/obj/structure/rack{ + color = "#6b675e"; + layer = 2.79; + resistance_flags = 1 + }, +/obj/item/reagent_containers/food/snacks/flour{ + pixel_x = 6 + }, +/obj/item/reagent_containers/food/condiment/sugar, +/obj/item/reagent_containers/food/condiment/sugar{ + pixel_y = 7; + pixel_x = 8 + }, +/obj/item/reagent_containers/food/snacks/flour{ + pixel_x = -4; + pixel_y = 4 + }, +/obj/item/reagent_containers/food/snacks/flour{ + pixel_x = 6; + pixel_y = 9 + }, +/obj/item/reagent_containers/food/snacks/flour{ + pixel_x = 6; + pixel_y = 9 + }, +/obj/item/reagent_containers/food/snacks/flour{ + pixel_x = 6; + pixel_y = 9 + }, +/obj/item/reagent_containers/food/snacks/flour{ + pixel_x = 6; + pixel_y = 9 + }, +/obj/item/reagent_containers/food/snacks/flour{ + pixel_x = 6; + pixel_y = 9 + }, +/turf/open/floor/tile/dark/red2{ + dir = 8 + }, +/area/yautja) +"wQ" = ( +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/structure/table/reinforced/prison{ + color = "#6b675e"; + resistance_flags = 1 + }, +/turf/open/floor/corsat, +/area/yautja) +"wT" = ( +/obj/structure/table/reinforced/prison{ + color = "#6b675e"; + resistance_flags = 1 + }, +/obj/item/reagent_containers/glass/beaker{ + pixel_x = -5; + pixel_y = 3 + }, +/turf/open/floor/corsat, +/area/yautja) +"xO" = ( +/obj/item/skull/hunter{ + pixel_y = 5; + anchored = 1 + }, +/obj/structure/table/reinforced/prison{ + color = "#6b675e"; + resistance_flags = 1 + }, +/turf/open/floor/corsat, +/area/yautja) +"xQ" = ( +/obj/structure/stairs/seamless/pred{ + color = "#6b675e"; + dir = 1; + resistance_flags = 1 + }, +/turf/open/floor/corsat, +/area/yautja) +"xY" = ( +/obj/structure/table/reinforced/prison{ + color = "#6b675e"; + resistance_flags = 1 + }, +/obj/item/restraints/handcuffs, +/obj/item/restraints/handcuffs{ + pixel_y = 9 + }, +/turf/open/shuttle/dropship/fourteen, +/area/yautja) +"yc" = ( +/obj/machinery/computer/sleep_console/pred, +/turf/open/floor/corsat, +/area/yautja) +"yY" = ( +/obj/machinery/door_control{ + id = "Cell Lockdown 5"; + name = "Cell Lockdown 5"; + pixel_x = -7; + pixel_y = 9; + dir = 8 + }, +/turf/open/floor/strata/multi_tiles, +/area/yautja) +"zr" = ( +/obj/structure/bed/pred, +/obj/item/bedsheet/captain{ + color = "#aba9a9"; + pixel_x = -1 + }, +/turf/open/floor/corsat, +/area/yautja) +"zA" = ( +/turf/open/floor/tile/dark2, +/area/yautja) +"zZ" = ( +/obj/structure/table/reinforced/prison{ + color = "#6b675e"; + resistance_flags = 1 + }, +/obj/structure/window/reinforced{ + dir = 8 + }, +/turf/open/floor/corsat, +/area/yautja) +"AA" = ( +/obj/structure/reagent_dispensers/fueltank/pred, +/turf/open/floor/corsat, +/area/yautja) +"Be" = ( +/obj/machinery/cryopod/right, +/turf/open/shuttle/dropship/fourteen, +/area/yautja) +"BB" = ( +/obj/structure/rack{ + color = "#6b675e"; + layer = 2.79; + resistance_flags = 1 + }, +/obj/item/weapon/gun/energy/yautja/plasmarifle{ + pixel_y = -8 + }, +/obj/item/weapon/gun/energy/yautja/plasmarifle, +/obj/item/weapon/gun/energy/yautja/plasmarifle{ + pixel_y = 7 + }, +/turf/open/floor/strata/multi_tiles, +/area/yautja) +"BK" = ( +/obj/structure/table/reinforced/prison{ + color = "#6b675e"; + resistance_flags = 1 + }, +/obj/item/storage/medicomp/full, +/turf/open/floor/strata/multi_tiles, +/area/yautja) +"BS" = ( +/obj/machinery/prop/yautja/bubbler, +/turf/open/floor/corsat, +/area/yautja) +"BY" = ( +/obj/machinery/griddle/yautja, +/turf/open/floor/strata/multi_tiles, +/area/yautja) +"Cz" = ( +/obj/item/skull/queen{ + pixel_y = 33; + anchored = 1 + }, +/turf/open/floor/corsat, +/area/yautja) +"CK" = ( +/obj/structure/table/reinforced/prison{ + color = "#6b675e"; + resistance_flags = 1 + }, +/obj/item/tool/kitchen/tray{ + color = "#FFE55C"; + pixel_y = 4 + }, +/turf/open/floor/corsat, +/area/yautja) +"Dk" = ( +/obj/item/flashlight/slime{ + anchored = 1 + }, +/obj/structure/table/reinforced/prison{ + color = "#6b675e"; + resistance_flags = 1 + }, +/turf/open/floor/corsat, +/area/yautja) +"Dr" = ( +/obj/machinery/door/airlock/yautja{ + locked = 1; + name = "\improper External Airlock" + }, +/turf/open/space, +/area/yautja) +"DF" = ( +/obj/structure/closet/secure_closet/freezer/fridge/yautja, +/turf/open/floor/tile/dark/red2{ + dir = 9 + }, +/area/yautja) +"DJ" = ( +/obj/machinery/computer/crew/pred, +/obj/structure/table/reinforced/prison{ + color = "#6b675e"; + resistance_flags = 1 + }, +/turf/open/floor/strata/multi_tiles, +/area/yautja) +"Es" = ( +/obj/structure/bed/chair/hunter, +/turf/open/floor/corsat, +/area/yautja) +"EB" = ( +/obj/structure/table/reinforced/prison{ + color = "#6b675e"; + resistance_flags = 1 + }, +/obj/item/tool/soap, +/turf/open/floor/corsat, +/area/yautja) +"Ft" = ( +/obj/structure/table/reinforced/prison{ + color = "#6b675e"; + resistance_flags = 1 + }, +/obj/item/storage/medicomp/full, +/turf/open/shuttle/dropship/fourteen, +/area/yautja) +"Fx" = ( +/obj/structure/table/reinforced/prison{ + color = "#6b675e"; + resistance_flags = 1 + }, +/obj/item/bedsheet/pred{ + anchored = 1; + dir = 8 + }, +/turf/open/floor/strata/multi_tiles, +/area/yautja) +"Fy" = ( +/obj/structure/window/framed/colony/reinforced/hull/pred, +/turf/open/floor/corsat, +/area/yautja) +"FG" = ( +/obj/effect/landmark/clan_spawn, +/turf/open/shuttle/dropship/fourteen, +/area/yautja) +"Gd" = ( +/obj/machinery/door/airlock/yautja, +/turf/open/shuttle/dropship/fourteen, +/area/yautja) +"Gk" = ( +/obj/item/explosive/grenade/spawnergrenade/spesscarp{ + anchored = 1 + }, +/obj/structure/table/reinforced/prison{ + color = "#6b675e"; + resistance_flags = 1 + }, +/turf/open/floor/corsat, +/area/yautja) +"GG" = ( +/obj/structure/barricade/metal/handrail{ + dir = 1 + }, +/turf/open/ground/grass, +/area/yautja) +"GP" = ( +/obj/structure/prop/brazier/torch{ + pixel_y = -2 + }, +/turf/closed/wall/cult, +/area/yautja) +"GY" = ( +/obj/structure/table/reinforced/prison{ + color = "#6b675e"; + resistance_flags = 1 + }, +/obj/item/weapon/chainofcommand, +/turf/open/floor/corsat, +/area/yautja) +"Ha" = ( +/obj/structure/rack{ + color = "#6b675e"; + layer = 2.79; + resistance_flags = 1 + }, +/obj/item/stack/medical/heal_pack/ointment/predator, +/obj/item/stack/medical/heal_pack/ointment/predator, +/obj/item/stack/medical/heal_pack/ointment/predator, +/obj/item/stack/medical/heal_pack/ointment/predator, +/obj/item/stack/medical/heal_pack/ointment/predator, +/obj/item/stack/medical/heal_pack/ointment/predator, +/obj/item/stack/medical/heal_pack/advanced/bruise_pack/predator, +/obj/item/stack/medical/heal_pack/advanced/bruise_pack/predator, +/obj/item/stack/medical/heal_pack/advanced/bruise_pack/predator, +/obj/item/stack/medical/heal_pack/advanced/bruise_pack/predator, +/obj/item/stack/medical/heal_pack/advanced/bruise_pack/predator, +/obj/item/stack/medical/heal_pack/advanced/bruise_pack/predator, +/turf/open/floor/strata/multi_tiles, +/area/yautja) +"Hp" = ( +/obj/structure/bed/chair/hunter{ + dir = 8 + }, +/turf/open/floor/corsat, +/area/yautja) +"Hv" = ( +/obj/item/bedsheet/captain{ + color = "#aba9a9"; + pixel_x = -1 + }, +/obj/structure/bed/pred, +/turf/open/floor/corsat, +/area/yautja) +"Hz" = ( +/obj/structure/barricade/metal/handrail{ + dir = 1 + }, +/obj/structure/barricade/metal/handrail{ + dir = 8 + }, +/turf/open/ground/grass, +/area/yautja) +"HN" = ( +/obj/structure/window/reinforced, +/obj/structure/table/reinforced/prison{ + color = "#6b675e"; + resistance_flags = 1 + }, +/turf/open/floor/corsat, +/area/yautja) +"Ia" = ( +/obj/structure/rack{ + color = "#6b675e"; + layer = 2.79; + resistance_flags = 1 + }, +/obj/item/stack/sheet/wood/large_stack, +/obj/item/stack/sheet/wood/large_stack, +/obj/item/stack/sheet/wood/large_stack, +/turf/open/shuttle/dropship/fourteen, +/area/yautja) +"If" = ( +/obj/item/weapon/yautja/scythe, +/obj/item/weapon/yautja/sword, +/obj/item/weapon/twohanded/yautja/glaive, +/obj/item/weapon/yautja/chain, +/obj/item/weapon/yautja/combistick, +/obj/item/weapon/twohanded/yautja/glaive/alt, +/obj/structure/closet/crate/secure{ + color = "#6b675e"; + name = "Secure Yautja crate"; + req_one_access = list(252) + }, +/turf/open/floor/strata/multi_tiles, +/area/yautja) +"Im" = ( +/obj/structure/rack{ + color = "#6b675e"; + layer = 2.79; + resistance_flags = 1 + }, +/obj/item/stack/medical/heal_pack/gauze{ + pixel_y = 9 + }, +/obj/item/stack/medical/heal_pack/gauze{ + pixel_y = -1; + pixel_x = 5 + }, +/obj/item/stack/medical/heal_pack/ointment{ + pixel_x = -6; + pixel_y = -4 + }, +/obj/item/stack/medical/heal_pack/gauze, +/obj/item/stack/medical/heal_pack/gauze, +/obj/item/stack/medical/heal_pack/gauze, +/obj/item/stack/medical/heal_pack/gauze, +/turf/open/floor/strata/multi_tiles, +/area/yautja) +"Iw" = ( +/obj/machinery/door/airlock/yautja{ + name = "\improper Hellhound Quarters" + }, +/turf/open/floor/corsat, +/area/yautja) +"IC" = ( +/obj/machinery/door/airlock/yautja{ + name = "\improper Elder Quarters" + }, +/turf/open/shuttle/dropship/fourteen, +/area/yautja) +"Je" = ( +/obj/structure/rack{ + color = "#6b675e"; + layer = 2.79; + resistance_flags = 1 + }, +/obj/item/stack/sheet/metal{ + amount = 50 + }, +/obj/item/stack/sheet/metal{ + amount = 50 + }, +/obj/item/stack/sheet/metal{ + amount = 50 + }, +/obj/item/stack/sheet/metal{ + amount = 50 + }, +/obj/item/stack/sheet/metal{ + amount = 50 + }, +/turf/open/floor/corsat, +/area/yautja) +"Jy" = ( +/obj/machinery/grill/yautja, +/turf/open/floor/strata/multi_tiles, +/area/yautja) +"JE" = ( +/obj/structure/rack{ + color = "#6b675e"; + layer = 2.79; + resistance_flags = 1 + }, +/obj/item/stack/yautja_rope, +/obj/item/stack/yautja_rope, +/obj/item/stack/yautja_rope, +/obj/item/stack/yautja_rope, +/obj/item/stack/yautja_rope, +/turf/open/floor/corsat, +/area/yautja) +"JH" = ( +/turf/open/floor/strata/multi_tiles, +/area/yautja) +"JL" = ( +/obj/item/weapon/yautja/knife{ + color = "#FFE55C"; + name = "sacred ceremonial dagger"; + pixel_x = 25; + anchored = 1 + }, +/turf/open/floor/corsat, +/area/yautja) +"JU" = ( +/obj/structure/stairs/seamless/pred{ + color = "#6b675e"; + dir = 4; + resistance_flags = 1 + }, +/turf/open/floor/strata/multi_tiles, +/area/yautja) +"Kp" = ( +/obj/effect/decal/remains/xeno, +/obj/effect/landmark/weed_node, +/turf/open/floor/strata/multi_tiles, +/area/yautja) +"Ku" = ( +/obj/structure/barricade/metal/handrail{ + dir = 4 + }, +/turf/open/floor/plating/ground/dirtgrassborder{ + dir = 8 + }, +/area/yautja) +"KI" = ( +/obj/item/tool/kitchen/tray{ + pixel_y = -5 + }, +/obj/effect/decal/cleanable/blood, +/turf/open/floor/strata/multi_tiles, +/area/yautja) +"KK" = ( +/obj/effect/decal/remains/human{ + pixel_y = -25 + }, +/turf/open/shuttle/dropship/fourteen, +/area/yautja) +"KR" = ( +/obj/structure/table/mainship{ + color = "#6b675e"; + resistance_flags = 1 + }, +/obj/machinery/chem_dispenser/beer/pred{ + pixel_y = 9 + }, +/turf/open/floor/strata/multi_tiles, +/area/yautja) +"KV" = ( +/obj/structure/table/mainship{ + color = "#6b675e"; + resistance_flags = 1 + }, +/obj/item/trash/plate, +/turf/open/floor/corsat, +/area/yautja) +"Lo" = ( +/obj/machinery/vending/dinnerware/yautja, +/turf/open/floor/corsat, +/area/yautja) +"LB" = ( +/obj/structure/kitchenspike, +/obj/item/reagent_containers/food/snacks/meat{ + pixel_x = -4 + }, +/obj/item/reagent_containers/food/snacks/meat{ + pixel_y = 7; + pixel_x = 3 + }, +/obj/item/reagent_containers/food/snacks/meat{ + pixel_y = 7; + pixel_x = 3 + }, +/obj/item/reagent_containers/food/snacks/meat{ + pixel_x = 3; + pixel_y = -7 + }, +/turf/open/floor/tile/dark/red2{ + dir = 8 + }, +/area/yautja) +"LX" = ( +/obj/item/moneybag/pred, +/turf/open/floor/corsat, +/area/yautja) +"Mb" = ( +/obj/item/skull/spitter{ + pixel_y = 4; + anchored = 1 + }, +/obj/structure/table/reinforced/prison{ + color = "#6b675e"; + resistance_flags = 1 + }, +/turf/open/floor/corsat, +/area/yautja) +"MD" = ( +/obj/effect/decal/remains/human, +/turf/open/floor/strata/multi_tiles, +/area/yautja) +"ME" = ( +/obj/structure/stairs/seamless{ + dir = 8; + color = "#6b675e"; + resistance_flags = 1 + }, +/turf/open/floor/strata/multi_tiles, +/area/yautja) +"MI" = ( +/obj/machinery/door/airlock/yautja{ + name = "\improper Blooded Teleporter" + }, +/turf/open/floor/strata/multi_tiles, +/area/yautja) +"Nh" = ( +/obj/structure/stairs/seamless/pred{ + dir = 4; + resistance_flags = 1 + }, +/turf/open/floor/strata/multi_tiles, +/area/yautja) +"Nn" = ( +/obj/effect/turf_decal/lvsanddecal/full, +/obj/effect/turf_decal/lvsanddecal/full, +/obj/effect/turf_decal/lvsanddecal/full, +/turf/open/beach/sand, +/area/yautja) +"Nq" = ( +/obj/structure/rack{ + color = "#6b675e"; + layer = 2.79; + resistance_flags = 1 + }, +/obj/item/radio/headset/yautja, +/obj/item/radio/headset/yautja{ + pixel_x = 4; + pixel_y = -3 + }, +/turf/open/floor/corsat, +/area/yautja) +"NA" = ( +/turf/open/floor/tile/dark/red2, +/area/yautja) +"NB" = ( +/obj/structure/table/reinforced/prison{ + color = "#6b675e"; + resistance_flags = 1 + }, +/obj/item/reagent_containers/spray/surgery{ + pixel_y = 7; + color = "#6b675e" + }, +/turf/open/floor/corsat, +/area/yautja) +"OZ" = ( +/obj/structure/bed/chair/comfy/black/pred{ + dir = 1 + }, +/turf/open/floor/corsat, +/area/yautja) +"Pb" = ( +/obj/structure/barricade/metal/handrail{ + dir = 8 + }, +/obj/structure/barricade/metal/handrail, +/turf/open/ground/grass, +/area/yautja) +"Pm" = ( +/obj/item/stack/sheet/glass{ + amount = 50 + }, +/obj/item/stack/sheet/glass{ + amount = 50 + }, +/obj/item/stack/sheet/glass{ + amount = 50 + }, +/obj/structure/rack{ + color = "#6b675e"; + layer = 2.79; + resistance_flags = 1 + }, +/turf/open/floor/corsat, +/area/yautja) +"Pr" = ( +/obj/machinery/door/airlock/yautja{ + name = "\improper Research Containment" + }, +/turf/open/floor/strata/multi_tiles, +/area/yautja) +"PJ" = ( +/obj/structure/table/reinforced/prison{ + color = "#6b675e"; + resistance_flags = 1 + }, +/obj/item/flashlight/lamp, +/turf/open/floor/corsat, +/area/yautja) +"PN" = ( +/obj/item/skull/lurker{ + pixel_y = 33; + anchored = 1 + }, +/turf/open/shuttle/dropship/fourteen, +/area/yautja) +"Qi" = ( +/obj/machinery/gibber/pred, +/turf/open/floor/tile/dark/red2{ + dir = 6 + }, +/area/yautja) +"Qj" = ( +/obj/structure/kitchenspike, +/obj/item/reagent_containers/food/snacks/carpmeat, +/obj/item/reagent_containers/food/snacks/carpmeat{ + pixel_y = 6; + pixel_x = 7 + }, +/obj/item/reagent_containers/food/snacks/carpmeat{ + pixel_y = 10; + pixel_x = -3 + }, +/obj/item/reagent_containers/food/snacks/carpmeat{ + pixel_y = -7; + pixel_x = 3 + }, +/turf/open/floor/tile/dark/red2{ + dir = 1 + }, +/area/yautja) +"Qs" = ( +/obj/machinery/chem_master/yautja, +/turf/open/floor/corsat, +/area/yautja) +"Qx" = ( +/obj/structure/barricade/metal/handrail{ + dir = 4 + }, +/obj/structure/barricade/metal/handrail, +/turf/open/floor/plating/ground/dirtgrassborder/corner{ + dir = 4 + }, +/area/yautja) +"QF" = ( +/obj/item/weapon/yautja/knife{ + color = "#FFE55C"; + name = "sacred ceremonial dagger"; + pixel_x = -25; + anchored = 1 + }, +/turf/open/floor/corsat, +/area/yautja) +"RE" = ( +/obj/structure/closet/secure_closet/freezer/fridge/yautja, +/obj/item/reagent_containers/food/snacks/grown/potato, +/obj/item/reagent_containers/food/snacks/grown/potato, +/obj/item/reagent_containers/food/snacks/grown/potato, +/obj/item/reagent_containers/food/snacks/grown/potato, +/obj/item/reagent_containers/food/snacks/grown/potato, +/obj/item/reagent_containers/food/snacks/grown/corn, +/obj/item/reagent_containers/food/snacks/grown/corn, +/obj/item/reagent_containers/food/snacks/grown/corn, +/obj/item/reagent_containers/food/snacks/grown/corn, +/obj/item/reagent_containers/food/snacks/grown/corn, +/turf/open/floor/tile/dark/red2{ + dir = 6 + }, +/area/yautja) +"Sx" = ( +/turf/open/floor/tile/dark/red2{ + dir = 8 + }, +/area/yautja) +"SB" = ( +/obj/structure/stairs/seamless{ + dir = 4; + color = "#6b675e"; + resistance_flags = 1 + }, +/turf/open/floor/corsat, +/area/yautja) +"Ut" = ( +/obj/structure/table/reinforced/prison{ + color = "#6b675e"; + resistance_flags = 1 + }, +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/structure/window/reinforced{ + dir = 4 + }, +/turf/open/floor/corsat, +/area/yautja) +"Uv" = ( +/obj/effect/decal/remains/xeno{ + pixel_y = -25 + }, +/turf/open/shuttle/dropship/fourteen, +/area/yautja) +"UG" = ( +/obj/structure/barricade/metal/handrail, +/turf/open/ground/grass, +/area/yautja) +"UR" = ( +/obj/structure/stairs/seamless/pred{ + color = "#6b675e"; + resistance_flags = 1 + }, +/turf/open/floor/corsat, +/area/yautja) +"UT" = ( +/obj/structure/table/reinforced/prison{ + color = "#6b675e"; + resistance_flags = 1 + }, +/obj/item/restraints/handcuffs, +/obj/item/restraints/handcuffs, +/obj/item/restraints/handcuffs, +/obj/item/restraints/handcuffs, +/obj/item/restraints/handcuffs, +/obj/item/restraints/handcuffs, +/obj/item/restraints/handcuffs, +/obj/item/restraints/handcuffs{ + pixel_y = 8 + }, +/turf/open/shuttle/dropship/fourteen, +/area/yautja) +"Vt" = ( +/obj/structure/table/mainship{ + color = "#6b675e"; + resistance_flags = 1 + }, +/obj/item/tool/kitchen/utensil/spoon, +/obj/item/reagent_containers/food/snacks/meatsteak{ + pixel_y = 9; + pixel_x = 18 + }, +/turf/open/floor/corsat, +/area/yautja) +"VN" = ( +/obj/machinery/atmospherics/components/unary/thermomachine/freezer/pred, +/turf/open/floor/corsat, +/area/yautja) +"VT" = ( +/obj/structure/table/reinforced/prison{ + color = "#6b675e"; + resistance_flags = 1 + }, +/obj/item/bedsheet/pred{ + anchored = 1; + dir = 4 + }, +/turf/open/floor/strata/multi_tiles, +/area/yautja) +"We" = ( +/obj/structure/table/reinforced/prison{ + color = "#6b675e"; + resistance_flags = 1 + }, +/obj/item/weapon/baton/cattleprod, +/obj/item/weapon/baton/cattleprod, +/obj/item/weapon/baton/cattleprod, +/obj/item/weapon/baton/cattleprod, +/obj/item/weapon/baton/cattleprod, +/obj/item/weapon/baton/cattleprod, +/turf/open/shuttle/dropship/fourteen, +/area/yautja) +"Wg" = ( +/obj/machinery/door/airlock/yautja{ + dir = 1; + name = "\improper Gladiator Hall" + }, +/turf/open/shuttle/dropship/fourteen, +/area/yautja) +"Ww" = ( +/obj/structure/table/mainship{ + color = "#6b675e"; + resistance_flags = 1 + }, +/obj/item/tool/kitchen/utensil/spoon, +/turf/open/floor/corsat, +/area/yautja) +"Xg" = ( +/obj/structure/table/mainship{ + color = "#6b675e"; + resistance_flags = 1 + }, +/obj/item/tool/kitchen/tray, +/obj/item/tool/kitchen/utensil/fork{ + pixel_x = 10; + pixel_y = 3 + }, +/turf/open/floor/corsat, +/area/yautja) +"Xk" = ( +/turf/open/floor/plating/ground/dirtgrassborder{ + dir = 1 + }, +/area/yautja) +"Xl" = ( +/obj/structure/stairs/seamless{ + color = "#6b675e"; + resistance_flags = 1 + }, +/turf/open/floor/strata/multi_tiles, +/area/yautja) +"Xn" = ( +/obj/structure/barricade/metal/handrail{ + dir = 1 + }, +/obj/structure/barricade/metal/handrail{ + dir = 4 + }, +/turf/open/floor/plating/ground/dirtgrassborder/corner{ + dir = 1 + }, +/area/yautja) +"Xp" = ( +/obj/structure/rack{ + color = "#6b675e"; + layer = 2.79; + resistance_flags = 1 + }, +/obj/item/weapon/baseballbat/metal{ + attack_speed = 12; + force = 25; + name = "\improper duelling metal bat"; + pixel_x = -2; + pixel_y = 2 + }, +/obj/item/weapon/baseballbat/metal{ + attack_speed = 12; + force = 25; + name = "\improper duelling metal bat"; + pixel_x = -5; + pixel_y = 4 + }, +/obj/item/weapon/baseballbat/metal{ + attack_speed = 12; + force = 25; + name = "\improper duelling metal bat" + }, +/obj/item/weapon/baseballbat/metal{ + attack_speed = 12; + force = 25; + name = "\improper duelling metal bat"; + pixel_x = -7; + pixel_y = 6 + }, +/turf/open/floor/strata/multi_tiles, +/area/yautja) +"Xv" = ( +/obj/structure/table/reinforced/prison{ + color = "#6b675e"; + resistance_flags = 1 + }, +/obj/item/research_resource/xeno/tier_one, +/turf/open/floor/strata/multi_tiles, +/area/yautja) +"XP" = ( +/obj/machinery/cryopod, +/turf/open/floor/strata/multi_tiles, +/area/yautja) +"Ys" = ( +/obj/structure/reagent_dispensers/watertank/pred, +/turf/open/floor/tile/dark/red2{ + dir = 10 + }, +/area/yautja) +"YL" = ( +/obj/machinery/door/airlock/yautja{ + dir = 1; + name = "\improper Cryo Room" + }, +/turf/open/shuttle/dropship/fourteen, +/area/yautja) +"Za" = ( +/obj/structure/table/mainship{ + color = "#6b675e"; + resistance_flags = 1 + }, +/obj/item/trash/plate, +/obj/item/reagent_containers/food/snacks/meatsteak{ + pixel_y = 9; + pixel_x = 12 + }, +/turf/open/floor/corsat, +/area/yautja) +"Zi" = ( +/obj/structure/sink{ + pixel_y = 25 + }, +/turf/open/shuttle/dropship/fourteen, +/area/yautja) +"Zs" = ( +/obj/machinery/door/airlock/yautja/secure{ + dir = 8; + name = "\improper Heavy Armory" + }, +/obj/machinery/door/poddoor/shutters/almayer/yautja{ + name = "Yautja Armory" + }, +/turf/open/floor/strata/multi_tiles, +/area/yautja) +"Zu" = ( +/obj/structure/table/reinforced/prison{ + color = "#6b675e"; + resistance_flags = 1 + }, +/obj/item/alien_embryo{ + pixel_y = 8 + }, +/turf/open/floor/corsat, +/area/yautja) +"ZD" = ( +/obj/structure/stairs/seamless{ + dir = 8; + color = "#6b675e"; + resistance_flags = 1 + }, +/turf/open/floor/corsat, +/area/yautja) +"ZR" = ( +/obj/structure/rack{ + color = "#6b675e"; + layer = 2.79; + resistance_flags = 1 + }, +/obj/item/stack/yautja_rope, +/turf/open/floor/corsat, +/area/yautja) + +(1,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(2,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(3,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(4,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(5,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(6,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(7,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(8,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(9,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(10,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(11,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +bj +sx +sx +sx +bj +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(12,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +bj +bj +oO +JH +aB +bj +bj +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(13,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +bj +bj +cY +JH +JH +JH +KI +bj +bj +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(14,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +bj +bj +aB +JH +JH +JH +JH +JH +aB +bj +bj +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(15,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +bj +bj +bj +bj +bj +bj +bj +bj +bj +bj +bj +Iw +bj +bj +bj +bj +bj +bj +bj +bj +bj +bj +bj +bj +bj +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(16,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ac +bj +bj +bL +VN +aY +ly +cj +bL +an +bj +bj +cT +bL +db +bj +JH +JH +bj +bY +cl +aD +aD +aD +bj +bj +bj +bj +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(17,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ae +bj +bj +fx +cP +cP +bL +yc +bL +hR +rt +bj +cU +cP +qj +bj +fg +cP +bj +NB +bL +bL +bL +bL +sx +vE +JH +bj +bj +bj +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(18,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ae +bj +at +cP +cP +cP +cP +cP +cP +cP +Ft +bj +cV +cP +AA +bj +cP +cP +bp +cP +cP +cP +cP +cP +dc +Xl +JH +kF +fv +bj +bj +bj +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(19,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ae +bj +at +cP +cP +cP +cP +cP +cP +cP +cP +bj +bq +br +cP +bx +cP +cP +bj +Zu +gp +Qs +bL +bL +sx +Nh +JH +JH +JH +fv +bj +bj +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(20,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ae +bj +bj +bL +bL +bL +bj +bs +cP +cP +cP +bj +cW +cP +cP +bx +cP +cP +bj +bR +wT +bA +aD +aD +bj +Xv +JH +JH +JH +JH +bj +bj +bj +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(21,1,1) = {" +aa +bj +bj +bj +aa +aa +aa +aa +aa +aa +ad +bj +bj +aE +aW +aQ +bj +qY +bL +cP +cP +bj +bL +cP +bL +bj +cP +cP +bj +bj +bj +bj +bj +bj +bj +bj +bj +sx +Pr +sx +bj +bj +bj +bj +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(22,1,1) = {" +aa +aa +bj +bj +bj +aa +aa +aa +aa +aa +aa +aa +bj +bj +bj +bj +bj +bj +bj +aT +aT +bj +bL +cP +bL +bj +cP +cP +bj +aa +aa +aa +aa +aa +bj +bj +bj +ua +MD +ua +bj +bj +bj +bj +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(23,1,1) = {" +aa +aa +aa +ac +bj +bj +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +bj +cP +cP +bj +cX +JE +cX +bj +cP +cP +bj +aa +aa +aa +aa +aa +aa +bj +bj +by +Kp +ua +bj +bj +bj +bj +bj +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(24,1,1) = {" +aa +aa +aa +ae +bj +bj +bj +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +bj +bj +cP +cP +bj +bj +bj +bj +bj +bl +bl +bj +bj +aa +aa +aa +aa +aa +aa +bj +bj +bj +bj +bj +bj +bj +bj +bj +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(25,1,1) = {" +aa +aa +aa +ad +bj +bj +bj +bj +aa +aa +aa +aa +aa +aa +aa +aa +aa +bj +hV +cP +cP +cP +cP +cP +cP +cP +cP +cP +wQ +bj +bj +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(26,1,1) = {" +aa +aa +bj +bj +bj +bj +bj +bj +bj +bj +bj +bj +bj +bj +bj +bj +bj +bj +hV +cP +cP +bz +ly +nh +HN +au +cP +cP +wQ +bj +bj +bj +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(27,1,1) = {" +aa +aa +aa +ac +bj +af +ZR +aV +bn +bj +PJ +jy +bO +bj +PJ +jy +bO +bj +hV +cP +cP +wQ +bj +bj +bj +wQ +cP +cP +wQ +bj +bj +bj +bj +bj +bj +bj +bj +bj +bj +bj +bj +bj +bj +bj +bj +bj +bj +bj +bj +bj +bj +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(28,1,1) = {" +aa +aa +aa +ae +bj +af +aC +cP +bL +bj +bL +eY +bL +bj +bL +eY +bL +bj +hV +cP +bL +wQ +rH +bd +rH +wQ +bL +cP +wQ +bj +bj +bj +bj +bj +bj +is +LB +cu +bj +cw +xY +bj +bL +cS +bj +bL +cS +bj +bL +cS +bj +bj +bj +Fy +Fy +bj +bj +bj +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(29,1,1) = {" +aa +aa +aa +ad +bj +af +GP +cP +bL +bj +bL +cP +bL +bj +bL +cP +bL +bj +hV +bL +JH +JH +af +MI +af +JH +JH +JH +bL +bL +bj +bj +bj +bj +Qj +zA +zA +NA +bj +UT +cP +bj +bL +bL +bj +bL +bL +bj +bL +bL +bj +bj +bj +GY +CK +QF +Hv +bj +bj +bj +bj +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(30,1,1) = {" +aa +aa +bj +bj +bj +ay +ap +cP +bL +bj +PN +cP +KK +bj +eS +cP +Uv +bj +BS +JH +JH +bL +bL +cP +bL +bL +bL +JH +JH +bL +bj +bM +da +bj +de +fb +fb +Qi +bj +We +cP +bj +bW +fq +bj +ce +fq +bj +cm +fq +bj +bj +bj +PJ +eY +cP +cP +bj +bd +bd +bj +bj +bj +bj +aa +aa +aa +aa +aa +aa +"} +(31,1,1) = {" +aa +aa +aa +ac +bj +aA +ap +cP +bL +bj +nT +cP +bL +bj +nT +cP +bL +bj +JH +JH +bL +bL +bL +cP +bL +bL +bL +bL +JH +bL +bj +cv +JH +bj +bj +bG +bj +bj +bj +bj +aw +bj +JH +JH +pA +JH +JH +tc +JH +JH +mb +Ha +bj +Cz +cP +cP +KK +bj +cA +cA +bj +cN +cN +bj +bj +bj +aa +aa +aa +aa +"} +(32,1,1) = {" +aa +aa +aa +ad +bj +af +ap +cP +bL +bj +oe +cP +bL +bj +oe +cP +bL +bj +JH +ab +fk +bL +bL +cP +bL +bL +mv +xO +JH +bL +bj +Jy +JH +Ia +lr +cP +cP +JH +JH +bj +cP +cP +bL +bL +bL +bL +bL +bL +bL +bL +bL +jP +bj +aq +cP +cP +cP +bj +cP +cP +cB +cP +cP +cP +cP +bj +sx +bj +aa +aa +"} +(33,1,1) = {" +aa +aa +bj +bj +bj +ah +ap +cP +bL +bj +bj +aw +bj +bj +bj +aw +bj +bj +JH +eA +cP +cP +cP +cP +cP +cP +cP +Dk +JH +bL +bj +BY +cP +bL +bL +bL +bL +cP +JH +bj +fg +cP +bL +cP +cP +cP +cP +cP +cP +cP +bL +Xp +bj +oe +cP +cP +fj +bj +cP +cP +cB +cP +cP +cP +cP +aX +ob +bj +bj +aa +"} +(34,1,1) = {" +aa +aa +aa +ac +bj +ai +ap +cP +bL +bL +ti +FG +cP +cP +cP +FG +ti +JH +JH +bL +cP +bL +bL +bL +bL +bL +cP +bL +JH +JH +bj +cP +bL +gp +iV +Vt +OZ +bL +cP +bj +cP +bL +bL +cP +pJ +ja +ja +ja +lu +cP +bL +bL +bj +bj +bj +IC +bj +bj +cP +bL +bj +bL +bL +bL +cP +Hp +VT +tn +sx +aa +"} +(35,1,1) = {" +aa +aa +aa +ae +bj +aj +ap +cP +cP +cP +ar +cP +JH +JH +JH +cP +aP +cP +cP +cP +cP +bL +er +ZD +xQ +bL +cP +cP +cP +cP +sV +cP +bL +gp +Ww +KV +OZ +bL +cP +Wg +bL +bL +cP +Hz +ag +bV +dm +Nn +Xk +Pb +cP +bL +bL +ct +cP +JH +cP +ct +cP +bL +hI +LX +bL +bL +cP +bL +Hp +fv +sx +sx +"} +(36,1,1) = {" +aa +aa +aa +ae +bj +GP +ap +cP +bL +bL +ti +cP +JH +wu +JH +cP +ti +bL +bL +bL +bL +bL +bI +cZ +bE +bL +bL +bL +bL +bL +bj +Lo +bL +gp +qS +iV +OZ +bL +bL +bj +cK +cP +cP +GG +ag +eg +Nn +Nn +Xk +UG +cP +cP +cP +ti +JH +wu +JH +ti +cP +bL +bj +wu +JH +JH +cP +cP +cP +Es +DJ +sx +"} +(37,1,1) = {" +aa +aa +aa +ae +bj +ak +ap +cP +cP +cP +ar +cP +JH +JH +JH +cP +aP +cP +cP +cP +cP +bL +UR +SB +eT +bL +cP +cP +cP +cP +sV +cP +bL +gp +Za +Ww +OZ +bL +cP +Wg +bL +bL +cP +ny +ag +Nn +Nn +Nn +Xk +mj +cP +bL +bL +ct +cP +JH +cP +ct +cP +bL +hI +LX +bL +bL +cP +bL +uO +fv +sx +sx +"} +(38,1,1) = {" +aa +aa +aa +ad +bj +al +ap +cP +bL +bL +ti +FG +cP +cP +cP +FG +ti +JH +JH +bL +cP +bL +bL +bL +bL +bL +cP +bL +JH +JH +bj +cP +bL +gp +Ww +Xg +OZ +bL +cP +bj +cP +bL +bL +cP +Xn +Ku +Ku +Ku +Qx +cP +bL +bL +bj +bj +bj +IC +bj +bj +cP +bL +bj +bL +bL +bL +cP +uO +Fx +tn +sx +aa +"} +(39,1,1) = {" +aa +aa +bj +bj +bj +am +ap +cP +bL +bj +bj +aw +bj +bj +bj +aw +bj +bj +JH +EB +cP +cP +cP +cP +cP +cP +cP +Gk +JH +bL +bj +JH +cP +bL +bL +bL +bL +cP +JH +bj +fg +cP +bL +cP +cP +cP +cP +cP +cP +cP +bL +Im +bj +oe +cP +cP +Be +bj +cP +cP +cB +cP +cP +cP +cP +cR +ob +bj +bj +aa +"} +(40,1,1) = {" +aa +aa +aa +ac +bj +af +ap +cP +bL +bj +oe +cP +bL +bj +oe +cP +bL +bj +JH +cz +kA +bL +bL +cP +bL +bL +uZ +Mb +JH +bL +bj +KR +JH +cP +cP +cP +cP +JH +JH +bj +cP +cP +bL +bL +bL +bL +bL +bL +bL +bL +bL +fF +bj +ao +cP +cP +cP +bj +cP +cP +cB +cP +cP +cP +cP +bj +sx +bj +aa +aa +"} +(41,1,1) = {" +aa +aa +aa +ad +bj +il +ap +cP +bL +bj +nT +cP +bL +bj +nT +cP +bL +bj +JH +JH +bL +bL +bL +cP +bL +bL +bL +bL +JH +bL +bj +cb +JH +bj +bj +bG +bj +bj +bj +bj +aw +bj +JH +JH +ge +JH +JH +yY +JH +JH +cg +rY +bj +Cz +cP +cP +Uv +bj +cA +cA +bj +cO +cO +bj +bj +bj +aa +aa +aa +aa +"} +(42,1,1) = {" +aa +aa +bj +bj +bj +uU +ap +cP +bL +bj +eS +cP +Uv +bj +PN +cP +KK +bj +bL +JH +JH +bL +bL +cP +bL +bL +bL +JH +JH +bL +bj +cJ +cr +bj +DF +Sx +wH +Ys +bj +vO +cP +bj +bX +fq +bj +cf +fq +bj +cn +fq +bj +bj +bj +PJ +eY +cP +cP +bj +bd +bd +bj +bj +bj +bj +aa +aa +aa +aa +aa +aa +"} +(43,1,1) = {" +aa +aa +aa +ac +bj +af +GP +cP +bL +bj +bL +cP +bL +bj +bL +cP +bL +bj +bL +bL +JH +JH +af +MI +af +JH +JH +JH +bL +bL +bj +bj +bj +bj +di +zA +zA +NA +bj +Zi +cP +bj +bL +bL +bj +bL +bL +bj +bL +bL +bj +bj +bj +GY +CK +JL +zr +bj +bj +bj +bj +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(44,1,1) = {" +aa +aa +aa +ae +bj +af +aC +cP +bL +bj +bL +eY +bL +bj +bL +eY +bL +bj +cQ +cP +bL +Nq +ti +bd +ti +Ut +bL +cP +Ut +bj +bj +bj +bj +bj +bj +bU +vI +RE +bj +oe +oe +bj +bL +cS +bj +bL +cS +bj +bL +cS +bj +bj +bj +Fy +Fy +bj +bj +bj +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(45,1,1) = {" +aa +aa +aa +ad +bj +af +ZR +aV +bn +bj +av +df +bO +bj +PJ +jy +bO +bj +tD +cP +cP +bg +bj +bj +bj +Ut +cP +cP +Ut +bj +bj +bj +bj +bj +bj +bj +bj +bj +bj +bj +bj +bj +bj +bj +bj +bj +bj +bj +bj +bj +bj +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(46,1,1) = {" +aa +aa +bj +bj +bj +bj +bj +bj +bj +bj +bj +bj +bj +bj +bj +bj +bj +bj +Je +cP +cP +Pm +ov +nh +jl +zZ +cP +cP +Ut +bj +bj +bj +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(47,1,1) = {" +aa +aa +aa +ac +bj +bj +bj +bj +aa +aa +aa +aa +aa +aa +aa +aa +aa +bj +cC +cP +cP +cP +cP +cP +cP +cP +cP +cP +Ut +bj +bj +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(48,1,1) = {" +aa +aa +aa +ae +bj +bj +bj +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +bj +bj +bj +bj +bj +bj +bj +bj +bj +bm +bm +bj +bj +aa +aa +aa +aa +aa +aa +bj +bj +bj +bj +bj +bj +bj +bj +bj +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(49,1,1) = {" +aa +aa +aa +ad +bj +bj +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +bj +bj +bc +bc +bc +bc +bc +bj +cP +cP +bj +aa +aa +aa +aa +aa +aa +bj +bj +BB +JH +bN +bj +nC +bj +bj +bj +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(50,1,1) = {" +aa +aa +bj +bj +bj +aa +aa +aa +aa +aa +aa +aa +bj +bj +bj +bj +bj +bj +bj +bj +cP +cP +cP +cP +cP +YL +cP +cP +bj +aa +aa +aa +aa +aa +bj +bj +bj +BB +JH +bN +bj +bj +bj +bj +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(51,1,1) = {" +aa +bj +bj +bj +aa +aa +aa +aa +aa +aa +ac +bj +bj +aF +JH +JH +JH +bL +bL +cF +cP +bL +bL +bL +cP +bj +cP +cP +bj +bj +bj +bj +bj +bj +bj +bj +bj +sx +Zs +sx +bj +bj +bj +bj +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(52,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ae +bj +bj +aG +aL +bL +JH +bL +bL +bj +cP +XP +XP +XP +cP +bj +cP +cP +bj +tf +bj +tf +bj +tf +bj +gb +JH +JH +JH +If +bj +bj +bj +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(53,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ae +bj +az +aI +bL +bL +JH +bL +bL +bj +cP +bc +bc +bc +cP +bj +fg +cP +bj +bL +bL +bL +gG +bL +Fy +dk +JH +JH +JH +dP +bj +bj +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(54,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ae +bj +az +aK +bL +bL +JH +bL +bL +cF +cP +bL +bL +bL +cP +bj +cP +cP +bu +cP +cP +cP +cP +cP +bD +dl +JH +BK +BK +bj +bj +bj +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(55,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ae +bj +bj +aG +aL +bL +JH +bL +bL +bj +cP +cP +cP +cP +cP +YL +cP +cP +bj +bL +bL +bL +bL +bL +Fy +JU +JH +bj +bj +bj +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(56,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +ad +bj +bj +nv +JH +JH +JH +bL +bL +bj +cG +ME +ME +ME +vE +bj +JH +JH +bj +bv +bv +bv +bv +bv +bj +bj +bj +bj +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(57,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +bj +bj +bj +bj +bj +bj +bj +bj +bj +Gd +bj +Gd +bj +bj +bj +bj +bj +bj +bj +bj +bj +bj +bj +bj +bj +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(58,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +bj +bj +JH +JH +JH +JH +JH +JH +JH +bj +bj +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(59,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +bj +bj +JH +JH +JH +JH +JH +bj +bj +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(60,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +bj +bj +JH +JH +JH +bj +bj +aa +aa +aa +dI +dI +dI +dI +dI +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(61,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +bj +Dr +sx +Dr +bj +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(62,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(63,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +dI +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(64,1,1) = {" +aa +aa +aa +aa +aa +aa +dI +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(65,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(66,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(67,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(68,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(69,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(70,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} diff --git a/code/__DEFINES/_radio.dm b/code/__DEFINES/_radio.dm index eb62966842572..07a1a131fca61 100644 --- a/code/__DEFINES/_radio.dm +++ b/code/__DEFINES/_radio.dm @@ -60,11 +60,14 @@ #define RADIO_CHANNEL_ECHO "Echo" #define RADIO_CHANNEL_DS1 "Alamo" #define RADIO_CHANNEL_DS2 "Normandy" - +#define RADIO_CHANNEL_YAUTJA "Yautja" //RU TGMC ADDITION #define MIN_FREE_FREQ 1201 // ------------------------------------------------- // Frequencies are always odd numbers and range from 1201 to 1599. +//Preds +#define YAUT_FREQ 1233 //RU TGMC ADDITION + //SOM squads #define FREQ_COMMAND_SOM 1235 #define FREQ_MEDICAL_SOM 1237 @@ -74,7 +77,6 @@ #define FREQ_YANKEE 1243 #define FREQ_XRAY 1245 #define FREQ_WHISKEY 1247 - #define MIN_ERT_FREQ 1331 #define FREQ_PMC 1331 #define FREQ_COLONIST 1335 @@ -86,7 +88,6 @@ #define FREQ_SECTOID 1347 #define FREQ_ECHO 1349 #define MAX_ERT_FREQ 1349 - #define FREQ_AI 1351 #define FREQ_COMMAND 1353 #define FREQ_REQUISITIONS 1354 diff --git a/code/__DEFINES/conflict.dm b/code/__DEFINES/conflict.dm index 4845ca5bfd070..e4664a5d551dc 100644 --- a/code/__DEFINES/conflict.dm +++ b/code/__DEFINES/conflict.dm @@ -217,5 +217,5 @@ #define X_R_HAND_LAYER 4 #define X_TARGETED_LAYER 3 #define X_FIRE_LAYER 1 -#define X_TOTAL_LAYERS 9 +// #define X_TOTAL_LAYERS 9 RU TGMC EDIT ///////////////////////////////// diff --git a/code/__DEFINES/is_helpers.dm b/code/__DEFINES/is_helpers.dm index 32ecac558c7f5..adf6054dc0fe8 100755 --- a/code/__DEFINES/is_helpers.dm +++ b/code/__DEFINES/is_helpers.dm @@ -294,8 +294,9 @@ // Xeno hives #define isnormalhive(hive) (istype(hive, /datum/hive_status/normal)) +/* RU TGMC EDIT #define isxenohive(A) ((A == XENO_HIVE_NONE) || (A == XENO_HIVE_NORMAL) || (A == XENO_HIVE_CORRUPTED) || (A == XENO_HIVE_ALPHA) || (A == XENO_HIVE_BETA) || (A == XENO_HIVE_ZETA) || (A == XENO_HIVE_ADMEME)) || (A == XENO_HIVE_FALLEN) - +RU TGMC EDIT*/ // Slot helpers #define ishandslot(A) ((A == SLOT_L_HAND) || (A == SLOT_R_HAND)) diff --git a/code/__DEFINES/minimap.dm b/code/__DEFINES/minimap.dm index f741551d50ad3..2452f1229cb10 100644 --- a/code/__DEFINES/minimap.dm +++ b/code/__DEFINES/minimap.dm @@ -3,7 +3,7 @@ #define MINIMAP_FLAG_MARINE (1<<1) #define MINIMAP_FLAG_MARINE_SOM (1<<2) #define MINIMAP_FLAG_EXCAVATION_ZONE (1<<3) -#define MINIMAP_FLAG_ALL (1<<4) - 1 +#define MINIMAP_FLAG_ALL (1<<6) - 1 //RU TGMC EDIT GLOBAL_LIST_INIT(faction_to_minimap_flag, list( FACTION_XENO = MINIMAP_FLAG_XENO, diff --git a/code/__DEFINES/mobs.dm b/code/__DEFINES/mobs.dm index c9865b73b58a6..d1fad63f8cd46 100644 --- a/code/__DEFINES/mobs.dm +++ b/code/__DEFINES/mobs.dm @@ -401,10 +401,12 @@ GLOBAL_LIST_INIT(xenoupgradetiers, list(XENO_UPGRADE_BASETYPE, XENO_UPGRADE_INVA // Human Overlay Indexes +/* RU TGMC EDIT #define LASER_LAYER 29 //For sniper targeting laser #define MOTH_WINGS_LAYER 28 #define MUTATIONS_LAYER 27 #define DAMAGE_LAYER 26 +RU TGMC EDIT */ #define UNIFORM_LAYER 25 #define TAIL_LAYER 24 //bs12 specific. this hack is probably gonna come back to haunt me #define ID_LAYER 23 @@ -430,9 +432,9 @@ GLOBAL_LIST_INIT(xenoupgradetiers, list(XENO_UPGRADE_BASETYPE, XENO_UPGRADE_INVA #define OVERHEALTH_SHIELD_LAYER 3 #define TARGETED_LAYER 2 //for target sprites when held at gun point, and holo cards. #define FIRE_LAYER 1 //If you're on fire - +/* RU TGMC EDIT #define TOTAL_LAYERS 29 - +RU TGMC EDIT */ #define MOTH_WINGS_BEHIND_LAYER 1 #define TOTAL_UNDERLAYS 1 diff --git a/code/__DEFINES/preferences.dm b/code/__DEFINES/preferences.dm index 9450befacc252..c676b30fa471f 100644 --- a/code/__DEFINES/preferences.dm +++ b/code/__DEFINES/preferences.dm @@ -108,13 +108,14 @@ #define TOGGLES_GAMEPLAY_DEFAULT (RADIAL_MEDICAL|MIDDLESHIFTCLICKING|RADIAL_STACKS|AUTO_INTERACT_DEPLOYABLES|RADIAL_LASERGUNS) #define CHARACTER_CUSTOMIZATION 1 +/* RU TGMC EDIT #define BACKGROUND_INFORMATION 2 #define GEAR_CUSTOMIZATION 3 #define JOB_PREFERENCES 4 #define GAME_SETTINGS 5 #define KEYBIND_SETTINGS 6 #define DRAW_ORDER 7 - +RU TGMC EDIT */ #define CITIZENSHIP_CHOICES list(\ "Earth Born",\ "Sol Born",\ diff --git a/code/__DEFINES/~RUtgmc_defines/_defines_include.dm b/code/__DEFINES/~RUtgmc_defines/_defines_include.dm index fa587fc9eaf0a..738a1344b4e72 100644 --- a/code/__DEFINES/~RUtgmc_defines/_defines_include.dm +++ b/code/__DEFINES/~RUtgmc_defines/_defines_include.dm @@ -20,3 +20,7 @@ #include "traits.dm" #include "xeno.dm" #include "dsc\signals.dm" +#include "predators.dm" +#include "equipment.dm" +#include "minimap.dm" +#include "span.dm" diff --git a/code/__DEFINES/~RUtgmc_defines/atom_hud.dm b/code/__DEFINES/~RUtgmc_defines/atom_hud.dm index e825be0c874de..51a781b95b848 100644 --- a/code/__DEFINES/~RUtgmc_defines/atom_hud.dm +++ b/code/__DEFINES/~RUtgmc_defines/atom_hud.dm @@ -1,2 +1,10 @@ #define XENO_BANISHED_HUD "xeno_banished_hud" // indicates that the xeno is banished + +#define HUNTER_HUD "hunter_hud" //displays various statuses on mobs for Hunters to identify targets +#define HUNTER_CLAN "hunter_clan_hud" //displays a colored icon to represent ingame Hunter Clans +#define HUNTER_HEALTH_HUD "hunter_health_hud" //displays a predator health + +#define DATA_HUD_HUNTER 17 +#define DATA_HUD_HUNTER_CLAN 18 + #define XENO_PRIMO_HUD "xeno_primo_hud" //indicates primo upgrade hud diff --git a/code/__DEFINES/~RUtgmc_defines/conflict.dm b/code/__DEFINES/~RUtgmc_defines/conflict.dm index a60c77bfacaae..cad063897caeb 100644 --- a/code/__DEFINES/~RUtgmc_defines/conflict.dm +++ b/code/__DEFINES/~RUtgmc_defines/conflict.dm @@ -1,3 +1,6 @@ +#define X_PRED_LASER_LAYER 10 +#define X_TOTAL_LAYERS 10 + // No neighbors #define NEIGHBORS_NONE 0 // Cardinal neighborhood @@ -19,3 +22,6 @@ //Explosion damage multipliers for different objects #define RESIN_EXPLOSIVE_MULTIPLIER 0.85 + +//Damage modificator +#define PRED_MELEE_DAMAGE_MOD 0.5 diff --git a/code/__DEFINES/~RUtgmc_defines/dsc/signals.dm b/code/__DEFINES/~RUtgmc_defines/dsc/signals.dm index 428351d3bd8a9..d0929f16d149d 100644 --- a/code/__DEFINES/~RUtgmc_defines/dsc/signals.dm +++ b/code/__DEFINES/~RUtgmc_defines/dsc/signals.dm @@ -46,6 +46,26 @@ #define COMSIG_XENOABILITY_CHIMERA_BODYSWAP "xenoability_chimera_bodyswap" #define COMSIG_XENOABILITY_CHIMERA_CRIPPLING_STRIKE "xenoability_chimera_crippling_strike" +//Preds +#define COMSIG_GLOB_YAUTJA_ARMORY_OPENED "yautja_armory_opened" + +#define COMSIG_ATOM_TELEPORT "atom_teleport" + +#define COMSIG_ATTEMPT_MOB_PULL "attempt_mob_pull" + #define COMPONENT_CANCEL_MOB_PULL (1<<0) + +#define COMSIG_ITEM_ATTEMPT_ATTACK "item_attempt_attack" //Triggered on the target mob. + +/// From /mob/living/verb/resist() +#define COMSIG_MOB_RECALCULATE_CLIENT_COLOR "mob_recalc_client_color" + +/// From /mob/living/carbon/human/ExtinguishMob() +#define COMSIG_HUMAN_EXTINGUISH "human_extinguish" + +/// From /datum/flaying_datum +#define COMSIG_HUMAN_FLAY_ATTEMPT "human_flay_attempt" + +#define COMSIG_XENOMORPH_INTERFERENCE "xenomorph_interference" #define COMSIG_XENOABILITY_CRESTTOSS_BEHIND "xenoability_cresttoss_behind" diff --git a/code/__DEFINES/~RUtgmc_defines/equipment.dm b/code/__DEFINES/~RUtgmc_defines/equipment.dm new file mode 100644 index 0000000000000..a82e7d2672113 --- /dev/null +++ b/code/__DEFINES/~RUtgmc_defines/equipment.dm @@ -0,0 +1,2 @@ +//flag_item +#define ITEM_PREDATOR (1<<20) diff --git a/code/__DEFINES/~RUtgmc_defines/footsteps.dm b/code/__DEFINES/~RUtgmc_defines/footsteps.dm index 190ea48715ebf..949532e98455e 100644 --- a/code/__DEFINES/~RUtgmc_defines/footsteps.dm +++ b/code/__DEFINES/~RUtgmc_defines/footsteps.dm @@ -1,6 +1,7 @@ //footstep mob defines #define FOOTSTEP_XENO_STOMPY 6 +#define FOOTSTEP_PREDALIEN_STOMPY 7 //claw footsteps lists GLOBAL_LIST_INIT(xenostompy, list( @@ -62,3 +63,63 @@ GLOBAL_LIST_INIT(xenostompy, list( 'modular_RUtgmc/sound/effects/footstep/alien_footstep_large2.ogg', 'modular_RUtgmc/sound/effects/footstep/alien_footstep_large3.ogg'), 40, -1), )) + +GLOBAL_LIST_INIT(predalienstompy, list( + FOOTSTEP_WOOD = list(list( + 'modular_RUtgmc/sound/effects/footstep/alien_footstep_medium1.ogg', + 'modular_RUtgmc/sound/effects/footstep/alien_footstep_medium2.ogg', + 'modular_RUtgmc/sound/effects/footstep/alien_footstep_medium3.ogg'), 60, 1), + FOOTSTEP_PLATING = list(list( + 'modular_RUtgmc/sound/effects/footstep/alien_footstep_medium1.ogg', + 'modular_RUtgmc/sound/effects/footstep/alien_footstep_medium2.ogg', + 'modular_RUtgmc/sound/effects/footstep/alien_footstep_medium3.ogg'), 70, 1), + FOOTSTEP_FLOOR = list(list( + 'modular_RUtgmc/sound/effects/footstep/alien_footstep_medium1.ogg', + 'modular_RUtgmc/sound/effects/footstep/alien_footstep_medium2.ogg', + 'modular_RUtgmc/sound/effects/footstep/alien_footstep_medium3.ogg'), 70, 1), + FOOTSTEP_HARD = list(list( + 'modular_RUtgmc/sound/effects/footstep/alien_footstep_medium1.ogg', + 'modular_RUtgmc/sound/effects/footstep/alien_footstep_medium2.ogg', + 'modular_RUtgmc/sound/effects/footstep/alien_footstep_medium3.ogg'), 70, 1), + FOOTSTEP_CARPET = list(list( + 'modular_RUtgmc/sound/effects/footstep/alien_footstep_medium1.ogg', + 'modular_RUtgmc/sound/effects/footstep/alien_footstep_medium2.ogg', + 'modular_RUtgmc/sound/effects/footstep/alien_footstep_medium3.ogg'), 55, -1), + FOOTSTEP_SAND = list(list( + 'modular_RUtgmc/sound/effects/footstep/alien_footstep_medium1.ogg', + 'modular_RUtgmc/sound/effects/footstep/alien_footstep_medium2.ogg', + 'modular_RUtgmc/sound/effects/footstep/alien_footstep_medium3.ogg'), 55, 1), + FOOTSTEP_GRASS = list(list( + 'modular_RUtgmc/sound/effects/footstep/alien_footstep_medium1.ogg', + 'modular_RUtgmc/sound/effects/footstep/alien_footstep_medium2.ogg', + 'modular_RUtgmc/sound/effects/footstep/alien_footstep_medium3.ogg'), 65, 1), + FOOTSTEP_WATER = list(list( + 'sound/effects/footstep/water1.ogg', + 'sound/effects/footstep/water2.ogg', + 'sound/effects/footstep/water3.ogg', + 'sound/effects/footstep/water4.ogg'), 50, 1), + FOOTSTEP_CATWALK = list(list( + 'modular_RUtgmc/sound/effects/footstep/alien_footstep_medium1.ogg', + 'modular_RUtgmc/sound/effects/footstep/alien_footstep_medium2.ogg', + 'modular_RUtgmc/sound/effects/footstep/alien_footstep_medium3.ogg'), 70, 1), + FOOTSTEP_SNOW = list(list( + 'modular_RUtgmc/sound/effects/footstep/alien_footstep_medium1.ogg', + 'modular_RUtgmc/sound/effects/footstep/alien_footstep_medium2.ogg', + 'modular_RUtgmc/sound/effects/footstep/alien_footstep_medium3.ogg'), 70, 1), + FOOTSTEP_ICE = list(list( + 'modular_RUtgmc/sound/effects/footstep/alien_footstep_medium1.ogg', + 'modular_RUtgmc/sound/effects/footstep/alien_footstep_medium2.ogg', + 'modular_RUtgmc/sound/effects/footstep/alien_footstep_medium3.ogg'), 50, 1), + FOOTSTEP_CONCRETE = list(list( + 'modular_RUtgmc/sound/effects/footstep/alien_footstep_medium1.ogg', + 'modular_RUtgmc/sound/effects/footstep/alien_footstep_medium2.ogg', + 'modular_RUtgmc/sound/effects/footstep/alien_footstep_medium3.ogg'), 70, 1), + FOOTSTEP_GRAVEL = list(list( + 'modular_RUtgmc/sound/effects/footstep/alien_footstep_medium1.ogg', + 'modular_RUtgmc/sound/effects/footstep/alien_footstep_medium2.ogg', + 'modular_RUtgmc/sound/effects/footstep/alien_footstep_medium3.ogg'), 55, 1), + FOOTSTEP_RESIN = list(list( + 'modular_RUtgmc/sound/effects/footstep/alien_footstep_medium1.ogg', + 'modular_RUtgmc/sound/effects/footstep/alien_footstep_medium2.ogg', + 'modular_RUtgmc/sound/effects/footstep/alien_footstep_medium3.ogg'), 40, -1), + )) diff --git a/code/__DEFINES/~RUtgmc_defines/is_helpers.dm b/code/__DEFINES/~RUtgmc_defines/is_helpers.dm index ac95406f4249f..55d9bc9a203d8 100644 --- a/code/__DEFINES/~RUtgmc_defines/is_helpers.dm +++ b/code/__DEFINES/~RUtgmc_defines/is_helpers.dm @@ -8,5 +8,16 @@ //Gamemode #define isdistressgamemode(O) (istype(O, /datum/game_mode/infestation/distress)) +#define isresearcher(A) (ishuman(A) && A.job.title == "Medical Researcher") +#define isyautja(H) (is_species(H, /datum/species/yautja)) + +#define ispredatorjob(J) (istype(J, /datum/job/predator)) + +#define ispredalien(A) (istype(A, /mob/living/carbon/xenomorph/predalien)) +#define isxenopredalienlarva(A) (istype(A, /mob/living/carbon/xenomorph/larva/predalien)) +#define isxenohellhound(A) (istype(A, /mob/living/carbon/xenomorph/hellhound)) + +// Why not using A in list(...)? +#define isxenohive(A) ((A == XENO_HIVE_NONE) || (A == XENO_HIVE_NORMAL) || (A == XENO_HIVE_CORRUPTED) || (A == XENO_HIVE_ALPHA) || (A == XENO_HIVE_BETA) || (A == XENO_HIVE_ZETA) || (A == XENO_HIVE_ADMEME)) || (A == XENO_HIVE_FALLEN) || (A == XENO_HIVE_FORSAKEN) || (A == XENO_HIVE_YAUTJA) //Objects #define iscontainmentshutter(A) (istype(A, /obj/machinery/door/poddoor/timed_late/containment/landing_zone)) diff --git a/code/__DEFINES/~RUtgmc_defines/minimap.dm b/code/__DEFINES/~RUtgmc_defines/minimap.dm new file mode 100644 index 0000000000000..a11b9948e8c0c --- /dev/null +++ b/code/__DEFINES/~RUtgmc_defines/minimap.dm @@ -0,0 +1 @@ +#define MINIMAP_FLAG_YAUTJA (1<<5) diff --git a/code/__DEFINES/~RUtgmc_defines/mobs.dm b/code/__DEFINES/~RUtgmc_defines/mobs.dm index 6885d11f5e283..ebe237eafbd28 100644 --- a/code/__DEFINES/~RUtgmc_defines/mobs.dm +++ b/code/__DEFINES/~RUtgmc_defines/mobs.dm @@ -17,3 +17,13 @@ #define HIVE_CAN_COLLAPSE_FROM_SILO (1<<1) #define XENO_WEAK_ACID_PUDDLE_DAMAGE 8 //Weak acid damage dealt by acid puddles #define XENO_HIGH_ACID_PUDDLE_DAMAGE 20 //Strong acid damage dealt by acid puddles + +#define IS_YAUTJA (1<<6) + +#define MOTH_WINGS_LAYER 28 +#define MUTATIONS_LAYER 27 +#define DAMAGE_LAYER 26 +#define FLAY_LAYER 25 +#define PRED_LASER_LAYER 1.9 +#define LASER_LAYER 1.8 +#define TOTAL_LAYERS 30 diff --git a/code/__DEFINES/~RUtgmc_defines/mode.dm b/code/__DEFINES/~RUtgmc_defines/mode.dm index ca14930e6338e..de07d0b4cb133 100644 --- a/code/__DEFINES/~RUtgmc_defines/mode.dm +++ b/code/__DEFINES/~RUtgmc_defines/mode.dm @@ -8,3 +8,40 @@ //Distress mode collapse duration #define DISTRESS_SILO_COLLAPSE 5 MINUTES + +#define WHITELIST_YAUTJA (1<<0) +///Old holders of YAUTJA_ELDER +#define WHITELIST_YAUTJA_LEGACY (1<<1) +#define WHITELIST_YAUTJA_COUNCIL (1<<2) +///Old holders of YAUTJA_COUNCIL for 3 months +#define WHITELIST_YAUTJA_COUNCIL_LEGACY (1<<3) +#define WHITELIST_YAUTJA_LEADER (1<<4) +#define WHITELIST_PREDATOR (WHITELIST_YAUTJA|WHITELIST_YAUTJA_LEGACY|WHITELIST_YAUTJA_COUNCIL|WHITELIST_YAUTJA_COUNCIL_LEGACY|WHITELIST_YAUTJA_LEADER) + +#define WHITELIST_NORMAL "Normal" +#define WHITELIST_COUNCIL "Council" +#define WHITELIST_LEADER "Leader" + +#define WHITELIST_HIERARCHY list(WHITELIST_NORMAL, WHITELIST_COUNCIL, WHITELIST_LEADER) + +/proc/get_desired_status(desired_status, status_limit) + var/found_desired = FALSE + var/found_limit = FALSE + + for(var/status in WHITELIST_HIERARCHY) + if(status == desired_status) + found_desired = TRUE + break + if(status == status_limit) + found_limit = TRUE + break + + if(found_desired) + return desired_status + else if(found_limit) + return status_limit + + return desired_status + +#define MODE_SHIPSIDE_SD (1<<16) +#define MODE_PREDATOR (1<<17) diff --git a/code/__DEFINES/~RUtgmc_defines/predators.dm b/code/__DEFINES/~RUtgmc_defines/predators.dm new file mode 100644 index 0000000000000..ae7fb2b101c07 --- /dev/null +++ b/code/__DEFINES/~RUtgmc_defines/predators.dm @@ -0,0 +1,165 @@ +#define PREDATOR_TO_TOTAL_SPAWN_RATIO 1/20 + +#define INIT_ORDER_PREDSHIPS -22 + +// Yautja Access Levels +/// Requires a visible ID chip to open +#define ACCESS_YAUTJA_SECURE 250 +/// Elders+ only +#define ACCESS_YAUTJA_ELDER 251 +/// Ancients only +#define ACCESS_YAUTJA_ANCIENT 252 + +#define ACCESSORY_SLOT_ARMOR_C "chest_armor" + +#define ACCESSORY_SLOT_ARMOR_A "arm_armor" +#define ACCESSORY_SLOT_ARMOR_L "leg_armor" +#define ACCESSORY_SLOT_ARMOR_S "armor_storage" +#define ACCESSORY_SLOT_ARMOR_M "misc_armor" + +#define ACCESSORY_SLOT_ARMOR_Y_C "chest_bones" +#define ACCESSORY_SLOT_ARMOR_Y_S "spine_bones" +#define ACCESSORY_SLOT_ARMOR_Y_H "head_bones" +#define ACCESSORY_SLOT_ARMOR_Y_RL "right_leg_bones" +#define ACCESSORY_SLOT_ARMOR_Y_LL "left_leg_bones" +#define ACCESSORY_SLOT_ARMOR_Y_RH "right_hand_bones" +#define ACCESSORY_SLOT_ARMOR_Y_LH "left_hand_bones" + +#define FACTION_YAUTJA "Yautja" +#define XENO_HIVE_FORSAKEN "forsaken_hive" +#define XENO_HIVE_YAUTJA "yautja_hive" + +#define JOB_PREDATOR "Predator" + +#define CATEGORY_YAUTJA "YAUTJA" +#define HUNTERSHIPS_TEMPLATE_PATH "_maps/~RUTGMC/predship/huntership.dmm" + +#define DUMMY_PRED_SLOT_PREFERENCES "dummy_preference_preview_second" + +#define PRED_MATERIALS list("ebony", "silver", "bronze", "crimson", "bone") +#define PRED_TRANSLATORS list("Modern", "Retro", "Combo") +#define PRED_LEGACIES list("None", "Dragon", "Swamp", "Enforcer", "Collector") +#define PRED_SKIN_COLOR list("Tan", "Green", "Purple", "Blue", "Red", "Black") + +#define PRED_YAUTJA_CAPE "yautja cape" +#define PRED_YAUTJA_CEREMONIAL_CAPE "yautja ceremonial cape" +#define PRED_YAUTJA_THIRD_CAPE "yautja third-cape" +#define PRED_YAUTJA_HALF_CAPE "yautja half-cape" +#define PRED_YAUTJA_QUARTER_CAPE "yautja quarter-cape" +#define PRED_YAUTJA_PONCHO "yautja poncho" + +#define SD_TYPE_BIG 0 +#define SD_TYPE_SMALL 1 + +///Sound volume defines +#define BLOCK_SOUND_VOLUME 70 +#define CLAN_PERMISSION_USER_VIEW 1 + +/// Modify ranks within clan +#define CLAN_PERMISSION_USER_MODIFY 2 + +#define CLAN_PERMISSION_USER_ALL (CLAN_PERMISSION_USER_MODIFY|CLAN_PERMISSION_USER_VIEW) + +/// View all clans +#define CLAN_PERMISSION_ADMIN_VIEW 4 +/// Modify all clans +#define CLAN_PERMISSION_ADMIN_MODIFY 8 +/// Move people to and from clans +#define CLAN_PERMISSION_ADMIN_MOVE 16 +/// Manages the ancients +#define CLAN_PERMISSION_ADMIN_MANAGER 32 + +#define CLAN_PERMISSION_ADMIN_ANCIENT (CLAN_PERMISSION_ADMIN_VIEW|CLAN_PERMISSION_ADMIN_MODIFY|CLAN_PERMISSION_ADMIN_MOVE) +#define CLAN_PERMISSION_ADMIN_ALL (CLAN_PERMISSION_ADMIN_ANCIENT|CLAN_PERMISSION_ADMIN_MANAGER) + +#define CLAN_PERMISSION_MODIFY (CLAN_PERMISSION_ADMIN_MODIFY|CLAN_PERMISSION_USER_MODIFY) +#define CLAN_PERMISSION_VIEW (CLAN_PERMISSION_USER_VIEW|CLAN_PERMISSION_ADMIN_VIEW) + +#define CLAN_PERMISSION_ALL (CLAN_PERMISSION_USER_ALL|CLAN_PERMISSION_ADMIN_ALL) + +/// Unused for the moment +#define CLAN_RANK_UNBLOODED "Unblooded" +/// Clanless +#define CLAN_RANK_YOUNG "Young Blood" +/// New to the clan +#define CLAN_RANK_BLOODED "Blooded" + +#define CLAN_RANK_ELITE "Elite" +#define CLAN_RANK_ELDER "Elder" +#define CLAN_RANK_LEADER "Clan Leader" + +/// Must be given by someone with CLAN_PERMISSION_ADMIN_MODIFY +#define CLAN_RANK_ADMIN "Ancient" + +#define CLAN_RANK_UNBLOODED_INT 1 +#define CLAN_RANK_YOUNG_INT 2 +#define CLAN_RANK_BLOODED_INT 3 +#define CLAN_RANK_ELITE_INT 4 +#define CLAN_RANK_ELDER_INT 5 +#define CLAN_RANK_LEADER_INT 6 +#define CLAN_RANK_ADMIN_INT 7 + +/// Hard limit +#define CLAN_LIMIT_NUMBER 1 +/// Scales with clan size +#define CLAN_LIMIT_SIZE 2 + +GLOBAL_LIST_INIT_TYPED(clan_ranks, /datum/yautja_rank, list( + CLAN_RANK_UNBLOODED = new /datum/yautja_rank/unblooded(), + CLAN_RANK_YOUNG = new /datum/yautja_rank/young(), + CLAN_RANK_BLOODED = new /datum/yautja_rank/blooded(), + CLAN_RANK_ELITE = new /datum/yautja_rank/elite(), + CLAN_RANK_ELDER = new /datum/yautja_rank/elder(), + CLAN_RANK_LEADER = new /datum/yautja_rank/leader(), + CLAN_RANK_ADMIN = new /datum/yautja_rank/ancient() +)) + +GLOBAL_LIST_INIT(clan_ranks_ordered, list( + CLAN_RANK_UNBLOODED = CLAN_RANK_UNBLOODED_INT, + CLAN_RANK_YOUNG = CLAN_RANK_YOUNG_INT, + CLAN_RANK_BLOODED = CLAN_RANK_BLOODED_INT, + CLAN_RANK_ELITE = CLAN_RANK_ELITE_INT, + CLAN_RANK_ELDER = CLAN_RANK_ELDER_INT, + CLAN_RANK_LEADER = CLAN_RANK_LEADER_INT, + CLAN_RANK_ADMIN = CLAN_RANK_ADMIN_INT +)) + +#define CLAN_HREF "clan_href" +#define CLAN_TARGET_HREF "clan_target_href" + +#define CLAN_ACTION "clan_action" + +/// Set name of clan +#define CLAN_ACTION_CLAN_RENAME "rename" +/// Set description of clan +#define CLAN_ACTION_CLAN_SETDESC "setdesc" +/// Set honor of clan +#define CLAN_ACTION_CLAN_SETHONOR "sethonor" + +#define CLAN_ACTION_CLAN_DELETE "delete" +#define CLAN_ACTION_CLAN_SETCOLOR "setcolor" + +/// Set a player's clan +#define CLAN_ACTION_PLAYER_MOVECLAN "moveclan" +/// Set a player's rank. Resets when moved from clan to Young Blood +#define CLAN_ACTION_PLAYER_MODIFYRANK "modifyrank" + +#define CLAN_ACTION_PLAYER_PURGE "purge" + +#define NO_CLAN_LIST list(\ + clan_id = null,\ + clan_name = "Clanless",\ + clan_description = "This is a list of players without a clan",\ + clan_honor = null,\ + clan_keys = list(),\ + \ + player_delete_clan = FALSE,\ + player_sethonor_clan = FALSE,\ + player_rename_clan = FALSE,\ + player_setdesc_clan = FALSE,\ + player_modify_ranks = FALSE,\ + \ + player_move_clans = (clan_info.permissions & CLAN_PERMISSION_ADMIN_MOVE)\ + ) + +#define CLAN_SHIP_PUBLIC -1 diff --git a/code/__DEFINES/~RUtgmc_defines/preferences.dm b/code/__DEFINES/~RUtgmc_defines/preferences.dm index b118fe8b65690..74fdd3449699f 100644 --- a/code/__DEFINES/~RUtgmc_defines/preferences.dm +++ b/code/__DEFINES/~RUtgmc_defines/preferences.dm @@ -1,3 +1,11 @@ +#define PRED_CHARACTER_CUSTOMIZATION 2 +#define BACKGROUND_INFORMATION 3 +#define GEAR_CUSTOMIZATION 4 +#define JOB_PREFERENCES 5 +#define GAME_SETTINGS 6 +#define KEYBIND_SETTINGS 7 +#define DRAW_ORDER 8 + #define WIDESCREEN_RESOLUTIONS list(\ CONFIG_GET(string/default_view1),\ CONFIG_GET(string/default_view2),\ diff --git a/code/__DEFINES/~RUtgmc_defines/span.dm b/code/__DEFINES/~RUtgmc_defines/span.dm new file mode 100644 index 0000000000000..aaa9808cfe90e --- /dev/null +++ b/code/__DEFINES/~RUtgmc_defines/span.dm @@ -0,0 +1,11 @@ +#define span_yautjabold(str) "" + str + "" +#define span_yautjaboldbig(str) "" + str + "" + +// Colors +#define span_blue(str) "" + str + "" +#define span_green(str) ("" + str + "") +#define span_red(str) ("" + str + "") +#define span_orange(str) ("" + str + "") + +#define font_size_huge(str) "" + str + "" +#define font_size_xl(str) "" + str + "" diff --git a/code/__DEFINES/~RUtgmc_defines/traits.dm b/code/__DEFINES/~RUtgmc_defines/traits.dm index eb08e8bcbf614..9bf03665a8b68 100644 --- a/code/__DEFINES/~RUtgmc_defines/traits.dm +++ b/code/__DEFINES/~RUtgmc_defines/traits.dm @@ -1,2 +1,9 @@ //mob traits #define TRAIT_BANISHED "banished" + +/// Knowledge of Yautja technology +#define TRAIT_YAUTJA_TECH "t_yautja_tech" +/// Absolutely RIPPED. Can do misc. heavyweight stuff others can't. (Yautja, Synths) +#define TRAIT_SUPER_STRONG "t_super_strong" +/// Foreign biology. Basic medHUDs won't show the mob. (Yautja, Zombies) +#define TRAIT_FOREIGN_BIO "t_foreign_bio" diff --git a/code/__HELPERS/mobs.dm b/code/__HELPERS/mobs.dm index b86b11f2e5daa..e6d8c69878529 100644 --- a/code/__HELPERS/mobs.dm +++ b/code/__HELPERS/mobs.dm @@ -1,5 +1,6 @@ /proc/random_ethnicity() - return pick(GLOB.ethnicities_list) + //return pick(GLOB.ethnicities_list) Original + return pick(GLOB.human_ethnicities_list) //RU TGMC EDIT /proc/random_hair_style(gender, species = "Human") var/list/valid_hairstyles = list() diff --git a/code/_globalvars/lists/flavor_misc.dm b/code/_globalvars/lists/flavor_misc.dm index b70e18677cb1c..affca044d8edc 100644 --- a/code/_globalvars/lists/flavor_misc.dm +++ b/code/_globalvars/lists/flavor_misc.dm @@ -1,4 +1,5 @@ //Preferences stuff +/* RUTGMC EDIT EDITION GLOBAL_LIST_INIT(ethnicities_list, init_ethnicities()) /// Ethnicity - Initialise all /datum/ethnicity into a list indexed by ethnicity name @@ -7,7 +8,7 @@ GLOBAL_LIST_INIT(ethnicities_list, init_ethnicities()) for(var/path in subtypesof(/datum/ethnicity)) var/datum/ethnicity/E = new path() .[E.name] = E - +*/ //Hairstyles GLOBAL_LIST_EMPTY(hair_styles_list) //stores /datum/sprite_accessory/hair indexed by name GLOBAL_LIST_EMPTY(hair_gradients_list) //stores /datum/sprite_accessory/hair_gradient indexed by name diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm index d97faf2dd2221..873b0dcda3f32 100644 --- a/code/_onclick/item_attack.dm +++ b/code/_onclick/item_attack.dm @@ -171,6 +171,8 @@ /obj/item/proc/attack(mob/living/M, mob/living/user) + if(SEND_SIGNAL(M, COMSIG_ITEM_ATTEMPT_ATTACK, user, src) & COMPONENT_ITEM_NO_ATTACK) //Sent by target mob. + return FALSE if(SEND_SIGNAL(src, COMSIG_ITEM_ATTACK, M, user) & COMPONENT_ITEM_NO_ATTACK) return FALSE if(SEND_SIGNAL(user, COMSIG_MOB_ITEM_ATTACK, M, src) & COMPONENT_ITEM_NO_ATTACK) diff --git a/code/controllers/subsystem/dbcore.dm b/code/controllers/subsystem/dbcore.dm index 6d4cb7d3aab5a..97c0f36c36023 100644 --- a/code/controllers/subsystem/dbcore.dm +++ b/code/controllers/subsystem/dbcore.dm @@ -29,7 +29,7 @@ SUBSYSTEM_DEF(dbcore) /datum/controller/subsystem/dbcore/fire() for(var/I in active_queries) var/datum/db_query/Q = I - if(world.time - Q.last_activity_time > (5 MINUTES)) + if(world.time - Q.last_activity_time > (5 MINUTES) && !Q.no_auto_delete) //RU TGMC EDIT message_admins("Found undeleted query, please check the server logs and notify coders.") log_sql("Undeleted query: \"[Q.sql]\" LA: [Q.last_activity] LAT: [Q.last_activity_time]") qdel(Q) diff --git a/code/datums/actions/observer_action.dm b/code/datums/actions/observer_action.dm index c62bc643645f5..ba7c0325a8e84 100644 --- a/code/datums/actions/observer_action.dm +++ b/code/datums/actions/observer_action.dm @@ -48,7 +48,7 @@ var/list/mob/living/free_ssd_mobs = list() for(var/mob/living/ssd_mob AS in GLOB.ssd_living_mobs) - if(is_centcom_level(ssd_mob.z) || ssd_mob.afk_status == MOB_RECENTLY_DISCONNECTED) + if(is_centcom_level(ssd_mob.z) || ssd_mob.afk_status == MOB_RECENTLY_DISCONNECTED || isyautja(ssd_mob)) continue free_ssd_mobs += ssd_mob diff --git a/code/datums/atom_hud.dm b/code/datums/atom_hud.dm index 18bf961e43be3..496bc837685d9 100644 --- a/code/datums/atom_hud.dm +++ b/code/datums/atom_hud.dm @@ -20,6 +20,10 @@ GLOBAL_LIST_INIT_TYPED(huds, /datum/atom_hud, list( DATA_HUD_SQUAD_SOM = new /datum/atom_hud/squad_som, DATA_HUD_XENO_DEBUFF = new /datum/atom_hud/xeno_debuff, DATA_HUD_XENO_HEART = new /datum/atom_hud/xeno_heart, + //RU TGMC EDIT + DATA_HUD_HUNTER = new /datum/atom_hud/hunter_hud, + DATA_HUD_HUNTER_CLAN = new /datum/atom_hud/hunter_clan + //RU TGMC EDIT )) diff --git a/code/datums/components/bump_attack.dm b/code/datums/components/bump_attack.dm index 3311609b4f92e..94fef2e61306c 100644 --- a/code/datums/components/bump_attack.dm +++ b/code/datums/components/bump_attack.dm @@ -58,7 +58,7 @@ if(TIMER_COOLDOWN_CHECK(src, COOLDOWN_BUMP_ATTACK)) return NONE var/mob/living/bumper = parent - if(!(target.flags_atom & BUMP_ATTACKABLE) || bumper.throwing || bumper.incapacitated()) + if(!(target.flags_atom & BUMP_ATTACKABLE) || bumper.throwing || bumper.incapacitated() || HAS_TRAIT(target, TRAIT_TURRET_HIDDEN)) //RU TGMC EDIT return NONE ///Handles carbon bump action checks before actually doing the attack checks. diff --git a/code/datums/elements/footstep.dm b/code/datums/elements/footstep.dm index 574b42899879a..fa820a46ff2ae 100644 --- a/code/datums/elements/footstep.dm +++ b/code/datums/elements/footstep.dm @@ -44,6 +44,8 @@ //RUTGMC EDIT ADDITION BEGIN - XENO_STOMP if(FOOTSTEP_XENO_STOMPY) footstep_sounds = GLOB.xenostompy + if(FOOTSTEP_PREDALIEN_STOMPY) + footstep_sounds = GLOB.predalienstompy //RUTGMC EDIT ADDITION END RegisterSignal(target, COMSIG_MOVABLE_MOVED, PROC_REF(simplestep_wrapper)) RegisterSignal(target, COMSIG_ELEMENT_JUMP_ENDED, PROC_REF(play_simplestep)) @@ -144,6 +146,8 @@ //RUTGMC EDIT ADDITION BEGIN - XENO_STOMP if(FOOTSTEP_XENO_STOMPY) turf_footstep = source_loc.mediumxenofootstep + if(FOOTSTEP_PREDALIEN_STOMPY) + turf_footstep = source_loc.mediumxenofootstep //RUTGMC EDIT ADDITION END if(!turf_footstep) return diff --git a/code/datums/gamemodes/_game_mode.dm b/code/datums/gamemodes/_game_mode.dm index 8e3e326484230..0cbe77d118a20 100644 --- a/code/datums/gamemodes/_game_mode.dm +++ b/code/datums/gamemodes/_game_mode.dm @@ -493,6 +493,8 @@ GLOBAL_LIST_INIT(bioscan_locations, list( var/mob/living/carbon/human/H = i if(!istype(H)) // Small fix? continue + if(isyautja(H)) //RU TGMC EDIT + continue if(count_flags & COUNT_IGNORE_HUMAN_SSD && !H.client && H.afk_status == MOB_DISCONNECTED) continue if(H.status_flags & XENO_HOST) @@ -508,7 +510,7 @@ GLOBAL_LIST_INIT(bioscan_locations, list( for(var/z in z_levels) for(var/i in GLOB.hive_datums[XENO_HIVE_NORMAL].xenos_by_zlevel["[z]"]) var/mob/living/carbon/xenomorph/X = i - if(!istype(X)) // Small fix? + if(!istype(X) || isxenohellhound(X)) // Small fix? and // RU TGMC EDIT continue if(count_flags & COUNT_IGNORE_XENO_SSD && !X.client && X.afk_status == MOB_DISCONNECTED) continue diff --git a/code/datums/jobs/job/job.dm b/code/datums/jobs/job/job.dm index 4848236866dd3..2d14d82542574 100644 --- a/code/datums/jobs/job/job.dm +++ b/code/datums/jobs/job/job.dm @@ -118,7 +118,7 @@ GLOBAL_PROTECT(exp_specialmap) if(!mannequin) CRASH("equip_dummy called without a mannequin") - mannequin.equipOutfit(outfit_override || outfit, TRUE) + mannequin.equipOutfit(outfit_override || outfit, TRUE, preference_source) /datum/job/proc/get_access() @@ -185,7 +185,7 @@ GLOBAL_PROTECT(exp_specialmap) return -/datum/outfit/job/proc/handle_id(mob/living/carbon/human/H) +/datum/outfit/job/proc/handle_id(mob/living/carbon/human/H, client/override_client) var/datum/job/job = H.job ? H.job : SSjob.GetJobType(jobtype) var/obj/item/card/id/id = H.wear_id if(istype(id)) @@ -280,6 +280,8 @@ GLOBAL_PROTECT(exp_specialmap) // Spawning mobs. /mob/living/proc/apply_assigned_role_to_spawn(datum/job/assigned_role, client/player, datum/squad/assigned_squad, admin_action = FALSE) + if(!player && client) + player = client job = assigned_role set_skills(getSkillsType(job.return_skills_type(player?.prefs))) faction = job.faction @@ -321,7 +323,16 @@ GLOBAL_PROTECT(exp_specialmap) job.outfit.handle_id(src, player) - equip_role_outfit(job) + var/job_whitelist = job.title + var/whitelist_status = job.get_whitelist_status(GLOB.roles_whitelist, player) + + if(whitelist_status) + job_whitelist = "[job_whitelist][whitelist_status]" + + if(job.gear_preset_whitelist[job_whitelist]) + job.gear_preset_whitelist[job_whitelist].equip(src, override_client = player) + else + equip_role_outfit(job) if((job.job_flags & JOB_FLAG_ALLOWS_PREFS_GEAR) && player) equip_preference_gear(player) @@ -371,7 +382,7 @@ GLOBAL_PROTECT(exp_specialmap) /datum/job/proc/return_skills_type(datum/preferences/prefs) return skills_type -/datum/job/proc/return_spawn_turf() +/datum/job/proc/return_spawn_turf(mob/living/new_character, client/player) return pick(GLOB.spawns_by_job[type]) /datum/job/proc/handle_special_preview(client/parent) diff --git a/code/datums/jobs/job/xenomorph.dm b/code/datums/jobs/job/xenomorph.dm index e822b64bb7c36..fc911cd953246 100644 --- a/code/datums/jobs/job/xenomorph.dm +++ b/code/datums/jobs/job/xenomorph.dm @@ -26,7 +26,7 @@ /datum/job/xenomorph/return_spawn_type(datum/preferences/prefs) return /mob/living/carbon/xenomorph/larva -/datum/job/xenomorph/return_spawn_turf() +/datum/job/xenomorph/return_spawn_turf(mob/living/new_character, client/player) if(length(GLOB.xeno_resin_silos_by_hive[XENO_HIVE_NORMAL])) return pick(GLOB.xeno_resin_silos_by_hive[XENO_HIVE_NORMAL]) return pick(GLOB.spawns_by_job[/datum/job/xenomorph]) @@ -75,7 +75,7 @@ /datum/job/xenomorph/queen/return_spawn_type(datum/preferences/prefs) return /mob/living/carbon/xenomorph/shrike -/datum/job/xenomorph/queen/return_spawn_turf() +/datum/job/xenomorph/queen/return_spawn_turf(mob/living/new_character, client/player) return pick(GLOB.spawns_by_job[/datum/job/xenomorph]) /datum/job/xenomorph/queen/radio_help_message(mob/M) diff --git a/code/datums/outfit.dm b/code/datums/outfit.dm index b9e17771e33a1..192f03f281a56 100644 --- a/code/datums/outfit.dm +++ b/code/datums/outfit.dm @@ -40,8 +40,8 @@ return -/datum/outfit/proc/equip(mob/living/carbon/human/H, visualsOnly = FALSE) - pre_equip(H, visualsOnly) +/datum/outfit/proc/equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/override_client) + pre_equip(H, visualsOnly, override_client) //Start with uniform,suit,backpack for additional slots if(w_uniform) diff --git a/code/datums/quick_load_outfits.dm b/code/datums/quick_load_outfits.dm index da809750cf9e4..c2e5626782bca 100644 --- a/code/datums/quick_load_outfits.dm +++ b/code/datums/quick_load_outfits.dm @@ -7,8 +7,8 @@ var/jobtype = "Squad Marine" -/datum/outfit/quick/equip(mob/living/carbon/human/H, visualsOnly = FALSE) - pre_equip(H, visualsOnly) +/datum/outfit/quick/equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/override_client) + pre_equip(H, visualsOnly, override_client) //Start with uniform,suit,backpack for additional slots. Deletes any existing equipped item to avoid accidentally losing half your loadout. Not suitable for standard gamemodes! if(w_uniform) diff --git a/code/datums/weather/weather_types/acid_rain.dm b/code/datums/weather/weather_types/acid_rain.dm index 19f48eb3f81d3..8291d75182a5c 100644 --- a/code/datums/weather/weather_types/acid_rain.dm +++ b/code/datums/weather/weather_types/acid_rain.dm @@ -56,7 +56,16 @@ L.clean_mob() if(L.fire_stacks > -20) L.fire_stacks = max(-20, L.fire_stacks - 1) - +// RU TGMC EDIT + if(ishuman(L)) + var/mob/living/carbon/human/human = L + if(!istype(human.gloves, /obj/item/clothing/gloves/yautja/hunter)) + return + var/obj/item/clothing/gloves/yautja/hunter/gloves = human.gloves + if(gloves.cloaked) + gloves.decloak(L) + to_chat(L, span_highdanger("Rain interferes with your cloaking device!")) +// RU TGMC EDIT /datum/weather/acid_rain/harmless target_trait = ZTRAIT_RAIN @@ -89,3 +98,13 @@ "As you move through the heavy rain, your clothes become completely waterlogged!", ) to_chat(L, span_warning(wetmessage)) +// RU TGMC EDIT + if(ishuman(L)) + var/mob/living/carbon/human/human = L + if(!istype(human.gloves, /obj/item/clothing/gloves/yautja/hunter)) + return + var/obj/item/clothing/gloves/yautja/hunter/gloves = human.gloves + if(gloves.cloaked) + gloves.decloak(L) + to_chat(L, span_highdanger("Rain interferes with your cloaking device!")) +// RU TGMC EDIT diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index 3d7f0531a2ee3..0c4d920b43cdd 100755 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -24,8 +24,9 @@ var/atom/movable/pulling var/atom/movable/moving_from_pull //attempt to resume grab after moving instead of before. var/glide_modifier_flags = NONE - +/* RU TGMC EDIT var/status_flags = CANSTUN|CANKNOCKDOWN|CANKNOCKOUT|CANPUSH|CANUNCONSCIOUS|CANCONFUSE //bitflags defining which status effects can be inflicted (replaces canweaken, canstun, etc) +RU TGMC EDIT */ var/generic_canpass = TRUE ///What things this atom can move past, if it has the corrosponding flag var/pass_flags = NONE diff --git a/code/game/communications.dm b/code/game/communications.dm index b6e59c9739c99..d0d8ea5fef459 100644 --- a/code/game/communications.dm +++ b/code/game/communications.dm @@ -94,6 +94,9 @@ GLOBAL_LIST_EMPTY(all_radios) GLOBAL_LIST_INIT(radiochannels, list( RADIO_CHANNEL_COMMON = FREQ_COMMON, +//RUTGMC EDIT + RADIO_CHANNEL_YAUTJA = YAUT_FREQ, +//RUTGMC EDIT RADIO_CHANNEL_REQUISITIONS = FREQ_REQUISITIONS, RADIO_CHANNEL_COMMAND = FREQ_COMMAND, RADIO_CHANNEL_MEDICAL = FREQ_MEDICAL, @@ -125,6 +128,7 @@ GLOBAL_LIST_INIT(radiochannels, list( GLOBAL_LIST_INIT(reverseradiochannels, list( "[FREQ_COMMON]" = RADIO_CHANNEL_COMMON, + "[YAUT_FREQ]" = RADIO_CHANNEL_YAUTJA, "[FREQ_REQUISITIONS]" = RADIO_CHANNEL_REQUISITIONS, "[FREQ_COMMAND]" = RADIO_CHANNEL_COMMAND, "[FREQ_MEDICAL]" = RADIO_CHANNEL_MEDICAL, diff --git a/code/game/data_huds.dm b/code/game/data_huds.dm index c2665aaaf0ed2..6927da95a7ed9 100644 --- a/code/game/data_huds.dm +++ b/code/game/data_huds.dm @@ -378,7 +378,6 @@ /mob/living/carbon/human/med_pain_set_perceived_health() if(species?.species_flags & IS_SYNTHETIC) return FALSE - var/image/holder = hud_list[PAIN_HUD] if(stat == DEAD) holder.icon_state = "hudhealth-100" diff --git a/code/game/objects/effects/step_triggers.dm b/code/game/objects/effects/step_triggers.dm index 0262f83690c3c..309f08b9d5fae 100644 --- a/code/game/objects/effects/step_triggers.dm +++ b/code/game/objects/effects/step_triggers.dm @@ -116,7 +116,9 @@ return if(teleport_x && teleport_y && teleport_z) - +// RU TGMC EDIT + SEND_SIGNAL(A, COMSIG_ATOM_TELEPORT, src) +// RU TGMC EDIT switch(teleportation_type) if(1) sleep(animation_teleport_quick_out(A)) //Sleep for the duration of the animation. @@ -126,10 +128,14 @@ sleep(animation_teleport_spooky_out(A)) if(A?.loc) +/* A.x = teleport_x A.y = teleport_y A.z = teleport_z - +*/ +// RUTGMC EDIT + A.forceMove(get_turf(locate(teleport_x, teleport_y, teleport_z))) +//RUTGMC EDIT switch(teleportation_type) if(1) animation_teleport_quick_in(A) diff --git a/code/game/objects/effects/weeds.dm b/code/game/objects/effects/weeds.dm index 06f65bec05fb4..1cea8b0dd0e3f 100644 --- a/code/game/objects/effects/weeds.dm +++ b/code/game/objects/effects/weeds.dm @@ -151,6 +151,11 @@ vehicle.last_move_time += WEED_SLOWDOWN return +//RU TGMC EDIT + if(HAS_TRAIT(crosser, TRAIT_SUPER_STRONG)) + return +//RU TGMC EDIT + if(isxeno(crosser)) var/mob/living/carbon/xenomorph/X = crosser X.next_move_slowdown += X.xeno_caste.weeds_speed_mod @@ -324,6 +329,11 @@ vehicle.last_move_time += WEED_SLOWDOWN return +//RU TGMC EDIT + if(HAS_TRAIT(crosser, TRAIT_SUPER_STRONG)) + return +//RU TGMC EDIT + if(!ishuman(crosser)) return diff --git a/code/game/objects/items/motion_detector.dm b/code/game/objects/items/motion_detector.dm index 550d58efffd2e..6afe631102738 100644 --- a/code/game/objects/items/motion_detector.dm +++ b/code/game/objects/items/motion_detector.dm @@ -137,6 +137,10 @@ if(nearby_human.last_move_time + move_sensitivity < world.time) continue RU TGMC EDIT */ +//RU TGMC EDIT + if(HAS_TRAIT(nearby_human, TRAIT_LIGHT_STEP)) + continue +//RUTGMC EDIT ADDITION END prepare_blip(nearby_human, nearby_human.wear_id?.iff_signal & operator.wear_id.iff_signal ? MOTION_DETECTOR_FRIENDLY : MOTION_DETECTOR_HOSTILE) for (var/mob/living/carbon/xenomorph/nearby_xeno AS in cheap_get_xenos_near(operator, range)) /* RU TGMC EDIT diff --git a/code/game/objects/items/scanners.dm b/code/game/objects/items/scanners.dm index b3b003f5731c5..0adbe90c14a7a 100644 --- a/code/game/objects/items/scanners.dm +++ b/code/game/objects/items/scanners.dm @@ -109,6 +109,11 @@ REAGENT SCANNER if(isxeno(M)) balloon_alert(user, "Unknown entity") return +//RU TGMC EDIT + if(HAS_TRAIT(M, TRAIT_FOREIGN_BIO) && !alien) + balloon_alert(user, "Unknown biology") + return +//RU TGMC EDIT if(M.species.species_flags & NO_SCAN) balloon_alert(user, "Not Organic") return diff --git a/code/game/objects/items/stacks/medical.dm b/code/game/objects/items/stacks/medical.dm index 595953a730eae..44d5863abcb4f 100644 --- a/code/game/objects/items/stacks/medical.dm +++ b/code/game/objects/items/stacks/medical.dm @@ -38,7 +38,11 @@ return var/datum/limb/affecting = user.client.prefs.toggles_gameplay & RADIAL_MEDICAL ? radial_medical(target, user) : target.get_limb(user.zone_selected) - +//RU TGMC EDIT + if(HAS_TRAIT(target, TRAIT_FOREIGN_BIO) && !alien) + to_chat(user, span_warning("\The [src] is incompatible with the biology of [target]!")) + return TRUE +//RU TGMC EDIT if(!affecting) return FALSE diff --git a/code/game/objects/items/tools/maintenance_tools.dm b/code/game/objects/items/tools/maintenance_tools.dm index c923a622c62c3..940466d749b25 100644 --- a/code/game/objects/items/tools/maintenance_tools.dm +++ b/code/game/objects/items/tools/maintenance_tools.dm @@ -79,7 +79,7 @@ /obj/item/tool/wirecutters/Initialize(mapload) . = ..() - if(prob(50)) + if(prob(50) && !istype(src, /obj/item/tool/wirecutters/yautja)) //RU TGMC EDIT icon_state = "cutters-y" item_state = "cutters_yellow" diff --git a/code/game/objects/machinery/telecomms/machines/bus.dm b/code/game/objects/machinery/telecomms/machines/bus.dm index 4635d9cc1eeca..dff1094e6f6c1 100644 --- a/code/game/objects/machinery/telecomms/machines/bus.dm +++ b/code/game/objects/machinery/telecomms/machines/bus.dm @@ -58,7 +58,7 @@ /obj/machinery/telecomms/bus/preset_two id = "Bus 2" network = "tcommsat" - freq_listening = list(FREQ_PMC, FREQ_COLONIST, FREQ_USL, FREQ_DEATHSQUAD, FREQ_IMPERIAL, FREQ_SOM, FREQ_SECTOID, FREQ_ECHO) + freq_listening = list(FREQ_PMC, FREQ_COLONIST, FREQ_USL, FREQ_DEATHSQUAD, FREQ_IMPERIAL, FREQ_SOM, FREQ_SECTOID, FREQ_ECHO, YAUT_FREQ) autolinkers = list("processor2", "ert") diff --git a/code/game/objects/machinery/telecomms/machines/receiver.dm b/code/game/objects/machinery/telecomms/machines/receiver.dm index 75c2f619b950f..12a0fbc357242 100644 --- a/code/game/objects/machinery/telecomms/machines/receiver.dm +++ b/code/game/objects/machinery/telecomms/machines/receiver.dm @@ -48,7 +48,7 @@ id = "Receiver A" network = "tcommsat" autolinkers = list("receiverA") // link to relay - freq_listening = list(FREQ_MEDICAL, FREQ_REQUISITIONS, FREQ_ALPHA, FREQ_BRAVO, FREQ_CHARLIE, FREQ_DELTA, FREQ_COMMAND, FREQ_ENGINEERING, FREQ_CAS, FREQ_PMC, FREQ_COLONIST, FREQ_USL, FREQ_DEATHSQUAD, FREQ_IMPERIAL, FREQ_SOM, FREQ_SECTOID, FREQ_ECHO) + freq_listening = list(FREQ_MEDICAL, FREQ_REQUISITIONS, FREQ_ALPHA, FREQ_BRAVO, FREQ_CHARLIE, FREQ_DELTA, FREQ_COMMAND, FREQ_ENGINEERING, FREQ_CAS, FREQ_PMC, FREQ_COLONIST, FREQ_USL, FREQ_DEATHSQUAD, FREQ_IMPERIAL, FREQ_SOM, FREQ_SECTOID, FREQ_ECHO, YAUT_FREQ) /obj/machinery/telecomms/receiver/preset_left/som id = "Receiver A som" diff --git a/code/game/objects/machinery/telecomms/machines/server.dm b/code/game/objects/machinery/telecomms/machines/server.dm index 8c35b413cac48..24a244dbffb50 100644 --- a/code/game/objects/machinery/telecomms/machines/server.dm +++ b/code/game/objects/machinery/telecomms/machines/server.dm @@ -168,14 +168,14 @@ /obj/machinery/telecomms/server/presets/common id = "Common Server" - freq_listening = list(FREQ_COMMON, FREQ_PMC, FREQ_COLONIST, FREQ_USL, FREQ_DEATHSQUAD, FREQ_IMPERIAL, FREQ_SOM, FREQ_SECTOID, FREQ_ECHO) + freq_listening = list(FREQ_COMMON, FREQ_PMC, FREQ_COLONIST, FREQ_USL, FREQ_DEATHSQUAD, FREQ_IMPERIAL, FREQ_SOM, FREQ_SECTOID, FREQ_ECHO, YAUT_FREQ) autolinkers = list("common", "ert") //adds a proper emergency server in CIC instead of an unlinked one. /obj/machinery/telecomms/server/presets/common/cicbackup on = 0 id = "Backup Common Server" - freq_listening = list(FREQ_COMMON, FREQ_PMC, FREQ_COLONIST, FREQ_USL, FREQ_DEATHSQUAD, FREQ_IMPERIAL, FREQ_SOM, FREQ_SECTOID, FREQ_ECHO) + freq_listening = list(FREQ_COMMON, FREQ_PMC, FREQ_COLONIST, FREQ_USL, FREQ_DEATHSQUAD, FREQ_IMPERIAL, FREQ_SOM, FREQ_SECTOID, FREQ_ECHO, YAUT_FREQ) autolinkers = list("common", "ert") /obj/machinery/telecomms/server/presets/common/som 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 6b46fca998e75..40258c4cfdc14 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 @@ -95,7 +95,11 @@ //TIMER_COOLDOWN_START(user, COOLDOWN_NEST, NEST_UNBUCKLED_COOLDOWN) //RUTGMC EDIT REMOVAL silent = TRUE return ..() - +// RU TGMC EDIT + if(force_nest) + to_chat(buckled_mob, span_warning("Nest to thick, you can't resist.")) + return FALSE +// RU TGMC EDIT if(buckled_mob.incapacitated(TRUE)) to_chat(buckled_mob, span_warning("You're currently unable to try that.")) return FALSE diff --git a/code/game/say.dm b/code/game/say.dm index 6795fda2270eb..c722afc2024bd 100644 --- a/code/game/say.dm +++ b/code/game/say.dm @@ -17,6 +17,7 @@ GLOBAL_LIST_INIT(freqtospan, list( "[FREQ_COMMAND_SOM]" = "comradio", "[FREQ_ENGINEERING_SOM]" = "engradio", "[FREQ_MEDICAL_SOM]" = "medradio", + "[YAUT_FREQ]" = "yautjaradio", )) diff --git a/code/game/sound.dm b/code/game/sound.dm index 8454e1df1857d..3e1b91f67dec3 100644 --- a/code/game/sound.dm +++ b/code/game/sound.dm @@ -357,4 +357,24 @@ A good representation is: 'byond applies a volume reduction to the sound every X S = pick('sound/voice/robot/robot_pain1.ogg', 'sound/voice/robot/robot_pain2.ogg', 'sound/voice/robot/robot_pain3.ogg') if("robot_warcry") S = pick('sound/voice/robot/robot_warcry1.ogg', 'sound/voice/robot/robot_warcry2.ogg', 'sound/voice/robot/robot_warcry3.ogg') + +//RUTGMC EDIT + //yautja race + if("pred_scream") + S = pick('modular_RUtgmc/sound/voice/pred_roar1.ogg','modular_RUtgmc/sound/voice/pred_roar2.ogg','modular_RUtgmc/sound/voice/pred_roar3.ogg','modular_RUtgmc/sound/voice/pred_roar4.ogg','modular_RUtgmc/sound/voice/pred_roar5.ogg') + if("pred_pain") + S = pick('modular_RUtgmc/sound/voice/pred_pain1.ogg','modular_RUtgmc/sound/voice/pred_pain2.ogg','modular_RUtgmc/sound/voice/pred_pain3.ogg','modular_RUtgmc/sound/voice/pred_pain4.ogg','modular_RUtgmc/sound/voice/pred_pain5.ogg') + if("pred_hugged") + S = pick('modular_RUtgmc/sound/voice/pred_facehugged.ogg') + if("pred_preburst") + S = pick('modular_RUtgmc/sound/voice/pred_pain_rare1.ogg') + if("pred_warcry") + S = pick('modular_RUtgmc/sound/voice/pred_warcry.ogg') + + //pred items + if("clan_sword_hit") + S = pick('modular_RUtgmc/sound/weapons/clan_sword_hit_1.ogg', 'modular_RUtgmc/sound/weapons/clan_sword_hit_2.ogg') + if("chain_swing") + S = pick('modular_RUtgmc/sound/items/chain_swing1.ogg', 'modular_RUtgmc/sound/items/chain_swing2.ogg', 'modular_RUtgmc/sound/items/chain_swing3.ogg') +//RUTGMC EDIT return S diff --git a/code/game/turfs/walls/walls.dm b/code/game/turfs/walls/walls.dm index ea43e83527327..da7d61af4f36c 100644 --- a/code/game/turfs/walls/walls.dm +++ b/code/game/turfs/walls/walls.dm @@ -320,6 +320,12 @@ to_chat(user, span_warning("You don't have the dexterity to do this!")) return +//RUTGMC EDIT + else if(istype(I, /obj/item/frame/torch_frame)) + var/obj/item/frame/torch_frame/AH = I + AH.try_build(src) +//RUTGMC EDIT + else if(istype(I, /obj/item/frame/apc)) var/obj/item/frame/apc/AH = I AH.try_build(src, user) diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index 430f4dd31202d..86bcc003ee04a 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -483,6 +483,15 @@ Status: [status ? status : "Unknown"] | Damage: [health ? health : "None"] newmob = M.change_mob_type(/mob/living/carbon/xenomorph/panther, location, null, delmob) if("chimera") newmob = M.change_mob_type(/mob/living/carbon/xenomorph/chimera, location, null, delmob) + //PREDS + if("hellhound") + newmob = M.change_mob_type(/mob/living/carbon/xenomorph/hellhound, location, null, delmob) + if("predalien_larva") + newmob = M.change_mob_type(/mob/living/carbon/xenomorph/larva/predalien, location, null, delmob) + if("predalien") + newmob = M.change_mob_type(/mob/living/carbon/xenomorph/predalien, location, null, delmob) + if("yautja") + newmob = M.change_mob_type(/mob/living/carbon/human/species/yautja, location, null, delmob) //RUTGMC EDIT END C.holder.show_player_panel(newmob) @@ -1142,6 +1151,19 @@ Status: [status ? status : "Unknown"] | Damage: [health ? health : "None"] log_admin("[key_name(src)] has [SSevacuation.flags_scuttle & FLAGS_SELF_DESTRUCT_DENY ? "forbidden" : "allowed"] the self-destruct system.") message_admins("[ADMIN_TPMONTY(usr)] has [SSevacuation.flags_scuttle & FLAGS_SELF_DESTRUCT_DENY ? "forbidden" : "allowed"] the self-destruct system.") +//RU TGMC EDIT + else if(href_list["admincancelpredsd"]) + if(!check_rights(R_ADMIN)) + return + var/obj/item/clothing/gloves/yautja/hunter/bracer = locate(href_list["bracer"]) + var/mob/living/carbon/victim = locate(href_list["victim"]) + if (!istype(bracer)) + return + if (alert("Are you sure you want to cancel this pred SD?",,"Yes","No") != "Yes") + return + bracer.exploding = FALSE + message_admins("[src.owner] has cancelled the predator self-destruct sequence [victim ? "of [victim] ([victim.key])":""].") +//RU TGMC EDIT else if(href_list["object_list"]) if(!check_rights(R_SPAWN)) @@ -1863,7 +1885,7 @@ Status: [status ? status : "Unknown"] | Damage: [health ? health : "None"] previous = H.gender H.gender = change if("ethnicity") - change = input("Select the ethnicity.", "Edit Appearance") as null|anything in sortList(GLOB.ethnicities_list) + change = input("Select the ethnicity.", "Edit Appearance") as null|anything in sortList(GLOB.human_ethnicities_list) if(!change || !istype(H)) return previous = H.ethnicity diff --git a/code/modules/animations/animation_library.dm b/code/modules/animations/animation_library.dm index 0f2f859b78c53..ad35e283ead1a 100644 --- a/code/modules/animations/animation_library.dm +++ b/code/modules/animations/animation_library.dm @@ -49,26 +49,44 @@ Instead of being uniform, it starts out a littler slower, goes fast in the middl //Basic megaman-like animation. No bells or whistles, but looks nice. /proc/animation_teleport_quick_out(atom/A, speed = 10) + A.status_flags |= INCORPOREAL + var/initial_matrix = A.transform animate(A, transform = matrix(0, 4, MATRIX_SCALE), alpha = 0, time = speed, easing = BACK_EASING) + spawn(speed) + A.transform = initial_matrix + A.status_flags &= ~INCORPOREAL return speed //We want to make sure to reset color here as it can be changed by other animations. /proc/animation_teleport_quick_in(atom/A, speed = 10) + A.status_flags |= INCORPOREAL + var/initial_matrix = A.transform A.transform = matrix(0, 4, MATRIX_SCALE) A.alpha = 0 //Start with transparency, just in case. animate(A, alpha = 255, transform = null, color = "#FFFFFF", time = speed, easing = BACK_EASING) + spawn(speed) + A.transform = initial_matrix + A.status_flags &= ~INCORPOREAL + return speed /*A magical teleport animation, for when the person is transported with some magic. Good for Halloween type events. Can look good elsewhere as well.*/ /proc/animation_teleport_magic_out(atom/A, speed = 6) + A.status_flags |= INCORPOREAL + var/initial_matrix = A.transform animate(A, transform = matrix(1.5, 0, MATRIX_SCALE), time = speed, easing = BACK_EASING) animate(transform = matrix(0, 4, MATRIX_SCALE) * matrix(0, 6, MATRIX_TRANSLATE), color = "#FFFF00", time = speed, alpha = 100, easing = BOUNCE_EASING|EASE_IN) animate(alpha = 0, time = speed) var/image/I = image('icons/effects/effects.dmi',A,"sparkle") flick_overlay_view(I, A, 9) + spawn(speed) + A.transform = initial_matrix + A.status_flags &= ~INCORPOREAL return speed*3 /proc/animation_teleport_magic_in(atom/A, speed = 6) + A.status_flags |= INCORPOREAL + var/initial_matrix = A.transform A.transform = matrix(0,3.5, MATRIX_SCALE) A.alpha = 0 animate(A, alpha = 255, color = "#FFFF00", time = speed, easing = BACK_EASING) @@ -76,23 +94,38 @@ Can look good elsewhere as well.*/ animate(transform = null, time = speed-1) var/image/I = image('icons/effects/effects.dmi',A,"sparkle") flick_overlay_view(I, A, 10) + spawn(speed) + A.transform = initial_matrix + A.status_flags &= ~INCORPOREAL + return speed //A spooky teleport for evil dolls, horrors, and whatever else. Halloween type stuff. /proc/animation_teleport_spooky_out(atom/A, speed = 6, sleep_duration = 0) + A.status_flags |= INCORPOREAL + var/initial_matrix = A.transform animate(A, transform = matrix() * 1.5, color = "#551a8b", time = speed, easing = BACK_EASING) animate(transform = matrix() * 0.2, alpha = 100, color = "#000000", time = speed, easing = BACK_EASING) animate(alpha = 0, time = speed) var/image/I = image('icons/effects/effects.dmi',A,"spooky") flick_overlay_view(I, A, 9) + spawn(speed) + A.transform = initial_matrix + A.status_flags &= ~INCORPOREAL return speed*3 /proc/animation_teleport_spooky_in(atom/A, speed = 4) + A.status_flags |= INCORPOREAL + var/initial_matrix = A.transform A.transform *= 1.2 A.alpha = 0 animate(A, alpha = 255, color = "#551a8b", time = speed) animate(transform = null, color = "#FFFFFF", time = speed, easing = QUAD_EASING|EASE_OUT) var/image/I = image('icons/effects/effects.dmi',A,"spooky") flick_overlay_view(I, A, 10) + spawn(speed) + A.transform = initial_matrix + A.status_flags &= ~INCORPOREAL + return speed //Regular fadeout disappear, for most objects. /proc/animation_destruction_fade(atom/A, speed = 12) diff --git a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm index e61228318592b..53644d95ad4af 100644 --- a/code/modules/client/client_procs.dm +++ b/code/modules/client/client_procs.dm @@ -299,6 +299,10 @@ get_message_output("watchlist entry", ckey) validate_key_in_db() +//RUTGMC EDIT + load_player_predator_info() +//RUTGMC EDIT + send_resources() generate_clickcatcher() diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm index 5a3f49b75fd8e..6475e5125973d 100644 --- a/code/modules/client/preferences_savefile.dm +++ b/code/modules/client/preferences_savefile.dm @@ -409,6 +409,30 @@ READ_FILE(S["xeno_name"], xeno_name) READ_FILE(S["ai_name"], ai_name) +//RUTGMC EDIT + READ_FILE(S["pred_name"], predator_name) + READ_FILE(S["pred_gender"], predator_gender) + READ_FILE(S["pred_age"], predator_age) + READ_FILE(S["pred_use_legacy"], predator_use_legacy) + READ_FILE(S["pred_trans_type"], predator_translator_type) + READ_FILE(S["pred_mask_type"], predator_mask_type) + READ_FILE(S["pred_armor_type"], predator_armor_type) + READ_FILE(S["pred_boot_type"], predator_boot_type) + READ_FILE(S["pred_mask_mat"], predator_mask_material) + READ_FILE(S["pred_armor_mat"], predator_armor_material) + READ_FILE(S["pred_greave_mat"], predator_greave_material) + READ_FILE(S["pred_caster_mat"], predator_caster_material) + READ_FILE(S["pred_cape_type"], predator_cape_type) + READ_FILE(S["pred_cape_color"], predator_cape_color) + READ_FILE(S["pred_h_style"], predator_h_style) + READ_FILE(S["pred_skin_color"], predator_skin_color) + READ_FILE(S["pred_flavor_text"], predator_flavor_text) + READ_FILE(S["pred_r_eyes"], pred_r_eyes) + READ_FILE(S["pred_g_eyes"], pred_g_eyes) + READ_FILE(S["pred_b_eyes"], pred_b_eyes) + READ_FILE(S["yautja_status"], yautja_status) +//RUTGMC EDIT + READ_FILE(S["real_name"], real_name) READ_FILE(S["random_name"], random_name) READ_FILE(S["gender"], gender) @@ -507,6 +531,12 @@ g_facial = sanitize_integer(g_facial, 0, 255, initial(g_facial)) b_facial = sanitize_integer(b_facial, 0, 255, initial(b_facial)) +//RUTGMC EDIT + pred_r_eyes = sanitize_integer(pred_r_eyes, 0, 255, initial(pred_r_eyes)) + pred_g_eyes = sanitize_integer(pred_g_eyes, 0, 255, initial(pred_g_eyes)) + pred_b_eyes = sanitize_integer(pred_b_eyes, 0, 255, initial(pred_b_eyes)) +//RUTGMC EDIT + r_eyes = sanitize_integer(r_eyes, 0, 255, initial(r_eyes)) g_eyes = sanitize_integer(g_eyes, 0, 255, initial(g_eyes)) b_eyes = sanitize_integer(b_eyes, 0, 255, initial(b_eyes)) @@ -559,6 +589,27 @@ xeno_name = reject_bad_name(xeno_name) ai_name = reject_bad_name(ai_name, TRUE) +//RUTGMC EDIT + predator_name = predator_name ? sanitize_text(predator_name, initial(predator_name)) : initial(predator_name) + predator_gender = sanitize_text(predator_gender, initial(predator_gender)) + predator_age = sanitize_integer(predator_age, 100, 10000, initial(predator_age)) + predator_use_legacy = sanitize_inlist(predator_use_legacy, PRED_LEGACIES, initial(predator_use_legacy)) + predator_translator_type = sanitize_inlist(predator_translator_type, PRED_TRANSLATORS, initial(predator_translator_type)) + predator_mask_type = sanitize_integer(predator_mask_type,1,1000000,initial(predator_mask_type)) + predator_armor_type = sanitize_integer(predator_armor_type,1,1000000,initial(predator_armor_type)) + predator_boot_type = sanitize_integer(predator_boot_type,1,1000000,initial(predator_boot_type)) + predator_mask_material = sanitize_inlist(predator_mask_material, PRED_MATERIALS, initial(predator_mask_material)) + predator_armor_material = sanitize_inlist(predator_armor_material, PRED_MATERIALS, initial(predator_armor_material)) + predator_greave_material = sanitize_inlist(predator_greave_material, PRED_MATERIALS, initial(predator_greave_material)) + predator_caster_material = sanitize_inlist(predator_caster_material, PRED_MATERIALS + "retro", initial(predator_caster_material)) + predator_cape_type = sanitize_inlist(predator_cape_type, GLOB.all_yautja_capes + "None", initial(predator_cape_type)) + predator_cape_color = sanitize_hexcolor(predator_cape_color, 6, TRUE, initial(predator_cape_color)) + predator_h_style = sanitize_inlist(predator_h_style, GLOB.yautja_hair_styles_list, initial(predator_h_style)) + predator_skin_color = sanitize_inlist(predator_skin_color, PRED_SKIN_COLOR, initial(predator_skin_color)) + predator_flavor_text = predator_flavor_text ? sanitize_text(predator_flavor_text, initial(predator_flavor_text)) : initial(predator_flavor_text) + yautja_status = sanitize_inlist(yautja_status, WHITELIST_HIERARCHY + list("Elder"), initial(yautja_status)) +//RUTGMC EDIT + real_name = reject_bad_name(real_name, TRUE) random_name = sanitize_integer(random_name, FALSE, TRUE, initial(random_name)) gender = sanitize_gender(gender, TRUE, TRUE) @@ -597,6 +648,12 @@ g_facial = sanitize_integer(g_facial, 0, 255, initial(g_facial)) b_facial = sanitize_integer(b_facial, 0, 255, initial(b_facial)) +//RUTGMC EDIT + pred_r_eyes = sanitize_integer(pred_r_eyes, 0, 255, initial(pred_r_eyes)) + pred_g_eyes = sanitize_integer(pred_g_eyes, 0, 255, initial(pred_g_eyes)) + pred_b_eyes = sanitize_integer(pred_b_eyes, 0, 255, initial(pred_b_eyes)) +//RUTGMC EDIT + r_eyes = sanitize_integer(r_eyes, 0, 255, initial(r_eyes)) g_eyes = sanitize_integer(g_eyes, 0, 255, initial(g_eyes)) b_eyes = sanitize_integer(b_eyes, 0, 255, initial(b_eyes)) @@ -623,6 +680,30 @@ WRITE_FILE(S["xeno_name"], xeno_name) WRITE_FILE(S["ai_name"], ai_name) +//RUTGMC EDIT + WRITE_FILE(S["pred_name"], predator_name) + WRITE_FILE(S["pred_gender"], predator_gender) + WRITE_FILE(S["pred_age"], predator_age) + WRITE_FILE(S["pred_use_legacy"], predator_use_legacy) + WRITE_FILE(S["pred_trans_type"], predator_translator_type) + WRITE_FILE(S["pred_mask_type"], predator_mask_type) + WRITE_FILE(S["pred_armor_type"], predator_armor_type) + WRITE_FILE(S["pred_boot_type"], predator_boot_type) + WRITE_FILE(S["pred_mask_mat"], predator_mask_material) + WRITE_FILE(S["pred_armor_mat"], predator_armor_material) + WRITE_FILE(S["pred_greave_mat"], predator_greave_material) + WRITE_FILE(S["pred_caster_mat"], predator_caster_material) + WRITE_FILE(S["pred_cape_type"], predator_cape_type) + WRITE_FILE(S["pred_cape_color"], predator_cape_color) + WRITE_FILE(S["pred_h_style"], predator_h_style) + WRITE_FILE(S["pred_skin_color"], predator_skin_color) + WRITE_FILE(S["pred_flavor_text"], predator_flavor_text) + WRITE_FILE(S["pred_r_eyes"], pred_r_eyes) + WRITE_FILE(S["pred_g_eyes"], pred_g_eyes) + WRITE_FILE(S["pred_b_eyes"], pred_b_eyes) + WRITE_FILE(S["yautja_status"], yautja_status) +//RUTGMC EDIT + WRITE_FILE(S["real_name"], real_name) WRITE_FILE(S["random_name"], random_name) WRITE_FILE(S["gender"], gender) diff --git a/code/modules/client/preferences_ui.dm b/code/modules/client/preferences_ui.dm index 10e700ea9926f..d6d79fc57ce14 100644 --- a/code/modules/client/preferences_ui.dm +++ b/code/modules/client/preferences_ui.dm @@ -69,6 +69,32 @@ data["h_style"] = h_style data["grad_style"] = grad_style data["f_style"] = f_style +//RUTGMC EDIT + if(PRED_CHARACTER_CUSTOMIZATION) + data["has_wl"] = GLOB.roles_whitelist[user.ckey] & WHITELIST_PREDATOR + data["legacy"] = GLOB.roles_whitelist[user.ckey] & WHITELIST_YAUTJA_LEGACY + data["predator_name"] = predator_name + data["predator_gender"] = predator_gender + data["predator_age"] = predator_age + data["predator_h_style"] = predator_h_style + data["predator_skin_color"] = predator_skin_color + data["predator_use_legacy"] = predator_use_legacy + data["predator_translator_type"] = predator_translator_type + data["predator_mask_type"] = predator_mask_type + data["predator_armor_type"] = predator_armor_type + data["predator_boot_type"] = predator_boot_type + data["predator_armor_material"] = predator_armor_material + data["predator_mask_material"] = predator_mask_material + data["predator_greave_material"] = predator_greave_material + data["predator_caster_material"] = predator_caster_material + data["predator_cape_type"] = predator_cape_type + data["predator_cape_color"] = predator_cape_color + data["predator_flavor_text"] = predator_flavor_text + data["pred_r_eyes"] = pred_r_eyes + data["pred_g_eyes"] = pred_g_eyes + data["pred_b_eyes"] = pred_b_eyes + data["yautja_status"] = yautja_status +//RUTGMC EDIT if(BACKGROUND_INFORMATION) data["slot"] = default_slot data["flavor_text"] = flavor_text @@ -160,6 +186,11 @@ if(CHARACTER_CUSTOMIZATION) update_preview_icon() .["mapRef"] = "player_pref_map" +//RUTGMC EDIT + if(PRED_CHARACTER_CUSTOMIZATION) + update_preview_icon(SSjob.GetJobType(/datum/job/predator), DUMMY_PRED_SLOT_PREFERENCES) + .["mapRef"] = "player_pref_map" +//RUTGMC EDIT if(GEAR_CUSTOMIZATION) .["clothing"] = list( "underwear" = list( @@ -271,6 +302,132 @@ return synthetic_type = choice + //RUTGMC EDIT ADDITION BEGIN - Preds + if("predator_name") + var/raw_name = input(user, "Choose your Predator's name:", "Character Preference") as text|null + if(raw_name) // Check to ensure that the user entered text (rather than cancel.) + var/new_name = reject_bad_name(raw_name) + if(new_name) predator_name = new_name + else to_chat(user, "Invalid name. Your name should be at least 2 and at most [MAX_NAME_LEN] characters long. It may only contain the characters A-Z, a-z, -, ' and .") + + if("predator_gender") + predator_gender = predator_gender == MALE ? FEMALE : MALE + + if("predator_age") + var/new_predator_age = tgui_input_number(user, "Choose your Predator's age(20 to 10000):", "Character Preference", 1234, 10000, 20) + if(new_predator_age) predator_age = max(min( round(text2num(new_predator_age)), 10000),20) + + if("predator_use_legacy") + var/legacy_choice = tgui_input_list(user, "What legacy set do you wish to use?", "Legacy Set", PRED_LEGACIES) + if(!legacy_choice) + return + predator_use_legacy = legacy_choice + + if("predator_translator_type") + var/new_translator_type = tgui_input_list(user, "Choose your translator type.", "Translator Type", PRED_TRANSLATORS) + if(!new_translator_type) + return + predator_translator_type = new_translator_type + + if("predator_mask_type") + var/new_predator_mask_type = tgui_input_number(user, "Choose your mask type:\n(1-12)", "Mask Selection", 1, 12, 1) + if(new_predator_mask_type) predator_mask_type = round(text2num(new_predator_mask_type)) + + if("predator_armor_type") + var/new_predator_armor_type = tgui_input_number(user, "Choose your armor type:\n(1-7)", "Armor Selection", 1, 7, 1) + if(new_predator_armor_type) predator_armor_type = round(text2num(new_predator_armor_type)) + + if("predator_boot_type") + var/new_predator_boot_type = tgui_input_number(user, "Choose your greaves type:\n(1-4)", "Greave Selection", 1, 4, 1) + if(new_predator_boot_type) predator_boot_type = round(text2num(new_predator_boot_type)) + + if("predator_mask_material") + var/new_pred_mask_mat = tgui_input_list(user, "Choose your mask material:", "Mask Material", PRED_MATERIALS) + if(!new_pred_mask_mat) + return + predator_mask_material = new_pred_mask_mat + + if("predator_armor_material") + var/new_pred_armor_mat = tgui_input_list(user, "Choose your armor material:", "Armor Material", PRED_MATERIALS) + if(!new_pred_armor_mat) + return + predator_armor_material = new_pred_armor_mat + + if("predator_greave_material") + var/new_pred_greave_mat = tgui_input_list(user, "Choose your greave material:", "Greave Material", PRED_MATERIALS) + if(!new_pred_greave_mat) + return + predator_greave_material = new_pred_greave_mat + + if("predator_caster_material") + var/new_pred_caster_mat = tgui_input_list(user, "Choose your caster material:", "Caster Material", PRED_MATERIALS + "retro") + if(!new_pred_caster_mat) + return + predator_caster_material = new_pred_caster_mat + + if("predator_cape_type") + var/datum/job/J = SSjob.GetJobType(/datum/job/predator) + var/whitelist_status = GLOB.clan_ranks_ordered[J.get_whitelist_status(GLOB.roles_whitelist, current_client)] + + var/list/options = list("None", "Default") + for(var/cape_name in GLOB.all_yautja_capes) + var/obj/item/clothing/yautja_cape/cape = GLOB.all_yautja_capes[cape_name] + if(whitelist_status >= initial(cape.clan_rank_required) || (initial(cape.councillor_override) && (GLOB.roles_whitelist[user.ckey] & (WHITELIST_YAUTJA_COUNCIL|WHITELIST_YAUTJA_COUNCIL_LEGACY)))) + options += cape_name + + var/new_cape = tgui_input_list(user, "Choose your cape type:", "Cape Type", options) + if(!new_cape) + return + predator_cape_type = new_cape + + if("predator_cape_color") + var/new_cape_color = input(user, "Choose your cape color:", "Cape Color") as null|color + if(!new_cape_color) + return + predator_cape_color = new_cape_color + + if("predator_h_style") + var/new_h_style = input(user, "Choose your quill style:", "Quill Style") as null|anything in GLOB.yautja_hair_styles_list + if(!new_h_style) + return + predator_h_style = new_h_style + + if("predator_skin_color") + var/new_skin_color = tgui_input_list(user, "Choose your skin color:", "Skin Color", PRED_SKIN_COLOR) + if(!new_skin_color) + return + predator_skin_color = new_skin_color + + if("predator_flavor_text") + var/pred_flv_raw = input(user, "Choose your Predator's flavor text:", "Flavor Text", predator_flavor_text) as message + if(!pred_flv_raw) + predator_flavor_text = "None" + return + predator_flavor_text = strip_html(pred_flv_raw, MAX_MESSAGE_LEN) + + if("pred_eyecolor") + var/eyecolor = input(user, "Choose your character's eye colour:", "Character Preference") as null|color + if(!eyecolor) + return + pred_r_eyes = hex2num(copytext_char(eyecolor, 2, 4)) + pred_g_eyes = hex2num(copytext_char(eyecolor, 4, 6)) + pred_b_eyes = hex2num(copytext_char(eyecolor, 6, 8)) + + if("yautja_status") + var/list/options = list("Normal" = WHITELIST_NORMAL) + + if(GLOB.roles_whitelist[user.ckey] & (WHITELIST_YAUTJA_COUNCIL|WHITELIST_YAUTJA_COUNCIL_LEGACY)) + options += list("Council" = WHITELIST_COUNCIL) + if(GLOB.roles_whitelist[user.ckey] & WHITELIST_YAUTJA_LEADER) + options += list("Leader" = WHITELIST_LEADER) + + var/new_yautja_status = tgui_input_list(user, "Choose your new Yautja Whitelist Status.", "Yautja Status", options) + if(!new_yautja_status) + return + + yautja_status = options[new_yautja_status] +//RUTGMC EDIT ADDITION END + if("robot_type") var/choice = tgui_input_list(ui.user, "What model of robot do you want to play with?", "Robot model choice", ROBOT_TYPES) if(!choice) @@ -315,7 +472,7 @@ if("ethnicity") - var/choice = tgui_input_list(ui.user, "What ethnicity do you want to play with?", "Ethnicity choice", GLOB.ethnicities_list) + var/choice = tgui_input_list(ui.user, "What ethnicity do you want to play with?", "Ethnicity choice", GLOB.human_ethnicities_list) if(!choice) return ethnicity = choice @@ -861,7 +1018,13 @@ save_preferences() save_character() save_keybinds() - update_preview_icon() +//RUTGMC EDIT + switch(tab_index) + if(CHARACTER_CUSTOMIZATION) + update_preview_icon() + if(PRED_CHARACTER_CUSTOMIZATION) + update_preview_icon(SSjob.GetJobType(/datum/job/predator), DUMMY_PRED_SLOT_PREFERENCES) +//RUTGMC EDIT ui_interact(user, ui) SEND_SIGNAL(current_client, COMSIG_CLIENT_PREFERENCES_UIACTED) return TRUE diff --git a/code/modules/clothing/modular_armor/attachments/storage.dm b/code/modules/clothing/modular_armor/attachments/storage.dm index d403204f64402..65003ad088982 100644 --- a/code/modules/clothing/modular_armor/attachments/storage.dm +++ b/code/modules/clothing/modular_armor/attachments/storage.dm @@ -395,6 +395,9 @@ storage_slots = 1 draw_mode = TRUE can_hold = list( +//RUTGMC EDIT + /obj/item/weapon/yautja/knife, +//RUTGMC EDIT /obj/item/weapon/combat_knife, /obj/item/weapon/gun/pistol/standard_pocketpistol, /obj/item/weapon/gun/shotgun/double/derringer, diff --git a/code/modules/events/hive_threat.dm b/code/modules/events/hive_threat.dm index f4415db983896..729805d71be84 100644 --- a/code/modules/events/hive_threat.dm +++ b/code/modules/events/hive_threat.dm @@ -17,7 +17,7 @@ for(var/z in z_levels) for(var/i in GLOB.humans_by_zlevel["[z]"]) var/mob/living/carbon/human/possible_target = i - if(!istype(possible_target) || !possible_target.client || issynth(possible_target)) + if(!istype(possible_target) || !possible_target.client || issynth(possible_target) || isyautja(possible_target)) //RU TGMC EDIT continue eligible_targets += possible_target if(!length(eligible_targets)) diff --git a/code/modules/mob/dead/observer/login.dm b/code/modules/mob/dead/observer/login.dm index f80dd5ac59062..4c1a14f54b7a4 100644 --- a/code/modules/mob/dead/observer/login.dm +++ b/code/modules/mob/dead/observer/login.dm @@ -48,3 +48,7 @@ if(length(GLOB.offered_mob_list)) to_chat(src, span_boldnotice("There's mobs available for taking! Ghost > Take Offered Mob")) +//RUTGMC EDIT + if(SSticker.mode && SSticker.mode.flags_round_type & MODE_PREDATOR) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), src, "This is a PREDATOR ROUND! If you are whitelisted, you may Join the Hunt!"), 2 SECONDS) +//RUTGMC EDIT diff --git a/code/modules/mob/dead/observer/orbit.dm b/code/modules/mob/dead/observer/orbit.dm index 4cf13caaaa130..ebf4865e0ba81 100644 --- a/code/modules/mob/dead/observer/orbit.dm +++ b/code/modules/mob/dead/observer/orbit.dm @@ -57,6 +57,9 @@ var/list/som = list() var/list/survivors = list() var/list/xenos = list() +//RUTGMC EDIT + var/list/yautja = list() +//RUTGMC EDIT var/list/dead = list() var/list/ghosts = list() var/list/valhalla = list() // RUTGMC ADDITION @@ -106,6 +109,11 @@ serialized["icon"] = caste.minimap_icon if(!isnum(xeno.nicknumber)) serialized["nickname"] = xeno.nicknumber +//RUTGMC EDIT + if(istype(xeno, /mob/living/carbon/xenomorph/hellhound)) + yautja += list(serialized) + continue +//RUTGMC EDIT if(HAS_TRAIT(xeno, TRAIT_VALHALLA_XENO)) // RUTGMC ADDITION valhalla += list(serialized) continue @@ -123,6 +131,14 @@ var/datum/job/job = human.job serialized["nickname"] = human.real_name +//RUTGMC EDIT + if(mob_poi.hunter_data.thralled) + serialized["icon"] = "thrall" + serialized["job"] = job.title + yautja += list(serialized) + continue +//RUTGMC EDIT + if(ismarinejob(human.job)) if(human.assigned_squad) serialized["icon"] = lowertext(human.assigned_squad.name) + "_" + job.minimap_icon @@ -134,6 +150,14 @@ serialized["icon"] = job.minimap_icon serialized["job"] = job.title +//RUTGMC EDIT + if(isyautja(mob_poi)) + serialized["icon"] = job.minimap_icon + serialized["job"] = job.title + yautja += list(serialized) + continue +//RUTGMC EDIT + if(issommarinejob(human.job)) som += list(serialized) continue @@ -156,6 +180,9 @@ data["misc"] = misc data["npcs"] = npcs data["marines"] = marines +//RUTGMC EDIT + data["yautja"] = yautja +//RUTGMC EDIT data["som"] = som data["survivors"] = survivors data["xenos"] = xenos diff --git a/code/modules/mob/death.dm b/code/modules/mob/death.dm index fd1bbc4b90dde..1c98a10bc957f 100644 --- a/code/modules/mob/death.dm +++ b/code/modules/mob/death.dm @@ -42,6 +42,15 @@ qdel(src) return set_stat(DEAD) +//RUTGMC EDIT + if(SSticker.current_state != GAME_STATE_FINISHED && !is_centcom_level(z)) + var/mob/living/living = last_damage_source + if(istype(living)) + hunter_data.death(living) + if(ishuman(living) && isyautja(living) && living != src) + INVOKE_ASYNC(living.client, TYPE_PROC_REF(/client, add_honor), life_kills_total + life_value) + living.life_kills_total += life_kills_total + life_value +//RUTGMC EDIT SEND_GLOBAL_SIGNAL(COMSIG_GLOB_MOB_DEATH, src) SEND_SIGNAL(src, COMSIG_MOB_DEATH, gibbing) log_combat(src, src, "[deathmessage]") diff --git a/code/modules/mob/living/blood.dm b/code/modules/mob/living/blood.dm index c4ce5d824d717..7c70846878885 100644 --- a/code/modules/mob/living/blood.dm +++ b/code/modules/mob/living/blood.dm @@ -110,6 +110,11 @@ if(reagents.get_reagent_amount(/datum/reagent/medicine/quickclot)) //Quickclot stops bleeding, magic! return +//RUTGMC EDIT + if(reagents.get_reagent_amount(/datum/reagent/thwei)) + return +//RUTGMC EDIT + if(blood_volume) blood_volume = max(blood_volume - amt, 0) if(isturf(src.loc)) //Blood loss still happens in locker, floor stays clean diff --git a/code/modules/mob/living/carbon/carbon_defines.dm b/code/modules/mob/living/carbon/carbon_defines.dm index 1856f7d8dee6c..afb36e4cdf30d 100644 --- a/code/modules/mob/living/carbon/carbon_defines.dm +++ b/code/modules/mob/living/carbon/carbon_defines.dm @@ -15,6 +15,10 @@ var/fire_alert = FALSE var/pressure_alert = FALSE +//RUTGMC EDIT + var/butchery_progress = 0 +//RUTGMC EDIT + var/list/internal_organs = list() ///Overall drunkenness - check handle_status_effects() in life.dm for effects var/drunkenness = 0 diff --git a/code/modules/mob/living/carbon/human/death.dm b/code/modules/mob/living/carbon/human/death.dm index cdddd345d9c54..0b5bef65ddfe5 100644 --- a/code/modules/mob/living/carbon/human/death.dm +++ b/code/modules/mob/living/carbon/human/death.dm @@ -49,6 +49,9 @@ /mob/living/carbon/human/death(gibbing, deathmessage, silent, special_death_message) if(stat == DEAD) +//RUTGMC EDIT + species.handle_death(src, gibbing) +//RUTGMC EDIT return ..() if(species.death_message) deathmessage = species.death_message diff --git a/code/modules/mob/living/carbon/human/emote.dm b/code/modules/mob/living/carbon/human/emote.dm index 6596e296d466b..3309d8ac920c8 100644 --- a/code/modules/mob/living/carbon/human/emote.dm +++ b/code/modules/mob/living/carbon/human/emote.dm @@ -371,7 +371,11 @@ /datum/emote/living/carbon/human/laugh/get_sound(mob/living/user) - if(user.gender == FEMALE) +//RUTGMC EDIT + if(isyautja(user)) + return pick('modular_RUtgmc/sound/voice/pred_laugh1.ogg', 'modular_RUtgmc/sound/voice/pred_laugh2.ogg', 'modular_RUtgmc/sound/voice/pred_laugh3.ogg', 'modular_RUtgmc/sound/voice/pred_laugh4.ogg') +//RUTGMC EDIT + else if(user.gender == FEMALE) return 'sound/voice/human_female_laugh_1.ogg' else return pick('sound/voice/human_male_laugh_1.ogg', 'sound/voice/human_male_laugh_2.ogg') diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm index 3f7e704cc1d82..dca2c21dd0e33 100644 --- a/code/modules/mob/living/carbon/human/examine.dm +++ b/code/modules/mob/living/carbon/human/examine.dm @@ -514,6 +514,26 @@ RU TGMC EDIT PUPPETEER REMOVAL */ if(has_status_effect(STATUS_EFFECT_ADMINSLEEP)) msg += span_highdanger("This player has been slept by staff. Best to leave them be.\n") +//RUTGMC EDIT + if(isyautja(user)) + var/obj/item/clothing/gloves/yautja/hunter/bracers = gloves + if(istype(bracers) && bracers.name_active) + msg += span_blue("Their bracers identifies them as [real_name].") + msg += span_blue("[src] has the scent of [life_kills_total] defeated prey.") + if(src.hunter_data.hunted) + msg += span_orange("[src] is being hunted by [src.hunter_data.hunter.real_name].") + + if(src.hunter_data.dishonored) + msg += span_red("[src] was marked as dishonorable for '[src.hunter_data.dishonored_reason]'.") + else if(src.hunter_data.honored) + msg += span_green("[src] was honored for '[src.hunter_data.honored_reason]'.") + + if(src.hunter_data.thralled) + msg += span_green("[src] was thralled by [src.hunter_data.thralled_set.real_name] for '[src.hunter_data.thralled_reason]'.") + else if(src.hunter_data.gear) + msg += span_red("[src] was marked as carrying gear by [src.hunter_data.gear_set].") +//RUTGMC EDIT + msg += "" return list(msg) diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 7e6543436d22c..373716f5f3adc 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -67,9 +67,14 @@ hud_set_order() //and display them add_to_all_mob_huds() - +/* GLOB.huds[DATA_HUD_BASIC].add_hud_to(src) GLOB.huds[DATA_HUD_XENO_HEART].add_to_hud(src) +*/ +//RUTGMC EDIT ADDITION BEGIN - Preds + var/datum/atom_hud/hud_to_add = GLOB.huds[DATA_HUD_BASIC] + hud_to_add.add_hud_to(src) +//RUTGMC EDIT ADDITION END /mob/living/carbon/human/register_init_signals() . = ..() diff --git a/code/modules/mob/living/carbon/human/human_attackhand.dm b/code/modules/mob/living/carbon/human/human_attackhand.dm index 83ec44552f87e..b9f48bc818e99 100644 --- a/code/modules/mob/living/carbon/human/human_attackhand.dm +++ b/code/modules/mob/living/carbon/human/human_attackhand.dm @@ -116,11 +116,12 @@ visible_message(span_danger("[H] [pick(attack.attack_verb)]ed [src]!"), null, null, 5) var/list/hit_report = list() +/* RU TGMC EDIT //FUCK MELEE STUNS if(damage >= 5 && prob(50)) visible_message(span_danger("[H] has weakened [src]!"), null, null, 5) apply_effect(modify_by_armor(6 SECONDS, MELEE, def_zone = target_zone), WEAKEN) hit_report += "(KO)" - +RU TGMC EDIT */ damage += attack.damage apply_damage(damage, BRUTE, target_zone, MELEE, attack.sharp, attack.edge, updating_health = TRUE) diff --git a/code/modules/mob/living/carbon/human/human_damage.dm b/code/modules/mob/living/carbon/human/human_damage.dm index 282b066946749..4e658368abc39 100644 --- a/code/modules/mob/living/carbon/human/human_damage.dm +++ b/code/modules/mob/living/carbon/human/human_damage.dm @@ -25,7 +25,9 @@ var/health_deficiency = max(1 - (health / maxHealth) * 100, staminaloss) - if(health_deficiency >= 50) + //RUTGMC EDIT ADDITION BEGIN - Preds + if(health_deficiency >= 50 && !(species?.species_flags & PARALYSE_RESISTANT)) +//RUTGMC EDIT ADDITION END add_movespeed_modifier(MOVESPEED_ID_DAMAGE_SLOWDOWN, TRUE, 0, NONE, TRUE, health_deficiency / 50) else remove_movespeed_modifier(MOVESPEED_ID_DAMAGE_SLOWDOWN) @@ -340,6 +342,11 @@ This function restores all limbs. /mob/living/carbon/human/apply_damage(damage = 0, damagetype = BRUTE, def_zone, blocked = 0, sharp = FALSE, edge = FALSE, updating_health = FALSE, penetration) if(status_flags & (GODMODE)) return + +//RUTGMC EDIT ADDITION BEGIN - Preds + last_damage_source = usr //where my cause_data??? no cause_data? https://media.discordapp.net/attachments/1059662710217908245/1128315728081211412/65939r.png?width=842&height=917 +//RUTGMC EDIT ADDITION END + return species.apply_damage(damage, damagetype, def_zone, blocked, sharp, edge, updating_health, penetration, src) /mob/living/carbon/human/get_soft_armor(armor_type, proj_def_zone) diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index d5bb457137a0f..63ff8480470a6 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -113,6 +113,11 @@ Contains most of the procs that are called when a mob is attacked by something return FALSE var/hit_area = affecting.display_name +//RUTGMC EDIT ADDITION BEGIN - Preds + if((user != src) && check_pred_shields(I.force, "the [I.name]", backside_attack = dir == get_dir(get_turf(user), get_turf(src)))) + return FALSE +//RUTGMC EDIT ADDITION END + var/damage = I.force + round(I.force * MELEE_SKILL_DAM_BUFF * user.skills.getRating(SKILL_MELEE_WEAPONS)) if(user != src) damage = check_shields(COMBAT_MELEE_ATTACK, damage, "melee") @@ -146,10 +151,14 @@ Contains most of the procs that are called when a mob is attacked by something if((weapon_sharp || weapon_edge) && !prob(modify_by_armor(100, MELEE, def_zone = target_zone))) weapon_sharp = FALSE weapon_edge = FALSE - +// RU TGMC EDIT + var/final_damage = applied_damage + if(isyautja(user) && (ishumanbasic(src) || isrobot(src))) + final_damage *= PRED_MELEE_DAMAGE_MOD +// RU TGMC EDIT user.do_attack_animation(src, used_item = I) - apply_damage(applied_damage, I.damtype, target_zone, 0, weapon_sharp, weapon_edge, updating_health = TRUE) + apply_damage(final_damage, I.damtype, target_zone, 0, weapon_sharp, weapon_edge, updating_health = TRUE) //RU TGMC EDIT var/list/hit_report = list("(RAW DMG: [damage])") @@ -275,6 +284,11 @@ Contains most of the procs that are called when a mob is attacked by something log_combat(living_thrower, src, "thrown at", thrown_item, "(FAILED: shield blocked)") return TRUE +//RUTGMC EDIT ADDITION BEGIN - Preds + if((living_thrower != src) && check_pred_shields(throw_damage, "[thrown_item]", backside_attack = dir == get_dir(get_turf(AM), get_turf(src)))) + return +//RUTGMC EDIT ADDITION END + var/datum/limb/affecting = get_limb(zone) if(affecting.limb_status & LIMB_DESTROYED) diff --git a/code/modules/mob/living/carbon/human/human_helpers.dm b/code/modules/mob/living/carbon/human/human_helpers.dm index de235eec2ae7f..b74dc0c3cc617 100644 --- a/code/modules/mob/living/carbon/human/human_helpers.dm +++ b/code/modules/mob/living/carbon/human/human_helpers.dm @@ -5,7 +5,7 @@ return g /proc/get_limb_icon_name(datum/species/S, gender, limb_name, ethnicity) - if(S.name == "Human" || S.name == "Synthetic") + if(S.name == "Human" || S.name == "Yautja" || S.name == "Synthetic") switch(limb_name) if ("torso", "chest") return "[ethnicity]_torso_[get_gender_name(gender)]" diff --git a/code/modules/mob/living/carbon/human/inventory.dm b/code/modules/mob/living/carbon/human/inventory.dm index a0688df0c9c48..e6116db991e47 100644 --- a/code/modules/mob/living/carbon/human/inventory.dm +++ b/code/modules/mob/living/carbon/human/inventory.dm @@ -550,7 +550,7 @@ message_admins("[ADMIN_TPMONTY(src)] took the [I] of [ADMIN_TPMONTY(M)].") -/mob/living/carbon/human/proc/equipOutfit(outfit, visualsOnly = FALSE) +/mob/living/carbon/human/proc/equipOutfit(outfit, visualsOnly = FALSE, client/override_client) var/datum/outfit/O = null if(ispath(outfit)) @@ -562,7 +562,7 @@ if(!O) return FALSE - return O.equip(src, visualsOnly) + return O.equip(src, visualsOnly, override_client) /mob/living/carbon/human/proc/delete_equipment(save_id = FALSE) diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm index 6c907b68229a3..c3feda5747fc7 100644 --- a/code/modules/mob/living/carbon/human/species.dm +++ b/code/modules/mob/living/carbon/human/species.dm @@ -323,6 +323,11 @@ if(CHECK_BITFIELD(species_flags, NO_POISON) && istype(chem, /datum/reagent/toxin)) H.reagents.remove_reagent(chem.type, chem.custom_metabolism * H.metabolism_efficiency) return TRUE +//RUTGMC EDIT ADDITION BEGIN - Preds + if(isyautja(H) && istype(chem, /datum/reagent/medicine)) + H.reagents.remove_reagent(chem.type, chem.custom_metabolism * H.metabolism_efficiency) + return TRUE +//RUTGMC EDIT ADDITION END if(CHECK_BITFIELD(species_flags, NO_OVERDOSE)) //no stacking if(chem.overdose_threshold && chem.volume > chem.overdose_threshold) H.reagents.remove_reagent(chem.type, chem.volume - chem.overdose_threshold) diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm index a52abcfe70284..32546524cb0fa 100644 --- a/code/modules/mob/living/carbon/human/update_icons.dm +++ b/code/modules/mob/living/carbon/human/update_icons.dm @@ -677,10 +677,18 @@ GLOBAL_LIST_EMPTY(damage_icon_parts) /mob/living/carbon/human/update_burst() remove_overlay(BURST_LAYER) var/mutable_appearance/standing +//RUTGMC EDIT ADDITION BEGIN - Preds if(chestburst == 1) - standing = mutable_appearance('icons/Xeno/Effects.dmi', "burst_stand", -BURST_LAYER) + if(isyautja(src)) + standing = mutable_appearance('modular_RUtgmc/icons/Xeno/Effects.dmi', "predburst_stand", -BURST_LAYER) + else + standing = mutable_appearance('icons/Xeno/Effects.dmi', "burst_stand", -BURST_LAYER) else if(chestburst == 2) - standing = mutable_appearance('icons/Xeno/Effects.dmi', "bursted_stand", -BURST_LAYER) + if(isyautja(src)) + standing = mutable_appearance('modular_RUtgmc/icons/Xeno/Effects.dmi', "predbursted_stand", -BURST_LAYER) + else + standing = mutable_appearance('icons/Xeno/Effects.dmi', "bursted_stand", -BURST_LAYER) +//RUTGMC EDIT ADDITION END overlays_standing[BURST_LAYER] = standing apply_overlay(BURST_LAYER) diff --git a/code/modules/mob/living/carbon/xenomorph/attack_alien.dm b/code/modules/mob/living/carbon/xenomorph/attack_alien.dm index 4f22cd7bc0bd8..0e3c5ec8aecdb 100644 --- a/code/modules/mob/living/carbon/xenomorph/attack_alien.dm +++ b/code/modules/mob/living/carbon/xenomorph/attack_alien.dm @@ -182,8 +182,29 @@ to_chat(X, span_warning("[src] is dead, why would we want to touch it?")) return FALSE +//RUTGMC EDIT ADDITION BEGIN - Preds + if(isyautja(src) && check_pred_shields(X.xeno_caste.melee_damage * X.xeno_melee_damage_modifier + dam_bonus, backside_attack = dir == get_dir(get_turf(X), get_turf(src)), xenomorph = TRUE)) + return FALSE +//RUTGMC EDIT ADDITION END + SEND_SIGNAL(X, COMSIG_XENOMORPH_ATTACK_HUMAN, src) +//RUTGMC EDIT ADDITION BEGIN - Preds + if(wear_mask && X.zone_selected == "head") + if(!istype(wear_mask, /obj/item/clothing/mask/gas/yautja)) + return FALSE + if(prob(5)) + playsound(loc, "alien_claw_metal", 25, 1) + X.visible_message(span_danger("The [X] smashes off [src]'s [wear_mask.name]!"), \ + span_danger("You smash off [src]'s [wear_mask.name]!"), null, 5) + dropItemToGround(wear_mask) + if(isyautja(src)) + emote("roar") + else + emote("scream") + return TRUE +//RUTGMC EDIT ADDITION END + . = ..() if(!.) return FALSE diff --git a/code/modules/mob/living/carbon/xenomorph/castes/hunter/abilities_hunter.dm b/code/modules/mob/living/carbon/xenomorph/castes/hunter/abilities_hunter.dm index d0363c8b6803f..24b3f8dcbf966 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/hunter/abilities_hunter.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/hunter/abilities_hunter.dm @@ -334,7 +334,12 @@ RU TGMC EDIT */ xeno_owner.Paralyze(XENO_POUNCE_SHIELD_STUN_DURATION) xeno_owner.set_throwing(FALSE) return - playsound(living_target.loc, 'sound/voice/alien_pounce.ogg', 25, TRUE) +// RU TGMC EDIT + if(istype(owner, /mob/living/carbon/xenomorph/predalien)) + owner.playsound_local(owner, 'sound/voice/predalien_pounce.ogg', 25, 0, 1) + else + playsound(living_target.loc, 'sound/voice/alien_pounce.ogg', 25, TRUE) +// RU TGMC EDIT xeno_owner.set_throwing(FALSE) xeno_owner.Immobilize(XENO_POUNCE_STANDBY_DURATION) xeno_owner.forceMove(get_turf(living_target)) diff --git a/code/modules/mob/living/carbon/xenomorph/castes/king/abilities_king.dm b/code/modules/mob/living/carbon/xenomorph/castes/king/abilities_king.dm index 98bc7623b0894..8650bb8bc9940 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/king/abilities_king.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/king/abilities_king.dm @@ -501,6 +501,10 @@ var/sisters_teleported = 0 for(var/mob/living/carbon/xenomorph/sister AS in allxenos) sister.remove_filter("summonoutline") +//RUTGMC EDIT ADDITION BEGIN - Preds + if(HAS_TRAIT(sister, TRAIT_LEASHED)) + continue +//RUTGMC EDIT ADDITION END if(sister.z == owner.z) sister.forceMove(get_turf(X)) sisters_teleported ++ diff --git a/code/modules/mob/living/carbon/xenomorph/castes/runner/abilities_runner.dm b/code/modules/mob/living/carbon/xenomorph/castes/runner/abilities_runner.dm index 7ebc250f2e9d7..178f535b29832 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/runner/abilities_runner.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/runner/abilities_runner.dm @@ -304,6 +304,16 @@ if(!do_after(owner, 0.5 SECONDS, IGNORE_HELD_ITEM, A, BUSY_ICON_DANGER, extra_checks = CALLBACK(owner, TYPE_PROC_REF(/mob, break_do_after_checks), list("health" = X.health)))) return FALSE var/mob/living/carbon/human/victim = A +//RUTGMC EDIT ADDITION BEGIN - Preds + if(isyautja(victim)) + victim.emote("laugh") + X.Paralyze(75) + playsound(X,'modular_RUtgmc/sound/effects/hit_kick.ogg', 35, FALSE) + victim.balloon_alert(owner, "Snatch failed, we got caught!") + to_chat(X, span_xenodanger("[victim] counterattacks during our snatch attemp!")) + to_chat(victim, span_danger("[X] tried to steal our equipment, but failed!")) + return FALSE +//RUTGMC EDIT ADDITION END stolen_item = victim.get_active_held_item() if(!stolen_item) stolen_item = victim.get_inactive_held_item() diff --git a/code/modules/mob/living/carbon/xenomorph/damage_procs.dm b/code/modules/mob/living/carbon/xenomorph/damage_procs.dm index bb8b914bd41b3..dc8ff832d5589 100644 --- a/code/modules/mob/living/carbon/xenomorph/damage_procs.dm +++ b/code/modules/mob/living/carbon/xenomorph/damage_procs.dm @@ -91,6 +91,10 @@ if(BURN) adjustFireLoss(damage) +//RUTGMC EDIT ADDITION BEGIN - Preds + last_damage_source = usr +//RUTGMC EDIT ADDITION END + if(updating_health) updatehealth() diff --git a/code/modules/mob/living/carbon/xenomorph/embryo.dm b/code/modules/mob/living/carbon/xenomorph/embryo.dm index df2a65770d64c..dcdc762b858d7 100644 --- a/code/modules/mob/living/carbon/xenomorph/embryo.dm +++ b/code/modules/mob/living/carbon/xenomorph/embryo.dm @@ -143,7 +143,14 @@ //Spawn the larva. var/mob/living/carbon/xenomorph/larva/new_xeno - new_xeno = new(affected_mob) +//RUTGMC EDIT ADDITION BEGIN - Preds + if(isyautja(affected_mob)) + new_xeno = new /mob/living/carbon/xenomorph/larva/predalien(affected_mob) + yautja_announcement(span_yautjaboldbig("WARNING!\n\nAn abomination has been detected at [get_area_name(new_xeno)]. It is a stain upon our purity and is unfit for life. Exterminate it immediately.\n\nHeavy Armory unlocked.")) + SEND_GLOBAL_SIGNAL(COMSIG_GLOB_YAUTJA_ARMORY_OPENED) + else + new_xeno = new(affected_mob) +//RUTGMC EDIT ADDITION END new_xeno.transfer_to_hive(hivenumber) new_xeno.update_icons() diff --git a/code/modules/mob/living/carbon/xenomorph/emote.dm b/code/modules/mob/living/carbon/xenomorph/emote.dm index 33f725935c529..cc524fc7fda65 100644 --- a/code/modules/mob/living/carbon/xenomorph/emote.dm +++ b/code/modules/mob/living/carbon/xenomorph/emote.dm @@ -1,5 +1,13 @@ /datum/emote/living/carbon/xenomorph mob_type_allowed_typecache = /mob/living/carbon/xenomorph + mob_type_blacklist_typecache = list(/mob/living/carbon/xenomorph/hellhound) + var/predalien_sound + +/datum/emote/living/carbon/xenomorph/get_sound(mob/living/user) + . = ..() + + if(ispredalien(user) && predalien_sound) + . = predalien_sound /datum/emote/living/carbon/xenomorph/growl @@ -7,6 +15,7 @@ key_third_person = "growls" message = "growls!" emote_type = EMOTE_AUDIBLE + predalien_sound = 'sound/voice/predalien_growl.ogg' sound = 'sound/voice/alien_growl1.ogg' @@ -30,6 +39,7 @@ key_third_person = "hisses" message = "hisses!" emote_type = EMOTE_AUDIBLE + predalien_sound = 'sound/voice/predalien_hiss.ogg' sound = 'sound/voice/alien_hiss1.ogg' @@ -71,6 +81,7 @@ key_third_person = "roars" message = "roars!" emote_type = EMOTE_AUDIBLE + predalien_sound = 'sound/voice/predalien_roar.ogg' sound = 'sound/voice/alien_roar1.ogg' diff --git a/code/modules/mob/living/carbon/xenomorph/facehuggers.dm b/code/modules/mob/living/carbon/xenomorph/facehuggers.dm index 91c628f062ffe..0ad69d28491c0 100644 --- a/code/modules/mob/living/carbon/xenomorph/facehuggers.dm +++ b/code/modules/mob/living/carbon/xenomorph/facehuggers.dm @@ -556,7 +556,13 @@ reset_attach_status(FALSE) return if(ishuman(user)) - var/hugsound = user.gender == FEMALE ? get_sfx("female_hugged") : get_sfx("male_hugged") +//RUTGMC EDIT ADDITION BEGIN - Preds + var/hugsound + if(isyautja(user)) + hugsound = get_sfx("pred_hugged") + else + hugsound = user.gender == FEMALE ? get_sfx("female_hugged") : get_sfx("male_hugged") +//RUTGMC EDIT ADDITION END playsound(loc, hugsound, 25, 0) if(!sterile && !issynth(user)) var/stamina_dmg = user.maxHealth + user.max_stamina @@ -578,6 +584,14 @@ if(source?.client) var/datum/personal_statistics/personal_statistics = GLOB.personal_statistics_list[source.ckey] personal_statistics.impregnations++ +//RUTGMC EDIT ADDITION BEGIN - Preds + if(isyautja(target)) + var/datum/hive_status/hive = GLOB.hive_datums[embryo.hivenumber] + if(!istype(hive)) + return + hive.max_thick_nests++ + xeno_message("The hive senses that a headhunter has been infected! The thick resin nest is now available in the mother's blessing!", hivenumber = hive.hivenumber) +//RUTGMC EDIT ADDITION END sterile = TRUE kill_hugger() else diff --git a/code/modules/mob/living/carbon/xenomorph/life.dm b/code/modules/mob/living/carbon/xenomorph/life.dm index f2e87e187b0bc..1b021f0022f5a 100644 --- a/code/modules/mob/living/carbon/xenomorph/life.dm +++ b/code/modules/mob/living/carbon/xenomorph/life.dm @@ -34,6 +34,9 @@ handle_living_sunder_updates() handle_living_health_updates() handle_living_plasma_updates() +//RUTGMC EDIT ADDITION BEGIN - Preds + handle_interference() +//RUTGMC EDIT ADDITION END update_action_button_icons() update_icons(FALSE) diff --git a/code/modules/mob/living/carbon/xenomorph/say.dm b/code/modules/mob/living/carbon/xenomorph/say.dm index 4457c85ad6d3a..31f2ea04cea50 100644 --- a/code/modules/mob/living/carbon/xenomorph/say.dm +++ b/code/modules/mob/living/carbon/xenomorph/say.dm @@ -38,6 +38,11 @@ return if(!hive) return +//RUTGMC EDIT ADDITION BEGIN - Preds + if(interference) + to_chat(src, span_warning("A headhunter temporarily cut off your psychic connection!")) + return +//RUTGMC EDIT ADDITION END if(hivenumber == XENO_HIVE_NORMAL && !hive.living_xeno_ruler && hive.get_hivemind_conduit_death_timer() && timeleft(hive.get_hivemind_conduit_death_timer()) > hive.get_total_hivemind_conduit_time() * 0.5) to_chat(src, span_warning("The ruler is dead. The hivemind is weakened. Despair!")) return diff --git a/code/modules/mob/living/carbon/xenomorph/update_icons.dm b/code/modules/mob/living/carbon/xenomorph/update_icons.dm index fef5eba8c4c3a..fdcfa5c149f06 100644 --- a/code/modules/mob/living/carbon/xenomorph/update_icons.dm +++ b/code/modules/mob/living/carbon/xenomorph/update_icons.dm @@ -72,10 +72,11 @@ overlays_standing[X_L_HAND_LAYER] = l_hand.make_worn_icon(inhands = TRUE, slot_name = slot_l_hand_str, default_icon = 'icons/mob/items_lefthand_1.dmi', default_layer = X_L_HAND_LAYER) apply_overlay(X_L_HAND_LAYER) +/* /mob/living/carbon/xenomorph/proc/create_shriekwave() overlays_standing[X_SUIT_LAYER] = image("icon"='icons/Xeno/64x64_Xeno_overlays.dmi', "icon_state" = "shriek_waves") //Ehh, suit layer's not being used. apply_temp_overlay(X_SUIT_LAYER, 3 SECONDS) - +*/ /mob/living/carbon/xenomorph/proc/create_stomp() overlays_standing[X_SUIT_LAYER] = image("icon"='icons/Xeno/64x64_Xeno_overlays.dmi', "icon_state" = "stomp") //Ehh, suit layer's not being used. apply_temp_overlay(X_SUIT_LAYER, 1.2 SECONDS) diff --git a/code/modules/mob/living/carbon/xenomorph/xenomorph.dm b/code/modules/mob/living/carbon/xenomorph/xenomorph.dm index 69f549903a167..bbed0e3066a30 100644 --- a/code/modules/mob/living/carbon/xenomorph/xenomorph.dm +++ b/code/modules/mob/living/carbon/xenomorph/xenomorph.dm @@ -325,7 +325,7 @@ /mob/living/carbon/xenomorph/pull_response(mob/puller) if(stat != CONSCIOUS) // If the Xeno is unconscious, don't fight back against a grab/pull return TRUE - if(!ishuman(puller)) + if(!ishuman(puller) || isyautja(puller)) return TRUE var/mob/living/carbon/human/H = puller H.Paralyze(rand(xeno_caste.tacklemin,xeno_caste.tacklemax) * 20) diff --git a/code/modules/mob/living/carbon/xenomorph/xenoprocs.dm b/code/modules/mob/living/carbon/xenomorph/xenoprocs.dm index 6b5f0b721c5db..1fcb5053c17fb 100644 --- a/code/modules/mob/living/carbon/xenomorph/xenoprocs.dm +++ b/code/modules/mob/living/carbon/xenomorph/xenoprocs.dm @@ -10,6 +10,12 @@ set desc = "Check the status of your current hive." set category = "Alien" +//RUTGMC EDIT ADDITION BEGIN - Preds + if(interference) + to_chat(src, span_warning("A headhunter temporarily cut off your psychic connection!")) + return +//RUTGMC EDIT ADDITION END + check_hive_status(src) /mob/living/carbon/xenomorph/verb/tunnel_list() diff --git a/code/modules/mob/living/damage_procs.dm b/code/modules/mob/living/damage_procs.dm index c330041e19628..e8bbe15dea0c7 100644 --- a/code/modules/mob/living/damage_procs.dm +++ b/code/modules/mob/living/damage_procs.dm @@ -25,6 +25,10 @@ if(!damage) //no damage return 0 +//RUTGMC EDIT ADDITION BEGIN - Preds + last_damage_source = usr +//RUTGMC EDIT ADDITION END + switch(damagetype) if(BRUTE) adjustBruteLoss(damage) diff --git a/code/modules/mob/living/living_movement.dm b/code/modules/mob/living/living_movement.dm index 6390311a02002..1a9b0fa324f37 100644 --- a/code/modules/mob/living/living_movement.dm +++ b/code/modules/mob/living/living_movement.dm @@ -1,4 +1,8 @@ /mob/living/proc/update_pull_movespeed() +//RUTGMC EDIT ADDITION BEGIN - Preds + if(HAS_TRAIT(src, TRAIT_SUPER_STRONG)) + return +//RUTGMC EDIT ADDITION END if(!pulling?.drag_delay) remove_movespeed_modifier(MOVESPEED_ID_BULKY_DRAGGING) return diff --git a/code/modules/mob/login.dm b/code/modules/mob/login.dm index 3babee66aa838..f13248064129b 100644 --- a/code/modules/mob/login.dm +++ b/code/modules/mob/login.dm @@ -32,6 +32,13 @@ if(!client) return +//RUTGMC EDIT ADDITION BEGIN - Preds + if(length(client_color_matrices)) + update_client_color_matrices(time = 0) //This mob has client color matrices set, apply them instantly on login. + else + update_client_color_matrices(time = 1.5 SECONDS) //Otherwise, fade any matrices from a previous mob. +//RUTGMC EDIT ADDITION END + canon_client = client clear_important_client_contents(client) enable_client_mobs_in_contents(client) diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 90e23f591ccbb..a9aa21994f39e 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -22,6 +22,10 @@ var/datum/action/action_to_remove = a action_to_remove.remove_action(src) set_focus(null) +//RUTGMC EDIT ADDITION BEGIN - Preds + if(hunter_data) + hunter_data.clean_data() +//RUTGMC EDIT ADDITION END return ..() /mob/Initialize(mapload) @@ -41,6 +45,11 @@ update_movespeed(TRUE) log_mob_tag("\[[tag]\] CREATED: [key_name(src)]") become_hearing_sensitive() +//RUTGMC EDIT ADDITION BEGIN - Preds + if(!hunter_data) + hunter_data = new /datum/huntdata(src) + hud_set_hunter() +//RUTGMC EDIT ADDITION END /mob/proc/show_message(msg, type, alt_msg, alt_type, avoid_highlight) if(!client) @@ -360,6 +369,11 @@ to_chat(src, span_warning("Cannot grab, lacking free hands to do so!")) return FALSE +//RUTGMC EDIT ADDITION BEGIN - Preds + if(SEND_SIGNAL(AM, COMSIG_ATTEMPT_MOB_PULL) & COMPONENT_CANCEL_MOB_PULL) + return FALSE +//RUTGMC EDIT ADDITION END + AM.add_fingerprint(src, "pull") changeNext_move(CLICK_CD_GRABBING) diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm index c0aa95f9c50ec..654a57c6173a9 100644 --- a/code/modules/mob/mob_movement.dm +++ b/code/modules/mob/mob_movement.dm @@ -121,6 +121,10 @@ return O.relaymove(L, direct) var/add_delay = mob.cached_multiplicative_slowdown + mob.next_move_slowdown +//RUTGMC EDIT ADDITION BEGIN - Preds + if(mob.shield_slowdown) + add_delay += mob.shield_slowdown +//RUTGMC EDIT ADDITION END mob.next_move_slowdown = 0 if(old_move_delay + (add_delay * MOVEMENT_DELAY_BUFFER_DELTA) + MOVEMENT_DELAY_BUFFER > world.time) move_delay = old_move_delay diff --git a/code/modules/mob/new_player/ethnicity.dm b/code/modules/mob/new_player/ethnicity.dm index 81f3d5ab1524e..799ef880f1105 100644 --- a/code/modules/mob/new_player/ethnicity.dm +++ b/code/modules/mob/new_player/ethnicity.dm @@ -3,112 +3,142 @@ var/icon_name var/ethnic_category -/datum/ethnicity/anglo +/datum/ethnicity/human/anglo name = "Anglo" icon_name = "anglo" ethnic_category = "European" -/datum/ethnicity/western +/datum/ethnicity/human/western name = "Western" icon_name = "western" ethnic_category = "European" -/datum/ethnicity/germanic +/datum/ethnicity/human/germanic name = "Germanic" icon_name = "germanic" ethnic_category = "European" -/datum/ethnicity/scandinavian +/datum/ethnicity/human/scandinavian name = "Scandinavian" icon_name = "scandinavian" ethnic_category = "European" -/datum/ethnicity/baltic +/datum/ethnicity/human/baltic name = "Baltic" icon_name = "baltic" ethnic_category = "European" -/datum/ethnicity/sinoorient +/datum/ethnicity/human/sinoorient name = "Sino-Orient" icon_name = "sinoorient" ethnic_category = "Oriental" -/datum/ethnicity/eastorient +/datum/ethnicity/human/eastorient name = "East-Orient" icon_name = "eastorient" ethnic_category = "Oriental" -/datum/ethnicity/southorient +/datum/ethnicity/human/southorient name = "South-Orient" icon_name = "southasian" ethnic_category = "Oriental" -/datum/ethnicity/indian +/datum/ethnicity/human/indian name = "Indian" icon_name = "indian" ethnic_category = "Oriental" -/datum/ethnicity/sino +/datum/ethnicity/human/sino name = "Eurasian" icon_name = "eurasian" ethnic_category = "Oriental" -/datum/ethnicity/mesoamerican +/datum/ethnicity/human/mesoamerican name = "Mesoamerican" icon_name = "mesoamerican" ethnic_category = "American" -/datum/ethnicity/northamerican +/datum/ethnicity/human/northamerican name = "North American" icon_name = "northamerican" ethnic_category = "American" -/datum/ethnicity/southamerican +/datum/ethnicity/human/southamerican name = "South American" icon_name = "southamerican" ethnic_category = "American" -/datum/ethnicity/circumpolar +/datum/ethnicity/human/circumpolar name = "Circumpolar" icon_name = "circumpolar" ethnic_category = "American" -/datum/ethnicity/northafrican +/datum/ethnicity/human/northafrican name = "North African" icon_name = "northafrican" ethnic_category = "African" -/datum/ethnicity/centralafrican +/datum/ethnicity/human/centralafrican name = "Central African" icon_name = "centralafrican" ethnic_category = "African" -/datum/ethnicity/costalafrican +/datum/ethnicity/human/costalafrican name = "Coastal African" icon_name = "costalafrican" ethnic_category = "African" -/datum/ethnicity/arabian +/datum/ethnicity/human/arabian name = "Arabian" icon_name = "arabian" ethnic_category = "Middle Eastern" -/datum/ethnicity/levant +/datum/ethnicity/human/levant name = "Levant" icon_name = "levant" ethnic_category = "Middle Eastern" -/datum/ethnicity/australasian +/datum/ethnicity/human/australasian name = "Australasian" icon_name = "australasian" ethnic_category = "Oceania" -/datum/ethnicity/polynesian +/datum/ethnicity/human/polynesian name = "Polynesian" icon_name = "polynesian" ethnic_category = "Oceania" -/datum/ethnicity/mediterranean - name = "Mediterranean" - icon_name = "mediterranean" - ethnic_category = "Mediterranean" +/datum/ethnicity/yautja/tan + name = "Tan" + icon_name = "tan" + ethnic_category = "Tan" + +/datum/ethnicity/yautja/green + name = "Green" + icon_name = "green" + ethnic_category = "Green" + +/datum/ethnicity/yautja/purple + name = "Purple" + icon_name = "purple" + ethnic_category = "Purple" + +/datum/ethnicity/yautja/blue + name = "Blue" + icon_name = "blue" + ethnic_category = "Blue" + +/datum/ethnicity/yautja/purple + name = "Purple" + icon_name = "purple" + ethnic_category = "Purple" + +/datum/ethnicity/yautja/red + name = "Red" + icon_name = "red" + ethnic_category = "Red" + +/datum/ethnicity/yautja/black + name = "Black" + icon_name = "black" + ethnic_category = "Black" diff --git a/code/modules/mob/new_player/new_player.dm b/code/modules/mob/new_player/new_player.dm index 6f794ba9efb54..5b019faae00e3 100644 --- a/code/modules/mob/new_player/new_player.dm +++ b/code/modules/mob/new_player/new_player.dm @@ -151,6 +151,12 @@ if((xeno_job.total_positions-xeno_job.current_positions) > length(GLOB.alive_xeno_list_hive[XENO_HIVE_NORMAL]) * TOO_MUCH_BURROWED_PROPORTION) if(tgui_alert(src, "There is a lack of xeno players on this round, unbalanced rounds are unfun for everyone. Are you sure you want to play as a marine? ", "Warning : the game is unbalanced", list("Yes", "No")) != "Yes") return +//RUTGMC EDIT ADDITION BEGIN - Preds + if(ispredatorjob(job_datum)) + if(SSticker.mode.check_predator_late_join(src)) + SSticker.mode.join_predator(src) + return +//RUTGMC EDIT ADDITION END if(!SSticker.mode.CanLateSpawn(src, job_datum)) // Try to assigns job to new player return SSticker.mode.LateSpawn(src) @@ -369,6 +375,10 @@ return FALSE if(job.required_playtime_remaining(client)) return FALSE +//RUTGMC EDIT ADDITION BEGIN - Preds + if(!(GLOB.roles_whitelist[ckey] && WHITELIST_PREDATOR) && job == /datum/job/predator) + return FALSE +//RUTGMC EDIT ADDITION END if(latejoin && !job.special_check_latejoin(client)) return FALSE if(faction && job.faction != faction) diff --git a/code/modules/organs/limbs.dm b/code/modules/organs/limbs.dm index d7066d19a3a27..91e88a3c8b201 100644 --- a/code/modules/organs/limbs.dm +++ b/code/modules/organs/limbs.dm @@ -421,6 +421,12 @@ Note that amputating the affected organ does in fact remove the infection from t germ_level = 0 return +//RUTGMC EDIT ADDITION BEGIN - Preds + if(isyautja(owner)) + germ_level = 0 + return +//RUTGMC EDIT ADDITION END + if(owner.bodytemperature >= 170 && !HAS_TRAIT(owner, TRAIT_STASIS)) //cryo stops germs from moving and doing their bad stuffs //** Syncing germ levels with external wounds handle_germ_sync() diff --git a/code/modules/organs/wound.dm b/code/modules/organs/wound.dm index 68868eebbb267..1b2c9a05c2786 100644 --- a/code/modules/organs/wound.dm +++ b/code/modules/organs/wound.dm @@ -67,11 +67,12 @@ var/bicardose = parent_limb.owner.reagents.get_reagent_amount(/datum/reagent/medicine/bicaridine) var/inaprovaline = parent_limb.owner.reagents.get_reagent_amount(/datum/reagent/medicine/inaprovaline) var/quickclot = parent_limb.owner.reagents.get_reagent_amount(/datum/reagent/medicine/quickclot) + var/thwei = parent_limb.owner.reagents.get_reagent_amount(/datum/reagent/thwei) if(!(bicardose && inaprovaline)) //bicaridine and inaprovaline stop internal wounds from harming the parent limb over time parent_limb.createwound(CUT, 0.1) - if(!quickclot) //Quickclot stops bleeding, magic! + if(!quickclot || !thwei) //Quickclot/thwei stops bleeding, magic! parent_limb.owner.blood_volume = max(0, parent_limb.owner.blood_volume - damage/30) if(prob(1)) parent_limb.owner.custom_pain("You feel a stabbing pain in your [parent_limb.display_name]!", 1) diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm index 60e7ba8c3dfdb..4f5f7d2949369 100644 --- a/code/modules/power/apc.dm +++ b/code/modules/power/apc.dm @@ -648,6 +648,53 @@ if(.) return +//RUTGMC EDIT ADDITION BEGIN - Preds + if(!ishuman(user)) + return FALSE + var/mob/living/carbon/human/grabber = user + if(grabber.a_intent != INTENT_GRAB) + return FALSE + // Yautja Bracer Recharge + var/obj/item/clothing/gloves/yautja/bracer = grabber.gloves + if(istype(bracer)) + if(!COOLDOWN_CHECK(bracer, bracer_recharge)) + to_chat(user, span_warning("It is too soon for [bracer.name] to siphon power again. Wait [COOLDOWN_TIMELEFT(bracer, bracer_recharge)] seconds.")) + return FALSE + to_chat(user, span_notice("You rest your bracer against the APC interface and begin to siphon off some of the stored energy.")) + if(!do_after(grabber, 20, TRUE, src, BUSY_ICON_HOSTILE)) + return FALSE + + if(machine_stat & (BROKEN|MAINT)) + var/datum/effect_system/spark_spread/spark = new() + spark.set_up(3, 1, src) + spark.start() + to_chat(grabber, span_danger("The APC's power currents surge eratically, super-heating your bracer!")) + playsound(src.loc, 'sound/effects/sparks2.ogg', 25, 1) + grabber.apply_damage(10,0, BURN) + return FALSE + if(!cell || cell.charge <= 0) + to_chat(user, span_warning("There is no charge to draw from that APC.")) + return FALSE + + if(bracer.charge_max <= bracer.charge) + to_chat(user, span_warning("[bracer.name] is already fully charged.")) + return FALSE + + var/charge_to_use = min(cell.charge, bracer.charge_max - bracer.charge) + if(!(cell.use(charge_to_use))) + return FALSE + playsound(src.loc, 'sound/effects/sparks2.ogg', 25, 1) + bracer.charge += charge_to_use + COOLDOWN_START(bracer, bracer_recharge, bracer.charge_cooldown) + to_chat(grabber, span_yautjabold("[icon2html(bracer)] \The [bracer] beep: Power siphon complete. Charge at [bracer.charge]/[bracer.charge_max].")) + if(bracer.notification_sound) + playsound(bracer.loc, 'modular_RUtgmc/sound/items/pred_bracer.ogg', 75, 1) + charging = APC_CHARGING + set_broken() // Breaks the APC + + return TRUE +//RUTGMC EDIT ADDITION END + if(opened && cell && !issilicon(user)) if(user.skills.getRating(SKILL_ENGINEER) < SKILL_ENGINEER_ENGI) balloon_alert_to_viewers("fumbles") diff --git a/code/modules/projectiles/sentries.dm b/code/modules/projectiles/sentries.dm index a32455915cc8e..254023554f049 100644 --- a/code/modules/projectiles/sentries.dm +++ b/code/modules/projectiles/sentries.dm @@ -376,7 +376,7 @@ if(!gun) return length(potential_targets) for(var/mob/living/carbon/human/nearby_human AS in cheap_get_humans_near(src, range)) - if(nearby_human.stat == DEAD || CHECK_BITFIELD(nearby_human.status_flags, INCORPOREAL) || (CHECK_BITFIELD(gun.turret_flags, TURRET_SAFETY) || nearby_human.wear_id?.iff_signal & iff_signal)) + if(nearby_human.stat == DEAD || CHECK_BITFIELD(nearby_human.status_flags, INCORPOREAL) || (CHECK_BITFIELD(gun.turret_flags, TURRET_SAFETY) || nearby_human.wear_id?.iff_signal & iff_signal) || HAS_TRAIT(nearby_human, TRAIT_TURRET_HIDDEN)) //RU TGMC EDIT continue potential_targets += nearby_human for(var/mob/living/carbon/xenomorph/nearby_xeno AS in cheap_get_xenos_near(src, range)) diff --git a/code/modules/reagents/reagents/toxin.dm b/code/modules/reagents/reagents/toxin.dm index 15573958fd8d2..6d8437155c169 100644 --- a/code/modules/reagents/reagents/toxin.dm +++ b/code/modules/reagents/reagents/toxin.dm @@ -124,7 +124,10 @@ taste_description = "death" /datum/reagent/toxin/huskpowder/on_mob_add(mob/living/L, metabolism) - ADD_TRAIT(L, TRAIT_FAKEDEATH, type) + if(isyautja(L)||isxeno(L)) + return + else + ADD_TRAIT(L, TRAIT_FAKEDEATH, type) return ..() /datum/reagent/toxin/huskpowder/on_mob_life(mob/living/L, metabolism) diff --git a/code/modules/surgery/surgery.dm b/code/modules/surgery/surgery.dm index 175732e59f208..4328d6c4630a1 100644 --- a/code/modules/surgery/surgery.dm +++ b/code/modules/surgery/surgery.dm @@ -199,7 +199,9 @@ GLOBAL_LIST_INIT(surgery_steps, init_surgery()) multipler += 0.45 if(M.shock_stage > 100) //Being near to unconsious is good in this case multipler += 0.25 - if(issynth(user)) +//RUTGMC EDIT ADDITION BEGIN - Preds + if(issynth(user) || isyautja(user)) +//RUTGMC EDIT ADDITION END multipler = 1 //calculate step duration diff --git a/config/role_whitelist.txt b/config/role_whitelist.txt new file mode 100644 index 0000000000000..4a047e3e35e9c --- /dev/null +++ b/config/role_whitelist.txt @@ -0,0 +1,21 @@ +# The format of this document is the person's ckey followed by their role permissions. +# You must list all permissions for a single ckey using one line. + +# Casing does not matter, spacing does not matter, and underscores do not matter. +# +Y_aut j a El_DER will be converted into yautjaelder. +# You may add any of the possible roles below, using different names as indicated. +# Adding two or more of the same role will not matter. +# A lot of the defines are just placeholders for right now. + +###################################################### +# +Yautja +# +YautjaLegacy +# +YautjaCouncil +# +YautjaLeader +# +YautjaCouncilLegacy +####################################################### + +#Your_name_here +All + + +Blundir +yautja +yautjaleader +yautjalegacy diff --git a/html/browser/banpanel.css b/html/browser/banpanel.css index 0ad85f80129c6..1d2418bbc3f07 100644 --- a/html/browser/banpanel.css +++ b/html/browser/banpanel.css @@ -84,6 +84,9 @@ background-color: #8972AA; } +.predator { + background-color: #FFEFDF; +} .abstract { background-color: #708090; diff --git a/interface/stylesheet.dm b/interface/stylesheet.dm index e4baa1eb7ab48..db11b821f1c74 100644 --- a/interface/stylesheet.dm +++ b/interface/stylesheet.dm @@ -140,6 +140,8 @@ a.popt {text-decoration: none;} .xrayradio {color: #008000;} .whiskeyradio {color: #CC00CC;} +.yautjaradio {color: #b33d3d;} + .binarysay {color: #20c20e; background-color: #000000; display: block;} .binarysay a {color: #00ff00;} .binarysay a:active, .binarysay a:visited {color: #88ff88;} @@ -227,6 +229,9 @@ h1.alert, h2.alert {color: #000000;} .connectionClosed.restored {background: green;} .internal.boldnshit {color: blue; font-weight: bold;} +.retro_translator {font-weight: bold;} +.yautja_translator {color: #aa0000; font-weight: bold;} + .text-normal {font-weight: normal; font-style: normal;} .hidden {display: none; visibility: hidden;} "} diff --git a/modular_RUtgmc/code/__HELPERS/matrices.dm b/modular_RUtgmc/code/__HELPERS/matrices.dm new file mode 100644 index 0000000000000..839568c0c5efc --- /dev/null +++ b/modular_RUtgmc/code/__HELPERS/matrices.dm @@ -0,0 +1,107 @@ +//word of warning: using a matrix like this as a color value will simplify it back to a string after being set +/proc/color_hex2color_matrix(string) + var/length = length(string) + if((length != 7 && length != 9) || length != length_char(string)) + return color_matrix_identity() + var/r = hex2num(copytext(string, 2, 4))/255 + var/g = hex2num(copytext(string, 4, 6))/255 + var/b = hex2num(copytext(string, 6, 8))/255 + var/a = 1 + if(length == 9) + a = hex2num(copytext(string, 8, 10))/255 + if(!isnum(r) || !isnum(g) || !isnum(b) || !isnum(a)) + return color_matrix_identity() + return list(r, 0, 0, 0, 0, g, 0, 0, 0, 0, b, 0, 0, 0, 0, a, 0, 0, 0, 0) + + +///Converts a hex color string to a color matrix. +/proc/color_matrix_from_string(string) + if(!string || !istext(string)) + return color_matrix_identity() + + var/string_r = hex2num(copytext(string, 2, 4)) / 255 + var/string_g = hex2num(copytext(string, 4, 6)) / 255 + var/string_b = hex2num(copytext(string, 6, 8)) / 255 + + return list(string_r, 0, 0, 0, 0, string_g, 0, 0, 0, 0, string_b, 0, 0, 0, 0, 1, 0, 0, 0, 0) + + + +/*Changing/updating a mob's client color matrices. These render over the map window and affect most things the player sees, except things like inventory, +text popups, HUD, and some fullscreens. Code based on atom filter code, since these have similar issues with application order - for ex. if you have +a desaturation and a recolor matrix, you'll get very different results if you desaturate before recoloring, or recolor before desaturating. +See matrices.dm for the matrix procs. +If you want to recolor a specific atom, you should probably do it as a color matrix filter instead since that code already exists. +Apparently color matrices are not the same sort of matrix used by matrix datums and can't be worked with using normal matrix procs.*/ + +///Adds a color matrix and updates the client. Priority is the order the matrices are applied, lowest first. Will replace an existing matrix of the same name, if one exists. +/mob/proc/add_client_color_matrix(name, priority, list/params, time, easing) + LAZYINITLIST(client_color_matrices) + + //Package the matrices in another list that stores priority. + client_color_matrices[name] = list("priority" = priority, "color_matrix" = params.Copy()) + + update_client_color_matrices(time, easing) + +/**Combines all color matrices and applies them to the client. +Also used on login to give a client its new body's color matrices. +Responsible for sorting the matrices. +Transition is animated but instant by default.**/ +/mob/proc/update_client_color_matrices(time = 0 SECONDS, easing = LINEAR_EASING) + if(!client) + return + + if(!length(client_color_matrices)) + animate(client, color = null, time = time, easing = easing) + UNSETEMPTY(client_color_matrices) + SEND_SIGNAL(src, COMSIG_MOB_RECALCULATE_CLIENT_COLOR) + return + + //Sort the matrix packages by priority. + client_color_matrices = sortTim(client_color_matrices, GLOBAL_PROC_REF(cmp_filter_data_priority), TRUE) + + var/list/final_matrix + + for(var/package in client_color_matrices) + var/list/current_matrix = client_color_matrices[package]["color_matrix"] + if(!final_matrix) + final_matrix = current_matrix + else + final_matrix = color_matrix_multiply(final_matrix, current_matrix) + + animate(client, color = final_matrix, time = time, easing = easing) + SEND_SIGNAL(src, COMSIG_MOB_RECALCULATE_CLIENT_COLOR) + +///Changes a matrix package's priority and updates client. +/mob/proc/change_client_color_matrix_priority(name, new_priority, time, easing) + if(!client_color_matrices || !client_color_matrices[name]) + return + + client_color_matrices[name]["priority"] = new_priority + + update_client_color_matrices(time, easing) + +///Returns the matrix of that name, if it exists. +/mob/proc/get_client_color_matrix(name) + return client_color_matrices[name]["color_matrix"] + +///Can take either a single name or a list of several. Attempts to remove target matrix packages and update client. +/mob/proc/remove_client_color_matrix(name_or_names, time, easing) + if(!client_color_matrices) + return + + var/found = FALSE + var/list/names = islist(name_or_names) ? name_or_names : list(name_or_names) + + for(var/name in names) + if(client_color_matrices[name]) + client_color_matrices -= name + found = TRUE + + if(found) + update_client_color_matrices(time, easing) + +///Removes all matrices and updates client. +/mob/proc/clear_client_color_matrices(time, easing) + client_color_matrices = null + update_client_color_matrices(time, easing) diff --git a/modular_RUtgmc/code/__HELPERS/unsorted.dm b/modular_RUtgmc/code/__HELPERS/unsorted.dm index 922d5f364e4bf..723c7dbd47695 100644 --- a/modular_RUtgmc/code/__HELPERS/unsorted.dm +++ b/modular_RUtgmc/code/__HELPERS/unsorted.dm @@ -1,3 +1,98 @@ +/proc/get_true_location(atom/loc) + var/atom/subLoc = loc + while(subLoc.z == 0) + if (istype(subLoc.loc, /atom)) + subLoc = subLoc.loc + else + return subLoc + return subLoc + +#define get_true_turf(loc) get_turf(get_true_location(loc)) + +GLOBAL_LIST_EMPTY(loose_yautja_gear) +GLOBAL_LIST_EMPTY(tracked_yautja_gear) // list of pred gear with a tracking element attached + +GLOBAL_LIST_EMPTY(mainship_yautja_teleports) +GLOBAL_LIST_EMPTY(mainship_yautja_desc) +GLOBAL_LIST_EMPTY(yautja_teleports) +GLOBAL_LIST_EMPTY(yautja_teleport_descs) + +GLOBAL_LIST_INIT_TYPED(all_yautja_capes, /obj/item/clothing/yautja_cape, setup_yautja_capes()) + +/proc/setup_yautja_capes() + var/list/cape_list = list() + for(var/obj/item/clothing/yautja_cape/cape_type as anything in typesof(/obj/item/clothing/yautja_cape)) + cape_list[initial(cape_type.name)] = cape_type + return cape_list + +GLOBAL_VAR_INIT(roles_whitelist, load_role_whitelist()) + +/proc/load_role_whitelist(filename = "config/role_whitelist.txt") + var/L[] = file2list(filename) + var/P[] + var/W[] = new //We want a temporary whitelist list, in case we need to reload. + + var/i + var/r + var/ckey + var/role + for(i in L) + if(!i) + continue + i = trim(i) + + if(!length(i)) + continue + + else if(copytext(i, 1, 2) == "#") + continue + + P = splittext(i, "+") + + if(!P.len) + continue + + ckey = ckey(P[1]) //Converting their key to canonical form. ckey() does this by stripping all spaces, underscores and converting to lower case. + + role = NONE + r = 1 + while(++r <= P.len) + switch(ckey(P[r])) + if("yautja") + role |= WHITELIST_YAUTJA + if("yautjalegacy") + role |= WHITELIST_YAUTJA_LEGACY + if("yautjacouncil") + role |= WHITELIST_YAUTJA_COUNCIL + if("yautjacouncillegacy") + role |= WHITELIST_YAUTJA_COUNCIL_LEGACY + if("yautjaleader") + role |= WHITELIST_YAUTJA_LEADER + + W[ckey] = role + + return W + +//yautja ship AI announcement +/proc/yautja_announcement(message, title = "You receive a message from your ship AI...", sound_to_play = sound('sound/misc/notice1.ogg')) + var/list/targets = GLOB.human_mob_list + GLOB.dead_mob_list + for(var/mob/M in targets) + if(!isobserver(M)) //observers see everything + var/mob/living/carbon/human/H = M + if(!isyautja(H) || H.stat != CONSCIOUS) + continue + + to_chat(M, html = "[title]

[span_alert(message)]") + SEND_SOUND(M, sound_to_play) + +/// Will attempt to find what's holding this item if it's being contained by something, ie if it's in a satchel held by a human, this'll return the human +/proc/recursive_holder_check(obj/item/held_item, recursion_limit = 3) + if(recursion_limit <= 0) + return held_item + if(!held_item.loc || isturf(held_item.loc)) + return held_item + recursion_limit-- + return recursive_holder_check(held_item.loc, recursion_limit) // returns turf relative to A for a given clockwise angle at set range // result is bounded to map size diff --git a/modular_RUtgmc/code/_globalvars/lists/flavor_misc.dm b/modular_RUtgmc/code/_globalvars/lists/flavor_misc.dm index cdfed1b7406b9..38058baae9050 100644 --- a/modular_RUtgmc/code/_globalvars/lists/flavor_misc.dm +++ b/modular_RUtgmc/code/_globalvars/lists/flavor_misc.dm @@ -45,8 +45,37 @@ GLOBAL_LIST_INIT(playable_icons, list( "xenoqueen", "xenoshrike", "chimera", + "predator", + "thrall", + "hellhound", )) +GLOBAL_LIST_EMPTY(human_ethnicities_list) +GLOBAL_LIST_EMPTY(yautja_ethnicities_list) + +GLOBAL_LIST_EMPTY(yautja_hair_styles_list) + +GLOBAL_LIST_INIT(ethnicities_list, init_ethnicities()) + +/// Ethnicity - Initialise all /datum/ethnicity into a list indexed by ethnicity name +/proc/init_ethnicities() + . = list() + + for(var/path in subtypesof(/datum/ethnicity) - /datum/ethnicity/human - /datum/ethnicity/yautja) + var/datum/ethnicity/E = new path() + .[E.name] = E + + if(istype(E, /datum/ethnicity/human)) + GLOB.human_ethnicities_list[E.name] = E + + if(istype(E, /datum/ethnicity/yautja)) + GLOB.yautja_ethnicities_list[E.name] = E + + for(var/path in subtypesof(/datum/sprite_accessory/yautja_hair)) + var/datum/sprite_accessory/yautja_hair/H = new path() + GLOB.yautja_hair_styles_list[H.name] = H + + GLOBAL_LIST_INIT(minimap_icons, init_minimap_icons()) /proc/init_minimap_icons() diff --git a/modular_RUtgmc/code/_globalvars/lists/mobs.dm b/modular_RUtgmc/code/_globalvars/lists/mobs.dm index 1653077bcf360..c58e4faec267e 100644 --- a/modular_RUtgmc/code/_globalvars/lists/mobs.dm +++ b/modular_RUtgmc/code/_globalvars/lists/mobs.dm @@ -61,3 +61,6 @@ GLOBAL_LIST_INIT(forbid_excepts, list( /mob/living/carbon/xenomorph/larva, /mob/living/carbon/xenomorph/drone, )) + +GLOBAL_LIST_EMPTY_TYPED(hellhound_list, /mob/living/carbon/xenomorph/hellhound) +GLOBAL_LIST_EMPTY_TYPED(yautja_mob_list, /mob/living/carbon/human/species/yautja) diff --git a/modular_RUtgmc/code/_onclick/hud/defines.dm b/modular_RUtgmc/code/_onclick/hud/defines.dm new file mode 100644 index 0000000000000..23084614f90fc --- /dev/null +++ b/modular_RUtgmc/code/_onclick/hud/defines.dm @@ -0,0 +1,18 @@ +//Upper-middle right (damage indicators) +#define ui_predator_power "EAST-1:28,CENTER:17" + +/atom/movable/screen/fullscreen/machine/pred + alpha = 140 + +/atom/movable/screen/fullscreen/machine/pred/meson + icon_state = "pred_meson" + icon = 'modular_RUtgmc/icons/mob/screen/full.dmi' + +/atom/movable/screen/fullscreen/machine/pred/night + icon_state = "robothalf" + +/datum/hud/var/atom/movable/screen/pred_power_icon + +/datum/hud/Destroy() + pred_power_icon = null + return ..() diff --git a/modular_RUtgmc/code/_onclick/hud/yautja.dm b/modular_RUtgmc/code/_onclick/hud/yautja.dm new file mode 100644 index 0000000000000..75faa71069515 --- /dev/null +++ b/modular_RUtgmc/code/_onclick/hud/yautja.dm @@ -0,0 +1,18 @@ +/datum/hud/human/species/yautja/New(mob/living/carbon/human/owner, ui_style='icons/mob/screen/White.dmi', ui_color = "#ffffff", ui_alpha = 230) + . = ..() + + pred_power_icon = new /atom/movable/screen() + pred_power_icon.icon = 'modular_RUtgmc/icons/mob/screen/yautja.dmi' + pred_power_icon.icon_state = "powerbar10" + pred_power_icon.name = "bracer power stored" + pred_power_icon.screen_loc = ui_predator_power + infodisplay += pred_power_icon + +/mob/living/carbon/human/species/yautja/create_mob_hud() + if(client && !hud_used) + var/ui_style = ui_style2icon(client.prefs.ui_style) + var/ui_color = client.prefs.ui_style_color + var/ui_alpha = client.prefs.ui_style_alpha + hud_used = new /datum/hud/human/species/yautja(src, ui_style, ui_color, ui_alpha) + else + hud_used = new /datum/hud/human/species/yautja(src) diff --git a/modular_RUtgmc/code/controllers/configuration/entries.dm b/modular_RUtgmc/code/controllers/configuration/entries.dm new file mode 100644 index 0000000000000..88c1d84bbd6a6 --- /dev/null +++ b/modular_RUtgmc/code/controllers/configuration/entries.dm @@ -0,0 +1,9 @@ +/datum/config_entry/number/pred_round + config_entry_value = 0 + min_val = 0 + max_val = 2 + +/datum/config_entry/number/pred_round_chance + config_entry_value = 0 + min_val = 0 + max_val = 100 diff --git a/modular_RUtgmc/code/controllers/subsystem/dbcore.dm b/modular_RUtgmc/code/controllers/subsystem/dbcore.dm new file mode 100644 index 0000000000000..d99b50d85a238 --- /dev/null +++ b/modular_RUtgmc/code/controllers/subsystem/dbcore.dm @@ -0,0 +1,2 @@ +/datum/db_query + var/no_auto_delete = FALSE diff --git a/modular_RUtgmc/code/controllers/subsystem/hunt_system.dm b/modular_RUtgmc/code/controllers/subsystem/hunt_system.dm new file mode 100644 index 0000000000000..b50f0fe622283 --- /dev/null +++ b/modular_RUtgmc/code/controllers/subsystem/hunt_system.dm @@ -0,0 +1,73 @@ +SUBSYSTEM_DEF(hunting) + name = "hunting" + wait = 10 MINUTES + flags = SS_NO_INIT + + var/list/xeno_blacklist = list( + /mob/living/carbon/xenomorph/drone, + /mob/living/carbon/xenomorph/queen, + /mob/living/carbon/xenomorph/king, + /mob/living/carbon/xenomorph/shrike, + /mob/living/carbon/xenomorph/boiler, + /mob/living/carbon/xenomorph/hivelord, + /mob/living/carbon/xenomorph/defiler, + /mob/living/carbon/xenomorph/larva, + /mob/living/carbon/xenomorph/hivemind + ) + var/list/human_blacklist = list( + /datum/job/terragov/squad/corpsman, + /datum/job/som/squad/medic, + /datum/job/terragov/medical, + /datum/job/terragov/engineering + ) + var/list/human_blacklist_type = list( + /datum/job/fallen, + /datum/job/terragov/command, + /datum/job/terragov/silicon + ) + var/list/hunter_datas = list() + +/datum/controller/subsystem/hunting/fire(resumed, init_tick_checks) + for(var/datum/huntdata/data in hunter_datas) + if(data.dishonored || data.thralled) + continue + if(ishuman(data.owner)) + if(isyautja(data.owner)) + continue + if(!data.owner.job || (data.owner.job.type in human_blacklist)) + continue + var/found = FALSE + for(var/str in human_blacklist_type) + if(istype(data.owner.job, str)) + found = TRUE + break + if(found) + continue + else if(isxeno(data.owner)) + var/mob/living/carbon/xenomorph/xeno = data.owner + if(xeno.hive == XENO_HIVE_FALLEN) + continue + var/number_tier = GLOB.tier_as_number[xeno.tier] + if(number_tier <= 0 || (xeno.type in xeno_blacklist)) + continue + else + continue + if(data.owner.stat || !data.honored && data.owner.life_kills_total < 2 || data.owner.life_value == 0) // Don't make zero kills xeno as target for additional honor or stunned/dead + continue + if(prob(80)) // nah + continue + + for(var/mob/living/carbon/pred in GLOB.yautja_mob_list) + if(pred.stat || !pred.hunter_data) + continue + if(length(pred.hunter_data.targets) > 4) + continue + data.automatic_target = TRUE + data.targeted = pred + pred.hunter_data.targets += data + hunter_datas -= data + break + +/datum/controller/subsystem/hunting/Recover() + hunter_datas = SShunting.hunter_datas + return ..() diff --git a/modular_RUtgmc/code/controllers/subsystem/job.dm b/modular_RUtgmc/code/controllers/subsystem/job.dm index 760508716cd8b..64708d21f9cdf 100644 --- a/modular_RUtgmc/code/controllers/subsystem/job.dm +++ b/modular_RUtgmc/code/controllers/subsystem/job.dm @@ -11,7 +11,7 @@ var/datum/job/terragov/squad/marine = job var/mob/living/carbon/human/h = new_character if(!ishuman(new_character) || !h.assigned_squad || !length_char(GLOB.start_squad_landmarks_list)) - spawn_turf = job.return_spawn_turf() + spawn_turf = job.return_spawn_turf(player, player.client) else spawn_turf = marine.spawn_by_squads(h.assigned_squad.id) if(spawn_turf) diff --git a/modular_RUtgmc/code/controllers/subsystem/minimaps.dm b/modular_RUtgmc/code/controllers/subsystem/minimaps.dm index 25379fab0800e..594c098bbfd09 100644 --- a/modular_RUtgmc/code/controllers/subsystem/minimaps.dm +++ b/modular_RUtgmc/code/controllers/subsystem/minimaps.dm @@ -1,2 +1,58 @@ /atom/movable/screen/minimap_locator icon = 'modular_RUTGMC/icons/UI_icons/map_blips.dmi' + +/datum/controller/subsystem/minimaps/proc/add_zlevel(zlevel) + minimaps_by_z["[zlevel]"] = new /datum/hud_displays + var/icon/icon_gen = new('icons/UI_icons/minimap.dmi') //480x480 blank icon template for drawing on the map + for(var/xval = 1 to world.maxx) + for(var/yval = 1 to world.maxy) //Scan all the turfs and draw as needed + var/turf/location = locate(xval,yval,zlevel) + if(isspaceturf(location)) + continue + if(location.density) + icon_gen.DrawBox(location.minimap_color, xval, yval) + continue + var/atom/movable/alttarget = (locate(/obj/machinery/door) in location) || (locate(/obj/structure/fence) in location) + if(alttarget) + icon_gen.DrawBox(alttarget.minimap_color, xval, yval) + continue + var/area/turfloc = location.loc + if(turfloc.minimap_color) + icon_gen.DrawBox(BlendRGB(location.minimap_color, turfloc.minimap_color, 0.5), xval, yval) + continue + icon_gen.DrawBox(location.minimap_color, xval, yval) + icon_gen.Scale(480*2,480*2) //scale it up x2 to make it easer to see + icon_gen.Crop(1, 1, min(icon_gen.Width(), 480), min(icon_gen.Height(), 480)) //then cut all the empty pixels + //generation is done, now we need to center the icon to someones view, this can be left out if you like it ugly and will halve SSinit time + //calculate the offset of the icon + var/largest_x = 0 + var/smallest_x = SCREEN_PIXEL_SIZE + var/largest_y = 0 + var/smallest_y = SCREEN_PIXEL_SIZE + for(var/xval=1 to SCREEN_PIXEL_SIZE step 2) //step 2 is twice as fast :) + for(var/yval=1 to SCREEN_PIXEL_SIZE step 2) //keep in mind 1 wide giant straight lines will offset wierd but you shouldnt be mapping those anyway right??? + if(!icon_gen.GetPixel(xval, yval)) + continue + if(xval > largest_x) + largest_x = xval + else if(xval < smallest_x) + smallest_x = xval + if(yval > largest_y) + largest_y = yval + else if(yval < smallest_y) + smallest_y = yval + + minimaps_by_z["[zlevel]"].x_offset = FLOOR((SCREEN_PIXEL_SIZE-largest_x-smallest_x)/2, 1) + minimaps_by_z["[zlevel]"].y_offset = FLOOR((SCREEN_PIXEL_SIZE-largest_y-smallest_y)/2, 1) + + icon_gen.Shift(EAST, minimaps_by_z["[zlevel]"].x_offset) + icon_gen.Shift(NORTH, minimaps_by_z["[zlevel]"].y_offset) + + minimaps_by_z["[zlevel]"].hud_image = icon_gen //done making the image! + +/datum/action/minimap/yautja + minimap_flags = MINIMAP_FLAG_XENO|MINIMAP_FLAG_MARINE|MINIMAP_FLAG_MARINE_SOM|MINIMAP_FLAG_YAUTJA + marker_flags = MINIMAP_FLAG_YAUTJA + +/datum/action/minimap/observer + minimap_flags = MINIMAP_FLAG_XENO|MINIMAP_FLAG_MARINE|MINIMAP_FLAG_MARINE_SOM|MINIMAP_FLAG_EXCAVATION_ZONE|MINIMAP_FLAG_YAUTJA diff --git a/modular_RUtgmc/code/controllers/subsystem/predships.dm b/modular_RUtgmc/code/controllers/subsystem/predships.dm new file mode 100644 index 0000000000000..351b0e5b083f2 --- /dev/null +++ b/modular_RUtgmc/code/controllers/subsystem/predships.dm @@ -0,0 +1,477 @@ +SUBSYSTEM_DEF(predships) + name = "PredShips" + init_order = INIT_ORDER_PREDSHIPS + flags = SS_NO_FIRE + + var/datum/map_template/ship_template // Current ship template in use + var/list/list/managed_z // Maps initating clan id to list(datum/space_level, list/turf(spawns)) + var/list/turf/spawnpoints // List of all spawn landmark locations + /* Note we map clan_id as string due to legacy code using them internally */ + + var/datum/clan_ui/clan_ui = new + +/datum/controller/subsystem/predships/Initialize(timeofday) + if(!ship_template) + ship_template = new /datum/map_template(HUNTERSHIPS_TEMPLATE_PATH, cache = TRUE) + LAZYINITLIST(managed_z) + load_new(CLAN_SHIP_PUBLIC) + return SS_INIT_SUCCESS + +/datum/controller/subsystem/predships/proc/init_spawnpoint(obj/effect/landmark/clan_spawn/clan_spawn) + LAZYADD(spawnpoints, get_turf(clan_spawn)) + +/datum/controller/subsystem/predships/proc/get_clan_spawnpoints(clan_id) + RETURN_TYPE(/list/turf) + if(isnum(clan_id)) + clan_id = "[clan_id]" + if(clan_id in managed_z) + return managed_z[clan_id][2] + +/datum/controller/subsystem/predships/proc/is_clanship_loaded(clan_id) + if(isnum(clan_id)) + clan_id = "[clan_id]" + if((clan_id in managed_z) && managed_z[clan_id][2]) + return TRUE + return FALSE + +/datum/controller/subsystem/predships/proc/load_new(initiating_clan_id) + RETURN_TYPE(/list) + if(isnum(initiating_clan_id)) + initiating_clan_id = "[initiating_clan_id]" + if(!ship_template || !initiating_clan_id) + return NONE + if(initiating_clan_id in managed_z) + return managed_z[initiating_clan_id] + var/datum/space_level/level = ship_template.load_new_z() + if(level) + var/new_z = level.z_value + var/list/turf/new_spawns = list() + SSminimaps.add_zlevel(new_z) + for(var/turf/spawnpoint in spawnpoints) + if(spawnpoint?.z == new_z) + new_spawns += spawnpoint + managed_z[initiating_clan_id] = list(level, new_spawns) + return managed_z[initiating_clan_id] + +/datum/clan_ui + var/list/clan_id_by_user = list() + +/datum/clan_ui/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "ClanMenu", "Clan Menu") + ui.open() + ui.set_autoupdate(TRUE) + +/datum/clan_ui/ui_data(mob/user) + . = list() + + var/datum/db_query/clan + var/datum/db_query/clan_players + var/clan_to_get = clan_id_by_user[user] + + if(clan_to_get) + clan = SSdbcore.NewQuery("SELECT id, name, description, honor, color FROM [format_table_name("clan")] WHERE id = :clan_id", list("clan_id" = clan_to_get)) + if(!clan.warn_execute()) + qdel(clan_players) + return + if(!clan.NextRow()) + qdel(clan) + + clan_players = SSdbcore.NewQuery("SELECT byond_ckey, clan_rank, permissions, clan_id, honor FROM [format_table_name("clan_player")] WHERE clan_id = :clan_id", list("clan_id" = clan ? clan.item[1] : 0)) + + if(!clan_players.warn_execute()) + qdel(clan_players) + return + + //safety, if something went wrong + var/player_rank = 1 + var/player_permissions = 0 + + if(user.client?.clan_info && length(user.client.clan_info.item)) + player_rank = user.client.clan_info.item[2] + player_permissions = user.client.clan_info.item[3] + + if(player_permissions & CLAN_PERMISSION_ADMIN_MANAGER) + player_rank = 999 // Target anyone except other managers + + if(clan) + . += list( + clan_id = clan.item[1], + clan_name = html_encode(clan.item[2]), + clan_description = html_encode(clan.item[3]), + clan_honor = clan.item[4], + clan_keys = list(), + + player_rank_pos = player_rank, + + player_delete_clan = (player_permissions & CLAN_PERMISSION_ADMIN_MANAGER), + player_sethonor_clan = (player_permissions & CLAN_PERMISSION_ADMIN_MANAGER), + player_setcolor_clan = (player_permissions & CLAN_PERMISSION_ADMIN_MODIFY), + + player_rename_clan = (player_permissions & CLAN_PERMISSION_ADMIN_MODIFY), + player_setdesc_clan = (player_permissions & CLAN_PERMISSION_MODIFY), + player_modify_ranks = (player_permissions & CLAN_PERMISSION_MODIFY), + + player_purge = (player_permissions & CLAN_PERMISSION_ADMIN_MANAGER), + player_move_clans = (player_permissions & CLAN_PERMISSION_ADMIN_MOVE) + ) + else + . += list( + clan_id = null, + clan_name = "Players without a clan", + clan_description = "This is a list of players without a clan", + clan_honor = null, + clan_keys = list(), + + player_rank_pos = player_rank, + + player_delete_clan = FALSE, + player_sethonor_clan = FALSE, + player_setcolor_clan = FALSE, + + player_rename_clan = FALSE, + player_setdesc_clan = FALSE, + player_modify_ranks = FALSE, + + player_purge = (player_permissions & CLAN_PERMISSION_ADMIN_MANAGER), + player_move_clans = (player_permissions & CLAN_PERMISSION_ADMIN_MOVE) + ) + + while(clan_players.NextRow()) + var/clan_rank = clan_players.item[2] > 0 && clan_players.item[2] <= GLOB.clan_ranks_ordered.len ? GLOB.clan_ranks_ordered[clan_players.item[2]] : GLOB.clan_ranks_ordered[1] + .["clan_keys"] += list(list( + name = clan_players.item[1], + rank = clan_rank, // rank_to_give not used here, because we need to get their visual rank, not their position + rank_pos = clan_players.item[3] & CLAN_PERMISSION_ADMIN_MANAGER ? 999 : clan_players.item[2], + honor = clan_players.item[5] + )) + + qdel(clan) + qdel(clan_players) + +/datum/clan_ui/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) + . = ..() + if(.) + return + + var/mob/user = usr + + if(!user.client.clan_info) + return + + user.client.clan_info.sql = "SELECT byond_ckey, clan_rank, permissions, clan_id, honor FROM [format_table_name("clan_player")] WHERE byond_ckey = :byond_ckey" + if(!user.client.clan_info.warn_execute()) + return + user.client.clan_info.next_row_to_take = 1 + user.client.clan_info.NextRow() + + var/clan_id = clan_id_by_user[user] + var/datum/db_query/db_query = SSdbcore.NewQuery() + db_query.no_auto_delete = TRUE + + addtimer(CALLBACK(db_query, GLOBAL_PROC_REF(qdel), db_query), 10 MINUTES) + + switch(action) + if(CLAN_ACTION_CLAN_RENAME) + db_query.sql = "SELECT id, name, description, honor, color FROM [format_table_name("clan")] WHERE id = :clan_id" + db_query.arguments = list("clan_id" = params["clan_id"]) + if(!db_query.warn_execute()) + return + db_query.NextRow() + if(!user.client.has_clan_permission(CLAN_PERMISSION_ADMIN_MODIFY)) + return + + var/input = input(user, "Input the new name", "Set Name", db_query.item[2]) as text|null + + if(!input || input == db_query.item[2]) + return + + + log_admin("[key_name_admin(user)] has set the name of [db_query.item[2]] to [input].") + to_chat(user, span_notice("Set the name of [db_query.item[2]] to [input].")) + + db_query.sql = "UPDATE [format_table_name("clan")] SET name = :name WHERE id = :clan_id" + db_query.arguments = list("clan_id" = clan_id, "name" = trim(input)) + if(!db_query.warn_execute()) + return + + if(CLAN_ACTION_CLAN_SETDESC) + db_query.sql = "SELECT id, name, description, honor, color FROM [format_table_name("clan")] WHERE id = :clan_id" + db_query.arguments = list("clan_id" = params["clan_id"]) + if(!db_query.warn_execute()) + return + db_query.NextRow() + if(!user.client.has_clan_permission(CLAN_PERMISSION_USER_MODIFY)) + return + + var/input = input(usr, "Input a new description", "Set Description", db_query.item[3]) as message|null + + if(!input || input == db_query.item[3]) + return + + log_admin("[key_name_admin(user)] has set the description of [db_query.item[2]].") + to_chat(user, span_notice("Set the description of [db_query.item[2]].")) + + db_query.sql = "UPDATE [format_table_name("clan")] SET description = :description WHERE id = :clan_id" + db_query.arguments = list("clan_id" = clan_id, "description" = trim(input)) + if(!db_query.warn_execute()) + return + + if(CLAN_ACTION_CLAN_SETCOLOR) + db_query.sql = "SELECT id, name, description, honor, color FROM [format_table_name("clan")] WHERE id = :clan_id" + db_query.arguments = list("clan_id" = params["clan_id"]) + if(!db_query.warn_execute()) + return + db_query.NextRow() + if(!user.client.has_clan_permission(CLAN_PERMISSION_ADMIN_MODIFY)) + return + + var/color = input(usr, "Input a new color", "Set Color", db_query.item[5]) as color|null + + if(!color || color == db_query.item[5]) + return + + log_admin("[key_name_admin(user)] has set the color of [db_query.item[2]] to [color].") + to_chat(user, span_notice("Set the name of [db_query.item[2]] to [color].")) + + db_query.sql = "UPDATE [format_table_name("clan")] SET color = :color WHERE id = :clan_id" + db_query.arguments = list("clan_id" = clan_id, "color" = color) + db_query.Execute() + + if(CLAN_ACTION_CLAN_SETHONOR) + db_query.sql = "SELECT id, name, description, honor, color FROM [format_table_name("clan")] WHERE id = :clan_id" + db_query.arguments = list("clan_id" = params["clan_id"]) + if(!db_query.warn_execute()) + return + db_query.NextRow() + if(!user.client.has_clan_permission(CLAN_PERMISSION_ADMIN_MANAGER)) + return + + var/input = tgui_input_number(user, "Input the new honor", "Set Honor", db_query.item[4]) + + if((!input && input != 0) || input == db_query.item[4]) + return + + log_admin("[key_name_admin(user)] has set the honor of clan [db_query.item[2]] from [db_query.item[4]] to [input].") + to_chat(user, span_notice("Set the honor of [db_query.item[2]] from [db_query.item[4]] to [input].")) + + db_query.sql = "UPDATE [format_table_name("clan")] SET honor = :honor WHERE id = :clan_id" + db_query.arguments = list("clan_id" = clan_id, "honor" = input) + db_query.Execute() + + if(CLAN_ACTION_CLAN_DELETE) + db_query.sql = "SELECT id, name, description, honor, color FROM [format_table_name("clan")] WHERE id = :clan_id" + db_query.arguments = list("clan_id" = params["clan_id"]) + if(!db_query.warn_execute()) + return + db_query.NextRow() + if(!user.client.has_clan_permission(CLAN_PERMISSION_ADMIN_MANAGER)) + return + + var/input = input(user, "Please input the name of the clan to proceed.", "Delete Clan") as text|null + + if(input != db_query.item[2]) + to_chat(user, "You have decided not to delete [db_query.item[2]].") + return + + log_admin("[key_name_admin(user)] has deleted the clan [db_query.item[2]].") + to_chat(user, span_notice("You have deleted [db_query.item[2]].")) + + db_query.sql = "UPDATE [format_table_name("clan_player")] SET clan_id = 0 WHERE clan_id = :clan_id" + db_query.arguments = list("clan_id" = clan_id) + db_query.Execute() + + db_query.sql = "DELETE FROM [format_table_name("clan")] WHERE id = :clan_id" + db_query.arguments = list("clan_id" = clan_id) + db_query.Execute() + + clan_id_by_user[user] = null + + if(CLAN_ACTION_PLAYER_PURGE) + db_query.sql = "SELECT byond_ckey, clan_rank, permissions, clan_id, honor FROM [format_table_name("clan_player")] WHERE byond_ckey = :byond_ckey" + db_query.arguments = list("byond_ckey" = params["ckey"]) + if(!db_query.warn_execute()) + return + db_query.NextRow() + var/player_rank = user.client.clan_info.item[2] + if(user.client.has_clan_permission(CLAN_PERMISSION_ADMIN_MANAGER, warn = FALSE)) + player_rank = 999 + + if((db_query.item[3] & CLAN_PERMISSION_ADMIN_MANAGER) || player_rank <= db_query.item[2]) + to_chat(user, span_danger("You can't target this person!")) + return + + if(!user.client.has_clan_permission(CLAN_PERMISSION_ADMIN_MANAGER)) + return + + var/input = input(user, "Are you sure you want to purge this person? Type '[db_query.item[1]]' to purge", "Confirm Purge") as text|null + + if(!input || input != db_query.item[1]) + return + + log_admin("[key_name_admin(user)] has purged [db_query.item[1]]'s clan profile.") + to_chat(user, span_notice("You have purged [db_query.item[1]]'s clan profile.")) + + db_query.sql = "DELETE FROM [format_table_name("clan_player")] WHERE byond_ckey = :byond_ckey" + db_query.arguments = list("byond_ckey" = params["ckey"]) + db_query.Execute() + + if(CLAN_ACTION_PLAYER_MOVECLAN) + db_query.sql = "SELECT byond_ckey, clan_rank, permissions, clan_id, honor FROM [format_table_name("clan_player")] WHERE byond_ckey = :byond_ckey" + db_query.arguments = list("byond_ckey" = params["ckey"]) + if(!db_query.warn_execute()) + return + db_query.NextRow() + var/player_rank = user.client.clan_info.item[2] + if(user.client.has_clan_permission(CLAN_PERMISSION_ADMIN_MANAGER, warn = FALSE)) + player_rank = 999 + + if((db_query.item[3] & CLAN_PERMISSION_ADMIN_MANAGER) || player_rank <= db_query.item[2]) + to_chat(user, span_danger("You can't target this person!")) + return + + if(!user.client.has_clan_permission(CLAN_PERMISSION_ADMIN_MOVE)) + return + + var/datum/db_query/db_clans = SSdbcore.NewQuery("SELECT id, name, description, honor, color FROM [format_table_name("clan")]") + if(!db_clans.warn_execute()) + qdel(db_clans) + return + var/list/clans = list() + while(db_clans.NextRow()) + clans += list("[db_clans.item[2]]" = db_clans.item[1]) + + qdel(db_clans) + + var/is_clan_manager = user.client.has_clan_permission(CLAN_PERMISSION_ADMIN_MANAGER, warn = FALSE) + if(is_clan_manager && clans.len >= 1) + if(db_query.item[3] & CLAN_PERMISSION_ADMIN_ANCIENT) + clans += list("Remove from Ancient") + else + clans += list("Make Ancient") + + if(db_query.item[4]) + clans += list("Remove from clan") + + var/input = tgui_input_list(user, "Choose the clan to put them in", "Change player's clan", clans) + + if(!input) + return + + if(input == "Remove from clan" && db_query.item[4]) + to_chat(user, span_notice("Removed [db_query.item[1]] from their clan.")) + log_admin("[key_name_admin(user)] has removed [db_query.item[1]] from their current clan.") + + db_query.sql = "UPDATE [format_table_name("clan_player")] SET clan_rank = :clan_rank, clan_id = 0 WHERE byond_ckey = :byond_ckey" + db_query.arguments = list("byond_ckey" = params["ckey"], "clan_rank" = GLOB.clan_ranks_ordered[CLAN_RANK_YOUNG]) + db_query.Execute() + + else if(input == "Remove from Ancient") + to_chat(user, span_notice("Removed [db_query.item[1]] from ancient.")) + log_admin("[key_name_admin(user)] has removed [db_query.item[1]] from ancient.") + + db_query.sql = "UPDATE [format_table_name("clan_player")] SET clan_rank = :clan_rank, permissions = :permissions WHERE byond_ckey = :byond_ckey" + db_query.arguments = list("byond_ckey" = params["ckey"], "clan_rank" = GLOB.clan_ranks_ordered[CLAN_RANK_YOUNG], "permissions" = GLOB.clan_ranks[CLAN_RANK_YOUNG].permissions) + db_query.Execute() + + else if(input == "Make Ancient" && is_clan_manager) + to_chat(user, span_notice("Made [db_query.item[1]] an ancient.")) + log_admin("[key_name_admin(user)] has made [db_query.item[1]] an ancient.") + + db_query.sql = "UPDATE [format_table_name("clan_player")] SET clan_rank = :clan_rank, permissions = :permissions WHERE byond_ckey = :byond_ckey" + db_query.arguments = list("byond_ckey" = params["ckey"], "clan_rank" = GLOB.clan_ranks_ordered[CLAN_RANK_ADMIN], "permissions" = CLAN_PERMISSION_ADMIN_ANCIENT) + db_query.Execute() + + else + to_chat(user, span_notice("Moved [db_query.item[1]] to [input].")) + log_admin("[key_name_admin(user)] has moved [db_query.item[1]] to clan [input].") + + if(!(db_query.item[3] & CLAN_PERMISSION_ADMIN_ANCIENT)) + db_query.sql = "UPDATE [format_table_name("clan_player")] SET clan_rank = :clan_rank, permissions = :permissions WHERE byond_ckey = :byond_ckey" + db_query.arguments = list("byond_ckey" = params["ckey"], "clan_rank" = GLOB.clan_ranks_ordered[CLAN_RANK_BLOODED], "permissions" = GLOB.clan_ranks[CLAN_RANK_BLOODED].permissions) + db_query.Execute() + + db_query.sql = "UPDATE [format_table_name("clan_player")] SET clan_id = :clan_id WHERE byond_ckey = :byond_ckey" + db_query.arguments = list("byond_ckey" = params["ckey"], "clan_id" = clans[input]) + db_query.Execute() + + if(CLAN_ACTION_PLAYER_MODIFYRANK) + db_query.sql = "SELECT byond_ckey, clan_rank, permissions, clan_id, honor FROM [format_table_name("clan_player")] WHERE byond_ckey = :byond_ckey" + db_query.arguments = list("byond_ckey" = params["ckey"]) + if(!db_query.warn_execute()) + return + db_query.NextRow() + var/player_rank = user.client.clan_info.item[2] + if(user.client.has_clan_permission(CLAN_PERMISSION_ADMIN_MANAGER, warn = FALSE)) + player_rank = 999 + + if((db_query.item[3] & CLAN_PERMISSION_ADMIN_MANAGER) || player_rank <= db_query.item[2]) + to_chat(user, span_danger("You can't target this person!")) + return + + if(!db_query.item[4]) + to_chat(user, span_warning("This player doesn't belong to a clan!")) + return + + var/list/datum/yautja_rank/ranks = GLOB.clan_ranks.Copy() + ranks -= CLAN_RANK_ADMIN // Admin rank should not and cannot be obtained from here + + var/datum/yautja_rank/chosen_rank + if(user.client.has_clan_permission(CLAN_PERMISSION_ADMIN_MODIFY, warn = FALSE)) + var/input = tgui_input_list(user, "Select the rank to change this user to.", "Select Rank", ranks) + + if(!input) + return + + chosen_rank = ranks[input] + + else if(user.client.has_clan_permission(CLAN_PERMISSION_USER_MODIFY, user.client.clan_info.item[4])) + for(var/rank in ranks) + if(!user.client.has_clan_permission(ranks[rank].permission_required, warn = FALSE)) + ranks -= rank + + var/input = tgui_input_list(user, "Select the rank to change this user to.", "Select Rank", ranks) + + if(!input) + return + + chosen_rank = ranks[input] + + if(chosen_rank.limit_type) + db_query.sql = "SELECT byond_ckey, clan_rank, permissions, clan_id, honor FROM [format_table_name("clan_player")] WHERE clan_id = :clan_id AND clan_rank = :clan_rank" + db_query.arguments = list("clan_id" = clan_id, "clan_rank" = GLOB.clan_ranks_ordered[input]) + db_query.Execute() + + var/players_in_rank = length(db_query.rows) + switch(chosen_rank.limit_type) + if(CLAN_LIMIT_NUMBER) + if(players_in_rank >= chosen_rank.limit) + to_chat(user, span_danger("This slot is full! (Maximum of [chosen_rank.limit] slots)")) + return + if(CLAN_LIMIT_SIZE) + db_query.sql = "SELECT byond_ckey, clan_rank, permissions, clan_id, honor FROM [format_table_name("clan_player")] WHERE clan_id = :clan_id" + db_query.arguments = list("clan_id" = clan_id) + db_query.Execute() + var/available_slots = length(db_query.rows) / chosen_rank.limit + + if(players_in_rank >= available_slots) + to_chat(user, span_danger("This slot is full! (Maximum of [chosen_rank.limit] per player in the clan, currently [available_slots])")) + return + + + else + return // Doesn't have permission to do this + + if(!user.client.has_clan_permission(chosen_rank.permission_required)) // Double check + return + + log_admin("[key_name_admin(user)] has set the rank of [db_query.item[1]] to [chosen_rank.name] for their clan.") + to_chat(user, span_notice("Set [db_query.item[1]]'s rank to [chosen_rank.name]")) + + db_query.sql = "UPDATE [format_table_name("clan_player")] SET clan_rank = :clan_rank, permissions = :permissions WHERE byond_ckey = :byond_ckey" + db_query.arguments = list("byond_ckey" = params["ckey"], "clan_rank" = GLOB.clan_ranks_ordered[chosen_rank.name], "permissions" = chosen_rank.permissions) + db_query.Execute() + +/datum/clan_ui/ui_status(mob/user, datum/ui_state/state) + return UI_INTERACTIVE diff --git a/modular_RUtgmc/code/datums/actions/observer_action.dm b/modular_RUtgmc/code/datums/actions/observer_action.dm index 965a50035eeaf..55f67172f0dd3 100644 --- a/modular_RUtgmc/code/datums/actions/observer_action.dm +++ b/modular_RUtgmc/code/datums/actions/observer_action.dm @@ -34,6 +34,8 @@ continue if(!potential_egg.hugger_type) continue + if(istype(potential_egg, /obj/alien/egg/hugger/forsaken)) + continue var/area_egg = get_area(potential_egg) if(area_egg in area_names) @@ -56,3 +58,34 @@ var/target = spawn_point[selected] dead_owner.abstract_move(get_turf(target)) + +/datum/action/observer_action/join_predator + name = "Join the Hunt" + action_icon_state = "pred_ghost" + +/datum/action/observer_action/join_predator/give_action(mob/M) + var/owner_ckey = M.client?.ckey + if(!owner_ckey) + return + + if(!(GLOB.roles_whitelist[owner_ckey] & WHITELIST_PREDATOR)) + return + + if(!SSticker.mode || !(SSticker.mode.flags_round_type & MODE_PREDATOR)) + RegisterSignal(SSdcs, COMSIG_GLOB_PREDATOR_ROUND_TOGGLED, PROC_REF(handle_button_status_visuals)) + + . = ..() + +/datum/action/observer_action/join_predator/can_use_action() + if(!SSticker.mode || !(SSticker.mode.flags_round_type & MODE_PREDATOR)) + return FALSE + return TRUE + +/datum/action/observer_action/join_predator/action_activate() + var/mob/dead/observer/activator = owner + if(SSticker.current_state < GAME_STATE_PLAYING || !SSticker.mode) + to_chat(activator, span_warning("The game hasn't started yet!")) + return + + if(SSticker.mode.check_predator_late_join(activator)) + SSticker.mode.join_predator(activator) diff --git a/modular_RUtgmc/code/datums/elements/yautja_tracked_item.dm b/modular_RUtgmc/code/datums/elements/yautja_tracked_item.dm new file mode 100644 index 0000000000000..b8eaa87bb0fc8 --- /dev/null +++ b/modular_RUtgmc/code/datums/elements/yautja_tracked_item.dm @@ -0,0 +1,44 @@ +/datum/element/yautja_tracked_item + element_flags = ELEMENT_COMPLEX_DETACH + +/datum/element/yautja_tracked_item/Attach(obj/item/target) + . = ..() + if(!isitem(target)) + return ELEMENT_INCOMPATIBLE + RegisterSignal(target, COMSIG_ITEM_EQUIPPED, PROC_REF(item_picked_up)) + RegisterSignal(target, COMSIG_ITEM_DROPPED, PROC_REF(item_dropped)) + + + if(!is_honorable_carrier(recursive_holder_check(target))) + add_to_missing_pred_gear(target) + GLOB.tracked_yautja_gear += target + +/datum/element/yautja_tracked_item/Detach(datum/source, force) + UnregisterSignal(source, list( + COMSIG_ITEM_EQUIPPED, + COMSIG_ITEM_DROPPED + )) + remove_from_missing_pred_gear(source) + GLOB.tracked_yautja_gear -= source + return ..() + +/datum/element/yautja_tracked_item/proc/item_picked_up(obj/item/picked_up_item, mob/living/carbon/human/user) + SIGNAL_HANDLER + + if(is_honorable_carrier(user)) + remove_from_missing_pred_gear(picked_up_item) + +/datum/element/yautja_tracked_item/proc/item_dropped(obj/item/dropped_item, mob/living/carbon/human/user) + SIGNAL_HANDLER + + if(!is_honorable_carrier(recursive_holder_check(dropped_item))) + add_to_missing_pred_gear(dropped_item) + +/proc/is_honorable_carrier(mob/living/carbon/human/carrier) + if(isyautja(carrier)) + return TRUE + if((issynth(carrier) || ishuman(carrier)) && (carrier.hunter_data.honored || carrier.hunter_data.thralled) && !(carrier.hunter_data.dishonored || carrier.stat == DEAD)) + return TRUE + if(istype(carrier, /mob/hologram/falcon)) + return TRUE + return FALSE diff --git a/modular_RUtgmc/code/datums/flaying.dm b/modular_RUtgmc/code/datums/flaying.dm new file mode 100644 index 0000000000000..7bfe6d25390a1 --- /dev/null +++ b/modular_RUtgmc/code/datums/flaying.dm @@ -0,0 +1,111 @@ +#define FLAY_STAGE_SCALP 1 +#define FLAY_STAGE_STRIP 2 +#define FLAY_STAGE_SKIN 3 + +///Records status of flaying attempts and handles progress. +/datum/flaying_datum + var/mob/living/carbon/human/victim + var/current_flayer + var/flaying_stage = FLAY_STAGE_SCALP + +/datum/flaying_datum/New(mob/living/carbon/human/target) + . = ..() + victim = target + RegisterSignal(victim, COMSIG_HUMAN_FLAY_ATTEMPT, PROC_REF(begin_flaying)) + +///Loops until interrupted or done. +/datum/flaying_datum/proc/begin_flaying(mob/living/carbon/human/target, mob/living/carbon/human/user, obj/item/tool, ongoing_attempt) + SIGNAL_HANDLER + if(current_flayer) + if(current_flayer != user) + to_chat(user, span_warning("You can't flay [target], [current_flayer] is already at work!")) + else + current_flayer = user + if(!ongoing_attempt) + playsound(user.loc, 'sound/weapons/pierce.ogg', 25) + user.visible_message(span_danger("[user] resumes the flaying of [victim] with \a [tool]..."), + span_danger("You resume the flaying of [victim] with your [tool.name]...")) + INVOKE_ASYNC(src, PROC_REF(flay), target, user, tool) //do_after sleeps. + return COMPONENT_ITEM_NO_ATTACK + +/datum/flaying_datum/proc/flay(mob/living/carbon/human/target, mob/living/carbon/human/user, obj/item/tool) + if(!do_after(user, 4 SECONDS, NONE, victim, BUSY_ICON_HOSTILE, BUSY_ICON_HOSTILE)) + to_chat(user, span_warning("You were interrupted before you could finish your work!")) + current_flayer = null + return + + switch(flaying_stage) + if(FLAY_STAGE_SCALP) + playsound(user.loc, 'sound/weapons/slashmiss.ogg', 25) + flaying_stage = FLAY_STAGE_STRIP + var/datum/limb/head/v_head = victim.get_limb("head") + if(!v_head || (v_head.limb_status & LIMB_DESTROYED)) //they might be beheaded + victim.apply_damage(10, BRUTE, "chest", sharp = TRUE) + user.visible_message(span_danger("[user] peels the skin around the stump of [victim]'s head loose with \the [tool]."), + span_danger("[victim] is missing \his head. Pelts like this just aren't the same... You peel the skin around the stump loose with your [tool.name].")) + else + victim.apply_damage(10, BRUTE, v_head, sharp = TRUE) + v_head.disfigured = TRUE + create_leftovers(victim, has_meat = FALSE, skin_amount = 1) + if(victim.h_style == "Bald") //you can't scalp someone with no hair. + user.visible_message(span_danger("[user] makes some rough cuts on [victim]'s head and face with \a [tool]."), + span_danger("You make some rough cuts on [victim]'s head and face.")) + else + user.visible_message(span_danger("[user] cuts around [victim]'s hairline, then tears \his scalp from \his head!"), + span_danger("You cut around [victim]'s hairline, then rip \his scalp from \his head.")) + var/obj/item/scalp/cut_scalp = new(get_turf(user), victim, user) //Create a scalp of the victim at the user's feet. + user.put_in_inactive_hand(cut_scalp) //Put it in the user's offhand if possible. + victim.h_style = "Bald" + victim.update_hair() //tear the hair off with the scalp + + if(FLAY_STAGE_STRIP) + user.visible_message(span_danger("[user] jabs \his [tool.name] into [victim]'s cuts, prying, cutting, then tearing off large areas of skin. The remainder hangs loosely."), + span_danger("You jab your [tool.name] into [victim]'s cuts, prying, cutting, then tearing off large areas of skin. The remainder hangs loosely.")) + playsound(user.loc, 'sound/weapons/bladeslice.ogg', 25) + create_leftovers(victim, has_meat = FALSE, skin_amount = 3) + flaying_stage = FLAY_STAGE_SKIN + for(var/limb in victim.limbs) + victim.apply_damage(18, BRUTE, limb, sharp = TRUE) + victim.remove_overlay(UNIFORM_LAYER) + victim.dropItemToGround(victim.get_item_by_slot(SLOT_W_UNIFORM)) //Drop uniform, belt etc as well. + victim.f_style = "Shaved" + victim.update_hair() //then rip the beard off along the skin + victim.add_flay_overlay(stage = 2) + + if(FLAY_STAGE_SKIN) + user.visible_message(span_danger("[user] completely flays [victim], pulling the remaining skin off of \his body like a glove!"), + span_danger("You completely flay [victim], pulling the remaining skin off of \his body like a glove.\nUse rope to hang \him from the ceiling.")) + playsound(user.loc, 'sound/weapons/wristblades_hit.ogg', 25) + create_leftovers(victim, has_meat = TRUE, skin_amount = 2) + for(var/limb in victim.limbs) + victim.apply_damage(22, BRUTE, limb, sharp = TRUE) + for(var/obj/item/item in victim) + victim.transferItemToLoc(item, victim.loc, FALSE, TRUE) + ADD_TRAIT(victim, TRAIT_UNDEFIBBABLE, TRAIT_UNDEFIBBABLE) + victim.add_flay_overlay(stage = 3) + + //End the loop and remove all references to the datum. + current_flayer = null + UnregisterSignal(victim, COMSIG_HUMAN_FLAY_ATTEMPT) + victim = null + return + + flay(target, user, tool) + + + +/datum/flaying_datum/proc/create_leftovers(mob/living/victim, has_meat, skin_amount) + if(has_meat) + var/obj/item/reagent_containers/food/snacks/meat/meat = new /obj/item/reagent_containers/food/snacks/meat(victim.loc) + meat.name = "raw [victim.name] steak" + + if(skin_amount) + var/obj/item/stack/sheet/animalhide/human/hide = new /obj/item/stack/sheet/animalhide/human(victim.loc) + hide.name = "[victim.name]-hide" + hide.singular_name = "[victim.name]-hide" + hide.stack_name = "[victim.name]-hide" + hide.amount = skin_amount + +#undef FLAY_STAGE_SCALP +#undef FLAY_STAGE_STRIP +#undef FLAY_STAGE_SKIN diff --git a/modular_RUtgmc/code/datums/gamemodes/_game_mode.dm b/modular_RUtgmc/code/datums/gamemodes/_game_mode.dm index d4b0bbcb173e3..e8b121c9550fc 100644 --- a/modular_RUtgmc/code/datums/gamemodes/_game_mode.dm +++ b/modular_RUtgmc/code/datums/gamemodes/_game_mode.dm @@ -1,5 +1,15 @@ /datum/game_mode + var/list/predators = list() + + var/pred_current_num = 0 //How many are there now? + var/pred_per_players = 20 //Preds per player + var/pred_start_count = 0 //The initial count of predators + + var/pred_additional_max = 0 + var/pred_leader_count = 0 //How many Leader preds are active + var/pred_leader_max = 1 //How many Leader preds are permitted. Currently fixed to 1. May add admin verb to adjust this later. var/quickbuild_points_flags = NONE + blacklist_ground_maps = list(MAP_DELTA_STATION, MAP_WHISKEY_OUTPOST, MAP_OSCAR_OUTPOST, MAP_FORT_PHOBOS) /datum/game_mode/post_setup() @@ -29,3 +39,105 @@ var/siloless_countdown = SSticker.mode.get_siloless_collapse_countdown() if(siloless_countdown) items +="Silo less hive collapse timer: [siloless_countdown]" + +/datum/game_mode/proc/predator_round() + switch(CONFIG_GET(number/pred_round)) + if(0) + return + if(1) + if(!prob(CONFIG_GET(number/pred_round_chance))) + return + + var/datum/job/PJ = SSjob.GetJobType(/datum/job/predator) + var/new_pred_max = min(max(round(length(GLOB.clients) * PREDATOR_TO_TOTAL_SPAWN_RATIO), 1), 4) + PJ.total_positions = new_pred_max + PJ.max_positions = new_pred_max + flags_round_type |= MODE_PREDATOR + +/datum/game_mode/proc/initialize_predator(mob/living/carbon/human/new_predator, client/player, ignore_pred_num = FALSE) + predators[lowertext(player.ckey)] = list("Name" = new_predator.real_name, "Status" = "Alive") + if(!ignore_pred_num) + pred_current_num++ + +/datum/game_mode/proc/get_whitelisted_predators(readied = 1) + // Assemble a list of active players who are whitelisted. + var/players[] = new + + var/mob/new_player/new_pred + for(var/mob/player in GLOB.player_list) + if(!player.client) continue //No client. DCed. + if(isyautja(player)) continue //Already a predator. Might be dead, who knows. + if(readied) //Ready check for new players. + new_pred = player + if(!istype(new_pred)) continue //Have to be a new player here. + if(!new_pred.ready) continue //Have to be ready. + else + if(!istype(player,/mob/dead)) continue //Otherwise we just want to grab the ghosts. + + if(GLOB.roles_whitelist[player.ckey] & WHITELIST_PREDATOR) //Are they whitelisted? + if(!player.client.prefs) + player.client.prefs = new /datum/preferences(player.client) //Somehow they don't have one. + + if(player.client.prefs.job_preferences[JOB_PREDATOR] > 0) //Are their prefs turned on? + if(!player.mind) //They have to have a key if they have a client. + player.mind_initialize() //Will work on ghosts too, but won't add them to active minds. + players += player.mind + return players + +#define calculate_pred_max (length(GLOB.player_list) / pred_per_players + pred_additional_max + pred_start_count) + +/datum/game_mode/proc/check_predator_late_join(mob/pred_candidate, show_warning = TRUE) + if(!pred_candidate?.client) // Nigga, how?! + return + + var/datum/job/job = SSjob.GetJobType(/datum/job/predator) + + if(!job) + if(show_warning) + to_chat(pred_candidate, span_warning("Something went wrong!")) + return + + if(show_warning && alert(pred_candidate, "Confirm joining the hunt. You will join as \a [lowertext(job.get_whitelist_status(GLOB.roles_whitelist, pred_candidate.client))] predator", "Confirm", "Yes", "No") != "Yes") + return + + if(!(GLOB.roles_whitelist[pred_candidate.ckey] & WHITELIST_PREDATOR)) + if(show_warning) + to_chat(pred_candidate, span_warning("You are not whitelisted! You may apply on the forums to be whitelisted as a predator.")) + return + + if(is_banned_from(ckey(pred_candidate.key), JOB_PREDATOR)) + if(show_warning) + to_chat(pred_candidate, span_warning("You are banned.")) + return + + if(!(flags_round_type & MODE_PREDATOR)) + if(show_warning) + to_chat(pred_candidate, span_warning("There is no Hunt this round! Maybe the next one.")) + return + + if(pred_candidate.ckey in predators) + if(show_warning) + to_chat(pred_candidate, span_warning("You already were a Yautja! Give someone else a chance.")) + return + + if(get_desired_status(pred_candidate.client.prefs.yautja_status, WHITELIST_COUNCIL) == WHITELIST_NORMAL) + var/pred_max = calculate_pred_max + if(pred_current_num >= pred_max) + if(show_warning) + to_chat(pred_candidate, span_warning("Only [pred_max] predators may spawn this round, but Councillors and Ancients do not count.")) + return + + return TRUE + +#undef calculate_pred_max + +/datum/game_mode/proc/join_predator(mob/pred_candidate) + var/datum/job/job = SSjob.GetJobType(/datum/job/predator) + var/datum/preferences/prefs = pred_candidate.client.prefs + var/spawn_type = job.return_spawn_type(prefs) + var/mob/living/carbon/human/new_predator = new spawn_type() + new_predator.forceMove(job.return_spawn_turf(pred_candidate, pred_candidate.client)) + new_predator.ckey = pred_candidate.ckey + new_predator.apply_assigned_role_to_spawn(job) + job.after_spawn(new_predator) + qdel(pred_candidate) diff --git a/modular_RUtgmc/code/datums/gamemodes/distress.dm b/modular_RUtgmc/code/datums/gamemodes/distress.dm index 8799e9e09a76e..f470623e1a54d 100644 --- a/modular_RUtgmc/code/datums/gamemodes/distress.dm +++ b/modular_RUtgmc/code/datums/gamemodes/distress.dm @@ -32,6 +32,7 @@ /datum/game_mode/infestation/distress/post_setup() . = ..() + predator_round() SSpoints.add_psy_points(XENO_HIVE_NORMAL, 2 * SILO_PRICE + 4 * XENO_TURRET_PRICE) for(var/obj/effect/landmark/corpsespawner/corpse AS in GLOB.corpse_landmarks_list) diff --git a/modular_RUtgmc/code/datums/jobs/job/job.dm b/modular_RUtgmc/code/datums/jobs/job/job.dm new file mode 100644 index 0000000000000..93137dea36b30 --- /dev/null +++ b/modular_RUtgmc/code/datums/jobs/job/job.dm @@ -0,0 +1,8 @@ +/datum/job + var/list/datum/outfit/gear_preset_whitelist = list()//Gear preset name used for council snowflakes ;) + +/datum/job/proc/get_whitelist_status(list/roles_whitelist, client/player) + if(!roles_whitelist) + return FALSE + + return WHITELIST_NORMAL diff --git a/modular_RUtgmc/code/datums/jobs/job/pred.dm b/modular_RUtgmc/code/datums/jobs/job/pred.dm new file mode 100644 index 0000000000000..8e172ca61adc8 --- /dev/null +++ b/modular_RUtgmc/code/datums/jobs/job/pred.dm @@ -0,0 +1,246 @@ +/datum/job/predator + title = JOB_PREDATOR + job_category = JOB_PREDATOR + job_flags = JOB_FLAG_OVERRIDELATEJOINSPAWN|JOB_FLAG_ROUNDSTARTJOINABLE|JOB_FLAG_SHOW_OPEN_POSITIONS + supervisors = "Ancients" + outfit = /datum/outfit/job/yautja/blooded + skills_type = /datum/skills/yautja/warrior + faction = FACTION_YAUTJA + minimap_icon = "predator" + + total_positions = 0 + max_positions = 0 + +/datum/job/predator/New() + . = ..() + gear_preset_whitelist = list( + "[JOB_PREDATOR][CLAN_RANK_YOUNG]" = new /datum/outfit/job/yautja/youngblood, + "[JOB_PREDATOR][CLAN_RANK_BLOODED]" = new /datum/outfit/job/yautja/blooded, + "[JOB_PREDATOR][CLAN_RANK_ELITE]" = new /datum/outfit/job/yautja/elite, + "[JOB_PREDATOR][CLAN_RANK_ELDER]" = new /datum/outfit/job/yautja/elder, + "[JOB_PREDATOR][CLAN_RANK_LEADER]" = new /datum/outfit/job/yautja/leader, + "[JOB_PREDATOR][CLAN_RANK_ADMIN]" = new /datum/outfit/job/yautja/ancient + ) + +/datum/job/predator/return_spawn_type(datum/preferences/prefs) + return /mob/living/carbon/human/species/yautja + +/datum/job/predator/return_spawn_turf(mob/living/carbon/human/new_predator, client/player) + var/clan_id = CLAN_SHIP_PUBLIC + var/clan_rank = CLAN_RANK_BLOODED + if(player.clan_info) + clan_id = player.clan_info.item[4] + clan_rank = player.clan_info.item[2] > 0 && player.clan_info.item[2] <= GLOB.clan_ranks_ordered.len ? GLOB.clan_ranks_ordered[player.clan_info.item[2]] : GLOB.clan_ranks_ordered[1] + + SSpredships.load_new(clan_id) + var/turf/spawn_point = SAFEPICK(SSpredships.get_clan_spawnpoints(clan_id)) + if(!isturf(spawn_point)) + //log_debug("Failed to find spawn point for new_predator ship in transform_predator - clan_id=[clan_id]") + to_chat(player, span_warning("Unable to setup spawn location - you might want to tell someone about this.")) + return + + if(SSticker.mode) + SSticker.mode.initialize_predator(new_predator, player, clan_rank == CLAN_RANK_ADMIN) + + return spawn_point + +/datum/job/predator/get_whitelist_status(list/roles_whitelist, client/player) // Might be a problem waiting here, but we've got no choice + . = ..() + if(!.) + return + + if(!player || !player.clan_info) + return CLAN_RANK_BLOODED + + var/title = player.clan_info.item[2] > 0 && player.clan_info.item[2] <= GLOB.clan_ranks_ordered.len ? GLOB.clan_ranks_ordered[player.clan_info.item[2]] : GLOB.clan_ranks_ordered[1] + + if(!title) + return CLAN_RANK_BLOODED + + if(!("[JOB_PREDATOR][title]" in gear_preset_whitelist)) + return CLAN_RANK_BLOODED + + if(\ + (roles_whitelist[player.ckey] & (WHITELIST_YAUTJA_LEADER|WHITELIST_YAUTJA_COUNCIL|WHITELIST_YAUTJA_COUNCIL_LEGACY)) &&\ + get_desired_status(player.prefs.yautja_status, WHITELIST_COUNCIL) == WHITELIST_NORMAL\ + ) + return CLAN_RANK_BLOODED + + return title + +/datum/job/predator/announce(mob/new_predator) + to_chat(new_predator, span_notice("You are Yautja, a great and noble predator!")) + to_chat(new_predator, span_notice("Your job is to first study your opponents. A hunt cannot commence unless intelligence is gathered.")) + to_chat(new_predator, span_notice("Hunt at your discretion, yet be observant rather than violent.")) + log_admin("([new_predator.key]) joined as Yautja, [new_predator.real_name].") + +/datum/outfit/job/yautja + name = "Yautja" + + id = null //No IDs for Yautja! + back = FALSE //Null hecks, no null here + + var/default_cape_type = "None" + var/clan_rank + +/datum/outfit/job/yautja/pre_equip(mob/living/carbon/human/H, visualsOnly, client/override_client) + var/client/mob_client = H.client + if(override_client) + mob_client = override_client + + H.ethnicity = "Tan" + if(mob_client) + H.ethnicity = mob_client.prefs.predator_skin_color + + H.set_species("Yautja") + if(mob_client) + H.h_style = mob_client.prefs.predator_h_style + H.update_hair() + + var/using_legacy = "No" + var/armor_number = 1 + var/boot_number = 1 + var/mask_number = 1 + var/armor_material = "ebony" + var/greave_material = "ebony" + var/caster_material = "ebony" + var/mask_material = "ebony" + var/translator_type = "Modern" + var/cape_type = default_cape_type + var/cape_color = "#654321" + + if(mob_client) + using_legacy = mob_client.prefs.predator_use_legacy + armor_number = mob_client.prefs.predator_armor_type + boot_number = mob_client.prefs.predator_boot_type + mask_number = mob_client.prefs.predator_mask_type + armor_material = mob_client.prefs.predator_armor_material + greave_material = mob_client.prefs.predator_greave_material + mask_material = mob_client.prefs.predator_mask_material + caster_material = mob_client.prefs.predator_caster_material + translator_type = mob_client.prefs.predator_translator_type + if(mob_client.prefs.predator_cape_type != "Default") + cape_type = mob_client.prefs.predator_cape_type + + cape_color = mob_client.prefs.predator_cape_color + + H.equip_to_slot_or_del(new /obj/item/clothing/under/chainshirt/hunter(H), SLOT_W_UNIFORM) + H.equip_to_slot_or_del(new /obj/item/clothing/gloves/yautja/hunter(H, translator_type, caster_material, clan_rank), SLOT_GLOVES, TRUE, TRUE) + H.equip_to_slot_or_del(new /obj/item/radio/headset/yautja(H), SLOT_EARS) + H.equip_to_slot_or_del(new /obj/item/flashlight/lantern(H), SLOT_R_STORE) + H.equip_to_slot_or_del(new /obj/item/yautja_teleporter(H), SLOT_L_STORE) + H.equip_to_slot_or_del(new /obj/item/storage/belt/yautja(H), SLOT_BELT) + H.equip_to_slot_or_del(new /obj/item/storage/medicomp/full(H), SLOT_IN_BELT) + + H.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/yautja/hunter/knife(H, boot_number, greave_material), SLOT_SHOES) + H.equip_to_slot_or_del(new /obj/item/clothing/suit/armor/yautja/hunter(H, armor_number, armor_material, using_legacy), SLOT_WEAR_SUIT) + H.equip_to_slot_or_del(new /obj/item/clothing/mask/gas/yautja/hunter(H, mask_number, mask_material, using_legacy), SLOT_WEAR_MASK) + + var/cape_path = GLOB.all_yautja_capes[cape_type] + if(ispath(cape_path)) + H.equip_to_slot_or_del(new cape_path(H, cape_color), SLOT_BACK) + +/datum/outfit/job/yautja/handle_id(mob/living/carbon/human/H, client/override_client) + var/client/mob_client = H.client + if(override_client) + mob_client = override_client + + var/datum/job/job = SSjob.GetJobType(jobtype) + if(!job) + job = H.job + + H.faction = GLOB.faction_to_iff[job.faction] + + var/final_name = "Le'pro" + H.gender = MALE + H.age = 100 + H.flavor_text = "" + + if(mob_client) + H.h_style = mob_client.prefs.predator_h_style + H.update_hair() + H.gender = mob_client.prefs.predator_gender + H.age = mob_client.prefs.predator_age + final_name = mob_client.prefs.predator_name + H.flavor_text = mob_client.prefs.predator_flavor_text + H.r_eyes = mob_client.prefs.pred_r_eyes + H.g_eyes = mob_client.prefs.pred_g_eyes + H.b_eyes = mob_client.prefs.pred_b_eyes + if(!final_name || final_name == "Undefined") //In case they don't have a name set or no prefs, there's a name. + final_name = "Le'pro" + + H.update_body() + H.update_hair() + H.regenerate_icons() + + H.real_name = final_name + H.name = final_name + H.hud_set_hunter() + +// YOUNG BLOOD +/datum/outfit/job/yautja/youngblood + name = "Yautja Young" + clan_rank = CLAN_RANK_UNBLOODED_INT + +/datum/outfit/job/yautja/youngblood/handle_id(mob/living/carbon/human/H, client/override_client) + . = ..() + var/new_name = "Young [H.real_name]" + H.real_name = new_name + H.name = new_name + +//BLOODED +/datum/outfit/job/yautja/blooded + name = "Yautja Blooded" + default_cape_type = PRED_YAUTJA_QUARTER_CAPE + clan_rank = CLAN_RANK_BLOODED_INT + +// ELITE +/datum/outfit/job/yautja/elite + name = "Yautja Elite" + default_cape_type = PRED_YAUTJA_HALF_CAPE + clan_rank = CLAN_RANK_ELITE_INT + +/datum/outfit/job/yautja/elite/handle_id(mob/living/carbon/human/H, client/override_client) + . = ..() + var/new_name = "Elite [H.real_name]" + H.real_name = new_name + H.name = new_name + +// ELDER +/datum/outfit/job/yautja/elder + name = "Yautja Elder" + default_cape_type = PRED_YAUTJA_THIRD_CAPE + ears = /obj/item/radio/headset/yautja/elder + clan_rank = CLAN_RANK_ELDER_INT + +/datum/outfit/job/yautja/elder/handle_id(mob/living/carbon/human/H, client/override_client) + . = ..() + var/new_name = "Elder [H.real_name]" + H.real_name = new_name + H.name = new_name + +// CLAN LEADER +/datum/outfit/job/yautja/leader + name = "Yautja Leader" + default_cape_type = PRED_YAUTJA_CAPE + ears = /obj/item/radio/headset/yautja/elder + clan_rank = CLAN_RANK_LEADER_INT + +/datum/outfit/job/yautja/leader/handle_id(mob/living/carbon/human/H, client/override_client) + . = ..() + var/new_name = "Clan Leader [H.real_name]" + H.real_name = new_name + H.name = new_name + +// ANCIENT +/datum/outfit/job/yautja/ancient + name = "Yautja Ancient" + default_cape_type = PRED_YAUTJA_PONCHO + ears = /obj/item/radio/headset/yautja/elder + clan_rank = CLAN_RANK_ADMIN_INT + +/datum/outfit/job/yautja/ancient/handle_id(mob/living/carbon/human/H, client/override_client) + . = ..() + var/new_name = "Ancient [H.real_name]" + H.real_name = new_name + H.name = new_name diff --git a/modular_RUtgmc/code/datums/keybinding/xeno.dm b/modular_RUtgmc/code/datums/keybinding/xeno.dm index 0da7e41709cdd..ac5dbdfa9bf15 100644 --- a/modular_RUtgmc/code/datums/keybinding/xeno.dm +++ b/modular_RUtgmc/code/datums/keybinding/xeno.dm @@ -117,6 +117,24 @@ keybind_signal = COMSING_XENOABILITY_HUGGER_POUNCE hotkey_keys = list("E") +/datum/keybinding/xeno/roar + name = "Roar" + full_name = "Predalien: Roar" + description = "Give bonuses to teamates and deactivate hitech utilities." + keybind_signal = COMSIG_XENOABILITY_ROAR + +/datum/keybinding/xeno/smash + name = "Smash" + full_name = "Predalien: Smash" + description = "Stomp and stun your enemies." + keybind_signal = COMSIG_XENOABILITY_SMASH + +/datum/keybinding/xeno/devastate + name = "Devastate" + full_name = "Predalien: Devastate" + description = "Rip enemy gut." + keybind_signal = COMSIG_XENOABILITY_DEVASTATE + /datum/keybinding/xeno/short_spray_acid name = "short_spray_acid" full_name = "Praetorian: Short Acid Spray" diff --git a/modular_RUtgmc/code/datums/skills.dm b/modular_RUtgmc/code/datums/skills.dm index 50d3146bb7e84..e0137f395fb40 100644 --- a/modular_RUtgmc/code/datums/skills.dm +++ b/modular_RUtgmc/code/datums/skills.dm @@ -49,3 +49,18 @@ /datum/skills/imperial/astartes swordplay = SKILL_SWORDPLAY_TRAINED + +/datum/skills/yautja/warrior + name = "Yautja Warrior" + + engineer = SKILL_ENGINEER_ENGI + construction = SKILL_CONSTRUCTION_MASTER + firearms = SKILL_FIREARMS_TRAINED + medical = SKILL_MEDICAL_MASTER + cqc = SKILL_CQC_MASTER + surgery = SKILL_SURGERY_EXPERT + melee_weapons = SKILL_MELEE_SUPER + pistols = SKILL_PISTOLS_TRAINED + rifles = SKILL_RIFLES_TRAINED + police = SKILL_POLICE_MP + swordplay = SKILL_SWORDPLAY_TRAINED diff --git a/modular_RUtgmc/code/datums/status_effects/xeno_buffs.dm b/modular_RUtgmc/code/datums/status_effects/xeno_buffs.dm index 48a4a61445f6c..f8c049fd51516 100644 --- a/modular_RUtgmc/code/datums/status_effects/xeno_buffs.dm +++ b/modular_RUtgmc/code/datums/status_effects/xeno_buffs.dm @@ -42,3 +42,53 @@ buff_owner.xeno_melee_damage_modifier -= modifier owner.remove_filter("frenzy_screech_outline") return ..() + +// *************************************** +// *********** Buff +// *************************************** +/atom/movable/screen/alert/status_effect/xeno_buff + name = "Empowered" + desc = "Your damage ands speed boosted for short time period." + +/datum/status_effect/xeno_buff + id = "buff" + duration = -1 + status_type = STATUS_EFFECT_MULTIPLE + alert_type = /atom/movable/screen/alert/status_effect/xeno_buff + + var/bonus_damage = 0 + var/bonus_speed = 0 + +/datum/status_effect/xeno_buff/on_creation(atom/A, mob/from = null, ttl = 35, bonus_damage = 0, bonus_speed = 0) + if(!isxeno(A)) + qdel(src) + return + + . = ..() + + to_chat(A, span_xenonotice("You feel empowered")) + + var/mob/living/carbon/xenomorph/X = A + X.melee_damage += bonus_damage + + X.xeno_caste.speed -= bonus_speed + + src.bonus_damage = bonus_damage + src.bonus_speed = bonus_speed + + + X.add_filter("overbonus_vis", 1, outline_filter(4 * (bonus_damage / 50), "#cf0b0b60")); \ + + addtimer(CALLBACK(src, PROC_REF(end_bonuses)), ttl) + +/datum/status_effect/xeno_buff/proc/end_bonuses() + if(owner) + to_chat(owner, span_xenonotice("You no longer feel empowered")) + var/mob/living/carbon/xenomorph/X = owner + X.melee_damage -= bonus_damage + + X.xeno_caste.speed += bonus_speed + + X.remove_filter("overbonus_vis"); + + qdel(src) diff --git a/modular_RUtgmc/code/game/atoms.dm b/modular_RUtgmc/code/game/atoms.dm index ff9d2abed1404..a6a1c4625e008 100644 --- a/modular_RUtgmc/code/game/atoms.dm +++ b/modular_RUtgmc/code/game/atoms.dm @@ -1,8 +1,13 @@ +/atom + var/status_flags = CANSTUN|CANKNOCKDOWN|CANKNOCKOUT|CANPUSH|CANUNCONSCIOUS|CANCONFUSE //bitflags defining which status effects can be inflicted (replaces canweaken, canstun, etc) + /atom/prepare_huds() hud_list = new for(var/hud in hud_possible) //Providing huds. var/image/new_hud = image('modular_RUtgmc/icons/mob/hud.dmi', src, "") + if(hud == HUNTER_CLAN || hud == HUNTER_HUD) + new_hud = image('modular_RUtgmc/icons/mob/hud_yautja.dmi', src, "") new_hud.appearance_flags = KEEP_APART hud_list[hud] = new_hud diff --git a/modular_RUtgmc/code/game/data_huds.dm b/modular_RUtgmc/code/game/data_huds.dm index 7c7d04f820518..4601f860fe9e0 100644 --- a/modular_RUtgmc/code/game/data_huds.dm +++ b/modular_RUtgmc/code/game/data_huds.dm @@ -218,12 +218,16 @@ return TRUE //medical hud used by ghosts + +/datum/atom_hud/medical/add_to_single_hud(mob/user, mob/target) + return ..() + /datum/atom_hud/medical/observer - hud_icons = list(HEALTH_HUD, XENO_EMBRYO_HUD, XENO_REAGENT_HUD, XENO_DEBUFF_HUD, STATUS_HUD, MACHINE_HEALTH_HUD, MACHINE_AMMO_HUD, XENO_BANISHED_HUD) + hud_icons = list(HEALTH_HUD, XENO_EMBRYO_HUD, XENO_REAGENT_HUD, XENO_DEBUFF_HUD, STATUS_HUD, MACHINE_HEALTH_HUD, MACHINE_AMMO_HUD, XENO_BANISHED_HUD, HUNTER_CLAN, HUNTER_HUD, HUNTER_HEALTH_HUD) //Xeno status hud, for xenos /datum/atom_hud/xeno - hud_icons = list(HEALTH_HUD_XENO, PLASMA_HUD, PHEROMONE_HUD, QUEEN_OVERWATCH_HUD, ARMOR_SUNDER_HUD, XENO_FIRE_HUD, XENO_RANK_HUD, XENO_PRIMO_HUD, XENO_BANISHED_HUD, XENO_BLESSING_HUD, XENO_EVASION_HUD) + hud_icons = list(HEALTH_HUD_XENO, PLASMA_HUD, PHEROMONE_HUD, QUEEN_OVERWATCH_HUD, ARMOR_SUNDER_HUD, XENO_FIRE_HUD, XENO_RANK_HUD, XENO_PRIMO_HUD, XENO_BANISHED_HUD, XENO_BLESSING_HUD, XENO_EVASION_HUD, HUNTER_HUD) /mob/living/carbon/xenomorph/proc/hud_set_banished() var/image/holder = hud_list[XENO_BANISHED_HUD] @@ -244,6 +248,13 @@ hud_list[XENO_RANK_HUD] = holder +/datum/atom_hud/hunter_clan + hud_icons = list(HUNTER_CLAN) + + +/datum/atom_hud/hunter_hud + hud_icons = list(HUNTER_HUD, HUNTER_HEALTH_HUD) + /mob/living/carbon/xenomorph/proc/hud_update_primo() var/image/holder = hud_list[XENO_PRIMO_HUD] if(!holder) @@ -256,8 +267,7 @@ hud_list[XENO_PRIMO_HUD] = holder - -/mob/living/carbon/human/med_hud_set_health() +/mob/living/carbon/human/med_hud_set_health(hud_holder = HEALTH_HUD) var/image/holder = hud_list[HEALTH_HUD] if(stat == DEAD) holder.icon_state = "hudhealth-100" @@ -324,10 +334,14 @@ else holder.icon_state = "hudhealth-100" +/mob/living/carbon/human/species/yautja/med_hud_set_health(hud_holder = HUNTER_HEALTH_HUD) + . = ..() + /mob/living/carbon/human/med_pain_set_perceived_health() if(species?.species_flags & IS_SYNTHETIC) return FALSE - + if(HAS_TRAIT(src, TRAIT_FOREIGN_BIO)) + return FALSE var/image/holder = hud_list[PAIN_HUD] if(stat == DEAD) holder.icon_state = "hudhealth-100" diff --git a/modular_RUtgmc/code/game/objects/effects/step_triggers.dm b/modular_RUtgmc/code/game/objects/effects/step_triggers.dm new file mode 100644 index 0000000000000..c126feef3cdbf --- /dev/null +++ b/modular_RUtgmc/code/game/objects/effects/step_triggers.dm @@ -0,0 +1,23 @@ +//RUTGMC MESSY FIX +/obj/effect/landmark/start/job/survivor/Initialize(mapload) + . = ..() + new /obj/effect/landmark/yautja_teleport(loc) + +/obj/effect/landmark/start/job/squadmarine/Initialize(mapload) + . = ..() + new /obj/effect/landmark/yautja_teleport(loc) +//END OF MESSY FIX TO DELETE + +/* Predator Ship Teleporter - set in each individual gamemode */ + +/obj/effect/step_trigger/teleporter/yautja_ship/Trigger(atom/movable/A) + var/turf/destination + if(length(GLOB.yautja_teleports)) //We have some possible locations. + var/pick = tgui_input_list(usr, "Where do you want to go today?", "Locations", GLOB.yautja_teleport_descs) //Pick one of them in the list.) + destination = GLOB.yautja_teleport_descs[pick] + if(!destination || (A.loc != loc)) + return + teleport_x = destination.x //Configure the destination locations. + teleport_y = destination.y + teleport_z = destination.z + ..(A, 1) //Run the parent proc for teleportation. Tell it to play the animation. diff --git a/modular_RUtgmc/code/game/objects/items/card_ids.dm b/modular_RUtgmc/code/game/objects/items/card_ids.dm new file mode 100644 index 0000000000000..cab05a444d534 --- /dev/null +++ b/modular_RUtgmc/code/game/objects/items/card_ids.dm @@ -0,0 +1,6 @@ +/obj/item/card/id/proc/set_user_data(mob/living/carbon/human/human_user) + if(!istype(human_user)) + return + + registered_name = human_user.real_name + blood_type = human_user.blood_type diff --git a/modular_RUtgmc/code/game/objects/items/reagent_containers/autoinjectors.dm b/modular_RUtgmc/code/game/objects/items/reagent_containers/autoinjectors.dm new file mode 100644 index 0000000000000..957e55e536bb5 --- /dev/null +++ b/modular_RUtgmc/code/game/objects/items/reagent_containers/autoinjectors.dm @@ -0,0 +1,26 @@ +/obj/item/reagent_containers/hypospray/autoinjector/yautja + name = "unusual crystal" + desc = "A strange glowing crystal with a spike at one end." + icon = 'modular_RUtgmc/icons/obj/hunter/pred_gear.dmi' + icon_state = "crystal" + item_state = "" + amount_per_transfer_from_this = REAGENTS_OVERDOSE + volume = REAGENTS_OVERDOSE + + list_reagents = list(/datum/reagent/thwei = REAGENTS_OVERDOSE) + +/obj/item/reagent_containers/hypospray/autoinjector/yautja/attack(mob/M, mob/user) + if(HAS_TRAIT(user, TRAIT_YAUTJA_TECH)) + ..() + else + to_chat(user, span_danger("You have no idea where to inject [src].")) + +/obj/item/reagent_containers/hypospray/autoinjector/yautja/interact(mob/user) + return + +/obj/item/reagent_containers/hypospray/autoinjector/synaptizine + volume = 18 + list_reagents = list( + /datum/reagent/medicine/synaptizine = 6, + /datum/reagent/medicine/hyronalin = 12, + ) diff --git a/modular_RUtgmc/code/game/objects/items/reagent_containers/snacks.dm b/modular_RUtgmc/code/game/objects/items/reagent_containers/snacks.dm new file mode 100644 index 0000000000000..5d031c46c76d9 --- /dev/null +++ b/modular_RUtgmc/code/game/objects/items/reagent_containers/snacks.dm @@ -0,0 +1,10 @@ +/obj/item/reagent_containers/food/snacks/meat/xenomeat + name = "meat" + desc = "A slab of acrid smelling meat." + icon_state = "xenomeat" + filling_color = "#43DE18" + +/obj/item/reagent_containers/food/snacks/meat/xenomeat/Initialize() + . = ..() + reagents.add_reagent(/datum/reagent/toxin/acid, 3) + src.bitesize = 6 diff --git a/modular_RUtgmc/code/game/objects/items/scanners.dm b/modular_RUtgmc/code/game/objects/items/scanners.dm index 8bbfd0178af9c..de95f31771b08 100644 --- a/modular_RUtgmc/code/game/objects/items/scanners.dm +++ b/modular_RUtgmc/code/game/objects/items/scanners.dm @@ -2,3 +2,14 @@ icon = 'modular_RUtgmc/icons/obj/clothing/gloves.dmi' item_icons = list( slot_gloves_str = 'modular_RUtgmc/icons/mob/clothing/hands.dmi') + +/obj/item/healthanalyzer + var/alien = FALSE + +/obj/item/healthanalyzer/alien + name = "\improper YMX scanner" + icon = 'modular_RUtgmc/icons/obj/hunter/pred_gear.dmi' + icon_state = "scanner" + item_state = "analyzer" + desc = "An alien design hand-held body scanner able to distinguish vital signs of the subject. The front panel is able to provide the basic readout of the subject's status." + alien = TRUE diff --git a/modular_RUtgmc/code/game/objects/items/stacks/leather.dm b/modular_RUtgmc/code/game/objects/items/stacks/leather.dm new file mode 100644 index 0000000000000..5cfbd6ef7ff9a --- /dev/null +++ b/modular_RUtgmc/code/game/objects/items/stacks/leather.dm @@ -0,0 +1,4 @@ +/obj/item/stack/sheet/animalhide/xeno/kinghide + name = "king hide" + desc = "The hide of an irregular strain, it is tattered and rotting." + color = "#f7897c" diff --git a/modular_RUtgmc/code/game/objects/items/stacks/medical.dm b/modular_RUtgmc/code/game/objects/items/stacks/medical.dm index 638ab09a7e45f..06f4210ec0f1e 100644 --- a/modular_RUtgmc/code/game/objects/items/stacks/medical.dm +++ b/modular_RUtgmc/code/game/objects/items/stacks/medical.dm @@ -1,7 +1,28 @@ +/obj/item/stack/medical + var/alien = FALSE + #define BANDAGE (1<<0) #define SALVE (1<<1) #define DISINFECT (1<<2) +/obj/item/stack/medical/heal_pack/advanced/bruise_pack/predator + name = "mending herbs" + singular_name = "mending herb" + desc = "A poultice made of soft leaves that is rubbed on bruises." + icon = 'modular_RUtgmc/icons/obj/hunter/pred_gear.dmi' + icon_state = "brute_herbs" + heal_brute = 15 + alien = TRUE + +/obj/item/stack/medical/heal_pack/ointment/predator + name = "soothing herbs" + singular_name = "soothing herb" + desc = "A poultice made of cold, blue petals that is rubbed on burns." + icon = 'modular_RUtgmc/icons/obj/hunter/pred_gear.dmi' + icon_state = "burn_herbs" + heal_burn = 15 + alien = TRUE + /// return TRUE if a given limb can be healed by src, FALSE otherwise /obj/item/stack/medical/heal_pack/can_heal_limb(datum/limb/affecting) if(zero_amount()) @@ -70,6 +91,24 @@ user.visible_message(span_notice("[user] covers the wounds on [patient]'s [target_limb.display_name] with regenerative membrane."), span_notice("You cover the wounds on [patient]'s [target_limb.display_name] with regenerative membrane.")) +/obj/item/stack/medical/heal_pack/advanced/bruise_pack/predator + name = "mending herbs" + singular_name = "mending herb" + desc = "A poultice made of soft leaves that is rubbed on bruises." + icon = 'modular_RUtgmc/icons/obj/hunter/pred_gear.dmi' + icon_state = "brute_herbs" + heal_brute = 15 + alien = TRUE + +/obj/item/stack/medical/heal_pack/ointment/predator + name = "soothing herbs" + singular_name = "soothing herb" + desc = "A poultice made of cold, blue petals that is rubbed on burns." + icon = 'modular_RUtgmc/icons/obj/hunter/pred_gear.dmi' + icon_state = "burn_herbs" + heal_burn = 15 + alien = TRUE + #undef BANDAGE #undef SALVE #undef DISINFECT diff --git a/modular_RUtgmc/code/game/objects/items/stacks/sheets/mineral.dm b/modular_RUtgmc/code/game/objects/items/stacks/sheets/mineral.dm new file mode 100644 index 0000000000000..7acc99bfc0edb --- /dev/null +++ b/modular_RUtgmc/code/game/objects/items/stacks/sheets/mineral.dm @@ -0,0 +1,3 @@ +/obj/item/stack/sheet/mineral/sandstone/runed + icon = 'modular_RUtgmc/icons/obj/stack_objects.dmi' + icon_state = "sheet-runedsandstone" diff --git a/modular_RUtgmc/code/game/objects/items/sheets/sheet_types.dm b/modular_RUtgmc/code/game/objects/items/stacks/sheets/sheet_types.dm similarity index 90% rename from modular_RUtgmc/code/game/objects/items/sheets/sheet_types.dm rename to modular_RUtgmc/code/game/objects/items/stacks/sheets/sheet_types.dm index 75f1052f76d4a..60cf74462dcdc 100644 --- a/modular_RUtgmc/code/game/objects/items/sheets/sheet_types.dm +++ b/modular_RUtgmc/code/game/objects/items/stacks/sheets/sheet_types.dm @@ -81,3 +81,14 @@ GLOBAL_LIST_INIT(plasteel_recipes, list ( \ create_object(user, new/datum/stack_recipe("folding plasteel barricade", /obj/structure/barricade/plasteel, 6, time = 10 SECONDS, max_per_turf = STACK_RECIPE_ONE_DIRECTIONAL_PER_TILE, on_floor = TRUE, skill_req = SKILL_CONSTRUCTION_PLASTEEL), 1) return FALSE + +/obj/item/stack/sheet/mineral/sandstone/runed/Initialize(mapload) + . = ..() + recipes = GLOB.runedsandstone_recipes + +GLOBAL_LIST_INIT(runedsandstone_recipes, list ( \ + new/datum/stack_recipe("brazier frame", /obj/structure/prop/brazier/frame, req_amount = 5, time = 3 SECONDS, max_per_turf = STACK_RECIPE_ONE_DIRECTIONAL_PER_TILE, on_floor = TRUE, skill_req = SKILL_CONSTRUCTION_MASTER), \ + new/datum/stack_recipe("torch frame", /obj/item/frame/torch_frame, req_amount = 3, time = 2 SECONDS, skill_req = SKILL_CONSTRUCTION_MASTER), \ + new/datum/stack_recipe("sandstone floor tile", /obj/item/stack/tile/plasteel/sandstone/runed, 1, 4, 20), \ + new/datum/stack_recipe("sandstone wall", /turf/closed/wall/mineral/sandstone/runed, req_amount = 15, time = 10 SECONDS, max_per_turf = STACK_RECIPE_ONE_DIRECTIONAL_PER_TILE, on_floor = TRUE, skill_req = SKILL_CONSTRUCTION_MASTER), +)) diff --git a/modular_RUtgmc/code/game/objects/items/stacks/tiles/tile_types.dm b/modular_RUtgmc/code/game/objects/items/stacks/tiles/tile_types.dm new file mode 100644 index 0000000000000..7d3c86d948b37 --- /dev/null +++ b/modular_RUtgmc/code/game/objects/items/stacks/tiles/tile_types.dm @@ -0,0 +1,9 @@ +/obj/item/stack/tile/plasteel/sandstone/runed + icon_state = "tile_runedsandstone" + icon = 'modular_RUtgmc/icons/obj/stack_objects.dmi' + force = 6 + throwforce = 8 + throw_speed = 3 + throw_range = 6 + flags_atom = CONDUCT + turf_type = /turf/open/floor/sandstone/runed diff --git a/modular_RUtgmc/code/game/objects/items/weapons/weapons.dm b/modular_RUtgmc/code/game/objects/items/weapons/weapons.dm new file mode 100644 index 0000000000000..46f5ecacb51a0 --- /dev/null +++ b/modular_RUtgmc/code/game/objects/items/weapons/weapons.dm @@ -0,0 +1,3 @@ +/obj/item/weapon + var/can_block_xeno = FALSE + var/can_block_chance = 30 // 0-100% diff --git a/modular_RUtgmc/code/game/objects/machinery/OpTable.dm b/modular_RUtgmc/code/game/objects/machinery/OpTable.dm index fe3735cba0854..de3391e31a59a 100644 --- a/modular_RUtgmc/code/game/objects/machinery/OpTable.dm +++ b/modular_RUtgmc/code/game/objects/machinery/OpTable.dm @@ -1,3 +1,7 @@ +/obj/machinery/optable/yautja + icon = 'modular_RUtgmc/icons/obj/machines/yautja_machines.dmi' + icon_state = "table2-idle" + /obj/machinery/optable/ex_act(severity) if(prob(severity / 3)) qdel(src) diff --git a/modular_RUtgmc/code/game/objects/machinery/adv_med.dm b/modular_RUtgmc/code/game/objects/machinery/adv_med.dm index b1ba8f9d0c6e8..b10ae08d270ca 100644 --- a/modular_RUtgmc/code/game/objects/machinery/adv_med.dm +++ b/modular_RUtgmc/code/game/objects/machinery/adv_med.dm @@ -1,3 +1,8 @@ +/obj/machinery/computer/body_scanconsole/pred + icon = 'modular_RUtgmc/icons/obj/machines/yautja_machines.dmi' + icon_state = "sleeperconsole" + base_icon_state = "sleeperconsole" + /obj/machinery/bodyscanner/ex_act(severity) if(!prob(severity / 3)) return diff --git a/modular_RUtgmc/code/game/objects/machinery/autodoc.dm b/modular_RUtgmc/code/game/objects/machinery/autodoc.dm index f4cac64adcb25..0bb996e4cccf7 100644 --- a/modular_RUtgmc/code/game/objects/machinery/autodoc.dm +++ b/modular_RUtgmc/code/game/objects/machinery/autodoc.dm @@ -1,2 +1,11 @@ /obj/machinery/autodoc icon = 'modular_RUtgmc/icons/obj/machines/cryogenics.dmi' + +/obj/machinery/autodoc/yautja + icon = 'modular_RUtgmc/icons/obj/machines/yautja_machines.dmi' + icon_state = "autodoc_open" + resistance_flags = INDESTRUCTIBLE + +/obj/machinery/computer/autodoc_console/pred + icon = 'modular_RUtgmc/icons/obj/machines/yautja_machines.dmi' + icon_state = "sleeperconsole" diff --git a/modular_RUtgmc/code/game/objects/machinery/computer/crew.dm b/modular_RUtgmc/code/game/objects/machinery/computer/crew.dm new file mode 100644 index 0000000000000..be3b716b7af50 --- /dev/null +++ b/modular_RUtgmc/code/game/objects/machinery/computer/crew.dm @@ -0,0 +1,4 @@ +/obj/machinery/computer/crew/pred + icon = 'modular_RUtgmc/icons/obj/machines/yautja_machines.dmi' + icon_state = "crew" + diff --git a/modular_RUtgmc/code/game/objects/machinery/kitchen/gibber.dm b/modular_RUtgmc/code/game/objects/machinery/kitchen/gibber.dm new file mode 100644 index 0000000000000..bebf5926362ec --- /dev/null +++ b/modular_RUtgmc/code/game/objects/machinery/kitchen/gibber.dm @@ -0,0 +1,3 @@ +/obj/machinery/gibber/pred + icon = 'modular_RUtgmc/icons/obj/machines/yautja_machines.dmi' + icon_state = "grinder" diff --git a/modular_RUtgmc/code/game/objects/machinery/sleeper.dm b/modular_RUtgmc/code/game/objects/machinery/sleeper.dm index 5bf8ecf1d37e3..db0ec29ff57b0 100644 --- a/modular_RUtgmc/code/game/objects/machinery/sleeper.dm +++ b/modular_RUtgmc/code/game/objects/machinery/sleeper.dm @@ -1,3 +1,7 @@ +/obj/machinery/computer/sleep_console/pred + icon = 'modular_RUtgmc/icons/obj/machines/yautja_machines.dmi' + icon_state = "sleeperconsole" + /obj/machinery/computer/sleep_console/ex_act(severity) if(prob(severity / 3)) qdel(src) diff --git a/modular_RUtgmc/code/game/objects/structures/barricade.dm b/modular_RUtgmc/code/game/objects/structures/barricade.dm index 7f5f7a1fa7d9d..f96a1cb90297f 100644 --- a/modular_RUtgmc/code/game/objects/structures/barricade.dm +++ b/modular_RUtgmc/code/game/objects/structures/barricade.dm @@ -194,3 +194,10 @@ living_carbon.Knockdown(2 SECONDS) //Leaping into barbed wire is VERY bad playsound(living_carbon, 'modular_RUtgmc/sound/machines/bonk.ogg', 75, FALSE) ..() + +/obj/structure/barricade/metal/handrail + resistance_flags = INDESTRUCTIBLE + icon_state = "handrail_strata" + name = "handrail" + barricade_type = "handrail" + icon = 'modular_RUtgmc/icons/Marine/barricades.dmi' diff --git a/modular_RUtgmc/code/game/objects/structures/bedsheet_bin.dm b/modular_RUtgmc/code/game/objects/structures/bedsheet_bin.dm new file mode 100644 index 0000000000000..873c43ab045de --- /dev/null +++ b/modular_RUtgmc/code/game/objects/structures/bedsheet_bin.dm @@ -0,0 +1,5 @@ +/obj/item/bedsheet/pred + name = "Hunter Nav Console" + desc = "A console used by the Hunters for navigation purposes." + icon = 'modular_RUtgmc/icons/obj/machines/yautja_machines.dmi' + icon_state = "cameras" diff --git a/modular_RUtgmc/code/game/objects/structures/crates_lockers/closets.dm b/modular_RUtgmc/code/game/objects/structures/crates_lockers/closets.dm index 71e8673a500ae..8d58f2cb8ecfa 100644 --- a/modular_RUtgmc/code/game/objects/structures/crates_lockers/closets.dm +++ b/modular_RUtgmc/code/game/objects/structures/crates_lockers/closets.dm @@ -32,6 +32,10 @@ dump_contents() return ..() +/obj/structure/closet/pred + icon = 'modular_RUtgmc/icons/obj/machines/yautja_machines.dmi' + icon_state = "closed" + /obj/structure/closet/ex_act(severity) take_damage(severity, BRUTE, BOMB) if(!locked || prob(severity / 3)) diff --git a/modular_RUtgmc/code/game/objects/structures/crates_lockers/secure/freezer.dm b/modular_RUtgmc/code/game/objects/structures/crates_lockers/secure/freezer.dm new file mode 100644 index 0000000000000..8033b3c2c59e7 --- /dev/null +++ b/modular_RUtgmc/code/game/objects/structures/crates_lockers/secure/freezer.dm @@ -0,0 +1,15 @@ +/obj/structure/closet/secure_closet/freezer/kitchen/yautja + req_access = null + locked = FALSE + icon = 'modular_RUtgmc/icons/obj/machines/yautja_machines.dmi' + icon_state = "freezer" + +/obj/structure/closet/secure_closet/freezer/fridge/yautja + locked = FALSE + icon = 'modular_RUtgmc/icons/obj/machines/yautja_machines.dmi' + icon_state = "fridge" + +/obj/structure/closet/secure_closet/freezer/meat/yautja + locked = FALSE + icon = 'modular_RUtgmc/icons/obj/machines/yautja_machines.dmi' + icon_state = "fridge" diff --git a/modular_RUtgmc/code/game/objects/structures/misc.dm b/modular_RUtgmc/code/game/objects/structures/misc.dm index 8b745117d5540..1d21edd2bb0c3 100644 --- a/modular_RUtgmc/code/game/objects/structures/misc.dm +++ b/modular_RUtgmc/code/game/objects/structures/misc.dm @@ -12,6 +12,22 @@ if(mob_occupant) new mob_occupant(loc) +/obj/structure/stairs/seamless/pred + icon_state = "staircorners_seamless" + color = "#6b675e" + +/obj/structure/showcase/yautja + name = "Radar Console" + desc = "A console equipped with a radar used by the Hunters to detect gear and good hunting grounds." + icon = 'modular_RUtgmc/icons/obj/machines/yautja_machines.dmi' + icon_state = "terminal" + +/obj/structure/showcase/yautja/alt + name = "alien sarcophagus" + icon = 'icons/obj/stationobjs.dmi' + desc = "An ancient, dusty tomb with strange alien writing. It's best not to touch it." + icon_state = "yaut" + /obj/structure/plasticflaps/ex_act(severity) if(prob(severity / 4)) qdel(src) diff --git a/modular_RUtgmc/code/game/objects/structures/reagent_dispensers.dm b/modular_RUtgmc/code/game/objects/structures/reagent_dispensers.dm index 8817a5d27668e..ae5080e1c7505 100644 --- a/modular_RUtgmc/code/game/objects/structures/reagent_dispensers.dm +++ b/modular_RUtgmc/code/game/objects/structures/reagent_dispensers.dm @@ -1,3 +1,11 @@ +/obj/structure/reagent_dispensers/fueltank/pred + icon = 'modular_RUtgmc/icons/obj/machines/yautja_machines.dmi' + icon_state = "weldtank" + +/obj/structure/reagent_dispensers/watertank/pred + icon = 'modular_RUtgmc/icons/obj/machines/yautja_machines.dmi' + icon_state = "watertank" + /obj/structure/reagent_dispensers/ex_act(severity) if(prob(severity / 4)) new /obj/effect/particle_effect/water(loc) diff --git a/modular_RUtgmc/code/game/objects/structures/stool_bed_chair_nest/bed.dm b/modular_RUtgmc/code/game/objects/structures/stool_bed_chair_nest/bed.dm index d631acd8d172e..2658790dca498 100644 --- a/modular_RUtgmc/code/game/objects/structures/stool_bed_chair_nest/bed.dm +++ b/modular_RUtgmc/code/game/objects/structures/stool_bed_chair_nest/bed.dm @@ -16,6 +16,13 @@ /obj/item/medevac_beacon w_class = WEIGHT_CLASS_SMALL +/obj/structure/bed/pred + icon = 'modular_RUtgmc/icons/obj/machines/yautja_machines.dmi' + icon_state = "bed" + +/obj/structure/bed/pred/alt + icon_state = "abed" + /obj/item/roller/medevac/unique_action(mob/user) . = ..() deploy_roller(user, user.loc) diff --git a/modular_RUtgmc/code/game/objects/structures/stool_bed_chair_nest/chairs.dm b/modular_RUtgmc/code/game/objects/structures/stool_bed_chair_nest/chairs.dm new file mode 100644 index 0000000000000..c5feacbde6dfd --- /dev/null +++ b/modular_RUtgmc/code/game/objects/structures/stool_bed_chair_nest/chairs.dm @@ -0,0 +1,3 @@ +/obj/structure/bed/chair/comfy/black/pred + icon = 'modular_RUtgmc/icons/obj/machines/yautja_machines.dmi' + icon_state = "comfychair" diff --git a/modular_RUtgmc/code/game/objects/structures/window.dm b/modular_RUtgmc/code/game/objects/structures/window.dm index dbcb5a49a42e6..bc94aa93ddeb7 100644 --- a/modular_RUtgmc/code/game/objects/structures/window.dm +++ b/modular_RUtgmc/code/game/objects/structures/window.dm @@ -27,3 +27,13 @@ /obj/structure/window/framed/colony/reinforced icon = 'modular_RUtgmc/icons/obj/smooth_objects/col_rwindow.dmi' + +/obj/structure/window/framed/colony/reinforced/hull/pred + basestate = "pred_window" + icon_state = "pred_window-0" + icon = 'modular_RUtgmc/icons/obj/smooth_objects/pred_window.dmi' + base_icon_state = "pred_window" + +/obj/structure/window/phoronreinforced/pred + icon_state = "phoronrwindow" + resistance_flags = INDESTRUCTIBLE diff --git a/modular_RUtgmc/code/game/objects/yautja_misc.dm b/modular_RUtgmc/code/game/objects/yautja_misc.dm new file mode 100644 index 0000000000000..845af18dc3b70 --- /dev/null +++ b/modular_RUtgmc/code/game/objects/yautja_misc.dm @@ -0,0 +1,100 @@ +/obj/structure/prop/brazier + name = "brazier" + desc = "The fire inside the brazier emits a relatively dim glow to flashlights and flares, but nothing can replace the feeling of sitting next to a fireplace with your friends." + icon = 'modular_RUtgmc/icons/obj/structures/torch.dmi' + icon_state = "brazier" + density = TRUE + light_on = TRUE + light_range = 5 + light_power = 2 + light_system = STATIC_LIGHT + light_color = "#b49a27" + +/obj/structure/prop/brazier/Initialize(...) + . = ..() + set_light_on(FALSE) + if(light_on) + set_light_on(TRUE) + +/obj/structure/prop/brazier/frame + name = "empty brazier" + desc = "An empty brazier." + icon_state = "brazier_frame" + light_range = 0 + light_on = FALSE + +/obj/structure/prop/brazier/frame/attackby(obj/item/hit_item, mob/user) + if(!istype(hit_item, /obj/item/stack/sheet/wood)) + return ..() + var/obj/item/stack/wooden_boards = hit_item + if(wooden_boards.amount < 5) + to_chat(user, span_warning("Not enough wood!")) + return + wooden_boards.use(5) + user.visible_message(span_notice("[user] fills the brazier with wood.")) + new /obj/structure/prop/brazier/frame_woodened(loc) + qdel(src) + +/obj/structure/prop/brazier/frame_woodened + name = "empty full brazier" + desc = "An empty brazier. Yet it's also full. What??? Use something hot to ignite it, like a welding tool." + icon_state = "brazier_frame_filled" + light_range = 0 + light_on = FALSE + +/obj/structure/prop/brazier/frame_woodened/attackby(obj/item/hit_item, mob/user) + if(hit_item.damtype != BURN) + return ..() + user.visible_message(span_notice("[user] ignites the brazier with [hit_item].")) + new /obj/structure/prop/brazier(loc) + qdel(src) + +/obj/structure/prop/brazier/torch + name = "torch" + desc = "It's a torch." + icon = 'modular_RUtgmc/icons/obj/structures/torch.dmi' + icon_state = "torch" + density = FALSE + light_range = 7 + light_power = 1 + +/obj/structure/prop/brazier/torch/frame + name = "unlit torch" + desc = "It's a torch, but it's not lit. Use something hot to ignite it, like a welding tool." + icon_state = "torch_frame" + light_range = 0 + +/obj/structure/prop/brazier/torch/frame/attackby(obj/item/hit_item, mob/user) + if(hit_item.damtype != BURN) + return ..() + user.visible_message(span_notice("[user] ignites the torch with [hit_item].")) + new /obj/structure/prop/brazier/torch(loc) + qdel(src) + +/obj/item/frame/torch_frame + name = "unlit torch" + icon = 'modular_RUtgmc/icons/obj/structures/torch.dmi' + desc = "It's a torch, but it's not lit or placed down. Click on a wall to place it." + icon_state = "torch_frame" + +/obj/item/frame/torch_frame/proc/try_build(turf/on_wall) + if(get_dist(on_wall, usr) > 1) + return + var/ndir = get_dir(usr, on_wall) + if(!(ndir in GLOB.cardinals)) + return + var/turf/loc = get_turf(usr) + if(!isfloorturf(loc)) + to_chat(usr, span_warning("[src.name] cannot be placed on this spot.")) + return + to_chat(usr, "Attaching [src] to the wall.") + playsound(src.loc, 'sound/machines/click.ogg', 15, 1) + var/constrdir = usr.dir + if(!do_after(usr, 30, TRUE, on_wall, BUSY_ICON_BUILD)) + return + var/obj/structure/prop/brazier/torch/frame/newlight = new /obj/structure/prop/brazier/torch/frame(get_turf(on_wall)) + newlight.setDir(constrdir) + + usr.visible_message("[usr.name] attaches [src] to the wall.", \ + "You attach [src] to the wall.") + qdel(src) diff --git a/modular_RUtgmc/code/game/turfs/floor_types.dm b/modular_RUtgmc/code/game/turfs/floor_types.dm index c2bd2e610b504..ddd5f70bc61d2 100644 --- a/modular_RUtgmc/code/game/turfs/floor_types.dm +++ b/modular_RUtgmc/code/game/turfs/floor_types.dm @@ -1,6 +1,31 @@ /turf/open/floor/mainship/terragov icon = 'modular_RUtgmc/icons/turf/mainship.dmi' +/turf/open/floor/corsat + icon = 'modular_RUtgmc/icons/turf/corsat.dmi' + icon_state = "squareswood" + base_icon_state = "squareswood" + +/turf/open/floor/strata //Instance me! + icon = 'modular_RUtgmc/icons/turf/strata_floor.dmi' + base_icon_state = "floor" + icon_state = "floor" + +/turf/open/floor/strata/multi_tiles + icon_state = "multi_tiles" + color = "#5e5d5d" + +/turf/open/floor/sandstone + name = "sandstone floor" + icon = 'modular_RUtgmc/icons/turf/sandstone.dmi' + base_icon_state = "whiteyellowfull" + icon_state = "whiteyellowfull" + +/turf/open/floor/sandstone/runed + name = "sandstone temple floor" + base_icon_state = "runedsandstone" + icon_state = "runedsandstone" + /turf/open/floor/carpet/ex_act(severity) if(hull_floor) return ..() diff --git a/modular_RUtgmc/code/game/turfs/walls/wall_types.dm b/modular_RUtgmc/code/game/turfs/walls/wall_types.dm index 893fd4c94f23e..502a6256babdc 100644 --- a/modular_RUtgmc/code/game/turfs/walls/wall_types.dm +++ b/modular_RUtgmc/code/game/turfs/walls/wall_types.dm @@ -26,3 +26,35 @@ ..() if(icon_state == "title_painting1") icon_state = "title_painting[rand(0,40)]" + +/turf/closed/wall/mineral/sandstone/runed + name = "sandstone temple wall" + desc = "A heavy wall of sandstone." + icon = 'icons/turf/walls/cult.dmi' + icon_state = "cult-0" + base_icon_state = "cult" + walltype = "cult" + mineral = "runed sandstone" + color = "#DDB5A4" + smoothing_behavior = DIAGONAL_SMOOTHING + smoothing_groups = SMOOTH_GROUP_GENERAL_STRUCTURES + max_integrity = 9000//Strong, but only available to Hunters, can can still be blown up or melted by boilers. + +/turf/closed/wall/mineral/sandstone/runed/attack_alien(mob/living/carbon/xenomorph/user, damage_amount = user.xeno_caste.melee_damage, damage_type = BRUTE, damage_flag = "", effects = TRUE, armor_penetration = 0, isrightclick = FALSE) + visible_message("[user] scrapes uselessly against [src] with their claws.") + return + +/turf/closed/wall/huntership + name = "hunter wall" + desc = "Nigh indestructible walls that make up the hull of a hunter ship." + icon = 'modular_RUtgmc/icons/turf/walls/hunter.dmi' + icon_state = "hunter-0"//DMI specific name + walltype = "hunter" + base_icon_state = "hunter" + resistance_flags = RESIST_ALL + +/turf/closed/wall/huntership/destructible + name = "degraded hunter wall" + color = "#c5beb4" + desc = "Ancient beyond measure, these walls make up the hull of a vessel of non human origin. Despite this, they can be felled with plastic explosives like any other opaque blocker." + resistance_flags = NONE diff --git a/modular_RUtgmc/code/modules/admin/admin_verbs.dm b/modular_RUtgmc/code/modules/admin/admin_verbs.dm index e4222941b12e3..86414f82353e5 100644 --- a/modular_RUtgmc/code/modules/admin/admin_verbs.dm +++ b/modular_RUtgmc/code/modules/admin/admin_verbs.dm @@ -42,3 +42,46 @@ log_admin("[key_name(H)] became a debug military policeman.") message_admins("[ADMIN_TPMONTY(H)] became a debug military policeman.") + +/client/proc/cmd_admin_create_predator_report() + set name = "Report: Yautja AI" + set category = "Admin" + + if(!check_rights(R_ADMIN)) + to_chat(src, "Only administrators may use this command.") + return + var/input = input(usr, "This is a message from the predator ship's AI. Check with online staff before you send this.", "What?", "") as message|null + if(!input) + return FALSE + yautja_announcement(span_yautjaboldbig(input)) + message_admins("[key_name_admin(src)] has created a predator ship AI report") + log_admin("[key_name_admin(src)] predator ship AI report: [input]") + +/datum/admins/proc/force_predator_round() + set category = "Server" + set name = "Toggle Predator Round" + set desc = "Force-toggle a predator round for the round type. Only works on maps that support Predator spawns." + + if(!check_rights(R_SERVER)) + return + + var/datum/game_mode/predator_round = SSticker.mode + if(!predator_round) + to_chat(usr, span_adminnotice("Wait until round start!")) + return + + if(alert("Are you sure you want to force-toggle a predator round? Predators currently: [(predator_round.flags_round_type & MODE_PREDATOR) ? "Enabled" : "Disabled"]",, "Yes", "No") != "Yes") + return + + if(!(predator_round.flags_round_type & MODE_PREDATOR)) + var/datum/job/PJ = SSjob.GetJobType(/datum/job/predator) + var/new_pred_max = min(max(round(length(GLOB.clients) * PREDATOR_TO_TOTAL_SPAWN_RATIO), 1), 4) + PJ.total_positions = new_pred_max + PJ.max_positions = new_pred_max + predator_round.flags_round_type |= MODE_PREDATOR + else + predator_round.flags_round_type &= ~MODE_PREDATOR + + log_admin("[key_name_admin(usr)] has [(predator_round.flags_round_type & MODE_PREDATOR) ? "allowed predators to spawn" : "prevented predators from spawning"].") + message_admins("[ADMIN_TPMONTY(usr)] has [(predator_round.flags_round_type & MODE_PREDATOR) ? "allowed predators to spawn" : "prevented predators from spawning"].") + SEND_GLOBAL_SIGNAL(COMSIG_GLOB_PREDATOR_ROUND_TOGGLED) diff --git a/modular_RUtgmc/code/modules/admin/holder.dm b/modular_RUtgmc/code/modules/admin/holder.dm index 9c8c8ecc400a5..2a493d5f89988 100644 --- a/modular_RUtgmc/code/modules/admin/holder.dm +++ b/modular_RUtgmc/code/modules/admin/holder.dm @@ -29,6 +29,7 @@ /datum/admins/proc/toggle_prayers, /datum/admins/proc/check_fingerprints, /datum/admins/proc/unforbid, + /client/proc/cmd_admin_create_predator_report, /client/proc/smite, /client/proc/show_traitor_panel, /client/proc/validate_objectives, @@ -37,6 +38,98 @@ /client/proc/msay, /client/proc/dsay ) + +/world/AVserver() + return list( + /datum/admins/proc/restart, + /datum/admins/proc/shutdown_server, + /datum/admins/proc/toggle_ooc, + /datum/admins/proc/toggle_looc, + /datum/admins/proc/toggle_deadchat, + /datum/admins/proc/toggle_deadooc, + /datum/admins/proc/start, + /datum/admins/proc/toggle_join, + /datum/admins/proc/toggle_respawn, + /datum/admins/proc/set_respawn_time, + /datum/admins/proc/end_round, + /datum/admins/proc/delay_start, + /datum/admins/proc/delay_end, + /datum/admins/proc/toggle_gun_restrictions, + /datum/admins/proc/toggle_synthetic_restrictions, + /datum/admins/proc/reload_admins, + /datum/admins/proc/change_ground_map, + /datum/admins/proc/change_ship_map, + /datum/admins/proc/panic_bunker, + /datum/admins/proc/mode_check, + /datum/admins/proc/toggle_valhalla, + /datum/admins/proc/toggle_sdd_possesion, + /datum/admins/proc/force_predator_round, + /client/proc/toggle_cdn + ) + +/client/remove_admin_verbs() + verbs.Remove( + GLOB.admin_verbs_default, + GLOB.admin_verbs_admin, + GLOB.admin_verbs_mentor, + GLOB.admin_verbs_ban, + GLOB.admin_verbs_asay, + GLOB.admin_verbs_fun, + GLOB.admin_verbs_server, + GLOB.admin_verbs_debug, + GLOB.admin_verbs_permissions, + GLOB.admin_verbs_sound, + GLOB.admin_verbs_color, + GLOB.admin_verbs_varedit, + GLOB.admin_verbs_spawn, + GLOB.admin_verbs_log, + GLOB.clan_verbs, + ) + +/world/proc/AVyautja() + return list( + /client/proc/usr_create_new_clan + ) + +GLOBAL_LIST_INIT(clan_verbs, world.AVyautja()) +GLOBAL_PROTECT(clan_verbs) + +/client/add_admin_verbs() + if(holder) + var/rights = holder.rank.rights + verbs += GLOB.admin_verbs_default + if(rights & R_ADMIN) + verbs += GLOB.admin_verbs_admin + if(rights & R_MENTOR) + verbs += GLOB.admin_verbs_mentor + if(rights & R_BAN) + verbs += GLOB.admin_verbs_ban + if(rights & R_ASAY) + verbs += GLOB.admin_verbs_asay + if(rights & R_FUN) + verbs += GLOB.admin_verbs_fun + if(rights & R_SERVER) + verbs += GLOB.admin_verbs_server + if(rights & R_DEBUG) + verbs += GLOB.admin_verbs_debug + if(rights & R_RUNTIME) + verbs += GLOB.admin_verbs_runtimes + if(rights & R_PERMISSIONS) + verbs += GLOB.admin_verbs_permissions + if(rights & R_DBRANKS) + verbs += GLOB.admin_verbs_permissions + if(rights & R_SOUND) + verbs += GLOB.admin_verbs_sound + if(rights & R_COLOR) + verbs += GLOB.admin_verbs_color + if(rights & R_VAREDIT) + verbs += GLOB.admin_verbs_varedit + if(rights & R_SPAWN) + verbs += GLOB.admin_verbs_spawn + if(rights & R_LOG) + verbs += GLOB.admin_verbs_log + if(GLOB.roles_whitelist[ckey] & WHITELIST_YAUTJA_LEADER) + verbs += GLOB.clan_verbs GLOBAL_LIST_INIT(admin_verbs_admin, world.AVadmin()) GLOBAL_PROTECT(admin_verbs_admin) diff --git a/modular_RUtgmc/code/modules/admin/panels/player_panel.dm b/modular_RUtgmc/code/modules/admin/panels/player_panel.dm index d32004255d527..8ce401162e4b8 100644 --- a/modular_RUtgmc/code/modules/admin/panels/player_panel.dm +++ b/modular_RUtgmc/code/modules/admin/panels/player_panel.dm @@ -97,9 +97,10 @@ Transformation:
Special: Observer | - AI + AI | Sectoid | - SKELETON + SKELETON | + Yautja
Humanoid: Human | Synthetic | @@ -109,9 +110,11 @@ Combat_Robot | Monkey | Moth | - Zombie + Zombie | + Hellhound
Alien Tier 0: Larva | + Predalien Larva | Facehugger
Alien Tier 1: Runner | @@ -140,7 +143,8 @@ Queen | Shrike | Hivemind | - King + King | + Predalien
"} diff --git a/modular_RUtgmc/code/modules/atmospherics/machinery/components/unary_devices/thermomachine.dm b/modular_RUtgmc/code/modules/atmospherics/machinery/components/unary_devices/thermomachine.dm new file mode 100644 index 0000000000000..a98fb571fd465 --- /dev/null +++ b/modular_RUtgmc/code/modules/atmospherics/machinery/components/unary_devices/thermomachine.dm @@ -0,0 +1,4 @@ +/obj/machinery/atmospherics/components/unary/thermomachine/freezer/pred + icon = 'modular_RUtgmc/icons/obj/machines/yautja_machines.dmi' + icon_state = "freezer" + resistance_flags = INDESTRUCTIBLE diff --git a/modular_RUtgmc/code/modules/atmospherics/machinery/portable/canister.dm b/modular_RUtgmc/code/modules/atmospherics/machinery/portable/canister.dm new file mode 100644 index 0000000000000..79157dc293c70 --- /dev/null +++ b/modular_RUtgmc/code/modules/atmospherics/machinery/portable/canister.dm @@ -0,0 +1,5 @@ +/obj/machinery/portable_atmospherics/canister/oxygen/pred + icon = 'modular_RUtgmc/icons/obj/machines/yautja_machines.dmi' + icon_state = "blue" + anchored = TRUE + resistance_flags = INDESTRUCTIBLE diff --git a/modular_RUtgmc/code/modules/clans/clan.dm b/modular_RUtgmc/code/modules/clans/clan.dm new file mode 100644 index 0000000000000..e860f30f97ae4 --- /dev/null +++ b/modular_RUtgmc/code/modules/clans/clan.dm @@ -0,0 +1,4 @@ +/proc/create_new_clan(clanname) + var/datum/db_query/query_create_clan = SSdbcore.NewQuery("INSERT INTO [format_table_name("clan")] (name, description, honor, color) VALUES (:name, :desc, 0, :color)", list("name" = clanname, "desc" = "This is a clan.", "color" = "#FFF")) + query_create_clan.Execute() + qdel(query_create_clan) diff --git a/modular_RUtgmc/code/modules/clans/client.dm b/modular_RUtgmc/code/modules/clans/client.dm new file mode 100644 index 0000000000000..e2a48d4f87e75 --- /dev/null +++ b/modular_RUtgmc/code/modules/clans/client.dm @@ -0,0 +1,181 @@ +/client + var/datum/db_query/clan_info + +/client/proc/load_player_predator_info() + set waitfor = FALSE + + if(!SSdbcore.IsConnected()) + return // Urgle test without DB... don't make runtime + + if(GLOB.roles_whitelist[ckey] & WHITELIST_PREDATOR) + if(!update_clan_info()) + return + + if(GLOB.roles_whitelist[ckey] & WHITELIST_YAUTJA_LEADER) + clan_info.item[2] = CLAN_RANK_ADMIN_INT + clan_info.item[3] |= CLAN_PERMISSION_ALL + else + clan_info.item[3] &= ~CLAN_PERMISSION_ADMIN_MANAGER // Only the leader can manage the ancients + + clan_info.sql = "UPDATE [format_table_name("clan_player")] SET clan_rank = :clan_rank, permissions = :permissions WHERE byond_ckey = :byond_ckey" + clan_info.arguments = list("byond_ckey" = ckey, "clan_rank" = clan_info.item[2], "permissions" = clan_info.item[3]) + clan_info.Execute() + + clan_info.sql = "SELECT byond_ckey, clan_rank, permissions, clan_id, honor FROM [format_table_name("clan_player")] WHERE byond_ckey = :byond_ckey" + clan_info.arguments = list("byond_ckey" = ckey) + if(!clan_info.warn_execute()) + qdel(clan_info) + return + clan_info.next_row_to_take = 1 + clan_info.NextRow() + +/client/proc/update_clan_info() + if(!SSdbcore.IsConnected()) + return // Urgle test without DB... don't make runtime + if(GLOB.roles_whitelist[ckey] & WHITELIST_PREDATOR) + if(clan_info) + clan_info.sql = "SELECT byond_ckey, clan_rank, permissions, clan_id, honor FROM [format_table_name("clan_player")] WHERE byond_ckey = :byond_ckey" + clan_info.arguments = list("byond_ckey" = ckey) + clan_info.next_row_to_take = 1 + else + clan_info = SSdbcore.NewQuery("SELECT byond_ckey, clan_rank, permissions, clan_id, honor FROM [format_table_name("clan_player")] WHERE byond_ckey = :byond_ckey", list("byond_ckey" = ckey)) + clan_info.no_auto_delete = TRUE + if(!clan_info.warn_execute()) + qdel(clan_info) + return FALSE + + if(!clan_info.NextRow()) + clan_info.sql = "INSERT INTO [format_table_name("clan_player")] (byond_ckey, clan_rank, permissions, clan_id, honor) VALUES (:byond_ckey, 0, 0, 0, 0)" + clan_info.Execute() + clan_info.sql = "SELECT byond_ckey, clan_rank, permissions, clan_id, honor FROM [format_table_name("clan_player")] WHERE byond_ckey = :byond_ckey" + if(!clan_info.warn_execute()) + qdel(clan_info) + return FALSE + + clan_info.next_row_to_take = 1 + clan_info.NextRow() + + return TRUE + else + return FALSE + +/client/proc/usr_create_new_clan() + set name = "Create New Clan" + set category = "Debug" + + if(!SSdbcore.IsConnected()) + return + + if(!istype(clan_info)) + return + + if(!(clan_info.item[3] & CLAN_PERMISSION_ADMIN_MANAGER)) + return + + var/input = tgui_input_text(src, "Set name to clan", "Clan Name") + + if(!input) + return + + to_chat(src, span_notice("Made a new clan called: [input]")) + + create_new_clan(input) + +/client/verb/view_clan_info() + set name = "View Clan Info" + set category = "OOC" + + if(!istype(clan_info)) + to_chat(src, span_warning("You don't have a yautja whitelist!")) + return + + if(!has_clan_permission(CLAN_PERMISSION_VIEW)) + return + + var/clan_to_get + if(clan_info.item[3] & CLAN_PERMISSION_ADMIN_VIEW) + var/datum/db_query/db_clans = SSdbcore.NewQuery("SELECT id, name, description, honor, color FROM [format_table_name("clan")]") + if(!db_clans.warn_execute()) + qdel(db_clans) + return + var/list/clans = list() + while(db_clans.NextRow()) + clans += list("[db_clans.item[2]]" = db_clans.item[1]) + + qdel(db_clans) + + clans += list("People without clans" = null) + + var/input = tgui_input_list(src, "Choose the clan to view", "View clan", clans) + + if(!input) + to_chat(src, span_warning("Couldn't find any clans for you to view!")) + return + + clan_to_get = clans[input] + else if(clan_info.item[4]) + + var/options = list( + "Your clan" = clan_info.item[4], + "People without clans" = null + ) + + var/input = tgui_input_list(src, "Choose the clan to view", "View clan", options) + + if(!input) + return + + clan_to_get = options[input] + else + clan_to_get = null + + SSpredships.clan_ui.clan_id_by_user[mob] = clan_to_get + + SSpredships.clan_ui.ui_interact(mob) + +/client/proc/has_clan_permission(permission_flag, clan_id, warn = TRUE) + if(!update_clan_info() || !istype(clan_info) || length(clan_info.item) != 5) + if(warn) + to_chat(src, "You do not have a yautja whitelist!") + return FALSE + + if(clan_id) + if(clan_id != clan_info.item[4]) + if(warn) + to_chat(src, "You do not have permission to perform actions on this clan!") + return FALSE + + + if(!(clan_info.item[3] & permission_flag)) + if(warn) + to_chat(src, "You do not have the necessary permissions to perform this action!") + return FALSE + + return TRUE + +/client/proc/add_honor(number) + if(!istype(clan_info)) + return FALSE + + clan_info.sql = "UPDATE [format_table_name("clan_player")] SET honor = :honor WHERE byond_ckey = :byond_ckey" + clan_info.arguments = list("byond_ckey" = ckey, "honor" = number + clan_info.item[5]) + clan_info.Execute() + + clan_info.sql = "SELECT byond_ckey, clan_rank, permissions, clan_id, honor FROM [format_table_name("clan_player")] WHERE byond_ckey = :byond_ckey" + clan_info.arguments = list("byond_ckey" = ckey) + if(!clan_info.warn_execute()) + return + clan_info.next_row_to_take = 1 + clan_info.NextRow() + + if(clan_info.item[4]) + var/datum/db_query/target_clan = SSdbcore.NewQuery("SELECT id, name, description, honor, color FROM [format_table_name("clan")] WHERE id = :clan_id", list("clan_id" = clan_info.item[4])) + if(!target_clan.warn_execute()) + return + target_clan.NextRow() + target_clan.sql = "UPDATE [format_table_name("clan")] SET honor = :honor WHERE id = :clan_id" + target_clan.arguments = list("clan_id" = clan_info.item[4], "honor" = number + target_clan.item[4]) + target_clan.Execute() + qdel(target_clan) + + return TRUE diff --git a/modular_RUtgmc/code/modules/clans/rank.dm b/modular_RUtgmc/code/modules/clans/rank.dm new file mode 100644 index 0000000000000..a6b78a0d95e92 --- /dev/null +++ b/modular_RUtgmc/code/modules/clans/rank.dm @@ -0,0 +1,44 @@ +/datum/yautja_rank + var/name + + var/limit_type + var/limit + + var/permissions = CLAN_PERMISSION_USER_VIEW + var/permission_required = CLAN_PERMISSION_USER_MODIFY + +/datum/yautja_rank/unblooded + name = CLAN_RANK_UNBLOODED + permission_required = CLAN_PERMISSION_ADMIN_MODIFY + +/datum/yautja_rank/young + name = CLAN_RANK_YOUNG + +/datum/yautja_rank/blooded + name = CLAN_RANK_BLOODED + +/datum/yautja_rank/elite + name = CLAN_RANK_ELITE + + limit_type = CLAN_LIMIT_SIZE + limit = 5 + +/datum/yautja_rank/elder + name = CLAN_RANK_ELDER + + limit_type = CLAN_LIMIT_SIZE + limit = 12 + +/datum/yautja_rank/leader + name = CLAN_RANK_LEADER + + permissions = CLAN_PERMISSION_USER_ALL + permission_required = CLAN_PERMISSION_ADMIN_MODIFY + limit_type = CLAN_LIMIT_NUMBER + limit = 1 + +/datum/yautja_rank/ancient + name = CLAN_RANK_ADMIN + + permission_required = CLAN_PERMISSION_ADMIN_MANAGER + permissions = CLAN_PERMISSION_ADMIN_ANCIENT diff --git a/modular_RUtgmc/code/modules/clans/ship.dm b/modular_RUtgmc/code/modules/clans/ship.dm new file mode 100644 index 0000000000000..97b382d857fe2 --- /dev/null +++ b/modular_RUtgmc/code/modules/clans/ship.dm @@ -0,0 +1,7 @@ +/obj/effect/landmark/clan_spawn + name = "clan spawn" + +/obj/effect/landmark/clan_spawn/New() + . = ..() + SSpredships.init_spawnpoint(src) + qdel(src) diff --git a/modular_RUtgmc/code/modules/client/preferences.dm b/modular_RUtgmc/code/modules/client/preferences.dm new file mode 100644 index 0000000000000..bef6a4b02cbe2 --- /dev/null +++ b/modular_RUtgmc/code/modules/client/preferences.dm @@ -0,0 +1,23 @@ +/datum/preferences + //Predator specific preferences. + var/predator_name = "Undefined" + var/predator_gender = MALE + var/predator_age = 100 + var/predator_h_style = "Standard" + var/predator_skin_color = "Tan" + var/predator_use_legacy = "None" + var/predator_translator_type = "Modern" + var/predator_mask_type = 1 + var/predator_armor_type = 1 + var/predator_boot_type = 1 + var/predator_armor_material = "ebony" + var/predator_mask_material = "ebony" + var/predator_greave_material = "ebony" + var/predator_caster_material = "ebony" + var/predator_cape_type = "None" + var/predator_cape_color = "#654321" + var/predator_flavor_text = "None" + var/pred_r_eyes = 0 + var/pred_g_eyes = 0 + var/pred_b_eyes = 0 + var/yautja_status = WHITELIST_NORMAL diff --git a/modular_RUtgmc/code/modules/clothing/glasses/meson.dm b/modular_RUtgmc/code/modules/clothing/glasses/meson.dm new file mode 100644 index 0000000000000..fecfe25246a32 --- /dev/null +++ b/modular_RUtgmc/code/modules/clothing/glasses/meson.dm @@ -0,0 +1,33 @@ +/obj/item/clothing/glasses/meson/yautja + name = "bio-mask x-ray" + desc = "A vision overlay generated by the Bio-Mask. Used to see through objects." + icon = 'modular_RUtgmc/icons/obj/hunter/pred_gear.dmi' + icon_state = "visor_meson" + item_state = "visor_meson" + item_icons = list( + slot_glasses_str = 'modular_RUtgmc/icons/mob/hunter/pred_gear.dmi' + ) + darkness_view = 12 + lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE + vision_flags = SEE_TURFS + flags_inventory = COVEREYES + actions_types = null + +/obj/item/clothing/glasses/meson/yautja/Initialize() + . = ..() + ADD_TRAIT(src, TRAIT_NODROP, TRAIT_GENERIC) + +/obj/item/clothing/glasses/meson/yautja/dropped(mob/living/carbon/human/user) + if(istype(user) && user.glasses == src) + user.clear_fullscreen("pred_meson", 5) + ..() + +/obj/item/clothing/glasses/meson/yautja/equipped(mob/living/carbon/human/user, slot) + if(slot == SLOT_GLASSES) + user.overlay_fullscreen("pred_meson", /atom/movable/screen/fullscreen/machine/pred/meson) + ..() + +/obj/item/clothing/glasses/meson/yautja/unequipped(mob/living/carbon/human/user, slot) + if(slot == SLOT_GLASSES) + user.clear_fullscreen("pred_meson", 5) + ..() diff --git a/modular_RUtgmc/code/modules/clothing/glasses/night.dm b/modular_RUtgmc/code/modules/clothing/glasses/night.dm index fb2d8253cf0f5..2ad57f6ee1d40 100644 --- a/modular_RUtgmc/code/modules/clothing/glasses/night.dm +++ b/modular_RUtgmc/code/modules/clothing/glasses/night.dm @@ -24,5 +24,38 @@ deactive_state = "degoggles_medpatch" toggleable = TRUE +/obj/item/clothing/glasses/night/yautja + name = "bio-mask nightvision" + gender = NEUTER + desc = "A vision overlay generated by the Bio-Mask. Used for low-light conditions." + icon = 'modular_RUtgmc/icons/obj/hunter/pred_gear.dmi' + icon_state = "visor_nvg" + item_state = "visor_nvg" + item_icons = list( + slot_glasses_str = 'modular_RUtgmc/icons/mob/hunter/pred_gear.dmi' + ) + flags_inventory = COVEREYES + actions_types = null + +/obj/item/clothing/glasses/night/yautja/Initialize() + . = ..() + ADD_TRAIT(src, TRAIT_NODROP, TRAIT_GENERIC) + +/obj/item/clothing/glasses/night/yautja/dropped(mob/living/carbon/human/user) + if(istype(user) && user.glasses == src) + user.clear_fullscreen("robothalf", 5) + ..() + +/obj/item/clothing/glasses/night/yautja/equipped(mob/living/carbon/human/user, slot) + if(slot == SLOT_GLASSES) + user.overlay_fullscreen("robothalf", /atom/movable/screen/fullscreen/machine/pred/night) + ..() + +/obj/item/clothing/glasses/night/yautja/unequipped(mob/living/carbon/human/user, slot) + if(slot == SLOT_GLASSES) + user.clear_fullscreen("robothalf", 5) + ..() + + /obj/item/clothing/glasses/night/optgoggles soft_armor = list(MELEE = 40, BULLET = 40, LASER = 0, ENERGY = 15, BOMB = 35, BIO = 10, FIRE = 30, ACID = 30) diff --git a/modular_RUtgmc/code/modules/clothing/glasses/thermal.dm b/modular_RUtgmc/code/modules/clothing/glasses/thermal.dm new file mode 100644 index 0000000000000..d41bee0332c47 --- /dev/null +++ b/modular_RUtgmc/code/modules/clothing/glasses/thermal.dm @@ -0,0 +1,31 @@ +/obj/item/clothing/glasses/thermal/yautja + name = "bio-mask thermal" + desc = "A vision overlay generated by the Bio-Mask. Used to sense the heat of prey." + icon = 'modular_RUtgmc/icons/obj/hunter/pred_gear.dmi' + icon_state = "visor_thermal" + item_state = "visor_thermal" + item_icons = list( + slot_glasses_str = 'modular_RUtgmc/icons/mob/hunter/pred_gear.dmi' + ) + vision_flags = SEE_MOBS + flags_inventory = COVEREYES + toggleable = FALSE + +/obj/item/clothing/glasses/thermal/yautja/Initialize() + . = ..() + ADD_TRAIT(src, TRAIT_NODROP, TRAIT_GENERIC) + +/obj/item/clothing/glasses/thermal/yautja/dropped(mob/living/carbon/human/user) + if(istype(user) && user.glasses == src) + user.clear_fullscreen("machine", 5) + ..() + +/obj/item/clothing/glasses/thermal/yautja/equipped(mob/living/carbon/human/user, slot) + if(slot == SLOT_GLASSES) + user.overlay_fullscreen("machine", /atom/movable/screen/fullscreen/machine/pred) + ..() + +/obj/item/clothing/glasses/thermal/yautja/unequipped(mob/living/carbon/human/user, slot) + if(slot == SLOT_GLASSES) + user.clear_fullscreen("machine", 5) + ..() diff --git a/modular_RUtgmc/code/modules/clothing/modular_armor/attachments/modules.dm b/modular_RUtgmc/code/modules/clothing/modular_armor/attachments/modules.dm index b29b87c0ae2df..95d325769d7e3 100644 --- a/modular_RUtgmc/code/modules/clothing/modular_armor/attachments/modules.dm +++ b/modular_RUtgmc/code/modules/clothing/modular_armor/attachments/modules.dm @@ -73,6 +73,8 @@ for(var/mob/living/carbon/human/nearby_human AS in cheap_get_humans_near(operator, range)) if(nearby_human == operator) continue + if(HAS_TRAIT(nearby_human, TRAIT_LIGHT_STEP)) + continue if(!hostile_detected && (!operator.wear_id || !nearby_human.wear_id || nearby_human.wear_id.iff_signal != operator.wear_id.iff_signal)) hostile_detected = TRUE prepare_blip(nearby_human, nearby_human.wear_id?.iff_signal & operator.wear_id?.iff_signal ? MOTION_DETECTOR_FRIENDLY : MOTION_DETECTOR_HOSTILE) diff --git a/modular_RUtgmc/code/modules/cm_preds/_yaut_defines.dm b/modular_RUtgmc/code/modules/cm_preds/_yaut_defines.dm new file mode 100644 index 0000000000000..c6d31b5f812f7 --- /dev/null +++ b/modular_RUtgmc/code/modules/cm_preds/_yaut_defines.dm @@ -0,0 +1,22 @@ +//Gear select defines +#define YAUTJA_GEAR_GLAIVE "The Lumbering Glaive" +#define YAUTJA_GEAR_WHIP "The Rending Chain-Whip" +#define YAUTJA_GEAR_SWORD "The Piercing Hunting Sword" +#define YAUTJA_GEAR_SCYTHE "The Cleaving War-Scythe" +#define YAUTJA_GEAR_STICK "The Adaptive Combi-Stick" +#define YAUTJA_GEAR_SPEAR "The Nimble Spear" +#define YAUTJA_GEAR_SCIMS "The Fearsome Scimitars" +#define YAUTJA_GEAR_LAUNCHER "The Fleeting Spike Launcher" +#define YAUTJA_GEAR_PISTOL "The Swift Plasma Pistol" +#define YAUTJA_GEAR_DISC "The Purifying Smart-Disc" +#define YAUTJA_GEAR_FULL_ARMOR "The Formidable Plate Armor" +#define YAUTJA_GEAR_SHIELD "The Steadfast Shield" +#define YAUTJA_GEAR_DRONE "The Agile Drone" + +#define YAUTJA_GEAR_GLAIVE_ALT "The Imposing Glaive" +#define YAUTJA_GEAR_SCYTHE_ALT "The Ripping War-Scythe" + +#define YAUTJA_THRALL_GEAR_MACHETE "The Swift Machete" +#define YAUTJA_THRALL_GEAR_RAPIER "The Dancing Rapier" +#define YAUTJA_THRALL_GEAR_CLAYMORE "The Broad Claymore" +#define YAUTJA_THRALL_GEAR_FIREAXE "The Purposeful Fireaxe" diff --git a/modular_RUtgmc/code/modules/cm_preds/falcon.dm b/modular_RUtgmc/code/modules/cm_preds/falcon.dm new file mode 100644 index 0000000000000..5e8bcfe103115 --- /dev/null +++ b/modular_RUtgmc/code/modules/cm_preds/falcon.dm @@ -0,0 +1,117 @@ +/obj/item/clothing/falcon_drone + name = "falcon drone" + desc = "An agile drone used by Yautja to survey the hunting grounds." + icon = 'modular_RUtgmc/icons/obj/hunter/pred_gear.dmi' + icon_state = "falcon_drone" + item_icons = list( + slot_ear_str = 'modular_RUtgmc/icons/mob/hunter/pred_gear.dmi', + slot_head_str = 'modular_RUtgmc/icons/mob/hunter/pred_gear.dmi', + slot_l_hand_str = 'modular_RUtgmc/icons/mob/hunter/items_lefthand.dmi', + slot_r_hand_str = 'modular_RUtgmc/icons/mob/hunter/items_righthand.dmi' + ) + flags_equip_slot = ITEM_SLOT_HEAD|ITEM_SLOT_EARS + flags_item = ITEM_PREDATOR + +/obj/item/clothing/falcon_drone/attack_self(mob/user) + ..() + control_falcon_drone() + +/obj/item/clothing/falcon_drone/verb/control_falcon_drone() + set name = "Control Falcon Drone" + set desc = "Activates your falcon drone." + set category = "Yautja" + set src in usr + + var/mob/living/mob = usr + if(mob.stat || (mob.lying_angle && !mob.resting && !mob.IsSleeping()) || (mob.IsParalyzed() || mob.IsUnconscious())) + return + + var/mob/living/carbon/human/H = usr + if(!istype(H) || !HAS_TRAIT(usr, TRAIT_YAUTJA_TECH)) + to_chat(usr, span_warning("You do not know how to use this.")) + return + + if(!istype(H.gloves, /obj/item/clothing/gloves/yautja)) + to_chat(usr, span_warning("You need your bracers to control \the [src]!")) + return + + var/mob/hologram/falcon/hologram = new /mob/hologram/falcon(usr.loc, usr, src, H.gloves) + usr.transferItemToLoc(src, hologram) + +/mob/hologram/falcon + name = "falcon drone" + icon = 'modular_RUtgmc/icons/obj/hunter/pred_gear.dmi' + icon_state = "falcon_drone_active" + hud_possible = list(HUNTER_HUD) + pass_flags = HOVERING + var/obj/item/clothing/falcon_drone/parent_drone + var/obj/item/clothing/gloves/yautja/owned_bracers + desc = "An agile drone used by Yautja to survey the hunting grounds." + +/mob/hologram/falcon/Initialize(mapload, mob/M, obj/item/clothing/falcon_drone/drone, obj/item/clothing/gloves/yautja/bracers) + . = ..() + parent_drone = drone + owned_bracers = bracers + RegisterSignal(owned_bracers, COMSIG_ITEM_DROPPED, PROC_REF(handle_bracer_drop)) + if(M) + M.client.eye = src + M.client.perspective = EYE_PERSPECTIVE + med_hud_set_status() + add_to_all_mob_huds() + +/mob/hologram/falcon/add_to_all_mob_huds() + var/datum/atom_hud/hud = GLOB.huds[DATA_HUD_HUNTER] + hud.add_to_hud(src) + +/mob/hologram/falcon/remove_from_all_mob_huds() + var/datum/atom_hud/hud = GLOB.huds[DATA_HUD_HUNTER] + hud.remove_from_hud(src) + +/mob/hologram/falcon/med_hud_set_status() + if(!hud_list) + return + + var/image/holder = hud_list[HUNTER_HUD] + holder?.icon_state = "falcon_drone_active" + +/mob/hologram/falcon/Destroy() + if(parent_drone) + if(!linked_mob.equip_to_slot_if_possible(parent_drone, slot_ear_str, TRUE, FALSE, TRUE, TRUE, FALSE)) + linked_mob.put_in_hands(parent_drone) + linked_mob.client.eye = linked_mob + linked_mob.client.perspective = MOB_PERSPECTIVE + parent_drone = null + if(owned_bracers) + UnregisterSignal(owned_bracers, COMSIG_ITEM_DROPPED) + owned_bracers = null + + remove_from_all_mob_huds() + + return ..() + +/mob/hologram/falcon/ex_act() + new /obj/item/trash/falcon_drone(loc) + QDEL_NULL(parent_drone) + qdel(src) + +/mob/hologram/falcon/emp_act() + new /obj/item/trash/falcon_drone/emp(loc) + QDEL_NULL(parent_drone) + qdel(src) + +/mob/hologram/falcon/proc/handle_bracer_drop() + SIGNAL_HANDLER + + qdel(src) + +/obj/item/trash/falcon_drone + name = "destroyed falcon drone" + desc = "The wreckage of a Yautja drone." + icon = 'modular_RUtgmc/icons/obj/hunter/pred_gear.dmi' + icon_state = "falcon_drone_destroyed" + flags_item = ITEM_PREDATOR + +/obj/item/trash/falcon_drone/emp + name = "disabled falcon drone" + desc = "An intact Yautja drone. The internal electronics are completely fried." + icon_state = "falcon_drone_emped" diff --git a/modular_RUtgmc/code/modules/cm_preds/huntdata.dm b/modular_RUtgmc/code/modules/cm_preds/huntdata.dm new file mode 100644 index 0000000000000..2c784685296eb --- /dev/null +++ b/modular_RUtgmc/code/modules/cm_preds/huntdata.dm @@ -0,0 +1,159 @@ +/mob/var/datum/huntdata/hunter_data //Stores all information relating to Hunters for use with their HUD and other systems. +/mob/var/atom/last_damage_source = null +/mob/var/life_value = 1 +/mob/var/default_honor_value = 1 +/mob/var/life_kills_total = 0 + +/datum/huntdata + var/mob/living/carbon/owner + var/name = "Hunter Data" + + var/claimed_equipment = FALSE + + var/list/targets = list() + var/mob/living/carbon/targeted + var/automatic_target = FALSE + var/target_completed = FALSE + + //vars for Hunters targeting prey. + var/hunted = FALSE + var/mob/living/carbon/hunter //Target has their hunter variable linked to the Hunter. + var/mob/living/carbon/prey //Hunter has their prey variable linked to their target. + + + //Vars for Hunters marking someone as dishonorable. + var/dishonored = FALSE + var/mob/living/carbon/dishonored_set //The Hunter who marked the target as Dishonorable. + var/list/dishonored_targets = list() //The list of people a specific Hunter has marked as Dishonorable. + var/dishonored_reason //The Reason the target was set as dishonorable. + + var/honored = FALSE + var/mob/living/carbon/honored_set //The Hunter who marked the target as Honorable. + var/list/honored_targets = list() //The list of people a specific Hunter has marked as Honorable. + var/honored_reason //The Reason the target was set as Honorable. + + var/gear = FALSE + var/mob/living/carbon/gear_set //The Hunter who marked the target as having Hunter Gear. + var/list/gear_targets = list() //The list of people a specific Hunter has marked as having Hunter Gear. + + var/thralled = FALSE + var/mob/living/carbon/thralled_set //The Hunter who marked a target as their Thrall. + var/thralled_reason //The Reason the target was Thralled. + var/mob/living/carbon/thrall //The Thrall the Hunter marked. + +/datum/huntdata/New(mob/mob_ref) + name = "[mob_ref.real_name]'s Hunter Data" + owner = mob_ref + SShunting.hunter_datas += src + +/datum/huntdata/proc/complete_target(mob/user) + target_completed = TRUE + INVOKE_ASYNC(user.client, TYPE_PROC_REF(/client, add_honor), owner.life_kills_total + owner.life_value + 3) + hunter = null + hunted = FALSE + prey = null + owner.hud_set_hunter() + +/datum/huntdata/proc/death(mob/killer) + if(hunter == killer) + var/honor_value = max(owner.life_kills_total + owner.life_value, owner.default_honor_value) + if(src in hunter.hunter_data.targets) + honor_value += 3 + to_chat(hunter, span_yautjabold("You killed your Prey")) + INVOKE_ASYNC(hunter.client, TYPE_PROC_REF(/client, add_honor), honor_value + 1) + if(hunted) + hunter.hunter_data.prey = null + hunter = null + hunted = FALSE + else + if(hunter) + to_chat(hunter, span_yautjabold("Your Prey has been killed!")) + hunter = null + hunted = FALSE + hunter.hunter_data.prey = null + owner.hud_set_hunter() + if(targeted) + to_chat(targeted, span_yautjabold("Your Target has been killed!")) + automatic_target = FALSE + target_completed = FALSE + targeted.hunter_data.targets -= src + targeted = null + SShunting.hunter_datas += src + if(prey) + prey.hunter_data.hunter = null + prey.hunter_data.hunted = FALSE + prey = null + prey.hud_set_hunter() + +/datum/huntdata/proc/clean_data() + if(length(targets)) + for(var/datum/huntdata/data in targets) + if(target_completed) + continue + SShunting.hunter_datas += data + data.targeted = null + automatic_target = FALSE + targets -= data + + if(targeted && !target_completed) + automatic_target = FALSE + target_completed = FALSE + targeted.hunter_data.targets -= src + targeted = null + + if(dishonored) + if(dishonored_set) + dishonored_set.hunter_data.dishonored_targets -= owner + dishonored_set = null + dishonored_reason = null + dishonored = FALSE + for(var/mob/living/carbon/M in dishonored_targets) + M.hunter_data.dishonored_set = null + dishonored_targets -= M + + if(honored) + if(honored_set) + honored_set.hunter_data.honored_targets -= owner + honored_set = null + honored_reason = null + honored = FALSE + for(var/mob/living/carbon/M in honored_targets) + M.hunter_data.honored_set = null + honored_targets -= M + + if(gear) + if(gear_set) + gear_set.hunter_data.gear_targets -= owner + gear_set = null + gear = FALSE + for(var/mob/living/carbon/M in gear_targets) + M.hunter_data.gear_set = null + gear_targets -= M + + if(hunted) + if(hunter) + hunter.hunter_data.prey = null + to_chat(hunter, span_yautjabold("Your Prey has been utterly destroyed!")) + hunter = null + hunted = FALSE + + if(prey) + prey.hunter_data.hunter = null + prey.hunter_data.hunted = FALSE + prey = null + + if(thralled) + if(thralled_set) + thralled_set.hunter_data.thrall = null + to_chat(thralled_set, span_yautjabold("Your Thrall has been utterly destroyed!")) + message_all_yautja("[thralled_set.real_name]'s Thrall, [owner.real_name], has been utterly destroyed!") + thralled_set = null + thralled = FALSE + if(thrall) + thrall.hunter_data.thralled_set = null + thrall = null + + if(owner) + owner = null + + SShunting.hunter_datas -= src diff --git a/modular_RUtgmc/code/modules/cm_preds/keybinds.dm b/modular_RUtgmc/code/modules/cm_preds/keybinds.dm new file mode 100644 index 0000000000000..eef8979b87017 --- /dev/null +++ b/modular_RUtgmc/code/modules/cm_preds/keybinds.dm @@ -0,0 +1,82 @@ +/datum/keybinding/yautja + category = CATEGORY_YAUTJA + weight = WEIGHT_MOB + + +/datum/keybinding/yautja/mark_hunt + name = "mark_hunt" + full_name = "Mark For Hunt" + description = "Mark a target for the hunt." + keybind_signal = COMSIG_PRED_MARK_HUNT + +/datum/keybinding/yautja/mark_panel + name = "mark_panel" + full_name = "Mark Panel" + description = "Allows you to mark your prey." + keybind_signal = COMSIG_PRED_MARK_PANEL + +/datum/keybinding/yautja/zoom + name = "pred_zoom" + full_name = "Toggle Mask Zoom" + description = "Toggle your mask's zoom function." + keybind_signal = COMSIG_PRED_ZOOM + +/datum/keybinding/yautja/togglesight + name = "pred_togglesight" + full_name = "Toggle Mask Visors" + description = "Toggle your mask visor sights. You must only be wearing a type of Yautja visor for this to work." + keybind_signal = COMSIG_PRED_TOGGLESIGHT + +/datum/keybinding/yautja/combistick + name = "pred_combistick" + full_name = "Yank combi-stick" + description = "Yank on your combi-stick's chain, if it's in range. Otherwise... recover it yourself." + keybind_signal = COMSIG_PRED_COMBISTICK + +/datum/keybinding/yautja/smart_disc + name = "pred_smart_disc" + full_name = "Call Smart-Disc" + description = "Call back your smart-disc, if it's in range. If not you'll have to go retrieve it." + keybind_signal = COMSIG_PRED_SMART_DISC + +/datum/keybinding/yautja/translator + name = "pred_translator" + full_name = "Translator" + description = "Emit a message from your bracer to those nearby." + keybind_signal = COMSIG_PRED_TRANSLATOR + +/datum/keybinding/yautja/crystal + name = "pred_crystal" + full_name = "Create Stabilising Crystal" + description = "Create a focus crystal to energize your natural healing processes." + keybind_signal = COMSIG_PRED_CRYSTAL + +/datum/keybinding/yautja/wristblades + name = "pred_wristblades" + full_name = "Use Wrist Blades" + description = "Extend your wrist blades. They cannot be dropped, but can be retracted." + keybind_signal = COMSIG_PRED_WRISTBLADES + +/datum/keybinding/yautja/caster + name = "pred_caster" + full_name = "Use Plasma Caster" + description = "Activate your plasma caster. If it is dropped it will retract back into your armor." + keybind_signal = COMSIG_PRED_CASTER + +/datum/keybinding/yautja/cloack + name = "pred_cloack" + full_name = "Toggle Cloaking Device" + description = "Activate your suit's cloaking device. It will malfunction if the suit takes damage or gets excessively wet." + keybind_signal = COMSIG_PRED_CLOACK + +/datum/keybinding/yautja/sd + name = "pred_sd" + full_name = "Final Countdown (!)" + description = "Activate the explosive device implanted into your bracers. You have failed! Show some honor!" + keybind_signal = COMSIG_PRED_SD + +/datum/keybinding/yautja/sd_mode + name = "pred_sd_mode" + full_name = "Change Explosion Type" + description = "Changes your bracer explosion to either only gib you or be a big explosion." + keybind_signal = COMSIG_PRED_SD_MODE diff --git a/modular_RUtgmc/code/modules/cm_preds/landmakrs.dm b/modular_RUtgmc/code/modules/cm_preds/landmakrs.dm new file mode 100644 index 0000000000000..53cae8aba731f --- /dev/null +++ b/modular_RUtgmc/code/modules/cm_preds/landmakrs.dm @@ -0,0 +1,20 @@ +/obj/effect/landmark/yautja_teleport + name = "yautja_teleport" + +/obj/effect/landmark/yautja_teleport/Initialize(mapload, ...) + . = ..() + var/turf/T = get_turf(src) + if(is_mainship_level(z)) + GLOB.mainship_yautja_teleports += src + GLOB.mainship_yautja_desc[T.loc.name + " ([T.x], [T.y], [T.z])"] = src + else + GLOB.yautja_teleports += src + GLOB.yautja_teleport_descs[T.loc.name + " ([T.x], [T.y], [T.z])"] = src + +/obj/effect/landmark/yautja_teleport/Destroy() + var/turf/T = get_turf(src) + GLOB.mainship_yautja_teleports -= src + GLOB.yautja_teleports -= src + GLOB.mainship_yautja_desc -= T.loc.name + " ([T.x], [T.y], [T.z])" + GLOB.yautja_teleport_descs -= T.loc.name + " ([T.x], [T.y], [T.z])" + return ..() diff --git a/modular_RUtgmc/code/modules/cm_preds/predator_action.dm b/modular_RUtgmc/code/modules/cm_preds/predator_action.dm new file mode 100644 index 0000000000000..52133835ab67c --- /dev/null +++ b/modular_RUtgmc/code/modules/cm_preds/predator_action.dm @@ -0,0 +1,315 @@ +/datum/action/predator_action + action_icon = 'modular_RUtgmc/icons/mob/hunter/actions.dmi' + background_icon = 'modular_RUtgmc/icons/mob/hunter/actions.dmi' + background_icon_state = "template_pred" + +/datum/action/predator_action/can_use_action() + . = ..() + if(!.) + return FALSE + + var/mob/living/carbon/human/human = owner + if(!istype(human)) + return FALSE + if(human.stat || (human.lying_angle && !human.resting && !human.IsSleeping()) || (human.IsParalyzed() || human.IsUnconscious())) + return FALSE + return TRUE + +/datum/action/predator_action/mark_for_hunt + name = "Mark for Hunt" + desc = "Find your next hunting prey." + action_icon_state = "prey_choice" + keybinding_signals = list( + KEYBINDING_NORMAL = COMSIG_PRED_MARK_HUNT, + ) + +/datum/action/predator_action/mark_for_hunt/action_activate() + if(!can_use_action()) + return FALSE + + var/mob/living/carbon/human/human = owner + human.mark_for_hunt() + +/datum/action/predator_action/mark_panel + name = "Mark Panel" + desc = "Panel for marking anything be it prey, gear carrier, thralls or honorable warriors." + action_icon_state = "prey_hunt" + keybinding_signals = list( + KEYBINDING_NORMAL = COMSIG_PRED_MARK_PANEL, + ) + +/datum/action/predator_action/mark_panel/action_activate() + if(!can_use_action()) + return FALSE + + var/mob/living/carbon/human/human = owner + human.mark_panel() + +/datum/action/predator_action/mask/can_use_action() + . = ..() + if(!.) + return FALSE + var/mob/living/carbon/human/human = owner + var/obj/item/clothing/mask/gas/yautja/mask = human.wear_mask + if(!mask) + return FALSE + return TRUE + +/datum/action/predator_action/mask/zoom + name = "Toggle Mask Zoom" + desc = "Toggles the mask magnification lens to see further." + action_icon_state = "zoom" + keybinding_signals = list( + KEYBINDING_NORMAL = COMSIG_PRED_ZOOM, + ) + +/datum/action/predator_action/mask/zoom/action_activate() + if(!can_use_action()) + return FALSE + + var/mob/living/carbon/human/human = owner + var/obj/item/clothing/mask/gas/yautja/mask = human.wear_mask + playsound(mask, 'sound/effects/binoctarget.ogg', 10, 1) + mask.zoom(owner, 11, 12) + +/datum/action/predator_action/mask/togglesight + name = "Toggle Mask Visors" + desc = "Switch between optical imaging, thermal and meson visions." + action_icon_state = "eye" + keybinding_signals = list( + KEYBINDING_NORMAL = COMSIG_PRED_TOGGLESIGHT, + ) + + var/current_mode = 0 + +/datum/action/predator_action/mask/togglesight/action_activate() + if(!can_use_action()) + return FALSE + + var/mob/living/carbon/human/human = owner + var/obj/item/clothing/mask/gas/yautja/mask = human.wear_mask + mask.togglesight(owner) + current_mode = mask.current_goggles + update_button_icon() + +/datum/action/predator_action/mask/togglesight/update_button_icon() + if(!button) + return + button.name = name + button.desc = desc + if(action_icon && action_icon_state) + var/mutable_appearance/action_appearence = visual_references[VREF_MUTABLE_ACTION_STATE] + if(action_appearence.icon != action_icon || action_appearence.icon_state != "[action_icon_state]_[current_mode]") + button.cut_overlay(action_appearence) + action_appearence.icon = action_icon + // We need to update the reference since it becomes a new appearance for byond internally + action_appearence.icon_state = "[action_icon_state]_[current_mode]" + visual_references[VREF_MUTABLE_ACTION_STATE] = action_appearence + button.add_overlay(action_appearence) + if(background_icon_state != button.icon_state) + button.icon_state = background_icon_state + handle_button_status_visuals() + return TRUE + +/datum/action/predator_action/bracer + var/power_to_drain = 0 + +/datum/action/predator_action/bracer/can_use_action() + . = ..() + if(!.) + return FALSE + var/mob/living/carbon/human/human = owner + var/obj/item/clothing/gloves/yautja/bracer = human.gloves + if(!bracer) + return FALSE + if(bracer?.charge < power_to_drain) + return FALSE + return TRUE + +/datum/action/predator_action/bracer/pred_buy + name = "Claim Equipment" + desc = "Choose equipment for your hunt." + action_icon_state = "equipment_selection" + +/datum/action/predator_action/bracer/pred_buy/action_activate() + if(!can_use_action()) + return FALSE + + var/mob/living/carbon/human/human = owner + var/obj/item/clothing/gloves/yautja/bracer = human.gloves + bracer.buy_gear(owner) + +/datum/action/predator_action/bracer/yank_combistick + name = "Yank combi-stick" + desc = "Pull combi-stick chain to return it. Requires bracer linking before usage." + action_icon_state = "combistick" + keybinding_signals = list( + KEYBINDING_NORMAL = COMSIG_PRED_COMBISTICK, + ) + +/datum/action/predator_action/bracer/yank_combistick/can_use_action() + . = ..() + if(.) + var/mob/living/carbon/human/human = owner + var/obj/item/clothing/gloves/yautja/bracer = human.gloves + if(bracer?.combistick) + return TRUE + return FALSE + +/datum/action/predator_action/bracer/yank_combistick/action_activate() + if(!can_use_action()) + return FALSE + + var/mob/living/carbon/human/human = owner + var/obj/item/clothing/gloves/yautja/bracer = human.gloves + bracer.call_combi_internal(owner) + +/datum/action/predator_action/bracer/call_disc + name = "Call Smart-Disc" + desc = "Calls back the smart disk into your hand. Requires bracer linking before usage." + action_icon_state = "disc" + keybinding_signals = list( + KEYBINDING_NORMAL = COMSIG_PRED_SMART_DISC, + ) + +/datum/action/predator_action/bracer/call_disc/can_use_action() + . = ..() + if(.) + var/mob/living/carbon/human/human = owner + var/obj/item/clothing/gloves/yautja/bracer = human.gloves + if(length(bracer?.discs)) + return TRUE + return FALSE + +/datum/action/predator_action/bracer/call_disc/action_activate() + if(!can_use_action()) + return FALSE + + var/mob/living/carbon/human/human = owner + var/obj/item/clothing/gloves/yautja/bracer = human.gloves + bracer.call_disc_internal(owner) + +/datum/action/predator_action/bracer/translate + name = "Translator" + desc = "Translates your speech to any known language." + action_icon_state = "translator" + keybinding_signals = list( + KEYBINDING_NORMAL = COMSIG_PRED_TRANSLATOR, + ) + +/datum/action/predator_action/bracer/translate/action_activate() + if(!can_use_action()) + return FALSE + + var/mob/living/carbon/human/human = owner + var/obj/item/clothing/gloves/yautja/bracer = human.gloves + bracer.translate_internal(owner) + +/datum/action/predator_action/bracer/injectors + name = "Create Stabilising Crystal" + desc = "Synthesize a thwei filled healing crystal, do not use more than one in a row." + action_icon_state = "crystal" + power_to_drain = 1000 + keybinding_signals = list( + KEYBINDING_NORMAL = COMSIG_PRED_CRYSTAL, + ) + +/datum/action/predator_action/bracer/injectors/can_use_action() + . = ..() + if(.) + var/mob/living/carbon/human/human = owner + var/obj/item/clothing/gloves/yautja/bracer = human.gloves + if(!bracer?.inject_timer) + return TRUE + return FALSE + +/datum/action/predator_action/bracer/injectors/action_activate() + if(!can_use_action()) + return FALSE + + var/mob/living/carbon/human/human = owner + var/obj/item/clothing/gloves/yautja/bracer = human.gloves + bracer.injectors_internal(owner, power_to_drain = power_to_drain) + +/datum/action/predator_action/bracer/wristblades + name = "Use Wrist Blades" + desc = "Activates integrated razorsharp blades from your forearm." + action_icon_state = "blades" + action_type = ACTION_SELECT + power_to_drain = 50 + keybinding_signals = list( + KEYBINDING_NORMAL = COMSIG_PRED_WRISTBLADES, + ) + +/datum/action/predator_action/bracer/wristblades/action_activate() + if(!can_use_action()) + return FALSE + + var/mob/living/carbon/human/human = owner + var/obj/item/clothing/gloves/yautja/bracer = human.gloves + bracer.wristblades_internal(owner, power_to_drain = power_to_drain) + set_toggle(bracer.wristblades_deployed) + +/datum/action/predator_action/bracer/caster + name = "Use Plasma Caster" + desc = "Activates your shoulder mounted plasma caster, use middle mouse button on target to auto aim plasma caster on it." + action_icon_state = "plasmacannon" + action_type = ACTION_SELECT + power_to_drain = 50 + keybinding_signals = list( + KEYBINDING_NORMAL = COMSIG_PRED_CASTER, + ) + +/datum/action/predator_action/bracer/caster/action_activate() + if(!can_use_action()) + return FALSE + + var/mob/living/carbon/human/human = owner + var/obj/item/clothing/gloves/yautja/bracer = human.gloves + bracer.caster_internal(owner) + set_toggle(bracer.caster_deployed) + +/datum/action/predator_action/bracer/cloaker + name = "Toggle Cloaking Device" + desc = "Turn on your stealth cloaking device, turns off after teleporting." + action_icon_state = "cloack" + action_type = ACTION_SELECT + keybinding_signals = list( + KEYBINDING_NORMAL = COMSIG_PRED_CLOACK, + ) + +/datum/action/predator_action/bracer/cloaker/action_activate() + if(!can_use_action()) + return FALSE + + var/mob/living/carbon/human/human = owner + var/obj/item/clothing/gloves/yautja/bracer = human.gloves + bracer.cloaker_internal(owner) + +/datum/action/predator_action/bracer/activate_suicide + name = "Final Countdown (!)" + desc = "Self destruct sequence, size of explosion can be changed on RMB." + action_icon_state = "selfdestruct" + keybinding_signals = list( + KEYBINDING_NORMAL = COMSIG_PRED_SD, + KEYBINDING_ALTERNATE = COMSIG_PRED_SD_MODE, + ) + +/datum/action/predator_action/bracer/activate_suicide/action_activate() + if(!can_use_action()) + return FALSE + + var/mob/living/carbon/human/human = owner + var/obj/item/clothing/gloves/yautja/bracer = human.gloves + bracer.activate_suicide_internal(owner) + +/datum/action/predator_action/bracer/activate_suicide/alternate_action_activate() + set waitfor = FALSE + + if(!can_use_action()) + return FALSE + + var/mob/living/carbon/human/human = owner + var/obj/item/clothing/gloves/yautja/bracer = human.gloves + + INVOKE_ASYNC(bracer, TYPE_PROC_REF(/obj/item/clothing/gloves/yautja, change_explosion_type), owner) diff --git a/modular_RUtgmc/code/modules/cm_preds/smartdisc.dm b/modular_RUtgmc/code/modules/cm_preds/smartdisc.dm new file mode 100644 index 0000000000000..4e96a7a195c34 --- /dev/null +++ b/modular_RUtgmc/code/modules/cm_preds/smartdisc.dm @@ -0,0 +1,278 @@ +/obj/item/explosive/grenade/spawnergrenade/smartdisc + name = "smart-disc" + spawner_type = /mob/living/simple_animal/hostile/smartdisc + deliveryamt = 1 + desc = "A strange piece of alien technology. It has many jagged, whirring blades and bizarre writing." + flags_item = ITEM_PREDATOR + icon = 'modular_RUtgmc/icons/obj/hunter/pred_gear.dmi' + item_icons = list( + slot_back_str = 'modular_RUtgmc/icons/mob/hunter/pred_gear.dmi', + slot_l_hand_str = 'modular_RUtgmc/icons/mob/hunter/items_lefthand.dmi', + slot_r_hand_str = 'modular_RUtgmc/icons/mob/hunter/items_righthand.dmi' + ) + icon_state = "disc" + item_state = "pred_disc" + w_class = WEIGHT_CLASS_TINY + det_time = 30 + resistance_flags = UNACIDABLE + embedding = list("embed_chance" = 0, "embedded_fall_chance" = 0) + + force = 15 + throwforce = 35 + throw_speed = 1 + + G_hit_sound = null + G_throw_sound = 'modular_RUtgmc/sound/effects/smartdisk_throw.ogg' + hitsound = 'modular_RUtgmc/sound/effects/smartdisk_hit.ogg' + + var/mob/living/simple_animal/hostile/smartdisc/spawned_item + +/obj/item/explosive/grenade/spawnergrenade/smartdisc/afterattack(atom/A, mob/user, proximity, params) + if(istype(A, /obj/item/clothing/gloves/yautja)) + var/obj/item/clothing/gloves/yautja/bracer = A + if(length(bracer.discs) < bracer.max_disc_cap) + if(src in bracer.discs) + to_chat(user, span_warning("You unlink [bracer] and [src].")) + playsound(user.loc, 'modular_RUtgmc/sound/items/pred_bracer.ogg', 75, 1) + bracer.discs -= src + else + bracer.discs += src + to_chat(user, span_warning("You link [src] to [bracer].")) + playsound(user.loc, 'modular_RUtgmc/sound/items/pred_bracer.ogg', 75, 1) + else + if(src in bracer.discs) + to_chat(user, span_warning("You unlink [bracer] and [src].")) + playsound(user.loc, 'modular_RUtgmc/sound/items/pred_bracer.ogg', 75, 1) + bracer.discs -= src + else + to_chat(user, span_warning("Your limit is [bracer.max_disc_cap], unlink before disc, to add another one.")) + bracer.owner.update_action_buttons() + ..() + +/obj/item/explosive/grenade/spawnergrenade/smartdisc/throw_at(atom/target, range, speed, thrower, spin, flying) + ..() + var/mob/user = usr + if(!active && isyautja(user) && (icon_state == initial(icon_state))) + boomerang(user) + +/obj/item/explosive/grenade/spawnergrenade/smartdisc/proc/boomerang(mob/user) + active = TRUE + icon_state = initial(icon_state) + "_active" + sleep(1 SECONDS) + var/mob/living/L = find_target(user) + if(L) + throw_at(L.loc, 4, 6.67, usr) + sleep(1 SECONDS) + throw_at(usr, 12, 1, usr) + addtimer(CALLBACK(src, PROC_REF(clear_boomerang)), 1 SECONDS) + playsound(src, 'modular_RUtgmc/sound/effects/smartdisk_throw.ogg', 25) + +/obj/item/explosive/grenade/spawnergrenade/smartdisc/proc/clear_boomerang() + active = FALSE + icon_state = initial(icon_state) + +/obj/item/explosive/grenade/spawnergrenade/smartdisc/proc/find_target(mob/user) + var/atom/T = null + for(var/mob/living/A in listtargets(4)) + if(A == src) + continue + if(isliving(A)) + var/mob/living/L = A + if(L.faction == user.faction) + continue + else if(isyautja(L)) + continue + else if (L.stat == DEAD) + continue + else + T = L + break + return T + +/obj/item/explosive/grenade/spawnergrenade/smartdisc/proc/listtargets(dist = 3) + var/list/L = hearers(src, dist) + return L + +/obj/item/explosive/grenade/spawnergrenade/smartdisc/attack_self(mob/user) + ..() + + if(active) + return + + if(!isyautja(user)) + if(prob(75)) + to_chat(user, span_warning("You fiddle with the disc, but nothing happens. Try again maybe?")) + return + to_chat(user, span_warning("You activate the smart-disc and it whirrs to life!")) + activate(user) + add_fingerprint(user) + var/mob/living/carbon/C = user + if(istype(C) && !C.in_throw_mode) + C.throw_mode_on() + +/obj/item/explosive/grenade/spawnergrenade/smartdisc/activate(mob/user) + if(active) + return + + if(user) + log_attack("[key_name(user)] primed \a [src] in [get_area(user)] ([user.loc.x],[user.loc.y],[user.loc.z]).", user.loc.x, user.loc.y, user.loc.z) + + icon_state = initial(icon_state) + "_active" + active = TRUE + playsound(loc, 'sound/items/countdown.ogg', 25, 1) + update_icon() + spawn(det_time) + prime() + return + +/obj/item/explosive/grenade/spawnergrenade/smartdisc/prime() + if(spawner_type && deliveryamt) + // Make a quick flash + var/turf/T = get_turf(src) + var/mob/living/simple_animal/hostile/smartdisc/x = new spawner_type + if(istype(loc, /mob)) + var/mob/handler = loc + handler.temporarilyRemoveItemFromInventory(src, TRUE) + x.forceMove(T) + forceMove(x) + spawned_item = x + x.spawner_item = src + return + +/obj/item/explosive/grenade/spawnergrenade/smartdisc/throw_impact(atom/hit_atom) + if(isyautja(hit_atom)) + var/mob/living/carbon/human/H = hit_atom + if(H.put_in_hands(src)) + clear_boomerang() + hit_atom.visible_message("[hit_atom] expertly catches [src] out of the air.","You catch [src] easily.") + throwing = FALSE + return TURF_ENTER_ALREADY_MOVED + return FALSE + ..() + +/mob/living/simple_animal/hostile/smartdisc + name = "smart-disc" + desc = "A furious, whirling array of blades and alien technology." + icon = 'modular_RUtgmc/icons/obj/hunter/pred_gear.dmi' + icon_state = "disc_active" + icon_living = "disc_active" + icon_dead = "disc" + icon_gib = "disc" + speak_chance = 0 + turns_per_move = 1 + response_help = "stares at the" + response_disarm = "bats aside the" + response_harm = "hits the" + speed = -2 + maxHealth = 60 + health = 60 + attack_same = 0 + density = FALSE + mob_size = MOB_SIZE_SMALL + + obj_damage = 50 + melee_damage = 25 + harm_intent_damage = 10 + attacktext = "slices" + attack_sound = 'modular_RUtgmc/sound/effects/smartdisk_hit.ogg' + + + faction = FACTION_YAUTJA + + var/obj/item/explosive/grenade/spawnergrenade/smartdisc/spawner_item + + var/lifetime = 8 //About 15 seconds. + var/time_idle = 0 + + +/mob/living/simple_animal/hostile/smartdisc/Process_Spacemove(check_drift = 0) + return 1 + + +/mob/living/simple_animal/hostile/smartdisc/bullet_act(obj/projectile/proj) + . = ..() + + if(prob(60 - proj.damage)) + return 0 + + if(!proj || proj.damage <= 0) + return 0 + + apply_damage(proj.damage, BRUTE) + return 1 + +/mob/living/simple_animal/hostile/smartdisc/Life() + . = ..() + lifetime-- + if(lifetime <= 0 || time_idle > 3) + visible_message("\The [src] stops whirring and spins out onto the floor.") + drop_real_disc() + qdel(src) + return + +/mob/living/simple_animal/hostile/smartdisc/death() + visible_message("\The [src] stops whirring and spins out onto the floor.") + drop_real_disc() + ..() + spawn(1) + if(src) + qdel(src) + +/mob/living/simple_animal/hostile/smartdisc/proc/drop_real_disc() + spawner_item.forceMove(loc) + spawner_item.icon_state = initial(spawner_item.icon_state) + spawner_item.overlays.Cut() + spawner_item.active = FALSE + // don't make GC cry + spawner_item.spawned_item = null + spawner_item = null + qdel(src) + +/mob/living/simple_animal/hostile/smartdisc/gib() + visible_message("\The [src] explodes!") + ..() + spawn(1) + if(src) + qdel(src) + +/mob/living/simple_animal/hostile/smartdisc/FindTarget() + var/atom/T = null + stop_automated_movement = 0 + + for(var/atom/A in ListTargets(5)) + if(A == src) + continue + + if(isliving(A)) + var/mob/living/L = A + if(L.faction == faction) + continue + else if(L in friends) + continue + else if(isyautja(L)) + continue + else if (L.stat == DEAD) + continue + else + if(!L.stat) + T = L + break + GiveTarget(T) + return T + +/mob/living/simple_animal/hostile/smartdisc/ListTargets(dist = 7) + var/list/L = hearers(src, dist) + return L + +/mob/living/simple_animal/hostile/smartdisc/AttackingTarget() + if(QDELETED(target)) return + if(!Adjacent(target)) return + if(isliving(target)) + var/mob/living/L = target + L.attack_animal(src) + if(prob(5)) + L.apply_effect(3, WEAKEN) + L.visible_message(span_danger("\The [src] viciously slashes at \the [L]!")) + log_attack("[key_name(L)] was knocked down by [src]") + log_attack("[key_name(L)] was attacked by [src]") + return L diff --git a/modular_RUtgmc/code/modules/cm_preds/thrall_items.dm b/modular_RUtgmc/code/modules/cm_preds/thrall_items.dm new file mode 100644 index 0000000000000..dce8ed6765d29 --- /dev/null +++ b/modular_RUtgmc/code/modules/cm_preds/thrall_items.dm @@ -0,0 +1,60 @@ +/obj/item/clothing/suit/armor/yautja/thrall + name = "alien armor" + desc = "Armor made from scraps of cloth and a strange alloy. It feels cold with an alien weight. It has been adapted to carry both human and alien melee weaponry." + + icon = 'modular_RUtgmc/icons/obj/hunter/thrall_gear.dmi' + icon_state = "chest1_cloth" + item_state = "chest1_cloth" + item_icons = list( + slot_wear_suit_str = 'modular_RUtgmc/icons/mob/hunter/thrall_gear.dmi' + ) + thrall = TRUE + + allowed = list( + /obj/item/weapon/gun/energy/yautja, + /obj/item/weapon, + ) + +/obj/item/clothing/suit/armor/yautja/thrall/New(mapload, armor_area = pick("shoulders", "chest", "mix"), armor_number = rand(1,3), armor_material = pick("cloth", "bare")) + if(armor_number > 3) + armor_number = 1 + if(armor_number) + icon_state = "[armor_area][armor_number]_[armor_material]" + LAZYSET(item_state_slots, slot_wear_suit_str, "[armor_area][armor_number]_[armor_material]") + ..() + +/obj/item/clothing/shoes/marine/yautja/thrall + name = "alien greaves" + desc = "Greaves made from scraps of cloth and a strange alloy. They feel cold with an alien weight. They have been adapted for compatibility with human equipment." + + icon = 'modular_RUtgmc/icons/obj/hunter/thrall_gear.dmi' + icon_state = "greaves1_cloth" + item_icons = list( + slot_shoes_str = 'modular_RUtgmc/icons/mob/hunter/thrall_gear.dmi' + ) + thrall = TRUE + +/obj/item/clothing/shoes/marine/yautja/thrall/New(mapload, greaves_number = 1, armor_material = pick("cloth", "bare")) + if(greaves_number > 1) + greaves_number = 1 + if(greaves_number) + icon_state = "greaves[greaves_number]_[armor_material]" + LAZYSET(item_state_slots, slot_wear_suit_str, "greaves[greaves_number]_[armor_material]") + ..() + +/obj/item/clothing/under/chainshirt/thrall + name = "alien mesh suit" + color = "#b85440" + desc = "A strange alloy weave in the form of a vest. It feels cold with an alien weight. It has been adapted for human physiology." + +/obj/item/storage/box/bracer + name = "alien box" + desc = "A strange, runed box." + color = "#68423b" + icon = 'modular_RUtgmc/icons/obj/structures/closet.dmi' + icon_state = "pred_coffin" + foldable = FALSE + +/obj/item/storage/box/bracer/Initialize() + . = ..() + new /obj/item/clothing/gloves/yautja/thrall(src) diff --git a/modular_RUtgmc/code/modules/cm_preds/thrall_procs.dm b/modular_RUtgmc/code/modules/cm_preds/thrall_procs.dm new file mode 100644 index 0000000000000..e4a5f89323954 --- /dev/null +++ b/modular_RUtgmc/code/modules/cm_preds/thrall_procs.dm @@ -0,0 +1,186 @@ +//Claim gear, same as the Hunter's get. +/obj/item/clothing/gloves/yautja/thrall/buy_gear(mob/living/carbon/human/wearer) + if(wearer.gloves != src) + to_chat(wearer, span_warning("You need to be wearing your thrall bracers to do this.")) + return + + if(wearer.hunter_data.claimed_equipment) + to_chat(wearer, span_warning("You've already claimed your equipment.")) + return + + if(wearer.stat || (wearer.lying_angle && !wearer.resting && !wearer.IsSleeping()) || (wearer.IsParalyzed() || wearer.IsUnconscious()) || wearer.lying_angle || wearer.buckled) + to_chat(wearer, span_warning("You're not able to do that right now.")) + return + + if(!istype(get_area(wearer), /area/yautja)) + to_chat(wearer, span_warning("Not here. Only on the ship.")) + return + + var/sure = alert("An array of powerful weapons are displayed to you. Pick your gear carefully. If you cancel at any point, you will not claim your equipment.","Sure?","Begin the Hunt","No, not now") + if(sure == "Begin the Hunt") + var/list/hmelee = list(YAUTJA_THRALL_GEAR_MACHETE = image(icon = 'icons/obj/items/weapons.dmi', icon_state = "machete"), YAUTJA_THRALL_GEAR_RAPIER = image(icon = 'icons/obj/items/weapons.dmi', icon_state = "officer_sword"), YAUTJA_THRALL_GEAR_CLAYMORE = image(icon = 'icons/obj/items/weapons.dmi', icon_state = "mercsword"), YAUTJA_THRALL_GEAR_FIREAXE = image(icon = 'icons/obj/items/weapons.dmi', icon_state = "fireaxe")) + var/list/ymelee = list(YAUTJA_GEAR_GLAIVE = image(icon = 'modular_RUtgmc/icons/obj/hunter/pred_gear.dmi', icon_state = "glaive"), YAUTJA_GEAR_WHIP = image(icon = 'modular_RUtgmc/icons/obj/hunter/pred_gear.dmi', icon_state = "whip"), YAUTJA_GEAR_SWORD = image(icon = 'modular_RUtgmc/icons/obj/hunter/pred_gear.dmi', icon_state = "clansword"), YAUTJA_GEAR_SCYTHE = image(icon = 'modular_RUtgmc/icons/obj/hunter/pred_gear.dmi', icon_state = "predscythe"), YAUTJA_GEAR_STICK = image(icon = 'modular_RUtgmc/icons/obj/hunter/pred_gear.dmi', icon_state = "combistick"), YAUTJA_GEAR_SPEAR = image(icon = 'modular_RUtgmc/icons/obj/hunter/pred_gear.dmi', icon_state = "spearhunter")) + + var/main_weapon + var/type = alert("Do you plan on embracing alien weaponry, or sticking to your human roots?", "Human or Alien?", "Once Human, Always Human", "Let's try Alien") + if(type == "Once Human, Always Human") + main_weapon = show_radial_menu(wearer, wearer, hmelee) + else + main_weapon = show_radial_menu(wearer, wearer, ymelee) + if(!main_weapon) + return //We don't want them to cancel out then get nothing. + + if(wearer.gloves != src) + to_chat(wearer, span_warning("You need to be wearing your thrall bracers to do this.")) + return + + if(wearer.hunter_data.claimed_equipment) + to_chat(src, span_warning("You've already claimed your equipment.")) + return + + var/obj/item/spawned_weapon + switch(main_weapon) + if(YAUTJA_GEAR_GLAIVE) + spawned_weapon = new /obj/item/weapon/twohanded/yautja/glaive(wearer.loc) + if(YAUTJA_GEAR_SPEAR) + spawned_weapon = new /obj/item/weapon/twohanded/yautja/spear(wearer.loc) + if(YAUTJA_GEAR_WHIP) + spawned_weapon = new /obj/item/weapon/yautja/chain(wearer.loc) + if(YAUTJA_GEAR_SWORD) + spawned_weapon = new /obj/item/weapon/yautja/sword(wearer.loc) + if(YAUTJA_GEAR_SCYTHE) + spawned_weapon = new /obj/item/weapon/yautja/scythe(wearer.loc) + if(YAUTJA_GEAR_STICK) + spawned_weapon = new /obj/item/weapon/yautja/combistick(wearer.loc) + if(YAUTJA_THRALL_GEAR_MACHETE) + spawned_weapon = new /obj/item/weapon/claymore/mercsword/machete(wearer.loc) + if(YAUTJA_THRALL_GEAR_RAPIER) + spawned_weapon = new /obj/item/weapon/claymore/mercsword/ceremonial(wearer.loc) + if(YAUTJA_THRALL_GEAR_CLAYMORE) + spawned_weapon = new /obj/item/weapon/claymore(wearer.loc) + if(YAUTJA_THRALL_GEAR_FIREAXE) + spawned_weapon = new /obj/item/weapon/twohanded/fireaxe(wearer.loc) + + if(istype(spawned_weapon, /obj/item/weapon/yautja)) + var/obj/item/weapon/yautja/yautja_melee = spawned_weapon + yautja_melee.human_adapted = TRUE + else if(istype(spawned_weapon, /obj/item/weapon/twohanded/yautja)) + var/obj/item/weapon/twohanded/yautja/yautja_melee = spawned_weapon + yautja_melee.human_adapted = TRUE + spawned_weapon.desc += " It looks like this one has been modified for human use." + + wearer.hunter_data.claimed_equipment = TRUE + + claim_equipment.remove_action(wearer) + new /obj/item/clothing/suit/armor/yautja/thrall(wearer.loc) + new /obj/item/clothing/shoes/marine/yautja/thrall(wearer.loc) + new /obj/item/clothing/under/chainshirt/thrall(wearer.loc) + new /obj/item/clothing/mask/gas/yautja/thrall(wearer.loc) + + +//Link to thrall bracer, enabling most of it's abilities +/obj/item/clothing/gloves/yautja/hunter/verb/link_bracer() + set name = "Link Thrall Bracer" + set desc = "Link your bracer to that of your thrall." + set category = "Yautja" + set src in usr + + var/mob/living/carbon/human/user = usr + if(!istype(user)) + return + if(!user.hunter_data) + to_chat(user, span_warning("ERROR: No hunter_data detected.")) + return + + if(linked_bracer) + to_chat(user, span_yautjabold("[icon2html(src)] \The [src] beeps: Link is already established!")) + return + + if(user.gloves != src) + to_chat(user, span_warning("You are not wearing your bracer!")) + return + else if(!owner || user != owner) + to_chat(user, span_yautjabold("[icon2html(src)] \The [src] beeps: Wrong user detected!")) + return + + var/mob/living/carbon/human/T = user.hunter_data.thrall + if(!T) + to_chat(user, span_warning("You do not have a thrall to link to!")) + return + else if(!istype(T.gloves, /obj/item/clothing/gloves/yautja/thrall)) + to_chat(user, span_yautjabold("[icon2html(src)] \The [src] beeps: Your thrall is not wearing a bracer!")) + return + else + var/obj/item/clothing/gloves/yautja/thrall/thrall_gloves = T.gloves + + linked_bracer = thrall_gloves + thrall_gloves.linked_bracer = src + thrall_gloves.owner = T + if(!T.hunter_data.claimed_equipment) + thrall_gloves.claim_equipment.give_action(T) + + to_chat(user, span_yautjabold("[icon2html(src)] \The [src] beeps: Your bracer is now linked to your thrall.")) + if(notification_sound) + playsound(loc, 'modular_RUtgmc/sound/items/pred_bracer.ogg', 75, 1) + + to_chat(T, span_warning("\The [thrall_gloves] locks around your wrist with a sharp click.")) + to_chat(T, span_yautjabold("[icon2html(thrall_gloves)] \The [thrall_gloves] beeps: Your master has linked their bracer to yours.")) + if(thrall_gloves.notification_sound) + playsound(thrall_gloves.loc, 'modular_RUtgmc/sound/items/pred_bracer.ogg', 75, 1) + +// Message thrall or master +/obj/item/clothing/gloves/yautja/verb/bracer_message() + set name = "Transmit Message" + set desc = "For direct communication between thrall and master." + set src in usr + + var/mob/living/carbon/human/messenger = usr + if(!istype(messenger)) + return + + var/mob/living/carbon/human/receiver + var/messenger_title = "thrall" + var/receiver_title = "master" + if(messenger.hunter_data.thralled) + receiver = messenger.hunter_data.thralled_set + else + receiver = messenger.hunter_data.thrall + messenger_title = "master" + receiver_title = "thrall" + + if(!istype(receiver)) + to_chat(messenger, span_warning("You have no one to message!")) + return + if(!istype(receiver.gloves, /obj/item/clothing/gloves/yautja)) + to_chat(messenger, span_warning("Your [receiver_title] isn't wearing their bracer!")) + return + + var/message = sanitize(input(messenger, "Enter the message you want to send:", "Send Message") as null|text) + if(!message) + return + + if(!istype(receiver)) + to_chat(messenger, span_warning("You have no one to message!")) + return + var/obj/item/clothing/gloves/yautja/receiver_gloves = receiver.gloves + if(!istype(receiver_gloves)) + to_chat(messenger, span_warning("Your [receiver_title] isn't wearing their bracer!")) + return + + to_chat(receiver, span_yautjabold("\The [receiver_gloves] beeps with a message from your [messenger_title]: [message]")) + to_chat(messenger, span_yautjabold("\The [src] beeps: You have sent '[message]' to your [receiver_title].")) + + if(notification_sound) + playsound(loc, 'modular_RUtgmc/sound/items/pred_bracer.ogg', 75, 1) + if(receiver_gloves.notification_sound) + playsound(receiver_gloves.loc, 'modular_RUtgmc/sound/items/pred_bracer.ogg', 75, 1) + + log_game("HUNTER: [key_name(messenger)] has sent [key_name(receiver)] the message '[message]' via bracer") + +/obj/item/clothing/gloves/yautja/hunter/bracer_message() + set category = "Yautja" + . = ..() + +/obj/item/clothing/gloves/yautja/thrall/bracer_message() + set category = "Thrall" + . = ..() diff --git a/modular_RUtgmc/code/modules/cm_preds/yaut_bracers.dm b/modular_RUtgmc/code/modules/cm_preds/yaut_bracers.dm new file mode 100644 index 0000000000000..a28bc9bfda759 --- /dev/null +++ b/modular_RUtgmc/code/modules/cm_preds/yaut_bracers.dm @@ -0,0 +1,1314 @@ +/obj/item/clothing/gloves/yautja + name = "ancient alien bracers" + desc = "A pair of strange, alien bracers." + + icon = 'modular_RUtgmc/icons/obj/hunter/pred_gear.dmi' + icon_state = "bracer" + item_icons = list( + slot_gloves_str = 'modular_RUtgmc/icons/mob/hunter/pred_gear.dmi' + ) + + siemens_coefficient = 0 + permeability_coefficient = 0.05 + flags_item = ITEM_PREDATOR + flags_cold_protection = HANDS + flags_heat_protection = HANDS + flags_armor_protection = HANDS + min_cold_protection_temperature = GLOVES_MIN_COLD_PROTECTION_TEMPERATURE + max_heat_protection_temperature = GLOVES_MAX_HEAT_PROTECTION_TEMPERATURE + resistance_flags = UNACIDABLE + w_class = WEIGHT_CLASS_GIGANTIC + + soft_armor = list(MELEE = 20, BULLET = 20, LASER = 20, ENERGY = 20, BOMB = 25, BIO = 20, FIRE = 20, ACID = 20) + + var/notification_sound = TRUE // Whether the bracer pings when a message comes or not + var/charge = 1500 + var/charge_max = 1500 + /// The amount charged per process + var/charge_rate = 30 + /// Cooldown on draining power from APC + var/charge_cooldown = 3 MINUTES + var/cloaked = 0 + var/cloak_timer = 0 + var/cloak_malfunction = 0 + /// Determines the alpha level of the cloaking device. + var/cloak_alpha = 50 + /// If TRUE will change the mob invisibility level, providing 100% invisibility. Exclusively for events. + var/true_cloak = FALSE + + var/translator_type = "Modern" + var/exploding = 0 + var/inject_timer = 0 + var/healing_capsule_timer = 0 + var/explosion_type = 1 //0 is BIG explosion, 1 ONLY gibs the user. + + var/caster_deployed = FALSE + var/obj/item/weapon/gun/energy/yautja/plasma_caster/caster + + var/wristblades_deployed = FALSE + var/obj/item/weapon/wristblades/left_wristblades + var/obj/item/weapon/wristblades/right_wristblades + + var/obj/item/weapon/yautja/combistick/combistick + + var/disc_timer = 0 + var/max_disc_cap = 2 + var/list/obj/item/explosive/grenade/spawnergrenade/smartdisc/discs = list() + + var/mob/living/carbon/human/real_owner //Pred spawned on, or thrall given to. + var/mob/living/carbon/human/owner + var/obj/item/clothing/gloves/yautja/linked_bracer //Bracer linked to this one (thrall or mentor). + var/obj/item/card/id/bracer_chip/embedded_id + + var/datum/action/predator_action/bracer/pred_buy/claim_equipment = new + + var/datum/action/predator_action/bracer/cloaker/action_cloaker + var/datum/action/predator_action/bracer/caster/action_caster + var/datum/action/predator_action/bracer/wristblades/action_wristblades + + var/list/actions_to_add = list() + + /// What minimap icon this bracer should have + var/minimap_icon = "predator" + COOLDOWN_DECLARE(bracer_recharge) + +/obj/item/clothing/gloves/yautja/Destroy() + STOP_PROCESSING(SSobj, src) + if(linked_bracer) + linked_bracer.linked_bracer = null + linked_bracer = null + return ..() + +/obj/item/clothing/gloves/yautja/dropped(mob/living/carbon/human/user) + STOP_PROCESSING(SSobj, src) + flags_item = initial(flags_item) + if(istype(user) && user.gloves == src) + move_chip_to_bracer() + if(cloaked) + decloak(user) + UnregisterSignal(user, list(COMSIG_MOB_REVIVE, COMSIG_MOB_DEATH, COMSIG_ATOM_TELEPORT)) + SSminimaps.remove_marker(user) + for(var/datum/action/action in actions_to_add + action_cloaker + action_caster + action_wristblades) + action.remove_action(user) + if(!user.hunter_data?.claimed_equipment) + claim_equipment.remove_action(user) + ..() + +/obj/item/clothing/gloves/yautja/equipped(mob/living/carbon/human/user, slot) + if(slot == SLOT_GLOVES) + START_PROCESSING(SSobj, src) + owner = user + if(!real_owner) + real_owner = user + + toggle_lock_internal(user, TRUE) + RegisterSignals(user, list(COMSIG_MOB_REVIVE, COMSIG_MOB_DEATH), PROC_REF(update_minimap_icon)) + RegisterSignal(user, COMSIG_ATOM_TELEPORT, PROC_REF(owner_teleported)) + INVOKE_NEXT_TICK(src, PROC_REF(update_minimap_icon), user) + for(var/datum/action/action in actions_to_add + action_cloaker + action_caster + action_wristblades) + action.give_action(user) + if(!user.hunter_data?.claimed_equipment) + claim_equipment.give_action(user) + ..() + +/obj/item/clothing/gloves/yautja/unequipped(mob/living/carbon/human/user, slot) + if(slot == SLOT_GLOVES) + move_chip_to_bracer() + if(cloaked) + decloak(user) + UnregisterSignal(user, list(COMSIG_MOB_REVIVE, COMSIG_MOB_DEATH, COMSIG_ATOM_TELEPORT)) + SSminimaps.remove_marker(user) + for(var/datum/action/action in actions_to_add + action_cloaker + action_caster + action_wristblades) + action.remove_action(user) + if(!user.hunter_data?.claimed_equipment) + claim_equipment.remove_action(user) + ..() + +/obj/item/clothing/gloves/yautja/pickup(mob/living/user) + ..() + if(!isyautja(user)) + to_chat(user, span_warning("The bracer feels cold against your skin, heavy with an unfamiliar, almost alien weight.")) + +/obj/item/clothing/gloves/yautja/proc/owner_teleported() + if(cloaked) + decloak(owner) + update_minimap_icon() + +//We use this to determine whether we should activate the given verb, or a random verb +//0 - do nothing, 1 - random function, 2 - this function +/obj/item/clothing/gloves/yautja/proc/check_random_function(mob/living/carbon/human/user, forced = FALSE, always_delimb = FALSE) + if(!istype(user)) + return TRUE + + if(forced || HAS_TRAIT(user, TRAIT_YAUTJA_TECH)) + return FALSE + + if(user.stat || (user.lying_angle && !user.resting && !user.IsSleeping()) || (user.IsParalyzed() || user.IsUnconscious())) //let's do this here to avoid to_chats to dead guys + return TRUE + + var/workingProbability = 20 + var/randomProbability = 10 + if(issynth(user)) // Synths are smart, they can figure this out pretty well + workingProbability = 25 + randomProbability = 7 + else if(isresearcher(user)) // Researchers are smart as well, they can figure this out + workingProbability = 40 + randomProbability = 4 + + to_chat(user, span_notice("You press a few buttons...")) + //Add a little delay so the user wouldn't be just spamming all the buttons + user.next_move = world.time + 3 + if(do_after(usr, 3, NONE, src, BUSY_ICON_FRIENDLY)) + if(prob(randomProbability)) + return activate_random_verb(user) + if(!prob(workingProbability)) + to_chat(user, span_warning("You fiddle with the buttons but nothing happens...")) + return TRUE + + if(always_delimb) + return delimb_user(user) + + return FALSE + +//This is used to punish people that fiddle with technology they don't understand +/obj/item/clothing/gloves/yautja/proc/delimb_user(mob/living/carbon/human/user) + if(!istype(user)) + return + if(isyautja(user)) + return + + var/datum/limb/O = user.get_limb(check_zone("r_arm")) + O.droplimb() + O = user.get_limb(check_zone("l_arm")) + O.droplimb() + + to_chat(user, span_notice("The device emits a strange noise and falls off... Along with your arms!")) + playsound(user,'sound/weapons/wristblades_on.ogg', 15, 1) + return TRUE + +//We use this to activate random verbs for non-Yautja +/obj/item/clothing/gloves/yautja/proc/activate_random_verb(mob/caller) + var/option = rand(1, 11) + //we have options from 1 to 8, but we're giving the user a higher probability of being punished if they already rolled this bad + switch(option) + if(1) + . = wristblades_internal(caller, TRUE) + if(2) + . = track_gear_internal(caller, TRUE) + if(3) + . = cloaker_internal(caller, TRUE) + if(4) + . = caster_internal(caller, TRUE) + if(5) + . = injectors_internal(caller, TRUE) + if(6) + . = call_disc_internal(caller, TRUE) + if(7) + . = translate_internal(caller, TRUE) + if(8) + . = call_combi_internal(caller, TRUE) + else + . = delimb_user(caller) + +/obj/item/clothing/gloves/yautja/proc/call_combi_internal(mob/living/caller, forced = FALSE) + . = check_random_function(caller, forced) + if(.) + return + + if(get_dist(combistick, src) <= 7 && isturf(combistick.loc)) + if(combistick in caller.contents) //Can't yank if they are wearing it + return FALSE + if(caller.put_in_active_hand(combistick))//Try putting it in our active hand, or, if it's full... + if(!drain_power(caller, 70)) //We should only drain power if we actually yank the chain back. Failed attempts can quickly drain the charge away. + return TRUE + caller.visible_message(span_warning("[caller] yanks [combistick]'s chain back!"), span_warning("You yank [combistick]'s chain back!")) + playsound(caller, "chain_swing", 25) + else if(caller.put_in_inactive_hand(combistick))///...Try putting it in our inactive hand. + if(!drain_power(caller, 70)) //We should only drain power if we actually yank the chain back. Failed attempts can quickly drain the charge away. + return TRUE + caller.visible_message(span_warning("[caller] yanks [combistick]'s chain back!"), span_warning("You yank [combistick]'s chain back!")) + playsound(caller, "chain_swing", 25) + else //If neither hand can hold it, you must not have a free hand. + to_chat(caller, span_warning("You need a free hand to do this!")) + +/obj/item/clothing/gloves/yautja/proc/call_disc_internal(mob/living/caller, forced = FALSE) + . = check_random_function(caller, forced) + if(.) + return + + if(disc_timer) + to_chat(caller, span_warning("Your bracers need some time to recuperate first.")) + return FALSE + + if(!drain_power(caller, 70)) + return FALSE + + disc_timer = TRUE + addtimer(VARSET_CALLBACK(src, disc_timer, FALSE), 10 SECONDS) + + for(var/obj/item/explosive/grenade/spawnergrenade/smartdisc/disc in discs) + if(disc.spawned_item) + if(get_dist(disc.spawned_item, src) <= 7) + to_chat(caller, span_warning("The [disc.spawned_item] skips back towards you!")) + disc.spawned_item.drop_real_disc() + else + if(get_dist(disc, src) <= 10) + if(isturf(disc.loc)) + disc.boomerang(caller) + playsound(disc, 'modular_RUtgmc/sound/effects/smartdisk_throw.ogg', 25) + playsound(src, 'modular_RUtgmc/sound/effects/smartdisk_return.ogg', 30) + return TRUE + +/obj/item/clothing/gloves/yautja/proc/translate_internal(mob/living/carbon/human/caller, forced = FALSE) + . = check_random_function(caller, forced) + if(.) + return + + if(caller.client.prefs.muted & MUTE_IC) + to_chat(caller, span_danger("You cannot translate (muted).")) + return + + caller.create_typing_indicator() + var/msg = sanitize(input(caller, "Your bracer beeps and waits patiently for you to input your message.", "Translator", "") as text) + caller.remove_typing_indicator() + if(!msg || !caller.client) + return + + if(!drain_power(caller, 50)) + return + + log_say("[caller.name != "Unknown" ? caller.name : "([caller.real_name])"] \[Yautja Translator\]: [msg] (CKEY: [caller.key])") + + var/list/heard = list() + for(var/CHM in get_hearers_in_view(7, caller)) + if(ismob(CHM)) + heard += CHM + + var/span_class = "yautja_translator" + if(translator_type != "Modern") + if(translator_type == "Retro") + span_class = "retro_translator" + msg = replacetext(msg, "a", "@") + msg = replacetext(msg, "e", "3") + msg = replacetext(msg, "i", "1") + msg = replacetext(msg, "o", "0") + msg = replacetext(msg, "s", "5") + msg = replacetext(msg, "l", "1") + msg = replacetext(msg, "а", "@") + msg = replacetext(msg, "е", "3") + msg = replacetext(msg, "ч", "4") + msg = replacetext(msg, "о", "0") + msg = replacetext(msg, "з", "3") + msg = replacetext(msg, "г", "r") + msg = replacetext(msg, "ь", "b") + msg = replacetext(msg, "в", "8") + msg = replacetext(msg, "и", "u") + msg = replacetext(msg, "к", "k") + msg = replacetext(msg, "ш", "w") + msg = replacetext(msg, "м", "m") + msg = replacetext(msg, "п", "n") + + var/voice_name = "A strange voice" + if(caller.name == caller.real_name && caller.alpha == initial(caller.alpha)) + voice_name = "[caller.name]" + + for(var/mob/Q as anything in heard) + if(Q.stat) + continue //Unconscious + Q.create_chat_message(caller, /datum/language/common, msg,) + to_chat(Q, "[span_info("[voice_name] says,")] '[msg]'") + +/obj/item/clothing/gloves/yautja/proc/injectors_internal(mob/living/caller, forced = FALSE, power_to_drain = 1000) + . = check_random_function(caller, forced) + if(.) + return + + if(caller.get_active_held_item()) + to_chat(caller, span_warning("Your active hand must be empty!")) + return FALSE + + if(inject_timer) + to_chat(caller, span_warning("You recently activated the stabilising crystal. Be patient.")) + return FALSE + + if(!drain_power(caller, power_to_drain)) + return FALSE + + inject_timer = TRUE + owner.update_action_buttons() + addtimer(CALLBACK(src, PROC_REF(injectors_ready)), 2 MINUTES) + + to_chat(caller, span_notice("You feel a faint hiss and a crystalline injector drops into your hand.")) + var/obj/item/reagent_containers/hypospray/autoinjector/yautja/O = new(caller) + caller.put_in_active_hand(O) + playsound(src, 'sound/machines/click.ogg', 15, 1) + return TRUE + +/obj/item/clothing/gloves/yautja/proc/injectors_ready() + if(ismob(loc)) + to_chat(loc, span_notice("Your bracers beep faintly and inform you that a new stabilising crystal is ready to be created.")) + inject_timer = FALSE + owner.update_action_buttons() + +/obj/item/clothing/gloves/yautja/hunter/verb/healing_capsule() + set name = "Create Healing Capsule" + set category = "Yautja" + set desc = "Create a healing capsule for your healing gun." + set src in usr + . = healing_capsule_internal(usr, FALSE) + +/obj/item/clothing/gloves/yautja/proc/healing_capsule_internal(mob/living/caller, forced = FALSE) + if(caller.stat || (caller.lying_angle && !caller.resting && !caller.IsSleeping()) || (caller.IsParalyzed() || caller.IsUnconscious())) + return FALSE + + . = check_random_function(caller, forced) + if(.) + return + + if(caller.get_active_held_item()) + to_chat(caller, span_warning("Your active hand must be empty!")) + return FALSE + + if(healing_capsule_timer) + to_chat(usr, span_warning("Your bracer is still generating a new healing capsule!")) + return FALSE + + if(!drain_power(caller, 800)) + return FALSE + + healing_capsule_timer = TRUE + addtimer(CALLBACK(src, PROC_REF(healing_capsule_ready)), 4 MINUTES) + + to_chat(caller, span_notice("You feel your bracer churn as it pops out a healing capsule.")) + var/obj/item/tool/surgery/healing_gel/O = new(caller) + caller.put_in_active_hand(O) + playsound(src, 'sound/machines/click.ogg', 15, 1) + return TRUE + +/obj/item/clothing/gloves/yautja/proc/healing_capsule_ready() + if(ismob(loc)) + to_chat(loc, span_notice("Your bracers beep faintly and inform you that a new healing capsule is ready to be created.")) + healing_capsule_timer = FALSE + +/obj/item/clothing/gloves/yautja/proc/wristblades_internal(mob/living/carbon/human/caller, forced = FALSE, power_to_drain = 50) + . = check_random_function(caller, forced) + if(.) + return + + if(wristblades_deployed) + if(left_wristblades.loc == caller) + caller.transferItemToLoc(left_wristblades, src, TRUE) + if(right_wristblades.loc == caller) + caller.transferItemToLoc(right_wristblades, src, TRUE) + wristblades_deployed = FALSE + to_chat(caller, span_notice("You retract your [left_wristblades.name].")) + else + if(!drain_power(caller, power_to_drain)) + return + + var/deploying_into_left_hand = caller.hand ? TRUE : FALSE + if(caller.get_active_held_item()) + to_chat(caller, span_warning("Your hand must be free to activate your wristblade!")) + return + var/datum/limb/hand = caller.get_limb(deploying_into_left_hand ? "l_hand" : "r_hand") + if(!istype(hand) || !hand.is_usable()) + to_chat(caller, span_warning("You can't hold that!")) + return + var/is_offhand_full = FALSE + var/datum/limb/off_hand = caller.get_limb(deploying_into_left_hand ? "r_hand" : "l_hand") + if(caller.get_inactive_held_item() || (!istype(off_hand) || !off_hand.is_usable())) + is_offhand_full = TRUE + if(deploying_into_left_hand) + caller.put_in_active_hand(left_wristblades) + if(!is_offhand_full) + caller.put_in_inactive_hand(right_wristblades) + else + caller.put_in_active_hand(right_wristblades) + if(!is_offhand_full) + caller.put_in_inactive_hand(left_wristblades) + wristblades_deployed = TRUE + to_chat(caller, span_notice("You activate your [left_wristblades].")) + playsound(caller, 'sound/weapons/wristblades_on.ogg', 15, TRUE) + +/obj/item/clothing/gloves/yautja/proc/caster_internal(mob/living/carbon/human/caller, forced = FALSE, power_to_drain = 50) + . = check_random_function(caller, forced) + if(.) + return + + if(caster_deployed) + caller.transferItemToLoc(caster, src, TRUE) + caster_deployed = FALSE + else + if(!drain_power(caller, power_to_drain)) + return + if(caller.get_active_held_item()) + to_chat(caller, span_warning("Your hand must be free to activate your wristblade!")) + return + var/datum/limb/hand = caller.get_limb(caller.hand ? "l_hand" : "r_hand") + if(!istype(hand) || !hand.is_usable()) + to_chat(caller, span_warning("You can't hold that!")) + return + caller.put_in_active_hand(caster) + caster_deployed = TRUE + to_chat(caller, span_notice("You activate your plasma caster. It is in [caster.mode] mode.")) + playsound(src, 'modular_RUtgmc/sound/weapons/pred_plasmacaster_on.ogg', 15, TRUE) + +/obj/item/clothing/gloves/yautja/proc/cloaker_internal(mob/living/caller, forced = FALSE) + . = check_random_function(caller, forced) + if(.) + return + + var/mob/living/carbon/human/M = caller + var/new_alpha = cloak_alpha + + if(!istype(M) || caller.stat || (caller.lying_angle && !caller.resting && !caller.IsSleeping()) || (caller.IsParalyzed() || caller.IsUnconscious())) + return FALSE + + if(cloaked) //Turn it off. + if(cloak_timer > world.time) + to_chat(M, span_warning("Your cloaking device is busy! Time left: [max(round((cloak_timer - world.time) / 10), 1)] seconds.")) + return FALSE + decloak(caller) + else //Turn it on! + if(exploding) + to_chat(M, span_warning("Your bracer is much too busy violently exploding to activate the cloaking device.")) + return FALSE + + if(cloak_malfunction > world.time) + to_chat(M, span_warning("Your cloak is malfunctioning and can't be enabled right now!")) + return FALSE + + if(cloak_timer > world.time) + to_chat(M, span_warning("Your cloaking device is still recharging! Time left: [max(round((cloak_timer - world.time) / 10), 1)] seconds.")) + return FALSE + + if(!drain_power(M, 50)) + return FALSE + + cloaked = TRUE + + action_cloaker.set_toggle(TRUE) + + RegisterSignal(M, COMSIG_HUMAN_EXTINGUISH, PROC_REF(wrapper_fizzle_camouflage)) + RegisterSignal(M, COMSIG_ATOM_BULLET_ACT, PROC_REF(bullet_act_sim)) + + cloak_timer = world.time + 1.5 SECONDS + if(true_cloak) + M.invisibility = 35 + M.see_invisible = 35 + new_alpha = 75 + + ADD_TRAIT(M, TRAIT_TURRET_HIDDEN, TRAIT_TURRET_HIDDEN) + ADD_TRAIT(M, TRAIT_LIGHT_STEP, TRAIT_LIGHT_STEP) + log_game("[key_name_admin(usr)] has enabled their cloaking device.") + M.visible_message(span_warning("[M] vanishes into thin air!"), span_notice("You are now invisible to normal detection.")) + playsound(M.loc,'modular_RUtgmc/sound/effects/pred_cloakon.ogg', 30) + animate(M, alpha = new_alpha, time = 1.5 SECONDS, easing = SINE_EASING|EASE_OUT) + + var/datum/atom_hud/security/SA = GLOB.huds[DATA_HUD_SECURITY_ADVANCED] + SA.remove_from_hud(M) + var/datum/atom_hud/xeno_infection/XI = GLOB.huds[DATA_HUD_XENO_INFECTION] + XI.remove_from_hud(M) + anim(M.loc,M,'icons/mob/mob.dmi',,"cloak",,M.dir) + +//Any projectile can decloak a predator. It does defeat one free bullet though. +/obj/item/clothing/gloves/yautja/proc/bullet_act_sim(mob/living/carbon/human/H, obj/projectile/proj) + var/ammo_flags = proj.ammo.flags_ammo_behavior + if(ammo_flags & (AMMO_ROCKET|AMMO_ENERGY|AMMO_XENO)) //<--- These will auto uncloak. + decloak(H) //Continue on to damage. + else if(prob(20)) + decloak(H) + return + +/obj/item/clothing/gloves/yautja/proc/wrapper_fizzle_camouflage() + SIGNAL_HANDLER + + var/mob/wearer = src.loc + wearer.visible_message(span_danger("[wearer]'s cloak fizzles out!"), span_danger("Your cloak fizzles out!")) + + var/datum/effect_system/spark_spread/sparks = new /datum/effect_system/spark_spread + sparks.set_up(5, 4, src) + sparks.start() + + spawn() + decloak(wearer, TRUE) + +/obj/item/clothing/gloves/yautja/proc/track_gear_internal(mob/caller, forced = FALSE) + . = check_random_function(caller, forced) + if(.) + return + + var/mob/living/carbon/human/M = caller + + var/dead_on_planet = 0 + var/dead_on_almayer = 0 + var/dead_low_orbit = 0 + var/gear_on_planet = 0 + var/gear_on_almayer = 0 + var/gear_low_orbit = 0 + var/closest = 10000 + var/direction = -1 + var/atom/areaLoc = null + for(var/obj/item/I as anything in GLOB.loose_yautja_gear) + var/atom/loc = get_true_location(I) + if(!I) + continue + if(I.anchored) + continue + if(is_honorable_carrier(recursive_holder_check(I))) + continue + if(istype(get_area(I), /area/yautja)) + continue + if(is_reserved_level(loc.z)) + gear_low_orbit++ + else if(is_mainship_level(loc.z)) + gear_on_almayer++ + else if(is_ground_level(loc.z)) + gear_on_planet++ + if(M.z == loc.z) + var/dist = get_dist(M,loc) + if(dist < closest) + closest = dist + direction = get_dir(M,loc) + areaLoc = loc + for(var/mob/living/carbon/human/Y as anything in GLOB.yautja_mob_list) + if(Y.stat != DEAD) + continue + if(istype(get_area(Y), /area/yautja)) + continue + if(is_reserved_level(Y.z)) + dead_low_orbit++ + else if(is_mainship_level(Y.z)) + dead_on_almayer++ + else if(is_ground_level(Y.z)) + dead_on_planet++ + if(M.z == Y.z) + var/dist = get_dist(M,Y) + if(dist < closest) + closest = dist + direction = get_dir(M,Y) + areaLoc = loc + + var/output = FALSE + if(dead_on_planet || dead_on_almayer || dead_low_orbit) + output = TRUE + to_chat(M, span_notice("Your bracer shows a readout of deceased Yautja bio signatures[dead_on_planet ? ", [dead_on_planet] in the hunting grounds" : ""][dead_on_almayer ? ", [dead_on_almayer] in orbit" : ""][dead_low_orbit ? ", [dead_low_orbit] in low orbit" : ""].")) + if(gear_on_planet || gear_on_almayer || gear_low_orbit) + output = TRUE + to_chat(M, span_notice("Your bracer shows a readout of Yautja technology signatures[gear_on_planet ? ", [gear_on_planet] in the hunting grounds" : ""][gear_on_almayer ? ", [gear_on_almayer] in orbit" : ""][gear_low_orbit ? ", [gear_low_orbit] in low orbit" : ""].")) + if(closest < 900) + output = TRUE + var/areaName = get_area_name(areaLoc) + if(closest == 0) + to_chat(M, span_notice("You are directly on top of the closest signature.")) + else + to_chat(M, span_notice("The closest signature is [closest > 10 ? "approximately [round(closest, 10)]" : "[closest]"] paces [dir2text(direction)] in [areaName].")) + if(!output) + to_chat(M, span_notice("There are no signatures that require your attention.")) + + +/obj/item/clothing/gloves/yautja/proc/explode(mob/living/carbon/victim) + set waitfor = FALSE + + if(exploding) + return + + exploding = TRUE + var/turf/T = get_turf(src) + if(explosion_type == SD_TYPE_BIG && victim.stat == CONSCIOUS && (is_ground_level(T.z) || SSticker.mode.flags_round_type & MODE_SHIPSIDE_SD)) + playsound(src, 'modular_RUtgmc/sound/voice/pred_deathlaugh.ogg', 100, 0, 17) + + playsound(src, 'modular_RUtgmc/sound/effects/pred_countdown.ogg', 100, 0, 17) + message_admins(font_size_xl("CLICK TO CANCEL THIS PRED SD")) + + our_socialistic_do_after(victim, rand(72, 80)) + + T = get_turf(src) + if(istype(T) && exploding) + victim.apply_damage(50, BRUTE, "chest") + if(victim) + victim.gib() // kills the pred + qdel(victim) + if(explosion_type == SD_TYPE_BIG && (is_ground_level(T.z) || SSticker.mode.flags_round_type & MODE_SHIPSIDE_SD)) + cell_explosion(T, 700, 100) + else + cell_explosion(T, 300, 100) + +//No moduled do after??? skull issue tgmc! +/obj/item/clothing/gloves/yautja/proc/our_socialistic_do_after(mob/user, delay) + if(!user) + return FALSE + + delay *= user.do_after_coefficent() + + var/datum/progressbar/P = new /datum/progressbar(user, delay, user, BUSY_ICON_HOSTILE, BUSY_ICON_HOSTILE) + + LAZYINCREMENT(user.do_actions, src) + var/endtime = world.time + delay + var/starttime = world.time + . = TRUE + while (world.time < endtime) + stoplag(1) + P?.update(world.time - starttime) + if(loc != user) + . = FALSE + break + if(P) + qdel(P) + LAZYDECREMENT(user.do_actions, src) + +/obj/item/clothing/gloves/yautja/proc/change_explosion_type() + if(explosion_type == SD_TYPE_SMALL && exploding) + to_chat(usr, span_warning("Why would you want to do this?")) + return + + if(alert("Which explosion type do you want?","Explosive Bracers", "Small", "Big") == "Big") + explosion_type = SD_TYPE_BIG + log_attack("[key_name_admin(usr)] has changed their Self-Destruct to Large") + else + explosion_type = SD_TYPE_SMALL + log_attack("[key_name_admin(usr)] has changed their Self-Destruct to Small") + return + +/obj/item/clothing/gloves/yautja/proc/activate_suicide_internal(mob/caller, forced = FALSE) + . = check_random_function(caller, forced, TRUE) + if(.) + return + + var/mob/living/carbon/human/M = caller + + if(cloaked) + to_chat(M, span_warning("Not while you're cloaked. It might disrupt the sequence.")) + return + if(M.stat == DEAD) + to_chat(M, span_warning("Little too late for that now!")) + return + if(M.health < -50) + to_chat(M, span_warning("As you fall into unconsciousness you fail to activate your self-destruct device before you collapse.")) + return + if(M.stat) + to_chat(M, span_warning("Not while you're unconcious...")) + return + + var/obj/item/grab/G = M.get_active_held_item() + if(istype(G)) + var/mob/living/carbon/human/victim = G.grabbed_thing + if(victim.stat == DEAD) + var/obj/item/clothing/gloves/yautja/hunter/bracer = victim.gloves + var/message = "Are you sure you want to detonate this [victim.species]'s bracer?" + if(isyautja(victim)) + message = "Are you sure you want to send this [victim.species] into the great hunting grounds?" + if(istype(bracer)) + if(forced || alert(message,"Explosive Bracers", "Yes", "No") == "Yes") + if(M.get_active_held_item() == G && victim && victim.gloves == bracer && !bracer.exploding) + var/area/A = get_area(M) + var/turf/T = get_turf(M) + if(A) + message_admins(font_size_huge("ALERT: [M] ([M.key]) triggered the predator self-destruct sequence of [victim] ([victim.key]) in [A.name] [ADMIN_JMP(T)]")) + log_attack("[key_name(M)] triggered the predator self-destruct sequence of [victim] ([victim.key]) in [A.name]") + if (!bracer.exploding) + bracer.explode(victim) + M.visible_message(span_warning("[M] presses a few buttons on [victim]'s wrist bracer."),span_danger("You activate the timer. May [victim]'s final hunt be swift.")) + message_all_yautja("[M.real_name] has triggered [victim.real_name]'s bracer's self-destruction sequence.") + else + to_chat(M, span_warning("This [victim.species] does not have a bracer attached.")) + return + + if(M.gloves != src && !forced) + return + + if(exploding) + if(forced || alert("Are you sure you want to stop the countdown?","Bracers", "Yes", "No") == "Yes") + if(M.gloves != src) + return + if(M.stat == DEAD) + to_chat(M, span_warning("Little too late for that now!")) + return + if(M.stat) + to_chat(M, span_warning("Not while you're unconcious...")) + return + exploding = FALSE + to_chat(M, span_notice("Your bracers stop beeping.")) + message_all_yautja("[M.real_name] has cancelled their bracer's self-destruction sequence.") + message_admins("[key_name(M)] has deactivated their Self-Destruct.") + return + if(istype(M.wear_mask,/obj/item/clothing/mask/facehugger) || (M.status_flags & XENO_HOST)) + to_chat(M, span_warning("Strange...something seems to be interfering with your bracer functions...")) + return + if(forced || alert("Detonate the bracers? Are you sure?\n\nNote: If you activate SD for any non-accidental reason during or after a fight, you commit to the SD. By initially activating the SD, you have accepted your impending death to preserve any lost honor.","Explosive Bracers", "Yes", "No") == "Yes") + if(M.gloves != src) + return + if(M.stat == DEAD) + to_chat(M, span_warning("Little too late for that now!")) + return + if(M.stat) + to_chat(M, span_warning("Not while you're unconcious...")) + return + if(exploding) + return + to_chat(M, span_danger("You set the timer. May your journey to the great hunting grounds be swift.")) + var/area/A = get_area(M) + var/turf/T = get_turf(M) + message_admins(font_size_huge("ALERT: [M] ([M.key]) triggered their predator self-destruct sequence [A ? "in [A.name]":""] [ADMIN_JMP(T)]")) + log_attack("[key_name(M)] triggered their predator self-destruct sequence in [A ? "in [A.name]":""]") + message_all_yautja("[M.real_name] has triggered their bracer's self-destruction sequence.") + explode(M) + +/obj/item/clothing/gloves/yautja/proc/move_chip_to_bracer() + if(!embedded_id || !embedded_id.loc) + return + + if(embedded_id.loc == src) + return + + if(ismob(embedded_id.loc)) + var/mob/M = embedded_id.loc + M.UnEquip(embedded_id, TRUE, src) + else + embedded_id.forceMove(src) + +/obj/item/clothing/gloves/yautja/process() + if(!ishuman(loc)) + STOP_PROCESSING(SSobj, src) + return + var/mob/living/carbon/human/human_holder = loc + + if(charge < charge_max) + var/charge_increase = charge_rate + if(is_ground_level(human_holder.z)) + charge_increase = charge_rate / 4 + else if(is_mainship_level(human_holder.z)) + charge_increase = charge_rate / 2 + + charge = min(charge + charge_increase, charge_max) + var/perc_charge = (charge / charge_max * 100) + human_holder.update_power_display(perc_charge) + + //Non-Yautja have a chance to get stunned with each power drain + if(!cloaked) + return + if(human_holder.stat == DEAD) + decloak(human_holder, TRUE) + if(!HAS_TRAIT(human_holder, TRAIT_YAUTJA_TECH) && !human_holder.hunter_data.thralled && prob(15)) + decloak(human_holder) + shock_user(human_holder) + +/// handles decloaking only on HUNTER gloves +/obj/item/clothing/gloves/yautja/proc/decloak() + return + +/// Called to update the minimap icon of the predator +/obj/item/clothing/gloves/yautja/proc/update_minimap_icon() + if(!ishuman(owner)) + return + + var/turf/wearer_turf = get_turf(owner) + if(!wearer_turf) + return + + SSminimaps.remove_marker(owner) + + if(!isyautja(owner)) + SSminimaps.add_marker(owner, MINIMAP_FLAG_YAUTJA, image('modular_RUtgmc/icons/UI_icons/map_blips.dmi', null, "bracer_stolen")) + if(owner.stat >= DEAD) + if(HAS_TRAIT(owner, TRAIT_UNDEFIBBABLE)) + SSminimaps.add_marker(owner, MINIMAP_FLAG_YAUTJA, image('modular_RUtgmc/icons/UI_icons/map_blips.dmi', null, "undefibbable")) + else + SSminimaps.add_marker(owner, MINIMAP_FLAG_YAUTJA, image('modular_RUtgmc/icons/UI_icons/map_blips.dmi', null, "defibbable")) + else + SSminimaps.add_marker(owner, MINIMAP_FLAG_YAUTJA, image('modular_RUtgmc/icons/UI_icons/map_blips.dmi', null, minimap_icon)) + if(owner?.stat >= DEAD) + SSminimaps.add_marker(owner, MINIMAP_FLAG_YAUTJA, image('modular_RUtgmc/icons/UI_icons/map_blips.dmi', null, "undefibbable")) + +/* +*This is the main proc for checking AND draining the bracer energy. It must have human passed as an argument. +*It can take a negative value in amount to restore energy. +*Also instantly updates the yautja power HUD display. +*/ +/obj/item/clothing/gloves/yautja/proc/drain_power(mob/living/carbon/human/human, amount) + if(!human) + return FALSE + if(charge < amount) + to_chat(human, span_warning("Your bracers lack the energy. They have only [charge]/[charge_max] remaining and need [amount].")) + return FALSE + + charge -= amount + var/perc = (charge / charge_max * 100) + human.update_power_display(perc) + + //Non-Yautja have a chance to get stunned with each power drain + if(!HAS_TRAIT(human, TRAIT_YAUTJA_TECH) && !human.hunter_data.thralled) + if(prob(15)) + if(cloaked) + decloak(human) + cloak_timer = world.time + 5 SECONDS + shock_user(human) + return FALSE + + return TRUE + +/obj/item/clothing/gloves/yautja/proc/shock_user(mob/living/carbon/human/M) + if(!HAS_TRAIT(M, TRAIT_YAUTJA_TECH) && !M.hunter_data.thralled) + //Spark + playsound(M, 'sound/effects/sparks2.ogg', 60, 1) + var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread + s.set_up(2, 1, src) + s.start() + M.visible_message(span_warning("[src] beeps and sends a shock through [M]'s body!")) + //Stun and knock out, scream in pain + M.apply_effect(2, STUN) + M.apply_effect(2, WEAKEN) + if(!M.species || !(M.species.species_flags & NO_PAIN)) + M.emote("scream") + //Apply a bit of burn damage + M.apply_damage(5, BURN, "l_arm", 0, 0, 0, src) + M.apply_damage(5, BURN, "r_arm", 0, 0, 0, src) + +/obj/item/clothing/gloves/yautja/examine(mob/user) + . = ..() + . += span_notice("They currently have [charge]/[charge_max] charge.") + + +// Toggle the notification sound +/obj/item/clothing/gloves/yautja/verb/toggle_notification_sound() + set name = "Toggle Bracer Sound" + set desc = "Toggle your bracer's notification sound." + set category = "Yautja" + set src in usr + + notification_sound = !notification_sound + to_chat(usr, span_notice("The bracer's sound is now turned [notification_sound ? "on" : "off"].")) + +/obj/item/clothing/gloves/yautja/proc/buy_gear(mob/living/carbon/human/wearer) + if(wearer.gloves != src) + to_chat(wearer, span_warning("You need to be wearing your thrall bracers to do this.")) + return + + if(wearer.hunter_data.claimed_equipment) + to_chat(wearer, span_warning("You've already claimed your equipment.")) + return + + if(wearer.stat || (wearer.lying_angle && !wearer.resting && !wearer.IsSleeping()) || (wearer.IsParalyzed() || wearer.IsUnconscious()) || wearer.lying_angle || wearer.buckled) + to_chat(wearer, span_warning("You're not able to do that right now.")) + return + + if(!istype(get_area(wearer), /area/yautja)) + to_chat(wearer, span_warning("Not here. Only on the ship.")) + return + + var/sure = alert("An array of powerful weapons are displayed to you. Pick your gear carefully. If you cancel at any point, you will not claim your equipment.", "Sure?", "Begin the Hunt", "No, not now") + if(sure != "Begin the Hunt") + return + + var/list/melee = list(YAUTJA_GEAR_GLAIVE = image(icon = 'modular_RUtgmc/icons/obj/hunter/pred_gear.dmi', icon_state = "glaive"), YAUTJA_GEAR_WHIP = image(icon = 'modular_RUtgmc/icons/obj/hunter/pred_gear.dmi', icon_state = "whip"),YAUTJA_GEAR_SWORD = image(icon = 'modular_RUtgmc/icons/obj/hunter/pred_gear.dmi', icon_state = "clansword"),YAUTJA_GEAR_SCYTHE = image(icon = 'modular_RUtgmc/icons/obj/hunter/pred_gear.dmi', icon_state = "predscythe"), YAUTJA_GEAR_STICK = image(icon = 'modular_RUtgmc/icons/obj/hunter/pred_gear.dmi', icon_state = "combistick"), YAUTJA_GEAR_SCIMS = image(icon = 'modular_RUtgmc/icons/obj/hunter/pred_gear.dmi', icon_state = "scim")) + var/list/other = list(YAUTJA_GEAR_LAUNCHER = image(icon = 'modular_RUtgmc/icons/obj/hunter/pred_gear.dmi', icon_state = "spikelauncher"), YAUTJA_GEAR_PISTOL = image(icon = 'modular_RUtgmc/icons/obj/hunter/pred_gear.dmi', icon_state = "plasmapistol"), YAUTJA_GEAR_DISC = image(icon = 'modular_RUtgmc/icons/obj/hunter/pred_gear.dmi', icon_state = "disc"), YAUTJA_GEAR_FULL_ARMOR = image(icon = 'modular_RUtgmc/icons/obj/hunter/pred_gear.dmi', icon_state = "fullarmor_ebony"), YAUTJA_GEAR_SHIELD = image(icon = 'modular_RUtgmc/icons/obj/hunter/pred_gear.dmi', icon_state = "shield"), YAUTJA_GEAR_DRONE = image(icon = 'modular_RUtgmc/icons/obj/hunter/pred_gear.dmi', icon_state = "falcon_drone")) + var/list/restricted = list(YAUTJA_GEAR_LAUNCHER, YAUTJA_GEAR_PISTOL, YAUTJA_GEAR_FULL_ARMOR, YAUTJA_GEAR_SHIELD, YAUTJA_GEAR_DRONE) //Can only select them once each. + + var/list/secondaries = list() + var/total_secondaries = 2 + + var/main_weapon = show_radial_menu(wearer, wearer, melee) + + if(main_weapon == YAUTJA_GEAR_SCYTHE) + var/list/scythe_variants = list(YAUTJA_GEAR_SCYTHE = image(icon = 'modular_RUtgmc/icons/obj/hunter/pred_gear.dmi', icon_state = "predscythe"), YAUTJA_GEAR_SCYTHE_ALT = image(icon = 'modular_RUtgmc/icons/obj/hunter/pred_gear.dmi', icon_state = "predscythe_alt")) + main_weapon = show_radial_menu(wearer, wearer, scythe_variants) + + if(main_weapon == YAUTJA_GEAR_GLAIVE) + var/list/glaive_variants = list(YAUTJA_GEAR_GLAIVE = image(icon = 'modular_RUtgmc/icons/obj/hunter/pred_gear.dmi', icon_state = "glaive"), YAUTJA_GEAR_GLAIVE_ALT = image(icon = 'modular_RUtgmc/icons/obj/hunter/pred_gear.dmi', icon_state = "glaive_alt")) + main_weapon = show_radial_menu(wearer, wearer, glaive_variants) + + if(!main_weapon) + return + for(var/i = 1 to total_secondaries) + var/secondary = show_radial_menu(wearer, wearer, other) + if(!secondary) + return + secondaries += secondary + if(secondary in restricted) + other -= secondary + + wearer.hunter_data.claimed_equipment = TRUE + + switch(main_weapon) + if(YAUTJA_GEAR_GLAIVE) + wearer.equip_to_slot_if_possible(new /obj/item/weapon/twohanded/yautja/glaive(wearer.loc), SLOT_S_STORE, warning = TRUE) + if(YAUTJA_GEAR_GLAIVE_ALT) + wearer.equip_to_slot_if_possible(new /obj/item/weapon/twohanded/yautja/glaive/alt(wearer.loc), SLOT_S_STORE, warning = TRUE) + if(YAUTJA_GEAR_WHIP) + wearer.equip_to_slot_if_possible(new /obj/item/weapon/yautja/chain(wearer.loc), SLOT_S_STORE, warning = TRUE) + if(YAUTJA_GEAR_SWORD) + wearer.equip_to_slot_if_possible(new /obj/item/weapon/yautja/sword(wearer.loc), SLOT_S_STORE, warning = TRUE) + if(YAUTJA_GEAR_SCYTHE) + wearer.equip_to_slot_if_possible(new /obj/item/weapon/yautja/scythe(wearer.loc), SLOT_S_STORE, warning = TRUE) + if(YAUTJA_GEAR_SCYTHE_ALT) + wearer.equip_to_slot_if_possible(new /obj/item/weapon/yautja/scythe/alt(wearer.loc), SLOT_S_STORE, warning = TRUE) + if(YAUTJA_GEAR_STICK) + wearer.equip_to_slot_if_possible(new /obj/item/weapon/yautja/combistick(wearer.loc), SLOT_S_STORE, warning = TRUE) + if(YAUTJA_GEAR_SCIMS) + if(wristblades_deployed) + wristblades_internal(usr, TRUE) + qdel(left_wristblades) + qdel(right_wristblades) + left_wristblades = new /obj/item/weapon/wristblades/scimitar(src) + right_wristblades = new /obj/item/weapon/wristblades/scimitar(src) + + for(var/choice in secondaries) + switch(choice) + if(YAUTJA_GEAR_LAUNCHER) + wearer.equip_to_slot_if_possible(new /obj/item/weapon/gun/energy/yautja/spike(wearer.loc), SLOT_IN_BELT, warning = TRUE) + if(YAUTJA_GEAR_PISTOL) + wearer.equip_to_slot_if_possible(new /obj/item/weapon/gun/energy/yautja/plasmapistol(wearer.loc), SLOT_IN_BELT, warning = TRUE) + if(YAUTJA_GEAR_DISC) + wearer.equip_to_slot_if_possible(new /obj/item/explosive/grenade/spawnergrenade/smartdisc(wearer.loc), SLOT_IN_BELT, warning = TRUE) + if(YAUTJA_GEAR_FULL_ARMOR) + if(wearer.wear_suit) + wearer.dropItemToGround(wearer.wear_suit) + wearer.equip_to_slot_if_possible(new /obj/item/clothing/suit/armor/yautja/hunter/full(wearer.loc, 0, wearer.client.prefs.predator_armor_material), SLOT_WEAR_SUIT, warning = TRUE) + if(YAUTJA_GEAR_SHIELD) + wearer.equip_to_slot_if_possible(new /obj/item/weapon/shield/riot/yautja(wearer.loc), SLOT_BACK, warning = TRUE) + if(YAUTJA_GEAR_DRONE) + wearer.equip_to_slot_if_possible(new /obj/item/clothing/falcon_drone(wearer.loc), SLOT_HEAD, warning = TRUE) + + claim_equipment.remove_action(wearer) + +/obj/item/clothing/gloves/yautja/thrall + name = "thrall bracers" + desc = "A pair of strange alien bracers, adapted for human biology." + + color = "#b85440" + minimap_icon = "thrall" + +/obj/item/clothing/gloves/yautja/thrall/update_minimap_icon() + if(!ishuman(owner)) + return + + var/turf/wearer_turf = get_turf(owner) + if(!wearer_turf) + return + + SSminimaps.add_marker(owner, MINIMAP_FLAG_YAUTJA, image('modular_RUtgmc/icons/UI_icons/map_blips.dmi', null, minimap_icon)) + if(owner.stat >= DEAD) + if(HAS_TRAIT(owner, TRAIT_UNDEFIBBABLE)) + SSminimaps.add_marker(owner, MINIMAP_FLAG_YAUTJA, image('modular_RUtgmc/icons/UI_icons/map_blips.dmi', null, "undefibbable")) + else + SSminimaps.add_marker(owner, MINIMAP_FLAG_YAUTJA, image('modular_RUtgmc/icons/UI_icons/map_blips.dmi', null, "defibbable")) + +/obj/item/clothing/gloves/yautja/hunter + name = "clan bracers" + desc = "An extremely complex, yet simple-to-operate set of armored bracers worn by the Yautja. It has many functions, activate them to use some." + + soft_armor = list(MELEE = 20, BULLET = 30, LASER = 25, ENERGY = 25, BOMB = 30, BIO = 25, FIRE = 25, ACID = 25) + + charge = 3000 + charge_max = 3000 + + cloak_alpha = 4 + + action_cloaker = new + action_caster = new + action_wristblades = new + + actions_to_add = list( + new /datum/action/predator_action/bracer/translate, + new /datum/action/predator_action/bracer/injectors, + new /datum/action/predator_action/bracer/call_disc, + new /datum/action/predator_action/bracer/yank_combistick, + new /datum/action/predator_action/bracer/activate_suicide + ) + + var/name_active = TRUE + var/caster_material = "ebony" + + var/owner_rank = CLAN_RANK_UNBLOODED_INT + +/obj/item/clothing/gloves/yautja/hunter/Initialize(mapload, new_translator_type, new_caster_material, new_owner_rank) + . = ..() + if(new_owner_rank) + owner_rank = new_owner_rank + embedded_id = new(src) + if(new_translator_type) + translator_type = new_translator_type + if(new_caster_material) + caster_material = new_caster_material + caster = new(src, FALSE, caster_material) + left_wristblades = new(src) + right_wristblades = new(src) + +/obj/item/clothing/gloves/yautja/hunter/Destroy() + . = ..() + left_wristblades = null + right_wristblades = null + +/obj/item/clothing/gloves/yautja/hunter/emp_act(severity) + charge = max(charge - (severity * 500), 0) + if(ishuman(loc)) + var/mob/living/carbon/human/wearer = loc + if(wearer.gloves == src) + wearer.visible_message(span_danger("You hear a hiss and crackle!"), span_danger("Your bracers hiss and spark!"), span_danger("You hear a hiss and crackle!")) + if(cloaked) + decloak(wearer) + else + var/turf/our_turf = get_turf(src) + our_turf.visible_message(span_danger("You hear a hiss and crackle!"), span_danger("You hear a hiss and crackle!")) + +/obj/item/clothing/gloves/yautja/hunter/equipped(mob/user, slot) + . = ..() + if(slot != SLOT_GLOVES) + move_chip_to_bracer() + else + if(embedded_id?.registered_name) + embedded_id.set_user_data(user) + +/obj/item/clothing/gloves/yautja/hunter/Destroy() + QDEL_NULL(caster) + QDEL_NULL(embedded_id) + return ..() + +/obj/item/clothing/gloves/yautja/hunter/process() + if(!ishuman(loc)) + STOP_PROCESSING(SSobj, src) + return + + var/mob/living/carbon/human/human = loc + + if(cloaked) + charge = max(charge - 10, 0) + if(charge <= 0) + decloak(loc) + //Non-Yautja have a chance to get stunned with each power drain + if(!isyautja(human)) + if(prob(15)) + decloak(human) + shock_user(human) + return + return ..() + +/obj/item/clothing/gloves/yautja/hunter/on_enter_storage(obj/item/storage/S) + if(ishuman(loc)) + var/mob/living/carbon/human/human = loc + if(cloaked) + decloak(human) + . = ..() + +/obj/item/clothing/gloves/yautja/hunter/verb/check_auto_targets() + set name = "Track Yautja Targets" + set desc = "Find Yauja Targets." + set category = "Yautja" + set src in usr + . = check_auto_targets_text(usr, FALSE) + +/obj/item/clothing/gloves/yautja/hunter/proc/check_auto_targets_text(mob/caller, forced = FALSE) + . = check_random_function(caller, forced) + if(.) + return + + . = span_info("Current priority targets:") + if(length(caller.hunter_data.targets)) + for(var/datum/huntdata/data in caller.hunter_data.targets) + . += span_warning("[data.owner.real_name] located in [get_area_name(data.owner)] and have [data.owner.life_kills_total + data.owner.life_value + 3] honor\n") + else + . += span_notice("NONE") + to_chat(caller, .) + +/obj/item/clothing/gloves/yautja/hunter/verb/track_gear() + set name = "Track Yautja Gear" + set desc = "Find Yauja Gear." + set category = "Yautja" + set src in usr + . = track_gear_internal(usr, FALSE) + +/obj/item/clothing/gloves/yautja/hunter/decloak(mob/user, forced) + if(!user) + return + + UnregisterSignal(user, COMSIG_HUMAN_EXTINGUISH) + UnregisterSignal(user, COMSIG_ATOM_BULLET_ACT) + + if(forced) + cloak_malfunction = world.time + 10 SECONDS + + cloaked = FALSE + + REMOVE_TRAIT(user, TRAIT_TURRET_HIDDEN, TRAIT_TURRET_HIDDEN) + REMOVE_TRAIT(user, TRAIT_LIGHT_STEP, TRAIT_LIGHT_STEP) + log_game("[key_name_admin(usr)] has disabled their cloaking device.") + user.visible_message(span_warning("[user] shimmers into existence!"), span_warning("Your cloaking device deactivates.")) + playsound(user.loc, 'modular_RUtgmc/sound/effects/pred_cloakoff.ogg', 35) + user.alpha = initial(user.alpha) + if(true_cloak) + user.invisibility = initial(user.invisibility) + user.see_invisible = initial(user.see_invisible) + cloak_timer = world.time + 5 SECONDS + + var/datum/atom_hud/security/SA = GLOB.huds[DATA_HUD_SECURITY_ADVANCED] + SA.add_to_hud(user) + var/datum/atom_hud/xeno_infection/XI = GLOB.huds[DATA_HUD_XENO_INFECTION] + XI.add_to_hud(user) + + action_cloaker.set_toggle(FALSE) + + anim(user.loc, user, 'icons/mob/mob.dmi', null, "uncloak", null, user.dir) + +/obj/item/clothing/gloves/yautja/hunter/verb/remove_tracked_item() + set name = "Remove Item from Tracker" + set desc = "Remove an item from the Yautja tracker." + set category = "Yautja" + set src in usr + . = remove_tracked_item_internal(usr, FALSE) + +/obj/item/clothing/gloves/yautja/hunter/proc/remove_tracked_item_internal(mob/living/caller, forced = FALSE) + if(caller.stat || (caller.lying_angle && !caller.resting && !caller.IsSleeping()) || (caller.IsParalyzed() || caller.IsUnconscious())) + return FALSE + + . = check_random_function(caller, forced) + if(.) + return + + var/obj/item/tracked_item = caller.get_active_held_item() + if(!tracked_item) + to_chat(caller, span_warning("You need the item in your active hand to remove it from the tracker!")) + return FALSE + if(!(tracked_item in GLOB.tracked_yautja_gear)) + to_chat(caller, span_warning("\The [tracked_item] isn't on the tracking system.")) + return FALSE + tracked_item.RemoveElement(/datum/element/yautja_tracked_item) + to_chat(caller, span_notice("You remove \the [tracked_item] from the tracking system.")) + playsound(caller.loc, 'modular_RUtgmc/sound/items/pred_bracer.ogg', 75, 1) + return TRUE + + +/obj/item/clothing/gloves/yautja/hunter/verb/add_tracked_item() + set name = "Add Item to Tracker" + set desc = "Add an item to the Yautja tracker." + set category = "Yautja" + set src in usr + . = add_tracked_item_internal(usr, FALSE) + +/obj/item/clothing/gloves/yautja/hunter/proc/add_tracked_item_internal(mob/living/caller, forced = FALSE) + if(caller.stat || (caller.lying_angle && !caller.resting && !caller.IsSleeping()) || (caller.IsParalyzed() || caller.IsUnconscious())) + return FALSE + + . = check_random_function(caller, forced) + if(.) + return + + var/obj/item/untracked_item = caller.get_active_held_item() + if(!untracked_item) + to_chat(caller, span_warning("You need the item in your active hand to remove it from the tracker!")) + return FALSE + if(untracked_item in GLOB.tracked_yautja_gear) + to_chat(caller, span_warning("\The [untracked_item] is already being tracked.")) + return FALSE + untracked_item.AddElement(/datum/element/yautja_tracked_item) + to_chat(caller, span_notice("You add \the [untracked_item] to the tracking system.")) + playsound(caller.loc, 'modular_RUtgmc/sound/items/pred_bracer.ogg', 75, 1) + return TRUE + +/obj/item/clothing/gloves/yautja/hunter/verb/bracername() + set name = "Toggle Bracer Name" + set desc = "Toggle whether fellow Yautja that examine you will be able to see your name." + set category = "Yautja" + set src in usr + + var/mob/living/mob = usr + if(mob.stat || (mob.lying_angle && !mob.resting && !mob.IsSleeping()) || (mob.IsParalyzed() || mob.IsUnconscious())) + return + + name_active = !name_active + to_chat(usr, span_notice("\The [src] will [name_active ? "now" : "no longer"] show your name when fellow Yautja examine you.")) + +/obj/item/clothing/gloves/yautja/hunter/verb/idchip() + set name = "Toggle ID Chip" + set desc = "Reveal/Hide your embedded bracer ID chip." + set category = "Yautja" + set src in usr + + var/mob/living/mob = usr + if(mob.stat || (mob.lying_angle && !mob.resting && !mob.IsSleeping()) || (mob.IsParalyzed() || mob.IsUnconscious())) + return + + var/mob/living/carbon/human/H = usr + if(!istype(H) || !HAS_TRAIT(usr, TRAIT_YAUTJA_TECH)) + to_chat(usr, span_warning("You do not know how to use this.")) + return + + if(H.wear_id == embedded_id) + to_chat(H, span_notice("You retract your ID chip.")) + playsound(src, 'sound/machines/click.ogg', 15, 1) + move_chip_to_bracer() + else if(H.wear_id) + to_chat(H, span_warning("Something is obstructing the deployment of your ID chip!")) + else + to_chat(H, span_notice("You expose your ID chip.")) + playsound(src, 'sound/machines/click.ogg', 15, 1) + if(!H.equip_to_slot_if_possible(embedded_id, SLOT_WEAR_ID, override_nodrop = TRUE)) + to_chat(H, span_warning("Something went wrong during your chip's deployment! (Make a Bug Report about this)")) + move_chip_to_bracer() + +/// Verb to let Yautja attempt the unlocking. +/obj/item/clothing/gloves/yautja/hunter/verb/toggle_lock() + set name = "Toggle Bracer Lock" + set desc = "Toggle the lock on your bracers, allowing them to be removed." + set category = "Yautja" + set src in usr + + if(usr.stat) + to_chat(usr, span_warning("You can't do that right now...")) + return FALSE + if(!HAS_TRAIT(usr, TRAIT_YAUTJA_TECH)) + to_chat(usr, span_warning("You have no idea how to use this...")) + return FALSE + + attempt_toggle_lock(usr, FALSE) + return TRUE + +/// Handles all the locking and unlocking of bracers. +/obj/item/clothing/gloves/yautja/proc/attempt_toggle_lock(mob/user, force_lock) + if(!user) + return FALSE + + if(!(flags_equip_slot & ITEM_SLOT_GLOVES)) + return FALSE + + var/obj/item/grab/held_mob = user.get_active_held_item() + if(!istype(held_mob)) + log_attack("[key_name_admin(usr)] has [HAS_TRAIT(src, TRAIT_NODROP) ? "unlocked" : "locked"] their own bracer.") + toggle_lock_internal(user) + return TRUE + + var/mob/living/carbon/human/victim = held_mob.grabbed_thing + var/obj/item/clothing/gloves/yautja/hunter/bracer = victim.gloves + if(isyautja(victim) && !(victim.stat == DEAD)) + to_chat(user, span_warning("You cannot unlock the bracer of a living hunter!")) + return FALSE + + if(!istype(bracer)) + to_chat(user, span_warning("This [victim.species] does not have a bracer attached.")) + return FALSE + + if(alert("Are you sure you want to unlock this [victim.species]'s bracer?", "Unlock Bracers", "Yes", "No") != "Yes") + return FALSE + + if(user.get_active_held_item() == held_mob && victim && victim.gloves == bracer) + user.visible_message(span_warning("[user] presses a few buttons on [victim]'s wrist bracer."), span_danger("You unlock the bracer.")) + bracer.toggle_lock_internal(victim) + return TRUE + +/// The actual unlock/lock function. +/obj/item/clothing/gloves/yautja/proc/toggle_lock_internal(mob/wearer, force_lock) + if(HAS_TRAIT(src, TRAIT_NODROP) && !force_lock) + REMOVE_TRAIT(src, TRAIT_NODROP, TRAIT_GENERIC) + if(!isyautja(wearer)) + to_chat(wearer, span_warning("The bracer beeps pleasantly, releasing it's grip on your forearm.")) + else + to_chat(wearer, span_warning("With an angry blare the bracer releases your forearm.")) + playsound(src, 'modular_RUtgmc/sound/items/air_release.ogg', 15, 1) + return TRUE + + ADD_TRAIT(src, TRAIT_NODROP, TRAIT_GENERIC) + if(isyautja(wearer)) + to_chat(wearer, span_warning("The bracer clamps securely around your forearm and beeps in a comfortable, familiar way.")) + else + to_chat(wearer, span_warning("The bracer clamps painfully around your forearm and beeps angrily. It won't come off!")) + playsound(src, 'sound/machines/click.ogg', 15, 1) + return TRUE diff --git a/modular_RUtgmc/code/modules/cm_preds/yaut_chems.dm b/modular_RUtgmc/code/modules/cm_preds/yaut_chems.dm new file mode 100644 index 0000000000000..5143326824ed4 --- /dev/null +++ b/modular_RUtgmc/code/modules/cm_preds/yaut_chems.dm @@ -0,0 +1,63 @@ +/datum/reagent/thwei //OP yautja chem + name = "Thwei" + description = "A strange, alien liquid." + reagent_state = LIQUID + overdose_threshold = REAGENTS_OVERDOSE + overdose_crit_threshold = REAGENTS_OVERDOSE_CRITICAL + taste_description = "cherry milkshake" + color = "#C8A5DC" // rgb: 200, 165, 220 + purge_list = list(/datum/reagent/medicine, /datum/reagent/toxin, /datum/reagent/zombium) + purge_rate = 5 + trait_flags = TACHYCARDIC + +/datum/reagent/thwei/on_mob_add(mob/living/L, metabolism) + if(isyautja(L)) + to_chat(L, span_userdanger("You feel revitalized!")) + else + to_chat(L, span_userdanger("Something feels off!")) + L.AdjustParalyzed(20) + +/datum/reagent/thwei/on_mob_life(mob/living/L, metabolism) + . = ..() + if(isyautja(L)) + L.blood_volume += 3 + L.hallucination = 0 + L.dizziness = 0 + L.adjustStaminaLoss(-15) + L.adjustToxLoss(-3) + L.adjustOxyLoss(-3) + L.adjustCloneLoss(-3) + L.adjustBrainLoss(-3) + L.adjustDrowsyness(-10) + L.AdjustUnconscious(-40) + L.AdjustStun(-40) + L.AdjustParalyzed(-40) + var/mob/living/carbon/human/species/yautja/Y = L + for(var/datum/limb/X in Y.limbs) + for(var/datum/wound/internal_bleeding/W in X.wounds) + W.damage = max(0, W.damage - (effect_str)) + if(X.limb_status & (LIMB_BROKEN | LIMB_SPLINTED)) + X.add_limb_flags(LIMB_STABILIZED) + else + L.vomit() + L.adjustToxLoss(0.1) + L.adjustFireLoss(0.1) + L.hallucination += 20 + L.jitter(8) + L.dizzy(8) + L.reagent_shock_modifier -= PAIN_REDUCTION_HEAVY + return ..() + +/datum/reagent/thwei/on_mob_delete(mob/living/L, metabolism) + if(isyautja(L)) + to_chat(L, span_userdanger("You feel thwei powers wearing off!")) + else + to_chat(L, span_userdanger("Toxins are wearing off!")) + +/datum/reagent/thwei/overdose_process(mob/living/L, metabolism) + L.take_limb_damage(2*effect_str, 0) + +/datum/reagent/thwei/overdose_crit_process(mob/living/L, metabolism) + L.apply_damages(2*effect_str, 3*effect_str) + L.adjustBrainLoss(1.5*effect_str, TRUE) + diff --git a/modular_RUtgmc/code/modules/cm_preds/yaut_hudprocs.dm b/modular_RUtgmc/code/modules/cm_preds/yaut_hudprocs.dm new file mode 100644 index 0000000000000..ef64534adfbdd --- /dev/null +++ b/modular_RUtgmc/code/modules/cm_preds/yaut_hudprocs.dm @@ -0,0 +1,390 @@ +/mob/living/carbon/human/proc/mark_panel() + if(stat || (lying_angle && !resting && !IsSleeping()) || (IsParalyzed() || IsUnconscious())) + to_chat(src, span_danger("You're not able to do that right now.")) + return + + var/mob/living/carbon/human/T = src + if(!isyautja(T)) + return + + var/list/options = list() + var/list/optionsp = list( + "Mark as Prey", + "Un-Mark as Prey", + "Mark as Thralled", + "Un-Mark as Thralled", + "Mark as Honored", + "Un-Mark as Honored", + "Mark as Dishonorable", + "Un-Mark as Dishonorable", + "Mark as Gear Carrier", + "Un-Mark as Gear Carrier" + ) + + options += optionsp + + var/input = tgui_input_list(usr, "Select which mark to apply", "Mark Panel", options) + + if(!input) + return + else if(input) + + switch(input) + if("Mark as Prey") + T.mark_for_hunt() + if("Un-Mark as Prey") + T.remove_from_hunt() + if("Mark as Honored") + T.mark_honored() + if("Un-Mark as Honored") + T.unmark_honored() + if("Mark as Dishonorable") + T.mark_dishonored() + if("Un-Mark as Dishonorable") + T.unmark_dishonored() + if("Mark as Gear Carrier") + T.mark_gear() + if("Un-Mark as Gear Carrier") + T.unmark_gear() + if("Mark as Thralled") + T.mark_thralled() + if("Un-Mark as Thralled") + T.unmark_thralled() + + return + +// Mark for Hunt verbs +// Add prey for hunt +/mob/living/carbon/human/proc/mark_for_hunt() + // Only one prey per pred + if(hunter_data.prey) + to_chat(src, span_danger("You're already hunting something.")) + return + + if(!isyautja(src)) + to_chat(src, span_warning("How did you get this verb?")) + return + + // List all possible preys + // We only target living humans and xenos + var/list/target_list = list() + for(var/mob/living/prey in view(7, usr.client)) + if((ishumanbasic(prey) || isxeno(prey)) && prey.stat != DEAD && prey.client) + target_list += prey + + var/mob/living/carbon/M = tgui_input_list(usr, "Target", "Choose a prey.", target_list) + if(!M) + return + if(M.hunter_data.hunter) + to_chat(src, span_yautjabold("[M] is already being hunted by [M.hunter_data.hunter.real_name]!")) + return + if(M.hunter_data.automatic_target && M.hunter_data.targeted != src) + to_chat(src, span_yautjabold("[M] is autamaticly selected for hunt for other hunter!")) + return + hunter_data.prey = M + M.hunter_data.hunter = src + M.hunter_data.hunted = TRUE + M.hud_set_hunter() + + // Notify the pred + to_chat(src, span_yautjabold("You have chosen [hunter_data.prey] as your next prey.")) + + // Notify other preds + message_all_yautja("[real_name] has chosen [hunter_data.prey] ([max(hunter_data.prey.life_kills_total, hunter_data.prey.default_honor_value)] honor) as their next target at \the [get_area_name(hunter_data.prey)].") + + // log to server file + log_game("[key_name(src)] has marked [key_name(hunter_data.prey)] for the Hunt in [get_area(hunter_data.prey)] ([x],[y],[z]).") + +// Removing prey from hunt (i.e. it died, it bugged, it left the game, etc.) +/mob/living/carbon/human/proc/remove_from_hunt() + if(!hunter_data.prey) + to_chat(src, span_danger("You're not hunting anything right now.")) + return + + if(!isyautja(src)) + to_chat(src, span_warning("How did you get this verb?")) + return + + if(alert(usr, "Are you sure you want to abandon this prey?", "Remove from Hunt:", "Yes", "No") != "Yes") + return + var/mob/living/carbon/prey = hunter_data.prey + to_chat(src, span_yautjabold("You have removed [prey] from your hunt.")) + prey.hunter_data.hunter = null + prey.hunter_data.hunted = FALSE + log_game("[key_name(src)] has un-marked [key_name(hunter_data.prey)] for the Hunt") + hunter_data.prey = null + prey.hud_set_hunter() + + + +/mob/living/carbon/human/proc/mark_honored() + if(!isyautja(src)) + to_chat(src, span_warning("How did you get this verb?")) + return + + var/list/target_list = list() + for(var/mob/living/carbon/target in view(7, usr.client)) + if((ishumanbasic(target) || isxeno(target)) && target.stat != DEAD) + target_list += target + + var/mob/living/carbon/T = tgui_input_list(usr, "Target", "Choose a target.", target_list) + if(!T) + return + if(T.hunter_data.honored) + to_chat(src, span_yautjabold("[T] has already been honored by [T.hunter_data.honored_set.real_name] for '[T.hunter_data.honored_reason]'!")) + return + + var/reason = stripped_input(usr, "Enter the reason for marking your target as honored.", "Mark as Honored", "", 120) + + if(!reason) + return + + log_game("[key_name(src)] has marked [key_name(T)] as Honored for '[reason]'.") + message_all_yautja("[real_name] has marked [T] as Honored for '[reason]'.") + + T.hunter_data.honored_set = src + hunter_data.honored_targets += T + T.hunter_data.honored = TRUE + T.hunter_data.honored_reason = "[reason]' by '[src.real_name]" + T.hud_set_hunter() + + + +/mob/living/carbon/human/proc/unmark_honored() + if(!isyautja(src)) + to_chat(src, span_warning("How did you get this verb?")) + return + + var/list/target_list = list() + for(var/mob/living/carbon/target in view(7, usr.client)) + if((ishumanbasic(target) || isxeno(target)) && target.stat != DEAD) + if(target.hunter_data.honored) + target_list += target + + var/mob/living/carbon/T = tgui_input_list(usr, "Target", "Choose a target.", target_list) + if(!T) + return + if(!T.hunter_data.honored) + to_chat(src, span_yautjabold("[T] is not marked as honored!")) + return + + if(!T.hunter_data.honored_set || src == T.hunter_data.honored_set) + + log_game("[key_name(src)] has un-marked [key_name(T)] as honored!") + message_all_yautja("[real_name] has un-marked [T] as honored!'.") + + T.hunter_data.honored_set = null + hunter_data.honored_targets += T + T.hunter_data.honored = FALSE + T.hunter_data.honored_reason = null + T.hud_set_hunter() + else + to_chat(src, span_yautjabold("You cannot undo the actions of a living brother or sister!")) + + + +/mob/living/carbon/human/proc/mark_dishonored() + if(!isyautja(src)) + to_chat(src, span_warning("How did you get this verb?")) + return + + var/list/target_list = list() + for(var/mob/living/carbon/target in view(7, usr.client)) + if((ishumanbasic(target) || isxeno(target)) && target.stat != DEAD) + target_list += target + + if(isyautja(src) && src.hunter_data.thrall) + target_list += src.hunter_data.thrall + + var/mob/living/carbon/T = tgui_input_list(usr, "Target", "Choose a target.", target_list) + if(!T) + return + if(T.hunter_data.dishonored) + to_chat(src, span_yautjabold("[T] has already been marked as dishonorable by [T.hunter_data.dishonored_set.real_name] for '[T.hunter_data.dishonored_reason]'!")) + return + + var/reason = stripped_input(usr, "Enter the reason for marking your target as dishonorable.", "Mark as Dishonorable", "", 120) + + if(!reason) + return + + log_game("[key_name(src)] has marked [key_name(T)] as Dishonorable for '[reason]'.") + message_all_yautja("[real_name] has marked [T] as Dishonorable for '[reason]'.") + + T.hunter_data.dishonored_set = src + hunter_data.dishonored_targets += T + T.hunter_data.dishonored = TRUE + T.hunter_data.dishonored_reason = "[reason]' by '[src.real_name]" + T.hud_set_hunter() + + + +/mob/living/carbon/human/proc/unmark_dishonored() + if(!isyautja(src)) + to_chat(src, span_warning("How did you get this verb?")) + return + + var/list/target_list = list() + for(var/mob/living/carbon/target in view(7, usr.client)) + if((ishumanbasic(target) || isxeno(target)) && target.stat != DEAD) + if(target.job != "Predalien" && target.job != "Predalien Larva") + if(target.hunter_data.dishonored) + target_list += target + + if(isyautja(src) && src.hunter_data.thrall) + target_list += src.hunter_data.thrall + + var/mob/living/carbon/T = tgui_input_list(usr, "Target", "Choose a target.", target_list) + if(!T) + return + if(!T.hunter_data.dishonored) + to_chat(src, span_yautjabold("[T] is not marked as dishonorable!")) + return + + if(!T.hunter_data.dishonored_set || src == T.hunter_data.dishonored_set) + + log_game("[key_name(src)] has un-marked [key_name(T)] as dishonorable!") + message_all_yautja("[real_name] has un-marked [T] as dishonorable!'.") + + T.hunter_data.dishonored_set = null + hunter_data.dishonored_targets -= T + T.hunter_data.dishonored = FALSE + T.hunter_data.dishonored_reason = null + T.hud_set_hunter() + else + to_chat(src, span_yautjabold("You cannot undo the actions of a living brother or sister!")) + + + +/mob/living/carbon/human/proc/mark_gear() + if(!isyautja(src)) + to_chat(src, span_warning("How did you get this verb?")) + return + + var/list/target_list = list() + for(var/mob/living/carbon/target in view(7, usr.client)) + if((ishumanbasic(target) && target.stat != DEAD)) + target_list += target + + var/mob/living/carbon/T = tgui_input_list(usr, "Target", "Choose a target.", target_list) + if(!T) + return + if(T.hunter_data.gear) + to_chat(src, span_yautjabold("[T] has already been marked as a gear carrier by [T.hunter_data.gear_set]!")) + return + + log_game("[key_name(src)] has marked [key_name(T)] as a Gear Carrier!") + message_all_yautja("[real_name] has marked [T] as a Gear Carrier!'.") + + T.hunter_data.gear_set = src + hunter_data.gear_targets += T + T.hunter_data.gear = TRUE + T.hud_set_hunter() + + + +/mob/living/carbon/human/proc/unmark_gear() + if(!isyautja(src)) + to_chat(src, span_warning("How did you get this verb?")) + return + + var/list/target_list = list() + for(var/mob/living/carbon/target in view(7, usr.client)) + if((ishumanbasic(target) && target.stat != DEAD)) + if(target.hunter_data.gear) + target_list += target + + var/mob/living/carbon/T = tgui_input_list(usr, "Target", "Choose a target.", target_list) + if(!T) + return + if(!T.hunter_data.gear) + to_chat(src, span_yautjabold("[T] is not marked as a gear carrier!")) + return + + if(!T.hunter_data.gear_set || src == T.hunter_data.gear_set) + + log_game("[key_name(src)] has un-marked [key_name(T)] as a Gear Carrier!") + message_all_yautja("[real_name] has un-marked [T] as a Gear Carrier!'.") + + T.hunter_data.gear_set = null + hunter_data.gear_targets -= T + T.hunter_data.gear = FALSE + T.hud_set_hunter() + else + to_chat(src, span_yautjabold("You cannot undo the actions of a living brother or sister!")) + + +/mob/living/carbon/human/proc/mark_thralled() + if(!isyautja(src)) + to_chat(src, span_warning("How did you get this verb?")) + return + + if(hunter_data.thrall) + to_chat(src, span_warning("You already have a thrall.")) + return + + // List all possible targets + // We only target living humans + var/list/target_list = list() + for(var/mob/living/carbon/target in view(7, usr.client)) + if(ishumanbasic(target) && target.stat != DEAD) + target_list += target + + var/mob/living/carbon/T = tgui_input_list(usr, "Target", "Choose a target.", target_list) + if(!T) + return + if(T.hunter_data.thralled) + to_chat(src, span_yautjabold("[T] has already been thralled by [T.hunter_data.thralled_set.real_name] for '[T.hunter_data.thralled_reason]'!")) + return + + var/reason = stripped_input(usr, "Enter the reason for marking your target as thralled.", "Mark as Thralled", "", 120) + + if(!reason) + return + + log_game("[key_name(src)] has taken [key_name(T)] as their Thrall for '[reason]'.") + message_all_yautja("[real_name] has taken [T] as their Thrall for '[reason]'.") + + T.hunter_data.thralled_set = src + T.hunter_data.thralled = TRUE + T.hunter_data.thralled_reason = reason + hunter_data.thrall = T + T.hud_set_hunter() + + + +/mob/living/carbon/human/proc/unmark_thralled() + if(!isyautja(src)) + to_chat(src, span_warning("How did you get this verb?")) + return + + // List all possible targets + // We only target living humans + var/list/target_list = list() + for(var/mob/living/carbon/target in view(7, usr.client)) + if(ishumanbasic(target) && target.stat != DEAD) + if(target.hunter_data.thralled) + target_list += target + + if(isyautja(src) && src.hunter_data.thrall) + target_list += src.hunter_data.thrall + + var/mob/living/carbon/T = tgui_input_list(usr, "Target", "Choose a target.", target_list) + if(!T) + return + if(!T.hunter_data.thralled) + to_chat(src, span_yautjabold("[T] is not marked as thralled!")) + return + + if(!T.hunter_data.thralled_set || src == T.hunter_data.thralled_set) + + log_game("[key_name(src)] has released [key_name(T)] from thralldom!") + message_all_yautja("[real_name] has released [T] from thralldom!'.") + + T.hunter_data.thralled_set = null + T.hunter_data.thralled = FALSE + T.hunter_data.thralled_reason = null + hunter_data.thrall = null + T.hud_set_hunter() + else + to_chat(src, span_yautjabold("You cannot undo the actions of a living brother or sister!")) diff --git a/modular_RUtgmc/code/modules/cm_preds/yaut_items.dm b/modular_RUtgmc/code/modules/cm_preds/yaut_items.dm new file mode 100644 index 0000000000000..798a2c46006a3 --- /dev/null +++ b/modular_RUtgmc/code/modules/cm_preds/yaut_items.dm @@ -0,0 +1,1219 @@ +//Items specific to yautja. Other people can use em, they're not restricted or anything. +//They can't, however, activate any of the special functions. +//Thrall subtypes are located in /code/modules/cm_preds/thrall_items.dm + +/proc/add_to_missing_pred_gear(obj/item/W) + if(!is_centcom_level(W.z)) + GLOB.loose_yautja_gear |= W + +/proc/remove_from_missing_pred_gear(obj/item/W) + GLOB.loose_yautja_gear -= W + +//=================//\\=================\\ +//======================================\\ + +/* + EQUIPMENT +*/ + +//======================================\\ +//=================\\//=================\\ + +/obj/item/clothing/suit/armor/yautja + name = "ancient alien armor" + desc = "Ancient armor made from a strange alloy. It feels cold with an alien weight." + + icon = 'modular_RUtgmc/icons/obj/hunter/pred_gear.dmi' + icon_state = "halfarmor1_ebony" + item_state = "armor" + item_icons = list( + slot_wear_suit_str = 'modular_RUtgmc/icons/mob/hunter/pred_gear.dmi' + ) + + attachments_by_slot = list( + ACCESSORY_SLOT_ARMOR_Y_C, + ACCESSORY_SLOT_ARMOR_Y_S, + ACCESSORY_SLOT_ARMOR_Y_H, + ACCESSORY_SLOT_ARMOR_Y_RL, + ACCESSORY_SLOT_ARMOR_Y_LL, + ACCESSORY_SLOT_ARMOR_Y_RH, + ACCESSORY_SLOT_ARMOR_Y_LH, + ) + attachments_allowed = list( + /obj/item/armor_module/limb/skeleton/l_arm, + /obj/item/armor_module/limb/skeleton/l_foot, + /obj/item/armor_module/limb/skeleton/l_hand, + /obj/item/armor_module/limb/skeleton/l_leg, + /obj/item/armor_module/limb/skeleton/r_arm, + /obj/item/armor_module/limb/skeleton/r_foot, + /obj/item/armor_module/limb/skeleton/r_hand, + /obj/item/armor_module/limb/skeleton/r_leg, + /obj/item/armor_module/limb/skeleton/head, + /obj/item/armor_module/limb/skeleton/head/spine, + /obj/item/armor_module/limb/skeleton/torso, + ) + + soft_armor = list(MELEE = 20, BULLET = 20, LASER = 20, ENERGY = 20, BOMB = 25, BIO = 20, FIRE = 20, ACID = 20) + + flags_armor_protection = CHEST|GROIN|ARMS + flags_item = ITEM_PREDATOR + flags_inventory = NONE + slowdown = 0 + min_cold_protection_temperature = HELMET_MIN_COLD_PROTECTION_TEMPERATURE + max_heat_protection_temperature = HELMET_MAX_HEAT_PROTECTION_TEMPERATURE + siemens_coefficient = 0.1 + allowed = list( + /obj/item/weapon/harpoon, + /obj/item/weapon/gun/energy/yautja, + /obj/item/weapon/yautja, + /obj/item/weapon/twohanded/yautja, + ) + resistance_flags = UNACIDABLE + item_state_slots = list(slot_wear_suit_str = "halfarmor1") + var/thrall = FALSE//Used to affect icon generation. + +/obj/item/clothing/suit/armor/yautja/Initialize(mapload, armor_number = rand(1,7), armor_material = "ebony", legacy = "None") + . = ..() + if(thrall) + return + + flags_cold_protection = flags_armor_protection + flags_heat_protection = flags_armor_protection + + if(legacy != "None") + switch(legacy) + if("Dragon") + name = "\improper 'Armor of the Dragon'" + icon_state = "halfarmor_elder_tr" + LAZYSET(item_state_slots, slot_wear_suit_str, "halfarmor_elder_tr") + return + if("Swamp") + name = "\improper 'Armor of the Swamp Horror'" + icon_state = "halfarmor_elder_joshuu" + LAZYSET(item_state_slots, slot_wear_suit_str, "halfarmor_elder_joshuu") + return + if("Enforcer") + name = "\improper 'Armor of the Enforcer'" + icon_state = "halfarmor_elder_feweh" + LAZYSET(item_state_slots, slot_wear_suit_str, "halfarmor_elder_feweh") + return + if("Collector") + name = "\improper 'Armor of the Ambivalent Collector'" + icon_state = "halfarmor_elder_n" + LAZYSET(item_state_slots, slot_wear_suit_str, "halfarmor_elder_n") + return + else + name = "clan elder's armor" + icon_state = "halfarmor_elder" + LAZYSET(item_state_slots, slot_wear_suit_str, "halfarmor_elder") + return + + if(armor_number > 7) + armor_number = 1 + if(armor_number) //Don't change full armor number + icon_state = "halfarmor[armor_number]_[armor_material]" + LAZYSET(item_state_slots, slot_wear_suit_str, "halfarmor[armor_number]_[armor_material]") + +/obj/item/clothing/suit/armor/yautja/hunter + name = "clan armor" + desc = "A suit of armor with light padding. It looks old, yet functional." + + soft_armor = list(MELEE = 15, BULLET = 30, LASER = 25, ENERGY = 25, BOMB = 30, BIO = 25, FIRE = 25, ACID = 25) + +/obj/item/clothing/suit/armor/yautja/hunter/pred + anchored = TRUE + color = "#FFE55C" + icon_state = "halfarmor_elder_joshuu" + +/obj/item/clothing/suit/armor/yautja/hunter/full + name = "heavy clan armor" + desc = "A suit of armor with heavy padding. It looks old, yet functional." + icon_state = "fullarmor_ebony" + flags_armor_protection = CHEST|GROIN|ARMS|HEAD|LEGS + flags_item = ITEM_PREDATOR + + soft_armor = list(MELEE = 40, BULLET = 30, LASER = 35, ENERGY = 35, BOMB = 45, BIO = 40, FIRE = 30, ACID = 30) + slowdown = 0.7 + item_state_slots = list(slot_wear_suit_str = "fullarmor") + allowed = list( + /obj/item/weapon/harpoon, + /obj/item/weapon/gun/energy/yautja, + /obj/item/weapon/yautja, + /obj/item/storage/belt/yautja, + /obj/item/weapon/twohanded/yautja, + ) + +/obj/item/clothing/suit/armor/yautja/hunter/full/Initialize(mapload, armor_number, armor_material = "ebony") + . = ..(mapload, 0) + icon_state = "fullarmor_[armor_material]" + LAZYSET(item_state_slots, slot_wear_suit_str, "fullarmor_[armor_material]") + + +/obj/item/clothing/yautja_cape + name = PRED_YAUTJA_CAPE + desc = "A battle-worn cape passed down by elder Yautja." + icon = 'modular_RUtgmc/icons/obj/hunter/pred_gear.dmi' + icon_state = "fullcape" + item_icons = list( + slot_back_str = 'modular_RUtgmc/icons/mob/hunter/pred_gear.dmi' + ) + flags_equip_slot = ITEM_SLOT_BACK + flags_item = ITEM_PREDATOR + resistance_flags = UNACIDABLE + var/clan_rank_required = CLAN_RANK_ELDER_INT + var/councillor_override = FALSE + +/obj/item/clothing/yautja_cape/Initialize(mapload, new_color = "#654321") + . = ..() + color = new_color + +/obj/item/clothing/yautja_cape/dropped(mob/living/user) + add_to_missing_pred_gear(src) + ..() + +/obj/item/clothing/yautja_cape/pickup(mob/living/user) + if(isyautja(user)) + remove_from_missing_pred_gear(src) + ..() + +/obj/item/clothing/yautja_cape/Destroy() + . = ..() + remove_from_missing_pred_gear(src) // after due to item handling calling dropped() + +/obj/item/clothing/yautja_cape/ceremonial + name = PRED_YAUTJA_CEREMONIAL_CAPE + icon_state = "ceremonialcape" + clan_rank_required = CLAN_RANK_ELDER_INT + +/obj/item/clothing/yautja_cape/third + name = PRED_YAUTJA_THIRD_CAPE + icon_state = "thirdcape" + clan_rank_required = CLAN_RANK_ELDER_INT + +/obj/item/clothing/yautja_cape/half + name = PRED_YAUTJA_HALF_CAPE + icon_state = "halfcape" + clan_rank_required = CLAN_RANK_BLOODED_INT + +/obj/item/clothing/yautja_cape/quarter + name = PRED_YAUTJA_QUARTER_CAPE + icon_state = "quartercape" + clan_rank_required = CLAN_RANK_BLOODED_INT + +/obj/item/clothing/yautja_cape/poncho + name = PRED_YAUTJA_PONCHO + icon_state = "councilor_poncho" + clan_rank_required = CLAN_RANK_BLOODED_INT + +/obj/item/clothing/shoes/marine/yautja + name = "ancient alien greaves" + desc = "Greaves made from scraps of cloth and a strange alloy. They feel cold with an alien weight." + + icon = 'modular_RUtgmc/icons/obj/hunter/pred_gear.dmi' + item_icons = list( + slot_shoes_str = 'modular_RUtgmc/icons/mob/hunter/pred_gear.dmi' + ) + icon_state = "y-boots1_ebony" + + resistance_flags = UNACIDABLE + permeability_coefficient = 0.01 + flags_inventory = NOSLIPPING + flags_armor_protection = FEET|LEGS + flags_item = ITEM_PREDATOR + + siemens_coefficient = 0.2 + min_cold_protection_temperature = SHOE_MIN_COLD_PROTECTION_TEMPERATURE + max_heat_protection_temperature = SHOE_MAX_HEAT_PROTECTION_TEMPERATURE + + soft_armor = list(MELEE = 15, BULLET = 25, LASER = 20, ENERGY = 20, BOMB = 25, BIO = 20, FIRE = 20, ACID = 20) + var/thrall = FALSE//Used to affect icon generation. + +/obj/item/clothing/shoes/marine/yautja/New(location, boot_number = rand(1,4), armor_material = "ebony") + ..() + if(thrall) + return + if(boot_number > 4) + boot_number = 1 + icon_state = "y-boots[boot_number]_[armor_material]" + + flags_cold_protection = flags_armor_protection + flags_heat_protection = flags_armor_protection + +/obj/item/clothing/shoes/marine/yautja/update_icon_state() + return + +/obj/item/clothing/shoes/marine/yautja/hunter + name = "clan greaves" + desc = "A pair of armored, perfectly balanced boots. Perfect for running through the jungle." + + soft_armor = list(MELEE = 20, BULLET = 30, LASER = 25, ENERGY = 25, BOMB = 30, BIO = 25, FIRE = 25, ACID = 25) + +/obj/item/clothing/shoes/marine/yautja/hunter/pred + color = "#FFE55C" + icon_state = "y-boots2" + anchored = TRUE + +/obj/item/clothing/shoes/marine/yautja/hunter/knife + attachments_allowed = list( + /obj/item/armor_module/storage/boot/yautja_knife + ) + starting_attachments = list(/obj/item/armor_module/storage/boot/yautja_knife) + +/obj/item/armor_module/storage/boot/yautja_knife/Initialize(mapload) + . = ..() + new /obj/item/weapon/yautja/knife(storage) + + +/obj/item/clothing/under/chainshirt + name = "ancient alien mesh suit" + desc = "A strange alloy weave in the form of a vest. It feels cold with an alien weight." + + icon = 'modular_RUtgmc/icons/obj/hunter/pred_gear.dmi' + icon_state = "mesh_shirt" + item_icons = list( + slot_w_uniform_str = 'modular_RUtgmc/icons/mob/hunter/pred_gear.dmi' + ) + + flags_armor_protection = CHEST|GROIN|ARMS + flags_cold_protection = CHEST|GROIN|LEGS|ARMS|FEET|HANDS //Does not cover the head though. + flags_heat_protection = CHEST|GROIN|LEGS|ARMS|FEET|HANDS + flags_item = ITEM_PREDATOR + has_sensor = 0 + sensor_mode = 0 + siemens_coefficient = 0.9 + min_cold_protection_temperature = ICE_PLANET_MIN_COLD_PROTECTION_TEMPERATURE + + soft_armor = list(MELEE = 10, BULLET = 10, LASER = 20, ENERGY = 20, BOMB = 25, BIO = 20, FIRE = 20, ACID = 20) + +/obj/item/clothing/under/chainshirt/hunter + name = "body mesh" + desc = "A set of very fine chainlink in a meshwork for comfort and utility." + + soft_armor = list(MELEE = 10, BULLET = 10, LASER = 25, ENERGY = 25, BOMB = 30, BIO = 25, FIRE = 25, ACID = 25) + resistance_flags = UNACIDABLE + +//=================//\\=================\\ +//======================================\\ + +/* + GEAR +*/ + +//======================================\\ +//=================\\//=================\\ + +//Yautja channel. Has to delete stock encryption key so we don't receive sulaco channel. +/obj/item/radio/headset/yautja + name = "\improper Communicator" + desc = "A strange Yautja device used for projecting the Yautja's voice to the others in its pack. Similar in function to a standard human radio." + icon_state = "communicator" + icon = 'modular_RUtgmc/icons/obj/hunter/pred_gear.dmi' + item_state = "headset" + frequency = YAUT_FREQ + keyslot = /obj/item/encryptionkey/yautja + freqlock = TRUE + independent = TRUE + resistance_flags = UNACIDABLE + var/no_radio_override = TRUE + +/obj/item/radio/headset/yautja/set_frequency(new_frequency) + if(no_radio_override) + new_frequency = YAUT_FREQ + SEND_SIGNAL(src, COMSIG_RADIO_NEW_FREQUENCY, args) + remove_radio(src, frequency) + frequency = add_radio(src, new_frequency) + +/obj/item/radio/headset/yautja/attack_self(mob/living/user) + return //no cargo shitcode + +/obj/item/radio/headset/yautja/talk_into(atom/movable/talking_movable, message, channel, list/spans, datum/language/language, list/message_mods) + if(!isyautja(talking_movable)) //Nope. + to_chat(talking_movable, span_warning("You try to talk into the headset, but just get a horrible shrieking in your ears!")) + return + + for(var/mob/living/carbon/xenomorph/hellhound/hellhound as anything in GLOB.hellhound_list) + if(!hellhound.stat) + to_chat(hellhound, "\[Radio\]: [talking_movable], '[message]'.") + ..() + +/obj/item/radio/headset/yautja/attackby() + return + +/obj/item/radio/headset/yautja/elder //primarily for use in another MR + name = "\improper Elder Communicator" + +/obj/item/encryptionkey/yautja + name = "\improper Yautja encryption key" + desc = "A complicated encryption device." + icon_state = "cypherkey" + channels = list(RADIO_CHANNEL_YAUTJA = TRUE) + +/obj/item/storage/belt/yautja + name = "hunting pouch" + desc = "A Yautja hunting pouch worn around the waist, made from a thick tanned hide. Capable of holding various devices and tools and used for the transport of trophies." + + icon = 'modular_RUtgmc/icons/obj/hunter/pred_gear.dmi' + icon_state = "beltbag" + item_state = "beltbag_w" + item_icons = list( + slot_belt_str = 'modular_RUtgmc/icons/mob/hunter/pred_gear.dmi' + ) + + can_hold = list() + max_w_class = WEIGHT_CLASS_BULKY + flags_item = ITEM_PREDATOR + storage_slots = 12 + max_storage_space = 30 + +/obj/item/yautja_teleporter + name = "relay beacon" + desc = "A device covered in sacred text. It whirrs and beeps every couple of seconds." + + icon = 'modular_RUtgmc/icons/obj/hunter/pred_gear.dmi' + icon_state = "teleporter" + + flags_item = ITEM_PREDATOR + flags_atom = CONDUCT + w_class = WEIGHT_CLASS_TINY + force = 1 + throwforce = 1 + resistance_flags = UNACIDABLE + var/timer = 0 + +/obj/item/yautja_teleporter/attack_self(mob/user) + set waitfor = FALSE + + ..() + + if(!ishuman(user)) + return + + if(!HAS_TRAIT(user, TRAIT_YAUTJA_TECH) || is_centcom_level(user.z)) + to_chat(user, span_warning("You fiddle with it, but nothing happens!")) + return + + var/mob/living/carbon/human/H = user + var/ship_to_tele = list("Yautja Ship" = -1, "Human Ship" = "Human") + + if(H.client && H.client.clan_info) + if(H.client.clan_info.item[3] & CLAN_PERMISSION_ADMIN_VIEW) + var/datum/db_query/clans = SSdbcore.NewQuery("SELECT id, name, description, honor, color FROM [format_table_name("clan")]") + clans.Execute() + while(clans.NextRow()) + if(!SSpredships.is_clanship_loaded(clans.item[1])) + continue + ship_to_tele += list("[clans.item[2]]" = clans.item[1]) + + if(SSpredships.is_clanship_loaded(H.client.clan_info.item[4])) + ship_to_tele += list("Your clan" = "[H.client.clan_info.item[4]]") + + var/clan = ship_to_tele[tgui_input_list(H, "Select a ship to teleport to", "[src]", ship_to_tele)] + if(clan != "Human" && !SSpredships.is_clanship_loaded(clan)) + return // Checking ship is valid + + // Getting an arrival point + var/turf/target_turf + if(clan == "Human") + var/obj/effect/landmark/yautja_teleport/pickedYT = pick(GLOB.mainship_yautja_teleports) + target_turf = get_turf(pickedYT) + else + target_turf = SAFEPICK(SSpredships.get_clan_spawnpoints(clan)) + if(!istype(target_turf)) + return + + // Let's go + playsound(src, 'sound/ambience/signal.ogg', 25, 1, sound_range = 6) + timer = 1 + user.visible_message(span_info("[user] starts becoming shimmery and indistinct...")) + + if(do_after(user, 10 SECONDS, NONE, src, BUSY_ICON_GENERIC, BUSY_ICON_GENERIC)) + // Display fancy animation for you and the person you might be pulling (Legacy) + user.visible_message(span_warning("[icon2html(user, viewers(src))][user] disappears!")) + var/tele_time = animation_teleport_quick_out(user) + var/mob/living/M = user.pulling + SEND_SIGNAL(H, COMSIG_ATOM_TELEPORT, src) + if(istype(M)) // Pulled person + SEND_SIGNAL(M, COMSIG_ATOM_TELEPORT, src) + M.visible_message(span_warning("[icon2html(M, viewers(src))][M] disappears!")) + animation_teleport_quick_out(M) + + sleep(tele_time) // Animation delay + user.trainteleport(target_turf) // Actually teleports everyone, not just you + pulled + + // Undo animations + animation_teleport_quick_in(user) + if(istype(M) && !QDELETED(M)) + animation_teleport_quick_in(M) + timer = 0 + else + addtimer(VARSET_CALLBACK(src, timer, FALSE), 1 SECONDS) + +/obj/item/yautja_teleporter/verb/add_tele_loc() + set name = "Add Teleporter Destination" + set desc = "Adds this location to the teleporter." + set category = "Yautja" + set src in usr + if(!usr || usr.stat || !is_ground_level(usr.z)) + return FALSE + + if(istype(usr.buckled, /obj/structure/bed/nest/)) + return FALSE + + if(!HAS_TRAIT(usr, TRAIT_YAUTJA_TECH)) + to_chat(usr, span_warning("You have no idea how this thing works!")) + return FALSE + + if(loc && istype(usr.loc, /turf)) + var/turf/location = usr.loc + GLOB.yautja_teleports += location + var/name = input("What would you like to name this location?", "Text") as null|text + if(!name) + return FALSE + GLOB.yautja_teleport_descs[name + " ([location.x], [location.y], [location.z])"] = location + to_chat(usr, span_warning("You can now teleport to this location!")) + log_game("[usr] ([usr.key]) has created a new teleport location at [get_area(usr)]") + message_all_yautja("[usr.real_name] has created a new teleport location, [name], at [usr.loc] in [get_area(usr)]") + return TRUE + +//=================//\\=================\\ +//======================================\\ + +/* + OTHER THINGS +*/ + +//======================================\\ +//=================\\//=================\\ + +/obj/item/scalp + name = "scalp" + icon = 'modular_RUtgmc/icons/obj/hunter/pred_gear.dmi' + icon_state = "scalp_1" + item_state = "scalp" + item_icons = list( + slot_l_hand_str = 'modular_RUtgmc/icons/mob/hunter/items_lefthand.dmi', + slot_r_hand_str = 'modular_RUtgmc/icons/mob/hunter/items_righthand.dmi' + ) + var/true_desc = "This is the scalp of a" //humans and Yautja see different things when examining these. + appearance_flags = NONE //So that the blood overlay renders separately and isn't affected by the hair color matrix. + +/obj/item/scalp/Initialize(mapload, mob/living/carbon/human/scalpee, mob/living/carbon/human/user) + . = ..() + + var/variant = rand(1, 4) //Random sprite variant. + icon_state = "scalp_[variant]" + blood_color = "#A10808" //So examine describes it as 'bloody'. Synths can't be scalped so it'll always be human blood. + flags_atom = NOBLOODY //Don't want the ugly item blood overlay ending up on this. We'll use our own blood overlay. + + var/image/blood_overlay = image('modular_RUtgmc/icons/obj/hunter/pred_gear.dmi', "scalp_[variant]_blood") + blood_overlay.appearance_flags = RESET_COLOR + overlays += blood_overlay + + if(!scalpee) //Presumably spawned as map decoration. + true_desc = "This is the scalp of an irrelevant human." + color = list(null, null, null, null, rgb(rand(0,255), rand(0,255), rand(0,255))) + return + + name = "\proper [scalpee.real_name]'s scalp" + color = list(null, null, null, null, rgb(scalpee.r_hair, scalpee.g_hair, scalpee.b_hair)) //Hair color. + + var/they = "they" + var/their = "their" + var/them = "them" + var/themselves = "themselves" + + //Gender? + switch(scalpee.gender) + if(MALE) + their = "his" + they = "he" + them = "him" + themselves = "himself" + + if(FEMALE) + their = "her" + they = "she" + them = "her" + themselves = "herself" + + //What did this person do? + var/list/biography = list() + //Did they disgrace themselves more than humans usually do? + var/dishonourable = FALSE + //Did they distinguish themselves? + var/honourable = FALSE + + if(scalpee.hunter_data.thralled) + biography += "enthralled by [scalpee.hunter_data.thralled_set.real_name] for '[scalpee.hunter_data.thralled_reason]'" + honourable = TRUE + + if(scalpee.hunter_data.honored) + biography += "honored for '[scalpee.hunter_data.honored_reason]'" + honourable = TRUE + + if(scalpee.hunter_data.dishonored) + biography += "marked as dishonorable for '[scalpee.hunter_data.dishonored_reason]'" + dishonourable = TRUE + + if(scalpee.hunter_data.gear) + biography += "killed after [scalpee.hunter_data.gear_set.real_name] marked [them] as a thief of Yautja equipment" + dishonourable = TRUE + + //How impressive a trophy is this? + var/worth = 1 + switch(scalpee.life_kills_total) + if(0) + if(dishonourable) + true_desc += " human who was even more shameful than usual." + worth = -1 + else if(honourable) //They weren't marked as killing anyone but otherwise distinguished themselves. + true_desc += " human." + else + true_desc += "n irrelevant human." + worth = 0 + + if(1 to 4) + if(dishonourable) + true_desc += " human who could have been worthy, had [they] not insisted on disgracing [themselves]." + worth = -1 + else + true_desc += " respectable human with blood on [their] hands." + + if(5 to 9) + true_desc += "n uncommonly destructive human." + if(!dishonourable) + worth = 2 //Even if they did do something dishonourable, this person is worth at least grudging respect. + + if(10 to INFINITY) + true_desc += " truly worthy human, no doubt descended from many storied warriors. [capitalize(their)] arms were soaked to the elbows with the life-blood of many." + worth = 2 + + if(length(biography)) + true_desc += " [scalpee.real_name] was [english_list(biography, final_comma_text = ",")]." + + if(scalpee.hunter_data.hunter == user) //You don't get your name on it unless you hunted them yourself. + if(scalpee.hunter_data.automatic_target && scalpee.hunter_data.targeted == user) + scalpee.hunter_data.complete_target(user) + + switch(worth) + if(-1) + true_desc += span_blue("\n[user.real_name] had the unpleasant duty of running [them] to ground.") + if(0) //You hunted someone with no kills for no real reason. + true_desc += span_blue("\nAn honourable first trophy for a truly precocious child. [user.real_name]'s parents must be so proud.") + if(1) + true_desc += span_blue("\nThis trophy was taken by [user.real_name] after a successful hunt.") + if(2) + true_desc += span_blue("\nThis fine trophy was taken by [user.real_name] after a successful hunt.") + +/obj/item/scalp/examine(mob/user) + . = ..() + if(isyautja(user) || isobserver(user)) + . += true_desc + else + . += span_warning("Scalp-collecting is supposed to be a joke. Has someone been going around doing this shit for real? What next, a necklace of severed ears? Jesus Christ.") + +/obj/item/explosive/grenade/spawnergrenade/hellhound + name = "hellhound caller" + spawner_type = /mob/living/carbon/xenomorph/hellhound + deliveryamt = 1 + desc = "A strange piece of alien technology. It seems to call forth a hellhound." + icon = 'modular_RUtgmc/icons/obj/hunter/pred_gear.dmi' + icon_state = "hellnade" + w_class = WEIGHT_CLASS_TINY + det_time = 30 + var/obj/machinery/camera/current = null + var/turf/activated_turf = null + +/obj/item/explosive/grenade/spawnergrenade/hellhound/dropped(mob/user) + check_eye(user) + return ..() + +/obj/item/explosive/grenade/spawnergrenade/hellhound/attack_self(mob/living/carbon/human/user) + ..() + if(!active) + if(!HAS_TRAIT(user, TRAIT_YAUTJA_TECH)) + to_chat(user, span_warning("What's this thing?")) + return + to_chat(user, span_warning("You activate the hellhound beacon!")) + activate(user) + add_fingerprint(user) + if(iscarbon(user)) + var/mob/living/carbon/C = user + C.toggle_throw_mode() + +/obj/item/explosive/grenade/spawnergrenade/hellhound/activate(mob/user) + if(active) + return + + if(user) + log_attack("[key_name(user)] primed \a [src] in [get_area(user)] ([user.loc.x],[user.loc.y],[user.loc.z]).") + icon_state = initial(icon_state) + "_active" + active = 1 + update_icon() + addtimer(CALLBACK(src, PROC_REF(prime)), det_time) + +/obj/item/explosive/grenade/spawnergrenade/hellhound/prime() + if(spawner_type && deliveryamt) + // Make a quick flash + var/turf/T = get_turf(src) + if(ispath(spawner_type)) + new spawner_type(T) + qdel(src) + return + +/obj/item/explosive/grenade/spawnergrenade/hellhound/check_eye(mob/living/user) + if(user.stat || (user.lying_angle && !user.resting && !user.IsSleeping()) || (user.IsParalyzed() || user.IsUnconscious())) + user.unset_interaction() + else if (!current || get_turf(user) != activated_turf || src.loc != user ) //camera doesn't work, or we moved. + user.unset_interaction() + +/obj/item/explosive/grenade/spawnergrenade/hellhound/New() + . = ..() + + force = 20 + throwforce = 40 + +/obj/item/explosive/grenade/spawnergrenade/hellhound/on_set_interaction(mob/user) + ..() + user.reset_perspective(current) + +/obj/item/explosive/grenade/spawnergrenade/hellhound/on_unset_interaction(mob/user) + ..() + current = null + user.reset_perspective(null) + + +/obj/item/weapon/claymore/mercsword/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 = "officer_sword" + item_state = "machete" + + +// Hunting traps +/obj/item/hunting_trap + name = "hunting trap" + throw_speed = 6.67 + throw_range = 2 + icon = 'modular_RUtgmc/icons/obj/hunter/pred_gear.dmi' + icon_state = "yauttrap0" + desc = "A bizarre Yautja device used for trapping and killing prey." + + resistance_flags = BANISH_IMMUNE + layer = LOWER_ITEM_LAYER + + var/armed = 0 + var/resist_time = 15 SECONDS + var/obj/effect/ebeam/beam + var/tether_range = 5 + var/mob/trapped_mob + +/obj/item/hunting_trap/Initialize() + . = ..() + var/static/list/connections = list( + COMSIG_ATOM_ENTERED = PROC_REF(on_cross), + ) + AddElement(/datum/element/connect_loc, connections) + +/obj/item/hunting_trap/Destroy() + cleanup_tether() + . = ..() + +/obj/item/hunting_trap/dropped(mob/living/carbon/human/mob) //Changes to "camouflaged" icons based on where it was dropped. + if(armed && isturf(mob.loc)) + var/turf/T = mob.loc + if(istype(T,/turf/open/floor/plating/ground/dirt)) + icon_state = "yauttrapdirt" + else if (istype(T,/turf/open/ground/jungle)) + icon_state = "yauttrapgrass" + else + icon_state = "yauttrap1" + ..() + +/obj/item/hunting_trap/attack_self(mob/user as mob) + ..() + if(ishuman(user) && !user.stat && !user.restrained()) + var/wait_time = 3 SECONDS + if(!HAS_TRAIT(user, TRAIT_YAUTJA_TECH)) + wait_time = rand(5 SECONDS, 10 SECONDS) + if(!do_after(user, wait_time, NONE, src, BUSY_ICON_HOSTILE, BUSY_ICON_HOSTILE)) + return + armed = TRUE + anchored = TRUE + icon_state = "yauttrap[armed]" + to_chat(user, span_notice("[src] is now armed.")) + log_attack("[key_name(user)] has armed \a [src] at [ADMIN_JMP_USER(user)].") + user.drop_held_item() + +/obj/item/hunting_trap/attack_hand(mob/living/carbon/human/user) + if(HAS_TRAIT(user, TRAIT_YAUTJA_TECH)) + disarm(user) + //Humans and synths don't know how to handle those traps! + if((issynth(user) || ishuman(user)) && armed) + to_chat(user, span_warning("You foolishly reach out for \the [src]...")) + trapMob(user) + return + . = ..() + +/obj/item/hunting_trap/proc/trapMob(mob/living/carbon/C) + if(!armed) + return + + armed = FALSE + anchored = TRUE + + trapped_mob = C + ADD_TRAIT(C, TRAIT_LEASHED, src) + beam = beam(C, "chain", 'icons/effects/beam.dmi', INFINITY, INFINITY) + RegisterSignal(C, COMSIG_LIVING_DO_RESIST, PROC_REF(resist_callback)) + RegisterSignal(C, COMSIG_MOVABLE_PRE_MOVE, PROC_REF(check_dist)) + + icon_state = "yauttrap0" + playsound(C,'sound/weapons/tablehit1.ogg', 25, 1) + to_chat(C, "[icon2html(src, C)] \red You get caught in \the [src]!") + + log_attack("[key_name(C)] was caught in \a [src] at [ADMIN_JMP_USER(C)].") + + if(ishuman(C)) + C.emote("pain") + if(isxeno(C)) + var/mob/living/carbon/xenomorph/X = C + C.emote("needhelp") + X.interference = 100 // Some base interference to give pred time to get some damage in, if it cannot land a single hit during this time pred is cheeks + message_all_yautja("A hunting trap has caught something in [get_area_name(loc)]!") + +/obj/item/hunting_trap/proc/on_cross(turf/passed, atom/movable/AM) + if(!isliving(AM)) + return + if(CHECK_MULTIPLE_BITFIELDS(AM.pass_flags, HOVERING)) + return + var/mob/living/L = AM + if(L.lying_angle || L.buckled) ///so dragged corpses don't trigger mines. + return + + if(armed) + if(isturf(src.loc)) + var/mob/living/carbon/H = L + if(isyautja(H)) + to_chat(H, span_notice("You carefully avoid stepping on the trap.")) + else + trapMob(H) + for(var/mob/O in viewers(H, null)) + if(O == H) + continue + O.show_message(span_warning("[icon2html(src, O)] [H] gets caught in \the [src]."), EMOTE_VISIBLE) + else if(isanimal(AM) && !istype(AM, /mob/living/simple_animal/parrot)) + armed = FALSE + var/mob/living/simple_animal/SA = AM + SA.health -= 20 + +/obj/item/hunting_trap/proc/check_dist(datum/victim, atom/newloc) + SIGNAL_HANDLER + if(get_dist(newloc, src) >= tether_range) + return COMPONENT_MOVABLE_BLOCK_PRE_MOVE + +/obj/item/hunting_trap/proc/resist_callback() + SIGNAL_HANDLER + + if(isnull(beam)) + return + + INVOKE_ASYNC(src, PROC_REF(resisted)) + +/obj/item/hunting_trap/proc/resisted() + to_chat(trapped_mob, span_danger("You attempt to break out of your tether to [src]. (This will take around [resist_time/10] seconds and you need to stand still)")) + if(!do_after(trapped_mob, resist_time, NONE, src, BUSY_ICON_HOSTILE, BUSY_ICON_HOSTILE)) + return + to_chat(trapped_mob, span_warning("You have broken out of your tether to [src]!")) + cleanup_tether() + +/obj/item/hunting_trap/proc/cleanup_tether() + if(trapped_mob) + UnregisterSignal(trapped_mob, COMSIG_MOVABLE_PRE_MOVE) + REMOVE_TRAIT(trapped_mob, TRAIT_LEASHED, src) + trapped_mob = null + QDEL_NULL(beam) + +/obj/item/hunting_trap/proc/disarm(mob/user) + SIGNAL_HANDLER + armed = FALSE + anchored = FALSE + icon_state = "yauttrap[armed]" + if(user) + to_chat(user, span_notice("[src] is now disarmed.")) + log_attack("[key_name(user)] has disarmed \a [src] at [ADMIN_JMP_USER(user)].") + cleanup_tether() + +/obj/item/hunting_trap/verb/configure_trap() + set name = "Configure Hunting Trap" + set category = "Object" + + var/mob/living/carbon/human/H = usr + if(!HAS_TRAIT(H, TRAIT_YAUTJA_TECH)) + to_chat(H, span_warning("You do not know how to configure the trap.")) + return + var/range = tgui_input_list(H, "Which range would you like to set the hunting trap to?", "Hunting Trap Range", list(2, 3, 4, 5, 6, 7)) + if(isnull(range)) + return + tether_range = range + to_chat(H, span_notice("You set the hunting trap's tether range to [range].")) + +//flavor armor & greaves, not a subtype +/obj/item/clothing/suit/armor/yautja_flavor + name = "alien stone armor" + desc = "A suit of armor made entirely out of stone. Looks incredibly heavy." + + icon = 'modular_RUtgmc/icons/obj/hunter/pred_gear.dmi' + item_icons = list( + slot_wear_suit_str = 'modular_RUtgmc/icons/mob/hunter/pred_gear.dmi' + ) + item_state = "armor" + icon_state = "fullarmor_ebony" + + flags_armor_protection = CHEST|GROIN|ARMS|HEAD|LEGS + soft_armor = list(MELEE = 20, BULLET = 30, LASER = 25, ENERGY = 25, BOMB = 30, BIO = 25, FIRE = 25, ACID = 25) + slowdown = SLOWDOWN_ARMOR_VERY_HEAVY + siemens_coefficient = 0.1 + allowed = list( + /obj/item/weapon/harpoon, + /obj/item/weapon/gun/energy/yautja, + /obj/item/weapon/yautja, + /obj/item/weapon/twohanded/yautja, + ) + resistance_flags = UNACIDABLE + item_state_slots = list(slot_wear_suit_str = "fullarmor_ebony") + +/obj/item/clothing/shoes/yautja_flavor + name = "alien stone greaves" + desc = "A pair of armored, perfectly balanced boots. Perfect for running through cement because they're incredibly heavy." + + icon = 'modular_RUtgmc/icons/obj/hunter/pred_gear.dmi' + item_icons = list( + slot_shoes_str = 'modular_RUtgmc/icons/mob/hunter/pred_gear.dmi' + ) + icon_state = "y-boots2_ebony" + + resistance_flags = UNACIDABLE + flags_armor_protection = FEET|LEGS|GROIN + soft_armor = list(MELEE = 20, BULLET = 30, LASER = 25, ENERGY = 25, BOMB = 30, BIO = 25, FIRE = 25, ACID = 25) + +/obj/item/card/id/bracer_chip + name = "bracer ID chip" + desc = "A complex cypher chip embedded within a set of clan bracers." + icon = 'modular_RUtgmc/icons/obj/items/radio.dmi' + icon_state = "upp_key" + access = list(ACCESS_YAUTJA_SECURE) + w_class = WEIGHT_CLASS_TINY + flags_item = ITEM_PREDATOR + paygrade = null + +/obj/item/card/id/bracer_chip/Initialize() + . = ..() + ADD_TRAIT(src, TRAIT_NODROP, TRAIT_GENERIC) + +/obj/item/card/id/bracer_chip/set_user_data(mob/living/carbon/human/human_user) + if(!istype(human_user)) + return + + registered_name = human_user.real_name + blood_type = human_user.blood_type + + var/list/new_access = list(ACCESS_YAUTJA_SECURE) + var/obj/item/clothing/gloves/yautja/hunter/bracer = loc + if(istype(bracer) && bracer.owner_rank) + switch(bracer.owner_rank) + if(CLAN_RANK_ELDER_INT, CLAN_RANK_LEADER_INT) + new_access = list(ACCESS_YAUTJA_SECURE, ACCESS_YAUTJA_ELDER) + if(CLAN_RANK_ADMIN_INT) + new_access = list(ACCESS_YAUTJA_SECURE, ACCESS_YAUTJA_ELDER, ACCESS_YAUTJA_ANCIENT) + access = new_access + +/obj/item/storage/medicomp + name = "medicomp" + desc = "A complex kit of alien tools and medicines." + icon = 'modular_RUtgmc/icons/obj/items/storage/storage.dmi' + icon_state = "medicomp" + use_sound = "toolbox" + w_class = WEIGHT_CLASS_SMALL + flags_item = ITEM_PREDATOR + storage_slots = 16 + max_storage_space = 17 + can_hold = list( + /obj/item/tool/surgery/stabilizer_gel, + /obj/item/tool/surgery/healing_gun, + /obj/item/tool/surgery/wound_clamp, + /obj/item/reagent_containers/hypospray/autoinjector/yautja, + /obj/item/healthanalyzer/alien, + /obj/item/tool/surgery/healing_gel, + /obj/item/stack/medical/heal_pack/advanced/bruise_pack/predator, + /obj/item/stack/medical/heal_pack/ointment/predator, + ) + +/obj/item/storage/medicomp/full/Initialize(mapload, ...) + . = ..() + new /obj/item/tool/surgery/stabilizer_gel(src) + new /obj/item/tool/surgery/healing_gun(src) + new /obj/item/tool/surgery/wound_clamp(src) + new /obj/item/healthanalyzer/alien(src) + new /obj/item/reagent_containers/hypospray/autoinjector/yautja(src) + new /obj/item/reagent_containers/hypospray/autoinjector/yautja(src) + new /obj/item/reagent_containers/hypospray/autoinjector/yautja(src) + new /obj/item/tool/surgery/healing_gel/(src) + new /obj/item/tool/surgery/healing_gel/(src) + new /obj/item/tool/surgery/healing_gel/(src) + +/obj/item/storage/medicomp/update_icon() + if(!contents.len) + icon_state = "medicomp_open" + else + icon_state = "medicomp" + +/obj/item/reagent_containers/glass/rag/polishing_rag + name = "polishing rag" + desc = "An astonishingly fine, hand-tailored piece of exotic cloth." + icon = 'modular_RUtgmc/icons/obj/hunter/pred_gear.dmi' + icon_state = "polishing_rag" + +/obj/item/reagent_containers/glass/rag/polishing_rag/examine(mob/user) + . = ..() + if(HAS_TRAIT(user, TRAIT_YAUTJA_TECH)) + . += span_notice("You could use this to polish bones.") + +/obj/item/reagent_containers/glass/rag/polishing_rag/afterattack(obj/potential_limb, mob/user, proximity_flag, click_parameters) + + if(!HAS_TRAIT(user, TRAIT_YAUTJA_TECH)) + return ..() + + if(!istype(potential_limb, /obj/item/armor_module/limb/skeleton)) + return ..() + + var/obj/item/armor_module/limb/skeleton/current_limb = potential_limb + if(current_limb.polished) + to_chat(user, span_notice("This limb has already been polished.")) + return ..() + + to_chat(user, span_warning("You start wiping [current_limb] with the [name].")) + if(!do_after(user, 5 SECONDS, NONE, current_limb, BUSY_ICON_HOSTILE, BUSY_ICON_HOSTILE)) + to_chat(user, span_notice("You stop polishing [current_limb].")) + return + to_chat(user, span_notice("You polish [current_limb] to perfection.")) + current_limb.polished = TRUE + current_limb.name = "polished [current_limb.name]" + +//Skeleton limbs, meant to be for bones +//Only an onmob for the skull +/obj/item/armor_module/limb/skeleton + name = "How did you get this?" + desc = "A bone from a human." + flags_attach_features = ATTACH_REMOVABLE|ATTACH_APPLY_ON_MOB|ATTACH_SEPERATE_MOB_OVERLAY|ATTACH_NO_HANDS + icon = 'modular_RUtgmc/icons/obj/items/skeleton.dmi' + attach_icon = 'modular_RUtgmc/icons/obj/items/skeleton.dmi' + mob_overlay_icon = 'modular_RUtgmc/icons/mob/hunter/pred_gear.dmi' + + slot = ACCESSORY_SLOT_ARMOR_M + + icon_state = null + + ///Has it been cleaned by a polishing rag? + var/polished = FALSE + +/obj/item/armor_module/limb/skeleton/l_arm + name = "arm bone" + icon_state = "l_arm" + slot = ACCESSORY_SLOT_ARMOR_Y_LH + +/obj/item/armor_module/limb/skeleton/l_foot + name = "foot bone" + icon_state = "l_foot" + slot = ACCESSORY_SLOT_ARMOR_Y_LL + +/obj/item/armor_module/limb/skeleton/l_hand + name = "hand bone" + icon_state = "l_hand" + slot = ACCESSORY_SLOT_ARMOR_Y_LH + +/obj/item/armor_module/limb/skeleton/l_leg + name = "leg bone" + icon_state = "l_leg" + slot = ACCESSORY_SLOT_ARMOR_Y_LL + +/obj/item/armor_module/limb/skeleton/r_arm + name = "arm bone" + icon_state = "r_arm" + slot = ACCESSORY_SLOT_ARMOR_Y_RH + +/obj/item/armor_module/limb/skeleton/r_foot + name = "foot bone" + icon_state = "r_foot" + slot = ACCESSORY_SLOT_ARMOR_Y_RL + +/obj/item/armor_module/limb/skeleton/r_hand + name = "hand bone" + icon_state = "r_hand" + slot = ACCESSORY_SLOT_ARMOR_Y_RH + +/obj/item/armor_module/limb/skeleton/r_leg + name = "leg bone" + icon_state = "r_leg" + slot = ACCESSORY_SLOT_ARMOR_Y_RL + +/obj/item/armor_module/limb/skeleton/head + name = "skull" + icon_state = "skull" + slot = ACCESSORY_SLOT_ARMOR_Y_H + +/obj/item/armor_module/limb/skeleton/head/spine + icon_state = "spine" + slot = ACCESSORY_SLOT_ARMOR_Y_S + +/obj/item/armor_module/limb/skeleton/torso + name = "ribcage" + icon_state = "torso" + slot = ACCESSORY_SLOT_ARMOR_Y_C + +/obj/item/armor_module/limb/skeleton/examine(mob/living/user) + . = ..() + if(HAS_TRAIT(user, TRAIT_YAUTJA_TECH)) + if(polished) + . += span_notice("Polished to perfection.") + else + . += span_notice("[src] is still dirty.") + +/obj/item/storage/belt/utility/pred + name = "\improper Yautja toolbelt" + desc = "A modular belt with various clips. This version lacks any hunting functionality, and is commonly used by engineers to transport important tools." + icon = 'modular_RUtgmc/icons/obj/hunter/pred_gear.dmi' + icon_state = "utilitybelt_pred" + item_state = "utility" + +/obj/item/storage/belt/utility/pred/full/Initialize() + . = ..() + new /obj/item/tool/screwdriver/yautja(src) + new /obj/item/tool/wrench/yautja(src) + new /obj/item/tool/weldingtool/yautja(src) + new /obj/item/tool/crowbar/yautja(src) + new /obj/item/tool/wirecutters/yautja(src) + new /obj/item/stack/cable_coil(src,30,pick("red","orange")) + new /obj/item/tool/multitool/yautja(src) + +/// SKULLS +/obj/item/skull + name = "skull" + icon = 'modular_RUtgmc/icons/obj/hunter/xeno_skulls.dmi' + resistance_flags = INDESTRUCTIBLE + +/obj/item/skull/queen + name = "Queen skull" + desc = "Skull of a prime hive ruler, mother to many." + icon_state = "queen_skull" + +/obj/item/skull/king + name = "King skull" + desc = "Skull of a militant hive ruler, lord of destruction." + icon_state = "king_skull" + +/obj/item/skull/lurker + name = "Lurker skull" + desc = "Skull of a stealthy xenomorph, a nocturnal entity." + icon_state = "lurker_skull" + +/obj/item/skull/hunter + name = "Hunter skull" + desc = "Skull of a stealthy xenomorph, an ambushing predator." + icon_state = "hunter_skull" + +/obj/item/skull/deacon + name = "Deacon skull" + desc = "Skull of an unusual xenomorph, a mysterious specimen." + icon_state = "deacon_skull" + +/obj/item/skull/spitter + name = "Spitter skull" + desc = "Skull of an acidic xenomorph, a boiling menace." + icon_state = "spitter_skull" + +/obj/item/skull/warrior + name = "Warrior skull" + desc = "Skull of a strong xenomorph, a swift fighter." + icon_state = "warrior_skull" + +/// TOOLS + +/obj/item/tool/crowbar/yautja + name = "yautja crowbar" + desc = "Used to remove floors and to pry open doors, made of an unusual alloy." + icon = 'modular_RUtgmc/icons/obj/hunter/pred_gear.dmi' + icon_state = "bar" + item_state = "bar" + item_icons = list( + slot_l_hand_str = 'modular_RUtgmc/icons/mob/hunter/items_lefthand.dmi', + slot_r_hand_str = 'modular_RUtgmc/icons/mob/hunter/items_righthand.dmi' + ) + +/obj/item/tool/wrench/yautja + name = "yautja wrench" + desc = "A wrench with many common uses. Made of some bizarre alien bones." + icon = 'modular_RUtgmc/icons/obj/hunter/pred_gear.dmi' + icon_state = "wrench" + item_state = "wrench" + item_icons = list( + slot_l_hand_str = 'modular_RUtgmc/icons/mob/hunter/items_lefthand.dmi', + slot_r_hand_str = 'modular_RUtgmc/icons/mob/hunter/items_righthand.dmi' + ) + +/obj/item/tool/wirecutters/yautja + name = "yautja wirecutters" + desc = "This cuts wires, also flesh. Made of some razorsharp animal teeth." + icon = 'modular_RUtgmc/icons/obj/hunter/pred_gear.dmi' + icon_state = "wirescutter" + item_state = "wirescutter" + item_icons = list( + slot_l_hand_str = 'modular_RUtgmc/icons/mob/hunter/items_lefthand.dmi', + slot_r_hand_str = 'modular_RUtgmc/icons/mob/hunter/items_righthand.dmi' + ) + +/obj/item/tool/screwdriver/yautja + name = "yautja screwdriver" + desc = "Some hightech screwing abilities." + icon = 'modular_RUtgmc/icons/obj/hunter/pred_gear.dmi' + icon_state = "screwdriver" + item_state = "screwdriver" + item_icons = list( + slot_l_hand_str = 'modular_RUtgmc/icons/mob/hunter/items_lefthand.dmi', + slot_r_hand_str = 'modular_RUtgmc/icons/mob/hunter/items_righthand.dmi' + ) + force = 7 + random_color = FALSE + +/obj/item/tool/multitool/yautja + name = "yautja multitool" + desc = "Top notch alien tech for B&E through hacking." + icon = 'modular_RUtgmc/icons/obj/hunter/pred_gear.dmi' + icon_state = "multitool" + item_state = "multitool" + item_icons = list( + slot_l_hand_str = 'modular_RUtgmc/icons/mob/hunter/items_lefthand.dmi', + slot_r_hand_str = 'modular_RUtgmc/icons/mob/hunter/items_righthand.dmi' + ) + +/obj/item/tool/weldingtool/yautja + name = "yautja chem welding tool" + desc = "A complex chemical welding device, keep away from youngblood." + icon = 'modular_RUtgmc/icons/obj/hunter/pred_gear.dmi' + icon_state = "welder" + item_icons = list( + slot_l_hand_str = 'modular_RUtgmc/icons/mob/hunter/items_lefthand.dmi', + slot_r_hand_str = 'modular_RUtgmc/icons/mob/hunter/items_righthand.dmi' + ) + force = 10 + throwforce = 15 + usesound = list('sound/items/welder.ogg', 'sound/items/welder2.ogg') + max_fuel = 150 //The max amount of fuel the welder can hold + +/obj/item/weapon/claymore/mercsword/machete/arnold + anchored = TRUE + icon = 'modular_RUtgmc/icons/obj/items/weapons.dmi' + icon_state = "arnold-machete" + desc = "Won by an Elder during their youthful hunting days. None are allowed to touch it." + name = "\improper Dutch's Machete" + force = 130 diff --git a/modular_RUtgmc/code/modules/cm_preds/yaut_machines.dm b/modular_RUtgmc/code/modules/cm_preds/yaut_machines.dm new file mode 100644 index 0000000000000..b1c2211f13881 --- /dev/null +++ b/modular_RUtgmc/code/modules/cm_preds/yaut_machines.dm @@ -0,0 +1,171 @@ +/obj/machinery/cic_maptable/yautja + name = "hunter globe" + desc = "A globe designed by the hunters to show them the location of prey across the hunting grounds." + icon = 'modular_RUtgmc/icons/obj/machines/yautja_machines.dmi' + icon_state = "globe" + + minimap_flag = MINIMAP_FLAG_XENO|MINIMAP_FLAG_MARINE|MINIMAP_FLAG_MARINE_SOM|MINIMAP_FLAG_EXCAVATION_ZONE|MINIMAP_FLAG_YAUTJA + +/obj/machinery/prop/yautja/bubbler + name = "yautja cauldron" + desc = "A large, black machine emitting an ominous hum with an attached pot of boiling fluid. Bits of what appears to be leftover lard and balls of hair can be seen floating inside of it." + icon = 'modular_RUtgmc/icons/obj/machines/yautja_machines.dmi' + icon_state = "vat" + density = TRUE + +/obj/machinery/prop/yautja/bubbler/examine(mob/living/user) + . = ..() + if(HAS_TRAIT(user, TRAIT_YAUTJA_TECH)) + . += span_notice("You can use this machine to clean the skin off limbs, and turn them into bones for your armor.") + . += span_notice("You first need to find a limb. Then you use a ceremonial dagger to prepare it.") + . += span_notice("After preparing the limb, you put it into the cauldron, removing the flesh, leaving you with a bone.") + . += span_notice("You will then clean and polish the resulting bones with a polishing rag, making it ready to be attached to your armor.") + +/obj/machinery/prop/yautja/bubbler/attackby(obj/potential_limb, mob/living/user) + if(!HAS_TRAIT(user, TRAIT_YAUTJA_TECH)) + to_chat(user, span_notice("You have no idea what this does, and you figure it is not time to find out.")) + return + + if(!istype(potential_limb, /obj/item/limb)) + to_chat(user, span_notice("You cannot put this in [src].")) + return + var/obj/item/limb/current_limb = potential_limb + + if(!current_limb.flayed) + to_chat(user, span_notice("This limb is not ready.")) + return + icon_state = "vat_boiling" + to_chat(user, span_warning("You place [current_limb] in and start the cauldron.")) + if(!do_after(user, 15 SECONDS, NONE, current_limb, BUSY_ICON_HOSTILE, BUSY_ICON_HOSTILE)) + to_chat(user, span_notice("You pull [current_limb] back out of the cauldron.")) + icon_state = initial(icon_state) + return + icon_state = initial(icon_state) + + var/obj/item/armor_module/limb/skeleton/new_bone = new current_limb.bone_type(get_turf(src)) + if(istype(new_bone, /obj/item/armor_module/limb/skeleton/head)) + new_bone.desc = span_notice("This skull used to be [current_limb.name].") + qdel(current_limb) + +/obj/machinery/microwave/yautja + name = "alien microwave" + desc = "Dark alloy sinister machine that heats up cold food." + icon = 'modular_RUtgmc/icons/obj/machines/yautja_machines.dmi' + +/obj/machinery/processor/yautja + name = "food grinder" + icon = 'modular_RUtgmc/icons/obj/machines/yautja_machines.dmi' + +/obj/machinery/grill/yautja + name = "alien grill" + desc = "For grilling the most delicious prey." + icon = 'modular_RUtgmc/icons/obj/machines/yautja_machines.dmi' + +/obj/machinery/vending/dinnerware/yautja + name = "dinnerplate dispenser" + icon = 'modular_RUtgmc/icons/obj/machines/yautja_machines.dmi' + products = list( + /obj/item/tool/kitchen/tray = 8, + /obj/item/tool/kitchen/utensil/fork = 6, + /obj/item/tool/kitchen/knife = 3, + /obj/item/reagent_containers/food/drinks/drinkingglass = 8, + /obj/item/clothing/suit/chef/classic = 2, + /obj/item/clothing/head/chefhat = 1, + /obj/item/tool/kitchen/utensil/spoon = 2, + /obj/item/tool/kitchen/utensil/knife = 2, + /obj/item/tool/kitchen/rollingpin = 2, + /obj/item/tool/kitchen/knife/butcher = 2, + ) + +/obj/machinery/vending/engivend/yautja + name = "yautja autolathe" + desc = "Weird alien industrial fabricator." + icon = 'modular_RUtgmc/icons/obj/machines/yautja_machines.dmi' + icon_state = "autolathe" + icon_vend = "autholate_n" + products = list( + /obj/item/tool/multitool/yautja = -1, + /obj/item/tool/analyzer = -1, + /obj/item/t_scanner = -1, + /obj/item/taperecorder = -1, + /obj/item/assembly/igniter = -1, + /obj/item/assembly/signaler = -1, + /obj/item/assembly/infra = -1, + /obj/item/assembly/timer = -1, + /obj/item/assembly/prox_sensor = -1, + /obj/item/light_bulb/tube = -1, + /obj/item/light_bulb/bulb = -1, + /obj/item/ashtray/glass = -1, + /obj/item/frame/camera = -1, + /obj/item/frame/table/reinforced = 10, + /obj/item/frame/table = 10, + /obj/item/reagent_containers/glass/bucket = -1, + ) + +/obj/machinery/griddle/yautja + icon = 'modular_RUtgmc/icons/obj/machines/yautja_machines.dmi' + +/obj/machinery/chem_master/yautja + name = "chemical distributor" + icon = 'modular_RUtgmc/icons/obj/machines/yautja_machines.dmi' + +/obj/structure/xenoautopsy/tank/hugger/yautja + icon = 'modular_RUtgmc/icons/obj/machines/yautja_machines.dmi' + broken_state = /obj/structure/xenoautopsy/tank/escaped/yautja + +/obj/structure/xenoautopsy/tank/escaped/yautja + icon = 'modular_RUtgmc/icons/obj/machines/yautja_machines.dmi' + +//YAUTJA SHIP - CURRENTLY USES STRATA DOORS +/obj/machinery/door/airlock/yautja + name = "\improper Airlock" + icon = 'modular_RUtgmc/icons/obj/doors/strata_doors.dmi' + openspeed = 5 + req_access = null + req_one_access = null + no_panel = TRUE + not_weldable = TRUE + resistance_flags = RESIST_ALL + +/obj/machinery/door/airlock/yautja/secure + req_one_access = list(ACCESS_YAUTJA_SECURE, ACCESS_YAUTJA_ELDER, ACCESS_YAUTJA_ANCIENT) + +/obj/machinery/door/airlock/yautja/secure/elder + req_one_access = list(ACCESS_YAUTJA_ELDER, ACCESS_YAUTJA_ANCIENT) + +/obj/machinery/door/airlock/yautja/secure/ancient + req_one_access = list(ACCESS_YAUTJA_ANCIENT) + +/obj/machinery/door/airlock/sandstone/runed + name = "\improper Runed Sandstone Airlock" + icon = 'modular_RUtgmc/icons/obj/doors/doorrunedsand.dmi' + mineral = "runed sandstone" + openspeed = 4 SECONDS + resistance_flags = RESIST_ALL + color = "#b29082" + +/obj/machinery/door/poddoor/shutters/almayer/yautja + name = "Armory Shutter" + id = "Yautja Armory" + resistance_flags = RESIST_ALL + +/obj/machinery/door/poddoor/shutters/almayer/yautja/Initialize() + . = ..() + RegisterSignal(SSdcs, COMSIG_GLOB_YAUTJA_ARMORY_OPENED, PROC_REF(open)) + +/obj/structure/closet/coffin/predator + name = "strange coffin" + desc = "It's a burial receptacle for the dearly departed. Seems to have weird markings on the side..?" + icon = 'modular_RUtgmc/icons/obj/structures/closet.dmi' + icon_state = "pred_coffin" + icon_closed = "pred_coffin" + icon_opened = "pred_coffin_open" + +/obj/structure/bed/chair/hunter + name = "hunter chair" + desc = "An exquisitely crafted chair for a large humanoid hunter." + icon = 'modular_RUtgmc/icons/obj/hunter/chair.dmi' + icon_state = "chair" + color = rgb(255,255,255) + buildstacktype = null + resistance_flags = UNACIDABLE diff --git a/modular_RUtgmc/code/modules/cm_preds/yaut_mask.dm b/modular_RUtgmc/code/modules/cm_preds/yaut_mask.dm new file mode 100644 index 0000000000000..fd2fac0831a44 --- /dev/null +++ b/modular_RUtgmc/code/modules/cm_preds/yaut_mask.dm @@ -0,0 +1,270 @@ +#define VISION_MODE_OFF 0 +#define VISION_MODE_NVG 1 +#define VISION_MODE_THERMAL 2 +#define VISION_MODE_MESON 3 + +///parent type +/obj/item/clothing/mask/gas/yautja + name = "alien mask" + desc = "A beautifully designed metallic face mask, both ornate and functional." + + icon = 'modular_RUtgmc/icons/obj/hunter/pred_gear.dmi' + item_icons = list( + slot_wear_mask_str = 'modular_RUtgmc/icons/mob/hunter/pred_gear.dmi' + ) + icon_state = "pred_mask1_ebony" + item_state = "helmet" + item_state_slots = list(slot_wear_mask_str = "pred_mask1_ebony") + + soft_armor = list(MELEE = 20, BULLET = 25, LASER = 20, ENERGY = 20, BOMB = 25, BIO = 20, FIRE = 20, ACID = 20) + + min_cold_protection_temperature = SPACE_HELMET_MIN_COLD_PROTECTION_TEMPERATURE + flags_armor_protection = HEAD|FACE|EYES + flags_cold_protection = HEAD + flags_inventory = COVEREYES|COVERMOUTH|NOPRESSUREDMAGE|BLOCKGASEFFECT|BLOCKSHARPOBJ + flags_inv_hide = HIDEEARS|HIDEEYES|HIDEFACE|HIDELOWHAIR + eye_protection = 2 + flags_item = ITEM_PREDATOR + var/current_goggles = VISION_MODE_OFF + resistance_flags = UNACIDABLE + unequip_delay_self = 20 + anti_hug = 5 + var/list/actions_to_add = list( + new /datum/action/predator_action/mask/zoom, + new /datum/action/predator_action/mask/togglesight + ) + var/list/obj/item/clothing/glasses/glasses = list( + "nvg" = new /obj/item/clothing/glasses/night/yautja, + "thermal" = new /obj/item/clothing/glasses/thermal/yautja, + "meson" = new /obj/item/clothing/glasses/meson/yautja, + ) + var/list/mask_huds = list(DATA_HUD_MEDICAL_OBSERVER, DATA_HUD_XENO_STATUS, DATA_HUD_HUNTER, DATA_HUD_HUNTER_CLAN) + var/thrall = FALSE //Used to affect icon generation. + +/obj/item/clothing/mask/gas/yautja/New(location, mask_number = rand(1,12), armor_material = "ebony", legacy = "None") + ..() + forceMove(location) + if(thrall) + return + + if(legacy != "None") + switch(legacy) + if("Dragon") + icon_state = "pred_mask_elder_tr" + LAZYSET(item_state_slots, slot_wear_mask_str, "pred_mask_elder_tr") + return + if("Swamp") + icon_state = "pred_mask_elder_joshuu" + LAZYSET(item_state_slots, slot_wear_mask_str, "pred_mask_elder_joshuu") + return + if("Enforcer") + icon_state = "pred_mask_elder_feweh" + LAZYSET(item_state_slots, slot_wear_mask_str, "pred_mask_elder_feweh") + return + if("Collector") + icon_state = "pred_mask_elder_n" + LAZYSET(item_state_slots, slot_wear_mask_str, "pred_mask_elder_n") + return + + if(mask_number > 12) + mask_number = 1 + + icon_state = "pred_mask[mask_number]_[armor_material]" + LAZYSET(item_state_slots, slot_wear_mask_str, "pred_mask[mask_number]_[armor_material]") + +/obj/item/clothing/glasses/welding/Initialize() + AddComponent(/datum/component/clothing_tint, TINT_NONE, FALSE) + . = ..() + +/obj/item/clothing/mask/gas/yautja/pickup(mob/living/user) + if(isyautja(user)) + remove_from_missing_pred_gear(src) + ..() + +/obj/item/clothing/mask/gas/yautja/Destroy() + remove_from_missing_pred_gear(src) + return ..() + +/obj/item/clothing/mask/gas/yautja/proc/togglesight(mob/living/carbon/human/M) + if(!HAS_TRAIT(M, TRAIT_YAUTJA_TECH) && !M.hunter_data.thralled) + to_chat(M, span_warning("You have no idea how to work this thing!")) + return + if(src != M.wear_mask) //sanity + to_chat(M, span_warning("You must wear \the [src]!")) + return + var/obj/item/clothing/gloves/yautja/Y = M.gloves //Doesn't actually reduce power, but needs the bracers anyway. + if(!Y || !istype(Y)) + to_chat(M, span_warning("You must be wearing your bracers, as they have the power source.")) + return + var/obj/item/G = M.glasses + if(G) + if(!istype(G,/obj/item/clothing/glasses/night/yautja) && !istype(G,/obj/item/clothing/glasses/meson/yautja) && !istype(G,/obj/item/clothing/glasses/thermal/yautja)) + to_chat(M, span_warning("You need to remove your glasses first. Why are you even wearing these?")) + return + M.transferItemToLoc(G, src, TRUE) + switch_vision_mode() + add_vision(M) + +/obj/item/clothing/mask/gas/yautja/proc/switch_vision_mode() //switches to the next one + switch(current_goggles) + if(VISION_MODE_OFF) + current_goggles = VISION_MODE_NVG + if(VISION_MODE_NVG) + current_goggles = VISION_MODE_THERMAL + if(VISION_MODE_THERMAL) + current_goggles = VISION_MODE_MESON + if(VISION_MODE_MESON) + current_goggles = VISION_MODE_OFF + +/obj/item/clothing/mask/gas/yautja/proc/add_vision(mob/living/carbon/human/user) //applies current_goggles + switch(current_goggles) + if(VISION_MODE_NVG) + user.equip_to_slot_if_possible(glasses["nvg"], SLOT_GLASSES, TRUE, FALSE, FALSE, TRUE, TRUE, TRUE) + to_chat(user, span_notice("Low-light vision module: activated.")) + if(VISION_MODE_THERMAL) + user.equip_to_slot_if_possible(glasses["thermal"], SLOT_GLASSES, TRUE, FALSE, FALSE, TRUE, TRUE, TRUE) + to_chat(user, span_notice("Thermal vision module: activated.")) + if(VISION_MODE_MESON) + user.equip_to_slot_if_possible(glasses["meson"], SLOT_GLASSES, TRUE, FALSE, FALSE, TRUE, TRUE, TRUE) + to_chat(user, span_notice("Material vision module: activated.")) + if(VISION_MODE_OFF) + to_chat(user, span_notice("You deactivate your visor.")) + + playsound(src, 'sound/effects/pred_vision.ogg', 15, 1) + user.update_inv_glasses() + +/obj/item/clothing/mask/gas/yautja/dropped(mob/living/carbon/human/user) //Clear the gogglors if the helmet is removed. + if(istype(user) && user.wear_mask == src) //inventory reference is only cleared after dropped(). + for(var/listed_hud in mask_huds) + var/datum/atom_hud/H = GLOB.huds[listed_hud] + H.remove_hud_from(user) + playsound(src, 'modular_RUtgmc/sound/items/air_release.ogg', 15, 1) + for(var/datum/action/action in actions_to_add) + action.remove_action(user) + var/obj/item/G = user.glasses + if(G) //make your hud fuck off + if(current_goggles) + user.UnEquip(G, TRUE, src) + ..() + +/obj/item/clothing/mask/gas/yautja/equipped(mob/living/carbon/human/user, slot) + if(slot == SLOT_WEAR_MASK) + for(var/listed_hud in mask_huds) + var/datum/atom_hud/H = GLOB.huds[listed_hud] + H.add_hud_to(user) + if(current_goggles) + add_vision(user) + for(var/datum/action/action in actions_to_add) + action.give_action(user) + ..() + +/obj/item/clothing/mask/gas/yautja/unequipped(mob/living/carbon/human/user, slot) + if(slot == SLOT_WEAR_MASK) + for(var/listed_hud in mask_huds) + var/datum/atom_hud/H = GLOB.huds[listed_hud] + H.remove_hud_from(user) + playsound(src, 'modular_RUtgmc/sound/items/air_release.ogg', 15, 1) + for(var/datum/action/action in actions_to_add) + action.remove_action(user) + var/obj/item/G = user.glasses + if(G) //make your hud fuck off + if(current_goggles) + user.UnEquip(G, TRUE, src) + ..() + +/obj/item/clothing/mask/gas/yautja/thrall + name = "alien mask" + desc = "A simplistic metallic face mask with advanced capabilities." + icon_state = "thrall_mask" + item_state = "thrall_mask" + icon = 'modular_RUtgmc/icons/obj/hunter/thrall_gear.dmi' + item_icons = list( + slot_wear_mask_str = 'modular_RUtgmc/icons/mob/hunter/thrall_gear.dmi' + ) + item_state_slots = list(slot_wear_mask_str = "thrall_mask") + thrall = TRUE + +/obj/item/clothing/mask/gas/yautja/thrall/togglesight() + set category = "Thrall" + ..() + +/obj/item/clothing/mask/gas/yautja/hunter + name = "clan mask" + desc = "A beautifully designed metallic face mask, both ornate and functional." + + soft_armor = list(MELEE = 20, BULLET = 30, LASER = 25, ENERGY = 25, BOMB = 30, BIO = 25, FIRE = 25, ACID = 25) + eye_protection = 2 + anti_hug = 100 + +/obj/item/clothing/mask/gas/yautja/hunter/pred + anchored = TRUE + color = "#FFE55C" + icon_state = "pred_mask_elder_joshuu" + +/obj/item/clothing/mask/gas/yautja/hunter/togglesight() + set category = "Yautja" + if(!isyautja(usr)) + to_chat(usr, span_warning("You have no idea how to work this thing!")) + return + ..() + +/obj/item/clothing/mask/gas/yautja/damaged + name = "ancient alien mask" + desc = "A beautifully designed metallic face mask, both ornate and functional. This one seems to be old and degraded." + +/obj/item/clothing/mask/gas/yautja/damaged/switch_vision_mode() + switch(current_goggles) + if(VISION_MODE_OFF) + current_goggles = VISION_MODE_NVG + if(VISION_MODE_NVG) + current_goggles = VISION_MODE_OFF + +/obj/item/clothing/mask/gas/yautja/damaged/add_vision(mob/living/carbon/human/user) + switch(current_goggles) + if(VISION_MODE_NVG) + user.equip_to_slot_if_possible(glasses["nvg"], SLOT_GLASSES, TRUE, FALSE, FALSE, TRUE, TRUE, TRUE) + to_chat(user, span_notice("You activate your visor.")) + if(VISION_MODE_OFF) + to_chat(user, span_notice("You deactivate your visor.")) + + playsound(src, 'sound/effects/pred_vision.ogg', 15, 1) + user.update_inv_glasses() + +#undef VISION_MODE_OFF +#undef VISION_MODE_NVG +#undef VISION_MODE_THERMAL +#undef VISION_MODE_MESON + + +//flavor, not a subtype +/obj/item/clothing/mask/yautja_flavor + name = "alien stone mask" + desc = "A beautifully designed face mask, ornate but non-functional and made entirely of stone." + + icon = 'modular_RUtgmc/icons/obj/hunter/pred_gear.dmi' + item_icons = list( + slot_wear_mask_str = 'modular_RUtgmc/icons/mob/hunter/pred_gear.dmi' + ) + icon_state = "pred_mask1_ebony" + + soft_armor = list(MELEE = 10, BULLET = 10, LASER = 0, ENERGY = 0, BOMB = 10, BIO = 0, FIRE = 0, ACID = 0) + flags_armor_protection = HEAD|FACE|EYES + flags_cold_protection = HEAD + flags_inv_hide = HIDEEARS|HIDEEYES|HIDEFACE|HIDELOWHAIR + resistance_flags = UNACIDABLE + item_state_slots = list(slot_wear_mask_str = "pred_mask1_ebony") + var/map_random = FALSE + +/obj/item/clothing/mask/yautja_flavor/Initialize(mapload, ...) + . = ..() + if(mapload && !map_random) + return + + var/list/possible_masks = list(1,2,3,4,5,6,7,8,9,10,11) //12 + var/mask_number = rand(1,11) + if(mask_number in possible_masks) + icon_state = "pred_mask[mask_number]_ebony" + LAZYSET(item_state_slots, slot_wear_mask_str, "pred_mask[mask_number]_ebony") + +/obj/item/clothing/mask/yautja_flavor/map_random + map_random = TRUE diff --git a/modular_RUtgmc/code/modules/cm_preds/yaut_procs.dm b/modular_RUtgmc/code/modules/cm_preds/yaut_procs.dm new file mode 100644 index 0000000000000..2582d678bad34 --- /dev/null +++ b/modular_RUtgmc/code/modules/cm_preds/yaut_procs.dm @@ -0,0 +1,227 @@ +// Notify all preds with the bracer icon +/proc/message_all_yautja(msg, soundeffect = TRUE) + for(var/mob/living/carbon/human/Y in GLOB.yautja_mob_list) + // Send message to the bracer; appear multiple times if we have more bracers + for(var/obj/item/clothing/gloves/yautja/hunter/G in Y.contents) + to_chat(Y, span_yautjabold("[icon2html(G)] \The [G] beeps: [msg]")) + if(G.notification_sound) + playsound(Y.loc, 'modular_RUtgmc/sound/items/pred_bracer.ogg', 75, 1) + +/mob/living/carbon/human/proc/message_thrall(msg) + if(!hunter_data.thrall) + return + + var/mob/living/carbon/T = hunter_data.thrall + + for(var/obj/item/clothing/gloves/yautja/hunter/G in T.contents) + to_chat(T, span_yautjabold("[icon2html(G)] \The [G] beeps: [msg]")) + if(G.notification_sound) + playsound(T.loc, 'modular_RUtgmc/sound/items/pred_bracer.ogg', 75, 1) + +//Update the power display thing. This is called in Life() +/mob/living/carbon/human/proc/update_power_display(perc) + if(hud_used?.pred_power_icon) + switch(perc) + if(91 to INFINITY) + hud_used.pred_power_icon.icon_state = "powerbar100" + if(81 to 91) + hud_used.pred_power_icon.icon_state = "powerbar90" + if(71 to 81) + hud_used.pred_power_icon.icon_state = "powerbar80" + if(61 to 71) + hud_used.pred_power_icon.icon_state = "powerbar70" + if(51 to 61) + hud_used.pred_power_icon.icon_state = "powerbar60" + if(41 to 51) + hud_used.pred_power_icon.icon_state = "powerbar50" + if(31 to 41) + hud_used.pred_power_icon.icon_state = "powerbar40" + if(21 to 31) + hud_used.pred_power_icon.icon_state = "powerbar30" + if(11 to 21) + hud_used.pred_power_icon.icon_state = "powerbar20" + else + hud_used.pred_power_icon.icon_state = "powerbar10" + +/mob/living/carbon/human/proc/butcher() + set category = "Yautja" + set name = "Butcher" + set desc = "Butcher a corpse you're standing on for its tasty meats." + + if(stat || (lying_angle && !resting && !IsSleeping()) || (IsParalyzed() || IsUnconscious()) || lying_angle || buckled) + return + + var/list/choices = list() + for(var/mob/living/carbon/M in view(1, src) - src) + if(Adjacent(M) && M.stat == DEAD) + if(ishuman(M)) + var/mob/living/carbon/human/Q = M + if(Q.species && species && Q.species.name == species.name) + continue + choices += M + + var/mob/living/carbon/T = tgui_input_list(src, "What do you wish to butcher?", "Butcher", choices) + + var/mob/living/carbon/xenomorph/xeno_victim + var/mob/living/carbon/human/victim + + if(!T || !src || !T.stat) + to_chat(src, span_warning("Nope.")) + return + + if(!Adjacent(T)) + to_chat(src, span_warning("You have to be next to your target.")) + return + + if(isxenolarva(T) || isxenofacehugger(T)) + to_chat(src, span_warning("This tiny worm is not even worth using your tools on.")) + return + + if(stat || (lying_angle && !resting && !IsSleeping()) || (IsParalyzed() || IsUnconscious()) || lying_angle || buckled) + return + + if(isxeno(T)) + xeno_victim = T + + else if(ishuman(T)) + victim = T + + if(issynth(T) || isrobot(T) || victim.species.species_flags & ROBOTIC_LIMBS) + to_chat(src, span_warning("You would break your tools if you did this!")) + return + + var/static/list/procedure_choices = list( + "Skin" = null, + "Behead" = "head", + "Delimb - Right Hand" = "r_hand", + "Delimb - Left Hand" = "l_hand", + "Delimb - Right Arm" = "r_arm", + "Delimb - Left Arm" = "l_arm", + "Delimb - Right Foot" = "r_foot", + "Delimb - Left Foot" = "l_foot", + "Delimb - Right Leg" = "r_leg", + "Delimb - Left Leg" = "l_leg", + ) + + var/procedure = "" + + if(victim) + procedure = tgui_input_list(src, "Which slice would you like to take?", "Take Slice", procedure_choices) + if(!procedure) + return + + if(isxeno(T) || procedure == "Skin") + if(T.butchery_progress) + playsound(loc, 'sound/weapons/pierce.ogg', 25) + visible_message(span_danger("[src] goes back to butchering \the [T]."), span_notice("You get back to butchering \the [T].")) + else + playsound(loc, 'sound/weapons/pierce.ogg', 25) + visible_message(span_danger("[src] begins chopping and mutilating \the [T]."), span_notice("You take out your tools and begin your gruesome work on \the [T]. Hold still.")) + T.butchery_progress = 1 + + if(T.butchery_progress == 1) + if(do_after(src, 7 SECONDS, NONE, src, BUSY_ICON_HOSTILE, BUSY_ICON_HOSTILE)) + visible_message(span_danger("[src] makes careful slices and tears out the viscera in \the [T]'s abdominal cavity."), span_notice("You carefully vivisect \the [T], ripping out the guts and useless organs. What a stench!")) + T.butchery_progress = 2 + playsound(loc, 'sound/weapons/slash.ogg', 25) + else + to_chat(src, span_notice("You pause your butchering for later.")) + + if(T.butchery_progress == 2) + if(do_after(src, 6.5 SECONDS, NONE, src, BUSY_ICON_HOSTILE, BUSY_ICON_HOSTILE)) + visible_message(span_danger("[src] hacks away at \the [T]'s limbs and slices off strips of dripping meat."), span_notice("You slice off a few of \the [T]'s limbs, making sure to get the finest cuts.")) + if(xeno_victim && isturf(xeno_victim.loc)) + var/obj/item/reagent_containers/food/snacks/meat/xenomeat = new /obj/item/reagent_containers/food/snacks/meat/xenomeat(T.loc) + xenomeat.name = "raw [xeno_victim.xeno_caste.upgrade_name][xeno_victim.xeno_caste.display_name] steak" + else if(victim && isturf(victim.loc)) + victim.apply_damage(100, BRUTE, pick("r_leg", "l_leg", "r_arm", "l_arm"), FALSE, TRUE) //Basically just rips off a random limb. + var/obj/item/reagent_containers/food/snacks/meat/meat = new /obj/item/reagent_containers/food/snacks/meat(victim.loc) + meat.name = "raw [victim.name] steak" + T.butchery_progress = 3 + playsound(loc, 'sound/weapons/bladeslice.ogg', 25) + else + to_chat(src, span_notice("You pause your butchering for later.")) + + if(T.butchery_progress == 3) + if(do_after(src, 7 SECONDS, NONE, src, BUSY_ICON_HOSTILE, BUSY_ICON_HOSTILE)) + visible_message(span_danger("[src] tears apart \the [T]'s ribcage and begins chopping off bit and pieces."), span_notice("You rip open \the [T]'s ribcage and start tearing the tastiest bits out.")) + if(xeno_victim && isturf(xeno_victim.loc)) + var/obj/item/reagent_containers/food/snacks/meat/xenomeat = new /obj/item/reagent_containers/food/snacks/meat/xenomeat(T.loc) + xenomeat.name = "raw [xeno_victim.xeno_caste.upgrade_name][xeno_victim.xeno_caste.display_name] tenderloin" + else if(victim && isturf(T.loc)) + var/obj/item/reagent_containers/food/snacks/meat/meat = new /obj/item/reagent_containers/food/snacks/meat(victim.loc) + meat.name = "raw [victim.name] tenderloin" + victim.apply_damage(100, BRUTE,"chest", FALSE, FALSE) + T.butchery_progress = 4 + playsound(loc, 'sound/weapons/wristblades_hit.ogg', 25) + else + to_chat(src, span_notice("You pause your butchering for later.")) + + if(T.butchery_progress == 4) + if(do_after(src, 9 SECONDS, NONE, src, BUSY_ICON_HOSTILE, BUSY_ICON_HOSTILE)) + if(xeno_victim && isturf(T.loc)) + visible_message(span_danger("[src] flenses the last of [victim]'s exoskeleton, revealing only bones!."), span_notice("You flense the last of [victim]'s exoskeleton clean off!")) + new /obj/effect/decal/remains/xeno(xeno_victim.loc) + var/obj/item/stack/sheet/animalhide/xeno/xenohide = new /obj/item/stack/sheet/animalhide/xeno(xeno_victim.loc) + xenohide.name = "[xeno_victim.xeno_caste.upgrade_name][xeno_victim.xeno_caste.display_name]-hide" + xenohide.singular_name = "[xeno_victim.xeno_caste.upgrade_name][xeno_victim.xeno_caste.display_name]-hide" + xenohide.merge_type = "[xeno_victim.xeno_caste.upgrade_name][xeno_victim.xeno_caste.display_name]-hide" + else if(victim && isturf(T.loc)) + visible_message(span_danger("[src] reaches down and rips out \the [T]'s spinal cord and skull!."), span_notice("You firmly grip the revealed spinal column and rip [T]'s head off!")) + var/datum/limb/head_limb = victim.get_limb("head") + if(!(head_limb.limb_status & LIMB_DESTROYED)) + victim.apply_damage(150, BRUTE, "head", FALSE, TRUE) + var/obj/item/armor_module/limb/skeleton/head/spine/new_spine = new /obj/item/armor_module/limb/skeleton/head/spine(victim.loc) + new_spine.name = "[victim]'s spine" + else + var/obj/item/reagent_containers/food/snacks/meat/meat = new /obj/item/reagent_containers/food/snacks/meat(victim.loc) + meat.name = "raw [victim.real_name] steak" + new /obj/item/armor_module/limb/skeleton/torso(victim.loc) + var/obj/item/stack/sheet/animalhide/human/hide = new /obj/item/stack/sheet/animalhide/human(victim.loc) + hide.name = "[victim.name]-hide" + hide.singular_name = "[victim.name]-hide" + new /obj/effect/decal/remains/human(T.loc) + T.butchery_progress = 5 //Won't really matter. + playsound(loc, 'sound/weapons/slice.ogg', 25) + if(hunter_data.prey == T) + to_chat(src, span_yautjabold("You have claimed [T] as your trophy.")) + emote("roar2") + message_all_yautja("[src.real_name] has claimed [T] as their trophy.") + hunter_data.prey = null + else + to_chat(src, span_notice("You finish butchering!")) + qdel(T) + else + to_chat(src, span_notice("You pause your butchering for later.")) + else + var/limb = procedure_choices[procedure] + var/limbName = parse_zone(limb) + var/datum/limb/limb_datum = victim.get_limb(limb) + if(limb_datum.limb_status & LIMB_DESTROYED) + to_chat(src, span_warning("The victim lacks a [limbName].")) + return + if(limb_datum.name == "head") + visible_message("[src] reaches down and starts beheading [T].","You reach down and start beheading [T].") + else + visible_message("[src] reaches down and starts removing [T]'s [limbName].","You reach down and start removing [T]'s [limbName].") + if(do_after(src, 9 SECONDS, NONE, src, BUSY_ICON_HOSTILE, BUSY_ICON_HOSTILE)) + if(limb_datum.limb_status & LIMB_DESTROYED) + to_chat(src, span_warning("The victim lacks a [limbName].")) + return + limb_datum.droplimb(TRUE, FALSE, "butchering") + playsound(loc, 'sound/weapons/slice.ogg', 25) + if(hunter_data.prey == T) + to_chat(src, span_yautjabold("You have claimed [T] as your trophy.")) + emote("roar2") + message_all_yautja("[src.real_name] has claimed [T] as their trophy.") + hunter_data.prey = null + else + to_chat(src, span_notice("You finish butchering!")) + +/area/yautja + name = "\improper Yautja Ship" + icon_state = "teleporter" + ceiling = CEILING_METAL + requires_power = FALSE + static_lighting = FALSE + base_lighting_alpha = 255 diff --git a/modular_RUtgmc/code/modules/cm_preds/yaut_shield.dm b/modular_RUtgmc/code/modules/cm_preds/yaut_shield.dm new file mode 100644 index 0000000000000..33c9b5cf32b08 --- /dev/null +++ b/modular_RUtgmc/code/modules/cm_preds/yaut_shield.dm @@ -0,0 +1,125 @@ +/obj/item/weapon/shield/riot/yautja + name = "clan shield" + desc = "A large tribal shield made of a strange metal alloy. The face of the shield bears three skulls, two human, one alien." + icon = 'modular_RUtgmc/icons/obj/hunter/pred_gear.dmi' + icon_state = "shield" + item_icons = list( + slot_l_hand_str = 'modular_RUtgmc/icons/mob/hunter/items_lefthand.dmi', + slot_r_hand_str = 'modular_RUtgmc/icons/mob/hunter/items_righthand.dmi', + slot_back_str = 'modular_RUtgmc/icons/mob/hunter/pred_gear.dmi' + ) + item_state = "shield" + flags_item = ITEM_PREDATOR + flags_equip_slot = ITEM_SLOT_BACK + resistance_flags = UNACIDABLE + + base_icon_state = "shield" + + var/passive_block = 15 + var/readied_block = 45 + + var/readied_slowdown = 0.5 // Walking around in a readied shield stance slows you! The armor defs are a useful existing reference point. + var/shield_readied = FALSE + var/blocks_on_back = TRUE + + max_integrity = 400 + integrity_failure = 0 + + var/last_attack = 0 + var/last_lowered = 0 + var/cooldown_time = 2.5 SECONDS + +/obj/item/weapon/shield/riot/yautja/set_shield() + return + +/obj/item/weapon/shield/riot/yautja/AltClick(mob/user) + if(!can_interact(user)) + return ..() + if(!ishuman(user)) + return ..() + if(!(user.l_hand == src || user.r_hand == src)) + return ..() + if(!HAS_TRAIT(src, TRAIT_NODROP)) + ADD_TRAIT(src, TRAIT_NODROP, TRAIT_GENERIC) + to_chat(user, span_warning("You tighten the strap of [src] around your hand!")) + else + REMOVE_TRAIT(src, TRAIT_NODROP, TRAIT_GENERIC) + to_chat(user, span_notice("You loosen the strap of [src] around your hand!")) + +/obj/item/weapon/shield/riot/yautja/proc/raise_shield(mob/user as mob) // Prepare for an attack. Slows you down slightly, but increases chance to block. + if(world.time < last_lowered + cooldown_time) + to_chat(user, span_warning("You need wait a little bit more before raise shield again!")) + return + + user.visible_message(span_blue("\The [user] raises \the [src].")) + shield_readied = TRUE + icon_state = "[base_icon_state]_ready" + item_state = "[base_icon_state]_ready" + user.shield_slowdown = max(readied_slowdown, user.shield_slowdown) + + if(user.r_hand == src) + user.update_inv_r_hand() + if(user.l_hand == src) + user.update_inv_l_hand() + +/obj/item/weapon/shield/riot/yautja/proc/lower_shield(mob/user as mob) + user.visible_message(span_blue("\The [user] lowers \the [src].")) + shield_readied = FALSE + icon_state = base_icon_state + item_state = base_icon_state + + var/mob/living/carbon/human/H = user + var/set_shield_slowdown = 0 + var/obj/item/weapon/shield/riot/yautja/offhand_shield + if(H.l_hand == src && istype(H.r_hand, /obj/item/weapon/shield/riot/yautja)) + offhand_shield = H.r_hand + else if(H.r_hand == src && istype(H.l_hand, /obj/item/weapon/shield/riot/yautja)) + offhand_shield = H.l_hand + if(offhand_shield?.shield_readied) + set_shield_slowdown = offhand_shield.readied_slowdown + H.shield_slowdown = set_shield_slowdown + + last_lowered = world.time + + if(user.r_hand == src) + user.update_inv_r_hand() + if(user.l_hand == src) + user.update_inv_l_hand() + +/obj/item/weapon/shield/riot/yautja/proc/toggle_shield(mob/user as mob) + if(shield_readied) + lower_shield(user) + else + raise_shield(user) + +// Making sure that debuffs don't stay +/obj/item/weapon/shield/riot/yautja/dropped(mob/user as mob) + if(shield_readied) + lower_shield(user) + ..() + +/obj/item/weapon/shield/riot/yautja/equipped(mob/user, slot) + if(shield_readied) + lower_shield(user) + ..() + +/obj/item/weapon/shield/riot/yautja/attack_self(mob/user) + ..() + toggle_shield(user) + +/obj/item/weapon/shield/riot/yautja/attack(mob/living/M, mob/living/user) + . = ..() + if(. && (world.time > last_attack + cooldown_time)) + last_attack = world.time + M.throw_at(get_step(M, user.dir), 1, 5, user, FALSE) + M.apply_effect(3, EYE_BLUR) + M.apply_effect(5, WEAKEN) + +/obj/item/weapon/shield/riot/yautja/attackby(obj/item/I, mob/user) + if(cooldown < world.time - 25) + if(istype(I, /obj/item/weapon) && (I.flags_item & ITEM_PREDATOR)) + user.visible_message(span_warning("[user] bashes \the [src] with \the [I]!")) + playsound(user.loc, 'sound/effects/shieldbash.ogg', 25, 1) + cooldown = world.time + else + ..() diff --git a/modular_RUtgmc/code/modules/cm_preds/yautja_rope.dm b/modular_RUtgmc/code/modules/cm_preds/yautja_rope.dm new file mode 100644 index 0000000000000..54ae56892b436 --- /dev/null +++ b/modular_RUtgmc/code/modules/cm_preds/yautja_rope.dm @@ -0,0 +1,111 @@ +/obj/item/stack/yautja_rope + name = "strange rope" + singular_name = "rope meter" + desc = "This unassuming rope seems to be covered in markings depicting strange humanoid forms." + icon = 'icons/obj/stack_objects.dmi' + icon_state = "brutepack" + item_state = "coil" + force = 2 + w_class = WEIGHT_CLASS_SMALL + attack_verb = list("whipped", "lashed", "disciplined", "flogged") + color = "#D2B48C" + attack_speed = 1.4 SECONDS //stop spam + amount = 8 + max_amount = 8 + +/obj/item/stack/yautja_rope/attack(mob/living/mob_victim, mob/living/carbon/human/user) + if(mob_victim.stat != DEAD) + return ..() + + if(mob_victim.mob_size != MOB_SIZE_HUMAN) + to_chat(user, span_warning("[mob_victim] has the wrong body plan to hang up.")) + return TRUE + + if(!HAS_TRAIT(user, TRAIT_SUPER_STRONG)) + to_chat(user, span_warning("You're not strong enough to lift [mob_victim] up with a rope. Also, that's kind of fucked up.")) + return TRUE + + var/mob/living/carbon/human/victim = mob_victim + + if(!do_after(user, 1 SECONDS, NONE, victim, BUSY_ICON_HOSTILE)) + return TRUE + + user.visible_message(span_notice("[user] starts to secure \his rope to the ceiling..."), + span_notice("You start securing the rope to the ceiling...")) + + if(do_after(user, 4 SECONDS, NONE, victim, BUSY_ICON_HOSTILE)) + var/turf/rturf = get_turf(victim) + var/area/rarea = get_area(victim) + if(rturf.density) + to_chat(user, span_warning("They're in a wall!")) + return TRUE + if(rarea.ceiling == CEILING_NONE) + to_chat(user, span_warning("There's no ceiling to hang them from!")) + return TRUE + user.visible_message(span_notice("[user] secures the rope."), + span_notice("You secure the rope.")) + if(!do_after(user, 1 SECONDS, NONE, victim, BUSY_ICON_HOSTILE)) + return + user.visible_message(span_warning("[user] begins hanging [victim] up by the rope..."), + span_notice("You start hanging [victim] up by the rope...")) + if(!do_after(user, 3 SECONDS, NONE, victim, BUSY_ICON_HOSTILE)) + return + user.visible_message(span_warning("[user] hangs [victim] from the ceiling!"), span_notice("You finish hanging [victim].")) + playsound(loc, 'modular_RUtgmc/sound/effects/noosed.ogg', 15, 1) + user.stop_pulling() + victim.get_hung() + use(1) + return TRUE + +/mob/living/carbon/human/proc/get_hung() + animate(src, pixel_y = 9, time = 0.5 SECONDS, easing = SINE_EASING|EASE_OUT) + setDir(SOUTH) + var/matrix/A = matrix() + A.Turn(180) + status_flags |= INCORPOREAL + initial_transform = transform + transform = A + var/rand_swing = rand(6, 3) + //-6, -3 + animate(src, pixel_x = (rand_swing * -1), time = 3 SECONDS, loop = -1, easing = SINE_EASING|EASE_OUT) + animate(pixel_x = rand_swing, time = 3 SECONDS, easing = SINE_EASING|EASE_OUT) + + anchored = TRUE + RegisterSignal(src, COMSIG_ATTEMPT_MOB_PULL, PROC_REF(deny_pull)) + RegisterSignals(src, list( + COMSIG_ITEM_ATTEMPT_ATTACK, + COMSIG_LIVING_POST_FULLY_HEAL + ), PROC_REF(cut_down)) + +/mob/living/carbon/human/proc/deny_pull() + return COMPONENT_CANCEL_MOB_PULL + +/mob/living/carbon/human/proc/cut_down(mob/living/carbon/human/target, mob/living/user, obj/item/source) + //source = item, target = src + SIGNAL_HANDLER + if(source && !source.sharp) + return + + if(user) + if(user.a_intent != INTENT_HELP) + return + user.visible_message(span_warning("[user] cuts down [src] with \the [source]."), span_warning("You cut down [src] with \the [source].")) + user.do_attack_animation(src) + playsound(src, 'sound/effects/vegetation_hit.ogg', 25, TRUE) + else + visible_message(span_danger("[src]'s body falls down from the hanging rope!")) + UnregisterSignal(src, list( + COMSIG_ATTEMPT_MOB_PULL, + COMSIG_ITEM_ATTEMPT_ATTACK, + COMSIG_LIVING_POST_FULLY_HEAL + )) + animate(src) //remove the anims + anchored = FALSE + var/matrix/A = matrix() + A.Turn(90) + transform = A + transform = initial_transform + status_flags &= ~INCORPOREAL + pixel_x = 0 + pixel_y = 0 + return COMPONENT_ITEM_NO_ATTACK diff --git a/modular_RUtgmc/code/modules/cm_preds/yautja_weapons/misc_weapons.dm b/modular_RUtgmc/code/modules/cm_preds/yautja_weapons/misc_weapons.dm new file mode 100644 index 0000000000000..f1338b4f3749b --- /dev/null +++ b/modular_RUtgmc/code/modules/cm_preds/yautja_weapons/misc_weapons.dm @@ -0,0 +1,127 @@ +/*######################################### +############## Misc Weapons ############### +#########################################*/ +/obj/item/weapon/harpoon/yautja + name = "large harpoon" + desc = "A huge metal spike with a hook at the end. It's carved with mysterious alien writing." + + icon = 'modular_RUtgmc/icons/obj/hunter/pred_gear.dmi' + icon_state = "spike" + item_icons = list( + slot_l_hand_str = 'modular_RUtgmc/icons/mob/hunter/items_lefthand.dmi', + slot_r_hand_str = 'modular_RUtgmc/icons/mob/hunter/items_righthand.dmi' + ) + item_state = "harpoon" + + attack_verb = list("jabbed","stabbed","ripped", "skewered") + throw_range = 4 + resistance_flags = UNACIDABLE + edge = 1 + hitsound = 'sound/weapons/bladeslice.ogg' + sharp = IS_SHARP_ITEM_BIG + force = 10 + throwforce = 30 + +/obj/item/weapon/wristblades + name = "\proper wrist blades" + desc = "A pair of huge, serrated blades extending out from metal gauntlets." + + icon = 'modular_RUtgmc/icons/obj/hunter/pred_gear.dmi' + icon_state = "wrist" + item_state = "wristblade" + item_icons = list( + slot_l_hand_str = 'modular_RUtgmc/icons/mob/hunter/items_lefthand.dmi', + slot_r_hand_str = 'modular_RUtgmc/icons/mob/hunter/items_righthand.dmi' + ) + + w_class = WEIGHT_CLASS_GIGANTIC + edge = TRUE + sharp = IS_SHARP_ITEM_ACCURATE + flags_item = ITEM_PREDATOR + flags_equip_slot = NONE + hitsound = 'sound/weapons/wristblades_hit.ogg' + attack_speed = 6 + force = 25 + penetration = 10 + pry_capable = IS_PRY_CAPABLE_FORCE + attack_verb = list("sliced", "slashed", "jabbed", "torn", "gored") + + var/obj/item/clothing/gloves/yautja/hunter/source + var/has_speed_bonus = TRUE + +/obj/item/weapon/wristblades/Initialize(mapload) + . = ..() + source = loc + if(!istype(source)) + qdel(src) + +/obj/item/weapon/wristblades/equipped(mob/user, slot) + . = ..() + if(slot == SLOT_L_HAND || slot == SLOT_R_HAND) + if(has_speed_bonus && istype(user.get_inactive_held_item(), /obj/item/weapon/wristblades)) + attack_speed = initial(attack_speed) - 2 + else + forceMove(source) + attack_speed = initial(attack_speed) + playsound(user, 'sound/weapons/wristblades_off.ogg', 15, TRUE) + if(source.left_wristblades.loc == source && source.right_wristblades.loc == source) + source.wristblades_deployed = FALSE + source.action_wristblades.set_toggle(FALSE) + +/obj/item/weapon/wristblades/dropped(mob/user) + if(source) + forceMove(source) + attack_speed = initial(attack_speed) + playsound(user, 'sound/weapons/wristblades_off.ogg', 15, TRUE) + if(source.left_wristblades.loc == source && source.right_wristblades.loc == source) + source.wristblades_deployed = FALSE + source.action_wristblades.set_toggle(FALSE) + return + ..() + +/obj/item/weapon/wristblades/afterattack(atom/attacked_target, mob/user, proximity) + if(!proximity || !user) + return FALSE + + if(istype(attacked_target, /obj/machinery/door/airlock)) + var/obj/machinery/door/airlock/door = attacked_target + if(!door.density || door.locked) + return FALSE + user.visible_message(span_danger("[user] jams their [name] into [door] and strains to rip it open..."), span_danger("You jam your [name] into [door] and strain to rip it open...")) + playsound(loc, 'sound/effects/metal_creaking.ogg', 25, TRUE) + if(do_after(user, 3 SECONDS, NONE, door, BUSY_ICON_HOSTILE, BUSY_ICON_HOSTILE) && door.density) + user.visible_message(span_danger("[user] forces [door] open with the [name]!"), span_danger("You force [door] open with the [name].")) + door.open(TRUE) + + else if(istype(attacked_target, /obj/structure/mineral_door/resin)) + var/obj/structure/mineral_door/resin/door = attacked_target + if(door.switching_states || user.a_intent == INTENT_HARM) + return + if(door.density) + user.visible_message(span_danger("[user] jams their [name] into [door] and strains to rip it open..."), span_danger("You jam your [name] into [door] and strain to rip it open...")) + playsound(loc, 'sound/weapons/wristblades_hit.ogg', 15, TRUE) + if(do_after(user, 1.5 SECONDS, NONE, door, BUSY_ICON_HOSTILE, BUSY_ICON_HOSTILE) && door.density) + user.visible_message(span_danger("[user] forces [door] open using the [name]!"), span_danger("You force [door] open with your [name].")) + door.toggle_state() + else + user.visible_message(span_danger("[user] pushes [door] with their [name] to force it closed..."), span_danger("You push [door] with your [name] to force it closed...")) + playsound(loc, 'sound/weapons/wristblades_hit.ogg', 15, TRUE) + if(do_after(user, 2 SECONDS, NONE, door, BUSY_ICON_HOSTILE, BUSY_ICON_HOSTILE) && !door.density) + user.visible_message(span_danger("[user] forces [door] closed using the [name]!"), span_danger("You force [door] closed with your [name].")) + door.toggle_state() + +/obj/item/weapon/wristblades/attack_self(mob/living/carbon/human/user) + ..() + if(istype(user)) + var/obj/item/clothing/gloves/yautja/hunter/gloves = user.gloves + gloves.wristblades_internal(user, TRUE) // unlikely that the yaut would have gloves without blades, so if they do, runtime logs here would be handy + +/obj/item/weapon/wristblades/scimitar + name = "\proper wrist scimitar" + desc = "A huge, serrated blade extending from metal gauntlets." + icon_state = "scim" + item_state = "scim" + attack_speed = 5 + penetration = 15 + attack_verb = list("sliced", "slashed", "jabbed", "torn", "gored") + force = 32 diff --git a/modular_RUtgmc/code/modules/cm_preds/yautja_weapons/one_handed.dm b/modular_RUtgmc/code/modules/cm_preds/yautja_weapons/one_handed.dm new file mode 100644 index 0000000000000..50268a53d80be --- /dev/null +++ b/modular_RUtgmc/code/modules/cm_preds/yautja_weapons/one_handed.dm @@ -0,0 +1,482 @@ +/*######################################### +########### One Handed Weapons ############ +#########################################*/ + +/obj/item/weapon/yautja + icon = 'modular_RUtgmc/icons/obj/hunter/pred_gear.dmi' + item_icons = list( + slot_back_str = 'modular_RUtgmc/icons/mob/hunter/pred_gear.dmi', + slot_l_hand_str = 'modular_RUtgmc/icons/mob/hunter/items_lefthand.dmi', + slot_r_hand_str = 'modular_RUtgmc/icons/mob/hunter/items_righthand.dmi', + slot_s_store_str = 'modular_RUtgmc/icons/mob/hunter/pred_gear.dmi' + ) + + var/human_adapted = FALSE + + var/charged = FALSE + var/ability_primed = FALSE + var/ability_charge = 0 + var/ability_cost = 5 + var/ability_charge_max = 5 + var/ability_charge_rate = 1 + +/obj/item/weapon/yautja/attack(mob/living/target as mob, mob/living/carbon/human/user as mob) + . = ..() + if(!.) + return + if(target.stat == DEAD || (!ishuman(target) && !isxeno(target)) || target == user) + return + if(ability_charge < ability_charge_max) + ability_charge = min(ability_charge + ability_charge_rate, ability_charge_max) + +/obj/item/weapon/yautja/AltClick(mob/user) + if(!can_interact(user) || !ishuman(user) || !(user.l_hand == src || user.r_hand == src)) + return ..() + if(!HAS_TRAIT(src, TRAIT_NODROP)) + ADD_TRAIT(src, TRAIT_NODROP, TRAIT_GENERIC) + to_chat(user, span_warning("You tighten the grip around [src]!")) + else + REMOVE_TRAIT(src, TRAIT_NODROP, TRAIT_GENERIC) + to_chat(user, span_notice("You loosen the grip around [src]!")) + +/obj/item/weapon/yautja/chain + name = "chainwhip" + desc = "A segmented, lightweight whip made of durable, acid-resistant metal. Not very common among Yautja Hunters, but still a dangerous weapon capable of shredding prey." + icon_state = "whip" + item_state = "whip" + flags_atom = CONDUCT + flags_item = ITEM_PREDATOR + flags_equip_slot = ITEM_SLOT_BELT + w_class = WEIGHT_CLASS_BULKY + resistance_flags = UNACIDABLE + force = 37 + throwforce = 25 + penetration = 25 + sharp = IS_SHARP_ITEM_SIMPLE + edge = TRUE + attack_verb = list("whipped", "slashed","sliced","diced","shredded") + attack_speed = 0.8 SECONDS + hitsound = 'modular_RUtgmc/sound/weapons/chain_whip.ogg' + + +/obj/item/weapon/yautja/chain/attack(mob/target, mob/living/user) + . = ..() + if((human_adapted || isyautja(user)) && isxeno(target)) + var/mob/living/carbon/xenomorph/xenomorph = target + xenomorph.interference = 30 + xenomorph.use_plasma(50) + +/obj/item/weapon/yautja/sword + name = "clan sword" + desc = "An expertly crafted Yautja blade carried by hunters who wish to fight up close. Razor sharp and capable of cutting flesh into ribbons. Commonly carried by aggressive and lethal hunters." + icon_state = "clansword" + flags_atom = CONDUCT + flags_item = ITEM_PREDATOR + flags_equip_slot = ITEM_SLOT_BACK + force = 40 + throwforce = 25 + penetration = 20 + can_block_xeno = TRUE + can_block_chance = 20 + sharp = IS_SHARP_ITEM_ACCURATE + edge = TRUE + w_class = WEIGHT_CLASS_HUGE + hitsound = "clan_sword_hit" + attack_verb = list("slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") + attack_speed = 1 SECONDS + resistance_flags = UNACIDABLE + +/obj/item/weapon/yautja/sword/attack(mob/target, mob/living/user) + . = ..() + if((human_adapted || isyautja(user)) && isxeno(target)) + var/mob/living/carbon/xenomorph/xenomorph = target + xenomorph.interference = 30 + +/obj/item/weapon/yautja/scythe + name = "dual war scythe" + desc = "A huge, incredibly sharp dual blade used for hunting dangerous prey. This weapon is commonly carried by Yautja who wish to disable and slice apart their foes." + icon_state = "predscythe" + item_state = "scythe_dual" + flags_atom = CONDUCT + flags_item = ITEM_PREDATOR + flags_equip_slot = ITEM_SLOT_BELT + force = 35 + throwforce = 25 + penetration = 20 + sharp = IS_SHARP_ITEM_SIMPLE + edge = TRUE + w_class = WEIGHT_CLASS_HUGE + hitsound = 'sound/weapons/bladeslice.ogg' + attack_verb = list("slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") + resistance_flags = UNACIDABLE + + ability_cost = 5 + ability_charge_max = 5 + ability_charge_rate = 1 + +/obj/item/weapon/yautja/scythe/verb/use_unique_action() + set category = "Weapons" + set name = "Unique Action" + set desc = "Activate or deactivate the scythe." + set src in usr + unique_action(usr) + +/obj/item/weapon/yautja/scythe/attack(mob/living/target as mob, mob/living/carbon/human/user as mob) + . = ..() + if(!.) + return + if((human_adapted || isyautja(user)) && isxeno(target)) + var/mob/living/carbon/xenomorph/xenomorph = target + xenomorph.interference = 15 + + if(!charged && ability_charge >= ability_cost) + var/color = target.get_blood_color() + var/alpha = 70 + charged = TRUE + color += num2text(alpha, 2, 16) + add_filter("scythe_ready", 1, list("type" = "outline", "color" = color, "size" = 2)) + +/obj/item/weapon/yautja/scythe/attack_self(mob/user) + ..() + ability_primed = !ability_primed + var/message = "You tighten your grip on [src], preparing to whirl it in a spin." + if(!ability_primed) + message = "You relax your grip on [src]." + to_chat(user, span_warning(message)) + +/obj/item/weapon/yautja/scythe/unique_action(mob/user) + if(user.get_active_held_item() != src) + return + if(!charged) + return + if(!ability_primed) + to_chat(user, span_warning("You need a stronger grip for this!")) + return FALSE + user.spin(15, 1) + for(var/mob/living/carbon/target in orange(1, user)) + if(!(ishuman(target) || isxeno(target)) || isyautja(target)) + continue + + if(target.stat == DEAD) + continue + + if(!line_of_sight(user, target)) + continue + + user.visible_message(span_highdanger("[user] slices open the guts of [target]!"), span_highdanger("You slice open the guts of [target]!")) + target.spawn_gibs() + playsound(get_turf(target), 'modular_RUtgmc/sound/effects/gibbed.ogg', 30, 1) + target.apply_effect(1, WEAKEN) + target.apply_damage(force * 3, BRUTE, "chest", MELEE, FALSE, FALSE, TRUE, 65) + + log_attack("[key_name(target)] was sliced by [key_name(user)] whirling their scythe.") + + ability_charge -= ability_cost + remove_filter("scythe_ready") + charged = FALSE + return TRUE + + +/obj/item/weapon/yautja/scythe/alt + name = "double war scythe" + desc = "A huge, incredibly sharp double blade used for hunting dangerous prey. This weapon is commonly carried by Yautja who wish to disable and slice apart their foes." + icon_state = "predscythe_alt" + item_state = "scythe_double" + +//Combistick +/obj/item/weapon/yautja/combistick + name = "combi-stick" + desc = "A compact yet deadly personal weapon. Can be concealed when folded. Functions well as a throwing weapon or defensive tool. A common sight in Yautja packs due to its versatility." + icon_state = "combistick" + flags_atom = CONDUCT + flags_equip_slot = ITEM_SLOT_BACK + flags_item = TWOHANDED|ITEM_PREDATOR + w_class = WEIGHT_CLASS_HUGE + throw_speed = 10 + throw_range = 4 + resistance_flags = UNACIDABLE + force = 25 + throwforce = 32 + penetration = 30 + sharp = IS_SHARP_ITEM_SIMPLE + edge = TRUE + hitsound = 'sound/weapons/bladeslice.ogg' + attack_verb = list("speared", "stabbed", "impaled") + + ability_cost = 1 + ability_charge_max = 1 + ability_charge_rate = 1 + + var/on = 1 + + var/force_wielded = 30 + var/force_unwielded = 10 + var/force_storage = 5 + var/throwforce_base = 32 + var/throwforce_storage = 5 + +/obj/item/weapon/yautja/combistick/Initialize() + . = ..() + RegisterSignal(src, COMSIG_MOVABLE_PRE_THROW, PROC_REF(try_to_throw)) + +/obj/item/weapon/yautja/combistick/afterattack(atom/A, mob/user, proximity, params) + if(istype(A, /obj/item/clothing/gloves/yautja)) + var/obj/item/clothing/gloves/yautja/bracer = A + if(bracer.combistick) + if(src == bracer.combistick) + to_chat(user, span_warning("You unlink [bracer] and [src].")) + playsound(user.loc, 'modular_RUtgmc/sound/items/pred_bracer.ogg', 75, 1) + bracer.combistick = null + else + to_chat(user, span_warning("Before that you need unlink your [bracer] that before linked.")) + else + bracer.combistick = src + to_chat(user, span_warning("You link [src] to [bracer].")) + playsound(user.loc, 'modular_RUtgmc/sound/items/pred_bracer.ogg', 75, 1) + bracer.owner.update_action_buttons() + ..() + +/obj/item/weapon/yautja/combistick/dropped(mob/living/carbon/human/M) + unwield(M) + ..() + +/obj/item/weapon/yautja/combistick/proc/try_to_throw() + SIGNAL_HANDLER + + var/mob/living/carbon/human/handler = usr + if(!istype(handler)) + return + + if(!charged) + to_chat(handler, span_warning("Your combistick refuses to leave your hand. You must charge it with blood from prey before throwing it.")) + unwield(handler) + handler.put_in_hands(src) + wield(handler) + return COMPONENT_MOVABLE_BLOCK_PRE_THROW + + charged = FALSE + remove_filter("combistick_charge") + unwield(handler) //Otherwise stays wielded even when thrown + +/obj/item/weapon/yautja/combistick/verb/use_unique_action() + set category = "Weapons" + set name = "Unique Action" + set desc = "Activate or deactivate the combistick." + set src in usr + unique_action(usr) + +/obj/item/weapon/yautja/combistick/attack_self(mob/user) + ..() + if(on) + if(flags_item & WIELDED) + unwield(user) + else + wield(user) + else + to_chat(user, span_warning("You need to extend the combi-stick before you can wield it.")) + + +/obj/item/weapon/yautja/combistick/wield(mob/user) + . = ..() + if(!.) + return + force = force_wielded + update_icon() + +/obj/item/weapon/yautja/combistick/unwield(mob/user) + . = ..() + if(!.) + return + force = force_unwielded + update_icon() + +/obj/item/weapon/yautja/combistick/update_icon() + if(flags_item & WIELDED) + item_state = "combistick_w" + else if(!on) + item_state = "combistick_f" + else + item_state = "combistick" + +/obj/item/weapon/yautja/combistick/unique_action(mob/living/user) + if(user.get_active_held_item() != src) + return + if(!on) + user.visible_message(span_info("With a flick of their wrist, [user] extends [src]."),\ + span_notice("You extend [src]."),\ + "You hear blades extending.") + playsound(src,'modular_RUtgmc/sound/items/combistick_open.ogg', 50, TRUE, 3) + icon_state = initial(icon_state) + flags_equip_slot = initial(flags_equip_slot) + flags_item |= TWOHANDED + w_class = WEIGHT_CLASS_HUGE + force = force_unwielded + throwforce = throwforce_base + attack_verb = list("speared", "stabbed", "impaled") + + if(blood_overlay && blood_color) + overlays.Cut() + add_blood(blood_color) + on = TRUE + update_icon() + else + unwield(user) + to_chat(user, span_notice("You collapse [src] for storage.")) + playsound(src, 'modular_RUtgmc/sound/items/combistick_close.ogg', 50, TRUE, 3) + icon_state = initial(icon_state) + "_f" + flags_equip_slot = ITEM_SLOT_BACK + flags_item &= ~TWOHANDED + w_class = WEIGHT_CLASS_TINY + force = force_storage + throwforce = throwforce_storage + attack_verb = list("thwacked", "smacked") + overlays.Cut() + on = FALSE + update_icon() + + if(istype(user,/mob/living/carbon/human)) + var/mob/living/carbon/human/H = user + H.update_inv_l_hand() + H.update_inv_r_hand() + + add_fingerprint(user, "attack_self") + + return + +/obj/item/weapon/yautja/combistick/attack(mob/living/target, mob/living/carbon/human/user) + . = ..() + if(!.) + return + if((human_adapted || isyautja(user)) && isxeno(target)) + var/mob/living/carbon/xenomorph/xenomorph = target + xenomorph.interference = 30 + + if(target == user || target.stat == DEAD) + to_chat(user, span_danger("You think you're smart?")) //very funny + return + if(isanimal(target)) + return + + + if(!charged && ability_charge >= ability_cost) + to_chat(user, span_danger("Your combistick's reservoir fills up with your opponent's blood! You may now throw it!")) + charged = TRUE + var/color = target.get_blood_color() + var/alpha = 70 + color += num2text(alpha, 2, 16) + add_filter("combistick_charge", 1, list("type" = "outline", "color" = color, "size" = 2)) + +/obj/item/weapon/yautja/combistick/attack_hand(mob/user) //Prevents marines from instantly picking it up via pickup macros. + if(!human_adapted && !HAS_TRAIT(user, TRAIT_SUPER_STRONG)) + user.visible_message(span_danger("[user] starts to untangle the chain on \the [src]..."), span_notice("You start to untangle the chain on \the [src]...")) + playsound(loc, 'modular_RUtgmc/sound/items/chain_fumble.ogg', 25) + if(do_after(user, 3 SECONDS, NONE, src, BUSY_ICON_HOSTILE, BUSY_ICON_HOSTILE, PROGRESS_BRASS)) + ..() + else ..() + +/obj/item/weapon/yautja/combistick/throw_impact(atom/hit_atom) + if(isyautja(hit_atom)) + var/mob/living/carbon/human/human = hit_atom + if(human.put_in_hands(src)) + hit_atom.visible_message(span_notice(" [hit_atom] expertly catches [src] out of the air. "), \ + span_notice(" You easily catch [src]. ")) + return + ..() + +/obj/item/weapon/yautja/knife + name = "ceremonial dagger" + desc = "A viciously sharp dagger inscribed with ancient Yautja markings. Smells thickly of blood. Carried by some hunters." + icon_state = "predknife" + item_state = "knife" + flags_atom = CONDUCT + flags_item = ITEM_PREDATOR + flags_equip_slot = ITEM_SLOT_BACK + sharp = IS_SHARP_ITEM_ACCURATE + force = 20 + penetration = 10 + w_class = WEIGHT_CLASS_TINY + throwforce = 15 + throw_speed = 10 + throw_range = 6 + hitsound = 'sound/weapons/slash.ogg' + attack_verb = list("slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") + resistance_flags = UNACIDABLE + +/obj/item/weapon/yautja/knife/Initialize() + . = ..() + AddElement(/datum/element/shrapnel_removal, 4 SECONDS, 0, TRUE) + +/obj/item/weapon/yautja/knife/attack(mob/living/target, mob/living/carbon/human/user) + if(target.stat != DEAD) + return ..() + + if(!ishuman(target)) + to_chat(user, span_warning("You can only use this dagger to flay humanoids!")) + return + + var/mob/living/carbon/human/victim = target + + if(!HAS_TRAIT(user, TRAIT_SUPER_STRONG)) + to_chat(user, span_warning("You're not strong enough to rip an entire humanoid apart. Also, that's kind of fucked up.")) //look at this dumbass + return TRUE + + if(user.species.name == victim.species.name) + to_chat(user, span_highdanger("ARE YOU OUT OF YOUR MIND!?")) + return + + if(issynth(victim) || isrobot(victim) || victim.species.species_flags & ROBOTIC_LIMBS) + to_chat(user, span_warning("You can't flay metal...")) //look at this dumbass + return + + if(SEND_SIGNAL(victim, COMSIG_HUMAN_FLAY_ATTEMPT, user, src) & COMPONENT_ITEM_NO_ATTACK) + return TRUE + + if(victim.overlays_standing[FLAY_LAYER]) //Already fully flayed. Possibly the user wants to cut them down? + return ..() + + if(!do_after(user, 1 SECONDS, NONE, victim, BUSY_ICON_HOSTILE, BUSY_ICON_HOSTILE)) + return TRUE + + user.visible_message(span_danger("[user] begins to flay [victim] with \a [src]..."), + span_danger("You start flaying [victim] with your [src.name]...")) + playsound(loc, 'sound/weapons/pierce.ogg', 25) + if(do_after(user, 4 SECONDS, NONE, victim, BUSY_ICON_HOSTILE, BUSY_ICON_HOSTILE)) + if(SEND_SIGNAL(victim, COMSIG_HUMAN_FLAY_ATTEMPT, user, src) & COMPONENT_ITEM_NO_ATTACK) //In case two preds try to flay the same person at once. + return TRUE + user.visible_message(span_danger("[user] makes a series of cuts in [victim]'s skin."), + span_danger("You prepare the skin, cutting the flesh off in vital places.")) + playsound(loc, 'sound/weapons/slash.ogg', 25) + + for(var/limb in victim.limbs) + victim.apply_damage(15, BRUTE, limb, sharp = FALSE) + victim.add_flay_overlay(stage = 1) + + var/datum/flaying_datum/flay_datum = new(victim) + flay_datum.create_leftovers(victim, TRUE, 0) + SEND_SIGNAL(victim, COMSIG_HUMAN_FLAY_ATTEMPT, user, src, TRUE) + else + to_chat(user, span_warning("You were interrupted before you could finish your work!")) + return TRUE + +/obj/item/weapon/yautja/knife/afterattack(obj/attacked_obj, mob/living/user, proximity) + if(!proximity) + return + + if(!HAS_TRAIT(user, TRAIT_YAUTJA_TECH)) + return + + if(!istype(attacked_obj, /obj/item/limb)) + return + var/obj/item/limb/current_limb = attacked_obj + + if(current_limb.flayed) + to_chat(user, span_notice("This limb has already been flayed.")) + return + + playsound(loc, 'sound/weapons/pierce.ogg', 25) + to_chat(user, span_warning("You start flaying the skin from [current_limb].")) + if(!do_after(user, 2 SECONDS, NONE, current_limb, BUSY_ICON_HOSTILE, BUSY_ICON_HOSTILE)) + to_chat(user, span_notice("You decide not to flay [current_limb].")) + return + to_chat(user, span_warning("You finish flaying [current_limb].")) + current_limb.flayed = TRUE diff --git a/modular_RUtgmc/code/modules/cm_preds/yautja_weapons/ranged.dm b/modular_RUtgmc/code/modules/cm_preds/yautja_weapons/ranged.dm new file mode 100644 index 0000000000000..5f072f6419d61 --- /dev/null +++ b/modular_RUtgmc/code/modules/cm_preds/yautja_weapons/ranged.dm @@ -0,0 +1,579 @@ +/*######################################### +############## Ranged Weapons ############# +#########################################*/ + +/datum/yautja_energy_weapon_modes + ///how much power the gun uses on this mode when shot. + var/rounds_per_shot = 0 + ///the ammo datum this mode is. + var/datum/ammo/ammo_datum_type = null + ///how long it takes between each shot of that mode, same as gun fire delay. + var/fire_delay = 0 + ///The gun firing sound of this mode + var/fire_sound = null + ///What message it sends to the user when you switch to this mode. + var/message_to_user = "" + ///Which icon file the radial menu will use. + var/radial_icon = 'modular_RUtgmc/icons/mob/radial.dmi' + ///The icon state the radial menu will use. + var/radial_icon_state = "laser" + ///The muzzleflash color of the weapon we use. + var/muzzle_flash_color = COLOR_MAGENTA + +/datum/yautja_energy_weapon_modes/stun_bolts + rounds_per_shot = 30 + ammo_datum_type = /datum/ammo/energy/yautja/caster/stun + fire_delay = 5 + fire_sound = 'modular_RUtgmc/sound/weapons/pred_plasmacaster_fire.ogg' + message_to_user = "will now fire low power stun bolts" + radial_icon_state = "plasma_weak" + muzzle_flash_color = COLOR_MAGENTA + +/datum/yautja_energy_weapon_modes/stun_heavy_bolts + rounds_per_shot = 100 + ammo_datum_type = /datum/ammo/energy/yautja/caster/bolt/stun + fire_delay = 15 + fire_sound = 'modular_RUtgmc/sound/weapons/pred_lasercannon.ogg' + message_to_user = "will now fire high power stun bolts" + radial_icon_state = "plasma_strong" + muzzle_flash_color = COLOR_MAGENTA + +/datum/yautja_energy_weapon_modes/stun_spheres + rounds_per_shot = 300 + ammo_datum_type = /datum/ammo/energy/yautja/caster/sphere/stun + fire_delay = 100 + fire_sound = 'modular_RUtgmc/sound/weapons/pulse.ogg' + message_to_user = "will now fire plasma immobilizers" + radial_icon_state = "laser_sniper_overcharge" + muzzle_flash_color = COLOR_MAGENTA + +/datum/yautja_energy_weapon_modes/lethal_bolts + rounds_per_shot = 300 + ammo_datum_type = /datum/ammo/energy/yautja/caster/bolt + fire_delay = 10 + fire_sound = 'modular_RUtgmc/sound/weapons/pred_lasercannon.ogg' + message_to_user = "will now fire plasma bolts" + radial_icon_state = "laser_disabler" + muzzle_flash_color = COLOR_BRIGHT_BLUE + +/datum/yautja_energy_weapon_modes/lethal_spheres + rounds_per_shot = 1200 + ammo_datum_type = /datum/ammo/energy/yautja/caster/sphere + fire_delay = 100 + fire_sound = 'modular_RUtgmc/sound/weapons/pulse.ogg' + message_to_user = "will now fire plasma spheres" + radial_icon_state = "laser_swarm" + muzzle_flash_color = COLOR_BRIGHT_BLUE + +/obj/item/weapon/gun/energy/yautja + icon = 'modular_RUtgmc/icons/obj/hunter/pred_gear.dmi' + icon_state = null + item_icons = list( + slot_back_str = 'modular_RUtgmc/icons/mob/hunter/pred_gear.dmi', + slot_l_hand_str = 'modular_RUtgmc/icons/mob/hunter/items_lefthand.dmi', + slot_r_hand_str = 'modular_RUtgmc/icons/mob/hunter/items_righthand.dmi', + slot_s_store_str = 'modular_RUtgmc/icons/mob/hunter/pred_gear.dmi' + ) + + rounds_per_shot = 1 + muzzle_flash = "muzzle_flash_laser" + muzzle_flash_color = COLOR_MAGENTA + default_ammo_type = null + + flags_gun_features = GUN_AMMO_COUNTER|GUN_NO_PITCH_SHIFT_NEAR_EMPTY|GUN_ENERGY|GUN_AMMO_COUNT_BY_PERCENTAGE|GUN_UNUSUAL_DESIGN + + var/list/datum/yautja_energy_weapon_modes/mode_list = list() + +/obj/item/weapon/gun/energy/yautja/unique_action(mob/user) + if(!user) + CRASH("switch_modes called with no user.") + + if(length(mode_list)) + change_ammo_type(user) + +/obj/item/weapon/gun/energy/yautja/update_icon_state() + return + +/obj/item/weapon/gun/energy/yautja/update_ammo_count() + gun_user?.hud_used.update_ammo_hud(src, get_ammo_list(), get_display_ammo_count()) + +/obj/item/weapon/gun/energy/yautja/get_display_ammo_count() + return round(rounds / rounds_per_shot, 1) + +/obj/item/weapon/gun/energy/yautja/unload(mob/living/user, drop = TRUE, after_fire = FALSE) + return + +/obj/item/weapon/gun/energy/yautja/proc/change_ammo_type(mob/user) + var/list/available_modes = list() + for(var/mode in mode_list) + available_modes += list("[mode]" = image(icon = initial(mode_list[mode].radial_icon), icon_state = initial(mode_list[mode].radial_icon_state))) + + var/datum/yautja_energy_weapon_modes/choice = mode_list[show_radial_menu(user, user, available_modes, null, 64, tooltips = TRUE)] + if(!choice) + return + + playsound(user, 'sound/weapons/emitter.ogg', 5, FALSE, 2) + + ammo_datum_type = GLOB.ammo_list[initial(choice.ammo_datum_type)] + fire_delay = initial(choice.fire_delay) + fire_sound = initial(choice.fire_sound) + rounds_per_shot = initial(choice.rounds_per_shot) + + to_chat(user, initial(choice.message_to_user)) + update_ammo_count() + +/obj/item/weapon/gun/energy/yautja/Destroy() + STOP_PROCESSING(SSobj, src) + return ..() + +//Spike launcher +/obj/item/weapon/gun/energy/yautja/spike + name = "spike launcher" + desc = "A compact Yautja device in the shape of a crescent. It can rapidly fire damaging spikes and automatically recharges." + icon = 'modular_RUtgmc/icons/obj/hunter/pred_gear.dmi' + icon_state = "spikelauncher" + item_state = "spikelauncher" + resistance_flags = UNACIDABLE + fire_sound = 'sound/effects/woodhit.ogg' // TODO: Decent THWOK noise. + ammo_datum_type = /datum/ammo/energy/yautja/alloy_spike + flags_equip_slot = ITEM_SLOT_BELT|ITEM_SLOT_BACK + w_class = WEIGHT_CLASS_BULKY //Fits in yautja bags. + rounds = 12 + max_rounds = 12 + var/last_regen + flags_item = ITEM_PREDATOR|TWOHANDED + + fire_delay = 5 + accuracy_mult = 1.25 + accuracy_mult_unwielded = 1 + scatter = 1 + scatter_unwielded = 2 + damage_mult = 1 + +/obj/item/weapon/gun/energy/yautja/spike/Initialize(mapload, spawn_empty) + . = ..() + START_PROCESSING(SSobj, src) + last_regen = world.time + update_icon() + +/obj/item/weapon/gun/energy/yautja/spike/get_display_ammo_count() + return rounds + +/obj/item/weapon/gun/energy/yautja/spike/process() + if(rounds < max_rounds && world.time > last_regen + 100 && prob(70)) + rounds++ + last_regen = world.time + update_icon() + +/obj/item/weapon/gun/energy/yautja/spike/examine(mob/user) + if(isyautja(user)) + . = ..() + . += span_notice("It currently has [rounds]/[max_rounds] spikes.") + else + . = list() + . += span_notice("Looks like some kind of...mechanical donut.") + +/obj/item/weapon/gun/energy/yautja/spike/update_icon() + ..() + var/new_icon_state = rounds <= 1 ? null : icon_state + "[round(rounds / (max_rounds / 3), 1)]" + update_special_overlay(new_icon_state) + +/obj/item/weapon/gun/energy/yautja/spike/able_to_fire(mob/user) + if(!HAS_TRAIT(user, TRAIT_YAUTJA_TECH)) + to_chat(user, span_warning("You have no idea how this thing works!")) + return + + return ..() + +/obj/item/weapon/gun/energy/yautja/spike/cycle() + if(rounds > 0) + in_chamber = get_ammo_object() + rounds-- + return in_chamber + +/obj/item/weapon/gun/energy/yautja/plasmarifle + name = "plasma rifle" + desc = "A long-barreled heavy plasma weapon. Intended for combat, not hunting. Has an integrated battery that allows for a functionally unlimited amount of shots to be discharged. Equipped with an internal gyroscopic stabilizer allowing its operator to fire the weapon one-handed if desired" + icon_state = "plasmarifle" + item_state = "plasmarifle" + resistance_flags = UNACIDABLE + fire_sound = 'modular_RUtgmc/sound/weapons/pred_plasma_shot.ogg' + ammo_datum_type = /datum/ammo/energy/yautja/rifle/bolt + zoomdevicename = "scope" + flags_equip_slot = ITEM_SLOT_BACK + w_class = WEIGHT_CLASS_GIGANTIC + rounds = 100 + max_rounds = 100 + charge_cost = 5 + var/last_regen = 0 + flags_item = ITEM_PREDATOR|TWOHANDED + flags_gun_features = GUN_AMMO_COUNTER|GUN_NO_PITCH_SHIFT_NEAR_EMPTY|GUN_ENERGY|GUN_AMMO_COUNT_BY_PERCENTAGE|GUN_UNUSUAL_DESIGN|GUN_WIELDED_FIRING_ONLY + + fire_delay = 10 + accuracy_mult = 1.5 + accuracy_mult_unwielded = 1.5 + scatter = 2 + scatter_unwielded = 4 + damage_mult = 1 + +/obj/item/weapon/gun/energy/yautja/plasmarifle/Initialize(mapload, spawn_empty) + . = ..() + START_PROCESSING(SSobj, src) + last_regen = world.time + update_icon() + +/obj/item/weapon/gun/energy/yautja/plasmarifle/process() + if(rounds < max_rounds) + rounds++ + if(rounds == max_rounds) + if(ismob(loc)) to_chat(loc, span_notice("[src] hums as it achieves maximum charge.")) + update_icon() + +/obj/item/weapon/gun/energy/yautja/plasmarifle/examine(mob/user) + if(isyautja(user)) + . = ..() + . += span_notice("It currently has [rounds]/[max_rounds] charge.") + else + . = list() + . += span_notice("This thing looks like an alien rifle of some kind. Strange.") + +/obj/item/weapon/gun/energy/yautja/plasmarifle/update_icon() + if(last_regen < rounds + max_rounds / 5 || last_regen > rounds || rounds > max_rounds / 1.05) + var/new_icon_state = rounds <= 15 ? null : icon_state + "[round(rounds/(max_rounds / 3), 1)]" + update_special_overlay(new_icon_state) + last_regen = rounds + +/obj/item/weapon/gun/energy/yautja/plasmarifle/able_to_fire(mob/user) + if(!HAS_TRAIT(user, TRAIT_YAUTJA_TECH)) + to_chat(user, span_warning("You have no idea how this thing works!")) + return + + return ..() + +/obj/item/weapon/gun/energy/yautja/plasmarifle/cycle() + if(rounds < charge_cost) + return + + ammo_datum_type = GLOB.ammo_list[/datum/ammo/energy/yautja/rifle/bolt] + rounds -= charge_cost + var/obj/projectile/proj = get_ammo_object() + in_chamber = proj + return in_chamber + +/obj/item/weapon/gun/energy/yautja/plasmapistol + name = "plasma pistol" + desc = "A plasma pistol capable of rapid fire. It has an integrated battery. Can be used to set fires, either to braziers or on people." + icon_state = "plasmapistol" + item_state = "plasmapistol" + + resistance_flags = UNACIDABLE + fire_sound = 'modular_RUtgmc/sound/weapons/pulse3.ogg' + flags_equip_slot = ITEM_SLOT_BELT + ammo_datum_type = /datum/ammo/energy/yautja/pistol + w_class = WEIGHT_CLASS_BULKY + rounds = 40 + max_rounds = 40 + charge_cost = 1 + flags_item = ITEM_PREDATOR|TWOHANDED + + fire_delay = 4 + accuracy_mult = 1.5 + accuracy_mult_unwielded = 1.35 + scatter = 1 + scatter_unwielded = 3 + damage_mult = 1 + + +/obj/item/weapon/gun/energy/yautja/plasmapistol/Initialize(mapload, spawn_empty) + . = ..() + START_PROCESSING(SSobj, src) + + +/obj/item/weapon/gun/energy/yautja/plasmapistol/Destroy() + . = ..() + STOP_PROCESSING(SSobj, src) + + +/obj/item/weapon/gun/energy/yautja/plasmapistol/process() + if(rounds < max_rounds) + rounds += 0.25 + if(rounds == max_rounds) + if(ismob(loc)) to_chat(loc, span_notice("[src] hums as it achieves maximum charge.")) + + +/obj/item/weapon/gun/energy/yautja/plasmapistol/examine(mob/user) + if(isyautja(user)) + . = ..() + . += span_notice("It currently has [rounds]/[max_rounds] charge.") + else + . = list() + . += span_notice("This thing looks like an alien rifle of some kind. Strange.") + + +/obj/item/weapon/gun/energy/yautja/plasmapistol/able_to_fire(mob/user) + if(!HAS_TRAIT(user, TRAIT_YAUTJA_TECH)) + to_chat(user, span_warning("You have no idea how this thing works!")) + return + else + return ..() + +/obj/item/weapon/gun/energy/yautja/plasmapistol/cycle() + if(rounds < charge_cost) + return + var/obj/projectile/proj = get_ammo_object() + in_chamber = proj + rounds -= charge_cost + return in_chamber + +#define PRED_MODE_STUN "stun" +#define PRED_MODE_LETHAL "lethal" + +/obj/item/weapon/gun/energy/yautja/plasma_caster + name = "plasma caster" + desc = "A powerful, shoulder-mounted energy weapon." + icon_state = "plasma_ebony" + var/initial_icon_state = "plasma" + var/base_item_state = "plasma_wear" + item_state_slots = list( + slot_back_str = "plasma_wear_off", + slot_s_store_str = "plasma_wear_off" + ) + fire_sound = 'modular_RUtgmc/sound/weapons/pred_plasmacaster_fire.ogg' + ammo_datum_type = /datum/ammo/energy/yautja/caster/stun + muzzle_flash_color = COLOR_VIOLET + w_class = WEIGHT_CLASS_GIGANTIC + force = 0 + fire_delay = 3 + flags_atom = CONDUCT + flags_item = NOBLUDGEON //Can't bludgeon with this. + + fire_delay = 5 + accuracy_mult = 1 + accuracy_mult_unwielded = 6 + scatter = 2 + scatter_unwielded = 4 + damage_mult = 1 + + var/obj/item/clothing/gloves/yautja/hunter/source = null + charge_cost = 100 //How much energy is needed to fire. + var/last_time_targeted = 0 + var/mode = "stun"//fire mode (stun/lethal) + var/strength = "low power stun bolts"//what it's shooting + + var/static/list/modes = list( + PRED_MODE_STUN = image(icon = 'modular_RUtgmc/icons/mob/radial.dmi', icon_state = "pred_mode_stun"), + PRED_MODE_LETHAL = image(icon = 'modular_RUtgmc/icons/mob/radial.dmi', icon_state = "pred_mode_lethal")) + var/list/mode_by_mode_list = list( + "stun" = list("low power stun bolts", "high power stun bolts", "plasma immobilizers"), + "lethal" = list("plasma bolts", "plasma spheres") + ) + mode_list = list( + "low power stun bolts" = /datum/yautja_energy_weapon_modes/stun_bolts, + "high power stun bolts" = /datum/yautja_energy_weapon_modes/stun_heavy_bolts, + "plasma immobilizers" = /datum/yautja_energy_weapon_modes/stun_spheres, + "plasma bolts" = /datum/yautja_energy_weapon_modes/lethal_bolts, + "plasma spheres" = /datum/yautja_energy_weapon_modes/lethal_spheres + ) + + var/mob/living/carbon/laser_target = null + +/obj/item/weapon/gun/energy/yautja/plasma_caster/Initialize(mapload, spawn_empty, caster_material = "ebony") + icon_state = "[initial_icon_state]_[caster_material]" + item_state = "[initial_icon_state]_[caster_material]" + item_state_slots[slot_back_str] = "[base_item_state]_off_[caster_material]" + item_state_slots[slot_s_store_str] = "[base_item_state]_off_[caster_material]" + . = ..() + source = loc + if(!istype(source)) + qdel(src) + RegisterSignal(src, COMSIG_ITEM_MIDDLECLICKON, PROC_REF(target_action)) + +/obj/item/weapon/gun/energy/yautja/plasma_caster/Destroy() + . = ..() + source = null + +/obj/item/weapon/gun/energy/yautja/plasma_caster/get_display_ammo_count() + return round(source.charge / source.charge_max * 100, 1) + +/obj/item/weapon/gun/energy/yautja/plasma_caster/change_ammo_type(mob/user) + var/list/available_modes = list() + for(var/proj_mode in modes) + available_modes += list("[proj_mode]" = image(icon = modes)) + + var/selected_mode = show_radial_menu(user, user, modes, null, 64, tooltips = TRUE) + if(selected_mode) + mode = selected_mode + + available_modes = list() + for(var/proj_mode in mode_by_mode_list[mode]) + available_modes += list("[proj_mode]" = image(icon = initial(mode_list[proj_mode].radial_icon), icon_state = initial(mode_list[proj_mode].radial_icon_state))) + + strength = show_radial_menu(user, user, available_modes, null, 64, tooltips = TRUE) + var/datum/yautja_energy_weapon_modes/choice = mode_list[strength] + if(!choice) + return + + playsound(user, 'sound/weapons/emitter.ogg', 5, FALSE, 2) + + ammo_datum_type = GLOB.ammo_list[initial(choice.ammo_datum_type)] + fire_delay = initial(choice.fire_delay) + fire_sound = initial(choice.fire_sound) + rounds_per_shot = initial(choice.rounds_per_shot) + muzzle_flash_color = initial(choice.muzzle_flash_color) + + to_chat(user, initial(choice.message_to_user)) + update_ammo_count() + +/obj/item/weapon/gun/energy/yautja/plasma_caster/examine(mob/user) + . = ..() + var/msg = "It is set to fire [strength]." + if(mode == "lethal") + . += span_red(msg) + else + . += span_orange(msg) + +/obj/item/weapon/gun/energy/yautja/plasma_caster/dropped(mob/living/carbon/human/M) + playsound(M, 'modular_RUtgmc/sound/weapons/pred_plasmacaster_off.ogg', 15, 1) + to_chat(M, span_notice("You deactivate your plasma caster.")) + if(laser_target) + laser_off(M) + . = ..() + if(source && !(src in M.contents)) + forceMove(source) + source.caster_deployed = FALSE + source.action_caster.set_toggle(FALSE) + return + +/obj/item/weapon/gun/energy/yautja/plasma_caster/able_to_fire(mob/user) + if(!source) + return + if(!HAS_TRAIT(user, TRAIT_YAUTJA_TECH)) + to_chat(user, span_warning("You have no idea how this thing works!")) + return + return ..() + +/obj/item/weapon/gun/energy/yautja/plasma_caster/cycle(mob/user) + if(source.drain_power(user, charge_cost)) + in_chamber = get_ammo_object() + return in_chamber + +/atom/proc/can_apply_pred_laser() + return FALSE + +/mob/living/carbon/human/can_apply_pred_laser() + if(!overlays_standing[PRED_LASER_LAYER]) + return TRUE + return FALSE + +/mob/living/carbon/xenomorph/can_apply_pred_laser() + if(!overlays_standing[X_PRED_LASER_LAYER]) + return TRUE + return FALSE + +/atom/proc/apply_pred_laser() + return FALSE + +/mob/living/carbon/human/apply_pred_laser() + overlays_standing[PRED_LASER_LAYER] = image("icon" = 'modular_RUtgmc/icons/mob/hunter/pred_gear.dmi', "icon_state" = "locking-y", "layer" = -PRED_LASER_LAYER) + apply_overlay(PRED_LASER_LAYER) + spawn(2 SECONDS) + if(overlays_standing[PRED_LASER_LAYER]) + remove_overlay(PRED_LASER_LAYER) + overlays_standing[PRED_LASER_LAYER] = image("icon" = 'modular_RUtgmc/icons/mob/hunter/pred_gear.dmi', "icon_state" = "locked-y", "layer" = -PRED_LASER_LAYER) + apply_overlay(PRED_LASER_LAYER) + return TRUE + +/mob/living/carbon/xenomorph/apply_pred_laser() + overlays_standing[X_PRED_LASER_LAYER] = image("icon" = 'modular_RUtgmc/icons/mob/hunter/pred_gear.dmi', "icon_state" = "locking-y", "layer" = -X_PRED_LASER_LAYER) + apply_overlay(X_PRED_LASER_LAYER) + spawn(2 SECONDS) + if(overlays_standing[X_PRED_LASER_LAYER]) + remove_overlay(X_PRED_LASER_LAYER) + overlays_standing[X_PRED_LASER_LAYER] = image("icon" = 'modular_RUtgmc/icons/mob/hunter/pred_gear.dmi', "icon_state" = "locked-y", "layer" = -X_PRED_LASER_LAYER) + apply_overlay(X_PRED_LASER_LAYER) + return TRUE + +/atom/proc/remove_pred_laser() + return FALSE + +/mob/living/carbon/human/remove_pred_laser() + remove_overlay(PRED_LASER_LAYER) + return TRUE + +/mob/living/carbon/xenomorph/remove_pred_laser() + remove_overlay(X_PRED_LASER_LAYER) + return TRUE + +/obj/item/weapon/gun/energy/yautja/plasma_caster/process() + var/mob/living/user = loc + if(!istype(user)) + laser_off() + else if(!line_of_sight(user, laser_target, 24)) + laser_off(user) + to_chat(user, span_danger("You lose sight of your target!")) + +/obj/item/weapon/gun/energy/yautja/plasma_caster/do_fire(obj/object_to_fire) + if(!QDELETED(laser_target)) + target = laser_target + return ..() + +/obj/item/weapon/gun/energy/yautja/plasma_caster/proc/target_action(datum/source, atom/A) + if((!istype(A, /mob/living/carbon) && laser_target) || A == laser_target) + laser_off(gun_user) + else if(!laser_target && istype(A, /mob/living/carbon)) + if(last_time_targeted + 3 SECONDS > world.time) + to_chat(gun_user, span_danger("You did it too recently!")) + return + if(!A.can_apply_pred_laser()) + return + laser_on(A, gun_user) + +/obj/item/weapon/gun/energy/yautja/plasma_caster/proc/scan_turf_for_target(datum/source, turf/target_turf) + SIGNAL_HANDLER + if(QDELETED(laser_target) || !isturf(laser_target.loc)) + return NONE + if(get_turf(laser_target) == target_turf) + return COMPONENT_PROJ_SCANTURF_TARGETFOUND + return COMPONENT_PROJ_SCANTURF_TURFCLEAR + +/obj/item/weapon/gun/energy/yautja/plasma_caster/proc/activate_laser_target(atom/target, mob/user) + if(laser_target) + laser_off(user) + target.apply_pred_laser() + laser_target = target + if(user) + to_chat(user, span_danger("You focus your target marker on [target]!")) + RegisterSignal(src, COMSIG_PROJ_SCANTURF, PROC_REF(scan_turf_for_target)) + START_PROCESSING(SSobj, src) + accuracy_mult += 0.50 //We get a big accuracy bonus vs the lasered target + +/obj/item/weapon/gun/energy/yautja/plasma_caster/proc/deactivate_laser_target(mob/user) + laser_target.remove_pred_laser() + laser_target = null + if(user) + playsound(user, 'sound/machines/click.ogg', 25, 1) + UnregisterSignal(src, COMSIG_PROJ_SCANTURF) + STOP_PROCESSING(SSobj, src) + accuracy_mult -= 0.50 //We lose a big accuracy bonus vs the now unlasered target + +/obj/item/weapon/gun/energy/yautja/plasma_caster/proc/laser_on(atom/target, mob/user) + if(user?.client) + user.client.click_intercept = src + to_chat(user, span_notice("You activate your target marker and take careful aim.")) + playsound(user,'sound/effects/nightvision.ogg', 25, 1) + activate_laser_target(target, user) + last_time_targeted = world.time + return TRUE + +/obj/item/weapon/gun/energy/yautja/plasma_caster/proc/laser_off(mob/user) + if(!laser_target) + return + deactivate_laser_target() + if(user?.client) + user.client.click_intercept = null + to_chat(user, span_notice("You deactivate your target marker.")) + playsound(user,'sound/machines/click.ogg', 25, 1) + return TRUE + +#undef PRED_MODE_STUN +#undef PRED_MODE_LETHAL diff --git a/modular_RUtgmc/code/modules/cm_preds/yautja_weapons/two_handed.dm b/modular_RUtgmc/code/modules/cm_preds/yautja_weapons/two_handed.dm new file mode 100644 index 0000000000000..9964dec018167 --- /dev/null +++ b/modular_RUtgmc/code/modules/cm_preds/yautja_weapons/two_handed.dm @@ -0,0 +1,82 @@ +/*######################################### +########### Two Handed Weapons ############ +#########################################*/ +/obj/item/weapon/twohanded/yautja + icon = 'modular_RUtgmc/icons/obj/hunter/pred_gear.dmi' + item_icons = list( + slot_back_str = 'modular_RUtgmc/icons/mob/hunter/pred_gear.dmi', + slot_l_hand_str = 'modular_RUtgmc/icons/mob/hunter/items_lefthand.dmi', + slot_r_hand_str = 'modular_RUtgmc/icons/mob/hunter/items_righthand.dmi', + slot_s_store_str = 'modular_RUtgmc/icons/mob/hunter/pred_gear.dmi' + ) + + flags_item = TWOHANDED|ITEM_PREDATOR + resistance_flags = UNACIDABLE + flags_equip_slot = ITEM_SLOT_BACK + w_class = WEIGHT_CLASS_HUGE + throw_speed = 10 + edge = TRUE + hitsound = 'sound/weapons/bladeslice.ogg' + var/human_adapted = FALSE + +/obj/item/weapon/twohanded/yautja/spear + name = "hunter spear" + desc = "A spear of exquisite design, used by an ancient civilisation." + icon_state = "spearhunter" + item_state = "spearhunter" + flags_item = TWOHANDED + force = 20 + force_wielded = 45 + penetration = 25 + throwforce = 40 + sharp = IS_SHARP_ITEM_SIMPLE + attack_verb = list("attacked", "stabbed", "jabbed", "torn", "gored") + +/obj/item/weapon/twohanded/yautja/glaive + name = "war glaive" + desc = "A huge, powerful blade on a metallic pole. Mysterious writing is carved into the weapon." + icon_state = "glaive" + item_state = "glaive" + force = 20 + force_wielded = 45 + reach = 2 + penetration = 30 + throwforce = 20 + sharp = IS_SHARP_ITEM_BIG + flags_atom = CONDUCT + attack_verb = list("sliced", "slashed", "carved", "diced", "gored") + attack_speed = 20 //Default is 7. + +/obj/item/weapon/twohanded/yautja/glaive/attack(mob/living/target, mob/living/carbon/human/user) + . = ..() + if(!.) + return + if((human_adapted || isyautja(user)) && isxeno(target)) + var/mob/living/carbon/xenomorph/xenomorph = target + xenomorph.interference = 30 + +/obj/item/weapon/twohanded/yautja/glaive/AltClick(mob/user) + if(!can_interact(user) || !ishuman(user) || !(user.l_hand == src || user.r_hand == src)) + return ..() + if(!HAS_TRAIT(src, TRAIT_NODROP)) + ADD_TRAIT(src, TRAIT_NODROP, TRAIT_GENERIC) + to_chat(user, span_warning("You tighten the grip around [src]!")) + else + REMOVE_TRAIT(src, TRAIT_NODROP, TRAIT_GENERIC) + to_chat(user, span_notice("You loosen the grip around [src]!")) + +/obj/item/weapon/twohanded/yautja/glaive/alt + icon_state = "glaive_alt" + item_state = "glaive_alt" + +/obj/item/weapon/twohanded/yautja/glaive/damaged + name = "ancient war glaive" + desc = "A huge, powerful blade on a metallic pole. Mysterious writing is carved into the weapon. This one is ancient and has suffered serious acid damage, making it near-useless." + force = 10 + force_wielded = 25 + penetration = 5 + throwforce = 10 + icon_state = "glaive_alt" + item_state = "glaive_alt" + flags_item = TWOHANDED + diff --git a/modular_RUtgmc/code/modules/language/hellhound.dm b/modular_RUtgmc/code/modules/language/hellhound.dm new file mode 100644 index 0000000000000..d2988b26c1391 --- /dev/null +++ b/modular_RUtgmc/code/modules/language/hellhound.dm @@ -0,0 +1,7 @@ +/datum/language/hellhound + name = "Hellhound" + desc = "A growling, guttural method of communication, only Hellhounds seem to be capable of producing these sounds." + speech_verb = "growls" + ask_verb = "grumbles" + exclaim_verb = "snarls" + key = "h" diff --git a/modular_RUtgmc/code/modules/language/yautja.dm b/modular_RUtgmc/code/modules/language/yautja.dm new file mode 100644 index 0000000000000..15934a8faa124 --- /dev/null +++ b/modular_RUtgmc/code/modules/language/yautja.dm @@ -0,0 +1,20 @@ +/datum/language/yautja + name = "Sainja" + desc = "The deep, rumbling, guttural sounds of the Yautja predators. It is difficult to speak for those without facial mandibles." + speech_verb = "rumbles" + ask_verb = "rumbles" + exclaim_verb = "roars" + icon_state = "pred" + key = "s" + space_chance = 20 + default_priority = 90 + syllables = list("!", "?", ".", "@", "$", "%", "^", "&", "*", "-", "=", "+", "e", "b", "y", "p", "|", "z", "~", ">") + +/datum/language_holder/yautja + languages = list(/datum/language/yautja) + only_speaks_language = /datum/language/yautja + +/datum/language_holder/yautja/New() + . = ..() + for(var/la in GLOB.all_languages - /datum/language/yautja) + grant_language(la, TRUE) diff --git a/modular_RUtgmc/code/modules/mining/money_bag.dm b/modular_RUtgmc/code/modules/mining/money_bag.dm new file mode 100644 index 0000000000000..def36279398b9 --- /dev/null +++ b/modular_RUtgmc/code/modules/mining/money_bag.dm @@ -0,0 +1,6 @@ +/obj/item/moneybag/pred + desc = "A console designed by the Hunters to assist in flight pathing and navigation."; + icon = 'modular_RUtgmc/icons/obj/machines/yautja_machines.dmi'; + icon_state = "overwatch"; + name = "Hunter Flight Console" + anchored = TRUE diff --git a/modular_RUtgmc/code/modules/mob/dead/observer.dm b/modular_RUtgmc/code/modules/mob/dead/observer.dm new file mode 100644 index 0000000000000..654eab0aa452b --- /dev/null +++ b/modular_RUtgmc/code/modules/mob/dead/observer.dm @@ -0,0 +1,52 @@ +/mob/dead/verb/join_as_hellhound() + set category = "Ghost" + set name = "Join as Hellhound" + set desc = "Select an alive and available Hellhound. THIS COMES WITH STRICT RULES. READ THEM OR GET BANNED." + + var/mob/dead/current_mob = src + if(!current_mob.stat || !current_mob.mind) + return + + if(SSticker.current_state < GAME_STATE_PLAYING || !SSticker.mode) + to_chat(src, span_warning("The game hasn't started yet!")) + return + + var/list/hellhound_mob_list = list() // the list we'll be choosing from + for(var/mob/living/carbon/xenomorph/hellhound/Hellhound as anything in GLOB.hellhound_list) + if(Hellhound.client) + continue + hellhound_mob_list[Hellhound.name] = Hellhound + + var/choice = tgui_input_list(usr, "Pick a Hellhound:", "Join as Hellhound", hellhound_mob_list) + if(!choice) + return + + var/mob/living/carbon/xenomorph/hellhound/Hellhound = hellhound_mob_list[choice] + if(!Hellhound || !(Hellhound in GLOB.hellhound_list)) + return + + if(QDELETED(Hellhound) || Hellhound.client) + to_chat(src, span_warning("Something went wrong.")) + return + + if(Hellhound.stat == DEAD) + to_chat(src, span_warning("That Hellhound has died.")) + return + + current_mob.mind.transfer_to(Hellhound, TRUE) + Hellhound.generate_name() + +/mob/dead/verb/join_as_yautja() + set category = "Ghost" + set name = "Join the Hunt" + set desc = "If you are whitelisted, and it is the right type of round, join in." + + if(!client) + return + + if(SSticker.current_state < GAME_STATE_PLAYING || !SSticker.mode) + to_chat(src, span_warning("The game hasn't started yet!")) + return + + if(SSticker.mode.check_predator_late_join(src)) + SSticker.mode.join_predator(src) diff --git a/modular_RUtgmc/code/modules/mob/hologram.dm b/modular_RUtgmc/code/modules/mob/hologram.dm new file mode 100644 index 0000000000000..483332808f0e9 --- /dev/null +++ b/modular_RUtgmc/code/modules/mob/hologram.dm @@ -0,0 +1,80 @@ +GLOBAL_LIST_EMPTY(hologram_list) + +/mob/hologram + name = "Hologram" + desc = "It seems to be a visual projection of someone" //jinkies! + icon = 'icons/mob/mob.dmi' + icon_state = "hologram" + canmove = TRUE + + invisibility = INVISIBILITY_OBSERVER + sight = SEE_SELF + layer = ABOVE_FLY_LAYER + + var/action_icon_state = "hologram_exit" + + var/mob/linked_mob + var/datum/action/predator_action/leave_hologram/leave_button + +/mob/hologram/Initialize(mapload, mob/M) + if(!M) + return INITIALIZE_HINT_QDEL + + . = ..() + + GLOB.hologram_list += src + RegisterSignal(M, COMSIG_MOVABLE_PRE_MOVE, PROC_REF(handle_move)) + RegisterSignals(M, list( + COMSIG_HUMAN_DAMAGE_TAKEN, + COMSIG_XENOMORPH_TAKING_DAMAGE + ), PROC_REF(take_damage)) + + linked_mob = M + linked_mob.reset_perspective() + + name = "[initial(name)] ([M.name])" + + leave_button = new(null, action_icon_state) + leave_button.linked_hologram = src + leave_button.give_action(M) + +/mob/hologram/proc/take_damage(mob/M, datum/source, amount) + SIGNAL_HANDLER + + if(amount > 5) + qdel(src) + +/mob/hologram/proc/handle_move(mob/M, NewLoc, direct) + SIGNAL_HANDLER + + Move(get_step(loc, direct), direct) + return COMPONENT_MOVABLE_BLOCK_PRE_MOVE + +/mob/hologram/Destroy() + if(linked_mob) + linked_mob.reset_perspective() + linked_mob = null + + if(!QDESTROYING(leave_button)) + QDEL_NULL(leave_button) + else + leave_button = null + + GLOB.hologram_list -= src + + return ..() + +/datum/action/predator_action/leave_hologram + name = "Leave" + action_icon_state = "drone_return" + background_icon_state = "template_pred" + + var/mob/hologram/linked_hologram + +/datum/action/predator_action/leave_hologram/action_activate() + qdel(src) + +/datum/action/predator_action/leave_hologram/Destroy() + if(!QDESTROYING(linked_hologram)) + QDEL_NULL(linked_hologram) + return ..() diff --git a/modular_RUtgmc/code/modules/mob/living/carbon/carbon_defense.dm b/modular_RUtgmc/code/modules/mob/living/carbon/carbon_defense.dm index b55a4efd82449..4952fb30e3fef 100644 --- a/modular_RUtgmc/code/modules/mob/living/carbon/carbon_defense.dm +++ b/modular_RUtgmc/code/modules/mob/living/carbon/carbon_defense.dm @@ -1,2 +1,24 @@ +/mob/living/carbon/examine(mob/user) + . = ..() + if(isyautja(user)) + var/honor_value = max(life_kills_total + life_value, default_honor_value) + if(user.hunter_data && (hunter_data in user.hunter_data.targets)) + honor_value += 3 + . += span_blue("[src] is worth [honor_value] honor.") + if(hunter_data.automatic_target) + . += span_red("[src] marked as target for [hunter_data.targeted.real_name]") + if(hunter_data.hunted) + . += span_orange("[src] is being hunted by [hunter_data.hunter.real_name].") + + if(hunter_data.dishonored) + . += span_green("[src] was marked as dishonorable for '[hunter_data.dishonored_reason]'.") + else if(hunter_data.honored) + . += span_green("[src] was honored for '[hunter_data.honored_reason]'.") + + if(hunter_data.thralled) + . += span_green("[src] was thralled by [hunter_data.thralled_set.real_name] for '[hunter_data.thralled_reason]'.") + else if(hunter_data.gear) + . += span_red("[src] was marked as carrying gear by [hunter_data.gear_set].") + /mob/living/carbon/plastique_act() ex_act(500) diff --git a/modular_RUtgmc/code/modules/mob/living/carbon/human/emote-yautja.dm b/modular_RUtgmc/code/modules/mob/living/carbon/human/emote-yautja.dm new file mode 100644 index 0000000000000..85d6a30470a2f --- /dev/null +++ b/modular_RUtgmc/code/modules/mob/living/carbon/human/emote-yautja.dm @@ -0,0 +1,170 @@ +/datum/emote/living/carbon/human/species/yautja + mob_type_allowed_typecache = /mob/living/carbon/human/species/yautja + +/datum/emote/living/carbon/human/species/yautja/anytime + key = "anytime" + sound = 'modular_RUtgmc/sound/voice/pred_anytime.ogg' + key_third_person = "anytime" + message = "any time" + emote_type = EMOTE_AUDIBLE + +/datum/emote/living/carbon/human/species/yautja/click + key = "click" + key_third_person = "click" + message = "clicks" + emote_type = EMOTE_AUDIBLE + +/datum/emote/living/carbon/human/species/yautja/click/get_sound(mob/living/user) + if(rand(0,100) < 50) + return 'modular_RUtgmc/sound/voice/pred_click1.ogg' + else + return 'modular_RUtgmc/sound/voice/pred_click2.ogg' + +/datum/emote/living/carbon/human/species/yautja/helpme + key = "helpme" + sound = 'modular_RUtgmc/sound/voice/pred_helpme.ogg' + key_third_person = "helpme" + message = "help me!" + emote_type = EMOTE_AUDIBLE + +/datum/emote/living/carbon/human/species/yautja/iseeyou + key = "iseeyou" + sound = 'sound/hallucinations/i_see_you2.ogg' + key_third_person = "iseeyou" + message = "i see you!" + emote_type = EMOTE_AUDIBLE + +/datum/emote/living/carbon/human/species/yautja/itsatrap + key = "itsatrap" + sound = 'modular_RUtgmc/sound/voice/pred_itsatrap.ogg' + key_third_person = "itsatrap" + message = "it's a trap!" + emote_type = EMOTE_AUDIBLE + +/datum/emote/living/carbon/human/species/yautja/laugh1 + key = "laugh1" + sound = 'modular_RUtgmc/sound/voice/pred_laugh1.ogg' + key_third_person = "laugh1" + message = "laughs" + emote_type = EMOTE_AUDIBLE + +/datum/emote/living/carbon/human/species/yautja/laugh2 + key = "laugh2" + sound = 'modular_RUtgmc/sound/voice/pred_laugh2.ogg' + key_third_person = "laugh2" + message = "laughs" + emote_type = EMOTE_AUDIBLE + +/datum/emote/living/carbon/human/species/yautja/laugh3 + key = "laugh3" + sound = 'modular_RUtgmc/sound/voice/pred_laugh3.ogg' + key_third_person = "laugh3" + message = "laughs" + emote_type = EMOTE_AUDIBLE + +/datum/emote/living/carbon/human/species/yautja/laugh4 + key = "laugh4" + sound = 'modular_RUtgmc/sound/voice/pred_laugh4.ogg' + key_third_person = "laugh4" + message = "laughs" + emote_type = EMOTE_AUDIBLE + +/datum/emote/living/carbon/human/species/yautja/overhere + key = "overhere" + sound = 'modular_RUtgmc/sound/voice/pred_overhere.ogg' + key_third_person = "overhere" + message = "over here!" + emote_type = EMOTE_AUDIBLE + +/datum/emote/living/carbon/human/species/yautja/predroar + key = "predroar" + key_third_person = "predroars" + message = "roars!" + emote_type = EMOTE_AUDIBLE + +/datum/emote/living/carbon/human/species/yautja/predroar/get_sound(mob/living/user) + return pick('modular_RUtgmc/sound/voice/pred_roar1.ogg', 'modular_RUtgmc/sound/voice/pred_roar2.ogg') + +/datum/emote/living/carbon/human/species/yautja/predroar2 + key = "predroar2" + key_third_person = "predroars2" + sound = 'modular_RUtgmc/sound/voice/pred_roar3.ogg' + message = "roars!" + emote_type = EMOTE_AUDIBLE + +/datum/emote/living/carbon/human/species/yautja/loudroar + key = "loudroar" + key_third_person = "loudroar" + message = "roars loudly!" + cooldown = 120 SECONDS + emote_type = EMOTE_AUDIBLE + +/datum/emote/living/carbon/human/species/yautja/loudroar/get_sound(mob/living/user) + return pick('modular_RUtgmc/sound/voice/pred_roar4.ogg', 'modular_RUtgmc/sound/voice/pred_roar5.ogg') + +/datum/emote/living/carbon/human/species/yautja/loudroar/run_emote(mob/user, params, type_override, intentional) + . = ..() + if(!.) + return + + for(var/mob/current_mob in GLOB.mob_list) + if(!current_mob.z != user.z || !get_dist(get_turf(current_mob), get_turf(user)) <= 18) + continue + var/relative_dir = get_dir(current_mob, user) + var/final_dir = dir2text(relative_dir) + to_chat(current_mob, span_highdanger("You hear a loud roar coming from [final_dir ? "the [final_dir]" : "nearby"]!")) + +/datum/emote/living/carbon/human/species/yautja/turnaround + key = "turnaround" + key_third_person = "turnaround" + message = "turn around!" + sound = 'modular_RUtgmc/sound/voice/pred_turnaround.ogg' + emote_type = EMOTE_AUDIBLE + +/datum/emote/living/carbon/human/species/yautja/click2 + key = "click2" + key_third_person = "click2" + message = "clicks" + emote_type = EMOTE_AUDIBLE + +/datum/emote/living/carbon/human/species/yautja/click2/get_sound(mob/living/user) + return pick('modular_RUtgmc/sound/voice/pred_click3.ogg', 'modular_RUtgmc/sound/voice/pred_click4.ogg') + +/datum/emote/living/carbon/human/species/yautja/aliengrowl + key = "aliengrowl" + key_third_person = "aliengrowl" + message = "growls!" + emote_type = EMOTE_AUDIBLE + +/datum/emote/living/carbon/human/species/yautja/aliengrowl/get_sound(mob/living/user) + return pick('sound/voice/alien_growl1.ogg', 'sound/voice/alien_growl2.ogg') + +/datum/emote/living/carbon/human/species/yautja/alienhelp + key = "alienhelp" + key_third_person = "alienhelp" + message = "needs help!" + emote_type = EMOTE_AUDIBLE + +/datum/emote/living/carbon/human/species/yautja/alienhelp/get_sound(mob/living/user) + return pick('sound/voice/alien_help1.ogg', 'sound/voice/alien_help2.ogg') + +/datum/emote/living/carbon/human/species/yautja/comeonout + key = "comeonout" + key_third_person = "comeonout" + message = "come on out!" + sound = 'modular_RUtgmc/sound/voice/pred_come_on_out.ogg' + emote_type = EMOTE_AUDIBLE + +/datum/emote/living/carbon/human/species/yautja/overthere + key = "overthere" + key_third_person = "overthere" + message = "over there!" + sound = 'modular_RUtgmc/sound/voice/pred_over_there.ogg' + emote_type = EMOTE_AUDIBLE + +/datum/emote/living/carbon/human/species/yautja/uglyfreak + key = "uglyfreak" + key_third_person = "uglyfreak" + message = "ugly freak!" + sound = 'modular_RUtgmc/sound/voice/pred_ugly_freak.ogg' + emote_type = EMOTE_AUDIBLE diff --git a/modular_RUtgmc/code/modules/mob/living/carbon/human/human_defense.dm b/modular_RUtgmc/code/modules/mob/living/carbon/human/human_defense.dm index 30de97f04185e..b45540cfb5571 100644 --- a/modular_RUtgmc/code/modules/mob/living/carbon/human/human_defense.dm +++ b/modular_RUtgmc/code/modules/mob/living/carbon/human/human_defense.dm @@ -18,3 +18,54 @@ user.put_in_hands(heart) chestburst = 2 update_burst() + +/mob/living/carbon/human/ExtinguishMob() + . = ..() + SEND_SIGNAL(src, COMSIG_HUMAN_EXTINGUISH) + +/mob/living/carbon/human/proc/check_pred_shields(damage = 0, attack_text = "the attack", combistick = FALSE, backside_attack = FALSE, xenomorph = FALSE) + if(skills.getRating("swordplay") < SKILL_SWORDPLAY_TRAINED) + return FALSE + + var/block_effect = /obj/effect/temp_visual/block + var/owner_turf = get_turf(src) + for(var/obj/item/weapon/I in list(l_hand, r_hand)) + if(I && istype(I, /obj/item/weapon) && !isgun(I) && !istype(I, /obj/item/weapon/twohanded/offhand))//Current base is the prob(50-d/3) + if(combistick && istype(I, /obj/item/weapon/yautja/combistick) && prob(I.can_block_chance)) + var/obj/item/weapon/yautja/combistick/C = I + if(C.on) + return TRUE + + if(istype(I, /obj/item/weapon/shield/riot/yautja)) // Activable shields + var/obj/item/weapon/shield/riot/yautja/S = I + var/shield_blocked = FALSE + if(S.shield_readied && prob(S.readied_block)) // User activated his shield before the attack. Lower if it blocks. + S.lower_shield(src) + shield_blocked = TRUE + else if(prob(S.passive_block)) + shield_blocked = TRUE + + if(shield_blocked) + new block_effect(owner_turf, COLOR_YELLOW) + playsound(src, 'modular_RUtgmc/sound/items/block_shield.ogg', BLOCK_SOUND_VOLUME, vary = TRUE) + visible_message(span_danger("[src] blocks [attack_text] with the [I.name]!"), null, null, 5) + return TRUE + // We cannot return FALSE on fail here, because we haven't checked r_hand yet. Dual-wielding shields perhaps! + + else if((!xenomorph || I.can_block_xeno) && (prob(I.can_block_chance - round(damage / 3)))) // 'other' shields, like predweapons. Make sure that item/weapon/shield does not apply here, no double-rolls. + new block_effect(owner_turf, COLOR_YELLOW) + if(istype(I, /obj/item/weapon/shield)) + playsound(src, 'modular_RUtgmc/sound/items/block_shield.ogg', BLOCK_SOUND_VOLUME, vary = TRUE) + else + playsound(src, 'modular_RUtgmc/sound/items/parry.ogg', BLOCK_SOUND_VOLUME, vary = TRUE) + visible_message(span_danger("[src] blocks [attack_text] with the [I.name]!"), null, null, 5) + return TRUE + + var/obj/item/weapon/shield/riot/yautja/shield = back + if(backside_attack && istype(shield) && prob(shield.readied_block)) + if(shield.blocks_on_back) + playsound(src, 'modular_RUtgmc/sound/items/block_shield.ogg', BLOCK_SOUND_VOLUME, vary = TRUE) + visible_message(span_danger("The [back] on [src]'s back blocks [attack_text]!"), null, null, 5) + return TRUE + + return FALSE diff --git a/modular_RUtgmc/code/modules/mob/living/carbon/human/human_defines.dm b/modular_RUtgmc/code/modules/mob/living/carbon/human/human_defines.dm index f6144533a37c2..11b7991df3fee 100644 --- a/modular_RUtgmc/code/modules/mob/living/carbon/human/human_defines.dm +++ b/modular_RUtgmc/code/modules/mob/living/carbon/human/human_defines.dm @@ -1,4 +1,7 @@ /mob/living/carbon/human + hud_possible = list(HEALTH_HUD, STATUS_HUD_SIMPLE, STATUS_HUD, XENO_EMBRYO_HUD, XENO_REAGENT_HUD, WANTED_HUD, SQUAD_HUD_TERRAGOV, SQUAD_HUD_SOM, ORDER_HUD, PAIN_HUD, XENO_DEBUFF_HUD, HEART_STATUS_HUD, HUNTER_CLAN, HUNTER_HUD, HUNTER_HEALTH_HUD) appearance_flags = KEEP_TOGETHER|TILE_BOUND|PIXEL_SCALE /// Used for preventing possible lags in the med_hud_set_status(), yes it's ugly var/initial_stage + + var/initial_transform diff --git a/modular_RUtgmc/code/modules/mob/living/carbon/human/update_icons.dm b/modular_RUtgmc/code/modules/mob/living/carbon/human/update_icons.dm new file mode 100644 index 0000000000000..cc6a025ee285e --- /dev/null +++ b/modular_RUtgmc/code/modules/mob/living/carbon/human/update_icons.dm @@ -0,0 +1,44 @@ +//HAIR OVERLAY +/mob/living/carbon/human/species/yautja/update_hair() + //Reset our hair + remove_overlay(HAIR_LAYER) + + if(species.species_flags & HAS_NO_HAIR) + return + + var/datum/limb/head/head_organ = get_limb("head") + if(!head_organ || (head_organ.limb_status & LIMB_DESTROYED) ) + return + + //masks and helmets can obscure our hair. + if((head?.flags_inv_hide & HIDEALLHAIR) || (wear_mask?.flags_inv_hide & HIDEALLHAIR)) + return + + //base icons + var/icon/face_standing = new /icon('icons/mob/human_face.dmi',"bald_s") + + if(h_style && !(head?.flags_inv_hide & HIDETOPHAIR)) + var/datum/sprite_accessory/hair_style = GLOB.yautja_hair_styles_list[h_style] + if(hair_style && (species.name in hair_style.species_allowed)) + var/icon/hair_s = new/icon("icon" = hair_style.icon, "icon_state" = "[hair_style.icon_state]_s") + + face_standing.Blend(hair_s, ICON_OVERLAY) + + var/mutable_appearance/hair_final = mutable_appearance(face_standing, layer =-HAIR_LAYER) + + if(head?.flags_inv_hide & HIDE_EXCESS_HAIR) + var/image/mask = image('icons/mob/human_face.dmi', null, "Jeager_Mask") + mask.render_target = "*[REF(src)]" + hair_final.overlays += mask + hair_final.filters += filter(arglist(alpha_mask_filter(0, 0, null, "*[REF(src)]"))) + + overlays_standing[HAIR_LAYER] = hair_final + apply_overlay(HAIR_LAYER) + +/mob/living/carbon/human/proc/add_flay_overlay(stage = 1) + remove_overlay(FLAY_LAYER) + var/image/flay_icon = new /image('modular_RUtgmc/icons/mob/hunter/dam_human.dmi', "human_[stage]") + flay_icon.layer = -FLAY_LAYER + flay_icon.blend_mode = BLEND_INSET_OVERLAY + overlays_standing[FLAY_LAYER] = flay_icon + apply_overlay(FLAY_LAYER) diff --git a/modular_RUtgmc/code/modules/mob/living/carbon/human/yautja.dm b/modular_RUtgmc/code/modules/mob/living/carbon/human/yautja.dm new file mode 100644 index 0000000000000..eb63198bd62f4 --- /dev/null +++ b/modular_RUtgmc/code/modules/mob/living/carbon/human/yautja.dm @@ -0,0 +1,295 @@ +/mob/living/carbon/human/species/yautja + chat_color = "#aa0000" + +/mob/living/carbon/human/species/yautja/get_paygrade() + if(client.clan_info) + return client.clan_info.item[2] <= GLOB.clan_ranks_ordered.len ? GLOB.clan_ranks_ordered[client.clan_info.item[2]] : GLOB.clan_ranks_ordered[1] + +/datum/species/yautja + name = "Yautja" + name_plural = "Yautja" + brute_mod = 0.28 //Beefy! + burn_mod = 0.45 + reagent_tag = IS_YAUTJA + species_flags = HAS_SKIN_COLOR|NO_POISON|NO_PAIN|USES_ALIEN_WEAPONS|PARALYSE_RESISTANT + inherent_traits = list( + TRAIT_YAUTJA_TECH, + TRAIT_SUPER_STRONG, + TRAIT_FOREIGN_BIO, + ) + inherent_actions = list( + /datum/action/predator_action/mark_for_hunt, + /datum/action/predator_action/mark_panel, + ) + + screams = list(MALE = "pred_scream", FEMALE = "pred_scream") + paincries = list(MALE = "pred_pain", FEMALE = "pred_pain") + goredcries = list(MALE = "pred_pain", FEMALE = "pred_pain") + burstscreams = list(MALE = "pred_preburst", FEMALE = "pred_preburst") + warcries = list(MALE = "pred_warcry", FEMALE = "pred_warcry") + + unarmed_type = /datum/unarmed_attack/punch/strong + secondary_unarmed_type = /datum/unarmed_attack/bite/strong + max_stamina = 250 + blood_color = "#20d450" + flesh_color = "#907E4A" + speech_sounds = list('sound/voice/pred_click1.ogg', 'sound/voice/pred_click2.ogg') + speech_chance = 100 + death_message = "clicks in agony and falls still, motionless and completely lifeless..." + + brute_damage_icon_state = "pred_brute" + burn_damage_icon_state = "pred_burn" + + darksight = 5 + slowdown = -0.5 + total_health = 175 //more health than regular humans + + default_language_holder = /datum/language_holder/yautja + + heat_level_1 = 500 + heat_level_2 = 700 + heat_level_3 = 1000 + + inherent_verbs = list( + /mob/living/carbon/human/proc/butcher, + ) + + knock_down_reduction = 4 + stun_reduction = 4 + + icobase = 'modular_RUtgmc/icons/mob/hunter/r_predator.dmi' + +/datum/species/yautja/handle_death(mob/living/carbon/human/H, gibbed) + if(gibbed) + GLOB.yautja_mob_list -= H + + for(var/mob/living/carbon/M in H.hunter_data.dishonored_targets) + M.hunter_data.dishonored_set = null + H.hunter_data.dishonored_targets -= M + for(var/mob/living/carbon/M in H.hunter_data.honored_targets) + M.hunter_data.honored_set = null + H.hunter_data.honored_targets -= M + for(var/mob/living/carbon/M in H.hunter_data.gear_targets) + M.hunter_data.gear_set = null + H.hunter_data.gear_targets -= M + + if(H.hunter_data.prey) + var/mob/living/carbon/M = H.hunter_data.prey + H.hunter_data.prey = null + M.hunter_data.hunter = null + M.hud_set_hunter() + + set_predator_status(H, gibbed ? "Gibbed" : "Dead") + + // Notify all yautja so they start the gear recovery + message_all_yautja("[H.real_name] has died at \the [get_area_name(H)].") + + if(H.hunter_data.thrall) + var/mob/living/carbon/T = H.hunter_data.thrall + message_all_yautja("[H.real_name]'s Thrall, [T.real_name] is now masterless.") + H.message_thrall("Your master has fallen!") + H.hunter_data.thrall = null + +/datum/species/yautja/proc/set_predator_status(mob/living/carbon/human/H, status = "Alive") + if(!H.key) + return + var/datum/game_mode/GM + if(SSticker?.mode) + GM = SSticker.mode + if(H.key in GM.predators) + GM.predators[lowertext(H.key)]["Status"] = status + else + GM.predators[lowertext(H.key)] = list("Name" = H.real_name, "Status" = status) + +/datum/species/yautja/on_species_gain(mob/living/carbon/human/H, datum/species/old_species) + . = ..() + var/datum/atom_hud/A = GLOB.huds[DATA_HUD_MEDICAL_ADVANCED] + A.add_to_hud(H) + add_inherent_abilities(H) + + for(var/datum/limb/limb in H.limbs) + switch(limb.name) + if("groin","chest") + limb.min_broken_damage = 120 + limb.max_damage = 350 + if("head") + limb.min_broken_damage = 100 + limb.max_damage = 350 + if("l_hand","r_hand","r_foot","l_foot") + limb.min_broken_damage = 85 + limb.max_damage = 180 + if("r_leg","r_arm","l_leg","l_arm") + limb.min_broken_damage = 100 + limb.max_damage = 225 + + set_predator_status(H, "Alive") + +/datum/species/yautja/post_species_loss(mob/living/carbon/human/H) + ..() + var/datum/atom_hud/A = GLOB.huds[DATA_HUD_MEDICAL_ADVANCED] + A.remove_hud_from(H) + remove_inherent_abilities(H) + H.blood_type = pick("A+","A-","B+","B-","O-","O+","AB+","AB-") + H.h_style = "Bald" + GLOB.yautja_mob_list -= H + + for(var/datum/limb/limb in H.limbs) + switch(limb.name) + if("groin","chest") + limb.min_broken_damage = 60 + limb.max_damage = 200 + if("head") + limb.min_broken_damage = 40 + limb.max_damage = 125 + if("l_hand","r_hand","r_foot","l_foot") + limb.min_broken_damage = 37 + limb.max_damage = 100 + if("r_arm","l_arm") + limb.min_broken_damage = 50 + limb.max_damage = 150 + if("r_leg","l_leg") + limb.min_broken_damage = 50 + limb.max_damage = 125 + + set_predator_status(H, "Demoted") + + if(H.actions_by_path[/datum/action/minimap/yautja]) + var/datum/action/minimap/yautja/mini = H.actions_by_path[/datum/action/minimap/yautja] + mini.remove_action(src) + +/datum/species/yautja/handle_post_spawn(mob/living/carbon/human/H) + GLOB.alive_human_list -= H + + H.blood_type = "Y*" + H.h_style = H.client ? H.client.prefs.predator_h_style : "Standard" + #ifndef UNIT_TESTS // Since this is a hard ref, we shouldn't confuse create_and_destroy + GLOB.yautja_mob_list += H + #endif + + if(!H.actions_by_path[/datum/action/minimap/yautja]) + var/datum/action/minimap/yautja/mini = new + mini.give_action(H) + + return ..() + +/mob/proc/hud_set_hunter() + return + +var/global/image/hud_icon_hunter_gear +var/global/image/hud_icon_hunter_hunted +var/global/image/hud_icon_hunter_dishonored +var/global/image/hud_icon_hunter_honored +var/global/image/hud_icon_hunter_thralled + +/mob/living/carbon/hud_set_hunter() + var/image/holder = hud_list[HUNTER_HUD] + if(!holder) + return + holder.icon_state = "hudblank" + holder.overlays.Cut() + if(hunter_data.hunted) + if(!hud_icon_hunter_hunted) + hud_icon_hunter_hunted = image('modular_RUtgmc/icons/mob/screen/yautja.dmi', src, "hunter_hunted") + holder.overlays += hud_icon_hunter_hunted + + if(hunter_data.dishonored) + if(!hud_icon_hunter_dishonored) + hud_icon_hunter_dishonored = image('modular_RUtgmc/icons/mob/screen/yautja.dmi', src, "hunter_dishonored") + holder.overlays += hud_icon_hunter_dishonored + else if(hunter_data.honored) + if(!hud_icon_hunter_honored) + hud_icon_hunter_honored = image('modular_RUtgmc/icons/mob/screen/yautja.dmi', src, "hunter_honored") + holder.overlays += hud_icon_hunter_honored + + if(hunter_data.thralled) + if(!hud_icon_hunter_thralled) + hud_icon_hunter_thralled = image('modular_RUtgmc/icons/mob/screen/yautja.dmi', src, "hunter_thralled") + holder.overlays += hud_icon_hunter_thralled + else if(hunter_data.gear) + if(!hud_icon_hunter_gear) + hud_icon_hunter_gear = image('modular_RUtgmc/icons/mob/screen/yautja.dmi', src, "hunter_gear") + holder.overlays += hud_icon_hunter_gear + + hud_list[HUNTER_HUD] = holder + +/mob/living/carbon/xenomorph/hud_set_hunter() + var/image/holder = hud_list[HUNTER_HUD] + if(!holder) + return + holder.icon_state = "hudblank" + holder.overlays.Cut() + holder.pixel_x = -17 + holder.pixel_y = 20 + if(hunter_data.hunted) + if(!hud_icon_hunter_hunted) + hud_icon_hunter_hunted = image('modular_RUtgmc/icons/mob/screen/yautja.dmi', src, "hunter_hunted") + holder.overlays += hud_icon_hunter_hunted + + if(hunter_data.dishonored) + if(!hud_icon_hunter_dishonored) + hud_icon_hunter_dishonored = image('modular_RUtgmc/icons/mob/screen/yautja.dmi', src, "hunter_dishonored") + holder.overlays += hud_icon_hunter_dishonored + else if(hunter_data.honored) + if(!hud_icon_hunter_honored) + hud_icon_hunter_honored = image('modular_RUtgmc/icons/mob/screen/yautja.dmi', src, "hunter_honored") + holder.overlays += hud_icon_hunter_honored + + hud_list[HUNTER_HUD] = holder + +/mob/living/carbon/human/species/yautja/hud_set_hunter() + . = ..() + + var/image/holder = hud_list[HUNTER_CLAN] + if(!holder) + return + + holder.icon_state = "predhud" + + if(client?.clan_info?.item?[4]) + var/datum/db_query/player_clan = SSdbcore.NewQuery("SELECT id, name, description, honor, color FROM [format_table_name("clan")] WHERE id = :clan_id", list("clan_id" = client.clan_info.item[4])) + player_clan.Execute() + if(player_clan.NextRow()) + holder.color = player_clan.item[5] + + hud_list[HUNTER_CLAN] = holder + +/mob/living/carbon/human/species/yautja/send_speech(message_raw, message_range = 6, obj/source = src, bubble_type = bubble_icon, list/spans, datum/language/message_language=null, message_mode, tts_message, list/tts_filter) + . = ..() + playsound(loc, pick('sound/voice/pred_click1.ogg', 'sound/voice/pred_click2.ogg'), 25, 1) + +/mob/living/carbon/human/species/yautja/get_idcard(hand_first = TRUE) + . = ..() + if(!.) + var/obj/item/clothing/gloves/yautja/hunter/bracer = gloves + if(istype(bracer)) + . = bracer.embedded_id + return . + +/mob/living/carbon/human/proc/disable_special_items() + set waitfor = FALSE // Scout decloak animation uses sleep(), which is problematic for taser gun + + if(istype(back, /obj/item/storage/backpack/marine/satchel/scout_cloak)) + var/obj/item/storage/backpack/marine/satchel/scout_cloak/SC = back + if(SC.camo_active) + SC.camo_off(src) + return + var/list/cont = list() + for(var/atom/A in contents) + cont += A + if(A.contents.len) + cont += A.contents + + for(var/i in cont) + if(istype(i, /obj/item/assembly/prox_sensor)) + var/obj/item/assembly/prox_sensor/prox = i + if(prox.scanning) + prox.toggle_scan() + if(istype(i, /obj/item/attachable/motiondetector)) + var/obj/item/attachable/motiondetector/md = i + md.clean_operator() + +/mob/living/carbon/human/species/yautja/get_reagent_tags() + return species?.reagent_tag + +/mob/living/carbon/human/species/yautja/can_be_operated_on(mob/user) + return TRUE diff --git a/modular_RUtgmc/code/modules/mob/living/carbon/xenomorph/abilities.dm b/modular_RUtgmc/code/modules/mob/living/carbon/xenomorph/abilities.dm index 37f9b8610073f..5739ce490ad1a 100644 --- a/modular_RUtgmc/code/modules/mob/living/carbon/xenomorph/abilities.dm +++ b/modular_RUtgmc/code/modules/mob/living/carbon/xenomorph/abilities.dm @@ -122,3 +122,7 @@ new_resin = new X.selected_resin(T) if(new_resin) SSresinshaping.increment_build_counter(owner) + +/datum/action/ability/activable/xeno/pounce/hellhound + cooldown_duration = 5 SECONDS + diff --git a/modular_RUtgmc/code/modules/mob/living/carbon/xenomorph/castes/beetle/beetle.dm b/modular_RUtgmc/code/modules/mob/living/carbon/xenomorph/castes/beetle/beetle.dm new file mode 100644 index 0000000000000..470ebc115f378 --- /dev/null +++ b/modular_RUtgmc/code/modules/mob/living/carbon/xenomorph/castes/beetle/beetle.dm @@ -0,0 +1,3 @@ +/mob/living/carbon/xenomorph/beetle + life_value = 0 + default_honor_value = 0 diff --git a/modular_RUtgmc/code/modules/mob/living/carbon/xenomorph/castes/defiler/defiler.dm b/modular_RUtgmc/code/modules/mob/living/carbon/xenomorph/castes/defiler/defiler.dm index 035017cd892d5..baf2b69278df7 100644 --- a/modular_RUtgmc/code/modules/mob/living/carbon/xenomorph/castes/defiler/defiler.dm +++ b/modular_RUtgmc/code/modules/mob/living/carbon/xenomorph/castes/defiler/defiler.dm @@ -1,2 +1,4 @@ /mob/living/carbon/xenomorph/defiler + life_value = 0 + default_honor_value = 0 mob_size = MOB_SIZE_BIG diff --git a/modular_RUtgmc/code/modules/mob/living/carbon/xenomorph/castes/facehugger/facehugger.dm b/modular_RUtgmc/code/modules/mob/living/carbon/xenomorph/castes/facehugger/facehugger.dm index 337bd7e80a835..0ad923e0682a4 100644 --- a/modular_RUtgmc/code/modules/mob/living/carbon/xenomorph/castes/facehugger/facehugger.dm +++ b/modular_RUtgmc/code/modules/mob/living/carbon/xenomorph/castes/facehugger/facehugger.dm @@ -9,6 +9,9 @@ maxHealth = 50 plasma_stored = 100 + life_value = 0 + default_honor_value = 0 + pixel_x = -8 pixel_y = -3 old_x = -8 diff --git a/modular_RUtgmc/code/modules/mob/living/carbon/xenomorph/castes/hellhound/hellhound.dm b/modular_RUtgmc/code/modules/mob/living/carbon/xenomorph/castes/hellhound/hellhound.dm index a55e5ed74e876..bc334b322682c 100644 --- a/modular_RUtgmc/code/modules/mob/living/carbon/xenomorph/castes/hellhound/hellhound.dm +++ b/modular_RUtgmc/code/modules/mob/living/carbon/xenomorph/castes/hellhound/hellhound.dm @@ -40,7 +40,7 @@ caste_base_type = /mob/living/carbon/xenomorph/hellhound name = "Hellhound" desc = "A disgusting beast from hell, it has four menacing spikes growing from its head." - icon = 'icons/Xeno/hellhound.dmi' + icon = 'modular_RUtgmc/icons/Xeno/castes/hellhound.dmi' icon_state = "Hellhound Walking" health = 290 maxHealth = 290 diff --git a/modular_RUtgmc/code/modules/mob/living/carbon/xenomorph/castes/larva/larva.dm b/modular_RUtgmc/code/modules/mob/living/carbon/xenomorph/castes/larva/larva.dm index 596b61c5b5a57..aab4a11d7c932 100644 --- a/modular_RUtgmc/code/modules/mob/living/carbon/xenomorph/castes/larva/larva.dm +++ b/modular_RUtgmc/code/modules/mob/living/carbon/xenomorph/castes/larva/larva.dm @@ -1,3 +1,109 @@ /mob/living/carbon/xenomorph/larva + hud_possible = list(HEALTH_HUD_XENO, PHEROMONE_HUD, QUEEN_OVERWATCH_HUD, ARMOR_SUNDER_HUD, XENO_DEBUFF_HUD, XENO_FIRE_HUD, XENO_BANISHED_HUD, XENO_BLESSING_HUD, XENO_EVASION_HUD, HUNTER_CLAN, HUNTER_HUD) + talk_sound = "larva_talk" - hud_possible = list(HEALTH_HUD_XENO, PHEROMONE_HUD, QUEEN_OVERWATCH_HUD, ARMOR_SUNDER_HUD, XENO_DEBUFF_HUD, XENO_FIRE_HUD, XENO_BANISHED_HUD, XENO_BLESSING_HUD, XENO_EVASION_HUD) + life_value = 0 + default_honor_value = 0 + +/datum/xeno_caste/larva_predalien + caste_name = "Predalien Larva" + display_name = "Predalien Bloody Larva" + upgrade_name = "" + caste_desc = "D'awwwww, so cute!" + caste_type_path = /mob/living/carbon/xenomorph/larva/predalien + tier = XENO_TIER_ZERO + upgrade = XENO_UPGRADE_BASETYPE + wound_type = "larva" //used to match appropriate wound overlays + + gib_anim = "larva_gib_corpse" + gib_flick = "larva_gib" + + // *** Melee Attacks *** // + melee_damage = 0 + + // *** Speed *** // + speed = -1.6 + + // *** Plasma *** // + plasma_gain = 1 + + // *** Health *** // + max_health = 50 + crit_health = -25 + + // *** Evolution *** // + evolution_threshold = 50 + evolves_to = list( + /mob/living/carbon/xenomorph/predalien, + ) + + // *** Flags *** // + caste_flags = CASTE_EVOLUTION_ALLOWED|CASTE_INNATE_HEALING + can_flags = CASTE_CAN_BE_QUEEN_HEALED|CASTE_CAN_RIDE_CRUSHER + caste_traits = list(TRAIT_CAN_VENTCRAWL) + + // *** Defense *** // + soft_armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, FIRE = 0, ACID = 0) + + // *** Minimap Icon *** // + minimap_icon = "predalien_larva" + + // *** Abilities *** // + actions = list( + /datum/action/ability/xeno_action/xeno_resting, + /datum/action/ability/xeno_action/watch_xeno, + /datum/action/ability/xeno_action/xenohide, + ) + + // *** Vent Crawl Parameters *** // + vent_enter_speed = LARVA_VENT_CRAWL_TIME + vent_exit_speed = LARVA_VENT_CRAWL_TIME + silent_vent_crawl = TRUE + +/datum/xeno_caste/larva_predalien/young + upgrade = XENO_UPGRADE_INVALID + +/mob/living/carbon/xenomorph/larva/predalien + icon = 'modular_RUtgmc/icons/Xeno/castes/predalien_larva.dmi' + icon_state = "Predalien Larva" + base_icon_state = "Predalien Larva" + caste_base_type = /mob/living/carbon/xenomorph/larva/predalien + +/mob/living/carbon/xenomorph/larva/predalien/Initialize(mapload, mob/living/carbon/xenomorph/oldxeno, h_number) + . = ..() + hunter_data.dishonored = TRUE + hunter_data.dishonored_reason = "An abomination upon the honor of us all!" + hunter_data.dishonored_set = src + hud_set_hunter() + +// *************************************** +// *********** Name +// *************************************** +/mob/living/carbon/xenomorph/larva/predalien/generate_name() + name = "[hive.prefix] Predalien Larva ([nicknumber])" + + //Update linked data so they show up properly + real_name = name + if(mind) + mind.name = name //This gives them the proper name in deadchat if they explode on death. It's always the small things + +// *************************************** +// *********** Icon +// *************************************** +/mob/living/carbon/xenomorph/larva/predalien/update_icons() + generate_name() + + color = hive.color + + if(stat == DEAD) + icon_state = "[base_icon_state] Dead" + else if(handcuffed) + icon_state = "[base_icon_state] Cuff" + + else if(lying_angle) + if((resting || IsSleeping()) && (!IsParalyzed() && !IsUnconscious() && health > 0)) + icon_state = "[base_icon_state] Sleeping" + else + icon_state = "[base_icon_state] Stunned" + else + icon_state = "[base_icon_state]" diff --git a/modular_RUtgmc/code/modules/mob/living/carbon/xenomorph/castes/mantis/mantis.dm b/modular_RUtgmc/code/modules/mob/living/carbon/xenomorph/castes/mantis/mantis.dm new file mode 100644 index 0000000000000..014ad31356c52 --- /dev/null +++ b/modular_RUtgmc/code/modules/mob/living/carbon/xenomorph/castes/mantis/mantis.dm @@ -0,0 +1,3 @@ +/mob/living/carbon/xenomorph/mantis + life_value = 0 + default_honor_value = 0 diff --git a/modular_RUtgmc/code/modules/mob/living/carbon/xenomorph/castes/predalien/abilities_predalien.dm b/modular_RUtgmc/code/modules/mob/living/carbon/xenomorph/castes/predalien/abilities_predalien.dm index 8b65e45d174cb..d960bacc6f5b5 100644 --- a/modular_RUtgmc/code/modules/mob/living/carbon/xenomorph/castes/predalien/abilities_predalien.dm +++ b/modular_RUtgmc/code/modules/mob/living/carbon/xenomorph/castes/predalien/abilities_predalien.dm @@ -6,8 +6,7 @@ desc = "Leap at your targer stunning and slashing them. Stun duration and damage increases with each stack of hunted prey." action_icon_state = "powerful_pounce" - range = 5 - mob_hit_sound = 'sound/voice/predalien_pounce.ogg' + pounce_range = 5 var/base_damage = 25 var/damage_scale = 10 // How much it scales by every kill @@ -174,10 +173,10 @@ xeno.anchored = TRUE xeno.Immobilize(30 SECONDS) - if(do_after(xeno, activation_delay, TRUE, carbon, BUSY_ICON_HOSTILE, BUSY_ICON_HOSTILE)) + if(do_after(xeno, activation_delay, NONE, carbon, BUSY_ICON_HOSTILE, BUSY_ICON_HOSTILE)) xeno.visible_message(span_xenohighdanger("[xeno] rips open the guts of [carbon]!"), span_xenohighdanger("You rip open the guts of [carbon]!")) carbon.spawn_gibs() - playsound(get_turf(carbon), 'sound/effects/gibbed.ogg', 75, 1) + playsound(get_turf(carbon), 'modular_RUtgmc/sound/effects/gibbed.ogg', 75, 1) carbon.apply_effect(0.5, WEAKEN) carbon.apply_damage(base_damage + damage_scale * min(xeno.life_kills_total, xeno.max_bonus_life_kills), BRUTE, "chest", MELEE, FALSE, FALSE, TRUE, 20) @@ -188,7 +187,7 @@ xeno.setDir(turn(xeno.dir, 90)) xeno.do_attack_animation(carbon, ATTACK_EFFECT_BITE) - playsound(xeno, 'sound/voice/predalien_growl.ogg', 75, 0) + playsound(xeno, 'modular_RUtgmc/sound/voice/predalien_growl.ogg', 75, 0) xeno.anchored = FALSE xeno.SetImmobilized(0) diff --git a/modular_RUtgmc/code/modules/mob/living/carbon/xenomorph/castes/predalien/castedatum_predalien.dm b/modular_RUtgmc/code/modules/mob/living/carbon/xenomorph/castes/predalien/castedatum_predalien.dm index 5cd1ad7392333..0efcaaee1ecd3 100644 --- a/modular_RUtgmc/code/modules/mob/living/carbon/xenomorph/castes/predalien/castedatum_predalien.dm +++ b/modular_RUtgmc/code/modules/mob/living/carbon/xenomorph/castes/predalien/castedatum_predalien.dm @@ -21,9 +21,6 @@ // *** Health *** // max_health = 650 - // *** Evolution *** // - upgrade_threshold = TIER_THREE_THRESHOLD - // *** Minimap Icon *** // minimap_icon = "predalien" diff --git a/modular_RUtgmc/code/modules/mob/living/carbon/xenomorph/castes/predalien/predalien.dm b/modular_RUtgmc/code/modules/mob/living/carbon/xenomorph/castes/predalien/predalien.dm index bd19371735311..63a08bd2e78f3 100644 --- a/modular_RUtgmc/code/modules/mob/living/carbon/xenomorph/castes/predalien/predalien.dm +++ b/modular_RUtgmc/code/modules/mob/living/carbon/xenomorph/castes/predalien/predalien.dm @@ -2,7 +2,7 @@ caste_base_type = /mob/living/carbon/xenomorph/predalien name = "Abomination" //snowflake name desc = "A strange looking creature with fleshy strands on its head. It appears like a mixture of armor and flesh, smooth, but well carapaced." - icon = 'modular_RUtgmc/icons/Xeno/castes/predalien.dmi' + icon = 'modular_RUtgmc/icons/Xeno/castes/predalien_praetorian.dmi' icon_state = "Predalien Walking" wall_smash = TRUE pixel_x = -16 @@ -14,6 +14,8 @@ tier = XENO_TIER_FOUR upgrade = XENO_UPGRADE_NORMAL + footstep_type = FOOTSTEP_PREDALIEN_STOMPY + var/max_bonus_life_kills = 10 var/butcher_time = 6 SECONDS diff --git a/modular_RUtgmc/code/modules/mob/living/carbon/xenomorph/castes/scorpion/scorpion.dm b/modular_RUtgmc/code/modules/mob/living/carbon/xenomorph/castes/scorpion/scorpion.dm new file mode 100644 index 0000000000000..4460071da4322 --- /dev/null +++ b/modular_RUtgmc/code/modules/mob/living/carbon/xenomorph/castes/scorpion/scorpion.dm @@ -0,0 +1,3 @@ +/mob/living/carbon/xenomorph/scorpion + life_value = 0 + default_honor_value = 0 diff --git a/modular_RUtgmc/code/modules/mob/living/carbon/xenomorph/egg.dm b/modular_RUtgmc/code/modules/mob/living/carbon/xenomorph/egg.dm index 0d737891390be..d2687282b1213 100644 --- a/modular_RUtgmc/code/modules/mob/living/carbon/xenomorph/egg.dm +++ b/modular_RUtgmc/code/modules/mob/living/carbon/xenomorph/egg.dm @@ -68,6 +68,12 @@ F.death(deathmessage = "get inside the egg", silent = TRUE) qdel(F) +/obj/alien/egg/hugger/forsaken + hivenumber = XENO_HIVE_FORSAKEN + +/obj/alien/egg/hugger/forsaken/attack_ghost(mob/dead/observer/user) + return + /obj/alien/egg/gas desc = "It looks like a suspiciously weird egg" name = "gas egg" diff --git a/modular_RUtgmc/code/modules/mob/living/carbon/xenomorph/evolution.dm b/modular_RUtgmc/code/modules/mob/living/carbon/xenomorph/evolution.dm index fe4d100e450f8..976c3272324f3 100644 --- a/modular_RUtgmc/code/modules/mob/living/carbon/xenomorph/evolution.dm +++ b/modular_RUtgmc/code/modules/mob/living/carbon/xenomorph/evolution.dm @@ -44,6 +44,12 @@ new_xeno.nicknumber = nicknumber new_xeno.hivenumber = hivenumber new_xeno.transfer_to_hive(hivenumber) + new_xeno.life_kills_total = life_kills_total + if(new_xeno.hunter_data) + new_xeno.hunter_data.clean_data() + qdel(new_xeno.hunter_data) + new_xeno.hunter_data = hunter_data + hunter_data = null transfer_observers_to(new_xeno) if(new_xeno.health - getBruteLoss(src) - getFireLoss(src) > 0) //Cmon, don't kill the new one! Shouldnt be possible though diff --git a/modular_RUtgmc/code/modules/mob/living/carbon/xenomorph/hive_datum.dm b/modular_RUtgmc/code/modules/mob/living/carbon/xenomorph/hive_datum.dm index 18d8af45b0fc6..76d6b9ababaf6 100644 --- a/modular_RUtgmc/code/modules/mob/living/carbon/xenomorph/hive_datum.dm +++ b/modular_RUtgmc/code/modules/mob/living/carbon/xenomorph/hive_datum.dm @@ -6,6 +6,10 @@ var/list/hive_forbiden_castes = list() var/forbid_count = 0 +///list of thick resin nests + var/max_thick_nests = 0 + var/list/obj/structure/xeno/thick_nest/thick_nests = list() + // *************************************** // *********** Init // *************************************** @@ -46,7 +50,7 @@ if(GLOB.key_to_time_of_death[user.key] + TIME_BEFORE_TAKING_BODY > world.time && !user.started_as_observer) to_chat(user, span_warning("You died too recently to be able to take a new facehugger.")) return FALSE - + if(tgui_alert(user, "Are you sure you want to be a Facehugger?", "Become part of the Horde!", list("Yes", "No")) != "Yes") return FALSE @@ -309,6 +313,23 @@ SSticker.mode.update_silo_death_timer(src) return ..() +/datum/hive_status/forsaken + name = "Forsaken Hive" + hivenumber = XENO_HIVE_FORSAKEN + prefix = "Forsaken " + color = "#cc8ec4" + +/datum/hive_status/forsaken/can_xeno_message() + return TRUE // can always talk in hivemind + +/datum/hive_status/yautja + name = "Yautja" + hivenumber = XENO_HIVE_YAUTJA + prefix = "Yautja " + +/datum/hive_status/yautja/can_xeno_message() + return FALSE + /datum/hive_status/proc/update_tier_limits() var/zeros = get_total_tier_zeros() var/ones = length(xenos_by_tier[XENO_TIER_ONE]) diff --git a/modular_RUtgmc/code/modules/mob/living/carbon/xenomorph/hive_upgrades.dm b/modular_RUtgmc/code/modules/mob/living/carbon/xenomorph/hive_upgrades.dm index ff1fec2b77caa..06940863a6aa9 100644 --- a/modular_RUtgmc/code/modules/mob/living/carbon/xenomorph/hive_upgrades.dm +++ b/modular_RUtgmc/code/modules/mob/living/carbon/xenomorph/hive_upgrades.dm @@ -60,6 +60,22 @@ return ..() +/datum/hive_upgrade/building/nest + name = "Thick nest" + desc = "A very thick nest, oozing with a thick sticky substance." + psypoint_cost = 0 + icon = "nest" + building_type = /obj/structure/xeno/thick_nest + building_loc = 0 //This results in spawning the structure under the user. + building_time = 5 SECONDS + +/datum/hive_upgrade/building/nest/can_buy(mob/living/carbon/xenomorph/buyer, silent = TRUE) + . = ..() + if(length(buyer.hive.thick_nests) >= buyer.hive.max_thick_nests) + to_chat(buyer, span_xenowarning("You cannot build any more thick nests!")) + return FALSE + return . + /datum/hive_upgrade/building/silo psypoint_cost = 800 diff --git a/modular_RUtgmc/code/modules/mob/living/carbon/xenomorph/life.dm b/modular_RUtgmc/code/modules/mob/living/carbon/xenomorph/life.dm index fdba7a088ec8f..5167683cb51ca 100644 --- a/modular_RUtgmc/code/modules/mob/living/carbon/xenomorph/life.dm +++ b/modular_RUtgmc/code/modules/mob/living/carbon/xenomorph/life.dm @@ -78,3 +78,10 @@ /mob/living/carbon/xenomorph/updatehealth() . = ..() handle_regular_health_hud_updates() + +/mob/living/carbon/xenomorph/proc/handle_interference() + if(interference) + interference = max(interference-2, 0) + SEND_SIGNAL(src, COMSIG_XENOMORPH_INTERFERENCE) + + return interference diff --git a/modular_RUtgmc/code/modules/mob/living/carbon/xenomorph/update_icons.dm b/modular_RUtgmc/code/modules/mob/living/carbon/xenomorph/update_icons.dm new file mode 100644 index 0000000000000..fd1da95dc950c --- /dev/null +++ b/modular_RUtgmc/code/modules/mob/living/carbon/xenomorph/update_icons.dm @@ -0,0 +1,6 @@ +/mob/living/carbon/xenomorph/proc/create_shriekwave(color) + var/image/shriekwave = image("icon"='icons/Xeno/64x64_Xeno_overlays.dmi', "icon_state" = "shriek_waves") //Ehh, suit layer's not being used. + if(color) + shriekwave.color = color + overlays_standing[X_SUIT_LAYER] = shriekwave + apply_temp_overlay(X_SUIT_LAYER, 3 SECONDS) diff --git a/modular_RUtgmc/code/modules/mob/living/carbon/xenomorph/xeno_defines.dm b/modular_RUtgmc/code/modules/mob/living/carbon/xenomorph/xeno_defines.dm index 12b2119688dbb..73f23f75ed3cd 100644 --- a/modular_RUtgmc/code/modules/mob/living/carbon/xenomorph/xeno_defines.dm +++ b/modular_RUtgmc/code/modules/mob/living/carbon/xenomorph/xeno_defines.dm @@ -1,5 +1,6 @@ /mob/living/carbon/xenomorph - hud_possible = list(HEALTH_HUD_XENO, PLASMA_HUD, PHEROMONE_HUD, XENO_RANK_HUD, XENO_PRIMO_HUD, QUEEN_OVERWATCH_HUD, ARMOR_SUNDER_HUD, XENO_DEBUFF_HUD, XENO_FIRE_HUD, XENO_BANISHED_HUD, XENO_BLESSING_HUD, XENO_EVASION_HUD) + hud_possible = list(HEALTH_HUD_XENO, PLASMA_HUD, PHEROMONE_HUD, XENO_RANK_HUD, QUEEN_OVERWATCH_HUD, ARMOR_SUNDER_HUD, XENO_DEBUFF_HUD, XENO_FIRE_HUD, XENO_BANISHED_HUD, XENO_BLESSING_HUD, XENO_EVASION_HUD, XENO_PRIMO_HUD, HUNTER_HUD) + var/interference = 0 // Stagger for predator weapons. Prevents hivemind usage, queen overwatching, etc. var/talk_sound = "alien_talk" // sound when talking /mob/living/carbon/xenomorph/send_speech(message_raw, message_range = 7, obj/source = src, bubble_type = bubble_icon, list/spans, datum/language/message_language=null, message_mode, tts_message, list/tts_filter) diff --git a/modular_RUtgmc/code/modules/mob/mob.dm b/modular_RUtgmc/code/modules/mob/mob.dm new file mode 100644 index 0000000000000..bdeff526c8b13 --- /dev/null +++ b/modular_RUtgmc/code/modules/mob/mob.dm @@ -0,0 +1,30 @@ +/mob + ///Slowdown from readying shields + var/shield_slowdown = 0 + ///Color matrices to be applied to the client window. Assoc. list. + var/list/client_color_matrices + +// Shows three different messages depending on who does it to who and how does it look like to outsiders +// message_mob: "You do something to X!" +// message_affected: "Y does something to you!" +// message_viewer: "X does something to Y!" +/mob/proc/affected_message(mob/affected, message_mob, message_affected, message_viewer) + src.show_message(message_mob, EMOTE_VISIBLE) + if(src != affected) + affected.show_message(message_affected, EMOTE_VISIBLE) + for(var/mob/V in viewers(7, src)) + if(V != src && V != affected) + V.show_message(message_viewer, EMOTE_VISIBLE) + +/obj/effect/temp_visual/block //color is white by default, set to whatever is needed + name = "blocking glow" + icon_state = "block" + icon = 'modular_RUtgmc/icons/effects/effects.dmi' + duration = 6.7 + +/obj/effect/temp_visual/block/Initialize(mapload, set_color) + if(set_color) + add_atom_colour(set_color, FIXED_COLOUR_PRIORITY) + . = ..() + pixel_x = rand(-12, 12) + pixel_y = rand(-9, 0) diff --git a/modular_RUtgmc/code/modules/mob/mob_transformation_simple.dm b/modular_RUtgmc/code/modules/mob/mob_transformation_simple.dm new file mode 100644 index 0000000000000..996c1eeb9edd8 --- /dev/null +++ b/modular_RUtgmc/code/modules/mob/mob_transformation_simple.dm @@ -0,0 +1,29 @@ +/mob/living/carbon/human/species/yautja/on_transformation(subspecies) + var/final_name = "Le'pro" + ethnicity = "Tan" + gender = MALE + age = 100 + flavor_text = "" + + if(client) + h_style = client.prefs.predator_h_style + ethnicity = client.prefs.predator_skin_color + gender = client.prefs.predator_gender + age = client.prefs.predator_age + final_name = client.prefs.predator_name + flavor_text = client.prefs.predator_flavor_text + r_eyes = client.prefs.pred_r_eyes + g_eyes = client.prefs.pred_g_eyes + b_eyes = client.prefs.pred_b_eyes + if(!final_name || final_name == "Undefined") //In case they don't have a name set or no prefs, there's a name. + final_name = "Le'pro" + + update_body() + update_hair() + regenerate_icons() + + real_name = final_name + name = final_name + + if(mind) + mind.name = real_name diff --git a/modular_RUtgmc/code/modules/mob/new_player/preferences_setup.dm b/modular_RUtgmc/code/modules/mob/new_player/preferences_setup.dm new file mode 100644 index 0000000000000..595bfb005b0b3 --- /dev/null +++ b/modular_RUtgmc/code/modules/mob/new_player/preferences_setup.dm @@ -0,0 +1,30 @@ +/datum/preferences/update_preview_icon(job_override, dummy_type = DUMMY_HUMAN_SLOT_PREFERENCES) + // Determine what job is marked as 'High' priority, and dress them up as such. + var/datum/job/previewJob + var/highest_pref = JOBS_PRIORITY_NEVER + for(var/job in job_preferences) + if(job_preferences[job] > highest_pref) + previewJob = SSjob.GetJob(job) + highest_pref = job_preferences[job] + if(job_override) + previewJob = job_override + + if(!previewJob) + var/mob/living/carbon/human/dummy/mannequin = generate_or_wait_for_human_dummy(dummy_type) + copy_to(mannequin) + parent.show_character_previews(new /mutable_appearance(mannequin)) + unset_busy_human_dummy(dummy_type) + return + + if(previewJob.handle_special_preview(parent)) + return + + // Set up the dummy for its photoshoot + var/mob/living/carbon/human/dummy/mannequin = generate_or_wait_for_human_dummy(dummy_type) + copy_to(mannequin) + + if(previewJob) + mannequin.job = previewJob + previewJob.equip_dummy(mannequin, preference_source = parent) + parent.show_character_previews(new /mutable_appearance(mannequin)) + unset_busy_human_dummy(dummy_type) diff --git a/modular_RUtgmc/code/modules/mob/new_player/yautja_hair.dm b/modular_RUtgmc/code/modules/mob/new_player/yautja_hair.dm new file mode 100644 index 0000000000000..6c4ba1a2be94d --- /dev/null +++ b/modular_RUtgmc/code/modules/mob/new_player/yautja_hair.dm @@ -0,0 +1,40 @@ +/datum/sprite_accessory/yautja_hair + icon = 'modular_RUtgmc/icons/mob/hunter/yaut_hair.dmi' + species_allowed = list("Yautja") + do_colouration = FALSE + +/datum/sprite_accessory/yautja_hair/standard + name = "Standard" + icon_state = "standard" + +/datum/sprite_accessory/yautja_hair/short_thick + name = "Short Thick" + icon_state = "short_thick" + +/datum/sprite_accessory/yautja_hair/straight_thin + name = "Straight Thin" + icon_state = "straight_thin" + +/datum/sprite_accessory/yautja_hair/long_tied + name = "Long Tied" + icon_state = "long_tied" + +/datum/sprite_accessory/yautja_hair/short_thin + name = "Short Thin" + icon_state = "short_thin" + +/datum/sprite_accessory/yautja_hair/long_curved + name = "Long Curved" + icon_state = "long_curved" + +/datum/sprite_accessory/yautja_hair/long_straight + name = "Long Straight" + icon_state = "long_straight" + +/datum/sprite_accessory/yautja_hair/long_wide + name = "Long Wide" + icon_state = "long_wide" + +/datum/sprite_accessory/yautja_hair/short_wide + name = "Short Wide" + icon_state = "short_wide" diff --git a/modular_RUtgmc/code/modules/organs/limb_objects.dm b/modular_RUtgmc/code/modules/organs/limb_objects.dm index 6df9d833abec7..2aabf29ea9173 100644 --- a/modular_RUtgmc/code/modules/organs/limb_objects.dm +++ b/modular_RUtgmc/code/modules/organs/limb_objects.dm @@ -1,2 +1,33 @@ /obj/item/limb icon = 'modular_RUtgmc/icons/mob/human_races/r_human.dmi' +///Predators can flay limbs to eventually turn them into bones for their armor + var/flayed = FALSE + ///What bone would be in this limb? + var/bone_type + +/obj/item/limb/l_arm + bone_type = /obj/item/armor_module/limb/skeleton/l_arm + +/obj/item/limb/l_foot + bone_type = /obj/item/armor_module/limb/skeleton/l_foot + +/obj/item/limb/l_hand + bone_type = /obj/item/armor_module/limb/skeleton/l_hand + +/obj/item/limb/l_leg + bone_type = /obj/item/armor_module/limb/skeleton/l_leg + +/obj/item/limb/r_arm + bone_type = /obj/item/armor_module/limb/skeleton/r_arm + +/obj/item/limb/r_foot + bone_type = /obj/item/armor_module/limb/skeleton/r_foot + +/obj/item/limb/r_hand + bone_type = /obj/item/armor_module/limb/skeleton/r_hand + +/obj/item/limb/r_leg + bone_type = /obj/item/armor_module/limb/skeleton/r_leg + +/obj/item/limb/head + bone_type = /obj/item/armor_module/limb/skeleton/head diff --git a/modular_RUtgmc/code/modules/projectiles/ammo_datums.dm b/modular_RUtgmc/code/modules/projectiles/ammo_datums.dm index edb80578cf772..9d38b4e6169b7 100644 --- a/modular_RUtgmc/code/modules/projectiles/ammo_datums.dm +++ b/modular_RUtgmc/code/modules/projectiles/ammo_datums.dm @@ -293,6 +293,195 @@ /datum/ammo/xeno/spine //puppeteer damage = 45 +/* +//================================================ + Yautja +//================================================ +*/ +/datum/ammo/energy/yautja + accurate_range = 12 + shell_speed = 2 + bullet_color = COLOR_STRONG_VIOLET + damage_type = BURN + flags_ammo_behavior = AMMO_IGNORE_RESIST + + hud_state = "plasma" + hud_state_empty = "electrothermal_empty" + +/datum/ammo/energy/yautja/alloy_spike + name = "alloy spike" + ping = "ping_s" + icon_state = "MSpearFlight" + hud_state = "alloy_spike" + sound_hit = "alloy_hit" + sound_armor = "alloy_armor" + sound_bounce = "alloy_bounce" + bullet_color = COLOR_MAGENTA + armor_type = BULLET + accuracy = 20 + accurate_range = 15 + max_range = 15 + damage = 40 + penetration = 50 + shrapnel_chance = 75 + +/datum/ammo/energy/yautja/pistol + name = "plasma pistol bolt" + icon_state = "ion" + + hud_state = "plasma_pistol" + + bullet_color = COLOR_MAGENTA + damage = 40 + shell_speed = 1.5 + +/datum/ammo/energy/yautja/caster + name = "root caster bolt" + icon_state = "ion" + +/datum/ammo/energy/yautja/caster/stun + name = "low power stun bolt" + var/stun_time = 5 SECONDS + hud_state = "plasma_pistol" + + bullet_color = COLOR_VIOLET + damage = 0 + flags_ammo_behavior = AMMO_ENERGY|AMMO_IGNORE_RESIST + +/datum/ammo/energy/yautja/caster/stun/on_hit_mob(mob/M, obj/projectile/P) + var/mob/living/carbon/C = M + 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 + H.apply_effect(stun_time + 10 SECONDS, WEAKEN) + else + C.apply_effect(stun_time, WEAKEN) + + C.apply_effect(stun_time, STUN) + ..() + +/datum/ammo/energy/yautja/caster/bolt + name = "plasma bolt" + icon_state = "pulse1" + flags_ammo_behavior = AMMO_IGNORE_RESIST + bullet_color = COLOR_BRIGHT_BLUE + shell_speed = 3 + damage = 35 + +/datum/ammo/energy/yautja/caster/bolt/stun + name = "high power stun bolt" + icon_state = "pred_stun" + var/stun_time = 20 SECONDS + bullet_color = COLOR_MAGENTA + + hud_state = "plasma_rifle" + + 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 + 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 + H.apply_effect(stun_time + 10 SECONDS, WEAKEN) + else + C.apply_effect(stun_time, WEAKEN) + + C.apply_effect(stun_time, STUN) + ..() + +/datum/ammo/energy/yautja/caster/sphere + name = "plasma eradicator" + icon_state = "bluespace" + bullet_color = COLOR_BRIGHT_BLUE + flags_ammo_behavior = AMMO_EXPLOSIVE + shell_speed = 2 + accuracy = 40 + + hud_state = "plasma_sphere" + + damage = 55 + + accurate_range = 8 + max_range = 8 + +/datum/ammo/energy/yautja/caster/sphere/on_hit_mob(mob/M, obj/projectile/P) + cell_explosion(get_turf(M), 50, 25) + +/datum/ammo/energy/yautja/caster/sphere/on_hit_turf(turf/T, obj/projectile/P) + cell_explosion(get_turf(T), 50, 25) + +/datum/ammo/energy/yautja/caster/sphere/on_hit_obj(obj/O, obj/projectile/P) + cell_explosion(get_turf(O), 50, 25) + +/datum/ammo/energy/yautja/caster/sphere/do_at_max_range(obj/projectile/P) + cell_explosion(get_turf(P), 50, 25) + + +/datum/ammo/energy/yautja/caster/sphere/stun + name = "plasma immobilizer" + bullet_color = COLOR_MAGENTA + damage = 0 + flags_ammo_behavior = AMMO_ENERGY|AMMO_IGNORE_RESIST + hud_state = "plasma_rifle_blast" + accurate_range = 20 + max_range = 20 + + var/stun_range = 4 + var/stun_time = 6 SECONDS + +/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(stun_range, get_turf(P))) + var/f_stun_time = 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)) + f_stun_time -= 2 SECONDS + if(ispredalien(M)) + continue + to_chat(M, span_danger("A powerful electric shock ripples through your body, freezing you in place!")) + M.apply_effect(f_stun_time, STUN) + + if(ishuman(M)) + var/mob/living/carbon/human/H = M + H.apply_effect(f_stun_time, WEAKEN) + else + M.apply_effect(f_stun_time, WEAKEN) + +/datum/ammo/energy/yautja/rifle/bolt + name = "plasma rifle bolt" + icon_state = "ion" + damage_type = BURN + flags_ammo_behavior = AMMO_IGNORE_RESIST + + hud_state = "plasma_rifle" + + damage = 70 + penetration = 55 + ////////////////////////////////////////////////// ////////////////////Shrapnel////////////////////// ////////////////////////////////////////////////// diff --git a/modular_RUtgmc/code/modules/projectiles/gun_helpers.dm b/modular_RUtgmc/code/modules/projectiles/gun_helpers.dm new file mode 100644 index 0000000000000..3342b7da941b9 --- /dev/null +++ b/modular_RUtgmc/code/modules/projectiles/gun_helpers.dm @@ -0,0 +1,6 @@ +/obj/item/weapon/gun/proc/update_special_overlay(new_icon_state) + overlays -= attachment_overlays["special"] + attachment_overlays["special"] = null + var/image/gun_image = image(icon, src, new_icon_state) + attachment_overlays["special"] = gun_image + overlays += gun_image diff --git a/modular_RUtgmc/code/modules/reagents/machinery/chem_dispenser.dm b/modular_RUtgmc/code/modules/reagents/machinery/chem_dispenser.dm index ca54999a7790b..d6f73f09e73cb 100644 --- a/modular_RUtgmc/code/modules/reagents/machinery/chem_dispenser.dm +++ b/modular_RUtgmc/code/modules/reagents/machinery/chem_dispenser.dm @@ -4,5 +4,17 @@ ui = new(user, src, "ChemDispenser", name) ui.open() +/obj/machinery/chem_dispenser/beer/pred + icon = 'modular_RUtgmc/icons/obj/machines/yautja_machines.dmi' + icon_state = "booze_dispenser" + +/obj/machinery/chem_dispenser/pred + icon = 'modular_RUtgmc/icons/obj/machines/yautja_machines.dmi' + icon_state = "dispenser" + +/obj/machinery/chem_dispenser/soda/pred + icon = 'modular_RUtgmc/icons/obj/machines/yautja_machines.dmi' + icon_state = "soda_dispenser" + /obj/machinery/chem_dispenser/ex_act(severity) take_damage(severity, BRUTE, BOMB) diff --git a/modular_RUtgmc/code/modules/reagents/machinery/reagentgrinder.dm b/modular_RUtgmc/code/modules/reagents/machinery/reagentgrinder.dm new file mode 100644 index 0000000000000..6c8c43ea4f1cb --- /dev/null +++ b/modular_RUtgmc/code/modules/reagents/machinery/reagentgrinder.dm @@ -0,0 +1,3 @@ +/obj/machinery/reagentgrinder/yautja + icon = 'modular_RUtgmc/icons/obj/machines/yautja_machines.dmi' + icon_state = "grinder" diff --git a/modular_RUtgmc/code/modules/requisitions/supply_export.dm b/modular_RUtgmc/code/modules/requisitions/supply_export.dm index 2e4e5323143e4..351a4868afe77 100644 --- a/modular_RUtgmc/code/modules/requisitions/supply_export.dm +++ b/modular_RUtgmc/code/modules/requisitions/supply_export.dm @@ -10,6 +10,9 @@ . = 100 return +/mob/living/carbon/human/species/yautja/get_export_value() + return 3000 + /proc/can_sell_human_body(mob/living/carbon/human/human_to_sell, seller_faction) var/to_sell_alignement = GLOB.faction_to_alignement[human_to_sell.faction] switch(to_sell_alignement) diff --git a/modular_RUtgmc/code/modules/shuttle/marine_dropship.dm b/modular_RUtgmc/code/modules/shuttle/marine_dropship.dm index 70ea9463406fc..8cb6452045aec 100644 --- a/modular_RUtgmc/code/modules/shuttle/marine_dropship.dm +++ b/modular_RUtgmc/code/modules/shuttle/marine_dropship.dm @@ -104,16 +104,8 @@ if(D.mode != SHUTTLE_IDLE && D.mode != SHUTTLE_RECHARGING) to_chat(user, span_warning("The bird's mind is currently active. We need to wait until it's more vulnerable...")) return FALSE - var/humans_on_ground = 0 - for(var/i in SSmapping.levels_by_trait(ZTRAIT_GROUND)) - for(var/m in GLOB.humans_by_zlevel["[i]"]) - var/mob/living/carbon/human/H = m - if(isnestedhost(H)) - continue - if(H.faction == FACTION_XENO) - continue - humans_on_ground++ - if(length(GLOB.alive_human_list) && ((humans_on_ground / length(GLOB.alive_human_list)) > ALIVE_HUMANS_FOR_CALLDOWN)) + var/list/living_player_list = count_humans_and_xenos(SSmapping.levels_by_any_trait(list(ZTRAIT_GROUND)), COUNT_IGNORE_ALIVE_SSD) + if(length_char(GLOB.alive_human_list) && ((living_player_list[1] / length_char(GLOB.alive_human_list)) > ALIVE_HUMANS_FOR_CALLDOWN)) to_chat(user, span_warning("There's too many tallhosts still on the ground. They interfere with our psychic field. We must dispatch them before we are able to do this.")) return FALSE return TRUE @@ -183,14 +175,10 @@ do_hijack(M, CT, X) if(href_list["abduct"]) - var/groundside_humans - for(var/N in GLOB.alive_human_list) - var/mob/H = N - if(H.z != X.z) - continue - groundside_humans++ - - if(groundside_humans > 5) +//RUTGMC EDIT ADDITION BEGIN - Preds + var/list/living_player_list = SSticker.mode.count_humans_and_xenos(SSmapping.levels_by_any_trait(list(ZTRAIT_GROUND)), COUNT_IGNORE_ALIVE_SSD) + if(living_player_list[1] > 5) +//RUTGMC EDIT ADDITION END to_chat(X, span_xenowarning("There is still prey left to hunt!")) return diff --git a/modular_RUtgmc/code/modules/surgery/mcomp_tendwounds.dm b/modular_RUtgmc/code/modules/surgery/mcomp_tendwounds.dm new file mode 100644 index 0000000000000..55fd834ab534d --- /dev/null +++ b/modular_RUtgmc/code/modules/surgery/mcomp_tendwounds.dm @@ -0,0 +1,169 @@ +/datum/surgery_step/mcomp_wounds + var/required_trait = TRAIT_YAUTJA_TECH// Only predators can do this + var/depth_op = 0 + +/datum/surgery_step/mcomp_wounds/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool, datum/limb/affected, checks_only) + if(target_zone != "chest") + return SURGERY_CANNOT_USE + if(HAS_TRAIT(user, required_trait) && (target.getBruteLoss() || target.getFireLoss() || depth_op) && affected.surgery_open_stage == depth_op) //Heals brute or burn + return SURGERY_CAN_USE + return SURGERY_CANNOT_USE + +//------------------------------------ + +/datum/surgery_step/mcomp_wounds/mstabilize_wounds + allowed_tools = list( + /obj/item/tool/surgery/stabilizer_gel = 100, + /obj/item/tool/surgery/bonegel = 60, + /obj/item/stack/cable_coil = 40, + ) + min_duration = 1 SECONDS + max_duration = 5 SECONDS + + blood_level = 1 + depth_op = 0 + +/datum/surgery_step/mcomp_wounds/mstabilize_wounds/begin_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool, datum/limb/affected) + if(user == target) + user.visible_message(span_notice("[user] begins to stabilize wounds on their body with [tool]."), + span_notice("You begin to stabilize your wounds with [tool].")) + else + user.affected_message(target, + span_notice("You begin to stabilize the wounds on [target]'s body with [tool]."), + span_notice("[user] begins to stabilize the wounds on your body with [tool]."), + span_notice("[user] begins to stabilize the wounds on [target]'s body with [tool].")) + +/datum/surgery_step/mcomp_wounds/mstabilize_wounds/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool, datum/limb/affected) + target.heal_overall_damage(40,40) + playsound(target, 'modular_RUtgmc/sound/misc/cautery.ogg', 25) + + if(isyautja(target)) + target.emote("click2") + else + target.emote("pain") + + affected.surgery_open_stage = 0.25 + if(user == target) + user.visible_message(span_notice("[user] finishes stabilizing the wounds on their body with [tool]."), + span_notice("You finish stabilizing your wounds with [tool].")) + else + user.affected_message(target, + span_notice("You finish stabilizing [target]'s wounds with [tool]."), + span_notice("[user] finished stabilizing your wounds with [tool]."), + span_notice("[user] finished treating [target]'s wounds with [tool].")) + +/datum/surgery_step/mcomp_wounds/mstabilize_wounds/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool, datum/limb/affected) + return FALSE + +/datum/surgery_step/mcomp_wounds/mtend_wounds + allowed_tools = list( + /obj/item/tool/surgery/healing_gun = 100, + ) + min_duration = 12 SECONDS + max_duration = 15 SECONDS + + blood_level = 1 + depth_op = 0.25 + +/datum/surgery_step/mcomp_wounds/mtend_wounds/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool, datum/limb/affected, checks_only) + . = ..() + + if(!.) + return FALSE + + var/obj/item/tool/surgery/healing_gun/gun = tool + if(!gun.loaded) + to_chat(user, span_warning("You can't heal yourself without a capsule in the gun!")) + return FALSE + return TRUE + +/datum/surgery_step/mcomp_wounds/mtend_wounds/begin_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool, datum/limb/affected) + playsound(target, 'modular_RUtgmc/sound/misc/heal_gun.ogg', 25) + flick("healing_gun_on", tool) + + if(user == target) + user.visible_message(span_notice("[user] begins to treat the stabilized wounds on their body with [tool]."), + span_notice("You begin to treat your stabilized wounds with [tool].")) + else + user.affected_message(target, + span_notice("You begin to treat the stabilized wounds on [target]'s body with [tool]."), + span_notice("[user] begins to treat the stabilized wounds on your body with [tool]."), + span_notice("[user] begins to treat the stabilized wounds on [target]'s body with [tool].")) + + target.custom_pain("It feels like your body is being stabbed with needles - because it is!") + +/datum/surgery_step/mcomp_wounds/mtend_wounds/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool, datum/limb/affected) + target.heal_overall_damage(65,65) + + for(var/datum/internal_organ/organ in target.internal_organs) //Fixes all organs + organ.heal_organ_damage(100) + + affected.surgery_open_stage = 0.75 + if(isyautja(target)) + target.emote("click") + else + target.emote("pain") + + if(user == target) + user.visible_message(span_notice("[user] finishes treating the stabilized wounds on their body with [tool]."), + span_notice("You finish treating the stabilized wounds on your body with [tool].")) + else + user.affected_message(target, + span_notice("You finish treating [target]'s stabilized wounds with [tool]."), + span_notice("[user] finished treating your stabilized wounds with [tool]."), + span_notice("[user] finished treating [target]'s stabilized wounds with [tool].")) + + if(!istype(tool, /obj/item/tool/surgery/healing_gun)) + return + var/obj/item/tool/surgery/healing_gun/gun = tool + gun.loaded = FALSE + gun.update_icon() + +/datum/surgery_step/mcomp_wounds/mtend_wounds/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool, datum/limb/affected) + return FALSE + +/datum/surgery_step/mcomp_wounds/mclamp_wound + allowed_tools = list( + /obj/item/tool/surgery/wound_clamp = 100, + /obj/item/tool/surgery/cautery = 60, + ) + min_duration = 4 SECONDS + max_duration = 10 SECONDS + + depth_op = 0.75 + +/datum/surgery_step/mcomp_wounds/mclamp_wound/begin_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool, datum/limb/affected) + playsound(target, 'modular_RUtgmc/sound/misc/cautery2.ogg', 25) + flick("wound_clamp_on", tool) + + if(user == target) + user.visible_message(span_notice("[user] begins to close the treated wounds on their body with [tool]."), + span_notice("You begin to close your treated wounds with [tool].")) + else + user.affected_message(target, + span_notice("You begin to close the treated wounds on [target]'s body with [tool]."), + span_notice("[user] begins to clamp the treated wounds on your body with [tool]."), + span_notice("[user] begns to clamp the treated wounds on [target]'s body with [tool].")) + +/datum/surgery_step/mcomp_wounds/mclamp_wound/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool, datum/limb/affected) + target.heal_overall_damage(65,65) //makes sure that all damage is healed + playsound(target, 'modular_RUtgmc/sound/misc/cautery.ogg', 25) + + if(user == target) + user.visible_message(span_notice("[user] finshes closing the treated wounds on their body with [tool]."), + span_notice("You finish closing the treated wounds on your body with [tool]")) + else + user.affected_message(target, + span_notice("You finish closing [target]'s treated wounds with [tool]."), + span_notice("[user] finished closing your treated wounds with [tool]."), + span_notice("[user] finished closing [target]'s treated wounds with [tool].")) + + if(isyautja(target)) + target.emote("loudroar") + else + target.emote("pain") + + affected.surgery_open_stage = 0 + +/datum/surgery_step/mcomp_wounds/mclamp_wound/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool, datum/limb/affected) + return FALSE diff --git a/modular_RUtgmc/code/modules/surgery/surgery_tools.dm b/modular_RUtgmc/code/modules/surgery/surgery_tools.dm new file mode 100644 index 0000000000000..1185892a0d534 --- /dev/null +++ b/modular_RUtgmc/code/modules/surgery/surgery_tools.dm @@ -0,0 +1,114 @@ +/obj/item/tool/surgery/retractor/predatorretractor + name = "opener" + icon = 'modular_RUtgmc/icons/obj/items/surgery_tools.dmi' + icon_state = "predator_retractor" + +/obj/item/tool/surgery/hemostat/predatorhemostat + name = "pincher" + icon = 'modular_RUtgmc/icons/obj/items/surgery_tools.dmi' + icon_state = "predator_hemostat" + +/obj/item/tool/surgery/cautery/predatorcautery + name = "cauterizer" + icon = 'modular_RUtgmc/icons/obj/items/surgery_tools.dmi' + icon_state = "predator_cautery" + flags_item = ITEM_PREDATOR + +/obj/item/tool/surgery/surgicaldrill/predatorsurgicaldrill + name = "bone drill" + icon = 'modular_RUtgmc/icons/obj/items/surgery_tools.dmi' + icon_state = "predator_drill" + +/obj/item/tool/surgery/scalpel/predatorscalpel + name = "cutter" + icon_state = "predator_scalpel" + force = 20 + +/obj/item/tool/surgery/circular_saw/predatorbonesaw + name = "bone saw" + icon = 'modular_RUtgmc/icons/obj/items/surgery_tools.dmi' + icon_state = "predator_bonesaw" + flags_item = ITEM_PREDATOR + force = 20 + +/obj/item/tool/surgery/bonegel/predatorbonegel + name = "gel gun" + icon = 'modular_RUtgmc/icons/obj/items/surgery_tools.dmi' + icon_state = "predator_bone-gel" + +/obj/item/tool/surgery/FixOVein/predatorFixOVein + name = "vein fixer" + icon = 'modular_RUtgmc/icons/obj/items/surgery_tools.dmi' + icon_state = "predator_fixovein" + +/obj/item/tool/surgery/bonesetter/predatorbonesetter + name = "bone placer" + icon = 'modular_RUtgmc/icons/obj/items/surgery_tools.dmi' + icon_state = "predator_bonesetter" + +/* + * MEDICOMP TOOLS + */ + +/obj/item/tool/surgery/stabilizer_gel + name = "stabilizer gel vial" + desc = "Used for stabilizing wounds for treatment." + icon = 'modular_RUtgmc/icons/obj/items/surgery_tools.dmi' + icon_state = "stabilizer_gel" + force = 0 + throwforce = 1 + w_class = WEIGHT_CLASS_SMALL + flags_item = ITEM_PREDATOR + +/obj/item/tool/surgery/healing_gun + name = "healing gun" + desc = "Used for mending stabilized wounds." + icon = 'modular_RUtgmc/icons/obj/items/surgery_tools.dmi' + icon_state = "healing_gun" + force = 0 + throwforce = 1 + w_class = WEIGHT_CLASS_SMALL + flags_item = ITEM_PREDATOR + var/loaded = TRUE + +/obj/item/tool/surgery/healing_gun/update_icon() + if(loaded) + icon_state = "healing_gun" + else + icon_state = "healing_gun_empty" + +/obj/item/tool/surgery/healing_gun/attackby(obj/item/O, mob/user) + if(!HAS_TRAIT(user, TRAIT_YAUTJA_TECH)) + to_chat(user, span_warning("You have no idea how to put \the [O] into \the [src]!")) + return + if(istype(O, /obj/item/tool/surgery/healing_gel)) + if(loaded) + to_chat(user, span_warning("There's already a capsule inside the healing gun!")) + return + user.visible_message(span_warning("[user] loads \the [src] with \a [O]."), span_warning("You load \the [src] with \a [O].")) + playsound(loc, 'modular_RUtgmc/sound/items/air_release.ogg',25) + loaded = TRUE + update_icon() + qdel(O) + return + return ..() + +/obj/item/tool/surgery/healing_gel + name = "healing gel capsule" + desc = "Used for reloading the healing gun." + icon = 'modular_RUtgmc/icons/obj/items/surgery_tools.dmi' + icon_state = "healing_gel" + force = 0 + throwforce = 1 + w_class = WEIGHT_CLASS_SMALL + flags_item = ITEM_PREDATOR + +/obj/item/tool/surgery/wound_clamp + name = "wound clamp" + desc = "Used for clamping wounds after treatment." + icon = 'modular_RUtgmc/icons/obj/items/surgery_tools.dmi' + icon_state = "wound_clamp" + force = 0 + throwforce = 1 + w_class = WEIGHT_CLASS_SMALL + flags_item = ITEM_PREDATOR diff --git a/modular_RUtgmc/code/modules/xenomorph/xeno_structures.dm b/modular_RUtgmc/code/modules/xenomorph/xeno_structures.dm index 105b838236309..c8f2a335af09d 100644 --- a/modular_RUtgmc/code/modules/xenomorph/xeno_structures.dm +++ b/modular_RUtgmc/code/modules/xenomorph/xeno_structures.dm @@ -101,6 +101,73 @@ . = ..() set_light(2, 2, LIGHT_COLOR_GREEN) +/obj/structure/xeno/thick_nest + name = "thick resin nest" + desc = "A very thick nest, oozing with a thick sticky substance." + pixel_x = -8 + pixel_y = -8 + max_integrity = 400 + mouse_opacity = MOUSE_OPACITY_ICON + + icon = 'modular_RUtgmc/icons/Xeno/nest.dmi' + icon_state = "reinforced_nest" + layer = 2.5 + + var/obj/structure/bed/nest/structure/pred_nest + +/obj/structure/xeno/thick_nest/examine(mob/user) + . = ..() + if((isxeno(user) || isobserver(user)) && hivenumber) + . += "Used to secure formidable hosts." + +/obj/structure/xeno/thick_nest/Initialize(mapload, new_hivenumber) + . = ..() + if(new_hivenumber) + hivenumber = new_hivenumber + + var/datum/hive_status/hive_ref = GLOB.hive_datums[hivenumber] + if(hive_ref) + hive_ref.thick_nests += src + + pred_nest = new /obj/structure/bed/nest/structure(loc, hive_ref, src) // Nest cannot be destroyed unless the structure itself is destroyed + + +/obj/structure/xeno/thick_nest/Destroy() + . = ..() + + if(hivenumber) + GLOB.hive_datums[hivenumber].thick_nests -= src + + pred_nest?.linked_structure = null + QDEL_NULL(pred_nest) + +/obj/structure/bed/nest + var/force_nest = FALSE + +/obj/structure/bed/nest/structure + name = "thick alien nest" + desc = "A very thick nest, oozing with a thick sticky substance." + force_nest = TRUE + var/obj/structure/xeno/thick_nest/linked_structure + +/obj/structure/bed/nest/structure/Initialize(mapload, hive, obj/structure/xeno/thick_nest/to_link) + . = ..() + if(to_link) + linked_structure = to_link + max_integrity = linked_structure.max_integrity + +/obj/structure/bed/nest/structure/Destroy() + . = ..() + if(linked_structure) + linked_structure.pred_nest = null + QDEL_NULL(linked_structure) + +/obj/structure/bed/nest/structure/attack_hand(mob/user) + if(!isxeno(user)) + to_chat(user, span_notice("The sticky resin is too strong for you to do anything to this nest")) + return FALSE + . = ..() + /obj/structure/xeno/acidwell/acid_well_fire_interaction() if(!charges) take_damage(50, BURN, FIRE) diff --git a/modular_RUtgmc/icons/Xeno/castes/predalien_praetorian.dmi b/modular_RUtgmc/icons/Xeno/castes/predalien_praetorian.dmi new file mode 100644 index 0000000000000000000000000000000000000000..3b646cfc9959ee529551fbef0668555f3bd96761 GIT binary patch literal 13488 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 o*vB|#XKZt<807*qoM6N<$g0&&On*aa+ literal 0 HcmV?d00001 diff --git a/modular_RUtgmc/icons/mob/screen/yautja.dmi b/modular_RUtgmc/icons/mob/screen/yautja.dmi new file mode 100644 index 0000000000000000000000000000000000000000..43007e633180bf14789bb7b202e6be65b608c607 GIT binary patch literal 2461 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 delta 1271 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 literal 0 HcmV?d00001 diff --git a/modular_RUtgmc/icons/turf/sandstone.dmi b/modular_RUtgmc/icons/turf/sandstone.dmi new file mode 100644 index 0000000000000000000000000000000000000000..86d0172c3105f1be54a0d94c94dd2a91ed5887ff GIT binary patch literal 18354 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 AzyJUM literal 0 HcmV?d00001 diff --git a/modular_RUtgmc/icons/turf/strata_floor.dmi b/modular_RUtgmc/icons/turf/strata_floor.dmi new file mode 100644 index 0000000000000000000000000000000000000000..91289c4a3a1b14c30ca03f072c670d7a439caa88 GIT binary patch literal 6132 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 literal 0 HcmV?d00001 diff --git a/modular_RUtgmc/includes.dm b/modular_RUtgmc/includes.dm index a960c7f6ad5dc..752779e235061 100644 --- a/modular_RUtgmc/includes.dm +++ b/modular_RUtgmc/includes.dm @@ -13,6 +13,8 @@ #include "code\controllers\configuration\entries\general.dm" #include "code\controllers\subsystem\cellauto.dm" #include "code\controllers\subsystem\job.dm" +#include "code\controllers\subsystem\predships.dm" +#include "code\controllers\subsystem\hunt_system.dm" #include "code\controllers\subsystem\minimaps.dm" #include "code\controllers\subsystem\points.dm" #include "code\controllers\subsystem\processing\resinshaping.dm" @@ -50,6 +52,7 @@ #include "code\datums\loadout\item_representation\_item_representation.dm" #include "code\datums\status_effects\debuffs.dm" #include "code\datums\status_effects\xeno_buffs.dm" +#include "code\datums\flaying.dm" #include "code\datums\looping_sounds\miscellaneous.dm" #include "code\game\atoms.dm" #include "code\game\atoms_movable.dm" @@ -92,7 +95,9 @@ #include "code\game\objects\items\reagent_containers\glass\bottle.dm" #include "code\game\objects\items\reagent_containers\hypospray.dm" #include "code\game\objects\items\robot\robot_parts.dm" -#include "code\game\objects\items\sheets\sheet_types.dm" +#include "code\game\objects\items\stacks\sheets\mineral.dm" +#include "code\game\objects\items\stacks\sheets\sheet_types.dm" +#include "code\game\objects\items\stacks\tiles\tile_types.dm" #include "code\game\objects\items\stacks\medical.dm" #include "code\game\objects\items\storage\pouch.dm" @@ -223,6 +228,7 @@ #include "code\modules\mob\living\carbon\human\human.dm" #include "code\modules\mob\living\carbon\human\species.dm" #include "code\modules\mob\living\carbon\human\zombie.dm" +#include "code\modules\mob\living\carbon\xenomorph\update_icons.dm" #include "code\modules\mob\living\carbon\xenomorph\abilities.dm" #include "code\modules\mob\living\carbon\xenomorph\attack_alien.dm" #include "code\modules\mob\living\carbon\xenomorph\charge_crush.dm" @@ -285,9 +291,10 @@ #include "code\modules\mob\living\carbon\xenomorph\castes\praetorian\abilities_praetorian.dm" #include "code\modules\mob\living\carbon\xenomorph\castes\praetorian\castedatum_praetorian.dm" #include "code\modules\mob\living\carbon\xenomorph\castes\praetorian\praetorian.dm" -// #include "code\modules\mob\living\carbon\xenomorph\castes\predalien\castedatum_predalien.dm" -// #include "code\modules\mob\living\carbon\xenomorph\castes\predalien\predalien.dm" -// #include "code\modules\mob\living\carbon\xenomorph\castes\predalien\abilities_predalien.dm" +#include "code\modules\mob\living\carbon\xenomorph\castes\hellhound\hellhound.dm" +#include "code\modules\mob\living\carbon\xenomorph\castes\predalien\castedatum_predalien.dm" +#include "code\modules\mob\living\carbon\xenomorph\castes\predalien\predalien.dm" +#include "code\modules\mob\living\carbon\xenomorph\castes\predalien\abilities_predalien.dm" #include "code\modules\mob\living\carbon\xenomorph\castes\queen\abilities_queen.dm" #include "code\modules\mob\living\carbon\xenomorph\castes\queen\castedatum_queen.dm" #include "code\modules\mob\living\carbon\xenomorph\castes\queen\queen.dm" @@ -317,6 +324,44 @@ #include "code\modules\power\terminal.dm" #include "code\modules\projectiles\ammo_datums.dm" #include "code\modules\projectiles\gun_attachables.dm" +#include "code\modules\clans\clan.dm" +#include "code\modules\clans\client.dm" +#include "code\modules\clans\rank.dm" +#include "code\modules\clans\ship.dm" +#include "code\modules\cm_preds\_yaut_defines.dm" +#include "code\modules\cm_preds\yautja_weapons\misc_weapons.dm" +#include "code\modules\cm_preds\yautja_weapons\one_handed.dm" +#include "code\modules\cm_preds\yautja_weapons\ranged.dm" +#include "code\modules\cm_preds\yautja_weapons\two_handed.dm" +#include "code\modules\cm_preds\falcon.dm" +#include "code\modules\cm_preds\huntdata.dm" +#include "code\modules\cm_preds\keybinds.dm" +#include "code\modules\cm_preds\landmakrs.dm" +#include "code\modules\cm_preds\predator_action.dm" +#include "code\modules\cm_preds\smartdisc.dm" +#include "code\modules\cm_preds\thrall_items.dm" +#include "code\modules\cm_preds\thrall_procs.dm" +#include "code\modules\cm_preds\yaut_bracers.dm" +#include "code\modules\cm_preds\yaut_chems.dm" +#include "code\modules\cm_preds\yaut_hudprocs.dm" +#include "code\modules\cm_preds\yaut_items.dm" +#include "code\modules\cm_preds\yaut_machines.dm" +#include "code\modules\cm_preds\yaut_mask.dm" +#include "code\modules\cm_preds\yaut_procs.dm" +#include "code\modules\cm_preds\yaut_shield.dm" +#include "code\modules\cm_preds\yautja_rope.dm" +#include "code\modules\clothing\glasses\meson.dm" +#include "code\modules\clothing\glasses\thermal.dm" +#include "code\modules\language\hellhound.dm" +#include "code\modules\mob\hologram.dm" +#include "code\modules\mob\mob.dm" +#include "code\modules\mob\mob_transformation_simple.dm" +#include "code\modules\mob\new_player\preferences_setup.dm" +#include "code\modules\mob\new_player\yautja_hair.dm" +#include "code\modules\projectiles\gun_helpers.dm" +#include "code\modules\surgery\mcomp_tendwounds.dm" +#include "code\modules\mob\living\carbon\human\emote-yautja.dm" +#include "code\modules\mob\living\carbon\human\yautja.dm" #include "code\modules\projectiles\projectile.dm" #include "code\modules\projectiles\sentries.dm" #include "code\modules\projectiles\tracer.dm" @@ -330,6 +375,18 @@ #include "code\modules\projectiles\guns\shotguns.dm" #include "code\modules\projectiles\guns\smgs.dm" #include "code\modules\projectiles\guns\specialist.dm" +#include "code\__HELPERS\matrices.dm" +#include "code\_onclick\hud\defines.dm" +#include "code\_onclick\hud\yautja.dm" +#include "code\datums\elements\yautja_tracked_item.dm" +#include "code\datums\jobs\job\job.dm" +#include "code\datums\jobs\job\pred.dm" +#include "code\game\objects\effects\step_triggers.dm" +#include "code\game\objects\items\reagent_containers\snacks.dm" +#include "code\game\objects\items\stacks\leather.dm" +#include "code\game\objects\yautja_misc.dm" +#include "code\modules\language\yautja.dm" +#include "code\modules\surgery\surgery_tools.dm" #include "code\modules\projectiles\magazines\magazines.dm" #include "code\modules\projectiles\magazines\misc.dm" #include "code\modules\projectiles\magazines\specialist.dm" @@ -348,4 +405,23 @@ #include "code\modules\vehicles\mecha\mecha_defense.dm" #include "code\modules\vehicles\powerloader.dm" #include "code\modules\xenomorph\xeno_structures.dm" +#include "code\controllers\configuration\entries.dm" +#include "code\controllers\subsystem\dbcore.dm" +#include "code\game\objects\items\weapons\weapons.dm" +#include "code\modules\client\preferences.dm" #include "code\modules\projectiles\mounted.dm" +#include "code\modules\mob\living\carbon\xenomorph\castes\beetle\beetle.dm" +#include "code\modules\mob\living\carbon\xenomorph\castes\mantis\mantis.dm" +#include "code\modules\mob\living\carbon\xenomorph\castes\scorpion\scorpion.dm" +#include "code\game\objects\items\reagent_containers\autoinjectors.dm" +#include "code\game\objects\items\card_ids.dm" +#include "code\game\objects\structures\crates_lockers\secure\freezer.dm" +#include "code\game\objects\machinery\computer\crew.dm" +#include "code\game\objects\structures\bedsheet_bin.dm" +#include "code\game\objects\structures\stool_bed_chair_nest\chairs.dm" +#include "code\modules\mining\money_bag.dm" +#include "code\modules\atmospherics\machinery\components\unary_devices\thermomachine.dm" +#include "code\modules\atmospherics\machinery\portable\canister.dm" +#include "code\modules\reagents\machinery\reagentgrinder.dm" +#include "code\game\objects\machinery\kitchen\gibber.dm" +#include "code\modules\mob\living\carbon\human\update_icons.dm" diff --git a/modular_RUtgmc/sound/effects/footstep/alien_footstep_medium1.ogg b/modular_RUtgmc/sound/effects/footstep/alien_footstep_medium1.ogg new file mode 100644 index 0000000000000000000000000000000000000000..dd68658f8aef908a61e7e295c9af89c2e29c575f GIT binary patch literal 25788 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 RrUXC9ZrXhZxC*!c_&*ea+zbE! literal 0 HcmV?d00001 diff --git a/modular_RUtgmc/sound/effects/footstep/alien_footstep_medium3.ogg b/modular_RUtgmc/sound/effects/footstep/alien_footstep_medium3.ogg new file mode 100644 index 0000000000000000000000000000000000000000..bc1b6589de5be3365a38fbac89b9d1d891ac86eb GIT binary patch literal 31168 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 literal 0 HcmV?d00001 diff --git a/tgui/packages/tgui-panel/chat/constants.js b/tgui/packages/tgui-panel/chat/constants.js index 7438679670bf0..5bfffd1850904 100644 --- a/tgui/packages/tgui-panel/chat/constants.js +++ b/tgui/packages/tgui-panel/chat/constants.js @@ -60,7 +60,7 @@ export const MESSAGE_TYPES = [ name: 'Radio', description: 'All departments of radio messages', selector: - '.alert, .minorannounce, .radio, .deptradio, .syndradio, .comradio, .casradio, .engradio, .medradio, .sciradio, .supradio, .alpharadio, .bravoradio, .charlieradio, .deltaradio, .zuluradio, .yankeeradio, .xrayradio, .whiskeyradio, .newscaster, .binarysay, .hivemind', + '.alert, .minorannounce, .radio, .deptradio, .syndradio, .comradio, .casradio, .engradio, .medradio, .sciradio, .supradio, .alpharadio, .bravoradio, .charlieradio, .deltaradio, .zuluradio, .yankeeradio, .xrayradio, .whiskeyradio, .newscaster, .binarysay, .hivemind, .yautjaradio', }, { type: MESSAGE_TYPE_INFO, diff --git a/tgui/packages/tgui-panel/styles/tgchat/chat-dark.scss b/tgui/packages/tgui-panel/styles/tgchat/chat-dark.scss index 1c32bc47679d3..17d08a49f9b9e 100644 --- a/tgui/packages/tgui-panel/styles/tgchat/chat-dark.scss +++ b/tgui/packages/tgui-panel/styles/tgchat/chat-dark.scss @@ -468,6 +468,10 @@ em { color: #cc00cc; } +.yautjaradio { + color: #b33d3d; +} + .binarysay { color: #24bf13; background-color: #000000; @@ -548,6 +552,69 @@ h2.alert { color: #2c7f5c; font-style: italic; } +.yautjabold { + color: #800080; + font-weight: bold; +} +.yautjaboldbig { + color: #800080; + font-weight: bold; + font-size: 120%; +} +.extra_large { + font-size: 130%; +} +.huge { + font-size: 150%; +} +.blue { + color: #215cff; +} +.green { + color: #059223; +} +.red { + color: #ff0000; +} +.orange { + color: #eca100; +} + +.retro_translator { + font-weight: bold; +} + +.yautja_translator { + color: #aa0000; + font-weight: bold; + + /*Animation*/ + animation: glitch 0.5s infinite; +} + +/*Keyframes*/ + +@keyframes glitch { + 25% { + color: #aa0000; + transform: translate(-2px, -1px); + } + + 50% { + color: #be0000; + transform: translate(1px, -2px); + } + + 75% { + color: #8d0000; + transform: translate(-1px, 2px); + } + + 100% { + color: #830000; + transform: translate(1px, 1px); + } +} .danger { color: #ff2626; font-weight: bold; diff --git a/tgui/packages/tgui-panel/styles/tgchat/chat-light.scss b/tgui/packages/tgui-panel/styles/tgchat/chat-light.scss index 82ded076cde5d..d62fa43dc7d71 100644 --- a/tgui/packages/tgui-panel/styles/tgchat/chat-light.scss +++ b/tgui/packages/tgui-panel/styles/tgchat/chat-light.scss @@ -479,6 +479,10 @@ em { color: #cc00cc; } +.yautjaradio { + color: #b33d3d; +} + .binarysay { color: #20c20e; background-color: #000000; @@ -559,6 +563,69 @@ h2.alert { color: #2a623d; font-style: italic; } +.yautjabold { + color: #800080; + font-weight: bold; +} +.yautjaboldbig { + color: #800080; + font-weight: bold; + font-size: 120%; +} +.extra_large { + font-size: 130%; +} +.huge { + font-size: 150%; +} +.blue { + color: #215cff; +} +.green { + color: #059223; +} +.red { + color: #ff0000; +} +.orange { + color: #eca100; +} + +.retro_translator { + font-weight: bold; +} + +.yautja_translator { + color: #aa0000; + font-weight: bold; + + /*Animation*/ + animation: glitch 0.5s infinite; +} + +/*Keyframes*/ + +@keyframes glitch { + 25% { + color: #aa0000; + transform: translate(-2px, -1px); + } + + 50% { + color: #be0000; + transform: translate(1px, -2px); + } + + 75% { + color: #8d0000; + transform: translate(-1px, 2px); + } + + 100% { + color: #830000; + transform: translate(1px, 1px); + } +} .danger { color: #ff0000; font-weight: bold; diff --git a/tgui/packages/tgui/constants.ts b/tgui/packages/tgui/constants.ts index 4ef168dd84bff..5876de06b6e1b 100644 --- a/tgui/packages/tgui/constants.ts +++ b/tgui/packages/tgui/constants.ts @@ -45,6 +45,7 @@ export const CSS_COLORS = [ 'black', 'white', 'red', + 'darkred', 'orange', 'yellow', 'olive', diff --git a/tgui/packages/tgui/interfaces/ClanMenu.js b/tgui/packages/tgui/interfaces/ClanMenu.js new file mode 100644 index 0000000000000..ee26ee2fe257f --- /dev/null +++ b/tgui/packages/tgui/interfaces/ClanMenu.js @@ -0,0 +1,202 @@ +import { Fragment } from 'inferno'; +import { useBackend } from '../backend'; +import { Button, Stack } from '../components'; +import { Window } from '../layouts'; + +export const ClanMenu = (props, context) => { + const { act, data } = useBackend(context); + const { + player_rank_pos, + clan_id, + clan_name, + clan_description, + clan_honor, + player_rename_clan, + player_setdesc_clan, + player_sethonor_clan, + player_setcolor_clan, + player_delete_clan, + player_modify_ranks, + player_move_clans, + player_purge, + clan_keys, + } = data; + + return ( + + + + +

{clan_name}

+
{clan_description}
+

Honor: {clan_honor}

+ + + {player_rename_clan ? ( + + ) : null} + {player_setdesc_clan ? ( + + ) : null} + {player_sethonor_clan ? ( + + ) : null} + {player_setcolor_clan ? ( + + ) : null} + {player_delete_clan ? ( + + ) : null} + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + + + + + + + {player_modify_ranks ? + {clan_keys.map((x, index) => ( + + ))} +
+ NameRankHonor : null} + {player_move_clans ? : null} + {player_purge ? : null} +
+
+ + + + ); +}; + +const GetPredInfo = (props, context) => { + const { act } = useBackend(context); + const { + name, + rank, + rank_pos, + honor, + player_rank_pos, + player_modify_ranks, + player_move_clans, + player_purge, + } = props; + + return ( + + + {name} + {rank} + {honor} + {player_rank_pos > rank_pos ? ( + + {player_modify_ranks ? ( + +
+
+ + ) : null} + {player_move_clans ? ( + +
+
+ + ) : null} + {player_purge ? ( + +
+
+ + ) : null} +
+ ) : null} + + ); +}; diff --git a/tgui/packages/tgui/interfaces/Orbit/index.tsx b/tgui/packages/tgui/interfaces/Orbit/index.tsx index 85b2dfd20604a..0f6d447c6ce14 100644 --- a/tgui/packages/tgui/interfaces/Orbit/index.tsx +++ b/tgui/packages/tgui/interfaces/Orbit/index.tsx @@ -33,6 +33,7 @@ const ObservableSearch = (props, context) => { auto_observe, humans = [], marines = [], + yautja = [], som = [], survivors = [], xenos = [], @@ -54,7 +55,7 @@ const ObservableSearch = (props, context) => { // Sorts descending by orbiters sortBy((observable) => -(observable.orbiters || 0)), // Makes a single Observables list for an easy search - ])([humans, marines, som, survivors, xenos, valhalla].flat())[0]; + ])([humans, marines, yautja, som, survivors, xenos, valhalla].flat())[0]; if (mostRelevant !== undefined) { act('orbit', { ref: mostRelevant.ref, @@ -116,6 +117,7 @@ const ObservableContent = (props, context) => { valhalla = [], humans = [], marines = [], + yautja = [], misc = [], npcs = [], som = [], @@ -130,6 +132,7 @@ const ObservableContent = (props, context) => { + diff --git a/tgui/packages/tgui/interfaces/Orbit/types.ts b/tgui/packages/tgui/interfaces/Orbit/types.ts index 1e671835fcaee..c20766540d5f5 100644 --- a/tgui/packages/tgui/interfaces/Orbit/types.ts +++ b/tgui/packages/tgui/interfaces/Orbit/types.ts @@ -11,6 +11,7 @@ export type OrbitData = { misc: Observable[]; npcs: Observable[]; som: Observable[]; + yautja: Observable[]; survivors: Observable[]; xenos: Observable[]; }; diff --git a/tgui/packages/tgui/interfaces/PlayerPreferences/KeybindSettings.tsx b/tgui/packages/tgui/interfaces/PlayerPreferences/KeybindSettings.tsx index fef72bf49876e..04ebed1bc3087 100644 --- a/tgui/packages/tgui/interfaces/PlayerPreferences/KeybindSettings.tsx +++ b/tgui/packages/tgui/interfaces/PlayerPreferences/KeybindSettings.tsx @@ -126,6 +126,12 @@ export const KeybindSettings = (props, context) => { {all_keybindings['XENO']?.filter(filterSearch).map((kb) => ( ))} + +

Yautja

+
+ {all_keybindings['YAUTJA']?.filter(filterSearch).map((kb) => ( + + ))} diff --git a/tgui/packages/tgui/interfaces/PlayerPreferences/Types.tsx b/tgui/packages/tgui/interfaces/PlayerPreferences/Types.tsx index 5e2137f05c0cf..d16c417d3a438 100644 --- a/tgui/packages/tgui/interfaces/PlayerPreferences/Types.tsx +++ b/tgui/packages/tgui/interfaces/PlayerPreferences/Types.tsx @@ -21,6 +21,31 @@ type CharacterCustomizationData = { b_eyes: number; }; +type YautjaCustomizationData = { + has_wl: number; + legacy: number; + predator_name: string; + predator_gender: string; + predator_age: number; + predator_h_style: string; + predator_skin_color: string; + predator_translator_type: string; + predator_mask_type: number; + predator_armor_type: number; + predator_boot_type: number; + predator_armor_material: string; + predator_mask_material: string; + predator_greave_material: string; + predator_caster_material: string; + predator_cape_type: string; + predator_cape_color: string; + predator_flavor_text: string; + pred_r_eyes: number; + pred_g_eyes: number; + pred_b_eyes: number; + yautja_status: string; +}; + type BackgroundInformationData = { slot: number; flavor_text: string; diff --git a/tgui/packages/tgui/interfaces/PlayerPreferences/YautjaCustomization.tsx b/tgui/packages/tgui/interfaces/PlayerPreferences/YautjaCustomization.tsx new file mode 100644 index 0000000000000..38f33e4b59bd4 --- /dev/null +++ b/tgui/packages/tgui/interfaces/PlayerPreferences/YautjaCustomization.tsx @@ -0,0 +1,199 @@ +import { useBackend } from '../../backend'; +import { Section, Flex, LabeledList, Box, ColorBox, Button } from '../../components'; +import { TextFieldPreference, SelectFieldPreference } from './FieldPreferences'; +import { ProfilePicture } from './ProfilePicture'; + +export const YautjaCustomization = (props, context) => { + const { act, data } = useBackend(context); + const { + has_wl, + legacy, + predator_name, + predator_gender, + predator_age, + predator_h_style, + predator_skin_color, + predator_translator_type, + predator_mask_type, + predator_armor_type, + predator_boot_type, + predator_armor_material, + predator_mask_material, + predator_greave_material, + predator_caster_material, + predator_cape_type, + predator_cape_color, + predator_flavor_text, + pred_r_eyes, + pred_g_eyes, + pred_b_eyes, + yautja_status, + } = data; + + const rgbToHex = (red, green, blue) => { + const convert = (comp) => { + const hex = comp.toString(16); + return hex.length === 1 ? `0${hex}` : hex; + }; + return '#' + convert(red) + convert(green) + convert(blue); + }; + + return has_wl ? ( + <> +
+ + + + + + + + + + +
+
+ + + + {legacy ? ( + + ) : ( + + )} + + + + + + + + + + + +
+
+ + + + + + +
+ + ) : ( + WL required + ); +}; diff --git a/tgui/packages/tgui/interfaces/PlayerPreferences/index.tsx b/tgui/packages/tgui/interfaces/PlayerPreferences/index.tsx index 7f1633c3dc28f..2744edffeaadc 100644 --- a/tgui/packages/tgui/interfaces/PlayerPreferences/index.tsx +++ b/tgui/packages/tgui/interfaces/PlayerPreferences/index.tsx @@ -3,6 +3,7 @@ import { Button, Section, Flex, Tabs } from '../../components'; import { Window } from '../../layouts'; import { GearCustomization } from './GearCustomisation'; import { CharacterCustomization } from './CharacterCustomization'; +import { YautjaCustomization } from './YautjaCustomization'; import { JobPreferences } from './JobPreferences'; import { GameSettings } from './GameSettings'; import { KeybindSettings } from './KeybindSettings'; @@ -22,24 +23,28 @@ export const PlayerPreferences = (props, context) => { affectsSave = true; break; case 2: - CurrentTab = BackgroundInformation; + CurrentTab = YautjaCustomization; affectsSave = true; break; case 3: - CurrentTab = GearCustomization; + CurrentTab = BackgroundInformation; affectsSave = true; break; case 4: - CurrentTab = JobPreferences; + CurrentTab = GearCustomization; affectsSave = true; break; case 5: - CurrentTab = GameSettings; + CurrentTab = JobPreferences; + affectsSave = true; break; case 6: - CurrentTab = KeybindSettings; + CurrentTab = GameSettings; break; case 7: + CurrentTab = KeybindSettings; + break; + case 8: CurrentTab = DrawOrder; break; default: @@ -95,31 +100,36 @@ const NavigationSelector = (props, context) => { act('tab_change', { tabIndex: 2 })}> - Background Information + Predator Customization act('tab_change', { tabIndex: 3 })}> - Gear Customization + Background Information act('tab_change', { tabIndex: 4 })}> - Job Preferences + Gear Customization act('tab_change', { tabIndex: 5 })}> - Game Settings + Job Preferences act('tab_change', { tabIndex: 6 })}> - Keybindings + Game Settings act('tab_change', { tabIndex: 7 })}> + Keybindings + + act('tab_change', { tabIndex: 8 })}> Draw Order diff --git a/tgui/packages/tgui/styles/colors.scss b/tgui/packages/tgui/styles/colors.scss index 1488d09aa43c2..5af16bdfb8373 100644 --- a/tgui/packages/tgui/styles/colors.scss +++ b/tgui/packages/tgui/styles/colors.scss @@ -11,6 +11,7 @@ $black: #000000 !default; $white: #ffffff !default; $red: #db2828 !default; +$darkred: #7e3131 !default; $orange: #f2711c !default; $yellow: #fbd608 !default; $olive: #b5cc18 !default; @@ -48,6 +49,7 @@ $_gen_map: ( 'black': $black, 'white': $white, 'red': $red, + 'darkred': $darkred, 'orange': $orange, 'yellow': $yellow, 'olive': $olive, diff --git a/tgui/packages/tgui/styles/interfaces/ClanMenu.scss b/tgui/packages/tgui/styles/interfaces/ClanMenu.scss new file mode 100644 index 0000000000000..91c54757db706 --- /dev/null +++ b/tgui/packages/tgui/styles/interfaces/ClanMenu.scss @@ -0,0 +1,48 @@ +@use '../base.scss'; + +.underlineCell { + border-bottom: 1px solid #fff; +} + +.whiteDescription { + color: white; + font-weight: bold; + font-family: inherit; + + width: 100%; + word-wrap: break-word; +} + +.noMargin { + margin: 0; +} + +.noPadCell { + padding: 2px; +} + +.clan_td_th { + padding: 10px 10px 10px 10px; + border-bottom: 1px solid #252933; +} + +.clan_h3 { + margin: 0; + padding: 0; +} + +.clan_h1 { + margin: 0; + padding: 0; +} + +.filter { + background-color: #684675; + color: #ccab7f; + border: 1px solid #161616; +} + +.clan_list { + border-collapse: collapse; + width: 100%; +} diff --git a/tgui/packages/tgui/styles/main.scss b/tgui/packages/tgui/styles/main.scss index ac2d750e3eb9c..813f53e85152f 100644 --- a/tgui/packages/tgui/styles/main.scss +++ b/tgui/packages/tgui/styles/main.scss @@ -52,6 +52,7 @@ @include meta.load-css('./interfaces/CameraConsole.scss'); @include meta.load-css('./interfaces/Mecha.scss'); @include meta.load-css('./interfaces/Changelog.scss'); +@include meta.load-css('./interfaces/ClanMenu.scss'); @include meta.load-css('./interfaces/NuclearBomb.scss'); @include meta.load-css('./interfaces/Paper.scss'); @include meta.load-css('./interfaces/Roulette.scss');