From 28e11dee540e61b6c42fa293c1e1da087c1c2b0a Mon Sep 17 00:00:00 2001 From: silicons <2003111+silicons@users.noreply.github.com> Date: Tue, 8 Nov 2022 23:57:00 -0800 Subject: [PATCH] lore/contractor/background/character overhaul project (public branch edition) (#4488) Co-authored-by: silicons <2003111+silicons@users.noreply.github.com> Co-authored-by: Zandario Co-authored-by: VM_USER Co-authored-by: AlphaM01 <33434925+AlphaM01@users.noreply.github.com> Co-authored-by: LordPapalus <54518057+LordPapalus@users.noreply.github.com> --- SQL/database_schema.sql | 11 + SQL/database_schema_prefixed.sql | 9 + citadel.dme | 297 +++++++----- code/__DEFINES/client/player_flags.dm | 7 + code/__DEFINES/controllers/_subsystems.dm | 4 +- code/__DEFINES/controllers/prototypes.dm | 5 + .../signals_atom/signals_atom_attack.dm | 2 +- code/__DEFINES/jobs.dm | 3 - code/__DEFINES/jobs/availability.dm | 24 + code/__DEFINES/jobs/jobs.dm | 64 +++ .../languages/{language_flags.dm => flags.dm} | 13 + code/__DEFINES/languages/ids.dm | 115 +++++ .../{languages.dm => languages/legacy.dm} | 3 +- .../preferences/data_keys_character.dm | 18 + .../__DEFINES/preferences/data_keys_global.dm | 3 + code/__DEFINES/preferences/jobs.dm | 15 + code/__DEFINES/preferences/load_order.dm | 12 + code/__DEFINES/preferences/misc.dm | 15 + code/__DEFINES/preferences/procs.dm | 16 + code/__DEFINES/preferences/savefiles.dm | 16 + code/__DEFINES/preferences/topic.dm | 6 + code/__DEFINES/species/species.dm | 72 ++- code/__DEFINES/species/species_flags.dm | 65 ++- code/__DEFINES/topic.dm | 6 - code/__HELPERS/_auxtools_api.dm | 8 + code/__HELPERS/game.dm | 14 +- code/__HELPERS/global_lists.dm | 42 -- code/__HELPERS/lists/copy.dm | 6 +- code/__HELPERS/mobs.dm | 4 +- code/__HELPERS/names.dm | 2 +- code/__HELPERS/sanitize/datatypes.dm | 17 + code/__HELPERS/sanitize/list.dm | 8 + code/__HELPERS/sanitize_values.dm | 18 - code/__HELPERS/sorts/comparators.dm | 72 +-- code/__HELPERS/unsorted.dm | 2 +- code/_globalvars/lists/client.dm | 24 - code/_globalvars/lists/clients.dm | 4 + code/_globalvars/lists/keybindings.dm | 22 + code/_globalvars/lists/mobs.dm | 2 + code/_globalvars/lists/objects.dm | 1 + code/_globalvars/lists/species.dm | 7 - code/_globalvars/mobs.dm | 9 +- code/_macros.dm | 4 +- code/_onclick/hud/alert.dm | 2 +- code/_onclick/hud/ghost.dm | 4 +- .../atom_huds/alternate_appearance.dm | 4 +- code/_rendering/atom_huds/atom_hud.dm | 2 +- .../configuration/configuration.dm | 1 + code/controllers/configuration/whitelists.dm | 97 ++++ code/controllers/controller.dm | 2 + code/controllers/subsystem/ai.dm | 2 +- code/controllers/subsystem/character_setup.dm | 38 -- .../subsystem/characters/_characters.dm | 67 +++ .../subsystem/characters/backgrounds.dm | 112 +++++ .../subsystem/characters/character_species.dm | 83 ++++ .../subsystem/characters/languages.dm | 79 ++++ .../subsystem/characters/species.dm | 120 +++++ code/controllers/subsystem/dbcore/_dbcore.dm | 4 + code/controllers/subsystem/inactivity.dm | 2 +- code/controllers/subsystem/job/_job.dm | 76 +++- ...job_controller.dm => _legacy_job_stuff.dm} | 325 +++++--------- code/controllers/subsystem/job/job_manager.dm | 64 +++ code/controllers/subsystem/job/joining.dm | 219 +++++++++ code/controllers/subsystem/job/roundstart.dm | 397 ++++++++++++++++ code/controllers/subsystem/job/spawnpoints.dm | 24 +- code/controllers/subsystem/mobs.dm | 2 +- code/controllers/subsystem/nightshift.dm | 2 +- code/controllers/subsystem/persist_vr.dm | 4 +- .../subsystem/prototypes/_prototypes.dm | 50 +++ code/controllers/subsystem/prototypes/dud.dm | 7 + code/controllers/subsystem/prototypes/lore.dm | 16 + .../subsystem/prototypes/prototype.dm | 19 + code/controllers/subsystem/server_maint.dm | 4 +- code/controllers/subsystem/supply.dm | 2 +- code/controllers/subsystem/ticker.dm | 18 +- code/controllers/subsystem/vote.dm | 2 +- code/datums/_datum.dm | 7 - code/datums/announce/_legacy.dm | 6 +- code/datums/announce/announce_location.dm | 2 +- code/datums/components/storage/storage.dm | 2 +- code/datums/datacore.dm | 8 +- code/datums/elements/digitalcamo.dm | 4 +- code/datums/ghost_query.dm | 2 +- code/datums/mind.dm | 7 + code/datums/world_topic.dm | 4 +- code/game/antagonist/antagonist_update.dm | 2 +- code/game/antagonist/mutiny/mutineer.dm | 4 +- code/game/antagonist/station/changeling.dm | 6 +- code/game/antagonist/station/highlander.dm | 2 +- code/game/antagonist/station/renegade.dm | 2 +- code/game/area/area.dm | 2 +- code/game/atoms/atoms_movable_pulling.dm | 4 +- code/game/dna/dna_modifier.dm | 2 +- .../gamemodes/changeling/powers/absorb.dm | 2 +- .../changeling/powers/extract_dna_sting.dm | 2 +- .../gamemodes/changeling/powers/transform.dm | 2 +- code/game/gamemodes/cult/narsie.dm | 6 +- code/game/gamemodes/cult/ritual.dm | 4 +- code/game/gamemodes/cult/runes.dm | 4 +- .../endgame/supermatter_cascade/portal.dm | 2 +- .../endgame/supermatter_cascade/universe.dm | 4 +- code/game/gamemodes/events.dm | 2 +- code/game/gamemodes/game_mode.dm | 12 +- code/game/gamemodes/meteor/meteor.dm | 2 +- code/game/gamemodes/meteor/meteors.dm | 2 +- code/game/gamemodes/objective.dm | 12 +- code/game/gamemodes/sandbox/sandbox.dm | 2 +- .../technomancer/spells/aura/fire_aura.dm | 2 +- .../technomancer/spells/aura/frost_aura.dm | 2 +- .../technomancer/spells/resurrect.dm | 2 +- .../game/landmarks/spawnpoint/station/jobs.dm | 4 +- code/game/machinery/air_alarm.dm | 2 +- code/game/machinery/bioprinter.dm | 4 +- code/game/machinery/cloning.dm | 6 +- code/game/machinery/computer/Operating.dm | 2 +- code/game/machinery/computer/ai_core.dm | 12 +- code/game/machinery/computer/cloning.dm | 4 +- .../game/machinery/computer/communications.dm | 8 +- code/game/machinery/computer/security.dm | 2 +- code/game/machinery/computer/timeclock_vr.dm | 12 +- code/game/machinery/cryopod.dm | 2 +- code/game/machinery/doors/airlock.dm | 2 +- .../airlock_docking_controller.dm | 14 +- .../airlock_docking_controller_multi.dm | 14 +- .../embedded_controller/docking_program.dm | 2 +- .../embedded_controller/mapping_helpers.dm | 6 +- code/game/machinery/fire_alarm.dm | 2 +- code/game/machinery/holoposter.dm | 4 +- code/game/machinery/telecomms/broadcaster.dm | 2 +- .../machinery/telecomms/telecomunications.dm | 2 +- code/game/mecha/mech_prosthetics.dm | 2 +- code/game/mecha/medical/odysseus.dm | 16 +- .../effects/map_effects/map_effects.dm | 4 +- .../effects/map_effects/screen_shaker.dm | 2 +- code/game/objects/explosion.dm | 2 +- code/game/objects/items/devices/PDA/PDA.dm | 2 +- .../items/devices/communicator/UI_tgui.dm | 2 +- .../items/devices/communicator/messaging.dm | 2 +- code/game/objects/items/devices/defib.dm | 4 +- .../objects/items/devices/radio/headset.dm | 4 +- code/game/objects/items/devices/translator.dm | 4 +- code/game/objects/items/robot/robot_parts.dm | 2 +- .../objects/items/robot/robot_upgrades.dm | 3 +- .../objects/items/weapons/material/shards.dm | 2 +- code/game/objects/misc.dm | 2 +- code/game/objects/mob_spawner.dm | 2 +- code/game/objects/objs.dm | 2 + .../objects/structures/medical_stand_vr.dm | 2 +- code/game/objects/structures/mirror.dm | 4 +- code/game/objects/structures/morgue.dm | 2 +- code/game/objects/structures/spiritboard.dm | 2 +- code/game/sound.dm | 4 +- code/game/statistics.dm | 2 +- code/game/verbs/ignore.dm | 4 +- code/game/world.dm | 11 +- code/modules/admin/admin.dm | 11 +- code/modules/admin/admin_verbs.dm | 4 +- code/modules/admin/ckey_vr.dm | 2 +- code/modules/admin/topic.dm | 44 +- code/modules/admin/verbs/adminjump.dm | 4 +- code/modules/admin/verbs/buildmode.dm | 2 +- code/modules/admin/verbs/debug.dm | 6 +- .../verbs/debug/reestablish_db_connection.dm | 3 + code/modules/admin/verbs/lightning_strike.dm | 2 +- code/modules/admin/verbs/playsound.dm | 10 +- code/modules/admin/verbs/randomverbs.dm | 10 +- code/modules/admin/verbs/smite.dm | 2 +- code/modules/admin/verbs/smite_vr.dm | 2 +- code/modules/admin/verbs/tripAI.dm | 2 +- code/modules/admin/view_variables/topic.dm | 4 +- code/modules/artifice/deadringer.dm | 2 +- code/modules/blob2/overmind/types.dm | 4 +- code/modules/catalogue/cataloguer.dm | 2 +- code/modules/client/client_defines.dm | 9 + code/modules/client/client_procs.dm | 45 +- code/modules/client/data.dm | 22 + code/modules/client/database.dm | 219 +++++++++ code/modules/client/player_details.dm | 1 + .../client/preference_setup/_defines.dm | 3 - .../preference_setup/general/02_language.dm | 97 ---- .../preference_setup/general/05_background.dm | 135 ------ .../preference_setup/occupation/occupation.dm | 408 ----------------- .../client/preference_setup/vore/07_vantag.dm | 52 --- code/modules/client/preferences_savefile.dm | 142 ------ code/modules/client/ui_style.dm | 2 +- code/modules/client/viewport.dm | 4 +- code/modules/events/comms_blackout.dm | 2 +- .../modules/events/communications_blackout.dm | 2 +- code/modules/events/event_container.dm | 2 +- code/modules/events/event_dynamic.dm | 12 +- code/modules/events/ion_storm.dm | 4 +- code/modules/events/prison_break.dm | 2 +- code/modules/events/viral_infection.dm | 2 +- code/modules/events/viral_outbreak.dm | 2 +- code/modules/food/food/snacks.dm | 2 +- .../food/kitchen/cooking_machines/fryer.dm | 2 +- .../gamemaster/actions/comms_blackout.dm | 2 +- code/modules/gamemaster/actions/ion_storm.dm | 2 +- .../gamemaster/actions/prison_break.dm | 2 +- .../modules/gamemaster/actions/solar_storm.dm | 2 +- .../actions/surprise_carp_attack.dm | 2 +- .../gamemaster/actions/viral_infection.dm | 2 +- .../gamemaster/actions/viral_outbreak.dm | 2 +- code/modules/gamemaster/controller.dm | 2 +- code/modules/ghostroles/instantiator.dm | 6 +- code/modules/ghosttrap/trap.dm | 2 +- .../integrated_electronics/core/assemblies.dm | 2 +- .../integrated_electronics/subtypes/input.dm | 4 +- code/modules/jobs/departments/cargo.dm | 2 +- code/modules/jobs/departments/civillian.dm | 2 +- code/modules/jobs/departments/command.dm | 2 +- code/modules/jobs/departments/engineering.dm | 2 +- code/modules/jobs/departments/misc.dm | 2 +- code/modules/jobs/departments/offduty.dm | 2 +- code/modules/jobs/departments/planetside.dm | 2 +- code/modules/jobs/departments/research.dm | 2 +- code/modules/jobs/departments/security.dm | 2 +- code/modules/jobs/departments/silicon.dm | 2 +- code/modules/jobs/job.dm | 139 +++++- code/modules/jobs/job_types/station.dm | 1 + .../station/admin/centcom_officer.dm | 3 +- .../station/admin/emergency_responder.dm | 3 +- .../job_types/station/civillian/assistant.dm | 1 + .../job_types/station/civillian/chaplain.dm | 1 + .../jobs/job_types/station/civillian/clown.dm | 2 +- .../station/civillian/entertainer.dm | 1 + .../civillian/internals_affairs_agent.dm | 1 + .../job_types/station/civillian/librarian.dm | 1 + .../jobs/job_types/station/civillian/mime.dm | 2 +- .../jobs/job_types/station/civillian/pilot.dm | 1 + .../jobs/job_types/station/command/captain.dm | 1 + .../station/command/command_secretary.dm | 1 + .../station/command/head_of_personnel.dm | 1 + .../engineering/atmospherics_technician.dm | 1 + .../station/engineering/chief_engineer.dm | 1 + .../station/engineering/senior_engineer.dm | 1 + .../station/engineering/station_engineer.dm | 1 + .../job_types/station/exploration/explorer.dm | 1 + .../station/exploration/field_medic.dm | 1 + .../station/exploration/pathfinder.dm | 1 + .../jobs/job_types/station/medical/chemist.dm | 1 + .../station/medical/chief_medical_officer.dm | 1 + .../job_types/station/medical/geneticist.dm | 1 + .../job_types/station/medical/head_nurse.dm | 1 + .../station/medical/medical_doctor.dm | 1 + .../job_types/station/medical/paramedic.dm | 1 + .../job_types/station/medical/psychiatrist.dm | 1 + .../job_types/station/offduty/_offduty.dm | 3 +- .../job_types/station/offduty/civillian.dm | 1 + .../jobs/job_types/station/offduty/command.dm | 4 +- .../job_types/station/offduty/engineering.dm | 1 + .../job_types/station/offduty/exploration.dm | 1 + .../jobs/job_types/station/offduty/medical.dm | 1 + .../jobs/job_types/station/offduty/science.dm | 1 + .../job_types/station/offduty/security.dm | 1 + .../jobs/job_types/station/offduty/supply.dm | 1 + .../station/science/research_director.dm | 1 + .../job_types/station/science/roboticist.dm | 1 + .../job_types/station/science/scientist.dm | 1 + .../station/science/senior_researcher.dm | 1 + .../job_types/station/security/detective.dm | 1 + .../station/security/head_of_security.dm | 1 + .../station/security/security_officer.dm | 1 + .../jobs/job_types/station/security/warden.dm | 1 + .../job_types/station/service/bartender.dm | 1 + .../job_types/station/service/botanist.dm | 1 + .../jobs/job_types/station/service/chef.dm | 1 + .../jobs/job_types/station/service/janitor.dm | 1 + .../jobs/job_types/station/silicon/ai.dm | 8 +- .../jobs/job_types/station/silicon/cyborg.dm | 1 + .../station/supply/cargo_technician.dm | 1 + .../job_types/station/supply/quartermaster.dm | 1 + .../job_types/station/supply/shaft_miner.dm | 1 + code/modules/jobs/outfit.dm | 2 +- code/modules/jobs/whitelist.dm | 64 --- code/modules/jobs/whitelist_vr.dm | 30 -- code/modules/keybindings/setup.dm | 1 + code/modules/language/abstract.dm | 97 ++++ code/modules/language/animal.dm | 51 +++ code/modules/language/antagonist/borer.dm | 25 ++ .../modules/language/antagonist/changeling.dm | 16 + code/modules/language/antagonist/cult.dm | 32 ++ code/modules/language/antagonist/swarmbot.dm | 13 + code/modules/language/antagonist/xenomorph.dm | 34 ++ code/modules/language/core.dm | 46 ++ code/modules/language/event.dm | 29 ++ code/modules/language/galactic.dm | 76 ++++ code/modules/language/generic.dm | 221 --------- code/modules/language/holder.dm | 1 + code/modules/language/language.dm | 51 +-- code/modules/language/monkey.dm | 59 +-- code/modules/language/outsider.dm | 181 -------- .../language/{synthetic.dm => silicons.dm} | 6 +- code/modules/language/species/adherent.dm | 16 + code/modules/language/species/akula.dm | 12 + code/modules/language/species/alraune.dm | 13 + code/modules/language/species/altevian.dm | 12 + code/modules/language/species/birdsong.dm | 10 + code/modules/language/species/celestial.dm | 25 ++ code/modules/language/species/diona.dm | 25 ++ code/modules/language/species/human.dm | 124 +++++ code/modules/language/species/moth.dm | 3 +- code/modules/language/species/naramadi.dm | 9 + code/modules/language/species/phoronoid.dm | 10 + code/modules/language/species/shadekin.dm | 11 + code/modules/language/species/skrell.dm | 32 ++ code/modules/language/species/tajaran.dm | 59 +++ code/modules/language/species/teshari.dm | 18 + code/modules/language/species/unathi.dm | 27 ++ code/modules/language/species/vasilissan.dm | 12 + code/modules/language/species/vox.dm | 16 + code/modules/language/species/vulpkanin.dm | 13 + code/modules/language/species/zaddat.dm | 11 + code/modules/language/species/zorren.dm | 11 + code/modules/language/station.dm | 422 ------------------ code/modules/lore_hardcoded/README.md | 9 + code/modules/lore_hardcoded/_hardcoded.dm | 69 +++ code/modules/lore_hardcoded/citizenship.dm | 74 +++ code/modules/lore_hardcoded/faction.dm | 368 +++++++++++++++ code/modules/lore_hardcoded/origin.dm | 22 + .../origin/hegemony/SHOVE_THINGS_HERE.dm | 13 + .../origin/hegemony/_hegemony.dm | 3 + .../origin/hegemony/naramadi.dm | 38 ++ .../lore_hardcoded/origin/hegemony/unathi.dm | 30 ++ .../lore_hardcoded/origin/oricon/_oricon.dm | 3 + .../lore_hardcoded/origin/oricon/sol.dm | 101 +++++ code/modules/lore_hardcoded/religion.dm | 14 + code/modules/mapping/preloader.dm | 2 +- .../misc_maps/trade/trade_station_jobs.dm | 3 +- code/modules/maps/tether/levels/alienship.dm | 2 +- code/modules/metric/activity.dm | 8 +- code/modules/metric/count.dm | 10 +- code/modules/metric/department.dm | 8 +- code/modules/mob/dead/observer/free_vr.dm | 2 +- code/modules/mob/dead/observer/observer.dm | 4 +- .../mob/dead/observer/observer_movement.dm | 2 +- code/modules/mob/dead/observer/observer_vr.dm | 2 +- code/modules/mob/grab.dm | 2 +- code/modules/mob/hear_say.dm | 10 +- code/modules/mob/inventory.dm | 2 + code/modules/mob/living/autohiss.dm | 2 +- code/modules/mob/living/bot/bot.dm | 2 +- .../mob/living/carbon/alien/diona/diona.dm | 2 +- .../living/carbon/alien/diona/progression.dm | 2 +- .../mob/living/carbon/alien/progression.dm | 2 +- .../mob/living/carbon/brain/posibrain.dm | 2 +- code/modules/mob/living/carbon/brain/say.dm | 2 +- code/modules/mob/living/carbon/carbon.dm | 8 +- .../mob/living/carbon/carbon_defense.dm | 2 +- .../mob/living/carbon/human/appearance.dm | 8 +- code/modules/mob/living/carbon/human/human.dm | 105 ++--- .../living/carbon/human/human_attackhand.dm | 2 +- .../mob/living/carbon/human/human_damage.dm | 16 +- .../mob/living/carbon/human/human_movement.dm | 2 +- code/modules/mob/living/carbon/human/life.dm | 8 +- .../mob/living/carbon/human/update_icons.dm | 5 +- .../mob/living/carbon/metroid/items.dm | 2 +- code/modules/mob/living/default_language.dm | 4 +- code/modules/mob/living/say.dm | 16 +- code/modules/mob/living/silicon/ai/ai.dm | 5 +- code/modules/mob/living/silicon/ai/ai_vr.dm | 1 - .../modules/mob/living/silicon/ai/latejoin.dm | 4 +- code/modules/mob/living/silicon/laws.dm | 2 +- .../modules/mob/living/silicon/pai/recruit.dm | 4 +- .../living/silicon/pai/software_modules.dm | 2 +- .../mob/living/silicon/robot/drone/drone.dm | 4 +- .../silicon/robot/drone/drone_console.dm | 2 +- .../silicon/robot/drone/drone_manufacturer.dm | 2 +- .../living/silicon/robot/drone/drone_say.dm | 4 +- .../modules/mob/living/silicon/robot/robot.dm | 2 +- code/modules/mob/living/silicon/silicon.dm | 10 +- .../living/simple_animal/animals/spiderbot.dm | 4 +- .../mob/living/simple_mob/simple_mob.dm | 4 +- .../simple_mob/subtypes/animal/borer/borer.dm | 4 +- .../subtypes/animal/borer/borer_captive.dm | 2 +- .../subtypes/slime/xenobio/consumption.dm | 2 +- .../subtypes/vore/solargrub_larva.dm | 8 +- code/modules/mob/living/voice/voice.dm | 8 +- code/modules/mob/login.dm | 6 +- code/modules/mob/logout.dm | 3 +- code/modules/mob/mob.dm | 2 +- code/modules/mob/mob_defines.dm | 21 +- code/modules/mob/mob_helpers.dm | 8 +- code/modules/mob/mob_transformation_simple.dm | 2 +- code/modules/mob/new_player/join_menu.dm | 258 +++++++++++ code/modules/mob/new_player/login.dm | 2 +- code/modules/mob/new_player/new_player.dm | 160 ++----- .../mob/new_player/preferences_setup_vr.dm | 15 - code/modules/mob/say.dm | 12 +- code/modules/mob/transform_procs.dm | 21 +- .../file_system/news_article.dm | 4 +- .../file_system/programs/command/comm.dm | 10 +- .../file_system/programs/generic/uav.dm | 14 +- code/modules/nano/modules/human_appearance.dm | 2 +- code/modules/nifsoft/nif.dm | 2 +- code/modules/organs/blood.dm | 2 +- code/modules/organs/external/_external.dm | 12 +- code/modules/organs/internal/brain.dm | 2 +- code/modules/organs/internal/voicebox.dm | 2 +- code/modules/organs/organ.dm | 10 +- code/modules/organs/robolimbs.dm | 4 +- .../overmap/disperser/disperser_fire.dm | 2 +- code/modules/overmap/spacetravel.dm | 2 +- code/modules/paperwork/photocopier.dm | 2 +- code/modules/planet/weather.dm | 2 +- code/modules/power/fission/engine.dm | 2 +- code/modules/power/gravitygenerator.dm | 4 +- code/modules/power/singularity/act.dm | 2 +- code/modules/power/supermatter/supermatter.dm | 4 +- .../_preferences.dm} | 167 ++----- code/modules/preferences/apply.dm | 55 +++ code/modules/preferences/data.dm | 270 +++++++++++ code/modules/preferences/errors.dm | 24 + code/modules/preferences/migration.dm | 126 ++++++ .../preference_setup/antagonism/01_basic.dm | 21 +- .../antagonism/02_candidacy.dm | 6 +- .../background/_background.dm | 18 + .../background/citizenship.dm | 71 +++ .../preference_setup/background/faction.dm | 91 ++++ .../preference_setup/background/language.dm | 117 +++++ .../preference_setup/background/origin.dm | 87 ++++ .../preference_setup/background/religion.dm | 70 +++ .../preference_setup/background/species.dm | 105 +++++ .../preference_setup/general/01_basic.dm | 46 +- .../preference_setup/general/03_body.dm | 292 ++++-------- .../preference_setup/general/04_equipment.dm | 25 +- .../preference_setup/general/05_background.dm | 71 +++ .../preference_setup/general/06_flavor.dm | 13 +- .../preference_setup/global/01_ui.dm | 28 +- .../preference_setup/global/02_settings.dm | 8 +- .../preference_setup/global/03_pai.dm | 4 +- .../preference_setup/global/04_ooc.dm | 8 +- .../preference_setup/global/05_media.dm | 6 +- .../global/language_prefix.dm | 66 +++ .../preference_setup/global/setting_datums.dm | 0 .../preference_setup/helpers/language_pick.dm | 93 ++++ .../preference_setup/helpers/species_pick.dm | 135 ++++++ .../keybindings/keybindings.dm | 27 +- .../preference_setup/loadout/gear_tweaks.dm | 0 .../preference_setup/loadout/loadout.dm | 47 +- .../loadout/loadout_accessories.dm | 0 .../loadout/loadout_cosmetics.dm | 0 .../loadout/loadout_donator.dm | 0 .../preference_setup/loadout/loadout_ears.dm | 0 .../loadout/loadout_event_rewards.dm | 0 .../preference_setup/loadout/loadout_eyes.dm | 0 .../loadout/loadout_general.dm | 0 .../loadout/loadout_gloves.dm | 0 .../preference_setup/loadout/loadout_head.dm | 0 .../preference_setup/loadout/loadout_mask.dm | 0 .../loadout/loadout_role_restricted.dm | 0 .../loadout/loadout_seasonal.dm | 0 .../preference_setup/loadout/loadout_shoes.dm | 0 .../loadout/loadout_smoking.dm | 0 .../preference_setup/loadout/loadout_suit.dm | 0 .../loadout/loadout_uniform.dm | 0 .../loadout/loadout_utility.dm | 0 .../preference_setup/loadout/loadout_xeno.dm | 15 +- .../preference_setup/occupation/occupation.dm | 359 +++++++++++++++ .../preference_category_new.dm | 9 + .../preference_setup/preference_item_new.dm | 164 +++++++ .../preference_setup/preference_setup.dm | 82 ++-- .../preference_setup/skills/skills.dm | 17 +- .../preference_setup/traits/trait_defines.dm | 0 .../preference_setup/traits/traits.dm | 10 +- .../preference_setup/vore/01_ears.dm | 71 +-- .../preference_setup/vore/02_size.dm | 21 +- .../preference_setup/vore/03_egg.dm | 13 +- .../preference_setup/vore/04_autohiss.dm | 32 +- .../preference_setup/vore/05_resleeving.dm | 13 +- .../preference_setup/vore/06_persistence.dm | 6 +- .../preference_setup/vore/08_traits.dm | 76 ++-- .../preference_setup/vore/09_nif.dm | 22 +- .../preference_setup/vore/10_misc.dm | 19 +- .../preferences_factions.dm | 0 .../preferences/preferences_savefile.dm | 188 ++++++++ .../preferences_setup.dm | 57 +-- .../preferences_spawnpoints.dm | 2 +- .../preferences_toggle_procs.dm | 50 +-- code/modules/preferences/shims.dm | 12 + code/modules/preferences/ui.dm | 50 +++ code/modules/projectiles/projectile/change.dm | 4 +- code/modules/projectiles/projectile/hook.dm | 2 +- .../modules/projectiles/projectile/special.dm | 4 +- .../Chemistry-Reagents-Toxins.dm | 6 +- code/modules/recycling/disposal.dm | 15 +- code/modules/research/prosfab_designs.dm | 8 +- code/modules/resleeving/designer.dm | 22 +- code/modules/resleeving/infocore_records.dm | 4 +- code/modules/resleeving/infomorph_software.dm | 2 +- code/modules/resleeving/machines.dm | 2 +- .../security levels/security levels.dm | 30 +- code/modules/shuttles/shuttle.dm | 2 +- code/modules/shuttles/shuttle_autodock.dm | 2 +- code/modules/species/character_species.dm | 160 +++++++ code/modules/species/lookup.dm | 71 --- code/modules/species/outsider/celestials.dm | 18 +- code/modules/species/outsider/replicant.dm | 24 +- code/modules/species/outsider/scori.dm | 10 +- code/modules/species/outsider/shadow.dm | 5 +- code/modules/species/outsider/skeleton.dm | 7 +- code/modules/species/outsider/vox.dm | 15 +- .../{station => }/promethean/promethean.dm | 11 +- .../promethean/promethean_blob.dm | 0 .../{station => }/protean/protean_blob.dm | 0 .../{station => }/protean/protean_powers.dm | 4 +- .../{station => }/protean/protean_species.dm | 8 +- .../shadekin/crew_shadekin_abilities.dm | 4 +- code/modules/species/shadekin/shadekin.dm | 16 +- .../species/shadekin/shadekin_abilities.dm | 4 + .../species/shadekin/shadekin_blackeyed.dm | 17 +- code/modules/species/species.dm | 103 +++-- code/modules/species/species_getters.dm | 31 +- code/modules/species/species_shapeshift.dm | 24 +- code/modules/species/station/adherent.dm | 10 +- code/modules/species/station/alraune.dm | 12 +- code/modules/species/station/apidaen.dm | 9 +- .../modules/species/station/custom_species.dm | 11 +- code/modules/species/station/diona.dm | 18 +- code/modules/species/station/golem.dm | 7 +- code/modules/species/station/monkey.dm | 37 +- code/modules/species/station/phoronoids.dm | 10 +- code/modules/species/station/rapala.dm | 7 +- .../modules/species/station/standard/akula.dm | 10 +- .../modules/species/station/standard/harpy.dm | 5 +- .../modules/species/station/standard/human.dm | 16 +- .../station/standard/human_subspecies.dm | 11 +- code/modules/species/station/standard/moth.dm | 15 +- .../species/station/standard/naramadi.dm | 10 +- .../species/station/standard/nevrean.dm | 9 +- .../species/station/standard/shadekin.dm | 6 +- .../species/station/standard/skrell.dm | 15 +- .../species/station/standard/tajaran.dm | 16 +- .../species/station/standard/teshari.dm | 15 +- .../species/station/standard/unathi.dm | 11 +- .../species/station/standard/vulpkanin.dm | 9 +- .../species/station/standard/zaddat.dm | 14 +- .../species/station/standard/zorren.dm | 20 +- code/modules/species/station/vasilissan.dm | 9 +- code/modules/species/station/werebeast.dm | 9 +- .../station/xenomorph_hybrids/xeno_hybrids.dm | 16 +- .../modules/species/virtual_reality/avatar.dm | 5 +- .../species/virtual_reality/opaque_form.dm | 9 + .../xenochimera.dm} | 17 +- .../species/xenomorphs/alien_embryo.dm | 6 +- .../species/xenomorphs/alien_species.dm | 18 +- code/modules/species/xenomorphs/xenomorphs.dm | 2 +- .../sprite_accessories/body_markings.dm | 0 .../facial_hair/facial_hair.dm | 0 .../facial_hair/tajaran_facial_hair.dm | 0 .../facial_hair/teshari_facial_hair.dm | 0 .../facial_hair/unathi_facial_hair.dm | 0 .../facial_hair/vox_facial_hair.dm | 0 .../facial_hair/vulpakin_facial_hair.dm | 0 .../sprite_accessories/hair/hair.dm | 0 .../sprite_accessories/hair/sergal_hair.dm | 0 .../sprite_accessories/hair/shadekin.dm | 0 .../sprite_accessories/hair/skrell_hair.dm | 0 .../sprite_accessories/hair/tajaran_hair.dm | 0 .../sprite_accessories/hair/teshari_hair.dm | 0 .../sprite_accessories/hair/unathi_hair.dm | 0 .../sprite_accessories/hair/vox_hair.dm | 0 .../sprite_accessories/hair/vulpakin_hair.dm | 0 .../hair/xenomorph_hybrid_domes.dm | 0 .../markings/diona_stuff.dm | 0 .../sprite_accessories/markings/eye_stuff.dm | 0 .../sprite_accessories/markings/panda.dm | 0 .../sprite_accessories/markings/sergal.dm | 0 .../markings/synth_stuff.dm | 0 .../sprite_accessories/markings/taj.dm | 0 .../sprite_accessories/markings/tanlines.dm | 0 .../sprite_accessories/markings/tattoo.dm | 0 .../sprite_accessories/markings/tesh.dm | 0 .../sprite_accessories/markings/unathi.dm | 0 .../sprite_accessories/markings/vox.dm | 0 .../sprite_accessories/markings/vulp.dm | 0 .../sprite_accessories/markings/werebeast.dm | 0 .../sprite_accessories/markings/zorren.dm | 0 .../sprite_accessories.dm | 0 code/modules/tgui/{modal.dm => modal_vr.dm} | 0 code/modules/tgui/modules/communications.dm | 10 +- code/modules/tgui/modules/gyrotron_control.dm | 2 +- code/modules/tgui/modules/rustcore_monitor.dm | 2 +- code/modules/tgui/modules/rustfuel_control.dm | 2 +- code/modules/tgui/states/new_player.dm | 14 + code/modules/unit_tests/human/species.dm | 11 + .../variable_setting_entry.dm | 6 +- .../ventcrawl/ventcrawl_atmospherics.dm | 2 +- code/modules/virus2/admin.dm | 2 +- code/modules/virus2/disease2.dm | 6 +- code/modules/vore/eating/belly_obj_vr.dm | 2 +- code/modules/vore/eating/transforming_vr.dm | 6 +- code/modules/vore/eating/vore_vr.dm | 48 +- code/modules/vore/fluffstuff/custom_items.dm | 6 +- code/modules/xenobio/items/slime_objects.dm | 2 +- config/legacy/config.txt | 2 +- html/changelogs/AutoChangeLog-pr-4491.yml | 4 + maps/submaps/_healpers.dm | 2 +- prototypes/example.yaml | 7 + tgui/.eslintrc.yml | 2 +- tgui/packages/tgui/interfaces/JoinMenu.tsx | 187 ++++++++ .../tgui/interfaces/LanguagePicker.tsx | 123 +++++ .../tgui/interfaces/SpeciesPicker.tsx | 130 ++++++ tools/deploy.sh | 2 + 604 files changed, 9140 insertions(+), 4230 deletions(-) create mode 100644 code/__DEFINES/client/player_flags.dm create mode 100644 code/__DEFINES/controllers/prototypes.dm delete mode 100644 code/__DEFINES/jobs.dm create mode 100644 code/__DEFINES/jobs/availability.dm create mode 100644 code/__DEFINES/jobs/jobs.dm rename code/__DEFINES/languages/{language_flags.dm => flags.dm} (79%) create mode 100644 code/__DEFINES/languages/ids.dm rename code/__DEFINES/{languages.dm => languages/legacy.dm} (96%) create mode 100644 code/__DEFINES/preferences/data_keys_character.dm create mode 100644 code/__DEFINES/preferences/data_keys_global.dm create mode 100644 code/__DEFINES/preferences/jobs.dm create mode 100644 code/__DEFINES/preferences/load_order.dm create mode 100644 code/__DEFINES/preferences/misc.dm create mode 100644 code/__DEFINES/preferences/procs.dm create mode 100644 code/__DEFINES/preferences/savefiles.dm create mode 100644 code/__DEFINES/preferences/topic.dm delete mode 100644 code/__DEFINES/topic.dm create mode 100644 code/__HELPERS/sanitize/datatypes.dm create mode 100644 code/__HELPERS/sanitize/list.dm delete mode 100644 code/_globalvars/lists/client.dm create mode 100644 code/_globalvars/lists/clients.dm create mode 100644 code/_globalvars/lists/mobs.dm delete mode 100644 code/_globalvars/lists/species.dm create mode 100644 code/controllers/configuration/whitelists.dm delete mode 100644 code/controllers/subsystem/character_setup.dm create mode 100644 code/controllers/subsystem/characters/_characters.dm create mode 100644 code/controllers/subsystem/characters/backgrounds.dm create mode 100644 code/controllers/subsystem/characters/character_species.dm create mode 100644 code/controllers/subsystem/characters/languages.dm create mode 100644 code/controllers/subsystem/characters/species.dm rename code/controllers/subsystem/job/{job_controller.dm => _legacy_job_stuff.dm} (66%) create mode 100644 code/controllers/subsystem/job/job_manager.dm create mode 100644 code/controllers/subsystem/job/joining.dm create mode 100644 code/controllers/subsystem/job/roundstart.dm create mode 100644 code/controllers/subsystem/prototypes/_prototypes.dm create mode 100644 code/controllers/subsystem/prototypes/dud.dm create mode 100644 code/controllers/subsystem/prototypes/lore.dm create mode 100644 code/controllers/subsystem/prototypes/prototype.dm create mode 100644 code/modules/client/data.dm create mode 100644 code/modules/client/database.dm delete mode 100644 code/modules/client/preference_setup/_defines.dm delete mode 100644 code/modules/client/preference_setup/general/02_language.dm delete mode 100644 code/modules/client/preference_setup/general/05_background.dm delete mode 100644 code/modules/client/preference_setup/occupation/occupation.dm delete mode 100644 code/modules/client/preference_setup/vore/07_vantag.dm delete mode 100644 code/modules/client/preferences_savefile.dm delete mode 100644 code/modules/jobs/whitelist_vr.dm create mode 100644 code/modules/language/abstract.dm create mode 100644 code/modules/language/animal.dm create mode 100644 code/modules/language/antagonist/borer.dm create mode 100644 code/modules/language/antagonist/changeling.dm create mode 100644 code/modules/language/antagonist/cult.dm create mode 100644 code/modules/language/antagonist/swarmbot.dm create mode 100644 code/modules/language/antagonist/xenomorph.dm create mode 100644 code/modules/language/core.dm create mode 100644 code/modules/language/event.dm create mode 100644 code/modules/language/galactic.dm delete mode 100644 code/modules/language/generic.dm create mode 100644 code/modules/language/holder.dm delete mode 100644 code/modules/language/outsider.dm rename code/modules/language/{synthetic.dm => silicons.dm} (94%) create mode 100644 code/modules/language/species/adherent.dm create mode 100644 code/modules/language/species/akula.dm create mode 100644 code/modules/language/species/alraune.dm create mode 100644 code/modules/language/species/altevian.dm create mode 100644 code/modules/language/species/birdsong.dm create mode 100644 code/modules/language/species/celestial.dm create mode 100644 code/modules/language/species/diona.dm create mode 100644 code/modules/language/species/human.dm create mode 100644 code/modules/language/species/naramadi.dm create mode 100644 code/modules/language/species/phoronoid.dm create mode 100644 code/modules/language/species/shadekin.dm create mode 100644 code/modules/language/species/skrell.dm create mode 100644 code/modules/language/species/tajaran.dm create mode 100644 code/modules/language/species/teshari.dm create mode 100644 code/modules/language/species/unathi.dm create mode 100644 code/modules/language/species/vasilissan.dm create mode 100644 code/modules/language/species/vox.dm create mode 100644 code/modules/language/species/vulpkanin.dm create mode 100644 code/modules/language/species/zaddat.dm create mode 100644 code/modules/language/species/zorren.dm delete mode 100644 code/modules/language/station.dm create mode 100644 code/modules/lore_hardcoded/README.md create mode 100644 code/modules/lore_hardcoded/_hardcoded.dm create mode 100644 code/modules/lore_hardcoded/citizenship.dm create mode 100644 code/modules/lore_hardcoded/faction.dm create mode 100644 code/modules/lore_hardcoded/origin.dm create mode 100644 code/modules/lore_hardcoded/origin/hegemony/SHOVE_THINGS_HERE.dm create mode 100644 code/modules/lore_hardcoded/origin/hegemony/_hegemony.dm create mode 100644 code/modules/lore_hardcoded/origin/hegemony/naramadi.dm create mode 100644 code/modules/lore_hardcoded/origin/hegemony/unathi.dm create mode 100644 code/modules/lore_hardcoded/origin/oricon/_oricon.dm create mode 100644 code/modules/lore_hardcoded/origin/oricon/sol.dm create mode 100644 code/modules/lore_hardcoded/religion.dm create mode 100644 code/modules/mob/new_player/join_menu.dm delete mode 100644 code/modules/mob/new_player/preferences_setup_vr.dm rename code/modules/{client/preferences.dm => preferences/_preferences.dm} (76%) create mode 100644 code/modules/preferences/apply.dm create mode 100644 code/modules/preferences/data.dm create mode 100644 code/modules/preferences/errors.dm create mode 100644 code/modules/preferences/migration.dm rename code/modules/{client => preferences}/preference_setup/antagonism/01_basic.dm (88%) rename code/modules/{client => preferences}/preference_setup/antagonism/02_candidacy.dm (97%) create mode 100644 code/modules/preferences/preference_setup/background/_background.dm create mode 100644 code/modules/preferences/preference_setup/background/citizenship.dm create mode 100644 code/modules/preferences/preference_setup/background/faction.dm create mode 100644 code/modules/preferences/preference_setup/background/language.dm create mode 100644 code/modules/preferences/preference_setup/background/origin.dm create mode 100644 code/modules/preferences/preference_setup/background/religion.dm create mode 100644 code/modules/preferences/preference_setup/background/species.dm rename code/modules/{client => preferences}/preference_setup/general/01_basic.dm (85%) rename code/modules/{client => preferences}/preference_setup/general/03_body.dm (77%) rename code/modules/{client => preferences}/preference_setup/general/04_equipment.dm (93%) create mode 100644 code/modules/preferences/preference_setup/general/05_background.dm rename code/modules/{client => preferences}/preference_setup/general/06_flavor.dm (95%) rename code/modules/{client => preferences}/preference_setup/global/01_ui.dm (86%) rename code/modules/{client => preferences}/preference_setup/global/02_settings.dm (95%) rename code/modules/{client => preferences}/preference_setup/global/03_pai.dm (96%) rename code/modules/{client => preferences}/preference_setup/global/04_ooc.dm (91%) rename code/modules/{client => preferences}/preference_setup/global/05_media.dm (96%) create mode 100644 code/modules/preferences/preference_setup/global/language_prefix.dm rename code/modules/{client => preferences}/preference_setup/global/setting_datums.dm (100%) create mode 100644 code/modules/preferences/preference_setup/helpers/language_pick.dm create mode 100644 code/modules/preferences/preference_setup/helpers/species_pick.dm rename code/modules/{client => preferences}/preference_setup/keybindings/keybindings.dm (92%) rename code/modules/{client => preferences}/preference_setup/loadout/gear_tweaks.dm (100%) rename code/modules/{client => preferences}/preference_setup/loadout/loadout.dm (91%) rename code/modules/{client => preferences}/preference_setup/loadout/loadout_accessories.dm (100%) rename code/modules/{client => preferences}/preference_setup/loadout/loadout_cosmetics.dm (100%) rename code/modules/{client => preferences}/preference_setup/loadout/loadout_donator.dm (100%) rename code/modules/{client => preferences}/preference_setup/loadout/loadout_ears.dm (100%) rename code/modules/{client => preferences}/preference_setup/loadout/loadout_event_rewards.dm (100%) rename code/modules/{client => preferences}/preference_setup/loadout/loadout_eyes.dm (100%) rename code/modules/{client => preferences}/preference_setup/loadout/loadout_general.dm (100%) rename code/modules/{client => preferences}/preference_setup/loadout/loadout_gloves.dm (100%) rename code/modules/{client => preferences}/preference_setup/loadout/loadout_head.dm (100%) rename code/modules/{client => preferences}/preference_setup/loadout/loadout_mask.dm (100%) rename code/modules/{client => preferences}/preference_setup/loadout/loadout_role_restricted.dm (100%) rename code/modules/{client => preferences}/preference_setup/loadout/loadout_seasonal.dm (100%) rename code/modules/{client => preferences}/preference_setup/loadout/loadout_shoes.dm (100%) rename code/modules/{client => preferences}/preference_setup/loadout/loadout_smoking.dm (100%) rename code/modules/{client => preferences}/preference_setup/loadout/loadout_suit.dm (100%) rename code/modules/{client => preferences}/preference_setup/loadout/loadout_uniform.dm (100%) rename code/modules/{client => preferences}/preference_setup/loadout/loadout_utility.dm (100%) rename code/modules/{client => preferences}/preference_setup/loadout/loadout_xeno.dm (99%) create mode 100644 code/modules/preferences/preference_setup/occupation/occupation.dm create mode 100644 code/modules/preferences/preference_setup/preference_category_new.dm create mode 100644 code/modules/preferences/preference_setup/preference_item_new.dm rename code/modules/{client => preferences}/preference_setup/preference_setup.dm (83%) rename code/modules/{client => preferences}/preference_setup/skills/skills.dm (88%) rename code/modules/{client => preferences}/preference_setup/traits/trait_defines.dm (100%) rename code/modules/{client => preferences}/preference_setup/traits/traits.dm (96%) rename code/modules/{client => preferences}/preference_setup/vore/01_ears.dm (93%) rename code/modules/{client => preferences}/preference_setup/vore/02_size.dm (90%) rename code/modules/{client => preferences}/preference_setup/vore/03_egg.dm (81%) rename code/modules/{client => preferences}/preference_setup/vore/04_autohiss.dm (83%) rename code/modules/{client => preferences}/preference_setup/vore/05_resleeving.dm (87%) rename code/modules/{client => preferences}/preference_setup/vore/06_persistence.dm (96%) rename code/modules/{client => preferences}/preference_setup/vore/08_traits.dm (87%) rename code/modules/{client => preferences}/preference_setup/vore/09_nif.dm (71%) rename code/modules/{client => preferences}/preference_setup/vore/10_misc.dm (88%) rename code/modules/{client => preferences}/preferences_factions.dm (100%) create mode 100644 code/modules/preferences/preferences_savefile.dm rename code/modules/{mob/new_player => preferences}/preferences_setup.dm (81%) rename code/modules/{client => preferences}/preferences_spawnpoints.dm (93%) rename code/modules/{client => preferences}/preferences_toggle_procs.dm (92%) create mode 100644 code/modules/preferences/shims.dm create mode 100644 code/modules/preferences/ui.dm create mode 100644 code/modules/species/character_species.dm delete mode 100644 code/modules/species/lookup.dm rename code/modules/species/{station => }/promethean/promethean.dm (96%) rename code/modules/species/{station => }/promethean/promethean_blob.dm (100%) rename code/modules/species/{station => }/protean/protean_blob.dm (100%) rename code/modules/species/{station => }/protean/protean_powers.dm (99%) rename code/modules/species/{station => }/protean/protean_species.dm (97%) rename code/modules/species/{station/station_special.dm => xenochimera/xenochimera.dm} (97%) rename code/modules/{mob/new_player => }/sprite_accessories/body_markings.dm (100%) rename code/modules/{mob/new_player => }/sprite_accessories/facial_hair/facial_hair.dm (100%) rename code/modules/{mob/new_player => }/sprite_accessories/facial_hair/tajaran_facial_hair.dm (100%) rename code/modules/{mob/new_player => }/sprite_accessories/facial_hair/teshari_facial_hair.dm (100%) rename code/modules/{mob/new_player => }/sprite_accessories/facial_hair/unathi_facial_hair.dm (100%) rename code/modules/{mob/new_player => }/sprite_accessories/facial_hair/vox_facial_hair.dm (100%) rename code/modules/{mob/new_player => }/sprite_accessories/facial_hair/vulpakin_facial_hair.dm (100%) rename code/modules/{mob/new_player => }/sprite_accessories/hair/hair.dm (100%) rename code/modules/{mob/new_player => }/sprite_accessories/hair/sergal_hair.dm (100%) rename code/modules/{mob/new_player => }/sprite_accessories/hair/shadekin.dm (100%) rename code/modules/{mob/new_player => }/sprite_accessories/hair/skrell_hair.dm (100%) rename code/modules/{mob/new_player => }/sprite_accessories/hair/tajaran_hair.dm (100%) rename code/modules/{mob/new_player => }/sprite_accessories/hair/teshari_hair.dm (100%) rename code/modules/{mob/new_player => }/sprite_accessories/hair/unathi_hair.dm (100%) rename code/modules/{mob/new_player => }/sprite_accessories/hair/vox_hair.dm (100%) rename code/modules/{mob/new_player => }/sprite_accessories/hair/vulpakin_hair.dm (100%) rename code/modules/{mob/new_player => }/sprite_accessories/hair/xenomorph_hybrid_domes.dm (100%) rename code/modules/{mob/new_player => }/sprite_accessories/markings/diona_stuff.dm (100%) rename code/modules/{mob/new_player => }/sprite_accessories/markings/eye_stuff.dm (100%) rename code/modules/{mob/new_player => }/sprite_accessories/markings/panda.dm (100%) rename code/modules/{mob/new_player => }/sprite_accessories/markings/sergal.dm (100%) rename code/modules/{mob/new_player => }/sprite_accessories/markings/synth_stuff.dm (100%) rename code/modules/{mob/new_player => }/sprite_accessories/markings/taj.dm (100%) rename code/modules/{mob/new_player => }/sprite_accessories/markings/tanlines.dm (100%) rename code/modules/{mob/new_player => }/sprite_accessories/markings/tattoo.dm (100%) rename code/modules/{mob/new_player => }/sprite_accessories/markings/tesh.dm (100%) rename code/modules/{mob/new_player => }/sprite_accessories/markings/unathi.dm (100%) rename code/modules/{mob/new_player => }/sprite_accessories/markings/vox.dm (100%) rename code/modules/{mob/new_player => }/sprite_accessories/markings/vulp.dm (100%) rename code/modules/{mob/new_player => }/sprite_accessories/markings/werebeast.dm (100%) rename code/modules/{mob/new_player => }/sprite_accessories/markings/zorren.dm (100%) rename code/modules/{mob/new_player => sprite_accessories}/sprite_accessories.dm (100%) rename code/modules/tgui/{modal.dm => modal_vr.dm} (100%) create mode 100644 html/changelogs/AutoChangeLog-pr-4491.yml create mode 100644 prototypes/example.yaml create mode 100644 tgui/packages/tgui/interfaces/JoinMenu.tsx create mode 100644 tgui/packages/tgui/interfaces/LanguagePicker.tsx create mode 100644 tgui/packages/tgui/interfaces/SpeciesPicker.tsx diff --git a/SQL/database_schema.sql b/SQL/database_schema.sql index 24afc5dd6de..151b9ce98ea 100644 --- a/SQL/database_schema.sql +++ b/SQL/database_schema.sql @@ -94,10 +94,21 @@ CREATE TABLE IF NOT EXISTS `%_PREFIX_%player_lookup` ( `ip` varchar(18) NOT NULL, `computerid` varchar(32) NOT NULL, `lastadminrank` varchar(32) NOT NULL DEFAULT 'Player', + `playerid` int(11), PRIMARY KEY (`id`), UNIQUE KEY `ckey` (`ckey`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; +--- Primary player table --- +--- Allows for one-to-many player-ckey association. --- +CREATE TABLE IF NOT EXISTS `%_PREFIX_%player` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `flags` int(24) NOT NULL DEFAULT 0, + `firstseen` datetime NOT NULL DEFAULT Now(), + `lastseen` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + CREATE TABLE IF NOT EXISTS `%_PREFIX_%poll_option` ( `id` int(11) NOT NULL AUTO_INCREMENT, `pollid` int(11) NOT NULL, diff --git a/SQL/database_schema_prefixed.sql b/SQL/database_schema_prefixed.sql index f973b7c13c1..8afb1c189c7 100644 --- a/SQL/database_schema_prefixed.sql +++ b/SQL/database_schema_prefixed.sql @@ -94,10 +94,19 @@ CREATE TABLE IF NOT EXISTS `rp_player_lookup` ( `ip` varchar(18) NOT NULL, `computerid` varchar(32) NOT NULL, `lastadminrank` varchar(32) NOT NULL DEFAULT 'Player', + `playerid` int(11), PRIMARY KEY (`id`), UNIQUE KEY `ckey` (`ckey`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; +CREATE TABLE IF NOT EXISTS `rp_player` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `flags` int(24) NOT NULL DEFAULT 0, + `firstseen` datetime NOT NULL DEFAULT Now(), + `lastseen` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + CREATE TABLE IF NOT EXISTS `rp_poll_option` ( `id` int(11) NOT NULL AUTO_INCREMENT, `pollid` int(11) NOT NULL, diff --git a/citadel.dme b/citadel.dme index b2127d8c44c..b9cfbb746b7 100644 --- a/citadel.dme +++ b/citadel.dme @@ -55,8 +55,6 @@ #include "code\__DEFINES\inventory_storage.dm" #include "code\__DEFINES\is_helpers.dm" #include "code\__DEFINES\items_clothing.dm" -#include "code\__DEFINES\jobs.dm" -#include "code\__DEFINES\languages.dm" #include "code\__DEFINES\lighting.dm" #include "code\__DEFINES\logging.dm" #include "code\__DEFINES\machinery.dm" @@ -95,7 +93,6 @@ #include "code\__DEFINES\tgs.dm" #include "code\__DEFINES\tgui.dm" #include "code\__DEFINES\time.dm" -#include "code\__DEFINES\topic.dm" #include "code\__DEFINES\traits.dm" #include "code\__DEFINES\turfs.dm" #include "code\__DEFINES\typeids.dm" @@ -123,6 +120,7 @@ #include "code\__DEFINES\atmospherics\helpers.dm" #include "code\__DEFINES\atmospherics\pipes.dm" #include "code\__DEFINES\cargo\supply.dm" +#include "code\__DEFINES\client\player_flags.dm" #include "code\__DEFINES\color\color.dm" #include "code\__DEFINES\color\colour_priority.dm" #include "code\__DEFINES\color\lum.dm" @@ -176,10 +174,14 @@ #include "code\__DEFINES\items\inducer.dm" #include "code\__DEFINES\items\nifs.dm" #include "code\__DEFINES\items\clothing\uniforms.dm" +#include "code\__DEFINES\jobs\availability.dm" #include "code\__DEFINES\jobs\factions.dm" +#include "code\__DEFINES\jobs\jobs.dm" #include "code\__DEFINES\jobs\join_types.dm" #include "code\__DEFINES\jobs\spawnpoints.dm" -#include "code\__DEFINES\languages\language_flags.dm" +#include "code\__DEFINES\languages\flags.dm" +#include "code\__DEFINES\languages\ids.dm" +#include "code\__DEFINES\languages\legacy.dm" #include "code\__DEFINES\mapping\multiz.dm" #include "code\__DEFINES\misc\message_ranges.dm" #include "code\__DEFINES\mobs\grab.dm" @@ -189,7 +191,15 @@ #include "code\__DEFINES\mobs\organs.dm" #include "code\__DEFINES\mobs\silicon_privileges.dm" #include "code\__DEFINES\power\power.dm" +#include "code\__DEFINES\preferences\data_keys_character.dm" +#include "code\__DEFINES\preferences\data_keys_global.dm" #include "code\__DEFINES\preferences\event_antag.dm" +#include "code\__DEFINES\preferences\jobs.dm" +#include "code\__DEFINES\preferences\load_order.dm" +#include "code\__DEFINES\preferences\misc.dm" +#include "code\__DEFINES\preferences\procs.dm" +#include "code\__DEFINES\preferences\savefiles.dm" +#include "code\__DEFINES\preferences\topic.dm" #include "code\__DEFINES\procs\buckling.dm" #include "code\__DEFINES\procs\clickcode.dm" #include "code\__DEFINES\procs\do_after.dm" @@ -281,6 +291,8 @@ #include "code\__HELPERS\matrices\transform_matrix.dm" #include "code\__HELPERS\misc\sonar.dm" #include "code\__HELPERS\rendering\positioning.dm" +#include "code\__HELPERS\sanitize\datatypes.dm" +#include "code\__HELPERS\sanitize\list.dm" #include "code\__HELPERS\sorts\__main.dm" #include "code\__HELPERS\sorts\comparators.dm" #include "code\__HELPERS\sorts\InsertSort.dm" @@ -308,14 +320,14 @@ #include "code\_globalvars\tgui.dm" #include "code\_globalvars\time_vars.dm" #include "code\_globalvars\traits.dm" -#include "code\_globalvars\lists\client.dm" +#include "code\_globalvars\lists\clients.dm" #include "code\_globalvars\lists\keybindings.dm" #include "code\_globalvars\lists\mapping.dm" #include "code\_globalvars\lists\medical.dm" #include "code\_globalvars\lists\misc.dm" +#include "code\_globalvars\lists\mobs.dm" #include "code\_globalvars\lists\names.dm" #include "code\_globalvars\lists\objects.dm" -#include "code\_globalvars\lists\species.dm" #include "code\_js\byjax.dm" #include "code\_js\menus.dm" #include "code\_onclick\adjacency.dm" @@ -376,6 +388,7 @@ #include "code\controllers\verbs.dm" #include "code\controllers\configuration\config_entry.dm" #include "code\controllers\configuration\configuration.dm" +#include "code\controllers\configuration\whitelists.dm" #include "code\controllers\configuration\entries\bot.dm" #include "code\controllers\configuration\entries\comms.dm" #include "code\controllers\configuration\entries\dbconfig.dm" @@ -398,7 +411,6 @@ #include "code\controllers\subsystem\atoms.dm" #include "code\controllers\subsystem\automata.dm" #include "code\controllers\subsystem\bellies_vr.dm" -#include "code\controllers\subsystem\character_setup.dm" #include "code\controllers\subsystem\chat.dm" #include "code\controllers\subsystem\dcs.dm" #include "code\controllers\subsystem\emergency_shuttle.dm" @@ -442,10 +454,18 @@ #include "code\controllers\subsystem\vis_overlays.dm" #include "code\controllers\subsystem\vote.dm" #include "code\controllers\subsystem\xenoarch.dm" +#include "code\controllers\subsystem\characters\_characters.dm" +#include "code\controllers\subsystem\characters\backgrounds.dm" +#include "code\controllers\subsystem\characters\character_species.dm" +#include "code\controllers\subsystem\characters\languages.dm" +#include "code\controllers\subsystem\characters\species.dm" #include "code\controllers\subsystem\dbcore\_dbcore.dm" #include "code\controllers\subsystem\dbcore\query.dm" #include "code\controllers\subsystem\job\_job.dm" -#include "code\controllers\subsystem\job\job_controller.dm" +#include "code\controllers\subsystem\job\_legacy_job_stuff.dm" +#include "code\controllers\subsystem\job\job_manager.dm" +#include "code\controllers\subsystem\job\joining.dm" +#include "code\controllers\subsystem\job\roundstart.dm" #include "code\controllers\subsystem\job\spawnpoints.dm" #include "code\controllers\subsystem\mapping\_mapping.dm" #include "code\controllers\subsystem\mapping\misc.dm" @@ -1966,66 +1986,14 @@ #include "code\modules\client\client procs_vr.dm" #include "code\modules\client\client_defines.dm" #include "code\modules\client\client_procs.dm" +#include "code\modules\client\data.dm" +#include "code\modules\client\database.dm" #include "code\modules\client\movement.dm" #include "code\modules\client\player_details.dm" -#include "code\modules\client\preferences.dm" -#include "code\modules\client\preferences_factions.dm" -#include "code\modules\client\preferences_savefile.dm" -#include "code\modules\client\preferences_spawnpoints.dm" -#include "code\modules\client\preferences_toggle_procs.dm" #include "code\modules\client\spam_prevention.dm" #include "code\modules\client\ui_style.dm" #include "code\modules\client\viewport.dm" #include "code\modules\client\winset_wrappers.dm" -#include "code\modules\client\preference_setup\_defines.dm" -#include "code\modules\client\preference_setup\preference_setup.dm" -#include "code\modules\client\preference_setup\antagonism\01_basic.dm" -#include "code\modules\client\preference_setup\antagonism\02_candidacy.dm" -#include "code\modules\client\preference_setup\general\01_basic.dm" -#include "code\modules\client\preference_setup\general\02_language.dm" -#include "code\modules\client\preference_setup\general\03_body.dm" -#include "code\modules\client\preference_setup\general\04_equipment.dm" -#include "code\modules\client\preference_setup\general\05_background.dm" -#include "code\modules\client\preference_setup\general\06_flavor.dm" -#include "code\modules\client\preference_setup\global\01_ui.dm" -#include "code\modules\client\preference_setup\global\02_settings.dm" -#include "code\modules\client\preference_setup\global\03_pai.dm" -#include "code\modules\client\preference_setup\global\04_ooc.dm" -#include "code\modules\client\preference_setup\global\05_media.dm" -#include "code\modules\client\preference_setup\global\setting_datums.dm" -#include "code\modules\client\preference_setup\keybindings\keybindings.dm" -#include "code\modules\client\preference_setup\loadout\gear_tweaks.dm" -#include "code\modules\client\preference_setup\loadout\loadout.dm" -#include "code\modules\client\preference_setup\loadout\loadout_accessories.dm" -#include "code\modules\client\preference_setup\loadout\loadout_cosmetics.dm" -#include "code\modules\client\preference_setup\loadout\loadout_donator.dm" -#include "code\modules\client\preference_setup\loadout\loadout_ears.dm" -#include "code\modules\client\preference_setup\loadout\loadout_event_rewards.dm" -#include "code\modules\client\preference_setup\loadout\loadout_eyes.dm" -#include "code\modules\client\preference_setup\loadout\loadout_general.dm" -#include "code\modules\client\preference_setup\loadout\loadout_gloves.dm" -#include "code\modules\client\preference_setup\loadout\loadout_head.dm" -#include "code\modules\client\preference_setup\loadout\loadout_mask.dm" -#include "code\modules\client\preference_setup\loadout\loadout_role_restricted.dm" -#include "code\modules\client\preference_setup\loadout\loadout_seasonal.dm" -#include "code\modules\client\preference_setup\loadout\loadout_shoes.dm" -#include "code\modules\client\preference_setup\loadout\loadout_smoking.dm" -#include "code\modules\client\preference_setup\loadout\loadout_suit.dm" -#include "code\modules\client\preference_setup\loadout\loadout_uniform.dm" -#include "code\modules\client\preference_setup\loadout\loadout_utility.dm" -#include "code\modules\client\preference_setup\loadout\loadout_xeno.dm" -#include "code\modules\client\preference_setup\occupation\occupation.dm" -#include "code\modules\client\preference_setup\skills\skills.dm" -#include "code\modules\client\preference_setup\vore\01_ears.dm" -#include "code\modules\client\preference_setup\vore\02_size.dm" -#include "code\modules\client\preference_setup\vore\03_egg.dm" -#include "code\modules\client\preference_setup\vore\04_autohiss.dm" -#include "code\modules\client\preference_setup\vore\05_resleeving.dm" -#include "code\modules\client\preference_setup\vore\06_persistence.dm" -#include "code\modules\client\preference_setup\vore\07_vantag.dm" -#include "code\modules\client\preference_setup\vore\08_traits.dm" -#include "code\modules\client\preference_setup\vore\09_nif.dm" -#include "code\modules\client\preference_setup\vore\10_misc.dm" #include "code\modules\client\verbs\minimap.dm" #include "code\modules\client\verbs\ooc.dm" #include "code\modules\client\verbs\panic_bunker_player.dm" @@ -2469,7 +2437,6 @@ #include "code\modules\jobs\jobs.dm" #include "code\modules\jobs\outfit.dm" #include "code\modules\jobs\whitelist.dm" -#include "code\modules\jobs\whitelist_vr.dm" #include "code\modules\jobs\departments\cargo.dm" #include "code\modules\jobs\departments\centcom.dm" #include "code\modules\jobs\departments\civillian.dm" @@ -2555,14 +2522,42 @@ #include "code\modules\keybindings\keybind\mob.dm" #include "code\modules\keybindings\keybind\movement.dm" #include "code\modules\keybindings\keybind\robot.dm" -#include "code\modules\language\generic.dm" +#include "code\modules\language\abstract.dm" +#include "code\modules\language\animal.dm" +#include "code\modules\language\core.dm" +#include "code\modules\language\event.dm" +#include "code\modules\language\galactic.dm" +#include "code\modules\language\holder.dm" #include "code\modules\language\language.dm" #include "code\modules\language\monkey.dm" -#include "code\modules\language\outsider.dm" -#include "code\modules\language\station.dm" -#include "code\modules\language\synthetic.dm" +#include "code\modules\language\silicons.dm" +#include "code\modules\language\antagonist\borer.dm" +#include "code\modules\language\antagonist\changeling.dm" +#include "code\modules\language\antagonist\cult.dm" +#include "code\modules\language\antagonist\swarmbot.dm" +#include "code\modules\language\antagonist\xenomorph.dm" #include "code\modules\language\species\_species.dm" +#include "code\modules\language\species\adherent.dm" +#include "code\modules\language\species\akula.dm" +#include "code\modules\language\species\alraune.dm" +#include "code\modules\language\species\altevian.dm" +#include "code\modules\language\species\birdsong.dm" +#include "code\modules\language\species\celestial.dm" +#include "code\modules\language\species\diona.dm" +#include "code\modules\language\species\human.dm" #include "code\modules\language\species\moth.dm" +#include "code\modules\language\species\naramadi.dm" +#include "code\modules\language\species\phoronoid.dm" +#include "code\modules\language\species\shadekin.dm" +#include "code\modules\language\species\skrell.dm" +#include "code\modules\language\species\tajaran.dm" +#include "code\modules\language\species\teshari.dm" +#include "code\modules\language\species\unathi.dm" +#include "code\modules\language\species\vasilissan.dm" +#include "code\modules\language\species\vox.dm" +#include "code\modules\language\species\vulpkanin.dm" +#include "code\modules\language\species\zaddat.dm" +#include "code\modules\language\species\zorren.dm" #include "code\modules\library\lib_items.dm" #include "code\modules\library\lib_machines.dm" #include "code\modules\library\lib_readme.dm" @@ -2590,6 +2585,17 @@ #include "code\modules\lore_codex\robutt_data\bybrand.dm" #include "code\modules\lore_codex\robutt_data\main_robutts.dm" #include "code\modules\lore_codex\robutt_data\more.dm" +#include "code\modules\lore_hardcoded\_hardcoded.dm" +#include "code\modules\lore_hardcoded\citizenship.dm" +#include "code\modules\lore_hardcoded\faction.dm" +#include "code\modules\lore_hardcoded\origin.dm" +#include "code\modules\lore_hardcoded\religion.dm" +#include "code\modules\lore_hardcoded\origin\hegemony\_hegemony.dm" +#include "code\modules\lore_hardcoded\origin\hegemony\naramadi.dm" +#include "code\modules\lore_hardcoded\origin\hegemony\SHOVE_THINGS_HERE.dm" +#include "code\modules\lore_hardcoded\origin\hegemony\unathi.dm" +#include "code\modules\lore_hardcoded\origin\oricon\_oricon.dm" +#include "code\modules\lore_hardcoded\origin\oricon\sol.dm" #include "code\modules\mapping\map_config.dm" #include "code\modules\mapping\map_orientation_patterns.dm" #include "code\modules\mapping\minimaps.dm" @@ -3172,45 +3178,12 @@ #include "code\modules\mob\living\simple_mob\subtypes\vore\shadekin\shadekin.dm" #include "code\modules\mob\living\simple_mob\subtypes\vore\shadekin\types.dm" #include "code\modules\mob\living\voice\voice.dm" +#include "code\modules\mob\new_player\join_menu.dm" #include "code\modules\mob\new_player\login.dm" #include "code\modules\mob\new_player\logout.dm" #include "code\modules\mob\new_player\new_player.dm" #include "code\modules\mob\new_player\poll.dm" -#include "code\modules\mob\new_player\preferences_setup.dm" -#include "code\modules\mob\new_player\preferences_setup_vr.dm" #include "code\modules\mob\new_player\skill.dm" -#include "code\modules\mob\new_player\sprite_accessories.dm" -#include "code\modules\mob\new_player\sprite_accessories\body_markings.dm" -#include "code\modules\mob\new_player\sprite_accessories\facial_hair\facial_hair.dm" -#include "code\modules\mob\new_player\sprite_accessories\facial_hair\tajaran_facial_hair.dm" -#include "code\modules\mob\new_player\sprite_accessories\facial_hair\teshari_facial_hair.dm" -#include "code\modules\mob\new_player\sprite_accessories\facial_hair\unathi_facial_hair.dm" -#include "code\modules\mob\new_player\sprite_accessories\facial_hair\vox_facial_hair.dm" -#include "code\modules\mob\new_player\sprite_accessories\facial_hair\vulpakin_facial_hair.dm" -#include "code\modules\mob\new_player\sprite_accessories\hair\hair.dm" -#include "code\modules\mob\new_player\sprite_accessories\hair\sergal_hair.dm" -#include "code\modules\mob\new_player\sprite_accessories\hair\shadekin.dm" -#include "code\modules\mob\new_player\sprite_accessories\hair\skrell_hair.dm" -#include "code\modules\mob\new_player\sprite_accessories\hair\tajaran_hair.dm" -#include "code\modules\mob\new_player\sprite_accessories\hair\teshari_hair.dm" -#include "code\modules\mob\new_player\sprite_accessories\hair\unathi_hair.dm" -#include "code\modules\mob\new_player\sprite_accessories\hair\vox_hair.dm" -#include "code\modules\mob\new_player\sprite_accessories\hair\vulpakin_hair.dm" -#include "code\modules\mob\new_player\sprite_accessories\hair\xenomorph_hybrid_domes.dm" -#include "code\modules\mob\new_player\sprite_accessories\markings\diona_stuff.dm" -#include "code\modules\mob\new_player\sprite_accessories\markings\eye_stuff.dm" -#include "code\modules\mob\new_player\sprite_accessories\markings\panda.dm" -#include "code\modules\mob\new_player\sprite_accessories\markings\sergal.dm" -#include "code\modules\mob\new_player\sprite_accessories\markings\synth_stuff.dm" -#include "code\modules\mob\new_player\sprite_accessories\markings\taj.dm" -#include "code\modules\mob\new_player\sprite_accessories\markings\tanlines.dm" -#include "code\modules\mob\new_player\sprite_accessories\markings\tattoo.dm" -#include "code\modules\mob\new_player\sprite_accessories\markings\tesh.dm" -#include "code\modules\mob\new_player\sprite_accessories\markings\unathi.dm" -#include "code\modules\mob\new_player\sprite_accessories\markings\vox.dm" -#include "code\modules\mob\new_player\sprite_accessories\markings\vulp.dm" -#include "code\modules\mob\new_player\sprite_accessories\markings\werebeast.dm" -#include "code\modules\mob\new_player\sprite_accessories\markings\zorren.dm" #include "code\modules\modular_computers\laptop_vendor.dm" #include "code\modules\modular_computers\computers\modular_computer\core.dm" #include "code\modules\modular_computers\computers\modular_computer\damage.dm" @@ -3515,6 +3488,76 @@ #include "code\modules\power\tesla\generator.dm" #include "code\modules\power\tesla\telsa_construction.dm" #include "code\modules\power\tesla\tesla_act.dm" +#include "code\modules\preferences\_preferences.dm" +#include "code\modules\preferences\apply.dm" +#include "code\modules\preferences\data.dm" +#include "code\modules\preferences\errors.dm" +#include "code\modules\preferences\migration.dm" +#include "code\modules\preferences\preferences_factions.dm" +#include "code\modules\preferences\preferences_savefile.dm" +#include "code\modules\preferences\preferences_setup.dm" +#include "code\modules\preferences\preferences_spawnpoints.dm" +#include "code\modules\preferences\preferences_toggle_procs.dm" +#include "code\modules\preferences\shims.dm" +#include "code\modules\preferences\ui.dm" +#include "code\modules\preferences\preference_setup\preference_category_new.dm" +#include "code\modules\preferences\preference_setup\preference_item_new.dm" +#include "code\modules\preferences\preference_setup\preference_setup.dm" +#include "code\modules\preferences\preference_setup\antagonism\01_basic.dm" +#include "code\modules\preferences\preference_setup\antagonism\02_candidacy.dm" +#include "code\modules\preferences\preference_setup\background\_background.dm" +#include "code\modules\preferences\preference_setup\background\citizenship.dm" +#include "code\modules\preferences\preference_setup\background\faction.dm" +#include "code\modules\preferences\preference_setup\background\language.dm" +#include "code\modules\preferences\preference_setup\background\origin.dm" +#include "code\modules\preferences\preference_setup\background\religion.dm" +#include "code\modules\preferences\preference_setup\background\species.dm" +#include "code\modules\preferences\preference_setup\general\01_basic.dm" +#include "code\modules\preferences\preference_setup\general\03_body.dm" +#include "code\modules\preferences\preference_setup\general\04_equipment.dm" +#include "code\modules\preferences\preference_setup\general\05_background.dm" +#include "code\modules\preferences\preference_setup\general\06_flavor.dm" +#include "code\modules\preferences\preference_setup\global\01_ui.dm" +#include "code\modules\preferences\preference_setup\global\02_settings.dm" +#include "code\modules\preferences\preference_setup\global\03_pai.dm" +#include "code\modules\preferences\preference_setup\global\04_ooc.dm" +#include "code\modules\preferences\preference_setup\global\05_media.dm" +#include "code\modules\preferences\preference_setup\global\language_prefix.dm" +#include "code\modules\preferences\preference_setup\global\setting_datums.dm" +#include "code\modules\preferences\preference_setup\helpers\language_pick.dm" +#include "code\modules\preferences\preference_setup\helpers\species_pick.dm" +#include "code\modules\preferences\preference_setup\keybindings\keybindings.dm" +#include "code\modules\preferences\preference_setup\loadout\gear_tweaks.dm" +#include "code\modules\preferences\preference_setup\loadout\loadout.dm" +#include "code\modules\preferences\preference_setup\loadout\loadout_accessories.dm" +#include "code\modules\preferences\preference_setup\loadout\loadout_cosmetics.dm" +#include "code\modules\preferences\preference_setup\loadout\loadout_donator.dm" +#include "code\modules\preferences\preference_setup\loadout\loadout_ears.dm" +#include "code\modules\preferences\preference_setup\loadout\loadout_event_rewards.dm" +#include "code\modules\preferences\preference_setup\loadout\loadout_eyes.dm" +#include "code\modules\preferences\preference_setup\loadout\loadout_general.dm" +#include "code\modules\preferences\preference_setup\loadout\loadout_gloves.dm" +#include "code\modules\preferences\preference_setup\loadout\loadout_head.dm" +#include "code\modules\preferences\preference_setup\loadout\loadout_mask.dm" +#include "code\modules\preferences\preference_setup\loadout\loadout_role_restricted.dm" +#include "code\modules\preferences\preference_setup\loadout\loadout_seasonal.dm" +#include "code\modules\preferences\preference_setup\loadout\loadout_shoes.dm" +#include "code\modules\preferences\preference_setup\loadout\loadout_smoking.dm" +#include "code\modules\preferences\preference_setup\loadout\loadout_suit.dm" +#include "code\modules\preferences\preference_setup\loadout\loadout_uniform.dm" +#include "code\modules\preferences\preference_setup\loadout\loadout_utility.dm" +#include "code\modules\preferences\preference_setup\loadout\loadout_xeno.dm" +#include "code\modules\preferences\preference_setup\occupation\occupation.dm" +#include "code\modules\preferences\preference_setup\skills\skills.dm" +#include "code\modules\preferences\preference_setup\vore\01_ears.dm" +#include "code\modules\preferences\preference_setup\vore\02_size.dm" +#include "code\modules\preferences\preference_setup\vore\03_egg.dm" +#include "code\modules\preferences\preference_setup\vore\04_autohiss.dm" +#include "code\modules\preferences\preference_setup\vore\05_resleeving.dm" +#include "code\modules\preferences\preference_setup\vore\06_persistence.dm" +#include "code\modules\preferences\preference_setup\vore\08_traits.dm" +#include "code\modules\preferences\preference_setup\vore\09_nif.dm" +#include "code\modules\preferences\preference_setup\vore\10_misc.dm" #include "code\modules\projectiles\ammunition.dm" #include "code\modules\projectiles\dnalocking.dm" #include "code\modules\projectiles\gun.dm" @@ -3791,7 +3834,7 @@ #include "code\modules\shuttles\shuttles_vr.dm" #include "code\modules\shuttles\shuttles_web.dm" #include "code\modules\shuttles\web_datums.dm" -#include "code\modules\species\lookup.dm" +#include "code\modules\species\character_species.dm" #include "code\modules\species\species.dm" #include "code\modules\species\species_attack.dm" #include "code\modules\species\species_getters.dm" @@ -3804,12 +3847,17 @@ #include "code\modules\species\outsider\shadow.dm" #include "code\modules\species\outsider\skeleton.dm" #include "code\modules\species\outsider\vox.dm" +#include "code\modules\species\promethean\promethean.dm" +#include "code\modules\species\promethean\promethean_blob.dm" +#include "code\modules\species\protean\protean_blob.dm" +#include "code\modules\species\protean\protean_powers.dm" +#include "code\modules\species\protean\protean_species.dm" +#include "code\modules\species\shadekin\crew_shadekin_abilities.dm" +#include "code\modules\species\shadekin\crew_shadekin_hud.dm" #include "code\modules\species\shadekin\shadekin.dm" #include "code\modules\species\shadekin\shadekin_abilities.dm" -#include "code\modules\species\shadekin\crew_shadekin_abilities.dm" #include "code\modules\species\shadekin\shadekin_blackeyed.dm" #include "code\modules\species\shadekin\shadekin_hud.dm" -#include "code\modules\species\shadekin\crew_shadekin_hud.dm" #include "code\modules\species\shadekin\shadekin_traits.dm" #include "code\modules\species\station\adherent.dm" #include "code\modules\species\station\alraune.dm" @@ -3820,15 +3868,9 @@ #include "code\modules\species\station\monkey.dm" #include "code\modules\species\station\phoronoids.dm" #include "code\modules\species\station\rapala.dm" -#include "code\modules\species\station\station_special.dm" #include "code\modules\species\station\station_special_abilities.dm" #include "code\modules\species\station\vasilissan.dm" #include "code\modules\species\station\werebeast.dm" -#include "code\modules\species\station\promethean\promethean.dm" -#include "code\modules\species\station\promethean\promethean_blob.dm" -#include "code\modules\species\station\protean\protean_blob.dm" -#include "code\modules\species\station\protean\protean_powers.dm" -#include "code\modules\species\station\protean\protean_species.dm" #include "code\modules\species\station\standard\akula.dm" #include "code\modules\species\station\standard\human.dm" #include "code\modules\species\station\standard\human_subspecies.dm" @@ -3847,6 +3889,7 @@ #include "code\modules\species\station\xenomorph_hybrids\xeno_hybrids.dm" #include "code\modules\species\virtual_reality\avatar.dm" #include "code\modules\species\virtual_reality\opaque_form.dm" +#include "code\modules\species\xenochimera\xenochimera.dm" #include "code\modules\species\xenomorphs\alien_embryo.dm" #include "code\modules\species\xenomorphs\alien_facehugger.dm" #include "code\modules\species\xenomorphs\alien_powers.dm" @@ -3885,6 +3928,38 @@ #include "code\modules\spells\targeted\projectile\fireball.dm" #include "code\modules\spells\targeted\projectile\magic_missile.dm" #include "code\modules\spells\targeted\projectile\projectile.dm" +#include "code\modules\sprite_accessories\body_markings.dm" +#include "code\modules\sprite_accessories\sprite_accessories.dm" +#include "code\modules\sprite_accessories\facial_hair\facial_hair.dm" +#include "code\modules\sprite_accessories\facial_hair\tajaran_facial_hair.dm" +#include "code\modules\sprite_accessories\facial_hair\teshari_facial_hair.dm" +#include "code\modules\sprite_accessories\facial_hair\unathi_facial_hair.dm" +#include "code\modules\sprite_accessories\facial_hair\vox_facial_hair.dm" +#include "code\modules\sprite_accessories\facial_hair\vulpakin_facial_hair.dm" +#include "code\modules\sprite_accessories\hair\hair.dm" +#include "code\modules\sprite_accessories\hair\sergal_hair.dm" +#include "code\modules\sprite_accessories\hair\shadekin.dm" +#include "code\modules\sprite_accessories\hair\skrell_hair.dm" +#include "code\modules\sprite_accessories\hair\tajaran_hair.dm" +#include "code\modules\sprite_accessories\hair\teshari_hair.dm" +#include "code\modules\sprite_accessories\hair\unathi_hair.dm" +#include "code\modules\sprite_accessories\hair\vox_hair.dm" +#include "code\modules\sprite_accessories\hair\vulpakin_hair.dm" +#include "code\modules\sprite_accessories\hair\xenomorph_hybrid_domes.dm" +#include "code\modules\sprite_accessories\markings\diona_stuff.dm" +#include "code\modules\sprite_accessories\markings\eye_stuff.dm" +#include "code\modules\sprite_accessories\markings\panda.dm" +#include "code\modules\sprite_accessories\markings\sergal.dm" +#include "code\modules\sprite_accessories\markings\synth_stuff.dm" +#include "code\modules\sprite_accessories\markings\taj.dm" +#include "code\modules\sprite_accessories\markings\tanlines.dm" +#include "code\modules\sprite_accessories\markings\tattoo.dm" +#include "code\modules\sprite_accessories\markings\tesh.dm" +#include "code\modules\sprite_accessories\markings\unathi.dm" +#include "code\modules\sprite_accessories\markings\vox.dm" +#include "code\modules\sprite_accessories\markings\vulp.dm" +#include "code\modules\sprite_accessories\markings\werebeast.dm" +#include "code\modules\sprite_accessories\markings\zorren.dm" #include "code\modules\stockmarket\articles.dm" #include "code\modules\stockmarket\computer.dm" #include "code\modules\stockmarket\events.dm" @@ -3926,7 +4001,7 @@ #include "code\modules\tgchat\to_chat.dm" #include "code\modules\tgs\includes.dm" #include "code\modules\tgui\external.dm" -#include "code\modules\tgui\modal.dm" +#include "code\modules\tgui\modal_vr.dm" #include "code\modules\tgui\states.dm" #include "code\modules\tgui\status_composers.dm" #include "code\modules\tgui\tgui.dm" diff --git a/code/__DEFINES/client/player_flags.dm b/code/__DEFINES/client/player_flags.dm new file mode 100644 index 00000000000..e3b045658a0 --- /dev/null +++ b/code/__DEFINES/client/player_flags.dm @@ -0,0 +1,7 @@ +//! player flags +/// exempt from any job timelock system +#define PLAYER_FLAG_JEXP_EXEMPT (1<<0) + +DEFINE_BITFIELD(player_flags, list( + BITFIELD(PLAYER_FLAG_JEXP_EXEMPT), +)) diff --git a/code/__DEFINES/controllers/_subsystems.dm b/code/__DEFINES/controllers/_subsystems.dm index e0d006a6c70..f8574de92f8 100644 --- a/code/__DEFINES/controllers/_subsystems.dm +++ b/code/__DEFINES/controllers/_subsystems.dm @@ -69,11 +69,13 @@ DEFINE_BITFIELD(runlevels, list( // Subsystems shutdown in the reverse of the order they initialize in // The numbers just define the ordering, they are meaningless otherwise. +#define INIT_ORDER_PROTOTYPES 103 #define INIT_ORDER_FAIL2TOPIC 102 #define INIT_ORDER_DBCORE 101 #define INIT_ORDER_INPUT 100 +#define INIT_ORDER_JOBS 99 +#define INIT_ORDER_CHARACTERS 98 #define INIT_ORDER_SOUNDS 95 -#define INIT_ORDER_JOBS 85 #define INIT_ORDER_VIS 80 #define INIT_ORDER_GARBAGE 70 #define INIT_ORDER_SERVER_MAINT 65 diff --git a/code/__DEFINES/controllers/prototypes.dm b/code/__DEFINES/controllers/prototypes.dm new file mode 100644 index 00000000000..1075e03a048 --- /dev/null +++ b/code/__DEFINES/controllers/prototypes.dm @@ -0,0 +1,5 @@ +//! types +/// dud for testing +#define YAML_PROTOTYPE_DUD "Dud" +/// lore datums +#define YAML_PROTOTYPE_LORE "Lore" diff --git a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_attack.dm b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_attack.dm index 4b16bf73a0a..b6c53a05768 100644 --- a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_attack.dm +++ b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_attack.dm @@ -35,7 +35,7 @@ ////#define COMPONENT_CANCEL_ATTACK_CHAIN (1<<0) ///? Skips the specific attack step, continuing for the next one to happen. ////#define COMPONENT_SKIP_ATTACK (1<<1) -/// From base of atom/attack_ghost(): (mob/dead/observer/ghost) +/// From base of atom/attack_ghost(): (mob/observer/dead/ghost) #define COMSIG_ATOM_ATTACK_GHOST "atom_attack_ghost" /// From base of atom/attack_hand(): (mob/user, list/modifiers) ////#define COMSIG_ATOM_ATTACK_HAND "atom_attack_hand" diff --git a/code/__DEFINES/jobs.dm b/code/__DEFINES/jobs.dm deleted file mode 100644 index 25148c2ce7e..00000000000 --- a/code/__DEFINES/jobs.dm +++ /dev/null @@ -1,3 +0,0 @@ -#define GET_RANDOM_JOB 0 -#define BE_ASSISTANT 1 -#define RETURN_TO_LOBBY 2 diff --git a/code/__DEFINES/jobs/availability.dm b/code/__DEFINES/jobs/availability.dm new file mode 100644 index 00000000000..9f61f9728c1 --- /dev/null +++ b/code/__DEFINES/jobs/availability.dm @@ -0,0 +1,24 @@ +//! bitfield! technically usable for ghostroles/anything else too +/// role is available +#define ROLE_AVAILABLE (NONE) +/// slots filled right now +#define ROLE_UNAVAILABLE_SLOTS_FULL (1<<0) +/// player is banned +#define ROLE_UNAVAILABLE_BANNED (1<<1) +/// player doesn't have enough hours in relevant departments/jobs/roles +#define ROLE_UNAVAILABLE_ROLE_TIME (1<<2) +/// player is too new in days since first connect +#define ROLE_UNAVAILABLE_CONNECT_TIME (1<<3) +/// player needs more paid time off (PTO) hours +#define ROLE_UNAVAILABLE_PTO (1<<4) +/// player isn't whitelisted +#define ROLE_UNAVAILABLE_WHITELIST (1<<5) +/// character issue; age, faction, etc +#define ROLE_UNAVAILABLE_CHAR_AGE (1<<6) +/// character is of wrong faction +#define ROLE_UNAVAILABLE_CHAR_FACTION (1<<7) +/// character is of wrong species +#define ROLE_UNAVAILABLE_CHAR_SPECIES (1<<8) + +//? fields irrelevant to preferences +#define ROLE_UNAVAILABILITY_EPHEMERAL (ROLE_UNAVAILABLE_SLOTS_FULL | ROLE_UNAVAILABLE_PTO) diff --git a/code/__DEFINES/jobs/jobs.dm b/code/__DEFINES/jobs/jobs.dm new file mode 100644 index 00000000000..508c5187be9 --- /dev/null +++ b/code/__DEFINES/jobs/jobs.dm @@ -0,0 +1,64 @@ +#define JOB_ID_CAPTAIN "captain" +#define JOB_ID_COMMAND_SECRETARY "command_secretary" + +#define JOB_ID_QUARTERMASTER "quartermaster" +#define JOB_ID_CARGO_TECHNICIAN "cargo_technician" +#define JOB_ID_SHAFT_MINER "shaft_miner" + +#define JOB_ID_RESEARCH_DIRECTOR "research_director" +#define JOB_ID_SENIOR_RESEARCHER "senior_researcher" +#define JOB_ID_SCIENTIST "scientist" +#define JOB_ID_ROBOTICIST "roboticist" + +#define JOB_ID_PATHFINDER "pathfinder" +#define JOB_ID_EXPLORER "explorer" +#define JOB_ID_FIELD_MEDIC "field_medic" + +#define JOB_ID_CHIEF_ENGINEER "chief_engineer" +#define JOB_ID_SENIOR_ENGINEER "senior_engineer" +#define JOB_ID_STATION_ENGINEER "station_engineer" +#define JOB_ID_ATMOSPHERIC_TECHNICIAN "atmospheric_technician" + +#define JOB_ID_CHIEF_MEDICAL_OFFICER "chief_medical_officer" +#define JOB_ID_HEAD_NURSE "head_nurse" +#define JOB_ID_MEDICAL_DOCTOR "medical_doctor" +#define JOB_ID_PARAMEDIC "paramedic" +#define JOB_ID_CHEMIST "chemist" +#define JOB_ID_PSYCHIATRIST "psychiatrist" + +#define JOB_ID_HEAD_OF_SECURITY "head_of_security" +#define JOB_ID_SECURITY_OFFICER "security_officer" +#define JOB_ID_WARDEN "warden" +#define JOB_ID_DETECTIVE "detective" + +#define JOB_ID_HEAD_OF_PERSONNEL "head_of_personnel" +#define JOB_ID_PILOT "pilot" +#define JOB_ID_BARTENDER "bartender" +#define JOB_ID_BOTANIST "botanist" +#define JOB_ID_CHEF "chef" +#define JOB_ID_JANITOR "janitor" +#define JOB_ID_ENTERTAINER "entertainer" +#define JOB_ID_CHAPLAIN "chaplain" +#define JOB_ID_LIBRARIAN "librarian" +#define JOB_ID_LAWYER "lawyer" // IAA +#define JOB_ID_ASSISTANT "assistant" + +#define JOB_ID_CLOWN "clown" +#define JOB_ID_MIME "mime" + +#define JOB_ID_AI "ai" +#define JOB_ID_CYBORG "cyborg" + +#define JOB_ID_CENTCOM_OFFICER "centcom_officer" +#define JOB_ID_EMERGENCY_RESPONDER "emergency_responder" + +#define JOB_ID_OFFDUTY_CIVILLIAN "offduty_civillian" +#define JOB_ID_OFFDUTY_EXPLORER "offduty_explorer" +#define JOB_ID_OFFDUTY_MEDBAY "offduty_medbay" +#define JOB_ID_OFFDUTY_CARGO "offduty_cargo" +#define JOB_ID_OFFDUTY_SECURITY "offduty_security" +#define JOB_ID_OFFDUTY_ENGINEER "offduty_engineer" +#define JOB_ID_OFFDUTY_COMMAND "offduty_command" +#define JOB_ID_OFFDUTY_SCIENCE "offduty_science" + +#define JOB_ID_TRADER "trader" diff --git a/code/__DEFINES/languages/language_flags.dm b/code/__DEFINES/languages/flags.dm similarity index 79% rename from code/__DEFINES/languages/language_flags.dm rename to code/__DEFINES/languages/flags.dm index 241172a6f3c..479abaad645 100644 --- a/code/__DEFINES/languages/language_flags.dm +++ b/code/__DEFINES/languages/flags.dm @@ -19,3 +19,16 @@ #define NO_STUTTER (1<<8) /// Language is not based on vision or sound. //Todo: Add this into the say code and use it for the rootspeak languages. #define ALT_TRANSMIT (1<<9) + +DEFINE_BITFIELD(language_flags, list( + BITFIELD(WHITELISTED), + BITFIELD(RESTRICTED), + BITFIELD(NONVERBAL), + BITFIELD(SIGNLANG), + BITFIELD(HIVEMIND), + BITFIELD(NONGLOBAL), + BITFIELD(INNATE), + BITFIELD(NO_TALK_MSG), + BITFIELD(NO_STUTTER), + BITFIELD(ALT_TRANSMIT), +)) diff --git a/code/__DEFINES/languages/ids.dm b/code/__DEFINES/languages/ids.dm new file mode 100644 index 00000000000..409219386cb --- /dev/null +++ b/code/__DEFINES/languages/ids.dm @@ -0,0 +1,115 @@ +//! Language IDs +//? Core +/// everyone-general +#define LANGUAGE_ID_COMMON "common" +/// signlang-general +#define LANGUAGE_ID_SIGN "sign" +/// synthetics-general +#define LANGUAGE_ID_EAL "eal" + +//? Foreign +#define LANGUAGE_ID_TRADEBAND "tradeband" +#define LANGUAGE_ID_GUTTER "gutter" + +//? Silicons +#define LANGUAGE_ID_SILICON_BINARY "binary_silicons" +#define LANGUAGE_ID_DRONE_BINARY "binary_drones" + +//? Species +/// adherent +#define LANGUAGE_ID_ADHERENT "adherent" +/// akula +#define LANGUAGE_ID_AKULA "akula" +/// altevians +#define LANGUAGE_ID_ALTEVIAN "altevian" +/// ???????? +#define LANGUAGE_ID_BIRDSONG "birdsong" +/// aurils +#define LANGUAGE_ID_DAEDAL_AURIL "auril" +/// dremachirs +#define LANGUAGE_ID_DAEDAL_DREMACHIR "dremachir" +/// diona +#define LANGUAGE_ID_DIONA "diona" +/// diona global +#define LANGUAGE_ID_DIONA_HIVEMIND "diona_global" +/// human +#define LANGUAGE_ID_HUMAN "human" +/// human v2 +#define LANGUAGE_ID_HUMAN_SLAVIC "human_slavic" +/// moth +#define LANGUAGE_ID_LUINIMMA "luinimma" +/// naramadi +#define LANGUAGE_ID_NARAMADI "naramadi" +/// phoronoids +#define LANGUAGE_ID_PHORONOID "phoronoid" +/// shadekin +#define LANGUAGE_ID_SHADEKIN_HIVEMIND "shadekin_global" +/// skrell +#define LANGUAGE_ID_SKRELL "skrell" +/// skrell v2 +#define LANGUAGE_ID_SKRELL_ALT "skrell_alt" +/// tajaran +#define LANGUAGE_ID_TAJARAN "tajaran" +/// tajaran but better (?) +#define LANGUAGE_ID_TAJARAN_ALT "tajaran_alt" +/// tajaran but sign +#define LANGUAGE_ID_TAJARAN_SIGN "tajaran_sign" +/// zorren +#define LANGUAGE_ID_TERMINUS "terminus" +/// teshari +#define LANGUAGE_ID_TESHARI "teshari" +/// unathi +#define LANGUAGE_ID_UNATHI "unathi" +/// alraune +#define LANGUAGE_ID_VERNAL "vernal" +/// vasilissan +#define LANGUAGE_ID_VASILISSAN "vasilissan" +/// vox +#define LANGUAGE_ID_VOX "vox" +/// vulpkanin +#define LANGUAGE_ID_VULPKANIN "vulpkanin" +/// zaddat +#define LANGUAGE_ID_ZADDAT "zaddat" + +//? Antagonist +#define LANGUAGE_ID_CHANGELING "changeling" +#define LANGUAGE_ID_BORER "borer" +#define LANGUAGE_ID_CULT "cult" +#define LANGUAGE_ID_CULT_COMMUNE "cult_global" +// #define LANGUAGE_ID_CLOCKCULT "clockcult" +// #define LANGUAGE_ID_CLOCKCULT_COMMUNE "clockcult_global" +#define LANGUAGE_ID_SWARMBOT "swarmbot" +#define LANGUAGE_ID_XENOMORPH "xenomorph" +#define LANGUAGE_ID_XENOMORPH_HIVEMIND "xenomorph_global" + +//? Monkey +/// human monkey +#define LANGUAGE_ID_CHIMPANZEE "monkey" +/// skrell monkey +#define LANGUAGE_ID_NEAERA "neaera" +/// unathi monkey +#define LANGUAGE_ID_STOK "stok" +/// tajaran monkey +#define LANGUAGE_ID_FARWA "farwa" +/// vulp monkey +#define LANGUAGE_ID_WOLPIN "wolpin" +/// sergal monkey +#define LANGUAGE_ID_SARU "saru" +/// nevrean monkey +#define LANGUAGE_ID_SPARRA "sparra" +/// akula monkey" +#define LANGUAGE_ID_SOBAKA "sobaka" + +//? Animal +#define LANGUAGE_ID_DOG "dog" +#define LANGUAGE_ID_CAT "cat" +#define LANGUAGE_ID_MOUSE "mouse" +#define LANGUAGE_ID_BIRD "bird" + +//? Abstract-ish +#define LANGUAGE_ID_NOISE "noise" +#define LANGUAGE_ID_GIBBERISH "gibberish" + +//? Event +#define LANGUAGE_ID_EVENT_1 "event_1" +#define LANGUAGE_ID_EVENT_2 "event_2" diff --git a/code/__DEFINES/languages.dm b/code/__DEFINES/languages/legacy.dm similarity index 96% rename from code/__DEFINES/languages.dm rename to code/__DEFINES/languages/legacy.dm index 5c1fa7d6d14..b6199ce57c1 100644 --- a/code/__DEFINES/languages.dm +++ b/code/__DEFINES/languages/legacy.dm @@ -1,4 +1,4 @@ -//! ## LANGUAGES +//! language names - stop using these, use id lookup #define LANGUAGE_ADHERENT "Vibrant" #define LANGUAGE_AKHANI "Akhani" #define LANGUAGE_AKULA "Olelo Mano" @@ -11,7 +11,6 @@ #define LANGUAGE_CULT "Cult" #define LANGUAGE_DAEMON "Daemon" #define LANGUAGE_EAL "Encoded Audio Language" -#define LANGUAGE_ECUREUILIAN "Ecureuilian" #define LANGUAGE_ENOCHIAN "Enochian" #define LANGUAGE_EVENT1 "Occursus" #define LANGUAGE_FARWA "Farwanese" diff --git a/code/__DEFINES/preferences/data_keys_character.dm b/code/__DEFINES/preferences/data_keys_character.dm new file mode 100644 index 00000000000..449267e6cf3 --- /dev/null +++ b/code/__DEFINES/preferences/data_keys_character.dm @@ -0,0 +1,18 @@ +//! Holds data list keys for character preferences. +//! All of these must either have a datum, or its own handling in read/write to work! +//? ABSTRACT +#define CHARACTER_DATA_VERSION "_VERSION_" + +//? Backgrounds +#define CHARACTER_DATA_ORIGIN "lore_origin" +#define CHARACTER_DATA_CITIZENSHIP "lore_citizenship" +#define CHARACTER_DATA_RELIGION "lore_religion" +#define CHARACTER_DATA_FACTION "lore_faction" +#define CHARACTER_DATA_REAL_SPECIES "real_species" +#define CHARACTER_DATA_CHAR_SPECIES "char_species" +#define CHARACTER_DATA_LANGUAGES "languages" + +//? Occupations +#define CHARACTER_DATA_JOBS "jobs" +#define CHARACTER_DATA_ALT_TITLES "alt_titles" +#define CHARACTER_DATA_OVERFLOW_MODE "overflow_mode" diff --git a/code/__DEFINES/preferences/data_keys_global.dm b/code/__DEFINES/preferences/data_keys_global.dm new file mode 100644 index 00000000000..3c0ca4b9530 --- /dev/null +++ b/code/__DEFINES/preferences/data_keys_global.dm @@ -0,0 +1,3 @@ +//! Holds data list keys for global options. +//! All of these must either have a datum, or its own handling in read/write to work! +#define GLOBAL_DATA_LANGUAGE_PREFIX "language_prefix" diff --git a/code/__DEFINES/preferences/jobs.dm b/code/__DEFINES/preferences/jobs.dm new file mode 100644 index 00000000000..f1775987a5f --- /dev/null +++ b/code/__DEFINES/preferences/jobs.dm @@ -0,0 +1,15 @@ +//! THESE MUST BE SEQUENTIAL 1 TO X FOR JOB CONTROLLER TO WORK!!! +#define JOB_PRIORITY_NEVER 0 +#define JOB_PRIORITY_LOW 1 +#define JOB_PRIORITY_MEDIUM 2 +#define JOB_PRIORITY_HIGH 3 + +//! USED INTERNALLY BY JOB CONTROLLER DURING ASSIGNMENT +#define JP_INDEX_LOW 1 +#define JP_INDEX_MEDIUM 2 +#define JP_INDEX_HIGH 3 +#define JP_INDEX_TOTAL 3 + +#define JOB_ALTERNATIVE_GET_RANDOM 0 +#define JOB_ALTERNATIVE_BE_ASSISTANT 1 +#define JOB_ALTERNATIVE_RETURN_LOBBY 2 diff --git a/code/__DEFINES/preferences/load_order.dm b/code/__DEFINES/preferences/load_order.dm new file mode 100644 index 00000000000..748ab0aec58 --- /dev/null +++ b/code/__DEFINES/preferences/load_order.dm @@ -0,0 +1,12 @@ +// basically everything depends on this +#define PREFERENCE_LOAD_ORDER_REAL_SPECIES -1000 +// basically everything depends on this but it needs to load after real for fallback +#define PREFERENCE_LOAD_ORDER_CHAR_SPECIES -999 +// default +#define PREFERENCE_LOAD_ORDER_DEFAULT 0 +// lore/fluff is unimportant and can load later +#define PREFERENCE_LOAD_ORDER_LORE 50 +// faction depends on origin/citizenship +#define PREFERENCE_LOAD_ORDER_LORE_FACTION 55 +// language loads last as intrinsincs need to load first +#define PREFERENCE_LOAD_ORDER_LANGUAGE 60 diff --git a/code/__DEFINES/preferences/misc.dm b/code/__DEFINES/preferences/misc.dm new file mode 100644 index 00000000000..15257d2e107 --- /dev/null +++ b/code/__DEFINES/preferences/misc.dm @@ -0,0 +1,15 @@ +#define AUTOHISS_OFF 0 +#define AUTOHISS_BASIC 1 +#define AUTOHISS_FULL 2 +///The number of autohiss types that we have. Used for sanitization +#define AUTOHISS_NUM 3 +///Equivalent to being off +#define AUTOHISS_TYPE_NONE 0 +#define AUTOHISS_TYPE_UNATHI 1 +#define AUTOHISS_TYPE_TAJARAN 2 +///The number of autohiss types that we have. Used for sanitization +#define AUTOHISS_TYPE_NUM 3 + +#define EQUIP_PREVIEW_LOADOUT 1 +#define EQUIP_PREVIEW_JOB 2 +#define EQUIP_PREVIEW_ALL (EQUIP_PREVIEW_LOADOUT|EQUIP_PREVIEW_JOB) diff --git a/code/__DEFINES/preferences/procs.dm b/code/__DEFINES/preferences/procs.dm new file mode 100644 index 00000000000..b0a73c2b9de --- /dev/null +++ b/code/__DEFINES/preferences/procs.dm @@ -0,0 +1,16 @@ +//! flags for /copy_to_mob() +/// we're actually spawning roundstart +#define PREF_COPY_TO_FOR_ROUNDSTART (1<<0) +/// we're spawning latejoin +#define PREF_COPY_TO_FOR_LATEJOIN (1<<1) +/// we're spawning ghostrole (or otherwise anything that isn't really a job) +#define PREF_COPY_TO_FOR_GHOSTROLE (1<<2) +/// we're just doing it for some preview/visual reason +#define PREF_COPY_TO_FOR_RENDER (1<<3) + +/// DO NOT update icons +#define PREF_COPY_TO_DO_NOT_RENDER (1<<23) + +/// helper +#define PREF_COPY_TO_IS_SPAWNING (flags & (PREF_COPY_TO_FOR_ROUNDSTART | PREF_COPY_TO_FOR_LATEJOIN | PREF_COPY_TO_FOR_GHOSTROLE)) + diff --git a/code/__DEFINES/preferences/savefiles.dm b/code/__DEFINES/preferences/savefiles.dm new file mode 100644 index 00000000000..92888c7e14d --- /dev/null +++ b/code/__DEFINES/preferences/savefiles.dm @@ -0,0 +1,16 @@ +//! Global version - stored directly on savefile +//* File gets wiped if version < MIN +//* We store this on savefile because you can handle global migrations +//* and advanced direct savefile migrations directly with this. +#define SAVEFILE_VERSION_MIN 8 +#define SAVEFILE_VERSION_MAX 15 + +//! Character version - stored in character data list +//* Slot gets wiped if version < MIN +//* We store this on character list itself because we have +//* no reason to need it for global loading, and global migrations +//* should be low level anyways +#define CHARACTER_VERSION_MIN -1 +#define CHARACTER_VERSION_MAX 2 +/// what nulled version fields are considered; this basically makes them go through all migrations +#define CHARACTER_VERSION_LEGACY 0 diff --git a/code/__DEFINES/preferences/topic.dm b/code/__DEFINES/preferences/topic.dm new file mode 100644 index 00000000000..04140ce5ade --- /dev/null +++ b/code/__DEFINES/preferences/topic.dm @@ -0,0 +1,6 @@ +///OnTopic return values +#define PREFERENCES_NOACTION 0 +#define PREFERENCES_HANDLED 1 +#define PREFERENCES_REFRESH 2 +#define PREFERENCES_UPDATE_PREVIEW 4 +#define PREFERENCES_REFRESH_UPDATE_PREVIEW (PREFERENCES_REFRESH|PREFERENCES_UPDATE_PREVIEW) diff --git a/code/__DEFINES/species/species.dm b/code/__DEFINES/species/species.dm index 3ebec36ed9b..2a2f5220e53 100644 --- a/code/__DEFINES/species/species.dm +++ b/code/__DEFINES/species/species.dm @@ -1,16 +1,74 @@ /** * Species IDs */ +#define SPECIES_ID_ADHERENT "adherent" +#define SPECIES_ID_AKULA "akula" +#define SPECIES_ID_ALRAUNE "alraune" +#define SPECIES_ID_APIDAEN "apidaen" +#define SPECIES_ID_AURIL "auril" +#define SPECIES_ID_CUSTOM "custom" +#define SPECIES_ID_DIONA "diona" +#define SPECIES_ID_DREMACHIR "dremachir" +#define SPECIES_ID_FARWA "farwa" +#define SPECIES_ID_GOLEM "golem" +#define SPECIES_ID_HARPY "harpy" +#define SPECIES_ID_HUMAN "human" + #define SPECIES_ID_HUMAN_GRAV "human_grav" + #define SPECIES_ID_HUMAN_SPACE "human_space" + #define SPECIES_ID_HUMAN_VAT "human_vat" +#define SPECIES_ID_MONKEY "monkey" #define SPECIES_ID_MOTH "moth" -#define SPECIES_ID_MOTH_DARK "moth_dark" -#define SPECIES_ID_MOTH_LIGHT "moth_light" + #define SPECIES_ID_MOTH_DARK "moth_dark" + #define SPECIES_ID_MOTH_LIGHT "moth_light" +#define SPECIES_ID_NARAMADI "naramadi" +#define SPECIES_ID_NEAERA "neaera" +#define SPECIES_ID_NEVREAN "nevrean" +#define SPECIES_ID_PHORONOID "phoronoid" #define SPECIES_ID_PROMETHEAN "promethean" -#define SPECIES_ID_TESHARI "teshari" -#define SPECIES_ID_VOX "vox" +#define SPECIES_ID_PROTEAN "protean" +#define SPECIES_ID_RAPALA "rapala" +#define SPECIES_ID_REPLICANT "replicant" + #define SPECIES_ID_REPLICANT_ALPHA "replicant_alpha" + #define SPECIES_ID_REPLICANT_BETA "replicant_beta" +#define SPECIES_ID_SCORI "scori" +#define SPECIES_ID_SERGLING "sergling" #define SPECIES_ID_SHADEKIN "shadekin" -#define SPECIES_ID_SHADEKIN_BLACK_EYED "shadekin_black_eyed" - -// +#define SPECIES_ID_SHADEKIN_BLACK "shadekin_black" +#define SPECIES_ID_SHADOW "shadow" +#define SPECIES_ID_SKELETON "skeleton" +#define SPECIES_ID_SKRELL "skrell" +#define SPECIES_ID_SOBAKA "sobaka" +#define SPECIES_ID_SPARRA "sparra" +#define SPECIES_ID_STOK "stok" +#define SPECIES_ID_TAJARAN "tajaran" +#define SPECIES_ID_TESHARI "teshari" +#define SPECIES_ID_UNATHI "unathi" +#define SPECIES_ID_VASILISSAN "vasilissan" +#define SPECIES_ID_VIRTUAL_REALITY "virtual_reality" + #define SPECIES_ID_VIRTUAL_REALITY_DIONA "virtual_reality_diona" + #define SPECIES_ID_VIRTUAL_REALITY_HUMAN "virtual_reality_human" + #define SPECIES_ID_VIRTUAL_REALITY_MONKEY "virtual_reality_monkey" + #define SPECIES_ID_VIRTUAL_REALITY_SKELETON "virtual_reality_skeleton" + #define SPECIES_ID_VIRTUAL_REALITY_SKRELL "virtual_reality_skrell" + #define SPECIES_ID_VIRTUAL_REALITY_TAJARAN "virtual_reality_tajaran" + #define SPECIES_ID_VIRTUAL_REALITY_TESHARI "virtual_reality_teshari" + #define SPECIES_ID_VIRTUAL_REALITY_UNATHI "virtual_reality_unathi" + #define SPECIES_ID_VIRTUAL_REALITY_VOX "virtual_reality_vox" +#define SPECIES_ID_VOX "vox" +#define SPECIES_ID_VULPKANIN "vulpkanin" +#define SPECIES_ID_WEREBEAST "werebeast" +#define SPECIES_ID_WOLPIN "wolpin" +#define SPECIES_ID_XENOCHIMERA "xenochimera" +#define SPECIES_ID_XENOMORPH "xenomorph" + #define SPECIES_ID_XENOMORPH_DRONE "xenomorph_drone" + #define SPECIES_ID_XENOMORPH_HUNTER "xenomorph_hunter" + #define SPECIES_ID_XENOMORPH_QUEEN "xenomorph_queen" + #define SPECIES_ID_XENOMORPH_SENTINEL "xenomorph_sentinel" +#define SPECIES_ID_XENOHYBRID "xenohybrid" +#define SPECIES_ID_ZADDAT "zaddat" +#define SPECIES_ID_ZORREN "zorren" + #define SPECIES_ID_ZORREN_HIGH "zorren_high" + #define SPECIES_ID_ZORREN_FLAT "zorren_flat" /** * !It is important to note that these are not only used for the name of the species. diff --git a/code/__DEFINES/species/species_flags.dm b/code/__DEFINES/species/species_flags.dm index 3358e1d9eb8..45afa317b06 100644 --- a/code/__DEFINES/species/species_flags.dm +++ b/code/__DEFINES/species/species_flags.dm @@ -1,3 +1,4 @@ +// todo: species_flags //! ## SPECIES_FLAGS /// Can step on broken glass with no ill-effects. Either thick skin (diona), cut resistant (slimes) or incorporeal (shadows) #define NO_MINOR_CUT (1<<0) @@ -25,27 +26,67 @@ #define NO_DEFIB (1<<11) ///(Phoron) Contamination doesnt affect them. #define CONTAMINATION_IMMUNE (1<<12) -// unused: 0x8000 - higher than this will overflow +DEFINE_BITFIELD(species_flags, list( + BITFIELD(NO_MINOR_CUT), + BITFIELD(IS_PLANT), + BITFIELD(NO_SCAN), + BITFIELD(NO_PAIN), + BITFIELD(NO_SLIP), + BITFIELD(NO_POISON), + BITFIELD(NO_EMBED), + BITFIELD(NO_HALLUCINATION), + BITFIELD(NO_BLOOD), + BITFIELD(UNDEAD), + BITFIELD(NO_INFECT), + BITFIELD(NO_DEFIB), + BITFIELD(CONTAMINATION_IMMUNE), +)) -//! ## SPAWN_FLAGS +//! species_fluff_flags +/// deny cultures that don't specifically whitelist us +#define SPECIES_FLUFF_PICKY_FACTION (1<<0) +/// deny origins that don't specifically whitelist us +#define SPECIES_FLUFF_PICKY_ORIGIN (1<<1) +/// deny citizenships that don't specifically whitelist us +#define SPECIES_FLUFF_PICKY_CITIZENSHIP (1<<2) +/// deny religions that don't specifically whitelist us +#define SPECIES_FLUFF_PICKY_RELIGION (1<<3) + +DEFINE_BITFIELD(species_fluff_flags, list( + BITFIELD(SPECIES_FLUFF_PICKY_FACTION), + BITFIELD(SPECIES_FLUFF_PICKY_ORIGIN), + BITFIELD(SPECIES_FLUFF_PICKY_CITIZENSHIP), + BITFIELD(SPECIES_FLUFF_PICKY_RELIGION), +)) + +//! species_spawn_flags /// Must be whitelisted to play. -#define SPECIES_IS_WHITELISTED (1<<0) +#define SPECIES_SPAWN_WHITELISTED (1<<0) /// Is not a core/normally playable species. (castes, mutantraces) -#define SPECIES_IS_RESTRICTED (1<<1) -/// Species is selectable in chargen. -#define SPECIES_CAN_JOIN (1<<2) +#define SPECIES_SPAWN_RESTRICTED (1<<1) +/// Species is selectable in chargen. - **this must be on a species to be roundstart/latejoin playable!!* +#define SPECIES_SPAWN_ALLOWED (1<<2) /// FBP of this species can't be made in-game. -#define SPECIES_NO_FBP_CONSTRUCTION (1<<3) +#define SPECIES_SPAWN_NO_FBP_CONSTRUCT (1<<3) /// FBP of this species can't be selected at chargen. -#define SPECIES_NO_FBP_CHARGEN (1<<4) +#define SPECIES_SPAWN_NO_FBP_SETUP (1<<4) /// Species cannot start with robotic organs or have them attached. -#define SPECIES_NO_ROBOTIC_INTERNAL_ORGANS (1<<5) +#define SPECIES_SPAWN_NO_ROBOTIC_ORGANS (1<<5) /// Can select and customize, but not join as -#define SPECIES_WHITELIST_SELECTABLE (1<<6) +#define SPECIES_SPAWN_WHITELIST_SELECTABLE (1<<6) +DEFINE_BITFIELD(species_spawn_flags, list( + BITFIELD(SPECIES_SPAWN_WHITELISTED), + BITFIELD(SPECIES_SPAWN_RESTRICTED), + BITFIELD(SPECIES_SPAWN_ALLOWED), + BITFIELD(SPECIES_SPAWN_NO_FBP_CONSTRUCT), + BITFIELD(SPECIES_SPAWN_NO_FBP_SETUP), + BITFIELD(SPECIES_SPAWN_NO_ROBOTIC_ORGANS), + BITFIELD(SPECIES_SPAWN_WHITELIST_SELECTABLE), +)) -//! ## APPEARANCE_FLAGS +//! species_appearance_flags /// Skin tone selectable in chargen. (0-255) #define HAS_SKIN_TONE (1<<0) /// Skin colour selectable in chargen. (RGB) @@ -75,7 +116,7 @@ DEFINE_BITFIELD(species_appearance_flags, list( )) -//! ## SKIN FLAGS +//! skin flags #define SKIN_NORMAL (1<<0) #define SKIN_THREAT (1<<1) #define SKIN_CLOAK (1<<2) diff --git a/code/__DEFINES/topic.dm b/code/__DEFINES/topic.dm deleted file mode 100644 index 19802eb606f..00000000000 --- a/code/__DEFINES/topic.dm +++ /dev/null @@ -1,6 +0,0 @@ -///OnTopic return values -#define TOPIC_NOACTION 0 -#define TOPIC_HANDLED 1 -#define TOPIC_REFRESH 2 -#define TOPIC_UPDATE_PREVIEW 4 -#define TOPIC_REFRESH_UPDATE_PREVIEW (TOPIC_REFRESH|TOPIC_UPDATE_PREVIEW) diff --git a/code/__HELPERS/_auxtools_api.dm b/code/__HELPERS/_auxtools_api.dm index 30e4866f414..ffbef3b0f74 100644 --- a/code/__HELPERS/_auxtools_api.dm +++ b/code/__HELPERS/_auxtools_api.dm @@ -19,3 +19,11 @@ GLOBAL_LIST_EMPTY(auxtools_initialized) call(LIB,"auxtools_shutdown")();\ GLOB.auxtools_initialized[LIB] = FALSE;\ }\ + +// #define AUXTOOLS_YAML (world.system_type == MS_WINDOWS? "auxyaml.dll" : null) + +// /proc/yaml_encode(content) +// CRASH("auxtools didn't hook this") + +// /proc/yaml_decode(content) +// CRASH("auxtools didn't hook this") diff --git a/code/__HELPERS/game.dm b/code/__HELPERS/game.dm index 32f94eb0e82..a5fb061d7e3 100644 --- a/code/__HELPERS/game.dm +++ b/code/__HELPERS/game.dm @@ -278,8 +278,8 @@ // Try to find all the players who can hear the message - for(var/i = 1; i <= player_list.len; i++) - var/mob/M = player_list[i] + for(var/i = 1; i <= GLOB.player_list.len; i++) + var/mob/M = GLOB.player_list[i] if(M) var/turf/ear = get_turf(M) if(ear) @@ -311,10 +311,10 @@ hearturfs |= get_turf(thing) // A list of every mob with a client. - for(var/mob in player_list) + for(var/mob in GLOB.player_list) if(!ismob(mob)) - player_list -= mob - crash_with("There is a null or non-mob reference inside player_list ([mob]).") + GLOB.player_list -= mob + crash_with("There is a null or non-mob reference inside GLOB.player_list ([mob]).") continue if(get_turf(mob) in hearturfs) mobs |= mob @@ -434,7 +434,7 @@ var/list/candidates = list() var/i = 0 while(candidates.len <= 0 && i < 5) - for(var/mob/observer/dead/G in player_list) + for(var/mob/observer/dead/G in GLOB.player_list) // The most active players are more likely to become an alien. if(((G.client.inactivity/10)/60) <= buffer + i) if(!(G.mind && G.mind.current && G.mind.current.stat != DEAD)) @@ -451,7 +451,7 @@ var/list/candidates = list() var/i = 0 while(candidates.len <= 0 && i < 5) - for(var/mob/observer/dead/G in player_list) + for(var/mob/observer/dead/G in GLOB.player_list) if(G.client.prefs.be_special & BE_ALIEN) // The most active players are more likely to become an alien. if(((G.client.inactivity/10)/60) <= ALIEN_SELECT_AFK_BUFFER + i) diff --git a/code/__HELPERS/global_lists.dm b/code/__HELPERS/global_lists.dm index 0c417997d7a..8064fcfba29 100644 --- a/code/__HELPERS/global_lists.dm +++ b/code/__HELPERS/global_lists.dm @@ -6,8 +6,6 @@ var/list/admins = list() //Since it didn't really belong in any other category, I'm putting this here //This is for procs to replace all the goddamn 'in world's that are chilling around the code -/// List of all mobs **with clients attached**. Excludes /mob/new_player -var/global/list/player_list = list() /// List of all human mobs and sub-types, including clientless. var/global/list/human_mob_list = list() /// List of all silicon mobs, including clientless. @@ -205,30 +203,6 @@ GLOBAL_LIST_EMPTY(mannequins) var/datum/job/J = new T joblist[J.title] = J - if(!length(GLOB.species_meta)) // yeah i hate it too but hey - initialize_static_species_cache() - // SScharacter_setup handling static caches and body markings and sprit eaccessories when?? this is all awful - - //Languages and species. - paths = subtypesof(/datum/language) - for(var/T in paths) - var/datum/language/L = T - if(initial(L.abstract_type) == T) - continue - L = new T - GLOB.all_languages[L.name] = L - - for (var/language_name in GLOB.all_languages) - var/datum/language/L = GLOB.all_languages[language_name] - if(!(L.flags & NONGLOBAL)) - GLOB.language_keys[L.key] = L - - for(var/datum/species/S as anything in all_static_species_meta()) - if(!(S.spawn_flags & SPECIES_IS_RESTRICTED)) - GLOB.playable_species += S.name - if(S.spawn_flags & SPECIES_IS_WHITELISTED) - GLOB.whitelisted_species += S.name - //Posters paths = typesof(/datum/poster) - /datum/poster paths -= typesof(/datum/poster/nanotrasen) @@ -279,19 +253,6 @@ GLOBAL_LIST_EMPTY(mannequins) if(0.1 to INFINITY) positive_traits[path] = instance - // Custom species icon bases - var/list/blacklisted_icons = list(SPECIES_CUSTOM, SPECIES_PROMETHEAN) - var/list/whitelisted_icons = list(SPECIES_VULPKANIN, SPECIES_XENOHYBRID) - for(var/species_name in GLOB.playable_species) - if(species_name in blacklisted_icons) - continue - var/datum/species/S = name_static_species_meta(species_name) - if(S.spawn_flags & SPECIES_IS_WHITELISTED) - continue - GLOB.custom_species_bases += species_name - for(var/species_name in whitelisted_icons) - GLOB.custom_species_bases += species_name - return 1 // Hooks must return 1 /* // Uncomment to debug chemical reaction list. @@ -308,9 +269,6 @@ GLOBAL_LIST_EMPTY(mannequins) ///Hexidecimal numbers var/global/list/hexNums = list("0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F") -//* Custom Species Lists *// -GLOBAL_LIST_EMPTY(custom_species_bases) - //! ## Traits /// Negative custom species traits, indexed by path. var/global/list/negative_traits = list() diff --git a/code/__HELPERS/lists/copy.dm b/code/__HELPERS/lists/copy.dm index 43fc075f4f4..a25c2d3ca25 100644 --- a/code/__HELPERS/lists/copy.dm +++ b/code/__HELPERS/lists/copy.dm @@ -2,7 +2,7 @@ * Copies a list, and all lists inside it recusively. * Does not copy any other reference type. */ -/proc/deepCopyList(list/l) +/proc/deep_copy_list(list/l) if(!islist(l)) return l . = l.Copy() @@ -13,9 +13,9 @@ continue var/value = .[key] if(islist(value)) - value = deepCopyList(value) + value = deep_copy_list(value) .[key] = value if(islist(key)) - key = deepCopyList(key) + key = deep_copy_list(key) .[i] = key .[key] = value diff --git a/code/__HELPERS/mobs.dm b/code/__HELPERS/mobs.dm index a6199399a89..91e964c8b16 100644 --- a/code/__HELPERS/mobs.dm +++ b/code/__HELPERS/mobs.dm @@ -75,7 +75,7 @@ /proc/sanitize_name(name, species = SPECIES_HUMAN) var/datum/species/current_species if(species) - current_species = name_static_species_meta(species) + current_species = SScharacters.resolve_species_name(species) return current_species ? current_species.sanitize_name(name) : sanitizeName(name, MAX_NAME_LEN) @@ -83,7 +83,7 @@ var/datum/species/current_species if(species) - current_species = name_static_species_meta(species) + current_species = SScharacters.resolve_species_name(species) if(!current_species || current_species.name_language == null) if(gender==FEMALE) diff --git a/code/__HELPERS/names.dm b/code/__HELPERS/names.dm index ada9492628b..45c48124e75 100644 --- a/code/__HELPERS/names.dm +++ b/code/__HELPERS/names.dm @@ -289,7 +289,7 @@ var/syndicate_code_response//Code response for traitors. // Returns null if the name doesn't meet some basic requirements. Tidies up a few other things like bad-characters. newname = sanitizeName(newname) - for(var/mob/living/M in player_list) + for(var/mob/living/M in GLOB.player_list) if(M == src) continue if(!newname || M.real_name == newname) diff --git a/code/__HELPERS/sanitize/datatypes.dm b/code/__HELPERS/sanitize/datatypes.dm new file mode 100644 index 00000000000..5521dfdb52c --- /dev/null +++ b/code/__HELPERS/sanitize/datatypes.dm @@ -0,0 +1,17 @@ +/** + * returns value if text, otherwise default + */ +/proc/sanitize_istext(value, default = "") + return istext(value)? value : default + +/** + * returns value if num, otherwise default + */ +/proc/sanitize_isnum(value, default = 0) + return isnum(value)? value : default + +/** + * returns value if list, otherwise default + */ +/proc/sanitize_islist(value, default = list()) + return islist(value)? value : default diff --git a/code/__HELPERS/sanitize/list.dm b/code/__HELPERS/sanitize/list.dm new file mode 100644 index 00000000000..77f0eec967d --- /dev/null +++ b/code/__HELPERS/sanitize/list.dm @@ -0,0 +1,8 @@ +/** + * returns value if it is in list, or default, or random from list + * default is treated as nonexistant if it is null! + */ +/proc/sanitize_inlist(value, list/L, default) + if(value in L) + return value + return isnull(default)? SAFEPICK(L) : default diff --git a/code/__HELPERS/sanitize_values.dm b/code/__HELPERS/sanitize_values.dm index cd55f0a1aa7..70cec1c3772 100644 --- a/code/__HELPERS/sanitize_values.dm +++ b/code/__HELPERS/sanitize_values.dm @@ -6,24 +6,6 @@ return number return default -/proc/sanitize_text(text, default="") - if(istext(text)) - return text - return default - -/proc/sanitize_islist(value, default) - if(islist(value) && length(value)) - return value - if(default) - return default - -/proc/sanitize_inlist(value, list/List, default) - if(value in List) - return value - if(default) - return default - if(List && List.len) - return pick(List) //more specialised stuff /proc/sanitize_gender(gender,neuter=0,plural=1, default="male") diff --git a/code/__HELPERS/sorts/comparators.dm b/code/__HELPERS/sorts/comparators.dm index 7568109e500..0c9265f51d5 100644 --- a/code/__HELPERS/sorts/comparators.dm +++ b/code/__HELPERS/sorts/comparators.dm @@ -3,12 +3,45 @@ * They should return negative, zero, or positive numbers for a < b, a == b, and a > b respectively. */ +//! Standard Sort +/** + * the lazy man's low performance sort + * + * uses a datum's compare_to() proc. + * + * **Do not use this for any high performance context. It is slower than hardcoded comparators. + * + * **Warning: Only use this between to datums of the same logical type**. E.g. if you use one on another kinid of datum, you're going to get weird results, + * because the compar procs are going to typecheck, and if it's not of the right type, you'll get unexpected results! + */ +/proc/cmp_auto_compare(datum/A, datum/B) + if(istext(A) || istext(B)) + return cmp_text_asc("[A]", "[B]") + return A.compare_to(B) + +/** + * standard datum comparison + * no types are checked! + * + * **Do not use this for any high performance context. It is slower than hardcoded comparators. + * + * **Warning: Only use this between to datums of the same logical type**. E.g. if you use one on another kinid of datum, you're going to get weird results, + * because the compar procs are going to typecheck, and if it's not of the right type, you'll get unexpected results! + * + * with the context of list index 1 = front, + * return -1 for "I am infront of B" (list index closer to 1), 1 for "I am behind B" (list index further from 1), 0 for "I am equivalent to B" + */ +/datum/proc/compare_to(datum/D) + return cmp_text_asc("[src]", "[D]") + +//! Numbers /proc/cmp_numeric_dsc(a,b) return b - a /proc/cmp_numeric_asc(a,b) return a - b +//! Text /proc/cmp_text_asc(a,b) return sorttext(b,a) @@ -106,10 +139,10 @@ GLOBAL_VAR_INIT(cmp_field, "name") /proc/cmp_department_datums(datum/department/a, datum/department/b) // First, sort by the sorting order vars. - . = b.sorting_order - a.sorting_order + . = a.sorting_order - b.sorting_order // If they have the same var, then sort by name. if(. == 0) - . = sorttext(b.name, a.name) + . = sorttext(a.name, b.name) /** * Sorts entries in a performance stats list. @@ -140,36 +173,7 @@ GLOBAL_VAR_INIT(cmp_field, "name") /proc/cmp_holiday_priority(datum/holiday/A, datum/holiday/B) return A.priority - B.priority -/** - * the lazy man's low performance sort - * - * uses a datum's compare_to() proc. - * - * **Do not use this for any high performance context. It is slower than hardcoded comparators. - * - * **Warning: Only use this between to datums of the same logical type**. E.g. if you use one on another kinid of datum, you're going to get weird results, - * because the compar procs are going to typecheck, and if it's not of the right type, you'll get unexpected results! - */ -/proc/cmp_auto_compare(datum/A, datum/B) - return A.compare_to(B) - -/** - * standard datum comparison - * no types are checked! - * - * **Do not use this for any high performance context. It is slower than hardcoded comparators. - * - * **Warning: Only use this between to datums of the same logical type**. E.g. if you use one on another kinid of datum, you're going to get weird results, - * because the compar procs are going to typecheck, and if it's not of the right type, you'll get unexpected results! - * - * with the context of list index 1 = front, - * return -1 for "I am infront of B" (list index closer to 1), 1 for "I am behind B" (list index further from 1), 0 for "I am equivalent to B" - */ -/datum/proc/compare_to(datum/D) - return cmp_text_asc("[src]", "[D]") - - -//! PROFILE STUFF +//! Line Profiling /proc/cmp_profile_avg_time_dsc(list/A, list/B) return (B[PROFILE_ITEM_TIME]/(B[PROFILE_ITEM_COUNT] || 1)) - (A[PROFILE_ITEM_TIME]/(A[PROFILE_ITEM_COUNT] || 1)) @@ -179,3 +183,7 @@ GLOBAL_VAR_INIT(cmp_field, "name") /proc/cmp_profile_count_dsc(list/A, list/B) return B[PROFILE_ITEM_COUNT] - A[PROFILE_ITEM_COUNT] + +//! Preferences +/proc/cmp_preference_load_order(datum/category_item/player_setup_item/A, datum/category_item/player_setup_item/B) + return A.load_order - B.load_order diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm index 78b8f5b22d9..df12da216d9 100644 --- a/code/__HELPERS/unsorted.dm +++ b/code/__HELPERS/unsorted.dm @@ -367,7 +367,7 @@ /proc/freeborg() var/select = null var/list/borgs = list() - for (var/mob/living/silicon/robot/A in player_list) + for (var/mob/living/silicon/robot/A in GLOB.player_list) if (A.stat == 2 || A.connected_ai || A.scrambledcodes || istype(A,/mob/living/silicon/robot/drone)) continue var/name = "[A.real_name] ([A.modtype] [A.braintype])" diff --git a/code/_globalvars/lists/client.dm b/code/_globalvars/lists/client.dm deleted file mode 100644 index c274877c1d5..00000000000 --- a/code/_globalvars/lists/client.dm +++ /dev/null @@ -1,24 +0,0 @@ -GLOBAL_LIST_EMPTY(classic_keybinding_list_by_key) -GLOBAL_LIST_EMPTY(hotkey_keybinding_list_by_key) -GLOBAL_LIST_EMPTY(keybindings_by_name) - -// This is a mapping from JS keys to Byond - ref: https://keycode.info/ -GLOBAL_LIST_INIT(_kbMap, list( - "UP" = "North", - "RIGHT" = "East", - "DOWN" = "South", - "LEFT" = "West", - "INSERT" = "Insert", - "HOME" = "Northwest", - "PAGEUP" = "Northeast", - "DEL" = "Delete", - "END" = "Southwest", - "PAGEDOWN" = "Southeast", - "SPACEBAR" = "Space", - "ALT" = "Alt", - "SHIFT" = "Shift", - "CONTROL" = "Ctrl" - )) - -//We don't have globalvars/objects, so I'm putting it here. -GLOBAL_LIST_EMPTY(crafting_recipes) diff --git a/code/_globalvars/lists/clients.dm b/code/_globalvars/lists/clients.dm new file mode 100644 index 00000000000..1c0464dcfce --- /dev/null +++ b/code/_globalvars/lists/clients.dm @@ -0,0 +1,4 @@ +/// ckey-client lookup: directory[ckey] = client +GLOBAL_LIST_EMPTY(directory) +/// all clients +GLOBAL_LIST_EMPTY(clients) diff --git a/code/_globalvars/lists/keybindings.dm b/code/_globalvars/lists/keybindings.dm index edc167be785..414c396026b 100644 --- a/code/_globalvars/lists/keybindings.dm +++ b/code/_globalvars/lists/keybindings.dm @@ -1,3 +1,25 @@ +GLOBAL_LIST_EMPTY(classic_keybinding_list_by_key) +GLOBAL_LIST_EMPTY(hotkey_keybinding_list_by_key) +GLOBAL_LIST_EMPTY(keybindings_by_name) + +// This is a mapping from JS keys to Byond - ref: https://keycode.info/ +GLOBAL_LIST_INIT(_kbMap, list( + "UP" = "North", + "RIGHT" = "East", + "DOWN" = "South", + "LEFT" = "West", + "INSERT" = "Insert", + "HOME" = "Northwest", + "PAGEUP" = "Northeast", + "DEL" = "Delete", + "END" = "Southwest", + "PAGEDOWN" = "Southeast", + "SPACEBAR" = "Space", + "ALT" = "Alt", + "SHIFT" = "Shift", + "CONTROL" = "Ctrl" + )) + /// Creates and sorts all the keybinding datums /proc/init_keybindings() for(var/KB in subtypesof(/datum/keybinding)) diff --git a/code/_globalvars/lists/mobs.dm b/code/_globalvars/lists/mobs.dm new file mode 100644 index 00000000000..6c5fa8de683 --- /dev/null +++ b/code/_globalvars/lists/mobs.dm @@ -0,0 +1,2 @@ +/// all player mobs (not clients!) +GLOBAL_LIST_EMPTY(player_list) diff --git a/code/_globalvars/lists/objects.dm b/code/_globalvars/lists/objects.dm index 4785ba3dda2..d4efb4a3b30 100644 --- a/code/_globalvars/lists/objects.dm +++ b/code/_globalvars/lists/objects.dm @@ -1 +1,2 @@ GLOBAL_LIST_EMPTY(machines) //NOTE: this is a list of ALL machines now. The processing machines list is SSmachine.processing ! +GLOBAL_LIST_EMPTY(crafting_recipes) diff --git a/code/_globalvars/lists/species.dm b/code/_globalvars/lists/species.dm deleted file mode 100644 index afc29e4b66d..00000000000 --- a/code/_globalvars/lists/species.dm +++ /dev/null @@ -1,7 +0,0 @@ -GLOBAL_LIST_INIT(all_languages, list()) -/// Table of say codes for all languages -GLOBAL_LIST_INIT(language_keys, list()) -/// Species that require a whitelist check. -GLOBAL_LIST_INIT(whitelisted_species, list(SPECIES_HUMAN)) -/// A list of ALL playable species, whitelisted, latejoin or otherwise. -GLOBAL_LIST_INIT(playable_species, list(SPECIES_HUMAN)) diff --git a/code/_globalvars/mobs.dm b/code/_globalvars/mobs.dm index 8e08755221c..fc4868ac830 100644 --- a/code/_globalvars/mobs.dm +++ b/code/_globalvars/mobs.dm @@ -1,12 +1,13 @@ GLOBAL_LIST_EMPTY(admins) //all clients whom are admins GLOBAL_PROTECT(admins) GLOBAL_LIST_EMPTY(deadmins) //all ckeys who have used the de-admin verb. +// todo: kill? GLOBAL_LIST_EMPTY(stealthminID) -GLOBAL_LIST_EMPTY(directory) //all ckeys with associated client -GLOBAL_LIST_EMPTY(clients) +// todo: move GLOBAL_LIST_EMPTY(players_by_zlevel) +// todo: kill GLOBAL_LIST_EMPTY(round_text_log) - +// todo: move GLOBAL_LIST_EMPTY(mob_list) - +// todo: move GLOBAL_VAR_INIT(moth_amount, 0) //Solar moth addition; diff --git a/code/_macros.dm b/code/_macros.dm index e8c450742ab..507e032b99c 100644 --- a/code/_macros.dm +++ b/code/_macros.dm @@ -8,9 +8,7 @@ #define RANDOM_BLOOD_TYPE pick(4;"O-", 36;"O+", 3;"A-", 28;"A+", 1;"B-", 20;"B+", 1;"AB-", 5;"AB+") -#define to_world(message) to_chat(world, message) -#define to_file(file_entry, source_var) file_entry << source_var -#define from_file(file_entry, target_var) file_entry >> target_var +#define TO_WORLD(message) to_chat(world, message) #define show_browser(target, browser_content, browser_name) target << browse(browser_content, browser_name) #define close_browser(target, browser_name) target << browse(null, browser_name) diff --git a/code/_onclick/hud/alert.dm b/code/_onclick/hud/alert.dm index fa1063f3a1e..565f84f903c 100644 --- a/code/_onclick/hud/alert.dm +++ b/code/_onclick/hud/alert.dm @@ -415,7 +415,7 @@ so as to remain in compliance with the most up-to-date laws." // /atom/movable/screen/alert/notify_jump/Click() // if(!usr || !usr.client) return // if(!jump_target) return -// var/mob/dead/observer/G = usr +// var/mob/observer/dead/G = usr // if(!istype(G)) return // if(attack_not_jump) // jump_target.attack_ghost(G) diff --git a/code/_onclick/hud/ghost.dm b/code/_onclick/hud/ghost.dm index f5d560552c2..8b290167fd2 100644 --- a/code/_onclick/hud/ghost.dm +++ b/code/_onclick/hud/ghost.dm @@ -160,7 +160,7 @@ /* I wish we had this. Not yet, though. /datum/hud/ghost/show_hud(version = 0, mob/viewmob) // don't show this HUD if observing; show the HUD of the observee - var/mob/dead/observer/O = mymob + var/mob/observer/dead/O = mymob if (istype(O) && O.observetarget) plane_masters_update() return FALSE @@ -176,7 +176,7 @@ //We should only see observed mob alerts. /datum/hud/ghost/reorganize_alerts(mob/viewmob) - var/mob/dead/observer/O = mymob + var/mob/observer/dead/O = mymob if (istype(O) && O.observetarget) return . = ..() diff --git a/code/_rendering/atom_huds/alternate_appearance.dm b/code/_rendering/atom_huds/alternate_appearance.dm index 0e93e6fa634..c823e67891f 100644 --- a/code/_rendering/atom_huds/alternate_appearance.dm +++ b/code/_rendering/atom_huds/alternate_appearance.dm @@ -138,7 +138,7 @@ GLOBAL_LIST_EMPTY(active_alternate_appearances) /datum/atom_hud/alternate_appearance/basic/noncult/New() ..() - for(var/mob in player_list) + for(var/mob in GLOB.player_list) if(mobShouldSee(mob)) add_hud_to(mob) @@ -151,7 +151,7 @@ GLOBAL_LIST_EMPTY(active_alternate_appearances) /datum/atom_hud/alternate_appearance/basic/cult/New() ..() - for(var/mob in player_list) + for(var/mob in GLOB.player_list) if(mobShouldSee(mob)) add_hud_to(mob) diff --git a/code/_rendering/atom_huds/atom_hud.dm b/code/_rendering/atom_huds/atom_hud.dm index bf3c825d602..f77b39d4cd5 100644 --- a/code/_rendering/atom_huds/atom_hud.dm +++ b/code/_rendering/atom_huds/atom_hud.dm @@ -110,5 +110,5 @@ GLOBAL_LIST_INIT(huds, list( for(var/atom/A in hud.hudatoms) hud.add_to_single_hud(src, A) -/mob/dead/new_player/reload_huds() +/mob/new_player/reload_huds() return diff --git a/code/controllers/configuration/configuration.dm b/code/controllers/configuration/configuration.dm index 7348178be83..9cd848f8834 100644 --- a/code/controllers/configuration/configuration.dm +++ b/code/controllers/configuration/configuration.dm @@ -53,6 +53,7 @@ LoadEntries(J) break loadmaplist(CONFIG_MAPS_FILE) + LoadWhitelists() LoadMOTD() loaded = TRUE diff --git a/code/controllers/configuration/whitelists.dm b/code/controllers/configuration/whitelists.dm new file mode 100644 index 00000000000..c6a4d51843b --- /dev/null +++ b/code/controllers/configuration/whitelists.dm @@ -0,0 +1,97 @@ +// todo: rework whitelists, fuck. +/datum/controller/configuration + /// alien whitelist: list() of species **NAME** (not uid because headmins don't read code) = list(ckeys) + /// language whitelists also go in here because what the fuck i hate this. + var/list/alien_whitelist = list() + /// job whitelist: list() of job **TITLE** (not uid because headmins don't read code) = list(ckeys) + var/list/job_whitelist = list() + +/** + * name, ckey must be CKEY()'d. + */ +/datum/controller/configuration/proc/check_alien_whitelist(name, ckey) + if(!config_legacy.usealienwhitelist) + // ignore + return TRUE + if(admin_datums[ckey]) + // bypass + return TRUE + var/list/relevant = alien_whitelist[name] + return relevant?.Find(ckey) + +/** + * get every alien (species | language) someone's whitelisted for + * returns *names*, not uids. + */ +/datum/controller/configuration/proc/all_alien_whitelists_for(ckey) + . = list() + for(var/ayy in alien_whitelist) + if(!(ckey in alien_whitelist[ayy])) + continue + . += ayy + +/** + * name, ckey must be CKEY()'d. + */ +/datum/controller/configuration/proc/check_job_whitelist(name, ckey) + if(admin_datums[ckey]) + // bypass + return TRUE + var/list/relevant = job_whitelist[name] + return relevant?.Find(ckey) + +/datum/controller/configuration/proc/LoadWhitelists() + reload_alien_whitelist() + reload_job_whitelist() + +/datum/controller/configuration/proc/reload_job_whitelist() + job_whitelist = list() + var/fname = "config/jobwhitelist.txt" + if(!fexists(fname)) + log_config("Failed to load [fname]") + return FALSE + var/list/lines = world.file2list(fname) + var/count = 0 + for(var/line in lines) + ++count + line = trim(line) + if(!length(line)) + continue + var/list/parts = splittext(line, "-") + if(length(parts) != 2) + log_config("jobwhitelist - skipping line [count]: [line]") + continue + var/title = ckey(parts[2]) + var/ckey = ckey(parts[1]) + LAZYINITLIST(job_whitelist[title]) + if(ckey in job_whitelist[title]) + log_config("jobwhitelist - duplicate ckey [ckey] for [title]") + continue + LAZYADD(job_whitelist[title], ckey) + return TRUE + +/datum/controller/configuration/proc/reload_alien_whitelist() + alien_whitelist = list() + var/fname = "config/alienwhitelist.txt" + if(!fexists(fname)) + log_config("Failed to load [fname]") + return FALSE + var/list/lines = world.file2list(fname) + var/count = 0 + for(var/line in lines) + ++count + line = trim(line) + if(!length(line)) + continue + var/list/parts = splittext(line, "-") + if(length(parts) != 2) + log_config("alienwhitelist - skipping line [count]: [line]") + continue + var/alien = ckey(parts[2]) + var/ckey = ckey(parts[1]) + LAZYINITLIST(alien_whitelist[alien]) + if(ckey in alien_whitelist[alien]) + log_config("alienwhitelist - duplicate ckey [ckey] for [alien]") + continue + LAZYADD(alien_whitelist[alien], ckey) + return TRUE diff --git a/code/controllers/controller.dm b/code/controllers/controller.dm index c9d5f1e5650..24289b18797 100644 --- a/code/controllers/controller.dm +++ b/code/controllers/controller.dm @@ -2,6 +2,8 @@ var/name // The object used for the clickable stat() button. var/obj/effect/statclick/statclick + /// debug/verbose logging? + var/verbose_logging = FALSE /datum/controller/proc/Initialize() diff --git a/code/controllers/subsystem/ai.dm b/code/controllers/subsystem/ai.dm index ce8fbd9d3da..66aac46fa7a 100644 --- a/code/controllers/subsystem/ai.dm +++ b/code/controllers/subsystem/ai.dm @@ -21,7 +21,7 @@ SUBSYSTEM_DEF(ai) src.currentrun = processing.Copy() slept_mobs = 0 busy_z_levels.Cut() - for(var/played_mob in player_list) + for(var/played_mob in GLOB.player_list) if(!played_mob || isobserver(played_mob)) continue var/turf/player_turf = get_turf(played_mob) diff --git a/code/controllers/subsystem/character_setup.dm b/code/controllers/subsystem/character_setup.dm deleted file mode 100644 index da4de15fea5..00000000000 --- a/code/controllers/subsystem/character_setup.dm +++ /dev/null @@ -1,38 +0,0 @@ -SUBSYSTEM_DEF(character_setup) - name = "Character Setup" - init_order = INIT_ORDER_DEFAULT - priority = FIRE_PRIORITY_CHARSETUP - subsystem_flags = SS_BACKGROUND - wait = 1 SECOND - runlevels = RUNLEVEL_LOBBY | RUNLEVELS_DEFAULT - - var/list/prefs_awaiting_setup = list() - var/list/preferences_datums = list() - var/list/newplayers_requiring_init = list() - - var/list/save_queue = list() -/* -/datum/controller/subsystem/character_setup/Initialize() - while(prefs_awaiting_setup.len) - var/datum/preferences/prefs = prefs_awaiting_setup[prefs_awaiting_setup.len] - prefs_awaiting_setup.len-- - prefs.setup() - while(newplayers_requiring_init.len) - var/mob/new_player/new_player = newplayers_requiring_init[newplayers_requiring_init.len] - newplayers_requiring_init.len-- - new_player.deferred_login() - . = ..() -*/ //Might be useful if we ever switch to Bay prefs. -/datum/controller/subsystem/character_setup/fire(resumed = FALSE) - while(save_queue.len) - var/datum/preferences/prefs = save_queue[save_queue.len] - save_queue.len-- - - if(!QDELETED(prefs)) - prefs.save_preferences() - - if(MC_TICK_CHECK) - return - -/datum/controller/subsystem/character_setup/proc/queue_preferences_save(var/datum/preferences/prefs) - save_queue |= prefs diff --git a/code/controllers/subsystem/characters/_characters.dm b/code/controllers/subsystem/characters/_characters.dm new file mode 100644 index 00000000000..23009184f9e --- /dev/null +++ b/code/controllers/subsystem/characters/_characters.dm @@ -0,0 +1,67 @@ +/** + * Manages character setup, character saving, loading, + * and will eventually serve as the middleware + * between character preferences and character + * persistence as well. + */ +SUBSYSTEM_DEF(characters) + name = "Characters" + init_order = INIT_ORDER_CHARACTERS + priority = FIRE_PRIORITY_CHARSETUP + subsystem_flags = SS_BACKGROUND + wait = 1 SECOND + runlevels = RUNLEVEL_LOBBY | RUNLEVELS_DEFAULT + + var/list/prefs_awaiting_setup = list() + var/list/preferences_datums = list() + var/list/newplayers_requiring_init = list() + + var/list/save_queue = list() + +/datum/controller/subsystem/characters/Initialize() + rebuild_caches() + for(var/ckey in GLOB.preferences_datums) + var/datum/preferences/P = GLOB.preferences_datums[ckey] + if(!istype(P)) + stack_trace("what?") + continue + P.Initialize() + return ..() + +/datum/controller/subsystem/characters/Recover() + . = ..() + rebuild_caches() + +/datum/controller/subsystem/characters/proc/rebuild_caches() + rebuild_species() + rebuild_languages() + rebuild_character_species() + rebuild_backgrounds() + +/* +/datum/controller/subsystem/characters/Initialize() + while(prefs_awaiting_setup.len) + var/datum/preferences/prefs = prefs_awaiting_setup[prefs_awaiting_setup.len] + prefs_awaiting_setup.len-- + prefs.setup() + while(newplayers_requiring_init.len) + var/mob/new_player/new_player = newplayers_requiring_init[newplayers_requiring_init.len] + newplayers_requiring_init.len-- + new_player.deferred_login() + . = ..() +*/ //Might be useful if we ever switch to Bay prefs. +/datum/controller/subsystem/characters/fire(resumed = FALSE) + while(save_queue.len) + var/datum/preferences/prefs = save_queue[save_queue.len] + save_queue.len-- + + if(!QDELETED(prefs)) + prefs.save_preferences() + + if(MC_TICK_CHECK) + return + +/datum/controller/subsystem/characters/proc/queue_preferences_save(var/datum/preferences/prefs) + save_queue |= prefs + + diff --git a/code/controllers/subsystem/characters/backgrounds.dm b/code/controllers/subsystem/characters/backgrounds.dm new file mode 100644 index 00000000000..14660f7b214 --- /dev/null +++ b/code/controllers/subsystem/characters/backgrounds.dm @@ -0,0 +1,112 @@ +/datum/controller/subsystem/characters + //! Backgrounds - to be shoved into some lore system later (maybe) + var/list/character_origins + var/list/character_citizenships + var/list/character_religions + var/list/character_factions + +/datum/controller/subsystem/characters/proc/rebuild_backgrounds() + character_origins = list() + character_citizenships = list() + character_religions = list() + character_factions = list() + + for(var/path in subtypesof(/datum/lore/character_background)) + var/datum/lore/character_background/L = path + if(initial(L.abstract_type) == path) + continue + L = new path + if(!L.id) + stack_trace("no ID on [L.type]") + continue + if(istype(L, /datum/lore/character_background/citizenship)) + if(character_citizenships[L.id]) + stack_trace("dupe [L.id] on [L.type]") + continue + character_citizenships[L.id] = L + if(istype(L, /datum/lore/character_background/origin)) + if(character_origins[L.id]) + stack_trace("dupe [L.id] on [L.type]") + continue + character_origins[L.id] = L + if(istype(L, /datum/lore/character_background/religion)) + if(character_religions[L.id]) + stack_trace("dupe [L.id] on [L.type]") + continue + character_religions[L.id] = L + if(istype(L, /datum/lore/character_background/faction)) + if(character_factions[L.id]) + stack_trace("dupe [L.id] on [L.type]") + continue + character_factions[L.id] = L + + tim_sort(character_origins, /proc/cmp_auto_compare, TRUE) + tim_sort(character_citizenships, /proc/cmp_auto_compare, TRUE) + tim_sort(character_religions, /proc/cmp_auto_compare, TRUE) + tim_sort(character_factions, /proc/cmp_auto_compare, TRUE) + +/datum/controller/subsystem/characters/proc/available_citizenships(species_id) + . = list() + for(var/id in character_citizenships) + var/datum/lore/character_background/citizenship/L = character_citizenships[id] + if(L.check_species_id(species_id)) + . += L + +/datum/controller/subsystem/characters/proc/available_religions(species_id) + . = list() + for(var/id in character_religions) + var/datum/lore/character_background/religion/L = character_religions[id] + if(L.check_species_id(species_id)) + . += L + +/datum/controller/subsystem/characters/proc/available_factions(species_id, origin_id, citizenship_id) + . = list() + for(var/id in character_factions) + var/datum/lore/character_background/faction/L = character_factions[id] + if(L.origin_whitelist && !(origin_id in L.origin_whitelist)) + continue + if(L.citizenship_whitelist && !(citizenship_id in L.citizenship_whitelist)) + continue + if(L.check_species_id(species_id)) + . += L + +/datum/controller/subsystem/characters/proc/available_origins(species_id, category) + . = list() + for(var/id in character_origins) + var/datum/lore/character_background/origin/L = character_origins[id] + if(category && (L.category != category)) + continue + if(L.check_species_id(species_id)) + . += L + +/datum/controller/subsystem/characters/proc/resolve_citizenship(id) + RETURN_TYPE(/datum/lore/character_background/citizenship) + if(ispath(id)) + var/datum/lore/character_background/bg = id + id = initial(bg.id) + return character_citizenships[id] + +/datum/controller/subsystem/characters/proc/resolve_faction(id) + RETURN_TYPE(/datum/lore/character_background/faction) + if(ispath(id)) + var/datum/lore/character_background/bg = id + id = initial(bg.id) + return character_factions[id] + +/datum/controller/subsystem/characters/proc/resolve_religion(id) + RETURN_TYPE(/datum/lore/character_background/religion) + if(ispath(id)) + var/datum/lore/character_background/bg = id + id = initial(bg.id) + return character_religions[id] + +/datum/controller/subsystem/characters/proc/resolve_origin(id) + RETURN_TYPE(/datum/lore/character_background/origin) + if(ispath(id)) + var/datum/lore/character_background/bg = id + id = initial(bg.id) + return character_origins[id] + +/datum/controller/subsystem/characters/proc/job_locks_for_faction(id) + var/datum/lore/character_background/faction/F = resolve_faction(id) + return F.job_whitelist diff --git a/code/controllers/subsystem/characters/character_species.dm b/code/controllers/subsystem/characters/character_species.dm new file mode 100644 index 00000000000..cb5eb1d8894 --- /dev/null +++ b/code/controllers/subsystem/characters/character_species.dm @@ -0,0 +1,83 @@ + +/datum/controller/subsystem/characters + //! Species + /** + * yeah so funny right + * + * we have a lot of fake-people around (minor races/human reskins) + * i can't remove them because that'd ruffle feathers + * ( literally, looking at you harpies ) + * so **everyone** gets to be a /datum/character_species + * that way we get the name, desc, and species id of what + * actual species we should be any are able to do roundstart tweaks. + */ + var/list/character_species_lookup + /** + * species ui cache + * so we don't rebuild this every time someone makes an ui + * list of categories associated to lists + * second layer of list contains: + * {name: str, desc: str, whitelisted: 1 or 0, id: str} + */ + var/list/character_species_cache + +/datum/controller/subsystem/characters/proc/rebuild_character_species() + // make species lookup + character_species_lookup = list() + for(var/path in species_paths) + var/datum/species/S = species_paths[path] + if(!(S.species_spawn_flags & SPECIES_SPAWN_ALLOWED)) // don't bother lmao + continue + if(!S.uid) + stack_trace("no species ID on [S.type].") + continue + if(character_species_lookup[S.uid]) + stack_trace("species uid collision on [S.uid] from [S.type].") + continue + character_species_lookup[S.uid] = S.construct_character_species() + for(var/path in subtypesof(/datum/character_species)) + var/datum/character_species/S = path + if(initial(S.abstract_type) == path) + continue + S = new path + if(character_species_lookup[S.uid]) + stack_trace("ignoring custom character species path [path] - collides on uid [S.uid]") + continue + character_species_lookup[S.uid] = S + + // make species data cache + character_species_cache = list() + for(var/id in character_species_lookup) + var/datum/character_species/S = character_species_lookup[id] + LAZYINITLIST(character_species_cache[S.category]) + character_species_cache[S.category] += list(list( + "id" = S.uid, + "whitelisted" = S.whitelisted, + "name" = S.name, + "desc" = S.desc, + "appearance_flags" = S.species_appearance_flags, + "flags" = S.species_flags, + "category" = S.category, // note to self optimize this + )) + + tim_sort(character_species_lookup, /proc/cmp_auto_compare, TRUE) + +/datum/controller/subsystem/characters/proc/resolve_character_species(uid) + RETURN_TYPE(/datum/character_species) + return character_species_lookup[uid] + +/datum/controller/subsystem/characters/proc/construct_character_species(uid) + RETURN_TYPE(/datum/species) + var/datum/character_species/faux = resolve_character_species(uid) + var/datum/species/built = new faux.real_species_type + if(faux.is_real) + // let's assume they aren't an idiot and didn't hardcode a real species as a character species + return built + faux.tweak(built) + return built + +/datum/controller/subsystem/characters/proc/all_character_species() + RETURN_TYPE(/list) + . = list() + for(var/uid in character_species_lookup) + . += character_species_lookup[uid] diff --git a/code/controllers/subsystem/characters/languages.dm b/code/controllers/subsystem/characters/languages.dm new file mode 100644 index 00000000000..cbd58ffb11e --- /dev/null +++ b/code/controllers/subsystem/characters/languages.dm @@ -0,0 +1,79 @@ +/datum/controller/subsystem/characters + /// languages by id + var/list/language_lookup + /// languages by path + var/list/language_paths + // todo: better way to determine so we have no collisions + /// language key cache + var/list/language_keys + // todo: remove + /// language by name + var/list/language_names + +/datum/controller/subsystem/characters/proc/rebuild_languages() + language_lookup = list() + language_keys = list() + language_names = list() + language_paths = list() + for(var/path in subtypesof(/datum/language)) + var/datum/language/L = path + if(initial(L.abstract_type) == path) + continue + L = new path + if(language_lookup[L.id]) + stack_trace("duped language id [L.id] on [path] skipped") + continue + if(language_names[L.name]) + stack_trace("duped language name [L.name] on [path] skipped") + continue + language_lookup[L.id] = L + language_names[L.name] = L + language_paths[path] = L + if(!(L.language_flags & NONGLOBAL)) + language_keys[L.key] = L + + tim_sort(language_names, /proc/cmp_auto_compare, TRUE) + tim_sort(language_keys, /proc/cmp_auto_compare) + tim_sort(language_paths, /proc/cmp_auto_compare, TRUE) + +/datum/controller/subsystem/characters/proc/resolve_language(id_path_name) + if(ispath(id_path_name)) + return resolve_language_path(id_path_name) + return resolve_language_id(id_path_name) || resolve_language_name(id_path_name) + +// todo: deprecated +/datum/controller/subsystem/characters/proc/resolve_language_name(name) + RETURN_TYPE(/datum/language) + return language_names[name] + +/datum/controller/subsystem/characters/proc/resolve_language_id(id) + RETURN_TYPE(/datum/language) + return language_lookup[id] + +// todo: deprecated +/datum/controller/subsystem/characters/proc/resolve_language_path(path) + RETURN_TYPE(/datum/language) + ASSERT(ispath(path, /datum/language)) + return language_paths[path] + +/** + * returns all language datums + * do NOT modify these unless you know what you are doing! + */ +/datum/controller/subsystem/characters/proc/all_languages() + RETURN_TYPE(/list) + . = list() + for(var/path in language_paths) + . += language_paths[path] + +/** + * returns all language names + */ +/datum/controller/subsystem/characters/proc/all_language_names() + RETURN_TYPE(/list) + . = list() + for(var/name in language_names) + . += name + +/datum/controller/subsystem/characters/proc/resolve_language_key(key) + return language_keys[key] diff --git a/code/controllers/subsystem/characters/species.dm b/code/controllers/subsystem/characters/species.dm new file mode 100644 index 00000000000..9eb987429ff --- /dev/null +++ b/code/controllers/subsystem/characters/species.dm @@ -0,0 +1,120 @@ +/datum/controller/subsystem/characters + /// species by id + var/list/species_lookup + /// species by type + var/list/species_paths + /// species by name + var/list/species_names + // todo: ids + /// playable species - names + var/list/whitelisted_species + // todo: ids + /// whitelisted species - names + var/list/playable_species + // todo: ids + /// custom species icon bases - names + var/list/custom_species_bases + /// default species path + var/default_species_path = /datum/species/human + +/datum/controller/subsystem/characters/proc/rebuild_species() + species_lookup = list() + species_paths = list() + species_names = list() + playable_species = list() + whitelisted_species = list() + custom_species_bases = list() + var/static/list/blacklisted_icon_ids = list(SPECIES_ID_CUSTOM, SPECIES_ID_PROMETHEAN) + var/static/list/whitelisted_icon_ids = list(SPECIES_ID_VULPKANIN, SPECIES_ID_XENOMORPH_HUNTER) + for(var/path in subtypesof(/datum/species)) + var/datum/species/S = path + if(initial(S.abstract_type) == path) + continue + S = new path + if(species_lookup[S.uid]) + stack_trace("species id collision on [S.uid] on [path]") + continue + if(species_names[S.name]) + stack_trace("species name collision on [S.name] on [path]") + continue + species_lookup[S.uid] = S + species_names[S.name] = S + species_paths[path] = S + + if(S.species_spawn_flags & SPECIES_SPAWN_WHITELISTED) + whitelisted_species += S.name + if(!(S.species_spawn_flags & SPECIES_SPAWN_RESTRICTED)) + playable_species += S.name + if((!(S.species_spawn_flags & (SPECIES_SPAWN_WHITELISTED | SPECIES_SPAWN_RESTRICTED)) && !(S.get_species_id() in blacklisted_icon_ids)) || (S.get_species_id() in whitelisted_icon_ids)) + custom_species_bases += S.name + + tim_sort(species_lookup, /proc/cmp_auto_compare, TRUE) + tim_sort(species_names, /proc/cmp_auto_compare, TRUE) + tim_sort(species_lookup, /proc/cmp_auto_compare, TRUE) + tim_sort(whitelisted_species, /proc/cmp_auto_compare) + tim_sort(playable_species, /proc/cmp_auto_compare) + tim_sort(custom_species_bases, /proc/cmp_auto_compare) + +/datum/controller/subsystem/characters/proc/resolve_species(id_path_name) + RETURN_TYPE(/datum/species) + if(ispath(id_path_name)) + return species_paths[id_path_name] + return species_lookup[id_path_name] || species_names[id_path_name] + +/datum/controller/subsystem/characters/proc/resolve_species_id(id) + RETURN_TYPE(/datum/species) + return species_lookup[id] + +/datum/controller/subsystem/characters/proc/resolve_species_path(path) + RETURN_TYPE(/datum/species) + ASSERT(ispath(path, /datum/species)) // why are you passing in invalid paths? + return species_paths[path] + +// todo: deprecated kinda - most of these uses should just be id +/datum/controller/subsystem/characters/proc/resolve_species_name(name) + RETURN_TYPE(/datum/species) + return species_names[name] + +/datum/controller/subsystem/characters/proc/construct_species_id(id) + RETURN_TYPE(/datum/species) + var/datum/species/static_copy = resolve_species_id(id) + if(!static_copy) + return + return new static_copy.type + +/datum/controller/subsystem/characters/proc/construct_species_path(path) + RETURN_TYPE(/datum/species) + ASSERT(ispath(path, /datum/species)) // why are you passing in invalid paths? + return new path + +// todo: deprecated +/datum/controller/subsystem/characters/proc/construct_species_name(name) + RETURN_TYPE(/datum/species) + var/datum/species/static_copy = resolve_species_name(name) + if(!static_copy) + return + return new static_copy.type + +// todo: deprecated +/** + * returns all static species datums + * DO NOT EVER MODIFY THESE. + */ +/datum/controller/subsystem/characters/proc/all_static_species_meta() + RETURN_TYPE(/list) + . = list() + for(var/path in species_paths) + . += species_paths[path] + +/datum/controller/subsystem/characters/proc/all_species_names() + RETURN_TYPE(/list) + . = list() + for(var/name in species_names) + . += name + +/** + * default species id for when someone's species is removed/no longer playable + */ +/datum/controller/subsystem/characters/proc/default_species_id() + var/datum/species/S = resolve_species_path(ispath(default_species_path, /datum/species)? default_species_path : /datum/species/human) + return S.id diff --git a/code/controllers/subsystem/dbcore/_dbcore.dm b/code/controllers/subsystem/dbcore/_dbcore.dm index fcff3ba34c4..bdfeccca66e 100644 --- a/code/controllers/subsystem/dbcore/_dbcore.dm +++ b/code/controllers/subsystem/dbcore/_dbcore.dm @@ -177,6 +177,8 @@ SUBSYSTEM_DEF(dbcore) /** * makes a query * + * **you must qdel this query yourself.** + * * @params * - sql_query - the query. use :arg for arguments * - arguments - keyed list @@ -192,6 +194,8 @@ SUBSYSTEM_DEF(dbcore) /** * makes, and runs a query * + * **you must qdel this query yourself.** + * * @params * - sql_query - the query. use :arg for arguments * - arguments - keyed list diff --git a/code/controllers/subsystem/inactivity.dm b/code/controllers/subsystem/inactivity.dm index fd4a4dfd358..53e15c3bc17 100644 --- a/code/controllers/subsystem/inactivity.dm +++ b/code/controllers/subsystem/inactivity.dm @@ -29,7 +29,7 @@ SUBSYSTEM_DEF(inactivity) information = " while a silicon." if(isAI(C.mob)) var/mob/living/silicon/ai/A = C.mob - empty_playable_ai_cores += new /obj/structure/AIcore/deactivated(A.loc) + GLOB.empty_playable_ai_cores += new /obj/structure/AIcore/deactivated(A.loc) GLOB.global_announcer.autosay("[A] has been moved to intelligence storage.", "Artificial Intelligence Oversight") A.clear_client() information = " while an AI." diff --git a/code/controllers/subsystem/job/_job.dm b/code/controllers/subsystem/job/_job.dm index 90d17a883c2..ad14c0e54a4 100644 --- a/code/controllers/subsystem/job/_job.dm +++ b/code/controllers/subsystem/job/_job.dm @@ -3,26 +3,70 @@ SUBSYSTEM_DEF(job) init_order = INIT_ORDER_JOBS subsystem_flags = SS_NO_FIRE - var/list/occupations = list() //List of all jobs - var/list/datum/job/name_occupations = list() //Dict of all jobs, keys are titles - var/list/type_occupations = list() //Dict of all jobs, keys are types + /// List of all jobs + var/list/occupations + /// Dict of all jobs, keys are titles + var/list/datum/job/name_occupations + /// Dict of all jobs, keys are types + var/list/type_occupations + /// jobs by id + var/list/job_lookup + /// job preferences ui cache - cache[faction string][department name] = list(job ids) + var/list/job_pref_ui_cache + /// jobs per column + var/job_pref_ui_per = 25 var/list/department_datums = list() var/debug_messages = FALSE /datum/controller/subsystem/job/Initialize(timeofday) - if(!department_datums.len) + if(!length(department_datums)) setup_departments() - if(!occupations.len) + if(!length(occupations)) setup_occupations() + reconstruct_job_ui_caches() return ..() /datum/controller/subsystem/job/Recover() - ReconstructSpawnpoints() + occupations = SSjob.occupations + name_occupations = SSjob.name_occupations + job_lookup = SSjob.job_lookup + type_occupations = SSjob.type_occupations + + reconstruct_spawnpoints() + reconstruct_job_ui_caches() + + return ..() + +/datum/controller/subsystem/job/proc/reconstruct_job_ui_caches() + // todo: this is shit but it works + job_pref_ui_cache = list() + for(var/id in job_lookup) + var/datum/job/J = job_lookup[id] + if(!(J.join_types & JOB_ROUNDSTART)) + continue + var/faction = J.faction + LAZYINITLIST(job_pref_ui_cache[faction]) + var/department = LAZYACCESS(J.departments, 1) || "Misc" + LAZYADD(job_pref_ui_cache[faction][department], id) + // todo: why + for(var/fname in job_pref_ui_cache) + var/list/faction = job_pref_ui_cache[fname] + var/list/asinine_sort = list() + for(var/depname in department_datums) + if(faction[depname]) + asinine_sort[depname] = faction[depname] + faction -= depname + faction.Insert(1, asinine_sort) + for(var/depname in asinine_sort) + faction[depname] = asinine_sort[depname] /datum/controller/subsystem/job/proc/setup_occupations() occupations = list() + job_lookup = list() + name_occupations = list() + type_occupations = list() var/list/all_jobs = subtypesof(/datum/job) if(!all_jobs.len) to_chat(world, SPAN_WARNING( "Error setting up jobs, no job datums found")) @@ -34,8 +78,21 @@ SUBSYSTEM_DEF(job) continue job = new J occupations += job + if(!job.id) + stack_trace("no job id for [J]") + continue + if(!job.title) + stack_trace("no job title for [J]") + continue + if(job_lookup[job.id]) + stack_trace("job id collision on [job.id] for [J]") + continue + if(name_occupations[job.title]) + stack_trace("job title collision on [job.title] for [J]") + continue name_occupations[job.title] = job type_occupations[J] = job + job_lookup[job.id] = job if(LAZYLEN(job.departments)) add_to_departments(job) @@ -84,11 +141,6 @@ SUBSYSTEM_DEF(job) setup_occupations() return name_occupations[rank] -/datum/controller/subsystem/job/proc/get_job_type(jobtype) - if(!occupations.len) - setup_occupations() - return type_occupations[jobtype] - // Determines if a job title is inside of a specific department. // Useful to replace the old `if(job_title in command_positions)` code. /datum/controller/subsystem/job/proc/is_job_in_department(rank, target_department_name) @@ -114,7 +166,7 @@ SUBSYSTEM_DEF(job) /datum/controller/subsystem/job/proc/get_primary_department_of_job(datum/job/J) if(!istype(J, /datum/job)) if(ispath(J)) - J = get_job_type(J) + J = job_by_type(J) else if(istext(J)) J = get_job(J) diff --git a/code/controllers/subsystem/job/job_controller.dm b/code/controllers/subsystem/job/_legacy_job_stuff.dm similarity index 66% rename from code/controllers/subsystem/job/job_controller.dm rename to code/controllers/subsystem/job/_legacy_job_stuff.dm index d70912f5160..10b7ba73577 100644 --- a/code/controllers/subsystem/job/job_controller.dm +++ b/code/controllers/subsystem/job/_legacy_job_stuff.dm @@ -1,168 +1,81 @@ -var/global/datum/controller/occupations/job_master - -/datum/controller/occupations - //List of all jobs - var/list/occupations = list() - //Players who need jobs - var/list/unassigned = list() - //Debug info +/datum/controller/subsystem/job + //job_debug info var/list/job_debug = list() //Cache of icons for job info window var/list/job_icons = list() -/datum/controller/occupations/proc/SetupOccupations() - occupations = list() - //var/list/all_jobs = typesof(/datum/job) - var/list/all_jobs = list(/datum/job/station/assistant) | GLOB.using_map.allowed_jobs - if(!all_jobs.len) - to_world(SPAN_DEBUGWARNING("Error setting up jobs, no job datums found!")) +/datum/controller/subsystem/job/proc/job_debug(text) + if(!verbose_logging) return FALSE - for(var/J in all_jobs) - var/datum/job/job = J - if(initial(job.abstract_type) == J) - continue - job = new J - occupations += job - tim_sort(occupations, /proc/cmp_job_datums) + subsystem_log(text) return TRUE +/datum/controller/subsystem/job/proc/GetPlayerAltTitle(mob/new_player/player, rank) + return player.client.prefs.get_job_alt_title_name(get_job(rank)) -/datum/controller/occupations/proc/Debug(text) - if(!GLOB.Debug2) - return FALSE - job_debug.Add(text) - return TRUE - - -/datum/controller/occupations/proc/GetJob(rank) - if(!rank) - return null - for(var/datum/job/J in occupations) - if(!J) - continue - if(J.title == rank) - return J - return null - - -/datum/controller/occupations/proc/GetPlayerAltTitle(mob/new_player/player, rank) - return player.client.prefs.GetPlayerAltTitle(GetJob(rank)) - - -/datum/controller/occupations/proc/AssignRole(mob/new_player/player, rank, latejoin = 0) - Debug("Running AR, Player: [player], Rank: [rank], LJ: [latejoin]") +/datum/controller/subsystem/job/proc/AssignRole(mob/new_player/player, rank, latejoin = 0) + job_debug("Running AR, Player: [player], Rank: [rank], LJ: [latejoin]") if(player && player.mind && rank) - var/datum/job/job = GetJob(rank) - if(!job) - return 0 - if(job.minimum_character_age && (player.client.prefs.age < job.minimum_character_age)) - return 0 - if(jobban_isbanned(player, rank)) - return 0 - if(!job.player_old_enough(player.client)) - return 0 - if(!is_job_whitelisted(player, rank)) - return 0 - - var/position_limit = job.total_positions - if(!latejoin) - position_limit = job.spawn_positions - if((job.current_positions < position_limit) || position_limit == -1) - Debug("Player: [player] is now Rank: [rank], JCP:[job.current_positions], JPL:[position_limit]") - player.mind.assigned_role = rank - player.mind.role_alt_title = GetPlayerAltTitle(player, rank) - unassigned -= player - job.current_positions++ - return 1 - Debug("AR has failed, Player: [player], Rank: [rank]") + var/datum/job/job = get_job(rank) + var/reasons = job.check_client_availability_one(player.client) + if(reasons != ROLE_AVAILABLE) + job_debug("AR failed: player [player], rank [rank], latejoin [latejoin], failed for [reasons]") + return FALSE + job_debug("Player: [player] is now Rank: [rank], JCP:[job.current_positions]") + player.mind.assigned_role = rank + player.mind.role_alt_title = GetPlayerAltTitle(player, rank) + // this can be called in latejoin!! + // todo: we shouldn't have to do this + divide_unassigned?.Remove(player) + job.current_positions++ + return 1 + job_debug("AR has failed, Player: [player], Rank: [rank]") return 0 - /// Making additional slot on the fly. -/datum/controller/occupations/proc/FreeRole(rank) - var/datum/job/job = GetJob(rank) +/datum/controller/subsystem/job/proc/FreeRole(rank) + var/datum/job/job = get_job(rank) if(job && job.total_positions != -1) job.total_positions++ return 1 return 0 - -/datum/controller/occupations/proc/FindOccupationCandidates(datum/job/job, level, flag) - Debug("Running FOC, Job: [job], Level: [level], Flag: [flag]") +/datum/controller/subsystem/job/proc/FindOccupationCandidates(datum/job/job, level) + job_debug("Running FOC, Job: [job], Level: [level]") var/list/candidates = list() - for(var/mob/new_player/player in unassigned) - if(jobban_isbanned(player, job.title)) - Debug("FOC isbanned failed, Player: [player]") + for(var/mob/new_player/player in divide_unassigned) + var/reasons = job.check_client_availability_one(player.client) + if(reasons != ROLE_AVAILABLE) + job_debug("FOC failed for [reasons], player: [player]") continue - if(!job.player_old_enough(player.client)) - Debug("FOC player not old enough, Player: [player]") - continue - if(job.minimum_character_age && (player.client.prefs.age < job.minimum_character_age)) - Debug("FOC character not old enough, Player: [player]") - continue - if(!is_job_whitelisted(player, job.title)) - Debug("FOC is_job_whitelisted failed, Player: [player]") - continue - if(flag && !(player.client.prefs.be_special & flag)) - Debug("FOC flag failed, Player: [player], Flag: [flag], ") - continue - if(player.client.prefs.GetJobDepartment(job, level) & job.flag) - Debug("FOC pass, Player: [player], Level:[level]") + if(player.client.prefs.get_job_priority(job) == level) + job_debug("FOC pass, Player: [player]") candidates += player return candidates -/datum/controller/occupations/proc/GiveRandomJob(mob/new_player/player) - Debug("GRJ Giving random job, Player: [player]") +/datum/controller/subsystem/job/proc/GiveRandomJob(mob/new_player/player) + job_debug("GRJ Giving random job, Player: [player]") for(var/datum/job/job in shuffle(occupations)) - if(!job) + var/reasons = job.check_client_availability_one(player.client) + if(reasons != ROLE_AVAILABLE) + job_debug("GRJ failed for [reasons] on [job.id]") continue - - if(job.minimum_character_age && (player.client.prefs.age < job.minimum_character_age)) + if(!AssignRole(player, job.title)) + job_debug("GRJ on [job.id] for [player] AssignRole failed!!!") continue + divide_unassigned -= player + break - if(istype(job, GetJob(USELESS_JOB))) // We don't want to give him visitor, that's boring! - continue - - if(SSjob.is_job_in_department(job.title, DEPARTMENT_COMMAND)) //If you want a command position, select it! - continue - - if(jobban_isbanned(player, job.title)) - Debug("GRJ isbanned failed, Player: [player], Job: [job.title]") - continue - - if(!job.player_old_enough(player.client)) - Debug("GRJ player not old enough, Player: [player]") - continue - - if(!is_job_whitelisted(player, job.title)) - Debug("GRJ player not whitelisted for this job, Player: [player], Job: [job.title]") - continue - - if((job.current_positions < job.spawn_positions) || job.spawn_positions == -1) - Debug("GRJ Random job given, Player: [player], Job: [job]") - AssignRole(player, job.title) - unassigned -= player - break - - -/datum/controller/occupations/proc/ResetOccupations() - for(var/mob/new_player/player in player_list) - if((player) && (player.mind)) - player.mind.assigned_role = null - player.mind.special_role = null - SetupOccupations() - unassigned = list() - return /** * This proc is called before the level loop of DivideOccupations() and will try to select a head, * ignoring ALL non-head preferences for every level until it locates a head or runs out of levels to check. */ -/datum/controller/occupations/proc/FillHeadPosition() - for(var/level = 1 to 3) +/datum/controller/subsystem/job/proc/FillHeadPosition() + for(var/level in JOB_PRIORITY_HIGH to JOB_PRIORITY_LOW step -1) for(var/command_position in SSjob.get_job_titles_in_department(DEPARTMENT_COMMAND)) - var/datum/job/job = GetJob(command_position) + var/datum/job/job = get_job(command_position) if(!job) continue var/list/candidates = FindOccupationCandidates(job, level) @@ -206,9 +119,9 @@ var/global/datum/controller/occupations/job_master * This proc is called at the start of the level loop of DivideOccupations() and will cause * head jobs to be checked before any other jobs of the same level. */ -/datum/controller/occupations/proc/CheckHeadPositions(level) +/datum/controller/subsystem/job/proc/CheckHeadPositions(level) for(var/command_position in SSjob.get_job_titles_in_department(DEPARTMENT_COMMAND)) - var/datum/job/job = GetJob(command_position) + var/datum/job/job = get_job(command_position) if(!job) continue var/list/candidates = FindOccupationCandidates(job, level) @@ -223,10 +136,12 @@ var/global/datum/controller/occupations/job_master * fills var "assigned_role" for all ready players. * This proc must not have any side effect besides of modifying "assigned_role". **/ -/datum/controller/occupations/proc/DivideOccupations() +/datum/controller/subsystem/job/proc/DivideOccupations() + /// gather for speed + gather_unassigned() + // todo: optimize this hellproc //Setup new player list and get the jobs list - Debug("Running DO") - SetupOccupations() + job_debug("Running DO") //Holder for Triumvirate is stored in the SSticker, this just processes it if(SSticker && SSticker.triai) @@ -235,38 +150,34 @@ var/global/datum/controller/occupations/job_master A.spawn_positions = 3 break - //Get the players who are ready - for(var/mob/new_player/player in player_list) - if(player.ready && player.mind && !player.mind.assigned_role) - unassigned += player - - Debug("DO, Len: [unassigned.len]") - if(unassigned.len == 0) + job_debug("DO, Len: [divide_unassigned.len]") + if(divide_unassigned.len == 0) + dispose_unassigned() return 0 //Shuffle players and jobs - unassigned = shuffle(unassigned) + divide_unassigned = shuffle(divide_unassigned) HandleFeedbackGathering() //People who wants to be assistants, sure, go on. - Debug("DO, Running Assistant Check 1") + job_debug("DO, Running Assistant Check 1") var/datum/job/assist = new DEFAULT_JOB_TYPE () - var/list/assistant_candidates = FindOccupationCandidates(assist, 3) - Debug("AC1, Candidates: [assistant_candidates.len]") + var/list/assistant_candidates = FindOccupationCandidates(assist, JOB_PRIORITY_HIGH) + job_debug("AC1, Candidates: [assistant_candidates.len]") for(var/mob/new_player/player in assistant_candidates) - Debug("AC1 pass, Player: [player]") + job_debug("AC1 pass, Player: [player]") AssignRole(player, USELESS_JOB) assistant_candidates -= player - Debug("DO, AC1 end") + job_debug("DO, AC1 end") //Select one head - Debug("DO, Running Head Check") + job_debug("DO, Running Head Check") FillHeadPosition() - Debug("DO, Head Check end") + job_debug("DO, Head Check end") //Other jobs are now checked - Debug("DO, Running Standard Check") + job_debug("DO, Running Standard Check") // New job giving system by Donkie @@ -276,87 +187,65 @@ var/global/datum/controller/occupations/job_master // Loop through all levels from high to low var/list/shuffledoccupations = shuffle(occupations) // var/list/disabled_jobs = SSticker.mode.disabled_jobs // So we can use .Find down below without a colon. - for(var/level = 1 to 3) + for(var/level in JOB_PRIORITY_HIGH to JOB_PRIORITY_LOW step -1) //Check the head jobs first each level CheckHeadPositions(level) - // Loop through all unassigned players - for(var/mob/new_player/player in unassigned) + // Loop through all divide_unassigned players + for(var/mob/new_player/player in divide_unassigned) // Loop through all jobs for(var/datum/job/job in shuffledoccupations) // SHUFFLE ME BABY - if(!job || SSticker.mode.disabled_jobs.Find(job.title) ) + if(job.title in SSticker.mode.disabled_jobs) continue - - if(jobban_isbanned(player, job.title)) - Debug("DO isbanned failed, Player: [player], Job:[job.title]") + var/reasons = job.check_client_availability_one(player.client) + if(reasons != ROLE_AVAILABLE) + job_debug("DO failed for [reasons] on [job.id] for [player]") continue - - if(!job.player_old_enough(player.client)) - Debug("DO player not old enough, Player: [player], Job:[job.title]") - continue - // If the player wants that job on this level, then try give it to him. - if(player.client.prefs.GetJobDepartment(job, level) & job.flag) - + if(player.client.prefs.get_job_priority(job) == level) // If the job isn't filled if((job.current_positions < job.spawn_positions) || job.spawn_positions == -1) - Debug("DO pass, Player: [player], Level:[level], Job:[job.title]") + job_debug("DO pass, Player: [player], Level:[level], Job:[job.title]") AssignRole(player, job.title) - unassigned -= player + divide_unassigned -= player break // Hand out random jobs to the people who didn't get any in the last check // Also makes sure that they got their preference correct - for(var/mob/new_player/player in unassigned) - if(player.client.prefs.alternate_option == GET_RANDOM_JOB) + for(var/mob/new_player/player in divide_unassigned) + if(divide_unassigned[player] == JOB_ALTERNATIVE_GET_RANDOM) GiveRandomJob(player) - /* - Old job system - for(var/level = 1 to 3) - for(var/datum/job/job in occupations) - Debug("Checking job: [job]") - if(!job) - continue - if(!unassigned.len) - break - if((job.current_positions >= job.spawn_positions) && job.spawn_positions != -1) - continue - var/list/candidates = FindOccupationCandidates(job, level) - while(candidates.len && ((job.current_positions < job.spawn_positions) || job.spawn_positions == -1)) - var/mob/new_player/candidate = pick(candidates) - Debug("Selcted: [candidate], for: [job.title]") - AssignRole(candidate, job.title) - candidates -= candidate*/ - Debug("DO, Standard Check end") + job_debug("DO, Standard Check end") - Debug("DO, Running AC2") + job_debug("DO, Running AC2") // For those who wanted to be assistant if their preferences were filled, here you go. - for(var/mob/new_player/player in unassigned) - if(player.client.prefs.alternate_option == BE_ASSISTANT) - Debug("AC2 Assistant located, Player: [player]") + for(var/mob/new_player/player in divide_unassigned) + if(divide_overflows[player] == JOB_ALTERNATIVE_BE_ASSISTANT) + job_debug("AC2 Assistant located, Player: [player]") AssignRole(player, USELESS_JOB) //For ones returning to lobby - for(var/mob/new_player/player in unassigned) - if(player.client.prefs.alternate_option == RETURN_TO_LOBBY) + for(var/mob/new_player/player in divide_unassigned) + if(divide_overflows[player] == JOB_ALTERNATIVE_RETURN_LOBBY) player.ready = 0 - player.new_player_panel_proc() - unassigned -= player + INVOKE_ASYNC(player, /mob/new_player/proc/new_player_panel_proc) + divide_unassigned -= player + dispose_unassigned() return 1 - -/datum/controller/occupations/proc/EquipRank(mob/living/carbon/human/H, rank, joined_late = 0) +/datum/controller/subsystem/job/proc/EquipRank(mob/living/carbon/human/H, rank, joined_late = 0) if(!H) return null - var/datum/job/job = GetJob(rank) + var/datum/job/job = get_job(rank) var/list/spawn_in_storage = list() + var/real_species_name = H.species.name if(!joined_late) - var/obj/landmark/spawnpoint/S = SSjob.GetRoundstartSpawnpoint(H, H.client, job.type, job.faction) + var/obj/landmark/spawnpoint/S = SSjob.get_roundstart_spawnpoint(H, H.client, job.type, job.faction) if(istype(S)) H.forceMove(S.GetSpawnLoc()) @@ -397,7 +286,7 @@ var/global/datum/controller/occupations/job_master permitted = 1 // Check if they're whitelisted for this gear (in alien whitelist? seriously?) - if(G.whitelisted && !is_alien_whitelisted(H, name_static_species_meta(G.whitelisted))) + if(G.legacy_species_lock && (real_species_name != G.legacy_species_lock)) permitted = 0 // If they aren't, tell them @@ -570,7 +459,7 @@ var/global/datum/controller/occupations/job_master H.update_hud_antag() return H -/datum/controller/occupations/proc/LoadJobs(jobsfile) //ran during round setup, reads info from jobs.txt -- Urist +/datum/controller/subsystem/job/proc/LoadJobs(jobsfile) //ran during round setup, reads info from jobs.txt -- Urist if(!config_legacy.load_jobs_from_txt) return 0 @@ -595,7 +484,7 @@ var/global/datum/controller/occupations/job_master continue if(name && value) - var/datum/job/J = GetJob(name) + var/datum/job/J = get_job(name) if(!J) continue J.total_positions = text2num(value) J.spawn_positions = text2num(value) @@ -605,7 +494,7 @@ var/global/datum/controller/occupations/job_master return 1 -/datum/controller/occupations/proc/HandleFeedbackGathering() +/datum/controller/subsystem/job/proc/HandleFeedbackGathering() for(var/datum/job/job in occupations) var/tmp_str = "|[job.title]|" @@ -615,7 +504,7 @@ var/global/datum/controller/occupations/job_master var/level4 = 0 //never var/level5 = 0 //banned var/level6 = 0 //account too young - for(var/mob/new_player/player in player_list) + for(var/mob/new_player/player in GLOB.player_list) if(!(player.ready && player.mind && !player.mind.assigned_role)) continue //This player is not ready if(jobban_isbanned(player, job.title)) @@ -624,18 +513,20 @@ var/global/datum/controller/occupations/job_master if(!job.player_old_enough(player.client)) level6++ continue - if(player.client.prefs.GetJobDepartment(job, 1) & job.flag) - level1++ - else if(player.client.prefs.GetJobDepartment(job, 2) & job.flag) - level2++ - else if(player.client.prefs.GetJobDepartment(job, 3) & job.flag) - level3++ - else level4++ //not selected + switch(player.client.prefs.get_job_priority(job)) + if(JOB_PRIORITY_HIGH) + level1++ + if(JOB_PRIORITY_MEDIUM) + level2++ + if(JOB_PRIORITY_LOW) + level3++ + else + level4++ tmp_str += "HIGH=[level1]|MEDIUM=[level2]|LOW=[level3]|NEVER=[level4]|BANNED=[level5]|YOUNG=[level6]|-" feedback_add_details("job_preferences",tmp_str) -/datum/controller/occupations/proc/LateSpawn(client/C, rank) +/datum/controller/subsystem/job/proc/LateSpawn(client/C, rank) var/fail_deadly = FALSE @@ -661,7 +552,7 @@ var/global/datum/controller/occupations/job_master . = list("spawnpoint") if(spawnpos && istype(spawnpos)) if(spawnpos.check_job_spawning(rank)) - S = SSjob.GetLatejoinSpawnpoint(method = preferred_method, job_path = J.type, faction = J.faction) + S = SSjob.get_latejoin_spawnpoint(method = preferred_method, job_path = J.type, faction = J.faction) .["spawnpoint"] = S .["channel"] = spawnpos.announce_channel else @@ -669,6 +560,6 @@ var/global/datum/controller/occupations/job_master to_chat(C, SPAN_WARNING("Your chosen spawnpoint ([spawnpos.display_name]) is unavailable for your chosen job. Please correct your spawn point choice.")) return to_chat(C, SPAN_WARNING("Your chosen spawnpoint ([spawnpos.display_name]) is unavailable for your chosen job. Spawning you at the Arrivals shuttle instead.")) - .["spawnpoint"] = SSjob.GetLatejoinSpawnpoint(J.faction) + .["spawnpoint"] = SSjob.get_latejoin_spawnpoint(J.faction) else if(!fail_deadly) - .["spawnpoint"] = SSjob.GetLatejoinSpawnpoint(J.faction) + .["spawnpoint"] = SSjob.get_latejoin_spawnpoint(J.faction) diff --git a/code/controllers/subsystem/job/job_manager.dm b/code/controllers/subsystem/job/job_manager.dm new file mode 100644 index 00000000000..d6f34440d02 --- /dev/null +++ b/code/controllers/subsystem/job/job_manager.dm @@ -0,0 +1,64 @@ +// todo: refactor _job.dm +/datum/controller/subsystem/job + +/datum/controller/subsystem/job/proc/job_by_id(id) + RETURN_TYPE(/datum/job) + return job_lookup[id] + +/datum/controller/subsystem/job/proc/job_by_type(path) + RETURN_TYPE(/datum/job) + return type_occupations[path] + +// todo: this should not be used most of the time, id/type is better +/datum/controller/subsystem/job/proc/job_by_title(title) + RETURN_TYPE(/datum/job) + return name_occupations[title] + +/datum/controller/subsystem/job/proc/all_job_ids(faction) + RETURN_TYPE(/list) + . = list() + if(faction) + for(var/datum/job/J as anything in occupations) + if(J.faction != faction) + continue + . += J.id + else + for(var/id as anything in job_lookup) + . += id + +/datum/controller/subsystem/job/proc/all_job_types(faction) + RETURN_TYPE(/list) + . = list() + if(faction) + for(var/datum/job/J as anything in occupations) + if(J.faction != faction) + continue + . += J.type + else + for(var/path as anything in type_occupations) + . += path + +// todo: avoid doing this where possible, id/type is better +/datum/controller/subsystem/job/proc/all_job_titles(faction) + RETURN_TYPE(/list) + . = list() + if(faction) + for(var/datum/job/J as anything in occupations) + if(J.faction != faction) + continue + . += J.title + else + for(var/title as anything in name_occupations) + . += title + +/datum/controller/subsystem/job/proc/all_jobs(faction) + RETURN_TYPE(/list) + . = list() + if(faction) + for(var/datum/job/J as anything in occupations) + if(J.faction != faction) + continue + . += J + else + for(var/datum/job/J as anything in occupations) + . += J diff --git a/code/controllers/subsystem/job/joining.dm b/code/controllers/subsystem/job/joining.dm new file mode 100644 index 00000000000..009201c7544 --- /dev/null +++ b/code/controllers/subsystem/job/joining.dm @@ -0,0 +1,219 @@ +/* +/datum/controller/subsystem/job/proc/ProcessRoundstartPlayer(mob/M, datum/job/J, loadout = TRUE, client/C) + // autodetect + if(!C) + C = M.client + if(!J && M.mind) + J = GetJobAuto(M.mind?.assigned_role) + // sigh make sure mind is set + if(J) + M.mind?.assigned_role = J.title + M.job = J.title + EquipPlayer(M, J, loadout, C.prefs, TRUE, FALSE, C) + J.after_spawn(M, FALSE, C) + GreetPlayer(M, J, TRUE, C) + if(!J?.override_latejoin_spawn(M)) + SendToRoundstart(M, C, J) + PostJoin(M, J, C, FALSE) + +/datum/controller/subsystem/job/proc/ProcessLatejoinPlayer(mob/M, datum/job/J, loadout = TRUE, client/C) + // autodetect + if(!C) + C = M.client + if(!J && M.mind) + J = GetJobAuto(M.mind?.assigned_role) + // sigh make sure mind is set + if(J) + M.mind.assigned_role = J.title + M.job = J.title + EquipPlayer(M, J, loadout, C.prefs, TRUE, TRUE, C) + J.after_spawn(M, TRUE, C) + GreetPlayer(M, J, TRUE, C) + if(!J?.override_latejoin_spawn(M)) + SendToLatejoin(M, C, job = J) + PostJoin(M, J, C, TRUE) + +/datum/controller/subsystem/job/proc/GreetPlayer(mob/M, datum/job/J, latejoin, client/C) + var/client/output = C || M.client + if(!J) + return + var/effective_title = output.prefs.GetPreferredAltTitle(J.title) + to_chat(output, span_bold("You are the [effective_title]")) + to_chat(output, span_bold("As the [effective_title] you answer directly to [J.GetSupervisorText()]. Special circumstances may change this.")) + J.radio_help_message(M) + if(J.req_admin_notify) + to_chat(output, "You are playing a job that is important for Game Progression. If you have to disconnect immediately, please notify the admins via adminhelp. Otherwise put your locker gear back into the locker and cryo out.") + if(J.custom_spawn_text) + to_chat(output, "[J.custom_spawn_text]") + if(CONFIG_GET(number/minimal_access_threshold)) + to_chat(output, "As this station was initially staffed with a [CONFIG_GET(flag/jobs_have_minimal_access) ? "full crew, only your job's necessities" : "skeleton crew, additional access may"] have been added to your ID card.") + if(ishuman(M)) + var/mob/living/carbon/human/wageslave = M + to_chat(output, "Your account ID is [wageslave.account_id].") + M.add_memory("Your account ID is [wageslave.account_id].") + +/datum/controller/subsystem/job/proc/EquipPlayer(mob/M, datum/job/J, loadout = TRUE, datum/preferences/prefs, announce, latejoin, client/C) + if(!istype(J)) + J = GetJobAuto(J) + ASSERT(istype(J)) + // attempt autodetect prefs + if(!prefs) + prefs = M.client?.prefs + // if dress code compliant or no job, do loadout only. otherwise, do loadout first or job first based on dress code compliance + var/list/obj/item/leftovers + if(!J || !J.dresscodecompliant) + leftovers = EquipLoadout(M, FALSE, null, prefs, C) + HandleLoadoutLeftovers(M, leftovers, null, C) + return + + J.equip(M, FALSE, announce, latejoin, null, prefs) + + if(J.dresscodecompliant) + leftovers = EquipLoadout(M, FALSE, null, prefs, C) + + HandleLoadoutLeftovers(M, leftovers, null, C) + +/datum/controller/subsystem/job/proc/PostJoin(mob/M, datum/job/J, client/C, latejoin) + // job handling + if(J) + SSpersistence.antag_rep_change[M.client.ckey] += J.GetAntagRep() + + // auto deadmin + if(M.client.holder) + if(CONFIG_GET(flag/auto_deadmin_players) || (M.client.prefs?.deadmin & DEADMIN_ALWAYS)) + M.client.holder.auto_deadmin() + else + handle_auto_deadmin_roles(M.client, J) + + // tcg card handling + var/list/tcg_cards = C.prefs.tcg_cards + var/list/tcg_decks = C.prefs.tcg_decks + if(tcg_cards && ishuman(M)) + var/mob/living/carbon/human/H = M + var/obj/item/tcgcard_binder/binder = new(get_turf(H)) + H.equip_to_slot_if_possible(binder, ITEM_SLOT_BACKPACK, disable_warning = TRUE, bypass_equip_delay_self = TRUE) + for(var/card_type in tcg_cards) + if(card_type) + if(islist(tcg_cards[card_type])) + for(var/duplicate in tcg_cards[card_type]) + var/obj/item/tcg_card/card = new(get_turf(H), card_type, duplicate) + card.forceMove(binder) + binder.cards.Add(card) + else + var/obj/item/tcg_card/card = new(get_turf(H), card_type, tcg_cards[card_type]) + card.forceMove(binder) + binder.cards.Add(card) + binder.check_for_exodia() + if(length(tcg_decks)) + binder.decks = tcg_decks + + if(latejoin) + AnnounceJoin(M, J, C) + +/datum/controller/subsystem/job/proc/AnnounceJoin(mob/M, datum/job/J, client/C) + if(istype(get_area(M), /area/shuttle/arrival) && SSshuttle.arrivals) + SSshuttle.arrivals.QueueAnnounce(M, J.title) + else + AnnounceArrival(M, J.title) +/** + * Assigns a player to a role. + * @params + * - M - mind or mob + * - J - job , job title, or job type + * - latejoin - latejoining mob? + * - force - bypass checks + */ +/datum/controller/subsystem/job/proc/Assign(datum/mind/M, datum/job/J, latejoin = FALSE, force = FALSE) + if(ismob(M)) + var/mob/_M = M + M = _M.mind + if(!istype(M)) + CRASH("Invalid mind.") + if(!istype(J)) + J = GetJobAuto(J) + if(!istype(J)) + CRASH("Invalid job.") + JobDebug("ASSIGN: [M], [J], latejoin: [latejoin]") + if(!force && !CanAssign(M, J, latejoin)) + JobDebug("ASSIGN: Failed CanAssign") + return FALSE + JobDebug("ASSIGN: Passed: JCP: [J.current_positions] (incremented)") + M.assigned_role = J.title + // hook into roundstart system so it doesn't have to call this manually + if(unassigned) + unassigned -= M.current + J.current_positions++ + return TRUE + +/datum/controller/subsystem/job/proc/CanAssign(M, datum/job/J, latejoin) + var/mob/checking = ismob(M) && M + if(!checking) + if(istype(M, /datum/mind)) + var/datum/mind/_M = M + checking = _M.current + if(istype(M, /client)) + var/client/_C = M + checking = _C.mob + . = FALSE + if(!checking) + CRASH("No mob") + if(!istype(J)) + CRASH("No job") + if(jobban_isbanned(checking, J.title)) + return FALSE + if(!J.player_old_enough(checking.client)) + return FALSE + if(J.required_playtime_remaining(checking.client)) + return FALSE + var/position_limit = latejoin? J.total_positions : J.roundstart_positions + if(J.current_positions + 1 > position_limit) + return FALSE + return TRUE + +/** + * Sends a mob to a spawnpoint. Set override = TRUE to disable auto-detect of job. + */ +/datum/controller/subsystem/job/proc/SendToLatejoin(mob/M, client/C = M.client, faction, job, method, override) + if(!override && M.mind?.assigned_role) + var/datum/job/J = SSjob.GetJobName(M.mind.assigned_role) + if(J) + faction = J.faction + job = J.GetID() + + var/atom/movable/landmark/spawnpoint/S + + S = SSjob.GetLatejoinSpawnpoint(C, job, faction, method) + + if(S) + M.forceMove(S.GetSpawnLoc()) + S.OnSpawn(M, C) + else + var/error_message = "Unable to send [key_name(M)] to latejoin." + message_admins(error_message) + subsystem_log(error_message) + CRASH(error_message) // this is serious. + +/datum/controller/subsystem/job/proc/SendToRoundstart(mob/M, client/C, datum/job/J) + var/atom/movable/landmark/spawnpoint/S = GetRoundstartSpawnpoint(M, C, J.GetID(), J.faction) + if(!S) + stack_trace("Couldn't find a roundstart spawnpoint for [M] ([C]) - [J.type] ([J.faction]).") + SendToLatejoin(M) + else + var/atom/A = S.GetSpawnLoc() + M.forceMove(A) + S.OnSpawn(M, C) + +/datum/controller/subsystem/job/proc/handle_auto_deadmin_roles(client/C, rank) + if(!C?.holder) + return TRUE + var/datum/job/job = GetJobAuto(rank) + if(!job) + return + if((job.auto_deadmin_role_flags & DEADMIN_POSITION_HEAD) && (CONFIG_GET(flag/auto_deadmin_heads) || (C.prefs?.deadmin & DEADMIN_POSITION_HEAD))) + return C.holder.auto_deadmin() + else if((job.auto_deadmin_role_flags & DEADMIN_POSITION_SECURITY) && (CONFIG_GET(flag/auto_deadmin_security) || (C.prefs?.deadmin & DEADMIN_POSITION_SECURITY))) + return C.holder.auto_deadmin() + else if((job.auto_deadmin_role_flags & DEADMIN_POSITION_SILICON) && (CONFIG_GET(flag/auto_deadmin_silicons) || (C.prefs?.deadmin & DEADMIN_POSITION_SILICON))) //in the event there's ever psuedo-silicon roles added, ie synths. + return C.holder.auto_deadmin() + +*/ diff --git a/code/controllers/subsystem/job/roundstart.dm b/code/controllers/subsystem/job/roundstart.dm new file mode 100644 index 00000000000..7c2651ba752 --- /dev/null +++ b/code/controllers/subsystem/job/roundstart.dm @@ -0,0 +1,397 @@ +/datum/controller/subsystem/job + /// players who need jobs + var/list/mob/new_player/divide_unassigned + /// cached list of job priorities by the player + var/list/mob/new_player/divide_priorities + /// cached list of job overflow preferences by the player + var/list/mob/new_player/divide_overflows + +/datum/controller/subsystem/job/proc/reset_occupations() + dispose_unassigned() + for(var/mob/new_player/NP in GLOB.player_list) + if(NP?.mind) + NP.mind.assigned_role = null + NP.mind.special_role = null + setup_occupations() + +/datum/controller/subsystem/job/proc/gather_unassigned() + //Get the players who are ready + divide_unassigned = list() + divide_priorities = list() + divide_overflows = list() + for(var/mob/new_player/player in GLOB.player_list) + if(!player.client) // git out + continue + if(player.ready && player.mind && !player.mind.assigned_role) + divide_unassigned += player + var/list/priorities = player.client.effective_job_priorities() + var/overflow_mode = player.client.prefs.get_job_alternative() + divide_priorities[player] = priorities + divide_overflows[player] = overflow_mode + +/datum/controller/subsystem/job/proc/dispose_unassigned() + divide_unassigned = null + divide_priorities = null + divide_overflows = null + +// todo: "why did you not just move everything?" +// because although splitting everything into procs that re-query the prefs every single time +// to figure out what people want to be, which while readable and workable, +// is hellishly slow +// i'm going to figure out if i can speed it up BEFORE rewriting everything. + +/* +/datum/controller/subsystem/job/proc/FindOccupationCandidates(datum/job/job, level, flag) + JobDebug("Running FOC, Job: [job], Level: [level], Flag: [flag]") + var/list/candidates = list() + for(var/mob/new_player/player in unassigned) + if(jobban_isbanned(player, job.title) || QDELETED(player)) + JobDebug("FOC isbanned failed, Player: [player]") + continue + if(!job.player_old_enough(player.client)) + JobDebug("FOC player not old enough, Player: [player]") + continue + if(job.required_playtime_remaining(player.client)) + JobDebug("FOC player not enough xp, Player: [player]") + continue + if(!player.client.prefs.pref_species.qualifies_for_rank(job.title, player.client.prefs.features)) + JobDebug("FOC non-human failed, Player: [player]") + continue + if(flag && (!(flag in player.client.prefs.be_special))) + JobDebug("FOC flag failed, Player: [player], Flag: [flag], ") + continue + if(player.mind && (job.title in player.mind.restricted_roles)) + JobDebug("FOC incompatible with antagonist role, Player: [player]") + continue + if(player.client.prefs.job_preferences[job.title] == level) + JobDebug("FOC pass, Player: [player], Level:[level]") + candidates += player + return candidates + +/datum/controller/subsystem/job/proc/GiveRandomJob(mob/new_player/player) + JobDebug("GRJ Giving random job, Player: [player]") + . = FALSE + for(var/datum/job/job in shuffle(GetAllJobs())) + if(!job) + continue + + if(istype(job, GetJobName(SSjob.overflow_role))) // We don't want to give him assistant, that's boring! + continue + + if(job.IsInDepartment(/datum/department/command)) //If you want a command position, select it! + continue + + if(jobban_isbanned(player, job.title) || QDELETED(player)) + if(QDELETED(player)) + JobDebug("GRJ isbanned failed, Player deleted") + break + JobDebug("GRJ isbanned failed, Player: [player], Job: [job.title]") + continue + + if(!job.player_old_enough(player.client)) + JobDebug("GRJ player not old enough, Player: [player]") + continue + + if(!player.client.prefs.pref_species.qualifies_for_rank(job.title, player.client.prefs.features)) + JobDebug("GRJ non-human failed, Player: [player]") + continue + + if(job.required_playtime_remaining(player.client)) + JobDebug("GRJ player not enough xp, Player: [player]") + continue + + if(player.mind && (job.title in player.mind.restricted_roles)) + JobDebug("GRJ incompatible with antagonist role, Player: [player], Job: [job.title]") + continue + + if((job.current_positions < job.roundstart_positions) || job.roundstart_positions == -1) + JobDebug("GRJ Random job given, Player: [player], Job: [job]") + if(Assign(player, job.title)) + return TRUE + +/datum/controller/subsystem/job/proc/reset_occupations() + JobDebug("Occupations reset.") + for(var/mob/new_player/player in GLOB.GLOB.player_list) + if((player) && (player.mind)) + player.mind.assigned_role = null + player.mind.special_role = null + SSpersistence.antag_rep_change[player.ckey] = 0 + SetupOccupations() + unassigned = list() + +//This proc is called before the level loop of DivideOccupations() and will try to select a head, ignoring ALL non-head preferences for every level until +//it locates a head or runs out of levels to check +//This is basically to ensure that there's atleast a few heads in the round +/datum/controller/subsystem/job/proc/FillHeadPosition() + for(var/level in level_order) + for(var/datum/job/job as anything in GetDepartmentJobDatums(/datum/department/command)) + if(!job) + continue + if((job.current_positions >= job.total_positions) && job.total_positions != -1) + continue + var/list/candidates = FindOccupationCandidates(job, level) + if(!candidates?.len) + continue + var/mob/new_player/candidate = pick(candidates) + if(Assign(candidate, job)) + return 1 + return 0 + +//This proc is called at the start of the level loop of DivideOccupations() and will cause head jobs to be checked before any other jobs of the same level +//This is also to ensure we get as many heads as possible +/datum/controller/subsystem/job/proc/CheckHeadPositions(level) + for(var/datum/job/job as anything in GetDepartmentJobDatums(/datum/department/command)) + if(!job) + continue + if((job.current_positions >= job.total_positions) && job.total_positions != -1) + continue + var/list/candidates = FindOccupationCandidates(job, level) + if(!candidates?.len) + continue + var/mob/new_player/candidate = pick(candidates) + Assign(candidate, job) + +/datum/controller/subsystem/job/proc/FillAIPosition() + var/ai_selected = 0 + var/datum/job/job = GetJobType(/datum/job/ai) + if(!job) + return 0 + for(var/i = job.total_positions, i > 0, i--) + for(var/level in level_order) + var/list/candidates = list() + candidates = FindOccupationCandidates(job, level) + if(candidates.len) + var/mob/new_player/candidate = pick(candidates) + if(Assign(candidate, "AI")) + ai_selected++ + break + if(ai_selected) + return 1 + return 0 + +/** Proc DivideOccupations + * fills var "assigned_role" for all ready players. + * This proc must not have any side effect besides of modifying "assigned_role". + **/ +/datum/controller/subsystem/job/proc/DivideOccupations(list/required_jobs) + //Setup new player list and get the jobs list + JobDebug("Running DO") + + //Holder for Triumvirate is stored in the SSticker, this just processes it + if(SSticker.triai) + for(var/datum/job/ai/A in GetAllJobs()) + A.roundstart_positions = 3 + var/left = 2 + for(var/atom/movable/landmark/spawnpoint/job/ai/secondary/S in GetAllSpawnpoints()) + if(!left) + break + left-- + S.latejoin_active = TRUE + + //Get the players who are ready + for(var/mob/new_player/player in GLOB.GLOB.player_list) + if(player.ready == PLAYER_READY_TO_PLAY && player.check_preferences() && player.mind && !player.mind.assigned_role) + unassigned += player + + initial_players_to_assign = unassigned.len + + JobDebug("DO, Len: [unassigned?.len]") + if(unassigned.len == 0) + return validate_required_jobs(required_jobs) + + //Scale number of open security officer slots to population + setup_officer_positions() + + //Jobs will have fewer access permissions if the number of players exceeds the threshold defined in game_options.txt + var/mat = CONFIG_GET(number/minimal_access_threshold) + if(mat) + if(mat > unassigned.len) + CONFIG_SET(flag/jobs_have_minimal_access, FALSE) + else + CONFIG_SET(flag/jobs_have_minimal_access, TRUE) + + //Shuffle players and jobs + unassigned = shuffle(unassigned) + + HandleFeedbackGathering() + + //People who wants to be the overflow role, sure, go on. + JobDebug("DO, Running Overflow Check 1") + var/datum/job/overflow = GetJobName(SSjob.overflow_role) + var/list/overflow_candidates = FindOccupationCandidates(overflow, JP_LOW) + JobDebug("AC1, Candidates: [overflow_candidates?.len]") + for(var/mob/new_player/player in overflow_candidates) + JobDebug("AC1 pass, Player: [player]") + Assign(player, SSjob.overflow_role) + overflow_candidates -= player + JobDebug("DO, AC1 end") + + //Select one head + JobDebug("DO, Running Head Check") + FillHeadPosition() + JobDebug("DO, Head Check end") + + //Check for an AI + JobDebug("DO, Running AI Check") + FillAIPosition() + JobDebug("DO, AI Check end") + + //Other jobs are now checked + JobDebug("DO, Running Standard Check") + + + // New job giving system by Donkie + // This will cause lots of more loops, but since it's only done once it shouldn't really matter much at all. + // Hopefully this will add more randomness and fairness to job giving. + + // Loop through all levels from high to low + var/list/shuffledoccupations = shuffle(GetAllJobs()) + for(var/level in level_order) + //Check the head jobs first each level + CheckHeadPositions(level) + + // Loop through all unassigned players + for(var/mob/new_player/player in unassigned) + if(PopcapReached()) + RejectPlayer(player) + + // Loop through all jobs + for(var/datum/job/job in shuffledoccupations) // SHUFFLE ME BABY + if(!job) + continue + + if(jobban_isbanned(player, job.title)) + JobDebug("DO isbanned failed, Player: [player], Job:[job.title]") + continue + + if(QDELETED(player)) + JobDebug("DO player deleted during job ban check") + break + + if(!job.player_old_enough(player.client)) + JobDebug("DO player not old enough, Player: [player], Job:[job.title]") + continue + + if(job.required_playtime_remaining(player.client)) + JobDebug("DO player not enough xp, Player: [player], Job:[job.title]") + continue + + if(!player.client.prefs.pref_species.qualifies_for_rank(job.title, player.client.prefs.features)) + JobDebug("DO non-human failed, Player: [player], Job:[job.title]") + continue + + if(player.mind && (job.title in player.mind.restricted_roles)) + JobDebug("DO incompatible with antagonist role, Player: [player], Job:[job.title]") + continue + + // If the player wants that job on this level, then try give it to him. + if(player.client.prefs.job_preferences[job.title] == level) + // If the job isn't filled + if((job.current_positions < job.roundstart_positions) || job.roundstart_positions == -1) + JobDebug("DO pass, Player: [player], Level:[level], Job:[job.title]") + Assign(player, job.title) + unassigned -= player + break + + + JobDebug("DO, Handling unassigned.") + // Hand out random jobs to the people who didn't get any in the last check + // Also makes sure that they got their preference correct + for(var/mob/new_player/player in unassigned) + HandleUnassigned(player) + + JobDebug("DO, Handling unrejectable unassigned") + //Mop up people who can't leave. + for(var/mob/new_player/player in unassigned) //Players that wanted to back out but couldn't because they're antags (can you feel the edge case?) + if(!GiveRandomJob(player)) + if(!Assign(player, SSjob.overflow_role)) //If everything is already filled, make them an assistant + return FALSE //Living on the edge, the forced antagonist couldn't be assigned to overflow role (bans, client age) - just reroll + + return validate_required_jobs(required_jobs) + +/datum/controller/subsystem/job/proc/validate_required_jobs(list/required_jobs) + if(!required_jobs.len) + return TRUE + for(var/required_group in required_jobs) + var/group_ok = TRUE + for(var/rank in required_group) + var/datum/job/J = GetJobName(rank) + if(!J) + SSticker.mode.setup_error = "Invalid job [rank] in gamemode required jobs." + return FALSE + if(J.current_positions < required_group[rank]) + group_ok = FALSE + break + if(group_ok) + return TRUE + SSticker.mode.setup_error = "Required jobs not present." + return FALSE + +//We couldn't find a job from prefs for this guy. +/datum/controller/subsystem/job/proc/HandleUnassigned(mob/new_player/player) + if(PopcapReached()) + RejectPlayer(player) + else if(player.client.prefs.joblessrole == BEOVERFLOW) + var/allowed_to_be_a_loser = !jobban_isbanned(player, SSjob.overflow_role) + if(QDELETED(player) || !allowed_to_be_a_loser) + RejectPlayer(player) + else + if(!Assign(player, SSjob.overflow_role)) + RejectPlayer(player) + else if(player.client.prefs.joblessrole == BERANDOMJOB) + if(!GiveRandomJob(player)) + RejectPlayer(player) + else if(player.client.prefs.joblessrole == RETURNTOLOBBY) + RejectPlayer(player) + else //Something gone wrong if we got here. + var/message = "DO: [player] fell through handling unassigned" + JobDebug(message) + log_game(message) + message_admins(message) + RejectPlayer(player) + + +/datum/controller/subsystem/job/proc/setup_officer_positions() + var/datum/job/J = SSjob.GetJobType(/datum/job/officer) + if(!J) + CRASH("setup_officer_positions(): Security officer job is missing") + + var/ssc = CONFIG_GET(number/security_scaling_coeff) + if(ssc > 0) + if(J.roundstart_positions > 0) + var/officer_positions = min(12, max(J.roundstart_positions, round(unassigned.len / ssc))) //Scale between configured minimum and 12 officers + JobDebug("Setting open security officer positions to [officer_positions]") + J.total_positions = officer_positions + J.roundstart_positions = officer_positions + + //Spawn some extra eqipment lockers if we have more than 5 officers + var/equip_needed = J.total_positions + if(equip_needed < 0) // -1: infinite available slots + equip_needed = 12 + for(var/i=equip_needed-5, i>0, i--) + if(GLOB.secequipment.len) + var/spawnloc = GLOB.secequipment[1] + new /obj/structure/closet/secure_closet/security/sec(spawnloc) + GLOB.secequipment -= spawnloc + else //We ran out of spare locker spawns! + break + +/datum/controller/subsystem/job/proc/RejectPlayer(mob/new_player/player) + if(player.mind && player.mind.special_role) + return + if(PopcapReached()) + JobDebug("Popcap overflow Check observer located, Player: [player]") + JobDebug("Player rejected :[player]") + to_chat(player, "You have failed to qualify for any job you desired.") + unassigned -= player + player.ready = PLAYER_NOT_READY + +/datum/controller/subsystem/job/proc/PopcapReached() + var/hpc = CONFIG_GET(number/hard_popcap) + var/epc = CONFIG_GET(number/extreme_popcap) + if(hpc || epc) + var/relevent_cap = max(hpc, epc) + if((initial_players_to_assign - unassigned.len) >= relevent_cap) + return TRUE + return FALSE +*/ diff --git a/code/controllers/subsystem/job/spawnpoints.dm b/code/controllers/subsystem/job/spawnpoints.dm index 185cd703361..c08480ccb0e 100644 --- a/code/controllers/subsystem/job/spawnpoints.dm +++ b/code/controllers/subsystem/job/spawnpoints.dm @@ -13,7 +13,7 @@ /** * Fully resets spawnpoints list and ensures validity */ -/datum/controller/subsystem/job/proc/ReconstructSpawnpoints() +/datum/controller/subsystem/job/proc/reconstruct_spawnpoints() spawnpoints = list() job_spawnpoints = list() latejoin_spawnpoints = list() @@ -51,7 +51,7 @@ * - harder - used when the first iteration failed, tells spawnpoints to skip certain checks * */ -/datum/controller/subsystem/job/proc/GetRoundstartSpawnpoint(mob/M, client/C, job_path, faction, random = TRUE, harder = FALSE) +/datum/controller/subsystem/job/proc/get_roundstart_spawnpoint(mob/M, client/C, job_path, faction, random = TRUE, harder = FALSE) RETURN_TYPE(/obj/landmark/spawnpoint) if(random) . = list() @@ -80,10 +80,10 @@ if(random && length(.)) return pick(.) if(!harder) - subsystem_log("GetRoundstartSpawnpoint() failed to get a spawnpoint, trying against with harder = TRUE") - return GetRoundstartSpawnpoint(M, C, job_path, faction, random, TRUE) + subsystem_log("get_roundstart_spawnpoint() failed to get a spawnpoint, trying against with harder = TRUE") + return get_roundstart_spawnpoint(M, C, job_path, faction, random, TRUE) else - CRASH("GetRoundstartSpawnpoint() failed to get a spawnpoint.") + CRASH("get_roundstart_spawnpoint() failed to get a spawnpoint.") /** * Gets a spawnpoint to use for a latejoin spawn @@ -99,7 +99,7 @@ * - random - deterministic first pick or random? * - harder - used when the first iteration failed, tells spawnpoints to skip certain checks */ -/datum/controller/subsystem/job/proc/GetLatejoinSpawnpoint(client/C, job_path, faction = JOB_FACTION_STATION, method, random = TRUE, harder = FALSE) +/datum/controller/subsystem/job/proc/get_latejoin_spawnpoint(client/C, job_path, faction = JOB_FACTION_STATION, method, random = TRUE, harder = FALSE) RETURN_TYPE(/obj/landmark/spawnpoint) if(random) . = list() // Priority 1: Job specific spawnpoints @@ -145,10 +145,10 @@ else . = null if(!harder) - subsystem_log("GetLatejoinSpawnpoint() failed to get a spawnpoint, trying against with harder = TRUE") - return GetRoundstartSpawnpoint(C, job_path, faction, method, random, TRUE) + subsystem_log("get_latejoin_spawnpoint() failed to get a spawnpoint, trying against with harder = TRUE") + return get_roundstart_spawnpoint(C, job_path, faction, method, random, TRUE) else - CRASH("GetLatejoinSpawnpoint() failed to get a spawnpoint.") + CRASH("get_latejoin_spawnpoint() failed to get a spawnpoint.") /** * Gets a list of possible join methods @@ -162,7 +162,7 @@ * - job_path - (optional) path to job * - faction - what faction the player is in terms of job factions */ -/datum/controller/subsystem/job/proc/PossibleLatejoinSpawnpoints(client/C, job_path, faction) +/datum/controller/subsystem/job/proc/possible_latejoin_spawnpoints(client/C, job_path, faction) . = list() // Get all job specific methods, and allow for override if needed if(job_path && length(job_spawnpoints[job_path])) @@ -194,7 +194,7 @@ * - C - (optional) client of player * - key - spawnpoint key to look for */ -/datum/controller/subsystem/job/proc/GetCustomSpawnpoint(mob/M, client/C, key) +/datum/controller/subsystem/job/proc/get_custom_spawnpoint(mob/M, client/C, key) if(!length(custom_spawnpoints[key])) return for(var/obj/landmark/spawnpoint/S as anything in custom_spawnpoints[key]) @@ -205,5 +205,5 @@ /** * Get all spawnpoint landmarks */ -/datum/controller/subsystem/job/proc/GetAllSpawnpoints() +/datum/controller/subsystem/job/proc/get_all_spawnpoints() return spawnpoints diff --git a/code/controllers/subsystem/mobs.dm b/code/controllers/subsystem/mobs.dm index caddc2c87cd..608abd19889 100644 --- a/code/controllers/subsystem/mobs.dm +++ b/code/controllers/subsystem/mobs.dm @@ -27,7 +27,7 @@ SUBSYSTEM_DEF(mobs) slept_mobs = 0 src.currentrun = GLOB.mob_list.Copy() busy_z_levels.Cut() - for(var/played_mob in player_list) + for(var/played_mob in GLOB.player_list) if(!played_mob || isobserver(played_mob)) continue var/mob/pm = played_mob diff --git a/code/controllers/subsystem/nightshift.dm b/code/controllers/subsystem/nightshift.dm index 1105e7be847..27dca33951b 100644 --- a/code/controllers/subsystem/nightshift.dm +++ b/code/controllers/subsystem/nightshift.dm @@ -33,7 +33,7 @@ SUBSYSTEM_DEF(nightshift) /datum/controller/subsystem/nightshift/proc/check_nightshift(check_canfire=FALSE) //This is called from elsewhere, like setting the alert levels if(check_canfire && !can_fire) return - var/emergency = security_level > SEC_LEVEL_GREEN + var/emergency = GLOB.security_level > SEC_LEVEL_GREEN var/announcing = TRUE var/time = station_time() var/night_time = (time < nightshift_end_time) || (time > nightshift_start_time) diff --git a/code/controllers/subsystem/persist_vr.dm b/code/controllers/subsystem/persist_vr.dm index b3cde7aaa1c..36745c3b41e 100644 --- a/code/controllers/subsystem/persist_vr.dm +++ b/code/controllers/subsystem/persist_vr.dm @@ -93,13 +93,13 @@ SUBSYSTEM_DEF(persist) if(R) // We found someone with a record. var/recorded_rank = R.fields["real_rank"] if(recorded_rank) - . = job_master.GetJob(recorded_rank) + . = SSjob.get_job(recorded_rank) if(.) return // They have a custom title, aren't crew, or someone deleted their record, so we need a fallback method. // Let's check the mind. if(M.mind && M.mind.assigned_role) - . = job_master.GetJob(M.mind.assigned_role) + . = SSjob.get_job(M.mind.assigned_role) // This proc tries makes sure old Command PTO doesn't linger /datum/controller/subsystem/persist/proc/clear_unused_pto(var/mob/M) diff --git a/code/controllers/subsystem/prototypes/_prototypes.dm b/code/controllers/subsystem/prototypes/_prototypes.dm new file mode 100644 index 00000000000..db94bb81e9a --- /dev/null +++ b/code/controllers/subsystem/prototypes/_prototypes.dm @@ -0,0 +1,50 @@ +//! This file is WIP and currently unused. +/** + * yaml prototype loader, now with blackjack and hookers + * + * someone from ss14 come put me out of my misery please + */ +SUBSYSTEM_DEF(prototypes) + name = "Prototypes" + init_order = INIT_ORDER_PROTOTYPES + subsystem_flags = SS_NO_FIRE + + /// prototype cache + var/list/prototypes + +/datum/controller/subsystem/prototypes/Initialize() + Reload() + return ..() + +/datum/controller/subsystem/prototypes/Recover() + Reload() + return ..() + +/datum/controller/subsystem/prototypes/proc/Reload() + subsystem_log("reloading...") + prototypes = list() + var/list/walking = list("prototypes/") + for(var/dir in walking) + var/list/files = flist(dir) + for(var/path in files) + if(path[length(path)] == "/") + walking += dir + path + else + Load(dir + path) + +/datum/controller/subsystem/prototypes/proc/Load(fname) + if(!fexists(fname)) + CRASH("failed to load filename [fname]") + var/yaml = file2text(file(fname)) + var/list/L = yaml_decode(yaml) + subsystem_log("loading [fname]") + +/datum/controller/subsystem/prototypes/proc/Type(t) + switch(t) + if(YAML_PROTOTYPE_LORE) + return /datum/prototype/lore + if(YAML_PROTOTYPE_DUD) + return /datum/prototype/dud + +/datum/controller/subsystem/prototypes/proc/Resolve(domain, id) + return prototypes[domain]?[id] diff --git a/code/controllers/subsystem/prototypes/dud.dm b/code/controllers/subsystem/prototypes/dud.dm new file mode 100644 index 00000000000..b7fc1be0879 --- /dev/null +++ b/code/controllers/subsystem/prototypes/dud.dm @@ -0,0 +1,7 @@ +/datum/prototype/dud + domain = YAML_PROTOTYPE_DUD + + var/list/read + +/datum/prototype/dud/Read(list/data) + read = data.Copy() diff --git a/code/controllers/subsystem/prototypes/lore.dm b/code/controllers/subsystem/prototypes/lore.dm new file mode 100644 index 00000000000..4744149725d --- /dev/null +++ b/code/controllers/subsystem/prototypes/lore.dm @@ -0,0 +1,16 @@ +/datum/prototype/lore + domain = YAML_PROTOTYPE_LORE + +/datum/prototype/lore/Read(list/data) + + +/datum/lore_shard + +/** + * has a fleet + */ +/datum/lore_shard/fleet + +/** + * + */ diff --git a/code/controllers/subsystem/prototypes/prototype.dm b/code/controllers/subsystem/prototypes/prototype.dm new file mode 100644 index 00000000000..3838d5ddee8 --- /dev/null +++ b/code/controllers/subsystem/prototypes/prototype.dm @@ -0,0 +1,19 @@ +/** + * lightweight datums that load + * prototype data based on type + * and do some processing on them to get + * important tidbits out, as well as + * doing semantic linking when needed. + */ +/datum/prototype + /// type but we can't call it type :( + var/domain + /// id + var/id + +/datum/prototype/New(id, list/data) + src.id = id + Initialize(data) + +/datum/prototype/proc/Initialize(list/data) + return diff --git a/code/controllers/subsystem/server_maint.dm b/code/controllers/subsystem/server_maint.dm index 22c3aa52a0e..742a14393e2 100644 --- a/code/controllers/subsystem/server_maint.dm +++ b/code/controllers/subsystem/server_maint.dm @@ -17,8 +17,8 @@ SUBSYSTEM_DEF(server_maint) src.currentrun = GLOB.clients.Copy() switch (cleanup_SSticker) // do only one of these at a time, once per 5 fires if (0) - if(listclearnulls(player_list)) - log_world("Found a null in player_list!") + if(listclearnulls(GLOB.player_list)) + log_world("Found a null in GLOB.player_list!") cleanup_SSticker++ if (5) if(listclearnulls(GLOB.mob_list)) diff --git a/code/controllers/subsystem/supply.dm b/code/controllers/subsystem/supply.dm index 2431806f200..dfca7723cb1 100644 --- a/code/controllers/subsystem/supply.dm +++ b/code/controllers/subsystem/supply.dm @@ -154,7 +154,7 @@ SUBSYSTEM_DEF(supply) var/datum/exported_crate/adm = new() adm.name = EC.name adm.value = EC.value - adm.contents = deepCopyList(EC.contents) + adm.contents = deep_copy_list(EC.contents) adm_export_history += adm qdel(MA) diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm index d529fed35f8..a8161cb2c08 100644 --- a/code/controllers/subsystem/ticker.dm +++ b/code/controllers/subsystem/ticker.dm @@ -196,10 +196,10 @@ SUBSYSTEM_DEF(ticker) to_chat(world, "Serious error in mode setup! Reverting to pregame lobby.") //Uses setup instead of set up due to computational context. return 0 - job_master.ResetOccupations() + SSjob.reset_occupations() src.mode.create_antagonists() src.mode.pre_setup() - job_master.DivideOccupations() // Apparently important for new antagonist system to register specific job antags properly. + SSjob.DivideOccupations() // Apparently important for new antagonist system to register specific job antags properly. if(!src.mode.can_start()) to_chat(world, "Unable to start [mode.name]. Not enough players readied, [config_legacy.player_requirements[mode.config_tag]] players needed. Reverting to pregame lobby.") @@ -207,7 +207,7 @@ SUBSYSTEM_DEF(ticker) Master.SetRunLevel(RUNLEVEL_LOBBY) mode.fail_setup() mode = null - job_master.ResetOccupations() + SSjob.reset_occupations() return 0 if(hide_mode) @@ -389,7 +389,7 @@ SUBSYSTEM_DEF(ticker) /datum/controller/subsystem/ticker/proc/create_characters() - for(var/mob/new_player/player in player_list) + for(var/mob/new_player/player in GLOB.player_list) if(player && player.ready && player.mind) if(player.mind.assigned_role=="AI") player.close_spawn_windows() @@ -405,22 +405,22 @@ SUBSYSTEM_DEF(ticker) /datum/controller/subsystem/ticker/proc/collect_minds() - for(var/mob/living/player in player_list) + for(var/mob/living/player in GLOB.player_list) if(player.mind) minds += player.mind /datum/controller/subsystem/ticker/proc/equip_characters() var/captainless=1 - for(var/mob/living/carbon/human/player in player_list) + for(var/mob/living/carbon/human/player in GLOB.player_list) if(player && player.mind && player.mind.assigned_role) if(player.mind.assigned_role == "Facility Director") captainless=0 if(!player_is_antag(player.mind, only_offstation_roles = 1)) - job_master.EquipRank(player, player.mind.assigned_role, 0) + SSjob.EquipRank(player, player.mind.assigned_role, 0) UpdateFactionList(player) if(captainless) - for(var/mob/M in player_list) + for(var/mob/M in GLOB.player_list) if(!istype(M,/mob/new_player)) to_chat(M, "Facility Directorship not forced on anyone.") @@ -492,7 +492,7 @@ SUBSYSTEM_DEF(ticker) var/datum/callback/cb = I cb.InvokeAsync() LAZYCLEARLIST(round_end_events) - for(var/mob/Player in player_list) + for(var/mob/Player in GLOB.player_list) if(Player.mind && !isnewplayer(Player)) if(Player.stat != DEAD) var/turf/playerTurf = get_turf(Player) diff --git a/code/controllers/subsystem/vote.dm b/code/controllers/subsystem/vote.dm index 9aa80306d6e..dd5f3811d30 100644 --- a/code/controllers/subsystem/vote.dm +++ b/code/controllers/subsystem/vote.dm @@ -34,7 +34,7 @@ SUBSYSTEM_DEF(vote) // Before doing the vote, see if anyone is playing. // If not, just do the transfer. var/players_are_in_round = FALSE - for(var/a in player_list) // Mobs with clients attached. + for(var/a in GLOB.player_list) // Mobs with clients attached. var/mob/living/L = a if(!istype(L)) // Exclude ghosts and other weird things. continue diff --git a/code/datums/_datum.dm b/code/datums/_datum.dm index bb04059ba01..84352d94bb1 100644 --- a/code/datums/_datum.dm +++ b/code/datums/_datum.dm @@ -124,7 +124,6 @@ clear_signal_refs() //END: ECS SHIT - return QDEL_HINT_QUEUE ///Only override this if you know what you're doing. You do not know what you're doing @@ -145,12 +144,6 @@ for(var/target in signal_procs) UnregisterSignal(target, signal_procs[target]) - //END: ECS SHIT - - SSnanoui.close_uis(src) - - return QDEL_HINT_QUEUE - #ifdef DATUMVAR_DEBUGGING_MODE /datum/proc/save_vars() cached_vars = list() diff --git a/code/datums/announce/_legacy.dm b/code/datums/announce/_legacy.dm index 12cef63115c..4f907329e0e 100644 --- a/code/datums/announce/_legacy.dm +++ b/code/datums/announce/_legacy.dm @@ -63,7 +63,7 @@ Log(message, message_title) /datum/legacy_announcement/proc/Message(message as text, message_title as text, list/zlevels) - for(var/mob/M in player_list) + for(var/mob/M in GLOB.player_list) if(!istype(M,/mob/new_player) && !isdeaf(M)) to_chat(M, "

[title]

") to_chat(M, "[message]") @@ -95,7 +95,7 @@ announce_newscaster_news(news) /datum/legacy_announcement/proc/PlaySound(message_sound, list/zlevels) - for(var/mob/M in player_list) + for(var/mob/M in GLOB.player_list) if(zlevels && !(M.z in zlevels)) continue if(!istype(M,/mob/new_player) && !isdeaf(M)) @@ -105,7 +105,7 @@ return spawn(22) // based on length of preamble.ogg + arbitrary delay - for(var/mob/M in player_list) + for(var/mob/M in GLOB.player_list) if(zlevels && !(M.z in zlevels)) continue if(!istype(M,/mob/new_player) && !isdeaf(M)) diff --git a/code/datums/announce/announce_location.dm b/code/datums/announce/announce_location.dm index 0e9b661bf6c..d76fce768b5 100644 --- a/code/datums/announce/announce_location.dm +++ b/code/datums/announce/announce_location.dm @@ -15,7 +15,7 @@ /datum/announce_location/proc/get_affected_atoms() . = list() var/list/levels = get_affected_levels() - for(var/mob/M in player_list) + for(var/mob/M in GLOB.player_list) if(always_allow_ghosts && istype(M, /mob/observer/dead)) . += M continue diff --git a/code/datums/components/storage/storage.dm b/code/datums/components/storage/storage.dm index 1451767cfdb..500a25b8a88 100644 --- a/code/datums/components/storage/storage.dm +++ b/code/datums/components/storage/storage.dm @@ -676,7 +676,7 @@ /datum/component/storage/proc/signal_can_insert(datum/source, obj/item/I, mob/M, silent = FALSE) return can_be_inserted(I, silent, M) -/datum/component/storage/proc/show_to_ghost(datum/source, mob/dead/observer/M) +/datum/component/storage/proc/show_to_ghost(datum/source, mob/observer/dead/M) return user_show_to_mob(M, TRUE) /datum/component/storage/proc/signal_show_attempt(datum/source, mob/showto, force = FALSE) diff --git a/code/datums/datacore.dm b/code/datums/datacore.dm index fb2f19fece9..511c4436b32 100644 --- a/code/datums/datacore.dm +++ b/code/datums/datacore.dm @@ -51,14 +51,14 @@ if(OOC) var/active = 0 - for(var/mob/M in player_list) + for(var/mob/M in GLOB.player_list) if(M.real_name == name && M.client && M.client.inactivity <= 10 MINUTES) active = 1 break isactive[name] = active ? "Active" : "Inactive" else isactive[name] = t.fields["p_stat"] - //to_world("[name]: [rank]") + //TO_WORLD("[name]: [rank]") //cael - to prevent multiple appearances of a player/job combination, add a continue after each line var/department = 0 if(SSjob.is_job_in_department(real_rank, DEPARTMENT_COMMAND)) @@ -96,7 +96,7 @@ var/real_rank = make_list_rank(t.fields["real_rank"]) var/active = 0 - for(var/mob/M in player_list) + for(var/mob/M in GLOB.player_list) if(M.real_name == name && M.client && M.client.inactivity <= 10 MINUTES) active = 1 break @@ -293,7 +293,7 @@ GLOBAL_LIST_EMPTY(PDA_Manifest) /datum/datacore/proc/manifest() spawn() - for(var/mob/living/carbon/human/H in player_list) + for(var/mob/living/carbon/human/H in GLOB.player_list) manifest_inject(H) return diff --git a/code/datums/elements/digitalcamo.dm b/code/datums/elements/digitalcamo.dm index 7c7f7070c44..b264da40a99 100644 --- a/code/datums/elements/digitalcamo.dm +++ b/code/datums/elements/digitalcamo.dm @@ -19,7 +19,7 @@ /datum/element/digitalcamo/Detach(datum/target) . = ..() UnregisterSignal(target, list(COMSIG_PARENT_EXAMINE, COMSIG_LIVING_CAN_TRACK)) - for(var/mob/living/silicon/ai/AI in GLOB.player_list) + for(var/mob/living/silicon/ai/AI in GLOB.GLOB.player_list) AI.client.images -= attached_mobs[target] attached_mobs -= target @@ -30,6 +30,6 @@ return COMPONENT_CANT_TRACK /datum/element/digitalcamo/process(delta_time) - for(var/mob/living/silicon/ai/AI in GLOB.player_list) + for(var/mob/living/silicon/ai/AI in GLOB.GLOB.player_list) for(var/mob in attached_mobs) AI.client.images |= attached_mobs[mob] diff --git a/code/datums/ghost_query.dm b/code/datums/ghost_query.dm index 0caa439f4bc..8fd34456a1b 100644 --- a/code/datums/ghost_query.dm +++ b/code/datums/ghost_query.dm @@ -13,7 +13,7 @@ /datum/ghost_query/proc/query() // First, ask all the ghosts who want to be asked. - for(var/mob/observer/dead/D in player_list) + for(var/mob/observer/dead/D in GLOB.player_list) if(!D.MayRespawn()) continue // They can't respawn for whatever reason. if(D.client) diff --git a/code/datums/mind.dm b/code/datums/mind.dm index 58ac5a8e477..7cfe400d859 100644 --- a/code/datums/mind.dm +++ b/code/datums/mind.dm @@ -32,11 +32,18 @@ var/mob/living/current var/mob/living/original //TODO: remove.not used in any meaningful way ~Carn. First I'll need to tweak the way silicon-mobs handle minds. var/active = FALSE + /** + * original save data + * ! TODO: REMOVE THIS; we shouldn't keep this potentially big list all round. ! + */ + var/list/original_save_data var/memory var/list/learned_recipes + // todo: id, not title var/assigned_role + // todo: id, not title; also unify /datum/role/(job | antagonist | ghostrole)? var/special_role var/role_alt_title diff --git a/code/datums/world_topic.dm b/code/datums/world_topic.dm index f498344cb30..314c764c238 100644 --- a/code/datums/world_topic.dm +++ b/code/datums/world_topic.dm @@ -54,7 +54,7 @@ log = FALSE /datum/world_topic/playing/Run(list/input) - return length(player_list) + return length(GLOB.player_list) /datum/world_topic/pr_announce keyword = "announce" @@ -124,7 +124,7 @@ /datum/world_topic/server_hop/Run(list/input) var/expected_key = input[keyword] - for(var/mob/dead/observer/O in GLOB.player_list) + for(var/mob/observer/dead/O in GLOB.GLOB.player_list) if(O.key == expected_key) if(O.client) new /atom/movable/screen/splash(O.client, TRUE) diff --git a/code/game/antagonist/antagonist_update.dm b/code/game/antagonist/antagonist_update.dm index a88dbcd426b..1f01982feac 100644 --- a/code/game/antagonist/antagonist_update.dm +++ b/code/game/antagonist/antagonist_update.dm @@ -85,7 +85,7 @@ if(SSticker.mode.antag_scaling_coeff) var/count = 0 - for(var/mob/living/M in player_list) + for(var/mob/living/M in GLOB.player_list) if(M.client) count++ diff --git a/code/game/antagonist/mutiny/mutineer.dm b/code/game/antagonist/mutiny/mutineer.dm index 31758278364..62ce6feef72 100644 --- a/code/game/antagonist/mutiny/mutineer.dm +++ b/code/game/antagonist/mutiny/mutineer.dm @@ -38,14 +38,14 @@ var/datum/antagonist/mutineer/mutineers // Returns an array in case we want to expand on this later. proc/get_head_loyalist_candidates() var/list/candidates[0] - for(var/mob/loyalist in player_list) + for(var/mob/loyalist in GLOB.player_list) if(loyalist.mind && loyalist.mind.assigned_role == "Facility Director") candidates.Add(loyalist.mind) return candidates proc/get_head_mutineer_candidates() var/list/candidates[0] - for(var/mob/mutineer in player_list) + for(var/mob/mutineer in GLOB.player_list) if(mutineer.client.prefs.be_special & BE_MUTINEER) for(var/job in command_positions - "Facility Director") if(mutineer.mind && mutineer.mind.assigned_role == job) diff --git a/code/game/antagonist/station/changeling.dm b/code/game/antagonist/station/changeling.dm index 3abe3066d05..3b4c8608e21 100644 --- a/code/game/antagonist/station/changeling.dm +++ b/code/game/antagonist/station/changeling.dm @@ -64,13 +64,13 @@ var/mob/living/carbon/human/H = player.current if(H.isSynthetic()) return 0 - if(H.species.flags & NO_SCAN) + if(H.species.species_flags & NO_SCAN) return 0 return 1 else if(isnewplayer(player.current)) if(player.current.client && player.current.client.prefs) - var/datum/species/S = name_static_species_meta(player.current.client.prefs.species) - if(S && (S.flags & NO_SCAN)) + var/datum/species/S = player.current.client.prefs.real_species_datum() + if(S && (S.species_flags & NO_SCAN)) return 0 if(player.current.client.prefs.organ_data["torso"] == "cyborg") // Full synthetic. return 0 diff --git a/code/game/antagonist/station/highlander.dm b/code/game/antagonist/station/highlander.dm index 71eb552ccc0..8c7920b0c8d 100644 --- a/code/game/antagonist/station/highlander.dm +++ b/code/game/antagonist/station/highlander.dm @@ -54,7 +54,7 @@ var/datum/antagonist/highlander/highlanders player.equip_to_slot_or_del(W, SLOT_ID_WORN_ID) /proc/only_one() - for(var/mob/living/carbon/human/H in player_list) + for(var/mob/living/carbon/human/H in GLOB.player_list) if(H.stat == 2 || !(H.client)) continue if(is_special_character(H)) continue highlanders.add_antagonist(H.mind) diff --git a/code/game/antagonist/station/renegade.dm b/code/game/antagonist/station/renegade.dm index f4b69aad34c..2e571fa473b 100644 --- a/code/game/antagonist/station/renegade.dm +++ b/code/game/antagonist/station/renegade.dm @@ -101,7 +101,7 @@ var/datum/antagonist/renegade/renegades /proc/rightandwrong() to_chat(usr, "You summoned guns!") message_admins("[key_name_admin(usr, 1)] summoned guns!") - for(var/mob/living/carbon/human/H in player_list) + for(var/mob/living/carbon/human/H in GLOB.player_list) if(H.stat == 2 || !(H.client)) continue if(is_special_character(H)) continue renegades.add_antagonist(H.mind) diff --git a/code/game/area/area.dm b/code/game/area/area.dm index 169bdce3eab..66835f030fc 100644 --- a/code/game/area/area.dm +++ b/code/game/area/area.dm @@ -559,7 +559,7 @@ GLOBAL_LIST_EMPTY(forced_ambiance_list) return // Being buckled to something solid keeps you in place. if(istype(H.shoes, /obj/item/clothing/shoes/magboots) && (H.shoes.clothing_flags & NOSLIP)) return - if(H.species.flags & NO_SLIP)//diona and similar should not slip from moving onto space either. + if(H.species.species_flags & NO_SLIP)//diona and similar should not slip from moving onto space either. return if(H.m_intent == MOVE_INTENT_RUN) H.AdjustStunned(6) diff --git a/code/game/atoms/atoms_movable_pulling.dm b/code/game/atoms/atoms_movable_pulling.dm index 9fa5eae5d84..e627d2ed1cd 100644 --- a/code/game/atoms/atoms_movable_pulling.dm +++ b/code/game/atoms/atoms_movable_pulling.dm @@ -106,7 +106,7 @@ var/bloodtrail = 1 //Checks if it's possible to even spill blood if(ishuman(M)) var/mob/living/carbon/human/H = M - if(H.species.flags & NO_BLOOD) + if(H.species.species_flags & NO_BLOOD) bloodtrail = 0 else var/blood_volume = H.vessel.get_reagent_amount("blood") @@ -131,7 +131,7 @@ var/bloodtrail = 1 //Checks if it's possible to even spill blood if(ishuman(M)) var/mob/living/carbon/human/H = M - if(H.species.flags & NO_BLOOD) + if(H.species.species_flags & NO_BLOOD) bloodtrail = 0 else var/blood_volume = H.vessel.get_reagent_amount("blood") diff --git a/code/game/dna/dna_modifier.dm b/code/game/dna/dna_modifier.dm index ebc26ef14f6..51b39c8dd2e 100644 --- a/code/game/dna/dna_modifier.dm +++ b/code/game/dna/dna_modifier.dm @@ -176,7 +176,7 @@ || locate(/obj/machinery/computer/cloning, get_step(src, WEST))) if(!M.client && M.mind) - for(var/mob/observer/dead/ghost in player_list) + for(var/mob/observer/dead/ghost in GLOB.player_list) if(ghost.mind == M.mind) to_chat(ghost, "Your corpse has been placed into a cloning scanner. Return to your body if you want to be resurrected/cloned! (Verbs -> Ghost -> Re-enter corpse)") break diff --git a/code/game/gamemodes/changeling/powers/absorb.dm b/code/game/gamemodes/changeling/powers/absorb.dm index 50b8c21157f..bda5b290804 100644 --- a/code/game/gamemodes/changeling/powers/absorb.dm +++ b/code/game/gamemodes/changeling/powers/absorb.dm @@ -24,7 +24,7 @@ to_chat(src, "\The [T] is not compatible with our biology.") return - if(T.species.flags & NO_SCAN) + if(T.species.species_flags & NO_SCAN) to_chat(src, "We do not know how to parse this creature's DNA!") return diff --git a/code/game/gamemodes/changeling/powers/extract_dna_sting.dm b/code/game/gamemodes/changeling/powers/extract_dna_sting.dm index 0b41a728c3c..5687689b7cd 100644 --- a/code/game/gamemodes/changeling/powers/extract_dna_sting.dm +++ b/code/game/gamemodes/changeling/powers/extract_dna_sting.dm @@ -27,7 +27,7 @@ to_chat(src, "\The [T] is not compatible with our biology.") return 0 - if(T.species.flags & NO_SCAN) + if(T.species.species_flags & NO_SCAN) to_chat(src, "We do not know how to parse this creature's DNA!") return 0 diff --git a/code/game/gamemodes/changeling/powers/transform.dm b/code/game/gamemodes/changeling/powers/transform.dm index efaf72bf4dd..0bb26e08834 100644 --- a/code/game/gamemodes/changeling/powers/transform.dm +++ b/code/game/gamemodes/changeling/powers/transform.dm @@ -32,7 +32,7 @@ if(ishuman(src)) var/mob/living/carbon/human/H = src var/newSpecies = chosen_dna.speciesName - H.set_species(name_static_species_meta(newSpecies).type) + H.set_species(SScharacters.resolve_species_name(newSpecies).type) src.dna = chosen_dna.dna.Clone() src.dna.b_type = "AB+" //This is needed to avoid blood rejection bugs. The fact that the blood type might not match up w/ records could be a *FEATURE* too. diff --git a/code/game/gamemodes/cult/narsie.dm b/code/game/gamemodes/cult/narsie.dm index 81a68b3e865..18f1e5a32c9 100644 --- a/code/game/gamemodes/cult/narsie.dm +++ b/code/game/gamemodes/cult/narsie.dm @@ -129,13 +129,13 @@ var/global/list/narsie_list = list() spawn(0) step(src, movement_dir) narsiefloor(get_turf(loc)) - for(var/mob/M in player_list) + for(var/mob/M in GLOB.player_list) if(M.client) M.see_narsie(src,movement_dir) spawn(10) step(src, movement_dir) narsiefloor(get_turf(loc)) - for(var/mob/M in player_list) + for(var/mob/M in GLOB.player_list) if(M.client) M.see_narsie(src,movement_dir) return 1 @@ -298,7 +298,7 @@ var/global/list/narsie_list = list() acquire(pick(cultists)) return //no living cultists, pick a living human instead. - for(var/mob/observer/dead/ghost in player_list) + for(var/mob/observer/dead/ghost in GLOB.player_list) if(!ghost.client) continue var/turf/pos = get_turf(ghost) diff --git a/code/game/gamemodes/cult/ritual.dm b/code/game/gamemodes/cult/ritual.dm index ce41d0cb3b5..bb5ed248045 100644 --- a/code/game/gamemodes/cult/ritual.dm +++ b/code/game/gamemodes/cult/ritual.dm @@ -69,13 +69,13 @@ var/global/list/rnwords = list("ire","ego","nahlizet","certum","veri","jatkaa"," . = ..() blood_image = image(loc = src) blood_image.override = 1 - for(var/mob/living/silicon/ai/AI in player_list) + for(var/mob/living/silicon/ai/AI in GLOB.player_list) if(AI.client) AI.client.images += blood_image rune_list.Add(src) /obj/effect/rune/Destroy() - for(var/mob/living/silicon/ai/AI in player_list) + for(var/mob/living/silicon/ai/AI in GLOB.player_list) if(AI.client) AI.client.images -= blood_image qdel(blood_image) diff --git a/code/game/gamemodes/cult/runes.dm b/code/game/gamemodes/cult/runes.dm index 3e1cfd2b19f..78fef99be3f 100644 --- a/code/game/gamemodes/cult/runes.dm +++ b/code/game/gamemodes/cult/runes.dm @@ -355,7 +355,7 @@ var/list/sacrificed = list() to_chat(usr, "The Geometer of Blood refuses to touch this one.") return fizzle() else if(!corpse_to_raise.client && corpse_to_raise.mind) //Don't force the dead person to come back if they don't want to. - for(var/mob/observer/dead/ghost in player_list) + for(var/mob/observer/dead/ghost in GLOB.player_list) if(ghost.mind == corpse_to_raise.mind) to_chat(ghost, "The cultist [usr.real_name] is trying to \ revive you. Return to your body if you want to be resurrected into the service of Nar'Sie! \ @@ -624,7 +624,7 @@ var/list/sacrificed = list() for(var/datum/mind/H in cult.current_antagonists) if (H.current) to_chat(H.current, "[input]") - for(var/mob/observer/dead/O in player_list) + for(var/mob/observer/dead/O in GLOB.player_list) to_chat(O, "[input]") qdel(src) return 1 diff --git a/code/game/gamemodes/endgame/supermatter_cascade/portal.dm b/code/game/gamemodes/endgame/supermatter_cascade/portal.dm index bc28be3270a..f50f25c5994 100644 --- a/code/game/gamemodes/endgame/supermatter_cascade/portal.dm +++ b/code/game/gamemodes/endgame/supermatter_cascade/portal.dm @@ -22,7 +22,7 @@ overlays = 0 /obj/singularity/narsie/large/exit/process(delta_time) - for(var/mob/M in player_list) + for(var/mob/M in GLOB.player_list) if(M.client) M.see_rift(src) eat() diff --git a/code/game/gamemodes/endgame/supermatter_cascade/universe.dm b/code/game/gamemodes/endgame/supermatter_cascade/universe.dm index acc7ca5fd6c..20386a6648f 100644 --- a/code/game/gamemodes/endgame/supermatter_cascade/universe.dm +++ b/code/game/gamemodes/endgame/supermatter_cascade/universe.dm @@ -34,7 +34,7 @@ var/global/universe_has_ended = 0 SEND_SOUND(world, sound('sound/effects/cascade.ogg')) - for(var/mob/M in player_list) + for(var/mob/M in GLOB.player_list) M.flash_eyes() if(SSemergencyshuttle.can_recall()) @@ -108,7 +108,7 @@ The access requirements on the Asteroid Shuttles' consoles have now been revoked APC.update_icon() /datum/universal_state/supermatter_cascade/proc/PlayerSet() - for(var/datum/mind/M in player_list) + for(var/datum/mind/M in GLOB.player_list) if(!istype(M.current,/mob/living)) continue if(M.current.stat!=2) diff --git a/code/game/gamemodes/events.dm b/code/game/gamemodes/events.dm index 59155924dd9..e565272b652 100644 --- a/code/game/gamemodes/events.dm +++ b/code/game/gamemodes/events.dm @@ -167,7 +167,7 @@ Would like to add a law like "Law x is _______" where x = a number, and _____ is var/allergysev = pick("deathly", "mildly", "severely", "contagiously") var/crew var/list/pos_crew = list() - for(var/mob/living/carbon/human/pos in player_list) + for(var/mob/living/carbon/human/pos in GLOB.player_list) pos_crew += pos.real_name if(pos_crew.len) crew = pick(pos_crew) diff --git a/code/game/gamemodes/game_mode.dm b/code/game/gamemodes/game_mode.dm index 64a7e2343db..1da5db3ab33 100644 --- a/code/game/gamemodes/game_mode.dm +++ b/code/game/gamemodes/game_mode.dm @@ -159,7 +159,7 @@ var/global/list/additional_antag_types = list() ///Checks to see if the game can be setup and ran with the current number of players or whatnot. /datum/game_mode/proc/can_start(var/do_not_spawn) var/playerC = 0 - for(var/mob/new_player/player in player_list) + for(var/mob/new_player/player in GLOB.player_list) if((player.client)&&(player.ready)) playerC++ @@ -322,7 +322,7 @@ var/global/list/additional_antag_types = list() /area/shuttle/escape_pod2/centcom, /area/shuttle/escape_pod3/centcom, /area/shuttle/escape_pod5/centcom, /area/shuttle/escape,/area/centcom/terminal) - for(var/mob/M in player_list) + for(var/mob/M in GLOB.player_list) if(M.client) clients++ if(ishuman(M)) @@ -382,7 +382,7 @@ var/global/list/additional_antag_types = list() // If this is being called post-roundstart then it doesn't care about ready status. if(SSticker && SSticker.current_state == GAME_STATE_PLAYING) - for(var/mob/player in player_list) + for(var/mob/player in GLOB.player_list) if(!player.client) continue if(istype(player, /mob/new_player)) @@ -394,7 +394,7 @@ var/global/list/additional_antag_types = list() candidates |= player.mind else // Assemble a list of active players without jobbans. - for(var/mob/new_player/player in player_list) + for(var/mob/new_player/player in GLOB.player_list) if( player.client && player.ready ) players += player @@ -423,7 +423,7 @@ var/global/list/additional_antag_types = list() /datum/game_mode/proc/num_players() . = 0 - for(var/mob/new_player/P in player_list) + for(var/mob/new_player/P in GLOB.player_list) if(P.client && P.ready) . ++ @@ -512,7 +512,7 @@ var/global/list/additional_antag_types = list() /proc/get_nt_opposed() var/list/dudes = list() - for(var/mob/living/carbon/human/man in player_list) + for(var/mob/living/carbon/human/man in GLOB.player_list) if(man.client) if(man.client.prefs.economic_status == CLASS_LOWER) dudes += man diff --git a/code/game/gamemodes/meteor/meteor.dm b/code/game/gamemodes/meteor/meteor.dm index 23fa99a7567..9cefe76ac35 100644 --- a/code/game/gamemodes/meteor/meteor.dm +++ b/code/game/gamemodes/meteor/meteor.dm @@ -22,7 +22,7 @@ /datum/game_mode/meteor/declare_completion() var/text var/survivors = 0 - for(var/mob/living/player in player_list) + for(var/mob/living/player in GLOB.player_list) if(player.stat != DEAD) var/turf/location = get_turf(player.loc) if(!location) continue diff --git a/code/game/gamemodes/meteor/meteors.dm b/code/game/gamemodes/meteor/meteors.dm index d23dc861723..bd6f9a32074 100644 --- a/code/game/gamemodes/meteor/meteors.dm +++ b/code/game/gamemodes/meteor/meteors.dm @@ -194,7 +194,7 @@ O.throw_at_old(dest, 5, 10) /obj/effect/meteor/proc/shake_players() - for(var/mob/M in player_list) + for(var/mob/M in GLOB.player_list) var/turf/T = get_turf(M) if(!T || T.z != src.z) continue diff --git a/code/game/gamemodes/objective.dm b/code/game/gamemodes/objective.dm index 57ec0383756..cc23ce6ec17 100644 --- a/code/game/gamemodes/objective.dm +++ b/code/game/gamemodes/objective.dm @@ -236,7 +236,7 @@ var/global/list/all_objectives = list() return FALSE var/area/shuttle = locate(/area/shuttle/escape/centcom) var/list/protected_mobs = list(/mob/living/silicon/ai, /mob/living/silicon/pai) - for(var/mob/living/player in player_list) + for(var/mob/living/player in GLOB.player_list) if(player.type in protected_mobs) continue if (player.mind && (player.mind != owner)) @@ -258,7 +258,7 @@ var/global/list/all_objectives = list() return FALSE var/area/shuttle = locate(/area/shuttle/escape/centcom) var/protected_mobs[] = list(/mob/living/silicon/ai, /mob/living/silicon/pai, /mob/living/silicon/robot) - for(var/mob/living/player in player_list) + for(var/mob/living/player in GLOB.player_list) if(player.type in protected_mobs) continue if (player.mind) if (player.stat != 2) @@ -273,7 +273,7 @@ var/global/list/all_objectives = list() if(!SSemergencyshuttle.returned()) return FALSE - for(var/mob/living/player in player_list) + for(var/mob/living/player in GLOB.player_list) if(player == owner.current) continue if(player.mind) @@ -620,11 +620,11 @@ var/global/list/all_objectives = list() if (SSticker) var/n_p = 1 //autowin if (SSticker.current_state == GAME_STATE_SETTING_UP) - for(var/mob/new_player/P in player_list) + for(var/mob/new_player/P in GLOB.player_list) if(P.client && P.ready && P.mind!=owner) n_p ++ else if (SSticker.current_state == GAME_STATE_PLAYING) - for(var/mob/living/carbon/human/P in player_list) + for(var/mob/living/carbon/human/P in GLOB.player_list) if(P.client && !(P.mind.changeling) && P.mind!=owner) n_p ++ target_amount = min(target_amount, n_p) @@ -871,7 +871,7 @@ var/global/list/all_objectives = list() /datum/objective/cult/sacrifice/find_target() var/list/possible_targets = list() if(!possible_targets.len) - for(var/mob/living/carbon/human/player in player_list) + for(var/mob/living/carbon/human/player in GLOB.player_list) if(player.mind && !(player.mind in cult)) possible_targets += player.mind if(possible_targets.len > 0) diff --git a/code/game/gamemodes/sandbox/sandbox.dm b/code/game/gamemodes/sandbox/sandbox.dm index 795f6df7a32..6829691e547 100644 --- a/code/game/gamemodes/sandbox/sandbox.dm +++ b/code/game/gamemodes/sandbox/sandbox.dm @@ -7,7 +7,7 @@ extended_round_description = "You can use the sandbox-panel command to access build options." /datum/game_mode/sandbox/pre_setup() - for(var/mob/M in player_list) + for(var/mob/M in GLOB.player_list) M.CanBuild() return 1 diff --git a/code/game/gamemodes/technomancer/spells/aura/fire_aura.dm b/code/game/gamemodes/technomancer/spells/aura/fire_aura.dm index fc26f180259..aeedc499c9f 100644 --- a/code/game/gamemodes/technomancer/spells/aura/fire_aura.dm +++ b/code/game/gamemodes/technomancer/spells/aura/fire_aura.dm @@ -23,7 +23,7 @@ var/list/nearby_things = range(round(calculate_spell_power(4)),owner) var/temp_change = calculate_spell_power(25) - var/datum/species/baseline = get_static_species_meta(/datum/species/human) + var/datum/species/baseline = SScharacters.resolve_species_path(/datum/species/human) var/temp_cap = baseline.heat_level_3 * 1.5 var/fire_power = calculate_spell_power(2) diff --git a/code/game/gamemodes/technomancer/spells/aura/frost_aura.dm b/code/game/gamemodes/technomancer/spells/aura/frost_aura.dm index fdff3fe47de..e7478e21842 100644 --- a/code/game/gamemodes/technomancer/spells/aura/frost_aura.dm +++ b/code/game/gamemodes/technomancer/spells/aura/frost_aura.dm @@ -23,7 +23,7 @@ var/list/nearby_mobs = range(round(calculate_spell_power(4)),owner) var/temp_change = calculate_spell_power(40) - var/datum/species/baseline = get_static_species_meta(/datum/species/human) + var/datum/species/baseline = SScharacters.resolve_species_path(/datum/species/human) var/temp_cap = baseline.cold_level_2 - 5 if(check_for_scepter()) diff --git a/code/game/gamemodes/technomancer/spells/resurrect.dm b/code/game/gamemodes/technomancer/spells/resurrect.dm index 1d1770cf410..b61050d6eae 100644 --- a/code/game/gamemodes/technomancer/spells/resurrect.dm +++ b/code/game/gamemodes/technomancer/spells/resurrect.dm @@ -42,7 +42,7 @@ var/mob/living/carbon/human/H = L if(!H.client && H.mind) //Don't force the dead person to come back if they don't want to. - for(var/mob/observer/dead/ghost in player_list) + for(var/mob/observer/dead/ghost in GLOB.player_list) if(ghost.mind == H.mind) ghost.notify_revive("The Technomancer [user.real_name] is trying to revive you. \ Re-enter your body if you want to be revived!", 'sound/effects/genetics.ogg') diff --git a/code/game/landmarks/spawnpoint/station/jobs.dm b/code/game/landmarks/spawnpoint/station/jobs.dm index 3a6a16ed08f..1b806363a5b 100644 --- a/code/game/landmarks/spawnpoint/station/jobs.dm +++ b/code/game/landmarks/spawnpoint/station/jobs.dm @@ -221,7 +221,7 @@ /obj/landmark/spawnpoint/job/ai/OnRoundstart() if(latejoin_active && !spawned) - empty_playable_ai_cores += new /obj/structure/AIcore/deactivated(loc) + GLOB.empty_playable_ai_cores += new /obj/structure/AIcore/deactivated(loc) return ..() // qdel happens AFTER we spawn core THANK YOU! /obj/landmark/spawnpoint/job/ai/secondary @@ -232,7 +232,7 @@ /obj/landmark/spawnpoint/job/ai/secondary/Available(mob/M, client/C, harder) . = ..() // yes this is unoptimized by sue me - for(var/obj/landmark/spawnpoint/job/ai/other in SSjob.GetAllSpawnpoints()) + for(var/obj/landmark/spawnpoint/job/ai/other in SSjob.get_all_spawnpoints()) if(other.primary_ai && !other.spawned) return FALSE // priority to primary slots diff --git a/code/game/machinery/air_alarm.dm b/code/game/machinery/air_alarm.dm index 789eb8f7f9f..79b4ff0b71e 100644 --- a/code/game/machinery/air_alarm.dm +++ b/code/game/machinery/air_alarm.dm @@ -431,7 +431,7 @@ signal.data["sigtype"] = "command" radio_connection.post_signal(src, signal, RADIO_FROM_AIRALARM) -// to_world("Signal [command] Broadcasted to [target]") +// TO_WORLD("Signal [command] Broadcasted to [target]") return 1 diff --git a/code/game/machinery/bioprinter.dm b/code/game/machinery/bioprinter.dm index 969bb746a6b..f78cf36bd45 100644 --- a/code/game/machinery/bioprinter.dm +++ b/code/game/machinery/bioprinter.dm @@ -243,9 +243,9 @@ malfunctioned = TRUE var/possible_species = list(SPECIES_HUMAN, SPECIES_VOX, SPECIES_SKRELL, SPECIES_ZADDAT, SPECIES_UNATHI, SPECIES_GOLEM, SPECIES_SHADOW) var/new_species = pick(possible_species) - var/datum/species/S = name_static_species_meta(new_species) + var/datum/species/S = SScharacters.resolve_species_name(new_species) if(!S) - new_species = name_static_species_meta(/datum/species/human) + new_species = SScharacters.resolve_species_name(/datum/species/human) O.species = new_species if(istype(O, /obj/item/organ/external) && !malfunctioned) diff --git a/code/game/machinery/cloning.dm b/code/game/machinery/cloning.dm index 2eb74bc73fa..627fb0ae272 100644 --- a/code/game/machinery/cloning.dm +++ b/code/game/machinery/cloning.dm @@ -9,7 +9,7 @@ return var/mob/selected = null - for(var/mob/living/M in player_list) + for(var/mob/living/M in GLOB.player_list) //Dead people only thanks! if((M.stat != 2) || (!M.client)) continue @@ -83,7 +83,7 @@ if(ckey(clonemind.key) != R.ckey) return FALSE else - for(var/mob/observer/dead/G in player_list) + for(var/mob/observer/dead/G in GLOB.player_list) if(G.ckey == R.ckey) if(G.can_reenter_corpse) break @@ -335,7 +335,7 @@ if(ishuman(occupant)) //Need to be safe. var/mob/living/carbon/human/patient = occupant - if(!(patient.species.flags & NO_SCAN)) //If, for some reason, someone makes a genetically-unalterable clone, let's not make them permanently disabled. + if(!(patient.species.species_flags & NO_SCAN)) //If, for some reason, someone makes a genetically-unalterable clone, let's not make them permanently disabled. domutcheck(occupant) //Waiting until they're out before possible transforming. occupant = null diff --git a/code/game/machinery/computer/Operating.dm b/code/game/machinery/computer/Operating.dm index 1d4887c4cac..680cc9b03a1 100644 --- a/code/game/machinery/computer/Operating.dm +++ b/code/game/machinery/computer/Operating.dm @@ -110,7 +110,7 @@ occupantData["btCelsius"] = occupant.bodytemperature - T0C occupantData["btFaren"] = ((occupant.bodytemperature - T0C) * (9.0/5.0))+ 32 - if(ishuman(occupant) && !(NO_BLOOD in occupant.species.flags) && occupant.vessel) + if(ishuman(occupant) && !(NO_BLOOD in occupant.species.species_flags) && occupant.vessel) occupantData["pulse"] = occupant.get_pulse(GETPULSE_TOOL) occupantData["hasBlood"] = 1 var/blood_volume = round(occupant.vessel.get_reagent_amount("blood")) diff --git a/code/game/machinery/computer/ai_core.dm b/code/game/machinery/computer/ai_core.dm index 7eeb48fb55c..36093139df2 100644 --- a/code/game/machinery/computer/ai_core.dm +++ b/code/game/machinery/computer/ai_core.dm @@ -169,7 +169,7 @@ var/open_for_latejoin = alert(user, "Would you like this core to be open for latejoining AIs?", "Latejoin", "Yes", "Yes", "No") == "Yes" var/obj/structure/AIcore/deactivated/D = new(loc) if(open_for_latejoin) - empty_playable_ai_cores += D + GLOB.empty_playable_ai_cores += D else var/mob/living/silicon/ai/A = new /mob/living/silicon/ai ( loc, laws, brain ) // If there's no brain, the mob is deleted and a structure/AIcore is created. @@ -190,8 +190,8 @@ GLOBAL_LIST_BOILERPLATE(all_deactivated_AI_cores, /obj/structure/AIcore/deactiva state = 20//So it doesn't interact based on the above. Not really necessary. /obj/structure/AIcore/deactivated/Destroy() - if(src in empty_playable_ai_cores) - empty_playable_ai_cores -= src + if(src in GLOB.empty_playable_ai_cores) + GLOB.empty_playable_ai_cores -= src return ..() /obj/structure/AIcore/deactivated/proc/load_ai(var/mob/living/silicon/ai/transfer, var/obj/item/aicard/card, var/mob/user) @@ -267,9 +267,9 @@ GLOBAL_LIST_BOILERPLATE(all_deactivated_AI_cores, /obj/structure/AIcore/deactiva var/obj/structure/AIcore/deactivated/D = cores[id] if(!D) return - if(D in empty_playable_ai_cores) - empty_playable_ai_cores -= D + if(D in GLOB.empty_playable_ai_cores) + GLOB.empty_playable_ai_cores -= D to_chat(src, "\The [id] is now not available for latejoining AIs.") else - empty_playable_ai_cores += D + GLOB.empty_playable_ai_cores += D to_chat(src, "\The [id] is now available for latejoining AIs.") diff --git a/code/game/machinery/computer/cloning.dm b/code/game/machinery/computer/cloning.dm index 679ead7f1d9..8cc62969653 100644 --- a/code/game/machinery/computer/cloning.dm +++ b/code/game/machinery/computer/cloning.dm @@ -313,7 +313,7 @@ if (MUTATION_NOCLONE in subject.mutations) scantemp = "Error: Mental interface failure." return - if (subject.species && subject.species.flags & NO_SCAN && !brain_skip) + if (subject.species && subject.species.species_flags & NO_SCAN && !brain_skip) scantemp = "Error: Mental interface failure." return for(var/modifier_type in subject.modifiers) //Can't be cloned, even if they had a previous scan @@ -323,7 +323,7 @@ if ((!subject.ckey) || (!subject.client)) scantemp = "Error: Mental interface failure." if(subject.stat == DEAD && subject.mind && subject.mind.key) // If they're dead and not in their body, tell them to get in it. - for(var/mob/observer/dead/ghost in player_list) + for(var/mob/observer/dead/ghost in GLOB.player_list) if(ghost.ckey == ckey(subject.mind.key)) ghost.notify_revive("Someone is trying to scan your body in the cloner. Re-enter your body if you want to be revived!", 'sound/effects/genetics.ogg') break diff --git a/code/game/machinery/computer/communications.dm b/code/game/machinery/computer/communications.dm index 2fb62d65807..66b53d5da7f 100644 --- a/code/game/machinery/computer/communications.dm +++ b/code/game/machinery/computer/communications.dm @@ -80,16 +80,16 @@ if("swipeidseclevel") if(src.authenticated) //Let heads change the alert level. - var/old_level = security_level + var/old_level = GLOB.security_level if(!tmp_alertlevel) tmp_alertlevel = SEC_LEVEL_GREEN if(tmp_alertlevel < SEC_LEVEL_GREEN) tmp_alertlevel = SEC_LEVEL_GREEN if(tmp_alertlevel > SEC_LEVEL_RED) tmp_alertlevel = SEC_LEVEL_BLUE //Cannot engage delta with this set_security_level(tmp_alertlevel) - if(security_level != old_level) + if(GLOB.security_level != old_level) //Only notify the admins if an actual change happened log_game("[key_name(usr)] has changed the security level to [get_security_level()].") message_admins("[key_name_admin(usr)] has changed the security level to [get_security_level()].") - switch(security_level) + switch(GLOB.security_level) if(SEC_LEVEL_GREEN) feedback_inc("alert_comms_green",1) if(SEC_LEVEL_BLUE) @@ -360,7 +360,7 @@ dat += " Biohazard \]

" if(STATE_ALERT_LEVEL) dat += "Current alert level: [get_security_level()]
" - if(security_level == SEC_LEVEL_DELTA) + if(GLOB.security_level == SEC_LEVEL_DELTA) dat += "The ship is in immediate danger of destruction. Find a way to neutralize the threat to lower the alert level or evacuate." else dat += "Orange
" diff --git a/code/game/machinery/computer/security.dm b/code/game/machinery/computer/security.dm index 5cd70db9d38..17c8ce281b1 100644 --- a/code/game/machinery/computer/security.dm +++ b/code/game/machinery/computer/security.dm @@ -395,7 +395,7 @@ active1.fields["real_rank"] = answer if(field == "criminal") - for(var/mob/living/carbon/human/H in player_list) + for(var/mob/living/carbon/human/H in GLOB.player_list) H.update_hud_sec_status() if(istype(active2) && (field in active2.fields)) diff --git a/code/game/machinery/computer/timeclock_vr.dm b/code/game/machinery/computer/timeclock_vr.dm index 996be172860..afa482c6e8b 100644 --- a/code/game/machinery/computer/timeclock_vr.dm +++ b/code/game/machinery/computer/timeclock_vr.dm @@ -92,7 +92,7 @@ if(card) data["card"] = "[card]" data["assignment"] = card.assignment - var/datum/job/job = job_master.GetJob(card.rank) + var/datum/job/job = SSjob.get_job(card.rank) if(job) data["job_datum"] = list( "title" = job.title, @@ -148,7 +148,7 @@ /obj/machinery/computer/timeclock/proc/getOpenOnDutyJobs(var/mob/user, var/department) var/list/available_jobs = list() - for(var/datum/job/job in job_master.occupations) + for(var/datum/job/job in SSjob.occupations) if(isOpenOnDutyJob(user, department, job)) available_jobs[job.title] = list(job.title) if(job.alt_titles) @@ -168,8 +168,8 @@ && job.timeoff_factor > 0 /obj/machinery/computer/timeclock/proc/makeOnDuty(var/newrank, var/newassignment) - var/datum/job/oldjob = job_master.GetJob(card.rank) - var/datum/job/newjob = job_master.GetJob(newrank) + var/datum/job/oldjob = SSjob.get_job(card.rank) + var/datum/job/newjob = SSjob.get_job(newrank) if(!oldjob || !isOpenOnDutyJob(usr, oldjob.pto_type, newjob)) return if(newassignment != newjob.title && !(newassignment in newjob.alt_titles)) @@ -190,12 +190,12 @@ return /obj/machinery/computer/timeclock/proc/makeOffDuty() - var/datum/job/foundjob = job_master.GetJob(card.rank) + var/datum/job/foundjob = SSjob.get_job(card.rank) if(!foundjob) return var/new_dept = foundjob.pto_type || PTO_CIVILIAN var/datum/job/ptojob = null - for(var/datum/job/job in job_master.occupations) + for(var/datum/job/job in SSjob.occupations) if(job.pto_type == new_dept && job.timeoff_factor < 0) ptojob = job break diff --git a/code/game/machinery/cryopod.dm b/code/game/machinery/cryopod.dm index 091d6829a28..160051cc68d 100644 --- a/code/game/machinery/cryopod.dm +++ b/code/game/machinery/cryopod.dm @@ -463,7 +463,7 @@ //Handle job slot/tater cleanup. var/job = to_despawn.mind.assigned_role - job_master.FreeRole(job) + SSjob.FreeRole(job) if(to_despawn.mind.objectives.len) qdel(to_despawn.mind.objectives) diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm index 5a1efdd4df9..4cac3aee5ca 100644 --- a/code/game/machinery/doors/airlock.dm +++ b/code/game/machinery/doors/airlock.dm @@ -1069,7 +1069,7 @@ About the new airlock wires panel: return src.p_open && (operating < 0 || (!operating && welded && !src.arePowerSystemsOn() && density && (!src.locked || (machine_stat & BROKEN)))) /obj/machinery/door/airlock/attackby(obj/item/C, mob/user as mob) - //to_world("airlock attackby src [src] obj [C] mob [user]") + //TO_WORLD("airlock attackby src [src] obj [C] mob [user]") if(!istype(usr, /mob/living/silicon)) if(src.isElectrified()) if(src.shock(user, 75)) diff --git a/code/game/machinery/embedded_controller/airlock_docking_controller.dm b/code/game/machinery/embedded_controller/airlock_docking_controller.dm index eccb7085f69..2d017876ab4 100644 --- a/code/game/machinery/embedded_controller/airlock_docking_controller.dm +++ b/code/game/machinery/embedded_controller/airlock_docking_controller.dm @@ -135,16 +135,16 @@ /*** DEBUG VERBS *** /datum/computer/file/embedded_program/docking/proc/print_state() - to_world("id_tag: [id_tag]") - to_world("dock_state: [dock_state]") - to_world("control_mode: [control_mode]") - to_world("tag_target: [tag_target]") - to_world("response_sent: [response_sent]") + TO_WORLD("id_tag: [id_tag]") + TO_WORLD("dock_state: [dock_state]") + TO_WORLD("control_mode: [control_mode]") + TO_WORLD("tag_target: [tag_target]") + TO_WORLD("response_sent: [response_sent]") /datum/computer/file/embedded_program/docking/post_signal(datum/signal/signal, comm_line) - to_world("Program [id_tag] sent a message!") + TO_WORLD("Program [id_tag] sent a message!") print_state() - to_world("[id_tag] sent command \"[signal.data["command"]]\" to \"[signal.data["recipient"]]\"") + TO_WORLD("[id_tag] sent command \"[signal.data["command"]]\" to \"[signal.data["recipient"]]\"") ..(signal) /obj/machinery/embedded_controller/radio/airlock/docking_port/verb/view_state() diff --git a/code/game/machinery/embedded_controller/airlock_docking_controller_multi.dm b/code/game/machinery/embedded_controller/airlock_docking_controller_multi.dm index 3b178d11861..a0ff624e8da 100644 --- a/code/game/machinery/embedded_controller/airlock_docking_controller_multi.dm +++ b/code/game/machinery/embedded_controller/airlock_docking_controller_multi.dm @@ -60,16 +60,16 @@ /*** DEBUG VERBS *** /datum/computer/file/embedded_program/docking/multi/proc/print_state() - to_world("id_tag: [id_tag]") - to_world("dock_state: [dock_state]") - to_world("control_mode: [control_mode]") - to_world("tag_target: [tag_target]") - to_world("response_sent: [response_sent]") + TO_WORLD("id_tag: [id_tag]") + TO_WORLD("dock_state: [dock_state]") + TO_WORLD("control_mode: [control_mode]") + TO_WORLD("tag_target: [tag_target]") + TO_WORLD("response_sent: [response_sent]") /datum/computer/file/embedded_program/docking/multi/post_signal(datum/signal/signal, comm_line) - to_world("Program [id_tag] sent a message!") + TO_WORLD("Program [id_tag] sent a message!") print_state() - to_world("[id_tag] sent command \"[signal.data["command"]]\" to \"[signal.data["recipient"]]\"") + TO_WORLD("[id_tag] sent command \"[signal.data["command"]]\" to \"[signal.data["recipient"]]\"") ..(signal) /obj/machinery/embedded_controller/radio/docking_port_multi/verb/view_state() diff --git a/code/game/machinery/embedded_controller/docking_program.dm b/code/game/machinery/embedded_controller/docking_program.dm index 4c78a0b3f10..05eee5c5e2d 100644 --- a/code/game/machinery/embedded_controller/docking_program.dm +++ b/code/game/machinery/embedded_controller/docking_program.dm @@ -259,7 +259,7 @@ received_confirm = 0 /datum/computer/file/embedded_program/docking/proc/force_undock() - //to_world("[id_tag]: forcing undock") + //TO_WORLD("[id_tag]: forcing undock") if (tag_target) send_docking_command(tag_target, "dock_error") reset() diff --git a/code/game/machinery/embedded_controller/mapping_helpers.dm b/code/game/machinery/embedded_controller/mapping_helpers.dm index 376b9e84a94..8d9e165d195 100644 --- a/code/game/machinery/embedded_controller/mapping_helpers.dm +++ b/code/game/machinery/embedded_controller/mapping_helpers.dm @@ -26,11 +26,11 @@ Any frequency works, it's self-setting, but it seems like people have decided 13 my_controller = get_controller(get_area(src)) my_device = locate(my_device_type) in get_turf(src) if(!my_device) - to_world("WARNING:Airlock helper '[name]' couldn't find what it wanted at: X:[x] Y:[y] Z:[z]") + TO_WORLD("WARNING:Airlock helper '[name]' couldn't find what it wanted at: X:[x] Y:[y] Z:[z]") else if(!my_controller) - to_world("WARNING:Airlock helper '[name]' couldn't find a controller at: X:[x] Y:[y] Z:[z]") + TO_WORLD("WARNING:Airlock helper '[name]' couldn't find a controller at: X:[x] Y:[y] Z:[z]") else if(!my_controller.id_tag) - to_world("WARNING:Airlock helper '[name]' found a controller without an 'id_tag' set: X:[x] Y:[y] Z:[z]") + TO_WORLD("WARNING:Airlock helper '[name]' found a controller without an 'id_tag' set: X:[x] Y:[y] Z:[z]") else setup() return INITIALIZE_HINT_QDEL diff --git a/code/game/machinery/fire_alarm.dm b/code/game/machinery/fire_alarm.dm index 95369306bf8..da91776f840 100644 --- a/code/game/machinery/fire_alarm.dm +++ b/code/game/machinery/fire_alarm.dm @@ -31,7 +31,7 @@ FIRE ALARM /obj/machinery/firealarm/Initialize(mapload) . = ..() if(z in GLOB.using_map.contact_levels) - set_security_level(security_level ? get_security_level() : "green") + set_security_level(GLOB.security_level ? get_security_level() : "green") /obj/machinery/firealarm/update_icon() cut_overlays() diff --git a/code/game/machinery/holoposter.dm b/code/game/machinery/holoposter.dm index 70433095ce7..62a160829e2 100644 --- a/code/game/machinery/holoposter.dm +++ b/code/game/machinery/holoposter.dm @@ -53,12 +53,12 @@ GLOBAL_LIST_EMPTY(holoposters) examine_addon = "It appears to be malfunctioning." new_color = "#6A6C71" else - if((z in GLOB.using_map.station_levels) && global.security_level) // 0 is fine, everything higher is alert levels + if((z in GLOB.using_map.station_levels) && GLOB.security_level) // 0 is fine, everything higher is alert levels icon_state = "attention" examine_addon = "It warns you to remain calm and contact your supervisor as soon as possible." new_color = "#AA7039" alerting = TRUE - else if(alerting && !global.security_level) // coming out of alert + else if(alerting && !GLOB.security_level) // coming out of alert alerting = FALSE set_rand_sprite() return diff --git a/code/game/machinery/telecomms/broadcaster.dm b/code/game/machinery/telecomms/broadcaster.dm index e04517ab560..29bf70a5b5a 100644 --- a/code/game/machinery/telecomms/broadcaster.dm +++ b/code/game/machinery/telecomms/broadcaster.dm @@ -745,6 +745,6 @@ var/message_delay = 0 // To make sure restarting the recentmessages list is kept if(do_sleep) sleep(rand(10,25)) - //to_world_log("Level: [signal.data["level"]] - Done: [signal.data["done"]]") + //TO_WORLD_log("Level: [signal.data["level"]] - Done: [signal.data["done"]]") return signal diff --git a/code/game/machinery/telecomms/telecomunications.dm b/code/game/machinery/telecomms/telecomunications.dm index 3ce3fa92362..e4b3a05e7dd 100644 --- a/code/game/machinery/telecomms/telecomunications.dm +++ b/code/game/machinery/telecomms/telecomunications.dm @@ -53,7 +53,7 @@ if(!on) return - //to_world("[src] ([src.id]) - [signal.debug_print()]") + //TO_WORLD("[src] ([src.id]) - [signal.debug_print()]") var/send_count = 0 signal.data["slow"] += rand(0, round((100-integrity))) // apply some lag based on integrity diff --git a/code/game/mecha/mech_prosthetics.dm b/code/game/mecha/mech_prosthetics.dm index b9675ce5aa4..90b16986b4f 100644 --- a/code/game/mecha/mech_prosthetics.dm +++ b/code/game/mecha/mech_prosthetics.dm @@ -148,7 +148,7 @@ if(istype(I,/obj/item/disk/species)) var/obj/item/disk/species/D = I - if(!D.species || !(species_type_by_name(D.species) in GLOB.species_meta)) + if(!SScharacters.resolve_species(D.species)) to_chat(user, SPAN_WARNING("This disk seems to be corrupted!")) else to_chat(user, SPAN_NOTICE("Uploading modification files for [D.species]...")) diff --git a/code/game/mecha/medical/odysseus.dm b/code/game/mecha/medical/odysseus.dm index cf6d751d34f..0160a522890 100644 --- a/code/game/mecha/medical/odysseus.dm +++ b/code/game/mecha/medical/odysseus.dm @@ -51,7 +51,7 @@ var/perspective = input("Select a perspective type.", "Client perspective", occupant.client.perspective) in list(MOB_PERSPECTIVE,EYE_PERSPECTIVE) - to_world("[perspective]") + TO_WORLD("[perspective]") occupant.client.perspective = perspective return @@ -63,7 +63,7 @@ occupant.client.eye = src else occupant.client.eye = occupant - to_world("[occupant.client.eye]") + TO_WORLD("[occupant.client.eye]") return */ @@ -74,15 +74,15 @@ // process_hud(var/mob/M) //TODO VIS /* - to_world("view(M)") + TO_WORLD("view(M)") for(var/mob/mob in view(M)) - to_world("[mob]") - to_world("view(M.client)") + TO_WORLD("[mob]") + TO_WORLD("view(M.client)") for(var/mob/mob in view(M.client)) - to_world("[mob]") - to_world("view(M.loc)") + TO_WORLD("[mob]") + TO_WORLD("view(M.loc)") for(var/mob/mob in view(M.loc)) - to_world("[mob]") + TO_WORLD("[mob]") if(!M || M.stat || !(M in view(M))) return diff --git a/code/game/objects/effects/map_effects/map_effects.dm b/code/game/objects/effects/map_effects/map_effects.dm index 9c64476a29b..57244fbf21b 100644 --- a/code/game/objects/effects/map_effects/map_effects.dm +++ b/code/game/objects/effects/map_effects/map_effects.dm @@ -61,8 +61,8 @@ if(!proximity_to) return FALSE - for(var/thing in player_list) - var/mob/M = thing // Avoiding typechecks for more speed, player_list will only contain mobs anyways. + for(var/thing in GLOB.player_list) + var/mob/M = thing // Avoiding typechecks for more speed, GLOB.player_list will only contain mobs anyways. if(ignore_ghosts && isobserver(M)) continue if(ignore_afk && M.client && M.client.is_afk(5 MINUTES)) diff --git a/code/game/objects/effects/map_effects/screen_shaker.dm b/code/game/objects/effects/map_effects/screen_shaker.dm index ff9ac1a0e82..de2f520b376 100644 --- a/code/game/objects/effects/map_effects/screen_shaker.dm +++ b/code/game/objects/effects/map_effects/screen_shaker.dm @@ -11,7 +11,7 @@ var/shake_strength = 1 // How much it shakes. /obj/effect/map_effect/interval/screen_shaker/trigger() - for(var/A in player_list) + for(var/A in GLOB.player_list) var/mob/M = A if(M.z == src.z && get_dist(src, M) <= shake_radius) shake_camera(M, shake_duration, shake_strength) diff --git a/code/game/objects/explosion.dm b/code/game/objects/explosion.dm index b7b88447101..3a802527db3 100644 --- a/code/game/objects/explosion.dm +++ b/code/game/objects/explosion.dm @@ -36,7 +36,7 @@ if(prob(devastation_range*30+heavy_impact_range*5) && on_station) // Huge explosions are near guaranteed to make the station creak and whine, smaller ones might. creaking_explosion = TRUE // prob over 100 always returns true var/far_volume = clamp(far_dist, 30, 50) // Volume is based on explosion size and dist - for(var/mob/M in player_list) + for(var/mob/M in GLOB.player_list) var/turf/M_turf = get_turf(M) var/dist = get_dist(M_turf, epicenter) if(M.z == epicenter.z) diff --git a/code/game/objects/items/devices/PDA/PDA.dm b/code/game/objects/items/devices/PDA/PDA.dm index 5c40d86c9f2..84eff921795 100644 --- a/code/game/objects/items/devices/PDA/PDA.dm +++ b/code/game/objects/items/devices/PDA/PDA.dm @@ -1114,7 +1114,7 @@ GLOBAL_LIST_EMPTY(PDAs) tnote.Add(list(list("sent" = 1, "owner" = "[P.owner]", "job" = "[P.ownjob]", "message" = "[t]", "target" = "\ref[P]"))) P.tnote.Add(list(list("sent" = 0, "owner" = "[owner]", "job" = "[ownjob]", "message" = "[t]", "target" = "\ref[src]"))) - for(var/mob/M in player_list) + for(var/mob/M in GLOB.player_list) if(M.stat == DEAD && M.client && (M.is_preference_enabled(/datum/client_preference/ghost_ears))) // src.client is so that ghosts don't have to listen to mice if(istype(M, /mob/new_player)) continue diff --git a/code/game/objects/items/devices/communicator/UI_tgui.dm b/code/game/objects/items/devices/communicator/UI_tgui.dm index a3713ab8b96..083f72ea434 100644 --- a/code/game/objects/items/devices/communicator/UI_tgui.dm +++ b/code/game/objects/items/devices/communicator/UI_tgui.dm @@ -372,7 +372,7 @@ exonet.send_message(their_address, "text", text) im_list += list(list("address" = exonet.address, "to_address" = their_address, "im" = text)) log_pda("(COMM: [src]) sent \"[text]\" to [exonet.get_atom_from_address(their_address)]", usr) - for(var/mob/M in player_list) + for(var/mob/M in GLOB.player_list) if(M.stat == DEAD && M.is_preference_enabled(/datum/client_preference/ghost_ears)) if(istype(M, /mob/new_player) || M.forbid_seeing_deadchat) continue diff --git a/code/game/objects/items/devices/communicator/messaging.dm b/code/game/objects/items/devices/communicator/messaging.dm index f009b571549..acb7463cded 100644 --- a/code/game/objects/items/devices/communicator/messaging.dm +++ b/code/game/objects/items/devices/communicator/messaging.dm @@ -141,7 +141,7 @@ to_chat(src, "You have sent '[text_message]' to [chosen_communicator].") exonet_messages.Add("To [chosen_communicator]:
[text_message]") log_pda("(DCOMM: [src]) sent \"[text_message]\" to [chosen_communicator]", src) - for(var/mob/M in player_list) + for(var/mob/M in GLOB.player_list) if(M.stat == DEAD && M.is_preference_enabled(/datum/client_preference/ghost_ears)) if(istype(M, /mob/new_player) || M.forbid_seeing_deadchat) continue diff --git a/code/game/objects/items/devices/defib.dm b/code/game/objects/items/devices/defib.dm index 5c6ffac4337..f89da8cab2f 100644 --- a/code/game/objects/items/devices/defib.dm +++ b/code/game/objects/items/devices/defib.dm @@ -253,7 +253,7 @@ //Checks for various conditions to see if the mob is revivable /obj/item/shockpaddles/proc/can_defib(mob/living/carbon/human/H) //This is checked before doing the defib operation - if((H.species.flags & NO_DEFIB)) + if((H.species.species_flags & NO_DEFIB)) return "buzzes, \"Alien physiology. Operation aborted. Consider alternative resucitation methods.\"" else if(H.isSynthetic() && !use_on_synthetic) return "buzzes, \"Synthetic Body. Operation aborted.\"" @@ -368,7 +368,7 @@ // This proc is used so that we can return out of the revive process while ensuring that busy and update_icon() are handled /obj/item/shockpaddles/proc/do_revive(mob/living/carbon/human/H, mob/user) if(!H.client && !H.teleop) - for(var/mob/observer/dead/ghost in player_list) + for(var/mob/observer/dead/ghost in GLOB.player_list) if(ghost.mind == H.mind) ghost.notify_revive("Someone is trying to resuscitate you. Re-enter your body if you want to be revived!", 'sound/effects/genetics.ogg') break diff --git a/code/game/objects/items/devices/radio/headset.dm b/code/game/objects/items/devices/radio/headset.dm index e3203af4996..2f12ec56487 100755 --- a/code/game/objects/items/devices/radio/headset.dm +++ b/code/game/objects/items/devices/radio/headset.dm @@ -50,10 +50,10 @@ /obj/item/radio/headset/handle_message_mode(mob/living/M as mob, message, channel) if (channel == "special") if (translate_binary) - var/datum/language/binary = GLOB.all_languages["Robot Talk"] + var/datum/language/binary = SScharacters.resolve_language_id(LANGUAGE_ID_SILICON_BINARY) binary.broadcast(M, message) if (translate_hive) - var/datum/language/hivemind = GLOB.all_languages["Hivemind"] + var/datum/language/hivemind = SScharacters.resolve_language_name("Hivemind") hivemind.broadcast(M, message) return null diff --git a/code/game/objects/items/devices/translator.dm b/code/game/objects/items/devices/translator.dm index d1a6047b3ae..fa487bef4b2 100644 --- a/code/game/objects/items/devices/translator.dm +++ b/code/game/objects/items/devices/translator.dm @@ -17,7 +17,7 @@ if(!listening) //Turning ON langset = input(user,"Translate to which of your languages?","Language Selection") as null|anything in user.languages if(langset) - if(langset && ((langset.flags & NONVERBAL) || (langset.flags & HIVEMIND) || (!langset.machine_understands))) + if(langset && ((langset.language_flags & NONVERBAL) || (langset.language_flags & HIVEMIND) || (!langset.machine_understands))) //Nonverbal means no spoken words to translate, so I didn't see the need to remove it. to_chat(user, "\The [src] cannot output that language.") return @@ -51,7 +51,7 @@ if(!language) return //Borgs were causing runtimes when passing language=null - if (language && (language.flags & NONVERBAL)) + if (language && (language.language_flags & NONVERBAL)) return //Not gonna translate sign language if (!language.machine_understands && !omni) // cit change - omni check diff --git a/code/game/objects/items/robot/robot_parts.dm b/code/game/objects/items/robot/robot_parts.dm index 8ed9e2881c1..bc90bdfd8c0 100644 --- a/code/game/objects/items/robot/robot_parts.dm +++ b/code/game/objects/items/robot/robot_parts.dm @@ -171,7 +171,7 @@ if(!M.brainmob.key) var/ghost_can_reenter = 0 if(M.brainmob.mind) - for(var/mob/observer/dead/G in player_list) + for(var/mob/observer/dead/G in GLOB.player_list) if(G.can_reenter_corpse && G.mind == M.brainmob.mind) ghost_can_reenter = 1 //May come in use again at another point. to_chat(user, "\The [W] is completely unresponsive; though it may be able to auto-resuscitate.") //Jamming a ghosted brain into a borg is likely detrimental, and may result in some problems. diff --git a/code/game/objects/items/robot/robot_upgrades.dm b/code/game/objects/items/robot/robot_upgrades.dm index dfaf671fc1a..50f92a77958 100644 --- a/code/game/objects/items/robot/robot_upgrades.dm +++ b/code/game/objects/items/robot/robot_upgrades.dm @@ -65,7 +65,7 @@ return FALSE if(!R.key) - for(var/mob/observer/dead/ghost in player_list) + for(var/mob/observer/dead/ghost in GLOB.player_list) if(ghost.mind && ghost.mind.current == R) R.key = ghost.key @@ -225,7 +225,6 @@ R.add_language(LANGUAGE_BIRDSONG, 1) //Languages moved from robot/upgrades_vr - Papalus R.add_language(LANGUAGE_SAGARU, 1) R.add_language(LANGUAGE_CANILUNZT, 1) - R.add_language(LANGUAGE_ECUREUILIAN, 1) R.add_language(LANGUAGE_DAEMON, 1) R.add_language(LANGUAGE_ENOCHIAN, 1) R.add_language(LANGUAGE_SLAVIC, 1) diff --git a/code/game/objects/items/weapons/material/shards.dm b/code/game/objects/items/weapons/material/shards.dm index 0fd1afd3361..7ad625506e6 100644 --- a/code/game/objects/items/weapons/material/shards.dm +++ b/code/game/objects/items/weapons/material/shards.dm @@ -126,7 +126,7 @@ if( H.shoes || ( H.wear_suit && (H.wear_suit.body_parts_covered & FEET) ) ) return - if(H.species.flags & NO_MINOR_CUT) + if(H.species.species_flags & NO_MINOR_CUT) return to_chat(H, "You step on \the [src]!") diff --git a/code/game/objects/misc.dm b/code/game/objects/misc.dm index f1fd873a6ee..2feb76d80e9 100644 --- a/code/game/objects/misc.dm +++ b/code/game/objects/misc.dm @@ -10,7 +10,7 @@ /obj/structure/signpost/attack_hand(mob/user) switch(tgui_alert(user, "Do you want to go to SS13?", "Travel", list("Yes", "No"))) if("Yes") - user.forceMove(SSjob.GetLatejoinSpawnpoint(faction = JOB_FACTION_STATION)) + user.forceMove(SSjob.get_latejoin_spawnpoint(faction = JOB_FACTION_STATION)) if("No") return diff --git a/code/game/objects/mob_spawner.dm b/code/game/objects/mob_spawner.dm index 55678b80d66..817650773d0 100644 --- a/code/game/objects/mob_spawner.dm +++ b/code/game/objects/mob_spawner.dm @@ -99,7 +99,7 @@ var/turf/T = get_turf(src) if(!T) return 0 - for(var/mob/living/L in player_list) + for(var/mob/living/L in GLOB.player_list) var/turf/L_T if(L.stat == DEAD) continue diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm index a9851ff8f59..333e6d613c7 100644 --- a/code/game/objects/objs.dm +++ b/code/game/objects/objs.dm @@ -47,6 +47,8 @@ STOP_PROCESSING(SSobj, src) if(register_as_dangerous_object) unregister_dangerous_to_step() + SStgui.close_uis(src) + SSnanoui.close_uis(src) return ..() /obj/Moved(atom/oldloc) diff --git a/code/game/objects/structures/medical_stand_vr.dm b/code/game/objects/structures/medical_stand_vr.dm index b185c665637..6ed8ff3a7ef 100644 --- a/code/game/objects/structures/medical_stand_vr.dm +++ b/code/game/objects/structures/medical_stand_vr.dm @@ -414,7 +414,7 @@ return if(MUTATION_NOCLONE in H.mutations) return - if(H.species.flags & NO_BLOOD) + if(H.species.species_flags & NO_BLOOD) return if(!H.should_have_organ(O_HEART)) return diff --git a/code/game/objects/structures/mirror.dm b/code/game/objects/structures/mirror.dm index c41a12a9d5e..d9e503398b2 100644 --- a/code/game/objects/structures/mirror.dm +++ b/code/game/objects/structures/mirror.dm @@ -123,7 +123,7 @@ /obj/structure/mirror/raider/attack_hand(var/mob/living/carbon/human/user) if(istype(get_area(src),/area/syndicate_mothership)) - if(istype(user) && user.mind && user.mind.special_role == "Raider" && user.species.name != SPECIES_VOX && is_alien_whitelisted(user, SPECIES_VOX)) + if(istype(user) && user.mind && user.mind.special_role == "Raider" && user.species.name != SPECIES_VOX && config.check_alien_whitelist(ckey(SPECIES_VOX), user.ckey)) var/choice = input("Do you wish to become a true Vox of the Shoal? This is not reversible.") as null|anything in list("No","Yes") if(choice && choice == "Yes") var/mob/living/carbon/human/vox/vox = new(get_turf(src),SPECIES_VOX) @@ -134,7 +134,7 @@ spawn(1) var/newname = sanitizeSafe(input(vox,"Enter a name, or leave blank for the default name.", "Name change","") as text, MAX_NAME_LEN) if(!newname || newname == "") - var/datum/language/L = GLOB.all_languages[vox.species.default_language] + var/datum/language/L = SScharacters.resolve_language_id(vox.species.default_language) newname = L.get_random_name() vox.real_name = newname vox.name = vox.real_name diff --git a/code/game/objects/structures/morgue.dm b/code/game/objects/structures/morgue.dm index 982bc1e695f..d347904a226 100644 --- a/code/game/objects/structures/morgue.dm +++ b/code/game/objects/structures/morgue.dm @@ -43,7 +43,7 @@ src.icon_state = "morgue2" get_occupants() for (var/mob/living/carbon/human/H in occupants) - if(H.isSynthetic() || H.suiciding || !H.ckey || !H.client || (MUTATION_NOCLONE in H.mutations) || (H.species && H.species.flags & NO_SCAN)) + if(H.isSynthetic() || H.suiciding || !H.ckey || !H.client || (MUTATION_NOCLONE in H.mutations) || (H.species && H.species.species_flags & NO_SCAN)) src.icon_state = "morgue2" break else diff --git a/code/game/objects/structures/spiritboard.dm b/code/game/objects/structures/spiritboard.dm index b18b772220e..5ee00e2fdfa 100644 --- a/code/game/objects/structures/spiritboard.dm +++ b/code/game/objects/structures/spiritboard.dm @@ -22,7 +22,7 @@ //ATTACK GHOST IGNORING PARENT RETURN VALUE -/obj/structure/spirit_board/attack_ghost(mob/dead/observer/user) +/obj/structure/spirit_board/attack_ghost(mob/observer/dead/user) spirit_board_pick_letter(user) return ..() diff --git a/code/game/sound.dm b/code/game/sound.dm index 567105ca356..c5332bda1d7 100644 --- a/code/game/sound.dm +++ b/code/game/sound.dm @@ -25,7 +25,7 @@ GLOBAL_VAR_INIT(sound_env_dry, 0) var/sound/S = sound(get_sfx(soundin)) var/maxdistance = (world.view + extrarange) * GLOB.sound_extrarange_multiplier var/z = turf_source.z - var/list/listeners = player_list //SSmobs.clients_by_zlevel[z] + var/list/listeners = GLOB.player_list //SSmobs.clients_by_zlevel[z] if(!ignore_walls) //these sounds don't carry through walls listeners = listeners & hearers(maxdistance,turf_source) for(var/P in listeners) @@ -177,7 +177,7 @@ GLOBAL_VAR_INIT(sound_distance_offscreen, 7) /proc/sound_to_playing_players(sound, volume = 100, vary) sound = get_sfx(sound) - for(var/M in player_list) + for(var/M in GLOB.player_list) if(ismob(M) && !isnewplayer(M)) var/mob/MO = M MO.playsound_local(get_turf(MO), sound, volume, vary, pressure_affected = FALSE) diff --git a/code/game/statistics.dm b/code/game/statistics.dm index f336d9c4c34..558c38171b4 100644 --- a/code/game/statistics.dm +++ b/code/game/statistics.dm @@ -1,7 +1,7 @@ /proc/sql_poll_population() var/admincount = admins.len var/playercount = 0 - for(var/mob/M in player_list) + for(var/mob/M in GLOB.player_list) if(M.client) playercount += 1 diff --git a/code/game/verbs/ignore.dm b/code/game/verbs/ignore.dm index e8baea77ac4..b1187db9bd9 100644 --- a/code/game/verbs/ignore.dm +++ b/code/game/verbs/ignore.dm @@ -15,7 +15,7 @@ return prefs.ignored_players |= key_to_ignore - SScharacter_setup.queue_preferences_save(prefs) + SScharacters.queue_preferences_save(prefs) to_chat(usr, "Now ignoring [key_to_ignore].") /client/verb/unignore(key_to_unignore as text) @@ -31,7 +31,7 @@ to_chat(usr, "[key_to_unignore] isn't being ignored.") return prefs.ignored_players -= key_to_unignore - SScharacter_setup.queue_preferences_save(prefs) + SScharacters.queue_preferences_save(prefs) to_chat(usr, "Reverted ignore on [key_to_unignore].") /mob/proc/is_key_ignored(var/key_to_check) diff --git a/code/game/world.dm b/code/game/world.dm index 5b4a52a7d1d..bdc185f122e 100644 --- a/code/game/world.dm +++ b/code/game/world.dm @@ -18,10 +18,12 @@ GLOBAL_LIST(topic_status_cache) //This happens after the Master subsystem new(s) (it's a global datum) //So subsystems globals exist, but are not initialised /world/New() + //! init auxtools var/debug_server = world.GetConfig("env", "AUXTOOLS_DEBUG_DLL") if (debug_server) call(debug_server, "auxtools_init")() enable_debugging() + // AUXTOOLS_CHECK(AUXTOOLS_YAML) log_world("World loaded at [TIME_STAMP("hh:mm:ss", FALSE)]!") @@ -76,10 +78,6 @@ GLOBAL_LIST(topic_status_cache) . = ..() - // *sighs* - job_master = new - job_master.SetupOccupations() - // This is kinda important. Set up details of what the hell things are made of. populate_material_list() @@ -280,6 +278,11 @@ GLOBAL_LIST(topic_status_cache) log_world("World rebooted at [time_stamp()]") shutdown_logging() // Past this point, no logging procs can be used, at risk of data loss. + + //! Shutdown Auxtools + // AUXTOOLS_SHUTDOWN(AUXTOOLS_YAML) + + //! Finale // hmmm let's sleep for one (1) second incase rust_g threads are running for whatever reason sleep(1 SECONDS) ..() diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm index a1d289152bb..bfb1efd82b3 100644 --- a/code/modules/admin/admin.dm +++ b/code/modules/admin/admin.dm @@ -191,15 +191,14 @@ var/global/floorIsLava = 0 // language toggles body += "

Languages:
" var/f = 1 - for(var/k in GLOB.all_languages) - var/datum/language/L = GLOB.all_languages[k] - if(!(L.flags & INNATE)) + for(var/datum/language/L as anything in SScharacters.all_languages()) + if(!(L.language_flags & INNATE)) if(!f) body += " | " else f = 0 if(L in M.languages) - body += "[k]" + body += "[L.name]" else - body += "[k]" + body += "[L.name]" body += {"
@@ -970,7 +969,7 @@ var/datum/legacy_announcement/minor/admin_min_announcer = new set name = "Unprison" if (M.z == 2) if (config_legacy.allow_admin_jump) - M.forceMove(SSjob.GetLatejoinSpawnpoint(faction = JOB_FACTION_STATION)) + M.forceMove(SSjob.get_latejoin_spawnpoint(faction = JOB_FACTION_STATION)) message_admins("[key_name_admin(usr)] has unprisoned [key_name_admin(M)]", 1) log_admin("[key_name(usr)] has unprisoned [key_name(M)]") else diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index 6ae26e1bcb7..18a859e6561 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -605,7 +605,7 @@ var/list/admin_verbs_event_manager = list( prefs.ooccolor = input(src, "Please select your OOC colour.", "OOC colour") as color else if(response == "Reset to default") prefs.ooccolor = initial(prefs.ooccolor) - SScharacter_setup.queue_preferences_save(prefs) + SScharacters.queue_preferences_save(prefs) feedback_add_details("admin_verb","OC") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! return @@ -1029,7 +1029,7 @@ var/list/admin_verbs_event_manager = list( return var/job = input("Please select job slot to free", "Free job slot") as null|anything in jobs if (job) - job_master.FreeRole(job) + SSjob.FreeRole(job) message_admins("A job slot for [job] has been opened by [key_name_admin(usr)]") return diff --git a/code/modules/admin/ckey_vr.dm b/code/modules/admin/ckey_vr.dm index 4e07c50b011..fc8140b491d 100644 --- a/code/modules/admin/ckey_vr.dm +++ b/code/modules/admin/ckey_vr.dm @@ -8,7 +8,7 @@ return var/list/keys = list() - for(var/mob/playerMob in player_list) + for(var/mob/playerMob in GLOB.player_list) keys += playerMob.client var/client/selection = input("Please, select a player!", "Set CKey", null, null) as null|anything in sortKey(keys) if(!selection || !istype(selection)) diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index d7b3db755d0..6deb14ae8f5 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -84,7 +84,7 @@ var/mob/playermob - for(var/mob/M in player_list) + for(var/mob/M in GLOB.player_list) if(M.ckey == banckey) playermob = M break @@ -376,7 +376,7 @@ if(!M.ckey) //sanity to_chat(usr, "This mob has no ckey") return - if(!job_master) + if(!SSjob) to_chat(usr, "Job Master has not been setup!") return @@ -397,7 +397,7 @@ jobs += "Command Positions" for(var/jobPos in SSjob.get_job_titles_in_department(DEPARTMENT_COMMAND)) if(!jobPos) continue - var/datum/job/job = job_master.GetJob(jobPos) + var/datum/job/job = SSjob.get_job(jobPos) if(!job) continue if(jobban_isbanned(M, job.title)) @@ -418,7 +418,7 @@ jobs += "Security Positions" for(var/jobPos in SSjob.get_job_titles_in_department(DEPARTMENT_SECURITY)) if(!jobPos) continue - var/datum/job/job = job_master.GetJob(jobPos) + var/datum/job/job = SSjob.get_job(jobPos) if(!job) continue if(jobban_isbanned(M, job.title)) @@ -439,7 +439,7 @@ jobs += "Engineering Positions" for(var/jobPos in SSjob.get_job_titles_in_department(DEPARTMENT_ENGINEERING)) if(!jobPos) continue - var/datum/job/job = job_master.GetJob(jobPos) + var/datum/job/job = SSjob.get_job(jobPos) if(!job) continue if(jobban_isbanned(M, job.title)) @@ -460,7 +460,7 @@ jobs += "Cargo Positions" for(var/jobPos in SSjob.get_job_titles_in_department(DEPARTMENT_CARGO)) if(!jobPos) continue - var/datum/job/job = job_master.GetJob(jobPos) + var/datum/job/job = SSjob.get_job(jobPos) if(!job) continue if(jobban_isbanned(M, job.title)) @@ -481,7 +481,7 @@ jobs += "Medical Positions" for(var/jobPos in SSjob.get_job_titles_in_department(DEPARTMENT_MEDICAL)) if(!jobPos) continue - var/datum/job/job = job_master.GetJob(jobPos) + var/datum/job/job = SSjob.get_job(jobPos) if(!job) continue if(jobban_isbanned(M, job.title)) @@ -502,7 +502,7 @@ jobs += "Science Positions" for(var/jobPos in SSjob.get_job_titles_in_department(DEPARTMENT_RESEARCH)) if(!jobPos) continue - var/datum/job/job = job_master.GetJob(jobPos) + var/datum/job/job = SSjob.get_job(jobPos) if(!job) continue if(jobban_isbanned(M, job.title)) @@ -522,7 +522,7 @@ jobs += "Science Positions" for(var/jobPos in SSjob.get_job_titles_in_department(DEPARTMENT_PLANET)) if(!jobPos) continue - var/datum/job/job = job_master.GetJob(jobPos) + var/datum/job/job = SSjob.get_job(jobPos) if(!job) continue if(jobban_isbanned(M, job.title)) @@ -542,7 +542,7 @@ jobs += "Civilian Positions" for(var/jobPos in SSjob.get_job_titles_in_department(DEPARTMENT_CIVILIAN)) if(!jobPos) continue - var/datum/job/job = job_master.GetJob(jobPos) + var/datum/job/job = SSjob.get_job(jobPos) if(!job) continue if(jobban_isbanned(M, job.title)) @@ -569,7 +569,7 @@ jobs += "Non-human Positions" for(var/jobPos in SSjob.get_job_titles_in_department(DEPARTMENT_SYNTHETIC)) if(!jobPos) continue - var/datum/job/job = job_master.GetJob(jobPos) + var/datum/job/job = SSjob.get_job(jobPos) if(!job) continue if(jobban_isbanned(M, job.title)) @@ -646,7 +646,7 @@ alert("You cannot perform this action. You must be of a higher administrative rank!") return - if(!job_master) + if(!SSjob) to_chat(usr, "Job Master has not been setup!") return @@ -656,56 +656,56 @@ if("commanddept") for(var/jobPos in SSjob.get_job_titles_in_department(DEPARTMENT_COMMAND)) if(!jobPos) continue - var/datum/job/temp = job_master.GetJob(jobPos) + var/datum/job/temp = SSjob.get_job(jobPos) if(!temp) continue joblist += temp.title if("securitydept") for(var/jobPos in SSjob.get_job_titles_in_department(DEPARTMENT_SECURITY)) if(!jobPos) continue - var/datum/job/temp = job_master.GetJob(jobPos) + var/datum/job/temp = SSjob.get_job(jobPos) if(!temp) continue joblist += temp.title if("engineeringdept") for(var/jobPos in SSjob.get_job_titles_in_department(DEPARTMENT_ENGINEERING)) if(!jobPos) continue - var/datum/job/temp = job_master.GetJob(jobPos) + var/datum/job/temp = SSjob.get_job(jobPos) if(!temp) continue joblist += temp.title if("cargodept") for(var/jobPos in SSjob.get_job_titles_in_department(DEPARTMENT_CARGO)) if(!jobPos) continue - var/datum/job/temp = job_master.GetJob(jobPos) + var/datum/job/temp = SSjob.get_job(jobPos) if(!temp) continue joblist += temp.title if("medicaldept") for(var/jobPos in SSjob.get_job_titles_in_department(DEPARTMENT_MEDICAL)) if(!jobPos) continue - var/datum/job/temp = job_master.GetJob(jobPos) + var/datum/job/temp = SSjob.get_job(jobPos) if(!temp) continue joblist += temp.title if("sciencedept") for(var/jobPos in SSjob.get_job_titles_in_department(DEPARTMENT_RESEARCH)) if(!jobPos) continue - var/datum/job/temp = job_master.GetJob(jobPos) + var/datum/job/temp = SSjob.get_job(jobPos) if(!temp) continue joblist += temp.title if("explorationdept") for(var/jobPos in SSjob.get_job_titles_in_department(DEPARTMENT_PLANET)) if(!jobPos) continue - var/datum/job/temp = job_master.GetJob(jobPos) + var/datum/job/temp = SSjob.get_job(jobPos) if(!temp) continue joblist += temp.title if("civiliandept") for(var/jobPos in SSjob.get_job_titles_in_department(DEPARTMENT_CIVILIAN)) if(!jobPos) continue - var/datum/job/temp = job_master.GetJob(jobPos) + var/datum/job/temp = SSjob.get_job(jobPos) if(!temp) continue joblist += temp.title if("nonhumandept") joblist += "pAI" for(var/jobPos in SSjob.get_job_titles_in_department(DEPARTMENT_SYNTHETIC)) if(!jobPos) continue - var/datum/job/temp = job_master.GetJob(jobPos) + var/datum/job/temp = SSjob.get_job(jobPos) if(!temp) continue joblist += temp.title else @@ -1897,7 +1897,7 @@ to_chat(usr, "[M] is illegal type, must be /mob!") return var/lang2toggle = href_list["lang"] - var/datum/language/L = GLOB.all_languages[lang2toggle] + var/datum/language/L = SScharacters.resolve_language_name(lang2toggle) if(L in M.languages) if(!M.remove_language(lang2toggle)) diff --git a/code/modules/admin/verbs/adminjump.dm b/code/modules/admin/verbs/adminjump.dm index bc7119fa699..919636c3743 100644 --- a/code/modules/admin/verbs/adminjump.dm +++ b/code/modules/admin/verbs/adminjump.dm @@ -78,7 +78,7 @@ if(config_legacy.allow_admin_jump) var/list/keys = list() - for(var/mob/M in player_list) + for(var/mob/M in GLOB.player_list) keys += M.client var/selection = input("Please, select a player!", "Admin Jumping", null, null) as null|anything in sortKey(keys) if(!selection) @@ -118,7 +118,7 @@ if(config_legacy.allow_admin_jump) var/list/keys = list() - for(var/mob/M in player_list) + for(var/mob/M in GLOB.player_list) keys += M.client var/selection = input("Please, select a player!", "Admin Jumping", null, null) as null|anything in sortKey(keys) if(!selection) diff --git a/code/modules/admin/verbs/buildmode.dm b/code/modules/admin/verbs/buildmode.dm index b37dea10817..f08ee90e743 100644 --- a/code/modules/admin/verbs/buildmode.dm +++ b/code/modules/admin/verbs/buildmode.dm @@ -1,4 +1,4 @@ -/proc/togglebuildmode(mob/M as mob in player_list) +/proc/togglebuildmode(mob/M as mob in GLOB.player_list) set name = "Toggle Build Mode" set category = "Special Verbs" if(M.client) diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm index 4fa494e5b6b..05151dec112 100644 --- a/code/modules/admin/verbs/debug.dm +++ b/code/modules/admin/verbs/debug.dm @@ -607,7 +607,7 @@ switch(input("Which list?") in list("Players","Admins","Mobs","Living Mobs","Dead Mobs", "Clients")) if("Players") - to_chat(usr, jointext(player_list,",")) + to_chat(usr, jointext(GLOB.player_list,",")) if("Admins") to_chat(usr, jointext(admins,",")) if("Mobs") @@ -706,7 +706,7 @@ if(!check_rights(R_ADMIN)) return - var/mob/living/carbon/human/H = input("Pick a mob with a player","Quick NIF") as null|anything in player_list + var/mob/living/carbon/human/H = input("Pick a mob with a player","Quick NIF") as null|anything in GLOB.player_list if(!H) return @@ -723,7 +723,7 @@ to_chat(usr,"Target already has a NIF.") return - if(H.species.flags & NO_SCAN) + if(H.species.species_flags & NO_SCAN) var/obj/item/nif/S = /obj/item/nif/bioadap input_NIF = initial(S.name) new /obj/item/nif/bioadap(H) diff --git a/code/modules/admin/verbs/debug/reestablish_db_connection.dm b/code/modules/admin/verbs/debug/reestablish_db_connection.dm index eda196614d9..df89e7d1ceb 100644 --- a/code/modules/admin/verbs/debug/reestablish_db_connection.dm +++ b/code/modules/admin/verbs/debug/reestablish_db_connection.dm @@ -28,3 +28,6 @@ message_admins("Database connection failed: " + SSdbcore.ErrorMsg()) else message_admins("Database connection re-established") + message_admins("Reloading client database data...") + for(var/client/C in GLOB.clients) + C.database?.Load() diff --git a/code/modules/admin/verbs/lightning_strike.dm b/code/modules/admin/verbs/lightning_strike.dm index 98b88384d6d..bda0f237083 100644 --- a/code/modules/admin/verbs/lightning_strike.dm +++ b/code/modules/admin/verbs/lightning_strike.dm @@ -65,7 +65,7 @@ // And for those far away. If the strike happens on a planet, everyone on the planet will hear it. // Otherwise only those on the current z-level will hear it. var/sound = get_sfx("thunder") - for(var/mob/M in player_list) + for(var/mob/M in GLOB.player_list) if((P && (M.z in P.expected_z_levels)) || M.z == T.z) if(M.is_preference_enabled(/datum/client_preference/weather_sounds)) M.playsound_local(get_turf(M), soundin = sound, vol = 70, vary = FALSE, is_global = TRUE) diff --git a/code/modules/admin/verbs/playsound.dm b/code/modules/admin/verbs/playsound.dm index 8dfd634ebcb..bf3c98a1f3c 100644 --- a/code/modules/admin/verbs/playsound.dm +++ b/code/modules/admin/verbs/playsound.dm @@ -32,7 +32,7 @@ log_admin("[key_name(src)] played sound [S]") message_admins("[key_name_admin(src)] played sound [S]") - for(var/mob/M in player_list) + for(var/mob/M in GLOB.player_list) if(M.is_preference_enabled(/datum/client_preference/play_admin_midis)) //if(M.client.prefs.toggles & SOUND_MIDI) admin_sound.volume = vol * M.client.admin_music_volume SEND_SOUND(M, admin_sound) @@ -123,7 +123,7 @@ to_chat(src, "The media provider returned a content URL that isn't using the HTTP or HTTPS protocol") return if(web_sound_url || stop_web_sounds) - for(var/m in player_list) + for(var/m in GLOB.player_list) var/mob/M = m var/client/C = M.client if(M.is_preference_enabled(/datum/client_preference/play_admin_midis)) //if(C.prefs.toggles & SOUND_MIDI) @@ -147,7 +147,7 @@ log_admin("[key_name(src)] stopped web sound") message_admins("[key_name(src)] stopped web sound") var/mob/M - for(var/i in player_list) + for(var/i in GLOB.player_list) M = i M?.client?.tgui_panel?.stop_music() return @@ -173,7 +173,7 @@ log_admin("[key_name(src)] played web sound: [web_sound_input]") message_admins("[key_name(src)] played web sound: [web_sound_input]") - for(var/m in player_list) + for(var/m in GLOB.player_list) var/mob/M = m var/client/C = M.client if(M.is_preference_enabled(/datum/client_preference/play_admin_midis)) //if(C.prefs.toggles & SOUND_MIDI) @@ -202,7 +202,7 @@ log_admin("[key_name(src)] stopped all currently playing sounds.") message_admins("[key_name_admin(src)] stopped all currently playing sounds.") - for(var/mob/M in player_list) + for(var/mob/M in GLOB.player_list) SEND_SOUND(M, sound(null)) var/client/C = M.client C?.tgui_panel?.stop_music() diff --git a/code/modules/admin/verbs/randomverbs.dm b/code/modules/admin/verbs/randomverbs.dm index 9fdd30d2cc2..26c9f8a9d17 100644 --- a/code/modules/admin/verbs/randomverbs.dm +++ b/code/modules/admin/verbs/randomverbs.dm @@ -125,7 +125,7 @@ return if(!M) - M = input("Direct narrate to whom?", "Active Players") as null|anything in player_list + M = input("Direct narrate to whom?", "Active Players") as null|anything in GLOB.player_list if(!M) return @@ -474,7 +474,7 @@ Traitors and the like can also be revived with the previous role mostly intact. spawnloc = get_turf(src.mob) if("Arrivals") //Spawn them at a latejoin spawnpoint - spawnloc = SSjob.GetLatejoinSpawnpoint(faction = JOB_FACTION_STATION)?.GetSpawnLoc() + spawnloc = SSjob.get_latejoin_spawnpoint(faction = JOB_FACTION_STATION)?.GetSpawnLoc() else //I have no idea how you're here to_chat(src, "Invalid spawn location choice.") @@ -514,7 +514,7 @@ Traitors and the like can also be revived with the previous role mostly intact. //If desired, apply equipment. if(equipment) if(charjob) - job_master.EquipRank(new_character, charjob, 1) + SSjob.EquipRank(new_character, charjob, 1) //If desired, add records. if(records) @@ -734,7 +734,7 @@ Traitors and the like can also be revived with the previous role mostly intact. switch(alert("How would you like to ban someone today?", "Manual Ban", "Key List", "Enter Manually", "Cancel")) if("Key List") var/list/keys = list() - for(var/mob/M in player_list) + for(var/mob/M in GLOB.player_list) keys += M.client var/selection = input("Please, select a player!", "Admin Jumping", null, null) as null|anything in keys if(!selection) @@ -1012,7 +1012,7 @@ Traitors and the like can also be revived with the previous role mostly intact. else if(issilicon(M)) if(isAI(M)) var/mob/living/silicon/ai/ai = M - empty_playable_ai_cores += new /obj/structure/AIcore/deactivated(ai.loc) + GLOB.empty_playable_ai_cores += new /obj/structure/AIcore/deactivated(ai.loc) GLOB.global_announcer.autosay("[ai] has been moved to intelligence storage.", "Artificial Intelligence Oversight") ai.clear_client() return diff --git a/code/modules/admin/verbs/smite.dm b/code/modules/admin/verbs/smite.dm index 9c4e23a7366..ad3ecbb7390 100644 --- a/code/modules/admin/verbs/smite.dm +++ b/code/modules/admin/verbs/smite.dm @@ -6,7 +6,7 @@ return if(!victim) - victim = input("Select a player", "Who?") as null|mob in player_list + victim = input("Select a player", "Who?") as null|mob in GLOB.player_list if(!ishuman(victim)) return diff --git a/code/modules/admin/verbs/smite_vr.dm b/code/modules/admin/verbs/smite_vr.dm index 0761b04c9fd..17eae7196d0 100644 --- a/code/modules/admin/verbs/smite_vr.dm +++ b/code/modules/admin/verbs/smite_vr.dm @@ -1,4 +1,4 @@ -/client/proc/smite_vr(var/mob/living/carbon/human/target in player_list) +/client/proc/smite_vr(var/mob/living/carbon/human/target in GLOB.player_list) set name = "Smite (Vore)" set desc = "Abuse a player with various 'special Vore-brand treatments' from a list." set category = "Fun" diff --git a/code/modules/admin/verbs/tripAI.dm b/code/modules/admin/verbs/tripAI.dm index ccca0a792bc..ac3de9fee47 100644 --- a/code/modules/admin/verbs/tripAI.dm +++ b/code/modules/admin/verbs/tripAI.dm @@ -7,7 +7,7 @@ return if(SSjob && SSticker) - var/datum/job/job = job_master.GetJob("AI") + var/datum/job/job = SSjob.get_job("AI") if(!job) to_chat(usr, "Unable to locate the AI job") return diff --git a/code/modules/admin/view_variables/topic.dm b/code/modules/admin/view_variables/topic.dm index 19e9a607c82..8b68097a6cd 100644 --- a/code/modules/admin/view_variables/topic.dm +++ b/code/modules/admin/view_variables/topic.dm @@ -441,7 +441,7 @@ to_chat(usr, "This can only be done to instances of type /mob/living/carbon/human") return - var/new_species = tgui_input_list(usr, "Please choose a new species.","Species", GLOB.species_meta) + var/new_species = tgui_input_list(usr, "Please choose a new species.","Species", SScharacters.all_species_names()) if(!H) to_chat(usr, "Mob doesn't exist anymore") @@ -460,7 +460,7 @@ to_chat(usr, "This can only be done to instances of type /mob") return - var/new_language = tgui_input_list(usr, "Please choose a language to add.","Language", GLOB.all_languages) + var/new_language = tgui_input_list(usr, "Please choose a language to add.","Language", SScharacters.all_language_names()) if(!new_language) return diff --git a/code/modules/artifice/deadringer.dm b/code/modules/artifice/deadringer.dm index ba5db739434..ccc6bd63698 100644 --- a/code/modules/artifice/deadringer.dm +++ b/code/modules/artifice/deadringer.dm @@ -161,7 +161,7 @@ corpse.flavor_texts = H.flavor_texts.Copy() corpse.real_name = H.real_name corpse.name = H.name - corpse.set_species(species_type_by_name(corpse.dna.species)) + corpse.set_species(corpse.dna.species) corpse.change_hair(H.h_style) corpse.change_facial_hair(H.f_style) corpse.change_hair_color(H.r_hair, H.g_hair, H.b_hair) diff --git a/code/modules/blob2/overmind/types.dm b/code/modules/blob2/overmind/types.dm index 76458a1e237..86618919e9d 100644 --- a/code/modules/blob2/overmind/types.dm +++ b/code/modules/blob2/overmind/types.dm @@ -423,7 +423,7 @@ var/protection = H.get_cold_protection(50) if(protection < 1) var/temp_change = 80 // Each hit can reduce temperature by up to 80 kelvin. - var/datum/species/baseline = get_static_species_meta(/datum/species/human) + var/datum/species/baseline = SScharacters.resolve_species_path(/datum/species/human) var/temp_cap = baseline.cold_level_3 - 5 // Can't go lower than this. var/cold_factor = abs(protection - 1) @@ -513,7 +513,7 @@ // Now for sounds. playsound(T, SFX_ALIAS_EXPLOSION, 75, 1) // Local sound. - for(var/mob/M in player_list) // For everyone else. + for(var/mob/M in GLOB.player_list) // For everyone else. if(M.z == T.z && get_dist(M, T) > world.view && !M.ear_deaf && !istype(M.loc,/turf/space)) SEND_SOUND(M, sound('sound/soundbytes/effects/explosion/explosionfar.ogg')) diff --git a/code/modules/catalogue/cataloguer.dm b/code/modules/catalogue/cataloguer.dm index 9e1869a1214..3aafb57ea61 100644 --- a/code/modules/catalogue/cataloguer.dm +++ b/code/modules/catalogue/cataloguer.dm @@ -150,7 +150,7 @@ GLOBAL_LIST_EMPTY(all_cataloguers) var/list/contributer_names = list() var/turf/T = get_turf(user) || get_turf(target) var/list/contributing_z = GetConnectedZlevels(T.z) - for(var/thing in player_list) + for(var/thing in GLOB.player_list) var/mob/living/L = thing if(L == user) continue diff --git a/code/modules/client/client_defines.dm b/code/modules/client/client_defines.dm index d84ce3dd435..765a4532320 100644 --- a/code/modules/client/client_defines.dm +++ b/code/modules/client/client_defines.dm @@ -35,6 +35,14 @@ */ parent_type = /datum + //! Intrinsics + /// did New() finish? + var/initialized = FALSE + /// Persistent round-by-round data holder + var/datum/client_data/persistent + /// Database data + var/datum/client_dbdata/database + //! Rendering /// Click catcher var/atom/movable/screen/click_catcher/click_catcher @@ -65,6 +73,7 @@ ///////// //OTHER// ///////// + // todo: rename to `preferences` & put it next to `persistent` to sate my OCD ~silicons ///Player preferences datum for the client var/datum/preferences/prefs = null ///Current area of the controlled mob diff --git a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm index a2c85d8b5e5..a70fcac2046 100644 --- a/code/modules/client/client_procs.dm +++ b/code/modules/client/client_procs.dm @@ -168,6 +168,10 @@ GLOBAL_LIST_INIT(blacklisted_builds, list( GLOB.clients += src GLOB.directory[ckey] = src + // resolve persistent data + persistent = resolve_client_data(ckey) + // todo: move resolve database data up here + // Instantiate tgui panel tgui_panel = new(src, "browseroutput") @@ -224,6 +228,7 @@ GLOBAL_LIST_INIT(blacklisted_builds, list( prefs = new /datum/preferences(src) GLOB.preferences_datums[ckey] = prefs + prefs.client = src prefs.last_ip = address //these are gonna be used for banning prefs.last_id = computer_id //these are gonna be used for banning //fps = prefs.clientfps //(prefs.clientfps < 0) ? RECOMMENDED_FPS : prefs.clientfps @@ -276,6 +281,11 @@ GLOBAL_LIST_INIT(blacklisted_builds, list( disconnect_with_message("Disconnected by bunker: [config_legacy.panic_bunker_message]") return FALSE + // resolve database data + // this is down here because player_lookup won't have an entry for us until log_client_to_db() runs!! + database = new(ckey) + database.LogConnect() + if (byond_version >= 512) if (!byond_build || byond_build < 1386) message_admins("[key_name(src)] has been detected as spoofing their byond version. Connection rejected.") @@ -365,8 +375,6 @@ GLOBAL_LIST_INIT(blacklisted_builds, list( // to_chat(src, get_message_output("memo")) // adminGreet() - prefs.sanitize_preferences() - if(custom_event_msg && custom_event_msg != "") to_chat(src, "

Custom Event

") to_chat(src, "

A custom event is taking place. OOC Info:

") @@ -394,7 +402,8 @@ GLOBAL_LIST_INIT(blacklisted_builds, list( if(isnum(account_age) && account_age <= 2) log_and_message_admins("PARANOIA: [key_name(src)] has a very new BYOND account ([account_age] days).") - fully_created = TRUE + initialized = TRUE + prefs.auto_flush_errors() ////////////// //DISCONNECT// @@ -410,6 +419,11 @@ GLOBAL_LIST_INIT(blacklisted_builds, list( GLOB.directory -= ckey log_access("Logout: [key_name(src)]") GLOB.ahelp_tickets.ClientLogout(src) + persistent = null + database = null + if(prefs) + prefs.client = null + prefs = null SSserver_maint.UpdateHubStatus() if(holder) holder.owner = null @@ -455,25 +469,6 @@ GLOBAL_LIST_INIT(blacklisted_builds, list( // Returns null if no DB connection can be established, or -1 if the requested key was not found in the database -/proc/get_player_age(key) - if(!SSdbcore.Connect()) - return null - - var/sql_ckey = sql_sanitize_text(ckey(key)) - - var/datum/db_query/query = SSdbcore.RunQuery( - "SELECT datediff(Now(), firstseen) as age FROM [format_table_name("player_lookup")] WHERE ckey = :ckey", - list( - "ckey" = sql_ckey - ) - ) - - if(query.NextRow()) - return text2num(query.item[1]) - else - return -1 - - /client/proc/log_client_to_db() if ( IsGuestKey(src.key) ) @@ -541,7 +536,7 @@ GLOBAL_LIST_INIT(blacklisted_builds, list( if(src.holder) admin_rank = src.holder.rank - var/sql_ip = sql_sanitize_text(src.address) + var/sql_ip = sql_sanitize_text(src.address) || "0.0.0.0" var/sql_computerid = sql_sanitize_text(src.computer_id) var/sql_admin_rank = sql_sanitize_text(admin_rank) @@ -850,9 +845,9 @@ GLOBAL_VAR_INIT(log_clicks, FALSE) var/http[] = world.Export(request) /* Debug - to_world_log("Requested this: [request]") + TO_WORLD_log("Requested this: [request]") for(var/entry in http) - to_world_log("[entry] : [http[entry]]") + TO_WORLD_log("[entry] : [http[entry]]") */ if(!http || !islist(http)) //If we couldn't check, the service might be down, fail-safe. diff --git a/code/modules/client/data.dm b/code/modules/client/data.dm new file mode 100644 index 00000000000..604a5b9c5b7 --- /dev/null +++ b/code/modules/client/data.dm @@ -0,0 +1,22 @@ +GLOBAL_LIST_EMPTY(client_data) + +/proc/resolve_client_data(ckey) + ckey = ckey(ckey) // just in case + if(!islist(GLOB.client_data)) + // we CANNOT RUNTIME + GLOB.client_data = list() + if(!istype(GLOB.client_data[ckey], /datum/client_data)) + GLOB.client_data[ckey] = new /datum/client_data(ckey) + return GLOB.client_data[ckey] + +/** + * client data datums, to hold + * round-based data that we don't want wiped + * by a disconnect. + */ +/datum/client_data + /// owner ckey + var/ckey + +/datum/client_data/New(ckey) + src.ckey = ckey diff --git a/code/modules/client/database.dm b/code/modules/client/database.dm new file mode 100644 index 00000000000..82b8297641e --- /dev/null +++ b/code/modules/client/database.dm @@ -0,0 +1,219 @@ +/** + * holds db-related data + * loaded every connect + */ +/datum/client_dbdata + //! intrinsics + /// our ckey + var/ckey + /// available: null if don't know yet, FALSE if no dbcon, TRUE if loaded + var/available + /// loading? + var/loading = FALSE + /// saving? + var/saving = FALSE + // todo: this lock system sucks ass + // todo: it should realistically be able to queue if something modifies us a lot + + //! loaded data + /// player id + var/player_id + /// player flags + var/player_flags = NONE + /// player age + var/player_age + +/datum/client_dbdata/New(ckey) + src.ckey = ckey + if(!src.ckey) + return + Load() + +/** + * async + */ +/datum/client_dbdata/proc/Load() + if(!SSdbcore.Connect()) + if(isnull(available)) + available = FALSE + return FALSE + INVOKE_ASYNC(src, .proc/Load_Async) + return TRUE + +/datum/client_dbdata/proc/Load_Async() + // allow admin proccalls - there's no args here. + var/was_proccall = !!IsAdminAdvancedProcCall() + var/old_usr = usr + usr = null + _Load_Lock(was_proccall) + usr = old_usr + +/datum/client_dbdata/proc/_Load_Lock(was_proccall) + if(IsAdminAdvancedProcCall()) + return + if(loading) + if(!was_proccall) + CRASH("loading is still locked; why are we loading this fast?") + return + loading = TRUE + _Load() + loading = FALSE + +/datum/client_dbdata/proc/_Load() + if(IsAdminAdvancedProcCall()) + return + var/datum/db_query/lookup + lookup = SSdbcore.ExecuteQuery( + "SELECT id, playerid, firstseen FROM [format_table_name("player_lookup")] WHERE ckey = :ckey", + list( + "ckey" = ckey + ) + ) + if(!lookup.NextRow()) + CRASH("failed to load lookup data") + var/lookup_id = lookup.item[1] + var/lookup_pid = lookup.item[2] + var/lookup_firstseen = lookup.item[3] + if(lookup_pid) + if(istext(lookup_id)) + lookup_id = text2num(lookup_id) + if(istext(lookup_pid)) + lookup_pid = text2num(lookup_pid) + qdel(lookup) + lookup = SSdbcore.ExecuteQuery( + "SELECT id, flags, datediff(Now(), firstseen) FROM [format_table_name("player")] WHERE id = :id", + list( + "id" = lookup_pid + ) + ) + if(lookup.NextRow()) + // found! + var/lookup_flags = lookup.item[2] + var/lookup_age = lookup.item[3] + if(istext(lookup_flags)) + lookup_flags = text2num(lookup_flags) + if(istext(lookup_age)) + lookup_age = text2num(lookup_age) + player_id = lookup_pid + player_flags = lookup_flags + player_age = lookup_age + qdel(lookup) + available = TRUE + else + CRASH("failed to lookup player row on id [lookup_pid] even though id was present in player_lookup.") + else + qdel(lookup) + RegisterNewPlayer(lookup_firstseen, lookup_id) + +/datum/client_dbdata/proc/RegisterNewPlayer(migrate_firstseen, lookup_id) + if(IsAdminAdvancedProcCall()) + return + // new person! + player_age = 0 + player_flags = NONE + var/datum/db_query/insert + if(migrate_firstseen) + insert = SSdbcore.ExecuteQuery( + "INSERT INTO [format_table_name("player")] (flags, firstseen, lastseen) VALUES (:flags, :fs, Now())", + list( + "flags" = player_flags, + "fs" = migrate_firstseen + ) + ) + else + insert = SSdbcore.ExecuteQuery( + "INSERT INTO [format_table_name("player")] (flags, firstseen, lastseen) VALUES (:flags, Now(), Now())", + list( + "flags" = player_flags, + ) + ) + var/insert_id = insert.last_insert_id + if(istext(insert_id)) + insert_id = text2num(insert_id) + if(!isnum(insert_id)) + CRASH("invalid insert id??") + player_id = insert_id + qdel(insert) + // now update lookup + insert = SSdbcore.ExecuteQuery( + "UPDATE [format_table_name("player_lookup")] SET playerid = :pid WHERE id = :id", + list( + "id" = lookup_id, + "pid" = insert_id + ) + ) + qdel(insert) + available = TRUE + // todo: lookup DATEDIFF so player age is set for the first connect after migrating a ckey. + +/** + * async + */ +/datum/client_dbdata/proc/Save() + set waitfor = FALSE + // why are we in here if we're write locked? + if(saving) + CRASH("write locked") + // don't fuck with things if we're read-locked + UNTIL(!loading) + // check again + if(saving) + CRASH("write locked") + // allow admin proccalls - there's no args here. + var/old_usr = usr + usr = null + // don't lock; if something is spamming our flags they probably shouldn't be + saving = TRUE + _Save() + saving = FALSE + usr = old_usr + +/datum/client_dbdata/proc/_Save() + qdel(SSdbcore.ExecuteQuery( + "UPDATE [format_table_name("player")] SET flags = :flags WHERE id = :id", + list( + "flags" = player_flags, + "id" = player_id + ) + )) + +/** + * async + */ +/datum/client_dbdata/proc/LogConnect() + set waitfor = FALSE + UpdateLastSeen() + +/datum/client_dbdata/proc/UpdateLastSeen() + // don't interrupt + if(!block_on_available()) + return FALSE + qdel(SSdbcore.ExecuteQuery( + "UPDATE [format_table_name("player")] SET lastseen = Now() WHERE id = :id", + list( + "id" = player_id + ) + )) + return TRUE + +/** + * sync + */ +/datum/client_dbdata/proc/player_age() + UNTIL(!loading) + return player_age + +/** + * block until we know if we're available + * then return if we are + */ +/datum/client_dbdata/proc/block_on_available() + UNTIL(!isnull(available)) + return available + +/** + * returns if we're available + * if we don't know yet, return false + */ +/datum/client_dbdata/proc/immediately_available() + return !!available diff --git a/code/modules/client/player_details.dm b/code/modules/client/player_details.dm index f4c1a1d7b2e..5e00e61c1df 100644 --- a/code/modules/client/player_details.dm +++ b/code/modules/client/player_details.dm @@ -2,6 +2,7 @@ ///assoc list of ckey -> /datum/player_details GLOBAL_LIST_EMPTY(player_details) +// todo: roll into client_data datums /datum/player_details var/list/player_actions = list() var/list/logging = list() diff --git a/code/modules/client/preference_setup/_defines.dm b/code/modules/client/preference_setup/_defines.dm deleted file mode 100644 index 0c4dbb60042..00000000000 --- a/code/modules/client/preference_setup/_defines.dm +++ /dev/null @@ -1,3 +0,0 @@ -#define EQUIP_PREVIEW_LOADOUT 1 -#define EQUIP_PREVIEW_JOB 2 -#define EQUIP_PREVIEW_ALL (EQUIP_PREVIEW_LOADOUT|EQUIP_PREVIEW_JOB) diff --git a/code/modules/client/preference_setup/general/02_language.dm b/code/modules/client/preference_setup/general/02_language.dm deleted file mode 100644 index 0d7158ddb4f..00000000000 --- a/code/modules/client/preference_setup/general/02_language.dm +++ /dev/null @@ -1,97 +0,0 @@ -/datum/category_item/player_setup_item/general/language - name = "Language" - sort_order = 2 - -/datum/category_item/player_setup_item/general/language/load_character(var/savefile/S) - S["language"] >> pref.alternate_languages - S["language_prefixes"] >> pref.language_prefixes - -/datum/category_item/player_setup_item/general/language/save_character(var/savefile/S) - S["language"] << pref.alternate_languages - S["language_prefixes"] << pref.language_prefixes - -/datum/category_item/player_setup_item/general/language/sanitize_character() - if(!islist(pref.alternate_languages)) pref.alternate_languages = list() - if(pref.species) - var/datum/species/S = pref.character_static_species_meta() - if(S && pref.alternate_languages.len > S.num_alternate_languages) - pref.alternate_languages.len = S.num_alternate_languages // Truncate to allowed length - if(isnull(pref.language_prefixes) || !pref.language_prefixes.len) - pref.language_prefixes = config_legacy.language_prefixes.Copy() - -/datum/category_item/player_setup_item/general/language/content() - . += "Languages
" - var/datum/species/S = pref.character_static_species_meta() - if(S.language) - . += "- [S.language]
" - if(S.default_language && S.default_language != S.language) - . += "- [S.default_language]
" - if(S.num_alternate_languages) - if(pref.alternate_languages.len) - for(var/i = 1 to pref.alternate_languages.len) - var/lang = pref.alternate_languages[i] - . += "- [lang] - remove
" - - if(pref.alternate_languages.len < S.num_alternate_languages) - . += "- add ([S.num_alternate_languages - pref.alternate_languages.len] remaining)
" - else - . += "- [pref.species] cannot choose secondary languages.
" - - . += "Language Keys
" - . += " [jointext(pref.language_prefixes, " ")] Change Reset
" - -/datum/category_item/player_setup_item/general/language/OnTopic(var/href,var/list/href_list, var/mob/user) - if(href_list["remove_language"]) - var/index = text2num(href_list["remove_language"]) - pref.alternate_languages.Cut(index, index+1) - return TOPIC_REFRESH - else if(href_list["add_language"]) - var/datum/species/S = pref.character_static_species_meta() - if(pref.alternate_languages.len >= S.num_alternate_languages) - alert(user, "You have already selected the maximum number of alternate languages for this species!") - else - var/list/available_languages = S.secondary_langs.Copy() - for(var/L in GLOB.all_languages) - var/datum/language/lang = GLOB.all_languages[L] - if(!(lang.flags & RESTRICTED) && (is_lang_whitelisted(user, lang))) - available_languages |= L - - // make sure we don't let them waste slots on the default languages - available_languages -= S.language - available_languages -= S.default_language - available_languages -= pref.alternate_languages - - if(!available_languages.len) - alert(user, "There are no additional languages available to select.") - else - var/new_lang = input(user, "Select an additional language", "Character Generation", null) as null|anything in available_languages - if(new_lang && pref.alternate_languages.len < S.num_alternate_languages) - pref.alternate_languages |= new_lang - return TOPIC_REFRESH - - else if(href_list["change_prefix"]) - var/char - var/keys[0] - do - char = input("Enter a single special character.\nYou may re-select the same characters.\nThe following characters are already in use by radio: ; : .\nThe following characters are already in use by special say commands: ! * ^", "Enter Character - [3 - keys.len] remaining") as null|text - if(char) - if(length(char) > 1) - alert(user, "Only single characters allowed.", "Error", "Ok") - else if(char in list(";", ":", ".")) - alert(user, "Radio character. Rejected.", "Error", "Ok") - else if(char in list("!","*", "^")) - alert(user, "Say character. Rejected.", "Error", "Ok") - else if(contains_az09(char)) - alert(user, "Non-special character. Rejected.", "Error", "Ok") - else - keys.Add(char) - while(char && keys.len < 3) - - if(keys.len == 3) - pref.language_prefixes = keys - return TOPIC_REFRESH - else if(href_list["reset_prefix"]) - pref.language_prefixes = config_legacy.language_prefixes.Copy() - return TOPIC_REFRESH - - return ..() diff --git a/code/modules/client/preference_setup/general/05_background.dm b/code/modules/client/preference_setup/general/05_background.dm deleted file mode 100644 index 9ec96fc3d12..00000000000 --- a/code/modules/client/preference_setup/general/05_background.dm +++ /dev/null @@ -1,135 +0,0 @@ -/datum/category_item/player_setup_item/general/background - name = "Background" - sort_order = 5 - -/datum/category_item/player_setup_item/general/background/load_character(var/savefile/S) - S["med_record"] >> pref.med_record - S["sec_record"] >> pref.sec_record - S["gen_record"] >> pref.gen_record - S["home_system"] >> pref.home_system - S["citizenship"] >> pref.citizenship - S["faction"] >> pref.faction - S["religion"] >> pref.religion - S["economic_status"] >> pref.economic_status - -/datum/category_item/player_setup_item/general/background/save_character(var/savefile/S) - S["med_record"] << pref.med_record - S["sec_record"] << pref.sec_record - S["gen_record"] << pref.gen_record - S["home_system"] << pref.home_system - S["citizenship"] << pref.citizenship - S["faction"] << pref.faction - S["religion"] << pref.religion - S["economic_status"] << pref.economic_status - -/datum/category_item/player_setup_item/general/background/sanitize_character() - if(!pref.home_system) pref.home_system = "Unset" - if(!pref.citizenship) pref.citizenship = "None" - if(!pref.faction) pref.faction = "None" - if(!pref.religion) pref.religion = "None" - - pref.economic_status = sanitize_inlist(pref.economic_status, ECONOMIC_CLASS, initial(pref.economic_status)) - -// Moved from /datum/preferences/proc/copy_to() -/datum/category_item/player_setup_item/general/background/copy_to_mob(var/mob/living/carbon/human/character) - character.med_record = pref.med_record - character.sec_record = pref.sec_record - character.gen_record = pref.gen_record - character.home_system = pref.home_system - character.citizenship = pref.citizenship - character.personal_faction = pref.faction - character.religion = pref.religion - -/datum/category_item/player_setup_item/general/background/content(var/mob/user) - . += "Background Information
" - . += "Economic Status: [pref.economic_status]
" - . += "Home System: [pref.home_system]
" - . += "Citizenship: [pref.citizenship]
" - . += "Faction: [pref.faction]
" - . += "Religion: [pref.religion]
" - - . += "
Records:
" - if(jobban_isbanned(user, "Records")) - . += "You are banned from using character records.
" - else - . += "Medical Records:
" - . += "[TextPreview(pref.med_record,40)]

" - . += "Employment Records:
" - . += "[TextPreview(pref.gen_record,40)]

" - . += "Security Records:
" - . += "[TextPreview(pref.sec_record,40)]
" - -/datum/category_item/player_setup_item/general/background/OnTopic(var/href,var/list/href_list, var/mob/user) - if(href_list["econ_status"]) - var/new_class = input(user, "Choose your economic status. This will affect the amount of money you will start with.", "Character Preference", pref.economic_status) as null|anything in ECONOMIC_CLASS - if(new_class && CanUseTopic(user)) - pref.economic_status = new_class - return TOPIC_REFRESH - - else if(href_list["home_system"]) - var/choice = input(user, "Please choose a home system.", "Character Preference", pref.home_system) as null|anything in home_system_choices + list("Unset","Other") - if(!choice || !CanUseTopic(user)) - return TOPIC_NOACTION - if(choice == "Other") - var/raw_choice = sanitize(input(user, "Please enter a home system.", "Character Preference") as text|null, MAX_NAME_LEN) - if(raw_choice && CanUseTopic(user)) - pref.home_system = raw_choice - else - pref.home_system = choice - return TOPIC_REFRESH - - else if(href_list["citizenship"]) - var/choice = input(user, "Please choose your current citizenship.", "Character Preference", pref.citizenship) as null|anything in citizenship_choices + list("None","Other") - if(!choice || !CanUseTopic(user)) - return TOPIC_NOACTION - if(choice == "Other") - var/raw_choice = sanitize(input(user, "Please enter your current citizenship.", "Character Preference") as text|null, MAX_NAME_LEN) - if(raw_choice && CanUseTopic(user)) - pref.citizenship = raw_choice - else - pref.citizenship = choice - return TOPIC_REFRESH - - else if(href_list["faction"]) - var/choice = input(user, "Please choose a faction to work for.", "Character Preference", pref.faction) as null|anything in faction_choices + list("None","Other") - if(!choice || !CanUseTopic(user)) - return TOPIC_NOACTION - if(choice == "Other") - var/raw_choice = sanitize(input(user, "Please enter a faction.", "Character Preference") as text|null, MAX_NAME_LEN) - if(raw_choice) - pref.faction = raw_choice - else - pref.faction = choice - return TOPIC_REFRESH - - else if(href_list["religion"]) - var/choice = input(user, "Please choose a religion.", "Character Preference", pref.religion) as null|anything in religion_choices + list("None","Other") - if(!choice || !CanUseTopic(user)) - return TOPIC_NOACTION - if(choice == "Other") - var/raw_choice = sanitize(input(user, "Please enter a religon.", "Character Preference") as text|null, MAX_NAME_LEN) - if(raw_choice) - pref.religion = sanitize(raw_choice) - else - pref.religion = choice - return TOPIC_REFRESH - - else if(href_list["set_medical_records"]) - var/new_medical = sanitize(input(user,"Enter medical information here.","Character Preference", html_decode(pref.med_record)) as message|null, MAX_RECORD_LENGTH, extra = 0) - if(!isnull(new_medical) && !jobban_isbanned(user, "Records") && CanUseTopic(user)) - pref.med_record = new_medical - return TOPIC_REFRESH - - else if(href_list["set_general_records"]) - var/new_general = sanitize(input(user,"Enter employment information here.","Character Preference", html_decode(pref.gen_record)) as message|null, MAX_RECORD_LENGTH, extra = 0) - if(!isnull(new_general) && !jobban_isbanned(user, "Records") && CanUseTopic(user)) - pref.gen_record = new_general - return TOPIC_REFRESH - - else if(href_list["set_security_records"]) - var/sec_medical = sanitize(input(user,"Enter security information here.","Character Preference", html_decode(pref.sec_record)) as message|null, MAX_RECORD_LENGTH, extra = 0) - if(!isnull(sec_medical) && !jobban_isbanned(user, "Records") && CanUseTopic(user)) - pref.sec_record = sec_medical - return TOPIC_REFRESH - - return ..() diff --git a/code/modules/client/preference_setup/occupation/occupation.dm b/code/modules/client/preference_setup/occupation/occupation.dm deleted file mode 100644 index 4097e1c43ee..00000000000 --- a/code/modules/client/preference_setup/occupation/occupation.dm +++ /dev/null @@ -1,408 +0,0 @@ -/datum/category_group/player_setup_category/occupation_preferences - name = "Occupation" - sort_order = 3 - category_item_type = /datum/category_item/player_setup_item/occupation - -/datum/category_group/player_setup_category/occupation_preferences/content(var/mob/user) - for(var/datum/category_item/player_setup_item/PI in items) - . += "[PI.content(user)]
" - -/datum/category_item/player_setup_item/occupation - name = "Occupation" - sort_order = 1 - -/datum/category_item/player_setup_item/occupation/load_character(var/savefile/S) - S["alternate_option"] >> pref.alternate_option - S["job_civilian_high"] >> pref.job_civilian_high - S["job_civilian_med"] >> pref.job_civilian_med - S["job_civilian_low"] >> pref.job_civilian_low - S["job_medsci_high"] >> pref.job_medsci_high - S["job_medsci_med"] >> pref.job_medsci_med - S["job_medsci_low"] >> pref.job_medsci_low - S["job_engsec_high"] >> pref.job_engsec_high - S["job_engsec_med"] >> pref.job_engsec_med - S["job_engsec_low"] >> pref.job_engsec_low - S["job_talon_low"] >> pref.job_talon_low - S["job_talon_med"] >> pref.job_talon_med - S["job_talon_high"] >> pref.job_talon_high - S["player_alt_titles"] >> pref.player_alt_titles - -/datum/category_item/player_setup_item/occupation/save_character(var/savefile/S) - S["alternate_option"] << pref.alternate_option - S["job_civilian_high"] << pref.job_civilian_high - S["job_civilian_med"] << pref.job_civilian_med - S["job_civilian_low"] << pref.job_civilian_low - S["job_medsci_high"] << pref.job_medsci_high - S["job_medsci_med"] << pref.job_medsci_med - S["job_medsci_low"] << pref.job_medsci_low - S["job_engsec_high"] << pref.job_engsec_high - S["job_engsec_med"] << pref.job_engsec_med - S["job_engsec_low"] << pref.job_engsec_low - S["job_talon_low"] << pref.job_talon_low - S["job_talon_med"] << pref.job_talon_med - S["job_talon_high"] << pref.job_talon_high - S["player_alt_titles"] << pref.player_alt_titles - -/datum/category_item/player_setup_item/occupation/sanitize_character() - pref.alternate_option = sanitize_integer(pref.alternate_option, 0, 2, initial(pref.alternate_option)) - pref.job_civilian_high = sanitize_integer(pref.job_civilian_high, 0, ALL, initial(pref.job_civilian_high)) //I'm not sorry, Kevin made me do this - Papalus - pref.job_civilian_med = sanitize_integer(pref.job_civilian_med, 0, ALL, initial(pref.job_civilian_med)) - pref.job_civilian_low = sanitize_integer(pref.job_civilian_low, 0, ALL, initial(pref.job_civilian_low)) - pref.job_medsci_high = sanitize_integer(pref.job_medsci_high, 0, ALL, initial(pref.job_medsci_high)) - pref.job_medsci_med = sanitize_integer(pref.job_medsci_med, 0, ALL, initial(pref.job_medsci_med)) - pref.job_medsci_low = sanitize_integer(pref.job_medsci_low, 0, ALL, initial(pref.job_medsci_low)) - pref.job_engsec_high = sanitize_integer(pref.job_engsec_high, 0, ALL, initial(pref.job_engsec_high)) - pref.job_engsec_med = sanitize_integer(pref.job_engsec_med, 0, ALL, initial(pref.job_engsec_med)) - pref.job_engsec_low = sanitize_integer(pref.job_engsec_low, 0, ALL, initial(pref.job_engsec_low)) - pref.job_talon_high = sanitize_integer(pref.job_talon_high, 0, ALL, initial(pref.job_talon_high)) - pref.job_talon_med = sanitize_integer(pref.job_talon_med, 0, ALL, initial(pref.job_talon_med)) - pref.job_talon_low = sanitize_integer(pref.job_talon_low, 0, ALL, initial(pref.job_talon_low)) - if(!(pref.player_alt_titles)) pref.player_alt_titles = new() - - if(!job_master) - return - - for(var/datum/job/job in job_master.occupations) - var/alt_title = pref.player_alt_titles[job.title] - if(alt_title && !(alt_title in job.alt_titles)) - pref.player_alt_titles -= job.title - -/datum/category_item/player_setup_item/occupation/content(mob/user, limit = 25, list/splitJobs = list()) - if(!job_master) - return - - . = list() - . += "
" - . += "Choose occupation chances
Unavailable occupations are crossed out.
" - . += "" - . += "
" // Table within a table for alignment, also allows you to easily add more columns. - . += "" - var/index = -1 - - //The job before the current job. I only use this to get the previous jobs color when I'm filling in blank rows. - var/datum/job/lastJob - var/datum/department/last_department = null // Used to avoid repeating the look-ahead check for if a whole department can fit. - - var/list/all_valid_jobs = list() - // If the occupation window gets opened before SSJob initializes, then it'll just be blank, with no runtimes. - // It will work once init is finished. - - for(var/D in SSjob.department_datums) - var/datum/department/department = SSjob.department_datums[D] - if(department.centcom_only) // No joining as a centcom role, if any are ever added. - continue - - for(var/J in department.primary_jobs) - all_valid_jobs += department.jobs[J] - - for(var/datum/job/job in all_valid_jobs) - if(job.latejoin_only) continue - var/datum/department/current_department = SSjob.get_primary_department_of_job(job) - - // Should we add a new column? - var/make_new_column = FALSE - if(++index > limit) - // Ran out of rows, make a new column. - make_new_column = TRUE - - else if(job.title in splitJobs) - // Is hardcoded to split at this job title. - make_new_column = TRUE - - else if(current_department != last_department) - // If the department is bigger than the limit then we have to split. - if(limit >= current_department.primary_jobs.len) - // Look ahead to see if we would need to split, and if so, avoid it. - if(index + current_department.primary_jobs.len > limit) - // Looked ahead, and determined that a new column is needed to avoid splitting the department into two. - make_new_column = TRUE - - - if(make_new_column) -/******* - if((index < limit) && (lastJob != null)) - //If the cells were broken up by a job in the splitJob list then it will fill in the rest of the cells with - //the last job's selection color and blank buttons that do nothing. Creating a rather nice effect. - for(var/i = 0, i < (limit - index), i++) - . += "" -*******/ - . += "
//>  
" - index = 0 - last_department = current_department - - . += "" - continue - if(!job.player_old_enough(user.client)) - var/available_in_days = job.available_in_days(user.client) - . += "[rank]" - continue - if(!is_job_whitelisted(user,rank)) - . += "[rank]" - continue - if(job.minimum_character_age && user.client && (user.client.prefs.age < job.minimum_character_age)) - . += "[rank]" - continue - if((pref.job_civilian_low & ASSISTANT) && job.type != /datum/job/station/assistant) - . += "[rank]" - continue - if((rank in SSjob.get_job_titles_in_department(DEPARTMENT_COMMAND) ) || (rank == "AI"))//Bold head jobs - . += "[rank]" - else - . += "[rank]" - - . += "" - . += "" - continue - - . += " \[[prefLevelLabel]]" - if(LAZYLEN(job.alt_titles)) - . += "" - . += "" - . += "
" - - var/rank = job.title - lastJob = job - . += "" - if(jobban_isbanned(user, rank)) - . += "[rank] \[BANNED]
\[IN [(available_in_days)] DAYS]
\[WHITELIST ONLY]
\[MINIMUM CHARACTER AGE: [job.minimum_character_age]]
" - - var/prefLevelLabel = "ERROR" - var/prefLevelColor = "pink" - var/prefUpperLevel = -1 // level to assign on left click - var/prefLowerLevel = -1 // level to assign on right click - if(pref.GetJobDepartment(job, 1) & job.flag) - prefLevelLabel = "High" - prefLevelColor = "55cc55" - prefUpperLevel = 4 - prefLowerLevel = 2 - else if(pref.GetJobDepartment(job, 2) & job.flag) - prefLevelLabel = "Medium" - prefLevelColor = "eecc22" - prefUpperLevel = 1 - prefLowerLevel = 3 - else if(pref.GetJobDepartment(job, 3) & job.flag) - prefLevelLabel = "Low" - prefLevelColor = "cc5555" - prefUpperLevel = 2 - prefLowerLevel = 4 - else - prefLevelLabel = "NEVER" - prefLevelColor = "black" - prefUpperLevel = 3 - prefLowerLevel = 1 - - . += "" - - if(job.type == /datum/job/station/assistant)//Assistant is special - if(pref.job_civilian_low & ASSISTANT) - . += " \[Yes]" - else - . += " \[No]" - if(LAZYLEN(job.alt_titles)) //Blatantly cloned from a few lines down. - . += "
 \[[pref.GetPlayerAltTitle(job)]\]
 \[[pref.GetPlayerAltTitle(job)]\]
" - . += "
" - - switch(pref.alternate_option) - if(GET_RANDOM_JOB) - . += "Get random job if preferences unavailable" - if(BE_ASSISTANT) - . += "Be assistant if preference unavailable" - if(RETURN_TO_LOBBY) - . += "Return to lobby if preference unavailable" - - . += "\[Reset\]
" - . += "
" - . = jointext(.,null) - -/datum/category_item/player_setup_item/occupation/OnTopic(href, href_list, user) - if(href_list["reset_jobs"]) - ResetJobs() - return TOPIC_REFRESH - - else if(href_list["job_alternative"]) - if(pref.alternate_option == GET_RANDOM_JOB || pref.alternate_option == BE_ASSISTANT) - pref.alternate_option += 1 - else if(pref.alternate_option == RETURN_TO_LOBBY) - pref.alternate_option = 0 - return TOPIC_REFRESH - - else if(href_list["select_alt_title"]) - var/datum/job/job = locate(href_list["select_alt_title"]) - if (job) - var/choices = list(job.title) + job.alt_titles - var/choice = input("Choose a title for [job.title].", "Choose Title", pref.GetPlayerAltTitle(job)) as anything in choices|null - if(choice && CanUseTopic(user)) - SetPlayerAltTitle(job, choice) - return (pref.equip_preview_mob ? TOPIC_REFRESH_UPDATE_PREVIEW : TOPIC_REFRESH) - - else if(href_list["set_job"]) - if(SetJob(user, href_list["set_job"], text2num(href_list["level"]))) - return (pref.equip_preview_mob ? TOPIC_REFRESH_UPDATE_PREVIEW : TOPIC_REFRESH) - - else if(href_list["job_info"]) - var/rank = href_list["job_info"] - var/datum/job/job = job_master.GetJob(rank) - var/dat = list() - - dat += "



" - if(job.alt_titles) - dat += "Alternate titles: [english_list(job.alt_titles)]." - user << browse_rsc(job.get_job_icon(), "job[ckey(rank)].png") - dat += "" - if(job.departments) - dat += "Departments: [english_list(job.departments)]." - if(LAZYLEN(job.departments_managed)) - dat += "You manage these departments: [english_list(job.departments_managed)]" - - dat += "You answer to [job.supervisors] normally." - - dat += "


" - if(config_legacy.wikiurl) - dat += "Open wiki page in browser" - - var/alt_title = pref.GetPlayerAltTitle(job) - var/list/description = job.get_description_blurb(alt_title) - if(LAZYLEN(description)) - dat += html_encode(description[1]) - if(description.len > 1) - if(!isnull(description[2])) - dat += "
" - dat += html_encode(description[2]) - - var/datum/browser/popup = new(user, "Job Info", "[capitalize(rank)]", 430, 520, src) - popup.set_content(jointext(dat,"
")) - popup.open() - - else if(href_list["job_wiki"]) - var/rank = href_list["job_wiki"] - user << link("[config_legacy.wikiurl][rank]") - - return ..() - -/datum/category_item/player_setup_item/occupation/proc/SetPlayerAltTitle(datum/job/job, new_title) - // remove existing entry - pref.player_alt_titles -= job.title - // add one if it's not default - if(job.title != new_title) - pref.player_alt_titles[job.title] = new_title - -/datum/category_item/player_setup_item/occupation/proc/SetJob(mob/user, role, level) - var/datum/job/job = job_master.GetJob(role) - if(!job) - return 0 - - if(job.type == /datum/job/station/assistant) - if(pref.job_civilian_low & job.flag) - pref.job_civilian_low &= ~job.flag - else - pref.job_civilian_low |= job.flag - return 1 - - SetJobDepartment(job, level) - return 1 - -/datum/category_item/player_setup_item/occupation/proc/reset_jobhigh() - pref.job_civilian_med |= pref.job_civilian_high - pref.job_medsci_med |= pref.job_medsci_high - pref.job_engsec_med |= pref.job_engsec_high - pref.job_talon_med |= pref.job_talon_high - pref.job_civilian_high = 0 - pref.job_medsci_high = 0 - pref.job_engsec_high = 0 - pref.job_talon_high = 0 - -// Level is equal to the desired new level of the job. So for a value of 4, we want to disable the job. -/datum/category_item/player_setup_item/occupation/proc/SetJobDepartment(var/datum/job/job, var/level) - if(!job || !level) - return 0 - - switch(job.department_flag) - if(CIVILIAN) - pref.job_civilian_low &= ~job.flag - pref.job_civilian_med &= ~job.flag - pref.job_civilian_high &= ~job.flag - switch(level) - if(1) - reset_jobhigh() - pref.job_civilian_high = job.flag - if(2) - pref.job_civilian_med |= job.flag - if(3) - pref.job_civilian_low |= job.flag - if(MEDSCI) - pref.job_medsci_low &= ~job.flag - pref.job_medsci_med &= ~job.flag - pref.job_medsci_high &= ~job.flag - switch(level) - if(1) - reset_jobhigh() - pref.job_medsci_high = job.flag - if(2) - pref.job_medsci_med |= job.flag - if(3) - pref.job_medsci_low |= job.flag - if(ENGSEC) - pref.job_engsec_low &= ~job.flag - pref.job_engsec_med &= ~job.flag - pref.job_engsec_high &= ~job.flag - switch(level) - if(1) - reset_jobhigh() - pref.job_engsec_high = job.flag - if(2) - pref.job_engsec_med |= job.flag - if(3) - pref.job_engsec_low |= job.flag - - return 1 - -/datum/category_item/player_setup_item/occupation/proc/ResetJobs() - pref.job_civilian_high = 0 - pref.job_civilian_med = 0 - pref.job_civilian_low = 0 - - pref.job_medsci_high = 0 - pref.job_medsci_med = 0 - pref.job_medsci_low = 0 - - pref.job_engsec_high = 0 - pref.job_engsec_med = 0 - pref.job_engsec_low = 0 - - pref.job_talon_high = 0 - pref.job_talon_med = 0 - pref.job_talon_low = 0 - - pref.player_alt_titles.Cut() - -/datum/preferences/proc/GetPlayerAltTitle(datum/job/job) - return (job.title in player_alt_titles) ? player_alt_titles[job.title] : job.title - -/datum/preferences/proc/GetJobDepartment(var/datum/job/job, var/level) - if(!job || !level) return 0 - switch(job.department_flag) - if(CIVILIAN) - switch(level) - if(1) - return job_civilian_high - if(2) - return job_civilian_med - if(3) - return job_civilian_low - if(MEDSCI) - switch(level) - if(1) - return job_medsci_high - if(2) - return job_medsci_med - if(3) - return job_medsci_low - if(ENGSEC) - switch(level) - if(1) - return job_engsec_high - if(2) - return job_engsec_med - if(3) - return job_engsec_low - return 0 diff --git a/code/modules/client/preference_setup/vore/07_vantag.dm b/code/modules/client/preference_setup/vore/07_vantag.dm deleted file mode 100644 index 7f6b7c4c1a0..00000000000 --- a/code/modules/client/preference_setup/vore/07_vantag.dm +++ /dev/null @@ -1,52 +0,0 @@ -// Define a place to save in character setup -/datum/preferences - var/vantag_volunteer = 0 // What state I want to be in, in terms of being affected by antags. - var/vantag_preference = VANTAG_NONE // Whether I'd like to volunteer to be an antag at some point. - -// Definition of the stuff for Sizing -/datum/category_item/player_setup_item/vore/vantag - name = "VS Events" - sort_order = 7 - -/datum/category_item/player_setup_item/vore/vantag/load_character(var/savefile/S) - S["vantag_volunteer"] >> pref.vantag_volunteer - S["vantag_preference"] >> pref.vantag_preference - -/datum/category_item/player_setup_item/vore/vantag/save_character(var/savefile/S) - S["vantag_volunteer"] << pref.vantag_volunteer - S["vantag_preference"] << pref.vantag_preference - -/datum/category_item/player_setup_item/vore/vantag/sanitize_character() - pref.vantag_volunteer = sanitize_integer(pref.vantag_volunteer, 0, 1, initial(pref.vantag_volunteer)) - pref.vantag_preference = sanitize_inlist(pref.vantag_preference, vantag_choices_list, initial(pref.vantag_preference)) - -/datum/category_item/player_setup_item/vore/vantag/copy_to_mob(var/mob/living/carbon/human/character) -/* - if(character && !istype(character,/mob/living/carbon/human/dummy)) - character.vantag_pref = pref.vantag_preference - BITSET(character.hud_updateflag, VANTAG_HUD) - whoever made hud updateflags is a curse -*/ - -/datum/category_item/player_setup_item/vore/vantag/content(var/mob/user) -/* no, we have our own system - . += "
" - . += "Event Volunteer: [pref.vantag_volunteer ? "Yes" : "No"]
" - . += "Event Pref: [vantag_choices_list[pref.vantag_preference]]
" -*/ - -/datum/category_item/player_setup_item/vore/vantag/OnTopic(var/href, var/list/href_list, var/mob/user) - if(href_list["toggle_vantag_volunteer"]) - pref.vantag_volunteer = pref.vantag_volunteer ? 0 : 1 - return TOPIC_REFRESH - - else if(href_list["change_vantag"]) - var/list/names_list = list() - for(var/C in vantag_choices_list) - names_list[vantag_choices_list[C]] = C - - var/selection = input(user, "How do you want to be involved with VS Event Characters, ERP-wise? They will see this choice on you in a HUD. Event characters are admin-selected and spawned players, possibly with assigned objectives, who are obligated to respect ERP prefs and RP their actions like any other player, though it may be a slightly shorter RP if they are pressed for time or being caught.", "Event Preference") as null|anything in names_list - if(selection && selection != "Normal") - pref.vantag_preference = names_list[selection] - - return TOPIC_REFRESH - return ..() diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm deleted file mode 100644 index 95e5b8d4ea3..00000000000 --- a/code/modules/client/preferences_savefile.dm +++ /dev/null @@ -1,142 +0,0 @@ -#define SAVEFILE_VERSION_MIN 13 -#define SAVEFILE_VERSION_MAX 14 - -//handles converting savefiles to new formats -//MAKE SURE YOU KEEP THIS UP TO DATE! -//If the sanity checks are capable of handling any issues. Only increase SAVEFILE_VERSION_MAX, -//this will mean that savefile_version will still be over SAVEFILE_VERSION_MIN, meaning -//this savefile update doesn't run everytime we load from the savefile. -//This is mainly for format changes, such as the bitflags in toggles changing order or something. -//if a file can't be updated, return 0 to delete it and start again -//if a file was updated, return 1 -/datum/preferences/proc/savefile_update() - if(savefile_version < 8) //lazily delete everything + additional files so they can be saved in the new format - for(var/ckey in GLOB.preferences_datums) - var/datum/preferences/D = GLOB.preferences_datums[ckey] - if(D == src) - var/delpath = "data/player_saves/[copytext(ckey,1,2)]/[ckey]/" - if(delpath && fexists(delpath)) - fdel(delpath) - break - addtimer(CALLBACK(src, .proc/force_reset_keybindings), 3 SECONDS) //No mob available when this is run, timer allows user choice. - return FALSE - if(savefile_version < 13) //TODO : PROPER MIGRATION SYSTEM - kevinz000 - savefile_version = 13 - addtimer(CALLBACK(src, .proc/force_reset_keybindings), 3 SECONDS) //No mob available when this is run, timer allows user choice. - - return TRUE - -/datum/preferences/proc/load_path(ckey,filename="preferences.sav") - if(!ckey) return - path = "data/player_saves/[copytext(ckey,1,2)]/[ckey]/[filename]" - savefile_version = SAVEFILE_VERSION_MAX - -/datum/preferences/proc/load_preferences() - if(!path) - return 0 - if(world.time < loadprefcooldown) //This is done before checking if the file exists to ensure that the server can't hang on read attempts - if(istype(client)) - to_chat(client, "You're attempting to load your preferences a little too fast. Wait half a second, then try again.") - return 0 - loadprefcooldown = world.time + PREF_SAVELOAD_COOLDOWN - if(!fexists(path)) - return 0 - var/savefile/S = new /savefile(path) - if(!S) - return 0 - S.cd = "/" - - S["version"] >> savefile_version - //Conversion - if(!savefile_version || !isnum(savefile_version) || savefile_version < SAVEFILE_VERSION_MIN || savefile_version > SAVEFILE_VERSION_MAX) - if(!savefile_update()) //handles updates - savefile_version = SAVEFILE_VERSION_MAX - save_preferences() - save_character() - return 0 - - player_setup.load_preferences(S) - return 1 - -/datum/preferences/proc/save_preferences() - if(!path) return 0 - if(world.time < saveprefcooldown) - if(istype(client)) - to_chat(client, "You're attempting to save your preferences a little too fast. Wait half a second, then try again.") - return 0 - saveprefcooldown = world.time + PREF_SAVELOAD_COOLDOWN - var/savefile/S = new /savefile(path) - if(!S) return 0 - S.cd = "/" - - S["version"] << savefile_version - player_setup.save_preferences(S) - return 1 - -/datum/preferences/proc/load_character(slot) - if(!path) return 0 - if(world.time < loadcharcooldown) - if(istype(client)) - to_chat(client, "You're attempting to load your character a little too fast. Wait half a second, then try again.") - return 0 - loadcharcooldown = world.time + PREF_SAVELOAD_COOLDOWN - if(!fexists(path)) return 0 - var/savefile/S = new /savefile(path) - if(!S) return 0 - S.cd = "/" - if(!slot) slot = default_slot - if(slot != SAVE_RESET) // SAVE_RESET will reset the slot as though it does not exist, but keep the current slot for saving purposes. - slot = sanitize_integer(slot, 1, config_legacy.character_slots, initial(default_slot)) - if(slot != default_slot) - default_slot = slot - S["default_slot"] << slot - else - S["default_slot"] << default_slot - - if(slot != SAVE_RESET) - S.cd = "/character[slot]" - player_setup.load_character(S) - else - player_setup.load_character(S) - S.cd = "/character[default_slot]" - - player_setup.load_character(S) - clear_character_previews() // Recalculate them on next show - return 1 - -/datum/preferences/proc/save_character() - if(!path) return 0 - if(world.time < savecharcooldown) - if(istype(client)) - to_chat(client, "You're attempting to save your character a little too fast. Wait half a second, then try again.") - return 0 - savecharcooldown = world.time + PREF_SAVELOAD_COOLDOWN - var/savefile/S = new /savefile(path) - if(!S) return 0 - S.cd = "/character[default_slot]" - - player_setup.save_character(S) - return 1 - -/datum/preferences/proc/overwrite_character(slot) - if(!path) return 0 - if(!fexists(path)) return 0 - var/savefile/S = new /savefile(path) - if(!S) return 0 - if(!slot) slot = default_slot - if(slot != SAVE_RESET) - slot = sanitize_integer(slot, 1, config_legacy.character_slots, initial(default_slot)) - if(slot != default_slot) - default_slot = slot - S["default_slot"] << slot - else - S["default_slot"] << default_slot - - return 1 - -/datum/preferences/proc/sanitize_preferences() - player_setup.sanitize_setup() - return 1 - -#undef SAVEFILE_VERSION_MAX -#undef SAVEFILE_VERSION_MIN diff --git a/code/modules/client/ui_style.dm b/code/modules/client/ui_style.dm index d8702605d6a..77e7600b33c 100644 --- a/code/modules/client/ui_style.dm +++ b/code/modules/client/ui_style.dm @@ -78,5 +78,5 @@ var/global/list/all_tooltip_styles = list( prefs.UI_style = UI_style_new prefs.UI_style_alpha = UI_style_alpha_new prefs.UI_style_color = UI_style_color_new - SScharacter_setup.queue_preferences_save(prefs) + SScharacters.queue_preferences_save(prefs) to_chat(usr, "UI was saved") diff --git a/code/modules/client/viewport.dm b/code/modules/client/viewport.dm index 58f33c01047..cfcb3d87e78 100644 --- a/code/modules/client/viewport.dm +++ b/code/modules/client/viewport.dm @@ -15,7 +15,7 @@ GLOBAL_LIST_INIT(valid_icon_sizes, list(32, 48, 64, 72, 96, 128)) if(prefs && val != prefs.icon_size) prefs.icon_size += val - SScharacter_setup.queue_preferences_save(prefs) + SScharacters.queue_preferences_save(prefs) winset(src, "mapwindow.map", "icon-size=[prefs.icon_size]") OnResize() @@ -24,7 +24,7 @@ GLOBAL_LIST_INIT(valid_icon_sizes, list(32, 48, 64, 72, 96, 128)) winset(src, "mapwindow.map", "icon-size=[val]") if(prefs && val != prefs.icon_size) prefs.icon_size = val - SScharacter_setup.queue_preferences_save(prefs) + SScharacters.queue_preferences_save(prefs) OnResize() /client/verb/OnResize() diff --git a/code/modules/events/comms_blackout.dm b/code/modules/events/comms_blackout.dm index 681d89a6e73..2fa8d6f11dc 100644 --- a/code/modules/events/comms_blackout.dm +++ b/code/modules/events/comms_blackout.dm @@ -4,7 +4,7 @@ if(!silent) command_announcement.Announce("Ionospheric anomalies detected. Temporary telecommunication failure imminent. Please contact you-BZZT", new_sound = 'sound/misc/interference.ogg') else // AIs will always know if there's a comm blackout, rogue AIs could then lie about comm blackouts in the future while they shutdown comms - for(var/mob/living/silicon/ai/A in player_list) + for(var/mob/living/silicon/ai/A in GLOB.player_list) to_chat(A, "
") to_chat(A, "Ionospheric anomalies detected. Temporary telecommunication failure imminent. Please contact you-BZZT") to_chat(A, "
") diff --git a/code/modules/events/communications_blackout.dm b/code/modules/events/communications_blackout.dm index 9e8b07e6145..826bdf360c2 100644 --- a/code/modules/events/communications_blackout.dm +++ b/code/modules/events/communications_blackout.dm @@ -20,7 +20,7 @@ "Ionospheri:%� MCayj^j<.3-BZZZZZZT", \ "#4nd%;f4y6,>�%-BZZZZZZZT") - for(var/mob/living/silicon/ai/A in player_list) //AIs are always aware of communication blackouts. + for(var/mob/living/silicon/ai/A in GLOB.player_list) //AIs are always aware of communication blackouts. to_chat(A, "
") to_chat(A, "[alert]") to_chat(A, "
") diff --git a/code/modules/events/event_container.dm b/code/modules/events/event_container.dm index 88ee5f05447..835ee6dbdea 100644 --- a/code/modules/events/event_container.dm +++ b/code/modules/events/event_container.dm @@ -97,7 +97,7 @@ var/global/list/severity_to_string = list(EVENT_LEVEL_MUNDANE = "Mundane", EVENT // Otherwise, follow the standard setup process else var/playercount_modifier = 1 - switch(player_list.len) + switch(GLOB.player_list.len) if(0 to 10) playercount_modifier = 1.2 if(11 to 15) diff --git a/code/modules/events/event_dynamic.dm b/code/modules/events/event_dynamic.dm index 7aa094e5d73..0098b71fcc2 100644 --- a/code/modules/events/event_dynamic.dm +++ b/code/modules/events/event_dynamic.dm @@ -50,10 +50,10 @@ var/list/event_last_fired = list() //possibleEvents[/datum/event/mundane_news] = 300 possibleEvents[/datum/event/lore_news] = 300 // up this if the above ones get removed as they damn well should - possibleEvents[/datum/event/pda_spam] = max(min(25, player_list.len) * 4, 200) - possibleEvents[/datum/event/money_lotto] = max(min(5, player_list.len), 50) + possibleEvents[/datum/event/pda_spam] = max(min(25, GLOB.player_list.len) * 4, 200) + possibleEvents[/datum/event/money_lotto] = max(min(5, GLOB.player_list.len), 50) if(account_hack_attempted) - possibleEvents[/datum/gm_action/money_hacker] = max(min(25, player_list.len) * 4, 200) + possibleEvents[/datum/gm_action/money_hacker] = max(min(25, GLOB.player_list.len) * 4, 200) possibleEvents[/datum/event/carp_migration] = 20 + 10 * active_with_role["Engineer"] @@ -114,7 +114,7 @@ var/list/event_last_fired = list() //moved this to proc/check_event() /*var/chance = possibleEvents[picked_event] var/base_chance = 0.4 - switch(player_list.len) + switch(GLOB.player_list.len) if(5 to 10) base_chance = 0.6 if(11 to 15) @@ -135,7 +135,7 @@ var/list/event_last_fired = list() /*switch(picked_event) if("Meteor") command_alert("Meteors have been detected on collision course with the station.", "Meteor Alert") - for(var/mob/M in player_list) + for(var/mob/M in GLOB.player_list) if(!istype(M,/mob/new_player)) SEND_SOUND(M, sound('sound/AI/meteors.ogg')) spawn(100) @@ -188,7 +188,7 @@ var/list/event_last_fired = list() active_with_role["Janitor"] = 0 active_with_role["Gardener"] = 0 - for(var/mob/M in player_list) + for(var/mob/M in GLOB.player_list) if(!M.mind || !M.client || M.client.is_afk(10 MINUTES)) // longer than 10 minutes AFK counts them as inactive continue diff --git a/code/modules/events/ion_storm.dm b/code/modules/events/ion_storm.dm index b4b1d8a7b4f..f0f64867ee8 100644 --- a/code/modules/events/ion_storm.dm +++ b/code/modules/events/ion_storm.dm @@ -19,7 +19,7 @@ // Interestingly enough, announce() actually *DOES* this event for some reason. /datum/event/ionstorm/announce() // command_alert("The station has entered an ion storm. Monitor all electronic equipment for malfunctions", "Anomaly Alert") - for (var/mob/living/carbon/human/player in player_list) + for (var/mob/living/carbon/human/player in GLOB.player_list) if( !player.mind || player_is_antag(player.mind, only_offstation_roles = 1) || player.client.inactivity > MinutesToTicks(10)) continue players += player.real_name @@ -102,7 +102,7 @@ Would like to add a law like "Law x is _______" where x = a number, and _____ is var/allergysev = pick("deathly", "mildly", "severely", "contagiously") var/crew var/list/pos_crew = list() - for(var/mob/living/carbon/human/pos in player_list) + for(var/mob/living/carbon/human/pos in GLOB.player_list) pos_crew += pos.real_name if(pos_crew.len) crew = pick(pos_crew) diff --git a/code/modules/events/prison_break.dm b/code/modules/events/prison_break.dm index 3c15a21fad2..e7cfd142be4 100644 --- a/code/modules/events/prison_break.dm +++ b/code/modules/events/prison_break.dm @@ -50,7 +50,7 @@ var/rc_message = "An unknown malicious program has been detected in the [english_list(areaName)] lighting and airlock control systems at [stationtime2text()]. Systems will be fully compromised within approximately three minutes. Direct intervention is required immediately.
" for(var/obj/machinery/message_server/MS in GLOB.machines) MS.send_rc_message("Engineering", my_department, rc_message, "", "", 2) - for(var/mob/living/silicon/ai/A in player_list) + for(var/mob/living/silicon/ai/A in GLOB.player_list) to_chat(A, "Malicious program detected in the [english_list(areaName)] lighting and airlock control systems by [my_department].") else diff --git a/code/modules/events/viral_infection.dm b/code/modules/events/viral_infection.dm index f426cc659f9..47b08efcc33 100644 --- a/code/modules/events/viral_infection.dm +++ b/code/modules/events/viral_infection.dm @@ -34,7 +34,7 @@ datum/event/viral_infection/start() if(!viruses.len) return var/list/candidates = list() //list of candidate keys - for(var/mob/living/carbon/human/G in player_list) + for(var/mob/living/carbon/human/G in GLOB.player_list) if(G.mind && G.stat != DEAD && G.is_client_active(5) && !player_is_antag(G.mind)) var/turf/T = get_turf(G) if(T.z in GLOB.using_map.station_levels) diff --git a/code/modules/events/viral_outbreak.dm b/code/modules/events/viral_outbreak.dm index 599b882bccc..5cfb4b7e6ac 100644 --- a/code/modules/events/viral_outbreak.dm +++ b/code/modules/events/viral_outbreak.dm @@ -13,7 +13,7 @@ /datum/event/viral_outbreak/start() var/list/candidates = list() //list of candidate keys - for(var/mob/living/carbon/human/G in player_list) + for(var/mob/living/carbon/human/G in GLOB.player_list) if(G.client && G.stat != DEAD) candidates += G if(!candidates.len) return diff --git a/code/modules/food/food/snacks.dm b/code/modules/food/food/snacks.dm index 10d993cbf48..fc7af89e8ea 100644 --- a/code/modules/food/food/snacks.dm +++ b/code/modules/food/food/snacks.dm @@ -1820,7 +1820,7 @@ /obj/item/reagent_containers/food/snacks/monkeycube/proc/Expand() src.visible_message("\The [src] expands!") var/mob/living/carbon/human/H = new(get_turf(src)) - H.set_species(species_type_by_name(monkey_type)) + H.set_species(monkey_type) H.real_name = H.species.get_random_name() H.name = H.real_name qdel(src) diff --git a/code/modules/food/kitchen/cooking_machines/fryer.dm b/code/modules/food/kitchen/cooking_machines/fryer.dm index af8582db9c6..15715e67c9f 100644 --- a/code/modules/food/kitchen/cooking_machines/fryer.dm +++ b/code/modules/food/kitchen/cooking_machines/fryer.dm @@ -169,7 +169,7 @@ if(ishuman(victim) && user.zone_sel.selecting != "groin" && user.zone_sel.selecting != "chest") var/mob/living/carbon/human/H = victim E = H.get_organ(user.zone_sel.selecting) - if(!E || E.species.flags & NO_PAIN) + if(!E || E.species.species_flags & NO_PAIN) nopain = 2 else if(E.robotic >= ORGAN_ROBOT) nopain = 1 diff --git a/code/modules/gamemaster/actions/comms_blackout.dm b/code/modules/gamemaster/actions/comms_blackout.dm index 314290fc24a..7bc6a44d9ff 100644 --- a/code/modules/gamemaster/actions/comms_blackout.dm +++ b/code/modules/gamemaster/actions/comms_blackout.dm @@ -10,7 +10,7 @@ if(prob(80)) command_announcement.Announce("Ionospheric anomalies detected. Temporary telecommunication failure imminent. Please contact you-BZZT", new_sound = 'sound/misc/interference.ogg') // AIs will always know if there's a comm blackout, rogue AIs could then lie about comm blackouts in the future while they shutdown comms - for(var/mob/living/silicon/ai/A in player_list) + for(var/mob/living/silicon/ai/A in GLOB.player_list) to_chat(A, "
") to_chat(A, "Ionospheric anomalies detected. Temporary telecommunication failure imminent. Please contact you-BZZT") to_chat(A, "
") diff --git a/code/modules/gamemaster/actions/ion_storm.dm b/code/modules/gamemaster/actions/ion_storm.dm index bfba485bdd6..8d351d05d66 100644 --- a/code/modules/gamemaster/actions/ion_storm.dm +++ b/code/modules/gamemaster/actions/ion_storm.dm @@ -9,7 +9,7 @@ /datum/gm_action/ionstorm/set_up() length = rand(length, length * 10) // command_alert("The station has entered an ion storm. Monitor all electronic equipment for malfunctions", "Anomaly Alert") - for (var/mob/living/carbon/human/player in player_list) + for (var/mob/living/carbon/human/player in GLOB.player_list) if( !player.mind || player_is_antag(player.mind, only_offstation_roles = 1) || player.client.inactivity > MinutesToTicks(10)) continue players += player.real_name diff --git a/code/modules/gamemaster/actions/prison_break.dm b/code/modules/gamemaster/actions/prison_break.dm index 7881d20be58..2f0062a8bc4 100644 --- a/code/modules/gamemaster/actions/prison_break.dm +++ b/code/modules/gamemaster/actions/prison_break.dm @@ -69,7 +69,7 @@ var/rc_message = "An unknown malicious program has been detected in the [english_list(areaName)] lighting and airlock control systems at [stationtime2text()]. Systems will be fully compromised within approximately three minutes. Direct intervention is required immediately.
" for(var/obj/machinery/message_server/MS in GLOB.machines) MS.send_rc_message("Engineering", my_department, rc_message, "", "", 2) - for(var/mob/living/silicon/ai/A in player_list) + for(var/mob/living/silicon/ai/A in GLOB.player_list) to_chat(A, "Malicious program detected in the [english_list(areaName)] lighting and airlock control systems by [my_department].") else diff --git a/code/modules/gamemaster/actions/solar_storm.dm b/code/modules/gamemaster/actions/solar_storm.dm index f468c024a95..53cf5924153 100644 --- a/code/modules/gamemaster/actions/solar_storm.dm +++ b/code/modules/gamemaster/actions/solar_storm.dm @@ -39,7 +39,7 @@ /datum/gm_action/solar_storm/proc/radiate() // Note: Too complicated to be worth trying to use the radiation system for this. Its only in space anyway, so we make an exception in this case. - for(var/mob/living/L in player_list) + for(var/mob/living/L in GLOB.player_list) var/turf/T = get_turf(L) if(!T) continue diff --git a/code/modules/gamemaster/actions/surprise_carp_attack.dm b/code/modules/gamemaster/actions/surprise_carp_attack.dm index ce4e3f16859..d64139e3249 100644 --- a/code/modules/gamemaster/actions/surprise_carp_attack.dm +++ b/code/modules/gamemaster/actions/surprise_carp_attack.dm @@ -13,7 +13,7 @@ /datum/gm_action/surprise_carp_attack/set_up() var/list/potential_victims = list() victim = null - for(var/mob/living/L in player_list) + for(var/mob/living/L in GLOB.player_list) if(!(L.z in GLOB.using_map.station_levels)) continue // Not on the right z-level. if(L.stat) diff --git a/code/modules/gamemaster/actions/viral_infection.dm b/code/modules/gamemaster/actions/viral_infection.dm index 619ed23bb2b..49cf74c8ac0 100644 --- a/code/modules/gamemaster/actions/viral_infection.dm +++ b/code/modules/gamemaster/actions/viral_infection.dm @@ -43,7 +43,7 @@ ..() var/list/candidates = list() //list of candidate keys - for(var/mob/living/carbon/human/G in player_list) + for(var/mob/living/carbon/human/G in GLOB.player_list) if(G.mind && G.stat != DEAD && G.is_client_active(5) && !player_is_antag(G.mind)) var/turf/T = get_turf(G) if(T.z in GLOB.using_map.station_levels) diff --git a/code/modules/gamemaster/actions/viral_outbreak.dm b/code/modules/gamemaster/actions/viral_outbreak.dm index 352627bd24d..eae89602a36 100644 --- a/code/modules/gamemaster/actions/viral_outbreak.dm +++ b/code/modules/gamemaster/actions/viral_outbreak.dm @@ -8,7 +8,7 @@ /datum/gm_action/viral_outbreak/set_up() candidates.Cut() // Incase we somehow get run twice. severity = rand(2, 4) - for(var/mob/living/carbon/human/G in player_list) + for(var/mob/living/carbon/human/G in GLOB.player_list) if(G.client && G.stat != DEAD) candidates += G if(!candidates.len) return diff --git a/code/modules/gamemaster/controller.dm b/code/modules/gamemaster/controller.dm index e4f53a84745..c0ffa83d2e8 100644 --- a/code/modules/gamemaster/controller.dm +++ b/code/modules/gamemaster/controller.dm @@ -37,7 +37,7 @@ HTML += "
" HTML += "Activity of players;
" - for(var/mob/player in player_list) + for(var/mob/player in GLOB.player_list) HTML += " [player] ([player.key]) : [metric.assess_player_activity(player)]%
" diff --git a/code/modules/ghostroles/instantiator.dm b/code/modules/ghostroles/instantiator.dm index ff4da3a80cc..0f18a669f42 100644 --- a/code/modules/ghostroles/instantiator.dm +++ b/code/modules/ghostroles/instantiator.dm @@ -158,12 +158,16 @@ /datum/ghostrole_instantiator/human/player_static/Create(client/C, atom/location, list/params) var/mob/living/carbon/human/H = ..() + var/list/errors = list() + if(!C.prefs.spawn_checks(PREF_COPY_TO_FOR_GHOSTROLE, errors)) + to_chat(C, SPAN_WARNING("An error has occured while attempting to spawn you in:
[errors.Join("
")]")) + return LoadSavefile(C, H) return H /datum/ghostrole_instantiator/human/player_static/proc/LoadSavefile(client/C, mob/living/carbon/human/H) C.prefs.copy_to(H) - job_master.EquipRank(H, USELESS_JOB) + SSjob.EquipRank(H, USELESS_JOB) // if(equip_loadout) // SSjob.EquipLoadout(H, FALSE, null, C.prefs, C.ckey) // if(equip_traits && CONFIG_GET(flag/roundstart_traits)) diff --git a/code/modules/ghosttrap/trap.dm b/code/modules/ghosttrap/trap.dm index 0f2de52f983..be9b4ecd39b 100644 --- a/code/modules/ghosttrap/trap.dm +++ b/code/modules/ghosttrap/trap.dm @@ -39,7 +39,7 @@ var/list/ghost_traps /datum/ghosttrap/proc/request_player(var/mob/target, var/request_string) if(!target) return - for(var/mob/observer/dead/O in player_list) + for(var/mob/observer/dead/O in GLOB.player_list) if(!O.MayRespawn()) continue if(islist(ban_checks)) diff --git a/code/modules/integrated_electronics/core/assemblies.dm b/code/modules/integrated_electronics/core/assemblies.dm index 020c3f44adf..30be49f9375 100644 --- a/code/modules/integrated_electronics/core/assemblies.dm +++ b/code/modules/integrated_electronics/core/assemblies.dm @@ -138,7 +138,7 @@ var/obj/item/integrated_circuit/IC = I /* Uncomment for debugging purposes. */ if(!IC) - to_world(SPAN_DEBUGERROR("Bad assembly_components entry in [src]. Has remove() been called incorrectly?")) + TO_WORLD(SPAN_DEBUGERROR("Bad assembly_components entry in [src]. Has remove() been called incorrectly?")) var/x = assembly_components.Find(null) assembly_components.Cut(x,++x) return diff --git a/code/modules/integrated_electronics/subtypes/input.dm b/code/modules/integrated_electronics/subtypes/input.dm index 0ad632679ba..c0fdd123860 100644 --- a/code/modules/integrated_electronics/subtypes/input.dm +++ b/code/modules/integrated_electronics/subtypes/input.dm @@ -1014,14 +1014,14 @@ /obj/item/integrated_circuit/input/microphone/sign/Initialize(mapload) . = ..() for(var/lang in readable_langs) - var/datum/language/newlang = GLOB.all_languages[lang] + var/datum/language/newlang = SScharacters.resolve_language_name(lang) my_langs |= newlang /obj/item/integrated_circuit/input/microphone/sign/hear_talk(mob/living/M, msg, var/verb="says", datum/language/speaking=null) var/signlang = FALSE if(M && msg) if(speaking) - if(!((speaking.flags & NONVERBAL) || (speaking.flags & SIGNLANG))) + if(!((speaking.language_flags & NONVERBAL) || (speaking.language_flags & SIGNLANG))) signlang = FALSE msg = speaking.scramble(msg, my_langs) else diff --git a/code/modules/jobs/departments/cargo.dm b/code/modules/jobs/departments/cargo.dm index ef9bb2706c0..32b86b2b75a 100644 --- a/code/modules/jobs/departments/cargo.dm +++ b/code/modules/jobs/departments/cargo.dm @@ -2,4 +2,4 @@ name = DEPARTMENT_CARGO short_name = "Car" color = "#BB9040" - sorting_order = 2 + sorting_order = 7 diff --git a/code/modules/jobs/departments/civillian.dm b/code/modules/jobs/departments/civillian.dm index 7d2408de492..f9c888be864 100644 --- a/code/modules/jobs/departments/civillian.dm +++ b/code/modules/jobs/departments/civillian.dm @@ -2,4 +2,4 @@ name = DEPARTMENT_CIVILIAN short_name = "Civ" color = "#A32800" - sorting_order = 1 + sorting_order = 10 diff --git a/code/modules/jobs/departments/command.dm b/code/modules/jobs/departments/command.dm index 6ce461e1693..bb2f8000329 100644 --- a/code/modules/jobs/departments/command.dm +++ b/code/modules/jobs/departments/command.dm @@ -2,4 +2,4 @@ name = DEPARTMENT_COMMAND short_name = "Heads" color = "#3333FF" - sorting_order = 10 + sorting_order = 1 diff --git a/code/modules/jobs/departments/engineering.dm b/code/modules/jobs/departments/engineering.dm index 9932aa8d048..01e1f3fa554 100644 --- a/code/modules/jobs/departments/engineering.dm +++ b/code/modules/jobs/departments/engineering.dm @@ -2,4 +2,4 @@ name = DEPARTMENT_ENGINEERING short_name = "Eng" color = "#B27300" - sorting_order = 5 + sorting_order = 3 diff --git a/code/modules/jobs/departments/misc.dm b/code/modules/jobs/departments/misc.dm index 4893a53fea9..964973e3d93 100644 --- a/code/modules/jobs/departments/misc.dm +++ b/code/modules/jobs/departments/misc.dm @@ -4,5 +4,5 @@ name = "Miscellaneous" short_name = "Misc" color = "#666666" - sorting_order = 0 + sorting_order = 18 assignable = FALSE diff --git a/code/modules/jobs/departments/offduty.dm b/code/modules/jobs/departments/offduty.dm index 526c173bce5..2e00f37ce74 100644 --- a/code/modules/jobs/departments/offduty.dm +++ b/code/modules/jobs/departments/offduty.dm @@ -2,5 +2,5 @@ name = "Off-Duty" short_name = "Offduty" color = "#666666" - sorting_order = -5 + sorting_order = 15 assignable = FALSE diff --git a/code/modules/jobs/departments/planetside.dm b/code/modules/jobs/departments/planetside.dm index 3575590213b..8186178b8d4 100644 --- a/code/modules/jobs/departments/planetside.dm +++ b/code/modules/jobs/departments/planetside.dm @@ -1,5 +1,5 @@ /datum/department/planetside name = DEPARTMENT_PLANET color = "#bab421" - sorting_order = 2 // Same as cargo in importance. + sorting_order = 6 // Same as cargo in importance. diff --git a/code/modules/jobs/departments/research.dm b/code/modules/jobs/departments/research.dm index 07cbf6808cc..d692df20b56 100644 --- a/code/modules/jobs/departments/research.dm +++ b/code/modules/jobs/departments/research.dm @@ -2,4 +2,4 @@ name = DEPARTMENT_RESEARCH short_name = "Sci" color = "#A65BA6" - sorting_order = 3 + sorting_order = 5 diff --git a/code/modules/jobs/departments/security.dm b/code/modules/jobs/departments/security.dm index 3b380039803..3a8ace658d8 100644 --- a/code/modules/jobs/departments/security.dm +++ b/code/modules/jobs/departments/security.dm @@ -2,4 +2,4 @@ name = DEPARTMENT_SECURITY short_name = "Sec" color = "#8E0000" - sorting_order = 6 + sorting_order = 2 diff --git a/code/modules/jobs/departments/silicon.dm b/code/modules/jobs/departments/silicon.dm index 2b73490d888..1bcbb17484f 100644 --- a/code/modules/jobs/departments/silicon.dm +++ b/code/modules/jobs/departments/silicon.dm @@ -2,5 +2,5 @@ name = DEPARTMENT_SYNTHETIC short_name = "Bot" color = "#222222" - sorting_order = -1 + sorting_order = 20 assignable = FALSE diff --git a/code/modules/jobs/job.dm b/code/modules/jobs/job.dm index c433403c9da..05323248c5f 100644 --- a/code/modules/jobs/job.dm +++ b/code/modules/jobs/job.dm @@ -1,4 +1,7 @@ /datum/job + //! Intrinsics + /// ID of the job, used for save/load + var/id /// The name of the job , used for preferences, bans and more. Make sure you know what you're doing before changing this. var/title = "NOPE" /// Description of the job @@ -45,9 +48,6 @@ // Requires a ckey to be whitelisted in jobwhitelist.txt var/whitelist_only = 0 - // Does not display this job on the occupation setup screen - var/latejoin_only = 0 - // Every hour playing this role gains this much time off. (Can be negative for off duty jobs!) var/timeoff_factor = 3 @@ -61,6 +61,133 @@ . = ..() GLOB.department_accounts = GLOB.department_accounts || departments_managed +/** + * checks slots remaining + * + * @return 0 to number of slots remaining + */ +/datum/job/proc/slots_remaining(latejoin) + if(!latejoin) + if(spawn_positions == -1) + return INFINITY + return max(spawn_positions, 0) + if(total_positions == -1) + return INFINITY + return max(total_positions - current_positions, 0) + +/** + * checks if we're available for a given client + * + * @params + * - C - client + * - check_char - check the current loaded character for violations + * + * todo: check ckey proc too? + */ +/datum/job/proc/check_client_availability(client/C, check_char, latejoin) + . = NONE + if(whitelist_only && !config.check_job_whitelist(ckey(title), C.ckey)) + . |= ROLE_UNAVAILABLE_WHITELIST + if(!slots_remaining()) + . |= ROLE_UNAVAILABLE_SLOTS_FULL + if(!player_has_enough_pto(C)) + . |= ROLE_UNAVAILABLE_PTO + if(jobban_isbanned(C.mob, title)) + . |= ROLE_UNAVAILABLE_BANNED + if(!player_old_enough(C)) + . |= ROLE_UNAVAILABLE_CONNECT_TIME + if(check_char) + var/datum/preferences/P = C.prefs + if(P.age < minimum_character_age) + . |= ROLE_UNAVAILABLE_CHAR_AGE + if(!P.lore_faction_job_check(src)) + . |= ROLE_UNAVAILABLE_CHAR_FACTION + if(!P.character_species_job_check(src)) + . |= ROLE_UNAVAILABLE_CHAR_SPECIES + // todo: JEXP/ROLE-EXP hours system + +/** + * checks if we're available for a given client, + * but short circuits with the most common checks first + * for efficiency + * + * @params + * - C - client + * - check_char - check the current loaded character for violations + * + * todo: check ckey proc too? + */ +/datum/job/proc/check_client_availability_one(client/C, check_char, latejoin) + . = NONE + if(whitelist_only && !config.check_job_whitelist(ckey(title), C.ckey)) + return ROLE_UNAVAILABLE_WHITELIST + else if(latejoin && !slots_remaining(TRUE)) + return ROLE_UNAVAILABLE_SLOTS_FULL + else if(!player_has_enough_pto(C)) + return ROLE_UNAVAILABLE_PTO + else if(jobban_isbanned(C.mob, title)) + return ROLE_UNAVAILABLE_BANNED + else if(!player_old_enough(C)) + return ROLE_UNAVAILABLE_CONNECT_TIME + if(check_char) + var/datum/preferences/P = C.prefs + if(P.age < minimum_character_age) + return ROLE_UNAVAILABLE_CHAR_AGE + if(!P.lore_faction_job_check(src)) + return ROLE_UNAVAILABLE_CHAR_FACTION + if(!P.character_species_job_check(src)) + return ROLE_UNAVAILABLE_CHAR_SPECIES + + // todo: JEXP/ROLE-EXP hours system + +/** + * get an user-friendly reason of why they can't spawn as us + */ +/datum/job/proc/get_availability_reason(client/C, reason) + if(reason & ROLE_UNAVAILABLE_BANNED) + return "BANNED" + if(reason & ROLE_UNAVAILABLE_SLOTS_FULL) + return "Slots are currently full; Please refresh the join menu." + if(reason & ROLE_UNAVAILABLE_PTO) + return "You do not have enough stored PTO." + if(reason & ROLE_UNAVAILABLE_ROLE_TIME) + return "You do not have enough hours in the relevant department(s)." + if(reason & ROLE_UNAVAILABLE_WHITELIST) + return "This role is whitelisted." + if(reason & ROLE_UNAVAILABLE_CONNECT_TIME) + return "Your account is too new; please wait a few days or contact administration if this is in error." + if(reason & ROLE_UNAVAILABLE_CHAR_AGE) + return "Your character is too young; they must be at least [minimum_character_age] years old." + if(reason & ROLE_UNAVAILABLE_CHAR_FACTION) + return "Your character is of the wrong faction." + if(reason & ROLE_UNAVAILABLE_CHAR_SPECIES) + return "This species is not allowed in this job." + return "This role is available; seeing this message is a bug. How did you get here?" + +/** + * get a short abbreviation for why they can't spawn as us; used for preferences + */ +/datum/job/proc/get_availability_error(client/C, reason) + if(reason & ROLE_UNAVAILABLE_BANNED) + return "BANNED" + if(reason & ROLE_UNAVAILABLE_SLOTS_FULL) + return "SLOTS FULL" + if(reason & ROLE_UNAVAILABLE_PTO) + return "INSUFFICIENT PTO" + if(reason & ROLE_UNAVAILABLE_ROLE_TIME) + return "INSUFFICIENT HOURS" + if(reason & ROLE_UNAVAILABLE_WHITELIST) + return "WHITELISTED" + if(reason & ROLE_UNAVAILABLE_CONNECT_TIME) + return "IN [available_in_days(C)] DAYS" + if(reason & ROLE_UNAVAILABLE_CHAR_AGE) + return "MIN AGE: [minimum_character_age]" + if(reason & ROLE_UNAVAILABLE_CHAR_FACTION) + return "FACTION" + if(reason & ROLE_UNAVAILABLE_CHAR_SPECIES) + return "SPECIES" + return "UNKNOWN (BUG)" + /datum/job/proc/equip(var/mob/living/carbon/human/H, var/alt_title) var/datum/outfit/outfit = get_outfit(H, alt_title) if(!outfit) @@ -164,7 +291,7 @@ return message /datum/job/proc/get_job_icon() - if(!job_master.job_icons[title]) + if(!SSjob.job_icons[title]) var/mob/living/carbon/human/dummy/mannequin/mannequin = get_mannequin("#job_icon") dress_mannequin(mannequin) mannequin.dir = SOUTH @@ -172,9 +299,9 @@ var/icon/preview_icon = get_flat_icon(mannequin) preview_icon.Scale(preview_icon.Width() * 2, preview_icon.Height() * 2) // Scaling here to prevent blurring in the browser. - job_master.job_icons[title] = preview_icon + SSjob.job_icons[title] = preview_icon - return job_master.job_icons[title] + return SSjob.job_icons[title] /datum/job/proc/dress_mannequin(mob/living/carbon/human/dummy/mannequin/mannequin) mannequin.delete_inventory(TRUE) diff --git a/code/modules/jobs/job_types/station.dm b/code/modules/jobs/job_types/station.dm index 0e6b3804caf..16261213156 100644 --- a/code/modules/jobs/job_types/station.dm +++ b/code/modules/jobs/job_types/station.dm @@ -1,2 +1,3 @@ /datum/job/station faction = JOB_FACTION_STATION + abstract_type = /datum/job/station diff --git a/code/modules/jobs/job_types/station/admin/centcom_officer.dm b/code/modules/jobs/job_types/station/admin/centcom_officer.dm index 994f4d9cf94..b9e3a91a420 100644 --- a/code/modules/jobs/job_types/station/admin/centcom_officer.dm +++ b/code/modules/jobs/job_types/station/admin/centcom_officer.dm @@ -1,4 +1,5 @@ /datum/job/station/centcom_officer //For Business + id = JOB_ID_CENTCOM_OFFICER title = "CentCom Officer" departments = list("Central Command") department_accounts = list(DEPARTMENT_COMMAND, DEPARTMENT_ENGINEERING, DEPARTMENT_MEDICAL, DEPARTMENT_RESEARCH, DEPARTMENT_SECURITY, DEPARTMENT_CARGO, DEPARTMENT_PLANET, DEPARTMENT_CIVILIAN) @@ -12,7 +13,7 @@ minimal_player_age = 14 economic_modifier = 20 whitelist_only = 1 - latejoin_only = 1 + join_types = JOB_LATEJOIN outfit_type = /datum/outfit/job/station/centcom_officer desc = "A Central Command Officer is there on official business. Most of time. Whatever it is, they're a VIP." diff --git a/code/modules/jobs/job_types/station/admin/emergency_responder.dm b/code/modules/jobs/job_types/station/admin/emergency_responder.dm index 07541d07250..40144a209b9 100644 --- a/code/modules/jobs/job_types/station/admin/emergency_responder.dm +++ b/code/modules/jobs/job_types/station/admin/emergency_responder.dm @@ -1,4 +1,5 @@ /datum/job/station/emergency_responder //For staff managing/leading ERTs + id = JOB_ID_EMERGENCY_RESPONDER title = "Emergency Responder" departments = list("Central Command") department_accounts = list(DEPARTMENT_COMMAND, DEPARTMENT_ENGINEERING, DEPARTMENT_MEDICAL, DEPARTMENT_RESEARCH, DEPARTMENT_SECURITY, DEPARTMENT_CARGO, DEPARTMENT_PLANET, DEPARTMENT_CIVILIAN) @@ -11,7 +12,7 @@ minimal_player_age = 14 economic_modifier = 20 whitelist_only = 1 - latejoin_only = 1 + join_types = JOB_LATEJOIN outfit_type = /datum/outfit/job/station/emergency_responder desc = "Emergency Responders are usually called in to deal with on-station emergencies that the crew require assistance to deal with." diff --git a/code/modules/jobs/job_types/station/civillian/assistant.dm b/code/modules/jobs/job_types/station/civillian/assistant.dm index 947630a77d4..def9e6f3d50 100644 --- a/code/modules/jobs/job_types/station/civillian/assistant.dm +++ b/code/modules/jobs/job_types/station/civillian/assistant.dm @@ -1,4 +1,5 @@ /datum/job/station/assistant + id = JOB_ID_ASSISTANT title = USELESS_JOB flag = ASSISTANT departments = list(DEPARTMENT_CIVILIAN) diff --git a/code/modules/jobs/job_types/station/civillian/chaplain.dm b/code/modules/jobs/job_types/station/civillian/chaplain.dm index 2f3251dc92d..e26e4439d88 100644 --- a/code/modules/jobs/job_types/station/civillian/chaplain.dm +++ b/code/modules/jobs/job_types/station/civillian/chaplain.dm @@ -1,4 +1,5 @@ /datum/job/station/chaplain + id = JOB_ID_CHAPLAIN title = "Chaplain" flag = CHAPLAIN departments = list(DEPARTMENT_CIVILIAN) diff --git a/code/modules/jobs/job_types/station/civillian/clown.dm b/code/modules/jobs/job_types/station/civillian/clown.dm index d6b88608da7..6f883a5b7d9 100644 --- a/code/modules/jobs/job_types/station/civillian/clown.dm +++ b/code/modules/jobs/job_types/station/civillian/clown.dm @@ -1,4 +1,5 @@ /datum/job/station/clown + id = JOB_ID_CLOWN title = "Clown" flag = CLOWN departments = list(DEPARTMENT_CIVILIAN) @@ -12,7 +13,6 @@ minimal_access = list(access_entertainment) desc = "A Clown is there to entertain the crew and keep high morale using various harmless pranks and ridiculous jokes!" whitelist_only = 1 - latejoin_only = 0 outfit_type = /datum/outfit/job/station/clown pto_type = PTO_CIVILIAN alt_titles = list("Jester" = /datum/alt_title/clown/jester, "Fool" = /datum/alt_title/clown/fool) diff --git a/code/modules/jobs/job_types/station/civillian/entertainer.dm b/code/modules/jobs/job_types/station/civillian/entertainer.dm index 55270bbfa14..0ac739ec305 100644 --- a/code/modules/jobs/job_types/station/civillian/entertainer.dm +++ b/code/modules/jobs/job_types/station/civillian/entertainer.dm @@ -1,4 +1,5 @@ /datum/job/station/entertainer + id = JOB_ID_ENTERTAINER title = "Entertainer" flag = ENTERTAINER departments = list(DEPARTMENT_CIVILIAN) diff --git a/code/modules/jobs/job_types/station/civillian/internals_affairs_agent.dm b/code/modules/jobs/job_types/station/civillian/internals_affairs_agent.dm index 80407ccad86..625bf80d729 100644 --- a/code/modules/jobs/job_types/station/civillian/internals_affairs_agent.dm +++ b/code/modules/jobs/job_types/station/civillian/internals_affairs_agent.dm @@ -1,4 +1,5 @@ /datum/job/station/lawyer + id = JOB_ID_LAWYER title = "Internal Affairs Agent" flag = LAWYER departments = list(DEPARTMENT_CIVILIAN) diff --git a/code/modules/jobs/job_types/station/civillian/librarian.dm b/code/modules/jobs/job_types/station/civillian/librarian.dm index 308db521417..da5fa141704 100644 --- a/code/modules/jobs/job_types/station/civillian/librarian.dm +++ b/code/modules/jobs/job_types/station/civillian/librarian.dm @@ -1,4 +1,5 @@ /datum/job/station/librarian + id = JOB_ID_LIBRARIAN title = "Librarian" flag = LIBRARIAN departments = list(DEPARTMENT_CIVILIAN) diff --git a/code/modules/jobs/job_types/station/civillian/mime.dm b/code/modules/jobs/job_types/station/civillian/mime.dm index 84b5546ef36..1fb341dd81d 100644 --- a/code/modules/jobs/job_types/station/civillian/mime.dm +++ b/code/modules/jobs/job_types/station/civillian/mime.dm @@ -1,4 +1,5 @@ /datum/job/station/mime + id = JOB_ID_MIME title = "Mime" flag = MIME departments = list(DEPARTMENT_CIVILIAN) @@ -13,7 +14,6 @@ desc = "A Mime is there to entertain the crew and keep high morale using unbelievable performances and acting skills!" alt_titles = list("Poseur" = /datum/alt_title/mime/poseur) whitelist_only = 1 - latejoin_only = 0 outfit_type = /datum/outfit/job/station/mime pto_type = PTO_CIVILIAN diff --git a/code/modules/jobs/job_types/station/civillian/pilot.dm b/code/modules/jobs/job_types/station/civillian/pilot.dm index ead7480d8dd..84cc053ea58 100644 --- a/code/modules/jobs/job_types/station/civillian/pilot.dm +++ b/code/modules/jobs/job_types/station/civillian/pilot.dm @@ -1,4 +1,5 @@ /datum/job/station/pilot + id = JOB_ID_PILOT title = "Pilot" flag = PILOT departments = list(DEPARTMENT_CIVILIAN) diff --git a/code/modules/jobs/job_types/station/command/captain.dm b/code/modules/jobs/job_types/station/command/captain.dm index 76d77c99277..2fe4a884f14 100644 --- a/code/modules/jobs/job_types/station/command/captain.dm +++ b/code/modules/jobs/job_types/station/command/captain.dm @@ -1,6 +1,7 @@ var/datum/legacy_announcement/minor/captain_announcement = new(do_newscast = 1) /datum/job/station/captain + id = JOB_ID_CAPTAIN title = "Facility Director" flag = CAPTAIN disallow_jobhop = TRUE diff --git a/code/modules/jobs/job_types/station/command/command_secretary.dm b/code/modules/jobs/job_types/station/command/command_secretary.dm index 606f44e8ff8..f0327b86b89 100644 --- a/code/modules/jobs/job_types/station/command/command_secretary.dm +++ b/code/modules/jobs/job_types/station/command/command_secretary.dm @@ -1,4 +1,5 @@ /datum/job/station/command_secretary + id = JOB_ID_COMMAND_SECRETARY title = "Command Secretary" flag = BRIDGE departments = list(DEPARTMENT_COMMAND) diff --git a/code/modules/jobs/job_types/station/command/head_of_personnel.dm b/code/modules/jobs/job_types/station/command/head_of_personnel.dm index f18188cf45f..69ffc3dfcb9 100644 --- a/code/modules/jobs/job_types/station/command/head_of_personnel.dm +++ b/code/modules/jobs/job_types/station/command/head_of_personnel.dm @@ -1,4 +1,5 @@ /datum/job/station/head_of_personnel + id = JOB_ID_HEAD_OF_PERSONNEL title = "Head of Personnel" flag = HOP departments = list(DEPARTMENT_COMMAND, DEPARTMENT_CIVILIAN, DEPARTMENT_CARGO) diff --git a/code/modules/jobs/job_types/station/engineering/atmospherics_technician.dm b/code/modules/jobs/job_types/station/engineering/atmospherics_technician.dm index e811d052b61..885446d678b 100644 --- a/code/modules/jobs/job_types/station/engineering/atmospherics_technician.dm +++ b/code/modules/jobs/job_types/station/engineering/atmospherics_technician.dm @@ -1,4 +1,5 @@ /datum/job/station/atmos + id = JOB_ID_ATMOSPHERIC_TECHNICIAN title = "Atmospheric Technician" flag = ATMOSTECH departments = list(DEPARTMENT_ENGINEERING) diff --git a/code/modules/jobs/job_types/station/engineering/chief_engineer.dm b/code/modules/jobs/job_types/station/engineering/chief_engineer.dm index b0b7732318b..2bd9109b6cc 100644 --- a/code/modules/jobs/job_types/station/engineering/chief_engineer.dm +++ b/code/modules/jobs/job_types/station/engineering/chief_engineer.dm @@ -1,4 +1,5 @@ /datum/job/station/chief_engineer + id = JOB_ID_CHIEF_ENGINEER title = "Chief Engineer" flag = CHIEF departments_managed = list(DEPARTMENT_ENGINEERING) diff --git a/code/modules/jobs/job_types/station/engineering/senior_engineer.dm b/code/modules/jobs/job_types/station/engineering/senior_engineer.dm index abe6d1704ea..08e164644e6 100644 --- a/code/modules/jobs/job_types/station/engineering/senior_engineer.dm +++ b/code/modules/jobs/job_types/station/engineering/senior_engineer.dm @@ -1,5 +1,6 @@ /datum/job/station/senior_engineer title = "Senior Engineer" + id = JOB_ID_SENIOR_ENGINEER flag = SENIOR_ENGINEER departments = list(DEPARTMENT_ENGINEERING) department_flag = ENGSEC diff --git a/code/modules/jobs/job_types/station/engineering/station_engineer.dm b/code/modules/jobs/job_types/station/engineering/station_engineer.dm index a7f3b585490..033ed01123c 100644 --- a/code/modules/jobs/job_types/station/engineering/station_engineer.dm +++ b/code/modules/jobs/job_types/station/engineering/station_engineer.dm @@ -1,4 +1,5 @@ /datum/job/station/engineer + id = JOB_ID_STATION_ENGINEER title = "Station Engineer" flag = ENGINEER departments = list(DEPARTMENT_ENGINEERING) diff --git a/code/modules/jobs/job_types/station/exploration/explorer.dm b/code/modules/jobs/job_types/station/exploration/explorer.dm index 150a08564f3..a9928a4fb2e 100644 --- a/code/modules/jobs/job_types/station/exploration/explorer.dm +++ b/code/modules/jobs/job_types/station/exploration/explorer.dm @@ -1,4 +1,5 @@ /datum/job/station/explorer + id = JOB_ID_EXPLORER title = "Explorer" flag = EXPLORER departments = list(DEPARTMENT_PLANET) diff --git a/code/modules/jobs/job_types/station/exploration/field_medic.dm b/code/modules/jobs/job_types/station/exploration/field_medic.dm index d67f7489cec..e0efb027b09 100644 --- a/code/modules/jobs/job_types/station/exploration/field_medic.dm +++ b/code/modules/jobs/job_types/station/exploration/field_medic.dm @@ -1,4 +1,5 @@ /datum/job/station/field_medic + id = JOB_ID_FIELD_MEDIC title = "Field Medic" flag = SAR departments = list(DEPARTMENT_PLANET, DEPARTMENT_MEDICAL) diff --git a/code/modules/jobs/job_types/station/exploration/pathfinder.dm b/code/modules/jobs/job_types/station/exploration/pathfinder.dm index 550955d59e8..7c39fcbeabd 100644 --- a/code/modules/jobs/job_types/station/exploration/pathfinder.dm +++ b/code/modules/jobs/job_types/station/exploration/pathfinder.dm @@ -1,4 +1,5 @@ /datum/job/station/pathfinder + id = JOB_ID_PATHFINDER title = "Pathfinder" flag = PATHFINDER departments = list(DEPARTMENT_PLANET) diff --git a/code/modules/jobs/job_types/station/medical/chemist.dm b/code/modules/jobs/job_types/station/medical/chemist.dm index 65ccf830f4a..9e71e648bb3 100644 --- a/code/modules/jobs/job_types/station/medical/chemist.dm +++ b/code/modules/jobs/job_types/station/medical/chemist.dm @@ -1,4 +1,5 @@ /datum/job/station/chemist + id = JOB_ID_CHEMIST title = "Chemist" flag = CHEMIST departments = list(DEPARTMENT_MEDICAL) diff --git a/code/modules/jobs/job_types/station/medical/chief_medical_officer.dm b/code/modules/jobs/job_types/station/medical/chief_medical_officer.dm index 913ff3a4cd9..43c781da6c1 100644 --- a/code/modules/jobs/job_types/station/medical/chief_medical_officer.dm +++ b/code/modules/jobs/job_types/station/medical/chief_medical_officer.dm @@ -1,4 +1,5 @@ /datum/job/station/chief_medical_officer + id = JOB_ID_CHIEF_MEDICAL_OFFICER title = "Chief Medical Officer" flag = CMO departments_managed = list(DEPARTMENT_MEDICAL) diff --git a/code/modules/jobs/job_types/station/medical/geneticist.dm b/code/modules/jobs/job_types/station/medical/geneticist.dm index b3ed4ccae61..fea9e268140 100644 --- a/code/modules/jobs/job_types/station/medical/geneticist.dm +++ b/code/modules/jobs/job_types/station/medical/geneticist.dm @@ -4,6 +4,7 @@ // Geneticist ////////////////////////////////// /datum/job/station/geneticist + id = "geneticist" title = "Geneticist" flag = GENETICIST departments = list(DEPARTMENT_MEDICAL, DEPARTMENT_RESEARCH) diff --git a/code/modules/jobs/job_types/station/medical/head_nurse.dm b/code/modules/jobs/job_types/station/medical/head_nurse.dm index 2d474af2579..2fad30fc90f 100644 --- a/code/modules/jobs/job_types/station/medical/head_nurse.dm +++ b/code/modules/jobs/job_types/station/medical/head_nurse.dm @@ -1,5 +1,6 @@ /datum/job/station/head_nurse title = "Head Nurse" + id = JOB_ID_HEAD_NURSE flag = HEAD_NURSE departments = list(DEPARTMENT_MEDICAL) department_flag = MEDSCI diff --git a/code/modules/jobs/job_types/station/medical/medical_doctor.dm b/code/modules/jobs/job_types/station/medical/medical_doctor.dm index 884025cfba1..e9b2cf5c048 100644 --- a/code/modules/jobs/job_types/station/medical/medical_doctor.dm +++ b/code/modules/jobs/job_types/station/medical/medical_doctor.dm @@ -1,4 +1,5 @@ /datum/job/station/doctor + id = JOB_ID_MEDICAL_DOCTOR title = "Medical Doctor" flag = DOCTOR departments = list(DEPARTMENT_MEDICAL) diff --git a/code/modules/jobs/job_types/station/medical/paramedic.dm b/code/modules/jobs/job_types/station/medical/paramedic.dm index 5126a52e88f..5b74227c3a6 100644 --- a/code/modules/jobs/job_types/station/medical/paramedic.dm +++ b/code/modules/jobs/job_types/station/medical/paramedic.dm @@ -1,4 +1,5 @@ /datum/job/station/paramedic + id = JOB_ID_PARAMEDIC title = "Paramedic" flag = PARAMEDIC departments = list(DEPARTMENT_MEDICAL) diff --git a/code/modules/jobs/job_types/station/medical/psychiatrist.dm b/code/modules/jobs/job_types/station/medical/psychiatrist.dm index 68dd00be729..23fe56ea6ad 100644 --- a/code/modules/jobs/job_types/station/medical/psychiatrist.dm +++ b/code/modules/jobs/job_types/station/medical/psychiatrist.dm @@ -1,4 +1,5 @@ /datum/job/station/psychiatrist + id = JOB_ID_PSYCHIATRIST title = "Psychiatrist" flag = PSYCHIATRIST departments = list(DEPARTMENT_MEDICAL) diff --git a/code/modules/jobs/job_types/station/offduty/_offduty.dm b/code/modules/jobs/job_types/station/offduty/_offduty.dm index c42e78aa6fd..cf49ea9b540 100644 --- a/code/modules/jobs/job_types/station/offduty/_offduty.dm +++ b/code/modules/jobs/job_types/station/offduty/_offduty.dm @@ -1,5 +1,6 @@ /datum/job/station/off_duty - latejoin_only = TRUE + abstract_type = /datum/job/station/off_duty + join_types = JOB_LATEJOIN timeoff_factor = -1 total_positions = -1 departments = list(DEPARTMENT_OFFDUTY) diff --git a/code/modules/jobs/job_types/station/offduty/civillian.dm b/code/modules/jobs/job_types/station/offduty/civillian.dm index ec11e1e5a9c..b71afa75903 100644 --- a/code/modules/jobs/job_types/station/offduty/civillian.dm +++ b/code/modules/jobs/job_types/station/offduty/civillian.dm @@ -1,4 +1,5 @@ /datum/job/station/off_duty/civilian + id = JOB_ID_OFFDUTY_CIVILLIAN title = "Off-duty Worker" selection_color = "#9b633e" access = list(access_maint_tunnels) diff --git a/code/modules/jobs/job_types/station/offduty/command.dm b/code/modules/jobs/job_types/station/offduty/command.dm index 0a0e059b9bc..9298d28dd06 100644 --- a/code/modules/jobs/job_types/station/offduty/command.dm +++ b/code/modules/jobs/job_types/station/offduty/command.dm @@ -1,9 +1,9 @@ /datum/job/station/off_duty/command + id = JOB_ID_OFFDUTY_COMMAND title = "Off-duty Command" - latejoin_only = TRUE timeoff_factor = -1 total_positions = -1 - departments = list(DEPARTMENT_COMMAND) + departments = list(DEPARTMENT_OFFDUTY, DEPARTMENT_COMMAND) selection_color = "#9b633e" access = list(access_maint_tunnels, access_external_airlocks) minimal_access = list(access_maint_tunnels, access_external_airlocks) diff --git a/code/modules/jobs/job_types/station/offduty/engineering.dm b/code/modules/jobs/job_types/station/offduty/engineering.dm index 03a68567471..3e11ce771d3 100644 --- a/code/modules/jobs/job_types/station/offduty/engineering.dm +++ b/code/modules/jobs/job_types/station/offduty/engineering.dm @@ -1,4 +1,5 @@ /datum/job/station/off_duty/engineering + id = JOB_ID_OFFDUTY_ENGINEER title = "Off-duty Engineer" selection_color = "#5B4D20" access = list(access_maint_tunnels, access_external_airlocks, access_construction) diff --git a/code/modules/jobs/job_types/station/offduty/exploration.dm b/code/modules/jobs/job_types/station/offduty/exploration.dm index 45ac86af73d..e0d2bbb57c2 100644 --- a/code/modules/jobs/job_types/station/offduty/exploration.dm +++ b/code/modules/jobs/job_types/station/offduty/exploration.dm @@ -1,4 +1,5 @@ /datum/job/station/off_duty/exploration + id = JOB_ID_OFFDUTY_EXPLORER title = "Off-duty Explorer" selection_color = "#999440" access = list(access_maint_tunnels, access_external_airlocks) diff --git a/code/modules/jobs/job_types/station/offduty/medical.dm b/code/modules/jobs/job_types/station/offduty/medical.dm index 9b5276f783a..189b609e8c4 100644 --- a/code/modules/jobs/job_types/station/offduty/medical.dm +++ b/code/modules/jobs/job_types/station/offduty/medical.dm @@ -1,4 +1,5 @@ /datum/job/station/off_duty/medical + id = JOB_ID_OFFDUTY_MEDBAY title = "Off-duty Medic" selection_color = "#013D3B" access = list(access_maint_tunnels, access_external_airlocks) diff --git a/code/modules/jobs/job_types/station/offduty/science.dm b/code/modules/jobs/job_types/station/offduty/science.dm index 623f450790d..444c4c17328 100644 --- a/code/modules/jobs/job_types/station/offduty/science.dm +++ b/code/modules/jobs/job_types/station/offduty/science.dm @@ -1,4 +1,5 @@ /datum/job/station/off_duty/science + id = JOB_ID_OFFDUTY_SCIENCE title = "Off-duty Scientist" selection_color = "#633D63" access = list(access_maint_tunnels) diff --git a/code/modules/jobs/job_types/station/offduty/security.dm b/code/modules/jobs/job_types/station/offduty/security.dm index 510f9f5a33e..d9c7d425c91 100644 --- a/code/modules/jobs/job_types/station/offduty/security.dm +++ b/code/modules/jobs/job_types/station/offduty/security.dm @@ -1,4 +1,5 @@ /datum/job/station/off_duty/security + id = JOB_ID_OFFDUTY_SECURITY title = "Off-duty Officer" selection_color = "#601C1C" access = list(access_maint_tunnels) diff --git a/code/modules/jobs/job_types/station/offduty/supply.dm b/code/modules/jobs/job_types/station/offduty/supply.dm index ef33f8357d9..94d18d70edb 100644 --- a/code/modules/jobs/job_types/station/offduty/supply.dm +++ b/code/modules/jobs/job_types/station/offduty/supply.dm @@ -1,4 +1,5 @@ /datum/job/station/off_duty/cargo + id = JOB_ID_OFFDUTY_CARGO title = "Off-duty Cargo" selection_color = "#9b633e" access = list(access_maint_tunnels) diff --git a/code/modules/jobs/job_types/station/science/research_director.dm b/code/modules/jobs/job_types/station/science/research_director.dm index 4394df0ffea..788dce83ed4 100644 --- a/code/modules/jobs/job_types/station/science/research_director.dm +++ b/code/modules/jobs/job_types/station/science/research_director.dm @@ -1,4 +1,5 @@ /datum/job/station/research_director + id = JOB_ID_RESEARCH_DIRECTOR title = "Research Director" flag = RD departments_managed = list(DEPARTMENT_RESEARCH) diff --git a/code/modules/jobs/job_types/station/science/roboticist.dm b/code/modules/jobs/job_types/station/science/roboticist.dm index 6cc2c049ea2..0726108fb2a 100644 --- a/code/modules/jobs/job_types/station/science/roboticist.dm +++ b/code/modules/jobs/job_types/station/science/roboticist.dm @@ -1,4 +1,5 @@ /datum/job/station/roboticist + id = JOB_ID_ROBOTICIST title = "Roboticist" flag = ROBOTICIST departments = list(DEPARTMENT_RESEARCH) diff --git a/code/modules/jobs/job_types/station/science/scientist.dm b/code/modules/jobs/job_types/station/science/scientist.dm index a97d692686a..233f3a96452 100644 --- a/code/modules/jobs/job_types/station/science/scientist.dm +++ b/code/modules/jobs/job_types/station/science/scientist.dm @@ -1,4 +1,5 @@ /datum/job/station/scientist + id = JOB_ID_SCIENTIST title = "Scientist" flag = SCIENTIST departments = list(DEPARTMENT_RESEARCH) diff --git a/code/modules/jobs/job_types/station/science/senior_researcher.dm b/code/modules/jobs/job_types/station/science/senior_researcher.dm index 15cd4a07083..14252c973b9 100644 --- a/code/modules/jobs/job_types/station/science/senior_researcher.dm +++ b/code/modules/jobs/job_types/station/science/senior_researcher.dm @@ -1,5 +1,6 @@ /datum/job/station/senior_researcher title = "Senior Researcher" + id = JOB_ID_SENIOR_RESEARCHER flag = SENIOR_RESEARCHER departments = list(DEPARTMENT_RESEARCH) department_flag = MEDSCI diff --git a/code/modules/jobs/job_types/station/security/detective.dm b/code/modules/jobs/job_types/station/security/detective.dm index bca5f4aea09..ee62e1b1b47 100644 --- a/code/modules/jobs/job_types/station/security/detective.dm +++ b/code/modules/jobs/job_types/station/security/detective.dm @@ -1,4 +1,5 @@ /datum/job/station/detective + id = JOB_ID_DETECTIVE title = "Detective" flag = DETECTIVE departments = list(DEPARTMENT_SECURITY) diff --git a/code/modules/jobs/job_types/station/security/head_of_security.dm b/code/modules/jobs/job_types/station/security/head_of_security.dm index 985a33d0bce..27007d156ca 100644 --- a/code/modules/jobs/job_types/station/security/head_of_security.dm +++ b/code/modules/jobs/job_types/station/security/head_of_security.dm @@ -1,4 +1,5 @@ /datum/job/station/head_of_security + id = JOB_ID_HEAD_OF_SECURITY title = "Head of Security" flag = HOS departments_managed = list(DEPARTMENT_SECURITY) diff --git a/code/modules/jobs/job_types/station/security/security_officer.dm b/code/modules/jobs/job_types/station/security/security_officer.dm index 43d14ba174a..e0091b74d5c 100644 --- a/code/modules/jobs/job_types/station/security/security_officer.dm +++ b/code/modules/jobs/job_types/station/security/security_officer.dm @@ -1,4 +1,5 @@ /datum/job/station/officer + id = JOB_ID_SECURITY_OFFICER title = "Security Officer" flag = OFFICER departments = list(DEPARTMENT_SECURITY) diff --git a/code/modules/jobs/job_types/station/security/warden.dm b/code/modules/jobs/job_types/station/security/warden.dm index c7172833050..bd0b60aff4b 100644 --- a/code/modules/jobs/job_types/station/security/warden.dm +++ b/code/modules/jobs/job_types/station/security/warden.dm @@ -1,4 +1,5 @@ /datum/job/station/warden + id = JOB_ID_WARDEN title = "Warden" flag = WARDEN departments = list(DEPARTMENT_SECURITY) diff --git a/code/modules/jobs/job_types/station/service/bartender.dm b/code/modules/jobs/job_types/station/service/bartender.dm index ce69ff3bd7f..de6cb66f1bd 100644 --- a/code/modules/jobs/job_types/station/service/bartender.dm +++ b/code/modules/jobs/job_types/station/service/bartender.dm @@ -1,4 +1,5 @@ /datum/job/station/bartender + id = JOB_ID_BARTENDER title = "Bartender" flag = BARTENDER departments = list(DEPARTMENT_CIVILIAN) diff --git a/code/modules/jobs/job_types/station/service/botanist.dm b/code/modules/jobs/job_types/station/service/botanist.dm index e2cc6e3cfe7..1b135857eec 100644 --- a/code/modules/jobs/job_types/station/service/botanist.dm +++ b/code/modules/jobs/job_types/station/service/botanist.dm @@ -1,4 +1,5 @@ /datum/job/station/hydro + id = JOB_ID_BOTANIST title = "Botanist" flag = BOTANIST departments = list(DEPARTMENT_CIVILIAN) diff --git a/code/modules/jobs/job_types/station/service/chef.dm b/code/modules/jobs/job_types/station/service/chef.dm index c228863bcf3..807d122c000 100644 --- a/code/modules/jobs/job_types/station/service/chef.dm +++ b/code/modules/jobs/job_types/station/service/chef.dm @@ -1,4 +1,5 @@ /datum/job/station/chef + id = JOB_ID_CHEF title = "Chef" flag = CHEF departments = list(DEPARTMENT_CIVILIAN) diff --git a/code/modules/jobs/job_types/station/service/janitor.dm b/code/modules/jobs/job_types/station/service/janitor.dm index 5bfc2741f96..2e26a13d320 100644 --- a/code/modules/jobs/job_types/station/service/janitor.dm +++ b/code/modules/jobs/job_types/station/service/janitor.dm @@ -1,4 +1,5 @@ /datum/job/station/janitor + id = JOB_ID_JANITOR title = "Janitor" flag = JANITOR departments = list(DEPARTMENT_CIVILIAN) diff --git a/code/modules/jobs/job_types/station/silicon/ai.dm b/code/modules/jobs/job_types/station/silicon/ai.dm index ecc17b31dc1..d6185a0361a 100644 --- a/code/modules/jobs/job_types/station/silicon/ai.dm +++ b/code/modules/jobs/job_types/station/silicon/ai.dm @@ -1,4 +1,5 @@ /datum/job/station/ai + id = JOB_ID_AI title = "AI" flag = AI departments = list(DEPARTMENT_SYNTHETIC) @@ -28,8 +29,13 @@ return 0 return 1 +/datum/job/station/ai/slots_remaining(latejoin) + if(latejoin) + return GLOB.empty_playable_ai_cores.len + return ..() + /datum/job/station/ai/is_position_available() - return (empty_playable_ai_cores.len != 0) + return (GLOB.empty_playable_ai_cores.len != 0) /datum/job/station/ai/equip_preview(mob/living/carbon/human/H) H.equip_to_slot_or_del(new /obj/item/clothing/suit/straight_jacket(H), SLOT_ID_SUIT) diff --git a/code/modules/jobs/job_types/station/silicon/cyborg.dm b/code/modules/jobs/job_types/station/silicon/cyborg.dm index 632d2600ce0..967a99759ed 100644 --- a/code/modules/jobs/job_types/station/silicon/cyborg.dm +++ b/code/modules/jobs/job_types/station/silicon/cyborg.dm @@ -1,4 +1,5 @@ /datum/job/station/cyborg + id = JOB_ID_CYBORG title = "Cyborg" flag = CYBORG departments = list(DEPARTMENT_SYNTHETIC) diff --git a/code/modules/jobs/job_types/station/supply/cargo_technician.dm b/code/modules/jobs/job_types/station/supply/cargo_technician.dm index 281b292a384..fd63d8b18a3 100644 --- a/code/modules/jobs/job_types/station/supply/cargo_technician.dm +++ b/code/modules/jobs/job_types/station/supply/cargo_technician.dm @@ -1,4 +1,5 @@ /datum/job/station/cargo_tech + id = JOB_ID_CARGO_TECHNICIAN title = "Cargo Technician" flag = CARGOTECH departments = list(DEPARTMENT_CARGO) diff --git a/code/modules/jobs/job_types/station/supply/quartermaster.dm b/code/modules/jobs/job_types/station/supply/quartermaster.dm index c9af69206f5..03c84753356 100644 --- a/code/modules/jobs/job_types/station/supply/quartermaster.dm +++ b/code/modules/jobs/job_types/station/supply/quartermaster.dm @@ -1,4 +1,5 @@ /datum/job/station/quartermaster + id = JOB_ID_QUARTERMASTER title = "Quartermaster" flag = QUARTERMASTER departments = list(DEPARTMENT_CARGO) diff --git a/code/modules/jobs/job_types/station/supply/shaft_miner.dm b/code/modules/jobs/job_types/station/supply/shaft_miner.dm index 858fd9af863..25e4adee441 100644 --- a/code/modules/jobs/job_types/station/supply/shaft_miner.dm +++ b/code/modules/jobs/job_types/station/supply/shaft_miner.dm @@ -1,4 +1,5 @@ /datum/job/station/mining + id = JOB_ID_SHAFT_MINER title = "Shaft Miner" flag = MINER departments = list(DEPARTMENT_CARGO) diff --git a/code/modules/jobs/outfit.dm b/code/modules/jobs/outfit.dm index cc15dadb680..178891eb3b7 100644 --- a/code/modules/jobs/outfit.dm +++ b/code/modules/jobs/outfit.dm @@ -17,7 +17,7 @@ var/obj/item/card/id/C = ..() if(!C) return - var/datum/job/J = job_master.GetJob(rank) + var/datum/job/J = SSjob.get_job(rank) if(J) C.access = J.get_access() if(H.mind) diff --git a/code/modules/jobs/whitelist.dm b/code/modules/jobs/whitelist.dm index 805588144ee..6193116494d 100644 --- a/code/modules/jobs/whitelist.dm +++ b/code/modules/jobs/whitelist.dm @@ -16,68 +16,4 @@ var/list/whitelist = list() return 0 return ("[M.ckey]" in whitelist) -/var/list/alien_whitelist = list() - -/hook/startup/proc/loadAlienWhitelist() - if(config_legacy.usealienwhitelist) - load_alienwhitelist() - return 1 - -/proc/load_alienwhitelist() - var/text = file2text("config/alienwhitelist.txt") - if (!text) - log_misc("Failed to load config/alienwhitelist.txt") - else - alien_whitelist = splittext(text, "\n") - -/proc/is_alien_whitelisted(mob/M, var/datum/species/species) - //They are admin or the whitelist isn't in use - if(whitelist_overrides(M)) - return 1 - - //You did something wrong - if(!M || !species) - return 0 - - //The species isn't even whitelisted - if(!(species.spawn_flags & SPECIES_IS_WHITELISTED)) - return 1 - - //If we have a loaded file, search it - if(alien_whitelist) - for (var/s in alien_whitelist) - if(findtext(s,"[M.ckey] - [species.name]")) - return 1 - if(findtext(s,"[M.ckey] - All")) - return 1 - -/proc/is_lang_whitelisted(mob/M, var/datum/language/language) - //They are admin or the whitelist isn't in use - if(whitelist_overrides(M)) - return 1 - - //You did something wrong - if(!M || !language) - return 0 - - //The language isn't even whitelisted - if(!(language.flags & WHITELISTED)) - return 1 - - //If we have a loaded file, search it - if(alien_whitelist) - for (var/s in alien_whitelist) - if(findtext(s,"[M.ckey] - [language.name]")) - return 1 - if(findtext(s,"[M.ckey] - All")) - return 1 - -/proc/whitelist_overrides(mob/M) - if(!config_legacy.usealienwhitelist) - return 1 - if(check_rights(R_ADMIN|R_EVENT, 0, M)) - return 1 - - return 0 - #undef WHITELISTFILE diff --git a/code/modules/jobs/whitelist_vr.dm b/code/modules/jobs/whitelist_vr.dm deleted file mode 100644 index aa96d8b1e1e..00000000000 --- a/code/modules/jobs/whitelist_vr.dm +++ /dev/null @@ -1,30 +0,0 @@ -var/list/job_whitelist = list() - -/hook/startup/proc/loadJobWhitelist() - load_jobwhitelist() - return 1 - -/proc/load_jobwhitelist() - var/text = file2text("config/jobwhitelist.txt") - if (!text) - log_misc("Failed to load config/jobwhitelist.txt") - else - job_whitelist = splittext(text, "\n") - -/proc/is_job_whitelisted(mob/M, var/rank) - var/datum/job/job = SSjob.get_job(rank) - if(!job.whitelist_only) - return 1 - if(rank == USELESS_JOB) - return 1 - if(check_rights(R_ADMIN, 0)) - return 1 - if(!job_whitelist) - return 0 - if(M && rank) - for (var/s in job_whitelist) - if(findtext(s,"[lowertext(M.ckey)] - [lowertext(rank)]")) - return 1 - if(findtext(s,"[M.ckey] - All")) - return 1 - return 0 diff --git a/code/modules/keybindings/setup.dm b/code/modules/keybindings/setup.dm index 50ae8d6af25..69171c0bc62 100644 --- a/code/modules/keybindings/setup.dm +++ b/code/modules/keybindings/setup.dm @@ -55,6 +55,7 @@ keys_held.Cut() erase_all_macros() + update_movement_keys() apply_macro_set(SKIN_MACROSET_HOTKEYS, SSinput.macroset_hotkey) apply_macro_set(SKIN_MACROSET_CLASSIC_HOTKEYS, SSinput.macroset_classic_hotkey) diff --git a/code/modules/language/abstract.dm b/code/modules/language/abstract.dm new file mode 100644 index 00000000000..728983dfcab --- /dev/null +++ b/code/modules/language/abstract.dm @@ -0,0 +1,97 @@ +// Noise "language", for audible emotes. +/datum/language/noise + id = LANGUAGE_ID_NOISE + name = "Noise" + desc = "Noises" + key = "" + language_flags = RESTRICTED|NONGLOBAL|INNATE|NO_TALK_MSG|NO_STUTTER + +/datum/language/noise/format_message(message, verb) + return "[message]" + +/datum/language/noise/format_message_plain(message, verb) + return message + +/datum/language/noise/format_message_radio(message, verb) + return "[message]" + +/datum/language/noise/get_talkinto_msg_range(message) + // if you make a loud noise (screams etc), you'll be heard from 4 tiles over instead of two + return (copytext(message, length(message)) == "!") ? 4 : 2 + +/datum/language/noise/can_speak_special(var/mob/speaker) + return TRUE //Audible emotes + +// Silly language for those times when you try to talk a languague you normally can't +/datum/language/gibberish + id = LANGUAGE_ID_GIBBERISH + name = LANGUAGE_GIBBERISH + desc = "A completely incomprehensible language." + signlang_verb = list("flails") + speech_verb = "spews" + whisper_verb = "mumbles" + exclaim_verb = "shrieks" + colour = "attack" + key = "r" // Radda radda radda + language_flags = RESTRICTED|NONGLOBAL + machine_understands = 0 + syllables = list ( + "radda", "fea","vea","vei","veh","vee","feh","fa","soa","su","sua","sou","se","seh","twa","twe","twi", + "ahm","lea","lee","nae","nah","pa","pau","fae","fai","soh","mou","ahe","ll","ea","ai","thi", + "hie","zei","zie","ize","ehy","uy","oya","dor","di","ja","ej","er","um","in","qu","is","re", + "nt","ti","us","it","en","at","tu","te","ri","es","et","ra","ta","an","ni","li","on","or","se", + "am","ae","ia","di","ue","em","ar","ui","st","si","de","ci","iu","ne","pe","co","os","ur","ru", + "gra","ba","ba","breh","bra","rah","dur","ra","ro","gro","go","ber","bar","geh","heh", "gra", + "a", "ai", "an", "ang", "ao", "ba", "bai", "ban", "bang", "bao", "bei", "ben", "beng", "bi", "bian", "biao", + "bie", "bin", "bing", "bo", "bu", "ca", "cai", "can", "cang", "cao", "ce", "cei", "cen", "ceng", "cha", "chai", + "chan", "chang", "chao", "che", "chen", "cheng", "chi", "chong", "chou", "chu", "chua", "chuai", "chuan", "chuang", "chui", "chun", + "chuo", "ci", "cong", "cou", "cu", "cuan", "cui", "cun", "cuo", "da", "dai", "dan", "dang", "dao", "de", "dei", + "den", "deng", "di", "dian", "diao", "die", "ding", "diu", "dong", "dou", "du", "duan", "dui", "dun", "duo", "e", + "ei", "en", "er", "fa", "fan", "fang", "fei", "fen", "feng", "fo", "fou", "fu", "ga", "gai", "gan", "gang", + "gao", "ge", "gei", "gen", "geng", "gong", "gou", "gu", "gua", "guai", "guan", "guang", "gui", "gun", "guo", "ha", + "hai", "han", "hang", "hao", "he", "hei", "hen", "heng", "hm", "hng", "hong", "hou", "hu", "hua", "huai", "huan", + "huang", "hui", "hun", "huo", "ji", "jia", "jian", "jiang", "jiao", "jie", "jin", "jing", "jiong", "jiu", "ju", "juan", + "jue", "jun", "ka", "kai", "kan", "kang", "kao", "ke", "kei", "ken", "keng", "kong", "kou", "ku", "kua", "kuai", + "kuan", "kuang", "kui", "kun", "kuo", "la", "lai", "lan", "lang", "lao", "le", "lei", "leng", "li", "lia", "lian", + "liang", "liao", "lie", "lin", "ling", "liu", "long", "lou", "lu", "luan", "lun", "luo", "ma", "mai", "man", "mang", + "mao", "me", "mei", "men", "meng", "mi", "mian", "miao", "mie", "min", "ming", "miu", "mo", "mou", "mu", "na", + "nai", "nan", "nang", "nao", "ne", "nei", "nen", "neng", "ng", "ni", "nian", "niang", "niao", "nie", "nin", "ning", + "niu", "nong", "nou", "nu", "nuan", "nuo", "o", "ou", "pa", "pai", "pan", "pang", "pao", "pei", "pen", "peng", + "pi", "pian", "piao", "pie", "pin", "ping", "po", "pou", "pu", "qi", "qia", "qian", "qiang", "qiao", "qie", "qin", + "qing", "qiong", "qiu", "qu", "quan", "que", "qun", "ran", "rang", "rao", "re", "ren", "reng", "ri", "rong", "rou", + "ru", "rua", "ruan", "rui", "run", "ruo", "sa", "sai", "san", "sang", "sao", "se", "sei", "sen", "seng", "sha", + "shai", "shan", "shang", "shao", "she", "shei", "shen", "sheng", "shi", "shou", "shu", "shua", "shuai", "shuan", "shuang", "shui", + "shun", "shuo", "si", "song", "sou", "su", "suan", "sui", "sun", "suo", "ta", "tai", "tan", "tang", "tao", "te", + "teng", "ti", "tian", "tiao", "tie", "ting", "tong", "tou", "tu", "tuan", "tui", "tun", "tuo", "wa", "wai", "wan", + "wang", "wei", "wen", "weng", "wo", "wu", "xi", "xia", "xian", "xiang", "xiao", "xie", "xin", "xing", "xiong", "xiu", + "xu", "xuan", "xue", "xun", "ya", "yan", "yang", "yao", "ye", "yi", "yin", "ying", "yong", "you", "yu", "yuan", + "yue", "yun", "za", "zai", "zan", "zang", "zao", "ze", "zei", "zen", "zeng", "zha", "zhai", "zhan", "zhang", "zhao", + "zhe", "zhei", "zhen", "zheng", "zhi", "zhong", "zhou", "zhu", "zhua", "zhuai", "zhuan", "zhuang", "zhui", "zhun", "zhuo", "zi", + "zong", "zou", "zuan", "zui", "zun", "zuo", "zu", "al", "an", "ar", "as", "at", "ea", "ed", "en", "er", "es", "ha", "he", "hi", "in", "is", "it", + "le", "me", "nd", "ne", "ng", "nt", "on", "or", "ou", "re", "se", "st", "te", "th", "ti", "to", + "ve", "wa", "all", "and", "are", "but", "ent", "era", "ere", "eve", "for", "had", "hat", "hen", "her", "hin", + "his", "ing", "ion", "ith", "not", "ome", "oul", "our", "sho", "ted", "ter", "tha", "the", "thi", + "al", "an", "ar", "as", "at", "ea", "ed", "en", "er", "es", "ha", "he", "hi", "in", "is", "it", + "le", "me", "nd", "ne", "ng", "nt", "on", "or", "ou", "re", "se", "st", "te", "th", "ti", "to", + "ve", "wa", "all", "and", "are", "but", "ent", "era", "ere", "eve", "for", "had", "hat", "hen", "her", "hin", + "his", "ing", "ion", "ith", "not", "ome", "oul", "our", "sho", "ted", "ter", "tha", "the", "thi", + "al", "an", "ar", "as", "at", "ea", "ed", "en", "er", "es", "ha", "he", "hi", "in", "is", "it", + "le", "me", "nd", "ne", "ng", "nt", "on", "or", "ou", "re", "se", "st", "te", "th", "ti", "to", + "ve", "wa", "all", "and", "are", "but", "ent", "era", "ere", "eve", "for", "had", "hat", "hen", "her", "hin", + "his", "ing", "ion", "ith", "not", "ome", "oul", "our", "sho", "ted", "ter", "tha", "the", "thi", + "al", "an", "ar", "as", "at", "ea", "ed", "en", "er", "es", "ha", "he", "hi", "in", "is", "it", + "le", "me", "nd", "ne", "ng", "nt", "on", "or", "ou", "re", "se", "st", "te", "th", "ti", "to", + "ve", "wa", "all", "and", "are", "but", "ent", "era", "ere", "eve", "for", "had", "hat", "hen", "her", "hin", + "his", "ing", "ion", "ith", "not", "ome", "oul", "our", "sho", "ted", "ter", "tha", "the", "thi", + "al", "an", "ar", "as", "at", "ea", "ed", "en", "er", "es", "ha", "he", "hi", "in", "is", "it", + "le", "me", "nd", "ne", "ng", "nt", "on", "or", "ou", "re", "se", "st", "te", "th", "ti", "to", + "ve", "wa", "all", "and", "are", "but", "ent", "era", "ere", "eve", "for", "had", "hat", "hen", "her", "hin", + "his", "ing", "ion", "ith", "not", "ome", "oul", "our", "sho", "ted", "ter", "tha", "the", "thi", + "al", "an", "ar", "as", "at", "ea", "ed", "en", "er", "es", "ha", "he", "hi", "in", "is", "it", + "le", "me", "nd", "ne", "ng", "nt", "on", "or", "ou", "re", "se", "st", "te", "th", "ti", "to", + "ve", "wa", "all", "and", "are", "but", "ent", "era", "ere", "eve", "for", "had", "hat", "hen", "her", "hin", + "his", "ing", "ion", "ith", "not", "ome", "oul", "our", "sho", "ted", "ter", "tha", "the", "thi" + ) + +/datum/language/gibberish/can_speak_special(var/mob/speaker) + return TRUE //Anyone can speak gibberish diff --git a/code/modules/language/animal.dm b/code/modules/language/animal.dm new file mode 100644 index 00000000000..7fd2d25109a --- /dev/null +++ b/code/modules/language/animal.dm @@ -0,0 +1,51 @@ +/datum/language/corgi + id = LANGUAGE_ID_DOG + name = "Dog" + desc = "Woof woof woof." + speech_verb = "barks" + ask_verb = "woofs" + exclaim_verb = "howls" + key = "n" + language_flags = RESTRICTED + machine_understands = 0 + space_chance = 100 + syllables = list("bark", "woof", "bowwow", "yap", "arf") + +/datum/language/cat + id = LANGUAGE_ID_CAT + name = "Cat" + desc = "Meow meow meow." + speech_verb = "meows" + ask_verb = "mrowls" + exclaim_verb = "yowls" + key = "c" + language_flags = RESTRICTED + machine_understands = 0 + space_chance = 100 + syllables = list("meow", "mrowl", "purr", "meow", "meow", "meow") + +/datum/language/mouse + id = LANGUAGE_ID_MOUSE + name = "Mouse" + desc = "Squeak squeak. *Nibbles on cheese*" + speech_verb = "squeaks" + ask_verb = "squeaks" + exclaim_verb = "squeaks" + key = "m" + language_flags = RESTRICTED + machine_understands = 0 + space_chance = 100 + syllables = list("squeak") // , "gripes", "oi", "meow") + +/datum/language/bird + id = LANGUAGE_ID_BIRD + name = "Bird" + desc = "Chirp chirp, give me food" + speech_verb = "chirps" + ask_verb = "tweets" + exclaim_verb = "squawks" + key = "m" + language_flags = RESTRICTED + machine_understands = 0 + space_chance = 100 + syllables = list("chirp", "squawk", "tweet") diff --git a/code/modules/language/antagonist/borer.dm b/code/modules/language/antagonist/borer.dm new file mode 100644 index 00000000000..35a1377f59f --- /dev/null +++ b/code/modules/language/antagonist/borer.dm @@ -0,0 +1,25 @@ +/datum/language/corticalborer + id = LANGUAGE_ID_BORER + name = "Cortical Link" + desc = "Cortical borers possess a strange link between their tiny minds." + speech_verb = "sings" + ask_verb = "sings" + exclaim_verb = "sings" + colour = "alien" + key = "" //!! THIS DOES NOT HAVE A LANGUAGE KEY IF YOU SOMEHOW MIRACULOUSLY GET ANTAGS WORKING ON RP BEFORE WE TRANSITION TO SS14 IN LIKE 2025 PUT ONE IN. + machine_understands = 0 + language_flags = RESTRICTED | HIVEMIND + +/datum/language/corticalborer/broadcast(var/mob/living/speaker,var/message,var/speaker_mask) + + var/mob/living/simple_mob/animal/borer/B + + if(istype(speaker,/mob/living/carbon)) + var/mob/living/carbon/M = speaker + B = M.has_brain_worms() + else if(istype(speaker,/mob/living/simple_mob/animal/borer)) + B = speaker + + if(B) + speaker_mask = B.true_name + ..(speaker,message,speaker_mask) diff --git a/code/modules/language/antagonist/changeling.dm b/code/modules/language/antagonist/changeling.dm new file mode 100644 index 00000000000..b204eff4da2 --- /dev/null +++ b/code/modules/language/antagonist/changeling.dm @@ -0,0 +1,16 @@ +/datum/language/ling + id = LANGUAGE_ID_CHANGELING + name = LANGUAGE_CHANGELING + desc = "Although they are normally wary and suspicious of each other, changelings can commune over a distance." + speech_verb = "says" + colour = "changeling" + key = "g" + machine_understands = 0 + language_flags = RESTRICTED | HIVEMIND + +/datum/language/ling/broadcast(var/mob/living/speaker,var/message,var/speaker_mask) + + if(speaker.mind && speaker.mind.changeling) + ..(speaker,message,speaker.mind.changeling.changelingID) + else + ..(speaker,message) diff --git a/code/modules/language/antagonist/cult.dm b/code/modules/language/antagonist/cult.dm new file mode 100644 index 00000000000..38fa1b31fd2 --- /dev/null +++ b/code/modules/language/antagonist/cult.dm @@ -0,0 +1,32 @@ +/datum/language/cultcommon + id = LANGUAGE_ID_CULT + name = LANGUAGE_CULT + desc = "The chants of the occult, the incomprehensible." + speech_verb = "intones" + ask_verb = "intones" + exclaim_verb = "chants" + colour = "cult" + key = "f" + language_flags = RESTRICTED + space_chance = 100 + machine_understands = 0 + syllables = list("ire","ego","nahlizet","certum","veri","jatkaa","mgar","balaq", "karazet", "geeri", \ + "orkan", "allaq", "sas'so", "c'arta", "forbici", "tarem", "n'ath", "reth", "sh'yro", "eth", "d'raggathnor", \ + "mah'weyh", "pleggh", "at", "e'ntrath", "tok-lyr", "rqa'nap", "g'lt-ulotf", "ta'gh", "fara'qha", "fel", "d'amar det", \ + "yu'gular", "faras", "desdae", "havas", "mithum", "javara", "umathar", "uf'kal", "thenar", "rash'tla", \ + "sektath", "mal'zua", "zasan", "therium", "viortia", "kla'atu", "barada", "nikt'o", "fwe'sh", "mah", "erl", "nyag", "r'ya", \ + "gal'h'rfikk", "harfrandid", "mud'gib", "il", "fuu", "ma'jin", "dedo", "ol'btoh", "n'ath", "reth", "sh'yro", "eth", \ + "d'rekkathnor", "khari'd", "gual'te", "nikka", "nikt'o", "barada", "kla'atu", "barhah", "hra" ,"zar'garis", "spiri", "malum") + +/datum/language/cult + id = LANGUAGE_ID_CULT_COMMUNE + name = LANGUAGE_OCCULT + desc = "The initiated can share their thoughts by means defying all reason." + speech_verb = "intones" + ask_verb = "intones" + exclaim_verb = "chants" + colour = "cult" + key = "y" + machine_understands = 0 + language_flags = RESTRICTED | HIVEMIND + diff --git a/code/modules/language/antagonist/swarmbot.dm b/code/modules/language/antagonist/swarmbot.dm new file mode 100644 index 00000000000..769c9b30399 --- /dev/null +++ b/code/modules/language/antagonist/swarmbot.dm @@ -0,0 +1,13 @@ +/datum/language/swarmbot + id = LANGUAGE_ID_SWARMBOT + name = LANGUAGE_SWARMBOT + desc = "A confusing mechanical language spoken by some form of ancient machine." + speech_verb = "clatters" + ask_verb = "chatters" + exclaim_verb = "shrieks" + colour = "changeling" + key = "_" + machine_understands = 0 + language_flags = NO_STUTTER | RESTRICTED + syllables = list("^", "v", "-", ".", "~") + space_chance = 60 diff --git a/code/modules/language/antagonist/xenomorph.dm b/code/modules/language/antagonist/xenomorph.dm new file mode 100644 index 00000000000..0f09096342b --- /dev/null +++ b/code/modules/language/antagonist/xenomorph.dm @@ -0,0 +1,34 @@ +/datum/language/xenocommon + id = LANGUAGE_ID_XENOMORPH + name = SPECIES_XENO + colour = "alien" + desc = "The common tongue of the xenomorphs." + speech_verb = "hisses" + ask_verb = "hisses" + exclaim_verb = "hisses" + key = "u" + machine_understands = 0 + language_flags = RESTRICTED + syllables = list("sss","sSs","SSS") + +/datum/language/xenos + id = LANGUAGE_ID_XENOMORPH_HIVEMIND + name = "Hivemind" + desc = "Xenomorphs have the strange ability to commune over a psychic hivemind." + speech_verb = "hisses" + ask_verb = "hisses" + exclaim_verb = "hisses" + colour = "alien" + machine_understands = 0 + key = "x" + language_flags = RESTRICTED | HIVEMIND + +/datum/language/xenos/check_special_condition(var/mob/other) + + var/mob/living/carbon/M = other + if(!istype(M)) + return 1 + if(locate(/obj/item/organ/internal/xenos/hivenode) in M.internal_organs) + return 1 + + return 0 diff --git a/code/modules/language/core.dm b/code/modules/language/core.dm new file mode 100644 index 00000000000..ba77081ab2b --- /dev/null +++ b/code/modules/language/core.dm @@ -0,0 +1,46 @@ +// 'basic' language; spoken by default. +/datum/language/common + id = LANGUAGE_ID_COMMON + name = LANGUAGE_GALCOM + desc = "The common galactic tongue, engineered for cross-species communication." + speech_verb = "says" + exclaim_verb = list("exclaims","shouts","yells") + whisper_verb = "whispers" + key = "0" + language_flags = RESTRICTED + syllables = list( +"vol", "zum", "coo","zoo","bi","do","ooz","ite","og","re","si","ite","ish", +"ar","at","on","ee","east","ma","da", "rim") + partial_understanding = list(LANGUAGE_SKRELLIAN = 30, LANGUAGE_SOL_COMMON = 30) + +/datum/language/machine + id = LANGUAGE_ID_EAL + name = LANGUAGE_EAL + desc = "An efficient language of encoded tones developed by positronics." + speech_verb = "whistles" + ask_verb = "chirps" + exclaim_verb = "whistles loudly" + colour = "changeling" + key = "6" + language_flags = NO_STUTTER + syllables = list("beep","beep","beep","beep","beep","boop","boop","boop","bop","bop","dee","dee","doo","doo","hiss","hss","buzz","buzz","bzz","ksssh","keey","wurr","wahh","tzzz","shh","shk") + space_chance = 10 + +/datum/language/machine/get_random_name() + if(prob(70)) + return "[pick(list("PBU","HIU","SINA","ARMA","OSI"))]-[rand(100, 999)]" + else + return pick(GLOB.ai_names) + +/datum/language/sign + id = LANGUAGE_ID_SIGN + name = LANGUAGE_SIGN + desc = "A sign language commonly used for those who are deaf or mute." + signlang_verb = list("gestures") + colour = "say_quote" + key = "s" + language_flags = SIGNLANG|NO_STUTTER|NONVERBAL + +/datum/language/sign/can_speak_special(var/mob/speaker) // TODO: If ever we make external organs assist languages, convert this over to the new format + var/obj/item/organ/external/hand/hands = locate() in speaker //you can't sign without hands + return (hands || !iscarbon(speaker)) diff --git a/code/modules/language/event.dm b/code/modules/language/event.dm new file mode 100644 index 00000000000..49a87bc9b31 --- /dev/null +++ b/code/modules/language/event.dm @@ -0,0 +1,29 @@ +// todo: dynamic language creation system we shouldn't have this +//For your event purposes. +/datum/language/occursus + name = LANGUAGE_EVENT1 + desc = "The Powers That Be have seen it fit to grace you with a special language that sounds like... something. This description should be overridden by the time you see this." + speech_verb = "says" + ask_verb = "asks" + exclaim_verb = "shouts" + colour = "warning" + key = "]" + language_flags = RESTRICTED + syllables = list("chan","ange","thi","se") + +//for your antag purposes. +/datum/language/minbus + id = LANGUAGE_ID_EVENT_2 + name = LANGUAGE_MINBUS + desc = "The Powers That Be have seen it fit to grace you with a special language that sounds like Russian for some reason." + speech_verb = "says" + ask_verb = "asks" + exclaim_verb = "shouts" + colour = "deadsay" + key = "r" + machine_understands = 0 + language_flags = RESTRICTED + syllables = list("rus","zem","ave","groz","ski","ska","ven","konst","pol","lin","svy", + "danya","da","mied","zan","das","krem","myka","cyka","blyat","to","st","no","na","ni", + "ko","ne","en","po","ra","li","on","byl","cto","eni","ost","ol","ego","ver","stv","pro") + diff --git a/code/modules/language/galactic.dm b/code/modules/language/galactic.dm new file mode 100644 index 00000000000..3d3c3a63d7c --- /dev/null +++ b/code/modules/language/galactic.dm @@ -0,0 +1,76 @@ +// Galactic common languages (systemwide accepted standards). +/datum/language/trader + id = LANGUAGE_ID_TRADEBAND + name = LANGUAGE_TRADEBAND + desc = "Maintained by the various trading cartels in major systems, this elegant, structured language is used for bartering and bargaining." + speech_verb = "enunciates" + colour = "say_quote" + key = "2" + syllables = list( +"fea","vea","vei","veh","vee","feh","fa","soa","su","sua","sou","se","seh","twa","twe","twi", +"ahm","lea","lee","nae","nah","pa","pau","fae","fai","soh","mou","ahe","ll","ea","ai","thi", +"hie","zei","zie","ize","ehy","uy","oya","dor","di","ja","ej","er","um","in","qu","is","re", +"nt","ti","us","it","en","at","tu","te","ri","es","et","ra","ta","an","ni","li","on","or","se", +"am","ae","ia","di","ue","em","ar","ui","st","si","de","ci","iu","ne","pe","co","os","ur","ru") + +// Criminal language. +/datum/language/gutter + name = LANGUAGE_GUTTER + desc = "Gutter originated as a Thieves' Cant of sorts during the early colonization era. The language eventually spread from the cartels and triads to the disenfranchised people of the Bowl." + speech_verb = "growls" + colour = "rough" + key = "3" + space_chance = 45 + machine_understands = FALSE + partial_understanding = list(LANGUAGE_GALCOM = 10, LANGUAGE_TRADEBAND = 20, LANGUAGE_SOL_COMMON = 20) + syllables = list ( +"gra","ba","ba","breh","bra","rah","dur","ra","ro","gro","go","ber","bar","geh","heh", "gra", +"a", "ai", "an", "ang", "ao", "ba", "bai", "ban", "bang", "bao", "bei", "ben", "beng", "bi", "bian", "biao", +"bie", "bin", "bing", "bo", "bu", "ca", "cai", "can", "cang", "cao", "ce", "cei", "cen", "ceng", "cha", "chai", +"chan", "chang", "chao", "che", "chen", "cheng", "chi", "chong", "chou", "chu", "chua", "chuai", "chuan", "chuang", "chui", "chun", +"chuo", "ci", "cong", "cou", "cu", "cuan", "cui", "cun", "cuo", "da", "dai", "dan", "dang", "dao", "de", "dei", +"den", "deng", "di", "dian", "diao", "die", "ding", "diu", "dong", "dou", "du", "duan", "dui", "dun", "duo", "e", +"ei", "en", "er", "fa", "fan", "fang", "fei", "fen", "feng", "fo", "fou", "fu", "ga", "gai", "gan", "gang", +"gao", "ge", "gei", "gen", "geng", "gong", "gou", "gu", "gua", "guai", "guan", "guang", "gui", "gun", "guo", "ha", +"hai", "han", "hang", "hao", "he", "hei", "hen", "heng", "hm", "hng", "hong", "hou", "hu", "hua", "huai", "huan", +"huang", "hui", "hun", "huo", "ji", "jia", "jian", "jiang", "jiao", "jie", "jin", "jing", "jiong", "jiu", "ju", "juan", +"jue", "jun", "ka", "kai", "kan", "kang", "kao", "ke", "kei", "ken", "keng", "kong", "kou", "ku", "kua", "kuai", +"kuan", "kuang", "kui", "kun", "kuo", "la", "lai", "lan", "lang", "lao", "le", "lei", "leng", "li", "lia", "lian", +"liang", "liao", "lie", "lin", "ling", "liu", "long", "lou", "lu", "luan", "lun", "luo", "ma", "mai", "man", "mang", +"mao", "me", "mei", "men", "meng", "mi", "mian", "miao", "mie", "min", "ming", "miu", "mo", "mou", "mu", "na", +"nai", "nan", "nang", "nao", "ne", "nei", "nen", "neng", "ng", "ni", "nian", "niang", "niao", "nie", "nin", "ning", +"niu", "nong", "nou", "nu", "nuan", "nuo", "o", "ou", "pa", "pai", "pan", "pang", "pao", "pei", "pen", "peng", +"pi", "pian", "piao", "pie", "pin", "ping", "po", "pou", "pu", "qi", "qia", "qian", "qiang", "qiao", "qie", "qin", +"qing", "qiong", "qiu", "qu", "quan", "que", "qun", "ran", "rang", "rao", "re", "ren", "reng", "ri", "rong", "rou", +"ru", "rua", "ruan", "rui", "run", "ruo", "sa", "sai", "san", "sang", "sao", "se", "sei", "sen", "seng", "sha", +"shai", "shan", "shang", "shao", "she", "shei", "shen", "sheng", "shi", "shou", "shu", "shua", "shuai", "shuan", "shuang", "shui", +"shun", "shuo", "si", "song", "sou", "su", "suan", "sui", "sun", "suo", "ta", "tai", "tan", "tang", "tao", "te", +"teng", "ti", "tian", "tiao", "tie", "ting", "tong", "tou", "tu", "tuan", "tui", "tun", "tuo", "wa", "wai", "wan", +"wang", "wei", "wen", "weng", "wo", "wu", "xi", "xia", "xian", "xiang", "xiao", "xie", "xin", "xing", "xiong", "xiu", +"xu", "xuan", "xue", "xun", "ya", "yan", "yang", "yao", "ye", "yi", "yin", "ying", "yong", "you", "yu", "yuan", +"yue", "yun", "za", "zai", "zan", "zang", "zao", "ze", "zei", "zen", "zeng", "zha", "zhai", "zhan", "zhang", "zhao", +"zhe", "zhei", "zhen", "zheng", "zhi", "zhong", "zhou", "zhu", "zhua", "zhuai", "zhuan", "zhuang", "zhui", "zhun", "zhuo", "zi", +"zong", "zou", "zuan", "zui", "zun", "zuo", "zu", "al", "an", "ar", "as", "at", "ea", "ed", "en", "er", "es", "ha", "he", "hi", "in", "is", "it", +"le", "me", "nd", "ne", "ng", "nt", "on", "or", "ou", "re", "se", "st", "te", "th", "ti", "to", +"ve", "wa", "all", "and", "are", "but", "ent", "era", "ere", "eve", "for", "had", "hat", "hen", "her", "hin", +"his", "ing", "ion", "ith", "not", "ome", "oul", "our", "sho", "ted", "ter", "tha", "the", "thi", +"al", "an", "ar", "as", "at", "ea", "ed", "en", "er", "es", "ha", "he", "hi", "in", "is", "it", +"le", "me", "nd", "ne", "ng", "nt", "on", "or", "ou", "re", "se", "st", "te", "th", "ti", "to", +"ve", "wa", "all", "and", "are", "but", "ent", "era", "ere", "eve", "for", "had", "hat", "hen", "her", "hin", +"his", "ing", "ion", "ith", "not", "ome", "oul", "our", "sho", "ted", "ter", "tha", "the", "thi", +"al", "an", "ar", "as", "at", "ea", "ed", "en", "er", "es", "ha", "he", "hi", "in", "is", "it", +"le", "me", "nd", "ne", "ng", "nt", "on", "or", "ou", "re", "se", "st", "te", "th", "ti", "to", +"ve", "wa", "all", "and", "are", "but", "ent", "era", "ere", "eve", "for", "had", "hat", "hen", "her", "hin", +"his", "ing", "ion", "ith", "not", "ome", "oul", "our", "sho", "ted", "ter", "tha", "the", "thi", +"al", "an", "ar", "as", "at", "ea", "ed", "en", "er", "es", "ha", "he", "hi", "in", "is", "it", +"le", "me", "nd", "ne", "ng", "nt", "on", "or", "ou", "re", "se", "st", "te", "th", "ti", "to", +"ve", "wa", "all", "and", "are", "but", "ent", "era", "ere", "eve", "for", "had", "hat", "hen", "her", "hin", +"his", "ing", "ion", "ith", "not", "ome", "oul", "our", "sho", "ted", "ter", "tha", "the", "thi", +"al", "an", "ar", "as", "at", "ea", "ed", "en", "er", "es", "ha", "he", "hi", "in", "is", "it", +"le", "me", "nd", "ne", "ng", "nt", "on", "or", "ou", "re", "se", "st", "te", "th", "ti", "to", +"ve", "wa", "all", "and", "are", "but", "ent", "era", "ere", "eve", "for", "had", "hat", "hen", "her", "hin", +"his", "ing", "ion", "ith", "not", "ome", "oul", "our", "sho", "ted", "ter", "tha", "the", "thi", +"al", "an", "ar", "as", "at", "ea", "ed", "en", "er", "es", "ha", "he", "hi", "in", "is", "it", +"le", "me", "nd", "ne", "ng", "nt", "on", "or", "ou", "re", "se", "st", "te", "th", "ti", "to", +"ve", "wa", "all", "and", "are", "but", "ent", "era", "ere", "eve", "for", "had", "hat", "hen", "her", "hin", +"his", "ing", "ion", "ith", "not", "ome", "oul", "our", "sho", "ted", "ter", "tha", "the", "thi") diff --git a/code/modules/language/generic.dm b/code/modules/language/generic.dm deleted file mode 100644 index c8ee7c1128d..00000000000 --- a/code/modules/language/generic.dm +++ /dev/null @@ -1,221 +0,0 @@ -// Noise "language", for audible emotes. -/datum/language/noise - name = "Noise" - desc = "Noises" - key = "" - flags = RESTRICTED|NONGLOBAL|INNATE|NO_TALK_MSG|NO_STUTTER - -/datum/language/noise/format_message(message, verb) - return "[message]" - -/datum/language/noise/format_message_plain(message, verb) - return message - -/datum/language/noise/format_message_radio(message, verb) - return "[message]" - -/datum/language/noise/get_talkinto_msg_range(message) - // if you make a loud noise (screams etc), you'll be heard from 4 tiles over instead of two - return (copytext(message, length(message)) == "!") ? 4 : 2 - -/datum/language/noise/can_speak_special(var/mob/speaker) - return TRUE //Audible emotes - -// 'basic' language; spoken by default. -/datum/language/common - name = LANGUAGE_GALCOM - desc = "The common galactic tongue, engineered for cross-species communication." - speech_verb = "says" - exclaim_verb = list("exclaims","shouts","yells") - whisper_verb = "whispers" - key = "0" - flags = RESTRICTED - syllables = list( -"vol", "zum", "coo","zoo","bi","do","ooz","ite","og","re","si","ite","ish", -"ar","at","on","ee","east","ma","da", "rim") - partial_understanding = list(LANGUAGE_SKRELLIAN = 30, LANGUAGE_SOL_COMMON = 30) - -// Galactic common languages (systemwide accepted standards). -/datum/language/trader - name = LANGUAGE_TRADEBAND - desc = "Maintained by the various trading cartels in major systems, this elegant, structured language is used for bartering and bargaining." - speech_verb = "enunciates" - colour = "say_quote" - key = "2" - syllables = list( -"fea","vea","vei","veh","vee","feh","fa","soa","su","sua","sou","se","seh","twa","twe","twi", -"ahm","lea","lee","nae","nah","pa","pau","fae","fai","soh","mou","ahe","ll","ea","ai","thi", -"hie","zei","zie","ize","ehy","uy","oya","dor","di","ja","ej","er","um","in","qu","is","re", -"nt","ti","us","it","en","at","tu","te","ri","es","et","ra","ta","an","ni","li","on","or","se", -"am","ae","ia","di","ue","em","ar","ui","st","si","de","ci","iu","ne","pe","co","os","ur","ru") - -/datum/language/terminus - name = LANGUAGE_TERMINUS - desc = "A group of languages spoken by the Zorren with a certain degree of mutual intelligibility under each other. Evidence shows it was a single lingua franca which has diverged into many sub languages due to isolation." - speech_verb = "mentions" - exclaim_verb = "insinuates" - colour = "terminus" - key = "4" - syllables = list (".a", "spa", "pan", "blaif", "stra", "!u", "!ei", "!am", "by", ".y", "gry", "zbly", "!y", "fl", - "sm", "rn", "cpi", "ku", "koi", "pr", "glau", "stu", "ved", "ki", "tsa", "xau", "jbu", "sny", "stro", "nu", - "uan", "ju", "!i", "ge", "luk", "an", "ar", "at", "es", "et", "bel", "ki", "jaa", "ch", "ki", "gh", "ll", "uu", "wat") - -// Criminal language. -/datum/language/gutter - name = LANGUAGE_GUTTER - desc = "Gutter originated as a Thieves' Cant of sorts during the early colonization era. The language eventually spread from the cartels and triads to the disenfranchised people of the Bowl." - speech_verb = "growls" - colour = "rough" - key = "3" - space_chance = 45 - machine_understands = FALSE - partial_understanding = list(LANGUAGE_GALCOM = 10, LANGUAGE_TRADEBAND = 20, LANGUAGE_SOL_COMMON = 20) - syllables = list ( -"gra","ba","ba","breh","bra","rah","dur","ra","ro","gro","go","ber","bar","geh","heh", "gra", -"a", "ai", "an", "ang", "ao", "ba", "bai", "ban", "bang", "bao", "bei", "ben", "beng", "bi", "bian", "biao", -"bie", "bin", "bing", "bo", "bu", "ca", "cai", "can", "cang", "cao", "ce", "cei", "cen", "ceng", "cha", "chai", -"chan", "chang", "chao", "che", "chen", "cheng", "chi", "chong", "chou", "chu", "chua", "chuai", "chuan", "chuang", "chui", "chun", -"chuo", "ci", "cong", "cou", "cu", "cuan", "cui", "cun", "cuo", "da", "dai", "dan", "dang", "dao", "de", "dei", -"den", "deng", "di", "dian", "diao", "die", "ding", "diu", "dong", "dou", "du", "duan", "dui", "dun", "duo", "e", -"ei", "en", "er", "fa", "fan", "fang", "fei", "fen", "feng", "fo", "fou", "fu", "ga", "gai", "gan", "gang", -"gao", "ge", "gei", "gen", "geng", "gong", "gou", "gu", "gua", "guai", "guan", "guang", "gui", "gun", "guo", "ha", -"hai", "han", "hang", "hao", "he", "hei", "hen", "heng", "hm", "hng", "hong", "hou", "hu", "hua", "huai", "huan", -"huang", "hui", "hun", "huo", "ji", "jia", "jian", "jiang", "jiao", "jie", "jin", "jing", "jiong", "jiu", "ju", "juan", -"jue", "jun", "ka", "kai", "kan", "kang", "kao", "ke", "kei", "ken", "keng", "kong", "kou", "ku", "kua", "kuai", -"kuan", "kuang", "kui", "kun", "kuo", "la", "lai", "lan", "lang", "lao", "le", "lei", "leng", "li", "lia", "lian", -"liang", "liao", "lie", "lin", "ling", "liu", "long", "lou", "lu", "luan", "lun", "luo", "ma", "mai", "man", "mang", -"mao", "me", "mei", "men", "meng", "mi", "mian", "miao", "mie", "min", "ming", "miu", "mo", "mou", "mu", "na", -"nai", "nan", "nang", "nao", "ne", "nei", "nen", "neng", "ng", "ni", "nian", "niang", "niao", "nie", "nin", "ning", -"niu", "nong", "nou", "nu", "nuan", "nuo", "o", "ou", "pa", "pai", "pan", "pang", "pao", "pei", "pen", "peng", -"pi", "pian", "piao", "pie", "pin", "ping", "po", "pou", "pu", "qi", "qia", "qian", "qiang", "qiao", "qie", "qin", -"qing", "qiong", "qiu", "qu", "quan", "que", "qun", "ran", "rang", "rao", "re", "ren", "reng", "ri", "rong", "rou", -"ru", "rua", "ruan", "rui", "run", "ruo", "sa", "sai", "san", "sang", "sao", "se", "sei", "sen", "seng", "sha", -"shai", "shan", "shang", "shao", "she", "shei", "shen", "sheng", "shi", "shou", "shu", "shua", "shuai", "shuan", "shuang", "shui", -"shun", "shuo", "si", "song", "sou", "su", "suan", "sui", "sun", "suo", "ta", "tai", "tan", "tang", "tao", "te", -"teng", "ti", "tian", "tiao", "tie", "ting", "tong", "tou", "tu", "tuan", "tui", "tun", "tuo", "wa", "wai", "wan", -"wang", "wei", "wen", "weng", "wo", "wu", "xi", "xia", "xian", "xiang", "xiao", "xie", "xin", "xing", "xiong", "xiu", -"xu", "xuan", "xue", "xun", "ya", "yan", "yang", "yao", "ye", "yi", "yin", "ying", "yong", "you", "yu", "yuan", -"yue", "yun", "za", "zai", "zan", "zang", "zao", "ze", "zei", "zen", "zeng", "zha", "zhai", "zhan", "zhang", "zhao", -"zhe", "zhei", "zhen", "zheng", "zhi", "zhong", "zhou", "zhu", "zhua", "zhuai", "zhuan", "zhuang", "zhui", "zhun", "zhuo", "zi", -"zong", "zou", "zuan", "zui", "zun", "zuo", "zu", "al", "an", "ar", "as", "at", "ea", "ed", "en", "er", "es", "ha", "he", "hi", "in", "is", "it", -"le", "me", "nd", "ne", "ng", "nt", "on", "or", "ou", "re", "se", "st", "te", "th", "ti", "to", -"ve", "wa", "all", "and", "are", "but", "ent", "era", "ere", "eve", "for", "had", "hat", "hen", "her", "hin", -"his", "ing", "ion", "ith", "not", "ome", "oul", "our", "sho", "ted", "ter", "tha", "the", "thi", -"al", "an", "ar", "as", "at", "ea", "ed", "en", "er", "es", "ha", "he", "hi", "in", "is", "it", -"le", "me", "nd", "ne", "ng", "nt", "on", "or", "ou", "re", "se", "st", "te", "th", "ti", "to", -"ve", "wa", "all", "and", "are", "but", "ent", "era", "ere", "eve", "for", "had", "hat", "hen", "her", "hin", -"his", "ing", "ion", "ith", "not", "ome", "oul", "our", "sho", "ted", "ter", "tha", "the", "thi", -"al", "an", "ar", "as", "at", "ea", "ed", "en", "er", "es", "ha", "he", "hi", "in", "is", "it", -"le", "me", "nd", "ne", "ng", "nt", "on", "or", "ou", "re", "se", "st", "te", "th", "ti", "to", -"ve", "wa", "all", "and", "are", "but", "ent", "era", "ere", "eve", "for", "had", "hat", "hen", "her", "hin", -"his", "ing", "ion", "ith", "not", "ome", "oul", "our", "sho", "ted", "ter", "tha", "the", "thi", -"al", "an", "ar", "as", "at", "ea", "ed", "en", "er", "es", "ha", "he", "hi", "in", "is", "it", -"le", "me", "nd", "ne", "ng", "nt", "on", "or", "ou", "re", "se", "st", "te", "th", "ti", "to", -"ve", "wa", "all", "and", "are", "but", "ent", "era", "ere", "eve", "for", "had", "hat", "hen", "her", "hin", -"his", "ing", "ion", "ith", "not", "ome", "oul", "our", "sho", "ted", "ter", "tha", "the", "thi", -"al", "an", "ar", "as", "at", "ea", "ed", "en", "er", "es", "ha", "he", "hi", "in", "is", "it", -"le", "me", "nd", "ne", "ng", "nt", "on", "or", "ou", "re", "se", "st", "te", "th", "ti", "to", -"ve", "wa", "all", "and", "are", "but", "ent", "era", "ere", "eve", "for", "had", "hat", "hen", "her", "hin", -"his", "ing", "ion", "ith", "not", "ome", "oul", "our", "sho", "ted", "ter", "tha", "the", "thi", -"al", "an", "ar", "as", "at", "ea", "ed", "en", "er", "es", "ha", "he", "hi", "in", "is", "it", -"le", "me", "nd", "ne", "ng", "nt", "on", "or", "ou", "re", "se", "st", "te", "th", "ti", "to", -"ve", "wa", "all", "and", "are", "but", "ent", "era", "ere", "eve", "for", "had", "hat", "hen", "her", "hin", -"his", "ing", "ion", "ith", "not", "ome", "oul", "our", "sho", "ted", "ter", "tha", "the", "thi") - -/datum/language/sign - name = LANGUAGE_SIGN - desc = "A sign language commonly used for those who are deaf or mute." - signlang_verb = list("gestures") - colour = "say_quote" - key = "s" - flags = SIGNLANG|NO_STUTTER|NONVERBAL - -/datum/language/sign/can_speak_special(var/mob/speaker) // TODO: If ever we make external organs assist languages, convert this over to the new format - var/obj/item/organ/external/hand/hands = locate() in speaker //you can't sign without hands - return (hands || !iscarbon(speaker)) - -// Alraune language that's literally just bushes rubbing together. -/datum/language/vernal - name = LANGUAGE_VERNAL - desc = "An imperceptibly complex and nuanced language, often confused for the natural sounds of the forest." - signlang_verb = list("sways") - speech_verb = "rustles" - whisper_verb = "susurrus" - exclaim_verb = "crackles" - colour = "soghun" - key = "t" //Rustles susurrus crackles - syllables = list ("shh", "fssh", "rustle", "snap", "kssh", "sffh", "mssh", "creak", - "knock", "crk", "srhh", "rrssh", "sh", "hk", "fsh", "rss", "ks") - -// Silly language for those times when you try to talk a languague you normally can't -/datum/language/gibberish - name = LANGUAGE_GIBBERISH - desc = "A completely incomprehensible language." - signlang_verb = list("flails") - speech_verb = "spews" - whisper_verb = "mumbles" - exclaim_verb = "shrieks" - colour = "attack" - key = "r" // Radda radda radda - flags = RESTRICTED|NONGLOBAL - machine_understands = 0 - syllables = list ( - "radda", "fea","vea","vei","veh","vee","feh","fa","soa","su","sua","sou","se","seh","twa","twe","twi", - "ahm","lea","lee","nae","nah","pa","pau","fae","fai","soh","mou","ahe","ll","ea","ai","thi", - "hie","zei","zie","ize","ehy","uy","oya","dor","di","ja","ej","er","um","in","qu","is","re", - "nt","ti","us","it","en","at","tu","te","ri","es","et","ra","ta","an","ni","li","on","or","se", - "am","ae","ia","di","ue","em","ar","ui","st","si","de","ci","iu","ne","pe","co","os","ur","ru", - "gra","ba","ba","breh","bra","rah","dur","ra","ro","gro","go","ber","bar","geh","heh", "gra", - "a", "ai", "an", "ang", "ao", "ba", "bai", "ban", "bang", "bao", "bei", "ben", "beng", "bi", "bian", "biao", - "bie", "bin", "bing", "bo", "bu", "ca", "cai", "can", "cang", "cao", "ce", "cei", "cen", "ceng", "cha", "chai", - "chan", "chang", "chao", "che", "chen", "cheng", "chi", "chong", "chou", "chu", "chua", "chuai", "chuan", "chuang", "chui", "chun", - "chuo", "ci", "cong", "cou", "cu", "cuan", "cui", "cun", "cuo", "da", "dai", "dan", "dang", "dao", "de", "dei", - "den", "deng", "di", "dian", "diao", "die", "ding", "diu", "dong", "dou", "du", "duan", "dui", "dun", "duo", "e", - "ei", "en", "er", "fa", "fan", "fang", "fei", "fen", "feng", "fo", "fou", "fu", "ga", "gai", "gan", "gang", - "gao", "ge", "gei", "gen", "geng", "gong", "gou", "gu", "gua", "guai", "guan", "guang", "gui", "gun", "guo", "ha", - "hai", "han", "hang", "hao", "he", "hei", "hen", "heng", "hm", "hng", "hong", "hou", "hu", "hua", "huai", "huan", - "huang", "hui", "hun", "huo", "ji", "jia", "jian", "jiang", "jiao", "jie", "jin", "jing", "jiong", "jiu", "ju", "juan", - "jue", "jun", "ka", "kai", "kan", "kang", "kao", "ke", "kei", "ken", "keng", "kong", "kou", "ku", "kua", "kuai", - "kuan", "kuang", "kui", "kun", "kuo", "la", "lai", "lan", "lang", "lao", "le", "lei", "leng", "li", "lia", "lian", - "liang", "liao", "lie", "lin", "ling", "liu", "long", "lou", "lu", "luan", "lun", "luo", "ma", "mai", "man", "mang", - "mao", "me", "mei", "men", "meng", "mi", "mian", "miao", "mie", "min", "ming", "miu", "mo", "mou", "mu", "na", - "nai", "nan", "nang", "nao", "ne", "nei", "nen", "neng", "ng", "ni", "nian", "niang", "niao", "nie", "nin", "ning", - "niu", "nong", "nou", "nu", "nuan", "nuo", "o", "ou", "pa", "pai", "pan", "pang", "pao", "pei", "pen", "peng", - "pi", "pian", "piao", "pie", "pin", "ping", "po", "pou", "pu", "qi", "qia", "qian", "qiang", "qiao", "qie", "qin", - "qing", "qiong", "qiu", "qu", "quan", "que", "qun", "ran", "rang", "rao", "re", "ren", "reng", "ri", "rong", "rou", - "ru", "rua", "ruan", "rui", "run", "ruo", "sa", "sai", "san", "sang", "sao", "se", "sei", "sen", "seng", "sha", - "shai", "shan", "shang", "shao", "she", "shei", "shen", "sheng", "shi", "shou", "shu", "shua", "shuai", "shuan", "shuang", "shui", - "shun", "shuo", "si", "song", "sou", "su", "suan", "sui", "sun", "suo", "ta", "tai", "tan", "tang", "tao", "te", - "teng", "ti", "tian", "tiao", "tie", "ting", "tong", "tou", "tu", "tuan", "tui", "tun", "tuo", "wa", "wai", "wan", - "wang", "wei", "wen", "weng", "wo", "wu", "xi", "xia", "xian", "xiang", "xiao", "xie", "xin", "xing", "xiong", "xiu", - "xu", "xuan", "xue", "xun", "ya", "yan", "yang", "yao", "ye", "yi", "yin", "ying", "yong", "you", "yu", "yuan", - "yue", "yun", "za", "zai", "zan", "zang", "zao", "ze", "zei", "zen", "zeng", "zha", "zhai", "zhan", "zhang", "zhao", - "zhe", "zhei", "zhen", "zheng", "zhi", "zhong", "zhou", "zhu", "zhua", "zhuai", "zhuan", "zhuang", "zhui", "zhun", "zhuo", "zi", - "zong", "zou", "zuan", "zui", "zun", "zuo", "zu", "al", "an", "ar", "as", "at", "ea", "ed", "en", "er", "es", "ha", "he", "hi", "in", "is", "it", - "le", "me", "nd", "ne", "ng", "nt", "on", "or", "ou", "re", "se", "st", "te", "th", "ti", "to", - "ve", "wa", "all", "and", "are", "but", "ent", "era", "ere", "eve", "for", "had", "hat", "hen", "her", "hin", - "his", "ing", "ion", "ith", "not", "ome", "oul", "our", "sho", "ted", "ter", "tha", "the", "thi", - "al", "an", "ar", "as", "at", "ea", "ed", "en", "er", "es", "ha", "he", "hi", "in", "is", "it", - "le", "me", "nd", "ne", "ng", "nt", "on", "or", "ou", "re", "se", "st", "te", "th", "ti", "to", - "ve", "wa", "all", "and", "are", "but", "ent", "era", "ere", "eve", "for", "had", "hat", "hen", "her", "hin", - "his", "ing", "ion", "ith", "not", "ome", "oul", "our", "sho", "ted", "ter", "tha", "the", "thi", - "al", "an", "ar", "as", "at", "ea", "ed", "en", "er", "es", "ha", "he", "hi", "in", "is", "it", - "le", "me", "nd", "ne", "ng", "nt", "on", "or", "ou", "re", "se", "st", "te", "th", "ti", "to", - "ve", "wa", "all", "and", "are", "but", "ent", "era", "ere", "eve", "for", "had", "hat", "hen", "her", "hin", - "his", "ing", "ion", "ith", "not", "ome", "oul", "our", "sho", "ted", "ter", "tha", "the", "thi", - "al", "an", "ar", "as", "at", "ea", "ed", "en", "er", "es", "ha", "he", "hi", "in", "is", "it", - "le", "me", "nd", "ne", "ng", "nt", "on", "or", "ou", "re", "se", "st", "te", "th", "ti", "to", - "ve", "wa", "all", "and", "are", "but", "ent", "era", "ere", "eve", "for", "had", "hat", "hen", "her", "hin", - "his", "ing", "ion", "ith", "not", "ome", "oul", "our", "sho", "ted", "ter", "tha", "the", "thi", - "al", "an", "ar", "as", "at", "ea", "ed", "en", "er", "es", "ha", "he", "hi", "in", "is", "it", - "le", "me", "nd", "ne", "ng", "nt", "on", "or", "ou", "re", "se", "st", "te", "th", "ti", "to", - "ve", "wa", "all", "and", "are", "but", "ent", "era", "ere", "eve", "for", "had", "hat", "hen", "her", "hin", - "his", "ing", "ion", "ith", "not", "ome", "oul", "our", "sho", "ted", "ter", "tha", "the", "thi", - "al", "an", "ar", "as", "at", "ea", "ed", "en", "er", "es", "ha", "he", "hi", "in", "is", "it", - "le", "me", "nd", "ne", "ng", "nt", "on", "or", "ou", "re", "se", "st", "te", "th", "ti", "to", - "ve", "wa", "all", "and", "are", "but", "ent", "era", "ere", "eve", "for", "had", "hat", "hen", "her", "hin", - "his", "ing", "ion", "ith", "not", "ome", "oul", "our", "sho", "ted", "ter", "tha", "the", "thi" - ) - -/datum/language/gibberish/can_speak_special(var/mob/speaker) - return TRUE //Anyone can speak gibberish diff --git a/code/modules/language/holder.dm b/code/modules/language/holder.dm new file mode 100644 index 00000000000..6fff77632fc --- /dev/null +++ b/code/modules/language/holder.dm @@ -0,0 +1 @@ +// todo: language holder and sources diff --git a/code/modules/language/language.dm b/code/modules/language/language.dm index f4dd6b21d51..772c380e880 100644 --- a/code/modules/language/language.dm +++ b/code/modules/language/language.dm @@ -3,7 +3,11 @@ /* Datum based languages. Easily editable and modular. */ - +/** + * language datums + * + * singletons stored on SScharacters, only referenced by id most of the time. + */ /datum/language /// abstract type var/abstract_type = /datum/language @@ -14,6 +18,9 @@ var/name = "an unknown language" /// Short description for 'Check Languages'. var/desc = "A language." + // todo: sort languages into categories + /// category in UI + var/category = "General" /// 'says', 'hisses', 'farts'. var/speech_verb = "says" /// Used when sentence ends in a ? @@ -22,14 +29,14 @@ var/exclaim_verb = "exclaims" /// Optional. When not specified speech_verb + quietly/softly is used instead. var/whisper_verb - /// list of emotes that might be displayed if this language has NONVERBAL or SIGNLANG flags + /// list of emotes that might be displayed if this language has NONVERBAL or SIGNLANG language_flags var/signlang_verb = list("signs", "gestures") /// CSS style to use for strings in this language. var/colour = "body" /// Character used to speak in language eg. :o for Unathi. var/key = "x" - /// Various language flags. - var/flags = 0 + /// Various language language_flags. + var/language_flags = NONE /// If set, non-native speakers will have trouble speaking. var/native /// Used when scrambling text for a non-speaker. @@ -153,7 +160,7 @@ if(!speaker_mask) speaker_mask = speaker.name message = format_message(message, get_spoken_verb(message)) - for(var/mob/player in player_list) + for(var/mob/player in GLOB.player_list) player.hear_broadcast(src, speaker, speaker_mask, message) /mob/proc/hear_broadcast(var/datum/language/language, var/mob/speaker, var/speaker_name, var/message) @@ -186,7 +193,7 @@ if(name != "Noise") // Audible Emotes if(ishuman(speaker)) var/mob/living/carbon/human/H = speaker - if(H.species.has_organ[O_VOICE] && !(flags & SIGNLANG) && !(flags & NONVERBAL)) // Does the species need a voicebox? Is the language even spoken? + if(H.species.has_organ[O_VOICE] && !(language_flags & SIGNLANG) && !(language_flags & NONVERBAL)) // Does the species need a voicebox? Is the language even spoken? var/obj/item/organ/internal/voicebox/vocal = H.internal_organs_by_name[O_VOICE] if(!vocal || vocal.is_broken() || vocal.mute) return FALSE @@ -201,7 +208,7 @@ // Language handling. /mob/proc/add_language(var/language) - var/datum/language/new_language = GLOB.all_languages[language] + var/datum/language/new_language = SScharacters.resolve_language(language) if(!istype(new_language) || (new_language in languages)) return 0 @@ -210,12 +217,12 @@ return 1 /mob/proc/remove_language(var/rem_language) - var/datum/language/L = GLOB.all_languages[rem_language] + var/datum/language/L = SScharacters.resolve_language(rem_language) . = (L in languages) languages.Remove(L) /mob/living/remove_language(rem_language) - var/datum/language/L = GLOB.all_languages[rem_language] + var/datum/language/L = SScharacters.resolve_language(rem_language) if(default_language == L) default_language = null return ..() @@ -227,32 +234,26 @@ log_debug("[src] attempted to speak a null language.") return 0 - if(speaking == GLOB.all_languages["Noise"]) + if(speaking == SScharacters.resolve_language_name("Noise")) return 1 - if (only_species_language && speaking != GLOB.all_languages[species_language]) + if (only_species_language && speaking != SScharacters.resolve_language_name(species_language)) return 0 if(speaking.can_speak_special(src)) if(universal_speak) return 1 - if(speaking && (speaking.flags & INNATE)) + if(speaking && (speaking.language_flags & INNATE)) return 1 if(speaking in src.languages) return 1 return 0 /mob/proc/get_language_prefix() - if(client && client.prefs.language_prefixes && client.prefs.language_prefixes.len) - return client.prefs.language_prefixes[1] + return client?.prefs?.get_primary_language_prefix() || config_legacy.language_prefixes[1] - return config_legacy.language_prefixes[1] - -/mob/proc/is_language_prefix(var/prefix) - if(client && client.prefs.language_prefixes && client.prefs.language_prefixes.len) - return prefix in client.prefs.language_prefixes - - return prefix in config_legacy.language_prefixes +/mob/proc/is_language_prefix(prefix) + return client?.prefs?.is_language_prefix(prefix) || (prefix in config_legacy.language_prefixes) //TBD /mob/verb/check_languages() @@ -263,7 +264,7 @@ var/dat = "Known Languages

" for(var/datum/language/L in languages) - if(!(L.flags & NONGLOBAL)) + if(!(L.language_flags & NONGLOBAL)) dat += "[L.name] ([get_language_prefix()][L.key])
[L.desc]

" src << browse(dat, "window=checklanguage") @@ -276,7 +277,7 @@ dat += "Current default language: [default_language] - reset

" for(var/datum/language/L in languages) - if(!(L.flags & NONGLOBAL)) + if(!(L.language_flags & NONGLOBAL)) if(L == default_language) dat += "[L.name] ([get_language_prefix()][L.key]) - default - reset
[L.desc]

" else if (can_speak(L)) @@ -290,7 +291,7 @@ if(href_list["default_lang"]) if(href_list["default_lang"] == "reset") if (species_language) - set_default_language(GLOB.all_languages[species_language]) + set_default_language(SScharacters.resolve_language_name(species_language)) else set_default_language(null) else @@ -304,7 +305,7 @@ /proc/transfer_languages(var/mob/source, var/mob/target, var/except_flags) for(var/datum/language/L in source.languages) - if(L.flags & except_flags) + if(L.language_flags & except_flags) continue target.add_language(L.name) diff --git a/code/modules/language/monkey.dm b/code/modules/language/monkey.dm index cbd2e861a39..4e8c26f1233 100644 --- a/code/modules/language/monkey.dm +++ b/code/modules/language/monkey.dm @@ -1,4 +1,5 @@ /datum/language/human/monkey + id = LANGUAGE_ID_CHIMPANZEE name = "Chimpanzee" desc = "Ook ook ook." speech_verb = "chimpers" @@ -6,77 +7,33 @@ exclaim_verb = "screeches" key = "6" syllables = list("ook","eek") - flags = RESTRICTED + language_flags = RESTRICTED machine_understands = 0 /datum/language/skrell/monkey + id = LANGUAGE_ID_NEAERA name = SPECIES_MONKEY_SKRELL desc = "Squik squik squik." key = "8" syllables = list("hiss","gronk") - flags = RESTRICTED + language_flags = RESTRICTED machine_understands = 0 /datum/language/unathi/monkey + id = LANGUAGE_ID_STOK name = SPECIES_MONKEY_UNATHI desc = "Hiss hiss hiss." key = "7" syllables = list("squick","croak") - flags = RESTRICTED + language_flags = RESTRICTED machine_understands = 0 /datum/language/tajaran/monkey + id = LANGUAGE_ID_FARWA name = SPECIES_MONKEY_TAJ desc = "Meow meow meow." key = "9" syllables = list("meow","mew") - flags = RESTRICTED + language_flags = RESTRICTED machine_understands = 0 -/datum/language/corgi - name = "Dog" - desc = "Woof woof woof." - speech_verb = "barks" - ask_verb = "woofs" - exclaim_verb = "howls" - key = "n" - flags = RESTRICTED - machine_understands = 0 - space_chance = 100 - syllables = list("bark", "woof", "bowwow", "yap", "arf") - -/datum/language/cat - name = "Cat" - desc = "Meow meow meow." - speech_verb = "meows" - ask_verb = "mrowls" - exclaim_verb = "yowls" - key = "c" - flags = RESTRICTED - machine_understands = 0 - space_chance = 100 - syllables = list("meow", "mrowl", "purr", "meow", "meow", "meow") - -/datum/language/mouse - name = "Mouse" - desc = "Squeak squeak. *Nibbles on cheese*" - speech_verb = "squeaks" - ask_verb = "squeaks" - exclaim_verb = "squeaks" - key = "m" - flags = RESTRICTED - machine_understands = 0 - space_chance = 100 - syllables = list("squeak") // , "gripes", "oi", "meow") - -/datum/language/bird - name = "Bird" - desc = "Chirp chirp, give me food" - speech_verb = "chirps" - ask_verb = "tweets" - exclaim_verb = "squawks" - key = "m" - flags = RESTRICTED - machine_understands = 0 - space_chance = 100 - syllables = list("chirp", "squawk", "tweet") diff --git a/code/modules/language/outsider.dm b/code/modules/language/outsider.dm deleted file mode 100644 index 3e0a2959459..00000000000 --- a/code/modules/language/outsider.dm +++ /dev/null @@ -1,181 +0,0 @@ -/datum/language/ling - name = LANGUAGE_CHANGELING - desc = "Although they are normally wary and suspicious of each other, changelings can commune over a distance." - speech_verb = "says" - colour = "changeling" - key = "g" - machine_understands = 0 - flags = RESTRICTED | HIVEMIND - -/datum/language/ling/broadcast(var/mob/living/speaker,var/message,var/speaker_mask) - - if(speaker.mind && speaker.mind.changeling) - ..(speaker,message,speaker.mind.changeling.changelingID) - else - ..(speaker,message) - -/datum/language/corticalborer - name = "Cortical Link" - desc = "Cortical borers possess a strange link between their tiny minds." - speech_verb = "sings" - ask_verb = "sings" - exclaim_verb = "sings" - colour = "alien" - key = "" //!! THIS DOES NOT HAVE A LANGUAGE KEY IF YOU SOMEHOW MIRACULOUSLY GET ANTAGS WORKING ON RP BEFORE WE TRANSITION TO SS14 IN LIKE 2025 PUT ONE IN. - machine_understands = 0 - flags = RESTRICTED | HIVEMIND - -/datum/language/corticalborer/broadcast(var/mob/living/speaker,var/message,var/speaker_mask) - - var/mob/living/simple_mob/animal/borer/B - - if(istype(speaker,/mob/living/carbon)) - var/mob/living/carbon/M = speaker - B = M.has_brain_worms() - else if(istype(speaker,/mob/living/simple_mob/animal/borer)) - B = speaker - - if(B) - speaker_mask = B.true_name - ..(speaker,message,speaker_mask) - -/datum/language/vox - name = LANGUAGE_VOX - desc = "The common tongue of the various Vox ships making up the Shoal. It sounds like chaotic shrieking to everyone else." - speech_verb = "shrieks" - ask_verb = "creels" - exclaim_verb = "SHRIEKS" - colour = "vox" - key = "5" - flags = WHITELISTED - syllables = list("ti","ti","ti","hi","hi","ki","ki","ki","ki","ya","ta","ha","ka","ya","chi","cha","kah", \ - "SKRE","AHK","EHK","RAWK","KRA","AAA","EEE","KI","II","KRI","KA") - machine_understands = 0 - -/datum/language/vox/get_random_name() - return ..(FEMALE,1,6) - -/datum/language/squeakish - name = LANGUAGE_SQUEAKISH - desc = "A language native to the Altevians, it has been adopted by other rodent faring species over time." - key = "E" - colour = "squeakish" - speech_verb = "squeaks" - whisper_verb = "squiks" - exclaim_verb = "squeaks loudly" - syllables = list ("sque", "uik", "squeak", "squee", "eak", "eek", "uek", "squik", - "squeek", "sq", "eek", "squeee", "ee", "ek", "ak", "ueak", "squea") - machine_understands = 1 - -/datum/language/cultcommon - name = LANGUAGE_CULT - desc = "The chants of the occult, the incomprehensible." - speech_verb = "intones" - ask_verb = "intones" - exclaim_verb = "chants" - colour = "cult" - key = "f" - flags = RESTRICTED - space_chance = 100 - machine_understands = 0 - syllables = list("ire","ego","nahlizet","certum","veri","jatkaa","mgar","balaq", "karazet", "geeri", \ - "orkan", "allaq", "sas'so", "c'arta", "forbici", "tarem", "n'ath", "reth", "sh'yro", "eth", "d'raggathnor", \ - "mah'weyh", "pleggh", "at", "e'ntrath", "tok-lyr", "rqa'nap", "g'lt-ulotf", "ta'gh", "fara'qha", "fel", "d'amar det", \ - "yu'gular", "faras", "desdae", "havas", "mithum", "javara", "umathar", "uf'kal", "thenar", "rash'tla", \ - "sektath", "mal'zua", "zasan", "therium", "viortia", "kla'atu", "barada", "nikt'o", "fwe'sh", "mah", "erl", "nyag", "r'ya", \ - "gal'h'rfikk", "harfrandid", "mud'gib", "il", "fuu", "ma'jin", "dedo", "ol'btoh", "n'ath", "reth", "sh'yro", "eth", \ - "d'rekkathnor", "khari'd", "gual'te", "nikka", "nikt'o", "barada", "kla'atu", "barhah", "hra" ,"zar'garis", "spiri", "malum") - -/datum/language/cult - name = LANGUAGE_OCCULT - desc = "The initiated can share their thoughts by means defying all reason." - speech_verb = "intones" - ask_verb = "intones" - exclaim_verb = "chants" - colour = "cult" - key = "y" - machine_understands = 0 - flags = RESTRICTED | HIVEMIND - -/datum/language/xenocommon - name = SPECIES_XENO - colour = "alien" - desc = "The common tongue of the xenomorphs." - speech_verb = "hisses" - ask_verb = "hisses" - exclaim_verb = "hisses" - key = "u" - machine_understands = 0 - flags = RESTRICTED - syllables = list("sss","sSs","SSS") - -/datum/language/xenos - name = "Hivemind" - desc = "Xenomorphs have the strange ability to commune over a psychic hivemind." - speech_verb = "hisses" - ask_verb = "hisses" - exclaim_verb = "hisses" - colour = "alien" - machine_understands = 0 - key = "x" - flags = RESTRICTED | HIVEMIND - -/datum/language/xenos/check_special_condition(var/mob/other) - - var/mob/living/carbon/M = other - if(!istype(M)) - return 1 - if(locate(/obj/item/organ/internal/xenos/hivenode) in M.internal_organs) - return 1 - - return 0 - -/datum/language/swarmbot - name = LANGUAGE_SWARMBOT - desc = "A confusing mechanical language spoken by some form of ancient machine." - speech_verb = "clatters" - ask_verb = "chatters" - exclaim_verb = "shrieks" - colour = "changeling" - key = "_" - machine_understands = 0 - flags = NO_STUTTER | RESTRICTED - syllables = list("^", "v", "-", ".", "~") - space_chance = 60 - -/datum/language/squirrel - name = LANGUAGE_ECUREUILIAN - desc = "The native tongue of the inhabitants of Gaia. Squirrelkin and other beastkins of Gaia can use their ears and tails in addition to speech to communitcate." - speech_verb = "squeaks" - whisper_verb = "whispers" - exclaim_verb = "chitters" - key = "9" - syllables = list("sque","sqah","boo","beh","nweh","boopa","nah","wah","een","sweh") - - -//for your antag purposes. -/datum/language/minbus - name = LANGUAGE_MINBUS - desc = "The Powers That Be have seen it fit to grace you with a special language that sounds like Russian for some reason." - speech_verb = "says" - ask_verb = "asks" - exclaim_verb = "shouts" - colour = "deadsay" - key = "r" - machine_understands = 0 - flags = RESTRICTED - syllables = list("rus","zem","ave","groz","ski","ska","ven","konst","pol","lin","svy", - "danya","da","mied","zan","das","krem","myka","cyka","blyat","to","st","no","na","ni", - "ko","ne","en","po","ra","li","on","byl","cto","eni","ost","ol","ego","ver","stv","pro") - -//For your event purposes. -/datum/language/occursus - name = LANGUAGE_EVENT1 - desc = "The Powers That Be have seen it fit to grace you with a special language that sounds like... something. This description should be overridden by the time you see this." - speech_verb = "says" - ask_verb = "asks" - exclaim_verb = "shouts" - colour = "warning" - key = "]" - flags = RESTRICTED - syllables = list("chan","ange","thi","se") diff --git a/code/modules/language/synthetic.dm b/code/modules/language/silicons.dm similarity index 94% rename from code/modules/language/synthetic.dm rename to code/modules/language/silicons.dm index 36dd57bc692..4fec93b4049 100644 --- a/code/modules/language/synthetic.dm +++ b/code/modules/language/silicons.dm @@ -1,4 +1,5 @@ /datum/language/binary + id = LANGUAGE_ID_SILICON_BINARY name = "Robot Talk" desc = "Most human stations support free-use communications protocols and routing hubs for synthetic use." colour = "say_quote" @@ -7,7 +8,7 @@ exclaim_verb = "declares" key = "b" machine_understands = 0 - flags = RESTRICTED | HIVEMIND + language_flags = RESTRICTED | HIVEMIND var/drone_only /datum/language/binary/broadcast(var/mob/living/speaker,var/message,var/speaker_mask) @@ -58,6 +59,7 @@ R.cell_use_power(C.active_usage) /datum/language/binary/drone + id = LANGUAGE_ID_DRONE_BINARY name = "Drone Talk" desc = "A heavily encoded damage control coordination stream." speech_verb = "transmits" @@ -66,5 +68,5 @@ colour = "say_quote" key = "d" machine_understands = 0 - flags = RESTRICTED | HIVEMIND + language_flags = RESTRICTED | HIVEMIND drone_only = 1 diff --git a/code/modules/language/species/adherent.dm b/code/modules/language/species/adherent.dm new file mode 100644 index 00000000000..f9291bea536 --- /dev/null +++ b/code/modules/language/species/adherent.dm @@ -0,0 +1,16 @@ +/datum/language/adherent + id = LANGUAGE_ID_ADHERENT + name = LANGUAGE_ADHERENT + desc = "The mellifluous wind chime tones of the Vigil's formal shared language." + speech_verb = "chimes" + ask_verb = "rings" + exclaim_verb = "peals" + colour = "adherent" + key = "p" + language_flags = WHITELISTED + syllables = list("\[Ab\]", "\[Bb\]", "\[Cb\]", "\[Db\]", "\[Eb\]", "\[Fb\]", + "\[Gb\]", "\[A#\]", "\[B#\]", "\[C#\]", "\[D#\]", "\[E#\]", "\[F#\]", + "\[G#\]", "\[A\]", "\[B\]", "\[C\]", "\[D\]", "\[E\]", "\[F\]", "\[G\]", + "\[harmonic\]", "\[disharmonic\]", "\[choral\]" + ) + space_chance = 0 diff --git a/code/modules/language/species/akula.dm b/code/modules/language/species/akula.dm new file mode 100644 index 00000000000..9b9c890ea19 --- /dev/null +++ b/code/modules/language/species/akula.dm @@ -0,0 +1,12 @@ +/datum/language/akula + id = LANGUAGE_ID_AKULA + name = LANGUAGE_AKULA + desc = "The language of the Akula consists of a wildly melodic combination of hard and soft consonants working in flowing conjuncture with one another." + speech_verb = "cants" + ask_verb = "inflects" + exclaim_verb = "shouts" + whisper_verb = "murmurs" + colour = "akula" + key = "a" + space_chance = 80 + syllables = list("ko'lakou","hiki","iloko'o","o'e","kekahi","olelo","keia","'ekahi","loaa","no'ka'mea","ia","ka'mea","ko'ino", "kela", "ma", "keia", "hai aku", "paani", "hopena", "heluhelu", "mai'o", "ke'awa", "a'hiki", "nui", "maanei", "ki'eki'e", "no'ke'aha'mai", "no'i", "malamalama", "keia'ano", "ka'hale", "pono", "ki'i", "holoholona", "wahi", "makuahine", "kokoke", "makuakāne", "kekahi", "lawe", "wahi", "mahope'iho'o", "ma'popo'eka") diff --git a/code/modules/language/species/alraune.dm b/code/modules/language/species/alraune.dm new file mode 100644 index 00000000000..caa182dba1a --- /dev/null +++ b/code/modules/language/species/alraune.dm @@ -0,0 +1,13 @@ +// Alraune language that's literally just bushes rubbing together. +/datum/language/vernal + id = LANGUAGE_ID_VERNAL + name = LANGUAGE_VERNAL + desc = "An imperceptibly complex and nuanced language, often confused for the natural sounds of the forest." + signlang_verb = list("sways") + speech_verb = "rustles" + whisper_verb = "susurrus" + exclaim_verb = "crackles" + colour = "soghun" + key = "t" //Rustles susurrus crackles + syllables = list ("shh", "fssh", "rustle", "snap", "kssh", "sffh", "mssh", "creak", + "knock", "crk", "srhh", "rrssh", "sh", "hk", "fsh", "rss", "ks") diff --git a/code/modules/language/species/altevian.dm b/code/modules/language/species/altevian.dm new file mode 100644 index 00000000000..d88fe8043c4 --- /dev/null +++ b/code/modules/language/species/altevian.dm @@ -0,0 +1,12 @@ +/datum/language/squeakish + id = LANGUAGE_ID_ALTEVIAN + name = LANGUAGE_SQUEAKISH + desc = "A language native to the Altevians, it has been adopted by other rodent faring species over time." + key = "E" + colour = "squeakish" + speech_verb = "squeaks" + whisper_verb = "squiks" + exclaim_verb = "squeaks loudly" + syllables = list ("sque", "uik", "squeak", "squee", "eak", "eek", "uek", "squik", + "squeek", "sq", "eek", "squeee", "ee", "ek", "ak", "ueak", "squea") + machine_understands = 1 diff --git a/code/modules/language/species/birdsong.dm b/code/modules/language/species/birdsong.dm new file mode 100644 index 00000000000..62a835ef4cd --- /dev/null +++ b/code/modules/language/species/birdsong.dm @@ -0,0 +1,10 @@ +/datum/language/birdsong + id = LANGUAGE_ID_BIRDSONG + name = LANGUAGE_BIRDSONG + desc = "A language primarily spoken by Narvians" + speech_verb = "chirps" + colour = "birdsongc" + key = "7" + syllables = list ("cheep", "peep", "tweet") + +// todo: wtf is this diff --git a/code/modules/language/species/celestial.dm b/code/modules/language/species/celestial.dm new file mode 100644 index 00000000000..760c6d1e152 --- /dev/null +++ b/code/modules/language/species/celestial.dm @@ -0,0 +1,25 @@ +/datum/language/demon + id = LANGUAGE_ID_DAEDAL_DREMACHIR + name = LANGUAGE_DAEMON + desc = "The language spoken by the demons of Infernum, it's composed of deep chanting. It's rarely spoken off of Infernum due to the volume one has to exert." + speech_verb = "chants" + ask_verb = "croons" + exclaim_verb = "incants" + colour = "daemon" //So fancy + key = "n" + syllables = list("viepn","e","bag","docu","kar","xlaqf","raa","qwos","nen","ty","von","kytaf","xin","ty","ka","baak","hlafaifpyk","znu","agrith","na'ar","uah","plhu","six","fhler","bjel","scee","lleri", + "dttm","aggr","uujl","hjjifr","wwuthaav",) + machine_understands = FALSE + +/datum/language/angel + id = LANGUAGE_ID_DAEDAL_AURIL + name = LANGUAGE_ENOCHIAN + desc = "The graceful language spoken by angels, composed of quiet hymns. Formally, Angels sing it." + speech_verb = "sings" + ask_verb = "hums" + exclaim_verb = "loudly sings" + colour = "enochian" //So fancy + key = "i" + syllables = list("salve","sum","loqui","operatur","iusta","et","permittit","facere","effercio","pluribus","enim","hoc", + "mihi","wan","six","tartu") + machine_understands = FALSE diff --git a/code/modules/language/species/diona.dm b/code/modules/language/species/diona.dm new file mode 100644 index 00000000000..c173ad893ee --- /dev/null +++ b/code/modules/language/species/diona.dm @@ -0,0 +1,25 @@ +/datum/language/diona_local + id = LANGUAGE_ID_DIONA + name = LANGUAGE_ROOTLOCAL + desc = "A complex language known instinctively by Dionaea, 'spoken' by emitting modulated radio waves. This version uses high frequency waves for quick communication at short ranges." + speech_verb = "creaks and rustles" + ask_verb = "creaks" + exclaim_verb = "rustles" + colour = "soghun" + key = "q" + machine_understands = 0 + language_flags = RESTRICTED + syllables = list("hs","zt","kr","st","sh") + +/datum/language/diona_local/get_random_name() + var/new_name = "[pick(list("To Sleep Beneath","Wind Over","Embrace of","Dreams of","Witnessing","To Walk Beneath","Approaching the"))]" + new_name += " [pick(list("the Void","the Sky","Encroaching Night","Planetsong","Starsong","the Wandering Star","the Empty Day","Daybreak","Nightfall","the Rain"))]" + return new_name + +/datum/language/diona_global + id = LANGUAGE_ID_DIONA_HIVEMIND + name = LANGUAGE_ROOTGLOBAL + desc = "A complex language known instinctively by Dionaea, 'spoken' by emitting modulated radio waves. This version uses low frequency waves for slow communication at long ranges." + key = "w" + machine_understands = 0 + language_flags = RESTRICTED | HIVEMIND diff --git a/code/modules/language/species/human.dm b/code/modules/language/species/human.dm new file mode 100644 index 00000000000..0a552185af3 --- /dev/null +++ b/code/modules/language/species/human.dm @@ -0,0 +1,124 @@ +/datum/language/human + id = LANGUAGE_ID_HUMAN + name = LANGUAGE_SOL_COMMON + desc = "A bastardized hybrid of many languages, including Chinese, English, French, and more; it is the common language of the Sol system." + speech_verb = "says" + whisper_verb = "whispers" + exclaim_verb = list("exclaims","shouts","yells") + colour = "solcom" + key = "1" + //syllables are at the bottom of the file + +/datum/language/human/get_random_name(gender) + if (prob(80)) + if(gender==FEMALE) + return capitalize(pick(GLOB.first_names_female)) + " " + capitalize(pick(GLOB.last_names)) + else + return capitalize(pick(GLOB.first_names_male)) + " " + capitalize(pick(GLOB.last_names)) + else + return ..() + +/datum/language/slavic + id = LANGUAGE_ID_HUMAN_SLAVIC + name = LANGUAGE_SLAVIC + desc = "Was established in 2122 by the short-lived United Slavic Confederation on Earth." + colour = "solcom" + key = "g" + syllables = list( + "rus", "zem", "ave", "groz", "ski", "ska", "ven", "konst", "pol", "lin", "svy", + "danya", "da", "mied", "zan", "das", "krem", "myka", "to", "st", "no", "na", "ni", + "ko", "ne", "en", "po", "ra", "li", "on", "byl", "cto", "eni", "ost", "ol", "ego", + "ver", "stv", "pro" + ) + +//Syllable Lists +/* + This list really long, mainly because I can't make up my mind about which mandarin syllables should be removed, + and the english syllables had to be duplicated so that there is roughly a 50-50 weighting. + The other 3 languages were duplicated just so they could show occasionally. + + Sources: + http://www.sttmedia.com/syllablefrequency-english + http://www.sttmedia.com/syllablefrequency-spanish + http://www.sttmedia.com/syllablefrequency-russian + http://www.sttmedia.com/syllablefrequency-french + http://www.chinahighlights.com/travelguide/learning-chinese/pinyin-syllables.htm +*/ +/datum/language/human/syllables = list( +"a", "ai", "an", "ang", "ao", "ba", "bai", "ban", "bang", "bao", "bei", "ben", "beng", "bi", "bian", "biao", +"bie", "bin", "bing", "bo", "bu", "ca", "cai", "can", "cang", "cao", "ce", "cei", "cen", "ceng", "cha", "chai", +"chan", "chang", "chao", "che", "chen", "cheng", "chi", "chong", "chou", "chu", "chua", "chuai", "chuan", "chuang", "chui", "chun", +"chuo", "ci", "cong", "cou", "cu", "cuan", "cui", "cun", "cuo", "da", "dai", "dan", "dang", "dao", "de", "dei", +"den", "deng", "di", "dian", "diao", "die", "ding", "diu", "dong", "dou", "du", "duan", "dui", "dun", "duo", "e", +"ei", "en", "er", "fa", "fan", "fang", "fei", "fen", "feng", "fo", "fou", "fu", "ga", "gai", "gan", "gang", +"gao", "ge", "gei", "gen", "geng", "gong", "gou", "gu", "gua", "guai", "guan", "guang", "gui", "gun", "guo", "ha", +"hai", "han", "hang", "hao", "he", "hei", "hen", "heng", "hm", "hng", "hong", "hou", "hu", "hua", "huai", "huan", +"huang", "hui", "hun", "huo", "ji", "jia", "jian", "jiang", "jiao", "jie", "jin", "jing", "jiong", "jiu", "ju", "juan", +"jue", "jun", "ka", "kai", "kan", "kang", "kao", "ke", "kei", "ken", "keng", "kong", "kou", "ku", "kua", "kuai", +"kuan", "kuang", "kui", "kun", "kuo", "la", "lai", "lan", "lang", "lao", "le", "lei", "leng", "li", "lia", "lian", +"liang", "liao", "lie", "lin", "ling", "liu", "long", "lou", "lu", "luan", "lun", "luo", "ma", "mai", "man", "mang", +"mao", "me", "mei", "men", "meng", "mi", "mian", "miao", "mie", "min", "ming", "miu", "mo", "mou", "mu", "na", +"nai", "nan", "nang", "nao", "ne", "nei", "nen", "neng", "ng", "ni", "nian", "niang", "niao", "nie", "nin", "ning", +"niu", "nong", "nou", "nu", "nuan", "nuo", "o", "ou", "pa", "pai", "pan", "pang", "pao", "pei", "pen", "peng", +"pi", "pian", "piao", "pie", "pin", "ping", "po", "pou", "pu", "qi", "qia", "qian", "qiang", "qiao", "qie", "qin", +"qing", "qiong", "qiu", "qu", "quan", "que", "qun", "ran", "rang", "rao", "re", "ren", "reng", "ri", "rong", "rou", +"ru", "rua", "ruan", "rui", "run", "ruo", "sa", "sai", "san", "sang", "sao", "se", "sei", "sen", "seng", "sha", +"shai", "shan", "shang", "shao", "she", "shei", "shen", "sheng", "shi", "shou", "shu", "shua", "shuai", "shuan", "shuang", "shui", +"shun", "shuo", "si", "song", "sou", "su", "suan", "sui", "sun", "suo", "ta", "tai", "tan", "tang", "tao", "te", +"teng", "ti", "tian", "tiao", "tie", "ting", "tong", "tou", "tu", "tuan", "tui", "tun", "tuo", "wa", "wai", "wan", +"wang", "wei", "wen", "weng", "wo", "wu", "xi", "xia", "xian", "xiang", "xiao", "xie", "xin", "xing", "xiong", "xiu", +"xu", "xuan", "xue", "xun", "ya", "yan", "yang", "yao", "ye", "yi", "yin", "ying", "yong", "you", "yu", "yuan", +"yue", "yun", "za", "zai", "zan", "zang", "zao", "ze", "zei", "zen", "zeng", "zha", "zhai", "zhan", "zhang", "zhao", +"zhe", "zhei", "zhen", "zheng", "zhi", "zhong", "zhou", "zhu", "zhua", "zhuai", "zhuan", "zhuang", "zhui", "zhun", "zhuo", "zi", +"zong", "zou", "zuan", "zui", "zun", "zuo", "zu", +"al", "an", "ar", "as", "at", "ea", "ed", "en", "er", "es", "ha", "he", "hi", "in", "is", "it", +"le", "me", "nd", "ne", "ng", "nt", "on", "or", "ou", "re", "se", "st", "te", "th", "ti", "to", +"ve", "wa", "all", "and", "are", "but", "ent", "era", "ere", "eve", "for", "had", "hat", "hen", "her", "hin", +"his", "ing", "ion", "ith", "not", "ome", "oul", "our", "sho", "ted", "ter", "tha", "the", "thi", +"al", "an", "ar", "as", "at", "ea", "ed", "en", "er", "es", "ha", "he", "hi", "in", "is", "it", +"le", "me", "nd", "ne", "ng", "nt", "on", "or", "ou", "re", "se", "st", "te", "th", "ti", "to", +"ve", "wa", "all", "and", "are", "but", "ent", "era", "ere", "eve", "for", "had", "hat", "hen", "her", "hin", +"his", "ing", "ion", "ith", "not", "ome", "oul", "our", "sho", "ted", "ter", "tha", "the", "thi", +"al", "an", "ar", "as", "at", "ea", "ed", "en", "er", "es", "ha", "he", "hi", "in", "is", "it", +"le", "me", "nd", "ne", "ng", "nt", "on", "or", "ou", "re", "se", "st", "te", "th", "ti", "to", +"ve", "wa", "all", "and", "are", "but", "ent", "era", "ere", "eve", "for", "had", "hat", "hen", "her", "hin", +"his", "ing", "ion", "ith", "not", "ome", "oul", "our", "sho", "ted", "ter", "tha", "the", "thi", +"al", "an", "ar", "as", "at", "ea", "ed", "en", "er", "es", "ha", "he", "hi", "in", "is", "it", +"le", "me", "nd", "ne", "ng", "nt", "on", "or", "ou", "re", "se", "st", "te", "th", "ti", "to", +"ve", "wa", "all", "and", "are", "but", "ent", "era", "ere", "eve", "for", "had", "hat", "hen", "her", "hin", +"his", "ing", "ion", "ith", "not", "ome", "oul", "our", "sho", "ted", "ter", "tha", "the", "thi", +"al", "an", "ar", "as", "at", "ea", "ed", "en", "er", "es", "ha", "he", "hi", "in", "is", "it", +"le", "me", "nd", "ne", "ng", "nt", "on", "or", "ou", "re", "se", "st", "te", "th", "ti", "to", +"ve", "wa", "all", "and", "are", "but", "ent", "era", "ere", "eve", "for", "had", "hat", "hen", "her", "hin", +"his", "ing", "ion", "ith", "not", "ome", "oul", "our", "sho", "ted", "ter", "tha", "the", "thi", +"al", "an", "ar", "as", "at", "ea", "ed", "en", "er", "es", "ha", "he", "hi", "in", "is", "it", +"le", "me", "nd", "ne", "ng", "nt", "on", "or", "ou", "re", "se", "st", "te", "th", "ti", "to", +"ve", "wa", "all", "and", "are", "but", "ent", "era", "ere", "eve", "for", "had", "hat", "hen", "her", "hin", +"his", "ing", "ion", "ith", "not", "ome", "oul", "our", "sho", "ted", "ter", "tha", "the", "thi", +"ah", "be", "bo", "eh", "ep", "et", "ka", "ko", "ha", "he", "ho", "ob", "oh", "op", "oc", "ot", "pa", "pe", "ct", "ta", "te", "to", +"vse", "tak", "nak", "no", "epo", "pre", "kan", "dly", "ime", "sha", "kur", "yey", "khi", "yeg", "ne", +"ion", "ne", "nas", "v", +"ah", "be", "bo", "eh", "ep", "et", "ka", "ko", "ha", "he", "ho", "ob", "oh", "op", "oc", "ot", "pa", "pe", "ct", "ta", "te", "to", +"vse", "tak", "nak", "no", "epo", "pre", "kan", "dly", "ime", "sha", "kur", "yey", "khi", "yeg", "ne", +"ion", "ne", "nas", "v", +"ah", "be", "bo", "eh", "ep", "et", "ka", "ko", "ha", "he", "ho", "ob", "oh", "op", "oc", "ot", "pa", "pe", "ct", "ta", "te", "to", +"vse", "tak", "nak", "no", "epo", "pre", "kan", "dly", "ime", "sha", "kur", "yey", "khi", "yeg", "ne", +"ion", "ne", "nas", "v", +"ai", "an", "ar", "au", "ce", "ch", "co", "de", "em", "en", "er", "es", "et", "eu", "il", "in", "is", "la", "le", +"ma", "me", "ne", "ns", "nt", "on", "ou", "pa", "qu", "ra", "re", "se", "te", "ti", "tr", "ue", "ur", "us", "ve", +"tou", "e", "eve", "hen", "son", "non", "not", "le", +"ai", "an", "ar", "au", "ce", "ch", "co", "de", "em", "en", "er", "es", "et", "eu", "il", "in", "is", "la", "le", +"ma", "me", "ne", "ns", "nt", "on", "ou", "pa", "qu", "ra", "re", "se", "te", "ti", "tr", "ue", "ur", "us", "ve", +"tou", "e", "eve", "hen", "son", "non", "not", "le", +"ai", "an", "ar", "au", "ce", "ch", "co", "de", "em", "en", "er", "es", "et", "eu", "il", "in", "is", "la", "le", +"ma", "me", "ne", "ns", "nt", "on", "ou", "pa", "qu", "ra", "re", "se", "te", "ti", "tr", "ue", "ur", "us", "ve", +"tou", "e", "eve", "hen", "son", "non", "not", "le", +"ad", "al", "an", "ar", "as", "ci", "co", "de", "do", "el", "en", "er", "es", "ie", "in", "la", "lo", "me", "na", +"no", "nt", "or", "os", "pa", "qu", "ra", "re", "ro", "se", "st", "ta", "te", "to", "ue", "un", +"tod", "ser", "su", "no", "nue", "el", +"ad", "al", "an", "ar", "as", "ci", "co", "de", "do", "el", "en", "er", "es", "ie", "in", "la", "lo", "me", "na", +"no", "nt", "or", "os", "pa", "qu", "ra", "re", "ro", "se", "st", "ta", "te", "to", "ue", "un", +"tod", "ser", "su", "no", "nue", "el", +"ad", "al", "an", "ar", "as", "ci", "co", "de", "do", "el", "en", "er", "es", "ie", "in", "la", "lo", "me", "na", +"no", "nt", "or", "os", "pa", "qu", "ra", "re", "ro", "se", "st", "ta", "te", "to", "ue", "un", +"tod", "ser", "su", "no", "nue", "el") diff --git a/code/modules/language/species/moth.dm b/code/modules/language/species/moth.dm index dd80d1ef84e..c9a5270a251 100644 --- a/code/modules/language/species/moth.dm +++ b/code/modules/language/species/moth.dm @@ -1,4 +1,5 @@ /datum/language/species/moth + id = LANGUAGE_ID_LUINIMMA name = LANGUAGE_LUINIMMA desc = "The language of the Dnin-Nepids, Luinimma sounds like a quick, tonal series of chitters, chirps, and clicks to \ non-speakers." @@ -10,7 +11,7 @@ colour = "luinimma" key = "e" native = TRUE - flags = NONE + language_flags = NONE syllables = list( "at", "az", "ak", "afz", "bv", "bz", diff --git a/code/modules/language/species/naramadi.dm b/code/modules/language/species/naramadi.dm new file mode 100644 index 00000000000..48510861a6a --- /dev/null +++ b/code/modules/language/species/naramadi.dm @@ -0,0 +1,9 @@ +/datum/language/sergal + id = LANGUAGE_ID_NARAMADI + // todo: papalus go replace the sergal text + name = LANGUAGE_SAGARU + desc = "The dominant language of the Sergal homeworld, Vilous. It consists of aggressive low-pitched hissing and throaty growling." + speech_verb = "snarls" + colour = "sergal" + key = "T" + syllables = list ("grr", "gah", "woof", "arf", "arra", "rah", "wor", "sarg") diff --git a/code/modules/language/species/phoronoid.dm b/code/modules/language/species/phoronoid.dm new file mode 100644 index 00000000000..2b925cb9986 --- /dev/null +++ b/code/modules/language/species/phoronoid.dm @@ -0,0 +1,10 @@ +/datum/language/bones + id = LANGUAGE_ID_PHORONOID + name = LANGUAGE_BONES + desc = "The language of skeletons, characterised by clunks and clatters. Native language of Phoronoids." + speech_verb = "rattles" + ask_verb = "clinks" + exclaim_verb = "clunks" + colour = "changeling" + key = "c" + syllables = list("clatter","tink","chink","clack","rattle","clink","clunk","dink","tonk","donk","plink,","plonk") diff --git a/code/modules/language/species/shadekin.dm b/code/modules/language/species/shadekin.dm new file mode 100644 index 00000000000..869f91924ee --- /dev/null +++ b/code/modules/language/species/shadekin.dm @@ -0,0 +1,11 @@ +/datum/language/shadekin + id = LANGUAGE_ID_SHADEKIN_HIVEMIND + name = LANGUAGE_SHADEKIN + desc = "Shadekin seem to always know what the others are thinking. This is probably why." + speech_verb = "mars" + ask_verb = "mars" + exclaim_verb = "mars" + colour = "changeling" + key = "m" + machine_understands = FALSE + language_flags = WHITELISTED | HIVEMIND diff --git a/code/modules/language/species/skrell.dm b/code/modules/language/species/skrell.dm new file mode 100644 index 00000000000..63b9f06851f --- /dev/null +++ b/code/modules/language/species/skrell.dm @@ -0,0 +1,32 @@ +/datum/language/skrell + id = LANGUAGE_ID_SKRELL + name = LANGUAGE_SKRELLIAN + desc = "A set of warbles and hums, the language itself a complex mesh of both melodic and rhythmic components, exceptionally capable of conveying intent and emotion of the speaker." + speech_verb = "warbles" + ask_verb = "warbles" + exclaim_verb = "sings" + whisper_verb = "hums" + colour = "skrell" + key = "k" + space_chance = 30 + syllables = list("qr","qrr","xuq","qil","quum","xuqm","vol","xrim","zaoo","qu-uu","qix","qoo","zix") + + +/datum/language/skrellfar + id = LANGUAGE_ID_SKRELL_ALT + name = LANGUAGE_SKRELLIANFAR + desc = "The most common language among the Skrellian Far Kingdoms. Has an even higher than usual concentration of inaudible phonemes." + speech_verb = "warbles" + ask_verb = "warbles" + exclaim_verb = "sings" + whisper_verb = "hums" + colour = "skrellfar" + key = "p" + space_chance = 30 + language_flags = WHITELISTED + syllables = list("qr","qrr","xuq","qil","quum","xuqm","vol","xrim","zaoo","qu-uu","qix","qoo","zix", "...", "oo", "q", "nq", "x", "xq", "ll", "...", "...", "...") //should sound like there's holes in it + +/datum/language/skrell/get_random_name(gender) + var/list/first_name = GLOB.skrell_first_names + var/list/last_name = GLOB.skrell_last_names + return "[pick(first_name)] [pick(last_name)]" diff --git a/code/modules/language/species/tajaran.dm b/code/modules/language/species/tajaran.dm new file mode 100644 index 00000000000..71b261f3604 --- /dev/null +++ b/code/modules/language/species/tajaran.dm @@ -0,0 +1,59 @@ +/datum/language/tajaran + id = LANGUAGE_ID_TAJARAN + name = LANGUAGE_SIIK + desc = "The most prevalant language of Meralar, composed of expressive yowls and chirps. Native to the Tajaran." + speech_verb = "mrowls" + ask_verb = "mrowls" + exclaim_verb = "yowls" + colour = "tajaran" + key = "j" + syllables = list("mrr","rr","tajr","kir","raj","kii","mir","kra","ahk","nal","vah","khaz","jri","ran","darr", + "mi","jri","dynh","manq","rhe","zar","rrhaz","kal","chur","eech","thaa","dra","jurl","mah","sanu","dra","ii'r", + "ka","aasi","far","wa","baq","ara","qara","zir","saam","mak","hrar","nja","rir","khan","jun","dar","rik","kah", + "hal","ket","jurl","mah","tul","cresh","azu","ragh","mro","mra","mrro","mrra") + +/datum/language/tajaran/get_random_name(var/gender) + var/new_name = ..(gender,1) + if(prob(50)) + new_name += " [pick(list("Hadii","Kaytam","Nazkiin","Zhan-Khazan","Hharar","Njarir'Akhan","Faaira'Nrezi","Rhezar","Mi'dynh","Rrhazkal","Bayan","Al'Manq","Mi'jri","Chur'eech","Sanu'dra","Ii'rka"))]" + else + new_name += " [..(gender,1)]" + return new_name + +/datum/language/tajaranakhani + id = LANGUAGE_ID_TAJARAN_ALT + name = LANGUAGE_AKHANI + desc = "The language of the sea-faring Njarir'Akhan Tajaran. Borrowing some elements from Siik, the language is distinctly more structured." + speech_verb = "chatters" + ask_verb = "mrowls" + exclaim_verb = "wails" + colour = "akhani" + key = "h" + language_flags = WHITELISTED + syllables = list("mrr","rr","marr","tar","ahk","ket","hal","kah","dra","nal","kra","vah","dar","hrar", "eh", + "ara","ka","zar","mah","ner","zir","mur","hai","raz","ni","ri","nar","njar","jir","ri","ahn","kha","sir", + "kar","yar","kzar","rha","hrar","err","fer","rir","rar","yarr","arr","ii'r","jar","kur","ran","rii","ii", + "nai","ou","kah","oa","ama","uuk","bel","chi","ayt","kay","kas","akor","tam","yir","enai") + +/datum/language/tajsign + id = LANGUAGE_ID_TAJARAN_SIGN + name = LANGUAGE_ALAI + desc = "A standardized Tajaran sign language that was developed in Zarraya and gradually adopted by other nations, incorporating \ + hand gestures and movements of the ears and tail." + signlang_verb = list("gestures with their hands", "gestures with their ears and tail", "gestures with their ears, tail and hands") + colour = "tajaran" + key = "l" + language_flags = WHITELISTED | SIGNLANG | NO_STUTTER | NONVERBAL + +/datum/language/tajsign/can_speak_special(var/mob/speaker) // TODO: If ever we make external organs assist languages, convert this over to the new format + var/list/allowed_species = list(SPECIES_TAJ, SPECIES_TESHARI) // Need a tail and ears and such to use this. + if(iscarbon(speaker)) + var/obj/item/organ/external/hand/hands = locate() in speaker //you can't sign without hands + if(!hands) + return FALSE + if(ishuman(speaker)) + var/mob/living/carbon/human/H = speaker + if(H.species.get_bodytype_legacy(H) in allowed_species) + return TRUE + + return FALSE diff --git a/code/modules/language/species/teshari.dm b/code/modules/language/species/teshari.dm new file mode 100644 index 00000000000..35688127597 --- /dev/null +++ b/code/modules/language/species/teshari.dm @@ -0,0 +1,18 @@ +/datum/language/teshari + id = LANGUAGE_ID_TESHARI + name = LANGUAGE_SCHECHI + desc = "A trilling language spoken by the diminutive Teshari." + speech_verb = "chirps" + ask_verb = "chirrups" + exclaim_verb = "trills" + colour = "alien" + key = "v" + space_chance = 50 + syllables = list( + "ca", "ra", "ma", "sa", "na", "ta", "la", "sha", "scha", "a", "a", + "ce", "re", "me", "se", "ne", "te", "le", "she", "sche", "e", "e", + "ci", "ri", "mi", "si", "ni", "ti", "li", "shi", "schi", "i", "i" + ) + +/datum/language/teshari/get_random_name(gender) + return ..(gender, 2, 4, 1.5) diff --git a/code/modules/language/species/unathi.dm b/code/modules/language/species/unathi.dm new file mode 100644 index 00000000000..0de7937c9b0 --- /dev/null +++ b/code/modules/language/species/unathi.dm @@ -0,0 +1,27 @@ +/datum/language/unathi + id = LANGUAGE_ID_UNATHI + name = LANGUAGE_UNATHI + desc = "The common language of the Moghes Hegemony, composed of sibilant hisses and rattles. Spoken natively by Unathi." + speech_verb = "hisses" + ask_verb = "hisses" + exclaim_verb = "roars" + colour = "soghun" + key = "o" + space_chance = 40 + syllables = list( + "za", "az", "ze", "ez", "zi", "iz", "zo", "oz", "zu", "uz", "zs", "sz", + "ha", "ah", "he", "eh", "hi", "ih", "ho", "oh", "hu", "uh", "hs", "sh", + "la", "al", "le", "el", "li", "il", "lo", "ol", "lu", "ul", "ls", "sl", + "ka", "ak", "ke", "ek", "ki", "ik", "ko", "ok", "ku", "uk", "ks", "sk", + "sa", "as", "se", "es", "si", "is", "so", "os", "su", "us", "ss", "ss", + "ra", "ar", "re", "er", "ri", "ir", "ro", "or", "ru", "ur", "rs", "sr", + "a", "a", "e", "e", "i", "i", "o", "o", "u", "u", "s", "s" + ) + +/datum/language/unathi/get_random_name() + + var/new_name = ..() + while(findtextEx(new_name,"sss",1,null)) + new_name = replacetext(new_name, "sss", "ss") + return capitalize(new_name) + diff --git a/code/modules/language/species/vasilissan.dm b/code/modules/language/species/vasilissan.dm new file mode 100644 index 00000000000..4d4a1fb544c --- /dev/null +++ b/code/modules/language/species/vasilissan.dm @@ -0,0 +1,12 @@ +/datum/language/bug + id = LANGUAGE_ID_VASILISSAN + name = LANGUAGE_VESPINAE + desc = "A jarring and clicky language developed and used by Vasilissans, it is designed for use with mouthparts and as a result has become a common language for various arthropod species." + speech_verb = "clicks" + ask_verb = "chitters" + exclaim_verb = "rasps" + colour = "bug" + key = "x" + syllables = list("vaur","uyek","uyit","avek","sc'theth","k'ztak","teth","wre'ge","lii","dra'","zo'","ra'","kax'","zz","vh","ik","ak", + "uhk","zir","sc'orth","sc'er","thc'yek","th'zirk","th'esk","k'ayek","ka'mil","sc'","ik'yir","yol","kig","k'zit","'","'","zrk","krg","isk'yet","na'k", + "sc'azz","th'sc","nil","n'ahk","sc'yeth","aur'sk","iy'it","azzg","a'","i'","o'","u'","a","i","o","u","zz","kr","ak","nrk","tzzk","bz","xic'","k'lax'","histh") diff --git a/code/modules/language/species/vox.dm b/code/modules/language/species/vox.dm new file mode 100644 index 00000000000..89d1fd1b4ff --- /dev/null +++ b/code/modules/language/species/vox.dm @@ -0,0 +1,16 @@ +/datum/language/vox + id = LANGUAGE_ID_VOX + name = LANGUAGE_VOX + desc = "The common tongue of the various Vox ships making up the Shoal. It sounds like chaotic shrieking to everyone else." + speech_verb = "shrieks" + ask_verb = "creels" + exclaim_verb = "SHRIEKS" + colour = "vox" + key = "5" + language_flags = WHITELISTED + syllables = list("ti","ti","ti","hi","hi","ki","ki","ki","ki","ya","ta","ha","ka","ya","chi","cha","kah", \ + "SKRE","AHK","EHK","RAWK","KRA","AAA","EEE","KI","II","KRI","KA") + machine_understands = 0 + +/datum/language/vox/get_random_name() + return ..(FEMALE,1,6) diff --git a/code/modules/language/species/vulpkanin.dm b/code/modules/language/species/vulpkanin.dm new file mode 100644 index 00000000000..3fcdd93ed98 --- /dev/null +++ b/code/modules/language/species/vulpkanin.dm @@ -0,0 +1,13 @@ +/datum/language/vulpkanin + id = LANGUAGE_ID_VULPKANIN + name = LANGUAGE_CANILUNZT + desc = "The guttural language spoken and utilized by the inhabitants of Vazzend system, composed of growls, barks, yaps, and heavy utilization of ears and tail movements. Vulpkanin speak this language with ease." + speech_verb = "rrrfts" + ask_verb = "rurs" + exclaim_verb = "barks" + colour = "vulpkanin" + key = "8" + syllables = list("rur","ya","cen","rawr","bar","kuk","tek","qat","uk","wu","vuh","tah","tch","schz","auch", \ + "ist","ein","entch","zwichs","tut","mir","wo","bis","es","vor","nic","gro","lll","enem","zandt","tzch","noch", \ + "hel","ischt","far","wa","baram","iereng","tech","lach","sam","mak","lich","gen","or","ag","eck","gec","stag","onn", \ + "bin","ket","jarl","vulf","einech","cresthz","azunein","ghzth") diff --git a/code/modules/language/species/zaddat.dm b/code/modules/language/species/zaddat.dm new file mode 100644 index 00000000000..c7150bf8a6a --- /dev/null +++ b/code/modules/language/species/zaddat.dm @@ -0,0 +1,11 @@ +/datum/language/zaddat + id = LANGUAGE_ID_ZADDAT + name = LANGUAGE_ZADDAT + desc = "A harsh buzzing language created by the Zaddat following their exodus from their homeworld." + speech_verb = "buzzes" + ask_verb = "buzzes" + exclaim_verb = "croaks" + colour = "zaddat" + key = "z" + space_chance = 20 + syllables = list("z", "dz", "i", "iv", "ti", "az", "hix", "xo", "av", "xo", "x", "za", "at", "vi") diff --git a/code/modules/language/species/zorren.dm b/code/modules/language/species/zorren.dm new file mode 100644 index 00000000000..392f740e875 --- /dev/null +++ b/code/modules/language/species/zorren.dm @@ -0,0 +1,11 @@ +/datum/language/terminus + id = LANGUAGE_ID_TERMINUS + name = LANGUAGE_TERMINUS + desc = "A group of languages spoken by the Zorren with a certain degree of mutual intelligibility under each other. Evidence shows it was a single lingua franca which has diverged into many sub languages due to isolation." + speech_verb = "mentions" + exclaim_verb = "insinuates" + colour = "terminus" + key = "4" + syllables = list (".a", "spa", "pan", "blaif", "stra", "!u", "!ei", "!am", "by", ".y", "gry", "zbly", "!y", "fl", + "sm", "rn", "cpi", "ku", "koi", "pr", "glau", "stu", "ved", "ki", "tsa", "xau", "jbu", "sny", "stro", "nu", + "uan", "ju", "!i", "ge", "luk", "an", "ar", "at", "es", "et", "bel", "ki", "jaa", "ch", "ki", "gh", "ll", "uu", "wat") diff --git a/code/modules/language/station.dm b/code/modules/language/station.dm deleted file mode 100644 index 159aced12c2..00000000000 --- a/code/modules/language/station.dm +++ /dev/null @@ -1,422 +0,0 @@ -/datum/language/diona_local - name = LANGUAGE_ROOTLOCAL - desc = "A complex language known instinctively by Dionaea, 'spoken' by emitting modulated radio waves. This version uses high frequency waves for quick communication at short ranges." - speech_verb = "creaks and rustles" - ask_verb = "creaks" - exclaim_verb = "rustles" - colour = "soghun" - key = "q" - machine_understands = 0 - flags = RESTRICTED - syllables = list("hs","zt","kr","st","sh") - -/datum/language/diona_local/get_random_name() - var/new_name = "[pick(list("To Sleep Beneath","Wind Over","Embrace of","Dreams of","Witnessing","To Walk Beneath","Approaching the"))]" - new_name += " [pick(list("the Void","the Sky","Encroaching Night","Planetsong","Starsong","the Wandering Star","the Empty Day","Daybreak","Nightfall","the Rain"))]" - return new_name - -/datum/language/diona_global - name = LANGUAGE_ROOTGLOBAL - desc = "A complex language known instinctively by Dionaea, 'spoken' by emitting modulated radio waves. This version uses low frequency waves for slow communication at long ranges." - key = "w" - machine_understands = 0 - flags = RESTRICTED | HIVEMIND - -/datum/language/unathi - name = LANGUAGE_UNATHI - desc = "The common language of the Moghes Hegemony, composed of sibilant hisses and rattles. Spoken natively by Unathi." - speech_verb = "hisses" - ask_verb = "hisses" - exclaim_verb = "roars" - colour = "soghun" - key = "o" - space_chance = 40 - syllables = list( - "za", "az", "ze", "ez", "zi", "iz", "zo", "oz", "zu", "uz", "zs", "sz", - "ha", "ah", "he", "eh", "hi", "ih", "ho", "oh", "hu", "uh", "hs", "sh", - "la", "al", "le", "el", "li", "il", "lo", "ol", "lu", "ul", "ls", "sl", - "ka", "ak", "ke", "ek", "ki", "ik", "ko", "ok", "ku", "uk", "ks", "sk", - "sa", "as", "se", "es", "si", "is", "so", "os", "su", "us", "ss", "ss", - "ra", "ar", "re", "er", "ri", "ir", "ro", "or", "ru", "ur", "rs", "sr", - "a", "a", "e", "e", "i", "i", "o", "o", "u", "u", "s", "s" - ) - -/datum/language/unathi/get_random_name() - - var/new_name = ..() - while(findtextEx(new_name,"sss",1,null)) - new_name = replacetext(new_name, "sss", "ss") - return capitalize(new_name) - -/datum/language/tajaran - name = LANGUAGE_SIIK - desc = "The most prevalant language of Meralar, composed of expressive yowls and chirps. Native to the Tajaran." - speech_verb = "mrowls" - ask_verb = "mrowls" - exclaim_verb = "yowls" - colour = "tajaran" - key = "j" - syllables = list("mrr","rr","tajr","kir","raj","kii","mir","kra","ahk","nal","vah","khaz","jri","ran","darr", - "mi","jri","dynh","manq","rhe","zar","rrhaz","kal","chur","eech","thaa","dra","jurl","mah","sanu","dra","ii'r", - "ka","aasi","far","wa","baq","ara","qara","zir","saam","mak","hrar","nja","rir","khan","jun","dar","rik","kah", - "hal","ket","jurl","mah","tul","cresh","azu","ragh","mro","mra","mrro","mrra") - -/datum/language/tajaran/get_random_name(var/gender) - var/new_name = ..(gender,1) - if(prob(50)) - new_name += " [pick(list("Hadii","Kaytam","Nazkiin","Zhan-Khazan","Hharar","Njarir'Akhan","Faaira'Nrezi","Rhezar","Mi'dynh","Rrhazkal","Bayan","Al'Manq","Mi'jri","Chur'eech","Sanu'dra","Ii'rka"))]" - else - new_name += " [..(gender,1)]" - return new_name - -/datum/language/tajaranakhani - name = LANGUAGE_AKHANI - desc = "The language of the sea-faring Njarir'Akhan Tajaran. Borrowing some elements from Siik, the language is distinctly more structured." - speech_verb = "chatters" - ask_verb = "mrowls" - exclaim_verb = "wails" - colour = "akhani" - key = "h" - flags = WHITELISTED - syllables = list("mrr","rr","marr","tar","ahk","ket","hal","kah","dra","nal","kra","vah","dar","hrar", "eh", - "ara","ka","zar","mah","ner","zir","mur","hai","raz","ni","ri","nar","njar","jir","ri","ahn","kha","sir", - "kar","yar","kzar","rha","hrar","err","fer","rir","rar","yarr","arr","ii'r","jar","kur","ran","rii","ii", - "nai","ou","kah","oa","ama","uuk","bel","chi","ayt","kay","kas","akor","tam","yir","enai") - -/datum/language/tajsign - name = LANGUAGE_ALAI - desc = "A standardized Tajaran sign language that was developed in Zarraya and gradually adopted by other nations, incorporating \ - hand gestures and movements of the ears and tail." - signlang_verb = list("gestures with their hands", "gestures with their ears and tail", "gestures with their ears, tail and hands") - colour = "tajaran" - key = "l" - flags = WHITELISTED | SIGNLANG | NO_STUTTER | NONVERBAL - -/datum/language/tajsign/can_speak_special(var/mob/speaker) // TODO: If ever we make external organs assist languages, convert this over to the new format - var/list/allowed_species = list(SPECIES_TAJ, SPECIES_TESHARI) // Need a tail and ears and such to use this. - if(iscarbon(speaker)) - var/obj/item/organ/external/hand/hands = locate() in speaker //you can't sign without hands - if(!hands) - return FALSE - if(ishuman(speaker)) - var/mob/living/carbon/human/H = speaker - if(H.species.get_bodytype_legacy(H) in allowed_species) - return TRUE - - return FALSE - -/datum/language/skrell - name = LANGUAGE_SKRELLIAN - desc = "A set of warbles and hums, the language itself a complex mesh of both melodic and rhythmic components, exceptionally capable of conveying intent and emotion of the speaker." - speech_verb = "warbles" - ask_verb = "warbles" - exclaim_verb = "sings" - whisper_verb = "hums" - colour = "skrell" - key = "k" - space_chance = 30 - syllables = list("qr","qrr","xuq","qil","quum","xuqm","vol","xrim","zaoo","qu-uu","qix","qoo","zix") - -/datum/language/akula - name = LANGUAGE_AKULA - desc = "The language of the Akula consists of a wildly melodic combination of hard and soft consonants working in flowing conjuncture with one another." - speech_verb = "cants" - ask_verb = "inflects" - exclaim_verb = "shouts" - whisper_verb = "murmurs" - colour = "akula" - key = "a" - space_chance = 80 - syllables = list("ko'lakou","hiki","iloko'o","o'e","kekahi","olelo","keia","'ekahi","loaa","no'ka'mea","ia","ka'mea","ko'ino", "kela", "ma", "keia", "hai aku", "paani", "hopena", "heluhelu", "mai'o", "ke'awa", "a'hiki", "nui", "maanei", "ki'eki'e", "no'ke'aha'mai", "no'i", "malamalama", "keia'ano", "ka'hale", "pono", "ki'i", "holoholona", "wahi", "makuahine", "kokoke", "makuakāne", "kekahi", "lawe", "wahi", "mahope'iho'o", "ma'popo'eka") - -/datum/language/skrellfar - name = LANGUAGE_SKRELLIANFAR - desc = "The most common language among the Skrellian Far Kingdoms. Has an even higher than usual concentration of inaudible phonemes." - speech_verb = "warbles" - ask_verb = "warbles" - exclaim_verb = "sings" - whisper_verb = "hums" - colour = "skrellfar" - key = "p" - space_chance = 30 - flags = WHITELISTED - syllables = list("qr","qrr","xuq","qil","quum","xuqm","vol","xrim","zaoo","qu-uu","qix","qoo","zix", "...", "oo", "q", "nq", "x", "xq", "ll", "...", "...", "...") //should sound like there's holes in it - -/datum/language/skrell/get_random_name(gender) - var/list/first_name = GLOB.skrell_first_names - var/list/last_name = GLOB.skrell_last_names - return "[pick(first_name)] [pick(last_name)]" - -/datum/language/human - name = LANGUAGE_SOL_COMMON - desc = "A bastardized hybrid of many languages, including Chinese, English, French, and more; it is the common language of the Sol system." - speech_verb = "says" - whisper_verb = "whispers" - exclaim_verb = list("exclaims","shouts","yells") - colour = "solcom" - key = "1" - //syllables are at the bottom of the file - - -/datum/language/human/get_random_name(gender) - if (prob(80)) - if(gender==FEMALE) - return capitalize(pick(GLOB.first_names_female)) + " " + capitalize(pick(GLOB.last_names)) - else - return capitalize(pick(GLOB.first_names_male)) + " " + capitalize(pick(GLOB.last_names)) - else - return ..() - -/datum/language/machine - name = LANGUAGE_EAL - desc = "An efficient language of encoded tones developed by positronics." - speech_verb = "whistles" - ask_verb = "chirps" - exclaim_verb = "whistles loudly" - colour = "changeling" - key = "6" - flags = NO_STUTTER - syllables = list("beep","beep","beep","beep","beep","boop","boop","boop","bop","bop","dee","dee","doo","doo","hiss","hss","buzz","buzz","bzz","ksssh","keey","wurr","wahh","tzzz","shh","shk") - space_chance = 10 - -/datum/language/machine/get_random_name() - if(prob(70)) - return "[pick(list("PBU","HIU","SINA","ARMA","OSI"))]-[rand(100, 999)]" - else - return pick(GLOB.ai_names) - -/datum/language/teshari - name = LANGUAGE_SCHECHI - desc = "A trilling language spoken by the diminutive Teshari." - speech_verb = "chirps" - ask_verb = "chirrups" - exclaim_verb = "trills" - colour = "alien" - key = "v" - space_chance = 50 - syllables = list( - "ca", "ra", "ma", "sa", "na", "ta", "la", "sha", "scha", "a", "a", - "ce", "re", "me", "se", "ne", "te", "le", "she", "sche", "e", "e", - "ci", "ri", "mi", "si", "ni", "ti", "li", "shi", "schi", "i", "i" - ) - -/datum/language/teshari/get_random_name(gender) - return ..(gender, 2, 4, 1.5) - - -/datum/language/zaddat - name = LANGUAGE_ZADDAT - desc = "A harsh buzzing language created by the Zaddat following their exodus from their homeworld." - speech_verb = "buzzes" - ask_verb = "buzzes" - exclaim_verb = "croaks" - colour = "zaddat" - key = "z" - space_chance = 20 - syllables = list("z", "dz", "i", "iv", "ti", "az", "hix", "xo", "av", "xo", "x", "za", "at", "vi") - -/datum/language/birdsong - name = LANGUAGE_BIRDSONG - desc = "A language primarily spoken by Narvians" - speech_verb = "chirps" - colour = "birdsongc" - key = "7" - syllables = list ("cheep", "peep", "tweet") - -/datum/language/sergal - name = LANGUAGE_SAGARU - desc = "The dominant language of the Sergal homeworld, Vilous. It consists of aggressive low-pitched hissing and throaty growling." - speech_verb = "snarls" - colour = "sergal" - key = "T" - syllables = list ("grr", "gah", "woof", "arf", "arra", "rah", "wor", "sarg") - -/datum/language/vulpkanin - name = LANGUAGE_CANILUNZT - desc = "The guttural language spoken and utilized by the inhabitants of Vazzend system, composed of growls, barks, yaps, and heavy utilization of ears and tail movements. Vulpkanin speak this language with ease." - speech_verb = "rrrfts" - ask_verb = "rurs" - exclaim_verb = "barks" - colour = "vulpkanin" - key = "8" - syllables = list("rur","ya","cen","rawr","bar","kuk","tek","qat","uk","wu","vuh","tah","tch","schz","auch", \ - "ist","ein","entch","zwichs","tut","mir","wo","bis","es","vor","nic","gro","lll","enem","zandt","tzch","noch", \ - "hel","ischt","far","wa","baram","iereng","tech","lach","sam","mak","lich","gen","or","ag","eck","gec","stag","onn", \ - "bin","ket","jarl","vulf","einech","cresthz","azunein","ghzth") - -/datum/language/demon - name = LANGUAGE_DAEMON - desc = "The language spoken by the demons of Infernum, it's composed of deep chanting. It's rarely spoken off of Infernum due to the volume one has to exert." - speech_verb = "chants" - ask_verb = "croons" - exclaim_verb = "incants" - colour = "daemon" //So fancy - key = "n" - syllables = list("viepn","e","bag","docu","kar","xlaqf","raa","qwos","nen","ty","von","kytaf","xin","ty","ka","baak","hlafaifpyk","znu","agrith","na'ar","uah","plhu","six","fhler","bjel","scee","lleri", - "dttm","aggr","uujl","hjjifr","wwuthaav",) - machine_understands = FALSE - -/datum/language/angel - name = LANGUAGE_ENOCHIAN - desc = "The graceful language spoken by angels, composed of quiet hymns. Formally, Angels sing it." - speech_verb = "sings" - ask_verb = "hums" - exclaim_verb = "loudly sings" - colour = "enochian" //So fancy - key = "i" - syllables = list("salve","sum","loqui","operatur","iusta","et","permittit","facere","effercio","pluribus","enim","hoc", - "mihi","wan","six","tartu") - machine_understands = FALSE - -/datum/language/bug - name = LANGUAGE_VESPINAE - desc = "A jarring and clicky language developed and used by Vasilissans, it is designed for use with mouthparts and as a result has become a common language for various arthropod species." - speech_verb = "clicks" - ask_verb = "chitters" - exclaim_verb = "rasps" - colour = "bug" - key = "x" - syllables = list("vaur","uyek","uyit","avek","sc'theth","k'ztak","teth","wre'ge","lii","dra'","zo'","ra'","kax'","zz","vh","ik","ak", - "uhk","zir","sc'orth","sc'er","thc'yek","th'zirk","th'esk","k'ayek","ka'mil","sc'","ik'yir","yol","kig","k'zit","'","'","zrk","krg","isk'yet","na'k", - "sc'azz","th'sc","nil","n'ahk","sc'yeth","aur'sk","iy'it","azzg","a'","i'","o'","u'","a","i","o","u","zz","kr","ak","nrk","tzzk","bz","xic'","k'lax'","histh") - -/datum/language/shadekin - name = LANGUAGE_SHADEKIN - desc = "Shadekin seem to always know what the others are thinking. This is probably why." - speech_verb = "mars" - ask_verb = "mars" - exclaim_verb = "mars" - colour = "changeling" - key = "m" - machine_understands = FALSE - flags = WHITELISTED | HIVEMIND - -/datum/language/slavic - name = LANGUAGE_SLAVIC - desc = "Was established in 2122 by the short-lived United Slavic Confederation on Earth." - colour = "solcom" - key = "g" - syllables = list( - "rus", "zem", "ave", "groz", "ski", "ska", "ven", "konst", "pol", "lin", "svy", - "danya", "da", "mied", "zan", "das", "krem", "myka", "to", "st", "no", "na", "ni", - "ko", "ne", "en", "po", "ra", "li", "on", "byl", "cto", "eni", "ost", "ol", "ego", - "ver", "stv", "pro" - ) - -/datum/language/bones - name = LANGUAGE_BONES - desc = "The language of skeletons, characterised by clunks and clatters. Native language of Phoronoids." - speech_verb = "rattles" - ask_verb = "clinks" - exclaim_verb = "clunks" - colour = "changeling" - key = "c" - syllables = list("clatter","tink","chink","clack","rattle","clink","clunk","dink","tonk","donk","plink,","plonk") - -//Syllable Lists -/* - This list really long, mainly because I can't make up my mind about which mandarin syllables should be removed, - and the english syllables had to be duplicated so that there is roughly a 50-50 weighting. - The other 3 languages were duplicated just so they could show occasionally. - - Sources: - http://www.sttmedia.com/syllablefrequency-english - http://www.sttmedia.com/syllablefrequency-spanish - http://www.sttmedia.com/syllablefrequency-russian - http://www.sttmedia.com/syllablefrequency-french - http://www.chinahighlights.com/travelguide/learning-chinese/pinyin-syllables.htm -*/ -/datum/language/human/syllables = list( -"a", "ai", "an", "ang", "ao", "ba", "bai", "ban", "bang", "bao", "bei", "ben", "beng", "bi", "bian", "biao", -"bie", "bin", "bing", "bo", "bu", "ca", "cai", "can", "cang", "cao", "ce", "cei", "cen", "ceng", "cha", "chai", -"chan", "chang", "chao", "che", "chen", "cheng", "chi", "chong", "chou", "chu", "chua", "chuai", "chuan", "chuang", "chui", "chun", -"chuo", "ci", "cong", "cou", "cu", "cuan", "cui", "cun", "cuo", "da", "dai", "dan", "dang", "dao", "de", "dei", -"den", "deng", "di", "dian", "diao", "die", "ding", "diu", "dong", "dou", "du", "duan", "dui", "dun", "duo", "e", -"ei", "en", "er", "fa", "fan", "fang", "fei", "fen", "feng", "fo", "fou", "fu", "ga", "gai", "gan", "gang", -"gao", "ge", "gei", "gen", "geng", "gong", "gou", "gu", "gua", "guai", "guan", "guang", "gui", "gun", "guo", "ha", -"hai", "han", "hang", "hao", "he", "hei", "hen", "heng", "hm", "hng", "hong", "hou", "hu", "hua", "huai", "huan", -"huang", "hui", "hun", "huo", "ji", "jia", "jian", "jiang", "jiao", "jie", "jin", "jing", "jiong", "jiu", "ju", "juan", -"jue", "jun", "ka", "kai", "kan", "kang", "kao", "ke", "kei", "ken", "keng", "kong", "kou", "ku", "kua", "kuai", -"kuan", "kuang", "kui", "kun", "kuo", "la", "lai", "lan", "lang", "lao", "le", "lei", "leng", "li", "lia", "lian", -"liang", "liao", "lie", "lin", "ling", "liu", "long", "lou", "lu", "luan", "lun", "luo", "ma", "mai", "man", "mang", -"mao", "me", "mei", "men", "meng", "mi", "mian", "miao", "mie", "min", "ming", "miu", "mo", "mou", "mu", "na", -"nai", "nan", "nang", "nao", "ne", "nei", "nen", "neng", "ng", "ni", "nian", "niang", "niao", "nie", "nin", "ning", -"niu", "nong", "nou", "nu", "nuan", "nuo", "o", "ou", "pa", "pai", "pan", "pang", "pao", "pei", "pen", "peng", -"pi", "pian", "piao", "pie", "pin", "ping", "po", "pou", "pu", "qi", "qia", "qian", "qiang", "qiao", "qie", "qin", -"qing", "qiong", "qiu", "qu", "quan", "que", "qun", "ran", "rang", "rao", "re", "ren", "reng", "ri", "rong", "rou", -"ru", "rua", "ruan", "rui", "run", "ruo", "sa", "sai", "san", "sang", "sao", "se", "sei", "sen", "seng", "sha", -"shai", "shan", "shang", "shao", "she", "shei", "shen", "sheng", "shi", "shou", "shu", "shua", "shuai", "shuan", "shuang", "shui", -"shun", "shuo", "si", "song", "sou", "su", "suan", "sui", "sun", "suo", "ta", "tai", "tan", "tang", "tao", "te", -"teng", "ti", "tian", "tiao", "tie", "ting", "tong", "tou", "tu", "tuan", "tui", "tun", "tuo", "wa", "wai", "wan", -"wang", "wei", "wen", "weng", "wo", "wu", "xi", "xia", "xian", "xiang", "xiao", "xie", "xin", "xing", "xiong", "xiu", -"xu", "xuan", "xue", "xun", "ya", "yan", "yang", "yao", "ye", "yi", "yin", "ying", "yong", "you", "yu", "yuan", -"yue", "yun", "za", "zai", "zan", "zang", "zao", "ze", "zei", "zen", "zeng", "zha", "zhai", "zhan", "zhang", "zhao", -"zhe", "zhei", "zhen", "zheng", "zhi", "zhong", "zhou", "zhu", "zhua", "zhuai", "zhuan", "zhuang", "zhui", "zhun", "zhuo", "zi", -"zong", "zou", "zuan", "zui", "zun", "zuo", "zu", -"al", "an", "ar", "as", "at", "ea", "ed", "en", "er", "es", "ha", "he", "hi", "in", "is", "it", -"le", "me", "nd", "ne", "ng", "nt", "on", "or", "ou", "re", "se", "st", "te", "th", "ti", "to", -"ve", "wa", "all", "and", "are", "but", "ent", "era", "ere", "eve", "for", "had", "hat", "hen", "her", "hin", -"his", "ing", "ion", "ith", "not", "ome", "oul", "our", "sho", "ted", "ter", "tha", "the", "thi", -"al", "an", "ar", "as", "at", "ea", "ed", "en", "er", "es", "ha", "he", "hi", "in", "is", "it", -"le", "me", "nd", "ne", "ng", "nt", "on", "or", "ou", "re", "se", "st", "te", "th", "ti", "to", -"ve", "wa", "all", "and", "are", "but", "ent", "era", "ere", "eve", "for", "had", "hat", "hen", "her", "hin", -"his", "ing", "ion", "ith", "not", "ome", "oul", "our", "sho", "ted", "ter", "tha", "the", "thi", -"al", "an", "ar", "as", "at", "ea", "ed", "en", "er", "es", "ha", "he", "hi", "in", "is", "it", -"le", "me", "nd", "ne", "ng", "nt", "on", "or", "ou", "re", "se", "st", "te", "th", "ti", "to", -"ve", "wa", "all", "and", "are", "but", "ent", "era", "ere", "eve", "for", "had", "hat", "hen", "her", "hin", -"his", "ing", "ion", "ith", "not", "ome", "oul", "our", "sho", "ted", "ter", "tha", "the", "thi", -"al", "an", "ar", "as", "at", "ea", "ed", "en", "er", "es", "ha", "he", "hi", "in", "is", "it", -"le", "me", "nd", "ne", "ng", "nt", "on", "or", "ou", "re", "se", "st", "te", "th", "ti", "to", -"ve", "wa", "all", "and", "are", "but", "ent", "era", "ere", "eve", "for", "had", "hat", "hen", "her", "hin", -"his", "ing", "ion", "ith", "not", "ome", "oul", "our", "sho", "ted", "ter", "tha", "the", "thi", -"al", "an", "ar", "as", "at", "ea", "ed", "en", "er", "es", "ha", "he", "hi", "in", "is", "it", -"le", "me", "nd", "ne", "ng", "nt", "on", "or", "ou", "re", "se", "st", "te", "th", "ti", "to", -"ve", "wa", "all", "and", "are", "but", "ent", "era", "ere", "eve", "for", "had", "hat", "hen", "her", "hin", -"his", "ing", "ion", "ith", "not", "ome", "oul", "our", "sho", "ted", "ter", "tha", "the", "thi", -"al", "an", "ar", "as", "at", "ea", "ed", "en", "er", "es", "ha", "he", "hi", "in", "is", "it", -"le", "me", "nd", "ne", "ng", "nt", "on", "or", "ou", "re", "se", "st", "te", "th", "ti", "to", -"ve", "wa", "all", "and", "are", "but", "ent", "era", "ere", "eve", "for", "had", "hat", "hen", "her", "hin", -"his", "ing", "ion", "ith", "not", "ome", "oul", "our", "sho", "ted", "ter", "tha", "the", "thi", -"ah", "be", "bo", "eh", "ep", "et", "ka", "ko", "ha", "he", "ho", "ob", "oh", "op", "oc", "ot", "pa", "pe", "ct", "ta", "te", "to", -"vse", "tak", "nak", "no", "epo", "pre", "kan", "dly", "ime", "sha", "kur", "yey", "khi", "yeg", "ne", -"ion", "ne", "nas", "v", -"ah", "be", "bo", "eh", "ep", "et", "ka", "ko", "ha", "he", "ho", "ob", "oh", "op", "oc", "ot", "pa", "pe", "ct", "ta", "te", "to", -"vse", "tak", "nak", "no", "epo", "pre", "kan", "dly", "ime", "sha", "kur", "yey", "khi", "yeg", "ne", -"ion", "ne", "nas", "v", -"ah", "be", "bo", "eh", "ep", "et", "ka", "ko", "ha", "he", "ho", "ob", "oh", "op", "oc", "ot", "pa", "pe", "ct", "ta", "te", "to", -"vse", "tak", "nak", "no", "epo", "pre", "kan", "dly", "ime", "sha", "kur", "yey", "khi", "yeg", "ne", -"ion", "ne", "nas", "v", -"ai", "an", "ar", "au", "ce", "ch", "co", "de", "em", "en", "er", "es", "et", "eu", "il", "in", "is", "la", "le", -"ma", "me", "ne", "ns", "nt", "on", "ou", "pa", "qu", "ra", "re", "se", "te", "ti", "tr", "ue", "ur", "us", "ve", -"tou", "e", "eve", "hen", "son", "non", "not", "le", -"ai", "an", "ar", "au", "ce", "ch", "co", "de", "em", "en", "er", "es", "et", "eu", "il", "in", "is", "la", "le", -"ma", "me", "ne", "ns", "nt", "on", "ou", "pa", "qu", "ra", "re", "se", "te", "ti", "tr", "ue", "ur", "us", "ve", -"tou", "e", "eve", "hen", "son", "non", "not", "le", -"ai", "an", "ar", "au", "ce", "ch", "co", "de", "em", "en", "er", "es", "et", "eu", "il", "in", "is", "la", "le", -"ma", "me", "ne", "ns", "nt", "on", "ou", "pa", "qu", "ra", "re", "se", "te", "ti", "tr", "ue", "ur", "us", "ve", -"tou", "e", "eve", "hen", "son", "non", "not", "le", -"ad", "al", "an", "ar", "as", "ci", "co", "de", "do", "el", "en", "er", "es", "ie", "in", "la", "lo", "me", "na", -"no", "nt", "or", "os", "pa", "qu", "ra", "re", "ro", "se", "st", "ta", "te", "to", "ue", "un", -"tod", "ser", "su", "no", "nue", "el", -"ad", "al", "an", "ar", "as", "ci", "co", "de", "do", "el", "en", "er", "es", "ie", "in", "la", "lo", "me", "na", -"no", "nt", "or", "os", "pa", "qu", "ra", "re", "ro", "se", "st", "ta", "te", "to", "ue", "un", -"tod", "ser", "su", "no", "nue", "el", -"ad", "al", "an", "ar", "as", "ci", "co", "de", "do", "el", "en", "er", "es", "ie", "in", "la", "lo", "me", "na", -"no", "nt", "or", "os", "pa", "qu", "ra", "re", "ro", "se", "st", "ta", "te", "to", "ue", "un", -"tod", "ser", "su", "no", "nue", "el") - -/datum/language/adherent - name = LANGUAGE_ADHERENT - desc = "The mellifluous wind chime tones of the Vigil's formal shared language." - speech_verb = "chimes" - ask_verb = "rings" - exclaim_verb = "peals" - colour = "adherent" - key = "p" - flags = WHITELISTED - syllables = list("\[Ab\]", "\[Bb\]", "\[Cb\]", "\[Db\]", "\[Eb\]", "\[Fb\]", - "\[Gb\]", "\[A#\]", "\[B#\]", "\[C#\]", "\[D#\]", "\[E#\]", "\[F#\]", - "\[G#\]", "\[A\]", "\[B\]", "\[C\]", "\[D\]", "\[E\]", "\[F\]", "\[G\]", - "\[harmonic\]", "\[disharmonic\]", "\[choral\]" - ) - space_chance = 0 diff --git a/code/modules/lore_hardcoded/README.md b/code/modules/lore_hardcoded/README.md new file mode 100644 index 00000000000..1a016e6da2f --- /dev/null +++ b/code/modules/lore_hardcoded/README.md @@ -0,0 +1,9 @@ +# hardcoded lore + +stuff hierarchical stuff in here +use SSlore to build a resolver to fetch it + +eventually we'll use entirely .yaml prototypes for lore +and have proper composition systems + +for now though, we don't have the manpower. diff --git a/code/modules/lore_hardcoded/_hardcoded.dm b/code/modules/lore_hardcoded/_hardcoded.dm new file mode 100644 index 00000000000..bf3b7beb79c --- /dev/null +++ b/code/modules/lore_hardcoded/_hardcoded.dm @@ -0,0 +1,69 @@ +/datum/lore + /// abstract type + var/abstract_type = /datum/lore + +/datum/lore/character_background + abstract_type = /datum/lore/character_background + /// name + var/name = "Unknown" + /// id - **must be unique on subtypes + var/id + /// description/what the player sees + var/desc = "What is this?" + /// subspecies are counted as the master species + var/subspecies_included = TRUE + /// allowed species ids - if is list, only these species can have them; these are character species uids, not normal species ids, subspecies do count; typepaths are allowed + var/list/allow_species + /// forbidden species ids - overridden by allowed; typepaths are allowed, will be converted to uids + var/list/forbid_species + /// languages that someone gets by picking this; typepaths are allowed, will be converted to uids + var/list/innate_languages + +/datum/lore/character_background/New() + // resolve typepaths + if(allow_species && !islist(allow_species)) + CRASH("innate languages not a list; fix your shit.") + for(var/thing in allow_species) + if(ispath(thing)) + allow_species += SScharacters.resolve_character_species(thing).uid + allow_species -= thing + else if(istext(thing)) + ASSERT(!!SScharacters.resolve_character_species(thing)) + else + CRASH("you didn't put a valid path or text; fix your shit.") + if(forbid_species && !islist(forbid_species)) + CRASH("innate languages not a list; fix your shit.") + for(var/thing in forbid_species) + if(ispath(thing)) + forbid_species += SScharacters.resolve_character_species(thing).uid + forbid_species -= thing + else if(istext(thing)) + ASSERT(!!SScharacters.resolve_character_species(thing)) + else + CRASH("you didn't put a valid path or text; fix your shit.") + if(innate_languages && !islist(innate_languages)) + CRASH("innate languages not a list; fix your shit.") + for(var/thing in innate_languages) + if(ispath(thing)) + innate_languages += SScharacters.resolve_language_path(thing).id + innate_languages -= thing + else if(istext(thing)) + ASSERT(!!SScharacters.resolve_language_id(thing)) + else + CRASH("you didn't put a valid path or text; fix your shit.") + +/** + * id passed in is for a /datum/character_species, NOT a /datum/speices! + */ +/datum/lore/character_background/proc/check_species_id(id) + return check_character_species(SScharacters.resolve_character_species(id)) + +/datum/lore/character_background/proc/check_character_species(datum/character_species/S) + if(allow_species) + return (S.uid in allow_species) || (subspecies_included && S.is_subspecies && (S.superspecies_id in allow_species)) + else if(forbid_species) + return !((S.uid in forbid_species) || (subspecies_included && S.is_subspecies && (S.superspecies_id in forbid_species))) + return TRUE + +/datum/lore/character_background/proc/get_default_language_ids() + return innate_languages.Copy() diff --git a/code/modules/lore_hardcoded/citizenship.dm b/code/modules/lore_hardcoded/citizenship.dm new file mode 100644 index 00000000000..2de29c5433e --- /dev/null +++ b/code/modules/lore_hardcoded/citizenship.dm @@ -0,0 +1,74 @@ +/datum/lore/character_background/citizenship + abstract_type = /datum/lore/character_background/citizenship + +/datum/lore/character_background/citizenship/check_character_species(datum/character_species/S) + if(S.species_fluff_flags & SPECIES_FLUFF_PICKY_CITIZENSHIP) + . = (S.uid in allow_species) || (subspecies_included && S.is_subspecies && (S.superspecies_id in allow_species)) + if(!.) + return + return ..() + +/datum/lore/character_background/citizenship/custom + name = "Other" + id = "custom" + desc = "Some individuals are nomadic, or simply, for one reason or another, don't belong to any one government's citizenry. Whatever the case for you, you don't identify with any of the standing governments." + +/datum/lore/character_background/citizenship/orionconfederation + name = "Orion Confederation" + id = "oricon" + desc = "Born from the cradle of humanity, the Orion Confederation is a coalition of human worlds spanning much of the space of the Orion Spur. \ + A constitutional government, the Orion Confederation was built from the remains of Terra's pre-space governments, and the semi-independent \ + colonies of Luna and Mars. \ + The largest megacorporations in the galaxy are predominantly human-centric, new frontiers are established on a regular basis by OriCon's \ + explorers, and territories solidify with every passing year. Today the Orion Confederation stands as the cultural center \ + of the galaxy, with it's megacorporations bringing untold prosperity to the galaxy... along with untold toil and struggle. \ + The Orion Confederation's hold on it's native megacorps is always tenuous; these major entities are almost left to their own affairs, \ + especially in the aftermath of the Phoron Wars, in regards to one of it's flagship corporations: NanoTrasen." + +/datum/lore/character_background/citizenship/naramadiascendancy + name = "Naramadi Ascendancy" + id = "narasc" + desc = "What began as a minor galactic power quickly grew to a major player on the galactic scene; the Naramadi Ascendancy. \ + An isolationist empire, the Ascendancy sits on a pocket of rich mineral veins that have proven to be a both a boon and a curse for a people that wanted \ + to live their lives in peace. \ + While most Naramadi technology resembles that of the outside world, some of it is strange and too complex \ + for the likes of the Orion Confederation to copy. Their culture of 'training over technology' and praise of individual strength \ + makes it difficult for other empires to relate to them, spare the Unathi and Zaddat. \ + While the Ascendancy might be one of the three founding fathers of the Hegemony, they have always put a high emphasis on self-governance - \ + keeping the same rules for their current allies as they do for everyone else." + +/datum/lore/character_background/citizenship/vikaracombine + name = "Vikara Combine" + id = "vikaracom" + desc = "Formed initially as an alliance between the Skrell and Teshari of the Vikara System, the Vikara Combine is \ + a long-standing compact which now incorporates not only it's founders, but newer races to the galactic stage such as \ + the Akula and Vulpkanin, and which has been a reliable ally of the Orion Confederation for over 400 years. Vikaran scientists \ + were the first to crack the intricacies of superluminal travel, and their engineers the first to devise the FTL drives which are now used \ + throughout the galaxy. Technologically advanced, yet diplomatically-minded, the combine's many territories span the central region of the \ + galaxy's Perseus Arm. The Combine's flagship corporation is Vey-Med, one of the largest and most well-known medical megacorporations in the \ + galaxy, which was founded and is primarily run by the Skrell." + +/datum/lore/character_background/citizenship/moghes + name = "Moghes Kingdom" + id = "mogheskingdom" + desc = "One of the various nations and Clans that inhabit the wider Moghes Hegemony. Bound together only by the Pact, these different \ + peoples are often at odds with each other. Their territories include many planets, some of which humans can only speculate on how to \ + safely colonize." + +/datum/lore/character_background/citizenship/zaddatmigrantfleet + name = "Zaddat Migrant Fleet" + id = "zaddatmigrantfleet" + desc = "One of several Zaddat communities finding common ground, often literally. These fleets include Shoal, Or'e, and Jzull. \ + The politics within these fleets are intense, meaning the contracts that they take may be for a myriad of reasons. \ + Overall their goal is to find a new homeworld." + +/datum/lore/character_background/citizenship/guwandi + name = "Guwandi" + id = "guwandi" + desc = "Exiles from Unathi Clans. They are unwelcome in Unathi society by and large, and often resort to crime. Those who are not killed \ + often flee to the Frontier, where they may find opportunities for a new life." + +/datum/lore/character_background/citizenship/custom + name = "Other" + id = "custom" + desc = "Some individuals are nomadic, or simply, for one reason or another, don't belong to any one government's citizenry. Whatever the case for you, you don't identify with any of the standing governments." diff --git a/code/modules/lore_hardcoded/faction.dm b/code/modules/lore_hardcoded/faction.dm new file mode 100644 index 00000000000..328bf49043f --- /dev/null +++ b/code/modules/lore_hardcoded/faction.dm @@ -0,0 +1,368 @@ +/datum/lore/character_background/faction + abstract_type = /datum/lore/character_background/faction + /// station job types you can play as under this - **typepaths** e.g. /datum/job/station/security_officer, etc + /// if null, you can play as everything + var/list/job_whitelist = list() + /// where 'desc' is the corporation description, this is what a player should know if they're a contractor + var/contractor_info + /// list of origins that can select this + /// if null, all can select + var/list/origin_whitelist + /// list of citizenships that can select this + /// if null, all can select + var/list/citizenship_whitelist + +/datum/lore/character_background/faction/New() + // job whitelist cache + for(var/i in job_whitelist) + job_whitelist[i] = TRUE + return ..() + +/datum/lore/character_background/faction/check_character_species(datum/character_species/S) + if(S.species_fluff_flags & SPECIES_FLUFF_PICKY_FACTION) + . = (S.uid in allow_species) || (subspecies_included && S.is_subspecies && (S.superspecies_id in allow_species)) + if(!.) + return + return ..() + +/datum/lore/character_background/faction/proc/check_job_id(id) + return job_whitelist? (job_whitelist[id]) : TRUE + +/datum/lore/character_background/faction/nanotrasen + name = "Nanotrasen" + id = "nanotrasen" + desc = "Formally established in 2274, NanoTrasen is one of the foremost research and development companies in the galaxy. \ + Originally focused on logistics and consumer product manufacturing, their swift move into the field of Phoron has lead to \ + them becoming the foremost experts on the substance and its uses. In the modern day, NanoTrasen prides \ + itself on being an early adopter to as many new technologies as possible, often offering the newest \ + products to their employees. In an effort to combat complaints about being 'guinea pigs', Nanotrasen \ + also offers one of the most comprehensive medical plans in Frontier space, up to and including cloning, \ + dedicated resleeving, mirror maintenance, and therapy.\ +

\ + NT's most well known products are its phoron based creations; especially those used in Cryotherapy. \ + It also boasts an prosthetic line, which is provided to its employees as needed, and is used as an incentive \ + for newly tested posibrains to remain with the company. NanoTrasen's corporate headquarters is based out of \ + the NTS Creon in the privateyl owned Thebes system." + contractor_info = "You are an employee working for NanoTrasen. You are not a contractor, you belong here." + job_whitelist = null + +/datum/lore/character_background/faction/aether + name = "Aether Atmos & Recycling" + id = "aether" + desc = "Aether Atmospherics and Recycling is the prime maintainer and provider of atmospherics systems to both the many ships that navigate the \ + vast expanses of space, and the life support on current and future Human colonies. The byproducts from the filtration of atmospheres across the galaxy \ + are then resold for a variety of uses to those willing to buy. With the nature of their services, most work they do is contracted for the construction of \ + these systems, or staffing to maintain them for colonies across human space. Recently, Aether executed a shockingly effective set of hostile acquisitions, \ + purchasing Focal Point Energistics and the Xion Manufacturing Group." + contractor_info = "You're used to being contracted out to maintain systems for other corporations. This assignment is probably routine to you." + job_whitelist = list( + JOB_ID_QUARTERMASTER, + JOB_ID_CARGO_TECHNICIAN, + JOB_ID_STATION_ENGINEER, + JOB_ID_ATMOSPHERIC_TECHNICIAN, + JOB_ID_BOTANIST, + JOB_ID_JANITOR, + JOB_ID_ASSISTANT, + JOB_ID_OFFDUTY_CIVILLIAN, + JOB_ID_OFFDUTY_CARGO, + JOB_ID_OFFDUTY_ENGINEER + ) + +/datum/lore/character_background/faction/centauri + name = "Centauri Provisions" + id = "centauri" + desc = "Headquartered in Alpha Centauri, Centauri Provisions made a name in the snack-food industry primarily by being the first to focus on colonial holdings. \ + The various brands of Centauri snackfoods are now household names, from SkrellSnax and Space Mountain Wind to the ubiquitous and allegedly edible Bread Tube. \ + They are well known for targeting as many species as possible with each brand - which, some will argue, is due to some of those brands being rather bland \ + in taste and texture. Their staying power is legendary, and many spacers have grown up on a mix of their cheap snacks and protein shakes." + contractor_info = "Although the occasional marketing trip isn't unheard of, it's meant to be rare. It may seem strange to be assigned to a different Corporate outpost, but it's a good marketing opportunity regardless, and the bosses are watching!" + job_whitelist = list( + JOB_ID_QUARTERMASTER, + JOB_ID_CARGO_TECHNICIAN, + JOB_ID_BARTENDER, + JOB_ID_BOTANIST, + JOB_ID_CHEF, + JOB_ID_JANITOR, + JOB_ID_ENTERTAINER, + JOB_ID_ASSISTANT, + JOB_ID_CLOWN, + JOB_ID_MIME, + JOB_ID_OFFDUTY_CIVILLIAN, + JOB_ID_OFFDUTY_CARGO + ) + +/datum/lore/character_background/faction/freetradeunion + name = "Free Trade Union" + id = "ftu" + desc = "The Free Trade Union is different from other tran-stellars in that they are not just a company, but also a large conglomerate \ + of various traders and merchants from across the galaxy. They control a sizable fleet of vessels of various classes, all of which maintain autonomy \ + from the centralized FTU to engage in free trade. They also host a fleet of combat vessels responsible for defending traders when necessary. They \ + control many large scale trade stations across the galaxy - even in non-human space. Generally, their multi-purpose stations keep local sectors \ + filled with duty-free shops and wares. Almost anything is sold at FTU markets, including products that are forbidden or have insanely high taxes in \ + government or Corporate space. The FTU are the originators of the Tradeband language, created specially to serve as the lingua franca for Merchants \ + across the Galaxy, to ensure members may understand each other regardless of native language or nationality." + contractor_info = "Working under a Corporation feels strange. You're used to exercising your autonomy, or perhaps you're used to the more strict maritime environment of your former vessel. Being surrounded by Corporate employees reminds you of why you're with the FTU." + job_whitelist = list( + JOB_ID_QUARTERMASTER, + JOB_ID_CARGO_TECHNICIAN, + JOB_ID_PATHFINDER, + JOB_ID_EXPLORER, + JOB_ID_FIELD_MEDIC, + JOB_ID_STATION_ENGINEER, + JOB_ID_PARAMEDIC, + JOB_ID_PILOT, + JOB_ID_BOTANIST, + JOB_ID_CHEF, + JOB_ID_JANITOR, + JOB_ID_ENTERTAINER, + JOB_ID_ASSISTANT, + JOB_ID_CLOWN, + JOB_ID_MIME, + JOB_ID_OFFDUTY_CIVILLIAN, + JOB_ID_OFFDUTY_EXPLORER, + JOB_ID_OFFDUTY_MEDBAY, + JOB_ID_OFFDUTY_CARGO, + JOB_ID_OFFDUTY_ENGINEER + ) + innate_languages = list( + /datum/language/trader + ) + +/datum/lore/character_background/faction/gilthari + name = "Gilthari Exports" + id = "gilthari" + desc = "Gilthari started as Sol's premier supplier of luxury goods, specializing in extracting money from the rich and successful that weren't already shareholders. \ + Their largest holdings are in gambling, but they maintain subsidiaries in everything from VR equipment to luxury watches. Their holdings in \ + mass media are a smaller but still important part of their empire. Gilthari is known for treating its positronic employees very well, sparking a number of \ + conspiracy theories. The gorgeous FBP model that Gilthari provides them is a symbol of the corporation's wealth and is known to reach ludicrous prices when \ + available on the black market, with legal ownership of the chassis limited, by contract, to employees." + contractor_info = "The drab atmosphere of this assignment is frustrating. Hardly any thought is put into how the environment might be made more elegant and pleasing to the senses. On the bright side, Corporate employees tend to have plenty of disposable income." + job_whitelist = list( + JOB_ID_QUARTERMASTER, + JOB_ID_CARGO_TECHNICIAN, + JOB_ID_SHAFT_MINER, + JOB_ID_PATHFINDER, + JOB_ID_EXPLORER, + JOB_ID_BARTENDER, + JOB_ID_CHEF, + JOB_ID_ENTERTAINER, + JOB_ID_CHAPLAIN, + JOB_ID_LIBRARIAN, + JOB_ID_ASSISTANT, + JOB_ID_OFFDUTY_CIVILLIAN, + JOB_ID_OFFDUTY_EXPLORER, + JOB_ID_OFFDUTY_CARGO + ) + +/datum/lore/character_background/faction/hephaestus + name = "Hephaestus Industries" + id = "hephaestus" + desc = "Hephaestus Industries is the largest supplier of arms, ammunition, and small millitary vehicles on the Frontier. \ + Hephaestus products have a reputation for reliability, and the corporation itself has a notable trade and research pact \ + with NanoTrasen. They otherwise enforce pacts and trade arrangements with the help of a fairly large asset-protection contingent which \ + prevents any contracting polities from using their own materiel against them. The Orion Confederation itself is one of Hephaestus' largest \ + non-corporate bulk contractors." + contractor_info = "NanoTrasen and Hephaestus have a long and beneficial working relationship. Your employers would not like it if you strained that relationship in any way, and therefore, neither would you." + job_whitelist = list( + JOB_ID_QUARTERMASTER, + JOB_ID_CARGO_TECHNICIAN, + JOB_ID_SHAFT_MINER, + JOB_ID_STATION_ENGINEER, + JOB_ID_ATMOSPHERIC_TECHNICIAN, + JOB_ID_ASSISTANT, + JOB_ID_OFFDUTY_CIVILLIAN, + JOB_ID_OFFDUTY_CARGO, + JOB_ID_OFFDUTY_ENGINEER + ) + +/datum/lore/character_background/faction/oculum + name = "Oculum News Network" + id = "oculum" + desc = "Oculum owns approximately 30% of Frontier-wide news networks, including microblogging aggregate sites, network and comedy news, and even \ + old-fashioned newspapers. Staunchly apolitical, they specialize in delivering the most popular news available - which means telling people what they \ + already want to hear. Oculum is a specialist in branding, and most people don't know that the reactionary Daedalus Dispatch newsletter and the radically \ + transhuman Liquid Steel webcrawler are in fact both controlled by the same organization." + contractor_info = "You're no stranger to working in a variety of Corporate environments. However you conduct your business, you're always chasing the story, even if that brings you into conflict with whoever's contracting you at the time." + job_whitelist = list( + JOB_ID_BARTENDER, + JOB_ID_ENTERTAINER, + JOB_ID_LIBRARIAN, + JOB_ID_ASSISTANT, + JOB_ID_OFFDUTY_CIVILLIAN + ) + +/datum/lore/character_background/faction/veymed + name = "Vey-Med" + id = "veymed" + desc = "Vey-Med is a medical supply and research company notable for being largely owned and opperated by Skrell. \ + Despite their alien origin, Vey-Med has obtained market dominance on the Frontier due to the quality and reliability \ + of their medical equipment - from surgical tools and industrial medical devices to the Oddyseus trauma response mecha \ + and everything in between. Their equipment tends to be top-of-the-line, most obviously shown by their incredibly \ + human-like FBP designs. Vey's rise to stardom came from their introduction of cosmetic resleeving, although in \ + recent years they've been forced to diversify as their patents expired and NanoTrasen-made medications became \ + essential to modern sleeving techniques. Vey-Medical possesses a number of trade agreements and research pacts with NanoTrasen, \ + resulting in what is functionally considered an alliance." + contractor_info = "Working with NanoTrasen has become a fact of life for Vey-Med employees over the years. You're no stranger to these types of environments, although you have seen better medical facilities before." + job_whitelist = list( + JOB_ID_FIELD_MEDIC, + JOB_ID_MEDICAL_DOCTOR, + JOB_ID_PARAMEDIC, + JOB_ID_CHEMIST, + JOB_ID_PSYCHIATRIST, + JOB_ID_PILOT, + JOB_ID_ASSISTANT, + JOB_ID_OFFDUTY_CIVILLIAN, + JOB_ID_OFFDUTY_EXPLORER, + JOB_ID_OFFDUTY_MEDBAY + ) + +/datum/lore/character_background/faction/wardtakahashi + name = "Ward-Takahashi" + id = "wardtakashi" + desc = "Ward-Takahashi focuses on the sale of small consumer electronics, with its computers, communicators, \ + and mid-class automobiles a fixture of many households. Less famously, Ward-Takahashi also supplies most \ + of the AI cores on which vital control systems are mounted, and it is this branch of their industry that has \ + led to their tertiary interest in the development and sale of high-grade AI systems. Ward-Takahashi's economies \ + of scale frequently steal market share from Nanotrasen's high-price products, leading to a bitter rivalry in the \ + consumer electronics market." + contractor_info = "Being allowed to work on a NanoTrasen facility is atypical. In fact, being employed here at all has made you suspicious. You're probably being watched. But Headquarters would love to hear about anything strange that you find." + job_whitelist = list( + JOB_ID_QUARTERMASTER, + JOB_ID_CARGO_TECHNICIAN, + JOB_ID_SHAFT_MINER, + JOB_ID_STATION_ENGINEER, + JOB_ID_ATMOSPHERIC_TECHNICIAN, + JOB_ID_JANITOR, + JOB_ID_ASSISTANT, + JOB_ID_OFFDUTY_CIVILLIAN,, + JOB_ID_OFFDUTY_CARGO, + JOB_ID_OFFDUTY_ENGINEER + ) + +/datum/lore/character_background/faction/zenghu + name = "Zeng-Hu Pharmaceuticals" + id = "zenghu" + desc = "Zeng-Hu is an old corporation, based close to Confederation space. Until the discovery of Phoron, Zeng-Hu maintained a stranglehold \ + on the market for medications, and many household names are patentted by Zeng-Hu-- Bicaridine, Dylovene, Tricordrizine, \ + and Dexalin all came from a Zeng-Hu medical laboratory. Zeng-Hu's fortunes have been in decline as Nanotrasen's near monopoly \ + on phoron research cut into their R&D capabilities and Vey-Med's superior medical equipment effectively decimated their own equipment \ + interests. The three-way rivalry between these companies for dominance in the medical field is well-known and a matter of \ + constant economic speculation." + contractor_info = "You dislike working under NanoTrasen. Zeng Hu saw fit to assign you to this post as part of a work exchange program. Although you were not explicitly told, you are presumably here to keep an eye on NanoTrasen's medical research." + job_whitelist = list( + JOB_ID_FIELD_MEDIC, + JOB_ID_MEDICAL_DOCTOR, + JOB_ID_PARAMEDIC, + JOB_ID_CHEMIST, + JOB_ID_PSYCHIATRIST, + JOB_ID_BOTANIST, + JOB_ID_ASSISTANT, + JOB_ID_OFFDUTY_CIVILLIAN, + JOB_ID_OFFDUTY_EXPLORER, + JOB_ID_OFFDUTY_MEDBAY + ) + +/datum/lore/character_background/faction/naramadiguilds + name = "Naramadi Guilds" + id = "narguild" + desc = "Within the Naramadi Ascendancy, every piece of land, equipment and technology is owned by either a House or a person. \ + To work around issues attached to repairing important infrastructure, and to upkeep the Ascendancy as a whole, a set of guilds \ + was created right after the unification of Naramadi People. \ + Offering both education and work, the guilds do not encompass the all possible fields of work; however offering education and experience \ + in the more practical fields. An example being various Engineering fields. The three Guilds currently operating within the ascendancy are: \ + Artificers, Logistici and Legionnarum" + contractor_info = "Your presence here is both a curse and a blessing for the Guild. Being contracted to work for a Human megacorporation presents various opportunities to learn technology unavalible in the Ascendancy." + job_whitelist = list( + JOB_ID_STATION_ENGINEER, + JOB_ID_ATMOSPHERIC_TECHNICIAN, + JOB_ID_SENIOR_ENGINEER, + JOB_ID_CARGO_TECHNICIAN, + JOB_ID_SHAFT_MINER, + JOB_ID_QUARTERMASTER, + JOB_ID_ROBOTICIST, + JOB_ID_OFFDUTY_CARGO, + JOB_ID_OFFDUTY_ENGINEER, + JOB_ID_OFFDUTY_SCIENCE + ) + origin_whitelist = list( + "naramadihouses", + "nameless" + ) + +/datum/lore/character_background/faction/onkhera_necropolis + name = "Onkhera Synthetics & Necropolis" + id = "oss_necro" + desc = "Onkhera Synthetic Solutions, and by extension it's subsidiary Necropolis Industries, is one of the few \ + Megacorporations not originating within the Confederacy; instead being owned by a Naramadi House - House Onkhera. \ + While the parent company Onkhera Synthetic Solutions focuses on the civilian market, providing high quality prosthetics to non-humans, \ + - becoming the direct rival of Vey-Med in the process - Necropolis Industries focuses on the Security and Military markets, providing \ + Security services to anybody willing to pay. The Company exports both biological and synthetic augumentations to various Megacorporations found \ + across the frontier." + contractor_info = "Neutrality of Onkhera Synthetic Solutions and Necropolis Industries has it's benefits, as You often get contracted with various corporations across the frontier. For you, this is just another assignement." + job_whitelist = list( + JOB_ID_FIELD_MEDIC, + JOB_ID_MEDICAL_DOCTOR, + JOB_ID_HEAD_NURSE, + JOB_ID_PARAMEDIC, + JOB_ID_CHEMIST, + JOB_ID_ROBOTICIST, + JOB_ID_SCIENTIST, + JOB_ID_SENIOR_RESEARCHER, + JOB_ID_OFFDUTY_MEDBAY, + JOB_ID_OFFDUTY_SCIENCE + ) + +/datum/lore/character_background/faction/xam + name = "Xsysorr Arms and Materiel" + id = "xam" + desc = "Xsysorr Arms and Material, also known as XAM. The only true Unathi Megacorporation, and a dealer in heavy equipment. They have cool \ + relations with other Megacorporations, especially those owned and operated by humans. Their exports are limited primarily to industrial equipment and \ + mining gear, along with weapons too cumbersome to use." + contractor_info = "You've been contracted as part of your obligations. Respect your role until you are disrespected." + job_whitelist = list( + JOB_ID_QUARTERMASTER, + JOB_ID_CARGO_TECHNICIAN, + JOB_ID_SHAFT_MINER, + JOB_ID_OFFDUTY_CARGO + ) + +/datum/lore/character_background/faction/zaddatguild + name = "Zaddat Guild" + id = "zaddatguild" + desc = "A collection of insular specialists in a given craft. Most well-known are the Engineers, yet there exists a Guild for most technical \ + skills. Often they have their skills contracted out for a period of time for the better interest of their Colony." + contractor_info = "You are a member from one of the famed Zaddat Guilds, here by agreement of the Colony. Your skill in your field is peerless, and you should not allow anyone to say otherwise. You should not prove otherwise." + job_whitelist = list( + JOB_ID_QUARTERMASTER, + JOB_ID_CARGO_TECHNICIAN, + JOB_ID_SHAFT_MINER, + JOB_ID_SENIOR_RESEARCHER, + JOB_ID_SCIENTIST, + JOB_ID_ROBOTICIST, + JOB_ID_PATHFINDER, + JOB_ID_EXPLORER, + JOB_ID_FIELD_MEDIC, + JOB_ID_SENIOR_ENGINEER, + JOB_ID_STATION_ENGINEER, + JOB_ID_ATMOSPHERIC_TECHNICIAN, + JOB_ID_HEAD_NURSE, + JOB_ID_MEDICAL_DOCTOR, + JOB_ID_PARAMEDIC, + JOB_ID_CHEMIST, + JOB_ID_PSYCHIATRIST, + JOB_ID_PILOT, + JOB_ID_BARTENDER, + JOB_ID_BOTANIST, + JOB_ID_CHEF, + JOB_ID_JANITOR, + JOB_ID_ENTERTAINER, + JOB_ID_CHAPLAIN, + JOB_ID_LIBRARIAN, + JOB_ID_ASSISTANT, + JOB_ID_OFFDUTY_CIVILLIAN, + JOB_ID_OFFDUTY_EXPLORER, + JOB_ID_OFFDUTY_MEDBAY, + JOB_ID_OFFDUTY_CARGO, + JOB_ID_OFFDUTY_ENGINEER, + JOB_ID_OFFDUTY_SCIENCE + ) diff --git a/code/modules/lore_hardcoded/origin.dm b/code/modules/lore_hardcoded/origin.dm new file mode 100644 index 00000000000..5b46658968f --- /dev/null +++ b/code/modules/lore_hardcoded/origin.dm @@ -0,0 +1,22 @@ +/datum/lore/character_background/origin + abstract_type = /datum/lore/character_background/origin + /// category + var/category = "Misc" + +/datum/lore/character_background/origin/check_character_species(datum/character_species/S) + if(S.species_fluff_flags & SPECIES_FLUFF_PICKY_ORIGIN) + . = (S.uid in allow_species) || (subspecies_included && S.is_subspecies && (S.superspecies_id in allow_species)) + if(!.) + return + return ..() + +/datum/lore/character_background/origin/qerrbalak + name = "Qerr'Balak" + id = "qerrbalak" + desc = "Be it from the jungle-wrapped kingdoms of the skrellian continents, the cold teshari territories of the polar tundras, or somewhere in-between, you hail from the Vikara Combine's capital planet of Qerr'Balak." + +/datum/lore/character_background/origin/custom + name = "Other" + id = "custom" + desc = "Whether it may be a frontier planet, some backwater asteroid mining colony, or simply somewhere not mentioned otherwise, you didn't come from any of the above." + category = "Misc" diff --git a/code/modules/lore_hardcoded/origin/hegemony/SHOVE_THINGS_HERE.dm b/code/modules/lore_hardcoded/origin/hegemony/SHOVE_THINGS_HERE.dm new file mode 100644 index 00000000000..ca6005b8855 --- /dev/null +++ b/code/modules/lore_hardcoded/origin/hegemony/SHOVE_THINGS_HERE.dm @@ -0,0 +1,13 @@ +// /datum/lore/character_background/origin/oricon/sol +// abstract_type = /datum/lore/character_background/origin/oricon/sol + +// /datum/lore/character_background/origin/oricon/sol/venusian +// name = "Venus" +// id = "venus" +// desc = "Unlike almost anyone else who would call a planet their home, you've never been to your own planet's surface. Instead, you are from one of the myriad orbital complexes floating in venusian space, used to seeing it's white cloudtops shimmer in the distance amid the pitch blackness of space." +// innate_languages = list( +// LANGUAGE_ID_HUMAN +// ) + +// ABOVE IS EXAMPLE +// #warn deal with this folder diff --git a/code/modules/lore_hardcoded/origin/hegemony/_hegemony.dm b/code/modules/lore_hardcoded/origin/hegemony/_hegemony.dm new file mode 100644 index 00000000000..414747c0b01 --- /dev/null +++ b/code/modules/lore_hardcoded/origin/hegemony/_hegemony.dm @@ -0,0 +1,3 @@ +/datum/lore/character_background/origin/hegemony + abstract_type = /datum/lore/character_background/origin/hegemony + category = "Hegemony" diff --git a/code/modules/lore_hardcoded/origin/hegemony/naramadi.dm b/code/modules/lore_hardcoded/origin/hegemony/naramadi.dm new file mode 100644 index 00000000000..ccdb99769cf --- /dev/null +++ b/code/modules/lore_hardcoded/origin/hegemony/naramadi.dm @@ -0,0 +1,38 @@ +/datum/lore/character_background/origin/hegemony/naramadi + abstract_type = /datum/lore/character_background/origin/hegemony/naramadi + +/datum/lore/character_background/origin/hegemony/naramadi/houses + name = "Naramadi Houses" + id = "naramadihouses" + desc = "The upper class of the Naramadi Ascendancy, the Houses, are what is considered a 'citizen class' of their society. \ + While House members enjoy certain rights that others do not, the main difference is that Houses are allowed to dictate the direction of the Ascendancy \ + through the Landsmeet. As well as owning land, industry and agricultural sites, Houses provide the majority of military and logistical power to the Ascendancy. " + innate_languages = list( + LANGUAGE_ID_UNATHI, + LANGUAGE_ID_NARAMADI + ) + +/datum/lore/character_background/origin/hegemony/naramadi/nameless + name = "Nameless" + id = "nameless" + desc = "While the Houses are the most well known part of the Naramadi Society, and the only ones considered true citizens, \ + the so-called Nameless form a majority of the Ascendancy. While lacking certain rights within the Naramadi Ascendancy, \ + such as the right to vote and freedom of movement, they are encouraged to 'ascend' and attempt to join a House through rites appropriate to said House." + innate_languages = list( + LANGUAGE_ID_NARAMADI, + LANGUAGE_ID_UNATHI + ) + +/datum/lore/character_background/origin/hegemony/naramadi/exiles + name = "Naramadi Exiles" + id = "naramadi_exiles" + desc = "Exile is considered the last course for punishments' within the isolationist Ascendancy. \ + Houses are always tight-knit, and being removed from them is like loosing a limb for many of the House Members. \ + The majority of the Exiles that were present in the Ascendancy hated their brethren, which lead to the attempted uprising. \ + After which, the failed majority of the Exiles left for Orion Confederacy to shape their own way, away from the isolated Naramadi Home." + allow_species = list( + SPECIES_ID_NARAMADI + ) + innate_languages = list( + LANGUAGE_ID_NARAMADI + ) diff --git a/code/modules/lore_hardcoded/origin/hegemony/unathi.dm b/code/modules/lore_hardcoded/origin/hegemony/unathi.dm new file mode 100644 index 00000000000..b67875af066 --- /dev/null +++ b/code/modules/lore_hardcoded/origin/hegemony/unathi.dm @@ -0,0 +1,30 @@ +/datum/lore/character_background/origin/hegemony/unathi + abstract_type = /datum/lore/character_background/origin/hegemony/unathi + +/datum/lore/character_background/origin/hegemony/unathi/zaddatcolony + name = "Zaddat Colony" + id = "zaddatcolony" + desc = "A lone Zaddat Colony ship, and it's escort craft. Plying the stars with their onboard Guilds, they often pass through civilized space in exchange for the labor of some or all of their crafts. Most welcome the help, while others disdain them for their trespass." + innate_languages = list( + LANGUAGE_ID_ZADDAT + ) + +/datum/lore/character_background/origin/hegemony/unathi/moghes + name = "Moghes" + id = "moghes" + desc = "The cradle of Unathi civilization, their homeworld. It's regional denominations set the standard for Clan culture to today, and all Clans trace their lineage back to this point in one form or another. Ecologically preserved, it serves as testament to Unathi tradition." + allow_species = list( + SPECIES_ID_UNATHI, + SPECIES_ID_ZADDAT + ) + innate_languages = list( + LANGUAGE_ID_UNATHI + ) + +/datum/lore/character_background/origin/hegemony/unathi/tersten + name = "Tersten" + id = "tersten" + desc = "A world presented as the 'ideal' version of Humans being subjugated by Unathi. Many Humans have in fact found success in their careers on Tersten, but often find themselves opposed by their overlords. Despite this the planet is one of the few open ports found within Hegemony space." + innate_languages = list( + LANGUAGE_ID_UNATHI + ) diff --git a/code/modules/lore_hardcoded/origin/oricon/_oricon.dm b/code/modules/lore_hardcoded/origin/oricon/_oricon.dm new file mode 100644 index 00000000000..30a8f3de56c --- /dev/null +++ b/code/modules/lore_hardcoded/origin/oricon/_oricon.dm @@ -0,0 +1,3 @@ +/datum/lore/character_background/origin/oricon + abstract_type = /datum/lore/character_background/origin/oricon + category = "OriCon" diff --git a/code/modules/lore_hardcoded/origin/oricon/sol.dm b/code/modules/lore_hardcoded/origin/oricon/sol.dm new file mode 100644 index 00000000000..82b1d935b65 --- /dev/null +++ b/code/modules/lore_hardcoded/origin/oricon/sol.dm @@ -0,0 +1,101 @@ +/datum/lore/character_background/origin/oricon/sol + abstract_type = /datum/lore/character_background/origin/oricon/sol + innate_languages = list( + LANGUAGE_ID_HUMAN + ) + +/datum/lore/character_background/origin/oricon/sol/venusian + name = "Venus" + id = "venus" + desc = "Unlike almost anyone else who would call a planet their home, you've never been to your own planet's surface. Instead, you are from one of the myriad orbital complexes floating in venusian space, used to seeing it's white cloudtops shimmer in the distance amid the pitch blackness of space." + +/datum/lore/character_background/origin/oricon/sol/terran + name = "Terra" + id = "terra" + desc = "You are from Humanity's storied homeworld of Terra. Whether you are from the arcologies spanning much of the planet's verdant surface, or it's many orbital habitats, you are likely to have been taught much about humanity's long history upon Earth." + +/datum/lore/character_background/origin/oricon/sol/lunarian + name = "Luna" + id = "luna" + desc = "You hail directly from Sol's capital body, the terran moon of Luna. It's intricately built and unimaginably busy underground metropolises are the beating heart of modern human culture, and one you know very well at that." + + +/datum/lore/character_background/origin/oricon/sol/martian + name = "Mars" + id = "mars" + desc = "Blue sunsets upon red sands would be a familiar sight for a Martian such as yourself. You have likely met many Tyrmalin (and possibly are one yourself!) somewhere in the industrial powerhouse that is Mars." + +/datum/lore/character_background/origin/oricon/sol/phobian + name = "Phobos" + id = "phobos" + desc = "Not quite from the red planet itself, you nonetheless know it well, if from a distance. Though a very tiny settlement by every metric, your time in Sol's largest shipyard has likely made you well-acquainted with the intricacies of spacefaring vessels." + +/datum/lore/character_background/origin/oricon/sol/cererian + name = "Ceres" + id = "ceres" + desc = "Though you've no doubt been around Sol's Main Belt at least a couple times, everyone always lands back at Ceres eventually, or so they say. You have seen both the no-nonsense work of asteroid mining operations and the luxurious halls of the big casinos back home in Ceres." + +/datum/lore/character_background/origin/oricon/sol/jovian + name = "Jupiter" + id = "jupiter" + desc = "From either one of Jupiter's countless minor moons and trojan asteroids, or from a space station somewhere in orbit of the gas giant itself, you are quite used to commonplace space travel between the moons and habitats of the bustling Jovian subsystem." + +/datum/lore/character_background/origin/oricon/sol/europan + name = "Europa" + id = "europa" + desc = "Buried safely under the ice, you have once called the jovian moon of Europa your home. Though most only rarely visit it's irradiated surface, anyone there has seen the spacious arcologies which tunnel beneath it, winding all the way down to the moon's frighteningly deep inner ocean." + +/datum/lore/character_background/origin/oricon/sol/ganymedean + name = "Ganymede" + id = "ganymede" + desc = "The largest moon of the Sol System, Ganymede was once your home. The sight of glowing auroras likely remind you of your time there... and of all the radiation there would've been outside, beneath them." + +/datum/lore/character_background/origin/oricon/sol/callistoan + name = "Callisto" + id = "callisto" + desc = "You are from the very cornerstone of the Jovian system itself, the land of it's first settlement, Callisto. You are used to seeing the other moons circle around Jupiter from a safe distance under the windows of biodomes dotting the large ring-shaped cities of Valhalla and Asgard." + +/datum/lore/character_background/origin/oricon/sol/saturnian + name = "Saturn" + id = "saturn" + desc = "Whether from a minor moon's settlement or a habitat in orbit of the Sol System's crown jewel, you come from saturnian space. Somehow, the view of it's rings really doesn't ever get old." + +/datum/lore/character_background/origin/oricon/sol/titanean + name = "Titan" + id = "titan" + desc = "Moon or not, Titan hardly feels like one on the rainy surface. Whether a synthetic or brave organic once living among it's seas of cryogenically cold methane, you come from the highly-flammable world of Titan." + +/datum/lore/character_background/origin/oricon/sol/enceladean + name = "Enceladus" + id = "enceladus" + desc = "White as pristine snow, the world of Enceladus is where you're from. You're well-acquainted with the underwater environment of it's subsurface ocean and have likely seen the fractures along the surface blanketing the dark sky in plumes of snow with your own eyes." + +/datum/lore/character_background/origin/oricon/sol/uranian + name = "Uranus" + id = "uranus" + desc = "The exception of Sol's gas giants in many ways, you are from one of the many large space stations orbiting Uranus. Most people you have known from home worked for one of the gas harvesting and refining companies in some way. Perhaps Phoron is not so different after all?" + +/datum/lore/character_background/origin/oricon/sol/titanian + name = "Titania" + id = "titania" + desc = "A quiet corner of Sol by most standards, Titania is your home. However, you are no stranger to having to travel away from it, as one would not have found a settlement larger than a small hydroponics-farming town back in Titania." + +/datum/lore/character_background/origin/oricon/sol/neptunian + name = "Neptune" + id = "neptune" + desc = "You come from one of the many space habitats orbiting low over the azure skies of Neptune. The furthest planet from Sol, you know the star best as a dim dot, casting it's cold light towards you from far in the distance." + +/datum/lore/character_background/origin/oricon/sol/tritonian + name = "Triton" + id = "triton" + desc = "Orbiting retrograde around Neptune, the frigid world of Triton was once your home. As it is too, home of scientists and businessmen, more often than not related to the trident planet's fuel export industry." + +/datum/lore/character_background/origin/oricon/sol/plutocharonian + name = "Pluto-Charon" + id = "plutocharon" + desc = "Two parts of the same whole, as every pluto-charonian knows, the twin ice-worlds of the Kuiper Belt were once your home. Whichever half you happened to live on, you have seen the tether which looms above, linking both dwarf-planets together as glowing city lights sprawl away from it's connection points into each." + +/datum/lore/character_background/origin/oricon/sol/eridian + name = "Eris" + id = "eris" + desc = "You are from one of the outermost colonies of the Sol System, the dwarf-planet Eris. Every city you have known there was compact, and buried under kilometers of frozen nitrogen and water ice, with immense freight elevators as the primary way out to the spaceports on it's desolate surface." diff --git a/code/modules/lore_hardcoded/religion.dm b/code/modules/lore_hardcoded/religion.dm new file mode 100644 index 00000000000..790407400bf --- /dev/null +++ b/code/modules/lore_hardcoded/religion.dm @@ -0,0 +1,14 @@ +/datum/lore/character_background/religion + abstract_type = /datum/lore/character_background/religion + +/datum/lore/character_background/religion/check_character_species(datum/character_species/S) + if(S.species_fluff_flags & SPECIES_FLUFF_PICKY_RELIGION) + . = (S.uid in allow_species) || (subspecies_included && S.is_subspecies && (S.superspecies_id in allow_species)) + if(!.) + return + return ..() + +/datum/lore/character_background/religion/custom + name = "Other" + id = "custom" + desc = "Whether you're in a small sect of a niche religion, or simply have nonstandard beliefs, you don't fit into any of the above." diff --git a/code/modules/mapping/preloader.dm b/code/modules/mapping/preloader.dm index ae37879ad72..0387e570c01 100644 --- a/code/modules/mapping/preloader.dm +++ b/code/modules/mapping/preloader.dm @@ -21,7 +21,7 @@ GLOBAL_DATUM_INIT(_preloader, /datum/map_preloader, new) for(var/attribute in preloader_local.attributes) var/value = preloader_local.attributes[attribute] if(islist(value)) - value = deepCopyList(value) + value = deep_copy_list(value) #ifdef TESTING if(what.vars[attribute] == value) var/message = "[what.type] at [AREACOORD(what)] - VAR: [attribute] = [isnull(value) ? "null" : (isnum(value) ? value : "\"[value]\"")]" diff --git a/code/modules/maps/misc_maps/trade/trade_station_jobs.dm b/code/modules/maps/misc_maps/trade/trade_station_jobs.dm index b4dd27fce3a..47900f92855 100644 --- a/code/modules/maps/misc_maps/trade/trade_station_jobs.dm +++ b/code/modules/maps/misc_maps/trade/trade_station_jobs.dm @@ -3,13 +3,14 @@ name = DEPARTMENT_TRADE short_name = "Beruang" color = "#afccb8" - sorting_order = -3 + sorting_order = 50 assignable = FALSE visible = FALSE /datum/job/trader title = "Trader" flag = TRADER + id = JOB_ID_TRADER // department = "Trader" //department_flag = TRADE department_flag = CIVILIAN diff --git a/code/modules/maps/tether/levels/alienship.dm b/code/modules/maps/tether/levels/alienship.dm index 0baeb006d47..a117803b427 100644 --- a/code/modules/maps/tether/levels/alienship.dm +++ b/code/modules/maps/tether/levels/alienship.dm @@ -128,7 +128,7 @@ R.update_power() //Teleport time! - for(var/mob in player_list) //This is extreme, but it's very hard to find people hiding in things, and this is pretty cheap. + for(var/mob in GLOB.player_list) //This is extreme, but it's very hard to find people hiding in things, and this is pretty cheap. try if(isliving(mob) && get_area(mob) == src) abduct(mob) diff --git a/code/modules/metric/activity.dm b/code/modules/metric/activity.dm index c33c88adcaf..6773c77fd46 100644 --- a/code/modules/metric/activity.dm +++ b/code/modules/metric/activity.dm @@ -27,7 +27,7 @@ return var/departmental_activity = 0 var/departmental_size = 0 - for(var/mob/M in player_list) + for(var/mob/M in GLOB.player_list) if(guess_department(M) != department) // Ignore people outside the department we're assessing. continue departmental_activity += assess_player_activity(M) @@ -66,7 +66,7 @@ /datum/metric/proc/assess_all_living_mobs() // Living refers to the type, not the stat variable. . = 0 var/num = 0 - for(var/mob/living/L in player_list) + for(var/mob/living/L in GLOB.player_list) . += assess_player_activity(L) num++ if(num) @@ -75,7 +75,7 @@ /datum/metric/proc/assess_all_dead_mobs() // Ditto. . = 0 var/num = 0 - for(var/mob/observer/dead/O in player_list) + for(var/mob/observer/dead/O in GLOB.player_list) . += assess_player_activity(O) num++ if(num) @@ -84,7 +84,7 @@ /datum/metric/proc/assess_all_outdoor_mobs() . = 0 var/num = 0 - for(var/mob/living/L in player_list) + for(var/mob/living/L in GLOB.player_list) var/turf/T = get_turf(L) if(istype(T) && !istype(T, /turf/space) && T.outdoors) . += assess_player_activity(L) diff --git a/code/modules/metric/count.dm b/code/modules/metric/count.dm index 79ff2910811..7aea60eeb73 100644 --- a/code/modules/metric/count.dm +++ b/code/modules/metric/count.dm @@ -4,7 +4,7 @@ /datum/metric/proc/count_all_outdoor_mobs(var/cutoff = 75) var/num = 0 - for(var/mob/living/L in player_list) + for(var/mob/living/L in GLOB.player_list) var/turf/T = get_turf(L) if(istype(T) && !istype(T, /turf/space) && T.outdoors) if(assess_player_activity(L) >= cutoff) @@ -13,7 +13,7 @@ /datum/metric/proc/count_all_space_mobs(var/cutoff = 75, var/respect_z = TRUE) var/num = 0 - for(var/mob/living/L in player_list) + for(var/mob/living/L in GLOB.player_list) var/turf/T = get_turf(L) if(istype(T, /turf/space) && istype(T.loc, /area/space)) if(respect_z && !(L.z in GLOB.using_map.station_levels)) @@ -26,7 +26,7 @@ // Note that `ignore_synths` makes this proc ignore posibrains and drones, but NOT cyborgs, as they are still the same species in-universe. /datum/metric/proc/count_all_of_specific_species(species_name, ignore_synths = TRUE, cutoff = 75, respect_z = TRUE) var/num = 0 - for(var/mob/living/carbon/human/H in player_list) + for(var/mob/living/carbon/human/H in GLOB.player_list) if(respect_z && !(H.z in GLOB.using_map.station_levels)) continue if(ignore_synths && H.isSynthetic() && H.get_FBP_type() != FBP_CYBORG) @@ -39,7 +39,7 @@ // Gives a count of how many FBPs of a specific type there are on the station. /datum/metric/proc/count_all_FBPs_of_kind(desired_FBP_class, cutoff = 75, respect_z = TRUE) var/num = 0 - for(var/mob/living/carbon/human/H in player_list) + for(var/mob/living/carbon/human/H in GLOB.player_list) if(respect_z && !(H.z in GLOB.using_map.station_levels)) continue if(H.get_FBP_type() != desired_FBP_class) @@ -58,7 +58,7 @@ /datum/metric/proc/get_all_antags(cutoff = 75) . = list() - for(var/mob/living/L in player_list) + for(var/mob/living/L in GLOB.player_list) if(L.mind && player_is_antag(L.mind) && assess_player_activity(L) >= cutoff) . += L diff --git a/code/modules/metric/department.dm b/code/modules/metric/department.dm index 0858e392ee0..4792434f772 100644 --- a/code/modules/metric/department.dm +++ b/code/modules/metric/department.dm @@ -69,7 +69,7 @@ . = list() if(!department) return - for(var/mob/M in player_list) + for(var/mob/M in GLOB.player_list) // Do not count AI's shells if(isrobot(M)) var/mob/living/silicon/robot/R = M @@ -84,12 +84,12 @@ /datum/metric/proc/get_people_with_job(job_type, cutoff = 75) . = list() // First, get the name. - var/datum/job/J = SSjob.get_job_type(job_type) + var/datum/job/J = SSjob.job_by_type(job_type) if(!istype(J)) return // Now find people with the job name. - for(var/M in player_list) + for(var/M in GLOB.player_list) var/datum/job/their_job = guess_job(M) if(!istype(their_job)) // No job was guessed. continue @@ -109,7 +109,7 @@ . = list() var/list/people_with_jobs = get_people_with_job(job_type, cutoff) - var/datum/job/J = SSjob.get_job_type(job_type) + var/datum/job/J = SSjob.job_by_type(job_type) var/datum/alt_title/A = new alt_title_type() for(var/M in people_with_jobs) diff --git a/code/modules/mob/dead/observer/free_vr.dm b/code/modules/mob/dead/observer/free_vr.dm index 5aed033a21d..0db6c2adfde 100644 --- a/code/modules/mob/dead/observer/free_vr.dm +++ b/code/modules/mob/dead/observer/free_vr.dm @@ -41,7 +41,7 @@ var/global/list/prevent_respawns = list() //Job slot cleanup var/job = src.mind.assigned_role - job_master.FreeRole(job) + SSjob.FreeRole(job) //Their objectives cleanup if(src.mind.objectives.len) diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm index 426f5da3cb3..4460c19fad6 100644 --- a/code/modules/mob/dead/observer/observer.dm +++ b/code/modules/mob/dead/observer/observer.dm @@ -135,7 +135,7 @@ mind = body.mind //we don't transfer the mind but we keep a reference to it. if(!T) - T = SSjob.GetLatejoinSpawnpoint() + T = SSjob.get_latejoin_spawnpoint() forceMove(T) for(var/v in GLOB.active_alternate_appearances) @@ -687,7 +687,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp set desc = "Toggles showing your key in dead chat." client.toggle_preference(/datum/client_preference/anonymous_ghost_chat) - SScharacter_setup.queue_preferences_save(client.prefs) + SScharacters.queue_preferences_save(client.prefs) if(is_preference_enabled(/datum/client_preference/anonymous_ghost_chat)) to_chat(src, "Your key won't be shown when you speak in dead chat.") else diff --git a/code/modules/mob/dead/observer/observer_movement.dm b/code/modules/mob/dead/observer/observer_movement.dm index 706d33f8df1..887cda18150 100644 --- a/code/modules/mob/dead/observer/observer_movement.dm +++ b/code/modules/mob/dead/observer/observer_movement.dm @@ -23,5 +23,5 @@ /mob/observer/dead/Process_Spacemove(dir) return TRUE //we don't drift. -/mob/dead/observer/canface() +/mob/observer/dead/canface() return TRUE diff --git a/code/modules/mob/dead/observer/observer_vr.dm b/code/modules/mob/dead/observer/observer_vr.dm index dfd16593063..85fc8ec1c65 100644 --- a/code/modules/mob/dead/observer/observer_vr.dm +++ b/code/modules/mob/dead/observer/observer_vr.dm @@ -4,7 +4,7 @@ set desc = "Select a player with a working NIF + Soulcatcher NIFSoft to join into it." var/list/filtered = list() - for(var/mob/living/carbon/human/H in player_list) + for(var/mob/living/carbon/human/H in GLOB.player_list) if(!H.nif?.imp_check(NIF_SOULCATCHER)) continue var/datum/nifsoft/soulcatcher/SC = H.nif.imp_check(NIF_SOULCATCHER) diff --git a/code/modules/mob/grab.dm b/code/modules/mob/grab.dm index 402d29e9ee3..866f4c3b3c3 100644 --- a/code/modules/mob/grab.dm +++ b/code/modules/mob/grab.dm @@ -495,7 +495,7 @@ attacker.visible_message("[attacker] [pick("bent", "twisted")] [target]'s [organ.name] into a jointlock!") - if(target.species.flags & NO_PAIN) + if(target.species.species_flags & NO_PAIN) return var/armor = target.run_armor_check(target, "melee") diff --git a/code/modules/mob/hear_say.dm b/code/modules/mob/hear_say.dm index 9ddd37412d6..c4bf01af631 100644 --- a/code/modules/mob/hear_say.dm +++ b/code/modules/mob/hear_say.dm @@ -25,11 +25,11 @@ return //non-verbal languages are garbled if you can't see the speaker. Yes, this includes if they are inside a closet. - if (language && (language.flags & NONVERBAL)) + if (language && (language.language_flags & NONVERBAL)) if (!speaker || (src.sdisabilities & SDISABILITY_NERVOUS || src.blinded) || !(speaker in view(src))) message = stars(message) - if(!(language && (language.flags & INNATE))) // skip understanding checks for INNATE languages + if(!(language && (language.language_flags & INNATE))) // skip understanding checks for INNATE languages if(!say_understands(speaker,language)) if(language) message = language.scramble(message, languages) @@ -57,7 +57,7 @@ message = "[message]" if(is_deaf()) - if(!language || !(language.flags & INNATE)) // INNATE is the flag for audible-emote-language, so we don't want to show an "x talks but you cannot hear them" message if it's set + if(!language || !(language.language_flags & INNATE)) // INNATE is the flag for audible-emote-language, so we don't want to show an "x talks but you cannot hear them" message if it's set if(speaker == src) to_chat(src, "You cannot hear yourself speak!") else @@ -153,11 +153,11 @@ var/track = null //non-verbal languages are garbled if you can't see the speaker. Yes, this includes if they are inside a closet. - if (language && (language.flags & NONVERBAL)) + if (language && (language.language_flags & NONVERBAL)) if (!speaker || (src.sdisabilities & SDISABILITY_NERVOUS || src.blinded) || !(speaker in view(src))) message = stars(message) - if(!(language && (language.flags & INNATE))) // skip understanding checks for INNATE languages + if(!(language && (language.language_flags & INNATE))) // skip understanding checks for INNATE languages if(!say_understands(speaker,language)) if(language) message = language.scramble(message, languages) diff --git a/code/modules/mob/inventory.dm b/code/modules/mob/inventory.dm index af1b69ea1a8..7551d1e520a 100644 --- a/code/modules/mob/inventory.dm +++ b/code/modules/mob/inventory.dm @@ -1,3 +1,5 @@ +// todo: see all this? needs to be decided what to do with and shoved into the inventory handling system proper once evaluated. + /mob var/obj/item/storage/s_active = null // Even ghosts can/should be able to peek into boxes on the ground diff --git a/code/modules/mob/living/autohiss.dm b/code/modules/mob/living/autohiss.dm index 921bc53c8e5..2bbfdd0ad0a 100644 --- a/code/modules/mob/living/autohiss.dm +++ b/code/modules/mob/living/autohiss.dm @@ -9,7 +9,7 @@ if(!maps.basic) return message - if(L.flags & NO_STUTTER) // Currently prevents EAL, Sign language, and emotes from autohissing + if(L.language_flags & NO_STUTTER) // Currently prevents EAL, Sign language, and emotes from autohissing return message if(maps.exempt && (L.name in maps.exempt)) return message diff --git a/code/modules/mob/living/bot/bot.dm b/code/modules/mob/living/bot/bot.dm index 7ddfcc5a22e..bc08f56c714 100644 --- a/code/modules/mob/living/bot/bot.dm +++ b/code/modules/mob/living/bot/bot.dm @@ -78,7 +78,7 @@ . = ..() update_icons() - default_language = GLOB.all_languages[LANGUAGE_GALCOM] + default_language = SScharacters.resolve_language_name(LANGUAGE_GALCOM) botcard = new /obj/item/card/id(src) botcard.access = botcard_access.Copy() diff --git a/code/modules/mob/living/carbon/alien/diona/diona.dm b/code/modules/mob/living/carbon/alien/diona/diona.dm index 4e2efc629ac..a97e68e0371 100644 --- a/code/modules/mob/living/carbon/alien/diona/diona.dm +++ b/code/modules/mob/living/carbon/alien/diona/diona.dm @@ -22,7 +22,7 @@ /mob/living/carbon/alien/diona/Initialize(mapload) . = ..() - species = get_static_species_meta(/datum/species/diona) + species = SScharacters.resolve_species_path(/datum/species/diona) add_language(LANGUAGE_ROOTGLOBAL) add_language(LANGUAGE_GALCOM) verbs += /mob/living/carbon/alien/diona/proc/merge diff --git a/code/modules/mob/living/carbon/alien/diona/progression.dm b/code/modules/mob/living/carbon/alien/diona/progression.dm index 9aedfb729e5..63414cbad9e 100644 --- a/code/modules/mob/living/carbon/alien/diona/progression.dm +++ b/code/modules/mob/living/carbon/alien/diona/progression.dm @@ -1,5 +1,5 @@ /mob/living/carbon/alien/diona/confirm_evolution() - if(!is_alien_whitelisted(src, get_static_species_meta(/datum/species/diona))) + if(!config.check_alien_whitelist(SPECIES_DIONA, ckey)) alert(src, "You are currently not whitelisted to play as a full diona.", "Evolution Error") return diff --git a/code/modules/mob/living/carbon/alien/progression.dm b/code/modules/mob/living/carbon/alien/progression.dm index 2a2ef1d3eaf..655210db527 100644 --- a/code/modules/mob/living/carbon/alien/progression.dm +++ b/code/modules/mob/living/carbon/alien/progression.dm @@ -25,7 +25,7 @@ return var/mob/living/carbon/human/adult = new adult_form(get_turf(src)) - adult.set_species(species_type_by_name(new_species)) + adult.set_species(new_species) show_evolution_blurb() transfer_languages(src, adult) diff --git a/code/modules/mob/living/carbon/brain/posibrain.dm b/code/modules/mob/living/carbon/brain/posibrain.dm index cfde2ceae79..ae592a0e95d 100644 --- a/code/modules/mob/living/carbon/brain/posibrain.dm +++ b/code/modules/mob/living/carbon/brain/posibrain.dm @@ -56,7 +56,7 @@ update_appearance() /obj/item/mmi/digital/posibrain/proc/request_player() - for(var/mob/observer/dead/O in player_list) + for(var/mob/observer/dead/O in GLOB.player_list) if(!O.MayRespawn()) continue if(jobban_isbanned(O, "AI") && jobban_isbanned(O, "Cyborg")) diff --git a/code/modules/mob/living/carbon/brain/say.dm b/code/modules/mob/living/carbon/brain/say.dm index b6da26e1a41..87d56664b6c 100644 --- a/code/modules/mob/living/carbon/brain/say.dm +++ b/code/modules/mob/living/carbon/brain/say.dm @@ -27,7 +27,7 @@ else message = Gibberish(message, (emp_damage*6))//scrambles the message, gets worse when emp_damage is higher - if(speaking && speaking.flags & HIVEMIND) + if(speaking && speaking.language_flags & HIVEMIND) speaking.broadcast(src,trim(message)) return diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 3e5093b6f7b..6691432c035 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -6,7 +6,7 @@ touching = new/datum/reagents/metabolism/touch(500, src) reagents = bloodstr if (!default_language && species_language) - default_language = GLOB.all_languages[species_language] + default_language = SScharacters.resolve_language_name(species_language) /mob/living/carbon/BiologicalLife(seconds, times_fired) if((. = ..())) @@ -278,12 +278,12 @@ if(can_speak(default_language)) return default_language else - return GLOB.all_languages[LANGUAGE_GIBBERISH] + return SScharacters.resolve_language_name(LANGUAGE_GIBBERISH) if(!species) return null - return species.default_language ? GLOB.all_languages[species.default_language] : null + return species.default_language ? SScharacters.resolve_language_id(species.default_language) : null /mob/living/carbon/proc/should_have_organ(var/organ_check) return 0 @@ -291,7 +291,7 @@ /mob/living/carbon/can_feel_pain(var/check_organ) if(isSynthetic()) return 0 - return !(species.flags & NO_PAIN) + return !(species.species_flags & NO_PAIN) /mob/living/carbon/needs_to_breathe() if(does_not_breathe) diff --git a/code/modules/mob/living/carbon/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm index b226ed652ca..6b5bafe319e 100644 --- a/code/modules/mob/living/carbon/carbon_defense.dm +++ b/code/modules/mob/living/carbon/carbon_defense.dm @@ -55,7 +55,7 @@ if(status_flags & GODMODE) return 0 //godmode if(def_zone == "l_hand" || def_zone == "r_hand") //Diona (And any other potential plant people) hands don't get shocked. - if(species.flags & IS_PLANT) + if(species.species_flags & IS_PLANT) return 0 shock_damage *= siemens_coeff if (shock_damage<1) diff --git a/code/modules/mob/living/carbon/human/appearance.dm b/code/modules/mob/living/carbon/human/appearance.dm index ff5b61b15e2..ccc6b80479a 100644 --- a/code/modules/mob/living/carbon/human/appearance.dm +++ b/code/modules/mob/living/carbon/human/appearance.dm @@ -10,7 +10,7 @@ if(species == new_species) return - if(!(new_species in all_species_names())) + if(!(new_species in SScharacters.all_species_names())) return set_species(new_species) @@ -184,17 +184,17 @@ /mob/living/carbon/human/proc/generate_valid_species(var/check_whitelist = 1, var/list/whitelist = list(), var/list/blacklist = list()) var/list/valid_species = new() - for(var/datum/species/S in all_static_species_meta()) + for(var/datum/species/S in SScharacters.all_static_species_meta()) var/current_species_name = S.name if(check_whitelist && config_legacy.usealienwhitelist && !check_rights(R_ADMIN, 0, src)) //If we're using the whitelist, make sure to check it! - if(!(S.spawn_flags & SPECIES_CAN_JOIN)) + if(!(S.species_spawn_flags & SPECIES_SPAWN_ALLOWED)) continue if(whitelist.len && !(current_species_name in whitelist)) continue if(blacklist.len && (current_species_name in blacklist)) continue - if((S.spawn_flags & SPECIES_IS_WHITELISTED) && !is_alien_whitelisted(src, S)) + if((S.species_spawn_flags & SPECIES_SPAWN_WHITELISTED) && !config.check_alien_whitelist(ckey(S.name), ckey)) continue valid_species += current_species_name diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 54b5b2d84a0..90eee362f28 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -1,16 +1,19 @@ -/mob/living/carbon/human/Initialize(mapload, datum/species/new_species_or_path) +/** + * constructor; pass in a specieslike resolver as second argument to set + * + * specieslike resolver = species datum, id, path, or name. + */ +/mob/living/carbon/human/Initialize(mapload, datum/species/specieslike) + . = ..() + if(!dna) dna = new /datum/dna(null) // Species name is handled by set_species() - if(new_species_or_path) - set_species(new_species_or_path, force = TRUE, regen_icons = FALSE) - else if(!istype(species)) - // no one set us yet - if(ispath(species)) - set_species(species, force = TRUE, regen_icons = FALSE) - else - set_species(force = TRUE, regen_icons = FALSE) + if(specieslike) + set_species(specieslike, force = TRUE, regen_icons = FALSE) + else + reset_species(force = TRUE) if(!species) stack_trace("Why is there no species? Resetting to human.") // NO NO, YOU DONT GET TO CHICKEN OUT, SET_SPECIES WAS CALLED AND YOU BETTER HAVE ONE @@ -28,9 +31,6 @@ AddComponent(/datum/component/personal_crafting) human_mob_list |= src - - . = ..() - hide_underwear.Cut() for(var/category in GLOB.global_underwear.categories_by_name) hide_underwear[category] = FALSE @@ -1060,51 +1060,41 @@ /** * Sets a human mob's species. * - * Accepts a typepath or species instance + * todo: no more using anything id, and MAYBE path/direct datum; we really don't like names, + * todo: and things generally shouldn't be making species datums. * * @param - * - species_or_path - species instance or typepath + * - specieslike - species instance, id, typepath, or name; if null, we reset species to dna. * - regen_icons - immediately update icons? * - force - change even if we are already that species **by type** * - skip - skip most ops that aren't apply or remove which are required for instance cleanup. do not do this unless you absolutely know what you are doing. * - example - dumbshit argument used for vore transformations to copy necessary data, why tf is this not done in the vore module? //TODO: REMOVE. */ -/mob/living/carbon/human/proc/set_species(datum/species/species_or_path, regen_icons = TRUE, force = FALSE, skip, mob/living/carbon/human/example) - // check if we need to - if(!force && species_or_path) - if(istype(species, istype(species_or_path)? species_or_path.type : species_or_path)) - // already are that typepath, don't bother - return - - if(!species_or_path) - // try to get default - // priority one: dna - if(dna?.species) - var/path = species_type_by_name(dna.species) - if(!path) - CRASH("dna species invalid name: [dna.species]") - species_or_path = path - // priority two: species var - else if(ispath(species)) - species_or_path = species - // priority 3: human - else - species_or_path = /datum/species/human +/mob/living/carbon/human/proc/set_species(datum/species/specieslike, regen_icons = TRUE, force = FALSE, skip, mob/living/carbon/human/example) + ASSERT(specieslike) + // resolve id + var/resolved_id + var/datum/species/resolving + if(istype(specieslike)) + resolving = specieslike + else + resolving = SScharacters.resolve_species(specieslike) + ASSERT(istype(resolving)) + resolved_id = resolving.uid + if(!force && (species?.uid == resolved_id)) + return var/datum/species/S - // if we're a typepath instead of a species instance - if(ispath(species_or_path)) - ASSERT(species_or_path in GLOB.species_meta) // check that too - S = new species_or_path - else if(!istype(species_or_path)) - // make sure no one did a bad call - CRASH("Invalid species change attempt: [species_or_path]") + // provided? if so, set + // (and hope to god the provider isn't stupid and didn't quantum entangle a datum) + // if not provided, make a new one + if(istype(specieslike)) + if(SScharacters.species_paths[specieslike.type] == specieslike) + CRASH("attempted to set species to static datum") + S = specieslike else - // we're a species datum - S = species_or_path - // in the future we might have unique instancing so it'd need a check too, for now, mobs can share species - // (DO NOT DO THIS OR IT WILL BUG OUT AND I **WILL** FIND YOU) + S = SScharacters.construct_species_path(resolving.type) // clean up old species if(istype(species)) @@ -1163,6 +1153,21 @@ regenerate_icons() update_transform() +/** + * resets our species to default with this priority: + * + * 1. dna species + * 2. species var (aka prototype species) + * 3. human + */ +/mob/living/carbon/human/proc/reset_species(force) + if(dna?.species) + return set_species(dna.species, force = force) + else if(ispath(species)) + return set_species(species, force = force) + else + return set_species(/datum/species/human, force = force) + /mob/living/carbon/human/proc/bloody_doodle() set category = "IC" set name = "Write in blood" @@ -1313,14 +1318,14 @@ return ..() /mob/living/carbon/human/getDNA() - if(species.flags & NO_SCAN) + if(species.species_flags & NO_SCAN) return null if(isSynthetic()) return ..() /mob/living/carbon/human/setDNA() - if(species.flags & NO_SCAN) + if(species.species_flags & NO_SCAN) return if(isSynthetic()) return @@ -1347,7 +1352,7 @@ if(C.body_parts_covered & FEET) footcoverage_check = TRUE break - if((species.flags & NO_SLIP && !footcoverage_check) || (shoes && (shoes.clothing_flags & NOSLIP))) //Footwear negates a species' natural traction. + if((species.species_flags & NO_SLIP && !footcoverage_check) || (shoes && (shoes.clothing_flags & NOSLIP))) //Footwear negates a species' natural traction. return 0 if(..(slipped_on,stun_duration)) return 1 @@ -1470,7 +1475,7 @@ if(!istype(check_organ)) return 0 return check_organ.organ_can_feel_pain() - return !(species.flags & NO_PAIN) + return !(species.species_flags & NO_PAIN) /mob/living/carbon/human/is_sentient() if(get_FBP_type() == FBP_DRONE) diff --git a/code/modules/mob/living/carbon/human/human_attackhand.dm b/code/modules/mob/living/carbon/human/human_attackhand.dm index 8a03cddd3df..2f6db0f7f4c 100644 --- a/code/modules/mob/living/carbon/human/human_attackhand.dm +++ b/code/modules/mob/living/carbon/human/human_attackhand.dm @@ -262,7 +262,7 @@ var/randn = rand(1, 100) last_push_time = world.time - if(!(species.flags & NO_SLIP) && randn <= 25) + if(!(species.species_flags & NO_SLIP) && randn <= 25) var/armor_check = run_armor_check(affecting, "melee") apply_effect(3, WEAKEN, armor_check) playsound(src, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) diff --git a/code/modules/mob/living/carbon/human/human_damage.dm b/code/modules/mob/living/carbon/human/human_damage.dm index e18deb292fe..0c0a8413486 100644 --- a/code/modules/mob/living/carbon/human/human_damage.dm +++ b/code/modules/mob/living/carbon/human/human_damage.dm @@ -213,13 +213,13 @@ ..() /mob/living/carbon/human/proc/Stasis(amount) - if((species.flags & NO_SCAN) || isSynthetic()) + if((species.species_flags & NO_SCAN) || isSynthetic()) in_stasis = 0 else in_stasis = amount /mob/living/carbon/human/proc/getStasis() - if((species.flags & NO_SCAN) || isSynthetic()) + if((species.species_flags & NO_SCAN) || isSynthetic()) return 0 return in_stasis @@ -233,12 +233,12 @@ return 0 /mob/living/carbon/human/getCloneLoss() - if((species.flags & NO_SCAN) || isSynthetic()) + if((species.species_flags & NO_SCAN) || isSynthetic()) cloneloss = 0 return ..() /mob/living/carbon/human/setCloneLoss(var/amount) - if((species.flags & NO_SCAN) || isSynthetic()) + if((species.species_flags & NO_SCAN) || isSynthetic()) cloneloss = 0 else ..() @@ -246,7 +246,7 @@ /mob/living/carbon/human/adjustCloneLoss(var/amount) ..() - if((species.flags & NO_SCAN) || isSynthetic()) + if((species.species_flags & NO_SCAN) || isSynthetic()) cloneloss = 0 return @@ -298,19 +298,19 @@ ..() /mob/living/carbon/human/getToxLoss() - if(species.flags & NO_POISON) + if(species.species_flags & NO_POISON) toxloss = 0 return ..() /mob/living/carbon/human/adjustToxLoss(var/amount) - if(species.flags & NO_POISON) + if(species.species_flags & NO_POISON) toxloss = 0 else amount = amount*species.toxins_mod ..(amount) /mob/living/carbon/human/setToxLoss(var/amount) - if(species.flags & NO_POISON) + if(species.species_flags & NO_POISON) toxloss = 0 else ..() diff --git a/code/modules/mob/living/carbon/human/human_movement.dm b/code/modules/mob/living/carbon/human/human_movement.dm index 897a47ea6a0..39f963c2d47 100644 --- a/code/modules/mob/living/carbon/human/human_movement.dm +++ b/code/modules/mob/living/carbon/human/human_movement.dm @@ -202,7 +202,7 @@ /mob/living/carbon/human/Process_Spaceslipping(var/prob_slip = 5) //If knocked out we might just hit it and stop. This makes it possible to get dead bodies and such. - if(species.flags & NO_SLIP) + if(species.species_flags & NO_SLIP) return if(stat) diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm index 21423d0657d..e6374b3feec 100644 --- a/code/modules/mob/living/carbon/human/life.dm +++ b/code/modules/mob/living/carbon/human/life.dm @@ -969,7 +969,7 @@ if(I.contaminated) if(check_belly(I)) continue - if(src.species && !(src.species.flags & CONTAMINATION_IMMUNE)) + if(src.species && !(src.species.species_flags & CONTAMINATION_IMMUNE)) // This is hacky, I'm so sorry. if(I != l_hand && I != r_hand) //If the item isn't in your hands, you're probably wearing it. Full damage for you. total_phoronloss += loss_per_part @@ -1059,7 +1059,7 @@ Paralyse(3) if(hallucination) - if(hallucination >= 20 && !(species.flags & (NO_POISON|IS_PLANT|NO_HALLUCINATION)) ) + if(hallucination >= 20 && !(species.species_flags & (NO_POISON|IS_PLANT|NO_HALLUCINATION)) ) if(prob(3)) fake_attack(src) if(!handling_hal) @@ -1276,7 +1276,7 @@ var/no_damage = 1 var/trauma_val = 0 // Used in calculating softcrit/hardcrit indicators. - if(!(species.flags & NO_PAIN)) + if(!(species.species_flags & NO_PAIN)) trauma_val = max(traumatic_shock,halloss)/species.total_health var/limb_trauma_val = trauma_val*0.3 // Collect and apply the images all at once to avoid appearance churn. @@ -1292,7 +1292,7 @@ // Show a general pain/crit indicator if needed. if(trauma_val) - if(!(species.flags & NO_PAIN)) + if(!(species.species_flags & NO_PAIN)) if(trauma_val > 0.7) health_images += image('icons/mob/screen1_health.dmi',"softcrit") if(trauma_val >= 1) diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm index 08a3f09cef7..dd9aa086e5c 100644 --- a/code/modules/mob/living/carbon/human/update_icons.dm +++ b/code/modules/mob/living/carbon/human/update_icons.dm @@ -82,8 +82,9 @@ GLOBAL_LIST_EMPTY(damage_icon_parts) /mob/living/carbon/human/update_transform() var/desired_scale_x = size_multiplier * icon_scale_x var/desired_scale_y = size_multiplier * icon_scale_y - desired_scale_x *= species.icon_scale_x - desired_scale_y *= species.icon_scale_y + if(istype(species)) + desired_scale_x *= species.icon_scale_x + desired_scale_y *= species.icon_scale_y var/matrix/M = matrix() var/anim_time = 3 diff --git a/code/modules/mob/living/carbon/metroid/items.dm b/code/modules/mob/living/carbon/metroid/items.dm index 485368387fb..d6434ced211 100644 --- a/code/modules/mob/living/carbon/metroid/items.dm +++ b/code/modules/mob/living/carbon/metroid/items.dm @@ -298,7 +298,7 @@ proc/announce_to_ghosts() - for(var/mob/observer/dead/G in player_list) + for(var/mob/observer/dead/G in GLOB.player_list) if(G.client) var/area/A = get_area(src) if(A) diff --git a/code/modules/mob/living/default_language.dm b/code/modules/mob/living/default_language.dm index df25980298f..8c8ded650ea 100644 --- a/code/modules/mob/living/default_language.dm +++ b/code/modules/mob/living/default_language.dm @@ -5,11 +5,11 @@ set name = "Set Default Language" set category = "IC" - if (only_species_language && language != GLOB.all_languages[src.species_language]) + if (only_species_language && language != SScharacters.resolve_language_name(species_language)) to_chat(src, "You can only speak your species language, [src.species_language].") return 0 - if(language == GLOB.all_languages[src.species_language]) + if(language == SScharacters.resolve_language_name(species_language)) to_chat(src, "You will now speak your standard default language, [language], if you do not specify a language when speaking.") else if (language) diff --git a/code/modules/mob/living/say.dm b/code/modules/mob/living/say.dm index 58aa094a16b..b11f2ccc931 100644 --- a/code/modules/mob/living/say.dm +++ b/code/modules/mob/living/say.dm @@ -191,7 +191,7 @@ var/list/channel_to_radio_key = new speaking = get_default_language() if(!can_speak(speaking)) - speaking = GLOB.all_languages[LANGUAGE_GIBBERISH] + speaking = SScharacters.resolve_language_name(LANGUAGE_GIBBERISH) var/babble_key = ",r" message = babble_key + message @@ -203,11 +203,11 @@ var/list/channel_to_radio_key = new while(speaking && is_language_prefix(copytext_char(message, 1, 2))) message = copytext_char(message,2+length_char(speaking.key)) - if(speaking && speaking == GLOB.all_languages["Noise"]) + if(speaking && speaking == SScharacters.resolve_language_name("Noise")) message = copytext_char(message,2) //HIVEMIND languages always send to all people with that language - if(speaking && (speaking.flags & HIVEMIND)) + if(speaking && (speaking.language_flags & HIVEMIND)) speaking.broadcast(src,trim(message)) return 1 @@ -216,7 +216,7 @@ var/list/channel_to_radio_key = new return //Self explanatory. - if(is_muzzled() && !(speaking && (speaking.flags & SIGNLANG))) + if(is_muzzled() && !(speaking && (speaking.language_flags & SIGNLANG))) to_chat(src, "You're muzzled and cannot speak!") return @@ -247,7 +247,7 @@ var/list/channel_to_radio_key = new w_not_heard = "[speaking.speech_verb] something [w_adverb]" //For speech disorders (hulk, slurring, stuttering) - if(!(speaking && (speaking.flags & NO_STUTTER || speaking.flags & SIGNLANG))) + if(!(speaking && (speaking.language_flags & NO_STUTTER || speaking.language_flags & SIGNLANG))) var/list/message_data = list(message, verb, whispering) if(handle_speech_problems(message_data)) message = message_data[1] @@ -286,7 +286,7 @@ var/list/channel_to_radio_key = new if(speaking) message_range = speaking.get_talkinto_msg_range(message) var/msg - if(!speaking || !(speaking.flags & NO_TALK_MSG)) + if(!speaking || !(speaking.language_flags & NO_TALK_MSG)) msg = "\The [src] talks into \the [used_radios[1]]" for(var/mob/living/M in hearers(7, src)) if((M != src) && msg) @@ -315,11 +315,11 @@ var/list/channel_to_radio_key = new //Handle nonverbal and sign languages here if (speaking) - if (speaking.flags & SIGNLANG) + if (speaking.language_flags & SIGNLANG) log_say("(SIGN) [message]", src) return say_signlang(message, pick(speaking.signlang_verb), speaking) - if (speaking.flags & NONVERBAL) + if (speaking.language_flags & NONVERBAL) if (prob(30)) src.custom_emote(1, "[pick(speaking.signlang_verb)].") diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm index 7d3f8f09a9d..e0fc9cb0e08 100644 --- a/code/modules/mob/living/silicon/ai/ai.dm +++ b/code/modules/mob/living/silicon/ai/ai.dm @@ -160,8 +160,6 @@ var/list/ai_verbs_default = list( holo_icon = getHologramIcon(icon('icons/mob/AI.dmi',"holo1")) - proc_holder_list = new() - if(L) if (istype(L, /datum/ai_laws)) laws = L @@ -200,7 +198,6 @@ var/list/ai_verbs_default = list( add_language(LANGUAGE_BIRDSONG, 1) add_language(LANGUAGE_SAGARU, 1) add_language(LANGUAGE_CANILUNZT, 1) - add_language(LANGUAGE_ECUREUILIAN, 1) add_language(LANGUAGE_DAEMON, 1) add_language(LANGUAGE_ENOCHIAN, 1) add_language(LANGUAGE_SQUEAKISH, 1) @@ -208,7 +205,7 @@ var/list/ai_verbs_default = list( if(!safety)//Only used by AIize() to successfully spawn an AI. if (!B)//If there is no player/brain inside. - empty_playable_ai_cores += new/obj/structure/AIcore/deactivated(loc)//New empty terminal. + GLOB.empty_playable_ai_cores += new/obj/structure/AIcore/deactivated(loc)//New empty terminal. qdel(src)//Delete AI. return else diff --git a/code/modules/mob/living/silicon/ai/ai_vr.dm b/code/modules/mob/living/silicon/ai/ai_vr.dm index 5c525ba28eb..cd6bf9c38b0 100644 --- a/code/modules/mob/living/silicon/ai/ai_vr.dm +++ b/code/modules/mob/living/silicon/ai/ai_vr.dm @@ -4,7 +4,6 @@ add_language(LANGUAGE_BIRDSONG, 1) add_language(LANGUAGE_SAGARU, 1) add_language(LANGUAGE_CANILUNZT, 1) - add_language(LANGUAGE_ECUREUILIAN, 1) add_language(LANGUAGE_DAEMON, 1) add_language(LANGUAGE_ENOCHIAN, 1) add_language(LANGUAGE_SQUEAKISH, 1) diff --git a/code/modules/mob/living/silicon/ai/latejoin.dm b/code/modules/mob/living/silicon/ai/latejoin.dm index ae7eb45bbd6..318717d1eab 100644 --- a/code/modules/mob/living/silicon/ai/latejoin.dm +++ b/code/modules/mob/living/silicon/ai/latejoin.dm @@ -1,4 +1,4 @@ -var/global/list/empty_playable_ai_cores = list() +GLOBAL_LIST_EMPTY(empty_playable_ai_cores) /mob/living/silicon/ai/verb/store_core() set name = "Store Core" @@ -15,7 +15,7 @@ var/global/list/empty_playable_ai_cores = list() return // We warned you. - empty_playable_ai_cores += new /obj/structure/AIcore/deactivated(loc) + GLOB.empty_playable_ai_cores += new /obj/structure/AIcore/deactivated(loc) GLOB.global_announcer.autosay("[src] has been moved to intelligence storage.", "Artificial Intelligence Oversight") //Handle job slot/tater cleanup. diff --git a/code/modules/mob/living/silicon/laws.dm b/code/modules/mob/living/silicon/laws.dm index fa74c128131..9c388a350c8 100644 --- a/code/modules/mob/living/silicon/laws.dm +++ b/code/modules/mob/living/silicon/laws.dm @@ -134,7 +134,7 @@ /mob/living/silicon/proc/generate_ion_law(var/exclude_crew_names = FALSE) var/list/players = list() - for(var/mob/living/carbon/human/player in player_list) + for(var/mob/living/carbon/human/player in GLOB.player_list) if(!player.mind || player_is_antag(player.mind, only_offstation_roles = 1) || player.client.inactivity > MinutesToTicks(10)) continue players += player.real_name diff --git a/code/modules/mob/living/silicon/pai/recruit.dm b/code/modules/mob/living/silicon/pai/recruit.dm index 4049fdba396..4a8de7232fd 100644 --- a/code/modules/mob/living/silicon/pai/recruit.dm +++ b/code/modules/mob/living/silicon/pai/recruit.dm @@ -233,7 +233,7 @@ var/datum/paiController/paiController // Global handler for pAI candidates for(var/datum/paiCandidate/c in paiController.pai_candidates) if(c.ready) var/found = 0 - for(var/mob/observer/dead/o in player_list) + for(var/mob/observer/dead/o in GLOB.player_list) if(o.key == c.key && o.MayRespawn()) found = 1 if(found) @@ -346,7 +346,7 @@ var/datum/paiController/paiController // Global handler for pAI candidates /datum/paiController/proc/requestRecruits(var/mob/user) inquirer = user - for(var/mob/observer/dead/O in player_list) + for(var/mob/observer/dead/O in GLOB.player_list) if(!O.MayRespawn()) continue if(jobban_isbanned(O, "pAI")) diff --git a/code/modules/mob/living/silicon/pai/software_modules.dm b/code/modules/mob/living/silicon/pai/software_modules.dm index bc22058bc8d..1ebe82d13ea 100644 --- a/code/modules/mob/living/silicon/pai/software_modules.dm +++ b/code/modules/mob/living/silicon/pai/software_modules.dm @@ -375,7 +375,7 @@ /mob/living/silicon/pai/proc/hackloop() var/turf/T = get_turf_or_move(src.loc) - for(var/mob/living/silicon/ai/AI in player_list) + for(var/mob/living/silicon/ai/AI in GLOB.player_list) if(T.loc) to_chat(AI, "Network Alert: Brute-force encryption crack in progress in [T.loc].") else diff --git a/code/modules/mob/living/silicon/robot/drone/drone.dm b/code/modules/mob/living/silicon/robot/drone/drone.dm index 9d6c5dd71f0..1238ef157c5 100644 --- a/code/modules/mob/living/silicon/robot/drone/drone.dm +++ b/code/modules/mob/living/silicon/robot/drone/drone.dm @@ -185,7 +185,7 @@ user.visible_message("\The [user] swipes [TU.his] ID card through \the [src], attempting to reboot it.", ">You swipe your ID card through \the [src], attempting to reboot it.") var/drones = 0 - for(var/mob/living/silicon/robot/drone/D in player_list) + for(var/mob/living/silicon/robot/drone/D in GLOB.player_list) drones++ if(drones < config_legacy.max_maint_drones) request_player() @@ -292,7 +292,7 @@ //Reboot procs. /mob/living/silicon/robot/drone/proc/request_player() - for(var/mob/observer/dead/O in player_list) + for(var/mob/observer/dead/O in GLOB.player_list) if(jobban_isbanned(O, "Cyborg")) continue if(O.client) diff --git a/code/modules/mob/living/silicon/robot/drone/drone_console.dm b/code/modules/mob/living/silicon/robot/drone/drone_console.dm index 47b38f7b0cb..7f8653e6188 100644 --- a/code/modules/mob/living/silicon/robot/drone/drone_console.dm +++ b/code/modules/mob/living/silicon/robot/drone/drone_console.dm @@ -74,7 +74,7 @@ if("ping") to_chat(usr, SPAN_NOTICE("You issue a maintenance request for all active drones, highlighting [drone_call_area].")) - for(var/mob/living/silicon/robot/drone/D in player_list) + for(var/mob/living/silicon/robot/drone/D in GLOB.player_list) if(D.stat == 0) to_chat(D, "-- Maintenance drone presence requested in: [drone_call_area].") diff --git a/code/modules/mob/living/silicon/robot/drone/drone_manufacturer.dm b/code/modules/mob/living/silicon/robot/drone/drone_manufacturer.dm index 70b03533b58..20d7fccfb95 100644 --- a/code/modules/mob/living/silicon/robot/drone/drone_manufacturer.dm +++ b/code/modules/mob/living/silicon/robot/drone/drone_manufacturer.dm @@ -1,6 +1,6 @@ /proc/count_drones() var/drones = 0 - for(var/mob/living/silicon/robot/drone/D in player_list) + for(var/mob/living/silicon/robot/drone/D in GLOB.player_list) drones++ return drones diff --git a/code/modules/mob/living/silicon/robot/drone/drone_say.dm b/code/modules/mob/living/silicon/robot/drone/drone_say.dm index c2fd5caeb3f..697c5a27cd2 100644 --- a/code/modules/mob/living/silicon/robot/drone/drone_say.dm +++ b/code/modules/mob/living/silicon/robot/drone/drone_say.dm @@ -14,7 +14,7 @@ return emote(copytext(message,2)) if(copytext(message,1,2) == ";") - var/datum/language/L = GLOB.all_languages["Drone Talk"] + var/datum/language/L = SScharacters.resolve_language_id(LANGUAGE_ID_DRONE_BINARY) if(istype(L)) return L.broadcast(src,trim(copytext(message,2))) @@ -29,7 +29,7 @@ if(D.client && D.local_transmit) to_chat(D, "[src] transmits, \"[message]\"") - for (var/mob/M in player_list) + for (var/mob/M in GLOB.player_list) if (istype(M, /mob/new_player)) continue else if(M.stat == DEAD && M.is_preference_enabled(/datum/client_preference/ghost_ears)) diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index 0b743e21a6b..97e7fad1345 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -312,7 +312,7 @@ return var/list/modules = list() modules.Add(robot_module_types) - if(crisis || security_level == SEC_LEVEL_RED || crisis_override) + if(crisis || GLOB.security_level == SEC_LEVEL_RED || crisis_override) to_chat(src, "Crisis mode active. Combat module available.") modules+="Combat" modules+="ERT" diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm index f5edc0b9a6f..4453fba0b14 100644 --- a/code/modules/mob/living/silicon/silicon.dm +++ b/code/modules/mob/living/silicon/silicon.dm @@ -52,7 +52,7 @@ silicon_mob_list |= src . = ..() add_language(LANGUAGE_GALCOM) - set_default_language(GLOB.all_languages[LANGUAGE_GALCOM]) + set_default_language(SScharacters.resolve_language_name(LANGUAGE_GALCOM)) init_id() init_subsystems() @@ -195,7 +195,7 @@ return universal_speak || (speaking in src.speech_synthesizer_langs) || (speaking.name == "Noise") //need speech synthesizer support to vocalize a language /mob/living/silicon/add_language(var/language, var/can_speak=1) - var/datum/language/added_language = GLOB.all_languages[language] + var/datum/language/added_language = SScharacters.resolve_language_name(language) if(!added_language) return @@ -205,7 +205,7 @@ return 1 /mob/living/silicon/remove_language(var/rem_language) - var/datum/language/removed_language = GLOB.all_languages[rem_language] + var/datum/language/removed_language = SScharacters.resolve_language_name(rem_language) if(!removed_language) return @@ -223,7 +223,7 @@ dat += "Current default language: [default_language] - reset

" for(var/datum/language/L in languages) - if(!(L.flags & NONGLOBAL)) + if(!(L.language_flags & NONGLOBAL)) var/default_str if(L == default_language) default_str = " - default - reset" @@ -383,7 +383,7 @@ //Handle job slot/tater cleanup. var/job = mind.assigned_role - job_master.FreeRole(job) + SSjob.FreeRole(job) if(mind.objectives.len) qdel(mind.objectives) diff --git a/code/modules/mob/living/simple_animal/animals/spiderbot.dm b/code/modules/mob/living/simple_animal/animals/spiderbot.dm index d1161eef44f..93173a7e13a 100644 --- a/code/modules/mob/living/simple_animal/animals/spiderbot.dm +++ b/code/modules/mob/living/simple_animal/animals/spiderbot.dm @@ -64,7 +64,7 @@ /mob/living/simple_mob/spiderbot/Initialize(mapload) . = ..() add_language(LANGUAGE_GALCOM) - default_language = GLOB.all_languages[LANGUAGE_GALCOM] + default_language = SScharacters.resolve_language_name(LANGUAGE_GALCOM) verbs |= /mob/living/proc/ventcrawl verbs |= /mob/living/proc/hide @@ -81,7 +81,7 @@ if(!B.brainmob.key) var/ghost_can_reenter = 0 if(B.brainmob.mind) - for(var/mob/observer/dead/G in player_list) + for(var/mob/observer/dead/G in GLOB.player_list) if(G.can_reenter_corpse && G.mind == B.brainmob.mind) ghost_can_reenter = 1 break diff --git a/code/modules/mob/living/simple_mob/simple_mob.dm b/code/modules/mob/living/simple_mob/simple_mob.dm index a4b7a3292e1..f16840d4731 100644 --- a/code/modules/mob/living/simple_mob/simple_mob.dm +++ b/code/modules/mob/living/simple_mob/simple_mob.dm @@ -247,7 +247,7 @@ var/limb_icon /// Used for if the mob can drop limbs. Overrides the icon cache key, so it doesn't keep remaking the icon needlessly. var/limb_icon_key - + ///Does the simple mob drop organs when butchered? butchery_drops_organs = FALSE @@ -270,7 +270,7 @@ randomize() for(var/L in has_langs) - languages |= GLOB.all_languages[L] + languages |= SScharacters.resolve_language_name(L) if(languages.len) default_language = languages[1] diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/borer/borer.dm b/code/modules/mob/living/simple_mob/subtypes/animal/borer/borer.dm index d9b74abc700..6acf1fc84a9 100644 --- a/code/modules/mob/living/simple_mob/subtypes/animal/borer/borer.dm +++ b/code/modules/mob/living/simple_mob/subtypes/animal/borer/borer.dm @@ -238,7 +238,7 @@ return emote(copytext(message, 2)) var/datum/language/L = parse_language(message) - if(L && L.flags & HIVEMIND) + if(L && L.language_flags & HIVEMIND) L.broadcast(src,trim(copytext(message,3)), src.true_name) return @@ -267,7 +267,7 @@ to_chat(src, "You drop words into [host]'s mind: \"[message]\"") to_chat(host, "Your own thoughts speak: \"[message]\"") - for(var/mob/M in player_list) + for(var/mob/M in GLOB.player_list) if(istype(M, /mob/new_player)) continue else if(M.stat == DEAD && M.is_preference_enabled(/datum/client_preference/ghost_ears)) diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/borer/borer_captive.dm b/code/modules/mob/living/simple_mob/subtypes/animal/borer/borer_captive.dm index 97633937165..1037aa5abc6 100644 --- a/code/modules/mob/living/simple_mob/subtypes/animal/borer/borer_captive.dm +++ b/code/modules/mob/living/simple_mob/subtypes/animal/borer/borer_captive.dm @@ -25,7 +25,7 @@ to_chat(src, "You whisper silently, \"[message]\"") to_chat(B.host, "The captive mind of [src] whispers, \"[message]\"") - for (var/mob/M in player_list) + for (var/mob/M in GLOB.player_list) if (istype(M, /mob/new_player)) continue else if(M.stat == DEAD && M.is_preference_enabled(/datum/client_preference/ghost_ears)) diff --git a/code/modules/mob/living/simple_mob/subtypes/slime/xenobio/consumption.dm b/code/modules/mob/living/simple_mob/subtypes/slime/xenobio/consumption.dm index a149bf16332..3b85d470986 100644 --- a/code/modules/mob/living/simple_mob/subtypes/slime/xenobio/consumption.dm +++ b/code/modules/mob/living/simple_mob/subtypes/slime/xenobio/consumption.dm @@ -132,7 +132,7 @@ return FALSE if(istype(L, /mob/living/carbon/human)) var/mob/living/carbon/human/H = L - if(H.species.flags & NO_SCAN) + if(H.species.species_flags & NO_SCAN) to_chat(src, "This subject's life energy is beyond my reach...") return FALSE if(L.has_buckled_mobs()) diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/solargrub_larva.dm b/code/modules/mob/living/simple_mob/subtypes/vore/solargrub_larva.dm index 8c2db6845ac..cc90ec97958 100644 --- a/code/modules/mob/living/simple_mob/subtypes/vore/solargrub_larva.dm +++ b/code/modules/mob/living/simple_mob/subtypes/vore/solargrub_larva.dm @@ -73,7 +73,7 @@ var/global/list/grub_machine_overlays = list() QDEL_NULL(powermachine) QDEL_NULL(sparks) if(machine_effect) - for(var/mob/L in player_list) + for(var/mob/L in GLOB.player_list) L.client?.images -= machine_effect QDEL_NULL(machine_effect) return ..() @@ -96,7 +96,7 @@ var/global/list/grub_machine_overlays = list() if(istype(loc, /obj/machinery)) // to anyone who sees me on git blame, i'm not responsible for this shit code ~silicons if(machine_effect && (air_master.current_cycle % 30)) - for(var/mob/M in player_list) + for(var/mob/M in GLOB.player_list) SEND_IMAGE(M, machine_effect) if(prob(10)) sparks.start() @@ -132,7 +132,7 @@ var/global/list/grub_machine_overlays = list() if(!(M.type in grub_machine_overlays)) generate_machine_effect(M) machine_effect = image(grub_machine_overlays[M.type], M) //Can't do this the reasonable way with an overlay, - for(var/mob/L in player_list) //because nearly every machine updates its icon by removing all overlays first + for(var/mob/L in GLOB.player_list) //because nearly every machine updates its icon by removing all overlays first SEND_IMAGE(L, machine_effect) /mob/living/simple_mob/animal/solargrub_larva/proc/generate_machine_effect(var/obj/machinery/M) @@ -150,7 +150,7 @@ var/global/list/grub_machine_overlays = list() forceMove(get_turf(M)) sparks.start() if(machine_effect) - for(var/mob/L in player_list) + for(var/mob/L in GLOB.player_list) L.client?.images -= machine_effect QDEL_NULL(machine_effect) ai_holder.target = null diff --git a/code/modules/mob/living/voice/voice.dm b/code/modules/mob/living/voice/voice.dm index f8a2d715fe6..ee833a494e0 100644 --- a/code/modules/mob/living/voice/voice.dm +++ b/code/modules/mob/living/voice/voice.dm @@ -10,7 +10,7 @@ /mob/living/voice/Initialize(mapload) . = ..() add_language(LANGUAGE_GALCOM) - set_default_language(GLOB.all_languages[LANGUAGE_GALCOM]) + set_default_language(SScharacters.resolve_language_name(LANGUAGE_GALCOM)) if(istype(loc, /obj/item/communicator)) comm = loc @@ -31,9 +31,9 @@ name = p.real_name real_name = name gender = p.identifying_gender - - for(var/language in p.alternate_languages) - add_language(language) + // we don't check if they're above max because fuck you + for(var/id in p.all_language_ids()) + add_language(id) // Proc: Login() // Parameters: None diff --git a/code/modules/mob/login.dm b/code/modules/mob/login.dm index ca237acab33..80d2e4ea083 100644 --- a/code/modules/mob/login.dm +++ b/code/modules/mob/login.dm @@ -2,7 +2,7 @@ * Run when a client is put in this mob or reconnets to byond and their client was on this mob * * Things it does: - * * Adds player to player_list + * * Adds player to GLOB.player_list * * sets lastKnownIP * * sets computer_id * * logs the login @@ -24,7 +24,7 @@ /mob/Login() SHOULD_CALL_PARENT(TRUE) - player_list |= src + GLOB.player_list |= src update_Login_details() world.update_status() @@ -94,7 +94,7 @@ computer_id = client.computer_id log_access_in(client) if(config_legacy.log_access) - for(var/mob/M in player_list) + for(var/mob/M in GLOB.player_list) if(M == src) continue if( M.key && (M.key != key) ) var/matches diff --git a/code/modules/mob/logout.dm b/code/modules/mob/logout.dm index 0fcea7f2312..e8edb3d9b88 100644 --- a/code/modules/mob/logout.dm +++ b/code/modules/mob/logout.dm @@ -1,8 +1,9 @@ /mob/Logout() + SHOULD_CALL_PARENT(TRUE) SEND_SIGNAL(src, COMSIG_MOB_CLIENT_LOGOUT, client) SSnanoui.user_logout(src) // this is used to clean up (remove) this user's Nano UIs SStgui.on_logout(src) // Cleanup any TGUIs the user has open - player_list -= src + GLOB.player_list -= src disconnect_time = world.realtime // Logging when we disappear. update_client_z(null) log_access_out(src) diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index c1e2f89937e..e8f5021f5ce 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -302,7 +302,7 @@ * * visible_message will handle invisibility properly * - * overridden here and in /mob/dead/observer for different point span classes and sanity checks + * overridden here and in /mob/observer/dead for different point span classes and sanity checks */ /mob/verb/pointed(atom/A as mob|obj|turf in view()) set name = "Point To" diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm index 6d7491b612d..3eae978b5f7 100644 --- a/code/modules/mob/mob_defines.dm +++ b/code/modules/mob/mob_defines.dm @@ -162,9 +162,6 @@ var/lying = 0 var/lying_prev = 0 - /// Player pixel shifting, if TRUE, we need to reset on move. - var/is_shifted = FALSE - var/canmove = 1 /// Allows mobs to move through dense areas without restriction. For instance, in space or out of holder objects. var/incorporeal_move = 0 //0 is off, 1 is normal, 2 is for ninjas. @@ -204,7 +201,6 @@ var/stunned = 0 var/weakened = 0 var/losebreath = 0 //?Carbon - var/_intent = null //?Living var/shakecamera = 0 var/a_intent = INTENT_HELP //?Living var/m_int = null //?Living @@ -221,10 +217,13 @@ /// whether or not we're prepared to throw stuff. var/in_throw_mode = THROW_MODE_OFF + // todo: nuke from orbit var/music_lastplayed = "null" + // todo: nuke from orbit var/job = null //?Living + // todo: nuke from orbit var/const/blindness = 1 //?Carbon var/const/deafness = 2 //?Carbon var/const/muteness = 4 //?Carbon @@ -245,21 +244,9 @@ ///Used for checking whether hostile simple animals will attack you, possibly more stuff later. var/faction = "neutral" /// To prevent pAIs/mice/etc from getting antag in autotraitor and future auto- modes. Uses inheritance instead of a bunch of typechecks. + // todo: what the fuck var/can_be_antagged = FALSE - /// Generic list for proc holders. Only way I can see to enable certain verbs/procs. Should be modified if needed. - var/proc_holder_list[] = list()//Right now unused. - //Also unlike the spell list, this would only store the object in contents, not an object in itself. - - /* Add this line to whatever stat module you need in order to use the proc holder list. - Unlike the object spell system, it's also possible to attach verb procs from these objects to right-click menus. - This requires creating a verb for the object proc holder. - - if (proc_holder_list.len)//Generic list for proc_holder objects. - for(var/obj/effect/proc_holder/P in proc_holder_list) - statpanel("[P.panel]","",P) - */ - /// The last mob/living/carbon to push/drag/grab this mob (mostly used by slimes friend recognition) var/mob/living/carbon/LAssailant = null diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm index e35c216a9a6..6937f3ce08a 100644 --- a/code/modules/mob/mob_helpers.dm +++ b/code/modules/mob/mob_helpers.dm @@ -286,7 +286,7 @@ var/list/intents = list(INTENT_HELP,INTENT_DISARM,INTENT_GRAB,INTENT_HARM) if(subject && subject.client) var/client/C = subject.client keyname = (C.holder && C.holder.fakekey) ? C.holder.fakekey : C.key - if(C.mob) //Most of the time this is the dead/observer mob; we can totally use him if there is no better name + if(C.mob) //Most of the time this is the observer/dead mob; we can totally use him if there is no better name var/mindname var/realname = C.mob.real_name if(C.mob.mind) @@ -301,7 +301,7 @@ var/list/intents = list(INTENT_HELP,INTENT_DISARM,INTENT_GRAB,INTENT_HARM) if(subject && subject.forbid_seeing_deadchat && !subject.client.holder) return // Can't talk in deadchat if you can't see it. - for(var/mob/M in player_list) + for(var/mob/M in GLOB.player_list) if(M.client && ((!istype(M, /mob/new_player) && M.stat == DEAD) || (M.client.holder && M.client.holder.rights)) && M.is_preference_enabled(/datum/client_preference/show_dsay)) var/follow var/lname @@ -332,7 +332,7 @@ var/list/intents = list(INTENT_HELP,INTENT_DISARM,INTENT_GRAB,INTENT_HARM) to_chat(M, "" + "DEAD: "+ "[lname][follow][message]") /proc/say_dead_object(var/message, var/obj/subject = null) - for(var/mob/M in player_list) + for(var/mob/M in GLOB.player_list) if(M.client && ((!istype(M, /mob/new_player) && M.stat == DEAD) || (M.client.holder && M.client.holder.rights)) && M.is_preference_enabled(/datum/client_preference/show_dsay)) var/follow var/lname = "Game Master" @@ -391,7 +391,7 @@ var/list/intents = list(INTENT_HELP,INTENT_DISARM,INTENT_GRAB,INTENT_HARM) // Don't notify for objects created during a mapload. if(ignore_mapload && SSatoms.initialized != INITIALIZATION_INNEW_REGULAR) return - for(var/mob/observer/dead/O in player_list) + for(var/mob/observer/dead/O in GLOB.player_list) if(!O.client) continue to_chat(O, "[message][(enter_link) ? " [enter_link]" : ""]") diff --git a/code/modules/mob/mob_transformation_simple.dm b/code/modules/mob/mob_transformation_simple.dm index 3f08273552a..d09bb6693ee 100644 --- a/code/modules/mob/mob_transformation_simple.dm +++ b/code/modules/mob/mob_transformation_simple.dm @@ -50,7 +50,7 @@ if(subspecies && istype(M,/mob/living/carbon/human)) var/mob/living/carbon/human/H = M - H.set_species(species_type_by_name(subspecies)) + H.set_species(subspecies) if(delete_old_mob) spawn(1) diff --git a/code/modules/mob/new_player/join_menu.dm b/code/modules/mob/new_player/join_menu.dm new file mode 100644 index 00000000000..5517fe5eb75 --- /dev/null +++ b/code/modules/mob/new_player/join_menu.dm @@ -0,0 +1,258 @@ +GLOBAL_DATUM_INIT(join_menu, /datum/join_menu, new) + +/** + * Global singleton for holding TGUI data for players joining. + */ +/datum/join_menu + +/datum/join_menu/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "JoinMenu", "Join Menu") + ui.open() + +/datum/join_menu/proc/queue_update() + addtimer(CALLBACK(src, /datum/proc/update_static_data), 0, TIMER_UNIQUE | TIMER_OVERRIDE) + +/datum/join_menu/ui_state(mob/user) + return GLOB.explicit_new_player_state + +/datum/join_menu/ui_static_data(mob/user) + var/list/data = ..() + // every entry will have: + // - faction + // - department + // - title, and a description + // faction dropdown --> department dropdown --> title (slots left) with join button and dropdown for description + // ghostroles will be considered a ""faction"" but will use a special list. + var/mob/new_player/N = user + if(!istype(N)) + return // nice one lmao + + // generate job list + var/list/jobs = list() + data["jobs"] = jobs + + // collect + var/list/datum/job/eligible = list() + for(var/title in SSjob.name_occupations) + var/datum/job/J = SSjob.name_occupations[title] + if(!(J.join_types & JOB_LATEJOIN)) + continue + if(!IsJobAvailable(J, N)) + continue + eligible += J + + // make + for(var/datum/job/J as anything in eligible) // already type filtered + // faction + var/list/faction + if(!jobs[J.faction]) + jobs[J.faction] = faction = list() + else + faction = jobs[J.faction] + // department + var/list/department + // todo: this is awful + var/department_name = LAZYACCESS(J.departments, 1) + department_name = capitalize(department_name) + if(!jobs[J.faction][department_name]) + jobs[J.faction][department_name] = department = list() + else + department = jobs[J.faction][department_name] + // finally, add job data + var/slots = J.slots_remaining(TRUE) + var/list/job_data = list( + "id" = J.id, + "name" = EffectiveTitle(J, N), + "desc" = EffectiveDesc(J, N), + "slots" = slots == INFINITY? -1 : slots, + "real_name" = J.title + ) + department += list(job_data) // wrap list + + // generate ghostrole list + var/list/ghostroles = list() + data["ghostroles"] = ghostroles + for(var/id in GLOB.ghostroles) + var/datum/ghostrole/R = GLOB.ghostroles[id] + // can't afford runtime here + if(!istype(R) || !IsGhostroleAvailable(R, N)) + continue + var/slots = R.SpawnsLeft(user.client) + var/list/ghostrole_data = list( + "id" = id, + "name" = R.name, + "desc" = R.desc, + "slots" = slots == INFINITY? -1 : slots + ) + ghostroles += list(ghostrole_data) // wrap list + return data + +/datum/join_menu/ui_data(mob/user) + var/list/data = ..() + // common info goes into ui data + var/level = "green" + switch(GLOB.security_level) + if(SEC_LEVEL_BLUE) + level = "blue"; + if(SEC_LEVEL_ORANGE) + level = "orange"; + if(SEC_LEVEL_VIOLET) + level = "violet"; + if(SEC_LEVEL_YELLOW) + level = "yellow"; + if(SEC_LEVEL_GREEN) + level = "green"; + if(SEC_LEVEL_RED) + level = "red"; + else + level = "delta"; + data["security_level"] = level + // todo: have js render this, not us + data["duration"] = DisplayTimeText(round(world.time - SSticker.round_start_time, 10)) + // 0 = not evaccing, 1 = evacuating, 2 = crew transfer, 3 = evacuated + var/evac = 0 + if(SSemergencyshuttle.going_to_centcom()) + evac = 3 + else if(SSemergencyshuttle.online()) + if(SSemergencyshuttle.evac) + evac = 1 + else + evac = 2 + data["evacuated"] = evac + data["charname"] = user.client?.prefs?.real_name || "Unknown User" + // position in queue, -1 for not queued, null for no queue active, otherwise number + // if -1, ui should present option to queue + // if null, ui shouldn't show queue at all or say "there is no queue" etc etc + data["queue"] = QueueStatus(user) + + return data + +/** + * checks if job is available + * if not, it shouldn't even show + */ +/datum/join_menu/proc/IsJobAvailable(datum/job/J, mob/new_player/N) + return J.check_client_availability_one(N.client, TRUE, TRUE) == ROLE_AVAILABLE + +/** + * checks if ghostrole is available + * if not, it shouldn't even show + */ +/datum/join_menu/proc/IsGhostroleAvailable(datum/ghostrole/G, mob/new_player/N) + return G.AllowSpawn(N.client) + +/** + * return effective title - used for alt titles - JOBS ONLY, not ghostroles + */ +/datum/join_menu/proc/EffectiveTitle(datum/job/J, mob/new_player/N) + return N.client.prefs.get_job_alt_title_name(J) || J.title + +/** + * returns effective desc - used for alt titles - JOBS ONLY, not ghostroles + */ +/datum/join_menu/proc/EffectiveDesc(datum/job/J, mob/new_player/N) + var/title = N.client.prefs.get_job_alt_title_name(J) + var/datum/alt_title/T = J.alt_titles?[title] + return isnull(T)? J.desc : (initial(T.title_blurb) || J.desc) + +/datum/join_menu/proc/QueueStatus(mob/new_player/N) + return null + +/* +/datum/join_menu/proc/QueueStatus(mob/new_player/N) + QueueActive()? (SSticker.queued_players.Find(N) || -1) : null +*/ + +/datum/join_menu/proc/QueueActive() + return FALSE + +/* +/datum/join_menu/proc/QueueActive() + var/relevant_cap = PopCap() + return length(SSticker.queued_players) || (relevant_cap && living_player_count() > relevant_cap) +*/ + +/datum/join_menu/proc/PopCap() + return INFINITY + +/* +/datum/join_menu/proc/PopCap() + . = null + var/hpc = CONFIG_GET(number/hard_popcap) + var/epc = CONFIG_GET(number/extreme_popcap) + if(hpc && epc) + . = min(hpc, epc) + else + . = max(hpc, epc) +*/ + +/datum/join_menu/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) + . = ..() + var/mob/new_player/N = usr + if(!istype(N)) + to_chat(usr, SPAN_DANGER("You are not in the lobby.")) + return + switch(action) + if("join") + if(!SSticker || !SSticker.IsRoundInProgress()) + to_chat(usr, SPAN_DANGER("The round is either not ready, or has already finished...")) + return + if(!AttemptQueue(usr)) + return + var/id = params["id"] + if(!id) + return + switch(params["type"]) + if("job") + if(!config_legacy.enter_allowed) + to_chat(usr, SPAN_NOTICE("There is an administrative lock on entering the game.")) + return + var/datum/job/J = SSjob.job_by_id(id) + if(!J) + to_chat(usr, SPAN_WARNING("Failed to find job [id].")) + return + to_chat(usr, SPAN_NOTICE("Attempting to latespawn as [id] ([J.title]).")) + N.AttemptLateSpawn(J.title) // todo: remove shim + if("ghostrole") + var/datum/ghostrole/R = get_ghostrole_datum(id) + if(!R) + to_chat(usr, SPAN_WARNING("Failed to find ghostrole [R]")) + return + to_chat(usr, SPAN_WARNING("Attempting to join as ghostrole [id] ([R.name]).")) + N.close_spawn_windows() + var/client/C = N.client + var/error = R.AttemptSpawn(C) + if(istext(error)) + to_chat(C, SPAN_DANGER("[error]")) + if("queue") + return + // AttemptQueue(usr) + +/** + * Return FALSE to block joining. + */ +/datum/join_menu/proc/AttemptQueue(mob/new_player/N) + . = TRUE +/* + if(QueueActive() && !(ckey(N.key) in GLOB.admin_datums)) + var/queue_position = SSticker.queued_players.Find(usr) + if(queue_position == 1) + if(living_player_count() < CONFIG_GET(number/hard_popcap)) + return TRUE + to_chat(usr, SPAN_NOTICE("You are next in line to join the game. You will be notified when a slot opens up.")) + return FALSE + else + to_chat(usr, SPAN_DANGER("[CONFIG_GET(string/hard_popcap_message)]")) + if(queue_position) + to_chat(usr, SPAN_NOTICE("There are [queue_position-1] players in front of you in the queue to join the game.")) + return FALSE + else + SSticker.queued_players += usr + to_chat(usr, SPAN_NOTICE("You have been added to the queue to join the game. Your position in queue is [SSticker.queued_players.len].")) + return FALSE +*/ + +/mob/new_player/proc/LateChoices() + GLOB.join_menu.ui_interact(src) diff --git a/code/modules/mob/new_player/login.dm b/code/modules/mob/new_player/login.dm index d5745fda72c..fd95d20c3b5 100644 --- a/code/modules/mob/new_player/login.dm +++ b/code/modules/mob/new_player/login.dm @@ -38,7 +38,7 @@ GLOBAL_DATUM_INIT(lobby_image, /obj/effect/lobby_image, new) loc = null my_client = client - player_list |= src + GLOB.player_list |= src new_player_panel() spawn(40) diff --git a/code/modules/mob/new_player/new_player.dm b/code/modules/mob/new_player/new_player.dm index 67a8d6725ed..13b6d6f8294 100644 --- a/code/modules/mob/new_player/new_player.dm +++ b/code/modules/mob/new_player/new_player.dm @@ -24,6 +24,7 @@ /mob/new_player/verb/new_player_panel() set src = usr + set waitfor = FALSE new_player_panel_proc() /mob/new_player/proc/new_player_panel_proc() @@ -116,6 +117,7 @@ return age_gate_result /mob/new_player/proc/verifyage() + UNTIL(client.prefs.initialized) // fuck this stupid ass broken piece of shit age gate if(client.holder) // they're an admin client.set_preference(/datum/client_preference/debug/age_verified, 1) return TRUE @@ -138,7 +140,7 @@ else //they claim to be of age, so allow them to continue and update their flags client.set_preference(/datum/client_preference/debug/age_verified, 1) - SScharacter_setup.queue_preferences_save(client.prefs) + SScharacters.queue_preferences_save(client.prefs) //log this message_admins("[ckey] has joined through the automated age gate process.") return TRUE @@ -166,7 +168,7 @@ stat("Players: [totalPlayers]", "Players Ready: [totalPlayersReady]") totalPlayers = 0 totalPlayersReady = 0 - for(var/mob/new_player/player in player_list) + for(var/mob/new_player/player in GLOB.player_list) stat("[player.key]", (player.ready)?("(Playing)"):(null)) totalPlayers++ if(player.ready)totalPlayersReady++ @@ -303,34 +305,6 @@ if(href_list["manifest"]) ViewManifest() - if(href_list["SelectedJob"]) -/* - // Prevents people rejoining as same character. - for (var/mob/living/carbon/human/C in GLOB.mob_list) - var/char_name = client.prefs.real_name - if(char_name == C.real_name) - to_chat(usr, "There is a character that already exists with the same name - [C.real_name], please join with a different one, or use Quit the Round with the previous character.") - return -*/ - if(!config_legacy.enter_allowed) - to_chat(usr, "There is an administrative lock on entering the game!") - return - else if(SSticker && SSticker.mode && SSticker.mode.explosion_in_progress) - to_chat(usr, "The station is currently exploding. Joining would go poorly.") - return -/* - if(!is_alien_whitelisted(src, GLOB.species_meta[client.prefs.species])) - src << alert("You are currently not whitelisted to play [client.prefs.species].") - return 0 -*/ - var/datum/species/S = client.prefs.character_static_species_meta() - if(!(S.spawn_flags & SPECIES_CAN_JOIN)) - src << alert("Your current species, [client.prefs.species], is not available for play on the station.") - return 0 - - AttemptLateSpawn(href_list["SelectedJob"],client.prefs.spawnpoint) - return - if(href_list["privacy_poll"]) if(!SSdbcore.Connect()) return @@ -451,7 +425,7 @@ var/savefile/F = get_server_news() if(F) client.prefs.lastnews = md5(F["body"]) - SScharacter_setup.queue_preferences_save(client.prefs) + SScharacters.queue_preferences_save(client.prefs) var/dat = "
" dat += "

[F["title"]]

" @@ -482,18 +456,7 @@ // Timer still going return timer - world.time -/mob/new_player/proc/IsJobAvailable(rank) - var/datum/job/job = job_master.GetJob(rank) - if(!job) return 0 - if(!job.is_position_available()) return 0 - if(jobban_isbanned(src,rank)) return 0 - if(!job.player_old_enough(src.client)) return 0 - if(!is_job_whitelisted(src,rank)) return 0 - if(!job.player_has_enough_pto(src.client)) return 0 - return 1 - - -/mob/new_player/proc/AttemptLateSpawn(rank, spawning_at) +/mob/new_player/proc/AttemptLateSpawn(rank) if(!client.is_preference_enabled(/datum/client_preference/debug/age_verified)) return if (src != usr) return 0 @@ -503,15 +466,20 @@ if(!config_legacy.enter_allowed) to_chat(usr, "There is an administrative lock on entering the game!") return 0 - if(!IsJobAvailable(rank)) - src << alert("[rank] is not available. Please try another.") - return 0 - if(!attempt_vr(src,"spawn_checks_vr",list())) return 0 - if(!client) - return 0 + var/datum/job/J = SSjob.job_by_title(rank) + var/reason + if((reason = J.check_client_availability_one(client)) != ROLE_AVAILABLE) + to_chat(src, SPAN_WARNING("[rank] is not available: [J.get_availability_reason(client, reason)]")) + return FALSE + if(!spawn_checks_vr()) + return FALSE + var/list/errors = list() + if(!client.prefs.spawn_checks(PREF_COPY_TO_FOR_LATEJOIN, errors)) + to_chat(src, SPAN_WARNING("An error has occured while trying to spawn you in:
[errors.Join("
")]")) + return FALSE //Find our spawning point. - var/list/join_props = job_master.LateSpawn(client, rank) + var/list/join_props = SSjob.LateSpawn(client, rank) var/obj/landmark/spawnpoint/SP = pick(join_props["spawnpoint"]) var/announce_channel = join_props["channel"] || "Common" @@ -521,14 +489,17 @@ spawning = 1 close_spawn_windows() - job_master.AssignRole(src, rank, 1) + if(!SSjob.AssignRole(src, rank, 1)) + to_chat(src, SPAN_WARNING("SSjob.AssignRole failed; something is seriously wrong. Attempted: [rank].")) + . = FALSE + CRASH("AssignRole failed; something is seriously wrong!") var/mob/living/character = create_character(SP.GetSpawnLoc()) // Creates the human and transfers vars and mind SP.OnSpawn(character) //Announces Cyborgs early, because that is the only way it works if(character.mind.assigned_role == "Cyborg") AnnounceCyborg(character, rank, SP.RenderAnnounceMessage(character, name = character.name, job_name = character.mind.role_alt_title || rank), announce_channel, character.z) - character = job_master.EquipRank(character, rank, 1) // Equips the human + character = SSjob.EquipRank(character, rank, 1) // Equips the human UpdateFactionList(character) // AIs don't need a spawnpoint, they must spawn at an empty core @@ -537,8 +508,8 @@ character = character.AIize(move=0) // AIize the character, but don't move them yet // IsJobAvailable for AI checks that there is an empty core available in this list - var/obj/structure/AIcore/deactivated/C = empty_playable_ai_cores[1] - empty_playable_ai_cores -= C + var/obj/structure/AIcore/deactivated/C = GLOB.empty_playable_ai_cores[1] + GLOB.empty_playable_ai_cores -= C character.loc = C.loc @@ -578,64 +549,28 @@ // can't use their name here, since cyborg namepicking is done post-spawn, so we'll just say "A new Cyborg has arrived"/"A new Android has arrived"/etc. GLOB.global_announcer.autosay("A new [rank] has arrived on the station.", "Arrivals Announcement Computer") -/mob/new_player/proc/LateChoices() - var/name = client.prefs.be_random_name ? "friend" : client.prefs.real_name - - var/dat = "
" - dat += "Welcome, [name].
" - dat += "Round Duration: [roundduration2text()]
" - - if(SSemergencyshuttle) //In case NanoTrasen decides reposess CentCom's shuttles. - if(SSemergencyshuttle.going_to_centcom()) //Shuttle is going to CentCom, not recalled - dat += "The station has been evacuated.
" - if(SSemergencyshuttle.online()) - if (SSemergencyshuttle.evac) // Emergency shuttle is past the point of no recall - dat += "The station is currently undergoing evacuation procedures.
" - else // Crew transfer initiated - dat += "The station is currently undergoing crew transfer procedures.
" - - dat += "Choose from the following open/valid positions:
" - dat += "[show_hidden_jobs ? "Hide":"Show"] Hidden Jobs.
" - for(var/datum/job/job in job_master.occupations) - if(job && IsJobAvailable(job.title)) - // Checks for jobs with minimum age requirements - if(job.minimum_character_age && (client.prefs.age < job.minimum_character_age)) - continue - // Checks for jobs set to "Never" in preferences //TODO: Figure out a better way to check for this - if(!(client.prefs.GetJobDepartment(job, 1) & job.flag)) - if(!(client.prefs.GetJobDepartment(job, 2) & job.flag)) - if(!(client.prefs.GetJobDepartment(job, 3) & job.flag)) - if(!show_hidden_jobs && job.title != "Assistant") // Assistant is always an option - continue - var/active = 0 - // Only players with the job assigned and AFK for less than 10 minutes count as active - for(var/mob/M in player_list) if(M.mind && M.client && M.mind.assigned_role == job.title && M.client.inactivity <= 10 * 60 * 10) - active++ - dat += "[job.title] ([job.current_positions]) (Active: [active])
" - - dat += "
" - src << browse(dat, "window=latechoices;size=300x640;can_close=1") - /mob/new_player/proc/create_character(var/turf/T) - if(!client.is_preference_enabled(/datum/client_preference/debug/age_verified)) return - if (!attempt_vr(src,"spawn_checks_vr",list())) - return 0 + if(!client.is_preference_enabled(/datum/client_preference/debug/age_verified)) + return FALSE + if(!spawn_checks_vr()) + return FALSE + var/list/errors = list() + if(!client.prefs.spawn_checks(PREF_COPY_TO_FOR_ROUNDSTART, errors)) + to_chat(src, SPAN_WARNING("An error has occured while trying to spawn you in:
[errors.Join("
")]")) + return FALSE spawning = 1 close_spawn_windows() var/mob/living/carbon/human/new_character var/use_species_name - var/datum/species/chosen_species - if(client.prefs.species) - chosen_species = name_static_species_meta(client.prefs.species) - use_species_name = chosen_species.get_station_variant() // Only used by pariahs atm. + var/datum/species/chosen_species = client.prefs.real_species_datum() if(chosen_species && use_species_name) // Have to recheck admin due to no usr at roundstart. Latejoins are fine though. - if(is_alien_whitelisted(chosen_species)) - new_character = new(T, species_type_by_name(use_species_name)) + if(!(chosen_species.species_spawn_flags & SPECIES_SPAWN_WHITELISTED) || config.check_alien_whitelist(ckey(chosen_species.name), ckey)) + new_character = new(T, use_species_name) if(!new_character) new_character = new(T) @@ -647,7 +582,7 @@ client.prefs.real_name = random_name(new_character.gender) client.prefs.randomize_appearance_and_body_for(new_character) else - client.prefs.copy_to(new_character, icon_updates = TRUE) + client.prefs.copy_to(new_character) if(client && client.media) client.media.stop_music() // MAD JAMS cant last forever yo @@ -659,9 +594,12 @@ // new_character.real_name = pick(GLOB.clown_names) // I hate this being here of all places but unfortunately dna is based on real_name! // new_character.rename_self("clown") mind.original = new_character + // todo: kick vore's persist shit into new persistence system... mind.loaded_from_ckey = client.ckey mind.loaded_from_slot = client.prefs.default_slot //mind.traits = client.prefs.traits.Copy() // Conflict + //! Preferences shim: transfer stuff over + client.prefs.imprint_mind(mind) mind.transfer_to(new_character) // Won't transfer key since the mind is not active new_character.name = real_name @@ -682,11 +620,6 @@ E.handle_implant(new_character) E.post_implant(new_character) - for(var/lang in client.prefs.alternate_languages) - var/datum/language/chosen_language = GLOB.all_languages[lang] - if(chosen_language) - if(is_lang_whitelisted(src,chosen_language) || (new_character.species && (chosen_language.name in new_character.species.secondary_langs))) - new_character.add_language(lang) // And uncomment this, too. //new_character.dna.UpdateSE() @@ -721,14 +654,12 @@ return check_rights(R_ADMIN, 0, src) /mob/new_player/get_species_name() - var/datum/species/chosen_species - if(client.prefs.species) - chosen_species = name_static_species_meta(client.prefs.species) + var/datum/species/chosen_species = client?.prefs?.real_species_datum() if(!chosen_species) return SPECIES_HUMAN - if(is_alien_whitelisted(chosen_species)) + if(!(chosen_species.species_spawn_flags & SPECIES_SPAWN_WHITELISTED) || config.check_alien_whitelist(ckey(chosen_species.name), ckey)) return chosen_species.name return SPECIES_HUMAN @@ -777,13 +708,8 @@ pass = FALSE to_chat(src, SPAN_WARNING("You have not set your scale yet. Do this on the Species Customization tab in character setup.")) - //Can they play? - if(!is_alien_whitelisted(src, client.prefs.character_static_species_meta()) && !check_rights(R_ADMIN, 0)) - pass = FALSE - to_chat(src,"You are not allowed to spawn in as this species.") - //Custom species checks - if (client && client.prefs && client.prefs.species == SPECIES_CUSTOM) + if (client && client.prefs && client.prefs.real_species_name() == SPECIES_CUSTOM) //Didn't name it if(!client.prefs.custom_species) diff --git a/code/modules/mob/new_player/preferences_setup_vr.dm b/code/modules/mob/new_player/preferences_setup_vr.dm deleted file mode 100644 index b9c6e6a910f..00000000000 --- a/code/modules/mob/new_player/preferences_setup_vr.dm +++ /dev/null @@ -1,15 +0,0 @@ -/datum/preferences/update_preview_icon() // Lines up and un-overlaps character edit previews. Also un-splits taurs. - var/mob/living/carbon/human/dummy/mannequin/mannequin = get_mannequin(client_ckey) - if(!mannequin.dna) // Special handling for preview icons before SSAtoms has initailized. - mannequin.dna = new /datum/dna(null) - mannequin.delete_inventory(TRUE) - if(regen_limbs) - var/datum/species/current_species = name_static_species_meta(species) - current_species.create_organs(mannequin) - regen_limbs = 0 - dress_preview_mob(mannequin) - mannequin.update_transform() - mannequin.toggle_tail_vr(setting = TRUE) - mannequin.toggle_wing_vr(setting = TRUE) - COMPILE_OVERLAYS(mannequin) - update_character_previews(new /mutable_appearance(mannequin)) diff --git a/code/modules/mob/say.dm b/code/modules/mob/say.dm index c8231189244..e266b98dd3a 100644 --- a/code/modules/mob/say.dm +++ b/code/modules/mob/say.dm @@ -77,7 +77,7 @@ return 1 return 0 - if(speaking.flags & INNATE) + if(speaking.language_flags & INNATE) return 1 //Language check. @@ -144,19 +144,19 @@ var/prefix = copytext_char(message,1,2) // This is for audible emotes if(length_char(message) >= 1 && prefix == "!") - return GLOB.all_languages["Noise"] + return SScharacters.resolve_language_name("Noise") if(length_char(message) >= 2 && is_language_prefix(prefix)) var/language_prefix = copytext_char(message, 2 ,3) - var/datum/language/L = GLOB.language_keys[language_prefix] + var/datum/language/L = SScharacters.resolve_language_key(language_prefix) if (can_speak(L)) return L else - var/alert_result = alert(src, "You dont know the langauge you are about to speak, instead you will speak Babel. Do you want to?", "Unknown Language Alert","No","Yes") + var/alert_result = alert(src, "You dont know the LANGUAGE you are about to speak, instead you will speak Babel. Do you want to?", "Unknown Language Alert","No","Yes") if(alert_result == "Yes") - return GLOB.all_languages[LANGUAGE_GIBBERISH] + return SScharacters.resolve_language_name(LANGUAGE_GIBBERISH) else if(isliving(src)) var/mob/living/caller = src - return GLOB.all_languages[caller.default_language] + return SScharacters.resolve_language_name(caller.default_language) return null diff --git a/code/modules/mob/transform_procs.dm b/code/modules/mob/transform_procs.dm index 3e090f9c7e7..04ca0f3f031 100644 --- a/code/modules/mob/transform_procs.dm +++ b/code/modules/mob/transform_procs.dm @@ -27,7 +27,7 @@ gib() return - set_species(species_type_by_name(species.primitive_form)) + set_species(species.primitive_form) dna.SetSEState(DNABLOCK_MONKEY,1) dna.SetSEValueRange(DNABLOCK_MONKEY,0xDAC, 0xFFF) @@ -88,15 +88,13 @@ add_language(LANGUAGE_ZADDAT, 0) // Lorefolks say it may be so. - if(O.client && O.client.prefs) - var/datum/preferences/B = O.client.prefs - if(LANGUAGE_ROOTGLOBAL in B.alternate_languages) - O.add_language(LANGUAGE_ROOTGLOBAL, 1) - if(LANGUAGE_ROOTLOCAL in B.alternate_languages) - O.add_language(LANGUAGE_ROOTLOCAL, 1) + if(LANGUAGE_ROOTGLOBAL in languages) + O.add_language(LANGUAGE_ROOTGLOBAL, 1) + if(LANGUAGE_ROOTLOCAL in languages) + O.add_language(LANGUAGE_ROOTLOCAL, 1) if(move) - var/obj/landmark/spawnpoint/S = SSjob.GetLatejoinSpawnpoint(job_path = /datum/job/station/ai) + var/obj/landmark/spawnpoint/S = SSjob.get_latejoin_spawnpoint(job_path = /datum/job/station/ai) O.forceMove(S.GetSpawnLoc()) S.OnSpawn(O) @@ -150,13 +148,14 @@ else O.key = key - O.loc = loc + O.forceMove(loc) O.job = "Cyborg" + for(var/i in languages) + O.add_language(i) + if(O.client && O.client.prefs) var/datum/preferences/B = O.client.prefs - for(var/language in B.alternate_languages) - O.add_language(language) O.resize(B.size_multiplier, animate = TRUE) // Adds size prefs to borgs O.fuzzy = B.fuzzy // Ditto diff --git a/code/modules/modular_computers/file_system/news_article.dm b/code/modules/modular_computers/file_system/news_article.dm index 07c924a4738..f2095ffe4e5 100644 --- a/code/modules/modular_computers/file_system/news_article.dm +++ b/code/modules/modular_computers/file_system/news_article.dm @@ -16,9 +16,9 @@ /// Filename of cover. var/cover -/datum/computer_file/data/news_article/New(var/load_from_file = 0) +/datum/computer_file/data/news_article/New(var/load_FROM_FILE = 0) ..() - if(server_file_path && load_from_file) + if(server_file_path && load_FROM_FILE) stored_data = file2text(server_file_path) calculate_size() diff --git a/code/modules/modular_computers/file_system/programs/command/comm.dm b/code/modules/modular_computers/file_system/programs/command/comm.dm index b0aee59a77b..840df72e62c 100644 --- a/code/modules/modular_computers/file_system/programs/command/comm.dm +++ b/code/modules/modular_computers/file_system/programs/command/comm.dm @@ -62,8 +62,8 @@ data["state"] = current_status data["isAI"] = issilicon(usr) data["authenticated"] = get_authentication_level(user) - data["current_security_level"] = security_level - data["current_security_level_title"] = num2seclevel(security_level) + data["current_security_level"] = GLOB.security_level + data["current_security_level_title"] = num2seclevel(GLOB.security_level) data["def_SEC_LEVEL_DELTA"] = SEC_LEVEL_DELTA data["def_SEC_LEVEL_YELLOW"] = SEC_LEVEL_YELLOW @@ -210,15 +210,15 @@ var/current_level = text2num(href_list["target"]) var/confirm = alert("Are you sure you want to change alert level to [num2seclevel(current_level)]?", name, "No", "Yes") if(confirm == "Yes" && can_still_topic()) - var/old_level = security_level + var/old_level = GLOB.security_level if(!current_level) current_level = SEC_LEVEL_GREEN if(current_level < SEC_LEVEL_GREEN) current_level = SEC_LEVEL_GREEN if(current_level > SEC_LEVEL_BLUE) current_level = SEC_LEVEL_BLUE //Cannot engage delta with this set_security_level(current_level) - if(security_level != old_level) + if(GLOB.security_level != old_level) log_game("[key_name(usr)] has changed the security level to [get_security_level()].") message_admins("[key_name_admin(usr)] has changed the security level to [get_security_level()].") - switch(security_level) + switch(GLOB.security_level) if(SEC_LEVEL_GREEN) feedback_inc("alert_comms_green",1) if(SEC_LEVEL_YELLOW) diff --git a/code/modules/modular_computers/file_system/programs/generic/uav.dm b/code/modules/modular_computers/file_system/programs/generic/uav.dm index a2aed1f70f2..2b879e3eca4 100644 --- a/code/modules/modular_computers/file_system/programs/generic/uav.dm +++ b/code/modules/modular_computers/file_system/programs/generic/uav.dm @@ -80,14 +80,14 @@ var/obj/item/uav/U = locate(href_list["switch_uav"]) //This is a \ref to the UAV itself if(!istype(U)) to_chat(usr,"Something is blocking the connection to that UAV. In-person investigation is required.") - return TOPIC_NOACTION + return PREFERENCES_NOACTION if(!get_signal_to(U)) to_chat(usr,"The screen freezes for a moment, before returning to the UAV selection menu. It's not able to connect to that UAV.") - return TOPIC_NOACTION + return PREFERENCES_NOACTION set_current(U) - return TOPIC_REFRESH + return PREFERENCES_REFRESH if(href_list["del_uav"]) var/refstring = href_list["del_uav"] //This is a \ref to the UAV itself @@ -101,17 +101,17 @@ else if(href_list["view_uav"]) if(!current_uav) - return TOPIC_NOACTION + return PREFERENCES_NOACTION if(current_uav.check_eye(user) < 0) to_chat(usr,SPAN_WARNING("The screen freezes for a moment, before returning to the UAV selection menu. It's not able to connect to that UAV.")) else viewing_uav(user) ? unlook(user) : look(user) - return TOPIC_NOACTION + return PREFERENCES_NOACTION else if(href_list["power_uav"]) if(!current_uav) - return TOPIC_NOACTION + return PREFERENCES_NOACTION else if(current_uav.toggle_power()) //Clean up viewers faster if(LAZYLEN(viewers)) @@ -119,7 +119,7 @@ var/M = W.resolve() if(M) unlook(M) - return TOPIC_REFRESH + return PREFERENCES_REFRESH /datum/nano_module/uav/proc/DefaultTopicState() return global.default_state diff --git a/code/modules/nano/modules/human_appearance.dm b/code/modules/nano/modules/human_appearance.dm index 5eea9c17e81..404fc9366f5 100644 --- a/code/modules/nano/modules/human_appearance.dm +++ b/code/modules/nano/modules/human_appearance.dm @@ -23,7 +23,7 @@ if(href_list["race"]) if(can_change(APPEARANCE_RACE) && (href_list["race"] in valid_species)) - if(owner.set_species(species_type_by_name(href_list["race"]))) + if(owner.set_species(href_list["race"])) cut_and_generate_data() return 1 if(href_list["gender"]) diff --git a/code/modules/nifsoft/nif.dm b/code/modules/nifsoft/nif.dm index 0501089af51..be4f5829567 100644 --- a/code/modules/nifsoft/nif.dm +++ b/code/modules/nifsoft/nif.dm @@ -138,7 +138,7 @@ GLOBAL_LIST_INIT(nif_id_lookup, init_nif_id_lookup()) should_be_in = brain.parent_organ if(istype(H) && !H.nif && H.species && (loc == H.get_organ(should_be_in))) - if(!bioadap && (H.species.flags & NO_SCAN)) //NO_SCAN is the default 'too complicated' flag + if(!bioadap && (H.species.species_flags & NO_SCAN)) //NO_SCAN is the default 'too complicated' flag return FALSE human = H diff --git a/code/modules/organs/blood.dm b/code/modules/organs/blood.dm index 8e75b33d954..65732bdc4d6 100644 --- a/code/modules/organs/blood.dm +++ b/code/modules/organs/blood.dm @@ -20,7 +20,7 @@ var/const/CE_STABLE_THRESHOLD = 0.5 if(vessel) return - if(species.flags & NO_BLOOD) + if(species.species_flags & NO_BLOOD) return vessel = new/datum/reagents(species.blood_volume) diff --git a/code/modules/organs/external/_external.dm b/code/modules/organs/external/_external.dm index 7b34e814853..4799b8e4a9b 100644 --- a/code/modules/organs/external/_external.dm +++ b/code/modules/organs/external/_external.dm @@ -440,14 +440,14 @@ //moved this before the open_wound check so that having many small wounds for example doesn't somehow protect you from taking internal damage (because of the return) //Possibly trigger an internal wound, too. var/local_damage = brute_dam + burn_dam + damage - if((damage > 15) && (type != BURN) && (local_damage > 30) && prob(damage) && (robotic < ORGAN_ROBOT) && !(species.flags & NO_BLOOD)) + if((damage > 15) && (type != BURN) && (local_damage > 30) && prob(damage) && (robotic < ORGAN_ROBOT) && !(species.species_flags & NO_BLOOD)) var/datum/wound/internal_bleeding/I = new (min(damage - 15, 15)) wounds += I owner.custom_pain("You feel something rip in your [name]!", 50) //Burn damage can cause fluid loss due to blistering and cook-off - if((damage > 5 || damage + burn_dam >= 15) && type == BURN && (robotic < ORGAN_ROBOT) && !(species.flags & NO_BLOOD)) + if((damage > 5 || damage + burn_dam >= 15) && type == BURN && (robotic < ORGAN_ROBOT) && !(species.species_flags & NO_BLOOD)) var/fluid_loss = 0.4 * (damage/(owner.getMaxHealth() - config_legacy.health_threshold_dead)) * owner.species.blood_volume*(1 - owner.species.blood_level_fatal) owner.remove_blood(fluid_loss) @@ -560,7 +560,7 @@ Note that amputating the affected organ does in fact remove the infection from t */ /obj/item/organ/external/proc/update_germs() - if(robotic >= ORGAN_ROBOT || (owner.species && (owner.species.flags & IS_PLANT || (owner.species.flags & NO_INFECT)))) //Robotic limbs shouldn't be infected, nor should nonexistant limbs. + if(robotic >= ORGAN_ROBOT || (owner.species && (owner.species.species_flags & IS_PLANT || (owner.species.species_flags & NO_INFECT)))) //Robotic limbs shouldn't be infected, nor should nonexistant limbs. germ_level = 0 return @@ -637,7 +637,7 @@ Note that amputating the affected organ does in fact remove the infection from t //Updating wounds. Handles wound natural I had some free spachealing, internal bleedings and infections /obj/item/organ/external/proc/update_wounds() - if((robotic >= ORGAN_ROBOT) || (species.flags & UNDEAD)) //Robotic and dead limbs don't heal or get worse. + if((robotic >= ORGAN_ROBOT) || (species.species_flags & UNDEAD)) //Robotic and dead limbs don't heal or get worse. for(var/datum/wound/W in wounds) //Repaired wounds disappear though if(W.damage <= 0) //and they disappear right away wounds -= W //TODO: robot wounds for robot limbs @@ -712,7 +712,7 @@ Note that amputating the affected organ does in fact remove the infection from t else brute_dam += W.damage - if(!(robotic >= ORGAN_ROBOT) && W.bleeding() && (H && H.should_have_organ(O_HEART)) && !(H.species.flags & NO_BLOOD)) + if(!(robotic >= ORGAN_ROBOT) && W.bleeding() && (H && H.should_have_organ(O_HEART)) && !(H.species.species_flags & NO_BLOOD)) W.bleed_timer-- status |= ORGAN_BLEEDING @@ -1129,7 +1129,7 @@ Note that amputating the affected organ does in fact remove the infection from t /obj/item/organ/external/proc/embed(var/obj/item/W, var/silent = 0) if(!owner || loc != owner) return - if(owner.species.flags & IS_SLIME) + if(owner.species.species_flags & IS_SLIME) createwound( CUT, 15 ) //fixes proms being bugged into paincrit;instead whatever would embed now just takes a chunk out src.visible_message("[owner] has been seriously wounded by [W]!") W.add_blood(owner) diff --git a/code/modules/organs/internal/brain.dm b/code/modules/organs/internal/brain.dm index ceb4afacf7c..56ae97de64c 100644 --- a/code/modules/organs/internal/brain.dm +++ b/code/modules/organs/internal/brain.dm @@ -226,7 +226,7 @@ GLOBAL_LIST_BOILERPLATE(all_brain_organs, /obj/item/organ/internal/brain) if(ckey(clonemind.key) != R.ckey) return FALSE else - for(var/mob/observer/dead/G in player_list) + for(var/mob/observer/dead/G in GLOB.player_list) if(G.ckey == R.ckey) if(G.can_reenter_corpse) break diff --git a/code/modules/organs/internal/voicebox.dm b/code/modules/organs/internal/voicebox.dm index 0561991ec19..d84efbca069 100644 --- a/code/modules/organs/internal/voicebox.dm +++ b/code/modules/organs/internal/voicebox.dm @@ -18,7 +18,7 @@ /obj/item/organ/internal/voicebox/proc/amend_assist_langs() // Adds the list of language datums assisted by the voicebox to the list used in speaking for(var/L in will_assist_languages) - assists_languages |= GLOB.all_languages[L] + assists_languages |= SScharacters.resolve_language_name(L) /obj/item/organ/internal/voicebox/proc/add_assistable_langs(var/language) // Adds a new language (by string/define) to the list of things the voicebox can assist will_assist_languages |= language diff --git a/code/modules/organs/organ.dm b/code/modules/organs/organ.dm index 4669a377c7f..396c0e27f40 100644 --- a/code/modules/organs/organ.dm +++ b/code/modules/organs/organ.dm @@ -28,7 +28,7 @@ if(iscarbon(owner)) var/mob/living/carbon/C = owner - species = get_static_species_meta(/datum/species/human) + species = SScharacters.resolve_species_path(/datum/species/human) if(owner.dna) dna = C.dna.Clone() species = C.species //For custom species @@ -47,7 +47,7 @@ blood_DNA = list() blood_DNA[dna.unique_enzymes] = dna.b_type else - species = get_static_species_meta(/datum/species/human) + species = SScharacters.resolve_species_path(/datum/species/human) if(owner) if(!meat_type) @@ -292,7 +292,7 @@ handle_organ_proc_special() //Process infections - if(robotic >= ORGAN_ROBOT || (istype(owner) && (owner.species && (owner.species.flags & (IS_PLANT | NO_INFECT))))) + if(robotic >= ORGAN_ROBOT || (istype(owner) && (owner.species && (owner.species.species_flags & (IS_PLANT | NO_INFECT))))) germ_level = 0 return @@ -316,7 +316,7 @@ handle_organ_proc_special() //Process infections - if(robotic >= ORGAN_ROBOT || (istype(owner) && (owner.species && (owner.species.flags & (IS_PLANT | NO_INFECT))))) + if(robotic >= ORGAN_ROBOT || (istype(owner) && (owner.species && (owner.species.species_flags & (IS_PLANT | NO_INFECT))))) germ_level = 0 return @@ -596,7 +596,7 @@ /obj/item/organ/proc/organ_can_feel_pain() - if(species.flags & NO_PAIN) + if(species.species_flags & NO_PAIN) return FALSE if(status & ORGAN_DESTROYED) return FALSE diff --git a/code/modules/organs/robolimbs.dm b/code/modules/organs/robolimbs.dm index 5dc81bca835..44bfda6f060 100644 --- a/code/modules/organs/robolimbs.dm +++ b/code/modules/organs/robolimbs.dm @@ -765,7 +765,7 @@ var/const/cyberbeast_monitor_styles= "blank=cyber_blank;\ modular_bodyparts = MODULAR_BODYPART_INVALID /datum/robolimb/dsi_teshari/New() - species_cannot_use = all_species_names() - SPECIES_TESHARI + species_cannot_use = SScharacters.all_species_names() - SPECIES_TESHARI ..() /obj/item/disk/limb/dsi_teshari @@ -810,5 +810,5 @@ var/const/cyberbeast_monitor_styles= "blank=cyber_blank;\ suggested_species = SPECIES_ADHERENT /datum/robolimb/adherent/New() - species_cannot_use = all_species_names() - SPECIES_ADHERENT + species_cannot_use = SScharacters.all_species_names() - SPECIES_ADHERENT ..() diff --git a/code/modules/overmap/disperser/disperser_fire.dm b/code/modules/overmap/disperser/disperser_fire.dm index 1c3ae0fe6bd..d9e907fb39e 100644 --- a/code/modules/overmap/disperser/disperser_fire.dm +++ b/code/modules/overmap/disperser/disperser_fire.dm @@ -31,7 +31,7 @@ LEGACY_EX_ACT(A, 1, null) var/list/relevant_z = GetConnectedZlevels(start.z) - for(var/mob/M in global.player_list) + for(var/mob/M in global.GLOB.player_list) var/turf/T = get_turf(M) if(!T || !(T.z in relevant_z)) continue diff --git a/code/modules/overmap/spacetravel.dm b/code/modules/overmap/spacetravel.dm index e83d4b68ad0..e304c751a0d 100644 --- a/code/modules/overmap/spacetravel.dm +++ b/code/modules/overmap/spacetravel.dm @@ -23,7 +23,7 @@ var/list/cached_space = list() /obj/effect/overmap/visitable/sector/temporary/proc/can_die(var/mob/observer) testing("Checking if sector at [map_z[1]] can die.") - for(var/mob/M in global.player_list) + for(var/mob/M in global.GLOB.player_list) if(M != observer && (M.z in map_z)) testing("There are people on it.") return 0 diff --git a/code/modules/paperwork/photocopier.dm b/code/modules/paperwork/photocopier.dm index 3d17ad53de1..36375b83305 100644 --- a/code/modules/paperwork/photocopier.dm +++ b/code/modules/paperwork/photocopier.dm @@ -119,7 +119,7 @@ copyitem = null else if(has_buckled_mobs()) to_chat(buckled_mobs[1], "You feel a slight pressure on your ass.") // It can't eject your asscheeks, but it'll try. - return TOPIC_REFRESH + return PREFERENCES_REFRESH else if(href_list["min"]) if(copies > 1) copies-- diff --git a/code/modules/planet/weather.dm b/code/modules/planet/weather.dm index 8d91d6efb68..7203a418e99 100644 --- a/code/modules/planet/weather.dm +++ b/code/modules/planet/weather.dm @@ -164,7 +164,7 @@ /datum/weather_holder/proc/message_all_outdoor_players(message) - for(var/mob/M in player_list) // Don't need to care about clientless mobs. + for(var/mob/M in GLOB.player_list) // Don't need to care about clientless mobs. if(M.z in our_planet.expected_z_levels) var/turf/T = get_turf(M) if(!T.outdoors) diff --git a/code/modules/power/fission/engine.dm b/code/modules/power/fission/engine.dm index d65f6e90647..2ea2f2c58a0 100644 --- a/code/modules/power/fission/engine.dm +++ b/code/modules/power/fission/engine.dm @@ -424,7 +424,7 @@ if(announce) var/sound = sound('sound/effects/nuclear_meltdown.ogg') if(!off_station) - for(var/mob/M in player_list) + for(var/mob/M in GLOB.player_list) SEND_SOUND(M,sound) spawn(1 SECONDS) radio.autosay("DANGER! FISSION CORE HAS BREACHED!", "Nuclear Monitor") diff --git a/code/modules/power/gravitygenerator.dm b/code/modules/power/gravitygenerator.dm index 1d37cb07796..a3af2f454ac 100644 --- a/code/modules/power/gravitygenerator.dm +++ b/code/modules/power/gravitygenerator.dm @@ -269,7 +269,7 @@ GLOBAL_LIST_EMPTY(gravity_generators) breaker = !breaker investigate_log("was toggled [breaker ? "ON" : "OFF"] by [key_name(usr)].", "gravity") set_power() - return TOPIC_REFRESH + return PREFERENCES_REFRESH // Power and Icon States @@ -389,7 +389,7 @@ GLOBAL_LIST_EMPTY(gravity_generators) // Shake everyone on the z level to let them know that gravity was enagaged/disenagaged. /obj/machinery/gravity_generator/main/proc/shake_everyone() var/sound/alert_sound = sound('sound/effects/alert.ogg') - for(var/mob/M as anything in player_list) + for(var/mob/M as anything in GLOB.player_list) if(!(M.z in levels)) continue M.update_gravity(M.mob_has_gravity()) diff --git a/code/modules/power/singularity/act.dm b/code/modules/power/singularity/act.dm index 12d5952e654..fa02816e26e 100644 --- a/code/modules/power/singularity/act.dm +++ b/code/modules/power/singularity/act.dm @@ -31,7 +31,7 @@ step_towards(hand, S) to_chat(src, "The [S] pulls \the [hand] from your grip!") - if(!lying && (!shoes || !(shoes.clothing_flags & NOSLIP)) && (!species || !(species.flags & NOSLIP)) && prob(current_size*5)) + if(!lying && (!shoes || !(shoes.clothing_flags & NOSLIP)) && (!species || !(species.species_flags & NOSLIP)) && prob(current_size*5)) to_chat(src, "A strong gravitational force slams you to the ground!") Weaken(current_size) ..() diff --git a/code/modules/power/supermatter/supermatter.dm b/code/modules/power/supermatter/supermatter.dm index 92bae119e82..9166fd011af 100644 --- a/code/modules/power/supermatter/supermatter.dm +++ b/code/modules/power/supermatter/supermatter.dm @@ -215,7 +215,7 @@ //Public alerts if((damage > emergency_point) && !public_alert) GLOB.global_announcer.autosay("WARNING: SUPERMATTER CRYSTAL DELAMINATION IMMINENT!", "Supermatter Monitor") - for(var/mob/M in player_list) + for(var/mob/M in GLOB.player_list) if(!istype(M,/mob/new_player) && !isdeaf(M)) SEND_SOUND(M, message_sound) admin_chat_message(message = "SUPERMATTER DELAMINATING!", color = "#FF2222") @@ -223,7 +223,7 @@ log_game("SUPERMATTER([x],[y],[z]) Emergency PUBLIC announcement. Power:[power], Oxygen:[oxygen], Damage:[damage], Integrity:[get_integrity()]") else if((damage > emergency_point) && public_alert) GLOB.global_announcer.autosay("DANGER: SUPERMATTER CRYSTAL DEGRADATION IN PROGRESS! INTEGRITY AT [integrity]%", "Supermatter Monitor") - for(var/mob/M in player_list) + for(var/mob/M in GLOB.player_list) if(!istype(M,/mob/new_player) && !isdeaf(M)) SEND_SOUND(M, sound('sound/ambience/engine_alert2.ogg')) else if(safe_warned && public_alert) diff --git a/code/modules/client/preferences.dm b/code/modules/preferences/_preferences.dm similarity index 76% rename from code/modules/client/preferences.dm rename to code/modules/preferences/_preferences.dm index 3c7bbf678bd..407f2d43852 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/preferences/_preferences.dm @@ -3,12 +3,21 @@ GLOBAL_LIST_EMPTY(preferences_datums) /datum/preferences + //! Intrinsics + /// did we load yet? + var/initialized = FALSE + + //! Error Handling + /// queued error messages to display + var/list/io_error_queue + //! ## Doohickeys For Savefiles var/path /// Holder so it doesn't default to slot 1, rather the last one used. var/default_slot = 1 var/savefile_version = 0 +// todo: kick this out of prefs //! ## Non-Preference Stuff var/warns = 0 var/muted = 0 @@ -22,6 +31,16 @@ GLOBAL_LIST_EMPTY(preferences_datums) var/savecharcooldown var/loadcharcooldown + //? Someday everything'll be in these lists. + //? These lists may only ever contain associative key-values, where + //? values MUST be string, number, or null. + //? Savefiles do not play nice with typepaths. + //! Loaded data + /// character data + var/list/character + /// global data + var/list/options + //! ## Game Preferences var/tgui_fancy = TRUE var/tgui_lock = TRUE @@ -99,14 +118,6 @@ GLOBAL_LIST_EMPTY(preferences_datums) var/g_eyes = 0 /// Eye color. var/b_eyes = 0 - /// Species datum to use. - var/species = SPECIES_HUMAN - /// Used for the species selection window. - var/species_preview - /// Secondary language(s) - var/list/alternate_languages = list() - /// Language prefix keys. - var/list/language_prefixes = list() /// Left in for Legacy reasons, will no longer save. var/list/gear /// Custom/fluff item loadouts. @@ -127,14 +138,6 @@ GLOBAL_LIST_EMPTY(preferences_datums) var/synth_markings = 1 //! ## Background Preferences - ///System of birth. - var/home_system = "Unset" - ///Current home system. - var/citizenship = "None" - ///General associated faction. - var/faction = "None" - ///Religious association. - var/religion = "None" ///Antag associated faction. var/antag_faction = "None" ///How visible antag association is to others. @@ -162,27 +165,6 @@ GLOBAL_LIST_EMPTY(preferences_datums) "BG" = "character_preview_map:1,1 to 3,8" ) -//! ## Job Preferences -//? ## Uses bitflags. - var/job_civilian_high = 0 - var/job_civilian_med = 0 - var/job_civilian_low = 0 - - var/job_medsci_high = 0 - var/job_medsci_med = 0 - var/job_medsci_low = 0 - - var/job_engsec_high = 0 - var/job_engsec_med = 0 - var/job_engsec_low = 0 - - var/job_talon_high = 0 - var/job_talon_med = 0 - var/job_talon_low = 0 - - /// Keeps track of preferrence for not getting any wanted jobs. - var/alternate_option = 1 - //! ## Skills Preferences - Depricated. var/used_skillpoints = 0 var/skill_specialization = null @@ -196,8 +178,6 @@ GLOBAL_LIST_EMPTY(preferences_datums) var/list/rlimb_data = list() /// Set to 1 when altering limb states. fix for prosthetic > normal changes not working on preview. var/regen_limbs = 0 - /// The default name of a job like "Medical Doctor". - var/list/player_alt_titles = new() var/list/body_markings = list() //? "name" = "#rgbcolor" @@ -245,26 +225,45 @@ GLOBAL_LIST_EMPTY(preferences_datums) var/widescreenpref = TRUE // Exists now... /datum/preferences/New(client/C) + if(istype(C)) + client = C + client_ckey = C.ckey + if(SScharacters.initialized) + Initialize() + +/datum/preferences/proc/Initialize() + // todo: refactor player_setup = new(src) + tim_sort(preference_by_key, /proc/cmp_preference_load_order, TRUE) + tim_sort(preference_by_type, /proc/cmp_preference_load_order, TRUE) + // set defaults before load + reset_everything_to_default() + set_biological_gender(pick(MALE, FEMALE)) - real_name = random_name(identifying_gender,species) + real_name = random_name(identifying_gender, real_species_name()) b_type = RANDOM_BLOOD_TYPE gear = list() gear_list = list() gear_slot = 1 - if(istype(C)) - client = C - client_ckey = C.ckey - if(!IsGuestKey(C.key)) - load_path(C.ckey) + if(client) + if(!IsGuestKey(client.key)) + load_path(client.ckey) if(load_preferences()) if(load_character()) + sanitize_everything() + player_setup.sanitize_setup() + client.update_movement_keys() + initialized = TRUE return - key_bindings = deepCopyList(GLOB.hotkey_keybinding_list_by_key) // give them default keybinds and update their movement keys - C?.update_movement_keys(src) + key_bindings = deep_copy_list(GLOB.hotkey_keybinding_list_by_key) // give them default keybinds and update their movement keys + client?.update_movement_keys(src) + initialized = TRUE + +/datum/preferences/proc/block_until_initialized() + UNTIL(initialized) /datum/preferences/Destroy() . = ..() @@ -322,45 +321,6 @@ GLOBAL_LIST_EMPTY(preferences_datums) if(24 to 1000) return "God" -/datum/preferences/proc/ShowChoices(mob/user) - if(!user || !user.client) - return - - if(!get_mob_by_key(client_ckey)) - to_chat(user, "No mob exists for the given client!") - close_load_dialog(user) - return - - if(!char_render_holders) - update_preview_icon() - show_character_previews() - - var/dat = "
" - - if(path) - dat += "Slot - " - dat += "Load slot - " - dat += "Save slot - " - dat += "Reload slot - " - dat += "Reset slot - " - dat += "Copy slot" - - else - dat += "Please create an account to save your preferences." - - dat += "
" - dat += player_setup.header() - dat += "

" - dat += player_setup.content(user) - - dat += "" - //user << browse(dat, "window=preferences;size=635x736") - winshow(user, "preferences_window", TRUE) - var/datum/browser/popup = new(user, "preferences_browser", "Character Setup", 800, 800) - popup.set_content(dat) - popup.open(FALSE) // Skip registring onclose on the browser pane - onclose(user, "preferences_window", src) // We want to register on the window itself - /datum/preferences/proc/update_character_previews(mutable_appearance/MA) if(!client) return @@ -458,37 +418,6 @@ GLOBAL_LIST_EMPTY(preferences_datums) ShowChoices(usr) return 1 -/datum/preferences/proc/copy_to(mob/living/carbon/human/character, icon_updates = TRUE) - // Sanitizing rather than saving as someone might still be editing when copy_to occurs. - player_setup.sanitize_setup() - - // This needs to happen before anything else becuase it sets some variables. - character.set_species(species_type_by_name(species)) - // Special Case: This references variables owned by two different datums, so do it here. - if(be_random_name) - real_name = random_name(identifying_gender,species) - - // Ask the preferences datums to apply their own settings to the new mob - player_setup.copy_to_mob(character) - - // Sync up all their organs and species one final time - character.force_update_organs() -// character.s_base = s_base //doesn't work, fuck me - - if(icon_updates) - character.force_update_limbs() - character.update_icons_body() - character.update_mutations() - character.update_underwear() - character.update_hair() - - if(LAZYLEN(character.descriptors)) - for(var/entry in body_descriptors) - character.descriptors[entry] = body_descriptors[entry] - -/datum/preferences/proc/character_static_species_meta() - return name_static_species_meta(species) || get_static_species_meta(/datum/species/human) - /datum/preferences/proc/open_load_dialog(mob/user) var/dat = "" dat += "
" @@ -551,7 +480,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) to_chat(src, "You will [ (is_preference_enabled(pref_path)) ? "now" : "no longer"] hear eating related vore noises.") - SScharacter_setup.queue_preferences_save(prefs) + SScharacters.queue_preferences_save(prefs) feedback_add_details("admin_verb","TEatNoise") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! @@ -567,6 +496,6 @@ GLOBAL_LIST_EMPTY(preferences_datums) to_chat(src, "You will [ (is_preference_enabled(pref_path)) ? "now" : "no longer"] hear digestion related vore noises.") - SScharacter_setup.queue_preferences_save(prefs) + SScharacters.queue_preferences_save(prefs) feedback_add_details("admin_verb","TDigestNoise") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! diff --git a/code/modules/preferences/apply.dm b/code/modules/preferences/apply.dm new file mode 100644 index 00000000000..e097dcd3cf1 --- /dev/null +++ b/code/modules/preferences/apply.dm @@ -0,0 +1,55 @@ +/datum/preferences/proc/spawn_checks(flags, list/errors) + . = TRUE + for(var/datum/category_group/player_setup_category/category in player_setup.categories) + if(!category.spawn_checks(src, flags, errors)) + . = FALSE + +// todo: at some point we should support nonhuman copy to's better. +/datum/preferences/proc/copy_to(mob/living/carbon/human/character, flags) + // Sanitizing rather than saving as someone might still be editing when copy_to occurs. + player_setup.sanitize_setup() + sanitize_everything() + + // snowflake begin + // Special Case: This references variables owned by two different datums, so do it here. + if(be_random_name) + real_name = random_name(identifying_gender, real_species_name()) + // snowflake end + + // Copy start + // Gather + // todo: cache items by load order + var/list/datum/category_item/player_setup_item/items = list() + for(var/datum/category_group/player_setup_category/C as anything in player_setup.categories) + for(var/datum/category_item/player_setup_item/I as anything in C.items) + BINARY_INSERT(I, items, /datum/category_item/player_setup_item, I, load_order, COMPARE_KEY) + // copy to + for(var/datum/category_item/player_setup_item/I as anything in items) + I.copy_to_mob(src, character, I.is_global? get_global_data(I.save_key) : get_character_data(I.save_key), flags) + + // Sync up all their organs and species one final time + character.force_update_organs() +// character.s_base = s_base //doesn't work, fuck me + + if(!(flags & PREF_COPY_TO_DO_NOT_RENDER)) + character.force_update_limbs() + character.update_icons_body() + character.update_mutations() + character.update_underwear() + character.update_hair() + + if(LAZYLEN(character.descriptors)) + for(var/entry in body_descriptors) + character.descriptors[entry] = body_descriptors[entry] + +/** + * /datum/mind is usually used to semantically track someone's soul + * (this sounds stupid to say in a code comment but whatever) + * + * therefore if we want to get original state of a player at roundstart, + * we're going to want to store prefs data + * + * pref items are able to copy_to_mob without a prefs datum to support this + */ +/datum/preferences/proc/imprint_mind(datum/mind/M) + M.original_save_data = deep_copy_list(character) diff --git a/code/modules/preferences/data.dm b/code/modules/preferences/data.dm new file mode 100644 index 00000000000..f23ce4a764c --- /dev/null +++ b/code/modules/preferences/data.dm @@ -0,0 +1,270 @@ +/** + * sets a character data key to a value + */ +/datum/preferences/proc/set_character_data(key, value) + character[key] = value + +/** + * reads a character data key + */ +/datum/preferences/proc/get_character_data(key) + return character[key] + +/** + * sets a global options data key to a value + */ +/datum/preferences/proc/set_global_data(key, value) + options[key] = value + +/** + * reads a global options data key + */ +/datum/preferences/proc/get_global_data(key) + return options[key] + +/** + * checked read of a global options key; + * use when accessing from an outside datum to that key + */ +/datum/preferences/proc/checked_get_global_data(key) + var/datum/category_item/player_setup_item/I = preference_by_key[key] + if(!I.is_global) + CRASH("tried to get character key") + return options[key] + +/** + * checked write of a global options key; + * use when accessing from an outside datum to that key + */ +/datum/preferences/proc/checked_set_global_data(key, value) + var/datum/category_item/player_setup_item/I = preference_by_key[key] + if(!I.is_global) + CRASH("tried to set character key") + options[key] = I.filter_data(src, value) + +/** + * checked read of a character key; + * use when accessing from an outside datum to that key + */ +/datum/preferences/proc/checked_get_character_data(key) + var/datum/category_item/player_setup_item/I = preference_by_key[key] + if(!I.is_global) + CRASH("tried to get global key") + return character[key] + +/** + * checked write of a character key; + * use when accessing from an outside datum to that key + */ +/datum/preferences/proc/checked_set_character_data(key, value) + var/datum/category_item/player_setup_item/I = preference_by_key[key] + if(I.is_global) + CRASH("tried to set global key") + character[key] = I.filter_data(src, value) + +/** + * flush character data to disk + */ +/datum/preferences/proc/write_character_data(savefile/S, slot, list/errors) + var/old_cd = S.cd + S.cd = "/" + var/list/transformed = list() + //! warning: missing keys are automatically dropped. + //? Handle abstract + //! Write character data version + transformed[CHARACTER_DATA_VERSION] = character[CHARACTER_DATA_VERSION] + //? Handle prefs + for(var/key in character) + var/datum/category_item/player_setup_item/I = preference_by_key[key] + if(!I) + continue + if(I.is_global) + continue + transformed[key] = I.serialize_data(src, I.filter_data(src, character[key], errors), errors) + S["slot_[slot]"] << transformed + S.cd = old_cd + +/** + * load character data from disk + */ +/datum/preferences/proc/read_character_data(savefile/S, slot, list/errors) + character = list() + var/old_cd = S.cd + S.cd = "/" + var/list/transforming + S["slot_[slot]"] >> transforming + if(!islist(transforming)) + transforming = list() + //! warning: missing keys are automatically dropped. + //? Handle abstract + //! Read character data version + character[CHARACTER_DATA_VERSION] = transforming[CHARACTER_DATA_VERSION] + //? Handle prefs + for(var/key in preference_by_key) + var/datum/category_item/player_setup_item/I = preference_by_key[key] + if(!I) + continue + if(I.is_global) + continue + character[key] = I.filter_data(src, I.deserialize_data(src, transforming[key], errors), errors) + S.cd = old_cd + +/** + * flush global data to disk + */ +/datum/preferences/proc/write_global_data(savefile/S, list/errors) + var/old_cd = S.cd + S.cd = "/" + var/list/transformed = list() + //! warning: missing keys are automatically dropped. + //? Handle abstract + //? Handle prefs + for(var/key in options) + var/datum/category_item/player_setup_item/I = preference_by_key[key] + if(!I) + continue + if(!I.is_global) + continue + transformed[key] = I.serialize_data(src, I.filter_data(src, character[key], errors), errors) + S["global"] << transformed + S.cd = old_cd + +/** + * load global data from disk + */ +/datum/preferences/proc/read_global_data(savefile/S, list/errors) + options = list() + var/old_cd = S.cd + S.cd = "/" + var/list/transforming + S["global"] >> transforming + if(!islist(transforming)) + transforming = list() + //! warning: missing keys are automatically dropped. + //? Handle abstract + //? Handle prefs + for(var/key in preference_by_key) + var/datum/category_item/player_setup_item/I = preference_by_key[key] + if(!I) + continue + if(!I.is_global) + continue + character[key] = I.filter_data(src, I.deserialize_data(src, transforming[key], errors), errors) + S.cd = old_cd + +/** + * checked set preference data + */ +/datum/preferences/proc/set_preference(pref, value) + var/datum/category_item/player_setup_item/preference = preference_by_type[pref] + value = preference.filter_data(src, value) + if(preference.is_global) + options[preference.save_key] = value + else + character[preference.save_key] = value + +/** + * checked get preference data + */ +/datum/preferences/proc/get_preference(pref) + var/datum/category_item/player_setup_item/preference = preference_by_type[pref] + if(preference.is_global) + return options[preference.save_key] + else + return character[preference.save_key] + +/** + * sanitize prefs data + */ +/datum/preferences/proc/sanitize_preference(pref, list/errors) + var/datum/category_item/player_setup_item/preference = preference_by_type[pref] + if(preference.is_global) + return options[preference.save_key] = preference.filter_data(src, options[preference.save_key], errors) + else + return character[preference.save_key] = preference.filter_data(src, character[preference.save_key], errors) + +/** + * resanitize everything + */ +/datum/preferences/proc/sanitize_everything(list/errors) + for(var/key in preference_by_key) + var/datum/category_item/player_setup_item/I = preference_by_key[key] + I.sanitize_data(src, errors) + +/datum/preferences/proc/sanitize_character(list/errors) + for(var/key in preference_by_key) + var/datum/category_item/player_setup_item/I = preference_by_key[key] + if(I.is_global) + continue + I.sanitize_data(src, errors) + +/datum/preferences/proc/sanitize_global(list/errors) + for(var/key in preference_by_key) + var/datum/category_item/player_setup_item/I = preference_by_key[key] + if(!I.is_global) + continue + I.sanitize_data(src, errors) + +/** + * default everything that has save keys + */ +/datum/preferences/proc/reset_everything_to_default() + character = list() + options = list() + for(var/key in preference_by_key) + var/datum/category_item/player_setup_item/I = preference_by_key[key] + if(I.is_global) + set_global_data(key, I.informed_default_value(src)) + else + set_character_data(key, I.informed_default_value(src)) + +/datum/preferences/proc/reset_character_to_default() + character = list() + for(var/key in preference_by_key) + var/datum/category_item/player_setup_item/I = preference_by_key[key] + if(I.is_global) + continue + set_character_data(key, I.informed_default_value(src)) + +/datum/preferences/proc/reset_options_to_default() + options = list() + for(var/key in preference_by_key) + var/datum/category_item/player_setup_item/I = preference_by_key[key] + if(!I.is_global) + continue + set_global_data(key, I.informed_default_value(src)) + +/** + * json export + */ +/datum/preferences/proc/json_export_character(list/errors) + var/list/transformed = list() + for(var/key in character) + var/datum/category_item/player_setup_item/I = preference_by_key[key] + transformed[key] = I.serialize_data(src, I.filter_data(src, character[key], errors), errors) + return json_encode(transformed) + +/** + * json import + */ +/datum/preferences/proc/json_import_character(list/json, list/errors) + if(!islist(json)) + json = safe_json_decode(json) + if(!islist(json)) + return FALSE + var/list/parsed = list() + for(var/key in preference_by_key) + if(!json[key]) + continue + var/datum/category_item/player_setup_item/I = preference_by_key[key] + if(!I) + continue + parsed += key + if(I.is_global) + errors?.Add("Skipping key [key] - was global") + continue + character[key] = I.filter_data(src, I.deserialize_data(src, json[key], errors), errors) + var/list/skipped = json - parsed + for(var/key in skipped) + errors?.Add("Skipping key [key] - no datum found.") + return TRUE diff --git a/code/modules/preferences/errors.dm b/code/modules/preferences/errors.dm new file mode 100644 index 00000000000..0299c753c0e --- /dev/null +++ b/code/modules/preferences/errors.dm @@ -0,0 +1,24 @@ +/datum/preferences/proc/auto_flush_errors() + if(!client) + return + flush_errors(client) + +/datum/preferences/proc/flush_errors(client/C) + if(!C) + return + if(!LAZYLEN(io_error_queue)) + return + to_chat(C, io_error_queue.Join("
")) + io_error_queue = null + +/datum/preferences/proc/queue_errors(list/errors, head_message) + if(!LAZYLEN(errors)) + return + LAZYINITLIST(io_error_queue) + var/list/lined = list() + var/i = 0 + if(head_message) + lined += head_message + for(var/error in errors) + lined += "[++i]: [error]" + io_error_queue += errors diff --git a/code/modules/preferences/migration.dm b/code/modules/preferences/migration.dm new file mode 100644 index 00000000000..c76247b5183 --- /dev/null +++ b/code/modules/preferences/migration.dm @@ -0,0 +1,126 @@ +/** + * @params + * - S - the savefile we operate on + * - current_version - the version it's at + * - errors - put errors into this list to be displayed to the player + * - options - the loaded global options list + */ +/datum/preferences/proc/perform_global_migrations(savefile/S, current_version, list/errors, list/options) + if(current_version < 13) + addtimer(CALLBACK(src, .proc/force_reset_keybindings), 5 SECONDS) + if(current_version < 15) + var/list/language_prefixes + S["language_prefixes"] >> language_prefixes + if(!islist(language_prefixes)) + language_prefixes = list() + options[GLOBAL_DATA_LANGUAGE_PREFIX] = language_prefixes.Copy() + +/** + * @params + * - S - the savefile we operate on + * - current_version - the version it's at + * - errors - put errors into this list to be displayed to the player + * - options - the loaded character options list + */ +/datum/preferences/proc/perform_character_migrations(savefile/S, current_version, list/errors, list/character) + if(current_version < 1) + // MIGRATE JOBS + var/alternative_option + var/job_civilian_high + var/job_civilian_med + var/job_civilian_low + var/job_medsci_high + var/job_medsci_low + var/job_medsci_med + var/job_talon_high + var/job_talon_low + var/job_talon_med + var/job_engsec_high + var/job_engsec_med + var/job_engsec_low + var/list/player_alt_titles + READ_FILE(S["alternate_option"], alternative_option) + READ_FILE(S["job_civilian_high"], job_civilian_high) + READ_FILE(S["job_civilian_med"], job_civilian_med) + READ_FILE(S["job_civilian_low"], job_civilian_low) + READ_FILE(S["job_medsci_high"], job_medsci_high) + READ_FILE(S["job_medsci_med"], job_medsci_med) + READ_FILE(S["job_medsci_low"], job_medsci_low) + READ_FILE(S["job_engsec_high"], job_engsec_high) + READ_FILE(S["job_engsec_med"], job_engsec_med) + READ_FILE(S["job_engsec_low"], job_engsec_low) + READ_FILE(S["job_talon_low"], job_talon_low) + READ_FILE(S["job_talon_med"], job_talon_med) + READ_FILE(S["job_talon_high"], job_talon_high) + READ_FILE(S["player_alt_titles"], player_alt_titles) + var/list/assembled = list() + var/list/assembled_titles = list() + if(!islist(player_alt_titles)) + player_alt_titles = list() + for(var/datum/job/J as anything in SSjob.occupations) + switch(J.department_flag) + if(CIVILIAN) + if(job_civilian_high & J.flag) + assembled[J.id] = JOB_PRIORITY_HIGH + else if(job_civilian_med & J.flag) + assembled[J.id] = JOB_PRIORITY_MEDIUM + else if(job_civilian_low & J.flag) + assembled[J.id] = JOB_PRIORITY_LOW + if(MEDSCI) + if(job_medsci_high & J.flag) + assembled[J.id] = JOB_PRIORITY_HIGH + else if(job_medsci_med & J.flag) + assembled[J.id] = JOB_PRIORITY_MEDIUM + else if(job_medsci_low & J.flag) + assembled[J.id] = JOB_PRIORITY_LOW + if(ENGSEC) + if(job_engsec_high & J.flag) + assembled[J.id] = JOB_PRIORITY_HIGH + else if(job_engsec_med & J.flag) + assembled[J.id] = JOB_PRIORITY_MEDIUM + else if(job_engsec_low & J.flag) + assembled[J.id] = JOB_PRIORITY_LOW + if(player_alt_titles[J.title]) + assembled_titles[J.id] = player_alt_titles[J.title] + var/overflow + switch(alternative_option) + if(0) + overflow = JOB_ALTERNATIVE_GET_RANDOM + if(1) + overflow = JOB_ALTERNATIVE_BE_ASSISTANT + if(2) + overflow = JOB_ALTERNATIVE_RETURN_LOBBY + character[CHARACTER_DATA_JOBS] = assembled + character[CHARACTER_DATA_OVERFLOW_MODE] = overflow + character[CHARACTER_DATA_ALT_TITLES] = assembled_titles + // BACKGROUNDS: NOT MIGRATED + // MIGRATE SPECIES + var/name_species + S["species"] >> name_species + var/datum/species/RS = SScharacters.resolve_species_name(name_species) + if(!RS) + if(name_species) // if they had any at all + errors?.Add(SPAN_WARNING("Species reset to human - no species found of old species name ([name_species])")) + RS = SScharacters.resolve_species_path(/datum/species/human) + // todo: default species? + if(RS) + character[CHARACTER_DATA_REAL_SPECIES] = RS.uid + character[CHARACTER_DATA_CHAR_SPECIES] = RS.uid + else + errors?.Add(SPAN_DANGER("Species migration failed - no species datum. Report this to a coder.")) + // MIGRATE LANGUAGES + var/list/alternate_languages + S["language"] >> alternate_languages + if(!islist(alternate_languages)) + alternate_languages = list() + var/list/translated_languages = list() + character[CHARACTER_DATA_LANGUAGES] = translated_languages + var/list/innate = innate_language_ids() + for(var/name in alternate_languages) + var/datum/language/L = SScharacters.resolve_language_name(name) + if(L.id in innate) + continue + translated_languages += L.id + translated_languages.len = clamp(translated_languages.len, 0, extraneous_languages_max()) + if(current_version < 2) + character -= GLOBAL_DATA_LANGUAGE_PREFIX diff --git a/code/modules/client/preference_setup/antagonism/01_basic.dm b/code/modules/preferences/preference_setup/antagonism/01_basic.dm similarity index 88% rename from code/modules/client/preference_setup/antagonism/01_basic.dm rename to code/modules/preferences/preference_setup/antagonism/01_basic.dm index 8a8ea5d0c1a..ad8bea0f97f 100644 --- a/code/modules/client/preference_setup/antagonism/01_basic.dm +++ b/code/modules/preferences/preference_setup/antagonism/01_basic.dm @@ -22,12 +22,17 @@ var/global/list/uplink_locations = list("PDA", "Headset", "None") if(!pref.antag_vis) pref.antag_vis = "Hidden" // Moved from /datum/preferences/proc/copy_to() -/datum/category_item/player_setup_item/antagonism/basic/copy_to_mob(var/mob/living/carbon/human/character) +/datum/category_item/player_setup_item/antagonism/basic/copy_to_mob(datum/preferences/prefs, mob/M, data, flags) + // todo: this is just a shim + if(!ishuman(M)) + return TRUE + var/mob/living/carbon/human/character = M character.exploit_record = pref.exploit_record character.antag_faction = pref.antag_faction character.antag_vis = pref.antag_vis + return TRUE -/datum/category_item/player_setup_item/antagonism/basic/content(var/mob/user) +/datum/category_item/player_setup_item/antagonism/basic/content(datum/preferences/prefs, mob/user, data) . += "Faction: [pref.antag_faction]
" . += "Visibility: [pref.antag_vis]
" . +="Uplink Type : [pref.uplinklocation]" @@ -41,32 +46,32 @@ var/global/list/uplink_locations = list("PDA", "Headset", "None") /datum/category_item/player_setup_item/antagonism/basic/OnTopic(var/href,var/list/href_list, var/mob/user) if (href_list["antagtask"]) pref.uplinklocation = next_list_item(pref.uplinklocation, uplink_locations) - return TOPIC_REFRESH + return PREFERENCES_REFRESH if(href_list["exploitable_record"]) var/exploitmsg = sanitize(input(user,"Set exploitable information about you here.","Exploitable Information", html_decode(pref.exploit_record)) as message|null, MAX_RECORD_LENGTH, extra = 0) if(!isnull(exploitmsg) && !jobban_isbanned(user, "Records") && CanUseTopic(user)) pref.exploit_record = exploitmsg - return TOPIC_REFRESH + return PREFERENCES_REFRESH if(href_list["antagfaction"]) var/choice = input(user, "Please choose an antagonistic faction to work for.", "Character Preference", pref.antag_faction) as null|anything in antag_faction_choices + list("None","Other") if(!choice || !CanUseTopic(user)) - return TOPIC_NOACTION + return PREFERENCES_NOACTION if(choice == "Other") var/raw_choice = sanitize(input(user, "Please enter a faction.", "Character Preference") as text|null, MAX_NAME_LEN) if(raw_choice) pref.antag_faction = raw_choice else pref.antag_faction = choice - return TOPIC_REFRESH + return PREFERENCES_REFRESH if(href_list["antagvis"]) var/choice = input(user, "Please choose an antagonistic visibility level.", "Character Preference", pref.antag_vis) as null|anything in antag_visiblity_choices if(!choice || !CanUseTopic(user)) - return TOPIC_NOACTION + return PREFERENCES_NOACTION else pref.antag_vis = choice - return TOPIC_REFRESH + return PREFERENCES_REFRESH return ..() diff --git a/code/modules/client/preference_setup/antagonism/02_candidacy.dm b/code/modules/preferences/preference_setup/antagonism/02_candidacy.dm similarity index 97% rename from code/modules/client/preference_setup/antagonism/02_candidacy.dm rename to code/modules/preferences/preference_setup/antagonism/02_candidacy.dm index 5a6ba354f00..fdbb249cf45 100644 --- a/code/modules/client/preference_setup/antagonism/02_candidacy.dm +++ b/code/modules/preferences/preference_setup/antagonism/02_candidacy.dm @@ -35,7 +35,7 @@ var/global/list/special_roles = list( //keep synced with the defines BE_* in set pref.be_special = sanitize_integer(pref.be_special, 0, 65535, initial(pref.be_special)) pref.be_event_role = sanitize_integer(pref.be_event_role, NONE, ALL, default = NONE) -/datum/category_item/player_setup_item/antagonism/candidacy/content(var/mob/user) +/datum/category_item/player_setup_item/antagonism/candidacy/content(datum/preferences/prefs, mob/user, data) . += "Event Role Preferences \[?]
" for(var/i in GLOB.event_role_list) . += "[i] \[?]: [pref.be_event_role & GLOB.event_role_list[i]? "Yes" : "No"]
" @@ -57,7 +57,7 @@ var/global/list/special_roles = list( //keep synced with the defines BE_* in set if(href_list["be_special"]) var/num = text2num(href_list["be_special"]) pref.be_special ^= (1<Toggles candidacy/preferences for partaking in certain kinds of events. Note that this doesn't mean you necessarily will or will not be involved in a certain way, \ but this may help administrators decide on candidates when necessary.") @@ -68,5 +68,5 @@ var/global/list/special_roles = list( //keep synced with the defines BE_* in set return if(href_list["event_role_toggle"]) pref.be_event_role ^= text2num(href_list["event_role_toggle"]) // do i care about href exploits no what are you gonna do turn your own prefs off LOL - return TOPIC_REFRESH + return PREFERENCES_REFRESH return ..() diff --git a/code/modules/preferences/preference_setup/background/_background.dm b/code/modules/preferences/preference_setup/background/_background.dm new file mode 100644 index 00000000000..90c1089d9b3 --- /dev/null +++ b/code/modules/preferences/preference_setup/background/_background.dm @@ -0,0 +1,18 @@ +/datum/category_group/player_setup_category/background + name = "Background" + sort_order = 1.5 // floating point gaming + category_item_type = /datum/category_item/player_setup_item/background + auto_split = FALSE + auto_rule = TRUE + +/datum/category_item/player_setup_item/background + is_global = FALSE + load_order = PREFERENCE_LOAD_ORDER_LORE + +/datum/preferences/proc/sanitize_background_lore() + sanitize_preference(/datum/category_item/player_setup_item/background/citizenship) + sanitize_preference(/datum/category_item/player_setup_item/background/faction) + sanitize_preference(/datum/category_item/player_setup_item/background/origin) + sanitize_preference(/datum/category_item/player_setup_item/background/religion) + // do language last + sanitize_preference(/datum/category_item/player_setup_item/background/language) diff --git a/code/modules/preferences/preference_setup/background/citizenship.dm b/code/modules/preferences/preference_setup/background/citizenship.dm new file mode 100644 index 00000000000..ba6dc6624a7 --- /dev/null +++ b/code/modules/preferences/preference_setup/background/citizenship.dm @@ -0,0 +1,71 @@ +/datum/category_item/player_setup_item/background/citizenship + name = "Citizenship" + save_key = CHARACTER_DATA_CITIZENSHIP + sort_order = 3 + +/datum/category_item/player_setup_item/background/citizenship/content(datum/preferences/prefs, mob/user, data) + . = list() + var/list/datum/lore/character_background/citizenship/available = SScharacters.available_citizenships(prefs.character_species_id()) + var/datum/lore/character_background/citizenship/current = SScharacters.resolve_citizenship(data) + . += "
" + . += "Citizenship
" + for(var/datum/lore/character_background/citizenship/O in available) + if(O == current) + . += "[O.name]" + else + . += href_simple(prefs, "pick", "[O.name]", O.id) + . += " " + . += "
" + . += "
" + . += current? current.desc : "
error; citizenship load failed
" + . += "
" + +/datum/category_item/player_setup_item/background/citizenship/act(datum/preferences/prefs, mob/user, action, list/params) + switch(action) + if("pick") + var/id = params["pick"] + var/datum/lore/character_background/citizenship/O = SScharacters.resolve_citizenship(id) + if(!id) + return + if(!O.check_species_id(prefs.character_species_id())) + to_chat(user, SPAN_WARNING("[prefs.character_species_name()] cannot pick this citizenship.")) + return PREFERENCES_NOACTION + write(prefs, id) + prefs.sanitize_background_lore() // update + return PREFERENCES_REFRESH + return ..() + +/datum/category_item/player_setup_item/background/citizenship/filter_data(datum/preferences/prefs, data, list/errors) + var/datum/lore/character_background/citizenship/current = SScharacters.resolve_citizenship(data) + if(!current?.check_species_id(prefs.character_species_id())) + return SScharacters.resolve_citizenship(/datum/lore/character_background/citizenship/custom).id + return data + +/datum/category_item/player_setup_item/background/citizenship/copy_to_mob(datum/preferences/prefs, mob/M, data, flags) + // todo: sources - this one is from culture/bcakground + var/datum/lore/character_background/B = SScharacters.resolve_citizenship(data) + for(var/id in B.innate_languages) + M.add_language(id) + return TRUE + +/datum/category_item/player_setup_item/background/citizenship/spawn_checks(datum/preferences/prefs, data, flags, list/errors) + var/datum/lore/character_background/citizenship/current = SScharacters.resolve_citizenship(data) + if(!current?.check_species_id(prefs.character_species_id())) + errors?.Add("Invalid citizenship for your current species.") + return FALSE + return TRUE + +/datum/category_item/player_setup_item/background/citizenship/default_value(randomizing) + return SScharacters.resolve_citizenship(/datum/lore/character_background/citizenship/custom).id + +/datum/category_item/player_setup_item/background/citizenship/informed_default_value(datum/preferences/prefs, randomizing) + var/datum/character_species/S = SScharacters.resolve_character_species(prefs.character_species_id()) + if(!S) + return ..() + return S.get_default_citizenship_id() + +/datum/preferences/proc/lore_citizenship_id() + return get_character_data(CHARACTER_DATA_CITIZENSHIP) + +/datum/preferences/proc/lore_citizenship_datum() + return SScharacters.resolve_citizenship(lore_citizenship_id()) diff --git a/code/modules/preferences/preference_setup/background/faction.dm b/code/modules/preferences/preference_setup/background/faction.dm new file mode 100644 index 00000000000..7125559f2ce --- /dev/null +++ b/code/modules/preferences/preference_setup/background/faction.dm @@ -0,0 +1,91 @@ +/datum/category_item/player_setup_item/background/faction + name = "Faction" + save_key = CHARACTER_DATA_FACTION + load_order = PREFERENCE_LOAD_ORDER_LORE_FACTION + sort_order = 5 + +/datum/category_item/player_setup_item/background/faction/content(datum/preferences/prefs, mob/user, data) + . = list() + var/list/datum/lore/character_background/faction/available = SScharacters.available_factions(prefs.character_species_id(), prefs.lore_origin_id(), prefs.lore_citizenship_id()) + var/datum/lore/character_background/faction/current = SScharacters.resolve_faction(data) + . += "
" + . += "Faction
" + for(var/datum/lore/character_background/faction/O in available) + if(O == current) + . += "[O.name]" + else + . += href_simple(prefs, "pick", "[O.name]", O.id) + . += " " + . += "
" + . += "
" + . += current? current.desc : "
error; faction load failed
" + . += "
" + +/datum/category_item/player_setup_item/background/faction/act(datum/preferences/prefs, mob/user, action, list/params) + switch(action) + if("pick") + var/id = params["pick"] + var/datum/lore/character_background/faction/O = SScharacters.resolve_faction(id) + if(!id) + return + if(!O.check_species_id(prefs.character_species_id())) + to_chat(user, SPAN_WARNING("[prefs.character_species_name()] cannot pick this faction.")) + return PREFERENCES_NOACTION + write(prefs, id) + GLOB.join_menu?.update_static_data(user) + return PREFERENCES_REFRESH_UPDATE_PREVIEW + return ..() + +/datum/category_item/player_setup_item/background/faction/filter_data(datum/preferences/prefs, data, list/errors) + var/datum/lore/character_background/faction/current = SScharacters.resolve_faction(data) + if(!current?.check_species_id(prefs.character_species_id())) + return SScharacters.resolve_faction(/datum/lore/character_background/faction/nanotrasen).id + // thanks papalus + var/datum/lore/character_background/origin/origin = prefs.lore_origin_datum() + if(current.origin_whitelist && !(origin.id in current.origin_whitelist)) + return SScharacters.resolve_faction(/datum/lore/character_background/faction/nanotrasen).id + var/datum/lore/character_background/citizenship/citizenship = prefs.lore_citizenship_datum() + if(current.citizenship_whitelist && !(citizenship.id in current.citizenship_whitelist)) + return SScharacters.resolve_faction(/datum/lore/character_background/faction/nanotrasen).id + return data + +/datum/category_item/player_setup_item/background/faction/copy_to_mob(datum/preferences/prefs, mob/M, data, flags) + // todo: sources - this one is from culture/bcakground + var/datum/lore/character_background/B = SScharacters.resolve_faction(data) + for(var/id in B.innate_languages) + M.add_language(id) + return TRUE + +/datum/category_item/player_setup_item/background/faction/spawn_checks(datum/preferences/prefs, data, flags, list/errors) + var/datum/lore/character_background/faction/current = SScharacters.resolve_faction(data) + if(!current?.check_species_id(prefs.character_species_id())) + errors?.Add("Invalid faction for your current species.") + return FALSE + // thanks papalus + var/datum/lore/character_background/origin/origin = prefs.lore_origin_datum() + if(current.origin_whitelist && !(origin.id in current.origin_whitelist)) + errors?.Add("Your current faction is not allowed to be chosen by your origin.") + return FALSE + var/datum/lore/character_background/citizenship/citizenship = prefs.lore_citizenship_datum() + if(current.citizenship_whitelist && !(citizenship.id in current.citizenship_whitelist)) + errors?.Add("Your current faction is not allowed to be chosen by your citizenship.") + return FALSE + return TRUE + +/datum/category_item/player_setup_item/background/faction/default_value(randomizing) + return SScharacters.resolve_faction(/datum/lore/character_background/faction/nanotrasen).id + +/datum/category_item/player_setup_item/background/faction/informed_default_value(datum/preferences/prefs, randomizing) + var/datum/character_species/S = SScharacters.resolve_character_species(prefs.character_species_id()) + if(!S) + return ..() + return S.get_default_faction_id() + +/datum/preferences/proc/lore_faction_id() + return get_character_data(CHARACTER_DATA_FACTION) + +/datum/preferences/proc/lore_faction_datum() + return get_character_data(CHARACTER_DATA_FACTION) + +/datum/preferences/proc/lore_faction_job_check(datum/job/J) + return SScharacters.resolve_faction(get_character_data(CHARACTER_DATA_FACTION))?.check_job_id(J.id) diff --git a/code/modules/preferences/preference_setup/background/language.dm b/code/modules/preferences/preference_setup/background/language.dm new file mode 100644 index 00000000000..eefdb2c9627 --- /dev/null +++ b/code/modules/preferences/preference_setup/background/language.dm @@ -0,0 +1,117 @@ +/datum/category_item/player_setup_item/background/language + name = "Language" + sort_order = 1.5 + save_key = CHARACTER_DATA_LANGUAGES + load_order = PREFERENCE_LOAD_ORDER_LANGUAGE + +/datum/category_item/player_setup_item/background/language/content(datum/preferences/prefs, mob/user, data) + . = list() + var/list/innate_names = list() + for(var/id in prefs.innate_language_ids()) + var/datum/language/L = SScharacters.resolve_language_id(id) + innate_names += L.name + . += "
Languages
" + . += "
" + . += "    Intrinsic (Species, Backgrounds, Cultures): [english_list(innate_names)]
" + . += "    Additional: " + var/count = 0 + for(var/id in prefs.extraneous_language_ids()) + ++count + var/datum/language/L = SScharacters.resolve_language_id(id) + . += "[L.name] [href_simple(prefs, "remove", "Remove", id)]" + . += " " + if(count < prefs.extraneous_languages_max()) + . += "[href_simple(prefs, "add", "Add")]" + . += "
" + +/datum/category_item/player_setup_item/background/language/act(datum/preferences/prefs, mob/user, action, list/params) + switch(action) + if("add") + prefs.language_pick(user) + return PREFERENCES_HANDLED + if("remove") + var/id = params["remove"] + var/list/existing = read(prefs) + if(existing.Remove(id)) + write(prefs, existing) + return PREFERENCES_REFRESH + return PREFERENCES_NOACTION + return ..() + +/datum/category_item/player_setup_item/background/language/filter_data(datum/preferences/prefs, data, list/errors) + var/list/languages = sanitize_islist(data) + var/list/innate = prefs.innate_language_ids() + var/list/extra = languages.Copy() + extra -= innate + var/extra_max = prefs.extraneous_languages_max() + if(extra.len > extra_max) + var/list/truncated = extra.Copy(extra_max + 1) + extra.len = clamp(extra.len, 0, extra_max) + errors?.Add(SPAN_WARNING("truncated [english_list(truncated)] languages - too many!")) + return extra + +/datum/category_item/player_setup_item/background/language/copy_to_mob(datum/preferences/prefs, mob/M, data, flags) + if(!ishuman(M)) + return TRUE + var/mob/living/carbon/human/H = M + // todo: sources - this one is extraneous + for(var/id in data) + H.add_language(id) + +/datum/category_item/player_setup_item/background/language/spawn_checks(datum/preferences/prefs, data, flags, list/errors) + if(length(data) > prefs.extraneous_languages_max()) + errors?.Add(SPAN_WARNING("You have selected too many extra languages for your species and culture.")) + return FALSE + var/list/extraneous = data + var/datum/character_species/CS = prefs.character_species_datum() + for(var/id in extraneous) + var/datum/language/L = SScharacters.resolve_language_id(id) + if((L.language_flags & WHITELISTED) && (!(L in CS.whitelist_languages)) && !config.check_alien_whitelist(ckey(L.name), prefs.client_ckey)) + errors?.Add(SPAN_WARNING("[L.id] is a whitelisted language.")) + return FALSE + return TRUE + +/datum/category_item/player_setup_item/background/language/default_value(randomizing) + return list(LANGUAGE_ID_COMMON) + +/datum/category_item/player_setup_item/background/language/informed_default_value(datum/preferences/prefs, randomizing) + return prefs.innate_language_ids() + +/** + * returns ids of languages that are innate to our species/background + */ +/datum/preferences/proc/innate_language_ids(include_background = TRUE) + RETURN_TYPE(/list) + var/datum/character_species/S = character_species_datum() + . = S.get_intrinsic_language_ids() + if(include_background) + var/list/datum/lore/character_background/backgrounds = list( + lore_citizenship_datum(), + lore_origin_datum(), + lore_religion_datum(), + lore_faction_datum() + ) + for(var/datum/lore/character_background/B in backgrounds) // eh let's type filter + if(!B.innate_languages) + continue + . |= B.innate_languages + +/** + * returns max amounts we can have. doesn't take into account what we do have. + */ +/datum/preferences/proc/extraneous_languages_max() + return max(character_species_datum().max_additional_languages, 0) + +/** + * returns ids of languages that aren't innate to our species/background + */ +/datum/preferences/proc/extraneous_language_ids() + RETURN_TYPE(/list) + return get_character_data(CHARACTER_DATA_LANGUAGES) - innate_language_ids() + +/** + * returns ids of ALL languages + */ +/datum/preferences/proc/all_language_ids() + RETURN_TYPE(/list) + return innate_language_ids() + get_character_data(CHARACTER_DATA_LANGUAGES) diff --git a/code/modules/preferences/preference_setup/background/origin.dm b/code/modules/preferences/preference_setup/background/origin.dm new file mode 100644 index 00000000000..6f431e50d40 --- /dev/null +++ b/code/modules/preferences/preference_setup/background/origin.dm @@ -0,0 +1,87 @@ +/datum/category_item/player_setup_item/background/origin + name = "Origin" + save_key = CHARACTER_DATA_ORIGIN + sort_order = 2 + +/datum/category_item/player_setup_item/background/origin/content(datum/preferences/prefs, mob/user, data) + . = list() + var/list/datum/lore/character_background/origin/available = SScharacters.available_origins(prefs.character_species_id()) + var/list/categories = list() + for(var/datum/lore/character_background/origin/O as anything in available) + LAZYADD(categories[O.category], O) + var/datum/lore/character_background/origin/current = SScharacters.resolve_origin(data) + . += "
" + . += "Origin
" + for(var/category in categories) + . += (category == current.category)? "[category] " : href_simple(prefs, "category", "[category]", category) + . += " " + . += "
" + for(var/datum/lore/character_background/origin/O in categories[current.category]) + if(O == current) + . += "[O.name]" + else + . += href_simple(prefs, "pick", "[O.name]", O.id) + . += " " + . += "
" + . += "
" + . += current? current.desc : "
error; origin load failed
" + . += "
" + +/datum/category_item/player_setup_item/background/origin/act(datum/preferences/prefs, mob/user, action, list/params) + switch(action) + if("pick") + var/id = params["pick"] + var/datum/lore/character_background/origin/O = SScharacters.resolve_origin(id) + if(!id) + return + if(!O.check_species_id(prefs.character_species_id())) + to_chat(user, SPAN_WARNING("[prefs.character_species_name()] cannot pick this origin.")) + return PREFERENCES_NOACTION + write(prefs, id) + return PREFERENCES_REFRESH + if("category") + var/cat = params["category"] + var/list/datum/lore/character_background/origin/origins = SScharacters.available_origins(prefs.character_species_id(), cat) + if(!length(origins)) + to_chat(user, SPAN_WARNING("No origins in that category have been found; this might be an error.")) + return PREFERENCES_NOACTION + var/datum/lore/character_background/origin/first = origins[1] + write(prefs, first.id) + prefs.sanitize_background_lore() // update + return PREFERENCES_REFRESH + return ..() + +/datum/category_item/player_setup_item/background/origin/filter_data(datum/preferences/prefs, data, list/errors) + var/datum/lore/character_background/origin/current = SScharacters.resolve_origin(data) + if(!current?.check_species_id(prefs.character_species_id())) + return SScharacters.resolve_religion(/datum/lore/character_background/origin/custom).id + return data + +/datum/category_item/player_setup_item/background/origin/copy_to_mob(datum/preferences/prefs, mob/M, data, flags) + // todo: sources - this one is from culture/bcakground + var/datum/lore/character_background/B = SScharacters.resolve_origin(data) + for(var/id in B.innate_languages) + M.add_language(id) + return TRUE + +/datum/category_item/player_setup_item/background/origin/spawn_checks(datum/preferences/prefs, data, flags, list/errors) + var/datum/lore/character_background/origin/current = SScharacters.resolve_origin(data) + if(!current?.check_species_id(prefs.character_species_id())) + errors?.Add("Invalid origin for your current species.") + return FALSE + return TRUE + +/datum/category_item/player_setup_item/background/origin/default_value(randomizing) + return SScharacters.resolve_religion(/datum/lore/character_background/origin/custom).id + +/datum/category_item/player_setup_item/background/origin/informed_default_value(datum/preferences/prefs, randomizing) + var/datum/character_species/S = SScharacters.resolve_character_species(prefs.character_species_id()) + if(!S) + return ..() + return S.get_default_origin_id() + +/datum/preferences/proc/lore_origin_id() + return get_character_data(CHARACTER_DATA_ORIGIN) + +/datum/preferences/proc/lore_origin_datum() + return SScharacters.resolve_origin(lore_origin_id()) diff --git a/code/modules/preferences/preference_setup/background/religion.dm b/code/modules/preferences/preference_setup/background/religion.dm new file mode 100644 index 00000000000..4d75fe4dbfa --- /dev/null +++ b/code/modules/preferences/preference_setup/background/religion.dm @@ -0,0 +1,70 @@ +/datum/category_item/player_setup_item/background/religion + name = "Religion" + save_key = CHARACTER_DATA_RELIGION + sort_order = 6 + +/datum/category_item/player_setup_item/background/religion/content(datum/preferences/prefs, mob/user, data) + . = list() + var/list/datum/lore/character_background/religion/available = SScharacters.available_religions(prefs.character_species_id()) + var/datum/lore/character_background/religion/current = SScharacters.resolve_religion(data) + . += "
" + . += "Religion
" + for(var/datum/lore/character_background/religion/O in available) + if(O == current) + . += "[O.name]" + else + . += href_simple(prefs, "pick", "[O.name]", O.id) + . += " " + . += "
" + . += "
" + . += current? current.desc : "
error; religion load failed
" + . += "
" + +/datum/category_item/player_setup_item/background/religion/act(datum/preferences/prefs, mob/user, action, list/params) + switch(action) + if("pick") + var/id = params["pick"] + var/datum/lore/character_background/religion/O = SScharacters.resolve_religion(id) + if(!id) + return + if(!O.check_species_id(prefs.character_species_id())) + to_chat(user, SPAN_WARNING("[prefs.character_species_name()] cannot pick this religion.")) + return PREFERENCES_NOACTION + write(prefs, id) + return PREFERENCES_REFRESH + return ..() + +/datum/category_item/player_setup_item/background/religion/filter_data(datum/preferences/prefs, data, list/errors) + var/datum/lore/character_background/religion/current = SScharacters.resolve_religion(data) + if(!current?.check_species_id(prefs.character_species_id())) + return SScharacters.resolve_religion(/datum/lore/character_background/religion/custom).id + return data + +/datum/category_item/player_setup_item/background/religion/copy_to_mob(datum/preferences/prefs, mob/M, data, flags) + // todo: sources - this one is from culture/bcakground + var/datum/lore/character_background/B = SScharacters.resolve_religion(data) + for(var/id in B.innate_languages) + M.add_language(id) + return TRUE + +/datum/category_item/player_setup_item/background/religion/spawn_checks(datum/preferences/prefs, data, flags, list/errors) + var/datum/lore/character_background/religion/current = SScharacters.resolve_religion(data) + if(!current?.check_species_id(prefs.character_species_id())) + errors?.Add("Invalid religion for your current species.") + return FALSE + return TRUE + +/datum/category_item/player_setup_item/background/religion/default_value(randomizing) + return SScharacters.resolve_religion(/datum/lore/character_background/religion/custom).id + +/datum/category_item/player_setup_item/background/religion/informed_default_value(datum/preferences/prefs, randomizing) + var/datum/character_species/S = SScharacters.resolve_character_species(prefs.character_species_id()) + if(!S) + return ..() + return S.get_default_religion_id() + +/datum/preferences/proc/lore_religion_id() + return get_character_data(CHARACTER_DATA_RELIGION) + +/datum/preferences/proc/lore_religion_datum() + return SScharacters.resolve_religion(lore_religion_id()) diff --git a/code/modules/preferences/preference_setup/background/species.dm b/code/modules/preferences/preference_setup/background/species.dm new file mode 100644 index 00000000000..465eafc80df --- /dev/null +++ b/code/modules/preferences/preference_setup/background/species.dm @@ -0,0 +1,105 @@ +/datum/category_item/player_setup_item/background/char_species + name = "Character Species" + sort_order = 1 + save_key = CHARACTER_DATA_CHAR_SPECIES + load_order = PREFERENCE_LOAD_ORDER_CHAR_SPECIES + // todo: proper view-only section support + +/datum/category_item/player_setup_item/background/char_species/content(datum/preferences/prefs, mob/user, data) + . = list() + var/datum/character_species/S = prefs.character_species_datum() + . += "
" + . += "Species
[S.name] - \[[href_simple(prefs, "change", "CHANGE")]\]" + . += "
" + . += "
" + . += "[S.desc]" + . += "
" + +/datum/category_item/player_setup_item/background/char_species/spawn_checks(datum/preferences/prefs, data, flags, list/errors) + var/datum/character_species/CS = SScharacters.resolve_character_species(data) + if(CS.whitelisted && !config.check_alien_whitelist(ckey(CS.name), prefs.client_ckey)) + errors?.Add(SPAN_WARNING("[CS.name] is a whitelisted species!")) + return FALSE + return TRUE + +/datum/category_item/player_setup_item/background/char_species/filter_data(datum/preferences/prefs, data, list/errors) + // resolve + var/datum/character_species/CS = SScharacters.resolve_character_species(data) + if(CS) + // cool we found it + // but also, make sure we don't, for some reason, mismatch real species + var/real_id = prefs.get_character_data(CHARACTER_DATA_REAL_SPECIES) + var/datum/species/check_type = CS.real_species_type + if(!check_type || (real_id != initial(check_type.uid))) + // oh no :( + // default to real species type if possible, don't if not + return check_type? initial(check_type.uid) : informed_default_value(prefs) + return data + return informed_default_value(prefs) + +/datum/category_item/player_setup_item/background/char_species/informed_default_value(datum/preferences/prefs, randomizing) + // do they have a valid real species we can use? + var/real_id = prefs.get_character_data(CHARACTER_DATA_REAL_SPECIES) + var/datum/character_species/CS = SScharacters.resolve_character_species(real_id) + if(CS) + return real_id + // no :( + return default_value() + +/datum/category_item/player_setup_item/background/char_species/default_value(randomizing) + return SScharacters.default_species_id() + +/datum/category_item/player_setup_item/background/char_species/act(datum/preferences/prefs, mob/user, action, list/params) + switch(action) + if("change") + prefs.species_pick(user) + return PREFERENCES_HANDLED + return ..() + +// todo: proper view-only section support +/datum/category_item/player_setup_item/background/real_species + name = "(Virtual) Real Species" + sort_order = 2 + save_key = CHARACTER_DATA_REAL_SPECIES + load_order = PREFERENCE_LOAD_ORDER_REAL_SPECIES + +/datum/category_item/player_setup_item/background/real_species/filter_data(datum/preferences/prefs, data, list/errors) + var/datum/species/S = SScharacters.resolve_species_id(data) + if(!S) + return SScharacters.default_species_id() + if(!(S.name in SScharacters.playable_species)) + return SScharacters.default_species_id() + return data + +/datum/category_item/player_setup_item/background/real_species/default_value(randomizing) + return SScharacters.default_species_id() + +/datum/category_item/player_setup_item/background/real_species/copy_to_mob(datum/preferences/prefs, mob/M, data, flags) + if(!ishuman(M)) + return TRUE + var/mob/living/carbon/human/H = M + // we construct character species + H.set_species(SScharacters.construct_character_species(prefs.get_character_data(CHARACTER_DATA_CHAR_SPECIES))) + +/datum/preferences/proc/real_species_id() + return get_character_data(CHARACTER_DATA_REAL_SPECIES) + +/datum/preferences/proc/character_species_id() + return get_character_data(CHARACTER_DATA_CHAR_SPECIES) + +/datum/preferences/proc/character_species_datum() + RETURN_TYPE(/datum/character_species) + return SScharacters.resolve_character_species(get_character_data(CHARACTER_DATA_CHAR_SPECIES)) + +/datum/preferences/proc/character_species_name() + return SScharacters.resolve_character_species(get_character_data(CHARACTER_DATA_CHAR_SPECIES))?.name || "ERROR" + +/datum/preferences/proc/real_species_datum() + RETURN_TYPE(/datum/species) + return SScharacters.resolve_species_id(get_character_data(CHARACTER_DATA_REAL_SPECIES)) + +/datum/preferences/proc/real_species_name() + return SScharacters.resolve_species_id(get_character_data(CHARACTER_DATA_REAL_SPECIES)).name + +/datum/preferences/proc/character_species_job_check(datum/job/J) + return TRUE // todo diff --git a/code/modules/client/preference_setup/general/01_basic.dm b/code/modules/preferences/preference_setup/general/01_basic.dm similarity index 85% rename from code/modules/client/preference_setup/general/01_basic.dm rename to code/modules/preferences/preference_setup/general/01_basic.dm index 82066f61de4..fd9d209589e 100644 --- a/code/modules/client/preference_setup/general/01_basic.dm +++ b/code/modules/preferences/preference_setup/general/01_basic.dm @@ -31,18 +31,23 @@ S["OOC_Notes"] << pref.metadata /datum/category_item/player_setup_item/general/basic/sanitize_character() + var/species_name = pref.real_species_name() pref.age = sanitize_integer(pref.age, get_min_age(), get_max_age(), initial(pref.age)) pref.biological_gender = sanitize_inlist(pref.biological_gender, get_genders(), pick(get_genders())) pref.identifying_gender = (pref.identifying_gender in all_genders_define_list) ? pref.identifying_gender : pref.biological_gender - pref.real_name = sanitize_name(pref.real_name, pref.species, is_FBP()) + pref.real_name = sanitize_name(pref.real_name, species_name, is_FBP()) if(!pref.real_name) - pref.real_name = random_name(pref.identifying_gender, pref.species) + pref.real_name = random_name(pref.identifying_gender, species_name) pref.nickname = sanitize_name(pref.nickname) pref.spawnpoint = sanitize_inlist(pref.spawnpoint, spawntypes, initial(pref.spawnpoint)) pref.be_random_name = sanitize_integer(pref.be_random_name, 0, 1, initial(pref.be_random_name)) // Moved from /datum/preferences/proc/copy_to() -/datum/category_item/player_setup_item/general/basic/copy_to_mob(var/mob/living/carbon/human/character) +/datum/category_item/player_setup_item/general/basic/copy_to_mob(datum/preferences/prefs, mob/M, data, flags) + // todo: this is just a shim + if(!ishuman(M)) + return TRUE + var/mob/living/carbon/human/character = M if(config_legacy.humans_need_surnames) var/firstspace = findtext(pref.real_name, " ") var/name_length = length(pref.real_name) @@ -61,8 +66,9 @@ character.gender = pref.biological_gender character.identifying_gender = pref.identifying_gender character.age = pref.age + return TRUE -/datum/category_item/player_setup_item/general/basic/content() +/datum/category_item/player_setup_item/general/basic/content(datum/preferences/prefs, mob/user, data) . = list() . += "Name: " . += "[pref.real_name]
" @@ -83,44 +89,44 @@ if(href_list["rename"]) var/raw_name = input(user, "Choose your character's name:", "Character Name") as text|null if (!isnull(raw_name) && CanUseTopic(user)) - var/new_name = sanitize_name(raw_name, pref.species, is_FBP()) + var/new_name = sanitize_name(raw_name, pref.real_species_name(), is_FBP()) if(new_name) pref.real_name = new_name - return TOPIC_REFRESH + return PREFERENCES_REFRESH 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 .") - return TOPIC_NOACTION + return PREFERENCES_NOACTION else if(href_list["random_name"]) - pref.real_name = random_name(pref.identifying_gender, pref.species) - return TOPIC_REFRESH + pref.real_name = random_name(pref.identifying_gender, pref.real_species_name()) + return PREFERENCES_REFRESH else if(href_list["always_random_name"]) pref.be_random_name = !pref.be_random_name - return TOPIC_REFRESH + return PREFERENCES_REFRESH else if(href_list["nickname"]) var/raw_nickname = input(user, "Choose your character's nickname:", "Character Nickname") as text|null if (!isnull(raw_nickname) && CanUseTopic(user)) - var/new_nickname = sanitize_name(raw_nickname, pref.species, is_FBP()) + var/new_nickname = sanitize_name(raw_nickname, pref.real_species_name(), is_FBP()) if(new_nickname) pref.nickname = new_nickname - return TOPIC_REFRESH + return PREFERENCES_REFRESH 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 .") - return TOPIC_NOACTION + return PREFERENCES_NOACTION else if(href_list["bio_gender"]) var/new_gender = input(user, "Choose your character's biological sex:", "Character Preference", pref.biological_gender) as null|anything in get_genders() if(new_gender && CanUseTopic(user)) pref.set_biological_gender(new_gender) - return TOPIC_REFRESH_UPDATE_PREVIEW + return PREFERENCES_REFRESH_UPDATE_PREVIEW else if(href_list["id_gender"]) var/new_gender = input(user, "Choose your character's pronouns:", "Character Preference", pref.identifying_gender) as null|anything in all_genders_define_list if(new_gender && CanUseTopic(user)) pref.identifying_gender = new_gender - return TOPIC_REFRESH + return PREFERENCES_REFRESH else if(href_list["age"]) var/min_age = get_min_age() @@ -128,27 +134,27 @@ var/new_age = input(user, "Choose your character's age:\n([min_age]-[max_age])", "Character Preference", pref.age) as num|null if(new_age && CanUseTopic(user)) pref.age = max(min(round(text2num(new_age)), max_age), min_age) - return TOPIC_REFRESH + return PREFERENCES_REFRESH else if(href_list["spawnpoint"]) var/list/spawnkeys = list() for(var/spawntype in spawntypes) spawnkeys += spawntype var/choice = input(user, "Where would you like to spawn when late-joining?") as null|anything in spawnkeys - if(!choice || !spawntypes[choice] || !CanUseTopic(user)) return TOPIC_NOACTION + if(!choice || !spawntypes[choice] || !CanUseTopic(user)) return PREFERENCES_NOACTION pref.spawnpoint = choice - return TOPIC_REFRESH + return PREFERENCES_REFRESH else if(href_list["metadata"]) var/new_metadata = sanitize(input(user, "Enter any information you'd like others to see, such as Roleplay-preferences:", "Game Preference" , html_decode(pref.metadata)) as message, extra = 0) if(new_metadata && CanUseTopic(user)) pref.metadata = new_metadata - return TOPIC_REFRESH + return PREFERENCES_REFRESH return ..() /datum/category_item/player_setup_item/general/basic/proc/get_genders() - var/datum/species/S = pref.character_static_species_meta() + var/datum/species/S = pref.real_species_datum() var/list/possible_genders = S.genders if(!pref.organ_data || pref.organ_data[BP_TORSO] != "cyborg") return possible_genders diff --git a/code/modules/client/preference_setup/general/03_body.dm b/code/modules/preferences/preference_setup/general/03_body.dm similarity index 77% rename from code/modules/client/preference_setup/general/03_body.dm rename to code/modules/preferences/preference_setup/general/03_body.dm index 268fddca8af..df4902e7bda 100644 --- a/code/modules/client/preference_setup/general/03_body.dm +++ b/code/modules/preferences/preference_setup/general/03_body.dm @@ -11,7 +11,6 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O sort_order = 3 /datum/category_item/player_setup_item/general/body/load_character(var/savefile/S) - S["species"] >> pref.species S["hair_red"] >> pref.r_hair S["hair_green"] >> pref.g_hair S["hair_blue"] >> pref.b_hair @@ -49,7 +48,6 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O S["s_base"] >> pref.s_base /datum/category_item/player_setup_item/general/body/save_character(var/savefile/S) - S["species"] << pref.species S["hair_red"] << pref.r_hair S["hair_green"] << pref.g_hair S["hair_blue"] << pref.b_hair @@ -86,8 +84,6 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O S["s_base"] << pref.s_base /datum/category_item/player_setup_item/general/body/sanitize_character(var/savefile/S) - if(!pref.species || !(pref.species in GLOB.playable_species)) - pref.species = SPECIES_HUMAN pref.r_hair = sanitize_integer(pref.r_hair, 0, 255, initial(pref.r_hair)) pref.g_hair = sanitize_integer(pref.g_hair, 0, 255, initial(pref.g_hair)) pref.b_hair = sanitize_integer(pref.b_hair, 0, 255, initial(pref.b_hair)) @@ -108,7 +104,7 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O pref.r_eyes = sanitize_integer(pref.r_eyes, 0, 255, initial(pref.r_eyes)) pref.g_eyes = sanitize_integer(pref.g_eyes, 0, 255, initial(pref.g_eyes)) pref.b_eyes = sanitize_integer(pref.b_eyes, 0, 255, initial(pref.b_eyes)) - pref.b_type = sanitize_text(pref.b_type, initial(pref.b_type)) + pref.b_type = sanitize_istext(pref.b_type, initial(pref.b_type)) if(pref.mirror == null) pref.mirror = TRUE @@ -121,7 +117,11 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O pref.bgstate = "000" // Moved from /datum/preferences/proc/copy_to() -/datum/category_item/player_setup_item/general/body/copy_to_mob(var/mob/living/carbon/human/character) +/datum/category_item/player_setup_item/general/body/copy_to_mob(datum/preferences/prefs, mob/M, data, flags) + // todo: this is just a shim + if(!ishuman(M)) + return TRUE + var/mob/living/carbon/human/character = M // Copy basic values character.r_eyes = pref.r_eyes character.g_eyes = pref.g_eyes @@ -192,21 +192,21 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O continue O.markings.Cut() - for(var/M in pref.body_markings) - var/datum/sprite_accessory/marking/mark_datum = body_marking_styles_list[M] - var/mark_color = "[pref.body_markings[M]]" + for(var/name in pref.body_markings) + var/datum/sprite_accessory/marking/mark_datum = body_marking_styles_list[name] + var/mark_color = "[pref.body_markings[name]]" for(var/BP in mark_datum.body_parts) var/obj/item/organ/external/O = character.organs_by_name[BP] if(O) - O.markings[M] = list("color" = mark_color, "datum" = mark_datum) + O.markings[name] = list("color" = mark_color, "datum" = mark_datum) var/list/last_descriptors = list() if(islist(pref.body_descriptors)) last_descriptors = pref.body_descriptors.Copy() pref.body_descriptors = list() - var/datum/species/mob_species = pref.character_static_species_meta() + var/datum/species/mob_species = pref.real_species_datum() if(LAZYLEN(mob_species.descriptors)) for(var/entry in mob_species.descriptors) var/datum/mob_descriptor/descriptor = mob_species.descriptors[entry] @@ -216,16 +216,16 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O else pref.body_descriptors[entry] = clamp(last_descriptors[entry], 1, LAZYLEN(descriptor.standalone_value_descriptors)) - return + return TRUE -/datum/category_item/player_setup_item/general/body/content(var/mob/user) +/datum/category_item/player_setup_item/general/body/content(datum/preferences/prefs, mob/user, data) . = list() - var/datum/species/mob_species = pref.character_static_species_meta() + var/datum/species/mob_species = pref.real_species_datum() . += "" + +/** + * return null if allowed, otherwise return error to display + */ +/datum/category_item/player_setup_item/occupation/jobs/proc/check_job(datum/preferences/prefs, datum/job/J, current_priority) + var/client/C = pref.client + if(!C) + return null + var/reasons = J.check_client_availability_one(C, TRUE, FALSE) & ~(ROLE_UNAVAILABILITY_EPHEMERAL) + if(reasons) + return J.get_availability_error(C, reasons) + return null + +/datum/category_item/player_setup_item/occupation/jobs/act(datum/preferences/prefs, mob/user, action, list/params) + switch(action) + if("job") + var/job_id = params["job"] + var/level = text2num(params["level"]) + prefs.set_job_priority(job_id, level) + return PREFERENCES_REFRESH_UPDATE_PREVIEW + if("title") + var/datum/job/J = SSjob.job_by_id(params["title"]) + if(!J) + return PREFERENCES_NOACTION + var/title = input(user, "Choose a title for [J.title].", "Choose Title", prefs.get_job_alt_title_name(J)) as null|anything in (J.alt_titles | J.title) + if(!title) + return PREFERENCES_NOACTION + prefs.set_job_title(params["title"], title) + return PREFERENCES_REFRESH_UPDATE_PREVIEW + if("help") + var/datum/job/J = SSjob.job_by_id(params["help"]) + var/list/built = list("
") + built += "

[J.title]

" + built += "Purpose: [J.desc]" + built += "Alternative titles: [english_list(J.alt_titles)]" + if(J.supervisors) + built += "You answer to [J.supervisors], normally." + if(J.departments) + built += "Departments: [english_list(J.departments)]" + if(J.departments_managed) + built += "You manage these departments: [english_list(J.departments_managed)]" + built += "
" + to_chat(user, built.Join("
")) + return PREFERENCES_HANDLED + if("overflow") + var/current = prefs.get_character_data(CHARACTER_DATA_OVERFLOW_MODE) + switch(current) + if(JOB_ALTERNATIVE_BE_ASSISTANT) + prefs.set_character_data(CHARACTER_DATA_OVERFLOW_MODE, JOB_ALTERNATIVE_GET_RANDOM) + if(JOB_ALTERNATIVE_GET_RANDOM) + prefs.set_character_data(CHARACTER_DATA_OVERFLOW_MODE, JOB_ALTERNATIVE_RETURN_LOBBY) + if(JOB_ALTERNATIVE_RETURN_LOBBY) + prefs.set_character_data(CHARACTER_DATA_OVERFLOW_MODE, JOB_ALTERNATIVE_BE_ASSISTANT) + return PREFERENCES_REFRESH + if("reset") + prefs.reset_jobs() + return PREFERENCES_REFRESH_UPDATE_PREVIEW + return ..() + +/datum/category_item/player_setup_item/occupation/jobs/default_value(randomizing) + return list() + +/** + * display is done by jobs; this datum only handles data filtering + * + * save format: list(job id = title NAME) + */ +/datum/category_item/player_setup_item/occupation/alt_titles + name = "(Virtual) Alt Titles" + save_key = CHARACTER_DATA_ALT_TITLES + +/datum/category_item/player_setup_item/occupation/alt_titles/filter_data(datum/preferences/prefs, data, list/errors) + var/list/jobs = sanitize_islist(data) + for(var/id in jobs) + var/datum/job/J = SSjob.job_by_id(id) + if(!J) + jobs -= id + continue + var/title = jobs[id] + if(!J.alt_titles[title]) + jobs -= id + continue + return jobs + +/datum/category_item/player_setup_item/occupation/alt_titles/default_value(randomizing) + return list() + +/** + * display is done by jobs; this datum only handles data filtering + * + * save format: overflow mode as enum define + */ +/datum/category_item/player_setup_item/occupation/overflow_mode + name = "(Virtual) Overflow Mode" + save_key = CHARACTER_DATA_OVERFLOW_MODE + +/datum/category_item/player_setup_item/occupation/overflow_mode/default_value(randomizing) + return JOB_ALTERNATIVE_BE_ASSISTANT + +/datum/category_item/player_setup_item/occupation/overflow_mode/filter_data(datum/preferences/prefs, data, list/errors) + var/static/list/static_list = list( + JOB_ALTERNATIVE_BE_ASSISTANT, + JOB_ALTERNATIVE_GET_RANDOM, + JOB_ALTERNATIVE_RETURN_LOBBY + ) + return sanitize_inlist(data, static_list, JOB_ALTERNATIVE_BE_ASSISTANT) + +/datum/preferences/proc/get_job_priority(datum/job/J) + var/list/jobs = get_character_data(CHARACTER_DATA_JOBS) + return jobs[J.id] + +/datum/preferences/proc/get_job_alt_title_name(datum/job/J) + RETURN_TYPE(/datum/alt_title) + var/list/titles = get_character_data(CHARACTER_DATA_ALT_TITLES) + return titles[J.id] || J.title + +/datum/preferences/proc/preview_job_id() + var/list/jobs = get_character_data(CHARACTER_DATA_JOBS) + if(jobs[JOB_ID_ASSISTANT]) + return JOB_ID_ASSISTANT + for(var/id in jobs) + if(jobs[id] == JOB_PRIORITY_HIGH) + return id + +/datum/preferences/proc/effective_job_priorities() + RETURN_TYPE(/list) + . = list() + var/datum/lore/character_background/faction/F = lore_faction_datum() + var/list/priorities = get_character_data(CHARACTER_DATA_JOBS) + for(var/id in priorities) + if(!F.check_job_id(id)) + continue + .[id] = priorities[id] + +/datum/preferences/proc/effective_job_priority(datum/job/J) + if(!lore_faction_job_check(J)) + return JOB_PRIORITY_NEVER + var/list/jobs = get_character_data(CHARACTER_DATA_JOBS) + return jobs[J.id] + +/** + * gets effective job priority of a job for current slot; used for + * roundstart procs. returns JOB_PRIORITY_NEVER if we can't be said job. + */ +/client/proc/effective_job_priority(datum/job/J) + if(J.check_client_availability_one(src) != ROLE_AVAILABLE) + return JOB_PRIORITY_NEVER + return prefs?.effective_job_priority(J) + +/** + * gets effective job priority of all jobs for current slot; used for + * roundstart procs. if we can't be said job, it isn't included. + * + * @return list of id = priority + */ +/client/proc/effective_job_priorities() + RETURN_TYPE(/list) + . = list() + var/list/priorities = sanitize_islist(prefs.get_character_data(CHARACTER_DATA_JOBS)) + for(var/datum/job/J as anything in SSjob.all_jobs()) + if(J.check_client_availability_one(src) != ROLE_AVAILABLE) + continue + var/id = J.id + if(!priorities[id]) + continue + .[J.id] = priorities[id] + +/** + * resets job prefs + */ +/datum/preferences/proc/reset_jobs() + set_character_data(CHARACTER_DATA_JOBS, list()) + set_character_data(CHARACTER_DATA_ALT_TITLES, list()) + set_character_data(CHARACTER_DATA_OVERFLOW_MODE, JOB_ALTERNATIVE_BE_ASSISTANT) + +/** + * resets any jobs set to high to medium + */ +/datum/preferences/proc/demote_high_priority_jobs() + var/list/jobs = get_character_data(CHARACTER_DATA_JOBS) + for(var/id in jobs) + if(jobs[id] == JOB_PRIORITY_HIGH) + jobs[id] = JOB_PRIORITY_MEDIUM + set_character_data(CHARACTER_DATA_JOBS, jobs) + +/datum/preferences/proc/get_job_alternative() + return get_character_data(CHARACTER_DATA_OVERFLOW_MODE) + +/datum/preferences/proc/set_job_priority(id, priority) + var/datum/job/J = SSjob.job_by_id(id) + if(!J) + return + if(priority < JOB_PRIORITY_NEVER || priority > JOB_PRIORITY_HIGH) + return + var/list/current = get_character_data(CHARACTER_DATA_JOBS) + if(priority == JOB_PRIORITY_NEVER) + current -= id // just nuke it + else + current[id] = priority + set_character_data(CHARACTER_DATA_JOBS, current) + +/datum/preferences/proc/set_job_title(id, title) + var/datum/job/J = SSjob.job_by_id(id) + if(!J) + return + var/list/current = get_character_data(CHARACTER_DATA_ALT_TITLES) + if(J.title == title) + // reset + current -= id + else + if(!J.alt_titles[title]) + return + current[id] = title + set_character_data(CHARACTER_DATA_ALT_TITLES, current) diff --git a/code/modules/preferences/preference_setup/preference_category_new.dm b/code/modules/preferences/preference_setup/preference_category_new.dm new file mode 100644 index 00000000000..2015a233a3f --- /dev/null +++ b/code/modules/preferences/preference_setup/preference_category_new.dm @@ -0,0 +1,9 @@ +/datum/category_group/player_setup_category + +/datum/category_group/player_setup_category/proc/spawn_checks(datum/preferences/prefs, flags, list/errors) + . = TRUE + for(var/datum/category_item/player_setup_item/preference in items) + if(!preference.spawn_checks(prefs, prefs.get_character_data(preference.save_key), flags, errors)) + . = FALSE + +// todo: multi stage random character generation diff --git a/code/modules/preferences/preference_setup/preference_item_new.dm b/code/modules/preferences/preference_setup/preference_item_new.dm new file mode 100644 index 00000000000..f2797adc9dc --- /dev/null +++ b/code/modules/preferences/preference_setup/preference_item_new.dm @@ -0,0 +1,164 @@ +//! right now these are just called via snowflake +//! please use these for new datums; in the future we'll standardize to this and decide +//! how to handle UI. +//! in the future, these are going to be singletons. +//? furthermore, in each item, "helper" functions for getting/setting related data from external +//? should be in the file too; this makes it easier to update/harder to forget about during +//? refactors. +/datum/category_item/player_setup_item + /// primary data key + // todo: unit test for this to exist + var/save_key // genuinely you have zero reason to change this at runtime + /// globally saved, or character-slot saved? + var/is_global // genuinely you have zero reason to change this at runtime + /// load order; sanitization + deserialization goes from lowest to highest + var/load_order = PREFERENCE_LOAD_ORDER_DEFAULT + +/** + * called to apply to mob + * + * @params + * - prefs - the preferences datum. This is OPTIONAL, as we can use prefs items in admin rejuv!! + * - M - the mob in question + * - data - our save data + * - flags - PREF_COPY_TO_FOR_ flags + */ +/datum/category_item/player_setup_item/proc/copy_to_mob(datum/preferences/prefs, mob/M, data, flags) + return TRUE + +// todo: apply to global/client +// todo: update to global/client + +/** + * called to check for errors; if non null, players get showed this while spawning and the + * spawn is blocked. + * + * put reasons into errors + */ +/datum/category_item/player_setup_item/proc/spawn_checks(datum/preferences/prefs, data, flags, list/errors) + return TRUE + +/** + * called to sanitize our value. + * + * called after deserialization. + * + * put errors into errors for user feedback + */ +/datum/category_item/player_setup_item/proc/filter_data(datum/preferences/prefs, data, list/errors) + return data + +/** + * called to sanitize our value on a preferences datum + * + * put errors into errors for user feedback + */ +/datum/category_item/player_setup_item/proc/sanitize_data(datum/preferences/prefs, list/errors) + write(prefs, read(prefs), errors) + +/** + * called to serialize our value for saving + * + * @return raw data to save + */ +/datum/category_item/player_setup_item/proc/serialize_data(datum/preferences/prefs, data, list/errors) + return data + +/** + * called to deserialize our value during loading + * + * migrations are obviously allowed + * + * @return deserialized data to set on preferences data lists + */ +/datum/category_item/player_setup_item/proc/deserialize_data(datum/preferences/prefs, raw, list/errors) + return raw + +/** + * write data, sanitizing in the process + */ +/datum/category_item/player_setup_item/proc/write(datum/preferences/prefs, data, list/errors) + if(is_global) + prefs.set_global_data(save_key, filter_data(prefs, data, errors)) + else + prefs.set_character_data(save_key, filter_data(prefs, data, errors)) + +/** + * read data; does not auto-sanitize + */ +/datum/category_item/player_setup_item/proc/read(datum/preferences/prefs) + if(is_global) + return prefs.get_global_data(save_key) + else + return prefs.get_character_data(save_key) + +/** + * get default value + * + * todo: randomizing is awful, we need multi stage randomizing + templates for this + */ +/datum/category_item/player_setup_item/proc/default_value(randomizing) + return null + +/** + * get default value assuming pref + * + * todo: randomizing is awful, we need multi stage randomizing + templates for this + */ +/datum/category_item/player_setup_item/proc/informed_default_value(datum/preferences/prefs, randomizing) + return default_value(randomizing) + +/** + * called to render the text the user sees + * + * @params + * - prefs - host preferences datum + * - user - viewer + * - data - our save data + */ +/datum/category_item/player_setup_item/proc/content(datum/preferences/prefs, mob/user, data) + RETURN_TYPE(/list) + return list() + +/** + * called when something acts on a href + * returns PREFERENCES_X bitfields for what to do + * + * @params + * - prefs - prefs we're acting on + * - user - person acting on us + * - action - the action + * - params - additional parameters + */ +/datum/category_item/player_setup_item/proc/act(datum/preferences/prefs, mob/user, action, list/params) + return PREFERENCES_NOACTION + +/** + * encodes href + */ +/datum/category_item/player_setup_item/proc/href(datum/preferences/prefs, action, innerhtml, list/params) + if(length(params)) + return "[innerhtml]" + return "[innerhtml]" + +/** + * encodes href + * + * act() will be called with action and the action associated to the option in params. + */ +/datum/category_item/player_setup_item/proc/href_simple(datum/preferences/prefs, action, innerhtml, option) + if(option) + return "[innerhtml]" + return "[innerhtml]" + +//! warning not all content() procs return a list properly for now + +// todo: multi stage random character generation + +/datum/category_item/player_setup_item/vv_edit_var(var_name, var_value, raw_edit) + switch(var_name) + if(NAMEOF(src, is_global)) + return FALSE // let's not! + if(NAMEOF(src, save_key)) + return FALSE // let's not! + return ..() diff --git a/code/modules/client/preference_setup/preference_setup.dm b/code/modules/preferences/preference_setup/preference_setup.dm similarity index 83% rename from code/modules/client/preference_setup/preference_setup.dm rename to code/modules/preferences/preference_setup/preference_setup.dm index 3b8fffc2dc9..4850c6c63c7 100644 --- a/code/modules/client/preference_setup/preference_setup.dm +++ b/code/modules/preferences/preference_setup/preference_setup.dm @@ -34,6 +34,7 @@ src.preferences = preferences ..() selected_category = categories[1] + tim_sort(preferences.preference_by_key, /proc/cmp_preference_load_order, TRUE) /datum/category_collection/player_setup_collection/Destroy() preferences = null @@ -60,10 +61,6 @@ for(var/datum/category_group/player_setup_category/PS in categories) PS.save_preferences(S) -/datum/category_collection/player_setup_collection/proc/copy_to_mob(var/mob/living/carbon/human/C) - for(var/datum/category_group/player_setup_category/PS in categories) - PS.copy_to_mob(C) - /datum/category_collection/player_setup_collection/proc/header() var/dat = "" for(var/datum/category_group/player_setup_category/PS in categories) @@ -97,7 +94,17 @@ * Category Category Setup * **************************/ /datum/category_group/player_setup_category + var/datum/preferences/prefs var/sort_order = 0 + /// automatically split into 2 horizontally + var/auto_split = TRUE + /// automatic
+ var/auto_rule = FALSE + +/datum/category_group/player_setup_category/New() + . = ..() + var/datum/category_collection/player_setup_collection/C = collection + prefs = C.preferences /datum/category_group/player_setup_category/compare_to(datum/D) if(istype(D, /datum/category_group/player_setup_category)) @@ -134,20 +141,38 @@ for(var/datum/category_item/player_setup_item/PI in items) PI.save_preferences(S) -/datum/category_group/player_setup_category/proc/copy_to_mob(var/mob/living/carbon/human/C) - for(var/datum/category_item/player_setup_item/PI in items) - PI.copy_to_mob(C) - /datum/category_group/player_setup_category/proc/content(var/mob/user) . = "
Body " . += "(®)" . += "
" - . += "Species: [pref.species]
" + . += "Species: [mob_species.name]
" . += "Blood Type: [pref.b_type]
" if(has_flag(mob_species, HAS_SKIN_TONE)) . += "Skin Tone: [-pref.s_tone + 35]/220
" @@ -390,11 +390,11 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O return mob_species && (mob_species.species_appearance_flags & flag) /datum/category_item/player_setup_item/general/body/OnTopic(var/href,var/list/href_list, var/mob/user) - var/datum/species/mob_species = pref.character_static_species_meta() + var/datum/species/mob_species = pref.real_species_datum() if(href_list["random"]) pref.randomize_appearance_and_body_for() - return TOPIC_REFRESH_UPDATE_PREVIEW + return PREFERENCES_REFRESH_UPDATE_PREVIEW else if(href_list["change_descriptor"]) if(mob_species.descriptors) @@ -404,97 +404,37 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O var/choice = input("Please select a descriptor.", "Descriptor") as null|anything in descriptor.chargen_value_descriptors if(choice && mob_species.descriptors[desc_id]) // Check in case they sneakily changed species. pref.body_descriptors[desc_id] = descriptor.chargen_value_descriptors[choice] - return TOPIC_REFRESH + return PREFERENCES_REFRESH else if(href_list["blood_type"]) var/new_b_type = input(user, "Choose your character's blood-type:", "Character Preference") as null|anything in valid_bloodtypes if(new_b_type && CanUseTopic(user)) pref.b_type = new_b_type - return TOPIC_REFRESH + return PREFERENCES_REFRESH else if(href_list["show_species"]) - // Actual whitelist checks are handled elsewhere, this is just for accessing the preview window. - var/choice = input("Which species would you like to look at?") as null|anything in GLOB.playable_species - if(!choice) return - pref.species_preview = choice - SetSpecies(preference_mob()) - pref.alternate_languages.Cut() // Reset their alternate languages. Todo: attempt to just fix it instead? - return TOPIC_HANDLED - - else if(href_list["set_species"]) - user << browse(null, "window=species") - if(!pref.species_preview || !(pref.species_preview in all_species_names())) - return TOPIC_NOACTION - - var/datum/species/setting_species - - if(name_static_species_meta(href_list["set_species"])) - setting_species = name_static_species_meta(href_list["set_species"]) - else - return TOPIC_NOACTION - - if(((!(setting_species.spawn_flags & SPECIES_CAN_JOIN)) || (!is_alien_whitelisted(preference_mob(),setting_species))) && !check_rights(R_ADMIN, 0) && !(setting_species.spawn_flags & SPECIES_WHITELIST_SELECTABLE)) - return TOPIC_NOACTION - - var/prev_species = pref.species - pref.species = href_list["set_species"] - if(prev_species != pref.species) - if(!(pref.biological_gender in mob_species.genders)) - pref.set_biological_gender(mob_species.genders[1]) - pref.custom_species = null // This is cleared on species changes - - //grab one of the valid hair styles for the newly chosen species - var/list/valid_hairstyles = pref.get_valid_hairstyles() - - if(valid_hairstyles.len) - pref.h_style = pick(valid_hairstyles) - else - //this shouldn't happen - pref.h_style = hair_styles_list["Bald"] - - //grab one of the valid facial hair styles for the newly chosen species - var/list/valid_facialhairstyles = pref.get_valid_facialhairstyles() - - if(valid_facialhairstyles.len) - pref.f_style = pick(valid_facialhairstyles) - else - //this shouldn't happen - pref.f_style = facial_hair_styles_list["Shaved"] - - //reset hair colour and skin colour - pref.r_hair = 0//hex2num(copytext(new_hair, 2, 4)) - pref.g_hair = 0//hex2num(copytext(new_hair, 4, 6)) - pref.b_hair = 0//hex2num(copytext(new_hair, 6, 8)) - pref.s_tone = 0 - - reset_limbs() // Safety for species with incompatible manufacturers; easier than trying to do it case by case. - pref.body_markings.Cut() // Basically same as above. - - var/min_age = get_min_age() - var/max_age = get_max_age() - pref.age = max(min(pref.age, max_age), min_age) - - return TOPIC_REFRESH_UPDATE_PREVIEW + pref.species_pick(usr) + return PREFERENCES_HANDLED else if(href_list["hair_color"]) if(!has_flag(mob_species, HAS_HAIR_COLOR)) - return TOPIC_NOACTION + return PREFERENCES_NOACTION var/new_hair = input(user, "Choose your character's hair colour:", "Character Preference", rgb(pref.r_hair, pref.g_hair, pref.b_hair)) as color|null if(new_hair && has_flag(mob_species, HAS_HAIR_COLOR) && CanUseTopic(user)) pref.r_hair = hex2num(copytext(new_hair, 2, 4)) pref.g_hair = hex2num(copytext(new_hair, 4, 6)) pref.b_hair = hex2num(copytext(new_hair, 6, 8)) - return TOPIC_REFRESH_UPDATE_PREVIEW + return PREFERENCES_REFRESH_UPDATE_PREVIEW else if(href_list["grad_color"]) if(!has_flag(mob_species, HAS_HAIR_COLOR)) - return TOPIC_NOACTION + return PREFERENCES_NOACTION var/new_grad = input(user, "Choose your character's secondary hair color:", "Character Preference", rgb(pref.r_grad, pref.g_grad, pref.b_grad)) as color|null if(new_grad && has_flag(mob_species, HAS_HAIR_COLOR) && CanUseTopic(user)) pref.r_grad = hex2num(copytext(new_grad, 2, 4)) pref.g_grad = hex2num(copytext(new_grad, 4, 6)) pref.b_grad = hex2num(copytext(new_grad, 6, 8)) - return TOPIC_REFRESH_UPDATE_PREVIEW + return PREFERENCES_REFRESH_UPDATE_PREVIEW else if(href_list["hair_style"]) var/list/valid_hairstyles = pref.get_valid_hairstyles() @@ -502,7 +442,7 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O var/new_h_style = input(user, "Choose your character's hair style:", "Character Preference", pref.h_style) as null|anything in valid_hairstyles if(new_h_style && CanUseTopic(user)) pref.h_style = new_h_style - return TOPIC_REFRESH_UPDATE_PREVIEW + return PREFERENCES_REFRESH_UPDATE_PREVIEW else if(href_list["hair_style_left"]) var/H = href_list["hair_style_left"] @@ -513,7 +453,7 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O pref.h_style = valid_hairstyles[start-1] else //But if we ARE, become the final element. pref.h_style = valid_hairstyles[valid_hairstyles.len] - return TOPIC_REFRESH_UPDATE_PREVIEW + return PREFERENCES_REFRESH_UPDATE_PREVIEW else if(href_list["hair_style_right"]) var/H = href_list["hair_style_right"] @@ -524,7 +464,7 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O pref.h_style = valid_hairstyles[start+1] else //But if we ARE, become the first element. pref.h_style = valid_hairstyles[1] - return TOPIC_REFRESH_UPDATE_PREVIEW + return PREFERENCES_REFRESH_UPDATE_PREVIEW else if(href_list["grad_style"]) var/list/valid_gradients = GLOB.hair_gradients @@ -532,7 +472,7 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O var/new_grad_style = input(user, "Choose a color pattern for your hair:", "Character Preference", pref.grad_style) as null|anything in valid_gradients if(new_grad_style && CanUseTopic(user)) pref.grad_style = new_grad_style - return TOPIC_REFRESH_UPDATE_PREVIEW + return PREFERENCES_REFRESH_UPDATE_PREVIEW else if(href_list["grad_style_left"]) var/G = href_list["grad_style_left"] @@ -543,7 +483,7 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O pref.grad_style = valid_gradients[start-1] else //But if we ARE, become the final element. pref.grad_style = valid_gradients[valid_gradients.len] - return TOPIC_REFRESH_UPDATE_PREVIEW + return PREFERENCES_REFRESH_UPDATE_PREVIEW else if(href_list["grad_style_right"]) var/G = href_list["grad_style_right"] @@ -554,53 +494,53 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O pref.grad_style = valid_gradients[start+1] else //But if we ARE, become the first element. pref.grad_style = valid_gradients[1] - return TOPIC_REFRESH_UPDATE_PREVIEW + return PREFERENCES_REFRESH_UPDATE_PREVIEW else if(href_list["eye_color"]) if(!has_flag(mob_species, HAS_EYE_COLOR)) - return TOPIC_NOACTION + return PREFERENCES_NOACTION var/new_eyes = input(user, "Choose your character's eye colour:", "Character Preference", rgb(pref.r_eyes, pref.g_eyes, pref.b_eyes)) as color|null if(new_eyes && has_flag(mob_species, HAS_EYE_COLOR) && CanUseTopic(user)) pref.r_eyes = hex2num(copytext(new_eyes, 2, 4)) pref.g_eyes = hex2num(copytext(new_eyes, 4, 6)) pref.b_eyes = hex2num(copytext(new_eyes, 6, 8)) - return TOPIC_REFRESH_UPDATE_PREVIEW + return PREFERENCES_REFRESH_UPDATE_PREVIEW else if(href_list["skin_tone"]) if(!has_flag(mob_species, HAS_SKIN_TONE)) - return TOPIC_NOACTION + return PREFERENCES_NOACTION var/new_s_tone = input(user, "Choose your character's skin-tone:\n(Light 1 - 220 Dark)", "Character Preference", (-pref.s_tone) + 35) as num|null if(new_s_tone && has_flag(mob_species, HAS_SKIN_TONE) && CanUseTopic(user)) pref.s_tone = 35 - max(min( round(new_s_tone), 220),1) - return TOPIC_REFRESH_UPDATE_PREVIEW + return PREFERENCES_REFRESH_UPDATE_PREVIEW else if(href_list["skin_color"]) if(!has_flag(mob_species, HAS_SKIN_COLOR)) - return TOPIC_NOACTION + return PREFERENCES_NOACTION var/new_skin = input(user, "Choose your character's skin colour: ", "Character Preference", rgb(pref.r_skin, pref.g_skin, pref.b_skin)) as color|null if(new_skin && has_flag(mob_species, HAS_SKIN_COLOR) && CanUseTopic(user)) pref.r_skin = hex2num(copytext(new_skin, 2, 4)) pref.g_skin = hex2num(copytext(new_skin, 4, 6)) pref.b_skin = hex2num(copytext(new_skin, 6, 8)) - return TOPIC_REFRESH_UPDATE_PREVIEW + return PREFERENCES_REFRESH_UPDATE_PREVIEW else if(href_list["base_skin"]) if(!has_flag(mob_species, HAS_BASE_SKIN_COLOR)) - return TOPIC_NOACTION + return PREFERENCES_NOACTION var/new_s_base = input(user, "Choose your character's base colour:", "Character preference") as null|anything in mob_species.base_skin_colours if(new_s_base && CanUseTopic(user)) pref.s_base = new_s_base - return TOPIC_REFRESH_UPDATE_PREVIEW + return PREFERENCES_REFRESH_UPDATE_PREVIEW else if(href_list["facial_color"]) if(!has_flag(mob_species, HAS_HAIR_COLOR)) - return TOPIC_NOACTION + return PREFERENCES_NOACTION var/new_facial = input(user, "Choose your character's facial-hair colour:", "Character Preference", rgb(pref.r_facial, pref.g_facial, pref.b_facial)) as color|null if(new_facial && has_flag(mob_species, HAS_HAIR_COLOR) && CanUseTopic(user)) pref.r_facial = hex2num(copytext(new_facial, 2, 4)) pref.g_facial = hex2num(copytext(new_facial, 4, 6)) pref.b_facial = hex2num(copytext(new_facial, 6, 8)) - return TOPIC_REFRESH_UPDATE_PREVIEW + return PREFERENCES_REFRESH_UPDATE_PREVIEW else if(href_list["facial_style"]) var/list/valid_facialhairstyles = pref.get_valid_facialhairstyles() @@ -608,7 +548,7 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O var/new_f_style = input(user, "Choose your character's facial-hair style:", "Character Preference", pref.f_style) as null|anything in valid_facialhairstyles if(new_f_style && CanUseTopic(user)) pref.f_style = new_f_style - return TOPIC_REFRESH_UPDATE_PREVIEW + return PREFERENCES_REFRESH_UPDATE_PREVIEW else if(href_list["facial_style_left"]) var/F = href_list["facial_style_left"] @@ -619,7 +559,7 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O pref.f_style = valid_facialhairstyles[start-1] else //But if we ARE, become the final element. pref.f_style = valid_facialhairstyles[valid_facialhairstyles.len] - return TOPIC_REFRESH_UPDATE_PREVIEW + return PREFERENCES_REFRESH_UPDATE_PREVIEW else if(href_list["facial_style_right"]) var/F = href_list["facial_style_right"] @@ -630,14 +570,14 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O pref.f_style = valid_facialhairstyles[start+1] else //But if we ARE, become the first element. pref.f_style = valid_facialhairstyles[1] - return TOPIC_REFRESH_UPDATE_PREVIEW + return PREFERENCES_REFRESH_UPDATE_PREVIEW else if(href_list["marking_style"]) var/list/usable_markings = pref.body_markings.Copy() ^ body_marking_styles_list.Copy() var/new_marking = input(user, "Choose a body marking:", "Character Preference") as null|anything in usable_markings if(new_marking && CanUseTopic(user)) pref.body_markings[new_marking] = "#000000" //New markings start black - return TOPIC_REFRESH_UPDATE_PREVIEW + return PREFERENCES_REFRESH_UPDATE_PREVIEW else if(href_list["marking_up"]) var/M = href_list["marking_up"] @@ -646,7 +586,7 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O move_element(pref.body_markings, start, start-1) else //But if we ARE, become the final element -ahead- of everything else. move_element(pref.body_markings, start, pref.body_markings.len+1) - return TOPIC_REFRESH_UPDATE_PREVIEW + return PREFERENCES_REFRESH_UPDATE_PREVIEW else if(href_list["marking_down"]) var/M = href_list["marking_down"] @@ -655,7 +595,7 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O move_element(pref.body_markings, start, start+2) else //But if we ARE, become the first element -behind- everything else. move_element(pref.body_markings, start, 1) - return TOPIC_REFRESH_UPDATE_PREVIEW + return PREFERENCES_REFRESH_UPDATE_PREVIEW else if(href_list["marking_move"]) var/M = href_list["marking_move"] @@ -668,30 +608,30 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O var/newpos = pref.body_markings.Find(inject_after) if(newpos) move_element(pref.body_markings, start, newpos+1) - return TOPIC_REFRESH_UPDATE_PREVIEW + return PREFERENCES_REFRESH_UPDATE_PREVIEW else if(href_list["marking_remove"]) var/M = href_list["marking_remove"] pref.body_markings -= M - return TOPIC_REFRESH_UPDATE_PREVIEW + return PREFERENCES_REFRESH_UPDATE_PREVIEW else if(href_list["marking_color"]) var/M = href_list["marking_color"] var/mark_color = input(user, "Choose the [M] color: ", "Character Preference", pref.body_markings[M]) as color|null if(mark_color && CanUseTopic(user)) pref.body_markings[M] = "[mark_color]" - return TOPIC_REFRESH_UPDATE_PREVIEW + return PREFERENCES_REFRESH_UPDATE_PREVIEW else if(href_list["reset_limbs"]) - reset_limbs() - return TOPIC_REFRESH_UPDATE_PREVIEW + pref.reset_limbs() + return PREFERENCES_REFRESH_UPDATE_PREVIEW else if(href_list["limbs"]) var/list/limb_selection_list = list("Left Leg","Right Leg","Left Arm","Right Arm","Left Foot","Right Foot","Left Hand","Right Hand","Full Body") // Full prosthetic bodies without a brain are borderline unkillable so make sure they have a brain to remove/destroy. - var/datum/species/current_species = pref.character_static_species_meta() + var/datum/species/current_species = pref.real_species_datum() if(!current_species.has_organ["brain"]) limb_selection_list -= "Full Body" else if(pref.organ_data[BP_TORSO] == "cyborg") @@ -699,7 +639,7 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O var/organ_tag = input(user, "Which limb do you want to change?") as null|anything in limb_selection_list - if(!organ_tag || !CanUseTopic(user)) return TOPIC_NOACTION + if(!organ_tag || !CanUseTopic(user)) return PREFERENCES_NOACTION var/limb = null var/second_limb = null // if you try to change the arm, the hand should also change @@ -742,7 +682,7 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O choice_options = list("Normal","Prosthesis") var/new_state = input(user, "What state do you wish the limb to be in?") as null|anything in choice_options - if(!new_state || !CanUseTopic(user)) return TOPIC_NOACTION + if(!new_state || !CanUseTopic(user)) return PREFERENCES_NOACTION pref.regen_limbs = 1 @@ -771,7 +711,7 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O pref.rlimb_data[second_limb] = null if("Prosthesis") - var/tmp_species = pref.species ? pref.species : SPECIES_HUMAN + var/tmp_species = pref.real_species_name() var/list/usable_manufacturers = list() for(var/company in GLOB.chargen_robolimbs) var/datum/robolimb/M = GLOB.chargen_robolimbs[company] @@ -809,7 +749,7 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O for(var/internal_organ in list(O_HEART,O_EYES)) pref.organ_data[internal_organ] = "mechanical" - return TOPIC_REFRESH_UPDATE_PREVIEW + return PREFERENCES_REFRESH_UPDATE_PREVIEW else if(href_list["organs"]) @@ -875,12 +815,12 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O if("Positronic") pref.organ_data[organ] = "mechanical" - return TOPIC_REFRESH + return PREFERENCES_REFRESH else if(href_list["disabilities"]) var/disability_flag = text2num(href_list["disabilities"]) pref.disabilities ^= disability_flag - return TOPIC_REFRESH_UPDATE_PREVIEW + return PREFERENCES_REFRESH_UPDATE_PREVIEW else if(href_list["mirror"]) if(pref.mirror) @@ -889,15 +829,15 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O else pref.mirror = TRUE to_chat(usr, "A mirror is an implant that, if recovered, will allow you to be resleeved.") - return TOPIC_REFRESH_UPDATE_PREVIEW + return PREFERENCES_REFRESH_UPDATE_PREVIEW else if(href_list["toggle_preview_value"]) pref.equip_preview_mob ^= text2num(href_list["toggle_preview_value"]) - return TOPIC_REFRESH_UPDATE_PREVIEW + return PREFERENCES_REFRESH_UPDATE_PREVIEW else if(href_list["synth_color"]) pref.synth_color = !pref.synth_color - return TOPIC_REFRESH_UPDATE_PREVIEW + return PREFERENCES_REFRESH_UPDATE_PREVIEW else if(href_list["synth2_color"]) var/new_color = input(user, "Choose your character's synth colour: ", "Character Preference", rgb(pref.r_synth, pref.g_synth, pref.b_synth)) as color|null @@ -905,107 +845,33 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O pref.r_synth = hex2num(copytext(new_color, 2, 4)) pref.g_synth = hex2num(copytext(new_color, 4, 6)) pref.b_synth = hex2num(copytext(new_color, 6, 8)) - return TOPIC_REFRESH_UPDATE_PREVIEW + return PREFERENCES_REFRESH_UPDATE_PREVIEW else if(href_list["synth_markings"]) pref.synth_markings = !pref.synth_markings - return TOPIC_REFRESH_UPDATE_PREVIEW + return PREFERENCES_REFRESH_UPDATE_PREVIEW else if(href_list["cycle_bg"]) pref.bgstate = next_list_item(pref.bgstate, pref.bgstate_options) - return TOPIC_REFRESH_UPDATE_PREVIEW + return PREFERENCES_REFRESH_UPDATE_PREVIEW return ..() -/datum/category_item/player_setup_item/general/body/proc/reset_limbs() +/datum/preferences/proc/reset_limbs() + for(var/organ in organ_data) + organ_data[organ] = null + while(null in organ_data) + organ_data -= null - for(var/organ in pref.organ_data) - pref.organ_data[organ] = null - while(null in pref.organ_data) - pref.organ_data -= null + for(var/organ in rlimb_data) + rlimb_data[organ] = null + while(null in rlimb_data) + rlimb_data -= null - for(var/organ in pref.rlimb_data) - pref.rlimb_data[organ] = null - while(null in pref.rlimb_data) - pref.rlimb_data -= null - - pref.regen_limbs = 1 + regen_limbs = 1 // Sanitize the name so that there aren't any numbers sticking around. - pref.real_name = sanitize_name(pref.real_name, pref.species) - if(!pref.real_name) - pref.real_name = random_name(pref.identifying_gender, pref.species) - -/datum/category_item/player_setup_item/general/body/proc/SetSpecies(mob/user) - if(!pref.species_preview || !(pref.species_preview in all_species_names())) - pref.species_preview = SPECIES_HUMAN - var/datum/species/current_species = name_static_species_meta(pref.species_preview) - var/dat = "" - dat += "

[current_species.name] \[change\]


" - dat += "" - dat += "" - if(current_species.wikilink) - dat += "" - else - dat += "" - dat += "" - dat += "" - dat += "
[current_species.blurb]

See the wiki for more details.
[current_species.blurb]" - if(current_species.preview_icon) - usr << browse_rsc(icon(icon = current_species.preview_icon, icon_state = ""), "species_preview_[current_species.name].png") - dat += "

" - dat += "Language: [current_species.species_language]
" - dat += "" - if(current_species.spawn_flags & SPECIES_CAN_JOIN) - switch(current_species.rarity_value) - if(1 to 2) - dat += "
Often present on human stations." - if(3 to 4) - dat += "
Rarely present on human stations." - if(5) - dat += "
Unheard of on human stations." - else - dat += "
May be present on human stations." - if(current_species.spawn_flags & SPECIES_IS_WHITELISTED) - dat += "
Whitelist restricted." - if(!current_species.has_organ[O_HEART]) - dat += "
Does not have a circulatory system." - if(!current_species.has_organ[O_LUNGS]) - dat += "
Does not have a respiratory system." - if(current_species.flags & NO_SCAN) - dat += "
Does not have DNA." - if(current_species.flags & NO_PAIN) - dat += "
Does not feel pain." - if(current_species.flags & NO_SLIP) - dat += "
Has excellent traction." - if(current_species.flags & NO_POISON) - dat += "
Immune to most poisons." - if(current_species.species_appearance_flags & HAS_SKIN_TONE) - dat += "
Has a variety of skin tones." - if(current_species.species_appearance_flags & HAS_BASE_SKIN_COLOR) - dat += "
Has a small number of base skin colors." - if(current_species.species_appearance_flags & HAS_SKIN_COLOR) - dat += "
Has a variety of skin colours." - if(current_species.species_appearance_flags & HAS_EYE_COLOR) - dat += "
Has a variety of eye colours." - if(current_species.flags & IS_PLANT) - dat += "
Has a plantlike physiology." - dat += "

" - - var/restricted = 0 - - if(!(current_species.spawn_flags & SPECIES_CAN_JOIN)) - restricted = 2 - else if(!is_alien_whitelisted(preference_mob(),current_species)) - restricted = 1 - - if(restricted) - if(restricted == 1) - dat += "You cannot play as this species.
If you wish to be whitelisted, you can make an application post on the forums.

" - else if(restricted == 2) - dat += "You cannot play as this species.
This species is not available for play as a station race..

" - if(!restricted || check_rights(R_ADMIN, 0) || current_species.spawn_flags & SPECIES_WHITELIST_SELECTABLE) //selectability - dat += "\[select\]" - dat += "
" - - user << browse(dat, "window=species;size=700x400") + var/species_name = real_species_name() + real_name = sanitize_name(real_name, species_name) + if(!real_name) + real_name = random_name(identifying_gender, species_name) diff --git a/code/modules/client/preference_setup/general/04_equipment.dm b/code/modules/preferences/preference_setup/general/04_equipment.dm similarity index 93% rename from code/modules/client/preference_setup/general/04_equipment.dm rename to code/modules/preferences/preference_setup/general/04_equipment.dm index 1e310deab5f..f4a27044f91 100644 --- a/code/modules/client/preference_setup/general/04_equipment.dm +++ b/code/modules/preferences/preference_setup/general/04_equipment.dm @@ -23,7 +23,11 @@ S["ringtone"] << pref.ringtone // Moved from /datum/preferences/proc/copy_to() -/datum/category_item/player_setup_item/general/equipment/copy_to_mob(var/mob/living/carbon/human/character) +/datum/category_item/player_setup_item/general/equipment/copy_to_mob(datum/preferences/prefs, mob/M, data, flags) + // todo: this is just a shim + if(!ishuman(M)) + return TRUE + var/mob/living/carbon/human/character = M character.all_underwear.Cut() character.all_underwear_metadata.Cut() @@ -45,6 +49,7 @@ if(pref.pdachoice > 7 || pref.pdachoice < 1) pref.pdachoice = 1 character.pdachoice = pref.pdachoice + return TRUE /datum/category_item/player_setup_item/general/equipment/sanitize_character() if(!islist(pref.gear)) pref.gear = list() @@ -77,7 +82,7 @@ pref.pdachoice = sanitize_integer(pref.pdachoice, 1, pdachoicelist.len, initial(pref.pdachoice)) pref.ringtone = sanitize(pref.ringtone, 20) -/datum/category_item/player_setup_item/general/equipment/content() +/datum/category_item/player_setup_item/general/equipment/content(datum/preferences/prefs, mob/user, data) . = list() . += "Equipment:
" for(var/datum/category_group/underwear/UWC in GLOB.global_underwear.categories) @@ -118,13 +123,13 @@ var/new_backbag = input(user, "Choose your character's style of bag:", "Character Preference", backbaglist[pref.backbag]) as null|anything in backbaglist if(!isnull(new_backbag) && CanUseTopic(user)) pref.backbag = backbaglist.Find(new_backbag) - return TOPIC_REFRESH_UPDATE_PREVIEW + return PREFERENCES_REFRESH_UPDATE_PREVIEW else if(href_list["change_pda"]) var/new_pdachoice = input(user, "Choose your character's style of PDA:", "Character Preference", pdachoicelist[pref.pdachoice]) as null|anything in pdachoicelist if(!isnull(new_pdachoice) && CanUseTopic(user)) pref.pdachoice = pdachoicelist.Find(new_pdachoice) - return TOPIC_REFRESH + return PREFERENCES_REFRESH else if(href_list["change_underwear"]) var/datum/category_group/underwear/UWC = GLOB.global_underwear.categories_by_name[href_list["change_underwear"]] @@ -133,26 +138,26 @@ var/datum/category_item/underwear/selected_underwear = input(user, "Choose underwear:", "Character Preference", pref.all_underwear[UWC.name]) as null|anything in UWC.items if(selected_underwear && CanUseTopic(user)) pref.all_underwear[UWC.name] = selected_underwear.name - return TOPIC_REFRESH_UPDATE_PREVIEW + return PREFERENCES_REFRESH_UPDATE_PREVIEW else if(href_list["underwear"] && href_list["tweak"]) var/underwear = href_list["underwear"] if(!(underwear in pref.all_underwear)) - return TOPIC_NOACTION + return PREFERENCES_NOACTION var/datum/gear_tweak/gt = locate(href_list["tweak"]) if(!gt) - return TOPIC_NOACTION + return PREFERENCES_NOACTION var/new_metadata = gt.get_metadata(usr, get_metadata(underwear, gt)) if(new_metadata) set_metadata(underwear, gt, new_metadata) - return TOPIC_REFRESH_UPDATE_PREVIEW + return PREFERENCES_REFRESH_UPDATE_PREVIEW else if(href_list["toggle_comm_visibility"]) if(CanUseTopic(user)) pref.communicator_visibility = !pref.communicator_visibility - return TOPIC_REFRESH + return PREFERENCES_REFRESH else if(href_list["set_ringtone"]) if(CanUseTopic(user)) pref.ringtone = sanitize(input(user, "Please enter a new ringtone.", "Character Preference") as null|text, 20) - return TOPIC_REFRESH + return PREFERENCES_REFRESH return ..() diff --git a/code/modules/preferences/preference_setup/general/05_background.dm b/code/modules/preferences/preference_setup/general/05_background.dm new file mode 100644 index 00000000000..5c6fc5ac1d6 --- /dev/null +++ b/code/modules/preferences/preference_setup/general/05_background.dm @@ -0,0 +1,71 @@ +/datum/category_item/player_setup_item/general/background + name = "Background" + sort_order = 5 + +/datum/category_item/player_setup_item/general/background/load_character(savefile/S) + READ_FILE(S["med_record"], pref.med_record) + READ_FILE(S["sec_record"], pref.sec_record) + READ_FILE(S["gen_record"], pref.gen_record) + READ_FILE(S["economic_status"], pref.economic_status) + +/datum/category_item/player_setup_item/general/background/save_character(savefile/S) + WRITE_FILE(S["med_record"], pref.med_record) + WRITE_FILE(S["sec_record"], pref.sec_record) + WRITE_FILE(S["gen_record"], pref.gen_record) + WRITE_FILE(S["economic_status"], pref.economic_status) + +/datum/category_item/player_setup_item/general/background/sanitize_character() + pref.economic_status = sanitize_inlist(pref.economic_status, ECONOMIC_CLASS, initial(pref.economic_status)) + +// Moved from /datum/preferences/proc/copy_to() +/datum/category_item/player_setup_item/general/background/copy_to_mob(datum/preferences/prefs, mob/M, data, flags) + // todo: this is just a shim + if(!ishuman(M)) + return TRUE + var/mob/living/carbon/human/character = M + character.med_record = pref.med_record + character.sec_record = pref.sec_record + character.gen_record = pref.gen_record + return TRUE + +/datum/category_item/player_setup_item/general/background/content(datum/preferences/prefs, mob/user, data) + . += "Background Information
" + . += "Economic Status: [pref.economic_status]
" + + . += "
Records:
" + if(jobban_isbanned(user, "Records")) + . += "You are banned from using character records.
" + else + . += "Medical Records:
" + . += "[TextPreview(pref.med_record,40)]

" + . += "Employment Records:
" + . += "[TextPreview(pref.gen_record,40)]

" + . += "Security Records:
" + . += "[TextPreview(pref.sec_record,40)]
" + +/datum/category_item/player_setup_item/general/background/OnTopic(var/href,var/list/href_list, var/mob/user) + if(href_list["econ_status"]) + var/new_class = input(user, "Choose your economic status. This will affect the amount of money you will start with.", "Character Preference", pref.economic_status) as null|anything in ECONOMIC_CLASS + if(new_class && CanUseTopic(user)) + pref.economic_status = new_class + return PREFERENCES_REFRESH + + else if(href_list["set_medical_records"]) + var/new_medical = sanitize(input(user,"Enter medical information here.","Character Preference", html_decode(pref.med_record)) as message|null, MAX_RECORD_LENGTH, extra = 0) + if(!isnull(new_medical) && !jobban_isbanned(user, "Records") && CanUseTopic(user)) + pref.med_record = new_medical + return PREFERENCES_REFRESH + + else if(href_list["set_general_records"]) + var/new_general = sanitize(input(user,"Enter employment information here.","Character Preference", html_decode(pref.gen_record)) as message|null, MAX_RECORD_LENGTH, extra = 0) + if(!isnull(new_general) && !jobban_isbanned(user, "Records") && CanUseTopic(user)) + pref.gen_record = new_general + return PREFERENCES_REFRESH + + else if(href_list["set_security_records"]) + var/sec_medical = sanitize(input(user,"Enter security information here.","Character Preference", html_decode(pref.sec_record)) as message|null, MAX_RECORD_LENGTH, extra = 0) + if(!isnull(sec_medical) && !jobban_isbanned(user, "Records") && CanUseTopic(user)) + pref.sec_record = sec_medical + return PREFERENCES_REFRESH + + return ..() diff --git a/code/modules/client/preference_setup/general/06_flavor.dm b/code/modules/preferences/preference_setup/general/06_flavor.dm similarity index 95% rename from code/modules/client/preference_setup/general/06_flavor.dm rename to code/modules/preferences/preference_setup/general/06_flavor.dm index fd91357f78a..6b615844c36 100644 --- a/code/modules/client/preference_setup/general/06_flavor.dm +++ b/code/modules/preferences/preference_setup/general/06_flavor.dm @@ -37,7 +37,11 @@ return // Moved from /datum/preferences/proc/copy_to() -/datum/category_item/player_setup_item/general/flavor/copy_to_mob(var/mob/living/carbon/human/character) +/datum/category_item/player_setup_item/general/flavor/copy_to_mob(datum/preferences/prefs, mob/M, data, flags) + // todo: this is just a shim + if(!ishuman(M)) + return TRUE + var/mob/living/carbon/human/character = M character.flavor_texts["general"] = pref.flavor_texts["general"] character.flavor_texts["head"] = pref.flavor_texts["head"] character.flavor_texts["face"] = pref.flavor_texts["face"] @@ -48,8 +52,9 @@ character.flavor_texts["legs"] = pref.flavor_texts["legs"] character.flavor_texts["feet"] = pref.flavor_texts["feet"] character.ooc_notes = pref.metadata + return TRUE -/datum/category_item/player_setup_item/general/flavor/content(var/mob/user) +/datum/category_item/player_setup_item/general/flavor/content(datum/preferences/prefs, mob/user, data) . += "Flavor:
" . += "Set Flavor Text
" . += "Set Robot Flavor Text
" @@ -67,7 +72,7 @@ if(CanUseTopic(user)) pref.flavor_texts[href_list["flavor_text"]] = msg SetFlavorText(user) - return TOPIC_HANDLED + return PREFERENCES_HANDLED else if(href_list["flavour_text_robot"]) switch(href_list["flavour_text_robot"]) @@ -81,7 +86,7 @@ if(CanUseTopic(user)) pref.flavour_texts_robot[href_list["flavour_text_robot"]] = msg SetFlavourTextRobot(user) - return TOPIC_HANDLED + return PREFERENCES_HANDLED return ..() diff --git a/code/modules/client/preference_setup/global/01_ui.dm b/code/modules/preferences/preference_setup/global/01_ui.dm similarity index 86% rename from code/modules/client/preference_setup/global/01_ui.dm rename to code/modules/preferences/preference_setup/global/01_ui.dm index bf375786090..b907234a8b6 100644 --- a/code/modules/client/preference_setup/global/01_ui.dm +++ b/code/modules/preferences/preference_setup/global/01_ui.dm @@ -26,7 +26,7 @@ pref.tooltipstyle = sanitize_inlist(pref.tooltipstyle, all_tooltip_styles, initial(pref.tooltipstyle)) pref.client_fps = sanitize_integer(pref.client_fps, 0, MAX_CLIENT_FPS, initial(pref.client_fps)) -/datum/category_item/player_setup_item/player_global/ui/content(var/mob/user) +/datum/category_item/player_setup_item/player_global/ui/content(datum/preferences/prefs, mob/user, data) . = "UI Style: [pref.UI_style]
" . += "Custom UI (recommended for White UI):
" . += "-Color: [pref.UI_style_color] [color_square(hex = pref.UI_style_color)] reset
" @@ -43,42 +43,42 @@ /datum/category_item/player_setup_item/player_global/ui/OnTopic(var/href,var/list/href_list, var/mob/user) if(href_list["select_style"]) var/UI_style_new = input(user, "Choose UI style.", "Character Preference", pref.UI_style) as null|anything in all_ui_styles - if(!UI_style_new || !CanUseTopic(user)) return TOPIC_NOACTION + if(!UI_style_new || !CanUseTopic(user)) return PREFERENCES_NOACTION pref.UI_style = UI_style_new - return TOPIC_REFRESH + return PREFERENCES_REFRESH else if(href_list["select_color"]) var/UI_style_color_new = input(user, "Choose UI color, dark colors are not recommended!", "Global Preference", pref.UI_style_color) as color|null - if(isnull(UI_style_color_new) || !CanUseTopic(user)) return TOPIC_NOACTION + if(isnull(UI_style_color_new) || !CanUseTopic(user)) return PREFERENCES_NOACTION pref.UI_style_color = UI_style_color_new - return TOPIC_REFRESH + return PREFERENCES_REFRESH else if(href_list["select_alpha"]) var/UI_style_alpha_new = input(user, "Select UI alpha (transparency) level, between 50 and 255.", "Global Preference", pref.UI_style_alpha) as num|null - if(isnull(UI_style_alpha_new) || (UI_style_alpha_new < 50 || UI_style_alpha_new > 255) || !CanUseTopic(user)) return TOPIC_NOACTION + if(isnull(UI_style_alpha_new) || (UI_style_alpha_new < 50 || UI_style_alpha_new > 255) || !CanUseTopic(user)) return PREFERENCES_NOACTION pref.UI_style_alpha = UI_style_alpha_new - return TOPIC_REFRESH + return PREFERENCES_REFRESH else if(href_list["select_ooc_color"]) var/new_ooccolor = input(user, "Choose OOC color:", "Global Preference") as color|null if(new_ooccolor && can_select_ooc_color(user) && CanUseTopic(user)) pref.ooccolor = new_ooccolor - return TOPIC_REFRESH + return PREFERENCES_REFRESH else if(href_list["select_tooltip_style"]) var/tooltip_style_new = input(user, "Choose tooltip style.", "Global Preference", pref.tooltipstyle) as null|anything in all_tooltip_styles - if(!tooltip_style_new || !CanUseTopic(user)) return TOPIC_NOACTION + if(!tooltip_style_new || !CanUseTopic(user)) return PREFERENCES_NOACTION pref.tooltipstyle = tooltip_style_new - return TOPIC_REFRESH + return PREFERENCES_REFRESH else if(href_list["select_client_fps"]) var/fps_new = input(user, "Input Client FPS (1-200, 0 uses server FPS)", "Global Preference", pref.client_fps) as null|num - if(isnull(fps_new) || !CanUseTopic(user)) return TOPIC_NOACTION - if(fps_new < 0 || fps_new > MAX_CLIENT_FPS) return TOPIC_NOACTION + if(isnull(fps_new) || !CanUseTopic(user)) return PREFERENCES_NOACTION + if(fps_new < 0 || fps_new > MAX_CLIENT_FPS) return PREFERENCES_NOACTION pref.client_fps = fps_new if(pref.client) pref.client.fps = fps_new - return TOPIC_REFRESH + return PREFERENCES_REFRESH else if(href_list["reset"]) switch(href_list["reset"]) @@ -88,7 +88,7 @@ pref.UI_style_alpha = initial(pref.UI_style_alpha) if("ooc") pref.ooccolor = initial(pref.ooccolor) - return TOPIC_REFRESH + return PREFERENCES_REFRESH return ..() diff --git a/code/modules/client/preference_setup/global/02_settings.dm b/code/modules/preferences/preference_setup/global/02_settings.dm similarity index 95% rename from code/modules/client/preference_setup/global/02_settings.dm rename to code/modules/preferences/preference_setup/global/02_settings.dm index 719744e08cf..b39b7e24545 100644 --- a/code/modules/client/preference_setup/global/02_settings.dm +++ b/code/modules/preferences/preference_setup/global/02_settings.dm @@ -48,11 +48,11 @@ if(!(key in client_preference_keys)) pref.preferences_disabled -= key - pref.lastchangelog = sanitize_text(pref.lastchangelog, initial(pref.lastchangelog)) - pref.lastnews = sanitize_text(pref.lastnews, initial(pref.lastnews)) + pref.lastchangelog = sanitize_istext(pref.lastchangelog, initial(pref.lastchangelog)) + pref.lastnews = sanitize_istext(pref.lastnews, initial(pref.lastnews)) pref.default_slot = sanitize_integer(pref.default_slot, 1, config_legacy.character_slots, initial(pref.default_slot)) -/datum/category_item/player_setup_item/player_global/settings/content(var/mob/user) +/datum/category_item/player_setup_item/player_global/settings/content(datum/preferences/prefs, mob/user, data) . = list() . += "Preferences
" . += "" @@ -79,7 +79,7 @@ else if(href_list["toggle_off"]) . = pref_mob.set_preference(href_list["toggle_off"], FALSE) if(.) - return TOPIC_REFRESH + return PREFERENCES_REFRESH return ..() diff --git a/code/modules/client/preference_setup/global/03_pai.dm b/code/modules/preferences/preference_setup/global/03_pai.dm similarity index 96% rename from code/modules/client/preference_setup/global/03_pai.dm rename to code/modules/preferences/preference_setup/global/03_pai.dm index 8e0b4ea8a5c..6e3acd9f496 100644 --- a/code/modules/client/preference_setup/global/03_pai.dm +++ b/code/modules/preferences/preference_setup/global/03_pai.dm @@ -22,7 +22,7 @@ candidate.savefile_save(preference_mob()) -/datum/category_item/player_setup_item/player_global/pai/content(var/mob/user) +/datum/category_item/player_setup_item/player_global/pai/content(datum/preferences/prefs, mob/user, data) . += "pAI:
" if(!candidate) log_debug("[user] pAI prefs have a null candidate var.") @@ -52,6 +52,6 @@ t = input(user, "Enter any OOC comments", "Global Preference", html_decode(candidate.comments)) as message if(!isnull(t) && CanUseTopic(user)) candidate.comments = sanitize(t) - return TOPIC_REFRESH + return PREFERENCES_REFRESH return ..() diff --git a/code/modules/client/preference_setup/global/04_ooc.dm b/code/modules/preferences/preference_setup/global/04_ooc.dm similarity index 91% rename from code/modules/client/preference_setup/global/04_ooc.dm rename to code/modules/preferences/preference_setup/global/04_ooc.dm index 40ea3497a99..a4c18e08f96 100644 --- a/code/modules/client/preference_setup/global/04_ooc.dm +++ b/code/modules/preferences/preference_setup/global/04_ooc.dm @@ -14,7 +14,7 @@ if(isnull(pref.ignored_players)) pref.ignored_players = list() -/datum/category_item/player_setup_item/player_global/ooc/content(var/mob/user) +/datum/category_item/player_setup_item/player_global/ooc/content(datum/preferences/prefs, mob/user, data) . += "OOC:
" . += "Ignored Players
" for(var/ignored_player in pref.ignored_players) @@ -25,7 +25,7 @@ if(href_list["unignore_player"]) if(CanUseTopic(user)) pref.ignored_players -= href_list["unignore_player"] - return TOPIC_REFRESH + return PREFERENCES_REFRESH if(href_list["ignore_player"]) if(CanUseTopic(user)) @@ -34,9 +34,9 @@ player_to_ignore = sanitize(ckey(player_to_ignore)) if(player_to_ignore == user.ckey) to_chat(user, "You can't ignore yourself.") - return TOPIC_REFRESH + return PREFERENCES_REFRESH pref.ignored_players |= player_to_ignore - return TOPIC_REFRESH + return PREFERENCES_REFRESH return ..() */ diff --git a/code/modules/client/preference_setup/global/05_media.dm b/code/modules/preferences/preference_setup/global/05_media.dm similarity index 96% rename from code/modules/client/preference_setup/global/05_media.dm rename to code/modules/preferences/preference_setup/global/05_media.dm index 1478fd25d82..5cdd1b10f64 100644 --- a/code/modules/client/preference_setup/global/05_media.dm +++ b/code/modules/preferences/preference_setup/global/05_media.dm @@ -18,7 +18,7 @@ pref.media_volume = isnum(pref.media_volume) ? clamp(pref.media_volume, 0, 1) : initial(pref.media_volume) pref.media_player = sanitize_inlist(pref.media_player, list(0, 1, 2), initial(pref.media_player)) -/datum/category_item/player_setup_item/player_global/media/content(var/mob/user) +/datum/category_item/player_setup_item/player_global/media/content(datum/preferences/prefs, mob/user, data) . += "Jukebox Volume:" . += "[round(pref.media_volume * 100)]%
" . += "Media Player Type: Depending on you operating system, one of these might work better. " @@ -39,7 +39,7 @@ pref.media_volume = value/100.0 if(user.client && user.client.media) user.client.media.update_volume(pref.media_volume) - return TOPIC_REFRESH + return PREFERENCES_REFRESH else if(href_list["set_media_player"]) if(CanUseTopic(user)) var/newval = sanitize_inlist(text2num(href_list["set_media_player"]), list(0, 1, 2), pref.media_player) @@ -49,5 +49,5 @@ user.client.media.open() spawn(10) user.update_music() - return TOPIC_REFRESH + return PREFERENCES_REFRESH return ..() diff --git a/code/modules/preferences/preference_setup/global/language_prefix.dm b/code/modules/preferences/preference_setup/global/language_prefix.dm new file mode 100644 index 00000000000..b9910f2f97e --- /dev/null +++ b/code/modules/preferences/preference_setup/global/language_prefix.dm @@ -0,0 +1,66 @@ +/datum/category_item/player_setup_item/player_global/language_prefix + name = "Language Prefix" + is_global = TRUE + save_key = GLOBAL_DATA_LANGUAGE_PREFIX + +/datum/category_item/player_setup_item/player_global/language_prefix/proc/valid_prefix(c) + return length(c) == 1 && !(c in list(";", ":", ".", "!", "*", "^")) && !contains_az09(c) + +/datum/category_item/player_setup_item/player_global/language_prefix/filter_data(datum/preferences/prefs, data, list/errors) + var/list/prefixes = data + prefixes = sanitize_islist(prefixes) + for(var/c in prefixes) + if(!valid_prefix(c)) + prefixes -= c + if(!length(prefixes)) + return default_value() + return prefixes + +/datum/category_item/player_setup_item/player_global/language_prefix/content(datum/preferences/prefs, mob/user, data) + var/list/prefixes = data + . = list() + . += "Language Keys
" + . += " [jointext(prefixes, "")] [href_simple(prefs, "change", "Change")] [href_simple(prefs, "reset", "Reset")]" + +/datum/category_item/player_setup_item/player_global/language_prefix/act(datum/preferences/prefs, mob/user, action, list/params) + switch(action) + if("change") + var/char + var/keys[0] + do + char = input("Enter a single special character.\nYou may re-select the same characters.\nThe following characters are already in use by radio: ; : .\nThe following characters are already in use by special say commands: ! * ^", "Enter Character - [3 - keys.len] remaining") as null|text + if(char) + if(length(char) > 1) + alert(user, "Only single characters allowed.", "Error", "Ok") + else if(char in list(";", ":", ".")) + alert(user, "Radio character. Rejected.", "Error", "Ok") + else if(char in list("!","*", "^")) + alert(user, "Say character. Rejected.", "Error", "Ok") + else if(contains_az09(char)) + alert(user, "Non-special character. Rejected.", "Error", "Ok") + else + keys.Add(char) + while(char && keys.len < 3) + + if(keys.len == 3) + write(prefs, keys) + return PREFERENCES_REFRESH + return PREFERENCES_HANDLED + if("reset") + write(prefs, config_legacy.language_prefixes.Copy()) + return PREFERENCES_REFRESH + return ..() + +/datum/category_item/player_setup_item/player_global/language_prefix/default_value(randomizing) + return config_legacy.language_prefixes.Copy() + +/datum/preferences/proc/get_language_prefixes() + var/list/L = get_global_data(GLOBAL_DATA_LANGUAGE_PREFIX) + return L.Copy() + +/datum/preferences/proc/get_primary_language_prefix() + var/list/L = get_global_data(GLOBAL_DATA_LANGUAGE_PREFIX) + return L[1] + +/datum/preferences/proc/is_language_prefix(c) + return c in get_global_data(GLOBAL_DATA_LANGUAGE_PREFIX) diff --git a/code/modules/client/preference_setup/global/setting_datums.dm b/code/modules/preferences/preference_setup/global/setting_datums.dm similarity index 100% rename from code/modules/client/preference_setup/global/setting_datums.dm rename to code/modules/preferences/preference_setup/global/setting_datums.dm diff --git a/code/modules/preferences/preference_setup/helpers/language_pick.dm b/code/modules/preferences/preference_setup/helpers/language_pick.dm new file mode 100644 index 00000000000..8044c26e8b3 --- /dev/null +++ b/code/modules/preferences/preference_setup/helpers/language_pick.dm @@ -0,0 +1,93 @@ +// todo: proper tgui preferences + +/datum/preferences/proc/language_pick(mob/user) + if(GLOB.language_picker_active[REF(user)]) + return + new /datum/tgui_language_picker(user, src) + +/datum/preferences/proc/route_language_pick(id, mob/user) + return language_pick_finalize(id, user) + +/datum/preferences/proc/language_pick_finalize(id, mob/user) + var/datum/language/L = SScharacters.resolve_language_id(id) + if(!L) + to_chat(user, SPAN_WARNING("BUG: Invalid language ID: [id]")) + return TRUE + if(extraneous_language_ids().len > extraneous_languages_max()) + to_chat(user, SPAN_WARNING("You cannot select another language!")) + return TRUE + var/datum/character_species/CS = character_species_datum() + if((L.language_flags & WHITELISTED) && !((L.id in CS.whitelist_languages) || config.check_alien_whitelist(ckey(L.name), client_ckey))) + to_chat(user, SPAN_WARNING("[L.name] is a whitelisted language!")) + return FALSE + var/list/current = get_character_data(CHARACTER_DATA_LANGUAGES) + current += L.id + set_character_data(CHARACTER_DATA_LANGUAGES, current) + refresh(user) + return TRUE + +GLOBAL_LIST_EMPTY(language_picker_active) +/datum/tgui_language_picker + /// user ref + var/user_ref + /// preferences + var/datum/preferences/prefs + +/datum/tgui_language_picker/New(mob/user, datum/preferences/prefs) + if(!istype(user) || !istype(prefs)) + qdel(src) + CRASH("what?") + src.prefs = prefs + user_ref = REF(user) + GLOB.language_picker_active[user_ref] = src + open() + +/datum/tgui_language_picker/Destroy() + SStgui.close_uis(src) + GLOB.language_picker_active -= user_ref + return ..() + +/datum/tgui_language_picker/proc/open() + var/mob/M = locate(user_ref) + ASSERT(M) + ui_interact(M) + +/datum/tgui_language_picker/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "LanguagePicker", "Choose language") + ui.autoupdate = FALSE // why the fuck are you updating language data?? + ui.open() + +/datum/tgui_language_picker/ui_status(mob/user, datum/ui_state/state) + return UI_INTERACTIVE + +/datum/tgui_language_picker/ui_static_data(mob/user) + var/list/data = ..() + var/list/built = list() + var/list/categories = list("General") + for(var/datum/language/L as anything in SScharacters.all_languages()) + if(L.language_flags & RESTRICTED) + continue + built[++built.len] = list( + "id" = L.id, + "name" = L.name, + "desc" = L.desc, + "category" = L.category + ) + LAZYOR(categories, L.category) + data["languages"] = built + data["categories"] = categories + return data + +/datum/tgui_language_picker/ui_close(mob/user) + . = ..() + if(!QDELING(src)) + qdel(src) + +/datum/tgui_language_picker/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) + . = ..() + switch(action) + if("pick") + if(prefs.route_language_pick(params["id"], usr)) + qdel(src) diff --git a/code/modules/preferences/preference_setup/helpers/species_pick.dm b/code/modules/preferences/preference_setup/helpers/species_pick.dm new file mode 100644 index 00000000000..5fb7bf9d1a6 --- /dev/null +++ b/code/modules/preferences/preference_setup/helpers/species_pick.dm @@ -0,0 +1,135 @@ +// todo: proper tgui preferences + +/datum/preferences/proc/species_pick(mob/user) + if(GLOB.species_picker_active[REF(user)]) + return + var/current_species_id = character_species_id() + new /datum/tgui_species_picker(user, resolve_whitelisted_species(), current_species_id, src) + +/** + * gets list of species we can play of those who are whitelisted + */ +/datum/preferences/proc/resolve_whitelisted_species() + var/list/names = config.all_alien_whitelists_for(client_ckey) + . = list() + for(var/datum/character_species/CS as anything in SScharacters.all_character_species()) + if(ckey(CS.name) in names) + . += CS.uid + +/** + * check if we can play a species + */ +/datum/preferences/proc/check_character_species(datum/character_species/CS) + if(CS.whitelisted && !(config.check_alien_whitelist(ckey(CS.name), client_ckey))) + return FALSE + return TRUE + +/datum/preferences/proc/route_species_pick(uid, mob/user) + // return true to close window + return species_pick_finalize(uid, user) + +/datum/preferences/proc/species_pick_finalize(uid, mob/user) + var/datum/character_species/CS = SScharacters.resolve_character_species(uid) + if(!CS) + to_chat(user, SPAN_WARNING("No species by id [uid] found; this is likely a bug!")) + return TRUE // close window; it shouldn't be letting us select null species + if(!check_character_species(CS, user)) + return TRUE // close window; it shouldn't be letting us select whitelisted speices + set_character_species(CS, user) + refresh(user, TRUE) + return TRUE // yay done + +/datum/preferences/proc/set_character_species(datum/character_species/CS, mob/user) + // first set their vars + set_preference(/datum/category_item/player_setup_item/background/real_species, CS.real_species_uid()) + set_preference(/datum/category_item/player_setup_item/background/char_species, CS.uid) + custom_species = null + //! WARNING: SHITCODE AHEAD / LEGACY SHIMS + // so because the guy who made body limbs was too lazy to make sanitization, we have to fully reset it + // as well as some other stuff + // are you fucking kidding me lol + // gender + if(!(biological_gender in CS.genders)) + biological_gender = SAFEACCESS(CS.genders, 1) || MALE + // hair/fhair + var/list/valid_hair = get_valid_hairstyles() + var/list/valid_fhair = get_valid_facialhairstyles() + if(!(h_style in valid_hair)) + var/datum/sprite_accessory/hair/H = /datum/sprite_accessory/hair/bald + h_style = initial(H.name) + if(!(f_style in valid_fhair)) + var/datum/sprite_accessory/facial_hair/FH = /datum/sprite_accessory/facial_hair/shaved + f_style = initial(FH.name) + // limbs/markings + reset_limbs() + body_markings.Cut() + // age + age = clamp(age, CS.min_age, CS.max_age) + //! END + // then resanitize literally everything + player_setup.sanitize_setup() // todo: legacy, remove + sanitize_everything() + // then update their join menu if they're a chucklefuck and had it open + GLOB.join_menu?.update_static_data(user) + +GLOBAL_LIST_EMPTY(species_picker_active) +/datum/tgui_species_picker + /// user ref + var/user_ref + /// whitelisted uids + var/list/whitelisted + /// default uid + var/default + /// preferences + var/datum/preferences/prefs + +/datum/tgui_species_picker/New(mob/user, list/whitelisted_for = list(), default_id, datum/preferences/prefs) + if(!istype(user) || !istype(prefs)) + qdel(src) + CRASH("what?") + src.whitelisted = whitelisted_for + src.default = default_id + src.prefs = prefs + user_ref = REF(user) + GLOB.species_picker_active[user_ref] = src + open() + +/datum/tgui_species_picker/Destroy() + SStgui.close_uis(src) + GLOB.species_picker_active -= user_ref + return ..() + +/datum/tgui_species_picker/proc/open() + var/mob/M = locate(user_ref) + ASSERT(M) + ui_interact(M) + +/datum/tgui_species_picker/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "SpeciesPicker", "Choose Species") + ui.autoupdate = FALSE // why the fuck are you updating species data?? + ui.open() + +/datum/tgui_species_picker/ui_status(mob/user, datum/ui_state/state) + return UI_INTERACTIVE + +/datum/tgui_species_picker/ui_static_data(mob/user) + var/list/data = ..() + data["whitelisted"] = whitelisted + data["species"] = SScharacters.character_species_cache + data["default"] = default + data["admin"] = !!admin_datums[user.ckey] + return data + +/datum/tgui_species_picker/ui_close(mob/user) + . = ..() + if(!QDELING(src)) + qdel(src) + +/datum/tgui_species_picker/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) + . = ..() + switch(action) + if("pick") + if(prefs.route_species_pick(params["id"], usr)) + qdel(src) diff --git a/code/modules/client/preference_setup/keybindings/keybindings.dm b/code/modules/preferences/preference_setup/keybindings/keybindings.dm similarity index 92% rename from code/modules/client/preference_setup/keybindings/keybindings.dm rename to code/modules/preferences/preference_setup/keybindings/keybindings.dm index 5683f016d42..ab2962da0fe 100644 --- a/code/modules/client/preference_setup/keybindings/keybindings.dm +++ b/code/modules/preferences/preference_setup/keybindings/keybindings.dm @@ -9,7 +9,7 @@ var/choice = tgalert(client.mob, "Your basic keybindings need to be reset, emotes will remain as before. Would you prefer 'hotkey' or 'classic' mode?", "Reset keybindings", "Hotkey", "Classic") hotkeys = (choice != "Classic") var/list/oldkeys = key_bindings - key_bindings = (hotkeys) ? deepCopyList(GLOB.hotkey_keybinding_list_by_key) : deepCopyList(GLOB.classic_keybinding_list_by_key) + key_bindings = (hotkeys) ? deep_copy_list(GLOB.hotkey_keybinding_list_by_key) : deep_copy_list(GLOB.classic_keybinding_list_by_key) for(var/key in oldkeys) if(!key_bindings[key]) @@ -20,10 +20,7 @@ name = "Keybindings" sort_order = 7 category_item_type = /datum/category_item/player_setup_item/keybinding - -/datum/category_group/player_setup_category/keybindings/content(var/mob/user) - for(var/datum/category_item/player_setup_item/PI in items) - . += "[PI.content(user)]
" + auto_split = FALSE /datum/category_item/player_setup_item/keybinding/hotkey_mode name = "Hotkey Mode" @@ -38,7 +35,7 @@ /datum/category_item/player_setup_item/keybinding/hotkey_mode/sanitize_preferences() pref.hotkeys = sanitize_integer(pref.hotkeys, 0, 1, initial(pref.hotkeys)) -/datum/category_item/player_setup_item/keybinding/hotkey_mode/content(mob/user) +/datum/category_item/player_setup_item/keybinding/hotkey_mode/content(datum/preferences/prefs, mob/user, data) . += "Hotkey mode:[(pref.hotkeys) ? "Hotkeys" : "Default"]
" . += "Keybindings mode controls how the game behaves with tab and map/input focus.
If it is on Hotkeys, the game will always attempt to force you to map focus, meaning keypresses are sent \ directly to the map instead of the input. You will still be able to use the command bar, but you need to tab to do it every time you click on the game map.
\ @@ -55,7 +52,7 @@ if("hotkeys") pref.hotkeys = !pref.hotkeys user.client.set_macros() - return TOPIC_REFRESH + return PREFERENCES_REFRESH return ..() /datum/category_item/player_setup_item/keybinding/bindings @@ -78,7 +75,7 @@ if(!length(L)) pref.key_bindings -= key -/datum/category_item/player_setup_item/keybinding/bindings/content(mob/user) +/datum/category_item/player_setup_item/keybinding/bindings/content(datum/preferences/prefs, mob/user, data) . = list() var/list/key_bindings = pref.key_bindings //cache for speed or atleast my finger's sake.. // Create an inverted list of keybindings -> key @@ -136,7 +133,7 @@ var/kb_name = href_list["keybinding"] if(!kb_name) user << browse(null, "window=capturekeypress") - return TOPIC_REFRESH + return PREFERENCES_REFRESH var/clear_key = text2num(href_list["clear_key"]) var/old_key = href_list["old_key"] @@ -146,8 +143,8 @@ if(!length(pref.key_bindings[old_key])) pref.key_bindings -= old_key user << browse(null, "window=capturekeypress") - SScharacter_setup.queue_preferences_save(pref) - return TOPIC_REFRESH + SScharacters.queue_preferences_save(pref) + return PREFERENCES_REFRESH var/new_key = uppertext(href_list["key"]) var/AltMod = text2num(href_list["alt"]) ? "Alt" : "" @@ -178,16 +175,16 @@ user << browse(null, "window=capturekeypress") user.client.update_movement_keys() - SScharacter_setup.queue_preferences_save(pref) + SScharacters.queue_preferences_save(pref) if("keybindings_reset") var/choice = tgalert(user, "Would you prefer 'hotkey' or 'classic' defaults?", "Setup keybindings", "Hotkey", "Classic", "Cancel") if(choice == "Cancel") - return TOPIC_REFRESH + return PREFERENCES_REFRESH pref.hotkeys = (choice == "Hotkey") - pref.key_bindings = (pref.hotkeys) ? deepCopyList(GLOB.hotkey_keybinding_list_by_key) : deepCopyList(GLOB.classic_keybinding_list_by_key) + pref.key_bindings = (pref.hotkeys) ? deep_copy_list(GLOB.hotkey_keybinding_list_by_key) : deep_copy_list(GLOB.classic_keybinding_list_by_key) user.client.update_movement_keys() - return TOPIC_REFRESH + return PREFERENCES_REFRESH return ..() /datum/preferences/proc/CaptureKeybinding(mob/user, datum/keybinding/kb, old_key, datum/category_item/player_setup_item/keybinding/bindings/host) diff --git a/code/modules/client/preference_setup/loadout/gear_tweaks.dm b/code/modules/preferences/preference_setup/loadout/gear_tweaks.dm similarity index 100% rename from code/modules/client/preference_setup/loadout/gear_tweaks.dm rename to code/modules/preferences/preference_setup/loadout/gear_tweaks.dm diff --git a/code/modules/client/preference_setup/loadout/loadout.dm b/code/modules/preferences/preference_setup/loadout/loadout.dm similarity index 91% rename from code/modules/client/preference_setup/loadout/loadout.dm rename to code/modules/preferences/preference_setup/loadout/loadout.dm index 0599308dd3d..94df71dda03 100644 --- a/code/modules/client/preference_setup/loadout/loadout.dm +++ b/code/modules/preferences/preference_setup/loadout/loadout.dm @@ -15,7 +15,8 @@ var/list/gear_datums = list() var/cost = 1 // Number of points used. Items in general cost 1 point, storage/armor/gloves/special use costs 2 points. var/slot // Slot to equip to. var/list/allowed_roles // Roles that can spawn with this item. - var/whitelisted // Term to check the whitelist for.. + // todo: remove in favor of uid locks and or just a better system. + var/legacy_species_lock // Term to check the whitelist for.. var/sort_category = "General" var/list/gear_tweaks = list() // List of datums which will alter the item after it has been spawned. var/exploitable = 0 // Does it go on the exploitable information list? @@ -107,34 +108,29 @@ var/list/gear_datums = list() var/current_tab = "General" /datum/category_item/player_setup_item/loadout/load_character(var/savefile/S) - from_file(S["gear_list"], pref.gear_list) - from_file(S["gear_slot"], pref.gear_slot) + READ_FILE(S["gear_list"], pref.gear_list) + READ_FILE(S["gear_slot"], pref.gear_slot) if(pref.gear_list!=null && pref.gear_slot!=null) pref.gear = pref.gear_list["[pref.gear_slot]"] else - from_file(S["gear"], pref.gear) + READ_FILE(S["gear"], pref.gear) pref.gear_slot = 1 /datum/category_item/player_setup_item/loadout/save_character(var/savefile/S) pref.gear_list["[pref.gear_slot]"] = pref.gear - to_file(S["gear_list"], pref.gear_list) - to_file(S["gear_slot"], pref.gear_slot) + WRITE_FILE(S["gear_list"], pref.gear_list) + WRITE_FILE(S["gear_slot"], pref.gear_slot) -/datum/category_item/player_setup_item/loadout/proc/valid_gear_choices(var/max_cost) +/datum/category_item/player_setup_item/loadout/proc/valid_gear_choices(datum/preferences/prefs ,max_cost) . = list() var/mob/preference_mob = preference_mob() - var/list/whitelist_cache = list() + // todo: loadouts should use char species UID + var/real_species_name = prefs.real_species_name() for(var/gear_name in gear_datums) var/datum/gear/G = gear_datums[gear_name] - if(G.whitelisted) - var/spec = G.whitelisted - if(whitelist_cache[spec] == null) - whitelist_cache[spec] = is_alien_whitelisted(preference_mob, name_static_species_meta(spec)) - if(!whitelist_cache[spec]) + if(G.legacy_species_lock) + if(G.legacy_species_lock != real_species_name) continue - - if(G.whitelisted && !is_alien_whitelisted(preference_mob, name_static_species_meta(G.whitelisted))) - continue if(max_cost && G.cost > max_cost) continue if(preference_mob && preference_mob.client) @@ -155,11 +151,12 @@ var/list/gear_datums = list() if(!(gear_name in gear_datums)) pref.gear -= gear_name var/total_cost = 0 + var/list/valid = valid_gear_choices(pref) for(var/gear_name in pref.gear) if(!gear_datums[gear_name]) to_chat(preference_mob, SPAN_WARNING("You cannot have more than one of the \the [gear_name]")) pref.gear -= gear_name - else if(!(gear_name in valid_gear_choices())) + else if(!(gear_name in valid)) to_chat(preference_mob, SPAN_WARNING("You cannot take \the [gear_name] as you are not whitelisted for the species or item.")) pref.gear -= gear_name else @@ -170,7 +167,7 @@ var/list/gear_datums = list() else total_cost += G.cost -/datum/category_item/player_setup_item/loadout/content() +/datum/category_item/player_setup_item/loadout/content(datum/preferences/prefs, mob/user, data) . = list() var/mob/preference_mob = preference_mob() var/total_cost = 0 @@ -264,17 +261,17 @@ var/list/gear_datums = list() if(istype(G)) total_cost += G.cost if((total_cost+TG.cost) <= max_gear_points()) pref.gear += TG.name - return TOPIC_REFRESH_UPDATE_PREVIEW + return PREFERENCES_REFRESH_UPDATE_PREVIEW if(href_list["gear"] && href_list["tweak"]) var/datum/gear/gear = gear_datums[href_list["gear"]] var/datum/gear_tweak/tweak = locate(href_list["tweak"]) if(!tweak || !istype(gear) || !(tweak in gear.gear_tweaks)) - return TOPIC_NOACTION + return PREFERENCES_NOACTION var/metadata = tweak.get_metadata(user, get_tweak_metadata(gear, tweak)) if(!metadata || !CanUseTopic(user)) - return TOPIC_NOACTION + return PREFERENCES_NOACTION set_tweak_metadata(gear, tweak, metadata) - return TOPIC_REFRESH_UPDATE_PREVIEW + return PREFERENCES_REFRESH_UPDATE_PREVIEW if(href_list["next_slot"] || href_list["prev_slot"]) // Set the current slot in the gear list to the currently selected gear pref.gear_list["[pref.gear_slot]"] = pref.gear @@ -297,13 +294,13 @@ var/list/gear_datums = list() pref.gear = list() pref.gear_list["[pref.gear_slot]"] = list() // Refresh? - return TOPIC_REFRESH_UPDATE_PREVIEW + return PREFERENCES_REFRESH_UPDATE_PREVIEW else if(href_list["select_category"]) current_tab = href_list["select_category"] - return TOPIC_REFRESH + return PREFERENCES_REFRESH else if(href_list["clear_loadout"]) pref.gear.Cut() - return TOPIC_REFRESH_UPDATE_PREVIEW + return PREFERENCES_REFRESH_UPDATE_PREVIEW return ..() /proc/max_gear_points() diff --git a/code/modules/client/preference_setup/loadout/loadout_accessories.dm b/code/modules/preferences/preference_setup/loadout/loadout_accessories.dm similarity index 100% rename from code/modules/client/preference_setup/loadout/loadout_accessories.dm rename to code/modules/preferences/preference_setup/loadout/loadout_accessories.dm diff --git a/code/modules/client/preference_setup/loadout/loadout_cosmetics.dm b/code/modules/preferences/preference_setup/loadout/loadout_cosmetics.dm similarity index 100% rename from code/modules/client/preference_setup/loadout/loadout_cosmetics.dm rename to code/modules/preferences/preference_setup/loadout/loadout_cosmetics.dm diff --git a/code/modules/client/preference_setup/loadout/loadout_donator.dm b/code/modules/preferences/preference_setup/loadout/loadout_donator.dm similarity index 100% rename from code/modules/client/preference_setup/loadout/loadout_donator.dm rename to code/modules/preferences/preference_setup/loadout/loadout_donator.dm diff --git a/code/modules/client/preference_setup/loadout/loadout_ears.dm b/code/modules/preferences/preference_setup/loadout/loadout_ears.dm similarity index 100% rename from code/modules/client/preference_setup/loadout/loadout_ears.dm rename to code/modules/preferences/preference_setup/loadout/loadout_ears.dm diff --git a/code/modules/client/preference_setup/loadout/loadout_event_rewards.dm b/code/modules/preferences/preference_setup/loadout/loadout_event_rewards.dm similarity index 100% rename from code/modules/client/preference_setup/loadout/loadout_event_rewards.dm rename to code/modules/preferences/preference_setup/loadout/loadout_event_rewards.dm diff --git a/code/modules/client/preference_setup/loadout/loadout_eyes.dm b/code/modules/preferences/preference_setup/loadout/loadout_eyes.dm similarity index 100% rename from code/modules/client/preference_setup/loadout/loadout_eyes.dm rename to code/modules/preferences/preference_setup/loadout/loadout_eyes.dm diff --git a/code/modules/client/preference_setup/loadout/loadout_general.dm b/code/modules/preferences/preference_setup/loadout/loadout_general.dm similarity index 100% rename from code/modules/client/preference_setup/loadout/loadout_general.dm rename to code/modules/preferences/preference_setup/loadout/loadout_general.dm diff --git a/code/modules/client/preference_setup/loadout/loadout_gloves.dm b/code/modules/preferences/preference_setup/loadout/loadout_gloves.dm similarity index 100% rename from code/modules/client/preference_setup/loadout/loadout_gloves.dm rename to code/modules/preferences/preference_setup/loadout/loadout_gloves.dm diff --git a/code/modules/client/preference_setup/loadout/loadout_head.dm b/code/modules/preferences/preference_setup/loadout/loadout_head.dm similarity index 100% rename from code/modules/client/preference_setup/loadout/loadout_head.dm rename to code/modules/preferences/preference_setup/loadout/loadout_head.dm diff --git a/code/modules/client/preference_setup/loadout/loadout_mask.dm b/code/modules/preferences/preference_setup/loadout/loadout_mask.dm similarity index 100% rename from code/modules/client/preference_setup/loadout/loadout_mask.dm rename to code/modules/preferences/preference_setup/loadout/loadout_mask.dm diff --git a/code/modules/client/preference_setup/loadout/loadout_role_restricted.dm b/code/modules/preferences/preference_setup/loadout/loadout_role_restricted.dm similarity index 100% rename from code/modules/client/preference_setup/loadout/loadout_role_restricted.dm rename to code/modules/preferences/preference_setup/loadout/loadout_role_restricted.dm diff --git a/code/modules/client/preference_setup/loadout/loadout_seasonal.dm b/code/modules/preferences/preference_setup/loadout/loadout_seasonal.dm similarity index 100% rename from code/modules/client/preference_setup/loadout/loadout_seasonal.dm rename to code/modules/preferences/preference_setup/loadout/loadout_seasonal.dm diff --git a/code/modules/client/preference_setup/loadout/loadout_shoes.dm b/code/modules/preferences/preference_setup/loadout/loadout_shoes.dm similarity index 100% rename from code/modules/client/preference_setup/loadout/loadout_shoes.dm rename to code/modules/preferences/preference_setup/loadout/loadout_shoes.dm diff --git a/code/modules/client/preference_setup/loadout/loadout_smoking.dm b/code/modules/preferences/preference_setup/loadout/loadout_smoking.dm similarity index 100% rename from code/modules/client/preference_setup/loadout/loadout_smoking.dm rename to code/modules/preferences/preference_setup/loadout/loadout_smoking.dm diff --git a/code/modules/client/preference_setup/loadout/loadout_suit.dm b/code/modules/preferences/preference_setup/loadout/loadout_suit.dm similarity index 100% rename from code/modules/client/preference_setup/loadout/loadout_suit.dm rename to code/modules/preferences/preference_setup/loadout/loadout_suit.dm diff --git a/code/modules/client/preference_setup/loadout/loadout_uniform.dm b/code/modules/preferences/preference_setup/loadout/loadout_uniform.dm similarity index 100% rename from code/modules/client/preference_setup/loadout/loadout_uniform.dm rename to code/modules/preferences/preference_setup/loadout/loadout_uniform.dm diff --git a/code/modules/client/preference_setup/loadout/loadout_utility.dm b/code/modules/preferences/preference_setup/loadout/loadout_utility.dm similarity index 100% rename from code/modules/client/preference_setup/loadout/loadout_utility.dm rename to code/modules/preferences/preference_setup/loadout/loadout_utility.dm diff --git a/code/modules/client/preference_setup/loadout/loadout_xeno.dm b/code/modules/preferences/preference_setup/loadout/loadout_xeno.dm similarity index 99% rename from code/modules/client/preference_setup/loadout/loadout_xeno.dm rename to code/modules/preferences/preference_setup/loadout/loadout_xeno.dm index 4f65b808300..1a1d86f8792 100644 --- a/code/modules/client/preference_setup/loadout/loadout_xeno.dm +++ b/code/modules/preferences/preference_setup/loadout/loadout_xeno.dm @@ -38,7 +38,7 @@ //**Species-Specific Datum Declarations //*Tajaran /datum/gear/xeno/tajaran - whitelisted = SPECIES_TAJ + legacy_species_lock = SPECIES_TAJ /datum/gear/xeno/tajaran/accessories slot = /datum/inventory_slot_meta/abstract/attach_as_accessory @@ -63,7 +63,7 @@ //*Promethean /datum/gear/xeno/promethean - whitelisted = SPECIES_PROMETHEAN + legacy_species_lock = SPECIES_PROMETHEAN /datum/gear/xeno/promethean/accessories slot = /datum/inventory_slot_meta/abstract/attach_as_accessory @@ -88,7 +88,7 @@ //*Teshari /datum/gear/xeno/teshari - whitelisted = SPECIES_TESHARI + legacy_species_lock = SPECIES_TESHARI /datum/gear/xeno/teshari/accessories slot = /datum/inventory_slot_meta/abstract/attach_as_accessory @@ -120,7 +120,7 @@ //*Phoronoid /datum/gear/xeno/phoronoid - whitelisted = SPECIES_PHORONOID + legacy_species_lock = SPECIES_PHORONOID /datum/gear/xeno/phoronoid/accessories slot = /datum/inventory_slot_meta/abstract/attach_as_accessory @@ -153,7 +153,8 @@ //*Skrell /datum/gear/xeno/skrell - whitelisted = SPECIES_SKRELL + // hello monara + // legacy_species_lock = SPECIES_SKRELL /datum/gear/xeno/skrell/accessories slot = /datum/inventory_slot_meta/abstract/attach_as_accessory @@ -186,7 +187,7 @@ //*Unathi /datum/gear/xeno/unathi - whitelisted = SPECIES_UNATHI + legacy_species_lock = SPECIES_UNATHI /datum/gear/xeno/unathi/accessories slot = /datum/inventory_slot_meta/abstract/attach_as_accessory @@ -219,7 +220,7 @@ //*Vox /datum/gear/xeno/vox - whitelisted = SPECIES_VOX + legacy_species_lock = SPECIES_VOX /datum/gear/xeno/vox/accessories slot = /datum/inventory_slot_meta/abstract/attach_as_accessory diff --git a/code/modules/preferences/preference_setup/occupation/occupation.dm b/code/modules/preferences/preference_setup/occupation/occupation.dm new file mode 100644 index 00000000000..103a9f7bc0f --- /dev/null +++ b/code/modules/preferences/preference_setup/occupation/occupation.dm @@ -0,0 +1,359 @@ +/datum/category_group/player_setup_category/occupation_preferences + name = "Occupation" + sort_order = 3 + category_item_type = /datum/category_item/player_setup_item/occupation + auto_split = FALSE + +/datum/category_item/player_setup_item/occupation + is_global = FALSE + +/** + * save format: list(job id = priority) + */ +/datum/category_item/player_setup_item/occupation/jobs + name = "Job Preferences" + save_key = CHARACTER_DATA_JOBS + +/datum/category_item/player_setup_item/occupation/jobs/filter_data(datum/preferences/prefs, data, list/errors) + var/list/jobs = sanitize_islist(data) + var/highest + for(var/id in jobs) + var/datum/job/J = SSjob.job_by_id(id) + if(!J) + jobs -= id + continue + if(jobs[id] == JOB_PRIORITY_HIGH) + if(highest) + jobs[id] = JOB_PRIORITY_MEDIUM + else + highest = jobs[id] + return jobs + +#define START_COLUMN . += "" +#define NEW_COLUMN END_COLUMN; START_COLUMN; count = 0; +/datum/category_item/player_setup_item/occupation/jobs/content(datum/preferences/prefs, mob/user, data) + // cast data + var/list/current = data + // if they have assistant selected all other jobs are irrelevant + var/assistant_selected = !!current[JOB_ID_ASSISTANT] + // prep list + . = list() + // monospace + . += "" + // center + . += "
" + // user intro + . += "

Choose occupation preferences

Unavailable occupations are crossed out.
" + // script inject for right click + . += "" + // grab job-by-department ui cache + var/list/ui_data = SSjob.job_pref_ui_cache + for(var/faction in ui_data) + // header + if(length(ui_data) != 1) + . += "[faction]" + // form table + . += "
" +#define END_COLUMN . += "
" + // form column + START_COLUMN + // iterate + var/count = 0 + var/limit = max(5, SSjob.job_pref_ui_per) + var/list/departments = ui_data[faction] + for(var/department in departments) + var/list/ids = departments[department] + var/dep_amt = length(department) + // if we'd hit limit, we split first as we're not longer than limit or would waste more than 4 slots. + if((count >= limit) || ((count + dep_amt > limit) && (dep_amt <= limit) && ((limit - count) <= 4))) + NEW_COLUMN + for(var/id in ids) + . += render_job(prefs, SSjob.job_by_id(id), current[id], assistant_selected) + ++count + if(count >= limit) + NEW_COLUMN + // close column + END_COLUMN + // close table + . += "
" + // linebreak + . += "
" + // remove monospace + . += "
" + // add alternative options + switch(prefs.get_character_data(CHARACTER_DATA_OVERFLOW_MODE)) + if(JOB_ALTERNATIVE_GET_RANDOM) + . += href_simple(prefs, "overflow", "Get random job if preferences unavailable") + if(JOB_ALTERNATIVE_BE_ASSISTANT) + . += href_simple(prefs, "overflow", "Be assistant if preference unavailable") + if(JOB_ALTERNATIVE_RETURN_LOBBY) + . += href_simple(prefs, "overflow", "Return to lobby if preference unavailable") + // add reset + . += href_simple(prefs, "reset", "\[Reset\]") + // remove center + . += "" + +#undef NEW_COLUMN +#undef END_COLUMN +#undef START_COLUMN + +/datum/category_item/player_setup_item/occupation/jobs/proc/render_job(datum/preferences/prefs, datum/job/J, current_priority, assistant_selected) + . = list() + . += "
" + // left side + . += "\[?\] " + var/rank + if((J.title in SSjob.get_job_titles_in_department(DEPARTMENT_COMMAND)) || (J.id == JOB_ID_AI)) + rank = "[J.title]" + else + rank = "[J.title]" + if(length(J.alt_titles)) + . += "[prefs.get_job_alt_title_name(J)] " + else + . += "[rank] " + // right side + . += " " + // assistant is treated as yes/no + var/fail_reason = check_job(prefs, J, current_priority) + if(fail_reason) + . += "\[[fail_reason]\]" + else if(J.id == JOB_ID_ASSISTANT) + . += "[assistant_selected? "Yes" : "No"]" + else if(assistant_selected) + else + var/lower + var/higher + var/current + switch(current_priority) + if(JOB_PRIORITY_HIGH) + lower = JOB_PRIORITY_MEDIUM + higher = JOB_PRIORITY_NEVER + current = "High" + if(JOB_PRIORITY_MEDIUM) + lower = JOB_PRIORITY_LOW + higher = JOB_PRIORITY_HIGH + current = "Medium" + if(JOB_PRIORITY_LOW) + lower = JOB_PRIORITY_NEVER + higher = JOB_PRIORITY_MEDIUM + current = "Low" + else + lower = JOB_PRIORITY_HIGH + higher = JOB_PRIORITY_LOW + current = "Never" + . += "[current]" + . += "
" - var/current = 0 - var/halfway = items.len / 2 - for(var/datum/category_item/player_setup_item/PI in items) - if(halfway && current++ >= halfway) - halfway = 0 - . += "" - . += "[PI.content(user)]
" - . += "
" + if(auto_split) + var/current = 0 + var/halfway = items.len / 2 + for(var/datum/category_item/player_setup_item/PI in items) + var/data + if(PI.save_key) + data = PI.is_global? prefs.get_global_data(PI.save_key) : prefs.get_character_data(PI.save_key) + var/list/c = PI.content(PI.pref, user, data) + if(!length(c)) + continue + if(current && auto_rule) + . += "
" + if(halfway && current++ >= halfway) + halfway = 0 + . += "" + . += "[islist(c)? c.Join("") : c]
" + . += "" + else + var/current = 0 + for(var/datum/category_item/player_setup_item/PI in items) + var/data + if(PI.save_key) + data = PI.is_global? prefs.get_global_data(PI.save_key) : prefs.get_character_data(PI.save_key) + var/list/content = PI.content(PI.pref, user, data) + if(!length(content)) + continue + if(current && auto_rule) + . += "
" + current++ + . += islist(content)? content.Join("") : content /********************** * Category Item Setup * @@ -160,6 +185,10 @@ ..() var/datum/category_collection/player_setup_collection/psc = category.collection pref = psc.preferences + pref.preference_datums += src + if(save_key) + pref.preference_by_key[save_key] = src + pref.preference_by_type[type] = src /datum/category_item/player_setup_item/Destroy() pref = null @@ -195,15 +224,6 @@ /datum/category_item/player_setup_item/proc/save_preferences(var/savefile/S) return -/* -* Called when the item is asked to apply its per character settings to a new mob. -*/ -/datum/category_item/player_setup_item/proc/copy_to_mob(var/mob/living/carbon/human/C) - return - -/datum/category_item/player_setup_item/proc/content() - return - /datum/category_item/player_setup_item/proc/sanitize_character() return @@ -218,17 +238,19 @@ return 1 . = OnTopic(href, href_list, usr) + var/resolved = href_list["act"] + . |= act(pref, usr, resolved, href_list) - if(. & TOPIC_UPDATE_PREVIEW) + if(. & PREFERENCES_UPDATE_PREVIEW) pref_mob.client.prefs.update_preview_icon() - if(. & TOPIC_REFRESH) + if(. & PREFERENCES_REFRESH) pref_mob.client.prefs.ShowChoices(usr) /datum/category_item/player_setup_item/CanUseTopic(var/mob/user) return 1 /datum/category_item/player_setup_item/proc/OnTopic(var/href,var/list/href_list, var/mob/user) - return TOPIC_NOACTION + return PREFERENCES_NOACTION /datum/category_item/player_setup_item/proc/preference_mob() if(!pref.client) @@ -261,7 +283,7 @@ return FALSE //Something went wrong! /datum/category_item/player_setup_item/proc/get_min_age() // Minimum limit is 18 - var/datum/species/S = pref.character_static_species_meta() + var/datum/species/S = pref.real_species_datum() if(S.min_age > 18) return S.min_age else if(!is_FBP()) @@ -269,7 +291,7 @@ return S.min_age /datum/category_item/player_setup_item/proc/get_max_age() - var/datum/species/S = pref.character_static_species_meta() + var/datum/species/S = pref.real_species_datum() if(!is_FBP()) return S.max_age // If they're not a robot, we can just use the species var. var/FBP_type = get_FBP_type() diff --git a/code/modules/client/preference_setup/skills/skills.dm b/code/modules/preferences/preference_setup/skills/skills.dm similarity index 88% rename from code/modules/client/preference_setup/skills/skills.dm rename to code/modules/preferences/preference_setup/skills/skills.dm index 02fd8bcc0b9..992c97d762e 100644 --- a/code/modules/client/preference_setup/skills/skills.dm +++ b/code/modules/preferences/preference_setup/skills/skills.dm @@ -21,11 +21,16 @@ if(pref.used_skillpoints < 0) pref.used_skillpoints = 0 // Moved from /datum/preferences/proc/copy_to() -/datum/category_item/player_setup_item/skills/copy_to_mob(var/mob/living/carbon/human/character) +/datum/category_item/player_setup_item/skills/copy_to_mob(datum/preferences/prefs, mob/M, data, flags) + // todo: this is just a shim + if(!ishuman(M)) + return TRUE + var/mob/living/carbon/human/character = M character.skills = pref.skills character.used_skillpoints = pref.used_skillpoints + return TRUE -/datum/category_item/player_setup_item/skills/content() +/datum/category_item/player_setup_item/skills/content(datum/preferences/prefs, mob/user, data) . = list() . += "Select your Skills
" . += "Current skill level: [pref.GetSkillClass(pref.used_skillpoints)] ([pref.used_skillpoints])
" @@ -60,14 +65,14 @@ var/datum/skill/S = locate(href_list["skillinfo"]) var/HTML = "[S.name]
[S.desc]" user << browse(HTML, "window=\ref[user]skillinfo") - return TOPIC_HANDLED + return PREFERENCES_HANDLED else if(href_list["setskill"]) var/datum/skill/S = locate(href_list["setskill"]) var/value = text2num(href_list["newvalue"]) pref.skills[S.ID] = value pref.CalculateSkillPoints() - return TOPIC_REFRESH + return PREFERENCES_REFRESH else if(href_list["preconfigured"]) var/selected = input(user, "Select a skillset", "Skillset") as null|anything in SKILL_PRE @@ -81,11 +86,11 @@ pref.skills[V] = SKILL_PRE[selected][V] pref.CalculateSkillPoints() - return TOPIC_REFRESH + return PREFERENCES_REFRESH else if(href_list["setspecialization"]) pref.skill_specialization = href_list["setspecialization"] pref.CalculateSkillPoints() - return TOPIC_REFRESH + return PREFERENCES_REFRESH return ..() diff --git a/code/modules/client/preference_setup/traits/trait_defines.dm b/code/modules/preferences/preference_setup/traits/trait_defines.dm similarity index 100% rename from code/modules/client/preference_setup/traits/trait_defines.dm rename to code/modules/preferences/preference_setup/traits/trait_defines.dm diff --git a/code/modules/client/preference_setup/traits/traits.dm b/code/modules/preferences/preference_setup/traits/traits.dm similarity index 96% rename from code/modules/client/preference_setup/traits/traits.dm rename to code/modules/preferences/preference_setup/traits/traits.dm index 060c708ecc3..375dc86f4e3 100644 --- a/code/modules/client/preference_setup/traits/traits.dm +++ b/code/modules/preferences/preference_setup/traits/traits.dm @@ -36,7 +36,7 @@ var/list/trait_categories = list() // The categories available for the trait men S["traits"] << pref.traits -/datum/category_item/player_setup_item/traits/content() +/datum/category_item/player_setup_item/traits/content(datum/preferences/prefs, mob/user, data) . = list() . += "" . += "" @@ -124,18 +124,18 @@ var/list/trait_categories = list() // The categories available for the trait men var/invalidity = T.test_for_invalidity(src) if(invalidity) to_chat(user, "You cannot take the [T.name] trait. Reason: [invalidity]") - return TOPIC_NOACTION + return PREFERENCES_NOACTION var/conflicts = T.test_for_trait_conflict(pref.traits) if(conflicts) to_chat(user, "The [T.name] trait is mutually exclusive with [conflicts].") - return TOPIC_NOACTION + return PREFERENCES_NOACTION pref.traits += T.name - return TOPIC_REFRESH_UPDATE_PREVIEW + return PREFERENCES_REFRESH_UPDATE_PREVIEW else if(href_list["select_category"]) current_tab = href_list["select_category"] - return TOPIC_REFRESH + return PREFERENCES_REFRESH return ..() diff --git a/code/modules/client/preference_setup/vore/01_ears.dm b/code/modules/preferences/preference_setup/vore/01_ears.dm similarity index 93% rename from code/modules/client/preference_setup/vore/01_ears.dm rename to code/modules/preferences/preference_setup/vore/01_ears.dm index a973c5ca570..71b265c72b8 100644 --- a/code/modules/client/preference_setup/vore/01_ears.dm +++ b/code/modules/preferences/preference_setup/vore/01_ears.dm @@ -186,28 +186,35 @@ pref.g_gradwing = sanitize_integer(pref.g_gradwing, 0, 255, initial(pref.g_gradwing)) pref.b_gradwing = sanitize_integer(pref.b_gradwing, 0, 255, initial(pref.b_gradwing)) + var/datum/species/S = pref.real_species_datum() + var/species_name = S.name + if(pref.ear_style) pref.ear_style = sanitize_inlist(pref.ear_style, ear_styles_list, initial(pref.ear_style)) var/datum/sprite_accessory/temp_ear_style = ear_styles_list[pref.ear_style] - if(temp_ear_style.apply_restrictions && (!(pref.species in temp_ear_style.species_allowed))) + if(temp_ear_style.apply_restrictions && (!(species_name in temp_ear_style.species_allowed))) pref.ear_style = initial(pref.ear_style) if(pref.horn_style) pref.horn_style = sanitize_inlist(pref.horn_style, horn_styles_list, initial(pref.horn_style)) var/datum/sprite_accessory/temp_horn_style = horn_styles_list[pref.horn_style] - if(temp_horn_style.apply_restrictions && (!(pref.species in temp_horn_style.species_allowed))) + if(temp_horn_style.apply_restrictions && (!(species_name in temp_horn_style.species_allowed))) pref.horn_style = initial(pref.horn_style) if(pref.tail_style) pref.tail_style = sanitize_inlist(pref.tail_style, tail_styles_list, initial(pref.tail_style)) var/datum/sprite_accessory/temp_tail_style = tail_styles_list[pref.tail_style] - if(temp_tail_style.apply_restrictions && (!(pref.species in temp_tail_style.species_allowed))) + if(temp_tail_style.apply_restrictions && (!(species_name in temp_tail_style.species_allowed))) pref.tail_style = initial(pref.tail_style) if(pref.wing_style) pref.wing_style = sanitize_inlist(pref.wing_style, wing_styles_list, initial(pref.wing_style)) var/datum/sprite_accessory/temp_wing_style = wing_styles_list[pref.wing_style] - if(temp_wing_style.apply_restrictions && (!(pref.species in temp_wing_style.species_allowed))) + if(temp_wing_style.apply_restrictions && (!(species_name in temp_wing_style.species_allowed))) pref.wing_style = initial(pref.wing_style) -/datum/category_item/player_setup_item/vore/ears/copy_to_mob(var/mob/living/carbon/human/character) +/datum/category_item/player_setup_item/vore/ears/copy_to_mob(datum/preferences/prefs, mob/M, data, flags) + // todo: this is just a shim + if(!ishuman(M)) + return TRUE + var/mob/living/carbon/human/character = M character.ear_style = ear_styles_list[pref.ear_style] character.r_ears = pref.r_ears character.b_ears = pref.b_ears @@ -251,10 +258,9 @@ character.r_gradwing = pref.r_gradwing character.g_gradwing = pref.g_gradwing character.b_gradwing = pref.b_gradwing + return TRUE - - -/datum/category_item/player_setup_item/vore/ears/content(var/mob/user) +/datum/category_item/player_setup_item/vore/ears/content(datum/preferences/prefs, mob/user, data) . += "

Appearance and Custom Species Settings

" var/ear_display = "Normal" @@ -334,15 +340,18 @@ /datum/category_item/player_setup_item/vore/ears/OnTopic(var/href,var/list/href_list, var/mob/user) + var/datum/species/S = pref.real_species_datum() + var/species_name = S.name + if(!CanUseTopic(user)) - return TOPIC_NOACTION + return PREFERENCES_NOACTION else if(href_list["ear_style"]) // Construct the list of names allowed for this user. var/list/pretty_ear_styles = list("Normal" = null) for(var/path in ear_styles_list) var/datum/sprite_accessory/ears/instance = ear_styles_list[path] - if(((!instance.ckeys_allowed) || (usr.ckey in instance.ckeys_allowed)) && ((!instance.apply_restrictions) || (pref.species in instance.species_allowed))) + if(((!instance.ckeys_allowed) || (usr.ckey in instance.ckeys_allowed)) && ((!instance.apply_restrictions) || (species_name in instance.species_allowed))) pretty_ear_styles[instance.name] = path // Present choice to user @@ -350,7 +359,7 @@ if(new_ear_style) pref.ear_style = pretty_ear_styles[new_ear_style] - return TOPIC_REFRESH_UPDATE_PREVIEW + return PREFERENCES_REFRESH_UPDATE_PREVIEW else if(href_list["ear_color"]) var/new_earc = input(user, "Choose your character's ear colour:", "Character Preference", @@ -359,7 +368,7 @@ pref.r_ears = hex2num(copytext(new_earc, 2, 4)) pref.g_ears = hex2num(copytext(new_earc, 4, 6)) pref.b_ears = hex2num(copytext(new_earc, 6, 8)) - return TOPIC_REFRESH_UPDATE_PREVIEW + return PREFERENCES_REFRESH_UPDATE_PREVIEW else if(href_list["ear_color2"]) var/new_earc2 = input(user, "Choose your character's secondary ear colour:", "Character Preference", @@ -368,7 +377,7 @@ pref.r_ears2 = hex2num(copytext(new_earc2, 2, 4)) pref.g_ears2 = hex2num(copytext(new_earc2, 4, 6)) pref.b_ears2 = hex2num(copytext(new_earc2, 6, 8)) - return TOPIC_REFRESH_UPDATE_PREVIEW + return PREFERENCES_REFRESH_UPDATE_PREVIEW else if(href_list["ear_color3"]) var/new_earc3 = input(user, "Choose your character's tertiary ear colour:", "Character Preference", @@ -377,14 +386,14 @@ pref.r_ears3 = hex2num(copytext(new_earc3, 2, 4)) pref.g_ears3 = hex2num(copytext(new_earc3, 4, 6)) pref.b_ears3 = hex2num(copytext(new_earc3, 6, 8)) - return TOPIC_REFRESH_UPDATE_PREVIEW + return PREFERENCES_REFRESH_UPDATE_PREVIEW else if(href_list["horn_style"]) // Construct the list of names allowed for this user. var/list/pretty_horn_styles = list("Normal" = null) for(var/path in horn_styles_list) var/datum/sprite_accessory/ears/instance = horn_styles_list[path] - if(((!instance.ckeys_allowed) || (usr.ckey in instance.ckeys_allowed)) && ((!instance.apply_restrictions) || (pref.species in instance.species_allowed))) + if(((!instance.ckeys_allowed) || (usr.ckey in instance.ckeys_allowed)) && ((!instance.apply_restrictions) || (species_name in instance.species_allowed))) pretty_horn_styles[instance.name] = path // Present choice to user @@ -392,7 +401,7 @@ if(new_horn_style) pref.horn_style = pretty_horn_styles[new_horn_style] - return TOPIC_REFRESH_UPDATE_PREVIEW + return PREFERENCES_REFRESH_UPDATE_PREVIEW else if(href_list["horn_color"]) var/new_hornc = input(user, "Choose your character's horn colour:", "Character Preference", @@ -401,7 +410,7 @@ pref.r_horn = hex2num(copytext(new_hornc, 2, 4)) pref.g_horn = hex2num(copytext(new_hornc, 4, 6)) pref.b_horn = hex2num(copytext(new_hornc, 6, 8)) - return TOPIC_REFRESH_UPDATE_PREVIEW + return PREFERENCES_REFRESH_UPDATE_PREVIEW else if(href_list["horn_color2"]) var/new_hornc2 = input(user, "Choose your character's secondary horn colour:", "Character Preference", @@ -410,7 +419,7 @@ pref.r_horn2 = hex2num(copytext(new_hornc2, 2, 4)) pref.g_horn2 = hex2num(copytext(new_hornc2, 4, 6)) pref.b_horn2 = hex2num(copytext(new_hornc2, 6, 8)) - return TOPIC_REFRESH_UPDATE_PREVIEW + return PREFERENCES_REFRESH_UPDATE_PREVIEW else if(href_list["horn_color3"]) var/new_hornc3 = input(user, "Choose your character's tertiary horn colour:", "Character Preference", @@ -419,14 +428,14 @@ pref.r_horn3 = hex2num(copytext(new_hornc3, 2, 4)) pref.g_horn3 = hex2num(copytext(new_hornc3, 4, 6)) pref.b_horn3 = hex2num(copytext(new_hornc3, 6, 8)) - return TOPIC_REFRESH_UPDATE_PREVIEW + return PREFERENCES_REFRESH_UPDATE_PREVIEW else if(href_list["tail_style"]) // Construct the list of names allowed for this user. var/list/pretty_tail_styles = list("Normal" = null) for(var/path in tail_styles_list) var/datum/sprite_accessory/tail/instance = tail_styles_list[path] - if(((!instance.ckeys_allowed) || (usr.ckey in instance.ckeys_allowed)) && ((!instance.apply_restrictions) || (pref.species in instance.species_allowed))) + if(((!instance.ckeys_allowed) || (usr.ckey in instance.ckeys_allowed)) && ((!instance.apply_restrictions) || (species_name in instance.species_allowed))) pretty_tail_styles[instance.name] = path // Present choice to user @@ -434,7 +443,7 @@ if(new_tail_style) pref.tail_style = pretty_tail_styles[new_tail_style] - return TOPIC_REFRESH_UPDATE_PREVIEW + return PREFERENCES_REFRESH_UPDATE_PREVIEW else if(href_list["tail_color"]) var/new_tailc = input(user, "Choose your character's tail/taur colour:", "Character Preference", @@ -443,7 +452,7 @@ pref.r_tail = hex2num(copytext(new_tailc, 2, 4)) pref.g_tail = hex2num(copytext(new_tailc, 4, 6)) pref.b_tail = hex2num(copytext(new_tailc, 6, 8)) - return TOPIC_REFRESH_UPDATE_PREVIEW + return PREFERENCES_REFRESH_UPDATE_PREVIEW else if(href_list["tail_color2"]) var/new_tailc2 = input(user, "Choose your character's secondary tail/taur colour:", "Character Preference", @@ -452,7 +461,7 @@ pref.r_tail2 = hex2num(copytext(new_tailc2, 2, 4)) pref.g_tail2 = hex2num(copytext(new_tailc2, 4, 6)) pref.b_tail2 = hex2num(copytext(new_tailc2, 6, 8)) - return TOPIC_REFRESH_UPDATE_PREVIEW + return PREFERENCES_REFRESH_UPDATE_PREVIEW else if(href_list["tail_color3"]) var/new_tailc3 = input(user, "Choose your character's tertiary tail/taur colour:", "Character Preference", @@ -461,14 +470,14 @@ pref.r_tail3 = hex2num(copytext(new_tailc3, 2, 4)) pref.g_tail3 = hex2num(copytext(new_tailc3, 4, 6)) pref.b_tail3 = hex2num(copytext(new_tailc3, 6, 8)) - return TOPIC_REFRESH_UPDATE_PREVIEW + return PREFERENCES_REFRESH_UPDATE_PREVIEW else if(href_list["wing_style"]) // Construct the list of names allowed for this user. var/list/pretty_wing_styles = list("Normal" = null) for(var/path in wing_styles_list) var/datum/sprite_accessory/wing/instance = wing_styles_list[path] - if(((!instance.ckeys_allowed) || (usr.ckey in instance.ckeys_allowed)) && ((!instance.apply_restrictions) || (pref.species in instance.species_allowed))) + if(((!instance.ckeys_allowed) || (usr.ckey in instance.ckeys_allowed)) && ((!instance.apply_restrictions) || (species_name in instance.species_allowed))) pretty_wing_styles[instance.name] = path // Present choice to user @@ -476,7 +485,7 @@ if(new_wing_style) pref.wing_style = pretty_wing_styles[new_wing_style] - return TOPIC_REFRESH_UPDATE_PREVIEW + return PREFERENCES_REFRESH_UPDATE_PREVIEW else if(href_list["wing_color"]) var/new_wingc = input(user, "Choose your character's wing colour:", "Character Preference", @@ -485,7 +494,7 @@ pref.r_wing = hex2num(copytext(new_wingc, 2, 4)) pref.g_wing = hex2num(copytext(new_wingc, 4, 6)) pref.b_wing = hex2num(copytext(new_wingc, 6, 8)) - return TOPIC_REFRESH_UPDATE_PREVIEW + return PREFERENCES_REFRESH_UPDATE_PREVIEW else if(href_list["wing_color2"]) var/new_wingc2 = input(user, "Choose your character's secondary wing colour:", "Character Preference", @@ -494,7 +503,7 @@ pref.r_wing2 = hex2num(copytext(new_wingc2, 2, 4)) pref.g_wing2 = hex2num(copytext(new_wingc2, 4, 6)) pref.b_wing2 = hex2num(copytext(new_wingc2, 6, 8)) - return TOPIC_REFRESH_UPDATE_PREVIEW + return PREFERENCES_REFRESH_UPDATE_PREVIEW else if(href_list["wing_color3"]) var/new_wingc3 = input(user, "Choose your character's tertiary wing colour:", "Character Preference", @@ -503,7 +512,7 @@ pref.r_wing3 = hex2num(copytext(new_wingc3, 2, 4)) pref.g_wing3 = hex2num(copytext(new_wingc3, 4, 6)) pref.b_wing3 = hex2num(copytext(new_wingc3, 6, 8)) - return TOPIC_REFRESH_UPDATE_PREVIEW + return PREFERENCES_REFRESH_UPDATE_PREVIEW else if(href_list["grad_wingcolor"]) var/new_gradwing = input(user, "Choose your character's wing gradiant color:", "Character Preference", rgb(pref.r_gradwing, pref.g_gradwing, pref.b_gradwing)) as color|null @@ -511,7 +520,7 @@ pref.r_gradwing = hex2num(copytext(new_gradwing, 2, 4)) pref.g_gradwing = hex2num(copytext(new_gradwing, 4, 6)) pref.b_gradwing = hex2num(copytext(new_gradwing, 6, 8)) - return TOPIC_REFRESH_UPDATE_PREVIEW + return PREFERENCES_REFRESH_UPDATE_PREVIEW else if(href_list["grad_wingstyle"]) var/list/valid_gradients = GLOB.hair_gradients @@ -519,6 +528,6 @@ var/new_grad_wingstyle = input(user, "Choose a color pattern for your wings:", "Character Preference", pref.grad_wingstyle) as null|anything in valid_gradients if(new_grad_wingstyle && CanUseTopic(user)) pref.grad_wingstyle = new_grad_wingstyle - return TOPIC_REFRESH_UPDATE_PREVIEW + return PREFERENCES_REFRESH_UPDATE_PREVIEW return ..() diff --git a/code/modules/client/preference_setup/vore/02_size.dm b/code/modules/preferences/preference_setup/vore/02_size.dm similarity index 90% rename from code/modules/client/preference_setup/vore/02_size.dm rename to code/modules/preferences/preference_setup/vore/02_size.dm index 47c36bfcfbe..73fd8baf8b9 100644 --- a/code/modules/client/preference_setup/vore/02_size.dm +++ b/code/modules/preferences/preference_setup/vore/02_size.dm @@ -40,14 +40,19 @@ if(pref.size_multiplier == null || pref.size_multiplier < RESIZE_TINY || pref.size_multiplier > RESIZE_HUGE) pref.size_multiplier = initial(pref.size_multiplier) -/datum/category_item/player_setup_item/vore/size/copy_to_mob(var/mob/living/carbon/human/character) +/datum/category_item/player_setup_item/vore/size/copy_to_mob(datum/preferences/prefs, mob/M, data, flags) + // todo: this is just a shim + if(!ishuman(M)) + return TRUE + var/mob/living/carbon/human/character = M character.weight = pref.weight_vr character.weight_gain = pref.weight_gain character.weight_loss = pref.weight_loss character.fuzzy = pref.fuzzy character.resize(pref.size_multiplier, animate = FALSE) + return TRUE -/datum/category_item/player_setup_item/vore/size/content(var/mob/user) +/datum/category_item/player_setup_item/vore/size/content(datum/preferences/prefs, mob/user, data) . += "
" . += "Scale:[round(pref.size_multiplier*100)]%
" . += "Scaled Appearance:[pref.fuzzy ? "Fuzzy" : "Sharp"]
" @@ -62,14 +67,14 @@ if (!ISINRANGE(new_size,25,200)) pref.size_multiplier = 1 to_chat(user, "Invalid size.") - return TOPIC_REFRESH_UPDATE_PREVIEW + return PREFERENCES_REFRESH_UPDATE_PREVIEW else if(new_size) pref.size_multiplier = (new_size/100) - return TOPIC_REFRESH_UPDATE_PREVIEW + return PREFERENCES_REFRESH_UPDATE_PREVIEW else if(href_list["toggle_fuzzy"]) pref.fuzzy = pref.fuzzy ? 0 : 1; - return TOPIC_REFRESH_UPDATE_PREVIEW + return PREFERENCES_REFRESH_UPDATE_PREVIEW else if(href_list["weight"]) var/new_weight = input(user, "Choose your character's relative body weight.\n\ @@ -84,7 +89,7 @@ if(unit_of_measurement == "Kilograms") new_weight = round(2.20462*text2num(new_weight),4) pref.weight_vr = sanitize_integer(new_weight, WEIGHT_MIN, WEIGHT_MAX, pref.weight_vr) - return TOPIC_REFRESH + return PREFERENCES_REFRESH else if(href_list["weight_gain"]) var/weight_gain_rate = input(user, "Choose your character's rate of weight gain between 100% \ @@ -93,7 +98,7 @@ ([WEIGHT_CHANGE_MIN]-[WEIGHT_CHANGE_MAX])", "Character Preference") as num|null if(weight_gain_rate) pref.weight_gain = round(text2num(weight_gain_rate),1) - return TOPIC_REFRESH + return PREFERENCES_REFRESH else if(href_list["weight_loss"]) var/weight_loss_rate = input(user, "Choose your character's rate of weight loss between 100% \ @@ -102,6 +107,6 @@ ([WEIGHT_CHANGE_MIN]-[WEIGHT_CHANGE_MAX])", "Character Preference") as num|null if(weight_loss_rate) pref.weight_loss = round(text2num(weight_loss_rate),1) - return TOPIC_REFRESH + return PREFERENCES_REFRESH return ..(); diff --git a/code/modules/client/preference_setup/vore/03_egg.dm b/code/modules/preferences/preference_setup/vore/03_egg.dm similarity index 81% rename from code/modules/client/preference_setup/vore/03_egg.dm rename to code/modules/preferences/preference_setup/vore/03_egg.dm index 127f6ebd683..7d4ab6e74d3 100644 --- a/code/modules/client/preference_setup/vore/03_egg.dm +++ b/code/modules/preferences/preference_setup/vore/03_egg.dm @@ -29,22 +29,27 @@ var/XENOMORPH_EGG = SPECIES_XENO var/valid_vore_egg_types = global_vore_egg_types pref.vore_egg_type = sanitize_inlist(pref.vore_egg_type, valid_vore_egg_types, initial(pref.vore_egg_type)) -/datum/category_item/player_setup_item/vore/egg/copy_to_mob(var/mob/living/carbon/human/character) +/datum/category_item/player_setup_item/vore/egg/copy_to_mob(datum/preferences/prefs, mob/M, data, flags) + // todo: this is just a shim + if(!ishuman(M)) + return TRUE + var/mob/living/carbon/human/character = M character.vore_egg_type = pref.vore_egg_type + return TRUE -/datum/category_item/player_setup_item/vore/egg/content(var/mob/user) +/datum/category_item/player_setup_item/vore/egg/content(datum/preferences/prefs, mob/user, data) . += "
" . += " Egg Type: [pref.vore_egg_type]
" /datum/category_item/player_setup_item/vore/egg/OnTopic(var/href, var/list/href_list, var/mob/user) if(!CanUseTopic(user)) - return TOPIC_NOACTION + return PREFERENCES_NOACTION else if(href_list["vore_egg_type"]) var/list/vore_egg_types = global_vore_egg_types var/selection = input(user, "Choose your character's egg type:", "Character Preference", pref.vore_egg_type) as null|anything in vore_egg_types if(selection) pref.vore_egg_type = vore_egg_types[selection] - return TOPIC_REFRESH + return PREFERENCES_REFRESH else return diff --git a/code/modules/client/preference_setup/vore/04_autohiss.dm b/code/modules/preferences/preference_setup/vore/04_autohiss.dm similarity index 83% rename from code/modules/client/preference_setup/vore/04_autohiss.dm rename to code/modules/preferences/preference_setup/vore/04_autohiss.dm index 1b823051e6e..c7f78c8dbc1 100644 --- a/code/modules/client/preference_setup/vore/04_autohiss.dm +++ b/code/modules/preferences/preference_setup/vore/04_autohiss.dm @@ -1,14 +1,3 @@ -#define AUTOHISS_OFF 0 -#define AUTOHISS_BASIC 1 -#define AUTOHISS_FULL 2 -///The number of autohiss types that we have. Used for sanitization -#define AUTOHISS_NUM 3 -///Equivalent to being off -#define AUTOHISS_TYPE_NONE 0 -#define AUTOHISS_TYPE_UNATHI 1 -#define AUTOHISS_TYPE_TAJARAN 2 -///The number of autohiss types that we have. Used for sanitization -#define AUTOHISS_TYPE_NUM 3 // Define a place to save in character setup /datum/preferences var/autohiss = AUTOHISS_OFF @@ -32,11 +21,16 @@ pref.autohiss = sanitize_integer(pref.autohiss, AUTOHISS_OFF, AUTOHISS_NUM, AUTOHISS_OFF) pref.autohiss_type = sanitize_integer(pref.autohiss_type, AUTOHISS_TYPE_NONE, AUTOHISS_TYPE_NUM, AUTOHISS_TYPE_NONE) -/datum/category_item/player_setup_item/vore/autohiss/copy_to_mob(var/mob/living/carbon/human/character) +/datum/category_item/player_setup_item/vore/autohiss/copy_to_mob(datum/preferences/prefs, mob/M, data, flags) + // todo: this is just a shim + if(!ishuman(M)) + return TRUE + var/mob/living/carbon/human/character = M character.autohiss_mode = pref.autohiss character.autohiss_type = pref.autohiss_type + return TRUE -/datum/category_item/player_setup_item/vore/autohiss/content(var/mob/user) +/datum/category_item/player_setup_item/vore/autohiss/content(datum/preferences/prefs, mob/user, data) . += "
" . += "Autohiss Type: " @@ -70,22 +64,22 @@ /datum/category_item/player_setup_item/vore/autohiss/OnTopic(var/href, var/list/href_list, var/mob/user) if(href_list["toggle_off"]) pref.autohiss = AUTOHISS_OFF - return TOPIC_REFRESH + return PREFERENCES_REFRESH if(href_list["toggle_basic"]) pref.autohiss = AUTOHISS_BASIC - return TOPIC_REFRESH + return PREFERENCES_REFRESH if(href_list["toggle_full"]) pref.autohiss = AUTOHISS_FULL - return TOPIC_REFRESH + return PREFERENCES_REFRESH if(href_list["toggle_type_none"]) pref.autohiss_type = AUTOHISS_TYPE_NONE - return TOPIC_REFRESH + return PREFERENCES_REFRESH if(href_list["toggle_type_unathi"]) pref.autohiss_type = AUTOHISS_TYPE_UNATHI - return TOPIC_REFRESH + return PREFERENCES_REFRESH if(href_list["toggle_type_tajaran"]) pref.autohiss_type = AUTOHISS_TYPE_TAJARAN - return TOPIC_REFRESH + return PREFERENCES_REFRESH return ..(); diff --git a/code/modules/client/preference_setup/vore/05_resleeving.dm b/code/modules/preferences/preference_setup/vore/05_resleeving.dm similarity index 87% rename from code/modules/client/preference_setup/vore/05_resleeving.dm rename to code/modules/preferences/preference_setup/vore/05_resleeving.dm index b89bc2023ae..6610099bb35 100644 --- a/code/modules/client/preference_setup/vore/05_resleeving.dm +++ b/code/modules/preferences/preference_setup/vore/05_resleeving.dm @@ -21,7 +21,11 @@ pref.resleeve_lock = sanitize_integer(pref.resleeve_lock, 0, 1, initial(pref.resleeve_lock)) pref.resleeve_scan = sanitize_integer(pref.resleeve_scan, 0, 1, initial(pref.resleeve_scan)) -/datum/category_item/player_setup_item/vore/resleeve/copy_to_mob(var/mob/living/carbon/human/character) +/datum/category_item/player_setup_item/vore/resleeve/copy_to_mob(datum/preferences/prefs, mob/M, data, flags) + // todo: this is just a shim + if(!ishuman(M)) + return TRUE + var/mob/living/carbon/human/character = M if(character && !istype(character,/mob/living/carbon/human/dummy)) spawn(50) if(QDELETED(character) || QDELETED(pref)) @@ -32,8 +36,9 @@ if(pref.resleeve_lock) character.resleeve_lock = character.ckey character.original_player = character.ckey + return TRUE -/datum/category_item/player_setup_item/vore/resleeve/content(var/mob/user) +/datum/category_item/player_setup_item/vore/resleeve/content(datum/preferences/prefs, mob/user, data) . += "
" . += "Start With Body Scan:[pref.resleeve_scan ? "Yes" : "No"]
" . += "Prevent Body Impersonation:[pref.resleeve_lock ? "Yes" : "No"]
" @@ -41,8 +46,8 @@ /datum/category_item/player_setup_item/vore/resleeve/OnTopic(var/href, var/list/href_list, var/mob/user) if(href_list["toggle_resleeve_lock"]) pref.resleeve_lock = pref.resleeve_lock ? 0 : 1; - return TOPIC_REFRESH + return PREFERENCES_REFRESH else if(href_list["toggle_resleeve_scan"]) pref.resleeve_scan = pref.resleeve_scan ? 0 : 1; - return TOPIC_REFRESH + return PREFERENCES_REFRESH return ..(); diff --git a/code/modules/client/preference_setup/vore/06_persistence.dm b/code/modules/preferences/preference_setup/vore/06_persistence.dm similarity index 96% rename from code/modules/client/preference_setup/vore/06_persistence.dm rename to code/modules/preferences/preference_setup/vore/06_persistence.dm index 2cc8738eccf..d1aa4d0ec4e 100644 --- a/code/modules/client/preference_setup/vore/06_persistence.dm +++ b/code/modules/preferences/preference_setup/vore/06_persistence.dm @@ -31,7 +31,7 @@ /datum/category_item/player_setup_item/vore/persistence/sanitize_character() pref.persistence_settings = sanitize_integer(pref.persistence_settings, 0, (1<<(PERSIST_COUNT+1)-1), initial(pref.persistence_settings)) -/datum/category_item/player_setup_item/vore/persistence/content(var/mob/user) +/datum/category_item/player_setup_item/vore/persistence/content(datum/preferences/prefs, mob/user, data) . = list() . += "Round-to-Round Persistence
" . += "

" @@ -69,9 +69,9 @@ if(href_list["toggle_on"]) var/bit = text2num(href_list["toggle_on"]) pref.persistence_settings |= bit - return TOPIC_REFRESH + return PREFERENCES_REFRESH else if(href_list["toggle_off"]) var/bit = text2num(href_list["toggle_off"]) pref.persistence_settings &= ~bit - return TOPIC_REFRESH + return PREFERENCES_REFRESH return ..() diff --git a/code/modules/client/preference_setup/vore/08_traits.dm b/code/modules/preferences/preference_setup/vore/08_traits.dm similarity index 87% rename from code/modules/client/preference_setup/vore/08_traits.dm rename to code/modules/preferences/preference_setup/vore/08_traits.dm index 3ace393ccbb..c7bb99d32f8 100644 --- a/code/modules/client/preference_setup/vore/08_traits.dm +++ b/code/modules/preferences/preference_setup/vore/08_traits.dm @@ -70,7 +70,7 @@ pref.starting_trait_points = STARTING_SPECIES_POINTS pref.max_traits = MAX_SPECIES_TRAITS - if(pref.species != SPECIES_CUSTOM) + if(pref.real_species_id() != SPECIES_ID_CUSTOM) pref.pos_traits.Cut() pref.neg_traits.Cut() // Clean up positive traits @@ -81,17 +81,17 @@ for(var/path in pref.neu_traits) if(!(path in neutral_traits)) pref.neu_traits -= path - if(!(pref.species == SPECIES_CUSTOM) && !(path in everyone_traits)) + if((pref.real_species_id() != SPECIES_ID_CUSTOM) && !(path in everyone_traits)) pref.neu_traits -= path //Negative traits for(var/path in pref.neg_traits) if(!(path in negative_traits)) pref.neg_traits -= path - var/datum/species/selected_species = pref.character_static_species_meta() + var/datum/species/selected_species = pref.real_species_datum() if(selected_species.selects_bodytype) // Allowed! - else if(!pref.custom_base || !(pref.custom_base in GLOB.custom_species_bases)) + else if(!pref.custom_base || !(pref.custom_base in SScharacters.custom_species_bases)) pref.custom_base = SPECIES_HUMAN pref.custom_say = lowertext(trim(pref.custom_say)) @@ -100,7 +100,11 @@ pref.custom_exclaim = lowertext(trim(pref.custom_exclaim)) -/datum/category_item/player_setup_item/vore/traits/copy_to_mob(mob/living/carbon/human/character) +/datum/category_item/player_setup_item/vore/traits/copy_to_mob(datum/preferences/prefs, mob/M, data, flags) + // todo: this is just a shim + if(!ishuman(M)) + return TRUE + var/mob/living/carbon/human/character = M character.custom_species = pref.custom_species character.custom_say = lowertext(trim(pref.custom_say)) character.custom_ask = lowertext(trim(pref.custom_ask)) @@ -108,30 +112,30 @@ character.custom_exclaim = lowertext(trim(pref.custom_exclaim)) var/datum/species/S = character.species - var/SB = S.selects_bodytype ? pref.custom_base : pref.character_static_species_meta() + var/SB = S.selects_bodytype ? pref.custom_base : pref.real_species_datum() S.copy_from(SB, pref.pos_traits + pref.neu_traits + pref.neg_traits, character) //Any additional non-trait settings can be applied here S.blood_color = pref.blood_color - if(pref.species == SPECIES_CUSTOM) + if(pref.real_species_id() == SPECIES_ID_CUSTOM) //Statistics for this would be nice var/english_traits = english_list(S.traits, and_text = ";", comma_text = ";") log_game("TRAITS [pref.client_ckey]/([character]) with: [english_traits]") //Terrible 'fake' key_name()... but they aren't in the same entity yet + return TRUE - -/datum/category_item/player_setup_item/vore/traits/content(mob/user) +/datum/category_item/player_setup_item/vore/traits/content(datum/preferences/prefs, mob/user, data) . += "Custom Species Name: " . += "[pref.custom_species ? pref.custom_species : "-Input Name-"]
" - var/datum/species/selected_species = pref.character_static_species_meta() + var/datum/species/selected_species = pref.real_species_datum() if(selected_species.selects_bodytype) . += "Icon Base: " . += "[pref.custom_base ? pref.custom_base : SPECIES_HUMAN]
" var/traits_left = pref.max_traits . += "Traits Left: [traits_left]
" - if(pref.species == SPECIES_CUSTOM) + if(pref.real_species_id() == SPECIES_ID_CUSTOM) var/points_left = pref.starting_trait_points for(var/T in pref.pos_traits + pref.neg_traits) points_left -= traits_costs[T] @@ -178,7 +182,7 @@ /datum/category_item/player_setup_item/vore/traits/OnTopic(var/href,var/list/href_list, var/mob/user) if(!CanUseTopic(user)) - return TOPIC_NOACTION + return PREFERENCES_NOACTION else if(href_list["custom_species"]) /*if(pref.species != SPECIES_CUSTOM) @@ -186,78 +190,78 @@ species on the 'General' tab. If you have this set to something, it's because you had it set before the \ Trait system was implemented. If you wish to change it, set your species to 'Custom Species' and configure \ the species completely.") - return TOPIC_REFRESH*/ //There was no reason to have this. + return PREFERENCES_REFRESH*/ //There was no reason to have this. var/raw_choice = sanitize(input(user, "Input your custom species name:", "Character Preference", pref.custom_species) as null|text, MAX_NAME_LEN) if (CanUseTopic(user)) pref.custom_species = raw_choice - return TOPIC_REFRESH + return PREFERENCES_REFRESH else if(href_list["custom_base"]) - var/list/choices = GLOB.custom_species_bases - if(pref.species != SPECIES_CUSTOM) - choices = (choices | pref.species) + var/list/choices = SScharacters.custom_species_bases + if(pref.real_species_id() != SPECIES_CUSTOM) + choices = (choices | pref.real_species_name()) var/text_choice = input("Pick an icon set for your species:","Icon Base") in choices if(text_choice in choices) pref.custom_base = text_choice - return TOPIC_REFRESH_UPDATE_PREVIEW + return PREFERENCES_REFRESH_UPDATE_PREVIEW else if(href_list["blood_color"]) var/color_choice = input("Pick a blood color (does not apply to synths)","Blood Color",pref.blood_color) as color if(color_choice) pref.blood_color = sanitize_hexcolor(color_choice, 6, TRUE, default = "#A10808") - return TOPIC_REFRESH + return PREFERENCES_REFRESH else if(href_list["blood_reset"]) var/choice = alert("Reset blood color to human default (#A10808)?","Reset Blood Color","Reset","Cancel") if(choice == "Reset") pref.blood_color = "#A10808" - return TOPIC_REFRESH + return PREFERENCES_REFRESH else if(href_list["clicked_pos_trait"]) var/datum/trait/trait = text2path(href_list["clicked_pos_trait"]) var/choice = alert("Remove [initial(trait.name)] and regain [initial(trait.cost)] points?","Remove Trait","Remove","Cancel") if(choice == "Remove") pref.pos_traits -= trait - return TOPIC_REFRESH + return PREFERENCES_REFRESH else if(href_list["clicked_neu_trait"]) var/datum/trait/trait = text2path(href_list["clicked_neu_trait"]) var/choice = alert("Remove [initial(trait.name)]?","Remove Trait","Remove","Cancel") if(choice == "Remove") pref.neu_traits -= trait - return TOPIC_REFRESH + return PREFERENCES_REFRESH else if(href_list["clicked_neg_trait"]) var/datum/trait/trait = text2path(href_list["clicked_neg_trait"]) var/choice = alert("Remove [initial(trait.name)] and lose [initial(trait.cost)] points?","Remove Trait","Remove","Cancel") if(choice == "Remove") pref.neg_traits -= trait - return TOPIC_REFRESH + return PREFERENCES_REFRESH else if(href_list["custom_say"]) var/say_choice = sanitize(input(usr, "This word or phrase will appear instead of 'says': [pref.real_name] says, \"Hi.\"", "Custom Say", pref.custom_say) as null|text, 12) if(say_choice) pref.custom_say = say_choice - return TOPIC_REFRESH + return PREFERENCES_REFRESH else if(href_list["custom_whisper"]) var/whisper_choice = sanitize(input(usr, "This word or phrase will appear instead of 'whispers': [pref.real_name] whispers, \"Hi...\"", "Custom Whisper", pref.custom_whisper) as null|text, 12) if(whisper_choice) pref.custom_whisper = whisper_choice - return TOPIC_REFRESH + return PREFERENCES_REFRESH else if(href_list["custom_ask"]) var/ask_choice = sanitize(input(usr, "This word or phrase will appear instead of 'asks': [pref.real_name] asks, \"Hi?\"", "Custom Ask", pref.custom_ask) as null|text, 12) if(ask_choice) pref.custom_ask = ask_choice - return TOPIC_REFRESH + return PREFERENCES_REFRESH else if(href_list["custom_exclaim"]) var/exclaim_choice = sanitize(input(usr, "This word or phrase will appear instead of 'exclaims', 'shouts' or 'yells': [pref.real_name] exclaims, \"Hi!\"", "Custom Exclaim", pref.custom_exclaim) as null|text, 12) if(exclaim_choice) pref.custom_exclaim = exclaim_choice - return TOPIC_REFRESH + return PREFERENCES_REFRESH else if(href_list["add_trait"]) var/mode = text2num(href_list["add_trait"]) @@ -268,7 +272,7 @@ picklist = positive_traits.Copy() - pref.pos_traits mylist = pref.pos_traits if(NEUTRAL_MODE) - if(pref.species == SPECIES_CUSTOM) + if(pref.real_species_id() == SPECIES_ID_CUSTOM) picklist = neutral_traits.Copy() - pref.neu_traits mylist = pref.neu_traits else @@ -280,10 +284,10 @@ else if(isnull(picklist)) - return TOPIC_REFRESH + return PREFERENCES_REFRESH if(isnull(mylist)) - return TOPIC_REFRESH + return PREFERENCES_REFRESH var/list/nicelist = list() for(var/P in picklist) @@ -312,7 +316,7 @@ done = TRUE if(!trait_choice) - return TOPIC_REFRESH + return PREFERENCES_REFRESH else if(trait_choice in nicelist) var/datum/trait/path = nicelist[trait_choice] var/datum/trait/instance = all_traits[path] @@ -321,11 +325,11 @@ // if(pref.species in instance.banned_species) // tgui_alert_async(usr, "The trait you've selected cannot be taken by the species you've chosen!", "Error") - // return TOPIC_REFRESH + // return PREFERENCES_REFRESH - if( LAZYLEN(instance.allowed_species) && !(pref.species in instance.allowed_species)) + if( LAZYLEN(instance.allowed_species) && !(pref.real_species_name() in instance.allowed_species)) tgui_alert_async(usr, "The trait you've selected cannot be taken by the species you've chosen!", "Error") - return TOPIC_REFRESH + return PREFERENCES_REFRESH if(trait_choice in pref.pos_traits + pref.neu_traits + pref.neg_traits) conflict = instance.name @@ -344,10 +348,10 @@ if(conflict) alert("You cannot take this trait and [conflict] at the same time. \ Please remove that trait, or pick another trait to add.","Error") - return TOPIC_REFRESH + return PREFERENCES_REFRESH mylist += path - return TOPIC_REFRESH + return PREFERENCES_REFRESH return ..() diff --git a/code/modules/client/preference_setup/vore/09_nif.dm b/code/modules/preferences/preference_setup/vore/09_nif.dm similarity index 71% rename from code/modules/client/preference_setup/vore/09_nif.dm rename to code/modules/preferences/preference_setup/vore/09_nif.dm index 07905af895f..675818de556 100644 --- a/code/modules/client/preference_setup/vore/09_nif.dm +++ b/code/modules/preferences/preference_setup/vore/09_nif.dm @@ -34,22 +34,16 @@ if(!islist(pref.nif_savedata)) pref.nif_savedata = list() -/datum/category_item/player_setup_item/vore/nif/copy_to_mob(var/mob/living/carbon/human/character) +/datum/category_item/player_setup_item/vore/nif/copy_to_mob(datum/preferences/prefs, mob/M, data, flags) + // todo: this is just a shim + if(!ishuman(M)) + return TRUE + var/mob/living/carbon/human/character = M //If you had a NIF... if((character.type == /mob/living/carbon/human) && pref.nif_id && pref.nif_durability) var/nif_path = GLOB.nif_id_lookup[pref.nif_id] new nif_path(character,pref.nif_durability,pref.nif_savedata) -/* - //And now here's the trick. We wipe these so that if they die, they lose the NIF. - //Backup implants will start saving this again periodically, and so will cryo'ing out. - pref.nif_id = null - pref.nif_durability = null - pref.nif_savedata = null - var/savefile/S = new /savefile(pref.path) - if(!S) - WARNING ("Couldn't load NIF save savefile? [pref.real_name]") - S.cd = "/character[pref.default_slot]" - save_character(S) -*/ -/datum/category_item/player_setup_item/vore/nif/content(var/mob/user) + return TRUE + +/datum/category_item/player_setup_item/vore/nif/content(datum/preferences/prefs, mob/user, data) . += "NIF: [pref.nif_id ? "Present" : "None"]" diff --git a/code/modules/client/preference_setup/vore/10_misc.dm b/code/modules/preferences/preference_setup/vore/10_misc.dm similarity index 88% rename from code/modules/client/preference_setup/vore/10_misc.dm rename to code/modules/preferences/preference_setup/vore/10_misc.dm index bee6ba34822..63fcde7a2fb 100644 --- a/code/modules/client/preference_setup/vore/10_misc.dm +++ b/code/modules/preferences/preference_setup/vore/10_misc.dm @@ -19,10 +19,15 @@ S["sensorpref"] << pref.sensorpref //TFF 5/8/19 - add sensor pref setting to be saveable //TFF 5/8/19 - add new datum category to allow for setting multiple settings when this is selected in the loadout. -/datum/category_item/player_setup_item/vore/misc/copy_to_mob(var/mob/living/carbon/human/character) +/datum/category_item/player_setup_item/vore/misc/copy_to_mob(datum/preferences/prefs, mob/M, data, flags) + // todo: this is just a shim + if(!ishuman(M)) + return TRUE + var/mob/living/carbon/human/character = M if(pref.sensorpref > 5 || pref.sensorpref < 1) pref.sensorpref = 5 character.sensorpref = pref.sensorpref + return TRUE /datum/category_item/player_setup_item/vore/misc/sanitize_character() pref.show_in_directory = sanitize_integer(pref.show_in_directory, 0, 1, initial(pref.show_in_directory)) @@ -30,7 +35,7 @@ pref.directory_erptag = sanitize_inlist(pref.directory_erptag, GLOB.char_directory_erptags, initial(pref.directory_erptag)) pref.sensorpref = sanitize_integer(pref.sensorpref, 1, sensorpreflist.len, initial(pref.sensorpref)) //TFF - 5/8/19 - add santisation for sensor prefs -/datum/category_item/player_setup_item/vore/misc/content(var/mob/user) +/datum/category_item/player_setup_item/vore/misc/content(datum/preferences/prefs, mob/user, data) . += "
" . += "Appear in Character Directory:[pref.show_in_directory ? "Yes" : "No"]
" . += "Character Directory Vore Tag:[pref.directory_tag]
" @@ -40,27 +45,27 @@ /datum/category_item/player_setup_item/vore/misc/OnTopic(var/href, var/list/href_list, var/mob/user) if(href_list["toggle_show_in_directory"]) pref.show_in_directory = pref.show_in_directory ? 0 : 1; - return TOPIC_REFRESH + return PREFERENCES_REFRESH else if(href_list["directory_tag"]) var/new_tag = input(user, "Pick a new tag for the character directory", "Character Tag", pref.directory_tag) as null|anything in GLOB.char_directory_tags if(!new_tag) return pref.directory_tag = new_tag - return TOPIC_REFRESH + return PREFERENCES_REFRESH else if(href_list["directory_erptag"]) var/new_erptag = input(user, "Pick a new ERP tag for the character directory", "Character ERP Tag", pref.directory_erptag) as null|anything in GLOB.char_directory_erptags if(!new_erptag) return pref.directory_erptag = new_erptag - return TOPIC_REFRESH + return PREFERENCES_REFRESH else if(href_list["directory_ad"]) var/msg = sanitize(input(user,"Write your advertisement here!", "Flavor Text", html_decode(pref.directory_ad)) as message, extra = 0) pref.directory_ad = msg - return TOPIC_REFRESH + return PREFERENCES_REFRESH //TFF 5/8/19 - add new thing so you can choose the sensor setting your character can get. else if(href_list["toggle_sensor_setting"]) var/new_sensorpref = input(user, "Choose your character's sensor preferences:", "Character Preferences", sensorpreflist[pref.sensorpref]) as null|anything in sensorpreflist if (!isnull(new_sensorpref) && CanUseTopic(user)) pref.sensorpref = sensorpreflist.Find(new_sensorpref) - return TOPIC_REFRESH + return PREFERENCES_REFRESH return ..(); diff --git a/code/modules/client/preferences_factions.dm b/code/modules/preferences/preferences_factions.dm similarity index 100% rename from code/modules/client/preferences_factions.dm rename to code/modules/preferences/preferences_factions.dm diff --git a/code/modules/preferences/preferences_savefile.dm b/code/modules/preferences/preferences_savefile.dm new file mode 100644 index 00000000000..ae69e8930b2 --- /dev/null +++ b/code/modules/preferences/preferences_savefile.dm @@ -0,0 +1,188 @@ +/datum/preferences/proc/load_path(ckey,filename="preferences.sav") + if(!ckey) return + path = "data/player_saves/[copytext(ckey,1,2)]/[ckey]/[filename]" + savefile_version = SAVEFILE_VERSION_MAX + +/datum/preferences/proc/load_preferences() + // todo: storage handler datums... + if(!path) + return FALSE + // check DOS guard + if(world.time < loadprefcooldown) //This is done before checking if the file exists to ensure that the server can't hang on read attempts + if(istype(client)) + to_chat(client, "You're attempting to load your preferences a little too fast. Wait half a second, then try again.") + return FALSE + loadprefcooldown = world.time + PREF_SAVELOAD_COOLDOWN + // get savefile + if(!fexists(path)) + return FALSE + var/savefile/S = new /savefile(path) + if(!S) + return FALSE + // prep savefile + S.cd = "/" + // load savefile version + S["version"] >> savefile_version + // load global data so we can access it during migrations + var/list/io_errors = list() + read_global_data(S, io_errors) + // perform migrations + if(savefile_version < SAVEFILE_VERSION_MIN) + io_errors += SPAN_DANGER("Your savefile version was [savefile_version], below minimum [SAVEFILE_VERSION_MIN]; your savefile will now be deleted and recreated.") + // todo: wipe + savefile_version = SAVEFILE_VERSION_MAX + else if(savefile_version < SAVEFILE_VERSION_MAX) + perform_global_migrations(S, savefile_version, io_errors, options) + savefile_version = SAVEFILE_VERSION_MAX + // don't flush immediately incase they want to cancel/ahelp about something breaking + // save_preferences() + queue_errors(io_errors, "error while migrating global data:") + // load legacy data + player_setup.load_preferences(S) + if(initialized) + auto_flush_errors() + return TRUE + +/datum/preferences/proc/save_preferences() + // todo: storage handler datums... + if(!path) + return FALSE + // check DOS guard + if(world.time < saveprefcooldown) + if(istype(client)) + to_chat(client, "You're attempting to save your preferences a little too fast. Wait half a second, then try again.") + return FALSE + saveprefcooldown = world.time + PREF_SAVELOAD_COOLDOWN + // get saveflie + var/savefile/S = new /savefile(path) + if(!S) + return FALSE + // prep saveflie + S.cd = "/" + // save savefile version + S["version"] << savefile_version + // write global data + write_global_data(S) + // write legacy data + player_setup.save_preferences(S) + if(initialized) + auto_flush_errors() + return TRUE + +/datum/preferences/proc/load_character(slot) + // todo: storage handler datums... + if(!path) + return FALSE + // check DOS guard + if(world.time < loadcharcooldown) + if(istype(client)) + to_chat(client, "You're attempting to load your character a little too fast. Wait half a second, then try again.") + return FALSE + loadcharcooldown = world.time + PREF_SAVELOAD_COOLDOWN + // get savefile + if(!fexists(path)) + return FALSE + var/savefile/S = new /savefile(path) + if(!S) + return FALSE + // prep savefile + S.cd = "/" + + // BEGIN SLOT HANDLING + if(!slot) + slot = default_slot + if(slot != SAVE_RESET) // SAVE_RESET will reset the slot as though it does not exist, but keep the current slot for saving purposes. + slot = sanitize_integer(slot, 1, config_legacy.character_slots, initial(default_slot)) + if(slot != default_slot) + default_slot = slot + S["default_slot"] << slot + else + S["default_slot"] << default_slot + if(slot != SAVE_RESET) + S.cd = "/character[slot]" + else + S.cd = "/character[default_slot]" + // END SLOT HANDLING + + var/list/io_errors = list() + + // load character data + read_character_data(S, slot, io_errors) + // perform migrations + var/current_version = character[CHARACTER_DATA_VERSION] + if(!isnum(current_version)) + current_version = CHARACTER_VERSION_LEGACY + if(current_version < CHARACTER_VERSION_MIN) + io_errors += SPAN_DANGER("Your character version was [current_version], below minimum [CHARACTER_VERSION_MIN]; your slot will now be reset.") + // todo: wipe slot + current_version = CHARACTER_VERSION_MAX + else if(current_version < CHARACTER_VERSION_MAX) + perform_character_migrations(S, current_version, io_errors, character) + current_version = CHARACTER_VERSION_MAX + queue_errors(io_errors, "error while migrating slot [slot]:") + character[CHARACTER_DATA_VERSION] = current_version + // load legacy data + player_setup.load_character(S) + // rebuild previews + clear_character_previews() // Recalculate them on next show + if(initialized) + auto_flush_errors() + return TRUE + +/datum/preferences/proc/save_character() + // todo: storage handler datums... + if(!path) + return FALSE + // check DOS guard + if(world.time < savecharcooldown) + if(istype(client)) + to_chat(client, "You're attempting to save your character a little too fast. Wait half a second, then try again.") + return FALSE + savecharcooldown = world.time + PREF_SAVELOAD_COOLDOWN + // get saveflie + var/savefile/S = new /savefile(path) + if(!S) + return FALSE + // prep saveflie + S.cd = "/character[default_slot]" + // write character data + write_character_data(S, default_slot) + // write legacy data + player_setup.save_character(S) + if(initialized) + auto_flush_errors() + return TRUE + +/datum/preferences/proc/overwrite_character(slot) + if(!path) + return 0 + if(!fexists(path)) + return 0 + var/savefile/S = new /savefile(path) + if(!S) + return 0 + if(!slot) + slot = default_slot + if(slot != SAVE_RESET) + slot = sanitize_integer(slot, 1, config_legacy.character_slots, initial(default_slot)) + if(slot != default_slot) + default_slot = slot + S["default_slot"] << slot + else + S["default_slot"] << default_slot + if(initialized) + auto_flush_errors() + return 1 + +/datum/preferences/proc/sanitize_preferences() + player_setup.sanitize_setup() + // todo: error feedback + var/list/io_errors = list() + sanitize_everything(io_errors) + queue_errors(io_errors, "error during sanitize_preferences(); unknown call stack.") + if(initialized) + auto_flush_errors() + return 1 + +#undef SAVEFILE_VERSION_MAX +#undef SAVEFILE_VERSION_MIN diff --git a/code/modules/mob/new_player/preferences_setup.dm b/code/modules/preferences/preferences_setup.dm similarity index 81% rename from code/modules/mob/new_player/preferences_setup.dm rename to code/modules/preferences/preferences_setup.dm index ad319ac8d43..6f109733277 100644 --- a/code/modules/mob/new_player/preferences_setup.dm +++ b/code/modules/preferences/preferences_setup.dm @@ -1,11 +1,11 @@ /datum/preferences //The mob should have a gender you want before running this proc. Will run fine without H /datum/preferences/proc/randomize_appearance_and_body_for(var/mob/living/carbon/human/H) - var/datum/species/current_species = name_static_species_meta(species) || get_static_species_meta(/datum/species/human) + var/datum/species/current_species = real_species_datum() set_biological_gender(pick(current_species.genders)) - h_style = random_hair_style(biological_gender, species) - f_style = random_facial_hair_style(biological_gender, species) + h_style = random_hair_style(biological_gender, current_species.name) + f_style = random_facial_hair_style(biological_gender, current_species.name) if(current_species) if(current_species.species_appearance_flags & HAS_SKIN_TONE) s_tone = random_skin_tone() @@ -34,7 +34,7 @@ age = rand(current_species.min_age, current_species.max_age) b_type = RANDOM_BLOOD_TYPE if(H) - copy_to(H,1) + copy_to(H) /datum/preferences/proc/randomize_hair_color(var/target = "hair") @@ -194,28 +194,12 @@ b_skin = blue /datum/preferences/proc/dress_preview_mob(var/mob/living/carbon/human/mannequin) - copy_to(mannequin, TRUE) + copy_to(mannequin) if(!equip_preview_mob) return - var/datum/job/previewJob - // Determine what job is marked as 'High' priority, and dress them up as such. - if(job_civilian_low & ASSISTANT) - previewJob = SSjob.get_job(USELESS_JOB) - else - for(var/datum/job/job in SSjob.occupations) - var/job_flag - switch(job.department_flag) - if(CIVILIAN) - job_flag = job_civilian_high - if(MEDSCI) - job_flag = job_medsci_high - if(ENGSEC) - job_flag = job_engsec_high - if(job.flag == job_flag) - previewJob = job - break + var/datum/job/previewJob = SSjob.job_by_id(preview_job_id()) if((equip_preview_mob & EQUIP_PREVIEW_LOADOUT) && !(previewJob && (equip_preview_mob & EQUIP_PREVIEW_JOB) && (previewJob.type == /datum/job/station/ai || previewJob.type == /datum/job/station/cyborg))) var/list/equipped_slots = list() @@ -232,7 +216,7 @@ if(previewJob.title == job_name) permitted = 1 - if(G.whitelisted && (G.whitelisted != mannequin.species.name)) + if(G.legacy_species_lock && (G.legacy_species_lock != mannequin.species.name)) permitted = 0 if(!permitted) @@ -249,13 +233,13 @@ if((equip_preview_mob & EQUIP_PREVIEW_JOB) && previewJob) mannequin.job = previewJob.title - previewJob.equip_preview(mannequin, player_alt_titles[previewJob.title]) + previewJob.equip_preview(mannequin, get_job_alt_title_name(previewJob)) /datum/preferences/proc/update_preview_icon() var/mob/living/carbon/human/dummy/mannequin/mannequin = get_mannequin(client_ckey) mannequin.delete_inventory(TRUE) if(regen_limbs) - var/datum/species/current_species = character_static_species_meta() + var/datum/species/current_species = real_species_datum() current_species.create_organs(mannequin) regen_limbs = 0 dress_preview_mob(mannequin) @@ -270,9 +254,10 @@ /datum/preferences/proc/get_valid_hairstyles() var/list/valid_hairstyles = list() + var/species_name = real_species_name() for(var/hairstyle in hair_styles_list) var/datum/sprite_accessory/S = hair_styles_list[hairstyle] - if(S.apply_restrictions && !(species in S.species_allowed) && (!custom_base || !(custom_base in S.species_allowed))) //Custom species base species allowance + if(S.apply_restrictions && !(species_name in S.species_allowed) && (!custom_base || !(custom_base in S.species_allowed))) //Custom species base species allowance continue valid_hairstyles[hairstyle] = hair_styles_list[hairstyle] @@ -281,15 +266,33 @@ /datum/preferences/proc/get_valid_facialhairstyles() var/list/valid_facialhairstyles = list() + var/datum/species/RS = real_species_datum() for(var/facialhairstyle in facial_hair_styles_list) var/datum/sprite_accessory/S = facial_hair_styles_list[facialhairstyle] if(biological_gender == MALE && S.gender == FEMALE) continue if(biological_gender == FEMALE && S.gender == MALE) continue - if(S.apply_restrictions && !(species in S.species_allowed) && (!custom_base || !(custom_base in S.species_allowed))) //Custom species base species allowance + if(S.apply_restrictions && !(RS.name in S.species_allowed) && (!custom_base || !(custom_base in S.species_allowed))) //Custom species base species allowance continue valid_facialhairstyles[facialhairstyle] = facial_hair_styles_list[facialhairstyle] return valid_facialhairstyles + +/datum/preferences/update_preview_icon() // Lines up and un-overlaps character edit previews. Also un-splits taurs. + var/mob/living/carbon/human/dummy/mannequin/mannequin = get_mannequin(client_ckey) + if(!mannequin.dna) // Special handling for preview icons before SSAtoms has initailized. + mannequin.dna = new /datum/dna(null) + mannequin.delete_inventory(TRUE) + if(regen_limbs) + var/datum/species/current_species = real_species_datum() + current_species.create_organs(mannequin) + regen_limbs = 0 + dress_preview_mob(mannequin) + mannequin.update_transform() + mannequin.toggle_tail_vr(setting = TRUE) + mannequin.toggle_wing_vr(setting = TRUE) + COMPILE_OVERLAYS(mannequin) + update_character_previews(new /mutable_appearance(mannequin)) + diff --git a/code/modules/client/preferences_spawnpoints.dm b/code/modules/preferences/preferences_spawnpoints.dm similarity index 93% rename from code/modules/client/preferences_spawnpoints.dm rename to code/modules/preferences/preferences_spawnpoints.dm index 2c6020bdac8..746d5fda39d 100644 --- a/code/modules/client/preferences_spawnpoints.dm +++ b/code/modules/preferences/preferences_spawnpoints.dm @@ -25,7 +25,7 @@ var/list/datum/spawnpoint/spawntypes = list() return 1 /datum/spawnpoint/proc/get_spawn_position(faction) - return SSjob.GetLatejoinSpawnpoint(faction = faction, method = method) + return SSjob.get_latejoin_spawnpoint(faction = faction, method = method) /datum/spawnpoint/arrivals display_name = "Arrivals Shuttle" diff --git a/code/modules/client/preferences_toggle_procs.dm b/code/modules/preferences/preferences_toggle_procs.dm similarity index 92% rename from code/modules/client/preferences_toggle_procs.dm rename to code/modules/preferences/preferences_toggle_procs.dm index 89a950058ac..145e5487889 100644 --- a/code/modules/client/preferences_toggle_procs.dm +++ b/code/modules/preferences/preferences_toggle_procs.dm @@ -10,7 +10,7 @@ to_chat(src,"You will [ (is_preference_enabled(pref_path)) ? "now" : "no longer"] hear all mob speech as a ghost.") - SScharacter_setup.queue_preferences_save(prefs) + SScharacters.queue_preferences_save(prefs) feedback_add_details("admin_verb","TGEars") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! @@ -25,7 +25,7 @@ to_chat(src,"You will [ (is_preference_enabled(pref_path)) ? "now" : "no longer"] see all emotes as a ghost.") - SScharacter_setup.queue_preferences_save(prefs) + SScharacters.queue_preferences_save(prefs) feedback_add_details("admin_verb","TGVision") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! @@ -40,7 +40,7 @@ to_chat(src,"You will [ (is_preference_enabled(pref_path)) ? "now" : "no longer"] hear all radios as a ghost.") - SScharacter_setup.queue_preferences_save(prefs) + SScharacters.queue_preferences_save(prefs) feedback_add_details("admin_verb","TGRadio") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! @@ -55,7 +55,7 @@ to_chat(src,"You will [ (is_preference_enabled(pref_path)) ? "now" : "no longer"] hear dead chat as a ghost.") - SScharacter_setup.queue_preferences_save(prefs) + SScharacters.queue_preferences_save(prefs) feedback_add_details("admin_verb","TDeadChat") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! @@ -70,7 +70,7 @@ to_chat(src,"You will [ (is_preference_enabled(/datum/client_preference/show_ooc)) ? "now" : "no longer"] hear global out of character chat.") - SScharacter_setup.queue_preferences_save(prefs) + SScharacters.queue_preferences_save(prefs) feedback_add_details("admin_verb","TOOC") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! @@ -85,7 +85,7 @@ to_chat(src,"You will [ (is_preference_enabled(pref_path)) ? "now" : "no longer"] hear local out of character chat.") - SScharacter_setup.queue_preferences_save(prefs) + SScharacters.queue_preferences_save(prefs) feedback_add_details("admin_verb","TLOOC") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! @@ -100,7 +100,7 @@ to_chat(src,"You will [ (is_preference_enabled(pref_path)) ? "now" : "no longer"] have the speech indicator.") - SScharacter_setup.queue_preferences_save(prefs) + SScharacters.queue_preferences_save(prefs) feedback_add_details("admin_verb","TTIND") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! @@ -115,7 +115,7 @@ to_chat(src,"You will [ (is_preference_enabled(pref_path)) ? "now" : "no longer"] receive noise from admin messages.") - SScharacter_setup.queue_preferences_save(prefs) + SScharacters.queue_preferences_save(prefs) feedback_add_details("admin_verb","TAHelp") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! @@ -130,7 +130,7 @@ to_chat(src,"You will [ (is_preference_enabled(pref_path)) ? "now" : "no longer"] hear music in the lobby.") - SScharacter_setup.queue_preferences_save(prefs) + SScharacters.queue_preferences_save(prefs) feedback_add_details("admin_verb","TLobMusic") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! @@ -145,7 +145,7 @@ to_chat(src,"You will [ (is_preference_enabled(pref_path)) ? "now" : "no longer"] hear MIDIs from admins.") - SScharacter_setup.queue_preferences_save(prefs) + SScharacters.queue_preferences_save(prefs) feedback_add_details("admin_verb","TAMidis") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! @@ -160,7 +160,7 @@ to_chat(src,"You will [ (is_preference_enabled(pref_path)) ? "now" : "no longer"] hear ambient noise.") - SScharacter_setup.queue_preferences_save(prefs) + SScharacters.queue_preferences_save(prefs) feedback_add_details("admin_verb","TAmbience") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! @@ -175,7 +175,7 @@ to_chat(src,"You will [ (is_preference_enabled(pref_path)) ? "now" : "no longer"] hear weather sounds.") - SScharacter_setup.queue_preferences_save(prefs) + SScharacters.queue_preferences_save(prefs) feedback_add_details("admin_verb","TWeatherSounds") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! @@ -190,7 +190,7 @@ to_chat(src,"You will [ (is_preference_enabled(pref_path)) ? "now" : "no longer"] hear a hum from the supermatter.") - SScharacter_setup.queue_preferences_save(prefs) + SScharacters.queue_preferences_save(prefs) feedback_add_details("admin_verb","TSupermatterHum") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! @@ -205,7 +205,7 @@ to_chat(src, "You will [ (is_preference_enabled(pref_path)) ? "now" : "no longer"] hear jukebox music.") - SScharacter_setup.queue_preferences_save(prefs) + SScharacters.queue_preferences_save(prefs) feedback_add_details("admin_verb","TJukebox") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! @@ -218,7 +218,7 @@ if(!role_flag) return prefs.be_special ^= role_flag - SScharacter_setup.queue_preferences_save(prefs) + SScharacters.queue_preferences_save(prefs) to_chat(src,"You will [(prefs.be_special & role_flag) ? "now" : "no longer"] be considered for [role] events (where possible).") @@ -235,7 +235,7 @@ to_chat(src, "You will [ (is_preference_enabled(pref_path)) ? "now" : "no longer"] hear air pumps hum, start, and stop.") - SScharacter_setup.queue_preferences_save(prefs) + SScharacters.queue_preferences_save(prefs) feedback_add_details("admin_verb","TAirPumpNoise") @@ -250,7 +250,7 @@ to_chat(src, "You will [ (is_preference_enabled(pref_path)) ? "now" : "no longer"] hear sounds when items are picked up or thrown.") - SScharacter_setup.queue_preferences_save(prefs) + SScharacters.queue_preferences_save(prefs) feedback_add_details("admin_verb", "TPickupSounds") @@ -261,7 +261,7 @@ var/pref_path = /datum/client_preference/mob_tooltips toggle_preference(pref_path) - SScharacter_setup.queue_preferences_save(prefs) + SScharacters.queue_preferences_save(prefs) to_chat(src,"You will now [(is_preference_enabled(/datum/client_preference/mob_tooltips)) ? "see" : "not see"] mob tooltips.") @@ -274,7 +274,7 @@ var/pref_path = /datum/client_preference/instrument_toggle toggle_preference(pref_path) - SScharacter_setup.queue_preferences_save(prefs) + SScharacters.queue_preferences_save(prefs) to_chat(src, "You will [(is_preference_enabled(/datum/client_preference/instrument_toggle)) ? "now hear" : "no longer hear"] instruments being played.") @@ -287,7 +287,7 @@ var/pref_path = /datum/client_preference/status_indicators toggle_preference(pref_path) - SScharacter_setup.queue_preferences_save(prefs) + SScharacters.queue_preferences_save(prefs) to_chat(src, "You will now [(is_preference_enabled(/datum/client_preference/status_indicators)) ? "see" : "not see"] status indicators.") @@ -300,7 +300,7 @@ var/pref_path = /datum/client_preference/overhead_chat toggle_preference(pref_path) - SScharacter_setup.queue_preferences_save(prefs) + SScharacters.queue_preferences_save(prefs) to_chat(src, "You will now [(is_preference_enabled(/datum/client_preference/overhead_chat)) ? "see" : "not see"] overhead chat messages..") @@ -313,7 +313,7 @@ var/pref_path = /datum/client_preference/scaling_viewport toggle_preference(pref_path) - SScharacter_setup.queue_preferences_save(prefs) + SScharacters.queue_preferences_save(prefs) to_chat(src, "You will now [(is_preference_enabled(/datum/client_preference/scaling_viewport)) ? "see" : "not see"] more...") is_preference_enabled(/datum/client_preference/scaling_viewport) ? OnResize() : change_view(world.view) @@ -332,7 +332,7 @@ if(check_rights(R_ADMIN|R_DEBUG)) toggle_preference(pref_path) to_chat(src,"You will [ (is_preference_enabled(pref_path)) ? "now" : "no longer"] receive debug logs.") - SScharacter_setup.queue_preferences_save(prefs) + SScharacters.queue_preferences_save(prefs) feedback_add_details("admin_verb","TBeSpecial") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! @@ -347,7 +347,7 @@ if(check_rights(R_ADMIN|R_MOD)) toggle_preference(pref_path) to_chat(src,"You will [ (is_preference_enabled(pref_path)) ? "now" : "no longer"] receive attack logs.") - SScharacter_setup.queue_preferences_save(prefs) + SScharacters.queue_preferences_save(prefs) feedback_add_details("admin_verb","TBeSpecial") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! @@ -363,7 +363,7 @@ to_chat(src,"You will [ (is_preference_enabled(pref_path)) ? "now" : "no longer"] be prompted to verify age.") - SScharacter_setup.queue_preferences_save(prefs) + SScharacters.queue_preferences_save(prefs) feedback_add_details("admin_verb","TAgeVerify") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! diff --git a/code/modules/preferences/shims.dm b/code/modules/preferences/shims.dm new file mode 100644 index 00000000000..61e0fbb18e1 --- /dev/null +++ b/code/modules/preferences/shims.dm @@ -0,0 +1,12 @@ +/datum/preferences + var/list/datum/category_item/player_setup_item/preference_datums = list() + var/list/preference_by_key = list() + var/list/preference_by_type = list() + +/datum/preferences/proc/preference_by_save_key(key) + RETURN_TYPE(/datum/category_item/player_setup_item) + return preference_by_key[key] + +/datum/preferences/proc/preference_by_type(type) + RETURN_TYPE(/datum/category_item/player_setup_item) + return preference_by_type[type] diff --git a/code/modules/preferences/ui.dm b/code/modules/preferences/ui.dm new file mode 100644 index 00000000000..82c4ec029ec --- /dev/null +++ b/code/modules/preferences/ui.dm @@ -0,0 +1,50 @@ +/datum/preferences/proc/refresh(mob/user, update_previews) + if(update_previews) + update_preview_icon() + ShowChoices(user) + +/datum/preferences/proc/show(mob/user) + ShowChoices(user) + +/datum/preferences/proc/ShowChoices(mob/user) + if(!user || !user.client) + return + + if(!initialized) + to_chat(user, SPAN_WARNING("Preferences not initialized; please wait!")) + return + + if(!get_mob_by_key(client_ckey)) + to_chat(user, "No mob exists for the given client!") + close_load_dialog(user) + return + + if(!char_render_holders) + update_preview_icon() + show_character_previews() + + var/dat = "
" + + if(path) + dat += "Slot - " + dat += "Load slot - " + dat += "Save slot - " + dat += "Reload slot - " + dat += "Reset slot - " + dat += "Copy slot" + + else + dat += "Please create an account to save your preferences." + + dat += "
" + dat += player_setup.header() + dat += "

" + dat += player_setup.content(user) + + dat += "" + //user << browse(dat, "window=preferences;size=635x736") + winshow(user, "preferences_window", TRUE) + var/datum/browser/popup = new(user, "preferences_browser", "Character Setup", 800, 800) + popup.set_content(dat) + popup.open(FALSE) // Skip registring onclose on the browser pane + onclose(user, "preferences_window", src) // We want to register on the window itself diff --git a/code/modules/projectiles/projectile/change.dm b/code/modules/projectiles/projectile/change.dm index ddfe50cd15f..e8176a3a4cd 100644 --- a/code/modules/projectiles/projectile/change.dm +++ b/code/modules/projectiles/projectile/change.dm @@ -28,7 +28,7 @@ var/mob/living/new_mob var/options = list("robot", "slime") - for(var/t in all_species_names()) + for(var/t in SScharacters.all_species_names()) options += t if(ishuman(M)) var/mob/living/carbon/human/H = M @@ -73,7 +73,7 @@ H.name += " [pick(GLOB.last_names)]" H.real_name = H.name - H.set_species(species_type_by_name(randomize)) + H.set_species(randomize) H.universal_speak = 1 var/datum/preferences/A = new() //Randomize appearance for the human A.randomize_appearance_and_body_for(H) diff --git a/code/modules/projectiles/projectile/hook.dm b/code/modules/projectiles/projectile/hook.dm index abd7d5d8c67..bb82c84a8f3 100644 --- a/code/modules/projectiles/projectile/hook.dm +++ b/code/modules/projectiles/projectile/hook.dm @@ -79,7 +79,7 @@ visible_message("[H]'s [W] goes off due to \the [src]!") return W.afterattack(target,H) - if(!(H.species.flags & NO_SLIP) && prob(50)) + if(!(H.species.species_flags & NO_SLIP) && prob(50)) var/armor_check = H.run_armor_check(def_zone, "melee") H.apply_effect(3, WEAKEN, armor_check) playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) diff --git a/code/modules/projectiles/projectile/special.dm b/code/modules/projectiles/projectile/special.dm index 3cce5ddee46..0a1327cc448 100644 --- a/code/modules/projectiles/projectile/special.dm +++ b/code/modules/projectiles/projectile/special.dm @@ -137,7 +137,7 @@ var/mob/living/M = target if(ishuman(target)) var/mob/living/carbon/human/H = M - if((H.species.flags & IS_PLANT) && (M.nutrition < 500)) + if((H.species.species_flags & IS_PLANT) && (M.nutrition < 500)) if(prob(15)) M.apply_effect((rand(30,80)),IRRADIATE) M.Weaken(5) @@ -191,7 +191,7 @@ var/mob/M = target if(ishuman(target)) //These rays make plantmen fat. var/mob/living/carbon/human/H = M - if((H.species.flags & IS_PLANT) && (M.nutrition < 500)) + if((H.species.species_flags & IS_PLANT) && (M.nutrition < 500)) M.nutrition += 30 else if (istype(target, /mob/living/carbon/)) M.show_message("The radiation beam dissipates harmlessly through your body.") diff --git a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Toxins.dm b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Toxins.dm index 66d464f645c..24968dc6de3 100644 --- a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Toxins.dm +++ b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Toxins.dm @@ -621,7 +621,7 @@ H.b_hair = max(0, min(255, H.b_hair + color_shift)) if(H.b_facial) H.b_facial = max(0, min(255, H.b_facial + color_shift)) - if(H.species.flags & NO_SCAN) + if(H.species.species_flags & NO_SCAN) return //The original coder comment here wanted it to be "Approx. one mutation per 10 injected/20 ingested/30 touching units" @@ -1034,7 +1034,7 @@ return var/mob/living/carbon/human/H = M - if(istype(H) && (H.species.flags & NO_SCAN)) + if(istype(H) && (H.species.species_flags & NO_SCAN)) return if(M.dna) @@ -1064,7 +1064,7 @@ return var/mob/living/carbon/human/H = M - if(istype(H) && (H.species.flags & NO_SCAN)) + if(istype(H) && (H.species.species_flags & NO_SCAN)) return if(M.dna) diff --git a/code/modules/recycling/disposal.dm b/code/modules/recycling/disposal.dm index f6b2cf1dbf9..3bd525d49f7 100644 --- a/code/modules/recycling/disposal.dm +++ b/code/modules/recycling/disposal.dm @@ -1443,16 +1443,11 @@ var/turf/target // this will be where the output objects are 'thrown' to. var/mode = 0 -/obj/structure/disposaloutlet/New() - ..() - - spawn(1) - target = get_ranged_target_turf(src, dir, 10) - - - var/obj/structure/disposalpipe/trunk/trunk = locate() in src.loc - if(trunk) - trunk.linked = src // link the pipe trunk to self +/obj/structure/disposaloutlet/LateInitialize() + target = get_ranged_target_turf(src, dir, 10) + var/obj/structure/disposalpipe/trunk/trunk = locate() in loc + if(trunk) + trunk.linked = src // link the pipe trunk to self // expel the contents of the holder object, then delete it // called when the holder exits the outlet diff --git a/code/modules/research/prosfab_designs.dm b/code/modules/research/prosfab_designs.dm index 9f9adef5f48..9a4eccbaf57 100644 --- a/code/modules/research/prosfab_designs.dm +++ b/code/modules/research/prosfab_designs.dm @@ -21,11 +21,11 @@ manf = manf.species_alternates[prosfab.species] if(!prosfab.species || (prosfab.species in manf.species_cannot_use)) // Fabricator ensures the manufacturer can make parts for the species we're set to. - O.species = name_static_species_meta(manf.suggested_species) + O.species = SScharacters.resolve_species_name(manf.suggested_species) else - O.species = name_static_species_meta(prosfab.species) + O.species = SScharacters.resolve_species_name(prosfab.species) else - O.species = get_static_species_meta(/datum/species/human) + O.species = SScharacters.resolve_species_path(/datum/species/human) O.robotize(prosfab.manufacturer) O.dna = new/datum/dna() //Uuughhhh... why do I have to do this? O.dna.ResetUI() @@ -62,7 +62,7 @@ EO.remove_rejuv() for(var/obj/item/organ/external/O in H.organs) - O.species = name_static_species_meta(newspecies) + O.species = SScharacters.resolve_species_name(newspecies) if(!(O.organ_tag in manf.parts)) // Make sure we're using an actually present icon. manf = GLOB.all_robolimbs["Unbranded"] diff --git a/code/modules/resleeving/designer.dm b/code/modules/resleeving/designer.dm index 6a645403726..845e8367b7c 100644 --- a/code/modules/resleeving/designer.dm +++ b/code/modules/resleeving/designer.dm @@ -1,6 +1,12 @@ // Little define makes it cleaner to read the tripple color values out of mobs. #define MOB_HEX_COLOR(M, V) "#[num2hex(M.r_##V, 2)][num2hex(M.g_##V, 2)][num2hex(M.b_##V, 2)]" +// todo: this entire file is no longer maintained and probably doesn't work +// it's a shame but frankly all of this is shitcode and therefore there's no point +// in maintaining it ~silicons + +// if you want in game bodymodding, please, talk with us so we can make a new system together. + /obj/machinery/computer/transhuman/designer name = "body design console" catalogue_data = list(///datum/category_item/catalogue/information/organization/vey_med, @@ -67,8 +73,8 @@ if(menu == "3") var/stock_bodyrecords_list_ui[0] - for (var/datum/species/S in all_static_species_meta()) - if((S.spawn_flags & (SPECIES_IS_WHITELISTED|SPECIES_CAN_JOIN)) != SPECIES_CAN_JOIN) + for (var/datum/species/S in SScharacters.all_static_species_meta()) + if((S.species_spawn_flags & (SPECIES_SPAWN_WHITELISTED|SPECIES_SPAWN_ALLOWED)) != SPECIES_SPAWN_ALLOWED) continue stock_bodyrecords_list_ui += S if(stock_bodyrecords_list_ui.len) @@ -171,8 +177,8 @@ temp = "ERROR: Record missing." else if(href_list["view_stock_brec"]) - var/datum/species/S = name_static_species_meta(href_list["view_stock_brec"]) - if(S && (S.spawn_flags & (SPECIES_IS_WHITELISTED|SPECIES_CAN_JOIN)) == SPECIES_CAN_JOIN) + var/datum/species/S = SScharacters.resolve_species_name(href_list["view_stock_brec"]) + if(S && (S.species_spawn_flags & (SPECIES_SPAWN_WHITELISTED|SPECIES_SPAWN_ALLOWED)) == SPECIES_SPAWN_ALLOWED) // Generate body record from species! mannequin = new(null, S.name) mannequin.real_name = "Stock [S.name] Body" @@ -250,7 +256,7 @@ //log_debug("designer.update_preview_mob([H]) active_br = \ref[active_br]") //Get the DNA and generate a new mob var/datum/dna2/record/R = active_br.mydna - H.set_species(species_type_by_name(R.dna.species)) // This needs to happen before anything else becuase it sets some variables. + H.set_species(R.dna.species) // This needs to happen before anything else becuase it sets some variables. // Update the external organs for(var/part in active_br.limb_data) @@ -320,7 +326,7 @@ var/datum/preferences/designer/P = new() // We did DNA to mob, now mob to prefs! - P.species = mannequin.species.name + P.set_character_data(CHARACTER_DATA_REAL_SPECIES, mannequin.species.id) apply_coloration_to_prefs(mannequin, P) apply_organs_to_prefs(mannequin, P) apply_markings_to_prefs(mannequin, P) @@ -347,13 +353,13 @@ var/action = 0 action = B.OnTopic(href, href_list, user) - if(action & TOPIC_UPDATE_PREVIEW && mannequin && active_br) + if(action & PREFERENCES_UPDATE_PREVIEW && mannequin && active_br) B.copy_to_mob(mannequin) active_br.mydna.dna.ResetUIFrom(mannequin) preview_icon = null return 1 action = E.OnTopic(href, href_list, user) - if(action & TOPIC_UPDATE_PREVIEW && mannequin && active_br) + if(action & PREFERENCES_UPDATE_PREVIEW && mannequin && active_br) E.copy_to_mob(mannequin) active_br.mydna.dna.ResetUIFrom(mannequin) preview_icon = null diff --git a/code/modules/resleeving/infocore_records.dm b/code/modules/resleeving/infocore_records.dm index 9d871aaf667..059c1e89898 100644 --- a/code/modules/resleeving/infocore_records.dm +++ b/code/modules/resleeving/infocore_records.dm @@ -109,9 +109,9 @@ locked = ckeylock //Prevent people from printing restricted and whitelisted species - var/datum/species/S = name_static_species_meta(M.dna.species) + var/datum/species/S = SScharacters.resolve_species_name(M.dna.species) if(S) - toocomplex = (S.spawn_flags & SPECIES_IS_WHITELISTED) || (S.spawn_flags & SPECIES_IS_RESTRICTED) + toocomplex = (S.species_spawn_flags & SPECIES_SPAWN_WHITELISTED) || (S.species_spawn_flags & SPECIES_SPAWN_RESTRICTED) //General stuff about them synthetic = M.isSynthetic() diff --git a/code/modules/resleeving/infomorph_software.dm b/code/modules/resleeving/infomorph_software.dm index 060810522da..19a0bfcf48c 100644 --- a/code/modules/resleeving/infomorph_software.dm +++ b/code/modules/resleeving/infomorph_software.dm @@ -203,7 +203,7 @@ /mob/living/silicon/infomorph/proc/hackloop() var/turf/T = get_turf(src) if(prob(20)) - for(var/mob/living/silicon/ai/AI in player_list) + for(var/mob/living/silicon/ai/AI in GLOB.player_list) if(T.loc) to_chat(AI, "Network Alert: Brute-force encryption crack in progress in [T.loc].") else diff --git a/code/modules/resleeving/machines.dm b/code/modules/resleeving/machines.dm index 72e5dd4a572..882a49eb707 100644 --- a/code/modules/resleeving/machines.dm +++ b/code/modules/resleeving/machines.dm @@ -32,7 +32,7 @@ //Get the DNA and generate a new mob var/datum/dna2/record/R = current_project.mydna var/mob/living/carbon/human/H = new /mob/living/carbon/human(src) - H.set_species(species_type_by_name(R.dna.species)) + H.set_species(R.dna.species) H.dna.base_species = R.dna.base_species //! Hacky way to get the DNA to work. if(current_project.locked) H.resleeve_lock = current_project.ckey diff --git a/code/modules/security levels/security levels.dm b/code/modules/security levels/security levels.dm index 2374d7da3ae..0c2a3c52295 100644 --- a/code/modules/security levels/security levels.dm +++ b/code/modules/security levels/security levels.dm @@ -1,4 +1,4 @@ -/var/security_level = 0 +GLOBAL_VAR_INIT(security_level, SEC_LEVEL_GREEN) //0 = code green //1 = code blue //2 = code yellow @@ -29,44 +29,44 @@ level = SEC_LEVEL_DELTA //Will not be announced if you try to set to the same level as it already is. Also To-Do. Add multi sound support for alerts.. - if(level >= SEC_LEVEL_GREEN && level <= SEC_LEVEL_DELTA && level != security_level) + if(level >= SEC_LEVEL_GREEN && level <= SEC_LEVEL_DELTA && level != GLOB.security_level) switch(level) if(SEC_LEVEL_GREEN) security_announcement_down.Announce("[CONFIG_GET(string/alert_desc_green)]", "Attention! Alert level lowered to code green.") - security_level = SEC_LEVEL_GREEN + GLOB.security_level = SEC_LEVEL_GREEN if(SEC_LEVEL_BLUE) - if(security_level < SEC_LEVEL_BLUE) + if(GLOB.security_level < SEC_LEVEL_BLUE) security_announcement_up.Announce("[CONFIG_GET(string/alert_desc_blue_upto)]", "Attention! Alert level elevated to blue", new_sound = 'sound/misc/voybluealert.ogg') else security_announcement_down.Announce("[CONFIG_GET(string/alert_desc_blue_downto)]", "Attention! Alert level lowered to blue", new_sound = 'sound/misc/voybluealert.ogg') - security_level = SEC_LEVEL_BLUE + GLOB.security_level = SEC_LEVEL_BLUE if(SEC_LEVEL_YELLOW) - if(security_level < SEC_LEVEL_YELLOW) + if(GLOB.security_level < SEC_LEVEL_YELLOW) security_announcement_up.Announce("[CONFIG_GET(string/alert_desc_yellow_upto)]", "Attention! Alert level elevated to yellow") else security_announcement_down.Announce("[CONFIG_GET(string/alert_desc_yellow_downto)]", "Attention! Alert level lowered to yellow") - security_level = SEC_LEVEL_YELLOW + GLOB.security_level = SEC_LEVEL_YELLOW if(SEC_LEVEL_VIOLET) - if(security_level < SEC_LEVEL_VIOLET) + if(GLOB.security_level < SEC_LEVEL_VIOLET) security_announcement_up.Announce("[CONFIG_GET(string/alert_desc_violet_upto)]", "Attention! Alert level elevated to violet") else security_announcement_down.Announce("[CONFIG_GET(string/alert_desc_violet_downto)]", "Attention! Alert level lowered to violet") - security_level = SEC_LEVEL_VIOLET + GLOB.security_level = SEC_LEVEL_VIOLET if(SEC_LEVEL_ORANGE) - if(security_level < SEC_LEVEL_ORANGE) + if(GLOB.security_level < SEC_LEVEL_ORANGE) security_announcement_up.Announce("[CONFIG_GET(string/alert_desc_orange_upto)]", "Attention! Alert level elevated to orange") else security_announcement_down.Announce("[CONFIG_GET(string/alert_desc_orange_downto)]", "Attention! Alert level lowered to orange") - security_level = SEC_LEVEL_ORANGE + GLOB.security_level = SEC_LEVEL_ORANGE if(SEC_LEVEL_RED) - if(security_level < SEC_LEVEL_RED) + if(GLOB.security_level < SEC_LEVEL_RED) security_announcement_up.Announce("[CONFIG_GET(string/alert_desc_red_upto)]", "Attention! Code red!", new_sound = 'sound/effects/alert_levels/red_alert.ogg') else security_announcement_down.Announce("[CONFIG_GET(string/alert_desc_red_downto)]", "Attention! Code red!", new_sound = 'sound/misc/voyalert.ogg') - security_level = SEC_LEVEL_RED + GLOB.security_level = SEC_LEVEL_RED if(SEC_LEVEL_DELTA) security_announcement_up.Announce("[CONFIG_GET(string/alert_desc_delta)]", "Attention! Delta alert level reached!", new_sound = 'sound/effects/alert_levels/deltaklaxon.ogg') - security_level = SEC_LEVEL_DELTA + GLOB.security_level = SEC_LEVEL_DELTA var/newlevel = get_security_level() for(var/obj/machinery/firealarm/FA in GLOB.machines) @@ -88,7 +88,7 @@ admin_chat_message(message = "Security level is now: [uppertext(get_security_level())]", color = "#CC2222") /proc/get_security_level() - switch(security_level) + switch(GLOB.security_level) if(SEC_LEVEL_GREEN) return "green" if(SEC_LEVEL_BLUE) diff --git a/code/modules/shuttles/shuttle.dm b/code/modules/shuttles/shuttle.dm index 1acb4c36c7a..dc37939e6f7 100644 --- a/code/modules/shuttles/shuttle.dm +++ b/code/modules/shuttles/shuttle.dm @@ -158,7 +158,7 @@ // TODO - Far Future - Would be great if this was driven by process too. /datum/shuttle/proc/long_jump(var/obj/effect/shuttle_landmark/destination, var/obj/effect/shuttle_landmark/interim, var/travel_time) - //to_world("shuttle/long_jump: current_location=[current_location], destination=[destination], interim=[interim], travel_time=[travel_time]") + //TO_WORLD("shuttle/long_jump: current_location=[current_location], destination=[destination], interim=[interim], travel_time=[travel_time]") if(moving_status != SHUTTLE_IDLE) return diff --git a/code/modules/shuttles/shuttle_autodock.dm b/code/modules/shuttles/shuttle_autodock.dm index 03ce5662f49..7ed0ab219b8 100644 --- a/code/modules/shuttles/shuttle_autodock.dm +++ b/code/modules/shuttles/shuttle_autodock.dm @@ -70,7 +70,7 @@ current_dock_target = docking_controller_tag shuttle_docking_controller = SSshuttle.docking_registry[current_dock_target] if(current_dock_target && !shuttle_docking_controller) - to_world("warning: shuttle [src] can't find its controller with tag [current_dock_target]!") + TO_WORLD("warning: shuttle [src] can't find its controller with tag [current_dock_target]!") /* Docking stuff */ diff --git a/code/modules/species/character_species.dm b/code/modules/species/character_species.dm new file mode 100644 index 00000000000..387e64953dd --- /dev/null +++ b/code/modules/species/character_species.dm @@ -0,0 +1,160 @@ +/datum/species/proc/construct_character_species() + var/datum/character_species/template = new + // copy basics + template.name = display_name || name + template.uid = uid + if(id != uid) + template.is_subspecies = TRUE + template.superspecies_id = id + template.category = category + template.desc = blurb + template.whitelisted = !!(species_spawn_flags & SPECIES_SPAWN_WHITELISTED) + template.real_species_type = type + template.genders = genders.Copy() + template.min_age = min_age + template.max_age = max_age + template.our_bodytype = default_bodytype + // copy mechanics + template.species_flags = species_flags + // copy appearance + template.species_appearance_flags = species_appearance_flags + // copy lore/culture + template.default_origin = default_origin + template.default_citizenship = default_citizenship + template.default_faction = default_faction + template.default_religion = default_religion + template.species_fluff_flags = species_fluff_flags + // copy language + template.default_language = default_language + template.name_language = name_language + template.max_additional_languages = max_additional_languages + template.whitelist_languages = islist(whitelist_languages)? whitelist_languages.Copy() : whitelist_languages + template.intrinsic_languages = islist(intrinsic_languages)? intrinsic_languages.Copy() : intrinsic_languages + template.galactic_language = galactic_language + return template + +/** + * since we're a server of snowflakes, we have this to embody character species + * + * they store real species UID so we can change species, and allow us to tweak the species on spawn. + * + * /datum/character_species is a singleton type stored on SScharacters. + */ +/datum/character_species + //! Intrinsics + /// abstract type (i'm addicted to abstract types) + var/abstract_type = /datum/character_species + /// uid (this must be unique with both species and minor species, don't be outrageous with it, don't be stupid) + var/uid + /// master species id + var/superspecies_id + /// is subspecies of master species + var/is_subspecies = FALSE + /// name (ALSO SETS THE PERSON'S CUSTOM RACE NAME!) + var/name + /// category + var/category = "Minor Races" + /// desc (lore fluff) + var/desc + /// are we an actual species as opposed to a demoted species? **DO NOT TOUCH THIS VAR.** + var/is_real = FALSE + /// is whitelisted (do someone need to be on alienwhitelist) + var/whitelisted = FALSE + /// real species type + var/real_species_type = /datum/species/custom + /// species fluff flags - read species_flags.dm in __DEFINES + var/species_fluff_flags = NONE + /// species appearance flags - read species_flags.dm in __DEFINES + var/species_appearance_flags = NONE + /// species main flags - read species_flags.dm in __DEFINES + var/species_flags = NONE + /// allowed genders + var/list/genders = list(MALE, FEMALE) + /// minimum age + var/min_age = 18 + /// maximum age + var/max_age = 90 + + //! Defaults to set for visuals + /// default ear path + var/ear_style_default + /// default tail path + var/tail_style_default + /// default wing path + var/wing_style_default + /// set species bodytype to this + var/our_bodytype = BODYTYPE_DEFAULT + + //! Defaults to set for background - typepaths allowed + /// default origin + var/default_origin = /datum/lore/character_background/origin/custom + /// default citizenship + var/default_citizenship = /datum/lore/character_background/citizenship/custom + /// default faction + var/default_faction = /datum/lore/character_background/faction/nanotrasen + /// default religion + var/default_religion = /datum/lore/character_background/religion/custom + + //! Languages - IDs only, as typepaths are too expensive to resolve + /// has galactic common? you better not disable this unless you know what you're doing + var/galactic_language = TRUE + /// additional languages we always have, regardless of background - list or ID + var/list/intrinsic_languages + /// name language is from for randomgen - id - null to use vanilla ss13 randomgen + var/name_language + /// languages we are always allowed to learn, even if restricted (obviously overridden by intrinsic languages) - list or ID + var/list/whitelist_languages + /// additional anguages we can learn (ontop of any we get from us, and from culture datums) + var/max_additional_languages = 3 + /// default language when talking; this should probably be part of intrinsics! + var/default_language = LANGUAGE_ID_COMMON + +/datum/character_species/proc/tweak(datum/species/S) + // we need this + S.default_bodytype = our_bodytype + // while we technically don't *need* this, we want this incase someone starts reading from these fields mid game + // for non customization purposes later. + S.galactic_language = galactic_language + S.intrinsic_languages = get_intrinsic_language_ids() // forces it to be a list + S.name_language = name_language + S.whitelist_languages = get_whitelisted_language_ids() // forces it to a list + S.max_additional_languages = max_additional_languages + S.default_language = default_language + +/datum/character_species/proc/get_default_origin_id() + return SScharacters.resolve_origin(default_origin).id + +/datum/character_species/proc/get_default_citizenship_id() + return SScharacters.resolve_citizenship(default_citizenship).id + +/datum/character_species/proc/get_default_faction_id() + return SScharacters.resolve_faction(default_faction).id + +/datum/character_species/proc/get_default_religion_id() + return SScharacters.resolve_religion(default_religion).id + +/datum/character_species/proc/get_intrinsic_language_ids() + RETURN_TYPE(/list) + . = intrinsic_languages? (islist(intrinsic_languages)? intrinsic_languages.Copy() : list(intrinsic_languages)) : list() + if(galactic_language) + . |= LANGUAGE_ID_COMMON + +/datum/character_species/proc/get_name_language_id() + return name_language + +/datum/character_species/proc/get_max_additional_languages() + return max_additional_languages + +/datum/character_species/proc/get_whitelisted_language_ids() + RETURN_TYPE(/list) + return whitelist_languages? (islist(whitelist_languages)? whitelist_languages.Copy() : list(whitelist_languages)) : list() + +/datum/character_species/proc/get_default_language_id() + return default_language + +/datum/character_species/proc/real_species_uid() + var/datum/species/S = SScharacters.resolve_species_path(real_species_type) + return S.uid + +//! LORE PEOPLE, SHOVE YOUR SNOWFLAKE HERE + diff --git a/code/modules/species/lookup.dm b/code/modules/species/lookup.dm deleted file mode 100644 index 08962e5e9aa..00000000000 --- a/code/modules/species/lookup.dm +++ /dev/null @@ -1,71 +0,0 @@ -/// all species by typepath -GLOBAL_LIST_INIT(species_meta, initialize_static_species_cache()) - -/proc/initialize_static_species_cache() - . = GLOB.species_meta = list() - for(var/path in typesof(/datum/species)) - var/datum/species/S = path - if(initial(S.abstract_type) == path) - continue - S = new path - .[path] = S - -// todo: optimize -/** - * Fetches the static species of a given species name - * - * **DO NOT EDIT RETURNED DATUM** - */ -/proc/name_static_species_meta(name) - RETURN_TYPE(/datum/species) - for(var/id in GLOB.species_meta) - var/datum/species/S = GLOB.species_meta[id] - if(S.name == name) - return S - -// todo: optimize -/** - * Gets the unique static id/type of a species of a given name - */ -/proc/species_type_by_name(name) - for(var/id in GLOB.species_meta) - var/datum/species/S = GLOB.species_meta[id] - if(S.name == name) - return S.type - -/** - * gets species name by type - */ -/proc/species_name_by_type(type) - var/datum/species/S = type - return initial(S.name) - -/** - * Fetches the static species cached globally - * - * **DO NOT EDIT RETURNED DATUM** - */ -/proc/get_static_species_meta(path) - RETURN_TYPE(/datum/species) - return GLOB.species_meta[path] - -/** - * Fetches all static species in the global cache - * - * returns a list, **DO NOT EVER EDIT RETURNED DATUMS** - */ -/proc/all_static_species_meta() - RETURN_TYPE(/list) - . = list() - for(var/path in GLOB.species_meta) - . += GLOB.species_meta[path] - -/** - * returns all species names - */ -/proc/all_species_names() - RETURN_TYPE(/list) - . = list() - for(var/id in GLOB.species_meta) - var/datum/species/S = GLOB.species_meta[id] - . += S.name diff --git a/code/modules/species/outsider/celestials.dm b/code/modules/species/outsider/celestials.dm index e20a890d537..8d4adc40f1e 100644 --- a/code/modules/species/outsider/celestials.dm +++ b/code/modules/species/outsider/celestials.dm @@ -1,6 +1,8 @@ /datum/species/auril name = SPECIES_AURIL name_plural = SPECIES_AURIL + uid = SPECIES_ID_AURIL + category = "Celestials" blurb = {" The Auril are humanoids that resemble the angelic figures of Old Earth Christian myth. The resemblance, however, @@ -14,11 +16,10 @@ icobase = 'icons/mob/species/human/body_greyscale.dmi' deform = 'icons/mob/species/human/deformed_body_greyscale.dmi' - default_language = LANGUAGE_GALCOM - language = LANGUAGE_ENOCHIAN - num_alternate_languages = 3 + intrinsic_languages = LANGUAGE_ID_DAEDAL_AURIL + max_additional_languages = 3 - spawn_flags = SPECIES_CAN_JOIN + species_spawn_flags = SPECIES_SPAWN_ALLOWED species_appearance_flags = HAS_HAIR_COLOR | HAS_SKIN_COLOR | HAS_LIPS | HAS_UNDERWEAR | HAS_EYE_COLOR color_mult = 1 @@ -53,8 +54,10 @@ /mob/living/proc/glow_color) /datum/species/dremachir + uid = SPECIES_ID_DREMACHIR name = SPECIES_DREMACHIR name_plural = SPECIES_DREMACHIR + category = "Celestials" blurb = {" Dremachir lore is still a work in progress. They are not actual supernatural creatures. They are aliens. @@ -65,11 +68,10 @@ icobase = 'icons/mob/species/human/body_greyscale.dmi' deform = 'icons/mob/species/human/deformed_body_greyscale.dmi' - default_language = LANGUAGE_GALCOM - language = LANGUAGE_DAEMON - num_alternate_languages = 3 + intrinsic_languages = LANGUAGE_ID_DAEDAL_DREMACHIR + max_additional_languages = 3 - spawn_flags = SPECIES_CAN_JOIN + species_spawn_flags = SPECIES_SPAWN_ALLOWED species_appearance_flags = HAS_HAIR_COLOR | HAS_SKIN_COLOR | HAS_LIPS | HAS_UNDERWEAR | HAS_EYE_COLOR color_mult = 1 diff --git a/code/modules/species/outsider/replicant.dm b/code/modules/species/outsider/replicant.dm index 09d73c9b87d..96e94680c96 100644 --- a/code/modules/species/outsider/replicant.dm +++ b/code/modules/species/outsider/replicant.dm @@ -3,16 +3,16 @@ */ /datum/species/shapeshifter/replicant + uid = SPECIES_ID_REPLICANT name = SPECIES_REPLICANT name_plural = "Replicants" primitive_form = SPECIES_MONKEY unarmed_types = list(/datum/unarmed_attack/stomp, /datum/unarmed_attack/kick, /datum/unarmed_attack/claws, /datum/unarmed_attack/bite/sharp) blurb = "The remnants of some lost or dead race's research. These seem relatively normal." - num_alternate_languages = 3 - species_language = LANGUAGE_GALCOM - secondary_langs = list(LANGUAGE_TERMINUS) + max_additional_languages = 3 + whitelist_languages = LANGUAGE_ID_TERMINUS assisted_langs = list(LANGUAGE_ROOTGLOBAL) - name_language = LANGUAGE_TERMINUS + name_language = LANGUAGE_ID_TERMINUS blood_color = "#aaaadd" @@ -22,7 +22,7 @@ health_hud_intensity = 1.5 - flags = NO_MINOR_CUT | NO_HALLUCINATION | NO_INFECT + species_flags = NO_MINOR_CUT | NO_HALLUCINATION | NO_INFECT vision_flags = SEE_SELF darksight = 5 @@ -37,7 +37,7 @@ siemens_coefficient = 0.9 heal_rate = 0 - spawn_flags = SPECIES_IS_RESTRICTED + species_spawn_flags = SPECIES_SPAWN_RESTRICTED species_appearance_flags = HAS_SKIN_COLOR | HAS_EYE_COLOR | HAS_HAIR_COLOR | HAS_UNDERWEAR valid_transform_species = list(SPECIES_HUMAN, SPECIES_HUMAN_VATBORN, SPECIES_UNATHI, SPECIES_TAJ, SPECIES_SKRELL, SPECIES_DIONA, SPECIES_TESHARI, SPECIES_MONKEY, SPECIES_VOX) @@ -67,11 +67,13 @@ /datum/species/shapeshifter/replicant/alpha name = SPECIES_REPLICANT_ALPHA + uid = SPECIES_ID_REPLICANT_ALPHA blurb = "The remnants of some lost or dead race's research. These seem caustic." blood_color = "#55ff55" - species_language = LANGUAGE_SIGN + intrinsic_languages = LANGUAGE_ID_SIGN + whitelist_languages = LANGUAGE_ID_TERMINUS assisted_langs = list(LANGUAGE_ROOTGLOBAL, LANGUAGE_SOL_COMMON, LANGUAGE_SKRELLIANFAR) inherent_verbs = list( @@ -104,12 +106,16 @@ /datum/species/shapeshifter/replicant/beta name = SPECIES_REPLICANT_BETA + uid = SPECIES_ID_REPLICANT_BETA blurb = "The remnants of some lost or dead race's research. These seem elastic." blood_color = "#C0C0C0" - species_language = LANGUAGE_SIGN - secondary_langs = list(LANGUAGE_TERMINUS, LANGUAGE_ROOTGLOBAL) // Radio-waves. + intrinsic_languages = LANGUAGE_ID_SIGN + whitelist_languages = list( + LANGUAGE_ID_TERMINUS, + LANGUAGE_ID_DIONA_HIVEMIND + ) has_organ = list( O_HEART = /obj/item/organ/internal/heart/replicant/rage, diff --git a/code/modules/species/outsider/scori.dm b/code/modules/species/outsider/scori.dm index e814535d231..117aa9d5c7d 100644 --- a/code/modules/species/outsider/scori.dm +++ b/code/modules/species/outsider/scori.dm @@ -1,9 +1,9 @@ /datum/species/scori + uid = SPECIES_ID_SCORI name = "Scorian" name_plural = SPECIES_SCORI - default_language = LANGUAGE_EVENT1 - language = LANGUAGE_EVENT1 - num_alternate_languages = 2 + default_language = LANGUAGE_ID_EVENT_1 + max_additional_languages = 2 unarmed_types = list(/datum/unarmed_attack/stomp, /datum/unarmed_attack/kick, /datum/unarmed_attack/bite) rarity_value = 4 @@ -16,7 +16,7 @@ Harmony have since confirmed the presence of a nearby Scori tribe." catalogue_data = list(/datum/category_item/catalogue/fauna/ashlander) - spawn_flags = SPECIES_IS_RESTRICTED + species_spawn_flags = SPECIES_SPAWN_RESTRICTED species_appearance_flags = HAS_HAIR_COLOR | HAS_SKIN_COLOR | HAS_LIPS | HAS_UNDERWEAR | HAS_EYE_COLOR icobase = 'icons/mob/species/human/body_greyscale.dmi' deform = 'icons/mob/species/human/deformed_body_greyscale.dmi' @@ -26,7 +26,7 @@ base_color = "#373652" blood_color = "#3c6d45" - flags = NO_MINOR_CUT + species_flags = NO_MINOR_CUT siemens_coefficient = 1.5 max_age = 200 diff --git a/code/modules/species/outsider/shadow.dm b/code/modules/species/outsider/shadow.dm index bbc3fe74dfc..6eab3225819 100644 --- a/code/modules/species/outsider/shadow.dm +++ b/code/modules/species/outsider/shadow.dm @@ -1,4 +1,5 @@ /datum/species/shadow + uid = SPECIES_ID_SHADOW name = SPECIES_SHADOW name_plural = "shadows" @@ -26,8 +27,8 @@ remains_type = /obj/effect/debris/cleanable/ash death_message = "dissolves into ash..." - flags = NO_SCAN | NO_SLIP | NO_POISON | NO_MINOR_CUT - spawn_flags = SPECIES_IS_RESTRICTED + species_flags = NO_SCAN | NO_SLIP | NO_POISON | NO_MINOR_CUT + species_spawn_flags = SPECIES_SPAWN_RESTRICTED genders = list(NEUTER) diff --git a/code/modules/species/outsider/skeleton.dm b/code/modules/species/outsider/skeleton.dm index 9bf9cadc9b3..958182c2eef 100644 --- a/code/modules/species/outsider/skeleton.dm +++ b/code/modules/species/outsider/skeleton.dm @@ -1,4 +1,5 @@ /datum/species/skeleton + uid = SPECIES_ID_SKELETON name = SPECIES_SKELETON name_plural = "Skeletons" primitive_form = SPECIES_MONKEY @@ -9,14 +10,14 @@ icobase = 'icons/mob/species/human/skeleton.dmi' - language = "Sol Common" + intrinsic_languages = LANGUAGE_ID_HUMAN // todo? name_language = null // Use the first-name last-name generator rather than a language scrambler max_age = 110 health_hud_intensity = 1.5 - flags = NO_SCAN | NO_PAIN | NO_SLIP | NO_POISON | NO_MINOR_CUT | NO_BLOOD | UNDEAD | NO_DEFIB - spawn_flags = SPECIES_IS_RESTRICTED + species_flags = NO_SCAN | NO_PAIN | NO_SLIP | NO_POISON | NO_MINOR_CUT | NO_BLOOD | UNDEAD | NO_DEFIB + species_spawn_flags = SPECIES_SPAWN_RESTRICTED species_appearance_flags = null show_ssd = null diff --git a/code/modules/species/outsider/vox.dm b/code/modules/species/outsider/vox.dm index af1edabd022..cb55037b9e5 100644 --- a/code/modules/species/outsider/vox.dm +++ b/code/modules/species/outsider/vox.dm @@ -2,15 +2,16 @@ name = SPECIES_VOX name_plural = SPECIES_VOX uid = SPECIES_ID_VOX + category = "Vox" default_bodytype = BODYTYPE_VOX icobase = 'icons/mob/species/vox/body.dmi' deform = 'icons/mob/species/vox/deformed_body.dmi' - num_alternate_languages = 1 - language = LANGUAGE_GALCOM - default_language = LANGUAGE_VOX - species_language = LANGUAGE_VOX + max_additional_languages = 1 + intrinsic_languages = LANGUAGE_ID_VOX + default_language = LANGUAGE_ID_VOX + name_language = LANGUAGE_ID_VOX assisted_langs = list(LANGUAGE_ROOTGLOBAL) blurb = {" @@ -55,8 +56,8 @@ poison_type = /datum/gas/oxygen siemens_coefficient = 0.2 - flags = NO_SCAN | CONTAMINATION_IMMUNE - spawn_flags = SPECIES_CAN_JOIN | SPECIES_IS_WHITELISTED | SPECIES_WHITELIST_SELECTABLE + species_flags = NO_SCAN | CONTAMINATION_IMMUNE + species_spawn_flags = SPECIES_SPAWN_ALLOWED | SPECIES_SPAWN_WHITELISTED | SPECIES_SPAWN_WHITELIST_SELECTABLE species_appearance_flags = HAS_EYE_COLOR | HAS_HAIR_COLOR | HAS_SKIN_COLOR blood_color = "#9066BD" @@ -111,7 +112,7 @@ ) /datum/species/vox/get_random_name(gender) - var/datum/language/species_language = GLOB.all_languages[default_language] + var/datum/language/species_language = SScharacters.resolve_language_id(default_language) return species_language.get_random_name(gender) /datum/species/vox/equip_survival_gear(mob/living/carbon/human/H, extendedtank = FALSE, comprehensive = FALSE) diff --git a/code/modules/species/station/promethean/promethean.dm b/code/modules/species/promethean/promethean.dm similarity index 96% rename from code/modules/species/station/promethean/promethean.dm rename to code/modules/species/promethean/promethean.dm index 1c81cfafdf3..acbb8c94429 100644 --- a/code/modules/species/station/promethean/promethean.dm +++ b/code/modules/species/promethean/promethean.dm @@ -3,8 +3,9 @@ var/datum/species/shapeshifter/promethean/prometheans // Species definition follows. /datum/species/shapeshifter/promethean name = SPECIES_PROMETHEAN - id = SPECIES_ID_PROMETHEAN + uid = SPECIES_ID_PROMETHEAN name_plural = "Prometheans" + category = "Special" default_bodytype = BODYTYPE_PROMETHEAN blurb = {" @@ -19,9 +20,7 @@ var/datum/species/shapeshifter/promethean/prometheans wikilink = "N/A" catalogue_data = list(/datum/category_item/catalogue/fauna/promethean) - num_alternate_languages = 2 - species_language = LANGUAGE_SOL_COMMON - secondary_langs = list(LANGUAGE_SOL_COMMON) // For some reason, having this as their species language does not allow it to be chosen. + max_additional_languages = 4 assisted_langs = list(LANGUAGE_ROOTGLOBAL, LANGUAGE_VOX) // Prometheans are weird, let's just assume they can use basically any language. show_ssd = "totally quiescent" @@ -36,9 +35,9 @@ var/datum/species/shapeshifter/promethean/prometheans push_flags = ~HEAVY swap_flags = ~HEAVY - flags = NO_SCAN | NO_SLIP | NO_MINOR_CUT | NO_HALLUCINATION | NO_INFECT + species_flags = NO_SCAN | NO_SLIP | NO_MINOR_CUT | NO_HALLUCINATION | NO_INFECT species_appearance_flags = HAS_SKIN_COLOR | HAS_EYE_COLOR | HAS_HAIR_COLOR | RADIATION_GLOWS | HAS_UNDERWEAR - spawn_flags = SPECIES_CAN_JOIN + species_spawn_flags = SPECIES_SPAWN_ALLOWED health_hud_intensity = 2 diff --git a/code/modules/species/station/promethean/promethean_blob.dm b/code/modules/species/promethean/promethean_blob.dm similarity index 100% rename from code/modules/species/station/promethean/promethean_blob.dm rename to code/modules/species/promethean/promethean_blob.dm diff --git a/code/modules/species/station/protean/protean_blob.dm b/code/modules/species/protean/protean_blob.dm similarity index 100% rename from code/modules/species/station/protean/protean_blob.dm rename to code/modules/species/protean/protean_blob.dm diff --git a/code/modules/species/station/protean/protean_powers.dm b/code/modules/species/protean/protean_powers.dm similarity index 99% rename from code/modules/species/station/protean/protean_powers.dm rename to code/modules/species/protean/protean_powers.dm index 2fd2e9d3db6..0b14de8182e 100644 --- a/code/modules/species/station/protean/protean_powers.dm +++ b/code/modules/species/protean/protean_powers.dm @@ -289,8 +289,8 @@ to_chat(src,"You must be awake and standing to perform this action!") return - var/new_species_name = input("Please select a species to emulate.", "Shapeshifter Body") as null|anything in GLOB.playable_species - var/datum/species/new_species = name_static_species_meta(new_species_name) + var/new_species_name = input("Please select a species to emulate.", "Shapeshifter Body") as null|anything in SScharacters.playable_species + var/datum/species/new_species = SScharacters.resolve_species_name(new_species_name) if(new_species) impersonate_bodytype_legacy = new_species.get_bodytype_legacy() impersonate_bodytype = new_species.default_bodytype diff --git a/code/modules/species/station/protean/protean_species.dm b/code/modules/species/protean/protean_species.dm similarity index 97% rename from code/modules/species/station/protean/protean_species.dm rename to code/modules/species/protean/protean_species.dm index ad029193140..33cc85a7cdb 100644 --- a/code/modules/species/station/protean/protean_species.dm +++ b/code/modules/species/protean/protean_species.dm @@ -2,8 +2,10 @@ #define METAL_PER_TICK 100 /datum/species/protean + uid = SPECIES_ID_PROTEAN name = SPECIES_PROTEAN name_plural = "Proteans" + category = "Special" blurb = "Sometimes very advanced civilizations will produce the ability to swap into manufactured, robotic bodies. And sometimes \ VERY advanced civilizations have the option of 'nanoswarm' bodies. Effectively a single robot body comprised \ of millions of tiny nanites working in concert to maintain cohesion." @@ -18,11 +20,11 @@ flesh_color = "#505050" base_color = "#FFFFFF" //Color mult, start out with this - flags = NO_SCAN | NO_SLIP | NO_MINOR_CUT | NO_HALLUCINATION | NO_INFECT | NO_PAIN | CONTAMINATION_IMMUNE + species_flags = NO_SCAN | NO_SLIP | NO_MINOR_CUT | NO_HALLUCINATION | NO_INFECT | NO_PAIN | CONTAMINATION_IMMUNE species_appearance_flags = HAS_SKIN_COLOR | HAS_EYE_COLOR | HAS_HAIR_COLOR | HAS_UNDERWEAR | HAS_LIPS - spawn_flags = SPECIES_CAN_JOIN | SPECIES_IS_WHITELISTED | SPECIES_WHITELIST_SELECTABLE + species_spawn_flags = SPECIES_SPAWN_ALLOWED | SPECIES_SPAWN_WHITELISTED | SPECIES_SPAWN_WHITELIST_SELECTABLE health_hud_intensity = 2 - num_alternate_languages = 5 // Let's not make them know every language, past me. + max_additional_languages = 5 // Let's not make them know every language, past me. assisted_langs = list(LANGUAGE_ROOTLOCAL, LANGUAGE_ROOTGLOBAL, LANGUAGE_VOX) color_mult = TRUE diff --git a/code/modules/species/shadekin/crew_shadekin_abilities.dm b/code/modules/species/shadekin/crew_shadekin_abilities.dm index 7e0e8b1ecdb..359b1eca082 100644 --- a/code/modules/species/shadekin/crew_shadekin_abilities.dm +++ b/code/modules/species/shadekin/crew_shadekin_abilities.dm @@ -21,7 +21,7 @@ var/ability_cost = 50 - if(species.get_exact_species_id() != SPECIES_ID_SHADEKIN_BLACK_EYED) + if(species.get_exact_species_id() != SPECIES_ID_SHADEKIN_BLACK) to_chat(src, "Only a black-eyed shadekin can use that!") return FALSE else if(stat) @@ -85,7 +85,7 @@ var/ability_cost = 25 - if(species.get_exact_species_id() != SPECIES_ID_SHADEKIN_BLACK_EYED) + if(species.get_exact_species_id() != SPECIES_ID_SHADEKIN_BLACK) to_chat(src, "Only a black-eyed shadekin can use that!") return FALSE else if(stat) diff --git a/code/modules/species/shadekin/shadekin.dm b/code/modules/species/shadekin/shadekin.dm index c0ab8fb380c..b9abf301268 100644 --- a/code/modules/species/shadekin/shadekin.dm +++ b/code/modules/species/shadekin/shadekin.dm @@ -1,8 +1,8 @@ /datum/species/shadekin + uid = SPECIES_ID_SHADEKIN name = SPECIES_SHADEKIN name_plural = SPECIES_SHADEKIN - uid = SPECIES_ID_SHADEKIN - id = SPECIES_ID_SHADEKIN + category = "Special" icobase = 'icons/mob/species/shadekin/body.dmi' deform = 'icons/mob/species/shadekin/body.dmi' @@ -23,11 +23,9 @@ catalogue_data = list(/datum/category_item/catalogue/fauna/shadekin) rarity_value = 15 //INTERDIMENSIONAL FLUFFERS - num_alternate_languages = 3 - language = LANGUAGE_SHADEKIN - name_language = LANGUAGE_SHADEKIN - species_language = LANGUAGE_SHADEKIN - secondary_langs = list(LANGUAGE_SHADEKIN) + max_additional_languages = 3 + intrinsic_languages = LANGUAGE_ID_SHADEKIN_HIVEMIND + name_language = LANGUAGE_ID_SHADEKIN_HIVEMIND unarmed_types = list( /datum/unarmed_attack/stomp, @@ -59,8 +57,8 @@ heat_level_2 = 1000 heat_level_3 = 1150 - flags = NO_SCAN | NO_MINOR_CUT | NO_INFECT | CONTAMINATION_IMMUNE - spawn_flags = SPECIES_IS_WHITELISTED | SPECIES_CAN_JOIN | SPECIES_WHITELIST_SELECTABLE + species_flags = NO_SCAN | NO_MINOR_CUT | NO_INFECT | CONTAMINATION_IMMUNE + species_spawn_flags = SPECIES_SPAWN_WHITELISTED | SPECIES_SPAWN_ALLOWED | SPECIES_SPAWN_WHITELIST_SELECTABLE reagent_tag = IS_SHADEKIN // for shadekin-unique chem interactions diff --git a/code/modules/species/shadekin/shadekin_abilities.dm b/code/modules/species/shadekin/shadekin_abilities.dm index a098e106b1a..e6c83bc38bd 100644 --- a/code/modules/species/shadekin/shadekin_abilities.dm +++ b/code/modules/species/shadekin/shadekin_abilities.dm @@ -72,6 +72,10 @@ to_chat(src, SPAN_WARNING("You can't use that here!")) return FALSE + if(!(ability_flags & AB_PHASE_SHIFTED)) + shadekin_adjust_energy(-ability_cost) + playsound(src, 'sound/effects/stealthoff.ogg', 75, TRUE) + forceMove(T) var/original_canmove = canmove SetStunned(0) diff --git a/code/modules/species/shadekin/shadekin_blackeyed.dm b/code/modules/species/shadekin/shadekin_blackeyed.dm index a48fbedcc57..28c348b18fd 100644 --- a/code/modules/species/shadekin/shadekin_blackeyed.dm +++ b/code/modules/species/shadekin/shadekin_blackeyed.dm @@ -1,7 +1,8 @@ /datum/species/crew_shadekin + uid = SPECIES_ID_SHADEKIN_BLACK name = SPECIES_SHADEKIN_CREW name_plural = SPECIES_SHADEKIN_CREW - uid = SPECIES_ID_SHADEKIN_BLACK_EYED + uid = SPECIES_ID_SHADEKIN_BLACK id = SPECIES_ID_SHADEKIN icobase = 'icons/mob/species/shadekin/body.dmi' @@ -22,11 +23,11 @@ wikilink = "https://citadel-station.net/wikiRP/index.php?title=Race:_Shadekin" - language = LANGUAGE_SHADEKIN - name_language = LANGUAGE_SHADEKIN - species_language = LANGUAGE_SHADEKIN - secondary_langs = list(LANGUAGE_SHADEKIN) - num_alternate_languages = 3 + name_language = LANGUAGE_ID_SHADEKIN_HIVEMIND + intrinsic_languages = list( + LANGUAGE_ID_SHADEKIN_HIVEMIND + ) + max_additional_languages = 3 rarity_value = 5 // INTERDIMENSIONAL FLUFFERS @@ -58,8 +59,8 @@ heat_level_3 = 1150 // Shadekin biology is still unknown to the universe (unless some bullshit lore says otherwise) - flags = NO_SCAN | NO_MINOR_CUT | CONTAMINATION_IMMUNE - spawn_flags = SPECIES_CAN_JOIN | SPECIES_IS_WHITELISTED | SPECIES_WHITELIST_SELECTABLE + species_flags = NO_SCAN | NO_MINOR_CUT | CONTAMINATION_IMMUNE + species_spawn_flags = SPECIES_SPAWN_ALLOWED | SPECIES_SPAWN_WHITELISTED | SPECIES_SPAWN_WHITELIST_SELECTABLE reagent_tag = IS_SHADEKIN // for shadekin-unique chem interactions diff --git a/code/modules/species/species.dm b/code/modules/species/species.dm index f3accd5a4f6..4714785f7b9 100644 --- a/code/modules/species/species.dm +++ b/code/modules/species/species.dm @@ -1,8 +1,10 @@ /** * Species Datums * - * They are globally cached by typepath. This is out of necessity, because unlike things like movespeed modifiers, - * species are always assumed to be variable. + * They are **not** singletons, however, they are globally cached as a static set + * for use in preferences to determine default properties/whatever + * + * ? Someday we'll rework this. Someday. I believe. * * Mob set_species supports either a datum or a typepath. Mobs, upon receiving a typepath, will make their own copy for modification. * @@ -16,19 +18,62 @@ * - A global cache of species by typepath will still be maintained for "static" usages of these datums, like for preferences rendering. */ /datum/species -//! ## Intrinsics + //! Intrinsics /// abstract type var/abstract_type = /datum/species - /// uid + /// uid - **must be unique** var/uid /// if we're a subspecies, real id var/id // TODO: ref species by id in code, so we can rename as needed + //! Appearance + /// Appearance/display related features. + var/species_appearance_flags = NONE + + //! Spawning + /// Flags that specify who can spawn as this species + var/species_spawn_flags = NONE + + //! Culture/Background - Typepaths + /// default origin + var/default_origin = /datum/lore/character_background/origin/custom + /// default citizenship + var/default_citizenship = /datum/lore/character_background/citizenship/custom + /// default faction + var/default_faction = /datum/lore/character_background/faction/nanotrasen + /// default religion + var/default_religion = /datum/lore/character_background/religion/custom + /// fluff flags + var/species_fluff_flags = NONE + + //! Language - IDs + /// default language used when speaking + var/default_language = LANGUAGE_ID_COMMON + /// do we have galactic common? this is so common we just have this as a var + var/galactic_language = TRUE + /// intrinsic species languages - list() or singular language or null + // todo: linter check for language default being in here + var/list/intrinsic_languages = LANGUAGE_ID_COMMON + /// language our name is in - used for namegen; null to force stock ss13 namegen instead + // todo: language for namegen is questionaable + var/name_language = LANGUAGE_ID_COMMON + /// languages we are always allowed to learn (overridden by intrinsic languages) even if restricted - list() or singular language + var/list/whitelist_languages + /// additional languages we can learn (ONTOP OF INTRINSIC AND CULTURE) + var/max_additional_languages = 3 + +//! ## Languages (old) + /// The languages the species can't speak without an assisted organ. + /// This list is a guess at things that no one other than the parent species should be able to speak + var/list/assisted_langs = list(LANGUAGE_EAL, LANGUAGE_SKRELLIAN, LANGUAGE_SKRELLIANFAR, LANGUAGE_ROOTLOCAL, LANGUAGE_ROOTGLOBAL, LANGUAGE_VOX) + //! ## Descriptors and strings. /// Species real name. // TODO: STOP USING THIS. This is being phased out for species IDs. var/name + /// Category in character setup + var/category = "Miscellaneous" /// what you see on tooltip/examine var/examine_name /// what you see on health analyzers/IC @@ -135,27 +180,11 @@ /// The maximum age a species is allowed to be played as. This is generally determined by lifespan. var/max_age = 70 -//! ## Language/culture vars. - /// Default language is used when 'say' is used without modifiers. - var/default_language = LANGUAGE_GALCOM - /// Default racial language, if any. - var/language = LANGUAGE_GALCOM - /// Used on the Character Setup screen - var/list/species_language = list(LANGUAGE_GALCOM) - /// The names of secondary languages that are available to this species. - var/list/secondary_langs = list() +//! ## Speech Sounds /// A list of sounds to potentially play when speaking. var/list/speech_sounds = list() /// The likelihood of a speech sound playing. var/list/speech_chance = list() - /// How many secondary languages are available to select at character creation. - var/num_alternate_languages = 0 - /// The language to use when determining names for this species, or null to use the first name/last name generator. - var/name_language = LANGUAGE_GALCOM - - /// The languages the species can't speak without an assisted organ. - /// This list is a guess at things that no one other than the parent species should be able to speak - var/list/assisted_langs = list(LANGUAGE_EAL, LANGUAGE_SKRELLIAN, LANGUAGE_SKRELLIANFAR, LANGUAGE_ROOTLOCAL, LANGUAGE_ROOTGLOBAL, LANGUAGE_VOX) //! ## Soundy emotey things. var/scream_verb = "screams" @@ -312,12 +341,7 @@ //! ## Flags /// Various specific features. - var/flags = NONE - /// Appearance/display related features. - var/species_appearance_flags = NONE - /// Flags that specify who can spawn as this species - var/spawn_flags = NONE - + var/species_flags = NONE /// What marks are left when walking var/obj/effect/debris/cleanable/blood/tracks/move_trail = /obj/effect/debris/cleanable/blood/tracks/footprints var/list/skin_overlays = list() @@ -447,9 +471,6 @@ var/selects_bodytype = FALSE // Allows the species to choose from body types intead of being forced to be just one. /datum/species/New() - if(isnull(uid)) - uid = ckey(name) - if(hud_type) hud = new hud_type() else @@ -485,12 +506,9 @@ * handle_post_spawn() and create_organs() should be called manually if you are applying a species to a human being instantiated! */ /datum/species/proc/on_apply(mob/living/carbon/human/H) - ASSERT(istype(H)) - - if(language) - H.add_language(language) - if(default_language) - H.add_language(default_language) + // todo: language sources and holder + for(var/id in intrinsic_languages) + H.add_language(id) if(holder_type) H.holder_type = holder_type @@ -511,12 +529,9 @@ * called when we are removed from a mob */ /datum/species/proc/on_remove(mob/living/carbon/human/H) - if(language) - H.remove_language(language) - if(default_language) - H.remove_language(default_language) - for(var/datum/language/L in assisted_langs) - H.remove_language(L) + // todo: language sources and holder + for(var/id in intrinsic_languages) + H.remove_language(id) remove_inherent_spells(H) remove_inherent_verbs(H) H.holder_type = null @@ -858,9 +873,9 @@ GLOBAL_LIST_INIT(species_oxygen_tank_by_gas, list( ASSERT(to_copy) if(ispath(to_copy)) - to_copy = get_static_species_meta(to_copy) + to_copy = SScharacters.resolve_species_path(to_copy) if(istext(to_copy)) - to_copy = name_static_species_meta(to_copy) + to_copy = SScharacters.resolve_species_name(to_copy) //Initials so it works with a simple path passed, or an instance base_species = to_copy.name diff --git a/code/modules/species/species_getters.dm b/code/modules/species/species_getters.dm index 31c7db26341..3ee395aa091 100644 --- a/code/modules/species/species_getters.dm +++ b/code/modules/species/species_getters.dm @@ -1,3 +1,4 @@ +//! IDs /** * get species id; subspecies returns main species */ @@ -10,12 +11,35 @@ /datum/species/proc/get_exact_species_id() return uid +//! Bodytypes /** * get effective bodytype */ /datum/species/proc/get_effective_bodytype(mob/living/carbon/human/H, obj/item/I, slot_id) return default_bodytype +//! Languages +/datum/species/proc/get_default_language_id() + return default_language + +/datum/species/proc/get_intrinsic_language_ids() + RETURN_TYPE(/list) + . = intrinsic_languages? (islist(intrinsic_languages)? intrinsic_languages.Copy() : list(intrinsic_languages)) : list() + if(galactic_language) + . |= LANGUAGE_ID_COMMON + +/datum/species/proc/get_name_language_id() + return name_language + +/datum/species/proc/get_max_additional_languages() + return max_additional_languages + +/datum/species/proc/get_whitelisted_language_ids() + RETURN_TYPE(/list) + return whitelist_languages? (islist(whitelist_languages)? whitelist_languages.Copy() : list(whitelist_languages)) : list() + +//? misc + /datum/species/proc/get_valid_shapeshifter_forms(mob/living/carbon/human/H) return list() @@ -46,9 +70,6 @@ /datum/species/proc/get_husk_icon(mob/living/carbon/human/H) return husk_icon -/datum/species/proc/get_station_variant() - return name - // used for limb caching // todo: rework limbs and get rid of this, numerical static keys are dumb as fuck, // limbs should use their own types! @@ -132,9 +153,9 @@ else return capitalize(pick(GLOB.first_names_male)) + " " + capitalize(pick(GLOB.last_names)) - var/datum/language/species_language = GLOB.all_languages[name_language] + var/datum/language/species_language = SScharacters.resolve_language_id(name_language) if(!species_language) - species_language = GLOB.all_languages[default_language] + species_language = SScharacters.resolve_language_id(default_language) if(!species_language) return "unknown" return species_language.get_random_name(gender) diff --git a/code/modules/species/species_shapeshift.dm b/code/modules/species/species_shapeshift.dm index 2ca5f880563..7b2d2cd661e 100644 --- a/code/modules/species/species_shapeshift.dm +++ b/code/modules/species/species_shapeshift.dm @@ -22,7 +22,7 @@ var/list/wrapped_species_by_ref = list() /datum/species/shapeshifter/get_icobase(mob/living/carbon/human/H, get_deform) if(!H) return ..(null, get_deform) - var/datum/species/S = get_static_species_meta(species_type_by_name(wrapped_species_by_ref["\ref[H]"])) + var/datum/species/S = SScharacters.resolve_species_name(wrapped_species_by_ref["\ref[H]"]) return S.get_icobase(H, get_deform) /datum/species/shapeshifter/real_race_key(mob/living/carbon/human/H) @@ -30,52 +30,52 @@ var/list/wrapped_species_by_ref = list() /datum/species/shapeshifter/get_effective_bodytype(mob/living/carbon/human/H, obj/item/I, slot_id) if(!H) return ..(H, I, slot_id) - var/datum/species/S = get_static_species_meta(species_type_by_name(wrapped_species_by_ref["\ref[H]"])) + var/datum/species/S = SScharacters.resolve_species_name(wrapped_species_by_ref["\ref[H]"]) return S.get_effective_bodytype(H, I, slot_id) /datum/species/shapeshifter/get_bodytype_legacy(mob/living/carbon/human/H) if(!H) return ..() - var/datum/species/S = get_static_species_meta(species_type_by_name(wrapped_species_by_ref["\ref[H]"])) + var/datum/species/S = SScharacters.resolve_species_name(wrapped_species_by_ref["\ref[H]"]) return S.get_bodytype_legacy(H) /datum/species/shapeshifter/get_worn_legacy_bodytype(mob/living/carbon/human/H) if(!H) return ..() - var/datum/species/S = get_static_species_meta(species_type_by_name(wrapped_species_by_ref["\ref[H]"])) + var/datum/species/S = SScharacters.resolve_species_name(wrapped_species_by_ref["\ref[H]"]) return S.get_worn_legacy_bodytype(H) /datum/species/shapeshifter/get_blood_mask(mob/living/carbon/human/H) if(!H) return ..() - var/datum/species/S = get_static_species_meta(species_type_by_name(wrapped_species_by_ref["\ref[H]"])) + var/datum/species/S = SScharacters.resolve_species_name(wrapped_species_by_ref["\ref[H]"]) return S.get_blood_mask(H) /datum/species/shapeshifter/get_damage_mask(mob/living/carbon/human/H) if(!H) return ..() - var/datum/species/S = get_static_species_meta(species_type_by_name(wrapped_species_by_ref["\ref[H]"])) + var/datum/species/S = SScharacters.resolve_species_name(wrapped_species_by_ref["\ref[H]"]) return S.get_damage_mask(H) /datum/species/shapeshifter/get_damage_overlays(mob/living/carbon/human/H) if(!H) return ..() - var/datum/species/S = get_static_species_meta(species_type_by_name(wrapped_species_by_ref["\ref[H]"])) + var/datum/species/S = SScharacters.resolve_species_name(wrapped_species_by_ref["\ref[H]"]) return S.get_damage_overlays(H) /datum/species/shapeshifter/get_tail(mob/living/carbon/human/H) if(!H) return ..() - var/datum/species/S = get_static_species_meta(species_type_by_name(wrapped_species_by_ref["\ref[H]"])) + var/datum/species/S = SScharacters.resolve_species_name(wrapped_species_by_ref["\ref[H]"]) return S.get_tail(H) /datum/species/shapeshifter/get_tail_animation(mob/living/carbon/human/H) if(!H) return ..() - var/datum/species/S = get_static_species_meta(species_type_by_name(wrapped_species_by_ref["\ref[H]"])) + var/datum/species/S = SScharacters.resolve_species_name(wrapped_species_by_ref["\ref[H]"]) return S.get_tail_animation(H) /datum/species/shapeshifter/get_tail_hair(mob/living/carbon/human/H) if(!H) return ..() - var/datum/species/S = get_static_species_meta(species_type_by_name(wrapped_species_by_ref["\ref[H]"])) + var/datum/species/S = SScharacters.resolve_species_name(wrapped_species_by_ref["\ref[H]"]) return S.get_tail_hair(H) /datum/species/shapeshifter/get_husk_icon(mob/living/carbon/human/H) if(H) - var/datum/species/S = get_static_species_meta(species_type_by_name(wrapped_species_by_ref["\ref[H]"])) + var/datum/species/S = SScharacters.resolve_species_name(wrapped_species_by_ref["\ref[H]"]) if(S) return S.get_husk_icon(H) return ..() @@ -180,7 +180,7 @@ var/list/wrapped_species_by_ref = list() var/new_species = null new_species = input("Please select a species to emulate.", "Shapeshifter Body") as null|anything in species.get_valid_shapeshifter_forms(src) - if(!new_species || !name_static_species_meta(new_species) || wrapped_species_by_ref["\ref[src]"] == new_species) + if(!new_species || !SScharacters.resolve_species_name(new_species) || wrapped_species_by_ref["\ref[src]"] == new_species) return shapeshifter_change_shape(new_species) diff --git a/code/modules/species/station/adherent.dm b/code/modules/species/station/adherent.dm index f9feef728d5..a6b1a6016f0 100644 --- a/code/modules/species/station/adherent.dm +++ b/code/modules/species/station/adherent.dm @@ -1,6 +1,7 @@ /datum/species/adherent name = SPECIES_ADHERENT name_plural = "Adherents" + uid = SPECIES_ID_ADHERENT default_bodytype = BODYTYPE_ADHERENT blurb = "The Vigil is a relatively loose association of machine-servitors, Adherents, \ @@ -47,13 +48,12 @@ heat_level_2 = 1000 heat_level_3 = 2000 - flags = NO_SCAN | NO_SLIP | NO_MINOR_CUT | NO_HALLUCINATION | NO_INFECT | NO_PAIN - spawn_flags = SPECIES_IS_WHITELISTED | SPECIES_NO_FBP_CONSTRUCTION | SPECIES_NO_FBP_CHARGEN | SPECIES_CAN_JOIN | SPECIES_WHITELIST_SELECTABLE + species_flags = NO_SCAN | NO_SLIP | NO_MINOR_CUT | NO_HALLUCINATION | NO_INFECT | NO_PAIN + species_spawn_flags = SPECIES_SPAWN_WHITELISTED | SPECIES_SPAWN_NO_FBP_CONSTRUCT | SPECIES_SPAWN_NO_FBP_SETUP | SPECIES_SPAWN_ALLOWED | SPECIES_SPAWN_WHITELIST_SELECTABLE species_appearance_flags = HAS_EYE_COLOR | HAS_BASE_SKIN_COLOR - language = LANGUAGE_ADHERENT - species_language = LANGUAGE_ADHERENT - num_alternate_languages = 2 + intrinsic_languages = LANGUAGE_ID_ADHERENT + max_additional_languages = 2 blood_color = "#2de00d" flesh_color = "#90edeb" diff --git a/code/modules/species/station/alraune.dm b/code/modules/species/station/alraune.dm index 04c8b6d846b..4c0b28a3e4f 100644 --- a/code/modules/species/station/alraune.dm +++ b/code/modules/species/station/alraune.dm @@ -1,5 +1,6 @@ /datum/species/alraune name = SPECIES_ALRAUNE + uid = SPECIES_ID_ALRAUNE name_plural = "Alraunes" icobase = 'icons/mob/species/human/body_greyscale.dmi' @@ -15,9 +16,8 @@ They are highly adaptable both mentally and physically, but tend to have a collecting intra-species mindset. "} - num_alternate_languages = 3 - language = LANGUAGE_VERNAL - species_language = LANGUAGE_VERNAL + max_additional_languages = 3 + intrinsic_languages = LANGUAGE_ID_VERNAL slowdown = 1 //slow, they're plants. Not as slow as full diona. total_health = 100 //standard @@ -58,8 +58,8 @@ breath_heat_level_2 = 450 breath_heat_level_3 = 800 //lower incineration threshold though - flags = NO_SCAN | IS_PLANT | NO_MINOR_CUT - spawn_flags = SPECIES_CAN_JOIN + species_flags = NO_SCAN | IS_PLANT | NO_MINOR_CUT + species_spawn_flags = SPECIES_SPAWN_ALLOWED species_appearance_flags = HAS_HAIR_COLOR | HAS_LIPS | HAS_UNDERWEAR | HAS_SKIN_COLOR | HAS_EYE_COLOR unarmed_types = list( @@ -411,5 +411,5 @@ //! WARNING SHITCODE /datum/species/alraune/get_race_key(mob/living/carbon/human/H) - var/datum/species/real = name_static_species_meta(base_species || SPECIES_HUMAN) + var/datum/species/real = SScharacters.resolve_species_name(base_species || SPECIES_HUMAN) return real.real_race_key(H) diff --git a/code/modules/species/station/apidaen.dm b/code/modules/species/station/apidaen.dm index 72b65d3dc0d..fb3055a4375 100644 --- a/code/modules/species/station/apidaen.dm +++ b/code/modules/species/station/apidaen.dm @@ -1,6 +1,7 @@ /datum/species/apidaen name = SPECIES_APIDAEN name_plural = SPECIES_APIDAEN + uid = SPECIES_ID_APIDAEN icobase = 'icons/mob/species/apidaen/body.dmi' deform = 'icons/mob/species/apidaen/body.dmi' // No deformed set has been made yet. @@ -14,8 +15,8 @@ brute_mod = 0.8 // 20% brute damage reduction seems fitting to match spiders, due to exoskeletons. burn_mod = 1.15 // 15% burn damage increase, the same as spiders. For the same reason. - num_alternate_languages = 2 - secondary_langs = list(LANGUAGE_VESPINAE) + max_additional_languages = 2 + intrinsic_languages = LANGUAGE_ID_VASILISSAN reagent_tag = IS_APIDAEN @@ -41,8 +42,8 @@ //primitive_form = SPECIES_MONKEY //I dunno. Replace this in the future. - flags = NO_MINOR_CUT - spawn_flags = SPECIES_CAN_JOIN + species_flags = NO_MINOR_CUT + species_spawn_flags = SPECIES_SPAWN_ALLOWED species_appearance_flags = HAS_HAIR_COLOR | HAS_LIPS | HAS_UNDERWEAR | HAS_SKIN_COLOR | HAS_EYE_COLOR color_mult = 1 diff --git a/code/modules/species/station/custom_species.dm b/code/modules/species/station/custom_species.dm index 5ce3614458b..f41f3b40942 100644 --- a/code/modules/species/station/custom_species.dm +++ b/code/modules/species/station/custom_species.dm @@ -1,6 +1,7 @@ /datum/species/custom name = SPECIES_CUSTOM + uid = SPECIES_ID_CUSTOM name_plural = "Custom" selects_bodytype = TRUE base_species = SPECIES_HUMAN @@ -15,10 +16,10 @@ name_language = null // Use the first-name last-name generator rather than a language scrambler max_age = 200 health_hud_intensity = 2 - num_alternate_languages = 3 + max_additional_languages = 3 assisted_langs = list(LANGUAGE_EAL, LANGUAGE_ROOTLOCAL, LANGUAGE_ROOTGLOBAL, LANGUAGE_VOX) - spawn_flags = SPECIES_CAN_JOIN + species_spawn_flags = SPECIES_SPAWN_ALLOWED species_appearance_flags = HAS_HAIR_COLOR | HAS_SKIN_COLOR | HAS_LIPS | HAS_UNDERWEAR | HAS_EYE_COLOR has_limbs = list( @@ -47,18 +48,18 @@ ) /datum/species/custom/get_effective_bodytype(mob/living/carbon/human/H, obj/item/I, slot_id) - return name_static_species_meta(base_species).get_effective_bodytype(H, I, slot_id) + return SScharacters.resolve_species_name(base_species).get_effective_bodytype(H, I, slot_id) /datum/species/custom/get_bodytype_legacy() return base_species /datum/species/custom/get_worn_legacy_bodytype() - var/datum/species/real = name_static_species_meta(base_species) + var/datum/species/real = SScharacters.resolve_species_name(base_species) // infinite loop guard return istype(real, src)? base_species : real.get_worn_legacy_bodytype() /datum/species/custom/get_race_key(mob/living/carbon/human/H) - var/datum/species/real = name_static_species_meta(base_species) + var/datum/species/real = SScharacters.resolve_species_name(base_species) return real.real_race_key(H) // Stub species overrides for shoving trait abilities into diff --git a/code/modules/species/station/diona.dm b/code/modules/species/station/diona.dm index 96c512040a7..fe7d642b91a 100644 --- a/code/modules/species/station/diona.dm +++ b/code/modules/species/station/diona.dm @@ -2,17 +2,19 @@ /datum/species/diona name = SPECIES_DIONA name_plural = "Dionaea" + uid = SPECIES_ID_DIONA //primitive_form = "Nymph" icobase = 'icons/mob/species/diona/body.dmi' deform = 'icons/mob/species/diona/deformed_body.dmi' preview_icon = 'icons/mob/species/diona/preview.dmi' - language = LANGUAGE_ROOTLOCAL - num_alternate_languages = 2 - name_language = LANGUAGE_ROOTLOCAL - species_language = LANGUAGE_ROOTLOCAL - secondary_langs = list(LANGUAGE_ROOTGLOBAL) + max_additional_languages = 2 + name_language = LANGUAGE_ID_DIONA + intrinsic_languages = list( + LANGUAGE_ID_DIONA, + LANGUAGE_ID_DIONA_HIVEMIND + ) assisted_langs = list(LANGUAGE_VOX) // Diona are weird, let's just assume they can use basically any language. slowdown = 2.5 @@ -93,8 +95,8 @@ body_temperature = T0C + 15 //make the plant people have a bit lower body temperature, why not hunger_factor = 0//Handled in handle_environment_special() - flags = NO_MINOR_CUT | IS_PLANT | NO_SCAN | NO_PAIN | NO_SLIP | NO_HALLUCINATION | NO_BLOOD | CONTAMINATION_IMMUNE - spawn_flags = SPECIES_CAN_JOIN | SPECIES_IS_WHITELISTED | SPECIES_WHITELIST_SELECTABLE + species_flags = NO_MINOR_CUT | IS_PLANT | NO_SCAN | NO_PAIN | NO_SLIP | NO_HALLUCINATION | NO_BLOOD | CONTAMINATION_IMMUNE + species_spawn_flags = SPECIES_SPAWN_ALLOWED | SPECIES_SPAWN_WHITELISTED | SPECIES_SPAWN_WHITELIST_SELECTABLE blood_color = "#004400" flesh_color = "#907E4A" @@ -125,7 +127,7 @@ if(H.isSynthetic()) H.visible_message(SPAN_DANGER("\The [H] collapses into parts, revealing a solitary diona nymph at the core.")) - H.set_species(get_static_species_meta(/datum/species/human), skip = TRUE, force = TRUE) + H.set_species(SScharacters.resolve_species_path(/datum/species/human), skip = TRUE, force = TRUE) for(var/obj/item/organ/internal/diona/Org in H.internal_organs) // Remove Nymph organs. qdel(Org) diff --git a/code/modules/species/station/golem.dm b/code/modules/species/station/golem.dm index e5764eca68b..90a60463764 100644 --- a/code/modules/species/station/golem.dm +++ b/code/modules/species/station/golem.dm @@ -1,16 +1,17 @@ /datum/species/golem name = SPECIES_GOLEM name_plural = "golems" + uid = SPECIES_ID_GOLEM icobase = 'icons/mob/species/golem/body.dmi' deform = 'icons/mob/species/golem/body.dmi' preview_icon = 'icons/mob/species/golem/preview.dmi' husk_icon = 'icons/mob/species/golem/husk.dmi' - language = "Sol Common" //todo? + intrinsic_languages = LANGUAGE_ID_HUMAN // todo? - spawn_flags = SPECIES_IS_RESTRICTED - flags = NO_PAIN | NO_SCAN | NO_POISON | NO_MINOR_CUT + species_spawn_flags = SPECIES_SPAWN_RESTRICTED + species_flags = NO_PAIN | NO_SCAN | NO_POISON | NO_MINOR_CUT siemens_coefficient = 0 diff --git a/code/modules/species/station/monkey.dm b/code/modules/species/station/monkey.dm index 94305b1e311..9d6131fb12d 100644 --- a/code/modules/species/station/monkey.dm +++ b/code/modules/species/station/monkey.dm @@ -1,5 +1,6 @@ /datum/species/monkey name = SPECIES_MONKEY + uid = SPECIES_ID_MONKEY name_plural = "Monkeys" greater_form = SPECIES_HUMAN @@ -11,8 +12,8 @@ damage_mask = 'icons/mob/species/monkey/damage_mask.dmi' blood_mask = 'icons/mob/species/monkey/blood_mask.dmi' - language = null - default_language = "Chimpanzee" + default_language = LANGUAGE_ID_CHIMPANZEE + intrinsic_languages = LANGUAGE_ID_CHIMPANZEE mob_size = MOB_SMALL has_fine_manipulation = 0 show_ssd = null @@ -34,7 +35,7 @@ brute_mod = 1.5 burn_mod = 1.5 - spawn_flags = SPECIES_IS_RESTRICTED + species_spawn_flags = SPECIES_SPAWN_RESTRICTED bump_flag = MONKEY swap_flags = MONKEY|SLIME|SIMPLE_ANIMAL @@ -72,12 +73,14 @@ /datum/species/monkey/tajaran name = SPECIES_MONKEY_TAJ name_plural = SPECIES_MONKEY_TAJ + uid = SPECIES_ID_FARWA icobase = 'icons/mob/species/monkey/body_farwa.dmi' deform = 'icons/mob/species/monkey/body_farwa.dmi' greater_form = SPECIES_TAJ - default_language = SPECIES_MONKEY_TAJ + default_language = LANGUAGE_ID_FARWA + intrinsic_languages = LANGUAGE_ID_FARWA flesh_color = "#AFA59E" base_color = "#333333" tail = "farwatail" @@ -85,12 +88,14 @@ /datum/species/monkey/skrell name = SPECIES_MONKEY_SKRELL name_plural = SPECIES_MONKEY_SKRELL + uid = SPECIES_ID_NEAERA icobase = 'icons/mob/species/monkey/body_neaera.dmi' deform = 'icons/mob/species/monkey/body_neaera.dmi' greater_form = SPECIES_SKRELL - default_language = LANGUAGE_NEAERA + default_language = LANGUAGE_ID_NEAERA + intrinsic_languages = LANGUAGE_ID_NEAERA flesh_color = "#8CD7A3" blood_color = "#1D2CBF" reagent_tag = IS_SKRELL @@ -99,13 +104,15 @@ /datum/species/monkey/unathi name = SPECIES_MONKEY_UNATHI name_plural = SPECIES_MONKEY_UNATHI + uid = SPECIES_ID_STOK icobase = 'icons/mob/species/monkey/body_stok.dmi' deform = 'icons/mob/species/monkey/body_stok.dmi' tail = "stoktail" greater_form = SPECIES_UNATHI - default_language = LANGUAGE_STOK + default_language = LANGUAGE_ID_STOK + intrinsic_languages = LANGUAGE_ID_STOK flesh_color = "#34AF10" base_color = "#066000" reagent_tag = IS_UNATHI @@ -113,28 +120,36 @@ /datum/species/monkey/shark name = SPECIES_MONKEY_AKULA name_plural = SPECIES_MONKEY_AKULA + uid = SPECIES_ID_SOBAKA + icobase = 'icons/mob/species/monkey/body_sobaka.dmi' deform = 'icons/mob/species/monkey/body_sobaka.dmi' tail = null //The tail is part of its body due to tail using the "icons/effects/species.dmi" file. It must be null, or they'll have a chimp tail. greater_form = SPECIES_AKULA - default_language = LANGUAGE_SKRELLIAN //Closest we have. + default_language = LANGUAGE_ID_SKRELL //Closest we have. + intrinsic_languages = LANGUAGE_ID_SKRELL /datum/species/monkey/sergal name = SPECIES_MONKEY_SERGAL greater_form = SPECIES_SERGAL + uid = SPECIES_ID_SERGLING + icobase = 'icons/mob/species/monkey/body_sergaling.dmi' deform = 'icons/mob/species/monkey/body_sergaling.dmi' tail = null - default_language = LANGUAGE_SAGARU + default_language = LANGUAGE_ID_NARAMADI + intrinsic_languages = LANGUAGE_ID_NARAMADI /datum/species/monkey/sparra name = SPECIES_MONKEY_NEVREAN name_plural = SPECIES_MONKEY_NEVREAN + uid = SPECIES_ID_SPARRA greater_form = SPECIES_NEVREAN icobase = 'icons/mob/species/monkey/body_sparra.dmi' deform = 'icons/mob/species/monkey/body_sparra.dmi' tail = null - default_language = LANGUAGE_BIRDSONG + default_language = LANGUAGE_ID_BIRDSONG + intrinsic_languages = LANGUAGE_ID_BIRDSONG /* Example @@ -155,12 +170,14 @@ /datum/species/monkey/vulpkanin name = SPECIES_MONKEY_VULPKANIN name_plural = SPECIES_MONKEY_VULPKANIN + uid = SPECIES_ID_WOLPIN icobase = 'icons/mob/species/monkey/body_wolpin.dmi' deform = 'icons/mob/species/monkey/body_wolpin.dmi' greater_form = SPECIES_VULPKANIN - default_language = LANGUAGE_CANILUNZT + default_language = LANGUAGE_ID_VULPKANIN + intrinsic_languages = LANGUAGE_ID_VULPKANIN flesh_color = "#966464" base_color = "#000000" tail = null diff --git a/code/modules/species/station/phoronoids.dm b/code/modules/species/station/phoronoids.dm index 68dc3f9ccd8..4a2a5aead32 100644 --- a/code/modules/species/station/phoronoids.dm +++ b/code/modules/species/station/phoronoids.dm @@ -1,5 +1,6 @@ /datum/species/phoronoid name = SPECIES_PHORONOID + uid = SPECIES_ID_PHORONOID name_plural = "Phoronoids" default_bodytype = BODYTYPE_PHORONOID @@ -8,9 +9,8 @@ preview_icon = 'icons/mob/species/phoronoid/preview.dmi' husk_icon = 'icons/mob/species/phoronoid/husk.dmi' - language = LANGUAGE_GALCOM - species_language = LANGUAGE_BONES - num_alternate_languages = 3 + intrinsic_languages = LANGUAGE_ID_PHORONOID + max_additional_languages = 3 name_language = null // name randomisers are fucking weird unarmed_types = list(/datum/unarmed_attack/stomp, /datum/unarmed_attack/kick, /datum/unarmed_attack/punch) @@ -25,8 +25,8 @@ rarity_value = 5 blood_color = "#FC2BC5" - flags = NO_SCAN | NO_MINOR_CUT | CONTAMINATION_IMMUNE - spawn_flags = SPECIES_IS_WHITELISTED | SPECIES_CAN_JOIN | SPECIES_WHITELIST_SELECTABLE + species_flags = NO_SCAN | NO_MINOR_CUT | CONTAMINATION_IMMUNE + species_spawn_flags = SPECIES_SPAWN_WHITELISTED | SPECIES_SPAWN_ALLOWED | SPECIES_SPAWN_WHITELIST_SELECTABLE species_appearance_flags = HAS_EYE_COLOR show_ssd = "completely motionless" diff --git a/code/modules/species/station/rapala.dm b/code/modules/species/station/rapala.dm index d7f23a65caa..c2512596f4d 100644 --- a/code/modules/species/station/rapala.dm +++ b/code/modules/species/station/rapala.dm @@ -1,6 +1,7 @@ /datum/species/rapala name = SPECIES_RAPALA name_plural = "Rapalans" + uid = SPECIES_ID_RAPALA icobase = 'icons/mob/species/rapala/body.dmi' deform = 'icons/mob/species/rapala/deformed_body.dmi' @@ -9,9 +10,9 @@ tail = "tail" icobase_tail = 1 - num_alternate_languages = 3 + max_additional_languages = 3 name_language = null - secondary_langs = list(LANGUAGE_BIRDSONG) + intrinsic_languages = LANGUAGE_ID_BIRDSONG color_mult = 1 max_age = 80 @@ -31,7 +32,7 @@ // wikilink = "" catalogue_data = list(/datum/category_item/catalogue/fauna/rapala) - spawn_flags = SPECIES_CAN_JOIN + species_spawn_flags = SPECIES_SPAWN_ALLOWED species_appearance_flags = HAS_HAIR_COLOR | HAS_LIPS | HAS_UNDERWEAR | HAS_SKIN_COLOR | HAS_EYE_COLOR heat_discomfort_strings = list( diff --git a/code/modules/species/station/standard/akula.dm b/code/modules/species/station/standard/akula.dm index c26cdb3f944..137072c39f0 100644 --- a/code/modules/species/station/standard/akula.dm +++ b/code/modules/species/station/standard/akula.dm @@ -1,4 +1,5 @@ /datum/species/akula + uid = SPECIES_ID_AKULA name = SPECIES_AKULA name_plural = SPECIES_AKULA //It's singular and plural. English is weird. primitive_form = SPECIES_MONKEY_AKULA @@ -7,6 +8,7 @@ deform = 'icons/mob/species/akula/deformed_body.dmi' preview_icon = 'icons/mob/species/akula/preview.dmi' husk_icon = 'icons/mob/species/akula/husk.dmi' + default_bodytype = BODYTYPE_AKULA tail = "tail" icobase_tail = 1 @@ -25,9 +27,9 @@ wikilink = "https://citadel-station.net/wikiRP/index.php?title=Akula" catalogue_data = list(/datum/category_item/catalogue/fauna/akula) - num_alternate_languages = 3 - name_language = LANGUAGE_SKRELLIAN - secondary_langs = list(LANGUAGE_SKRELLIAN) + max_additional_languages = 3 + name_language = LANGUAGE_ID_SKRELL + intrinsic_languages = LANGUAGE_ID_SKRELL assisted_langs = list(LANGUAGE_EAL, LANGUAGE_ROOTLOCAL, LANGUAGE_ROOTGLOBAL, LANGUAGE_VOX) // darksight = 8 @@ -40,7 +42,7 @@ water_movement = -4 max_age = 80 - spawn_flags = SPECIES_CAN_JOIN + species_spawn_flags = SPECIES_SPAWN_ALLOWED species_appearance_flags = HAS_HAIR_COLOR | HAS_LIPS | HAS_UNDERWEAR | HAS_SKIN_COLOR | HAS_EYE_COLOR flesh_color = "#AFA59E" diff --git a/code/modules/species/station/standard/harpy.dm b/code/modules/species/station/standard/harpy.dm index 285b8753728..ade9b15a494 100644 --- a/code/modules/species/station/standard/harpy.dm +++ b/code/modules/species/station/standard/harpy.dm @@ -1,4 +1,5 @@ /datum/species/harpy + uid = SPECIES_ID_HARPY name = SPECIES_RAPALA name_plural = "Rapalans" icobase = 'icons/mob/human_races/r_harpy_vr.dmi' @@ -6,7 +7,7 @@ tail = "tail" icobase_tail = 1 unarmed_types = list(/datum/unarmed_attack/stomp, /datum/unarmed_attack/kick, /datum/unarmed_attack/punch, /datum/unarmed_attack/bite) - num_alternate_languages = 3 + max_additional_languages = 3 secondary_langs = list(LANGUAGE_BIRDSONG) name_language = null color_mult = 1 @@ -29,7 +30,7 @@ catalogue_data = list(/datum/category_item/catalogue/fauna/rapala) - spawn_flags = SPECIES_CAN_JOIN + species_spawn_flags = SPECIES_SPAWN_ALLOWED species_appearance_flags = HAS_HAIR_COLOR | HAS_LIPS | HAS_UNDERWEAR | HAS_SKIN_COLOR | HAS_EYE_COLOR diff --git a/code/modules/species/station/standard/human.dm b/code/modules/species/station/standard/human.dm index d34bd852e56..ec4ddfe541e 100644 --- a/code/modules/species/station/standard/human.dm +++ b/code/modules/species/station/standard/human.dm @@ -1,4 +1,7 @@ /datum/species/human + id = SPECIES_ID_HUMAN + uid = SPECIES_ID_HUMAN + category = "Human" name = SPECIES_HUMAN name_plural = "Humans" primitive_form = SPECIES_MONKEY @@ -12,9 +15,14 @@ worlds tumultous at best." catalogue_data = list(/datum/category_item/catalogue/fauna/humans) - num_alternate_languages = 3 - species_language = LANGUAGE_SOL_COMMON - secondary_langs = list(LANGUAGE_SOL_COMMON, LANGUAGE_TERMINUS) + max_additional_languages = 3 + intrinsic_languages = list( + LANGUAGE_ID_COMMON, + LANGUAGE_ID_HUMAN + ) + whitelist_languages = list( + LANGUAGE_ID_HUMAN_SLAVIC + ) name_language = null // Use the first-name last-name generator rather than a language scrambler assisted_langs = list(LANGUAGE_EAL, LANGUAGE_SKRELLIAN, LANGUAGE_SKRELLIANFAR, LANGUAGE_ROOTLOCAL, LANGUAGE_ROOTGLOBAL, LANGUAGE_VOX) @@ -24,7 +32,7 @@ health_hud_intensity = 1.5 - spawn_flags = SPECIES_CAN_JOIN + species_spawn_flags = SPECIES_SPAWN_ALLOWED has_organ = list( O_HEART = /obj/item/organ/internal/heart, diff --git a/code/modules/species/station/standard/human_subspecies.dm b/code/modules/species/station/standard/human_subspecies.dm index 42929ee31ae..d31f22b5091 100644 --- a/code/modules/species/station/standard/human_subspecies.dm +++ b/code/modules/species/station/standard/human_subspecies.dm @@ -1,4 +1,5 @@ /datum/species/human/gravworlder + uid = SPECIES_ID_HUMAN_GRAV name = SPECIES_HUMAN_GRAV name_plural = "grav-adapted Humans" @@ -26,8 +27,8 @@ total_health = 130 hunger_factor = 0.075//50% more hungry - flags = NO_MINOR_CUT - spawn_flags = SPECIES_CAN_JOIN + species_flags = NO_MINOR_CUT + species_spawn_flags = SPECIES_SPAWN_ALLOWED species_appearance_flags = HAS_HAIR_COLOR | HAS_SKIN_COLOR | HAS_LIPS | HAS_UNDERWEAR | HAS_EYE_COLOR color_mult = 1 @@ -49,6 +50,7 @@ ) /datum/species/human/spacer + uid = SPECIES_ID_HUMAN_SPACE name = SPECIES_HUMAN_SPACER name_plural = "space-adapted Humans" @@ -73,7 +75,7 @@ slowdown = -0.1//Minor speedboost item_slowdown_mod = 1.05 //Minor slowdown - spawn_flags = SPECIES_CAN_JOIN + species_spawn_flags = SPECIES_SPAWN_ALLOWED species_appearance_flags = HAS_HAIR_COLOR | HAS_SKIN_COLOR | HAS_LIPS | HAS_UNDERWEAR | HAS_EYE_COLOR color_mult = 1 @@ -95,6 +97,7 @@ ) /datum/species/human/vatgrown + uid = SPECIES_ID_HUMAN_VAT name = SPECIES_HUMAN_VATBORN name_plural = SPECIES_HUMAN_VATBORN @@ -113,7 +116,7 @@ total_health = 115 hunger_factor = 0.35//less hungry - spawn_flags = SPECIES_CAN_JOIN + species_spawn_flags = SPECIES_SPAWN_ALLOWED species_appearance_flags = HAS_HAIR_COLOR | HAS_SKIN_COLOR | HAS_LIPS | HAS_UNDERWEAR | HAS_EYE_COLOR color_mult = 1 diff --git a/code/modules/species/station/standard/moth.dm b/code/modules/species/station/standard/moth.dm index 1bfca5f3166..78359c7dfb2 100644 --- a/code/modules/species/station/standard/moth.dm +++ b/code/modules/species/station/standard/moth.dm @@ -8,6 +8,7 @@ GLOBAL_LIST_INIT(moth_lore_data, init_moth_lore()) name = SPECIES_MOTH uid = SPECIES_ID_MOTH id = SPECIES_ID_MOTH + category = "Dnin-Nepid (Moth)" abstract_type = /datum/species/moth name_plural = "Dnin-Nepids" examine_name = "Dnin-Nepid" @@ -29,12 +30,10 @@ GLOBAL_LIST_INIT(moth_lore_data, init_moth_lore()) burn_mod = 1 metabolic_rate = 0.5 gluttonous = 0 - num_alternate_languages = 3 + max_additional_languages = 3 rarity_value = 2 - species_language = list( - LANGUAGE_LUINIMMA, - ) - name_language = LANGUAGE_LUINIMMA + intrinsic_languages = LANGUAGE_ID_LUINIMMA + name_language = LANGUAGE_ID_LUINIMMA // sensitive health_hud_intensity = 1.5 @@ -111,7 +110,7 @@ GLOBAL_LIST_INIT(moth_lore_data, init_moth_lore()) move_trail = /obj/effect/debris/cleanable/blood/tracks/claw - spawn_flags = SPECIES_CAN_JOIN + species_spawn_flags = SPECIES_SPAWN_ALLOWED primitive_form = null species_appearance_flags = HAS_HAIR_COLOR | HAS_UNDERWEAR | HAS_SKIN_COLOR | HAS_EYE_COLOR @@ -158,7 +157,7 @@ GLOBAL_LIST_INIT(moth_lore_data, init_moth_lore()) /datum/species/moth/dark name = SPECIES_MOTH_DARK uid = SPECIES_ID_MOTH_DARK - spawn_flags = SPECIES_CAN_JOIN + species_spawn_flags = SPECIES_SPAWN_ALLOWED // darksight, but weak to light darksight = 7 @@ -168,7 +167,7 @@ GLOBAL_LIST_INIT(moth_lore_data, init_moth_lore()) /datum/species/moth/light name = SPECIES_MOTH_LIGHT uid = SPECIES_ID_MOTH_LIGHT - spawn_flags = SPECIES_CAN_JOIN + species_spawn_flags = SPECIES_SPAWN_ALLOWED // hardy, but no darksight darksight = 2 diff --git a/code/modules/species/station/standard/naramadi.dm b/code/modules/species/station/standard/naramadi.dm index 6391b85adcf..e31e99f5b16 100644 --- a/code/modules/species/station/standard/naramadi.dm +++ b/code/modules/species/station/standard/naramadi.dm @@ -1,6 +1,8 @@ /datum/species/naramadi name = SPECIES_SERGAL + uid = SPECIES_ID_NARAMADI name_plural = "Naramadi" + category = "Naramadi" default_bodytype = BODYTYPE_SERGAL icobase = 'icons/mob/species/naramadi/body.dmi' deform = 'icons/mob/species/naramadi/deformed_body.dmi' @@ -15,9 +17,9 @@ //burn_mod = 1.15 //gluttonous = 1 hunger_factor = 0.1 // By math should be half of the Teshari Nutrition drain - num_alternate_languages = 3 - secondary_langs = list(LANGUAGE_SAGARU) - name_language = LANGUAGE_SAGARU + max_additional_languages = 3 + intrinsic_languages = LANGUAGE_ID_NARAMADI + name_language = LANGUAGE_ID_NARAMADI color_mult = 1 max_age = 120 @@ -33,7 +35,7 @@ primitive_form = SPECIES_MONKEY_SERGAL - spawn_flags = SPECIES_CAN_JOIN + species_spawn_flags = SPECIES_SPAWN_ALLOWED species_appearance_flags = HAS_HAIR_COLOR | HAS_LIPS | HAS_UNDERWEAR | HAS_SKIN_COLOR | HAS_EYE_COLOR flesh_color = "#AFA59E" diff --git a/code/modules/species/station/standard/nevrean.dm b/code/modules/species/station/standard/nevrean.dm index aaeb6885b71..f1dbcdff094 100644 --- a/code/modules/species/station/standard/nevrean.dm +++ b/code/modules/species/station/standard/nevrean.dm @@ -1,4 +1,5 @@ /datum/species/nevrean + uid = SPECIES_ID_NEVREAN name = SPECIES_NEVREAN name_plural = "Nevreans" primitive_form = SPECIES_MONKEY_NEVREAN @@ -21,9 +22,9 @@ catalogue_data = list(/datum/category_item/catalogue/fauna/nevrean) - num_alternate_languages = 3 - name_language = LANGUAGE_BIRDSONG - secondary_langs = list(LANGUAGE_BIRDSONG) + max_additional_languages = 3 + name_language = LANGUAGE_ID_BIRDSONG + intrinsic_languages = LANGUAGE_ID_BIRDSONG //darksight = 8 //slowdown = -0.5 @@ -34,7 +35,7 @@ color_mult = 1 max_age = 80 - spawn_flags = SPECIES_CAN_JOIN + species_spawn_flags = SPECIES_SPAWN_ALLOWED species_appearance_flags = HAS_HAIR_COLOR | HAS_LIPS | HAS_UNDERWEAR | HAS_SKIN_COLOR | HAS_EYE_COLOR flesh_color = "#AFA59E" diff --git a/code/modules/species/station/standard/shadekin.dm b/code/modules/species/station/standard/shadekin.dm index c1ff93c3a76..d7f58de05da 100644 --- a/code/modules/species/station/standard/shadekin.dm +++ b/code/modules/species/station/standard/shadekin.dm @@ -1,6 +1,8 @@ /datum/species/crew_shadekin + uid = SPECIES_ID_SHADEKIN_BLACK name = SPECIES_SHADEKIN_CREW name_plural = SPECIES_SHADEKIN_CREW + category = "Special" icobase = 'icons/mob/human_races/r_shadekin_vr.dmi' deform = 'icons/mob/human_races/r_shadekin_vr.dmi' tail = "tail" @@ -15,7 +17,7 @@ name_language = LANGUAGE_SHADEKIN species_language = LANGUAGE_SHADEKIN secondary_langs = list(LANGUAGE_SHADEKIN) - num_alternate_languages = 3 + max_additional_languages = 3 unarmed_types = list(/datum/unarmed_attack/stomp, /datum/unarmed_attack/kick, /datum/unarmed_attack/claws, /datum/unarmed_attack/bite/sharp) rarity_value = 5 //INTERDIMENSIONAL FLUFFERS @@ -46,7 +48,7 @@ heat_level_3 = 1150 flags = NO_SCAN | NO_MINOR_CUT | CONTAMINATION_IMMUNE //shadekin biology is still unknown to the universe (unless some bullshit lore says otherwise); CitadelRP: Now able to walk over shards of glass like regular shadekins - spawn_flags = SPECIES_CAN_JOIN | SPECIES_IS_WHITELISTED | SPECIES_WHITELIST_SELECTABLE + species_spawn_flags = SPECIES_SPAWN_ALLOWED | SPECIES_SPAWN_WHITELISTED | SPECIES_SPAWN_WHITELIST_SELECTABLE reagent_tag = IS_SHADEKIN // for shadekin-unique chem interactions diff --git a/code/modules/species/station/standard/skrell.dm b/code/modules/species/station/standard/skrell.dm index b8c93f393d1..491ba67450a 100644 --- a/code/modules/species/station/standard/skrell.dm +++ b/code/modules/species/station/standard/skrell.dm @@ -1,4 +1,5 @@ /datum/species/skrell + uid = SPECIES_ID_SKRELL name = SPECIES_SKRELL name_plural = SPECIES_SKRELL primitive_form = SPECIES_MONKEY_SKRELL @@ -18,10 +19,14 @@ wikilink = "https://citadel-station.net/wikiRP/index.php?title=Skrell" catalogue_data = list(/datum/category_item/catalogue/fauna/skrell) - num_alternate_languages = 3 - name_language = LANGUAGE_SKRELLIAN - species_language = LANGUAGE_SKRELLIAN - secondary_langs = list(LANGUAGE_SKRELLIAN, LANGUAGE_SCHECHI) + max_additional_languages = 3 + name_language = LANGUAGE_ID_SKRELL + intrinsic_languages = LANGUAGE_ID_SKRELL + whitelist_languages = list( + LANGUAGE_ID_SKRELL, + LANGUAGE_ID_SKRELL_ALT, + LANGUAGE_ID_TESHARI + ) assisted_langs = list(LANGUAGE_EAL, LANGUAGE_ROOTLOCAL, LANGUAGE_ROOTGLOBAL, LANGUAGE_VOX) color_mult = 1 @@ -41,7 +46,7 @@ ambiguous_genders = TRUE - spawn_flags = SPECIES_CAN_JOIN + species_spawn_flags = SPECIES_SPAWN_ALLOWED species_appearance_flags = HAS_HAIR_COLOR | HAS_LIPS | HAS_UNDERWEAR | HAS_SKIN_COLOR flesh_color = "#8CD7A3" diff --git a/code/modules/species/station/standard/tajaran.dm b/code/modules/species/station/standard/tajaran.dm index 01ae9e55ff1..b9ecc594727 100644 --- a/code/modules/species/station/standard/tajaran.dm +++ b/code/modules/species/station/standard/tajaran.dm @@ -1,6 +1,8 @@ /datum/species/tajaran + uid = SPECIES_ID_TAJARAN name = SPECIES_TAJ name_plural = "Tajaran" + category = "Tajaran" default_bodytype = BODYTYPE_TAJARAN icobase = 'icons/mob/species/tajaran/body_greyscale.dmi' @@ -10,10 +12,14 @@ tail = "tajtail" tail_animation = 'icons/mob/species/tajaran/tail_greyscale.dmi' - num_alternate_languages = 3 - name_language = LANGUAGE_SIIK - species_language = LANGUAGE_SIIK - secondary_langs = list(LANGUAGE_SIIK, LANGUAGE_AKHANI, LANGUAGE_ALAI) + max_additional_languages = 3 + name_language = LANGUAGE_ID_TAJARAN + intrinsic_languages = LANGUAGE_ID_TAJARAN + whitelist_languages = list( + LANGUAGE_ID_TAJARAN, + LANGUAGE_ID_TAJARAN_ALT, + LANGUAGE_ID_TAJARAN_SIGN + ) darksight = 8 slowdown = -0.5 @@ -64,7 +70,7 @@ primitive_form = SPECIES_MONKEY_TAJ - spawn_flags = SPECIES_CAN_JOIN + species_spawn_flags = SPECIES_SPAWN_ALLOWED species_appearance_flags = HAS_HAIR_COLOR | HAS_LIPS | HAS_UNDERWEAR | HAS_SKIN_COLOR | HAS_EYE_COLOR flesh_color = "#AFA59E" diff --git a/code/modules/species/station/standard/teshari.dm b/code/modules/species/station/standard/teshari.dm index 95da386559f..70d8a3f8155 100644 --- a/code/modules/species/station/standard/teshari.dm +++ b/code/modules/species/station/standard/teshari.dm @@ -1,6 +1,8 @@ /datum/species/teshari + uid = SPECIES_ID_TESHARI name = SPECIES_TESHARI default_bodytype = BODYTYPE_TESHARI + category = "Teshari" name_plural = "Tesharii" uid = SPECIES_ID_TESHARI @@ -23,10 +25,13 @@ tail_hair = "feathers" icobase_tail = 1 - num_alternate_languages = 3 - name_language = LANGUAGE_SCHECHI - species_language = LANGUAGE_SCHECHI - secondary_langs = list(LANGUAGE_SCHECHI, LANGUAGE_SKRELLIAN) + max_additional_languages = 3 + name_language = LANGUAGE_ID_TESHARI + intrinsic_languages = LANGUAGE_ID_TESHARI + whitelist_languages = list( + LANGUAGE_ID_TESHARI, + LANGUAGE_ID_SKRELL + ) male_cough_sounds = list('sound/effects/mob_effects/tesharicougha.ogg', 'sound/effects/mob_effects/tesharicoughb.ogg') female_cough_sounds = list('sound/effects/mob_effects/tesharicougha.ogg', 'sound/effects/mob_effects/tesharicoughb.ogg') @@ -66,7 +71,7 @@ ambiguous_genders = TRUE - spawn_flags = SPECIES_CAN_JOIN + species_spawn_flags = SPECIES_SPAWN_ALLOWED species_appearance_flags = HAS_HAIR_COLOR | HAS_SKIN_COLOR | HAS_EYE_COLOR bump_flag = MONKEY diff --git a/code/modules/species/station/standard/unathi.dm b/code/modules/species/station/standard/unathi.dm index fa2f3ea07e7..5b8fb8a5927 100644 --- a/code/modules/species/station/standard/unathi.dm +++ b/code/modules/species/station/standard/unathi.dm @@ -1,5 +1,7 @@ /datum/species/unathi + uid = SPECIES_ID_UNATHI name = SPECIES_UNATHI + category = "Unathi" name_plural = SPECIES_UNATHI primitive_form = SPECIES_MONKEY_UNATHI default_bodytype = BODYTYPE_UNATHI @@ -22,10 +24,9 @@ wikilink = "https://citadel-station.net/wikiRP/index.php?title=Unathi" catalogue_data = list(/datum/category_item/catalogue/fauna/unathi) - num_alternate_languages = 3 - name_language = LANGUAGE_UNATHI - species_language = LANGUAGE_UNATHI - secondary_langs = list(LANGUAGE_UNATHI) + max_additional_languages = 3 + name_language = LANGUAGE_ID_UNATHI + intrinsic_languages = LANGUAGE_ID_UNATHI ambiguous_genders = TRUE gluttonous = 1 @@ -67,7 +68,7 @@ body_temperature = null //mesothermic is basically cold-blooded right? - spawn_flags = SPECIES_CAN_JOIN // Species_can_join is the only spawn flag all the races get, so that none of them will be whitelist only if whitelist is enabled. + species_spawn_flags = SPECIES_SPAWN_ALLOWED // Species_can_join is the only spawn flag all the races get, so that none of them will be whitelist only if whitelist is enabled. species_appearance_flags = HAS_HAIR_COLOR | HAS_LIPS | HAS_UNDERWEAR | HAS_SKIN_COLOR | HAS_EYE_COLOR color_mult = 1 diff --git a/code/modules/species/station/standard/vulpkanin.dm b/code/modules/species/station/standard/vulpkanin.dm index 903e73a72be..25b0eaa8ade 100644 --- a/code/modules/species/station/standard/vulpkanin.dm +++ b/code/modules/species/station/standard/vulpkanin.dm @@ -1,4 +1,5 @@ /datum/species/vulpkanin + uid = SPECIES_ID_VULPKANIN name = SPECIES_VULPKANIN name_plural = SPECIES_VULPKANIN primitive_form = SPECIES_MONKEY_VULPKANIN @@ -12,9 +13,9 @@ tail = "vulptail" tail_animation = 'icons/mob/clothing/species/vulpkanin/tail.dmi' // probably need more than just one of each, but w/e - num_alternate_languages = 3 - name_language = LANGUAGE_CANILUNZT - secondary_langs = list(LANGUAGE_CANILUNZT) + max_additional_languages = 3 + name_language = LANGUAGE_ID_VULPKANIN + intrinsic_languages = LANGUAGE_ID_VULPKANIN darksight = 5 //worse than cats, but better than lizards. -- Poojawa // gluttonous = 1 @@ -33,7 +34,7 @@ primitive_form = SPECIES_MONKEY_VULPKANIN - spawn_flags = SPECIES_CAN_JOIN + species_spawn_flags = SPECIES_SPAWN_ALLOWED species_appearance_flags = HAS_HAIR_COLOR | HAS_LIPS | HAS_UNDERWEAR | HAS_SKIN_COLOR | HAS_EYE_COLOR flesh_color = "#966464" diff --git a/code/modules/species/station/standard/zaddat.dm b/code/modules/species/station/standard/zaddat.dm index b7064e8ff6c..b1071dd827b 100644 --- a/code/modules/species/station/standard/zaddat.dm +++ b/code/modules/species/station/standard/zaddat.dm @@ -1,4 +1,5 @@ /datum/species/zaddat + uid = SPECIES_ID_ZADDAT name = SPECIES_ZADDAT name_plural = SPECIES_ZADDAT icobase = 'icons/mob/species/zaddat/body.dmi' @@ -15,10 +16,13 @@ gluttonous = 0 taste_sensitivity = TASTE_SENSITIVE - num_alternate_languages = 3 - name_language = LANGUAGE_ZADDAT - species_language = LANGUAGE_ZADDAT - secondary_langs = list(LANGUAGE_ZADDAT, LANGUAGE_UNATHI) + max_additional_languages = 3 + name_language = LANGUAGE_ID_ZADDAT + intrinsic_languages = LANGUAGE_ID_ZADDAT + whitelist_languages = list( + LANGUAGE_ID_ZADDAT, + LANGUAGE_ID_UNATHI + ) assisted_langs = list(LANGUAGE_EAL, LANGUAGE_TERMINUS, LANGUAGE_SKRELLIANFAR, LANGUAGE_ROOTLOCAL, LANGUAGE_ROOTGLOBAL, LANGUAGE_VOX, LANGUAGE_SOL_COMMON, LANGUAGE_AKHANI, LANGUAGE_SIIK, LANGUAGE_GUTTER) //limited vocal range; can talk Unathi and magical Galcom but not much else @@ -50,7 +54,7 @@ genders = list(FEMALE, PLURAL) //females are polyp-producing, infertile females and males are nigh-identical - spawn_flags = SPECIES_CAN_JOIN + species_spawn_flags = SPECIES_SPAWN_ALLOWED species_appearance_flags = null flesh_color = "#AFA59E" diff --git a/code/modules/species/station/standard/zorren.dm b/code/modules/species/station/standard/zorren.dm index d40ce999718..820982e601e 100644 --- a/code/modules/species/station/standard/zorren.dm +++ b/code/modules/species/station/standard/zorren.dm @@ -1,4 +1,6 @@ /datum/species/hi_zoxxen + uid = SPECIES_ID_ZORREN_HIGH + id = SPECIES_ID_ZORREN name = SPECIES_ZORREN_HIGH name_plural = "Zorren" //primitive_form = "" //We don't have fox-monkey sprites. @@ -9,9 +11,9 @@ tail = "tail" icobase_tail = 1 - num_alternate_languages = 3 - secondary_langs = list(LANGUAGE_TERMINUS) - name_language = LANGUAGE_TERMINUS + max_additional_languages = 3 + intrinsic_languages = LANGUAGE_ID_TERMINUS + name_language = LANGUAGE_ID_TERMINUS inherent_verbs = list(/mob/living/carbon/human/proc/lick_wounds) max_age = 80 @@ -33,7 +35,7 @@ ) - spawn_flags = SPECIES_CAN_JOIN + species_spawn_flags = SPECIES_SPAWN_ALLOWED species_appearance_flags = HAS_HAIR_COLOR | HAS_LIPS | HAS_UNDERWEAR | HAS_SKIN_COLOR | HAS_EYE_COLOR flesh_color = "#AFA59E" @@ -60,6 +62,8 @@ ) /datum/species/fl_zorren + uid = SPECIES_ID_ZORREN_FLAT + id = SPECIES_ID_ZORREN name = SPECIES_ZORREN_FLAT name_plural = "Zorren" //primitive_form = "" //We don't have fennec-monkey sprites. @@ -70,9 +74,9 @@ tail = "tail" icobase_tail = 1 - num_alternate_languages = 3 - secondary_langs = list(LANGUAGE_TERMINUS) - name_language = LANGUAGE_TERMINUS + max_additional_languages = 3 + intrinsic_languages = LANGUAGE_ID_TERMINUS + name_language = LANGUAGE_ID_TERMINUS inherent_verbs = list(/mob/living/carbon/human/proc/lick_wounds) max_age = 80 @@ -95,7 +99,7 @@ /datum/category_item/catalogue/fauna/flatzorren, ) - spawn_flags = SPECIES_CAN_JOIN + species_spawn_flags = SPECIES_SPAWN_ALLOWED species_appearance_flags = HAS_HAIR_COLOR | HAS_LIPS | HAS_UNDERWEAR | HAS_SKIN_COLOR | HAS_EYE_COLOR flesh_color = "#AFA59E" diff --git a/code/modules/species/station/vasilissan.dm b/code/modules/species/station/vasilissan.dm index 430d2331716..718f0a894df 100644 --- a/code/modules/species/station/vasilissan.dm +++ b/code/modules/species/station/vasilissan.dm @@ -1,6 +1,7 @@ /datum/species/vasilissan //These actually look pretty damn spooky! name = SPECIES_VASILISSAN name_plural = "Vasilissans" + uid = SPECIES_ID_VASILISSAN icobase = 'icons/mob/species/vasilissan/body.dmi' deform = 'icons/mob/species/vasilissan/deformed_body.dmi' @@ -14,8 +15,8 @@ brute_mod = 0.8 // 20% brute damage reduction burn_mod = 1.15 // 15% burn damage increase. They're spiders. Aerosol can+lighter = dead spiders. - num_alternate_languages = 2 - secondary_langs = list(LANGUAGE_VESPINAE) + max_additional_languages = 2 + intrinsic_languages = LANGUAGE_ID_VASILISSAN is_weaver = TRUE silk_reserve = 500 @@ -49,8 +50,8 @@ //primitive_form = SPECIES_MONKEY //I dunno. Replace this in the future. - flags = NO_MINOR_CUT | CONTAMINATION_IMMUNE - spawn_flags = SPECIES_CAN_JOIN + species_flags = NO_MINOR_CUT | CONTAMINATION_IMMUNE + species_spawn_flags = SPECIES_SPAWN_ALLOWED species_appearance_flags = HAS_HAIR_COLOR | HAS_UNDERWEAR | HAS_SKIN_COLOR | HAS_EYE_COLOR color_mult = 1 diff --git a/code/modules/species/station/werebeast.dm b/code/modules/species/station/werebeast.dm index e5d8a33784c..b61a7e59430 100644 --- a/code/modules/species/station/werebeast.dm +++ b/code/modules/species/station/werebeast.dm @@ -1,5 +1,6 @@ /datum/species/werebeast name = SPECIES_WEREBEAST + uid = SPECIES_ID_WEREBEAST name_plural = "Werebeasts" primitive_form = SPECIES_MONKEY_VULPKANIN default_bodytype = BODYTYPE_WEREBEAST @@ -10,9 +11,9 @@ preview_icon = 'icons/mob/species/werebeast/preview.dmi' tail = "tail" - num_alternate_languages = 3 - secondary_langs = list(LANGUAGE_CANILUNZT) - name_language = LANGUAGE_CANILUNZT + max_additional_languages = 3 + intrinsic_languages = LANGUAGE_ID_VULPKANIN + name_language = LANGUAGE_ID_VULPKANIN total_health = 200 brute_mod = 0.85 @@ -34,7 +35,7 @@ wikilink="N/A" catalogue_data = list(/datum/category_item/catalogue/fauna/vulpkanin) - spawn_flags = SPECIES_CAN_JOIN | SPECIES_IS_WHITELISTED | SPECIES_WHITELIST_SELECTABLE + species_spawn_flags = SPECIES_SPAWN_ALLOWED | SPECIES_SPAWN_WHITELISTED | SPECIES_SPAWN_WHITELIST_SELECTABLE species_appearance_flags = HAS_HAIR_COLOR | HAS_SKIN_COLOR | HAS_EYE_COLOR inherent_verbs = list( diff --git a/code/modules/species/station/xenomorph_hybrids/xeno_hybrids.dm b/code/modules/species/station/xenomorph_hybrids/xeno_hybrids.dm index e77dc6ed6d7..97c73ea2005 100644 --- a/code/modules/species/station/xenomorph_hybrids/xeno_hybrids.dm +++ b/code/modules/species/station/xenomorph_hybrids/xeno_hybrids.dm @@ -1,6 +1,7 @@ /datum/species/xenohybrid name = SPECIES_XENOHYBRID name_plural = "Xenomorph Hybrids" + uid = SPECIES_ID_XENOHYBRID default_bodytype = BODYTYPE_XENOHYBRID icobase = 'icons/mob/species/xenohybrid/body.dmi' @@ -9,7 +10,7 @@ tail = "tail" icobase_tail = 1 unarmed_types = list(/datum/unarmed_attack/stomp, /datum/unarmed_attack/kick, /datum/unarmed_attack/claws, /datum/unarmed_attack/bite/sharp) - num_alternate_languages = 2 + max_additional_languages = 2 max_age = 150//Xenomorphs probably get pretty old if not shot dead @@ -22,15 +23,12 @@ catalogue_data = list(/datum/category_item/catalogue/fauna/xenohybrid) wikilink = "https://citadel-station.net/wikiRP/index.php?title=Race:_Neomorphs" - //primitive_form = "" //None for these guys - language = LANGUAGE_XENO - name_language = LANGUAGE_XENO - species_language = LANGUAGE_XENO - secondary_langs = list(LANGUAGE_XENO) - num_alternate_languages = 3 + intrinsic_languages = LANGUAGE_ID_XENOMORPH + name_language = LANGUAGE_ID_XENOMORPH + max_additional_languages = 3 - flags = NO_MINOR_CUT | CONTAMINATION_IMMUNE//Chitin like VASILISSANs should have the same flags - spawn_flags = SPECIES_CAN_JOIN | SPECIES_IS_WHITELISTED | SPECIES_WHITELIST_SELECTABLE + species_flags = NO_MINOR_CUT | CONTAMINATION_IMMUNE//Chitin like VASILISSANs should have the same flags + species_spawn_flags = SPECIES_SPAWN_ALLOWED | SPECIES_SPAWN_WHITELISTED | SPECIES_SPAWN_WHITELIST_SELECTABLE species_appearance_flags = HAS_HAIR_COLOR | HAS_LIPS | HAS_UNDERWEAR | HAS_SKIN_COLOR blood_color = "#12ff12" diff --git a/code/modules/species/virtual_reality/avatar.dm b/code/modules/species/virtual_reality/avatar.dm index 5d200edd842..1becaa34fc6 100644 --- a/code/modules/species/virtual_reality/avatar.dm +++ b/code/modules/species/virtual_reality/avatar.dm @@ -4,7 +4,8 @@ // ### // Species definition follows. /datum/species/shapeshifter/promethean/avatar - + uid = SPECIES_ID_VIRTUAL_REALITY + id = SPECIES_ID_VIRTUAL_REALITY name = SPECIES_VR name_plural = "Virtual Reality Avatars" blurb = "A 3-dimensional representation of some sort of animate object used to display the presence and actions of some-one or -thing using a virtual reality program." @@ -12,7 +13,7 @@ death_message = "flickers briefly, their gear falling in a heap on the floor around their motionless body." knockout_message = "has been knocked unconscious!" - spawn_flags = SPECIES_IS_RESTRICTED + species_spawn_flags = SPECIES_SPAWN_RESTRICTED speech_bubble_appearance = "cyber" diff --git a/code/modules/species/virtual_reality/opaque_form.dm b/code/modules/species/virtual_reality/opaque_form.dm index 4e71f6ee160..12b4d492fe8 100644 --- a/code/modules/species/virtual_reality/opaque_form.dm +++ b/code/modules/species/virtual_reality/opaque_form.dm @@ -3,6 +3,7 @@ /datum/species/shapeshifter/promethean/avatar/human name = SPECIES_VR_HUMAN + uid = SPECIES_ID_VIRTUAL_REALITY_HUMAN icobase = 'icons/mob/species/human/body.dmi' deform = 'icons/mob/species/human/deformed_body.dmi' species_appearance_flags = HAS_HAIR_COLOR | HAS_SKIN_COLOR | HAS_LIPS | HAS_UNDERWEAR | HAS_EYE_COLOR @@ -22,6 +23,7 @@ /datum/species/shapeshifter/promethean/avatar/unathi name = SPECIES_VR_UNATHI + uid = SPECIES_ID_VIRTUAL_REALITY_UNATHI icobase = 'icons/mob/species/unathi/body_greyscale.dmi' deform = 'icons/mob/species/unathi/deformed_body_greyscale.dmi' tail = "sogtail" @@ -43,6 +45,7 @@ /datum/species/shapeshifter/promethean/avatar/tajaran name = "Virtual Reality Tajaran" + uid = SPECIES_ID_VIRTUAL_REALITY_TAJARAN icobase = 'icons/mob/species/tajaran/body_greyscale.dmi' deform = 'icons/mob/species/tajaran/deformed_body_greyscale.dmi' tail = "tajtail" @@ -64,6 +67,7 @@ /datum/species/shapeshifter/promethean/avatar/skrell name = SPECIES_VR_SKRELL + uid = SPECIES_ID_VIRTUAL_REALITY_SKRELL icobase = 'icons/mob/species/skrell/body_greyscale.dmi' deform = 'icons/mob/species/skrell/deformed_body_greyscale.dmi' species_appearance_flags = HAS_HAIR_COLOR | HAS_LIPS | HAS_UNDERWEAR | HAS_SKIN_COLOR @@ -83,6 +87,7 @@ /datum/species/shapeshifter/promethean/avatar/teshari name = SPECIES_VR_TESHARI + uid = SPECIES_ID_VIRTUAL_REALITY_TESHARI icobase = 'icons/mob/species/teshari/body.dmi' deform = 'icons/mob/species/teshari/deformed_body.dmi' species_appearance_flags = HAS_HAIR_COLOR | HAS_SKIN_COLOR | HAS_EYE_COLOR @@ -101,6 +106,7 @@ ) /datum/species/shapeshifter/promethean/avatar/diona + uid = SPECIES_ID_VIRTUAL_REALITY_DIONA name = SPECIES_VR_DIONA icobase = 'icons/mob/species/diona/body.dmi' deform = 'icons/mob/species/diona/deformed_body.dmi' @@ -120,6 +126,7 @@ ) /datum/species/shapeshifter/promethean/avatar/monkey + uid = SPECIES_ID_VIRTUAL_REALITY_MONKEY name = SPECIES_VR_MONKEY icobase = 'icons/mob/species/monkey/body_monkey.dmi' deform = 'icons/mob/species/monkey/body_monkey.dmi' @@ -143,6 +150,7 @@ ) /datum/species/shapeshifter/promethean/avatar/vox + uid = SPECIES_ID_VIRTUAL_REALITY_VOX name = SPECIES_VR_VOX icobase = 'icons/mob/species/vox/body.dmi' deform = 'icons/mob/species/vox/deformed_body.dmi' @@ -162,6 +170,7 @@ ) /datum/species/shapeshifter/promethean/avatar/skeleton + uid = SPECIES_ID_VIRTUAL_REALITY_SKELETON name = SPECIES_VR_SKELETON icobase = 'icons/mob/species/human/skeleton.dmi' deform = 'icons/mob/species/human/skeleton.dmi' diff --git a/code/modules/species/station/station_special.dm b/code/modules/species/xenochimera/xenochimera.dm similarity index 97% rename from code/modules/species/station/station_special.dm rename to code/modules/species/xenochimera/xenochimera.dm index e611b78808e..ee8aa6c712e 100644 --- a/code/modules/species/station/station_special.dm +++ b/code/modules/species/xenochimera/xenochimera.dm @@ -1,13 +1,9 @@ -///////////////File for all snowflake/special races///////////////////////////// -/////Anything that is spectacularly special should be put in here/////////////// -//////////////////////////////////////////////////////////////////////////////// - - - /datum/species/shapeshifter/xenochimera //Scree's race. name = SPECIES_XENOCHIMERA name_plural = "Xenochimeras" base_species = SPECIES_XENOCHIMERA + uid = SPECIES_ID_XENOCHIMERA + category = "Special" selects_bodytype = TRUE @@ -18,8 +14,7 @@ tail = "tail" //Scree's tail. Can be disabled in the Species Customization tab by choosing "hide species specific tail sprite" icobase_tail = 1 - num_alternate_languages = 5 - secondary_langs = list("Sol Common") + max_additional_languages = 5 darksight = 8 //critters with instincts to hide in the dark need to see in the dark - about as good as tajara. slowdown = -0.2 //scuttly, but not as scuttly as a tajara or a teshari. @@ -88,8 +83,8 @@ SPECIES_MONKEY_SERGAL, SPECIES_MONKEY_NEVREAN, SPECIES_VOX, ) - flags = NO_SCAN | NO_INFECT | NO_DEFIB //Dying as a chimera is, quite literally, a death sentence. Well, if it wasn't for their revive, that is. - spawn_flags = SPECIES_CAN_JOIN | SPECIES_IS_WHITELISTED | SPECIES_WHITELIST_SELECTABLE //Whitelisted as restricted is broken. + species_flags = NO_SCAN | NO_INFECT | NO_DEFIB //Dying as a chimera is, quite literally, a death sentence. Well, if it wasn't for their revive, that is. + species_spawn_flags = SPECIES_SPAWN_ALLOWED | SPECIES_SPAWN_WHITELISTED | SPECIES_SPAWN_WHITELIST_SELECTABLE //Whitelisted as restricted is broken. species_appearance_flags = HAS_HAIR_COLOR | HAS_LIPS | HAS_UNDERWEAR | HAS_SKIN_COLOR | HAS_EYE_COLOR has_organ = list( @@ -427,7 +422,7 @@ return base_species /datum/species/shapeshifter/xenochimera/get_race_key(mob/living/carbon/human/H) - var/datum/species/real = name_static_species_meta(base_species) + var/datum/species/real = SScharacters.resolve_species_name(base_species) return real.real_race_key(H) /datum/species/shapeshifter/xenochimera/proc/update_xenochimera_hud(var/mob/living/carbon/human/H, var/danger, var/feral) diff --git a/code/modules/species/xenomorphs/alien_embryo.dm b/code/modules/species/xenomorphs/alien_embryo.dm index 202900eb40f..4781e3701a6 100644 --- a/code/modules/species/xenomorphs/alien_embryo.dm +++ b/code/modules/species/xenomorphs/alien_embryo.dm @@ -106,7 +106,7 @@ Des: Removes all infection images from aliens and places an infection image on a ----------------------------------------*/ /obj/item/alien_embryo/proc/RefreshInfectionImage() - for(var/mob/living/carbon/alien in player_list) + for(var/mob/living/carbon/alien in GLOB.player_list) if(!locate(/obj/item/organ/internal/xenos/hivenode) in alien.internal_organs) continue @@ -128,7 +128,7 @@ Des: Checks if the passed mob (C) is infected with the alien egg, then gives eac /obj/item/alien_embryo/proc/AddInfectionImages(var/mob/living/C) if(C) - for(var/mob/living/carbon/alien in player_list) + for(var/mob/living/carbon/alien in GLOB.player_list) if(!locate(/obj/item/organ/internal/xenos/hivenode) in alien.internal_organs) continue @@ -147,7 +147,7 @@ Des: Removes the alien infection image from all aliens in the world located in p if(C) - for(var/mob/living/carbon/alien in player_list) + for(var/mob/living/carbon/alien in GLOB.player_list) if(!locate(/obj/item/organ/internal/xenos/hivenode) in alien.internal_organs) continue diff --git a/code/modules/species/xenomorphs/alien_species.dm b/code/modules/species/xenomorphs/alien_species.dm index 399db089afe..3e03c53c4c3 100644 --- a/code/modules/species/xenomorphs/alien_species.dm +++ b/code/modules/species/xenomorphs/alien_species.dm @@ -1,10 +1,15 @@ //Stand-in until this is made more lore-friendly. /datum/species/xenos + id = SPECIES_ID_XENOMORPH + uid = SPECIES_ID_XENOMORPH name = SPECIES_XENO name_plural = "Xenomorphs" - default_language = LANGUAGE_XENO - language = "Hivemind" + default_language = LANGUAGE_ID_XENOMORPH + intrinsic_languages = list( + LANGUAGE_ID_XENOMORPH, + LANGUAGE_ID_XENOMORPH_HIVEMIND + ) assisted_langs = list() unarmed_types = list(/datum/unarmed_attack/claws/strong/xeno, /datum/unarmed_attack/bite/strong/xeno) hud_type = /datum/hud_data/alien @@ -24,8 +29,8 @@ cold_level_2 = -1 cold_level_3 = -1 - flags = NO_SCAN | NO_PAIN | NO_SLIP | NO_POISON | NO_MINOR_CUT | NO_INFECT - spawn_flags = SPECIES_IS_RESTRICTED + species_flags = NO_SCAN | NO_PAIN | NO_SLIP | NO_POISON | NO_MINOR_CUT | NO_INFECT + species_spawn_flags = SPECIES_SPAWN_RESTRICTED reagent_tag = IS_XENOS @@ -167,6 +172,7 @@ */ /datum/species/xenos/drone + uid = SPECIES_ID_XENOMORPH_DRONE name = SPECIES_XENO_DRONE caste_name = "drone" weeds_plasma_rate = 15 @@ -207,6 +213,7 @@ ..() /datum/species/xenos/hunter + uid = SPECIES_ID_XENOMORPH_HUNTER name = SPECIES_XENO_HUNTER weeds_plasma_rate = 5 caste_name = "hunter" @@ -237,6 +244,7 @@ ) /datum/species/xenos/sentinel + uid = SPECIES_ID_XENOMORPH_SENTINEL name = SPECIES_XENO_SENTINEL weeds_plasma_rate = 10 caste_name = "sentinel" @@ -269,7 +277,7 @@ ) /datum/species/xenos/queen - + uid = SPECIES_ID_XENOMORPH_QUEEN name = SPECIES_XENO_QUEEN total_health = 250 weeds_heal_rate = 5 diff --git a/code/modules/species/xenomorphs/xenomorphs.dm b/code/modules/species/xenomorphs/xenomorphs.dm index debc05b24af..2c44851e4fa 100644 --- a/code/modules/species/xenomorphs/xenomorphs.dm +++ b/code/modules/species/xenomorphs/xenomorphs.dm @@ -4,7 +4,7 @@ if(!target || !alien_caste) return var/mob/living/carbon/human/new_alien = new(target) - new_alien.set_species(species_type_by_name("Xenomorph [alien_caste]")) + new_alien.set_species("Xenomorph [alien_caste]") return new_alien /mob/living/carbon/human/xdrone diff --git a/code/modules/mob/new_player/sprite_accessories/body_markings.dm b/code/modules/sprite_accessories/body_markings.dm similarity index 100% rename from code/modules/mob/new_player/sprite_accessories/body_markings.dm rename to code/modules/sprite_accessories/body_markings.dm diff --git a/code/modules/mob/new_player/sprite_accessories/facial_hair/facial_hair.dm b/code/modules/sprite_accessories/facial_hair/facial_hair.dm similarity index 100% rename from code/modules/mob/new_player/sprite_accessories/facial_hair/facial_hair.dm rename to code/modules/sprite_accessories/facial_hair/facial_hair.dm diff --git a/code/modules/mob/new_player/sprite_accessories/facial_hair/tajaran_facial_hair.dm b/code/modules/sprite_accessories/facial_hair/tajaran_facial_hair.dm similarity index 100% rename from code/modules/mob/new_player/sprite_accessories/facial_hair/tajaran_facial_hair.dm rename to code/modules/sprite_accessories/facial_hair/tajaran_facial_hair.dm diff --git a/code/modules/mob/new_player/sprite_accessories/facial_hair/teshari_facial_hair.dm b/code/modules/sprite_accessories/facial_hair/teshari_facial_hair.dm similarity index 100% rename from code/modules/mob/new_player/sprite_accessories/facial_hair/teshari_facial_hair.dm rename to code/modules/sprite_accessories/facial_hair/teshari_facial_hair.dm diff --git a/code/modules/mob/new_player/sprite_accessories/facial_hair/unathi_facial_hair.dm b/code/modules/sprite_accessories/facial_hair/unathi_facial_hair.dm similarity index 100% rename from code/modules/mob/new_player/sprite_accessories/facial_hair/unathi_facial_hair.dm rename to code/modules/sprite_accessories/facial_hair/unathi_facial_hair.dm diff --git a/code/modules/mob/new_player/sprite_accessories/facial_hair/vox_facial_hair.dm b/code/modules/sprite_accessories/facial_hair/vox_facial_hair.dm similarity index 100% rename from code/modules/mob/new_player/sprite_accessories/facial_hair/vox_facial_hair.dm rename to code/modules/sprite_accessories/facial_hair/vox_facial_hair.dm diff --git a/code/modules/mob/new_player/sprite_accessories/facial_hair/vulpakin_facial_hair.dm b/code/modules/sprite_accessories/facial_hair/vulpakin_facial_hair.dm similarity index 100% rename from code/modules/mob/new_player/sprite_accessories/facial_hair/vulpakin_facial_hair.dm rename to code/modules/sprite_accessories/facial_hair/vulpakin_facial_hair.dm diff --git a/code/modules/mob/new_player/sprite_accessories/hair/hair.dm b/code/modules/sprite_accessories/hair/hair.dm similarity index 100% rename from code/modules/mob/new_player/sprite_accessories/hair/hair.dm rename to code/modules/sprite_accessories/hair/hair.dm diff --git a/code/modules/mob/new_player/sprite_accessories/hair/sergal_hair.dm b/code/modules/sprite_accessories/hair/sergal_hair.dm similarity index 100% rename from code/modules/mob/new_player/sprite_accessories/hair/sergal_hair.dm rename to code/modules/sprite_accessories/hair/sergal_hair.dm diff --git a/code/modules/mob/new_player/sprite_accessories/hair/shadekin.dm b/code/modules/sprite_accessories/hair/shadekin.dm similarity index 100% rename from code/modules/mob/new_player/sprite_accessories/hair/shadekin.dm rename to code/modules/sprite_accessories/hair/shadekin.dm diff --git a/code/modules/mob/new_player/sprite_accessories/hair/skrell_hair.dm b/code/modules/sprite_accessories/hair/skrell_hair.dm similarity index 100% rename from code/modules/mob/new_player/sprite_accessories/hair/skrell_hair.dm rename to code/modules/sprite_accessories/hair/skrell_hair.dm diff --git a/code/modules/mob/new_player/sprite_accessories/hair/tajaran_hair.dm b/code/modules/sprite_accessories/hair/tajaran_hair.dm similarity index 100% rename from code/modules/mob/new_player/sprite_accessories/hair/tajaran_hair.dm rename to code/modules/sprite_accessories/hair/tajaran_hair.dm diff --git a/code/modules/mob/new_player/sprite_accessories/hair/teshari_hair.dm b/code/modules/sprite_accessories/hair/teshari_hair.dm similarity index 100% rename from code/modules/mob/new_player/sprite_accessories/hair/teshari_hair.dm rename to code/modules/sprite_accessories/hair/teshari_hair.dm diff --git a/code/modules/mob/new_player/sprite_accessories/hair/unathi_hair.dm b/code/modules/sprite_accessories/hair/unathi_hair.dm similarity index 100% rename from code/modules/mob/new_player/sprite_accessories/hair/unathi_hair.dm rename to code/modules/sprite_accessories/hair/unathi_hair.dm diff --git a/code/modules/mob/new_player/sprite_accessories/hair/vox_hair.dm b/code/modules/sprite_accessories/hair/vox_hair.dm similarity index 100% rename from code/modules/mob/new_player/sprite_accessories/hair/vox_hair.dm rename to code/modules/sprite_accessories/hair/vox_hair.dm diff --git a/code/modules/mob/new_player/sprite_accessories/hair/vulpakin_hair.dm b/code/modules/sprite_accessories/hair/vulpakin_hair.dm similarity index 100% rename from code/modules/mob/new_player/sprite_accessories/hair/vulpakin_hair.dm rename to code/modules/sprite_accessories/hair/vulpakin_hair.dm diff --git a/code/modules/mob/new_player/sprite_accessories/hair/xenomorph_hybrid_domes.dm b/code/modules/sprite_accessories/hair/xenomorph_hybrid_domes.dm similarity index 100% rename from code/modules/mob/new_player/sprite_accessories/hair/xenomorph_hybrid_domes.dm rename to code/modules/sprite_accessories/hair/xenomorph_hybrid_domes.dm diff --git a/code/modules/mob/new_player/sprite_accessories/markings/diona_stuff.dm b/code/modules/sprite_accessories/markings/diona_stuff.dm similarity index 100% rename from code/modules/mob/new_player/sprite_accessories/markings/diona_stuff.dm rename to code/modules/sprite_accessories/markings/diona_stuff.dm diff --git a/code/modules/mob/new_player/sprite_accessories/markings/eye_stuff.dm b/code/modules/sprite_accessories/markings/eye_stuff.dm similarity index 100% rename from code/modules/mob/new_player/sprite_accessories/markings/eye_stuff.dm rename to code/modules/sprite_accessories/markings/eye_stuff.dm diff --git a/code/modules/mob/new_player/sprite_accessories/markings/panda.dm b/code/modules/sprite_accessories/markings/panda.dm similarity index 100% rename from code/modules/mob/new_player/sprite_accessories/markings/panda.dm rename to code/modules/sprite_accessories/markings/panda.dm diff --git a/code/modules/mob/new_player/sprite_accessories/markings/sergal.dm b/code/modules/sprite_accessories/markings/sergal.dm similarity index 100% rename from code/modules/mob/new_player/sprite_accessories/markings/sergal.dm rename to code/modules/sprite_accessories/markings/sergal.dm diff --git a/code/modules/mob/new_player/sprite_accessories/markings/synth_stuff.dm b/code/modules/sprite_accessories/markings/synth_stuff.dm similarity index 100% rename from code/modules/mob/new_player/sprite_accessories/markings/synth_stuff.dm rename to code/modules/sprite_accessories/markings/synth_stuff.dm diff --git a/code/modules/mob/new_player/sprite_accessories/markings/taj.dm b/code/modules/sprite_accessories/markings/taj.dm similarity index 100% rename from code/modules/mob/new_player/sprite_accessories/markings/taj.dm rename to code/modules/sprite_accessories/markings/taj.dm diff --git a/code/modules/mob/new_player/sprite_accessories/markings/tanlines.dm b/code/modules/sprite_accessories/markings/tanlines.dm similarity index 100% rename from code/modules/mob/new_player/sprite_accessories/markings/tanlines.dm rename to code/modules/sprite_accessories/markings/tanlines.dm diff --git a/code/modules/mob/new_player/sprite_accessories/markings/tattoo.dm b/code/modules/sprite_accessories/markings/tattoo.dm similarity index 100% rename from code/modules/mob/new_player/sprite_accessories/markings/tattoo.dm rename to code/modules/sprite_accessories/markings/tattoo.dm diff --git a/code/modules/mob/new_player/sprite_accessories/markings/tesh.dm b/code/modules/sprite_accessories/markings/tesh.dm similarity index 100% rename from code/modules/mob/new_player/sprite_accessories/markings/tesh.dm rename to code/modules/sprite_accessories/markings/tesh.dm diff --git a/code/modules/mob/new_player/sprite_accessories/markings/unathi.dm b/code/modules/sprite_accessories/markings/unathi.dm similarity index 100% rename from code/modules/mob/new_player/sprite_accessories/markings/unathi.dm rename to code/modules/sprite_accessories/markings/unathi.dm diff --git a/code/modules/mob/new_player/sprite_accessories/markings/vox.dm b/code/modules/sprite_accessories/markings/vox.dm similarity index 100% rename from code/modules/mob/new_player/sprite_accessories/markings/vox.dm rename to code/modules/sprite_accessories/markings/vox.dm diff --git a/code/modules/mob/new_player/sprite_accessories/markings/vulp.dm b/code/modules/sprite_accessories/markings/vulp.dm similarity index 100% rename from code/modules/mob/new_player/sprite_accessories/markings/vulp.dm rename to code/modules/sprite_accessories/markings/vulp.dm diff --git a/code/modules/mob/new_player/sprite_accessories/markings/werebeast.dm b/code/modules/sprite_accessories/markings/werebeast.dm similarity index 100% rename from code/modules/mob/new_player/sprite_accessories/markings/werebeast.dm rename to code/modules/sprite_accessories/markings/werebeast.dm diff --git a/code/modules/mob/new_player/sprite_accessories/markings/zorren.dm b/code/modules/sprite_accessories/markings/zorren.dm similarity index 100% rename from code/modules/mob/new_player/sprite_accessories/markings/zorren.dm rename to code/modules/sprite_accessories/markings/zorren.dm diff --git a/code/modules/mob/new_player/sprite_accessories.dm b/code/modules/sprite_accessories/sprite_accessories.dm similarity index 100% rename from code/modules/mob/new_player/sprite_accessories.dm rename to code/modules/sprite_accessories/sprite_accessories.dm diff --git a/code/modules/tgui/modal.dm b/code/modules/tgui/modal_vr.dm similarity index 100% rename from code/modules/tgui/modal.dm rename to code/modules/tgui/modal_vr.dm diff --git a/code/modules/tgui/modules/communications.dm b/code/modules/tgui/modules/communications.dm index 875a36b9989..76c86990e1c 100644 --- a/code/modules/tgui/modules/communications.dm +++ b/code/modules/tgui/modules/communications.dm @@ -65,16 +65,16 @@ /datum/tgui_module/communications/proc/change_security_level(new_level) tmp_alertlevel = new_level - var/old_level = security_level + var/old_level = GLOB.security_level if(!tmp_alertlevel) tmp_alertlevel = SEC_LEVEL_GREEN if(tmp_alertlevel < SEC_LEVEL_GREEN) tmp_alertlevel = SEC_LEVEL_GREEN if(tmp_alertlevel > SEC_LEVEL_BLUE) tmp_alertlevel = SEC_LEVEL_BLUE //Cannot engage delta with this set_security_level(tmp_alertlevel) - if(security_level != old_level) + if(GLOB.security_level != old_level) //Only notify the admins if an actual change happened log_game("[key_name(usr)] has changed the security level to [get_security_level()].") message_admins("[key_name_admin(usr)] has changed the security level to [get_security_level()].") - switch(security_level) + switch(GLOB.security_level) if(SEC_LEVEL_GREEN) feedback_inc("alert_comms_green",1) if(SEC_LEVEL_YELLOW) @@ -111,8 +111,8 @@ ), ) - data["security_level"] = security_level - switch(security_level) + data["GLOB.security_level"] = GLOB.security_level + switch(GLOB.security_level) if(SEC_LEVEL_BLUE) data["security_level_color"] = "blue"; if(SEC_LEVEL_ORANGE) diff --git a/code/modules/tgui/modules/gyrotron_control.dm b/code/modules/tgui/modules/gyrotron_control.dm index ff70476274a..863ff270ad4 100644 --- a/code/modules/tgui/modules/gyrotron_control.dm +++ b/code/modules/tgui/modules/gyrotron_control.dm @@ -18,7 +18,7 @@ switch(action) if("set_tag") - var/new_ident = sanitize_text(input("Enter a new ident tag.", "Gyrotron Control", gyro_tag) as null|text) + var/new_ident = sanitize_istext(input("Enter a new ident tag.", "Gyrotron Control", gyro_tag) as null|text) if(new_ident) gyro_tag = new_ident return TRUE diff --git a/code/modules/tgui/modules/rustcore_monitor.dm b/code/modules/tgui/modules/rustcore_monitor.dm index 3fd304e7e4a..33611edf9b0 100644 --- a/code/modules/tgui/modules/rustcore_monitor.dm +++ b/code/modules/tgui/modules/rustcore_monitor.dm @@ -25,7 +25,7 @@ return TRUE if("set_tag") - var/new_ident = sanitize_text(input("Enter a new ident tag.", "Core Control", core_tag) as null|text) + var/new_ident = sanitize_istext(input("Enter a new ident tag.", "Core Control", core_tag) as null|text) if(new_ident) core_tag = new_ident return TRUE diff --git a/code/modules/tgui/modules/rustfuel_control.dm b/code/modules/tgui/modules/rustfuel_control.dm index 9b42ce42984..0ce30fed958 100644 --- a/code/modules/tgui/modules/rustfuel_control.dm +++ b/code/modules/tgui/modules/rustfuel_control.dm @@ -22,7 +22,7 @@ return TRUE if("set_tag") - var/new_ident = sanitize_text(input("Enter a new ident tag.", "Gyrotron Control", fuel_tag) as null|text) + var/new_ident = sanitize_istext(input("Enter a new ident tag.", "Gyrotron Control", fuel_tag) as null|text) if(new_ident) fuel_tag = new_ident diff --git a/code/modules/tgui/states/new_player.dm b/code/modules/tgui/states/new_player.dm index f74c2643827..3054e2a4a74 100644 --- a/code/modules/tgui/states/new_player.dm +++ b/code/modules/tgui/states/new_player.dm @@ -10,3 +10,17 @@ GLOBAL_DATUM_INIT(new_player_state, /datum/ui_state/new_player_state, new) if(isnewplayer(user) || check_rights_for(user.client, R_ADMIN)) return UI_INTERACTIVE return UI_CLOSE + +/** + * tgui state: explicit_new_player_state + * + * Checks that the user is a new_player + */ + +GLOBAL_DATUM_INIT(explicit_new_player_state, /datum/ui_state/explicit_new_player_state, new) + +/datum/ui_state/explicit_new_player_state/can_use_topic(src_object, mob/user) + if(isnewplayer(user)) + return UI_INTERACTIVE + return UI_CLOSE + diff --git a/code/modules/unit_tests/human/species.dm b/code/modules/unit_tests/human/species.dm index c37f468e6a5..cc499c9a00f 100644 --- a/code/modules/unit_tests/human/species.dm +++ b/code/modules/unit_tests/human/species.dm @@ -12,3 +12,14 @@ Fail("Duplicate name on [S.name] - [S.type].") continue sanity_name[S.name] = S + +// welcome to dealing with 18+ content +/datum/unit_test/species_age_sanity/Run() + for(var/path in subtypesof(/datum/species)) + var/datum/species/S = path + if(initial(S.min_age) < 18) + Fail("[path] has min age below 18") + for(var/path in subtypesof(/datum/character_species)) + var/datum/character_species/S = path + if(initial(S.min_age) < 18) + Fail("[path] has min age below 18") diff --git a/code/modules/variable_settings/variable_setting_entry.dm b/code/modules/variable_settings/variable_setting_entry.dm index 35fd7e58f33..490e7f3ff6c 100644 --- a/code/modules/variable_settings/variable_setting_entry.dm +++ b/code/modules/variable_settings/variable_setting_entry.dm @@ -19,13 +19,13 @@ if(!islist(_value)) value = initial_value = _value else - value = deepCopyList(_value) - initial_value = deepCopyList(_value) + value = deep_copy_list(_value) + initial_value = deep_copy_list(_value) // we do not handle datums yet. /datum/variable_setting_entry/proc/reset_to_default() if(islist(initial_value)) - value = deepCopyList(initial_value) + value = deep_copy_list(initial_value) else value = initial_value diff --git a/code/modules/ventcrawl/ventcrawl_atmospherics.dm b/code/modules/ventcrawl/ventcrawl_atmospherics.dm index 7a79883334e..59c443e9904 100644 --- a/code/modules/ventcrawl/ventcrawl_atmospherics.dm +++ b/code/modules/ventcrawl/ventcrawl_atmospherics.dm @@ -6,7 +6,7 @@ M.forceMove(get_turf(src)) M.update_perspective() if(pipe_image) - for(var/mob/living/M in player_list) + for(var/mob/living/M in GLOB.player_list) if(M.client) M.client.images -= pipe_image M.pipes_shown -= pipe_image diff --git a/code/modules/virus2/admin.dm b/code/modules/virus2/admin.dm index 04d34bcd66f..2d5426b3b23 100644 --- a/code/modules/virus2/admin.dm +++ b/code/modules/virus2/admin.dm @@ -88,7 +88,7 @@ Infectable Species:
"} var/f = 1 - var/list/species_cache = all_static_species_meta() + var/list/species_cache = SScharacters.all_static_species_meta() for(var/datum/species/S in species_cache) if(S.get_virus_immune()) continue diff --git a/code/modules/virus2/disease2.dm b/code/modules/virus2/disease2.dm index 707e0232f95..07d71f02e06 100644 --- a/code/modules/virus2/disease2.dm +++ b/code/modules/virus2/disease2.dm @@ -49,7 +49,7 @@ var/list/meat = list() var/list/res = list() - var/list/species_cache = all_static_species_meta() + var/list/species_cache = SScharacters.all_static_species_meta() for(var/datum/species/S in species_cache) if(S.get_virus_immune()) continue @@ -284,7 +284,7 @@ var/global/list/virusDB = list() /proc/virus2_lesser_infection() var/list/candidates = list() //list of candidate keys - for(var/mob/living/carbon/human/G in player_list) + for(var/mob/living/carbon/human/G in GLOB.player_list) if(G.client && G.stat != DEAD) candidates += G @@ -297,7 +297,7 @@ var/global/list/virusDB = list() /proc/virus2_greater_infection() var/list/candidates = list() //list of candidate keys - for(var/mob/living/carbon/human/G in player_list) + for(var/mob/living/carbon/human/G in GLOB.player_list) if(G.client && G.stat != DEAD) candidates += G if(!candidates.len) return diff --git a/code/modules/vore/eating/belly_obj_vr.dm b/code/modules/vore/eating/belly_obj_vr.dm index a663284070f..ecd83c1eb9c 100644 --- a/code/modules/vore/eating/belly_obj_vr.dm +++ b/code/modules/vore/eating/belly_obj_vr.dm @@ -506,7 +506,7 @@ //Sketchy fallback for safety, put them somewhere safe. else stack_trace("[src] (\ref[src]) doesn't have an owner, and dropped someone at a latespawn point!") - var/fallback = SSjob.GetLatejoinSpawnpoint(faction = JOB_FACTION_STATION) + var/fallback = SSjob.get_latejoin_spawnpoint(faction = JOB_FACTION_STATION) return get_turf(fallback) //Yes, it's ""safe"" to drop items here diff --git a/code/modules/vore/eating/transforming_vr.dm b/code/modules/vore/eating/transforming_vr.dm index 521eae6b2ef..28a92610c15 100644 --- a/code/modules/vore/eating/transforming_vr.dm +++ b/code/modules/vore/eating/transforming_vr.dm @@ -225,11 +225,11 @@ for(var/obj/item/implant/backup/BI in backup_implants) BI.forceMove(src) if(color_action == 1) - M.set_species(species_type_by_name(O.species.name), example = M) + M.set_species(O.species.name, example = M) else if(color_action == 2) - M.set_species(species_type_by_name(O.species.name), example = O) + M.set_species(O.species.name, example = O) else - M.set_species(species_type_by_name(O.species.name)) + M.set_species(O.species.name) M.custom_species = O.custom_species M.update_icons_body() diff --git a/code/modules/vore/eating/vore_vr.dm b/code/modules/vore/eating/vore_vr.dm index 5e85f0e5cf6..ba45fddf4a9 100644 --- a/code/modules/vore/eating/vore_vr.dm +++ b/code/modules/vore/eating/vore_vr.dm @@ -90,28 +90,28 @@ save_vore() //Make the file first return TRUE - var/list/json_from_file = json_decode(file2text(path)) - if(!json_from_file) + var/list/json_FROM_FILE = json_decode(file2text(path)) + if(!json_FROM_FILE) return FALSE //My concern grows - var/version = json_from_file["version"] - json_from_file = patch_version(json_from_file,version) + var/version = json_FROM_FILE["version"] + json_FROM_FILE = patch_version(json_FROM_FILE,version) - digestable = json_from_file["digestable"] - devourable = json_from_file["devourable"] - feeding = json_from_file["feeding"] - digest_leave_remains = json_from_file["digest_leave_remains"] - allowmobvore = json_from_file["allowmobvore"] - vore_taste = json_from_file["vore_taste"] - vore_smell = json_from_file["vore_smell"] - permit_healbelly = json_from_file["permit_healbelly"] - can_be_drop_prey = json_from_file["can_be_drop_prey"] - can_be_drop_pred = json_from_file["can_be_drop_pred"] - belly_prefs = json_from_file["belly_prefs"] - permit_sizegun = json_from_file["permit_sizegun"] - permit_size_trample = json_from_file["permit_size_trample"] - permit_size_pickup = json_from_file["permit_size_pickup"] - permit_stripped = json_from_file["permit_stripped"] + digestable = json_FROM_FILE["digestable"] + devourable = json_FROM_FILE["devourable"] + feeding = json_FROM_FILE["feeding"] + digest_leave_remains = json_FROM_FILE["digest_leave_remains"] + allowmobvore = json_FROM_FILE["allowmobvore"] + vore_taste = json_FROM_FILE["vore_taste"] + vore_smell = json_FROM_FILE["vore_smell"] + permit_healbelly = json_FROM_FILE["permit_healbelly"] + can_be_drop_prey = json_FROM_FILE["can_be_drop_prey"] + can_be_drop_pred = json_FROM_FILE["can_be_drop_pred"] + belly_prefs = json_FROM_FILE["belly_prefs"] + permit_sizegun = json_FROM_FILE["permit_sizegun"] + permit_size_trample = json_FROM_FILE["permit_size_trample"] + permit_size_pickup = json_FROM_FILE["permit_size_pickup"] + permit_stripped = json_FROM_FILE["permit_stripped"] //Quick sanitize if(isnull(digestable)) @@ -167,8 +167,8 @@ ) //List to JSON - var/json_to_file = json_encode(settings_list) - if(!json_to_file) + var/json_TO_FILE = json_encode(settings_list) + if(!json_TO_FILE) log_debug("Saving: [path] failed jsonencode") return FALSE @@ -176,7 +176,7 @@ // Fall back to using old format if we are not using rust-g if(fexists(path)) fdel(path) //Byond only supports APPENDING to files, not replacing. - text2file(json_to_file, path) + text2file(json_TO_FILE, path) if(!fexists(path)) log_debug("Saving: [path] failed file write") return FALSE @@ -184,5 +184,5 @@ return TRUE //Can do conversions here -/datum/vore_preferences/proc/patch_version(var/list/json_from_file,var/version) - return json_from_file +/datum/vore_preferences/proc/patch_version(var/list/json_FROM_FILE,var/version) + return json_FROM_FILE diff --git a/code/modules/vore/fluffstuff/custom_items.dm b/code/modules/vore/fluffstuff/custom_items.dm index 6b666786195..17d2f1236d5 100644 --- a/code/modules/vore/fluffstuff/custom_items.dm +++ b/code/modules/vore/fluffstuff/custom_items.dm @@ -1176,11 +1176,7 @@ if(configured == 1) return ..() - var/title - if(user.client.prefs.player_alt_titles[user.job]) - title = user.client.prefs.player_alt_titles[user.job] - else - title = user.job + var/title = user.client.prefs.get_job_alt_title_name(SSjob.name_occupations[user.job]) || user.job assignment = title user.set_id_info(src) if(user.mind && user.mind.initial_account) diff --git a/code/modules/xenobio/items/slime_objects.dm b/code/modules/xenobio/items/slime_objects.dm index 5cb26598dfe..89326d3b956 100644 --- a/code/modules/xenobio/items/slime_objects.dm +++ b/code/modules/xenobio/items/slime_objects.dm @@ -18,7 +18,7 @@ // Sometime down the road it would be great to make all of these 'ask ghosts if they want to be X' procs into a generic datum. /obj/item/slime_cube/proc/request_player() - for(var/mob/observer/dead/O in player_list) + for(var/mob/observer/dead/O in GLOB.player_list) if(!O.MayRespawn()) continue if(O.client) diff --git a/config/legacy/config.txt b/config/legacy/config.txt index 531e9b5bd7c..31b9967904c 100644 --- a/config/legacy/config.txt +++ b/config/legacy/config.txt @@ -317,7 +317,7 @@ ALLOW_CULT_GHOSTWRITER REQ_CULT_GHOSTWRITER 6 ## Sets the number of available character slots -CHARACTER_SLOTS 10 +CHARACTER_SLOTS 64 ## Sets the number of loadout slots per character LOADOUT_SLOTS 3 diff --git a/html/changelogs/AutoChangeLog-pr-4491.yml b/html/changelogs/AutoChangeLog-pr-4491.yml new file mode 100644 index 00000000000..28831a4520c --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-4491.yml @@ -0,0 +1,4 @@ +author: "Captain277" +delete-after: True +changes: + - rscadd: "Adds faction data." diff --git a/maps/submaps/_healpers.dm b/maps/submaps/_healpers.dm index 0e79b4becee..8ce99a51dae 100644 --- a/maps/submaps/_healpers.dm +++ b/maps/submaps/_healpers.dm @@ -56,7 +56,7 @@ if(FS._stair_tag == _stair_tag) target = FS if(!target && mapload) - to_world("Fake stairs at [x],[y],[z] couldn't get a target!") + TO_WORLD("Fake stairs at [x],[y],[z] couldn't get a target!") /obj/structure/fake_stairs/Destroy() if(target) diff --git a/prototypes/example.yaml b/prototypes/example.yaml new file mode 100644 index 00000000000..5dde332b2e5 --- /dev/null +++ b/prototypes/example.yaml @@ -0,0 +1,7 @@ +- type: Dud + content: ayy + num: 2 + fragments: + - trait: faction + ATC: NT + nul: ~ diff --git a/tgui/.eslintrc.yml b/tgui/.eslintrc.yml index daf5f9936e9..31d1b345d47 100644 --- a/tgui/.eslintrc.yml +++ b/tgui/.eslintrc.yml @@ -370,7 +370,7 @@ rules: # max-depth: error ## Enforce a maximum line length max-len: [error, { - code: 80, + code: 120, ## Ignore imports ignorePattern: '^(import\s.+\sfrom\s|.*require\()', ignoreUrls: true, diff --git a/tgui/packages/tgui/interfaces/JoinMenu.tsx b/tgui/packages/tgui/interfaces/JoinMenu.tsx new file mode 100644 index 00000000000..86d76ac428c --- /dev/null +++ b/tgui/packages/tgui/interfaces/JoinMenu.tsx @@ -0,0 +1,187 @@ +/* eslint-disable react/jsx-max-depth */ +import { Fragment } from 'inferno'; +import { useBackend } from '../backend'; +import { Box, Button, Section, Icon, NoticeBox, Collapsible, Stack } from '../components'; +import { Window } from '../layouts'; + +interface JoinableRoles { + /** + * The ID of the role (typepath) + */ + id: string; + /** + * The default name of the role (`initial(role.name)`) + */ + name: string; + /** + * Optional description of the job + */ + desc?: string; + /** + * How many slots does this role still have? `-1` is infinity + */ + slots: number; +} + +interface JoinableJob extends JoinableRoles { + real_name: string; +} + +interface JoinMenuData { + jobs: { + /** Factions */ + [key: string]: { + /** Department */ + [key: string]: JoinableJob[] + } + }; + ghostroles: JoinableRoles[]; + security_level: "green" | "blue" | "red" | "violet" | "yellow" | "orange" | "delta"; + evacuated: 0 | 1 | 2 | 3; + duration: string; // timetext + charname: string; + queue?: number; +} + +interface JoinFactionProps { + faction: string; + departments: { + [key: string]: JoinableJob[] + } +} + +// LateChoices +export const JoinMenu = (props, context) => { + const { act, data } = useBackend(context); + + return ( + + +
+ Round Duration: {data.duration}
+ Security Level: {data.security_level} + {!!data.evacuated && ( + + {(data.evacuated === 2)? "A crew transfer is in progress." + : ((data.evacuated === 3)? "The installation has been evacuated." + : "An evacuation is in progress.")} + + )} +
+
+ + + { + Object.entries(data.jobs).map(([k, v]) => { + return ( + + ); + }) + } + + +
+ { + data.ghostroles.map((role) => { + return ( + {(role.slots === -1)? '' : role.slots} + act('join', { id: role.id, type: "ghostrole" })} /> + + } style={{ "padding-left": "5%" }}> + + {role.desc} + + + ); + }) + } +
+
+
+
+
+
+ ); +}; + +const JoinFaction = (props: JoinFactionProps, context) => { + const { act } = useBackend(context); + const ordered = Object.keys(props.departments).sort((a, b) => { + const A = a.toLowerCase(); + const B = b.toLowerCase(); + let hasA = (A in sortWeight); + let hasB = (B in sortWeight); + if (hasA && !hasB) { + return -1; + } + else if (!hasA && hasB) { + return 1; + } + else if (!hasA && !hasB) { + return 0; + } + else { + return sortWeight[B] - sortWeight[A]; + } + }); + + return ( + + { + ordered.map((depName) => { + const jobs: JoinableJob[] = props.departments[depName]; + return ( + + { + jobs.map((job) => { + return ( + {(job.slots === -1)? 'Unlimited' : `${job.slots} left`} + act('join', { id: job.id, type: "job" })} /> + + }> +
+ {job.desc} +
+
+ ); + }) + } +
+ ); + }) + } +
+ ); +}; + +const sortWeight = { + command: 100, + security: 90, + engineering: 70, + medical: 80, + research: 70, + science: 70, + exploration: 60, + cargo: 55, + civilian: 50, + misc: 40, + miscellaneous: 40, + "off-duty": 30, + silicons: 20, + synthetics: 20, + trade: -20, + "central command": -100, +}; diff --git a/tgui/packages/tgui/interfaces/LanguagePicker.tsx b/tgui/packages/tgui/interfaces/LanguagePicker.tsx new file mode 100644 index 00000000000..757723ffff5 --- /dev/null +++ b/tgui/packages/tgui/interfaces/LanguagePicker.tsx @@ -0,0 +1,123 @@ +import { useBackend, useLocalState } from '../backend'; +import { Window } from '../layouts'; +import { Section, Stack, Button } from '../components'; + +type LanguagePickerContext = { + categories: String[], + languages: Language[], +}; + +type Language = { + id: String, + name: String, + desc: String, + category: String, +}; + +export const LanguagePicker = (props, context) => { + const { act, data } = useBackend(context); + + return ( + + + + + + + + + + + + + + + + ); +}; + +const LanguageInfo = (props, context) => { + const { act, data } = useBackend(context); + const [selectedLanguage, setSelectedLanguage] = useLocalState(context, 'selectedLanguage', null); + let lang = data.languages.find((l) => l.id === selectedLanguage); + if (lang === undefined) { + return (
); + } else { + return ( +
+ {lang?.desc} + +
+ ); + } +}; + +const LanguageCategories = (props, context) => { + const { act, data } = useBackend(context); + const { categories } = data; + let [selectedCategory, setSelectedCategory] = useLocalState(context, 'selectedCategory', null); + return ( +
+ { + Object.values(categories).map((c) => { + return ( + + ); + }) + } +
+ ); +}; + +const LanguageSelect = (props, context) => { + const { act, data } = useBackend(context); + let [selectedLanguage, setSelectedLanguage] = useLocalState(context, 'selectedLanguage', null); + let [selectedCategory, setSelectedCategory] = useLocalState(context, 'selectedCategory', null); + if (selectedCategory === null) { + return ( +
+ ); + } else { + return ( +
+ { + data.languages.filter((l) => l.category === selectedCategory).map((l) => { + return ( + + ); + }) + } +
+ ); + } +}; diff --git a/tgui/packages/tgui/interfaces/SpeciesPicker.tsx b/tgui/packages/tgui/interfaces/SpeciesPicker.tsx new file mode 100644 index 00000000000..6262184fec7 --- /dev/null +++ b/tgui/packages/tgui/interfaces/SpeciesPicker.tsx @@ -0,0 +1,130 @@ +import { BooleanLike } from 'common/react'; +import { useBackend, useLocalState } from '../backend'; +import { Section, Stack, Button, Box } from '../components'; +import { Window } from '../layouts'; + +type SpeciesPickerContext = { + whitelisted: string[], + species: [String: Species[]], + default: String, + admin: BooleanLike, +}; + +type Species = { + id: String, + whitelisted: BooleanLike, + name: String, + desc: String, + appearance_flags: Number, + flags: Number, + category: String, +}; + +// We currently do NOT render species appearance flags/numbers! + +export const SpeciesPicker = (props, context) => { + const { act, data } = useBackend(context); + const [selectedCategory, setSelectedCategory] = useLocalState(context, 'selectedCategory', null); + const [selectedSpecies, setSelectedSpecies] = useLocalState(context, 'selectedSpecies', data.default); + const { whitelisted = [] } = data; + let categories: String[] = []; + let species: Species[] = []; + let selected: Species | undefined; + Object.entries(data.species).forEach(([k, v]) => { + if (categories.indexOf(k) === -1) { + categories.push(k); + } + v.forEach((s) => { + species.push(s); + if (s.id === selectedSpecies) { + selected = s; + } + }); + }); + categories.sort(); + const isWhitelisted = (id) => ( + !(species.find((s) => s.id === id)?.whitelisted) || (whitelisted.findIndex((s) => s === id) !== -1) || !!data.admin + ); + + return ( + + + + +
+ { + categories.map((k) => ( + + )) + } +
+
+ + { + (selectedCategory === null) + ? ( +
+ ) : ( +
+ { + species.filter((s) => s.category === selectedCategory).map((s) => ( + + )) + } +
+ ) + } + + + { + (selected === undefined) + ? ( +
+ ) : ( +
+ {selected.desc} + {isWhitelisted(selected.id) + ? ( + + ) : ( + + Whitelisted + + )} +
+ ) + } + + + + + ); +}; + diff --git a/tools/deploy.sh b/tools/deploy.sh index 3b347ebefb0..ff55684e2ab 100755 --- a/tools/deploy.sh +++ b/tools/deploy.sh @@ -12,6 +12,7 @@ fi mkdir -p \ $1/_maps \ $1/icons/runtime \ + $1/prototypes \ $1/sound/runtime \ $1/strings \ $1/tgui/public \ @@ -25,6 +26,7 @@ fi cp citadel.dmb citadel.rsc $1/ cp -r _maps/* $1/_maps/ cp -r icons/runtime/* $1/icons/runtime/ +cp -r prototypes/* $1/prototypes/ cp -r sound/runtime/* $1/sound/runtime/ cp -r strings/* $1/strings/ cp -r tgui/public/* $1/tgui/public/