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, "