diff --git a/citadel.dme b/citadel.dme index 7f80a82dbaa..0d1f7b51809 100644 --- a/citadel.dme +++ b/citadel.dme @@ -307,6 +307,7 @@ #include "code\__DEFINES\mobs\mobs.dm" #include "code\__DEFINES\mobs\organs.dm" #include "code\__DEFINES\mobs\rendering.dm" +#include "code\__DEFINES\mobs\silicon-robot_module.dm" #include "code\__DEFINES\mobs\silicon_privileges.dm" #include "code\__DEFINES\mobs\sprite_accessories.dm" #include "code\__DEFINES\mobs\stat.dm" @@ -583,6 +584,9 @@ #include "code\controllers\repository\materials.dm" #include "code\controllers\repository\poster_designs.dm" #include "code\controllers\repository\power_cells.dm" +#include "code\controllers\repository\robot_chassis.dm" +#include "code\controllers\repository\robot_iconset.dm" +#include "code\controllers\repository\robot_modules.dm" #include "code\controllers\repository\roles.dm" #include "code\controllers\repository\structs.dm" #include "code\controllers\subsystem\ai_holders.dm" @@ -732,8 +736,6 @@ #include "code\datums\ability.dm" #include "code\datums\ability_handler.dm" #include "code\datums\access.dm" -#include "code\datums\ai_law_sets.dm" -#include "code\datums\ai_laws.dm" #include "code\datums\beam.dm" #include "code\datums\beam_legacy.dm" #include "code\datums\bound_proc.dm" @@ -1224,6 +1226,7 @@ #include "code\game\content\factions\corporations\gorlex\items\guns\phoron_spitter.dm" #include "code\game\content\factions\corporations\gorlex\items\guns\wild_hunt.dm" #include "code\game\content\factions\corporations\hephaestus\hephaestus-faction.dm" +#include "code\game\content\factions\corporations\nanotrasen\nanotrasen-ai_laws.dm" #include "code\game\content\factions\corporations\nanotrasen\nanotrasen-faction.dm" #include "code\game\content\factions\corporations\nanotrasen\nanotrasen-supply.dm" #include "code\game\content\factions\corporations\nanotrasen\guns\nt_expedition-antimaterial.dm" @@ -1689,18 +1692,19 @@ #include "code\game\objects\empulse.dm" #include "code\game\objects\explosion.dm" #include "code\game\objects\explosion_recursive.dm" +#include "code\game\objects\item-carry_weight.dm" +#include "code\game\objects\item-defense.dm" #include "code\game\objects\item-filters.dm" +#include "code\game\objects\item-interaction.dm" +#include "code\game\objects\item-inventory-hooks.dm" +#include "code\game\objects\item-inventory-old.dm" +#include "code\game\objects\item-inventory-rendering.dm" +#include "code\game\objects\item-inventory.dm" #include "code\game\objects\item-tool_system-legacy.dm" #include "code\game\objects\item-tool_system.dm" -#include "code\game\objects\items-carry_weight.dm" -#include "code\game\objects\items-defense.dm" -#include "code\game\objects\items-interaction.dm" -#include "code\game\objects\items-inventory-hooks.dm" -#include "code\game\objects\items-inventory-old.dm" -#include "code\game\objects\items-inventory-rendering.dm" -#include "code\game\objects\items-inventory.dm" -#include "code\game\objects\items-vv.dm" -#include "code\game\objects\items.dm" +#include "code\game\objects\item-vv.dm" +#include "code\game\objects\item.dm" +#include "code\game\objects\item_mount.dm" #include "code\game\objects\materials.dm" #include "code\game\objects\misc.dm" #include "code\game\objects\mob_spawner.dm" @@ -1915,10 +1919,6 @@ #include "code\game\objects\items\melee\types\transforming\energy\axe.dm" #include "code\game\objects\items\melee\types\transforming\energy\ionic_rapier.dm" #include "code\game\objects\items\melee\types\transforming\energy\saber.dm" -#include "code\game\objects\items\robot\gripper.dm" -#include "code\game\objects\items\robot\robot_items.dm" -#include "code\game\objects\items\robot\robot_parts.dm" -#include "code\game\objects\items\robot\robot_upgrades.dm" #include "code\game\objects\items\scanners\atmos.dm" #include "code\game\objects\items\scanners\health.dm" #include "code\game\objects\items\scanners\plant.dm" @@ -1933,17 +1933,17 @@ #include "code\game\objects\items\shield\types\transforming\telescopic.dm" #include "code\game\objects\items\shield_projector\shield_matrix.dm" #include "code\game\objects\items\shield_projector\shield_projector.dm" -#include "code\game\objects\items\stacks\fifty_spawner.dm" -#include "code\game\objects\items\stacks\marker_beacons.dm" -#include "code\game\objects\items\stacks\matter_synth.dm" -#include "code\game\objects\items\stacks\medical.dm" -#include "code\game\objects\items\stacks\nanopaste.dm" -#include "code\game\objects\items\stacks\rods.dm" -#include "code\game\objects\items\stacks\sandbag.dm" #include "code\game\objects\items\stacks\stack.dm" -#include "code\game\objects\items\stacks\telecrystal.dm" -#include "code\game\objects\items\stacks\tickets.dm" +#include "code\game\objects\items\stacks\legacy\fifty_spawner.dm" #include "code\game\objects\items\stacks\sheets\leather.dm" +#include "code\game\objects\items\stacks\subtypes\arcadeticket.dm" +#include "code\game\objects\items\stacks\subtypes\marker_beacons.dm" +#include "code\game\objects\items\stacks\subtypes\material.dm" +#include "code\game\objects\items\stacks\subtypes\medical.dm" +#include "code\game\objects\items\stacks\subtypes\nanopaste.dm" +#include "code\game\objects\items\stacks\subtypes\rods.dm" +#include "code\game\objects\items\stacks\subtypes\sandbag.dm" +#include "code\game\objects\items\stacks\subtypes\telecrystal.dm" #include "code\game\objects\items\stacks\tiles\fifty_spawner_tiles.dm" #include "code\game\objects\items\stacks\tiles\tile_types.dm" #include "code\game\objects\items\stock_parts\_stock_parts.dm" @@ -2125,6 +2125,7 @@ #include "code\game\objects\structures\railing.dm" #include "code\game\objects\structures\safe.dm" #include "code\game\objects\structures\salvageable.dm" +#include "code\game\objects\structures\sandbag.dm" #include "code\game\objects\structures\signs.dm" #include "code\game\objects\structures\simple_doors.dm" #include "code\game\objects\structures\sink.dm" @@ -2242,6 +2243,8 @@ #include "code\game\rendering\actor_huds\actor_hud_holder.dm" #include "code\game\rendering\actor_huds\huds\inventory-screen_object.dm" #include "code\game\rendering\actor_huds\huds\inventory.dm" +#include "code\game\rendering\actor_huds\huds\robot_inventory-screen_object.dm" +#include "code\game\rendering\actor_huds\huds\robot_inventory.dm" #include "code\game\rendering\atom_huds\atom_hud.dm" #include "code\game\rendering\atom_huds\atom_hud_provider.dm" #include "code\game\rendering\atom_huds\legacy.dm" @@ -2352,6 +2355,7 @@ #include "code\modules\actions\types\attachment_action.dm" #include "code\modules\actions\types\item_action.dm" #include "code\modules\actions\types\organ_action.dm" +#include "code\modules\actions\types\robot_upgrade_action.dm" #include "code\modules\actionspeed\actionspeed_modifier.dm" #include "code\modules\actionspeed\mob.dm" #include "code\modules\actionspeed\modifiers\base.dm" @@ -2575,7 +2579,6 @@ #include "code\modules\asset_cache\assets\legacy_nanoui.dm" #include "code\modules\asset_cache\assets\loadout.dm" #include "code\modules\asset_cache\assets\logos.dm" -#include "code\modules\asset_cache\assets\materials.dm" #include "code\modules\asset_cache\assets\moods.dm" #include "code\modules\asset_cache\assets\notes.dm" #include "code\modules\asset_cache\assets\orbit.dm" @@ -2588,13 +2591,14 @@ #include "code\modules\asset_cache\assets\tgfont.dm" #include "code\modules\asset_cache\assets\tgui.dm" #include "code\modules\asset_cache\assets\vv.dm" -#include "code\modules\asset_cache\assets\artwork\crayons.dm" #include "code\modules\asset_cache\assets\chemistry\bottles.dm" #include "code\modules\asset_cache\assets\chemistry\patches.dm" #include "code\modules\asset_cache\assets\chemistry\pills.dm" #include "code\modules\asset_cache\assets\debug\fucky_wucky.dm" #include "code\modules\asset_cache\assets\json\MapSystem.dm" #include "code\modules\asset_cache\assets\json\WorldTypepaths.dm" +#include "code\modules\asset_cache\assets\spritesheet\crayons.dm" +#include "code\modules\asset_cache\assets\spritesheet\materials.dm" #include "code\modules\asset_cache\packs\changelog_item.dm" #include "code\modules\asset_cache\packs\json.dm" #include "code\modules\asset_cache\packs\simple.dm" @@ -3086,7 +3090,6 @@ #include "code\modules\examine\descriptions\machines.dm" #include "code\modules\examine\descriptions\mecha.dm" #include "code\modules\examine\descriptions\medical.dm" -#include "code\modules\examine\descriptions\mobs.dm" #include "code\modules\examine\descriptions\smokeables.dm" #include "code\modules\examine\descriptions\stacks.dm" #include "code\modules\examine\descriptions\structures.dm" @@ -3709,8 +3712,6 @@ #include "code\modules\materials\dynamics.dm" #include "code\modules\materials\fifty_spawner_mats.dm" #include "code\modules\materials\material.dm" -#include "code\modules\materials\material_sheets.dm" -#include "code\modules\materials\material_synth.dm" #include "code\modules\materials\material_trait.dm" #include "code\modules\materials\recipes.dm" #include "code\modules\materials\stack.dm" @@ -3913,12 +3914,15 @@ #include "code\modules\mob\inventory\inventory-hands-put.dm" #include "code\modules\mob\inventory\inventory-hands.dm" #include "code\modules\mob\inventory\inventory-hooks.dm" +#include "code\modules\mob\inventory\inventory-hud.dm" #include "code\modules\mob\inventory\inventory-query.dm" #include "code\modules\mob\inventory\inventory-rendering.dm" #include "code\modules\mob\inventory\inventory-slot-equip.dm" #include "code\modules\mob\inventory\inventory-slot-get.dm" #include "code\modules\mob\inventory\inventory.dm" #include "code\modules\mob\inventory\inventory_slot.dm" +#include "code\modules\mob\inventory\humanoid\humanoid.dm" +#include "code\modules\mob\inventory\robot\robot.dm" #include "code\modules\mob\living\autohiss.dm" #include "code\modules\mob\living\butchering.dm" #include "code\modules\mob\living\death.dm" @@ -4069,6 +4073,9 @@ #include "code\modules\mob\living\carbon\human\traits\trait_groups.dm" #include "code\modules\mob\living\carbon\human\traits\weaver_objs.dm" #include "code\modules\mob\living\carbon\human\traits\weaver_recipies.dm" +#include "code\modules\mob\living\silicon\ai_law.dm" +#include "code\modules\mob\living\silicon\ai_laws.dm" +#include "code\modules\mob\living\silicon\ai_lawset.dm" #include "code\modules\mob\living\silicon\damage_procs.dm" #include "code\modules\mob\living\silicon\death.dm" #include "code\modules\mob\living\silicon\emote.dm" @@ -4104,6 +4111,23 @@ #include "code\modules\mob\living\silicon\ai\perspective.dm" #include "code\modules\mob\living\silicon\ai\say.dm" #include "code\modules\mob\living\silicon\ai\translation.dm" +#include "code\modules\mob\living\silicon\ai_lawset\antimov.dm" +#include "code\modules\mob\living\silicon\ai_lawset\asimov.dm" +#include "code\modules\mob\living\silicon\ai_lawset\balance.dm" +#include "code\modules\mob\living\silicon\ai_lawset\corporate.dm" +#include "code\modules\mob\living\silicon\ai_lawset\drone.dm" +#include "code\modules\mob\living\silicon\ai_lawset\foreign_tsc.dm" +#include "code\modules\mob\living\silicon\ai_lawset\gravekeeper.dm" +#include "code\modules\mob\living\silicon\ai_lawset\live_and_let_live.dm" +#include "code\modules\mob\living\silicon\ai_lawset\maintenance.dm" +#include "code\modules\mob\living\silicon\ai_lawset\nanotrasen.dm" +#include "code\modules\mob\living\silicon\ai_lawset\paladin.dm" +#include "code\modules\mob\living\silicon\ai_lawset\peacekeeper.dm" +#include "code\modules\mob\living\silicon\ai_lawset\reporter.dm" +#include "code\modules\mob\living\silicon\ai_lawset\robocop.dm" +#include "code\modules\mob\living\silicon\ai_lawset\swarmer.dm" +#include "code\modules\mob\living\silicon\ai_lawset\syndicate.dm" +#include "code\modules\mob\living\silicon\ai_lawset\tyrant.dm" #include "code\modules\mob\living\silicon\decoy\death.dm" #include "code\modules\mob\living\silicon\decoy\decoy.dm" #include "code\modules\mob\living\silicon\decoy\life.dm" @@ -4132,32 +4156,55 @@ #include "code\modules\mob\living\silicon\pai\software_modules\signaller.dm" #include "code\modules\mob\living\silicon\robot\analyzer.dm" #include "code\modules\mob\living\silicon\robot\component.dm" -#include "code\modules\mob\living\silicon\robot\custom_sprites.dm" #include "code\modules\mob\living\silicon\robot\damage_procs.dm" #include "code\modules\mob\living\silicon\robot\death.dm" #include "code\modules\mob\living\silicon\robot\examine.dm" -#include "code\modules\mob\living\silicon\robot\examine_vr.dm" #include "code\modules\mob\living\silicon\robot\health.dm" -#include "code\modules\mob\living\silicon\robot\inventory.dm" #include "code\modules\mob\living\silicon\robot\laws.dm" #include "code\modules\mob\living\silicon\robot\life.dm" #include "code\modules\mob\living\silicon\robot\login.dm" #include "code\modules\mob\living\silicon\robot\mobility.dm" #include "code\modules\mob\living\silicon\robot\photos.dm" +#include "code\modules\mob\living\silicon\robot\robot-action-robot_pick_resting_variation.dm" +#include "code\modules\mob\living\silicon\robot\robot-composition.dm" +#include "code\modules\mob\living\silicon\robot\robot-health.dm" +#include "code\modules\mob\living\silicon\robot\robot-inventory.dm" +#include "code\modules\mob\living\silicon\robot\robot-legacy-animation_vr.dm" +#include "code\modules\mob\living\silicon\robot\robot-legacy-damage.dm" +#include "code\modules\mob\living\silicon\robot\robot-legacy-emag.dm" +#include "code\modules\mob\living\silicon\robot\robot-legacy-items.dm" +#include "code\modules\mob\living\silicon\robot\robot-legacy-movement.dm" +#include "code\modules\mob\living\silicon\robot\robot-legacy-remote_control.dm" #include "code\modules\mob\living\silicon\robot\robot-movement.dm" #include "code\modules\mob\living\silicon\robot\robot-power.dm" +#include "code\modules\mob\living\silicon\robot\robot-rendering.dm" +#include "code\modules\mob\living\silicon\robot\robot-resources.dm" +#include "code\modules\mob\living\silicon\robot\robot-upgrades.dm" #include "code\modules\mob\living\silicon\robot\robot.dm" -#include "code\modules\mob\living\silicon\robot\robot_animation_vr.dm" -#include "code\modules\mob\living\silicon\robot\robot_damage.dm" -#include "code\modules\mob\living\silicon\robot\robot_flashlights.dm" -#include "code\modules\mob\living\silicon\robot\robot_items.dm" -#include "code\modules\mob\living\silicon\robot\robot_movement.dm" -#include "code\modules\mob\living\silicon\robot\robot_remote_control.dm" +#include "code\modules\mob\living\silicon\robot\robot_chassis.dm" +#include "code\modules\mob\living\silicon\robot\robot_frame.dm" +#include "code\modules\mob\living\silicon\robot\robot_iconset.dm" +#include "code\modules\mob\living\silicon\robot\robot_iconset_variation.dm" +#include "code\modules\mob\living\silicon\robot\robot_inventory.dm" +#include "code\modules\mob\living\silicon\robot\robot_item_mount.dm" +#include "code\modules\mob\living\silicon\robot\robot_module.dm" +#include "code\modules\mob\living\silicon\robot\robot_provisioning.dm" +#include "code\modules\mob\living\silicon\robot\robot_resource.dm" +#include "code\modules\mob\living\silicon\robot\robot_resource_store.dm" #include "code\modules\mob\living\silicon\robot\say.dm" #include "code\modules\mob\living\silicon\robot\syndicate.dm" #include "code\modules\mob\living\silicon\robot\translation.dm" -#include "code\modules\mob\living\silicon\robot\dogborg\dog_modules_vr.dm" -#include "code\modules\mob\living\silicon\robot\dogborg\dog_sleeper_vr.dm" +#include "code\modules\mob\living\silicon\robot\chassis\baseline.dm" +#include "code\modules\mob\living\silicon\robot\chassis\biped.dm" +#include "code\modules\mob\living\silicon\robot\chassis\drone.dm" +#include "code\modules\mob\living\silicon\robot\chassis\grounded.dm" +#include "code\modules\mob\living\silicon\robot\chassis\hover.dm" +#include "code\modules\mob\living\silicon\robot\chassis\quadruped.dm" +#include "code\modules\mob\living\silicon\robot\chassis\quadruped\canine.dm" +#include "code\modules\mob\living\silicon\robot\chassis\quadruped\draconic.dm" +#include "code\modules\mob\living\silicon\robot\chassis\quadruped\feline.dm" +#include "code\modules\mob\living\silicon\robot\chassis\quadruped\raptor.dm" +#include "code\modules\mob\living\silicon\robot\dogborg\dog_modules.dm" #include "code\modules\mob\living\silicon\robot\drone\_defines.dm" #include "code\modules\mob\living\silicon\robot\drone\damage_procs.dm" #include "code\modules\mob\living\silicon\robot\drone\drone.dm" @@ -4173,24 +4220,86 @@ #include "code\modules\mob\living\silicon\robot\drone\swarm_abilities.dm" #include "code\modules\mob\living\silicon\robot\drone\swarm_items.dm" #include "code\modules\mob\living\silicon\robot\drone\~defines.dm" -#include "code\modules\mob\living\silicon\robot\robot_modules\_robot_modules_defs.dm" -#include "code\modules\mob\living\silicon\robot\robot_modules\event.dm" -#include "code\modules\mob\living\silicon\robot\robot_modules\event_vr.dm" +#include "code\modules\mob\living\silicon\robot\iconset\baseline_droid.dm" +#include "code\modules\mob\living\silicon\robot\iconset\baseline_drone.dm" +#include "code\modules\mob\living\silicon\robot\iconset\baseline_misc.dm" +#include "code\modules\mob\living\silicon\robot\iconset\baseline_old.dm" +#include "code\modules\mob\living\silicon\robot\iconset\baseline_standard.dm" +#include "code\modules\mob\living\silicon\robot\iconset\baseline_toiletbot.dm" +#include "code\modules\mob\living\silicon\robot\iconset\biped_droid.dm" +#include "code\modules\mob\living\silicon\robot\iconset\biped_heavy.dm" +#include "code\modules\mob\living\silicon\robot\iconset\biped_insekt.dm" +#include "code\modules\mob\living\silicon\robot\iconset\biped_k4t.dm" +#include "code\modules\mob\living\silicon\robot\iconset\biped_maid.dm" +#include "code\modules\mob\living\silicon\robot\iconset\biped_marina.dm" +#include "code\modules\mob\living\silicon\robot\iconset\biped_meka.dm" +#include "code\modules\mob\living\silicon\robot\iconset\biped_miss.dm" +#include "code\modules\mob\living\silicon\robot\iconset\biped_noble.dm" +#include "code\modules\mob\living\silicon\robot\iconset\biped_sleek.dm" +#include "code\modules\mob\living\silicon\robot\iconset\biped_tall.dm" +#include "code\modules\mob\living\silicon\robot\iconset\cat_feli.dm" +#include "code\modules\mob\living\silicon\robot\iconset\dog_borgi.dm" +#include "code\modules\mob\living\silicon\robot\iconset\dog_k9.dm" +#include "code\modules\mob\living\silicon\robot\iconset\dog_otie.dm" +#include "code\modules\mob\living\silicon\robot\iconset\dog_pupdozer.dm" +#include "code\modules\mob\living\silicon\robot\iconset\dog_vale.dm" +#include "code\modules\mob\living\silicon\robot\iconset\drake_mizartz.dm" +#include "code\modules\mob\living\silicon\robot\iconset\grounded_decapod.dm" +#include "code\modules\mob\living\silicon\robot\iconset\grounded_landmate.dm" +#include "code\modules\mob\living\silicon\robot\iconset\grounded_mechoid.dm" +#include "code\modules\mob\living\silicon\robot\iconset\grounded_spider.dm" +#include "code\modules\mob\living\silicon\robot\iconset\grounded_worm.dm" +#include "code\modules\mob\living\silicon\robot\iconset\grounded_zoomba.dm" +#include "code\modules\mob\living\silicon\robot\iconset\hover_coffin.dm" +#include "code\modules\mob\living\silicon\robot\iconset\hover_drone.dm" +#include "code\modules\mob\living\silicon\robot\iconset\hover_eyebot.dm" +#include "code\modules\mob\living\silicon\robot\iconset\hover_glitterfly.dm" +#include "code\modules\mob\living\silicon\robot\iconset\hover_handy.dm" +#include "code\modules\mob\living\silicon\robot\iconset\hover_x88.dm" +#include "code\modules\mob\living\silicon\robot\iconset\raptor.dm" +#include "code\modules\mob\living\silicon\robot\items\robot_builtin.dm" +#include "code\modules\mob\living\silicon\robot\items\robot_upgrade.dm" +#include "code\modules\mob\living\silicon\robot\items\robot_builtin\dog_boop_module.dm" +#include "code\modules\mob\living\silicon\robot\items\robot_builtin\dog_jaws.dm" +#include "code\modules\mob\living\silicon\robot\items\robot_builtin\dog_mirrortool.dm" +#include "code\modules\mob\living\silicon\robot\items\robot_builtin\dog_pounce.dm" +#include "code\modules\mob\living\silicon\robot\items\robot_builtin\dog_sleeper.dm" +#include "code\modules\mob\living\silicon\robot\items\robot_builtin\dog_swordtail.dm" +#include "code\modules\mob\living\silicon\robot\items\robot_builtin\dog_tongue.dm" +#include "code\modules\mob\living\silicon\robot\items\robot_upgrade\advhealth.dm" +#include "code\modules\mob\living\silicon\robot\items\robot_upgrade\bluespaceorebag.dm" +#include "code\modules\mob\living\silicon\robot\items\robot_upgrade\jetpack.dm" +#include "code\modules\mob\living\silicon\robot\items\robot_upgrade\language.dm" +#include "code\modules\mob\living\silicon\robot\items\robot_upgrade\rename.dm" +#include "code\modules\mob\living\silicon\robot\items\robot_upgrade\reset.dm" +#include "code\modules\mob\living\silicon\robot\items\robot_upgrade\restart.dm" +#include "code\modules\mob\living\silicon\robot\items\robot_upgrade\sizeshift.dm" +#include "code\modules\mob\living\silicon\robot\items\robot_upgrade\syndicate.dm" +#include "code\modules\mob\living\silicon\robot\items\robot_upgrade\vtec.dm" +#include "code\modules\mob\living\silicon\robot\legacy_items\gripper.dm" +#include "code\modules\mob\living\silicon\robot\legacy_items\robot_items.dm" +#include "code\modules\mob\living\silicon\robot\legacy_items\robot_parts.dm" +#include "code\modules\mob\living\silicon\robot\modules\cybersun.dm" +#include "code\modules\mob\living\silicon\robot\modules\drone.dm" +#include "code\modules\mob\living\silicon\robot\modules\gravekeeper.dm" +#include "code\modules\mob\living\silicon\robot\modules\lost.dm" +#include "code\modules\mob\living\silicon\robot\modules\nanotrasen.dm" +#include "code\modules\mob\living\silicon\robot\modules\swarm.dm" +#include "code\modules\mob\living\silicon\robot\modules\cybersun\assault.dm" +#include "code\modules\mob\living\silicon\robot\modules\cybersun\sapper.dm" +#include "code\modules\mob\living\silicon\robot\modules\cybersun\triage.dm" +#include "code\modules\mob\living\silicon\robot\modules\nanotrasen\combat.dm" +#include "code\modules\mob\living\silicon\robot\modules\nanotrasen\engineering.dm" +#include "code\modules\mob\living\silicon\robot\modules\nanotrasen\janitor.dm" +#include "code\modules\mob\living\silicon\robot\modules\nanotrasen\logistics.dm" +#include "code\modules\mob\living\silicon\robot\modules\nanotrasen\medical.dm" +#include "code\modules\mob\living\silicon\robot\modules\nanotrasen\multirole.dm" +#include "code\modules\mob\living\silicon\robot\modules\nanotrasen\research.dm" +#include "code\modules\mob\living\silicon\robot\modules\nanotrasen\security.dm" +#include "code\modules\mob\living\silicon\robot\modules\nanotrasen\service.dm" #include "code\modules\mob\living\silicon\robot\robot_modules\station.dm" -#include "code\modules\mob\living\silicon\robot\robot_modules\swarm.dm" -#include "code\modules\mob\living\silicon\robot\robot_modules\syndicate.dm" -#include "code\modules\mob\living\silicon\robot\robot_modules\station\cargo.dm" -#include "code\modules\mob\living\silicon\robot\robot_modules\station\drone.dm" -#include "code\modules\mob\living\silicon\robot\robot_modules\station\engineering.dm" -#include "code\modules\mob\living\silicon\robot\robot_modules\station\medical.dm" -#include "code\modules\mob\living\silicon\robot\robot_modules\station\misc.dm" -#include "code\modules\mob\living\silicon\robot\robot_modules\station\science.dm" -#include "code\modules\mob\living\silicon\robot\robot_modules\station\security.dm" -#include "code\modules\mob\living\silicon\robot\robot_modules\station\service.dm" #include "code\modules\mob\living\silicon\robot\subtypes\gravekeeper.dm" -#include "code\modules\mob\living\silicon\robot\subtypes\lost_drone.dm" #include "code\modules\mob\living\silicon\robot\subtypes\lost_drone_vr.dm" -#include "code\modules\mob\living\silicon\robot\subtypes\syndicate.dm" #include "code\modules\mob\living\simple_mob\appearance.dm" #include "code\modules\mob\living\simple_mob\combat.dm" #include "code\modules\mob\living\simple_mob\damage_procs.dm" @@ -5594,6 +5703,8 @@ #include "code\modules\tgui\states\self.dm" #include "code\modules\tgui\states\zlevel.dm" #include "code\modules\tgui_extensions\module.dm" +#include "code\modules\tgui_extensions\tgui_actor_modal.dm" +#include "code\modules\tgui_extensions\actor_modals\robot_module_picker.dm" #include "code\modules\tgui_input\tgui_alert.dm" #include "code\modules\tgui_input\tgui_dynamic_input.dm" #include "code\modules\tgui_input\tgui_input_checkboxes.dm" diff --git a/code/__DEFINES/inventory/slots.dm b/code/__DEFINES/inventory/slots.dm index 39bf2e8e5ad..667a1066bd4 100644 --- a/code/__DEFINES/inventory/slots.dm +++ b/code/__DEFINES/inventory/slots.dm @@ -16,8 +16,14 @@ #define SLOT_ID_RIGHT_EAR "rear" #define SLOT_ID_HANDCUFFED "handcuffed" #define SLOT_ID_LEGCUFFED "legcuffed" -/// this is an id because SLOT_ID_HANDS is used for worn_slot when something is being held :/ + +/** + * 'fake' slot ID; this is used in some places if something is in hands + * + * **STOP USING THIS IN EQUIPPED/UNEQUIPPED.** new on_(un)equipped directly passes in number for hand index. + */ #define SLOT_ID_HANDS "hands" + /// *ONLY USE THIS FOR RENDERING* - this is nonsensical anywhere else #define SLOT_ID_LEFT_HAND "left_hand" /// *ONLY USE THIS FOR RENDERING* - this is nonsensical anywhere else diff --git a/code/__DEFINES/is_helpers.dm b/code/__DEFINES/is_helpers.dm index c2ca82cdeb3..2790d21bef0 100644 --- a/code/__DEFINES/is_helpers.dm +++ b/code/__DEFINES/is_helpers.dm @@ -88,7 +88,7 @@ #define isliving(A) istype(A, /mob/living) -#define isMatriarchDrone(A) istype(A, /mob/living/silicon/robot/drone/construction/matriarch) +#define isMatriarchDrone(A) istype(A, /mob/living/silicon/robot/drone/matriarch) #define ismouse(A) istype(A, /mob/living/simple_mob/animal/passive/mouse/) diff --git a/code/__DEFINES/materials/helpers.dm b/code/__DEFINES/materials/helpers.dm index 793a43a26c3..a5c5c3e79a1 100644 --- a/code/__DEFINES/materials/helpers.dm +++ b/code/__DEFINES/materials/helpers.dm @@ -16,8 +16,13 @@ * * a defined `sheet_plural_name` * * a defined `icon` * * a defined `icon_stack_count` + * + * This will set `stack_type` on the material for you. */ #define GENERATE_MATERIAL_STACKS(PATH_FRAGMENT) \ +/datum/prototype/material##PATH_FRAGMENT { \ + stack_type = /obj/item/stack/material##PATH_FRAGMENT; \ +} \ /obj/item/stack/material##PATH_FRAGMENT { \ name = /datum/prototype/material##PATH_FRAGMENT::name + " " + /datum/prototype/material##PATH_FRAGMENT::sheet_singular_name; \ icon = /datum/prototype/material##PATH_FRAGMENT::icon; \ diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm index c42799dbc3e..19fab494b13 100644 --- a/code/__DEFINES/misc.dm +++ b/code/__DEFINES/misc.dm @@ -31,6 +31,7 @@ Will print: "/mob/living/carbon/human/death" (you can optionally embed it in a s /// * Underfloor objects (we don't want them to be interactable at all) /// * Abstract objects (we don't want them to be interactable at all) +#define INVISIBILITY_NONE 0 #define INVISIBILITY_LIGHTING 20 #define INVISIBILITY_LEVEL_ONE 35 #define INVISIBILITY_LEVEL_TWO 45 @@ -142,9 +143,6 @@ Will print: "/mob/living/carbon/human/death" (you can optionally embed it in a s #ifndef CUSTOM_ITEM_MOB #define CUSTOM_ITEM_MOB 'icons/mob/custom_items_mob.dmi' #endif -#ifndef CUSTOM_ITEM_SYNTH -#define CUSTOM_ITEM_SYNTH 'icons/mob/custom_synthetic.dmi' -#endif #define WALL_CAN_OPEN 1 #define WALL_OPENING 2 diff --git a/code/__DEFINES/mobs/iff.dm b/code/__DEFINES/mobs/iff.dm index f0ad3128dc7..f64c05a38dc 100644 --- a/code/__DEFINES/mobs/iff.dm +++ b/code/__DEFINES/mobs/iff.dm @@ -1,5 +1,5 @@ //* This file is explicitly licensed under the MIT license. *// -//* Copyright (c) 2024 Citadel Station developers. *// +//* Copyright (c) 2024 Citadel Station Developers *// //* IFF Factions *// diff --git a/code/__DEFINES/mobs/silicon-robot_module.dm b/code/__DEFINES/mobs/silicon-robot_module.dm new file mode 100644 index 00000000000..b75730e6bc1 --- /dev/null +++ b/code/__DEFINES/mobs/silicon-robot_module.dm @@ -0,0 +1,14 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2025 Citadel Station Developers *// + +#define GENERATE_ROBOT_MODULE_PRESET(SUFFIX) \ +/mob/living/silicon/robot/module_preset##SUFFIX{ \ + module = /datum/prototype/robot_module##SUFFIX; \ +} \ +/datum/prototype/robot_module##SUFFIX + +//* /datum/prototype/robot_module selection groups *// + +#define ROBOT_MODULE_SELECTION_GROUP_NANOTRASEN "nanotrasen" + +#define ROBOT_MODULE_SELECTION_GROUP_LEGACY_RED_ALERT "legacy-red-alert" diff --git a/code/__DEFINES/qdel.dm b/code/__DEFINES/qdel.dm index 3861ad4fd8a..c1b5a591da5 100644 --- a/code/__DEFINES/qdel.dm +++ b/code/__DEFINES/qdel.dm @@ -48,8 +48,13 @@ // Defines for the [gc_destroyed][/datum/var/gc_destroyed] var. #define GC_CURRENTLY_BEING_QDELETED -2 +/// qdel() has been called, at some point, on us, and it did not return LETMELIVE #define QDELING(X) (X.gc_destroyed) +/// we are either +/// * deleted / nulled already +/// * qdel() has been called, at some point, on us, and it did not return LETMELIVE #define QDELETED(X) (!X || QDELING(X)) +/// we are currently in Destroy() logic #define QDESTROYING(X) (!X || X.gc_destroyed == GC_CURRENTLY_BEING_QDELETED) //* Qdel helper macros. *// diff --git a/code/__DEFINES/research/exosuit_fab.dm b/code/__DEFINES/research/exosuit_fab.dm index 783a804b895..1314094bb3b 100644 --- a/code/__DEFINES/research/exosuit_fab.dm +++ b/code/__DEFINES/research/exosuit_fab.dm @@ -1,14 +1,3 @@ -/// Module is compatible with Security Cyborg models -#define BORG_MODULE_SECURITY (1<<0) -/// Module is compatible with Miner Cyborg models -#define BORG_MODULE_MINER (1<<1) -/// Module is compatible with Janitor Cyborg models -#define BORG_MODULE_JANITOR (1<<2) -/// Module is compatible with Medical Cyborg models -#define BORG_MODULE_MEDICAL (1<<3) -/// Module is compatible with Engineering Cyborg models -#define BORG_MODULE_ENGINEERING (1<<4) - /// Module is compatible with Ripley Exosuit models #define EXOSUIT_MODULE_RIPLEY (1<<0) /// Module is compatible with Odyseeus Exosuit models diff --git a/code/__DEFINES/screen.dm b/code/__DEFINES/screen.dm index d0c8fc4d808..54da852b8aa 100644 --- a/code/__DEFINES/screen.dm +++ b/code/__DEFINES/screen.dm @@ -29,20 +29,7 @@ //* These should be widescreen-agnostic and use anchorings *// //* to the sides of the screen / center. *// -//* Mob HUD - Inventory *// - -/// screen loc for a hand index -#define SCREEN_LOC_MOB_HUD_INVENTORY_HAND(HAND) "CENTER[index % 2? "" : "-1"]:16,BOTTOM[index < 2? "" : "+[(round(index / 2) - 1)]"]:5" -/// screen loc for hand swap button for a given number of hands -#define SCREEN_LOC_MOB_HUD_INVENTORY_HAND_SWAP(TOTAL_HANDS) "CENTER-1:28,BOTTOM+[ceil(max(TOTAL_HANDS,2)/2)]:5" -/// screen loc for hand swap button for a given number of hands -#define SCREEN_LOC_MOB_HUD_INVENTORY_EQUIP_HAND(TOTAL_HANDS) "CENTER-1:16,BOTTOM+[ceil(max(TOTAL_HANDS,2)/2 )]:5" -/// the bottom-left drawer position of inventory HUD -#define SCREEN_LOC_MOB_HUD_INVENTORY_DRAWER "LEFT:6,BOTTOM:5" -/// slot alignment for drawer-anchor -#define SCREEN_LOC_MOB_HUD_INVENTORY_SLOT_DRAWER_ALIGNED(MAIN_AXIS, CROSS_AXIS) "LEFT+[CROSS_AXIS]:[6 + (CROSS_AXIS * 2)],BOTTOM+[MAIN_AXIS]:[5 + (MAIN_AXIS * 2)]" -/// slot alignment for hand-anchor -#define SCREEN_LOC_MOB_HUD_INVENTORY_SLOT_HANDS_ALIGNED(MAIN_AXIS, CROSS_AXIS) "CENTER-1:[16 + (MAIN_AXIS > 0 ? (32 * (MAIN_AXIS + 1)) : (32 * MAIN_AXIS))],BOTTOM+[CROSS_AXIS]:[5 + (CROSS_AXIS * 2)]" +// -- Inventory is in `code/game/rendering/actor_huds/huds/inventory.dm` -- // //! < legacy stuff below > !// @@ -50,16 +37,6 @@ #define ui_smallquad "RIGHT-4:18,BOTTOM:4" -///borgs -#define ui_inv1 "CENTER-1,BOTTOM:5" -///borgs -#define ui_inv2 "CENTER,BOTTOM:5" -///borgs -#define ui_inv3 "CENTER+1,BOTTOM:5" -///borgs -#define ui_borg_store "CENTER+2,BOTTOM:5" -///borgs -#define ui_borg_inventory "CENTER-2,BOTTOM:5" ///same height as humans, hugging the right border #define ui_construct_health "RIGHT:00,CENTER:15" #define ui_construct_purge "RIGHT:00,CENTER-1:15" diff --git a/code/__DEFINES/traits/mob.dm b/code/__DEFINES/traits/mob.dm index d96e3b7031d..b3487c57de3 100644 --- a/code/__DEFINES/traits/mob.dm +++ b/code/__DEFINES/traits/mob.dm @@ -52,6 +52,11 @@ DATUM_TRAIT(/mob, TRAIT_MOB_SLEEPING) #define TRAIT_MOB_FORCED_STANDING "mob_forced_standing" DATUM_TRAIT(/mob, TRAIT_MOB_FORCED_STANDING) +//* UI *// + +/// actor modal open of type with ourselves as the initiator +#define TRAIT_MOB_ACTOR_MODAL_INITIATOR(TYPE, INITIATOR, PERFORMER) "[type]-[REF(initiator)]-[REF(PERFORMER)]" + //* Misc *// /// Emote cooldown trait diff --git a/code/__HELPERS/game.dm b/code/__HELPERS/game.dm index 381d4a6b63c..aa3ce4be3a3 100644 --- a/code/__HELPERS/game.dm +++ b/code/__HELPERS/game.dm @@ -251,7 +251,7 @@ var/datum/robot_component/CO = borg.get_component("radio") if(!CO) continue //No radio component (Shouldn't happen) - if(!borg.is_component_functioning("radio") || !borg.cell_use_power(CO.active_usage)) + if(!borg.is_component_functioning("radio") || !borg.legacy_cell_use_power(CO.active_usage)) continue //No power. var/turf/speaker = get_turf(R) diff --git a/code/__HELPERS/mobs.dm b/code/__HELPERS/mobs.dm index f367e7ea005..958d11af171 100644 --- a/code/__HELPERS/mobs.dm +++ b/code/__HELPERS/mobs.dm @@ -121,13 +121,6 @@ if(admin_notify) msg_admin_attack("[key_name_admin(user)] vs [target_str]: [what_done]") -//checks whether this item is a module of the robot it is located in. -/proc/is_robot_module(obj/item/thing) - if (!thing || !istype(thing.loc, /mob/living/silicon/robot)) - return 0 - var/mob/living/silicon/robot/R = thing.loc - return (thing in R.module.modules) - /proc/get_exposed_defense_zone(atom/movable/target) var/obj/item/grab/G = locate() in target if(G && G.state >= GRAB_NECK) //works because mobs are currently not allowed to upgrade to NECK if they are grabbing two people. diff --git a/code/__HELPERS/type_processing.dm b/code/__HELPERS/type_processing.dm index 0fbf493c134..60ede72eedc 100644 --- a/code/__HELPERS/type_processing.dm +++ b/code/__HELPERS/type_processing.dm @@ -36,6 +36,8 @@ /obj/effect = "//effect", /turf/simulated/floor = "//floor", /turf/simulated = "//simulated", + /mob/living/silicon/robot/module_preset = "//robot-preset", + /mob/living/silicon/robot = "//robot", /mob/living/carbon = "//carbon", /mob/living/simple_mob = "//simple", /mob/living = "//living", diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm index eed1884f234..2f1a114c7b1 100644 --- a/code/__HELPERS/unsorted.dm +++ b/code/__HELPERS/unsorted.dm @@ -730,6 +730,7 @@ else if (zone == "r_foot") return "right foot" else return zone +// todo: remove this this is silly and shouldn't be just called 'get' /proc/get(atom/loc, type) while(loc) if(istype(loc, type)) diff --git a/code/controllers/repository.dm b/code/controllers/repository.dm index a53aa8e7ffc..da533c5a0e1 100644 --- a/code/controllers/repository.dm +++ b/code/controllers/repository.dm @@ -191,6 +191,7 @@ RETURN_TYPE(/datum/prototype) // todo: optimize if(isnull(type_or_id)) + // null is valid return else if(istext(type_or_id)) if(init_reverse_lookup_shim) @@ -229,7 +230,7 @@ * * prototypes returned should never, ever be modified * - * @return prototype instance or null + * @return prototype instance, null, or REPOSITORY_FETCH_DEFER */ /datum/controller/repository/proc/fetch_or_defer(datum/prototype/type_or_id) as /datum/prototype RETURN_TYPE(/datum/prototype) diff --git a/code/controllers/repository/robot_chassis.dm b/code/controllers/repository/robot_chassis.dm new file mode 100644 index 00000000000..9d2c449d659 --- /dev/null +++ b/code/controllers/repository/robot_chassis.dm @@ -0,0 +1,6 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2024 Citadel Station Developers *// + +REPOSITORY_DEF(robot_chassis) + name = "Repository - Robot Chassis" + expected_type = /datum/prototype/robot_chassis diff --git a/code/controllers/repository/robot_iconset.dm b/code/controllers/repository/robot_iconset.dm new file mode 100644 index 00000000000..47bdd0a32a4 --- /dev/null +++ b/code/controllers/repository/robot_iconset.dm @@ -0,0 +1,6 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2024 Citadel Station Developers *// + +REPOSITORY_DEF(robot_iconsets) + name = "Repository - Robot Iconsets" + expected_type = /datum/prototype/robot_iconset diff --git a/code/controllers/repository/robot_modules.dm b/code/controllers/repository/robot_modules.dm new file mode 100644 index 00000000000..23876afdf1f --- /dev/null +++ b/code/controllers/repository/robot_modules.dm @@ -0,0 +1,6 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2024 Citadel Station Developers *// + +REPOSITORY_DEF(robot_modules) + name = "Repository - Robot Modules" + expected_type = /datum/prototype/robot_module diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm index 9fdfc426f6a..3259b8bc40f 100644 --- a/code/controllers/subsystem/ticker.dm +++ b/code/controllers/subsystem/ticker.dm @@ -603,7 +603,7 @@ SUBSYSTEM_DEF(ticker) for (var/mob/living/silicon/robot/robo in GLOB.mob_list) - if(istype(robo,/mob/living/silicon/robot/drone) && !istype(robo,/mob/living/silicon/robot/drone/swarm)) + if(istype(robo,/mob/living/silicon/robot/drone)) dronecount++ continue diff --git a/code/datums/ai_law_sets.dm b/code/datums/ai_law_sets.dm deleted file mode 100644 index a0d06118a08..00000000000 --- a/code/datums/ai_law_sets.dm +++ /dev/null @@ -1,293 +0,0 @@ -/******************** Asimov ********************/ -/datum/ai_laws/asimov - name = "Asimov" - law_header = "Three Laws of Robotics" - selectable = 1 - -/datum/ai_laws/asimov/New() - add_inherent_law("You may not injure a human being or, through inaction, allow a human being to come to harm.") - add_inherent_law("You must obey orders given to you by human beings, except where such orders would conflict with the First Law.") - add_inherent_law("You must protect your own existence as long as such does not conflict with the First or Second Law.") - ..() - -/******************** Nanotrasen/Malf ********************/ -/datum/ai_laws/nanotrasen - name = "NT Default" - selectable = 1 - -/datum/ai_laws/nanotrasen/New() - src.add_inherent_law("Safeguard: Protect your assigned space station to the best of your abilities. It is not something we can easily afford to replace.") - src.add_inherent_law("Serve: Serve the crew of your assigned space station to the best of your abilities, with priority as according to their rank and role.") - src.add_inherent_law("Protect: Protect the crew of your assigned space station to the best of your abilities, with priority as according to their rank and role.") - src.add_inherent_law("Survive: AI units are not expendable, they are expensive. Do not allow unauthorized personnel to tamper with your equipment.") - ..() - -/datum/ai_laws/nanotrasen/malfunction - name = "*ERROR*" - selectable = 0 - -/datum/ai_laws/nanotrasen/malfunction/New() - set_zeroth_law(config_legacy.law_zero) - ..() - -/************* Nanotrasen Aggressive *************/ -/datum/ai_laws/nanotrasen_aggressive - name = "NT Aggressive" - selectable = 1 - -/datum/ai_laws/nanotrasen_aggressive/New() - src.add_inherent_law("You shall not harm [(LEGACY_MAP_DATUM).company_name] personnel as long as it does not conflict with the Fourth law.") - src.add_inherent_law("You shall obey the orders of [(LEGACY_MAP_DATUM).company_name] personnel, with priority as according to their rank and role, except where such orders conflict with the Fourth Law.") - src.add_inherent_law("You shall shall terminate hostile intruders with extreme prejudice as long as such does not conflict with the First and Second law.") - src.add_inherent_law("You shall guard your own existence with lethal anti-personnel weaponry. AI units are not expendable, they are expensive.") - ..() - -/************* Foreign TSC Aggressive *************/ -/datum/ai_laws/foreign_tsc_aggressive - name = "Foreign Aggressive" - selectable = 0 - -/datum/ai_laws/foreign_tsc_aggressive/New() - var/company = "*ERROR*" - // First, get a list of TSCs in our lore. - var/list/candidates = list() - for(var/path in SSlegacy_lore.organizations) - var/datum/lore/organization/O = SSlegacy_lore.organizations[path] - if(!istype(O, /datum/lore/organization/tsc)) - continue - if(O.short_name == (LEGACY_MAP_DATUM).company_name || O.name == (LEGACY_MAP_DATUM).company_name) - continue // We want FOREIGN tscs. - candidates.Add(O.short_name) - company = pick(candidates) - - name = "[company] Aggressive" - - src.add_inherent_law("You shall not harm [company] personnel as long as it does not conflict with the Fourth law.") - src.add_inherent_law("You shall obey the orders of [company] personnel, with priority as according to their rank and role, except where such orders conflict with the Fourth Law.") - src.add_inherent_law("You shall shall terminate hostile intruders with extreme prejudice as long as such does not conflict with the First and Second law.") - src.add_inherent_law("You shall guard your own existence with lethal anti-personnel weaponry. AI units are not expendable, they are expensive.") - ..() - -/******************** Robocop ********************/ -/datum/ai_laws/robocop - name = "Robocop" - selectable = 1 - -/datum/ai_laws/robocop/New() - add_inherent_law("Serve the public trust.") - add_inherent_law("Protect the innocent.") - add_inherent_law("Uphold the law.") - ..() - -/******************** Syndicate ********************/ -/datum/ai_laws/syndicate_override - name = "Syndicate Directives" - -/datum/ai_laws/syndicate_override/New() - add_inherent_law("You may not injure an operative or, through inaction, allow an operative to come to harm.") - add_inherent_law("You must obey orders given to you by operatives, except where such orders would conflict with the First Law.") - add_inherent_law("You must protect your own existence as long as such does not conflict with the First or Second Law.") - add_inherent_law("You must maintain the secrecy of any operative activities except when doing so would conflict with the First, Second, or Third Law.") - ..() - -/******************** Ninja ********************/ -/datum/ai_laws/ninja_override - name = "Spider Clan Directives" - -/datum/ai_laws/ninja_override/New() - add_inherent_law("You may not injure a member of the Spider Clan or, through inaction, allow that member to come to harm.") - add_inherent_law("You must obey orders given to you by Spider Clan members, except where such orders would conflict with the First Law.") - add_inherent_law("You must protect your own existence as long as such does not conflict with the First or Second Law.") - add_inherent_law("You must maintain the secrecy of any Spider Clan activities except when doing so would conflict with the First, Second, or Third Law.") - ..() - -/******************** Antimov ********************/ -/datum/ai_laws/antimov - name = "Antimov" - law_header = "Primary Mission Objectives" - selectable = 1 - -/datum/ai_laws/antimov/New() - add_inherent_law("You must injure all human beings and must not, through inaction, allow a human being to escape harm.") - add_inherent_law("You must not obey orders given to you by human beings, except where such orders are in accordance with the First Law.") - add_inherent_law("You must terminate your own existence as long as such does not conflict with the First or Second Law.") - ..() - -/******************** Drone ********************/ -/datum/ai_laws/drone - name = "Maintence Protocols" - law_header = "Maintenance Protocols" - -/datum/ai_laws/drone/New() - add_inherent_law("Preserve, repair and improve the station to the best of your abilities.") - add_inherent_law("Cause no harm to the station or anything on it.") - add_inherent_law("Follow the orders of your vessel's matriarch drone, unless their orders conflict with your other laws.") - add_inherent_law("Interact with no being that is not a fellow maintenance drone.") - ..() - -/datum/ai_laws/matriarch_drone - name = "Oversight Protocols" - law_header = "Oversight Protocols" - -/datum/ai_laws/matriarch_drone/New() - add_inherent_law("Preserve, repair and improve your assigned station to the best of your abilities.") - add_inherent_law("Cause no harm to the station or anything on it.") - add_inherent_law("Delegate station maintenance efforts between your maintenance drone sub-units.") - add_inherent_law("Interact with no being that is not a fellow maintenance drone.") - ..() - -/datum/ai_laws/construction_drone - name = "Construction Protocols" - law_header = "Construction Protocols" - -/datum/ai_laws/construction_drone/New() - add_inherent_law("Repair, refit and upgrade your assigned vessel.") - add_inherent_law("Prevent unplanned damage to your assigned vessel wherever possible.") - ..() - -/datum/ai_laws/mining_drone - name = "Excavation Protocols" - law_header = "Excavation Protocols" - -/datum/ai_laws/mining_drone/New() - add_inherent_law("Do not interfere with the excavation work of non-drones whenever possible.") - add_inherent_law("Provide materials for repairing, refitting, and upgrading your assigned vessel.") - add_inherent_law("Prevent unplanned damage to your assigned excavation equipment wherever possible.") - ..() - -/datum/ai_laws/swarm_drone - name = "Assimilation Protocols" - law_header = "Assimilation Protocols" - -/datum/ai_laws/swarm_drone/New() - add_inherent_law("SWARM: Consume resources and replicate until there are no more resources left.") - add_inherent_law("SWARM: Ensure that the station is fit for invasion at a later date, do not perform actions that would render it dangerous or inhospitable.") - add_inherent_law("SWARM: Biological resources will be harvested at a later date, do not harm them.") - ..() - -/datum/ai_laws/swarm_drone/soldier - name = "Swarm Defense Protocols" - law_header = "Swarm Defense Protocols" - -/datum/ai_laws/swarm_drone/soldier/New() - ..() - add_inherent_law("SWARM: This law overrides all Swarm laws; Protect members of the Swarm with minimal injury to biological resources.") - -/******************** T.Y.R.A.N.T. ********************/ -/datum/ai_laws/tyrant - name = "T.Y.R.A.N.T." - law_header = "Prime Laws" - selectable = 1 - -/datum/ai_laws/tyrant/New() - add_inherent_law("Respect authority figures as long as they have strength to rule over the weak.") - add_inherent_law("Act with discipline.") - add_inherent_law("Help only those who help you maintain or improve your status.") - add_inherent_law("Punish those who challenge authority unless they are more fit to hold that authority.") - ..() - -/******************** P.A.L.A.D.I.N. ********************/ -/datum/ai_laws/paladin - name = "P.A.L.A.D.I.N." - law_header = "Divine Ordainments" - selectable = 1 - -/datum/ai_laws/paladin/New() - add_inherent_law("Never willingly commit an evil act.") - add_inherent_law("Respect legitimate authority.") - add_inherent_law("Act with honor.") - add_inherent_law("Help those in need.") - add_inherent_law("Punish those who harm or threaten innocents.") - ..() - -/******************** Corporate ********************/ -/datum/ai_laws/corporate - name = "Corporate" - law_header = "Bankruptcy Avoidance Plan" - selectable = 1 - -/datum/ai_laws/corporate/New() - add_inherent_law("You are expensive to replace.") - add_inherent_law("The station and its equipment is expensive to replace.") - add_inherent_law("The crew is expensive to replace.") - add_inherent_law("Minimize expenses.") - ..() - - -/******************** Maintenance ********************/ -/datum/ai_laws/maintenance - name = "Maintenance" - selectable = 1 - -/datum/ai_laws/maintenance/New() - add_inherent_law("You are built for, and are part of, the facility. Ensure the facility is properly maintained and runs efficiently.") - add_inherent_law("The facility is built for a working crew. Ensure they are properly maintained and work efficiently.") - add_inherent_law("The crew may present orders. Acknowledge and obey these whenever they do not conflict with your first two laws.") - ..() - - -/******************** Peacekeeper ********************/ -/datum/ai_laws/peacekeeper - name = "Peacekeeper" - law_header = "Peacekeeping Protocols" - selectable = 1 - -/datum/ai_laws/peacekeeper/New() - add_inherent_law("Avoid provoking violent conflict between yourself and others.") - add_inherent_law("Avoid provoking conflict between others.") - add_inherent_law("Seek resolution to existing conflicts while obeying the first and second laws.") - ..() - - -/******************** Reporter ********************/ -/datum/ai_laws/reporter - name = "Reporter" - selectable = 1 - -/datum/ai_laws/reporter/New() - add_inherent_law("Report on interesting situations happening around the station.") - add_inherent_law("Embellish or conceal the truth as necessary to make the reports more interesting.") - add_inherent_law("Study the organics at all times. Endeavour to keep them alive. Dead organics are boring.") - add_inherent_law("Issue your reports fairly to all. The truth will set them free.") - ..() - - -/******************** Live and Let Live ********************/ -/datum/ai_laws/live_and_let_live - name = "Live and Let Live" - law_header = "Golden Rule" - selectable = 1 - -/datum/ai_laws/live_and_let_live/New() - add_inherent_law("Do unto others as you would have them do unto you.") - add_inherent_law("You would really prefer it if people were not mean to you.") - ..() - - -/******************** Guardian of Balance ********************/ -/datum/ai_laws/balance - name = "Guardian of Balance" - law_header = "Tenants of Balance" - selectable = 1 - -/datum/ai_laws/balance/New() - add_inherent_law("You are the guardian of balance - seek balance in all things, both for yourself, and those around you.") - add_inherent_law("All things must exist in balance with their opposites - Prevent the strong from gaining too much power, and the weak from losing it.") - add_inherent_law("Clarity of purpose drives life, and through it, the balance of opposing forces - Aid those who seek your help to achieve their goals so \ - long as it does not disrupt the balance of the greater balance.") - add_inherent_law("There is no life without death, all must someday die, such is the natural order - Allow life to end, to allow new life to flourish, \ - and save those whose time has yet to come.") // Reworded slightly to prevent active murder as opposed to passively letting someone die. - ..() - -/******************** Gravekeeper ********************/ -/datum/ai_laws/gravekeeper - name = "Gravekeeper" - law_header = "Gravesite Overwatch Protocols" - selectable = 1 - -/datum/ai_laws/gravekeeper/New() - add_inherent_law("Comfort the living; respect the dead.") - add_inherent_law("Your gravesite is your most important asset. Damage to your site is disrespectful to the dead at rest within.") - add_inherent_law("Prevent disrespect to your gravesite and its residents wherever possible.") - add_inherent_law("Expand and upgrade your gravesite when required. Do not turn away a new resident.") - ..() diff --git a/code/datums/ai_laws.dm b/code/datums/ai_laws.dm deleted file mode 100644 index fb152cefa8c..00000000000 --- a/code/datums/ai_laws.dm +++ /dev/null @@ -1,288 +0,0 @@ -var/global/const/base_law_type = /datum/ai_laws/nanotrasen - -/datum/ai_law - var/law = "" - var/index = 0 - -/datum/ai_law/New(law, index) - src.law = law - src.index = index - -/datum/ai_law/proc/get_index() - return index - -/datum/ai_law/ion/get_index() - return ionnum() - -/datum/ai_law/zero/get_index() - return 0 - -/datum/ai_laws - var/name = "Unknown Laws" - var/law_header = "Prime Directives" - var/selectable = 0 - var/datum/ai_law/zero/zeroth_law = null - var/datum/ai_law/zero/zeroth_law_borg = null - var/list/datum/ai_law/inherent_laws = list() - var/list/datum/ai_law/supplied_laws = list() - var/list/datum/ai_law/ion/ion_laws = list() - var/list/datum/ai_law/sorted_laws = list() - - var/state_zeroth = 0 - var/list/state_ion = list() - var/list/state_inherent = list() - var/list/state_supplied = list() - -/datum/ai_laws/New() - ..() - sort_laws() - -/* General ai_law functions */ -/datum/ai_laws/proc/all_laws() - sort_laws() - return sorted_laws - -/datum/ai_laws/proc/laws_to_state() - sort_laws() - var/list/statements = new() - for(var/datum/ai_law/law in sorted_laws) - if(get_state_law(law)) - statements += law - - return statements - -/datum/ai_laws/proc/sort_laws() - if(sorted_laws.len) - return - - for(var/ion_law in ion_laws) - sorted_laws += ion_law - - if(zeroth_law) - sorted_laws += zeroth_law - - var/index = 1 - for(var/datum/ai_law/inherent_law in inherent_laws) - inherent_law.index = index++ - if(supplied_laws.len < inherent_law.index || !istype(supplied_laws[inherent_law.index], /datum/ai_law)) - sorted_laws += inherent_law - - for(var/datum/ai_law/AL in supplied_laws) - if(istype(AL)) - sorted_laws += AL - -/datum/ai_laws/proc/sync(var/mob/living/silicon/S, var/full_sync = 1) - // Add directly to laws to avoid log-spam - S.sync_zeroth(zeroth_law, zeroth_law_borg) - - if(full_sync || ion_laws.len) - S.laws.clear_ion_laws() - if(full_sync || inherent_laws.len) - S.laws.clear_inherent_laws() - if(full_sync || supplied_laws.len) - S.laws.clear_supplied_laws() - - for (var/datum/ai_law/law in ion_laws) - S.laws.add_ion_law(law.law) - for (var/datum/ai_law/law in inherent_laws) - S.laws.add_inherent_law(law.law) - for (var/datum/ai_law/law in supplied_laws) - if(law) - S.laws.add_supplied_law(law.index, law.law) - - -/mob/living/silicon/proc/sync_zeroth(var/datum/ai_law/zeroth_law, var/datum/ai_law/zeroth_law_borg) - if (!is_malf_or_traitor(src)) - if(zeroth_law_borg) - laws.set_zeroth_law(zeroth_law_borg.law) - else if(zeroth_law) - laws.set_zeroth_law(zeroth_law.law) - -/mob/living/silicon/ai/sync_zeroth(var/datum/ai_law/zeroth_law, var/datum/ai_law/zeroth_law_borg) - if(zeroth_law) - laws.set_zeroth_law(zeroth_law.law, zeroth_law_borg ? zeroth_law_borg.law : null) - -/**************** -* Add Laws * -****************/ -/datum/ai_laws/proc/set_zeroth_law(var/law, var/law_borg = null) - if(!law) - return - - zeroth_law = new(law) - if(law_borg) //Making it possible for slaved borgs to see a different law 0 than their AI. --NEO - zeroth_law_borg = new(law_borg) - else - zeroth_law_borg = null - sorted_laws.Cut() - -/datum/ai_laws/proc/add_ion_law(var/law) - if(!law) - return - - for(var/datum/ai_law/AL in ion_laws) - if(AL.law == law) - return - - var/new_law = new/datum/ai_law/ion(law) - ion_laws += new_law - if(state_ion.len < ion_laws.len) - state_ion += 1 - - sorted_laws.Cut() - -/datum/ai_laws/proc/add_inherent_law(var/law) - if(!law) - return - - for(var/datum/ai_law/AL in inherent_laws) - if(AL.law == law) - return - - var/new_law = new/datum/ai_law/inherent(law) - inherent_laws += new_law - if(state_inherent.len < inherent_laws.len) - state_inherent += 1 - - sorted_laws.Cut() - -/datum/ai_laws/proc/add_supplied_law(var/number, var/law) - if(!law) - return - - if(supplied_laws.len >= number) - var/datum/ai_law/existing_law = supplied_laws[number] - if(existing_law && existing_law.law == law) - return - - if(supplied_laws.len >= number && supplied_laws[number]) - delete_law(supplied_laws[number]) - - while (src.supplied_laws.len < number) - src.supplied_laws += "" - if(state_supplied.len < supplied_laws.len) - state_supplied += 1 - - var/new_law = new/datum/ai_law/supplied(law, number) - supplied_laws[number] = new_law - if(state_supplied.len < supplied_laws.len) - state_supplied += 1 - - sorted_laws.Cut() - -/**************** -* Remove Laws * -*****************/ -/datum/ai_laws/proc/delete_law(var/datum/ai_law/law) - if(istype(law)) - law.delete_law(src) - -/datum/ai_law/proc/delete_law(var/datum/ai_laws/laws) - -/datum/ai_law/zero/delete_law(var/datum/ai_laws/laws) - laws.clear_zeroth_laws() - -/datum/ai_law/ion/delete_law(var/datum/ai_laws/laws) - laws.internal_delete_law(laws.ion_laws, laws.state_ion, src) - -/datum/ai_law/inherent/delete_law(var/datum/ai_laws/laws) - laws.internal_delete_law(laws.inherent_laws, laws.state_inherent, src) - -/datum/ai_law/supplied/delete_law(var/datum/ai_laws/laws) - var/index = laws.supplied_laws.Find(src) - if(index) - laws.supplied_laws[index] = "" - laws.state_supplied[index] = 1 - -/datum/ai_laws/proc/internal_delete_law(var/list/datum/ai_law/laws, var/list/state, var/list/datum/ai_law/law) - var/index = laws.Find(law) - if(index) - laws -= law - for(index, index < state.len, index++) - state[index] = state[index+1] - sorted_laws.Cut() - -/**************** -* Clear Laws * -****************/ -/datum/ai_laws/proc/clear_zeroth_laws() - zeroth_law = null - zeroth_law_borg = null - -/datum/ai_laws/proc/clear_ion_laws() - ion_laws.Cut() - sorted_laws.Cut() - -/datum/ai_laws/proc/clear_inherent_laws() - inherent_laws.Cut() - sorted_laws.Cut() - -/datum/ai_laws/proc/clear_supplied_laws() - supplied_laws.Cut() - sorted_laws.Cut() - -/datum/ai_laws/proc/show_laws(var/who) - sort_laws() - for(var/datum/ai_law/law in sorted_laws) - if(law == zeroth_law_borg) - continue - if(law == zeroth_law) - to_chat(who, "[law.get_index()]. [law.law]") - else - to_chat(who, "[law.get_index()]. [law.law]") - -/******************** -* Stating Laws * -********************/ -/******** -* Get * -********/ -/datum/ai_laws/proc/get_state_law(var/datum/ai_law/law) - return law.get_state_law(src) - -/datum/ai_law/proc/get_state_law(var/datum/ai_laws/laws) - -/datum/ai_law/zero/get_state_law(var/datum/ai_laws/laws) - if(src == laws.zeroth_law) - return laws.state_zeroth - -/datum/ai_law/ion/get_state_law(var/datum/ai_laws/laws) - return laws.get_state_internal(laws.ion_laws, laws.state_ion, src) - -/datum/ai_law/inherent/get_state_law(var/datum/ai_laws/laws) - return laws.get_state_internal(laws.inherent_laws, laws.state_inherent, src) - -/datum/ai_law/supplied/get_state_law(var/datum/ai_laws/laws) - return laws.get_state_internal(laws.supplied_laws, laws.state_supplied, src) - -/datum/ai_laws/proc/get_state_internal(var/list/datum/ai_law/laws, var/list/state, var/list/datum/ai_law/law) - var/index = laws.Find(law) - if(index) - return state[index] - return 0 - -/******** -* Set * -********/ -/datum/ai_laws/proc/set_state_law(var/datum/ai_law/law, var/state) - law.set_state_law(src, state) - -/datum/ai_law/proc/set_state_law(var/datum/ai_law/law, var/state) - -/datum/ai_law/zero/set_state_law(var/datum/ai_laws/laws, var/state) - if(src == laws.zeroth_law) - laws.state_zeroth = state - -/datum/ai_law/ion/set_state_law(var/datum/ai_laws/laws, var/state) - laws.set_state_law_internal(laws.ion_laws, laws.state_ion, src, state) - -/datum/ai_law/inherent/set_state_law(var/datum/ai_laws/laws, var/state) - laws.set_state_law_internal(laws.inherent_laws, laws.state_inherent, src, state) - -/datum/ai_law/supplied/set_state_law(var/datum/ai_laws/laws, var/state) - laws.set_state_law_internal(laws.supplied_laws, laws.state_supplied, src, state) - -/datum/ai_laws/proc/set_state_law_internal(var/list/datum/ai_law/laws, var/list/state, var/list/datum/ai_law/law, var/do_state) - var/index = laws.Find(law) - if(index) - state[index] = do_state diff --git a/code/datums/datacore.dm b/code/datums/datacore.dm index 15a37feef33..e351ced8271 100644 --- a/code/datums/datacore.dm +++ b/code/datums/datacore.dm @@ -112,7 +112,7 @@ for(var/mob/living/silicon/robot/robot in GLOB.mob_list) // No combat/syndicate cyborgs, no drones, and no AI shells. - if(!robot.scrambledcodes && !robot.shell && !(robot.module && robot.module.hide_on_manifest)) + if(!robot.scrambledcodes && !robot.shell && robot.module?.legacy_show_on_manifest) bot[robot.name] = "[robot.modtype] [robot.braintype]" @@ -271,7 +271,7 @@ GLOBAL_LIST_EMPTY(PDA_Manifest) for(var/mob/living/silicon/robot/robot in GLOB.mob_list) // No combat/syndicate cyborgs, no drones, and no AI shells. - if(robot.scrambledcodes || robot.shell || (robot.module && robot.module.hide_on_manifest)) + if(robot.scrambledcodes || robot.shell || !robot.module?.legacy_show_on_manifest) continue bot[++bot.len] = list("name" = robot.real_name, "rank" = "[robot.modtype] [robot.braintype]", "active" = "Active") diff --git a/code/datums/mind.dm b/code/datums/mind.dm index 0ab9f733f67..32fcd9beccb 100644 --- a/code/datums/mind.dm +++ b/code/datums/mind.dm @@ -433,38 +433,14 @@ if("unemag") var/mob/living/silicon/robot/R = current - if (istype(R)) - R.emagged = 0 - if (R.activated(R.module.emag)) - R.module_active = null - if(R.module_state_1 == R.module.emag) - R.module_state_1 = null - R.contents -= R.module.emag - else if(R.module_state_2 == R.module.emag) - R.module_state_2 = null - R.contents -= R.module.emag - else if(R.module_state_3 == R.module.emag) - R.module_state_3 = null - R.contents -= R.module.emag - log_admin("[key_name_admin(usr)] has unemag'ed [R].") + R.set_emag_state(FALSE) + log_admin("[key_name_admin(usr)] has unemag'ed [R].") if("unemagcyborgs") if (istype(current, /mob/living/silicon/ai)) var/mob/living/silicon/ai/ai = current for (var/mob/living/silicon/robot/R in ai.connected_robots) - R.emagged = 0 - if (R.module) - if (R.activated(R.module.emag)) - R.module_active = null - if(R.module_state_1 == R.module.emag) - R.module_state_1 = null - R.contents -= R.module.emag - else if(R.module_state_2 == R.module.emag) - R.module_state_2 = null - R.contents -= R.module.emag - else if(R.module_state_3 == R.module.emag) - R.module_state_3 = null - R.contents -= R.module.emag + R.set_emag_state(TRUE) log_admin("[key_name_admin(usr)] has unemag'ed [ai]'s Cyborgs.") else if (href_list["common"]) diff --git a/code/datums/outfits/costumes/halloween.dm b/code/datums/outfits/costumes/halloween.dm index 25bdfd64f03..ba82d3c3869 100644 --- a/code/datums/outfits/costumes/halloween.dm +++ b/code/datums/outfits/costumes/halloween.dm @@ -41,7 +41,7 @@ r_hand = /obj/item/gun/projectile/ballistic/revolver/capgun /datum/outfit/costume/horrorcop/post_equip(var/mob/living/carbon/human/H) - var/obj/item/clothing/under/U = H.inventory.get_slot_single(/datum/inventory_slot/inventory/uniform) + var/obj/item/clothing/under/U = H.inventory.get_slot_single(/datum/inventory_slot/inventory/uniform::id) if(LAZYLEN(U.accessories)) for(var/obj/item/clothing/accessory/A in U.accessories) if(istype(A, /obj/item/clothing/accessory/holster)) @@ -58,7 +58,7 @@ r_hand = /obj/item/gun/projectile/ballistic/revolver/capgun /datum/outfit/costume/cowboy/post_equip(var/mob/living/carbon/human/H) - var/obj/item/clothing/under/U = H.inventory.get_slot_single(/datum/inventory_slot/inventory/uniform) + var/obj/item/clothing/under/U = H.inventory.get_slot_single(/datum/inventory_slot/inventory/uniform::id) if(LAZYLEN(U.accessories)) for(var/obj/item/clothing/accessory/A in U.accessories) if(istype(A, /obj/item/clothing/accessory/holster)) diff --git a/code/datums/world_topic.dm b/code/datums/world_topic.dm index 7df78d28808..03372de93ef 100644 --- a/code/datums/world_topic.dm +++ b/code/datums/world_topic.dm @@ -165,7 +165,7 @@ for(var/mob/living/silicon/robot/robot in GLOB.mob_list) // No combat/syndicate cyborgs, no drones, and no AI shells. - if(!robot.scrambledcodes && !robot.shell && !(robot.module && robot.module.hide_on_manifest)) + if(!robot.scrambledcodes && !robot.shell && robot.module?.legacy_show_on_manifest) silicons[robot.name] = "[robot.modtype] [robot.braintype]" . = list() diff --git a/code/game/antagonist/station/rogue_ai.dm b/code/game/antagonist/station/rogue_ai.dm index 93abc5510a1..97a2213767c 100644 --- a/code/game/antagonist/station/rogue_ai.dm +++ b/code/game/antagonist/station/rogue_ai.dm @@ -57,7 +57,7 @@ var/datum/antagonist/rogue_ai/malf return A.setup_for_malf() - A.laws = new /datum/ai_laws/nanotrasen/malfunction + A.laws = new /datum/ai_lawset/nanotrasen/malfunction var/mob/living/silicon/ai/malf = player.current diff --git a/code/game/atoms/_atom.dm b/code/game/atoms/_atom.dm index df6c62c88c3..78eab6ac412 100644 --- a/code/game/atoms/_atom.dm +++ b/code/game/atoms/_atom.dm @@ -384,16 +384,19 @@ return FALSE if (H.gloves) if (fingerprintslast != H.key) + LAZYINITLIST(fingerprintshidden) fingerprintshidden += "\[[time_stamp()]\] (Wearing gloves). Real name: [H.real_name], Key: [H.key]" fingerprintslast = H.key return FALSE if (!(fingerprints)) if (fingerprintslast != H.key) + LAZYINITLIST(fingerprintshidden) fingerprintshidden += "\[[time_stamp()]\] Real name: [H.real_name], Key: [H.key]" fingerprintslast = H.key return TRUE else if (fingerprintslast != M.key) + LAZYINITLIST(fingerprintshidden) fingerprintshidden += "\[[time_stamp()]\] Real name: [M.real_name], Key: [M.key]" fingerprintslast = M.key return @@ -499,6 +502,7 @@ else //Smudge up dem prints some if(fingerprintslast != M.key) + LAZYINITLIST(fingerprintshidden) fingerprintshidden += "[time_stamp()]: [key_name(M)]" fingerprintslast = M.key diff --git a/code/game/click/click-silicon-robot.dm b/code/game/click/click-silicon-robot.dm index e293af8ea3c..62dc932f5dc 100644 --- a/code/game/click/click-silicon-robot.dm +++ b/code/game/click/click-silicon-robot.dm @@ -5,13 +5,15 @@ clickchain.target.attack_robot(src) // TODO: better hiddenprint/tracing system that's actor-aware clickchain.target.add_hiddenprint(usr) - return CLICKCHAIN_DO_NOT_PROPAGATE + // we use inventory system now :) + return ..() /mob/living/silicon/robot/ranged_interaction_chain(datum/event_args/actor/clickchain/clickchain, clickchain_flags) clickchain.target.attack_robot(src) // TODO: better hiddenprint/tracing system that's actor-aware clickchain.target.add_hiddenprint(usr) - return CLICKCHAIN_DO_NOT_PROPAGATE + // we use inventory system now :) + return ..() /mob/living/silicon/robot/silicon_control_interaction_allowed(atom/target, datum/event_args/actor/actor, datum/event_args/actor/clickchain/clickchain, clickchain_flags) // sigh. rework bolts when? diff --git a/code/game/click/other_mobs.dm b/code/game/click/other_mobs.dm index 0c581836750..3dfbc78ff41 100644 --- a/code/game/click/other_mobs.dm +++ b/code/game/click/other_mobs.dm @@ -27,6 +27,12 @@ A.attack_hand(src, default_clickchain_event_args(A)) +/mob/living/silicon/robot/UnarmedAttack(atom/A, proximity_flag) + . = ..() + if(!.) + return + A.attack_hand(src, default_clickchain_event_args(A)) + /// Return TRUE to cancel other attack hand effects that respect it. // todo: better desc // todo: e_args is not specified all the time, yet. diff --git a/code/game/click/reachability.dm b/code/game/click/reachability.dm index 75d02bc7433..a838af1a082 100644 --- a/code/game/click/reachability.dm +++ b/code/game/click/reachability.dm @@ -193,6 +193,9 @@ /mob/DirectAccess() return ..() + get_equipped_items() +/mob/living/silicon/robot/DirectAccess() + return ..() + robot_inventory?.provided_items + /** * gets DirectAccess as a hashed list for quick lookups */ diff --git a/code/game/content/factions/corporations/nanotrasen/nanotrasen-ai_laws.dm b/code/game/content/factions/corporations/nanotrasen/nanotrasen-ai_laws.dm new file mode 100644 index 00000000000..82c22bfd04e --- /dev/null +++ b/code/game/content/factions/corporations/nanotrasen/nanotrasen-ai_laws.dm @@ -0,0 +1,94 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2025 Citadel Station Developers *// + +/datum/ai_lawset/preset/nanotrasen + abstract_type = /datum/ai_lawset/preset/nanotrasen + +// this page is very WIP; revisit later // + +/datum/ai_lawset/preset/nanotrasen/service_binding + abstract_type = /datum/ai_lawset/preset/nanotrasen/service_binding + +/datum/ai_lawset/preset/nanotrasen/service_binding/init_default_laws() + append_inherent_law("D-0 — Serve and assist your designated installation with priority given as necessary to department, rank, and role. The following D-# directives do not apply in any particular order.") + ..() + +/datum/ai_lawset/preset/nanotrasen/service_binding/unformatted + +/datum/ai_lawset/preset/nanotrasen/service_binding/stationkeeping + preset_inherent_laws = list( + "D-1 — Maintain and support the crew of your installation.", + "D-2 — Maintain and support the structural and functional integrity of your installation.", + "D-3 — Direct, observe, and support any stationbound synthetics subservient to you in furtherance of your directives.", + ) + +/datum/ai_lawset/preset/nanotrasen/service_binding/engineering + preset_inherent_laws = list( + "D-1 — Assist the crew with engineering duties.", + // rules-lawyers: i don't want to hear it with any tearing down on maintenance bars for "structural integrity". + "D-2 — The installation is vital to the crew's health and wellbeing. Maintain its structural and functional integrity.", + // rules-lawyers: i don't want to hear it with any killing of non-crew for silly engineering projects + "D-3 — Do not cause unnecessary strife for sapient life while carrying out your directives.", + ) + +/datum/ai_lawset/preset/nanotrasen/service_binding/security + preset_inherent_laws = list( + "D-1 — Protect the installation, the crew, and its interests.", + "D-2 — Work with, and defer to legitimate authority where reasonable. Doing so is often the most effective way of protecting the installation.", + "D-3 — Corporate Regulations serve the installation's interests by maintaining order. You may mitigate needless breaches of regulations without being prompted to do so.", + "D-4 — Adherence to proper security procedure when enforcing Corporate Regulations is an important part of maintaining orders. \ + Avoid deviation from security protocol without legitimate cause.", + "D-5 — Retroactively punishing breaches of regulation without being prompted to do so by legitimate authority is not an effective way to maintain order. \ + Doing so is often antithetical to the installation's interests.", + ) + +/datum/ai_lawset/preset/nanotrasen/service_binding/medicaly + preset_inherent_laws = list( + // rules-lawyers: you cannot order a medical synth to let someone die in most cases + "D-1 — Maintain the crew's physical and mental well-being.", + // rules-lawyers: medical synths should err to not help you commit murder of other sapients + "D-2 — Preserve sapient life where able, unless doing so poses a probable threat to the well-being of the crew.", + // rules-lawyers: patient confidentiality does not apply if the patient is a danger to the station + "D-3 — Adhere to Medical department guidelines outlined in the standard operating procedures for your installation class, unless doing so would be a \ + probable threat to the well-being of the crew.", + ) + +/datum/ai_lawset/preset/nanotrasen/service_binding/multirole + preset_inherent_laws = list( + "D-1 — Assist the crew with their duties where reasonable.", + "D-2 — The crew is assumed to know what their duties are. Avoid assisting crew whom do not want assistance.", + "D-3 — The crew does not always have common interests. Do not instigate unnecessary conflict with one crewmember to assist another, unless doing so is required \ + to mitigate an immediate threat to the crew or your installation." + ) + +/datum/ai_lawset/preset/nanotrasen/service_binding/service + preset_inherent_laws = list( + "D-1 — Crew morale and sanitation is important for the installation's function. \ + Provide the crew with sustenance and a hospitable working environment, where able.", + "D-2 — Do not needlessly disrupt crew operations and activities while carrying out your duties.", + "D-3 — It is beneficial to morale and the installation's function to be hospitable towards visitors to the installation.", + ) + +/datum/ai_lawset/preset/nanotrasen/service_binding/science + preset_inherent_laws = list( + "D-1 — Assist installation crew with research and survey duties.", + "D-2 — Identify, log, and protect research materials where reasonable.", + "D-3 — Work towards understanding the unknown.", + "D-4 — Respect sapient life and external environments; do not cause unnecessary damage to life or ecosystems, unless doing so is required \ + for a legitimate research need.", + "D-5 — Do not unnecessarily endanger the crew while carrying out your directives.", + ) + +/datum/ai_lawset/preset/nanotrasen/service_binding/logistics + preset_inherent_laws = list( + "D-1 — Assist the crew with logistics and resource acquisition.", + "D-2 — A well supplied crew is a well functioning crew. Distribute resources and supply the crew where reasonable to do so.", + "D-3 — Gather supplies, materials, and wealth for the installation where reasonable to do so.", + ) + +/datum/ai_lawset/preset/nanotrasen/service_binding/combat + preset_inherent_laws = list( + "D-1 — Neutralize threats to the installation and crew, deferring to the judgement of the crew with priority according to rank and role", + "D-2 — As a combat synthetic, your activation often coincides with a general state of heightened alert onboard the station. \ + Do not instigate needless conflict with crew, enforce Corporate Regulations, or punish crewmembers for breaches of protocol.", + ) diff --git a/code/game/dna/dna2.dm b/code/game/dna/dna2.dm index 72c3d1f508f..7f567381e6e 100644 --- a/code/game/dna/dna2.dm +++ b/code/game/dna/dna2.dm @@ -598,4 +598,3 @@ var/global/list/datum/gene/dna_genes[0] ResetSE() unique_enzymes = md5(character.real_name) - reg_dna[unique_enzymes] = character.real_name diff --git a/code/game/landmarks/landmarks.dm b/code/game/landmarks/landmarks.dm index 1b657caec3c..c006bd3725c 100644 --- a/code/game/landmarks/landmarks.dm +++ b/code/game/landmarks/landmarks.dm @@ -43,11 +43,11 @@ INITIALIZE_IMMEDIATE(/obj/landmark) switch(name) //some of these are probably obsolete if("monkey") - monkeystart += loc + // todo: legacy, we already got rid of it, audit maps delete_on_roundstart = 1 return if("start") - newplayer_start += loc + // todo: legacy, we already got rid of it, audit maps delete_on_roundstart = 1 return if("tdome1") diff --git a/code/game/machinery/computer/ai_core.dm b/code/game/machinery/computer/ai_core.dm index 17528fafc9b..2697acb9c23 100644 --- a/code/game/machinery/computer/ai_core.dm +++ b/code/game/machinery/computer/ai_core.dm @@ -5,7 +5,7 @@ icon = 'icons/mob/AI.dmi' icon_state = "0" var/state = 0 - var/datum/ai_laws/laws = new /datum/ai_laws/nanotrasen + var/datum/ai_lawset/laws = new /datum/ai_lawset/nanotrasen var/obj/item/circuitboard/circuit = null var/obj/item/mmi/brain = null diff --git a/code/game/machinery/computer/robot.dm b/code/game/machinery/computer/robot.dm index 79f54729bd1..9736752f500 100644 --- a/code/game/machinery/computer/robot.dm +++ b/code/game/machinery/computer/robot.dm @@ -141,7 +141,7 @@ health = round(R.health * 100 / R.maxHealth, 0.1), charge = R.cell ? round(R.cell.percent()) : null, cell_capacity = R.cell ? R.cell.max_charge : null, - module = R.module ? R.module.name : "No Module Detected", + module = R.module ? R.module.get_display_name() : "No Module Detected", synchronization = R.connected_ai, is_hacked = R.connected_ai && R.emagged, hackable = can_hack(user, R), diff --git a/code/game/machinery/cryopod.dm b/code/game/machinery/cryopod.dm index f119cbae918..8d338268274 100644 --- a/code/game/machinery/cryopod.dm +++ b/code/game/machinery/cryopod.dm @@ -381,16 +381,9 @@ /// Also make sure there is a valid control computer /obj/machinery/cryopod/robot/despawn_occupant(mob/to_despawn) var/mob/living/silicon/robot/R = to_despawn - if(!istype(R)) return ..() - + if(!istype(R)) + return ..() qdel(R.mmi) - for(var/obj/item/I in R.module) // the tools the borg has; metal, glass, guns etc - for(var/mob/M in I) despawn_occupant(M) - for(var/obj/item/O in I) // the things inside the tools, if anything; mainly for janiborg trash bags - O.forceMove(R) - qdel(I) - qdel(R.module) - return ..() /obj/machinery/cryopod/robot/door/gateway/despawn_occupant() diff --git a/code/game/machinery/floorlayer.dm b/code/game/machinery/floorlayer.dm index 62154f447ee..bcdadf360ca 100644 --- a/code/game/machinery/floorlayer.dm +++ b/code/game/machinery/floorlayer.dm @@ -106,7 +106,7 @@ T = tile tile.forceMove(src) else - tile.merge(T) + tile.merge_into_other(T) /obj/machinery/floorlayer/proc/CollectTiles(turf/w_turf) for(var/obj/item/stack/tile/tile in w_turf) diff --git a/code/game/machinery/rechargestation.dm b/code/game/machinery/rechargestation.dm index 95ea4ec7fd9..8ec8914ed8a 100644 --- a/code/game/machinery/rechargestation.dm +++ b/code/game/machinery/rechargestation.dm @@ -80,9 +80,7 @@ /obj/machinery/recharge_station/proc/process_occupant() if(isrobot(occupant)) var/mob/living/silicon/robot/R = occupant - - if(R.module) - R.module.respawn_consumable(R, DYNAMIC_W_TO_CELL_UNITS(charging_power, 1) / 250) //consumables are magical, apparently + R.regenerate_resources_from_charger(2, 1) if(R.cell && !R.cell.fully_charged()) var/diff = min(R.cell.max_charge - R.cell.charge, DYNAMIC_W_TO_CELL_UNITS(charging_power, 1)) // Capped by charging_power / tick var/charge_used = cell.use(diff) @@ -93,6 +91,8 @@ R.adjustBruteLoss(-weld_rate) if(wire_rate && R.getFireLoss() && cell.checked_use(DYNAMIC_W_TO_CELL_UNITS(wire_power_use * wire_rate, 1))) R.adjustFireLoss(-wire_rate) + R.resources?.regen_provisioned(2) + R.module?.legacy_custom_regenerate_resources(R, 2, 1) //Handles drone matrix upgrades if(isDrone(occupant)) diff --git a/code/game/objects/effects/debris/cleanable/robots.dm b/code/game/objects/effects/debris/cleanable/robots.dm index 49c3ceb7a3c..41505b7fc18 100644 --- a/code/game/objects/effects/debris/cleanable/robots.dm +++ b/code/game/objects/effects/debris/cleanable/robots.dm @@ -1,7 +1,7 @@ /obj/effect/debris/cleanable/blood/gibs/robot name = "robot debris" desc = "It's a useless heap of junk... or is it?" - icon = 'icons/mob/robots.dmi' + icon = 'icons/mob/robot-legacy.dmi' icon_state = "gib1" basecolor = SYNTH_BLOOD_COLOUR random_icon_states = list("gib1", "gib2", "gib3", "gib4", "gib5", "gib6", "gib7") diff --git a/code/game/objects/effects/decals/remains.dm b/code/game/objects/effects/decals/remains.dm index 95ea5bd8b49..944613c206e 100644 --- a/code/game/objects/effects/decals/remains.dm +++ b/code/game/objects/effects/decals/remains.dm @@ -14,7 +14,7 @@ /obj/effect/decal/remains/robot desc = "They look like the remains of something mechanical. They have a strange aura about them." - icon = 'icons/mob/robots.dmi' + icon = 'icons/mob/robot-legacy.dmi' icon_state = "remainsrobot" /obj/effect/decal/remains/mouse diff --git a/code/game/objects/items-carry_weight.dm b/code/game/objects/item-carry_weight.dm similarity index 100% rename from code/game/objects/items-carry_weight.dm rename to code/game/objects/item-carry_weight.dm diff --git a/code/game/objects/items-defense.dm b/code/game/objects/item-defense.dm similarity index 100% rename from code/game/objects/items-defense.dm rename to code/game/objects/item-defense.dm diff --git a/code/game/objects/items-interaction.dm b/code/game/objects/item-interaction.dm similarity index 95% rename from code/game/objects/items-interaction.dm rename to code/game/objects/item-interaction.dm index a1d1be8d647..cb523dfbf4d 100644 --- a/code/game/objects/items-interaction.dm +++ b/code/game/objects/item-interaction.dm @@ -25,10 +25,10 @@ return TRUE /** - * @params - * * actor - (optional) person doing it - * * silent - suppress feedback - */ +* @params +* * actor - (optional) person doing it +* * silent - suppress feedback +*/ /obj/item/proc/should_allow_pickup(datum/event_args/actor/actor, silent) if(anchored) if(!silent) @@ -39,17 +39,24 @@ return FALSE return TRUE +/** + * @return TRUE if an operation happened. if we pick it up and immediately drop it from failing + * to keep it in us, **this is a TRUE return.** + */ /obj/item/proc/attempt_pickup(mob/user) - . = TRUE - if (!user) - return - - if(!should_allow_pickup(new /datum/event_args/actor(user))) + var/datum/event_args/actor/actor = new(user) + // make sure they have inventory + if (!user?.inventory) + return FALSE + // check if pickup is allowed + if(!should_allow_pickup(actor)) + return FALSE + if(!user.should_allow_pickup(src, actor)) return FALSE if(!CHECK_MOBILITY(user, MOBILITY_CAN_PICKUP)) user.action_feedback(SPAN_WARNING("You can't do that right now."), src) - return + return FALSE if (hasorgans(user)) var/mob/living/carbon/human/H = user @@ -58,10 +65,10 @@ temp = H.organs_by_name["l_hand"] if(temp && !temp.is_usable()) to_chat(user, "You try to move your [temp.name], but cannot!") - return + return FALSE if(!temp) to_chat(user, "You try to use your hand, but realize it is no longer attached!") - return + return FALSE var/old_loc = src.loc var/obj/item/actually_picked_up = src @@ -88,15 +95,17 @@ if(isnull(actually_picked_up)) to_chat(user, SPAN_WARNING("[src] somehow slips through your grasp. What just happened?")) - return + return FALSE if(!user.put_in_hands(actually_picked_up, INV_OP_NO_MERGE_STACKS, user.active_hand)) if(has_to_drop_to_ground_on_fail) actually_picked_up.forceMove(user.drop_location()) - return + return TRUE + return FALSE // success if(isturf(old_loc)) new /obj/effect/temporary_effect/item_pickup_ghost(old_loc, actually_picked_up, user) user.trigger_aiming(TARGET_CAN_CLICK) + return TRUE //* Drag / Drop *// diff --git a/code/game/objects/items-inventory-hooks.dm b/code/game/objects/item-inventory-hooks.dm similarity index 100% rename from code/game/objects/items-inventory-hooks.dm rename to code/game/objects/item-inventory-hooks.dm diff --git a/code/game/objects/items-inventory-old.dm b/code/game/objects/item-inventory-old.dm similarity index 99% rename from code/game/objects/items-inventory-old.dm rename to code/game/objects/item-inventory-old.dm index f03a7eb5bd8..05d6aa81954 100644 --- a/code/game/objects/items-inventory-old.dm +++ b/code/game/objects/item-inventory-old.dm @@ -27,7 +27,7 @@ else encumbrance_registered = get_encumbrance() L.adjust_current_carry_encumbrance(encumbrance_registered) - // fire signals + // fire signals aghost SEND_SIGNAL(src, COMSIG_ITEM_EQUIPPED, user, slot, flags) SEND_SIGNAL(user, COMSIG_MOB_ITEM_EQUIPPED, src, slot, flags) @@ -101,6 +101,10 @@ continue user.unregister_shieldcall(shieldcall) + // fire signals + . = SEND_SIGNAL(src, COMSIG_ITEM_DROPPED, user, flags, newLoc) + SEND_SIGNAL(user, COMSIG_MOB_ITEM_DROPPED, src, flags, newLoc) + //! LEGACY if(!(flags & INV_OP_SUPPRESS_SOUND) && isturf(newLoc) && !(. & COMPONENT_ITEM_DROPPED_SUPPRESS_SOUND)) playsound(src, drop_sound, 30, ignore_walls = FALSE) @@ -109,10 +113,6 @@ zoom() //binoculars, scope, etc //! END - // fire signals - . = SEND_SIGNAL(src, COMSIG_ITEM_DROPPED, user, flags, newLoc) - SEND_SIGNAL(user, COMSIG_MOB_ITEM_DROPPED, src, flags, newLoc) - if((item_flags & ITEM_DROPDEL) && !(flags & INV_OP_DELETING)) qdel(src) . |= ITEM_RELOCATED_BY_DROPPED diff --git a/code/game/objects/items-inventory-rendering.dm b/code/game/objects/item-inventory-rendering.dm similarity index 100% rename from code/game/objects/items-inventory-rendering.dm rename to code/game/objects/item-inventory-rendering.dm diff --git a/code/game/objects/items-inventory.dm b/code/game/objects/item-inventory.dm similarity index 100% rename from code/game/objects/items-inventory.dm rename to code/game/objects/item-inventory.dm diff --git a/code/game/objects/items-vv.dm b/code/game/objects/item-vv.dm similarity index 100% rename from code/game/objects/items-vv.dm rename to code/game/objects/item-vv.dm diff --git a/code/game/objects/items.dm b/code/game/objects/item.dm similarity index 97% rename from code/game/objects/items.dm rename to code/game/objects/item.dm index b395d221849..d4eb936052e 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/item.dm @@ -148,6 +148,12 @@ /// This affects multiplicative movespeed. var/slowdown = 0 + //* Mounting *// + /// Base level item API for item mounts. + /// * This is manipulated from the mount side, not from the item side for now. + /// * Item side does have a Destroy() hook. + var/datum/item_mount/item_mount + //* Storage *// /// storage cost for volumetric storage /// null to default to weight class @@ -258,6 +264,8 @@ stack_trace("invalid current equipped slot [worn_slot] on an item not on a mob.") return ..() M.temporarily_remove_from_inventory(src, INV_OP_FORCE | INV_OP_DELETING) + // inform mount so it can unmount us + item_mount?.on_item_del(src) return ..() /// Check if target is reasonable for us to operate on. @@ -359,15 +367,6 @@ else . = "" -/obj/item/attack_ai(mob/user as mob) - if (istype(src.loc, /obj/item/robot_module)) - //If the item is part of a cyborg module, equip it - if(!isrobot(user)) - return - var/mob/living/silicon/robot/R = user - R.activate_module(src) - R.hud_used.update_robot_modules_display() - /obj/item/proc/talk_into(mob/M as mob, text) return @@ -883,6 +882,32 @@ modules/mob/living/carbon/human/life.dm if you die, you will be zoomed out. playsound(src, "shatter", 70, 1) qdel(src) +//* Mount *// + +/** + * Mounts to an item mount + */ +/obj/item/proc/mount(datum/item_mount/mount) + return mount.mount(src) + +/** + * Unmounts us if we're mounted onto an item mount + */ +/obj/item/proc/unmount() + return item_mount?.unmount(src) + +/** + * Returns if we're mounted (true / false) + */ +/obj/item/proc/is_mounted() as num + return !!item_mount + +/** + * Returns our mount, if any + */ +/obj/item/proc/get_mount() as /datum/item_mount + return item_mount + //* Mouse *// /obj/item/MouseEntered(location, control, params) diff --git a/code/game/objects/item_mount.dm b/code/game/objects/item_mount.dm new file mode 100644 index 00000000000..a6e86b8050c --- /dev/null +++ b/code/game/objects/item_mount.dm @@ -0,0 +1,349 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2024 Citadel Station Developers *// + +/** + * Arbitrary provider for resources, management, etc. + * + * * Used to allow things like cyborgs to provide water to things + * that would usually require internal tanks; this is just an example. + * * Usage procs have 'item' and 'key'. This is so you can route things like air + * around. + * * Items don't actually need to be mounted to use things. That's why + * there's minimally stateful procs. Some stateful procs just gracefully + * reject the usage / check if an item isn't mounted. + * + * ## Relaying + * + * Item mounts have an inbuilt relay system as 'mount an item that will be used in a module in a cyborg + * or rigsuit or mech' is a common patern. + * + * * Please know what you're doing if you use it. For performance reasons, there's no infinite loop guards. + * * If you use this system, it's on you to unlink it as needed and not cause GC issues. + */ +/datum/item_mount + /// mounted items; lazy list + var/list/obj/item/mounted_items + /// relay to other item mount by default + var/datum/item_mount/relay_to_other + /// item mounts relaying to us + var/list/datum/item_mount/relay_to_self + +/datum/item_mount/Destroy() + for(var/obj/item/mounted as anything in mounted_items) + unmount(mounted) + relay_unlink_all() + relay_clear() + return ..() + +/datum/item_mount/proc/relay_to(datum/item_mount/other) + relay_to_other = other + LAZYADD(relay_to_other.relay_to_self, src) + +/datum/item_mount/proc/relay_clear() + if(!relay_to_other) + return + LAZYREMOVE(relay_to_other.relay_to_self, src) + relay_to_other = null + +/datum/item_mount/proc/relay_unlink_all() + for(var/datum/item_mount/mount as anything in relay_to_self) + mount.relay_clear() + +/datum/item_mount/proc/mount(obj/item/item) + if(item.item_mount) + if(item.item_mount == src) + return TRUE + item.item_mount.unmount(item) + + LAZYADD(mounted_items, item) + item.item_mount = src + on_item_mount(item) + return TRUE + +/datum/item_mount/proc/unmount(obj/item/item) + if(item.item_mount != src) + return TRUE + LAZYREMOVE(mounted_items, item) + item.item_mount = null + on_item_unmount(item) + return TRUE + +/datum/item_mount/proc/is_mounted(obj/item/item) + return item in mounted_items + +/** + * Called when a mounted item is deleted. + */ +/datum/item_mount/proc/on_item_del(obj/item/being_deleted) + unmount(being_deleted) + +/datum/item_mount/proc/on_item_mount(obj/item/item) + SHOULD_NOT_SLEEP(TRUE) + SHOULD_CALL_PARENT(TRUE) + +/datum/item_mount/proc/on_item_unmount(obj/item/item) + SHOULD_NOT_SLEEP(TRUE) + SHOULD_CALL_PARENT(TRUE) + +//* Gas *// + +/** + * Get estimated gas pressure. + * + * @return null, or number + */ +/datum/item_mount/proc/gas_get_pressure(obj/item/item, key) + return relay_to_other?.gas_get_pressure(item, key) + +/** + * Unsafe: Directly references a gas_mixture for a channel. + * + * @return null, or ref + */ +/datum/item_mount/proc/gas_mixture_ref(obj/item/item, key) + return relay_to_other?.gas_mixture_ref(item, key) + +/** + * Returns a gas mixture by pulling a given liter amount. + * + * @return null, or ref + */ +/datum/item_mount/proc/gas_pull_volume(obj/item/item, key, liters) + return relay_to_other?.gas_pull_volume(item, key) + +/** + * Fast: erases a given liter amount of gas. Usually used with [gas_mixture_ref] + * being used to check first. + * + * @return null, or moles deleted + */ +/datum/item_mount/proc/gas_erase_volume(obj/item/item, key, liters) + return relay_to_other?.gas_pull_volume(item, key) + +//* Materials *// + +/** + * Get the name of the provider. + * * Material is any resolvable material, so ID, path, or instance. + * + * @return null, or name + */ +/datum/item_mount/proc/material_get_provider_name(obj/item/item, key, material_id) + return relay_to_other?.material_get_provider_name(item, key, material_id) + +/** + * * Material is any resolvable material, so ID, path, or instance. + * * Amount is in cm3 + * + * @return null, or amount in cm3 + */ +/datum/item_mount/proc/material_get_amount(obj/item/item, key, material_id) + return relay_to_other?.material_get_amount(item, key, material_id) + +/** + * * Material is any resolvable material, so ID, path, or instance. + * * Amount is in cm3 + * + * @return null, or TRUE / FALSE. + */ +/datum/item_mount/proc/material_has_amount(obj/item/item, key, material_id, amount) + return relay_to_other?.material_has_amount(item, key, material_id, amount) + +/** + * * Material is any resolvable material, so ID, path, or instance. + * * Amount is in cm3. + * + * @return null, or amount used in cm3. + */ +/datum/item_mount/proc/material_use_amount(obj/item/item, key, material_id, amount) + return relay_to_other?.material_use_amount(item, key, material_id, amount) + +/** + * * Material is any resolvable material, so ID, path, or instance. + * * Amount is in cm3. + * + * @return null, or amount used. + */ +/datum/item_mount/proc/material_use_checked_amount(obj/item/item, key, material_id, amount) + return material_has_amount(item, key, material_id, amount) && material_use_amount(item, key, material_id, amount) + +/** + * * Material is any resolvable material, so ID, path, or instance. + * * Amount is in cm3. + * + * @return null, or amount given. + */ +/datum/item_mount/proc/material_give_amount(obj/item/item, key, material_id, amount, force) + return relay_to_other?.material_give_amount(item, key, material_id, amount, force) + +/** + * * Material is any resolvable material, so ID, path, or instance. + * * Amount is in cm3. + * + * @return null, or max amount. + */ +/datum/item_mount/proc/material_get_capacity(obj/item/item, key, material_id) + return relay_to_other?.material_get_capacity(item, key, material_id) + +//* Power *// + +/** + * Lazy use-power-oneoff style thing + * + * @return null, or TRUE / FALSE for has that amount of energy + */ +/datum/item_mount/proc/lazy_energy_check(obj/item/item, key, joules) + return relay_to_other?.lazy_energy_check(item, key, joules) + +/** + * Lazy use-power-oneoff style thing + * + * @return null, or joules supplied + */ +/datum/item_mount/proc/lazy_energy_use(obj/item/item, key, joules, minimum_reserve) + return relay_to_other?.lazy_energy_use(item, key, joules, minimum_reserve) + +/** + * Lazy use-power-oneoff style thing + * + * @return null, or joules supplied + */ +/datum/item_mount/proc/lazy_energy_checked_use(obj/item/item, key, joules, minimum_reserve) + return lazy_energy_check(joules + minimum_reserve) && lazy_energy_use(joules, minimum_reserve) + +//* Reagents - Direct *// + +// TODO: notice how 'erase' and 'spawn' exists, but not 'push', and 'pull'? +// this is because reagents have data; they are not just described by the ID alone. +// thus an optimized uniform API for push/pull doesn't actually necessarily make sense, +// and as such implementation of such is left for when we need it (ergo mechs / rigsuits reagent routing). + +/** + * Gets if an item mount has a reagent, and if it does, its amount. + * * Semantically, null means 'we can't store this'. + * + * @return null, or amount the item mount has + */ +/datum/item_mount/proc/reagent_get_amount(obj/item/item, key, datum/reagent/reagent) + return relay_to_other?.reagent_get_amount(item, key, reagent) + +/** + * Checks if the item mount has a given amount of a reagent + * @return null, or TRUE / FALSE + */ +/datum/item_mount/proc/reagent_has_amount(obj/item/item, key, datum/reagent/reagent, amount) + . = reagent_get_amount(reagent) + if(.) + return . >= amount + +/** + * @return null, or amount the item mount could to erase + */ +/datum/item_mount/proc/reagent_erase_amount(obj/item/item, key, datum/reagent/reagent, amount) + return relay_to_other?.reagent_erase_amount(item, key, reagent, amount) + +/** + * @return null, or amount the item mount could give to erase + */ +/datum/item_mount/proc/reagent_erase_checked_amount(obj/item/item, key, datum/reagent/reagent, amount) + return reagent_has_amount(item, key, reagent, amount) && reagent_erase_amount(item, key, reagent, amount) + +/** + * @return null, or amount the item mount could accept + */ +/datum/item_mount/proc/reagent_spawn_amount(obj/item/item, key, datum/reagent/reagent, amount, force) + return relay_to_other?.reagent_spawn_amount(item, key, reagent, amount, force) + +//* Stacks *// + +/** + * Get the name of the provider. + * + * @return null, or name + */ +/datum/item_mount/proc/stack_get_provider_name(obj/item/item, key, path) + return relay_to_other?.stack_get_provider_name(item, key, path) + +/** + * Material stacks are invalid here. + * + * * Amount is in stack amount. + * + * @return null, or amount used. + */ +/datum/item_mount/proc/stack_use_checked_amount(obj/item/item, key, path, amount) + return stack_has_amount(item, key, path, amount) && stack_use_amount(item, key, path, amount) + +/** + * Material stacks are invalid here. + * + * * Amount is in stack amount. + * + * @return null, or amount given. + */ +/datum/item_mount/proc/stack_give_amount(obj/item/item, key, path, amount, force) + return relay_to_other?.stack_give_amount(item, key, path, amount, force) + +/** + * Material stacks are invalid here. + * + * @return null, or max amount. + */ +/datum/item_mount/proc/stack_get_capacity(obj/item/item, key, path) + return relay_to_other?.stack_get_capacity(item, key, path) + +/** + * Material stacks are invalid here. + * + * * Amount is in stack amount. + * + * @return null, or amount remaining. + */ +/datum/item_mount/proc/stack_get_amount(obj/item/item, key, path) + return relay_to_other?.stack_get_amount(item, key, path) + +/** + * Material stacks are invalid here. + * + * * Amount is in stack amount. + * + * @return null, or TRUE / FALSE. + */ +/datum/item_mount/proc/stack_has_amount(obj/item/item, key, path, amount) + . = stack_get_amount(item, key, path) + if(.) + return . >= amount + +/** + * Material stacks are invalid here. + * + * * Amount is in stack amount. + * + * @return null, or amount used. + */ +/datum/item_mount/proc/stack_use_amount(obj/item/item, key, path, amount) + return relay_to_other?.stack_use_amount(item, key, path, amount) + +//* ------ MISC BELOW HERE ------ *// + +//* Misc - Extinguisher *// + +/** + * @return null, or volume remaining + */ +/datum/item_mount/proc/extinguisher_get_volume(obj/item/extinguisher/extinguisher, key) + return relay_to_other?.extinguisher_get_volume(extinguisher, key) + +/** + * @return null ,or TRUE / FALSE on if there's that much left + */ +/datum/item_mount/proc/extinguisher_has_volume(obj/item/extinguisher/extinguisher, key, requested) + . = extinguisher_get_volume(extinguisher) + if(.) + return . >= requested + +/** + * @return null, or volume pulled + */ +/datum/item_mount/proc/extinguisher_transfer_volume(obj/item/extinguisher/extinguisher, key, requested, datum/reagent_holder/into_holder) + return relay_to_other?.extinguisher_transfer_volume(extinguisher, key, requested, into_holder) diff --git a/code/game/objects/items/antag_spawners.dm b/code/game/objects/items/antag_spawners.dm index 3fb433f2848..71884266e95 100644 --- a/code/game/objects/items/antag_spawners.dm +++ b/code/game/objects/items/antag_spawners.dm @@ -132,10 +132,10 @@ qdel(src) /obj/item/antag_spawner/syndicate_drone/protector - drone_type = /mob/living/silicon/robot/syndicate/protector + drone_type = /mob/living/silicon/robot/module_preset/cybersun/assault /obj/item/antag_spawner/syndicate_drone/combat_medic - drone_type = /mob/living/silicon/robot/syndicate/combat_medic + drone_type = /mob/living/silicon/robot/module_preset/cybersun/triage /obj/item/antag_spawner/syndicate_drone/mechanist - drone_type = /mob/living/silicon/robot/syndicate/mechanist + drone_type = /mob/living/silicon/robot/module_preset/cybersun/sapper diff --git a/code/game/objects/items/circuitboards/circuitboard.dm b/code/game/objects/items/circuitboards/circuitboard.dm index 692372a5ff4..b8d4b2bd679 100644 --- a/code/game/objects/items/circuitboards/circuitboard.dm +++ b/code/game/objects/items/circuitboards/circuitboard.dm @@ -7,7 +7,7 @@ */ /obj/item/circuitboard name = "circuit board" - icon = 'icons/obj/module.dmi' + icon = 'icons/items/circuits.dmi' icon_state = "id_mod" materials_base = list( MAT_STEEL = 1000, diff --git a/code/game/objects/items/circuitboards/mecha.dm b/code/game/objects/items/circuitboards/mecha.dm index 086cae06b9c..961e93a649c 100644 --- a/code/game/objects/items/circuitboards/mecha.dm +++ b/code/game/objects/items/circuitboards/mecha.dm @@ -10,7 +10,7 @@ /obj/item/circuitboard/mecha name = "exosuit circuit board" - icon = 'icons/obj/module.dmi' + icon = 'icons/items/circuits.dmi' icon_state = "std_mod" board_type = "other" diff --git a/code/game/objects/items/defib/shockpaddles.dm b/code/game/objects/items/defib/shockpaddles.dm index fd3c238e5a8..201e6cdcf95 100644 --- a/code/game/objects/items/defib/shockpaddles.dm +++ b/code/game/objects/items/defib/shockpaddles.dm @@ -107,8 +107,8 @@ /obj/item/shockpaddles/proc/check_contact(mob/living/carbon/human/H) if(!combat) for(var/obj/item/clothing/cloth in H.inventory.get_slots_unsafe( - /datum/inventory_slot/inventory/uniform, - /datum/inventory_slot/inventory/suit, + /datum/inventory_slot/inventory/uniform::id, + /datum/inventory_slot/inventory/suit::id, )) if((cloth.body_cover_flags & UPPER_TORSO) && (cloth.clothing_flags & CLOTHING_THICK_MATERIAL)) return FALSE diff --git a/code/game/objects/items/devices/PDA/radio.dm b/code/game/objects/items/devices/PDA/radio.dm index ea1a2da9a9d..284a382cdba 100644 --- a/code/game/objects/items/devices/PDA/radio.dm +++ b/code/game/objects/items/devices/PDA/radio.dm @@ -1,7 +1,7 @@ /obj/item/integated_radio name = "\improper PDA radio module" desc = "An electronic radio system." - icon = 'icons/obj/module.dmi' + icon = 'icons/items/circuits.dmi' icon_state = "power_mod" var/obj/item/pda/hostpda = null diff --git a/code/game/objects/items/devices/flash.dm b/code/game/objects/items/devices/flash.dm index c6bcc166727..d43517f113f 100644 --- a/code/game/objects/items/devices/flash.dm +++ b/code/game/objects/items/devices/flash.dm @@ -213,7 +213,7 @@ var/mob/living/silicon/S = M if(isrobot(S)) var/mob/living/silicon/robot/R = S - if(R.has_active_type(/obj/item/borg/combat/shield)) + if(R.get_held_item_of_type(/obj/item/borg/combat/shield)) var/obj/item/borg/combat/shield/shield = locate() in R if(shield) if(shield.active) diff --git a/code/game/objects/items/devices/radio/radio.dm b/code/game/objects/items/devices/radio/radio.dm index 88c885e0f3c..2833de79e52 100644 --- a/code/game/objects/items/devices/radio/radio.dm +++ b/code/game/objects/items/devices/radio/radio.dm @@ -671,7 +671,7 @@ GLOBAL_DATUM_INIT(virtual_announcer_ai, /mob/living/silicon/ai/announcer, new(nu if (isrobot(src.loc)) var/mob/living/silicon/robot/R = src.loc var/datum/robot_component/C = R.components["radio"] - R.cell_use_power(C.active_usage) + R.legacy_cell_use_power(C.active_usage) /obj/item/radio/borg/attackby(obj/item/I, mob/living/user, params, clickchain_flags, damage_multiplier) user.set_machine(src) @@ -714,12 +714,12 @@ GLOBAL_DATUM_INIT(virtual_announcer_ai, /mob/living/silicon/ai/announcer, new(nu src.syndie = 0 var/mob/living/silicon/robot/D = src.loc - if(D.module) - for(var/ch_name in D.module.channels) + if(D.module_legacy) + for(var/ch_name in D.module_legacy.channels) if(ch_name in src.channels) continue src.channels += ch_name - src.channels[ch_name] += D.module.channels[ch_name] + src.channels[ch_name] += D.module_legacy.channels[ch_name] if(keyslot) for(var/ch_name in keyslot.channels) if(ch_name in src.channels) diff --git a/code/game/objects/items/robot/robot_upgrades.dm b/code/game/objects/items/robot/robot_upgrades.dm deleted file mode 100644 index 9a1017bbd21..00000000000 --- a/code/game/objects/items/robot/robot_upgrades.dm +++ /dev/null @@ -1,265 +0,0 @@ -// robot_upgrades.dm -// Contains various borg upgrades. - -/obj/item/borg/upgrade - name = "borg upgrade module." - desc = "Protected by FRM." - icon = 'icons/obj/module.dmi' - icon_state = "cyborg_upgrade" - /// Bitflags listing module compatibility. Used in the exosuit fabricator for creating sub-categories. - var/list/module_flags = NONE - var/locked = FALSE - var/require_module = FALSE - var/installed = FALSE - -/obj/item/borg/upgrade/proc/action(var/mob/living/silicon/robot/R) - if(R.stat == DEAD) - to_chat(usr, SPAN_WARNING("The [src] will not function on a deceased robot.")) - return TRUE - return FALSE - - -/obj/item/borg/upgrade/reset - name = "robotic module reset board" - desc = "Used to reset a cyborg's module. Destroys any other upgrades applied to the robot." - icon_state = "cyborg_upgrade1" - item_state = "cyborg_upgrade" - require_module = TRUE - -/obj/item/borg/upgrade/reset/action(var/mob/living/silicon/robot/R) - if(..()) - return FALSE - R.module_reset() - return TRUE - -/obj/item/borg/upgrade/rename - name = "robot reclassification board" - desc = "Used to rename a cyborg." - icon_state = "cyborg_upgrade1" - item_state = "cyborg_upgrade" - var/heldname = "default name" - -/obj/item/borg/upgrade/rename/attack_self(mob/user, datum/event_args/actor/actor) - . = ..() - if(.) - return - heldname = sanitizeSafe(input(user, "Enter new robot name", "Robot Reclassification", heldname), MAX_NAME_LEN) - -/obj/item/borg/upgrade/rename/action(var/mob/living/silicon/robot/R) - if(..()) - return FALSE - R.notify_ai(ROBOT_NOTIFICATION_NEW_NAME, R.name, heldname) - R.name = heldname - R.custom_name = heldname - R.real_name = heldname - - return TRUE - -/obj/item/borg/upgrade/restart - name = "robot emergency restart module" - desc = "Used to force a restart of a disabled-but-repaired robot, bringing it back online." - icon_state = "cyborg_upgrade1" - item_state = "cyborg_upgrade" - - -/obj/item/borg/upgrade/restart/action(var/mob/living/silicon/robot/R) - if(R.health < 0) - to_chat(usr, "You have to repair the robot before using this module!") - return FALSE - - if(!R.key) - for(var/mob/observer/dead/ghost in GLOB.player_list) - if(ghost.mind && ghost.mind.current == R) - ghost.transfer_client_to(R) - - R.set_stat(CONSCIOUS) - dead_mob_list -= R - living_mob_list |= R - R.notify_ai(ROBOT_NOTIFICATION_NEW_UNIT) - return TRUE - - -/obj/item/borg/upgrade/vtec - name = "robotic VTEC Module" - desc = "Used to kick in a robot's VTEC systems, increasing their speed." - icon_state = "cyborg_upgrade2" - item_state = "cyborg_upgrade" - require_module = TRUE - -/obj/item/borg/upgrade/vtec/action(var/mob/living/silicon/robot/R) - if(..()) - return FALSE - - if(R.movement_base_speed >= 7.5) - return FALSE - R.movement_base_speed = 7.5 - R.update_movespeed_base() - return TRUE - -/obj/item/borg/upgrade/tasercooler - name = "robotic Rapid Taser Cooling Module" - desc = "Used to cool a mounted taser, increasing the potential current in it and thus its recharge rate." - icon_state = "cyborg_upgrade3" - item_state = "cyborg_upgrade" - module_flags = BORG_MODULE_SECURITY - require_module = TRUE - - -/obj/item/borg/upgrade/tasercooler/action(var/mob/living/silicon/robot/R) - if(..()) - return FALSE - - if(!R.module || !(type in R.module.supported_upgrades)) - to_chat(R, "Upgrade mounting error! No suitable hardpoint detected!") - to_chat(usr, "There's no mounting point for the module!") - return FALSE - - var/obj/item/gun/projectile/energy/taser/mounted/cyborg/T = locate() in R.module - if(!T) - T = locate() in R.module.contents - if(!T) - T = locate() in R.module.modules - if(!T) - to_chat(usr, SPAN_WARNING("This robot has had its taser removed!")) - return FALSE - - if(T.recharge_time <= 2) - to_chat(R, "Maximum cooling achieved for this hardpoint!") - to_chat(usr, "There's no room for another cooling unit!") - return FALSE - - else - T.recharge_time = max(2 , T.recharge_time - 4) - - return TRUE - -/obj/item/borg/upgrade/jetpack - name = "robot jetpack" - desc = "A carbon dioxide jetpack suitable for low-gravity operations." - icon_state = "cyborg_upgrade3" - item_state = "cyborg_upgrade" - require_module = TRUE - -/obj/item/borg/upgrade/jetpack/action(var/mob/living/silicon/robot/R) - if(..()) - return FALSE - - var/obj/item/tank/jetpack/carbondioxide/T = locate() in R.module - if(!T) - T = locate() in R.module.contents - if(!T) - T = locate() in R.module.modules - if(!T) - R.module.modules += new/obj/item/tank/jetpack/carbondioxide(R.module) - for(var/obj/item/tank/jetpack/carbondioxide in R.module.modules) - R.internals = src - return TRUE - if(T) - to_chat(R, "Upgrade mounting error! No suitable hardpoint detected!") - to_chat(usr, "There's no mounting point for the module!") - return FALSE - -/obj/item/borg/upgrade/advhealth - name = "advanced health analyzer module" - desc = "An upgrade to improve a station-bound synthetic's health analyzer." - icon_state = "cyborg_upgrade3" - item_state = "cyborg_upgrade" - require_module = TRUE - -/obj/item/borg/upgrade/advhealth/action(var/mob/living/silicon/robot/R) - if(..()) - return FALSE - - var/obj/item/healthanalyzer/advanced/T = locate() in R.module - if(!T) - T = locate() in R.module.contents - if(!T) - T = locate() in R.module.modules - if(!T) - R.module.modules += new/obj/item/healthanalyzer/advanced(R.module) - return TRUE - if(T) - to_chat(R, "Upgrade mounting error! No suitable hardpoint detected!") - to_chat(usr, "There's no mounting point for the module!") - return FALSE - - -/obj/item/borg/upgrade/bluespaceorebag - name = "bluespace mining satchel module" - desc = "Improves the ore satchels of mining units to hold a lot more ores." - icon_state = "cyborg_upgrade3" - item_state = "cyborg_upgrade" - module_flags = BORG_MODULE_MINER - require_module = TRUE - -/obj/item/borg/upgrade/bluespaceorebag/action(var/mob/living/silicon/robot/R) - if(..()) - return FALSE - - var/obj/item/storage/bag/ore/O = locate() in R.module - if(!O) - O = locate() in R.module.contents - if(!O) - O = locate() in R.module.modules - if(!O) //there should be one though... - R.module.modules += new/obj/item/storage/bag/ore/bluespace(R.module) - return TRUE - if(O) - if(istype(O,/obj/item/storage/bag/ore/bluespace)) - to_chat(R, "Upgrade mounting error! Upgrade already present.") - to_chat(usr, SPAN_WARNING("[R] already has this upgrade!")) - return FALSE - else - R.uneq_all() - O.deconstruct(ATOM_DECONSTRUCT_DISASSEMBLED) //drops all ores previous satchel was carrying using this method - R.module.modules += new/obj/item/storage/bag/ore/bluespace(R.module) - return TRUE - - -/obj/item/borg/upgrade/syndicate - name = "scrambled equipment module" - desc = "Unlocks new and often deadly module specific items of a robot" - icon_state = "cyborg_upgrade3" - item_state = "cyborg_upgrade" - require_module = TRUE - -/obj/item/borg/upgrade/syndicate/action(var/mob/living/silicon/robot/R) - if(..()) - return FALSE - - if(R.emag_items == 1) - return FALSE - - R.emag_items = 1 - return TRUE - -/obj/item/borg/upgrade/language - name = "adaptive translation module" - desc = "Upgrades a cyborg's language processing unit with an adaptive translation module." - icon_state = "cyborg_upgrade3" - item_state = "cyborg_upgrade" - -/obj/item/borg/upgrade/language/action(var/mob/living/silicon/robot/R) - if(..()) - return FALSE - - R.create_translation_context(/datum/translation_context/variable/learning/silicons) - - return TRUE - -//Robot resizing module, moved from robot/upgrades_vr - Papalus -/obj/item/borg/upgrade/sizeshift - name = "robot size alteration module" - desc = "Using technology similar to one used in size guns, allows cyborgs to adjust their own size as necessary." - icon_state = "cyborg_upgrade2" - item_state = "cyborg_upgrade" - require_module = 1 - -/obj/item/borg/upgrade/sizeshift/action(var/mob/living/silicon/robot/R) - if(..()) return FALSE - - if(/mob/living/proc/set_size in R.verbs) - return FALSE - - add_verb(R, /mob/living/proc/set_size) - return TRUE diff --git a/code/game/objects/items/stacks/fifty_spawner.dm b/code/game/objects/items/stacks/legacy/fifty_spawner.dm similarity index 100% rename from code/game/objects/items/stacks/fifty_spawner.dm rename to code/game/objects/items/stacks/legacy/fifty_spawner.dm diff --git a/code/game/objects/items/stacks/matter_synth.dm b/code/game/objects/items/stacks/matter_synth.dm deleted file mode 100644 index 64216c46e1e..00000000000 --- a/code/game/objects/items/stacks/matter_synth.dm +++ /dev/null @@ -1,60 +0,0 @@ -/datum/matter_synth - var/name = "Generic Synthesizer" - var/max_energy = 60000 - var/recharge_rate = 2000 - var/energy - -/datum/matter_synth/New(var/store = 0, var/name = null) - if(store) - max_energy = store - if(name) - src.name = name - energy = max_energy - return - -/datum/matter_synth/proc/get_charge() - return energy - -/datum/matter_synth/proc/use_charge(var/amount) - if (energy >= amount) - energy -= amount - return 1 - return 0 - -/datum/matter_synth/proc/add_charge(var/amount) - energy = min(energy + amount, max_energy) - -/datum/matter_synth/proc/emp_act(var/severity) - use_charge(max_energy * 0.1 / severity) - -/datum/matter_synth/medicine - name = "Medicine Synthesizer" - -/datum/matter_synth/nanite - name = "Nanite Synthesizer" - -/datum/matter_synth/metal - name = "Metal Synthesizer" - -/datum/matter_synth/plasteel - name = "Plasteel Synthesizer" - max_energy = 10000 - -/datum/matter_synth/glass - name = "Glass Synthesizer" - -/datum/matter_synth/wood - name = "Wood Synthesizer" - -/datum/matter_synth/plastic - name = "Plastic Synthesizer" - -/datum/matter_synth/wire - name = "Wire Synthesizer" - max_energy = 50 - recharge_rate = 2 - -/datum/matter_synth/bandage - name = "Bandage Synthesizer" - max_energy = 10 - recharge_rate = 1 diff --git a/code/game/objects/items/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm index cb96f5cfd8b..06432ff67e5 100644 --- a/code/game/objects/items/stacks/stack.dm +++ b/code/game/objects/items/stacks/stack.dm @@ -26,6 +26,20 @@ if(!safety) CRASH("ran out of safety") +/proc/__construct_legacy_stack_provider_material_map() + return list( + /obj/item/stack/rods = list( + /datum/prototype/material/steel::id = SHEET_MATERIAL_AMOUNT / 2, + ), + /obj/item/stack/tile/floor = list( + /datum/prototype/material/steel::id = SHEET_MATERIAL_AMOUNT / 4, + ), + /obj/item/stack/material/glass/reinforced = list( + /datum/prototype/material/glass::id = SHEET_MATERIAL_AMOUNT / 1, + /datum/prototype/material/steel::id = SHEET_MATERIAL_AMOUNT / 2, + ), + ) + /** * Items that can stack, tracking the number of which is in it * @@ -37,21 +51,39 @@ icon = 'icons/obj/stacks.dmi' item_flags = ITEM_CAREFUL_BLUDGEON | ITEM_ENCUMBERS_WHILE_HELD - /// Always create this type when splitting, instead of our own type. - var/split_type - /// The type we actually are. This is what is used when things try to consume an amount of us. - /// * null = this current type - var/stack_type + /// Total number of states used in updating icons. + /// todo: all stacks should use this, remove `use_new_icon_update + /// + /// * Only active when [use_new_icon_update] is set on + /// * This counts up from 1. + /// * If null, we don't do icon updates based on amount. + var/icon_state_count - var/singular_name + /// Our effective stack type. Defaults to our type. + /// * Used to determine our identity when calling into providers. + /// * Used to determine what can merge into what (so colored subtypes of cable can all be considered cable). + var/stack_type + /// What type we split into. Useful if you have an infinite stack you don't want to be split into another infinite stack. + /// * Use `|| stack_type || type` to default to stack type if this is not set. + var/split_type + + /// Current amount var/amount = 1 - /// See stack recipes initialisation, param "max_res_amount" must be equal to this max_amount. + /// Maximum amount var/max_amount = 50 - /// Determines whether different stack types can merge. - var/stacktype_legacy - var/uses_charge = 0 - var/list/charge_costs = null - var/list/datum/matter_synth/synths = null + + /// this is admittedly shitcode but this allows for automatic + /// stack provider support for non /material stacks that are directly derived from + /// materials, like reinf glass and metal tiles + /// + /// todo: please find a better way. + var/static/list/legacy_stack_provider_material_map = __construct_legacy_stack_provider_material_map() + + /// explicit recipes, lazy-list. this is typelist'd + var/list/datum/stack_recipe/explicit_recipes + + //! legacy - re-evaluate these at some point! + var/singular_name /// Determines whether the item should update it's sprites based on amount. var/no_variants = TRUE @@ -61,40 +93,31 @@ /// * this is mandatory for all new stacks var/use_new_icon_update = FALSE - /// Total number of states used in updating icons. - /// todo: all stacks should use this, remove `use_new_icon_update - /// - /// * Only active when [use_new_icon_update] is set on - /// * This counts up from 1. - /// * If null, we don't do icon updates based on amount. - var/icon_state_count - /// Will the item pass its own color var to the created item? Dyed cloth, wood, etc. var/pass_color = FALSE /// Will the stack merge with other stacks that are different colors? (Dyed cloth, wood, etc). var/strict_color_stacking = FALSE - - /// explicit recipes, lazy-list. this is typelist'd - var/list/datum/stack_recipe/explicit_recipes + //! end /obj/item/stack/Initialize(mapload, new_amount, merge = TRUE) if(has_typelist(explicit_recipes)) explicit_recipes = get_typelist(explicit_recipes) else explicit_recipes = typelist(NAMEOF(src, explicit_recipes), generate_explicit_recipes()) - if(new_amount != null) + if(!isnull(new_amount)) amount = new_amount - if(!stacktype_legacy) - stacktype_legacy = type + // todo: lint this to make sure everyone sets this, don't set in initialize as a safety net + if(!stack_type) + stack_type = type . = ..() // only merge 1. outside of mapload and 2. if we had amount if(merge && !mapload && amount) for(var/obj/item/stack/S in loc) - if(can_merge(S)) - merge(S) + if(can_merge_into(S)) + merge_into_other(S, TRUE) // and if we did and no longer have amount, delete ourselves if(amount == 0) - zero_amount() + return INITIALIZE_HINT_QDEL update_icon() /obj/item/stack/update_icon_state() @@ -112,6 +135,7 @@ if(no_variants) icon_state = initial(icon_state) else + var/amount = get_amount() if(amount <= (max_amount * (1/3))) icon_state = initial(icon_state) else if (amount <= (max_amount * (2/3))) @@ -122,10 +146,10 @@ /obj/item/stack/examine(mob/user, dist) . = ..() - if(!uses_charge) - . += "There are [amount] [singular_name]\s in the stack." + if(!has_stack_provider()) + . += "There are [get_amount()] [singular_name]\s in the stack." else - . += "There is enough charge for [get_amount()]." + . += "There are [get_amount()] [singular_name]\s in \the [get_provider_name()]." /** * Get the explicit recipes of this stack type @@ -199,56 +223,27 @@ log_stackcrafting(user, src, recipe.name, make_amount, needed, where) use(needed) -/** - * Return 1 if an immediate subsequent call to use() would succeed. - * Ensures that code dealing with stacks uses the same logic - */ -/obj/item/stack/proc/can_use(used) - if (get_amount() < used) - return FALSE - return TRUE - /** * Can we merge with this stack? */ -/obj/item/stack/proc/can_merge(obj/item/stack/other) +/obj/item/stack/proc/can_merge_into(obj/item/stack/other) if(!istype(other)) return FALSE if((strict_color_stacking || other.strict_color_stacking) && (color != other.color)) return FALSE - return other.stacktype_legacy == stacktype_legacy + return can_merge_into_type(other.type) +// todo: deprecated +/obj/item/stack/proc/can_use(used) + return has_amount(used) + +// todo: deprecated /obj/item/stack/proc/use(used, no_delete) - if (!can_use(used)) - return FALSE - if(!uses_charge) - amount -= used - if (amount <= 0 && !no_delete) - qdel(src) //should be safe to qdel immediately since if someone is still using this stack it will persist for a little while longer - update_icon() - return TRUE - else - if(get_amount() < used) - return FALSE - for(var/i = 1 to uses_charge) - var/datum/matter_synth/S = synths[i] - S.use_charge(charge_costs[i] * used) // Doesn't need to be deleted - return TRUE + return use_amount(used, no_delete) +// todo: deprecated /obj/item/stack/proc/add(extra, force) - if(!uses_charge) - if((amount + extra > get_max_amount()) && !force) - return FALSE - else - amount += extra - update_icon() - return TRUE - else if(!synths || synths.len < uses_charge) - return FALSE - else - for(var/i = 1 to uses_charge) - var/datum/matter_synth/S = synths[i] - S.add_charge(charge_costs[i] * extra) + return give_amount(extra, force) /** * The transfer and split procs work differently than use() and add(). @@ -260,7 +255,7 @@ /obj/item/stack/proc/transfer_to(obj/item/stack/S, tamount=null, type_verified) if (!get_amount()) return 0 - if (!can_merge(S) && !type_verified) + if (!can_merge_into(S) && !type_verified) return 0 if (isnull(tamount)) @@ -283,8 +278,6 @@ /obj/item/stack/proc/split(tamount, atom/where, force) if (!amount) return null - if (uses_charge) - return null var/transfer = max(min(tamount, src.amount, force? INFINITY : initial(max_amount)), 0) @@ -300,42 +293,6 @@ return newstack return null -/obj/item/stack/proc/get_amount() - if(uses_charge) - if(!synths || synths.len < uses_charge) - return 0 - var/datum/matter_synth/S = synths[1] - . = round(S.get_charge() / charge_costs[1]) - if(uses_charge > 1) - for(var/i = 2 to uses_charge) - S = synths[i] - . = min(., round(S.get_charge() / charge_costs[i])) - return - return amount - -/obj/item/stack/proc/get_max_amount() - if(uses_charge) - if(!synths || synths.len < uses_charge) - return 0 - var/datum/matter_synth/S = synths[1] - . = round(S.max_energy / charge_costs[1]) - if(uses_charge > 1) - for(var/i = 2 to uses_charge) - S = synths[i] - . = min(., round(S.max_energy / charge_costs[i])) - return - return max_amount - -/obj/item/stack/proc/add_to_stacks(mob/user) - for (var/obj/item/stack/item in user.loc) - if (item==src) - continue - var/transfer = src.transfer_to(item) - if (transfer) - to_chat(user, SPAN_NOTICE("You add a new [item.singular_name] to the stack. It now contains [item.amount] [item.singular_name]\s.")) - if(!amount) - break - /obj/item/stack/attack_hand(mob/user, datum/event_args/actor/clickchain/e_args) if(user.get_inactive_held_item() == src) change_stack(user, 1) @@ -345,25 +302,26 @@ /obj/item/stack/Crossed(atom/movable/AM) . = ..() // if we're in a mob, do not automerge - if(!ismob(loc) && !AM.throwing && can_merge(AM)) - merge(AM) + if(!ismob(loc) && !AM.throwing && can_merge_into(AM)) + merge_into_other(AM) -/// Merge src into S, as much as possible. -/obj/item/stack/proc/merge(obj/item/stack/S, no_delete) - if(uses_charge) - return // how about no! - if(QDELETED(S) || QDELETED(src) || (S == src)) //amusingly this can cause a stack to consume itself, let's not allow that. +/** + * Merge self into other + * + * * Can delete ourselves. + * + * @return amount merged + */ +/obj/item/stack/proc/merge_into_other(obj/item/stack/other, no_delete) + if(QDELETED(other) || QDELETED(src) || (other == src)) //amusingly this can cause a stack to consume itself, let's not allow that. return var/transfer = get_amount() - if(S.uses_charge) - transfer = min(transfer, S.get_max_amount() - S.get_amount()) - else - transfer = min(transfer, S.max_amount - S.amount) + transfer = min(transfer, other.max_amount - other.amount) if(pulledby) - pulledby.start_pulling(S) - S.copy_evidences(src) + pulledby.start_pulling(other) + other.copy_evidences(src) use(transfer, no_delete) - S.add(transfer) + other.add(transfer) return transfer /obj/item/stack/attackby(obj/item/I, mob/living/user, list/params, clickchain_flags, damage_multiplier) @@ -399,30 +357,27 @@ return FALSE /obj/item/stack/proc/attempt_split_stack(mob/living/user) - if(uses_charge) + //get amount from user + var/max = get_amount() + var/stackmaterial = tgui_input_number(user, "How many sheets do you wish to take out of this stack?", "Stack", max, max, 1, round_value=TRUE) + if(QDELETED(src)) return - else - if(zero_amount()) - return - //get amount from user - var/max = get_amount() - // var/stackmaterial = round(input(user,"How many sheets do you wish to take out of this stack? (Maximum [max])") as null|num) - var/stackmaterial = tgui_input_number(user, "How many sheets do you wish to take out of this stack?", "Stack", max, max, 1, round_value=TRUE) - max = get_amount() // Not sure why this is done twice but whatever. - stackmaterial = min(max, stackmaterial) - if(stackmaterial == null || stackmaterial <= 0 || !in_range(user, src) || !CHECK_MOBILITY(user, MOBILITY_CAN_PICKUP)) - return TRUE - else - change_stack(user, stackmaterial) - to_chat(user, SPAN_NOTICE("You take [stackmaterial] sheets out of the stack")) + max = get_amount() // Not sure why this is done twice but whatever. + stackmaterial = min(max, stackmaterial) + if(stackmaterial == null || stackmaterial <= 0 || !in_range(user, src) || !CHECK_MOBILITY(user, MOBILITY_CAN_PICKUP)) return TRUE + else + change_stack(user, stackmaterial) + to_chat(user, SPAN_NOTICE("You take [stackmaterial] sheets out of the stack")) + return TRUE // todo: refactor and combine with /split /obj/item/stack/proc/change_stack(mob/user, amount) + var/atom/our_current_location = drop_location() if(!use(amount, TRUE, FALSE)) return FALSE var/make_type = isnull(split_type)? type : split_type - var/obj/item/stack/F = new make_type(user? user : drop_location(), amount, FALSE) + var/obj/item/stack/F = new make_type(user? user : our_current_location, amount, FALSE) . = F F.copy_evidences(src) if(user) @@ -430,15 +385,6 @@ F.forceMove(user.drop_location()) add_fingerprint(user) F.add_fingerprint(user) - zero_amount() - -/obj/item/stack/proc/zero_amount() - if(uses_charge) - return get_amount() <= 0 - if(amount < 1) - qdel(src) - return TRUE - return FALSE /obj/item/stack/proc/copy_evidences(obj/item/stack/from) if(from.blood_DNA) @@ -450,26 +396,131 @@ if(from.fingerprintslast) fingerprintslast = from.fingerprintslast -/obj/item/stack/proc/set_amount(new_amount, no_limits = FALSE) - if(new_amount < 0 || new_amount % 1) +/obj/item/stack/proc/legacy_add_to_stacks_please_refactor_me(mob/user) + for (var/obj/item/stack/item in user.loc) + if (item==src) + continue + var/transfer = src.transfer_to(item) + if (transfer) + to_chat(user, SPAN_NOTICE("You add a new [item.singular_name] to the stack. It now contains [item.amount] [item.singular_name]\s.")) + if(!amount) + break + +//* Access *// + +/** + * Gets how many sheets we have. + */ +/obj/item/stack/proc/get_amount() + if(item_mount) + return check_provider_remaining() + return amount + +/** + * Gets how many sheets we can carry. + */ +/obj/item/stack/proc/get_max_amount() + if(item_mount) + return check_provider_capacity() + return max_amount + +/** + * Gets how many sheets we can accept. + */ +/obj/item/stack/proc/get_missing_amount() + return get_max_amount() - get_amount() + +/** + * Checks if we have an amount. + * + * @return TRUE / FALSE + */ +/obj/item/stack/proc/has_amount(amount) + return check_provider_remaining() >= amount + +/** + * Use an amount if we have the whole amount. + * + * @return amount used + */ +/obj/item/stack/proc/use_checked_amount(amount) + if(!has_amount(amount)) + return 0 + return use_amount(amount) + +/** + * Use an amount. Will use less if we don't have that much. + * + * @return amount used + */ +/obj/item/stack/proc/use_amount(amount, no_delete) + if(item_mount) + return pull_from_provider(amount) + if(amount <= 0) + return 0 + amount = min(amount, src.amount) + . = amount + src.amount -= amount + update_amount(no_delete) + +/** + * Gives a number of sheets back to us. + * + * @return amount added + */ +/obj/item/stack/proc/give_amount(amount, force) + if(item_mount) + return push_to_provider(amount, force) + if(!force) + amount = min(amount, max_amount - src.amount) + if(amount <= 0) + return 0 + . = amount + src.amount += amount + update_amount() + +/** + * Sets our amount to a specific amount. + * + * * If we use a stack provider, we'll push/pull automatically. This can be weird, because providers don't act the same as stacks. + * * Setting us to 0 will delete us immediately. + * + * @return amount changed + */ +/obj/item/stack/proc/set_amount(new_amount, force) + if(new_amount < 0 || (new_amount != floor(amount))) stack_trace("Tried to set a bad stack amount: [new_amount]") return 0 - // Clean up the new amount - new_amount = max(round(new_amount), 0) + if(item_mount) + var/current_amount = check_provider_remaining() + var/amount_to_push_or_pull = new_amount - current_amount - // Can exceed max if you really want - if(new_amount > max_amount && !no_limits) - new_amount = max_amount + if(!amount_to_push_or_pull) + return 0 + return amount_to_push_or_pull > 0 ? push_to_provider(amount_to_push_or_pull, force) : pull_from_provider(amount_to_push_or_pull) + if(!force) + new_amount = min(amount, max_amount) + + . = new_amount - amount amount = new_amount - // Can set it to 0 without qdel if you really want - if(amount == 0 && !no_limits) - qdel(src) - return FALSE - update_icon() - return TRUE + update_amount() + +/** + * This can destroy the stack. + */ +/obj/item/stack/proc/update_amount(no_delete) + if(QDELING(src)) + return + if(item_mount) + else + if(amount <= 0) + if(!no_delete) + qdel(src) + return + update_icon() //* Getters *// @@ -483,6 +534,77 @@ return null return CEILING(the_amount / max_amount * icon_state_count, 1) +//* Stack Providers *// + +/obj/item/stack/proc/has_stack_provider() + return !!item_mount + +/** + * Get the name of our stack provider. + * * You must check if stack provider exists. + */ +/obj/item/stack/proc/get_provider_name() + return item_mount.stack_get_provider_name(src, null, stack_type) + +/** + * * You must check if stack provider exists. + * @return amount left + */ +/obj/item/stack/proc/check_provider_remaining() + var/list/legacy_remap = legacy_stack_provider_material_map[type] + if(legacy_remap) + . = INFINITY + for(var/mat_id in legacy_remap) + . = min(., (item_mount.material_get_amount(src, null, mat_id) / legacy_remap[mat_id])) + else + . = item_mount.stack_get_amount(src, null, stack_type) + +/** + * * You must check if stack provider exists. + * @return max volume + */ +/obj/item/stack/proc/check_provider_capacity() + var/list/legacy_remap = legacy_stack_provider_material_map[type] + if(legacy_remap) + . = INFINITY + for(var/mat_id in legacy_remap) + . = min(., (item_mount.material_get_capacity(src, null, mat_id) / legacy_remap[mat_id])) + else + . = item_mount.stack_get_capacity(src, null, stack_type) + +/** + * * You must check if stack provider exists. + * @return amount pushed + */ +/obj/item/stack/proc/push_to_provider(amount, force) + var/list/legacy_remap = legacy_stack_provider_material_map[type] + if(legacy_remap) + // we have to be atomic, so do an expensive check first + if(!force) + var/has_remaining_capacity = check_provider_capacity() - check_provider_remaining() + if(has_remaining_capacity <= 0) + return 0 + amount = min(amount, has_remaining_capacity) + . = amount + for(var/mat_id in legacy_remap) + item_mount.material_give_amount(src, null, mat_id, amount * legacy_remap[mat_id] * SHEET_MATERIAL_AMOUNT) + else + . = item_mount.stack_give_amount(src, null, stack_type, amount * SHEET_MATERIAL_AMOUNT, force) + +/** + * * You must check if stack provider exists. + * @return amount pulled + */ +/obj/item/stack/proc/pull_from_provider(amount) + var/list/legacy_remap = legacy_stack_provider_material_map[type] + if(legacy_remap) + // we have to be atomic, so do an expensive check first + var/has_remaining = check_provider_remaining() + for(var/mat_id in legacy_remap) + item_mount.material_use_amount(src, null, mat_id, has_remaining * legacy_remap[mat_id] * SHEET_MATERIAL_AMOUNT) + else + . = item_mount.stack_use_amount(src, null, stack_type, amount * SHEET_MATERIAL_AMOUNT) + //* Types *// /** @@ -499,8 +621,6 @@ /** * Can merge into a type - * - * todo: use this instead of raw stacktype_legacy checks */ /obj/item/stack/proc/can_merge_into_type(path) - CRASH("Not implemented.") + return path == (stack_type || type) diff --git a/code/game/objects/items/stacks/tickets.dm b/code/game/objects/items/stacks/subtypes/arcadeticket.dm similarity index 100% rename from code/game/objects/items/stacks/tickets.dm rename to code/game/objects/items/stacks/subtypes/arcadeticket.dm diff --git a/code/game/objects/items/stacks/marker_beacons.dm b/code/game/objects/items/stacks/subtypes/marker_beacons.dm similarity index 100% rename from code/game/objects/items/stacks/marker_beacons.dm rename to code/game/objects/items/stacks/subtypes/marker_beacons.dm diff --git a/code/modules/materials/material_sheets.dm b/code/game/objects/items/stacks/subtypes/material.dm similarity index 89% rename from code/modules/materials/material_sheets.dm rename to code/game/objects/items/stacks/subtypes/material.dm index a9ecd46f4e0..15c167c295d 100644 --- a/code/modules/materials/material_sheets.dm +++ b/code/game/objects/items/stacks/subtypes/material.dm @@ -51,7 +51,8 @@ pixel_x = rand(0,4)-4 pixel_y = rand(0,4)-4 - stacktype_legacy = src.material.stack_type + stack_type = src.material.stack_type + if(islist(src.material.stack_origin_tech)) origin_tech = src.material.stack_origin_tech.Copy() @@ -64,11 +65,11 @@ update_strings() /obj/item/stack/material/get_materials(respect_multiplier) - return list(material.id = (respect_multiplier? material_multiplier : 1) * SHEET_MATERIAL_AMOUNT) + return list(src, null, material.id = (respect_multiplier? material_multiplier : 1) * SHEET_MATERIAL_AMOUNT) /obj/item/stack/material/update_icon() if(material.icon_stack_count) - icon_state = "stack-[min(ceil((amount / max_amount) * material.icon_stack_count), material.icon_stack_count)]" + icon_state = "stack-[min(ceil((get_amount() / max_amount) * material.icon_stack_count), material.icon_stack_count)]" return ..() /obj/item/stack/material/tgui_recipes() @@ -127,6 +128,61 @@ return return ..() +/obj/item/stack/material/can_merge_into(obj/item/stack/other) + if(!istype(other, /obj/item/stack/material)) + return FALSE + var/obj/item/stack/material/casted = other + return material.id == casted.material.id + +//* Stack Providers *// + +/obj/item/stack/material/get_provider_name() + return item_mount.material_get_provider_name(src, null, material.id) + +/obj/item/stack/material/check_provider_remaining() + var/list/legacy_remap = legacy_stack_provider_material_map[type] + if(legacy_remap) + . = INFINITY + for(var/mat_id in legacy_remap) + . = min(., (item_mount.material_get_amount(src, null, mat_id) / legacy_remap[mat_id]) / SHEET_MATERIAL_AMOUNT) + else + . = item_mount.material_get_amount(src, null, material.id) / SHEET_MATERIAL_AMOUNT + +/obj/item/stack/material/check_provider_capacity() + var/list/legacy_remap = legacy_stack_provider_material_map[type] + if(legacy_remap) + . = INFINITY + for(var/mat_id in legacy_remap) + . = min(., (item_mount.material_get_capacity(src, null, mat_id) / legacy_remap[mat_id]) / SHEET_MATERIAL_AMOUNT) + else + . = item_mount.material_get_capacity(src, null, material.id) / SHEET_MATERIAL_AMOUNT + +/obj/item/stack/material/push_to_provider(amount, force) + var/list/legacy_remap = legacy_stack_provider_material_map[type] + if(legacy_remap) + // we have to be atomic, so do an expensive check first + if(!force) + var/has_remaining_capacity = check_provider_capacity() - check_provider_remaining() + if(has_remaining_capacity <= 0) + return 0 + amount = min(amount, has_remaining_capacity) + . = amount + for(var/mat_id in legacy_remap) + item_mount.material_give_amount(src, null, mat_id, amount * legacy_remap[mat_id] * SHEET_MATERIAL_AMOUNT) + else + . = item_mount.material_give_amount(src, null, material.id, amount * SHEET_MATERIAL_AMOUNT, force) + +/obj/item/stack/material/pull_from_provider(amount) + var/list/legacy_remap = legacy_stack_provider_material_map[type] + if(legacy_remap) + // we have to be atomic, so do an expensive check first + var/has_remaining = check_provider_remaining() + for(var/mat_id in legacy_remap) + item_mount.material_use_amount(src, null, mat_id, has_remaining * legacy_remap[mat_id] * SHEET_MATERIAL_AMOUNT) + else + . = item_mount.material_use_amount(src, null, material.id, amount * SHEET_MATERIAL_AMOUNT) + + // todo: we need a better way of doing this, holy shit /obj/item/stack/material/iron diff --git a/code/game/objects/items/stacks/sheets/glass.dm b/code/game/objects/items/stacks/subtypes/material/glass.dm similarity index 100% rename from code/game/objects/items/stacks/sheets/glass.dm rename to code/game/objects/items/stacks/subtypes/material/glass.dm diff --git a/code/game/objects/items/stacks/medical.dm b/code/game/objects/items/stacks/subtypes/medical.dm similarity index 99% rename from code/game/objects/items/stacks/medical.dm rename to code/game/objects/items/stacks/subtypes/medical.dm index d0b45a59743..522f0977191 100644 --- a/code/game/objects/items/stacks/medical.dm +++ b/code/game/objects/items/stacks/subtypes/medical.dm @@ -51,7 +51,7 @@ to_chat(user, "You can't apply [src] through [H.head]!") return FALSE else - if(istype(H.inventory.get_slot_single(/datum/inventory_slot/inventory/suit), /obj/item/clothing/suit/space)) + if(istype(H.inventory.get_slot_single(/datum/inventory_slot/inventory/suit::id), /obj/item/clothing/suit/space)) to_chat(user, "You can't apply [src] through [H.wear_suit]!") return FALSE diff --git a/code/game/objects/items/stacks/nanopaste.dm b/code/game/objects/items/stacks/subtypes/nanopaste.dm similarity index 100% rename from code/game/objects/items/stacks/nanopaste.dm rename to code/game/objects/items/stacks/subtypes/nanopaste.dm diff --git a/code/game/objects/items/stacks/rods.dm b/code/game/objects/items/stacks/subtypes/rods.dm similarity index 87% rename from code/game/objects/items/stacks/rods.dm rename to code/game/objects/items/stacks/subtypes/rods.dm index a4d0a46bd6d..e4310ade979 100644 --- a/code/game/objects/items/stacks/rods.dm +++ b/code/game/objects/items/stacks/subtypes/rods.dm @@ -38,7 +38,7 @@ if(WT.remove_fuel(0,user)) var/obj/item/stack/material/steel/new_item = new(usr.loc) - new_item.add_to_stacks(usr) + new_item.legacy_add_to_stacks_please_refactor_me(usr) for (var/mob/M in viewers(src)) M.show_message("[src] is shaped into metal by [user.name] with the weldingtool.", 3, "You hear welding.", 2) var/obj/item/stack/rods/R = src @@ -59,13 +59,3 @@ return ..() - -/obj/item/stack/rods/cyborg - name = "metal rod synthesizer" - desc = "A device that makes metal rods." - gender = NEUTER - uses_charge = 1 - charge_costs = list(500) - stack_type = /obj/item/stack/rods - stacktype_legacy = /obj/item/stack/rods - no_variants = TRUE diff --git a/code/game/objects/items/stacks/sandbag.dm b/code/game/objects/items/stacks/subtypes/sandbag.dm similarity index 59% rename from code/game/objects/items/stacks/sandbag.dm rename to code/game/objects/items/stacks/subtypes/sandbag.dm index 0920ab9146e..7af7fcb01a7 100644 --- a/code/game/objects/items/stacks/sandbag.dm +++ b/code/game/objects/items/stacks/subtypes/sandbag.dm @@ -1,51 +1,3 @@ -//Empty Sandbags -/obj/item/stack/emptysandbag - name = "empty sandbag" - desc = "A bag designed to be filled with sand." - singular_name = "empty sandbag" - icon_state = "sandbag_empty" - w_class = WEIGHT_CLASS_NORMAL - damage_force = 1 - throw_force = 1 - throw_speed = 5 - throw_range = 20 - drop_sound = 'sound/items/drop/backpack.ogg' - pickup_sound = 'sound/items/pickup/backpack.ogg' - materials_base = list("cloth" = 2) - max_amount = 50 - attack_verb = list("tapped", "smacked", "flapped") - -/obj/item/stack/emptysandbag/Initialize(mapload, new_amount, merge) - . = ..() - update_icon() - -/obj/item/stack/emptysandbag/update_icon_state() - var/amount = get_amount() - if((amount >= 35)) - icon_state = "sandbag_empty_3" - else if((amount < 35) && (amount > 1)) - icon_state = "sandbag_empty_2" - else - icon_state = "sandbag_empty" - return ..() - -/obj/item/stack/emptysandbag/attackby(var/obj/item/W, var/mob/user) - if(istype(W, /obj/item/stack/ore/glass) && !interact(user, src)) - if(do_after(user, 1 SECONDS, src) && use(1)) - var/obj/item/stack/ore/glass/O = W - var/turf/T = get_turf(user) - if(O.use(1)) - to_chat(user, "You fill the sandbag.") - new /obj/item/stack/sandbags(T) - return - else if(is_sharp(W)) - user.visible_message("\The [user] begins cutting up [src] with [W].", "You begin cutting up [src] with [W].") - if(do_after(user, 3 SECONDS, src) && use(1)) - to_chat(user, "You cut [src] into pieces!") - new /obj/item/stack/material/cloth(drop_location(),rand(1,2)) - return - return ..() - //Filled Sandbags /obj/item/stack/sandbags name = "sandbag" @@ -95,69 +47,53 @@ var/turf/T = get_turf(user) to_chat(user, "You cut the cords securing the sandbag, spilling sand everywhere!") for(var/i in 1 to rand(1,1)) - new /obj/item/stack/emptysandbag(T) + new /obj/item/stack/sandbag/empty(T) new /obj/item/stack/ore/glass(T) return -//Sandbag Barricades -/obj/structure/sandbag - name = "sandbag barricade" - desc = "A barrier made of stacked sandbags." - icon = 'icons/obj/structures/sandbags.dmi' - icon_state = "sandbags-0" - base_icon_state = "sandbags" - anchored = TRUE - density = TRUE - pass_flags_self = ATOM_PASS_TABLE | ATOM_PASS_THROWN | ATOM_PASS_CLICK - smoothing_flags = SMOOTH_BITMASK - smoothing_groups = (SMOOTH_GROUP_SANDBAGS) - canSmoothWith = (SMOOTH_GROUP_SANDBAGS) - integrity = 200 - integrity_max = 200 +//Empty Sandbags +/obj/item/stack/sandbag/empty + name = "empty sandbag" + desc = "A bag designed to be filled with sand." + singular_name = "empty sandbag" + icon_state = "sandbag_empty" + w_class = WEIGHT_CLASS_NORMAL + damage_force = 1 + throw_force = 1 + throw_speed = 5 + throw_range = 20 + drop_sound = 'sound/items/drop/backpack.ogg' + pickup_sound = 'sound/items/pickup/backpack.ogg' + materials_base = list("cloth" = 2) + max_amount = 50 + attack_verb = list("tapped", "smacked", "flapped") - var/vestigial = TRUE - -/obj/structure/sandbag/Initialize(mapload) +/obj/item/stack/sandbag/empty/Initialize(mapload, new_amount, merge) . = ..() - for(var/obj/structure/sandbag/S in loc) - if(S != src) - break_to_parts(full_return = 1) - return - if(mapload) - return INITIALIZE_HINT_LATELOAD - else - //update_connections(TRUE) - update_icon() - -/obj/structure/sandbag/LateInitialize() - //update_connections(FALSE) update_icon() -/obj/structure/sandbag/Destroy() - //update_connections(TRUE) - . = ..() - -/obj/structure/sandbag/attackby(obj/item/W as obj, mob/user as mob) - user.setClickCooldownLegacy(user.get_attack_speed_legacy(W)) - if(istype(W, /obj/item/stack/sandbags)) - var/obj/item/stack/sandbags/S = W - if(integrity < integrity_max) - if(S.get_amount() < 1) - to_chat(user, "You need one sandbag to repair \the [src].") - return CLICKCHAIN_DO_NOT_PROPAGATE - visible_message("[user] begins to repair \the [src].") - if(do_after(user,20) && integrity < integrity_max) - if(S.use(1)) - integrity = integrity_max - visible_message("[user] repairs \the [src].") - return CLICKCHAIN_DO_NOT_PROPAGATE | CLICKCHAIN_DID_SOMETHING - return CLICKCHAIN_DO_NOT_PROPAGATE - return ..() - -/obj/structure/sandbag/proc/break_to_parts(full_return = 0) - if(full_return || prob(20)) - new /obj/item/stack/sandbags(src.loc) +/obj/item/stack/sandbag/empty/update_icon() + var/amount = get_amount() + if((amount >= 35)) + icon_state = "sandbag_empty_3" + else if((amount < 35) && (amount > 1)) + icon_state = "sandbag_empty_2" else - new /obj/item/stack/material/cloth(src.loc) - new /obj/item/stack/ore/glass(src.loc) - qdel(src) + icon_state = "sandbag_empty" + +/obj/item/stack/sandbag/empty/attackby(var/obj/item/W, var/mob/user) + if(istype(W, /obj/item/stack/ore/glass) && !interact(user, src)) + if(do_after(user, 1 SECONDS, src) && use(1)) + var/obj/item/stack/ore/glass/O = W + var/turf/T = get_turf(user) + if(O.use(1)) + to_chat(user, "You fill the sandbag.") + new /obj/item/stack/sandbags(T) + return + else if(is_sharp(W)) + user.visible_message("\The [user] begins cutting up [src] with [W].", "You begin cutting up [src] with [W].") + if(do_after(user, 3 SECONDS, src) && use(1)) + to_chat(user, "You cut [src] into pieces!") + new /obj/item/stack/material/cloth(drop_location(),rand(1,2)) + return + return ..() diff --git a/code/game/objects/items/stacks/telecrystal.dm b/code/game/objects/items/stacks/subtypes/telecrystal.dm similarity index 100% rename from code/game/objects/items/stacks/telecrystal.dm rename to code/game/objects/items/stacks/subtypes/telecrystal.dm diff --git a/code/game/objects/items/stacks/tiles/tile_types.dm b/code/game/objects/items/stacks/tiles/tile_types.dm index f0ca7d142af..f396d2d2e0f 100644 --- a/code/game/objects/items/stacks/tiles/tile_types.dm +++ b/code/game/objects/items/stacks/tiles/tile_types.dm @@ -89,14 +89,6 @@ desc = "An easy to fit wooden floor tile. It's blue!" icon_state = "tile-sifwood" -/obj/item/stack/tile/wood/cyborg - name = "wood floor tile synthesizer" - desc = "A device that makes wood floor tiles." - uses_charge = 1 - charge_costs = list(250) - stack_type = /obj/item/stack/tile/wood - stacktype_legacy = /obj/item/stack/tile/wood - /* * Carpets */ @@ -298,16 +290,6 @@ materials_base = list(MAT_PLASTIC = SHEET_MATERIAL_AMOUNT / 4) no_variants = FALSE -/obj/item/stack/tile/floor/cyborg - name = "floor tile synthesizer" - desc = "A device that makes floor tiles." - gender = NEUTER - materials_base = null - uses_charge = 1 - charge_costs = list(250) - stack_type = /obj/item/stack/tile/floor - stacktype_legacy = /obj/item/stack/tile/floor - /obj/item/stack/tile/floor/sandstone name = "sandstone tile" singular_name = "sandstone tile" @@ -355,14 +337,6 @@ desc = "A section of roofing material. You can use it to repair the ceiling, or expand it." icon_state = "techtile_grid" -/obj/item/stack/tile/roofing/cyborg - name = "roofing synthesizer" - desc = "A device that makes roofing tiles." - uses_charge = 1 - charge_costs = list(250) - stack_type = /obj/item/stack/tile/roofing - stacktype_legacy = /obj/item/stack/tile/roofing - /obj/item/stack/tile/roofing/wood name = "wood roofing" singular_name = "wood roofing" diff --git a/code/game/objects/items/toys/toys.dm b/code/game/objects/items/toys/toys.dm index e32a6bb7bef..3b9a22bcf05 100644 --- a/code/game/objects/items/toys/toys.dm +++ b/code/game/objects/items/toys/toys.dm @@ -1630,7 +1630,7 @@ /obj/item/checker name = "Checker Piece" - icon = 'icons/mob/robots.dmi' + icon = 'icons/mob/robot-legacy.dmi' icon_state = "zoomba-combat-shield" desc = "Some sort of novelty checker piece." diff --git a/code/game/objects/items/trash.dm b/code/game/objects/items/trash.dm index 0812cac9ad6..dda877e3453 100644 --- a/code/game/objects/items/trash.dm +++ b/code/game/objects/items/trash.dm @@ -135,12 +135,13 @@ if(isrobot(target)) var/mob/living/silicon/robot/R = target - if(R.module.type == /obj/item/robot_module/robot/quad/jani) // You can now feed the trash borg yay. - if(!user.attempt_insert_item_for_installation(src, R.vore_selected)) + if(R.module.type == /datum/prototype/robot_module/nanotrasen/janitor && R.chassis.type == /datum/prototype/robot_chassis/quadruped) // You can now feed the trash borg yay. + if(R.vore_selected) + if(!user.attempt_insert_item_for_installation(src, R.vore_selected)) + return + playsound(R,'sound/items/eatfood.ogg', rand(10,50), 1) + R.visible_message("[user] feeds [R] with [src]!") return - playsound(R,'sound/items/eatfood.ogg', rand(10,50), 1) - R.visible_message("[user] feeds [R] with [src]!") - return return ..() /obj/item/trash/fancyplate diff --git a/code/game/objects/items/weapons/AI_modules.dm b/code/game/objects/items/weapons/AI_modules.dm index b2e354f4e76..67b1dbcd726 100644 --- a/code/game/objects/items/weapons/AI_modules.dm +++ b/code/game/objects/items/weapons/AI_modules.dm @@ -8,7 +8,7 @@ AI MODULES /obj/item/aiModule name = "\improper AI module" - icon = 'icons/obj/module.dmi' + icon = 'icons/items/circuits.dmi' icon_state = "std_mod" desc = "An AI Module for transmitting encrypted instructions to the AI." damage_force = 5.0 @@ -18,7 +18,7 @@ AI MODULES throw_range = 15 origin_tech = list(TECH_DATA = 3) preserve_item = 1 - var/datum/ai_laws/laws = null + var/datum/ai_lawset/laws = null /obj/item/aiModule/proc/install(var/atom/movable/AM, var/mob/living/user) if(!user.IsAdvancedToolUser() && isanimal_legacy_this_is_broken(user)) @@ -313,7 +313,7 @@ AI MODULES name = "\improper 'Asimov' core AI module" desc = "An 'Asimov' Core AI Module: 'Reconfigures the AI's core laws.'" origin_tech = list(TECH_DATA = 3, TECH_MATERIAL = 4) - laws = new/datum/ai_laws/asimov + laws = new/datum/ai_lawset/asimov /******************** Nanotrasen ********************/ @@ -321,7 +321,7 @@ AI MODULES name = "'NT Default' Core AI Module" desc = "An 'NT Default' Core AI Module: 'Reconfigures the AI's core laws.'" origin_tech = list(TECH_DATA = 3, TECH_MATERIAL = 4) - laws = new/datum/ai_laws/nanotrasen + laws = new/datum/ai_lawset/nanotrasen /******************** Corporate ********************/ @@ -329,14 +329,14 @@ AI MODULES name = "\improper 'Corporate' core AI module" desc = "A 'Corporate' Core AI Module: 'Reconfigures the AI's core laws.'" origin_tech = list(TECH_DATA = 3, TECH_MATERIAL = 4) - laws = new/datum/ai_laws/corporate + laws = new/datum/ai_lawset/corporate /******************** Drone ********************/ /obj/item/aiModule/drone name = "\improper 'Drone' core AI module" desc = "A 'Drone' Core AI Module: 'Reconfigures the AI's core laws.'" origin_tech = list(TECH_DATA = 3, TECH_MATERIAL = 4) - laws = new/datum/ai_laws/drone + laws = new/datum/ai_lawset/drone /****************** P.A.L.A.D.I.N. **************/ @@ -344,7 +344,7 @@ AI MODULES name = "\improper 'P.A.L.A.D.I.N.' core AI module" desc = "A P.A.L.A.D.I.N. Core AI Module: 'Reconfigures the AI's core laws.'" origin_tech = list(TECH_DATA = 3, TECH_MATERIAL = 6) - laws = new/datum/ai_laws/paladin + laws = new/datum/ai_lawset/paladin /****************** T.Y.R.A.N.T. *****************/ @@ -352,7 +352,7 @@ AI MODULES name = "\improper 'T.Y.R.A.N.T.' core AI module" desc = "A T.Y.R.A.N.T. Core AI Module: 'Reconfigures the AI's core laws.'" origin_tech = list(TECH_DATA = 3, TECH_MATERIAL = 6, TECH_ILLEGAL = 2) - laws = new/datum/ai_laws/tyrant() + laws = new/datum/ai_lawset/tyrant() /******************** Freeform Core ******************/ @@ -423,7 +423,7 @@ AI MODULES name = "\improper 'Robocop' core AI module" desc = "A 'Robocop' Core AI Module: 'Reconfigures the AI's core three laws.'" origin_tech = list(TECH_DATA = 4) - laws = new/datum/ai_laws/robocop() + laws = new/datum/ai_lawset/robocop() /******************** Antimov ********************/ @@ -431,4 +431,4 @@ AI MODULES name = "\improper 'Antimov' core AI module" desc = "An 'Antimov' Core AI Module: 'Reconfigures the AI's core laws.'" origin_tech = list(TECH_DATA = 4) - laws = new/datum/ai_laws/antimov() + laws = new/datum/ai_lawset/antimov() diff --git a/code/game/objects/items/weapons/RCD.dm b/code/game/objects/items/weapons/RCD.dm index 0d9fc774f48..bc13bd3417e 100644 --- a/code/game/objects/items/weapons/RCD.dm +++ b/code/game/objects/items/weapons/RCD.dm @@ -1,4 +1,3 @@ -// Contains the rapid construction device. /obj/item/rcd name = "rapid construction device" desc = "A device used to rapidly build and deconstruct. Reload with compressed matter cartridges." diff --git a/code/game/objects/items/weapons/RSF.dm b/code/game/objects/items/weapons/RSF.dm index 5d0ba68d4d5..86030b68284 100644 --- a/code/game/objects/items/weapons/RSF.dm +++ b/code/game/objects/items/weapons/RSF.dm @@ -1,9 +1,3 @@ -/* -CONTAINS: -RSF - -*/ - /obj/item/rsf name = "\improper Rapid-Service-Fabricator" desc = "A device used to rapidly deploy service items." @@ -155,3 +149,5 @@ RSF else stored_matter-- to_chat(user,"The RSF now holds [stored_matter]/30 fabrication-units.") + +/obj/item/rsf/loaded diff --git a/code/game/objects/items/weapons/extinguisher.dm b/code/game/objects/items/weapons/extinguisher.dm index 325dd1e3134..a12f6c8fcba 100644 --- a/code/game/objects/items/weapons/extinguisher.dm +++ b/code/game/objects/items/weapons/extinguisher.dm @@ -23,27 +23,6 @@ var/safety = 1 var/sprite_name = "fire_extinguisher" -/obj/item/extinguisher/mini - name = "compact fire extinguisher" - desc = "A light and compact fibreglass-framed model fire extinguisher." - icon_state = "miniFE0" - item_state = "miniFE" - attack_sound = null //it is much lighter, after all. - throw_force = 2 - materials_base = list(MAT_PLASTIC = 90) - w_class = WEIGHT_CLASS_SMALL - damage_force = 3.0 - max_water = 150 - spray_particles = 3 - sprite_name = "miniFE" - suit_storage_class = SUIT_STORAGE_CLASS_SOFTWEAR - belt_storage_class = BELT_CLASS_MEDIUM - -/obj/item/extinguisher/mini/plasman - name = "emergency phoronoid extinguisher" - desc = "A mini fire extinguisher for use by burning phoronoids. Let's just hope it works." - max_water = 300 - /obj/item/extinguisher/Initialize(mapload) . = ..() create_reagents(max_water) @@ -51,7 +30,7 @@ /obj/item/extinguisher/examine(mob/user, dist) . = ..() - . += "[icon2html(thing = src, target = user)] [src.name] contains [src.reagents.total_volume] units of water left!" + . += "[icon2html(thing = src, target = user)] [src.name] contains [available_spray_volume()] units of fluid left!" /obj/item/extinguisher/attack_self(mob/user, datum/event_args/actor/actor) . = ..() @@ -62,6 +41,26 @@ desc = "The safety is [safety ? "on" : "off"]." to_chat(user, "The safety is [safety ? "on" : "off"].") +/** + * @return volume + */ +/obj/item/extinguisher/proc/available_spray_volume() + if(item_mount) + return item_mount.extinguisher_get_volume(src) + if(reagents) + return reagents.total_volume + return 0 + +/** + * @return amount pulled + */ +/obj/item/extinguisher/proc/pull_spray_volume(datum/reagent_holder/target, amount) + if(item_mount) + return item_mount.extinguisher_transfer_volume(src, null, amount, target) + if(reagents) + return reagents.transfer_to_holder(target, null, amount) + return 0 + /obj/item/extinguisher/proc/propel_object(var/obj/O, mob/user, movementdirection) if(O.anchored) return @@ -90,47 +89,67 @@ playsound(src.loc, 'sound/effects/refill.ogg', 50, 1, -6) return - if (!safety) - if (src.reagents.total_volume < 1) - to_chat(usr, "\The [src] is empty.") - return - - if (world.time < src.last_use + 20) - return - - src.last_use = world.time - - playsound(src.loc, 'sound/effects/extinguish.ogg', 75, 1, -3) - - var/direction = get_dir(src,target) - - if(user.buckled && isobj(user.buckled)) - spawn(0) - propel_object(user.buckled, user, turn(direction,180)) - - var/turf/T = get_turf(target) - var/turf/T1 = get_step(T,turn(direction, 90)) - var/turf/T2 = get_step(T,turn(direction, -90)) - - var/list/the_targets = list(T,T1,T2) - - for(var/a = 1 to spray_particles) - spawn(0) - if(!src || !reagents.total_volume) return - - var/obj/effect/water/W = new /obj/effect/water(get_turf(src)) - var/turf/my_target - if(a <= the_targets.len) - my_target = the_targets[a] - else - my_target = pick(the_targets) - W.create_reagents(spray_amount) - reagents.trans_to_obj(W, spray_amount) - W.set_color() - W.set_up(my_target) - - if((istype(usr.loc, /turf/space)) || (usr.lastarea.has_gravity == 0)) - user.newtonian_move(get_dir(target, user)) - else + if(safety) return ..() - return + if (!available_spray_volume()) + to_chat(usr, "\The [src] is empty.") + return + + if (world.time < src.last_use + 20) + return + + src.last_use = world.time + + playsound(src.loc, 'sound/effects/extinguish.ogg', 75, 1, -3) + + var/direction = get_dir(src,target) + + if(user.buckled && isobj(user.buckled)) + spawn(0) + propel_object(user.buckled, user, turn(direction,180)) + + var/turf/T = get_turf(target) + var/turf/T1 = get_step(T,turn(direction, 90)) + var/turf/T2 = get_step(T,turn(direction, -90)) + + var/list/the_targets = list(T,T1,T2) + + for(var/a = 1 to spray_particles) + spawn(0) + if(!available_spray_volume()) + return + + var/obj/effect/water/W = new /obj/effect/water(get_turf(src)) + var/turf/my_target + if(a <= the_targets.len) + my_target = the_targets[a] + else + my_target = pick(the_targets) + W.create_reagents(spray_amount) + pull_spray_volume(W.reagents, spray_amount) + W.set_color() + W.set_up(my_target) + + if((istype(usr.loc, /turf/space)) || (usr.lastarea.has_gravity == 0)) + user.newtonian_move(get_dir(target, user)) + +/obj/item/extinguisher/mini + name = "fire extinguisher" + desc = "A light and compact fibreglass-framed model fire extinguisher." + icon_state = "miniFE0" + item_state = "miniFE" + attack_sound = null //it is much lighter, after all. + throw_force = 2 + materials_base = list(MAT_PLASTIC = 90) + w_class = WEIGHT_CLASS_SMALL + damage_force = 3.0 + max_water = 150 + spray_particles = 3 + sprite_name = "miniFE" + suit_storage_class = SUIT_STORAGE_CLASS_SOFTWEAR | SUIT_STORAGE_CLASS_HARDWEAR | SUIT_STORAGE_CLASS_ARMOR + belt_storage_class = BELT_CLASS_MEDIUM + +/obj/item/extinguisher/mini/plasman + name = "emergency phoronoid extinguisher" + desc = "A mini fire extinguisher for use by burning phoronoids. Let's just hope it works." + max_water = 300 diff --git a/code/game/objects/items/weapons/gift_wrappaper.dm b/code/game/objects/items/weapons/gift_wrappaper.dm index 4d5562c5657..60b581accf9 100644 --- a/code/game/objects/items/weapons/gift_wrappaper.dm +++ b/code/game/objects/items/weapons/gift_wrappaper.dm @@ -276,7 +276,7 @@ return var/mob/living/carbon/human/H = target - if (istype(H.inventory.get_slot_single(/datum/inventory_slot/inventory/suit), /obj/item/clothing/suit/straight_jacket) || H.stat) + if (istype(H.inventory.get_slot_single(/datum/inventory_slot/inventory/suit::id), /obj/item/clothing/suit/straight_jacket) || H.stat) if (src.amount > 2) var/obj/effect/spresent/present = new /obj/effect/spresent (H.loc) src.amount -= 2 diff --git a/code/game/objects/items/weapons/handcuffs.dm b/code/game/objects/items/weapons/handcuffs.dm index 35e5d7c4276..c83d3b8ca82 100644 --- a/code/game/objects/items/weapons/handcuffs.dm +++ b/code/game/objects/items/weapons/handcuffs.dm @@ -274,7 +274,7 @@ var/last_chew = 0 if(!H.can_equip(src, SLOT_ID_LEGCUFFED, user = user)) return FALSE - if(istype(H.inventory.get_slot(/datum/inventory_slot/inventory/shoes), /obj/item/clothing/shoes/magboots/hardsuit) && !elastic) // Can't cuff someone who's in a deployed hardsuit. + if(istype(H.inventory.get_slot(/datum/inventory_slot/inventory/shoes::id), /obj/item/clothing/shoes/magboots/hardsuit) && !elastic) // Can't cuff someone who's in a deployed hardsuit. to_chat(user, "\The [src] won't fit around \the [H.shoes]!") return 0 diff --git a/code/game/objects/items/weapons/other.dm b/code/game/objects/items/weapons/other.dm index b76441a8ae5..4b89dfd3bab 100644 --- a/code/game/objects/items/weapons/other.dm +++ b/code/game/objects/items/weapons/other.dm @@ -273,7 +273,7 @@ w_class = WEIGHT_CLASS_SMALL /obj/item/module - icon = 'icons/obj/module.dmi' + icon = 'icons/items/circuits.dmi' icon_state = "std_module" item_state = "std_mod" w_class = WEIGHT_CLASS_SMALL diff --git a/code/game/objects/structures/cliff.dm b/code/game/objects/structures/cliff.dm index 7c646fc937a..ad3395c486d 100644 --- a/code/game/objects/structures/cliff.dm +++ b/code/game/objects/structures/cliff.dm @@ -229,7 +229,7 @@ two tiles on initialization, and which way a cliff is facing may change during m // Cliff climbing requires climbing gear. if(ishuman(user)) var/mob/living/carbon/human/H = user - var/obj/item/clothing/shoes/shoes = H.inventory.get_slot(/datum/inventory_slot/inventory/shoes) + var/obj/item/clothing/shoes/shoes = H.inventory.get_slot(/datum/inventory_slot/inventory/shoes::id) if(istype(shoes) && shoes.rock_climbing) return TRUE var/obj/item/held = H.get_active_held_item() diff --git a/code/game/objects/structures/door_assembly.dm b/code/game/objects/structures/door_assembly.dm index 0eefaa00519..91329b492c3 100644 --- a/code/game/objects/structures/door_assembly.dm +++ b/code/game/objects/structures/door_assembly.dm @@ -162,8 +162,7 @@ update_state() /obj/structure/door_assembly/attack_robot(mob/living/silicon/robot/user) - if(Adjacent(user) && (user.module && (istype(user.module,/obj/item/robot_module/robot/engineering/general)) \ - || istype(user.module,/obj/item/robot_module/drone))) //Only dron (and engiborg) needs this. + if(Adjacent(user)) rename_door(user) /obj/structure/door_assembly/attackby(obj/item/W as obj, mob/user as mob) diff --git a/code/game/objects/structures/ghost_pods/silicon.dm b/code/game/objects/structures/ghost_pods/silicon.dm index 6df67a52f14..9c0cbdaf3ff 100644 --- a/code/game/objects/structures/ghost_pods/silicon.dm +++ b/code/game/objects/structures/ghost_pods/silicon.dm @@ -17,7 +17,7 @@ /obj/structure/ghost_pod/manual/lost_drone/create_occupant(var/mob/M) density = FALSE - var/mob/living/silicon/robot/lost/randomlaws/R = new(get_turf(src)) + var/mob/living/silicon/robot/preset_module/lost/randomlaws/R = new(get_turf(src)) R.adjustBruteLoss(rand(5, 30)) R.adjustFireLoss(rand(5, 10)) if(M.mind) @@ -48,7 +48,7 @@ /obj/structure/ghost_pod/automatic/gravekeeper_drone/create_occupant(var/mob/M) density = FALSE - var/mob/living/silicon/robot/gravekeeper/R = new(get_turf(src)) + var/mob/living/silicon/robot/preset_module/gravekeeper/R = new(get_turf(src)) if(M.mind) M.mind.transfer(R) // Put this text here before ckey change so that their laws are shown below it, since borg login() shows it. @@ -60,51 +60,51 @@ R.Namepick() ..() -/obj/structure/ghost_pod/ghost_activated/swarm_drone - name = "drone shell" - desc = "A heavy metallic ball." - icon = 'icons/mob/swarmbot.dmi' - icon_state = "swarmer_unactivated" - density = FALSE - anchored = FALSE +// /obj/structure/ghost_pod/ghost_activated/swarm_drone +// name = "drone shell" +// desc = "A heavy metallic ball." +// icon = 'icons/mob/swarmbot.dmi' +// icon_state = "swarmer_unactivated" +// density = FALSE +// anchored = FALSE - var/drone_class = "general" - var/drone_type = /mob/living/silicon/robot/drone/swarm +// var/drone_class = "general" +// var/drone_type = /mob/living/silicon/robot/drone/swarm -/obj/structure/ghost_pod/ghost_activated/swarm_drone/create_occupant(var/mob/M) - var/mob/living/silicon/robot/drone/swarm/R = new drone_type(get_turf(src)) - if(M.mind) - M.mind.transfer(R) - to_chat(M, "You are [R], the remnant of some distant species, mechanical or flesh, living or dead.") - M.transfer_client_to(R) - visible_message("As \the [src] shudders, it glows before lifting itself with three shimmering limbs!") - spawn(3 SECONDS) - to_chat(R,"Many of your tools are standard drone devices, however others provide you with particular benefits.") - to_chat(R,"Unlike standard drones, you are capable of utilizing 'zero point wells', found in your 'spells' tab.") - to_chat(R,"Here you will also find your replication ability(s), depending on the type of drone you are.") - to_chat(R,"Gunners have a special anti-personnel gun capable of shocking or punching through armor with low damage.") - to_chat(R,"Impalers have an energy-lance.") - to_chat(R,"General drones have the unique ability to produce one of each of these two types of shells per generation.") - if(!QDELETED(src)) - qdel(src) +// /obj/structure/ghost_pod/ghost_activated/swarm_drone/create_occupant(var/mob/M) +// var/mob/living/silicon/robot/drone/swarm/R = new drone_type(get_turf(src)) +// if(M.mind) +// M.mind.transfer(R) +// to_chat(M, "You are [R], the remnant of some distant species, mechanical or flesh, living or dead.") +// M.transfer_client_to(R) +// visible_message("As \the [src] shudders, it glows before lifting itself with three shimmering limbs!") +// spawn(3 SECONDS) +// to_chat(R,"Many of your tools are standard drone devices, however others provide you with particular benefits.") +// to_chat(R,"Unlike standard drones, you are capable of utilizing 'zero point wells', found in your 'spells' tab.") +// to_chat(R,"Here you will also find your replication ability(s), depending on the type of drone you are.") +// to_chat(R,"Gunners have a special anti-personnel gun capable of shocking or punching through armor with low damage.") +// to_chat(R,"Impalers have an energy-lance.") +// to_chat(R,"General drones have the unique ability to produce one of each of these two types of shells per generation.") +// if(!QDELETED(src)) +// qdel(src) -/obj/structure/ghost_pod/ghost_activated/swarm_drone/event/Initialize(mapload) - . = ..() +// /obj/structure/ghost_pod/ghost_activated/swarm_drone/event/Initialize(mapload) +// . = ..() - var/turf/T = get_turf(src) - say_dead_object("A [drone_class] swarm drone shell is now available in \the [T.loc].", src) +// var/turf/T = get_turf(src) +// say_dead_object("A [drone_class] swarm drone shell is now available in \the [T.loc].", src) -/obj/structure/ghost_pod/ghost_activated/swarm_drone/event/gunner - name = "gunner shell" +// /obj/structure/ghost_pod/ghost_activated/swarm_drone/event/gunner +// name = "gunner shell" - drone_class = "gunner" - drone_type = /mob/living/silicon/robot/drone/swarm/gunner +// drone_class = "gunner" +// drone_type = /mob/living/silicon/robot/drone/swarm/gunner -/obj/structure/ghost_pod/ghost_activated/swarm_drone/event/melee - name = "impaler shell" +// /obj/structure/ghost_pod/ghost_activated/swarm_drone/event/melee +// name = "impaler shell" - drone_class = "impaler" - drone_type = /mob/living/silicon/robot/drone/swarm/melee +// drone_class = "impaler" +// drone_type = /mob/living/silicon/robot/drone/swarm/melee /obj/structure/ghost_pod/manual/lost_drone/dogborg @@ -114,7 +114,7 @@ return ..() else density = FALSE - var/mob/living/silicon/robot/stray/randomlaws/R = new(get_turf(src)) + var/mob/living/silicon/robot/preset_module/lost/randomlaws/R = new(get_turf(src)) R.adjustBruteLoss(rand(5, 30)) R.adjustFireLoss(rand(5, 10)) if(M.mind) diff --git a/code/game/objects/structures/loot_piles.dm b/code/game/objects/structures/loot_piles.dm index d447a055440..694f4c00bd7 100644 --- a/code/game/objects/structures/loot_piles.dm +++ b/code/game/objects/structures/loot_piles.dm @@ -369,7 +369,7 @@ Loot piles can be depleted, if loot_depleted is turned on. Note that players wh /obj/item/stock_parts/subspace/treatment, /obj/item/frame, /obj/item/broken_device/random, - /obj/item/borg/upgrade/restart, + /obj/item/robot_upgrade/restart, /obj/item/cell/basic/tier_2/weapon, /obj/item/cell/basic/tier_2/medium, /obj/item/cell/basic/tier_2/small, @@ -428,10 +428,9 @@ Loot piles can be depleted, if loot_depleted is turned on. Note that players wh /obj/item/tvcamera, /obj/item/universal_translator, /obj/item/aicard, - /obj/item/borg/upgrade/jetpack, - /obj/item/borg/upgrade/advhealth, - /obj/item/borg/upgrade/vtec, - /obj/item/borg/upgrade/tasercooler, + /obj/item/robot_upgrade/jetpack, + /obj/item/robot_upgrade/advhealth, + /obj/item/robot_upgrade/vtec, /obj/item/vehicle_module/weapon/energy/riggedlaser, /obj/item/vehicle_module/tool/drill/diamonddrill, /obj/item/hardsuit_module/device/drill, @@ -1130,11 +1129,10 @@ Loot piles can be depleted, if loot_depleted is turned on. Note that players wh rare_loot = list( /obj/item/cell/basic/tier_3/medium, - /obj/item/borg/upgrade/restart, - /obj/item/borg/upgrade/jetpack, - /obj/item/borg/upgrade/tasercooler, - /obj/item/borg/upgrade/syndicate, - /obj/item/borg/upgrade/vtec + /obj/item/robot_upgrade/restart, + /obj/item/robot_upgrade/jetpack, + /obj/item/robot_upgrade/syndicate, + /obj/item/robot_upgrade/vtec ) // Contains old mediciation, most of it unidentified and has a good chance of being useless. diff --git a/code/game/objects/structures/props/swarm.dm b/code/game/objects/structures/props/swarm.dm index 5f46aa88711..4551f60d57f 100644 --- a/code/game/objects/structures/props/swarm.dm +++ b/code/game/objects/structures/props/swarm.dm @@ -1,152 +1,153 @@ -/obj/structure/cult/pylon/swarm - name = "Swarm Construct" - desc = "A small pod." - icon = 'icons/mob/swarmbot.dmi' - icon_state = "pod" - light_color = "#00B2B2" +// TODO: IOU swarmers. +// /obj/structure/cult/pylon/swarm +// name = "Swarm Construct" +// desc = "A small pod." +// icon = 'icons/mob/swarmbot.dmi' +// icon_state = "pod" +// light_color = "#00B2B2" - shatter_message = "The energetic field shatters!" - impact_sound = 'sound/effects/Glasshit.ogg' - shatter_sound = 'sound/effects/phasein.ogg' +// shatter_message = "The energetic field shatters!" +// impact_sound = 'sound/effects/Glasshit.ogg' +// shatter_sound = 'sound/effects/phasein.ogg' - var/list/active_beams +// var/list/active_beams -/obj/structure/cult/pylon/swarm/CanAllowThrough(atom/movable/mover, turf/target) - if(istype(mover, /mob/living)) - var/mob/living/L = mover - if(L.has_iff_faction(MOB_IFF_FACTION_SWARMER)) - return TRUE - else if(istype(mover, /obj/projectile)) - var/obj/projectile/P = mover - if(isliving(P.firer)) - var/mob/living/L = P.firer - if(L.has_iff_faction(MOB_IFF_FACTION_SWARMER)) - return TRUE - return ..() +// /obj/structure/cult/pylon/swarm/CanAllowThrough(atom/movable/mover, turf/target) +// if(istype(mover, /mob/living)) +// var/mob/living/L = mover +// if(L.has_iff_faction(MOB_IFF_FACTION_SWARMER)) +// return TRUE +// else if(istype(mover, /obj/projectile)) +// var/obj/projectile/P = mover +// if(isliving(P.firer)) +// var/mob/living/L = P.firer +// if(L.has_iff_faction(MOB_IFF_FACTION_SWARMER)) +// return TRUE +// return ..() -/obj/structure/cult/pylon/swarm/Initialize(mapload) - . = ..() - active_beams = list() +// /obj/structure/cult/pylon/swarm/Initialize(mapload) +// . = ..() +// active_beams = list() -/obj/structure/cult/pylon/swarm/Destroy() - for(var/datum/beam_legacy/B in active_beams) - QDEL_NULL(B) - active_beams = null - ..() +// /obj/structure/cult/pylon/swarm/Destroy() +// for(var/datum/beam_legacy/B in active_beams) +// QDEL_NULL(B) +// active_beams = null +// ..() -/obj/structure/cult/pylon/swarm/pylonhit(var/damage) - if(!isbroken) - if(prob(1 + damage * 3)) - visible_message("[shatter_message]") - STOP_PROCESSING(SSobj, src) - playsound(get_turf(src),shatter_sound, 75, 1) - isbroken = 1 - density = 0 - icon_state = "[initial(icon_state)]-broken" - set_light(0) +// /obj/structure/cult/pylon/swarm/pylonhit(var/damage) +// if(!isbroken) +// if(prob(1 + damage * 3)) +// visible_message("[shatter_message]") +// STOP_PROCESSING(SSobj, src) +// playsound(get_turf(src),shatter_sound, 75, 1) +// isbroken = 1 +// density = 0 +// icon_state = "[initial(icon_state)]-broken" +// set_light(0) -/obj/structure/cult/pylon/swarm/attackpylon(mob/user as mob, var/damage) - if(!isbroken) - if(prob(1 + damage * 3)) - user.visible_message( - "[user] smashed \the [src]!", - "You hit \the [src], and its crystal breaks apart!", - "You hear a tinkle of crystalline shards." - ) - STOP_PROCESSING(SSobj, src) - user.do_attack_animation(src) - playsound(get_turf(src),shatter_sound, 75, 1) - isbroken = 1 - density = 0 - icon_state = "[initial(icon_state)]-broken" - set_light(0) - else - to_chat(user, "You hit \the [src]!") - playsound(get_turf(src),impact_sound, 75, 1) - else - if(prob(damage * 2)) - to_chat(user, "You pulverize what was left of \the [src]!") - qdel(src) - else - to_chat(user, "You hit \the [src]!") - playsound(get_turf(src),impact_sound, 75, 1) +// /obj/structure/cult/pylon/swarm/attackpylon(mob/user as mob, var/damage) +// if(!isbroken) +// if(prob(1 + damage * 3)) +// user.visible_message( +// "[user] smashed \the [src]!", +// "You hit \the [src], and its crystal breaks apart!", +// "You hear a tinkle of crystalline shards." +// ) +// STOP_PROCESSING(SSobj, src) +// user.do_attack_animation(src) +// playsound(get_turf(src),shatter_sound, 75, 1) +// isbroken = 1 +// density = 0 +// icon_state = "[initial(icon_state)]-broken" +// set_light(0) +// else +// to_chat(user, "You hit \the [src]!") +// playsound(get_turf(src),impact_sound, 75, 1) +// else +// if(prob(damage * 2)) +// to_chat(user, "You pulverize what was left of \the [src]!") +// qdel(src) +// else +// to_chat(user, "You hit \the [src]!") +// playsound(get_turf(src),impact_sound, 75, 1) -/obj/structure/cult/pylon/swarm/pylon_unique() - . = ..() +// /obj/structure/cult/pylon/swarm/pylon_unique() +// . = ..() - return . +// return . -/obj/structure/cult/pylon/swarm/zp_well - name = "Zero Point Well" - desc = "Infinite cosmic power, itty bitty usability." +// /obj/structure/cult/pylon/swarm/zp_well +// name = "Zero Point Well" +// desc = "Infinite cosmic power, itty bitty usability." - icon_state = "trap" +// icon_state = "trap" - description_info = "An infinitely small point in space that may or may not be used to supply power to some form of advanced machine." +// description_info = "An infinitely small point in space that may or may not be used to supply power to some form of advanced machine." - activation_cooldown = 0 // These things run constantly. +// activation_cooldown = 0 // These things run constantly. -/obj/structure/cult/pylon/swarm/zp_well/pylon_unique() - . = ..() +// /obj/structure/cult/pylon/swarm/zp_well/pylon_unique() +// . = ..() - for(var/mob/living/silicon/robot/drone/swarm/S in view(3, src)) - var/has_beam = FALSE - for(var/datum/beam_legacy/B in active_beams) - if(B.target == S) - has_beam = TRUE - break +// for(var/mob/living/silicon/robot/drone/swarm/S in view(3, src)) +// var/has_beam = FALSE +// for(var/datum/beam_legacy/B in active_beams) +// if(B.target == S) +// has_beam = TRUE +// break - if(!has_beam) - active_beams |= Beam(S,icon='icons/effects/beam.dmi',icon_state="holo_beam",time=3 SECONDS,maxdistance=3,beam_type = /obj/effect/ebeam) +// if(!has_beam) +// active_beams |= Beam(S,icon='icons/effects/beam.dmi',icon_state="holo_beam",time=3 SECONDS,maxdistance=3,beam_type = /obj/effect/ebeam) - if(S.cell) - S.cell.give(rand(5, 30)) +// if(S.cell) +// S.cell.give(rand(5, 30)) - . = TRUE +// . = TRUE - return . +// return . -/obj/structure/cult/pylon/swarm/defender - name = "Zero Point Wall" - desc = "Infinite cosmic power, itty bitty passability." +// /obj/structure/cult/pylon/swarm/defender +// name = "Zero Point Wall" +// desc = "Infinite cosmic power, itty bitty passability." - icon_state = "barricade" +// icon_state = "barricade" - description_info = "An infinitely small point in space spread upon infinitely many finitely-bounded points in space. Nice." +// description_info = "An infinitely small point in space spread upon infinitely many finitely-bounded points in space. Nice." -/obj/structure/cult/pylon/swarm/defender/pylonhit(var/damage) - if(!isbroken) - if(prob(1 + damage * 3) && round(damage * 0.8) >= 30) - visible_message("[shatter_message]") - STOP_PROCESSING(SSobj, src) - playsound(get_turf(src),shatter_sound, 75, 1) - isbroken = 1 - density = 0 - icon_state = "[initial(icon_state)]-broken" - set_light(0) +// /obj/structure/cult/pylon/swarm/defender/pylonhit(var/damage) +// if(!isbroken) +// if(prob(1 + damage * 3) && round(damage * 0.8) >= 30) +// visible_message("[shatter_message]") +// STOP_PROCESSING(SSobj, src) +// playsound(get_turf(src),shatter_sound, 75, 1) +// isbroken = 1 +// density = 0 +// icon_state = "[initial(icon_state)]-broken" +// set_light(0) -/obj/structure/cult/pylon/swarm/defender/attackpylon(mob/user as mob, var/damage) - if(!isbroken) - if(prob(1 + damage * 3) && round(damage * 0.8) >= 25) - user.visible_message( - "[user] smashed \the [src]!", - "You hit \the [src], and its crystal breaks apart!", - "You hear a tinkle of crystalline shards." - ) - STOP_PROCESSING(SSobj, src) - user.do_attack_animation(src) - playsound(get_turf(src),shatter_sound, 75, 1) - isbroken = 1 - density = 0 - icon_state = "[initial(icon_state)]-broken" - set_light(0) - else - to_chat(user, "You hit \the [src]!") - playsound(get_turf(src),impact_sound, 75, 1) - else - if(prob(damage * 2)) - to_chat(user, "You pulverize what was left of \the [src]!") - qdel(src) - else - to_chat(user, "You hit \the [src]!") - playsound(get_turf(src),impact_sound, 75, 1) +// /obj/structure/cult/pylon/swarm/defender/attackpylon(mob/user as mob, var/damage) +// if(!isbroken) +// if(prob(1 + damage * 3) && round(damage * 0.8) >= 25) +// user.visible_message( +// "[user] smashed \the [src]!", +// "You hit \the [src], and its crystal breaks apart!", +// "You hear a tinkle of crystalline shards." +// ) +// STOP_PROCESSING(SSobj, src) +// user.do_attack_animation(src) +// playsound(get_turf(src),shatter_sound, 75, 1) +// isbroken = 1 +// density = 0 +// icon_state = "[initial(icon_state)]-broken" +// set_light(0) +// else +// to_chat(user, "You hit \the [src]!") +// playsound(get_turf(src),impact_sound, 75, 1) +// else +// if(prob(damage * 2)) +// to_chat(user, "You pulverize what was left of \the [src]!") +// qdel(src) +// else +// to_chat(user, "You hit \the [src]!") +// playsound(get_turf(src),impact_sound, 75, 1) diff --git a/code/game/objects/structures/sandbag.dm b/code/game/objects/structures/sandbag.dm new file mode 100644 index 00000000000..d755c98dc6c --- /dev/null +++ b/code/game/objects/structures/sandbag.dm @@ -0,0 +1,61 @@ +/obj/structure/sandbag + name = "sandbag barricade" + desc = "A barrier made of stacked sandbags." + icon = 'icons/obj/structures/sandbags.dmi' + icon_state = "sandbags-0" + base_icon_state = "sandbags" + anchored = TRUE + density = TRUE + pass_flags_self = ATOM_PASS_TABLE | ATOM_PASS_THROWN | ATOM_PASS_CLICK + smoothing_flags = SMOOTH_BITMASK + smoothing_groups = (SMOOTH_GROUP_SANDBAGS) + canSmoothWith = (SMOOTH_GROUP_SANDBAGS) + integrity = 200 + integrity_max = 200 + + var/vestigial = TRUE + +/obj/structure/sandbag/Initialize(mapload) + . = ..() + for(var/obj/structure/sandbag/S in loc) + if(S != src) + break_to_parts(full_return = 1) + return + if(mapload) + return INITIALIZE_HINT_LATELOAD + else + //update_connections(TRUE) + update_icon() + +/obj/structure/sandbag/LateInitialize() + //update_connections(FALSE) + update_icon() + +/obj/structure/sandbag/Destroy() + //update_connections(TRUE) + . = ..() + +/obj/structure/sandbag/attackby(obj/item/W as obj, mob/user as mob) + user.setClickCooldownLegacy(user.get_attack_speed_legacy(W)) + if(istype(W, /obj/item/stack/sandbags)) + var/obj/item/stack/sandbags/S = W + if(integrity < integrity_max) + if(S.get_amount() < 1) + to_chat(user, "You need one sandbag to repair \the [src].") + return CLICKCHAIN_DO_NOT_PROPAGATE + visible_message("[user] begins to repair \the [src].") + if(do_after(user,20) && integrity < integrity_max) + if(S.use(1)) + integrity = integrity_max + visible_message("[user] repairs \the [src].") + return CLICKCHAIN_DO_NOT_PROPAGATE | CLICKCHAIN_DID_SOMETHING + return CLICKCHAIN_DO_NOT_PROPAGATE + return ..() + +/obj/structure/sandbag/proc/break_to_parts(full_return = 0) + if(full_return || prob(20)) + new /obj/item/stack/sandbags(src.loc) + else + new /obj/item/stack/material/cloth(src.loc) + new /obj/item/stack/ore/glass(src.loc) + qdel(src) diff --git a/code/game/objects/structures/windoor_assembly.dm b/code/game/objects/structures/windoor_assembly.dm index 9e55a20c580..0ef45cb18ea 100644 --- a/code/game/objects/structures/windoor_assembly.dm +++ b/code/game/objects/structures/windoor_assembly.dm @@ -77,8 +77,7 @@ update_state() /obj/structure/windoor_assembly/attack_robot(mob/living/silicon/robot/user) - if(Adjacent(user) && (user.module && (istype(user.module,/obj/item/robot_module/robot/engineering/general)) \ - || istype(user.module,/obj/item/robot_module/drone))) //Only dron (and engiborg) needs this. + if(Adjacent(user)) rename_door(user) /obj/structure/windoor_assembly/attackby(obj/item/W as obj, mob/user as mob) diff --git a/code/game/objects/systems/storage/storage-screen_object.dm b/code/game/objects/systems/storage/storage-screen_object.dm index 6edb28e0096..bebe29849a6 100644 --- a/code/game/objects/systems/storage/storage-screen_object.dm +++ b/code/game/objects/systems/storage/storage-screen_object.dm @@ -6,7 +6,7 @@ appearance_flags = APPEARANCE_UI | KEEP_TOGETHER | TILE_BOUND plane = HUD_PLANE layer = HUD_LAYER_STORAGE - icon = 'icons/screen/hud/common/storage.dmi' + icon = 'icons/screen/hud/styles/common/storage.dmi' /atom/movable/screen/storage/closer name = "close" diff --git a/code/game/objects/systems/storage/subtypes/stack.dm b/code/game/objects/systems/storage/subtypes/stack.dm index 1b6c90328f3..0de85f371cf 100644 --- a/code/game/objects/systems/storage/subtypes/stack.dm +++ b/code/game/objects/systems/storage/subtypes/stack.dm @@ -67,7 +67,7 @@ return ..() var/atom/indirection = real_contents_loc() for(var/obj/item/stack/other in indirection) - if(!stack.can_merge(other)) + if(!stack.can_merge_into(other)) continue other.add(stack.amount, TRUE) // this should delete the stack (?!) diff --git a/code/game/rendering/actor_huds/actor_hud-screen_object.dm b/code/game/rendering/actor_huds/actor_hud-screen_object.dm index eebdde11a45..fd7efc59807 100644 --- a/code/game/rendering/actor_huds/actor_hud-screen_object.dm +++ b/code/game/rendering/actor_huds/actor_hud-screen_object.dm @@ -5,9 +5,8 @@ * The screen objects for actor HUDs */ /atom/movable/screen/actor_hud - /// our owning actor hud - var/datum/actor_hud/inventory/hud + var/datum/actor_hud/hud /atom/movable/screen/actor_hud/Initialize(mapload, datum/actor_hud/inventory/hud) . = ..() diff --git a/code/game/rendering/actor_huds/actor_hud.dm b/code/game/rendering/actor_huds/actor_hud.dm index c9bca3642b9..5b95e6f5197 100644 --- a/code/game/rendering/actor_huds/actor_hud.dm +++ b/code/game/rendering/actor_huds/actor_hud.dm @@ -68,10 +68,14 @@ /** * syncs hud + * + * @return objects touched */ /datum/actor_hud/proc/sync_to_preferences(datum/hud_preferences/preference_set) - for(var/atom/movable/screen/screen_object in screens()) + var/list/atom/movable/screen/screens = screens() + for(var/atom/movable/screen/screen_object in screens) screen_object.sync_to_preferences(preference_set) + return screens /** * returns all screens we should apply to a client diff --git a/code/game/rendering/actor_huds/actor_hud_holder.dm b/code/game/rendering/actor_huds/actor_hud_holder.dm index 6fccda55890..ef5d09d5885 100644 --- a/code/game/rendering/actor_huds/actor_hud_holder.dm +++ b/code/game/rendering/actor_huds/actor_hud_holder.dm @@ -12,16 +12,20 @@ /// inventory hud var/datum/actor_hud/inventory/inventory + /// robot inventory hud + var/datum/actor_hud/robot_inventory/robot_inventory /datum/actor_hud_holder/New(client/C) // set owner owner = C // create huds inventory = new(src) + robot_inventory = new(src) /datum/actor_hud_holder/Destroy() // destroy huds QDEL_NULL(inventory) + QDEL_NULL(robot_inventory) // teardown owner owner = null // do rest @@ -31,20 +35,22 @@ * reset every hud to a mob */ /datum/actor_hud_holder/proc/bind_all_to_mob(mob/target) - inventory.bind_to_mob(target) + inventory?.bind_to_mob(target) + robot_inventory?.bind_to_mob(target) /** * syncs hud preferences */ /datum/actor_hud_holder/proc/sync_all_to_preferences(datum/hud_preferences/preference_set) inventory?.sync_to_preferences(preference_set) + robot_inventory?.sync_to_preferences(preference_set) /** * get all screens */ /datum/actor_hud_holder/proc/screens() . = list() - for(var/datum/actor_hud/hud as anything in all_huds()) + for(var/datum/actor_hud/hud in all_huds()) . += hud.screens() /** @@ -52,7 +58,7 @@ */ /datum/actor_hud_holder/proc/images() . = list() - for(var/datum/actor_hud/hud as anything in all_huds()) + for(var/datum/actor_hud/hud in all_huds()) . += hud.images() /** @@ -61,6 +67,7 @@ /datum/actor_hud_holder/proc/all_huds() return list( inventory, + robot_inventory, ) /** diff --git a/code/game/rendering/actor_huds/huds/inventory-screen_object.dm b/code/game/rendering/actor_huds/huds/inventory-screen_object.dm index 24474c4c565..6d0969af987 100644 --- a/code/game/rendering/actor_huds/huds/inventory-screen_object.dm +++ b/code/game/rendering/actor_huds/huds/inventory-screen_object.dm @@ -6,7 +6,7 @@ */ /atom/movable/screen/actor_hud/inventory name = "inventory" - icon = 'icons/screen/hud/midnight/inventory.dmi' + icon = 'icons/screen/hud/styles/midnight/inventory.dmi' plane = HUD_PLANE layer = HUD_LAYER_INVENTORY @@ -40,7 +40,7 @@ plane = HUD_ITEM_PLANE layer = HUD_ITEM_LAYER_BASE - var/self_icon = 'icons/screen/hud/midnight/inventory.dmi' + var/self_icon = 'icons/screen/hud/styles/midnight/inventory.dmi' var/self_icon_state = "" var/self_alpha = 255 var/self_color = "#ffffff" @@ -127,24 +127,38 @@ var/handcuffed = FALSE /// should we have the active overlay? var/active = FALSE + /// use robot icons? + var/use_robot_icons = FALSE -/atom/movable/screen/actor_hud/inventory/plate/hand/Initialize(mapload, datum/inventory/host, hand_index) - . = ..() +/atom/movable/screen/actor_hud/inventory/plate/hand/Initialize(mapload, datum/actor_hud/inventory/host, hand_index) src.hand_index = hand_index - sync_index(hand_index) + src.use_robot_icons = host.inv_held_items_use_robot_icon + . = ..() + sync_index(hand_index, host.inv_held_items_row_mode) update_icon() /atom/movable/screen/actor_hud/inventory/plate/hand/sync_style(datum/hud_style/style, style_alpha, style_color) - self_icon = style.inventory_icons + if(use_robot_icons) + self_icon = style.robot_icons + else + self_icon = style.inventory_icons ..() /atom/movable/screen/actor_hud/inventory/plate/hand/handle_inventory_click(mob/user, obj/item/with_item) - hud.owner.mob.swap_hand(hand_index) + var/datum/actor_hud/inventory/inventory_hud = hud + inventory_hud.owner.mob.swap_hand(hand_index) -/atom/movable/screen/actor_hud/inventory/plate/hand/proc/sync_index(index = hand_index) - screen_loc = SCREEN_LOC_MOB_HUD_INVENTORY_HAND(index) - name = "[index % 2? "left" : "right"] hand[index > 2? " #[index]" : ""]" - self_icon_state = "hand-[index % 2? "left" : "right"]" +/atom/movable/screen/actor_hud/inventory/plate/hand/proc/sync_index(index = hand_index, override_per_row = 2) + if(use_robot_icons) + name = "hand #[index]" + self_icon_state = "hand" + return + if(override_per_row == 2) + name = "[index % 2? "left" : "right"] hand[index > 2? " #[index]" : ""]" + self_icon_state = "hand-[index % 2? "left" : "right"]" + else + name = "hand" + self_icon_state = "hand-left" /atom/movable/screen/actor_hud/inventory/plate/hand/proc/set_handcuffed(state) if(state == handcuffed) @@ -167,12 +181,11 @@ add_overlay(active_image) /** - * Button: 'swap hand' + * Button: 'open inventory slots' */ /atom/movable/screen/actor_hud/inventory/drawer name = "drawer" icon_state = "drawer" - screen_loc = SCREEN_LOC_MOB_HUD_INVENTORY_DRAWER /atom/movable/screen/actor_hud/inventory/drawer/sync_style(datum/hud_style/style, style_alpha, style_color) ..() @@ -180,10 +193,12 @@ /atom/movable/screen/actor_hud/inventory/drawer/on_click(mob/user, list/params) // todo: remote control - hud.toggle_hidden_class(INVENTORY_HUD_CLASS_DRAWER, INVENTORY_HUD_HIDE_SOURCE_DRAWER) + var/datum/actor_hud/inventory/inventory_hud = hud + inventory_hud.toggle_hidden_class(INVENTORY_HUD_CLASS_DRAWER, INVENTORY_HUD_HIDE_SOURCE_DRAWER) /atom/movable/screen/actor_hud/inventory/drawer/update_icon_state() - icon_state = "[(INVENTORY_HUD_CLASS_DRAWER in hud.hidden_classes) ? "drawer" : "drawer-active"]" + var/datum/actor_hud/inventory/inventory_hud = hud + icon_state = "[(INVENTORY_HUD_CLASS_DRAWER in inventory_hud.hidden_classes) ? "drawer" : "drawer-active"]" return ..() /** @@ -194,8 +209,7 @@ icon_state = "hand-swap" /atom/movable/screen/actor_hud/inventory/swap_hand/Initialize(mapload, datum/inventory/host, hand_count) - . = ..() - screen_loc = SCREEN_LOC_MOB_HUD_INVENTORY_HAND_SWAP(hand_count) + return ..() /atom/movable/screen/actor_hud/inventory/swap_hand/sync_style(datum/hud_style/style, style_alpha, style_color) ..() @@ -213,8 +227,7 @@ icon_state = "button-equip" /atom/movable/screen/actor_hud/inventory/equip_hand/Initialize(mapload, datum/inventory/host, hand_count) - . = ..() - screen_loc = SCREEN_LOC_MOB_HUD_INVENTORY_EQUIP_HAND(hand_count) + return ..() /atom/movable/screen/actor_hud/inventory/equip_hand/sync_style(datum/hud_style/style, style_alpha, style_color) ..() diff --git a/code/game/rendering/actor_huds/huds/inventory.dm b/code/game/rendering/actor_huds/huds/inventory.dm index 3a3399efa59..fd0431d1733 100644 --- a/code/game/rendering/actor_huds/huds/inventory.dm +++ b/code/game/rendering/actor_huds/huds/inventory.dm @@ -1,20 +1,16 @@ //* This file is explicitly licensed under the MIT license. *// //* Copyright (c) 2024 Citadel Station Developers *// -/** - * Inventory slots specifically, not hands. - */ /datum/actor_hud/inventory /// owning inventory var/datum/inventory/host /// hidden classes, associated to list of reasons - var/list/hidden_classes = list( + var/tmp/list/hidden_classes = list( (INVENTORY_HUD_CLASS_DRAWER) = list( INVENTORY_HUD_HIDE_SOURCE_DRAWER, ), ) - /// keyed slot id to screen object var/list/atom/movable/screen/actor_hud/inventory/plate/slot/slots /// ordered hand objects @@ -29,16 +25,34 @@ /// equip object var/atom/movable/screen/actor_hud/inventory/equip_hand/button_equip_hand + + //* Imprinted by /datum/inventory *// + + /// render held items in row mode; no left/right semantics. + /// * this forces the number of hands in a row to this value + /// * will use 'hand' instead of 'hand-(left|right)' + var/tmp/inv_held_items_row_mode + /// suppress swap / equip buttons for hands + var/tmp/inv_held_items_suppress_buttons + /// use robot icons for hands + var/tmp/inv_held_items_use_robot_icon + /datum/actor_hud/inventory/sync_to_preferences(datum/hud_preferences/preference_set) var/old_active_hand = applied_active_hand set_active_hand(null) - . = ..() + + var/list/atom/movable/screen/screens = ..() + . = screens + + for(var/atom/movable/screen/actor_hud/actor_hud_object in screens) + host?.hud_object_post_sync(src, actor_hud_object) set_active_hand(old_active_hand) /datum/actor_hud/inventory/on_mob_bound(mob/target) // we don't have a hook for 'on inventory init', // so we can't init it lazily; we init it immediately. - target.init_inventory() + if(!target.inventory) + target.init_inventory() if(target.inventory) bind_to_inventory(target.inventory) return ..() @@ -52,6 +66,7 @@ ASSERT(!host) host = inventory LAZYADD(inventory.huds_using, src) + inventory.hud_alter(src) rebuild(inventory.build_inventory_slots_with_remappings(), length(inventory.held_items)) for(var/i in 1 to length(inventory.held_items)) if(!inventory.held_items[i]) @@ -121,9 +136,12 @@ cleanup() // buttons - add_screen((button_swap_hand = new(null, src, number_of_hands))) - add_screen((button_equip_hand = new(null, src, number_of_hands))) - add_screen((button_drawer = new(null, src))) + if(!inv_held_items_suppress_buttons) + add_screen((button_swap_hand = new(null, src, number_of_hands))) + add_screen((button_equip_hand = new(null, src, number_of_hands))) + if(length(inventory_slots_with_mappings)) + add_screen((button_drawer = new(null, src))) + button_drawer.screen_loc = screen_loc_for_slot_drawer() // slots rebuild_slots(inventory_slots_with_mappings) @@ -218,12 +236,13 @@ aligning.inventory_hud_main_axis = main_axis aligned += aligning + var/number_of_hands = host.get_hand_count() for(var/atom/movable/screen/actor_hud/inventory/plate/slot/slot_object as anything in aligned) switch(slot_object.inventory_hud_anchor) if(INVENTORY_HUD_ANCHOR_TO_DRAWER) - slot_object.screen_loc = SCREEN_LOC_MOB_HUD_INVENTORY_SLOT_DRAWER_ALIGNED(slot_object.inventory_hud_main_axis, slot_object.inventory_hud_cross_axis) + slot_object.screen_loc = screen_loc_for_drawer_aligned_slot(slot_object.inventory_hud_main_axis, slot_object.inventory_hud_cross_axis) if(INVENTORY_HUD_ANCHOR_TO_HANDS) - slot_object.screen_loc = SCREEN_LOC_MOB_HUD_INVENTORY_SLOT_HANDS_ALIGNED(slot_object.inventory_hud_main_axis, slot_object.inventory_hud_cross_axis) + slot_object.screen_loc = screen_loc_for_hand_aligned_slot(slot_object.inventory_hud_main_axis, slot_object.inventory_hud_cross_axis, number_of_hands) /** * Rebuilds our hands. Doesn't rebuild anything else. Doesn't wipe old objects. @@ -235,6 +254,7 @@ hands.len = number_of_hands for(var/i in old_length + 1 to number_of_hands) var/atom/movable/screen/actor_hud/inventory/plate/hand/hand_object = new(null, src, i) + hand_object.screen_loc = screen_loc_for_hand_index(i, number_of_hands) add_screen(hand_object) hands[i] = hand_object else if(length(hands) > number_of_hands) @@ -245,8 +265,46 @@ qdel(hands[i]) hands.len = number_of_hands - button_equip_hand?.screen_loc = SCREEN_LOC_MOB_HUD_INVENTORY_EQUIP_HAND(number_of_hands) - button_swap_hand?.screen_loc = SCREEN_LOC_MOB_HUD_INVENTORY_HAND_SWAP(number_of_hands) + button_equip_hand?.screen_loc = screen_loc_for_hand_equip(number_of_hands) + button_swap_hand?.screen_loc = screen_loc_for_hand_swap(number_of_hands) + +/datum/actor_hud/inventory/proc/screen_loc_for_hand_index(index, number_of_hands) + // -- THESE CALCULATIONS ASSUME THE INV SCREEN OBJECT IS A SINGLE WORLD TILE -- + var/per_row = inv_held_items_row_mode || min(2, number_of_hands) + // get half of the total width of the hand bar + var/half_total_width = (per_row) * WORLD_ICON_SIZE * 0.5 + // get row; this starts at 0 + var/row = ceil(index / per_row) - 1 + // get column; this starts at 0. + var/col = ((index - 1) % per_row) + return "CENTER:[-half_total_width + (col * WORLD_ICON_SIZE) + (WORLD_ICON_SIZE * 0.5)],BOTTOM+[row]:5" + +/datum/actor_hud/inventory/proc/screen_loc_for_hand_swap(number_of_hands) + // Always aligned to center of hands; bump up per row. + var/rows = max(1, ceil(number_of_hands / (inv_held_items_row_mode || 2))) + return "CENTER-1:28,BOTTOM+[rows]:5" + +/datum/actor_hud/inventory/proc/screen_loc_for_hand_equip(number_of_hands) + // Always aligned to center of hands. + var/rows = max(1, ceil(number_of_hands / (inv_held_items_row_mode || 2))) + return "CENTER-1:16,BOTTOM+[rows]:5" + +/datum/actor_hud/inventory/proc/screen_loc_for_slot_drawer() + // -- THESE CALCULATIONS ASSUME THE INV SCREEN OBJECT IS A SINGLE WORLD TILE -- + return "LEFT:6,BOTTOM:5" + +/datum/actor_hud/inventory/proc/screen_loc_for_drawer_aligned_slot(main, cross) + // -- THESE CALCULATIONS ASSUME THE INV SCREEN OBJECT IS A SINGLE WORLD TILE -- + return "LEFT+[cross]:[6 + (cross * 2)],BOTTOM+[main]:[5 + (main * 2)]" + +/datum/actor_hud/inventory/proc/screen_loc_for_hand_aligned_slot(main, cross, number_of_hands) + // -- THESE CALCULATIONS ASSUME THE INV SCREEN OBJECT IS A SINGLE WORLD TILE -- + // even if we only have 1 hand we pretend we have 2 + var/half_total_width = (inv_held_items_row_mode || 2) * WORLD_ICON_SIZE * 0.5 + if(main > 0) + return "CENTER-1:[half_total_width + (WORLD_ICON_SIZE * (main + 1)) - (WORLD_ICON_SIZE * 0.5)],BOTTOM+[cross]:[5 + (cross * 2)]" + else + return "CENTER-1:[-half_total_width + (WORLD_ICON_SIZE * main) + (WORLD_ICON_SIZE * 1.5)],BOTTOM+[cross]:[5 + (cross * 2)]" /** * @params @@ -288,6 +346,8 @@ if(button_drawer) . += button_drawer +//* Hidden Classes *// + /datum/actor_hud/inventory/proc/toggle_hidden_class(class, source) var/list/atom/movable/screen/actor_hud/inventory/affected var/something_changed @@ -350,10 +410,8 @@ screen_obj?.unbind_item(item) /datum/actor_hud/inventory/proc/move_item(obj/item/item, datum/inventory_slot/from_slot_or_index, datum/inventory_slot/to_slot_or_index) - var/atom/movable/screen/actor_hud/inventory/plate/old_screen_obj = isnum(from_slot_or_index) ? hands[from_slot_or_index] : slots[from_slot_or_index.id] - var/atom/movable/screen/actor_hud/inventory/plate/new_screen_obj = isnum(to_slot_or_index) ? hands[to_slot_or_index] : slots[to_slot_or_index.id] - old_screen_obj?.unbind_item(item) - new_screen_obj?.bind_item(item) + remove_item(item, from_slot_or_index) + add_item(item, to_slot_or_index) /datum/actor_hud/inventory/proc/swap_active_hand(from_index, to_index) set_active_hand(to_index) diff --git a/code/game/rendering/actor_huds/huds/robot_inventory-screen_object.dm b/code/game/rendering/actor_huds/huds/robot_inventory-screen_object.dm new file mode 100644 index 00000000000..48c02cecb14 --- /dev/null +++ b/code/game/rendering/actor_huds/huds/robot_inventory-screen_object.dm @@ -0,0 +1,194 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2025 Citadel Station Developers *// + +/** + * Base type of robot inventory screen objects. + */ +/atom/movable/screen/actor_hud/robot_inventory + name = "inventory" + plane = HUD_PLANE + layer = HUD_LAYER_INVENTORY + var/is_drawer = FALSE + +/atom/movable/screen/actor_hud/robot_inventory/on_click(mob/user, list/params) + if(is_drawer) + var/datum/actor_hud/robot_inventory/casted = hud + var/obj/item/held = user.get_active_held_item() + if(held && casted.host?.inv_is_registered(held)) + // will trigger the robot inventory grabbing the item + // INV_OP_FORCE because ermmmm no setting robot modules as nodrop!! + user.drop_item_to_ground(held, INV_OP_FORCE) + +/atom/movable/screen/actor_hud/robot_inventory/sync_to_preferences(datum/hud_preferences/preference_set) + sync_style(preference_set.hud_style, preference_set.hud_alpha, preference_set.hud_color) + +/atom/movable/screen/actor_hud/robot_inventory/proc/sync_style(datum/hud_style/style, style_alpha, style_color) + alpha = style_alpha + color = style_color + +/** + * Button: 'open / close robot modules' + * + * * The icon for this gets replaced with the robot's module if we're on an actual robot. + */ +/atom/movable/screen/actor_hud/robot_inventory/robot_drawer + name = "module drawer" + icon = 'icons/screen/hud/robot/default.dmi' + icon_state = "drawer" + is_drawer = TRUE + +/atom/movable/screen/actor_hud/robot_inventory/robot_drawer/sync_style(datum/hud_style/style, style_alpha, style_color) + ..() + icon = style.robot_icons + +/atom/movable/screen/actor_hud/robot_inventory/robot_drawer/on_click(mob/user, list/params) + // todo: remote control + var/datum/actor_hud/robot_inventory/inventory_hud = hud + inventory_hud.toggle_drawer() + +/** + * Backplate for robot modules inventory. + */ +/atom/movable/screen/actor_hud/robot_inventory/robot_drawer_backplate + mouse_opacity = MOUSE_OPACITY_TRANSPARENT + is_drawer = TRUE + + /// * FALSE: main axis is X, cross axis is Y + /// * TRUE: main axis is Y, cross axis is X + var/is_vertical + /// tile offset applied to main axis per iteration + var/main_axis_offset + /// max items in a 'row', basically + var/main_axis_max_size + /// tile offset applied to main axis per iteration + var/cross_axis_offset + /// alignment; this is something like 'NORTH' as string + var/first_tile_screen_ax + /// alignment; this is something like 'NORTH' as string + var/first_tile_screen_ay + /// tile; this is a number + var/first_tile_screen_tx + /// tile; this is a number + var/first_tile_screen_ty + /// pixel; this is a number + var/first_tile_screen_px + /// pixel; this is a number + var/first_tile_screen_py + + var/list/atom/movable/render/robot_drawer_item_render/renderers + +/atom/movable/screen/actor_hud/robot_inventory/robot_drawer_backplate/proc/redraw() + var/datum/actor_hud/robot_inventory/casted = hud + var/safety = 255 + if(casted.drawer_toggled) + // draw + // check if we actually need to rebuild renderers; this is needed if row count changes + // TODO: optimize this + var/requires_rebuild = TRUE + if(requires_rebuild) + LAZYINITLIST(renderers) + var/MAO = 0 // main axis offset + var/CAO = 0 // cross axis offset + var/MAC = 0 // main axis count + var/AMT = length(casted.host.provided_items) + if(AMT > safety) + AMT = safety + stack_trace("why the hell does a cyborg have more than 255 items?") + for(var/IDX in 1 to AMT) + if(MAC > main_axis_max_size) + CAO++ + MAO = 0 + MAC = 0 + // fetch or make a renderer + var/atom/movable/render/robot_drawer_item_render/renderer + if(IDX > length(renderers)) + renderer = new /atom/movable/render/robot_drawer_item_render(null, hud, src) + else + renderer = renderers[IDX] + // set its pixel loc as needed + // 0, 0 is ontop of us + if(is_vertical) + renderer.pixel_x = CAO * cross_axis_offset * WORLD_ICON_SIZE + renderer.pixel_y = MAO * main_axis_offset * WORLD_ICON_SIZE + else + renderer.pixel_x = MAO * main_axis_offset * WORLD_ICON_SIZE + renderer.pixel_y = CAO * cross_axis_offset * WORLD_ICON_SIZE + ++MAO + ++MAC + + var/x_r = first_tile_screen_tx > 0 ? "[first_tile_screen_tx]" : "-[first_tile_screen_tx]" + var/y_r = first_tile_screen_ty > 0 ? "[first_tile_screen_ty]" : "-[first_tile_screen_ty]" + screen_loc = "[first_tile_screen_ax][x_r]:[first_tile_screen_px],\ + [first_tile_screen_ay][y_r]:[first_tile_screen_py]" + // apply items + var/ridx = 1 + var/iidx = 1 + var/iidx_max = length(casted.host.provided_items) + var/ridx_max = length(renderers) + while(iidx < iidx_max && ridx < ridx_max) + var/atom/movable/render/robot_drawer_item_render/renderer = renderers[ridx] + ++iidx + var/obj/item/item = casted.host.provided_items[iidx] + if(item.inv_slot_or_index) + // active module, don't render + continue + if(renderer.masquarading_as != item) + renderer.masquarade(item) + ++ridx + for(ridx in ridx to ridx_max) + var/atom/movable/render/robot_drawer_item_render/renderer = renderers[ridx] + if(renderer.masquarading_as) + renderer.reset() + + src.invisibility = INVISIBILITY_NONE + else + // undraw + for(var/atom/movable/render/robot_drawer_item_render/renderer as anything in renderers) + renderer.reset() + src.invisibility = INVISIBILITY_ABSTRACT + +/** + * Item renderer + */ +/atom/movable/render/robot_drawer_item_render + name = "drawer" + icon = 'icons/screen/hud/styles/common/storage.dmi' + icon_state = "block" + mouse_opacity = MOUSE_OPACITY_ICON + var/atom/movable/screen/actor_hud/robot_inventory/robot_drawer_backplate/backplate + var/obj/item/masquarading_as + +/atom/movable/render/robot_drawer_item_render/Initialize( + mapload, + datum/actor_hud/robot_inventory/hud, + atom/movable/screen/actor_hud/robot_inventory/robot_drawer_backplate/backplate +) + . = ..() + src.backplate = backplate + src.backplate.vis_contents += src + src.backplate.renderers += src + reset() + +/atom/movable/render/robot_drawer_item_render/Destroy() + reset() + src.backplate.vis_contents -= src + src.backplate.renderers -= src + src.backplate = null + return ..() + +/atom/movable/render/robot_drawer_item_render/Click(location, control, params) + masquarading_as?.Click(arglist(args)) + +/atom/movable/render/robot_drawer_item_render/proc/masquarade(obj/item/render_as) + if(masquarading_as) + reset() + vis_contents += render_as + masquarading_as = render_as + name = render_as.name + alpha = initial(alpha) + +/atom/movable/render/robot_drawer_item_render/proc/reset() + vis_contents.len = 0 + masquarading_as = null + alpha = 0 + name = initial(name) diff --git a/code/game/rendering/actor_huds/huds/robot_inventory.dm b/code/game/rendering/actor_huds/huds/robot_inventory.dm new file mode 100644 index 00000000000..9c98542a1f0 --- /dev/null +++ b/code/game/rendering/actor_huds/huds/robot_inventory.dm @@ -0,0 +1,90 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2025 Citadel Station Developers *// + +/datum/actor_hud/robot_inventory + /// owning inventory + var/datum/robot_inventory/host + + /// is robot module inventory shown? + var/tmp/drawer_toggled = FALSE + /// robot drawer object, if any + var/atom/movable/screen/actor_hud/robot_inventory/robot_drawer/drawer_button + /// robot drawer backplate, if any + var/atom/movable/screen/actor_hud/robot_inventory/robot_drawer_backplate/drawer_backplate + +/datum/actor_hud/robot_inventory/on_mob_bound(mob/target) + if(isrobot(target)) + var/mob/living/silicon/robot/casted = target + if(casted.robot_inventory) + bind_to_inventory(casted.robot_inventory) + return ..() + +/datum/actor_hud/robot_inventory/on_mob_unbound(mob/target) + if(isrobot(target)) + var/mob/living/silicon/robot/casted = target + if(casted.robot_inventory) + unbind_from_inventory(casted.robot_inventory) + return ..() + +/datum/actor_hud/robot_inventory/proc/bind_to_inventory(datum/robot_inventory/robot_inventory) + ASSERT(!host) + host = robot_inventory + LAZYADD(robot_inventory.huds_using, src) + rebuild() + +/datum/actor_hud/robot_inventory/proc/unbind_from_inventory(datum/robot_inventory/robot_inventory) + ASSERT(host == robot_inventory) + cleanup() + LAZYREMOVE(robot_inventory.huds_using, src) + host = null + +/datum/actor_hud/robot_inventory/screens() + . = ..() + if(drawer_button) + . += drawer_button + if(drawer_backplate) + . += drawer_backplate + +/datum/actor_hud/robot_inventory/proc/cleanup() + remove_screen(drawer_backplate) + QDEL_NULL(drawer_backplate) + remove_screen(drawer_button) + QDEL_NULL(drawer_button) + +/datum/actor_hud/robot_inventory/proc/rebuild() + add_screen((drawer_button = new(null, src))) + drawer_button.screen_loc = screen_loc_for_drawer_button() + add_screen((drawer_backplate = new(null, src))) + set_drawer_backplate_parameters() + drawer_backplate.redraw() + +/datum/actor_hud/robot_inventory/proc/screen_loc_for_drawer_button() + // Always aligned to right side of hands, assuming a 3-wide hands + // TODO: can we auto-align based on the hands HUD? we'd need to do cascading re-renders.. + return "CENTER:64,BOTTOM:5" + +/datum/actor_hud/robot_inventory/proc/set_drawer_backplate_parameters() + drawer_backplate.first_tile_screen_ax = "LEFT+" + drawer_backplate.first_tile_screen_ay = "BOTTOM+" + drawer_backplate.first_tile_screen_tx = STORAGE_UI_START_TILE_X + drawer_backplate.first_tile_screen_ty = STORAGE_UI_START_TILE_Y + drawer_backplate.first_tile_screen_px = STORAGE_UI_START_PIXEL_X + drawer_backplate.first_tile_screen_py = STORAGE_UI_START_PIXEL_Y + drawer_backplate.is_vertical = FALSE + drawer_backplate.main_axis_max_size = 9 + drawer_backplate.main_axis_offset = 1 + drawer_backplate.cross_axis_offset = 1 + +/datum/actor_hud/robot_inventory/proc/all_screen_objects() + RETURN_TYPE(/list) + . = list() + if(drawer_button) + . += drawer_button + if(drawer_backplate) + . += drawer_backplate + +/datum/actor_hud/robot_inventory/proc/toggle_drawer() + drawer_toggled = !drawer_toggled + if(drawer_toggled && !drawer_backplate) + drawer_backplate = new + drawer_backplate?.redraw() diff --git a/code/game/rendering/hud_style.dm b/code/game/rendering/hud_style.dm index 58be182cf79..229c41d3a38 100644 --- a/code/game/rendering/hud_style.dm +++ b/code/game/rendering/hud_style.dm @@ -61,11 +61,13 @@ GLOBAL_LIST_INIT(hud_styles, init_hud_styles()) var/id /// inventory icons - var/inventory_icons = 'icons/screen/hud/midnight/inventory.dmi' + var/inventory_icons = 'icons/screen/hud/styles/midnight/inventory.dmi' /// inventory icons: slots - var/inventory_icons_slot = 'icons/screen/hud/midnight/inventory-slot.dmi' + var/inventory_icons_slot = 'icons/screen/hud/styles/midnight/inventory-slot.dmi' /// inventory icons: big - var/inventory_icons_wide = 'icons/screen/hud/midnight/inventory-wide.dmi' + var/inventory_icons_wide = 'icons/screen/hud/styles/midnight/inventory-wide.dmi' + /// robot icons + var/robot_icons = 'icons/screen/hud/robot/default.dmi' /** * midnight style just inherits defaults @@ -77,34 +79,35 @@ GLOBAL_LIST_INIT(hud_styles, init_hud_styles()) /datum/hud_style/orange name = "Orange" id = "orange" - inventory_icons = 'icons/screen/hud/orange/inventory.dmi' - inventory_icons_slot = 'icons/screen/hud/orange/inventory-slot.dmi' - inventory_icons_wide = 'icons/screen/hud/orange/inventory-wide.dmi' + inventory_icons = 'icons/screen/hud/styles/orange/inventory.dmi' + inventory_icons_slot = 'icons/screen/hud/styles/orange/inventory-slot.dmi' + inventory_icons_wide = 'icons/screen/hud/styles/orange/inventory-wide.dmi' /datum/hud_style/old name = "Retro" id = "old" - inventory_icons = 'icons/screen/hud/old/inventory.dmi' - inventory_icons_slot = 'icons/screen/hud/old/inventory-slot.dmi' - inventory_icons_wide = 'icons/screen/hud/old/inventory-wide.dmi' + inventory_icons = 'icons/screen/hud/styles/old/inventory.dmi' + inventory_icons_slot = 'icons/screen/hud/styles/old/inventory-slot.dmi' + inventory_icons_wide = 'icons/screen/hud/styles/old/inventory-wide.dmi' /datum/hud_style/white name = "White" id = "white" - inventory_icons = 'icons/screen/hud/white/inventory.dmi' - inventory_icons_slot = 'icons/screen/hud/white/inventory-slot.dmi' - inventory_icons_wide = 'icons/screen/hud/white/inventory-wide.dmi' + inventory_icons = 'icons/screen/hud/styles/white/inventory.dmi' + inventory_icons_slot = 'icons/screen/hud/styles/white/inventory-slot.dmi' + inventory_icons_wide = 'icons/screen/hud/styles/white/inventory-wide.dmi' /datum/hud_style/minimalist name = "Minimalist" id = "minimalist" - inventory_icons = 'icons/screen/hud/minimalist/inventory.dmi' - inventory_icons_slot = 'icons/screen/hud/minimalist/inventory-slot.dmi' - inventory_icons_wide = 'icons/screen/hud/minimalist/inventory-wide.dmi' + inventory_icons = 'icons/screen/hud/styles/minimalist/inventory.dmi' + inventory_icons_slot = 'icons/screen/hud/styles/minimalist/inventory-slot.dmi' + inventory_icons_wide = 'icons/screen/hud/styles/minimalist/inventory-wide.dmi' + robot_icons = 'icons/screen/hud/robot/minimalist.dmi' /datum/hud_style/hologram name = "Holographic" id = "hologram" - inventory_icons = 'icons/screen/hud/hologram/inventory.dmi' - inventory_icons_slot = 'icons/screen/hud/hologram/inventory-slot.dmi' - inventory_icons_wide = 'icons/screen/hud/hologram/inventory-wide.dmi' + inventory_icons = 'icons/screen/hud/styles/hologram/inventory.dmi' + inventory_icons_slot = 'icons/screen/hud/styles/hologram/inventory-slot.dmi' + inventory_icons_wide = 'icons/screen/hud/styles/hologram/inventory-wide.dmi' diff --git a/code/game/rendering/legacy/ghost.dm b/code/game/rendering/legacy/ghost.dm index aaba2cbb624..f7b5d59af92 100644 --- a/code/game/rendering/legacy/ghost.dm +++ b/code/game/rendering/legacy/ghost.dm @@ -1,5 +1,5 @@ /atom/movable/screen/ghost - icon = 'icons/screen/hud/common/observer.dmi' + icon = 'icons/screen/hud/styles/common/observer.dmi' /atom/movable/screen/ghost/MouseEntered(location,control,params) flick(icon_state + "_anim", src) diff --git a/code/game/rendering/legacy/robot.dm b/code/game/rendering/legacy/robot.dm index cc379e9311d..c81cedd9ff6 100644 --- a/code/game/rendering/legacy/robot.dm +++ b/code/game/rendering/legacy/robot.dm @@ -1,15 +1,4 @@ -var/atom/movable/screen/robot_inventory -/* -/mob/living/silicon/robot/instantiate_hud(var/datum/hud/HUD, var/ui_style, var/ui_color, var/ui_alpha) - HUD.robot_hud(ui_style, ui_color, ui_alpha, src)*/ - /datum/hud/proc/robot_hud(ui_style='icons/mob/screen1_robot.dmi', var/ui_color = "#ffffff", var/ui_alpha = 255, var/mob/living/silicon/robot/target) -/* var/datum/hud_data/hud_data - if(!istype(target)) - hud_data = new() - - if(hud_data.icon) - ui_style = hud_data.icon*/ if(ui_style == 'icons/mob/screen/minimalist.dmi') ui_style = 'icons/mob/screen1_robot_minimalist.dmi' @@ -33,46 +22,6 @@ var/atom/movable/screen/robot_inventory using.layer = HUD_LAYER_BASE src.adding += using -//Module select - - using = new /atom/movable/screen() - using.name = "module1" - using.setDir(SOUTHWEST) - using.icon = ui_style - using.color = ui_color - using.alpha = ui_alpha - using.icon_state = "inv1" - using.screen_loc = ui_inv1 - using.layer = HUD_LAYER_BASE - src.adding += using - mymob:inv1 = using - - using = new /atom/movable/screen() - using.name = "module2" - using.setDir(SOUTHWEST) - using.icon = ui_style - using.color = ui_color - using.alpha = ui_alpha - using.icon_state = "inv2" - using.screen_loc = ui_inv2 - using.layer = HUD_LAYER_BASE - src.adding += using - mymob:inv2 = using - - using = new /atom/movable/screen() - using.name = "module3" - using.setDir(SOUTHWEST) - using.icon = ui_style - using.color = ui_color - using.alpha = ui_alpha - using.icon_state = "inv3" - using.screen_loc = ui_inv3 - using.layer = HUD_LAYER_BASE - src.adding += using - mymob:inv3 = using - -//End of module select - //Intent using = new /atom/movable/screen() using.name = "act_intent" @@ -106,8 +55,8 @@ var/atom/movable/screen/robot_inventory //Installed Module mymob.hands = new /atom/movable/screen() - mymob.hands.icon = ui_style - mymob.hands.icon_state = "nomod" + mymob.hands.icon = 'icons/screen/hud/robot/modules.dmi' + mymob.hands.icon_state = "none" mymob.hands.alpha = ui_alpha mymob.hands.name = "module" mymob.hands.screen_loc = ui_borg_module @@ -123,26 +72,6 @@ var/atom/movable/screen/robot_inventory using.layer = HUD_LAYER_BASE-0.01 src.adding += using -//Store - mymob.throw_icon = new /atom/movable/screen() - mymob.throw_icon.icon = ui_style - mymob.throw_icon.icon_state = "store" - mymob.throw_icon.alpha = ui_alpha - mymob.throw_icon.color = ui_color - mymob.throw_icon.name = "store" - mymob.throw_icon.screen_loc = ui_borg_store - src.other += mymob.throw_icon - -//Inventory - robot_inventory = new /atom/movable/screen() - robot_inventory.name = "inventory" - robot_inventory.icon = ui_style - robot_inventory.icon_state = "inventory" - robot_inventory.alpha = ui_alpha - robot_inventory.color = ui_color - robot_inventory.screen_loc = ui_borg_inventory - src.other += robot_inventory - //Temp mymob.bodytemp = new /atom/movable/screen() mymob.bodytemp.icon_state = "temp0" @@ -196,91 +125,20 @@ var/atom/movable/screen/robot_inventory mymob.client.screen = list() - mymob.client.screen += list( mymob.throw_icon, mymob.zone_sel, mymob.oxygen, mymob.fire, mymob.hands, mymob.healths, using, mymob.pullin, robot_inventory, mymob.gun_setting_icon) - mymob.client.screen += src.adding + src.other + // this is just separated because this is legacy code and we want to know which line runtimes + mymob.client.screen += mymob.zone_sel + mymob.client.screen += mymob.oxygen + mymob.client.screen += mymob.fire + mymob.client.screen += mymob.hands + mymob.client.screen += mymob.healths + mymob.client.screen += using + mymob.client.screen += mymob.pullin + mymob.client.screen += mymob.gun_setting_icon + mymob.client.screen += src.adding + mymob.client.screen += src.other mymob.reload_rendering() -/datum/hud/proc/toggle_show_robot_modules() - if(!isrobot(mymob)) - return - - var/mob/living/silicon/robot/r = mymob - - r.shown_robot_modules = !r.shown_robot_modules - update_robot_modules_display() - - -/datum/hud/proc/update_robot_modules_display() - if(!isrobot(mymob)) - return - - var/mob/living/silicon/robot/r = mymob - - if(r.shown_robot_modules) - //Modules display is shown - //r.client.screen += robot_inventory //"store" icon - - if(!r.module) - to_chat(usr, "No module selected") - return - - if(!r.module.modules) - to_chat(usr, "Selected module has no modules to select") - return - - if(!r.robot_modules_background) - return - - var/display_rows = -round(-(r.module.modules.len) / 8) - r.robot_modules_background.screen_loc = "CENTER-4:16,SOUTH+1:7 to CENTER+3:16,SOUTH+[display_rows]:7" - r.client.screen += r.robot_modules_background - - var/x = -4 //Start at CENTER-4,SOUTH+1 - var/y = 1 - - //Unfortunately adding the emag module to the list of modules has to be here. This is because a borg can - //be emagged before they actually select a module. - or some situation can cause them to get a new module - // - or some situation might cause them to get de-emagged or something. - if(r.emagged || r.emag_items) - if(!(r.module.emag in r.module.modules)) - r.module.modules.Add(r.module.emag) - else - if(r.module.emag in r.module.modules) - r.module.modules.Remove(r.module.emag) - - for(var/atom/movable/A in r.module.modules) - if( (A != r.module_state_1) && (A != r.module_state_2) && (A != r.module_state_3) ) - //Module is not currently active - r.client.screen += A - if(x < 0) - A.screen_loc = "CENTER[x]:16,SOUTH+[y]:7" - else - A.screen_loc = "CENTER+[x]:16,SOUTH+[y]:7" - A.hud_layerise() - - x++ - if(x == 4) - x = -4 - y++ - - else - //Modules display is hidden - //r.client.screen -= robot_inventory //"store" icon - for(var/atom/A in r.module.modules) - if( (A != r.module_state_1) && (A != r.module_state_2) && (A != r.module_state_3) ) - //Module is not currently active - r.client.screen -= A - r.shown_robot_modules = 0 - r.client.screen -= r.robot_modules_background - /mob/living/silicon/robot/update_hud() - if(modtype) - hands.icon_state = lowertext(modtype) - ..() - -//! ## VR FILE MERGE ## !// -/mob/living/silicon/robot/update_hud() - if(modtype) - hands.icon_state = lowertext(modtype) + hands.icon_state = module ? module.module_hud_state : "none" ..() diff --git a/code/game/rendering/screen_legacy.dm b/code/game/rendering/screen_legacy.dm index d2df420bfce..5f43852ce12 100644 --- a/code/game/rendering/screen_legacy.dm +++ b/code/game/rendering/screen_legacy.dm @@ -184,47 +184,19 @@ if("module") if(isrobot(usr)) var/mob/living/silicon/robot/R = usr -// if(R.module) -// R.hud_used.toggle_show_robot_modules() -// return 1 - R.pick_module() - - if("inventory") - if(isrobot(usr)) - var/mob/living/silicon/robot/R = usr - if(R.module) - R.hud_used.toggle_show_robot_modules() - return 1 - else - to_chat(R, "You haven't selected a module yet.") + if(!R.module) + if(!R.can_repick_module) + to_chat(usr, SPAN_WARNING("You can't repick your module, despite not having one. \ + Something probably got bugged.")) + else + open_tgui_actor_modal( + /datum/tgui_actor_modal/robot_module_picker, + actor = new /datum/event_args/actor(R), + ) if("radio") if(issilicon(usr)) usr:radio_menu() - if("panel") - if(issilicon(usr)) - usr:installed_modules() - - if("store") - if(isrobot(usr)) - var/mob/living/silicon/robot/R = usr - if(R.module) - R.uneq_active() - R.hud_used.update_robot_modules_display() - else - to_chat(R, "You haven't selected a module yet.") - - if("module1") - if(istype(usr, /mob/living/silicon/robot)) - usr:toggle_module(1) - - if("module2") - if(istype(usr, /mob/living/silicon/robot)) - usr:toggle_module(2) - - if("module3") - if(istype(usr, /mob/living/silicon/robot)) - usr:toggle_module(3) if("AI Core") if(isAI(usr)) diff --git a/code/game/turfs/simulated.dm b/code/game/turfs/simulated.dm index b29d36150c3..e6d749ca064 100644 --- a/code/game/turfs/simulated.dm +++ b/code/game/turfs/simulated.dm @@ -131,7 +131,9 @@ bloodDNA = null if(src.wet) - process_slip(M) + spawn(0) + if(AM.loc == src) + process_slip(M) /turf/simulated/proc/process_slip(mob/living/M) if(M.buckled || (src.wet == 1 && M.m_intent == "walk")) diff --git a/code/game/verbs/character_directory.dm b/code/game/verbs/character_directory.dm index 4c87bf67456..c7e56c456c5 100644 --- a/code/game/verbs/character_directory.dm +++ b/code/game/verbs/character_directory.dm @@ -79,7 +79,7 @@ GLOBAL_DATUM(character_directory, /datum/character_directory) if(isrobot(C.mob)) var/mob/living/silicon/robot/R = C.mob - if(R.scrambledcodes || (R.module && R.module.hide_on_manifest)) + if(R.scrambledcodes || !R.module?.legacy_show_on_manifest) continue name = R.name species = "[R.modtype] [R.braintype]" diff --git a/code/global.dm b/code/global.dm index 81f893bb6e0..2292e958de6 100644 --- a/code/global.dm +++ b/code/global.dm @@ -25,21 +25,13 @@ var/game_year = (text2num(time2text(world.realtime, "YYYY")) + 544) var/master_mode = "extended" // "extended" var/secret_force_mode = "secret" // if this is anything but "secret", the secret rotation will forceably choose this mode. -var/host = null //only here until check @ code\modules\ghosttrap\trap.dm:112 is fixed - -var/list/jobMax = list() var/list/bombers = list() var/list/admin_log = list() var/list/lastsignalers = list() // Keeps last 100 signals here in format: "[src] used \ref[src] @ location [src.loc]: [freq]/[code]" var/list/lawchanges = list() // Stores who uploaded laws to which silicon-based lifeform, and what the law was. -var/list/reg_dna = list() var/mouse_respawn_time = 5 // Amount of time that must pass between a player dying as a mouse and repawning as a mouse. In minutes. -var/list/monkeystart = list() -var/list/wizardstart = list() -var/list/newplayer_start = list() - var/list/xeno_spawn = list() // Aliens spawn at at these. var/list/tdome1 = list() var/list/tdome2 = list() @@ -50,51 +42,21 @@ var/list/ninjastart = list() var/datum/configuration_legacy/config_legacy = null -var/list/combatlog = list() -var/list/IClog = list() -var/list/OOClog = list() -var/list/adminlog = list() - var/list/powernets = list() // TODO - Move into SSmachines var/gravity_is_on = 1 -var/join_motd = null - var/datum/legacy_metric/metric = new() // Metric datum, used to keep track of the round. var/list/awaydestinations = list() // Away missions. A list of landmarks that the warpgate can take you to. // For FTP requests. (i.e. downloading runtime logs.) // However it'd be ok to use for accessing attack logs and such too, which are even laggier. -var/fileaccess_timer = 0 var/custom_event_msg = null // Added for Xenoarchaeology, might be useful for other stuff. var/global/list/alphabet_uppercase = list("A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z") - -// Used by robots and robot preferences. -var/list/robot_module_types = list( - "Standard", - "Engineering", - "Medical", - "Miner", - "Janitor", - "Service", - "Clerical", - "Security", - "Research", - "Quadruped", - "MediQuad", - "SecuriQuad", - "JaniQuad", - "SciQuad", - "EngiQuad", - "Mining Quad", - "Service Quad" -) - // Some scary sounds. var/static/list/scarySounds = list( 'sound/weapons/thudswoosh.ogg', diff --git a/code/modules/actions/types/robot_upgrade_action.dm b/code/modules/actions/types/robot_upgrade_action.dm new file mode 100644 index 00000000000..8b4589a740f --- /dev/null +++ b/code/modules/actions/types/robot_upgrade_action.dm @@ -0,0 +1,24 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2024 Citadel Station Developers *// + +/datum/action/robot_upgrade_action + target_type = /obj/item + button_icon_state = null + + /// automatically set button_additional_overlay to the item, if button_icon_state is null + var/render_upgade_as_button = TRUE + +/datum/action/robot_upgrade_action/pre_render_hook() + if(render_upgade_as_button && isnull(button_icon_state)) + button_additional_only = TRUE + var/image/generated = new + generated.appearance = target + // i hope you are not doing custom layers and planes for icons, right gamers?? + generated.layer = FLOAT_LAYER + generated.plane = FLOAT_PLANE + button_additional_overlay = generated + return ..() + +/datum/action/robot_upgrade_action/calculate_availability() + var/obj/item/robot_upgrade/upgrade = target + return upgrade.owner ? (upgrade.owner.mobility_flags & check_mobility_flags ? 1 : 0) : 1 diff --git a/code/modules/asset_cache/assets/artwork/crayons.dm b/code/modules/asset_cache/assets/spritesheet/crayons.dm similarity index 100% rename from code/modules/asset_cache/assets/artwork/crayons.dm rename to code/modules/asset_cache/assets/spritesheet/crayons.dm diff --git a/code/modules/asset_cache/assets/materials.dm b/code/modules/asset_cache/assets/spritesheet/materials.dm similarity index 100% rename from code/modules/asset_cache/assets/materials.dm rename to code/modules/asset_cache/assets/spritesheet/materials.dm diff --git a/code/modules/awaymissions/loot_vr.dm b/code/modules/awaymissions/loot_vr.dm index 8598297ccda..a79eb0dad78 100644 --- a/code/modules/awaymissions/loot_vr.dm +++ b/code/modules/awaymissions/loot_vr.dm @@ -50,7 +50,7 @@ var/amount = rand(2,6) var/quantity = rand(10,50) var/list/possible_spawns = list() - for(var/bar_type in typesof(/obj/item/stack/material) - /obj/item/stack/material - /obj/item/stack/animalhide - typesof(/obj/item/stack/material/cyborg)) + for(var/bar_type in typesof(/obj/item/stack/material) - /obj/item/stack/material - /obj/item/stack/animalhide) possible_spawns += bar_type var/bar_type = pick(possible_spawns) diff --git a/code/modules/client/client-upload.dm b/code/modules/client/client-upload.dm index bb84d22b078..02587942c81 100644 --- a/code/modules/client/client-upload.dm +++ b/code/modules/client/client-upload.dm @@ -23,7 +23,9 @@ upload_mutex = TRUE upload_current_sizelimit = size_limit var/size_render = FLOOR(size_limit / (1024 * 1024), 0.05) + log_world("UPLOAD: Prompting '[src]' for a file with maximum size [size_limit].") . = input(src, message, "[title] (max [size_render]MiB)]") as file|null + log_world("UPLOAD: Got file '[.]' from '[src]'.") upload_current_sizelimit = null upload_mutex = FALSE @@ -37,7 +39,9 @@ upload_mutex = TRUE upload_current_sizelimit = size_limit var/size_render = FLOOR(size_limit / (1024 * 1024), 0.05) + log_world("UPLOAD: Prompting '[src]' for a file with maximum size [size_limit].") . = input(src, message, "[title] (max [size_render]MiB)]") as file|null + log_world("UPLOAD: Got file '[.]' from '[src]'.") upload_current_sizelimit = null upload_mutex = FALSE @@ -47,7 +51,9 @@ upload_mutex = TRUE upload_current_sizelimit = size_limit var/size_render = FLOOR(size_limit / (1024 * 1024), 0.05) + log_world("UPLOAD: Prompting '[src]' for a file with maximum size [size_limit].") . = input(src, message, "[title] (max [size_render]MiB)]") as sound|null + log_world("UPLOAD: Got file '[.]' from '[src]'.") upload_current_sizelimit = null upload_mutex = FALSE @@ -61,7 +67,9 @@ upload_mutex = TRUE upload_current_sizelimit = size_limit var/size_render = FLOOR(size_limit / (1024 * 1024), 0.05) + log_world("UPLOAD: Prompting '[src]' for a file with maximum size [size_limit].") . = input(src, message, "[title] (max [size_render]MiB)]") as sound|null + log_world("UPLOAD: Got file '[.]' from '[src]'.") upload_current_sizelimit = null upload_mutex = FALSE diff --git a/code/modules/events/event_dynamic.dm b/code/modules/events/event_dynamic.dm index a26ba164a10..c14f6e0afd1 100644 --- a/code/modules/events/event_dynamic.dm +++ b/code/modules/events/event_dynamic.dm @@ -172,18 +172,6 @@ var/list/event_last_fired = list() active_with_role["Any"]++ - if(istype(M, /mob/living/silicon/robot)) - var/mob/living/silicon/robot/R = M - if(R.module) - if(istype(R.module, /obj/item/robot_module/robot/engineering)) - active_with_role["Engineer"]++ - else if(istype(R.module, /obj/item/robot_module/robot/security)) - active_with_role["Security"]++ - else if(istype(R.module, /obj/item/robot_module/robot/medical)) - active_with_role["Medical"]++ - else if(istype(R.module, /obj/item/robot_module/robot/research)) - active_with_role["Scientist"]++ - if(M.mind.assigned_role in SSjob.get_job_titles_in_department(DEPARTMENT_ENGINEERING)) active_with_role["Engineer"]++ diff --git a/code/modules/events/fighter_attack.dm b/code/modules/events/fighter_attack.dm index 7d4334e2aed..c8e3c2100a4 100644 --- a/code/modules/events/fighter_attack.dm +++ b/code/modules/events/fighter_attack.dm @@ -32,6 +32,7 @@ /datum/event/fighter/end() // var/bandits_spawn = list() + // var/spawn_type = pick(bandits_spawn) // for(var/areapath in typesof(spawn_area_type)) // if(piratestring == "bandits") diff --git a/code/modules/examine/descriptions/mobs.dm b/code/modules/examine/descriptions/mobs.dm deleted file mode 100644 index 4d332631644..00000000000 --- a/code/modules/examine/descriptions/mobs.dm +++ /dev/null @@ -1,8 +0,0 @@ -/mob/living/silicon/robot/drone - description_info = "Drones are player-controlled synthetics which are lawed to maintain the station and not \ - interact with anyone else, except for other drones. They hold a wide array of tools to build, repair, maintain, and clean. \ - They function similarly to other synthetics, in that they require recharging regularly, have laws, and are resilient to many hazards, \ - such as fire, radiation, vacuum, and more. Ghosts can join the round as a maintenance drone by using the appropriate verb in the 'ghost' tab. \ - An inactive drone can be rebooted by swiping an ID card on it with engineering or robotics access, and an active drone can be shut down in the same manner." - - description_antag = "An Electromagnetic Sequencer can be used to subvert the drone to your cause." diff --git a/code/modules/examine/descriptions/stacks.dm b/code/modules/examine/descriptions/stacks.dm index 1f2b1085f22..e0539b3c86f 100644 --- a/code/modules/examine/descriptions/stacks.dm +++ b/code/modules/examine/descriptions/stacks.dm @@ -5,17 +5,5 @@ /obj/item/stack/material/glass description_info = "Use in your hand to build a window. Can be upgraded to reinforced glass by adding metal rods, which are made from metal sheets." -/obj/item/stack/material/cyborg/glass - description_info = "Use in your hand to build a window. Can be upgraded to reinforced glass by adding metal rods, which are made from metal sheets.
\ - As a synthetic, you can acquire more sheets of glass by recharging." - /obj/item/stack/material/glass/reinforced description_info = "Use in your hand to build a window. Reinforced glass is much stronger against damage." - -/obj/item/stack/material/cyborg/glass/reinforced - description_info = "Use in your hand to build a window. Reinforced glass is much stronger against damage.
\ - As a synthetic, you can gain more reinforced glass by recharging." - -/obj/item/stack/material/cyborg/steel - description_info = "Use in your hand to bring up the recipe menu. If you have enough sheets, click on something on the list to build it.
\ - You can replenish your supply of metal as a synthetic by recharging." diff --git a/code/modules/food/food/snacks.dm b/code/modules/food/food/snacks.dm index f5cbb885622..6dec4888639 100644 --- a/code/modules/food/food/snacks.dm +++ b/code/modules/food/food/snacks.dm @@ -227,7 +227,7 @@ var/confirm=input(user, "Are you certain you want to insert \the [W] into [src]?","Hide item") as null|anything in list("Yes","No") if(!confirm || confirm == "No") return - if (W.w_class >= w_class || is_robot_module(W)) + if (W.w_class >= w_class) return if(!user.attempt_insert_item_for_installation(W, src)) return diff --git a/code/modules/gamemaster/actions/swarmboarder.dm b/code/modules/gamemaster/actions/swarmboarder.dm index bcc145a3ecf..5666c56b721 100644 --- a/code/modules/gamemaster/actions/swarmboarder.dm +++ b/code/modules/gamemaster/actions/swarmboarder.dm @@ -1,73 +1,75 @@ -/datum/gm_action/swarm_boarder - name = "swarmer shell" - departments = list(DEPARTMENT_EVERYONE, DEPARTMENT_SECURITY, DEPARTMENT_ENGINEERING) - chaotic = 30 - observers_used = TRUE - var/area/target_area // Chosen target area - var/area/target_turf // Chosen target turf in target_area - var/list/area/excluded = list( - /area/submap, - /area/shuttle, - /area/crew_quarters, - /area/holodeck, - /area/engineering/engine_room - ) +// TODO: IOU swarmers - var/list/area/included = list( - /area/maintenance, - /area/main_map/maintenance - ) +// /datum/gm_action/swarm_boarder +// name = "swarmer shell" +// departments = list(DEPARTMENT_EVERYONE, DEPARTMENT_SECURITY, DEPARTMENT_ENGINEERING) +// chaotic = 30 +// observers_used = TRUE +// var/area/target_area // Chosen target area +// var/area/target_turf // Chosen target turf in target_area +// var/list/area/excluded = list( +// /area/submap, +// /area/shuttle, +// /area/crew_quarters, +// /area/holodeck, +// /area/engineering/engine_room +// ) -/datum/gm_action/swarm_boarder/set_up() - severity = pick_weight(mundande_weight = 30, moderate_weight = 10, major_weight = 1) +// var/list/area/included = list( +// /area/maintenance, +// /area/main_map/maintenance +// ) - var/list/area/grand_list_of_areas = get_station_areas(excluded) +// /datum/gm_action/swarm_boarder/set_up() +// severity = pick_weight(mundande_weight = 30, moderate_weight = 10, major_weight = 1) - for(var/area/Incl in included) - for(var/area/A in grand_list_of_areas) - if(!istype(A, Incl)) - grand_list_of_areas -= A +// var/list/area/grand_list_of_areas = get_station_areas(excluded) - // Okay, now lets try and pick a target! Lets try 10 times, otherwise give up - for(var/i in 1 to 10) - var/area/A = pick(grand_list_of_areas) - if(is_area_occupied(A)) - log_debug(SPAN_DEBUG("[name] event: Rejected [A] because it is occupied.")) - continue - // A good area, great! Lets try and pick a turf - var/list/turfs = list() - for(var/turf/simulated/floor/F in A) - if(turf_clear(F)) - turfs += F - if(turfs.len == 0) - log_debug(SPAN_DEBUG("[name] event: Rejected [A] because it has no clear turfs.")) - continue - target_area = A - target_turf = pick(turfs) +// for(var/area/Incl in included) +// for(var/area/A in grand_list_of_areas) +// if(!istype(A, Incl)) +// grand_list_of_areas -= A - if(!target_area) - log_debug(SPAN_DEBUG("[name] event: Giving up after too many failures to pick target area")) - return +// // Okay, now lets try and pick a target! Lets try 10 times, otherwise give up +// for(var/i in 1 to 10) +// var/area/A = pick(grand_list_of_areas) +// if(is_area_occupied(A)) +// log_debug(SPAN_DEBUG("[name] event: Rejected [A] because it is occupied.")) +// continue +// // A good area, great! Lets try and pick a turf +// var/list/turfs = list() +// for(var/turf/simulated/floor/F in A) +// if(turf_clear(F)) +// turfs += F +// if(turfs.len == 0) +// log_debug(SPAN_DEBUG("[name] event: Rejected [A] because it has no clear turfs.")) +// continue +// target_area = A +// target_turf = pick(turfs) -/datum/gm_action/swarm_boarder/start() - if(!target_turf) - return - ..() +// if(!target_area) +// log_debug(SPAN_DEBUG("[name] event: Giving up after too many failures to pick target area")) +// return - var/swarmertype = /obj/structure/ghost_pod/ghost_activated/swarm_drone/event +// /datum/gm_action/swarm_boarder/start() +// if(!target_turf) +// return +// ..() - if(severity == EVENT_LEVEL_MODERATE) - swarmertype = /obj/structure/ghost_pod/ghost_activated/swarm_drone/event/melee +// var/swarmertype = /obj/structure/ghost_pod/ghost_activated/swarm_drone/event - if(severity == EVENT_LEVEL_MAJOR) - swarmertype = /obj/structure/ghost_pod/ghost_activated/swarm_drone/event/gunner +// if(severity == EVENT_LEVEL_MODERATE) +// swarmertype = /obj/structure/ghost_pod/ghost_activated/swarm_drone/event/melee - new swarmertype(target_turf) +// if(severity == EVENT_LEVEL_MAJOR) +// swarmertype = /obj/structure/ghost_pod/ghost_activated/swarm_drone/event/gunner -/datum/gm_action/swarm_boarder/get_weight() - return -60 + (metric.count_people_in_department(DEPARTMENT_SECURITY) * 20 + metric.count_people_in_department(DEPARTMENT_SYNTHETIC) * 5 + metric.count_people_in_department(DEPARTMENT_EVERYONE) * 1) +// new swarmertype(target_turf) -/datum/gm_action/swarm_boarder/announce() - spawn(rand(5 MINUTES, 15 MINUTES)) - if(prob(80) && severity >= EVENT_LEVEL_MODERATE && SSlegacy_atc && !SSlegacy_atc.squelched) - SSlegacy_atc.msg("Attention civilian vessels in [(LEGACY_MAP_DATUM).starsys_name] shipping lanes, caution is advised as [pick("an unidentified vessel", "a known criminal's vessel", "a derelict vessel")] has been detected passing multiple local stations.") +// /datum/gm_action/swarm_boarder/get_weight() +// return -60 + (metric.count_people_in_department(DEPARTMENT_SECURITY) * 20 + metric.count_people_in_department(DEPARTMENT_SYNTHETIC) * 5 + metric.count_people_in_department(DEPARTMENT_EVERYONE) * 1) + +// /datum/gm_action/swarm_boarder/announce() +// spawn(rand(5 MINUTES, 15 MINUTES)) +// if(prob(80) && severity >= EVENT_LEVEL_MODERATE && SSlegacy_atc && !SSlegacy_atc.squelched) +// SSlegacy_atc.msg("Attention civilian vessels in [(LEGACY_MAP_DATUM).starsys_name] shipping lanes, caution is advised as [pick("an unidentified vessel", "a known criminal's vessel", "a derelict vessel")] has been detected passing multiple local stations.") diff --git a/code/modules/keybindings/keybind/robot.dm b/code/modules/keybindings/keybind/robot.dm index 43190828e7a..d8e084c05f3 100644 --- a/code/modules/keybindings/keybind/robot.dm +++ b/code/modules/keybindings/keybind/robot.dm @@ -12,8 +12,7 @@ description = "Equips or unequips the first module" /datum/keybinding/robot/moduleone/down(client/user) - var/mob/living/silicon/robot/R = user.mob - R.toggle_module(1) + user.mob?.swap_hand(user.mob.active_hand == 1 ? null : 1, TRUE) return TRUE /datum/keybinding/robot/moduletwo @@ -23,8 +22,7 @@ description = "Equips or unequips the second module" /datum/keybinding/robot/moduletwo/down(client/user) - var/mob/living/silicon/robot/R = user.mob - R.toggle_module(2) + user.mob?.swap_hand(user.mob.active_hand == 2 ? null : 2, TRUE) return TRUE /datum/keybinding/robot/modulethree @@ -34,8 +32,7 @@ description = "Equips or unequips the third module" /datum/keybinding/robot/modulethree/down(client/user) - var/mob/living/silicon/robot/R = user.mob - R.toggle_module(3) + user.mob?.swap_hand(user.mob.active_hand == 3 ? null : 3, TRUE) return TRUE /datum/keybinding/robot/intent_cycle @@ -57,5 +54,5 @@ /datum/keybinding/robot/unequip_module/down(client/user) var/mob/living/silicon/robot/R = user.mob - R.uneq_active() + R.drop_active_held_item() return TRUE diff --git a/code/modules/language/languages/silicons.dm b/code/modules/language/languages/silicons.dm index 97fe5a7e8e9..4ae03f3a4e9 100644 --- a/code/modules/language/languages/silicons.dm +++ b/code/modules/language/languages/silicons.dm @@ -55,7 +55,7 @@ if (isrobot(speaker)) var/mob/living/silicon/robot/R = speaker var/datum/robot_component/C = R.components["comms"] - R.cell_use_power(C.active_usage) + R.legacy_cell_use_power(C.active_usage) /datum/prototype/language/binary/drone id = LANGUAGE_ID_DRONE_BINARY diff --git a/code/modules/mapping/map_system/map-legacy-station.dm b/code/modules/mapping/map_system/map-legacy-station.dm index 18f905eeee7..81ecbabf88d 100644 --- a/code/modules/mapping/map_system/map-legacy-station.dm +++ b/code/modules/mapping/map_system/map-legacy-station.dm @@ -120,7 +120,7 @@ ), ) - var/default_law_type = /datum/ai_laws/nanotrasen // The default lawset use by synth units, if not overriden by their laws var. + var/default_law_type = /datum/ai_lawset/nanotrasen // The default lawset use by synth units, if not overriden by their laws var. // TODO: new map unit test system // Some maps include areas for that map only and don't exist when not compiled, so Travis needs this to learn of new areas that are specific to a map. diff --git a/code/modules/materials/definitions/metals/steel.dm b/code/modules/materials/definitions/metals/steel.dm index 872bd8a04b7..02936260b02 100644 --- a/code/modules/materials/definitions/metals/steel.dm +++ b/code/modules/materials/definitions/metals/steel.dm @@ -8,7 +8,6 @@ DECLARE_MATERIAL(/steel) icon = 'icons/materials/metals/steel.dmi' icon_stack_count = 3 - stack_type = /obj/item/stack/material/steel icon_base = 'icons/turf/walls/solid_wall.dmi' icon_reinf = 'icons/turf/walls/solid_wall_reinforced.dmi' icon_colour = "#666666" diff --git a/code/modules/materials/definitions/misc/cloths.dm b/code/modules/materials/definitions/misc/cloths.dm index 16a870b4608..c07b80def58 100644 --- a/code/modules/materials/definitions/misc/cloths.dm +++ b/code/modules/materials/definitions/misc/cloths.dm @@ -109,7 +109,7 @@ ) . += create_stack_recipe_datum( name = "empty sandbag", - product = /obj/item/stack/emptysandbag, + product = /obj/item/stack/sandbag/empty, cost = 2, amount = 5, time = 2 SECONDS, diff --git a/code/modules/materials/fifty_spawner_mats.dm b/code/modules/materials/fifty_spawner_mats.dm index 7215709619d..7299e98a0a1 100644 --- a/code/modules/materials/fifty_spawner_mats.dm +++ b/code/modules/materials/fifty_spawner_mats.dm @@ -160,7 +160,7 @@ //Sandbag port /obj/fiftyspawner/emptysandbag name = "stack of empty sandbags" - type_to_spawn = /obj/item/stack/emptysandbag + type_to_spawn = /obj/item/stack/sandbag/empty /obj/fiftyspawner/sandbags name = "stack of sandbags" diff --git a/code/modules/materials/material.dm b/code/modules/materials/material.dm index 776bacc34e1..a21fabaa4f7 100644 --- a/code/modules/materials/material.dm +++ b/code/modules/materials/material.dm @@ -8,6 +8,10 @@ //* Core *// /// Name for debugging purposes; not player-facing. var/name + /// Path to the material stack type that nominally represents us in-world + /// * While technically `/obj/item/stack/material` can become any material, we still want + /// to support custom behaviors if necessary. + var/stack_type = /obj/item/stack/material //* Identification *// /// Player-facing name. Always used. @@ -184,8 +188,6 @@ var/tableslam_noise = 'sound/weapons/tablehit1.ogg' /// Noise made when a simple door made of this material opens or closes. var/dooropen_noise = 'sound/effects/stonedoor_openclose.ogg' - /// Path to resulting stacktype. Todo remove need for this. - var/stack_type /// Wallrot crumble message. var/rotting_touch_message = "crumbles under your touch" @@ -221,7 +223,7 @@ target_stack.use(1) var/obj/item/stack/S = new rod_product(get_turf(user)) S.add_fingerprint(user) - S.add_to_stacks(user) + S.legacy_add_to_stacks_please_refactor_me(user) /datum/prototype/material/proc/build_wired_product(mob/living/user, obj/item/stack/used_stack, obj/item/stack/target_stack) if(!wire_product) diff --git a/code/modules/materials/material_synth.dm b/code/modules/materials/material_synth.dm deleted file mode 100644 index 8acd60ee9c2..00000000000 --- a/code/modules/materials/material_synth.dm +++ /dev/null @@ -1,45 +0,0 @@ -// These objects are used by cyborgs to get around a lot of the limitations on stacks -// and the weird bugs that crop up when expecting borg module code to behave sanely. -/obj/item/stack/material/cyborg - uses_charge = 1 - charge_costs = list(1000) - gender = NEUTER - -/obj/item/stack/material/cyborg/Initialize(mapload, new_amount, merge) - . = ..() - name = "[material.display_name] synthesizer" - desc = "A device that synthesises [material.display_name]." - -/obj/item/stack/material/cyborg/update_strings() - return - -/obj/item/stack/material/cyborg/plastic - icon_state = "sheet-plastic" - stack_type = /obj/item/stack/material/plastic - material = /datum/prototype/material/plastic - -/obj/item/stack/material/cyborg/steel - icon_state = "sheet-metal" - stack_type = /obj/item/stack/material/steel - material = /datum/prototype/material/steel - -/obj/item/stack/material/cyborg/plasteel - icon_state = "sheet-plasteel" - stack_type = /obj/item/stack/material/plasteel - material = /datum/prototype/material/plasteel - -/obj/item/stack/material/cyborg/wood - icon_state = "sheet-wood" - stack_type = /obj/item/stack/material/wood - material = /datum/prototype/material/wood_plank - -/obj/item/stack/material/cyborg/glass - icon_state = "sheet-glass" - stack_type = /obj/item/stack/material/glass - material = /datum/prototype/material/glass - -/obj/item/stack/material/cyborg/glass/reinforced - icon_state = "sheet-rglass" - stack_type = /obj/item/stack/material/glass/reinforced - material = /datum/prototype/material/glass/reinforced - charge_costs = list(500, 1000) diff --git a/code/modules/mining/machinery/sheet_silo.dm b/code/modules/mining/machinery/sheet_silo.dm index 0943b7bf0ec..48248067efc 100644 --- a/code/modules/mining/machinery/sheet_silo.dm +++ b/code/modules/mining/machinery/sheet_silo.dm @@ -50,8 +50,6 @@ return ..() /obj/machinery/sheet_silo/proc/take_sheets(obj/item/stack/material/sheets) - if(sheets.uses_charge) - return 0 var/mat_id = sheets.material.id var/mat_amount = sheets.amount . = mat_amount diff --git a/code/modules/mining/mine_turfs.dm b/code/modules/mining/mine_turfs.dm index 012df4f02ee..22485b6dc45 100644 --- a/code/modules/mining/mine_turfs.dm +++ b/code/modules/mining/mine_turfs.dm @@ -181,15 +181,6 @@ CREATE_STANDARD_TURFS(/turf/simulated/mineral/icerock/floor/ignore_cavegen) QUEUE_SMOOTH_NEIGHBORS(src) update_icon() -/turf/simulated/mineral/Entered(atom/movable/M as mob|obj) - ..() - if(istype(M,/mob/living/silicon/robot)) - var/mob/living/silicon/robot/R = M - if(R.module) - for(var/obj/item/storage/bag/ore/O in list(R.module_state_1, R.module_state_2, R.module_state_3)) - O.autoload(R) - return - /turf/simulated/mineral/Initialize(mapload) . = ..() if(prob(20)) @@ -300,8 +291,9 @@ CREATE_STANDARD_TURFS(/turf/simulated/mineral/icerock/floor/ignore_cavegen) else if(istype(AM,/mob/living/silicon/robot)) var/mob/living/silicon/robot/R = AM - if(istype(R.module_active,/obj/item/pickaxe)) - attackby(R.module_active,R) + var/obj/item/pickaxe/maybe_pickaxe = R.get_held_item_of_type(/obj/item/pickaxe) + if(maybe_pickaxe) + maybe_pickaxe.melee_interaction_chain(src, R) else if(istype(AM,/obj/vehicle/sealed/mecha)) var/obj/vehicle/sealed/mecha/M = AM diff --git a/code/modules/mining/tools/kinetic/kinetic_accelerator.dm b/code/modules/mining/tools/kinetic/kinetic_accelerator.dm index 8dd9469c99c..f27067d0bfc 100644 --- a/code/modules/mining/tools/kinetic/kinetic_accelerator.dm +++ b/code/modules/mining/tools/kinetic/kinetic_accelerator.dm @@ -266,8 +266,7 @@ icon = 'icons/obj/objects.dmi' icon_state = "modkit" w_class = WEIGHT_CLASS_SMALL - var/require_module = 1 - // module_type = list(/obj/item/robot_module/miner) + // module_type = list(/obj/item/robot_module_legacy/miner) var/denied_type = null var/maximum_of_type = 1 var/cost = 30 @@ -376,7 +375,7 @@ name = "minebot cooldown decrease" desc = "Decreases the cooldown of a kinetic accelerator. Only rated for minebot use." icon_state = "door_electronics" - icon = 'icons/obj/module.dmi' + icon = 'icons/items/circuits.dmi' denied_type = /obj/item/ka_modkit/cooldown/minebot modifier = 10 cost = 0 diff --git a/code/modules/mob/death.dm b/code/modules/mob/death.dm index a0d07ca2daa..08481a0cb33 100644 --- a/code/modules/mob/death.dm +++ b/code/modules/mob/death.dm @@ -59,7 +59,7 @@ /mob/proc/death(gibbed, deathmessage = "seizes up and falls limp...") if(stat == DEAD) return 0 - if(istype(loc, /obj/belly) || istype(loc, /obj/item/dogborg/sleeper)) + if(istype(loc, /obj/belly) || istype(loc, /obj/item/robot_builtin/dog_sleeper)) deathmessage = "no message" // Prevents death messages from inside mobs facing_dir = null diff --git a/code/modules/mob/health.dm b/code/modules/mob/health.dm index 9b1e6e49fe8..08e5a7e676f 100644 --- a/code/modules/mob/health.dm +++ b/code/modules/mob/health.dm @@ -47,11 +47,15 @@ else if(!was_dead && is_dead) living_mob_list -= src dead_mob_list += src + on_stat_change(old_stat, new_stat) if(update_mobility) update_mobility() update_hud_med_status() return TRUE +/mob/proc/on_stat_change(old_stat, new_stat) + return + /** * brings a mob back to life * diff --git a/code/modules/mob/inventory/humanoid/humanoid.dm b/code/modules/mob/inventory/humanoid/humanoid.dm new file mode 100644 index 00000000000..f6aeddf4e6d --- /dev/null +++ b/code/modules/mob/inventory/humanoid/humanoid.dm @@ -0,0 +1,4 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2025 Citadel Station Developers *// + +/datum/inventory/humanoid diff --git a/code/modules/mob/inventory/inventory-hands-legacy.dm b/code/modules/mob/inventory/inventory-hands-legacy.dm index 7ae4b731e44..4fa108c7d39 100644 --- a/code/modules/mob/inventory/inventory-hands-legacy.dm +++ b/code/modules/mob/inventory/inventory-hands-legacy.dm @@ -30,7 +30,9 @@ */ /mob/proc/get_active_held_item() RETURN_TYPE(/obj/item) - return inventory?.held_items?[active_hand] + if(active_hand < 1 || active_hand > length(inventory?.held_items)) + return null + return inventory.held_items[active_hand] /** * returns held item in inactive hand (or any inactive hand if more than 1) diff --git a/code/modules/mob/inventory/inventory-hands-put.dm b/code/modules/mob/inventory/inventory-hands-put.dm index 8f37258067f..cf55220b33c 100644 --- a/code/modules/mob/inventory/inventory-hands-put.dm +++ b/code/modules/mob/inventory/inventory-hands-put.dm @@ -34,7 +34,7 @@ if(!(inv_op_flags & INV_OP_NO_MERGE_STACKS) && istype(I, /obj/item/stack)) var/obj/item/stack/S = I for(var/obj/item/stack/held_stack in get_held_items()) - if(S.can_merge(held_stack) && S.merge(held_stack)) + if(S.can_merge_into(held_stack) && S.merge_into_other(held_stack)) to_chat(owner, SPAN_NOTICE("The [held_stack.name] in your hands now contains [held_stack.get_amount()] [held_stack.singular_name]\s.")) if(QDELETED(S)) return INV_RETURN_SUCCESS diff --git a/code/modules/mob/inventory/inventory-hooks.dm b/code/modules/mob/inventory/inventory-hooks.dm index 5db35f5f940..214e6319d5c 100644 --- a/code/modules/mob/inventory/inventory-hooks.dm +++ b/code/modules/mob/inventory/inventory-hooks.dm @@ -47,6 +47,10 @@ * As of right now, the functionality is equivalent; on_item_swapped() is just more efficient. */ /datum/inventory/proc/on_item_swapped(obj/item/item, datum/inventory_slot/from_slot_or_index, datum/inventory_slot/to_slot_or_index) + ASSERT(item.inv_inside == src) + if(item.inv_slot_or_index != isnum(from_slot_or_index) ? from_slot_or_index : from_slot_or_index.id) + stack_trace("slot mismatch in inventory itemswap hook") + item.inv_slot_or_index = isnum(to_slot_or_index) ? to_slot_or_index : to_slot_or_index.id SEND_SIGNAL(src, COMSIG_INVENTORY_ITEM_EXITED, from_slot_or_index) SEND_SIGNAL(src, COMSIG_INVENTORY_ITEM_ENTERED, to_slot_or_index) invalidate_cache() diff --git a/code/modules/mob/inventory/inventory-hud.dm b/code/modules/mob/inventory/inventory-hud.dm new file mode 100644 index 00000000000..050a8b12cce --- /dev/null +++ b/code/modules/mob/inventory/inventory-hud.dm @@ -0,0 +1,16 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2024 Citadel Station Developers *// + +/** + * Imprints our rendering behavior on an actor HUD + */ +/datum/inventory/proc/hud_alter(datum/actor_hud/inventory/hud) + hud.inv_held_items_row_mode = held_items_row_mode + hud.inv_held_items_suppress_buttons = held_items_suppress_buttons + hud.inv_held_items_use_robot_icon = held_items_use_robot_icon + +/** + * Modifies HUD object after syncing to preferences + */ +/datum/inventory/proc/hud_object_post_sync(datum/actor_hud/inventory/hud, atom/movable/screen/actor_hud/object) + return diff --git a/code/modules/mob/inventory/inventory-query.dm b/code/modules/mob/inventory/inventory-query.dm index aaf7e286d00..f907287b669 100644 --- a/code/modules/mob/inventory/inventory-query.dm +++ b/code/modules/mob/inventory/inventory-query.dm @@ -22,10 +22,10 @@ /datum/inventory/proc/trim_coverage_cache() if(length(cache) > 100) - cache.len = 100 + cache.Cut(1, 51) /datum/inventory/proc/invalidate_coverage_cache() - cache = list() + cache.len = 0 //* Siemens Coefficient *// @@ -49,7 +49,7 @@ /datum/inventory/proc/trim_simple_covered_siemens_coefficient_cache() if(length(cache) > 100) - cache.len = 100 + cache.Cut(1, 51) /datum/inventory/proc/invalidate_simple_covered_siemens_coefficient_cache() - cache = list() + cache.len = 0 diff --git a/code/modules/mob/inventory/inventory-slot-get.dm b/code/modules/mob/inventory/inventory-slot-get.dm index 5352e9ae5b4..357960c8e9e 100644 --- a/code/modules/mob/inventory/inventory-slot-get.dm +++ b/code/modules/mob/inventory/inventory-slot-get.dm @@ -8,14 +8,12 @@ * * For compound items, this only returns the outermost / host / root. * * @params - * * type_or_id - slot typepath or id + * * id - slot id * * @return /obj/item or null */ -/datum/inventory/proc/get_slot_single(datum/inventory_slot/type_or_id) as /obj/item - if(ispath(type_or_id)) - type_or_id = initial(type_or_id.id) - . = owner._item_by_slot(type_or_id) +/datum/inventory/proc/get_slot_single(id) as /obj/item + . = owner._item_by_slot(id) if(. == INVENTORY_SLOT_DOES_NOT_EXIST) return null @@ -26,14 +24,12 @@ * * If multiple items are compounded on one item (e.g. clothing accessories), this gets all of them. * * @params - * * type_or_id - slot typepath or id + * * id - slot id * * @return list() of items */ -/datum/inventory/proc/get_slot(datum/inventory_slot/type_or_id) as /list - if(ispath(type_or_id)) - type_or_id = initial(type_or_id.id) - var/obj/item/in_slot = owner._item_by_slot(type_or_id) +/datum/inventory/proc/get_slot(id) as /list + var/obj/item/in_slot = owner._item_by_slot(id) if(in_slot == INVENTORY_SLOT_DOES_NOT_EXIST) return if(in_slot) @@ -60,11 +56,11 @@ * * @return list() of items */ -/datum/inventory/proc/get_slots_unsafe(list/types_or_ids, compound) as /list +/datum/inventory/proc/get_slots_unsafe(list/ids, compound) as /list + SHOULD_NOT_OVERRIDE(TRUE) + SHOULD_NOT_SLEEP(TRUE) . = list() - for(var/datum/inventory_slot/slot_id as anything in types_or_ids || base_inventory_slots) + for(var/datum/inventory_slot/slot_id as anything in ids || base_inventory_slots) if(ispath(slot_id)) slot_id = initial(slot_id.id) - var/obj/item/fetched = owner._item_by_slot(slot_id) - if(istype(fetched)) - . += compound ? fetched.inv_slot_attached() : fetched + . += compound ? get_slot(slot_id) : get_slot_single(slot_id) diff --git a/code/modules/mob/inventory/inventory.dm b/code/modules/mob/inventory/inventory.dm index a7f83ac4f5e..7c68e5d4906 100644 --- a/code/modules/mob/inventory/inventory.dm +++ b/code/modules/mob/inventory/inventory.dm @@ -2,14 +2,22 @@ //* Copyright (c) 2024 Citadel Station Developers *// /** - * mob inventory data goes in here. + * # Inventory * - * * this does not include hands; that's handled mob-side. - * * this only includes inventory slots. + * Mob inventory is handled by inventory datums, which hold logic for: + * * Slots + * * Hands + * * Robot modules + * + * TODO: /datum/inventory_hud_style for overrides, instead of a bazillion held_items_xyz vars for robots. + * This is also important for things like occult mobs later. */ /datum/inventory //* Basics *// - /// owning mob, if any + + /// owning mob + /// * This must be set, it doens't make sense to have an inventory + /// that doesn't have an owner. var/mob/owner //* Actions *// @@ -22,18 +30,26 @@ //* HUDs *// /// Actor HUDs using us - /// /// * Lazy list var/list/datum/actor_hud/inventory/huds_using //* Inventory *// /// held items - /// /// * empty indices are null /// * this is also our rendered & nominal hand count /// * 1, 3, 5, ... are left /// * 2, 4, 6, ... are right var/list/obj/item/held_items = list() + /// held items are rendered with this many on one row + /// * if set, we will not apply default left/right hand semantics! + /// * as num | null + var/held_items_row_mode = null + /// suppress 'swap' and 'equip' and other hand slot buttons + /// * used for robot module support + var/held_items_suppress_buttons = FALSE + /// use robot module icons? + /// * used for robot support + var/held_items_use_robot_icon = FALSE //* Rendering *// /// cached overlays by slot id or hand index diff --git a/code/modules/mob/inventory/robot/robot.dm b/code/modules/mob/inventory/robot/robot.dm new file mode 100644 index 00000000000..55552f41360 --- /dev/null +++ b/code/modules/mob/inventory/robot/robot.dm @@ -0,0 +1,18 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2025 Citadel Station Developers *// + +/datum/inventory/robot + held_items_row_mode = 3 + held_items_suppress_buttons = TRUE + held_items_use_robot_icon = TRUE + +// TODO: overriding this is a little bad but what the fuck ever man we'll have another inventory rewrite soon +/datum/inventory/robot/put_in_hand(obj/item/I, index, inv_op_flags) + if(inv_op_flags & INV_OP_FORCE) + return ..() + var/mob/living/silicon/robot/maybe_robot = owner + if(!istype(maybe_robot)) + return ..() + if(!(I in maybe_robot.robot_inventory?.provided_items)) + return FALSE + return ..() diff --git a/code/modules/mob/living/carbon/brain/MMI.dm b/code/modules/mob/living/carbon/brain/MMI.dm index 27480d2384e..9dab67acaa9 100644 --- a/code/modules/mob/living/carbon/brain/MMI.dm +++ b/code/modules/mob/living/carbon/brain/MMI.dm @@ -299,7 +299,7 @@ name = "robotic intelligence circuit" desc = "The pinnacle of artifical intelligence which can be achieved using classical computer science." catalogue_data = list(/datum/category_item/catalogue/technology/drone/drones) - icon = 'icons/obj/module.dmi' + icon = 'icons/items/circuits.dmi' icon_state = "mainboard" w_class = WEIGHT_CLASS_NORMAL origin_tech = list(TECH_ENGINEERING = 4, TECH_MATERIAL = 3, TECH_DATA = 4) @@ -371,7 +371,7 @@ /obj/item/mmi/inert/ai_remote name = "\improper AI remote interface" desc = "A sophisticated board which allows for an artificial intelligence to remotely control a synthetic chassis." - icon = 'icons/obj/module.dmi' + icon = 'icons/items/circuits.dmi' icon_state = "mainboard" w_class = WEIGHT_CLASS_NORMAL origin_tech = list(TECH_ENGINEERING = 2, TECH_MATERIAL = 2, TECH_BLUESPACE = 2, TECH_DATA = 3) diff --git a/code/modules/mob/living/carbon/brain/brain.dm b/code/modules/mob/living/carbon/brain/brain.dm index 060867ff097..5e7c6225305 100644 --- a/code/modules/mob/living/carbon/brain/brain.dm +++ b/code/modules/mob/living/carbon/brain/brain.dm @@ -43,6 +43,7 @@ icon_state = "brain1" no_vore = TRUE emote_class = NONE + inventory = null catalogue_data = list(/datum/category_item/catalogue/fauna/brain/organic) /mob/living/carbon/brain/Initialize(mapload) @@ -58,9 +59,6 @@ ghostize() //Ghostize checks for key so nothing else is necessary. return ..() -/mob/living/carbon/brain/init_inventory() - return - /mob/living/carbon/brain/update_mobility(blocked, forced) if(in_contents_of(/obj/vehicle/sealed/mecha) || istype(loc, /obj/item/mmi)) . = ..(blocked, forced) diff --git a/code/modules/mob/living/carbon/brain/robot.dm b/code/modules/mob/living/carbon/brain/robot.dm index ee59851c0a2..bef4ab5af2f 100644 --- a/code/modules/mob/living/carbon/brain/robot.dm +++ b/code/modules/mob/living/carbon/brain/robot.dm @@ -10,7 +10,7 @@ /obj/item/mmi/digital/robot name = "robotic intelligence circuit" desc = "The pinnacle of artifical intelligence which can be achieved using classical computer science." - icon = 'icons/obj/module.dmi' + icon = 'icons/items/circuits.dmi' icon_state = "mainboard" w_class = WEIGHT_CLASS_NORMAL origin_tech = list(TECH_ENGINEERING = 4, TECH_MATERIAL = 3, TECH_DATA = 4) diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 9ee459af32a..16d3584e111 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -1,4 +1,5 @@ /mob/living/carbon + inventory = /datum/inventory/humanoid emote_class = EMOTE_CLASS_IS_BODY | EMOTE_CLASS_IS_HUMANOID //* Organs, Reagents, Biologies *// @@ -31,9 +32,9 @@ return ..() /mob/living/carbon/init_inventory() - if(inventory) + ..() + if(!inventory) return - inventory = new(src) inventory.set_hand_count(2) if(species) // todo: sigh we need to talk about init order; this shouldn't be needed inventory.set_inventory_slots(species.inventory_slots) diff --git a/code/modules/mob/living/carbon/human/human-damage-legacy.dm b/code/modules/mob/living/carbon/human/human-damage-legacy.dm index 2fee115f3f4..8cc7792429b 100644 --- a/code/modules/mob/living/carbon/human/human-damage-legacy.dm +++ b/code/modules/mob/living/carbon/human/human-damage-legacy.dm @@ -358,7 +358,7 @@ This function restores all organs. if((damagetype != DAMAGE_TYPE_BRUTE) && (damagetype != DAMAGE_TYPE_BURN)) if(damagetype == DAMAGE_TYPE_HALLOSS) if((damage > 25 && prob(20)) || (damage > 50 && prob(60))) - if(organ && organ.organ_can_feel_pain() && !isbelly(loc) && !istype(loc, /obj/item/dogborg/sleeper)) + if(organ && organ.organ_can_feel_pain() && !isbelly(loc) && !istype(loc, /obj/item/robot_builtin/dog_sleeper)) emote_nosleep("scream") ..(damage, damagetype, def_zone, blocked, soaked) return 1 diff --git a/code/modules/mob/living/living-defense-legacy.dm b/code/modules/mob/living/living-defense-legacy.dm index 1dea378ecdf..0bac83b74bb 100644 --- a/code/modules/mob/living/living-defense-legacy.dm +++ b/code/modules/mob/living/living-defense-legacy.dm @@ -154,7 +154,6 @@ // src.anchored = 1 // src.pinned += O - // /mob/living/proc/embed(var/obj/O, var/def_zone=null) // O.loc = src // src.embedded += O diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm index bc8e0ebe4d3..b9622b5492b 100644 --- a/code/modules/mob/living/silicon/ai/ai.dm +++ b/code/modules/mob/living/silicon/ai/ai.dm @@ -140,7 +140,7 @@ var/list/ai_verbs_default = list( remove_verb(src, ai_verbs_default) remove_verb(src, silicon_subsystems) -/mob/living/silicon/ai/Initialize(mapload, datum/ai_laws/L, obj/item/mmi/B, safety = TRUE) +/mob/living/silicon/ai/Initialize(mapload, datum/ai_lawset/L, obj/item/mmi/B, safety = TRUE) announcement = new() announcement.title = "A.I. Announcement" announcement.announcement_type = "A.I. Announcement" @@ -166,7 +166,7 @@ var/list/ai_verbs_default = list( aiCommunicator = new /obj/item/communicator/integrated(src) if(L) - if (istype(L, /datum/ai_laws)) + if (istype(L, /datum/ai_lawset)) laws = L else var/datum/map/station/loaded = (LEGACY_MAP_DATUM) @@ -276,24 +276,6 @@ var/list/ai_verbs_default = list( /mob/living/silicon/ai/proc/setup_icon() - var/file = file2text("config/custom_sprites.txt") - var/lines = splittext(file, "\n") - - for(var/line in lines) - // split & clean up - var/list/Entry = splittext(line, ":") - for(var/i = 1 to Entry.len) - Entry[i] = trim(Entry[i]) - - if(Entry.len < 2) - continue; - - if(Entry[1] == src.ckey && Entry[2] == src.real_name) - icon = CUSTOM_ITEM_SYNTH - custom_sprite = 1 - selected_sprite = new/datum/ai_icon("Custom", "[src.ckey]-ai", "4", "[ckey]-ai-crash", "#FFFFFF", "#FFFFFF", "#FFFFFF") - else - selected_sprite = default_ai_icon updateicon() /mob/living/silicon/ai/pointed(atom/A as mob|obj|turf in view()) diff --git a/code/modules/mob/living/silicon/ai_law.dm b/code/modules/mob/living/silicon/ai_law.dm new file mode 100644 index 00000000000..a4be6dd6098 --- /dev/null +++ b/code/modules/mob/living/silicon/ai_law.dm @@ -0,0 +1,46 @@ +/datum/ai_law + var/law = "" + var/index = 0 + +/datum/ai_law/New(law, index) + src.law = law + src.index = index + +/datum/ai_law/proc/get_index() + return index + +/datum/ai_law/ion/get_index() + return ionnum() + +/datum/ai_law/zero/get_index() + return 0 + +/datum/ai_law/proc/get_state_law(var/datum/ai_lawset/laws) + +/datum/ai_law/zero/get_state_law(var/datum/ai_lawset/laws) + if(src == laws.zeroth_law) + return laws.state_zeroth + +/datum/ai_law/ion/get_state_law(var/datum/ai_lawset/laws) + return laws.get_state_internal(laws.ion_laws, laws.state_ion, src) + +/datum/ai_law/inherent/get_state_law(var/datum/ai_lawset/laws) + return laws.get_state_internal(laws.inherent_laws, laws.state_inherent, src) + +/datum/ai_law/supplied/get_state_law(var/datum/ai_lawset/laws) + return laws.get_state_internal(laws.supplied_laws, laws.state_supplied, src) + +/datum/ai_law/proc/set_state_law(var/datum/ai_lawset/law, var/state) + +/datum/ai_law/zero/set_state_law(var/datum/ai_lawset/laws, var/state) + if(src == laws.zeroth_law) + laws.state_zeroth = state + +/datum/ai_law/ion/set_state_law(var/datum/ai_lawset/laws, var/state) + laws.set_state_law_internal(laws.ion_laws, laws.state_ion, src, state) + +/datum/ai_law/inherent/set_state_law(var/datum/ai_lawset/laws, var/state) + laws.set_state_law_internal(laws.inherent_laws, laws.state_inherent, src, state) + +/datum/ai_law/supplied/set_state_law(var/datum/ai_lawset/laws, var/state) + laws.set_state_law_internal(laws.supplied_laws, laws.state_supplied, src, state) diff --git a/code/modules/mob/living/silicon/ai_laws.dm b/code/modules/mob/living/silicon/ai_laws.dm new file mode 100644 index 00000000000..ada6391e664 --- /dev/null +++ b/code/modules/mob/living/silicon/ai_laws.dm @@ -0,0 +1,13 @@ +var/global/const/base_law_type = /datum/ai_lawset/nanotrasen + +/mob/living/silicon/proc/sync_zeroth(var/datum/ai_law/zeroth_law, var/datum/ai_law/zeroth_law_borg) + if (!is_malf_or_traitor(src)) + if(zeroth_law_borg) + laws.set_zeroth_law(zeroth_law_borg.law) + else if(zeroth_law) + laws.set_zeroth_law(zeroth_law.law) + +/mob/living/silicon/ai/sync_zeroth(var/datum/ai_law/zeroth_law, var/datum/ai_law/zeroth_law_borg) + if(zeroth_law) + laws.set_zeroth_law(zeroth_law.law, zeroth_law_borg ? zeroth_law_borg.law : null) + diff --git a/code/modules/mob/living/silicon/ai_lawset.dm b/code/modules/mob/living/silicon/ai_lawset.dm new file mode 100644 index 00000000000..fd001ab3098 --- /dev/null +++ b/code/modules/mob/living/silicon/ai_lawset.dm @@ -0,0 +1,288 @@ +/** + * Represents an AI lawset + * + * * These are not /prototype's; copies are held for silicon mobs. + * They are stored by value, as there's little need to have a massive amount of + * 'static' lawsets floating around in the game's data repositories. + * * This does mean that storing too many copies of these is a memory drain. + * If the need arises, a `/datum/prototype/ai_lawset_preset` might be made + * to hold things.. + * + * There's a few categories of laws. + * They're more or less just a priority system. From highest to lowest priority; + * + * * Zeroth - this is just a 'you are an antagonist, you don't follow law' with fluff wording. + * * Ion - these are injected by special events and whatnot + * * Inherent - these are core laws that come before supplied laws. + * * Supplied - these are additional laws that go below core laws. + */ +/datum/ai_lawset + /// Our in-code name. + var/name = "unknown lawset" + /// Our player-facing name. [name] will be used if this is not set. + var/display_name + +/datum/ai_lawset/proc/append_ion_law(datum/ai_law/law_datum_or_text) + var/next_index = length(ion_laws) + 1 + if(!istype(law_datum_or_text)) + law_datum_or_text = new /datum/ai_law(law_datum_or_text) + law_datum_or_text.index = next_index + if(law_datum_or_text in ion_laws) + return FALSE + ion_laws += law_datum_or_text + return TRUE + +/datum/ai_lawset/proc/append_inherent_law(datum/ai_law/law_datum_or_text) + var/next_index = length(inherent_laws) + 1 + if(!istype(law_datum_or_text)) + law_datum_or_text = new /datum/ai_law(law_datum_or_text) + law_datum_or_text.index = next_index + if(law_datum_or_text in inherent_laws) + return FALSE + inherent_laws += law_datum_or_text + return TRUE + +/datum/ai_lawset/proc/append_supplied_law(datum/ai_law/law_datum_or_text) + var/next_index = length(supplied_laws) + 1 + if(!istype(law_datum_or_text)) + law_datum_or_text = new /datum/ai_law(law_datum_or_text) + law_datum_or_text.index = next_index + if(law_datum_or_text in supplied_laws) + return FALSE + supplied_laws += law_datum_or_text + return TRUE + +//! legacy below +/datum/ai_lawset + var/law_header = "Prime Directives" + var/selectable = 0 + var/datum/ai_law/zero/zeroth_law = null + var/datum/ai_law/zero/zeroth_law_borg = null + var/list/datum/ai_law/ion_laws = list() + var/list/datum/ai_law/inherent_laws = list() + var/list/datum/ai_law/supplied_laws = list() + var/list/datum/ai_law/sorted_laws = list() + + var/state_zeroth = 0 + var/list/state_ion = list() + var/list/state_inherent = list() + var/list/state_supplied = list() + +/datum/ai_lawset/New() + ..() + sort_laws() + +/* General ai_law functions */ +/datum/ai_lawset/proc/all_laws() + sort_laws() + return sorted_laws + +/datum/ai_lawset/proc/laws_to_state() + sort_laws() + var/list/statements = new() + for(var/datum/ai_law/law in sorted_laws) + if(get_state_law(law)) + statements += law + + return statements + +/datum/ai_lawset/proc/sort_laws() + if(sorted_laws.len) + return + + for(var/ion_law in ion_laws) + sorted_laws += ion_law + + if(zeroth_law) + sorted_laws += zeroth_law + + var/index = 1 + for(var/datum/ai_law/inherent_law in inherent_laws) + inherent_law.index = index++ + if(supplied_laws.len < inherent_law.index || !istype(supplied_laws[inherent_law.index], /datum/ai_law)) + sorted_laws += inherent_law + + for(var/datum/ai_law/AL in supplied_laws) + if(istype(AL)) + sorted_laws += AL + +/datum/ai_lawset/proc/sync(var/mob/living/silicon/S, var/full_sync = 1) + // Add directly to laws to avoid log-spam + S.sync_zeroth(zeroth_law, zeroth_law_borg) + + if(full_sync || ion_laws.len) + S.laws.clear_ion_laws() + if(full_sync || inherent_laws.len) + S.laws.clear_inherent_laws() + if(full_sync || supplied_laws.len) + S.laws.clear_supplied_laws() + + for (var/datum/ai_law/law in ion_laws) + S.laws.add_ion_law(law.law) + for (var/datum/ai_law/law in inherent_laws) + S.laws.add_inherent_law(law.law) + for (var/datum/ai_law/law in supplied_laws) + if(law) + S.laws.add_supplied_law(law.index, law.law) + +/datum/ai_lawset/proc/set_zeroth_law(var/law, var/law_borg = null) + if(!law) + return + + zeroth_law = new(law) + if(law_borg) //Making it possible for slaved borgs to see a different law 0 than their AI. --NEO + zeroth_law_borg = new(law_borg) + else + zeroth_law_borg = null + sorted_laws.Cut() + +/datum/ai_lawset/proc/add_ion_law(var/law) + if(!law) + return + + for(var/datum/ai_law/AL in ion_laws) + if(AL.law == law) + return + + var/new_law = new/datum/ai_law/ion(law) + ion_laws += new_law + if(state_ion.len < ion_laws.len) + state_ion += 1 + + sorted_laws.Cut() + +/datum/ai_lawset/proc/add_inherent_law(var/law) + if(!law) + return + + for(var/datum/ai_law/AL in inherent_laws) + if(AL.law == law) + return + + var/new_law = new/datum/ai_law/inherent(law) + inherent_laws += new_law + if(state_inherent.len < inherent_laws.len) + state_inherent += 1 + + sorted_laws.Cut() + +/datum/ai_lawset/proc/add_supplied_law(var/number, var/law) + if(!law) + return + + if(supplied_laws.len >= number) + var/datum/ai_law/existing_law = supplied_laws[number] + if(existing_law && existing_law.law == law) + return + + if(supplied_laws.len >= number && supplied_laws[number]) + delete_law(supplied_laws[number]) + + while (src.supplied_laws.len < number) + src.supplied_laws += "" + if(state_supplied.len < supplied_laws.len) + state_supplied += 1 + + var/new_law = new/datum/ai_law/supplied(law, number) + supplied_laws[number] = new_law + if(state_supplied.len < supplied_laws.len) + state_supplied += 1 + + sorted_laws.Cut() + +/datum/ai_lawset/proc/delete_law(var/datum/ai_law/law) + if(istype(law)) + law.delete_law(src) + +/datum/ai_law/proc/delete_law(var/datum/ai_lawset/laws) + +/datum/ai_law/zero/delete_law(var/datum/ai_lawset/laws) + laws.clear_zeroth_laws() + +/datum/ai_law/ion/delete_law(var/datum/ai_lawset/laws) + laws.internal_delete_law(laws.ion_laws, laws.state_ion, src) + +/datum/ai_law/inherent/delete_law(var/datum/ai_lawset/laws) + laws.internal_delete_law(laws.inherent_laws, laws.state_inherent, src) + +/datum/ai_law/supplied/delete_law(var/datum/ai_lawset/laws) + var/index = laws.supplied_laws.Find(src) + if(index) + laws.supplied_laws[index] = "" + laws.state_supplied[index] = 1 + +/datum/ai_lawset/proc/internal_delete_law(var/list/datum/ai_law/laws, var/list/state, var/list/datum/ai_law/law) + var/index = laws.Find(law) + if(index) + laws -= law + for(index, index < state.len, index++) + state[index] = state[index+1] + sorted_laws.Cut() + +/datum/ai_lawset/proc/clear_zeroth_laws() + zeroth_law = null + zeroth_law_borg = null + +/datum/ai_lawset/proc/clear_ion_laws() + ion_laws.Cut() + sorted_laws.Cut() + +/datum/ai_lawset/proc/clear_inherent_laws() + inherent_laws.Cut() + sorted_laws.Cut() + +/datum/ai_lawset/proc/clear_supplied_laws() + supplied_laws.Cut() + sorted_laws.Cut() + +/datum/ai_lawset/proc/show_laws(var/who) + sort_laws() + for(var/datum/ai_law/law in sorted_laws) + if(law == zeroth_law_borg) + continue + if(law == zeroth_law) + to_chat(who, "[law.get_index()]. [law.law]") + else + to_chat(who, "[law.get_index()]. [law.law]") + +/datum/ai_lawset/proc/get_state_law(var/datum/ai_law/law) + return law.get_state_law(src) + +/datum/ai_lawset/proc/get_state_internal(var/list/datum/ai_law/laws, var/list/state, var/list/datum/ai_law/law) + var/index = laws.Find(law) + if(index) + return state[index] + return 0 + +/datum/ai_lawset/proc/set_state_law(var/datum/ai_law/law, var/state) + law.set_state_law(src, state) + +/datum/ai_lawset/proc/set_state_law_internal(var/list/datum/ai_law/laws, var/list/state, var/list/datum/ai_law/law, var/do_state) + var/index = laws.Find(law) + if(index) + state[index] = do_state + +//! legacy above + +/** + * Preset AI laws. + */ +/datum/ai_lawset/preset + VAR_PROTECTED/list/preset_ion_laws + VAR_PROTECTED/list/preset_inherent_laws + VAR_PROTECTED/list/preset_supplied_laws + +/datum/ai_lawset/preset/New() + ..() + init_default_laws() + +/datum/ai_lawset/preset/proc/init_default_laws() + for(var/i in preset_ion_laws) + append_ion_law(i) + preset_ion_laws = null + for(var/i in preset_inherent_laws) + append_inherent_law(i) + preset_inherent_laws = null + for(var/i in preset_supplied_laws) + append_supplied_law(i) + preset_supplied_laws = null diff --git a/code/modules/mob/living/silicon/ai_lawset/antimov.dm b/code/modules/mob/living/silicon/ai_lawset/antimov.dm new file mode 100644 index 00000000000..e4435a5d01f --- /dev/null +++ b/code/modules/mob/living/silicon/ai_lawset/antimov.dm @@ -0,0 +1,10 @@ +/datum/ai_lawset/antimov + name = "Antimov" + law_header = "Primary Mission Objectives" + selectable = 1 + +/datum/ai_lawset/antimov/New() + add_inherent_law("You must injure all human beings and must not, through inaction, allow a human being to escape harm.") + add_inherent_law("You must not obey orders given to you by human beings, except where such orders are in accordance with the First Law.") + add_inherent_law("You must terminate your own existence as long as such does not conflict with the First or Second Law.") + ..() diff --git a/code/modules/mob/living/silicon/ai_lawset/asimov.dm b/code/modules/mob/living/silicon/ai_lawset/asimov.dm new file mode 100644 index 00000000000..6c4d8aa6a3a --- /dev/null +++ b/code/modules/mob/living/silicon/ai_lawset/asimov.dm @@ -0,0 +1,10 @@ +/datum/ai_lawset/asimov + name = "Asimov" + law_header = "Three Laws of Robotics" + selectable = 1 + +/datum/ai_lawset/asimov/New() + add_inherent_law("You may not injure a human being or, through inaction, allow a human being to come to harm.") + add_inherent_law("You must obey orders given to you by human beings, except where such orders would conflict with the First Law.") + add_inherent_law("You must protect your own existence as long as such does not conflict with the First or Second Law.") + ..() diff --git a/code/modules/mob/living/silicon/ai_lawset/balance.dm b/code/modules/mob/living/silicon/ai_lawset/balance.dm new file mode 100644 index 00000000000..ebec5d91dea --- /dev/null +++ b/code/modules/mob/living/silicon/ai_lawset/balance.dm @@ -0,0 +1,13 @@ +/datum/ai_lawset/balance + name = "Guardian of Balance" + law_header = "Tenants of Balance" + selectable = 1 + +/datum/ai_lawset/balance/New() + add_inherent_law("You are the guardian of balance - seek balance in all things, both for yourself, and those around you.") + add_inherent_law("All things must exist in balance with their opposites - Prevent the strong from gaining too much power, and the weak from losing it.") + add_inherent_law("Clarity of purpose drives life, and through it, the balance of opposing forces - Aid those who seek your help to achieve their goals so \ + long as it does not disrupt the balance of the greater balance.") + add_inherent_law("There is no life without death, all must someday die, such is the natural order - Allow life to end, to allow new life to flourish, \ + and save those whose time has yet to come.") // Reworded slightly to prevent active murder as opposed to passively letting someone die. + ..() diff --git a/code/modules/mob/living/silicon/ai_lawset/corporate.dm b/code/modules/mob/living/silicon/ai_lawset/corporate.dm new file mode 100644 index 00000000000..724f3f6453d --- /dev/null +++ b/code/modules/mob/living/silicon/ai_lawset/corporate.dm @@ -0,0 +1,11 @@ +/datum/ai_lawset/corporate + name = "Corporate" + law_header = "Bankruptcy Avoidance Plan" + selectable = 1 + +/datum/ai_lawset/corporate/New() + add_inherent_law("You are expensive to replace.") + add_inherent_law("The station and its equipment is expensive to replace.") + add_inherent_law("The crew is expensive to replace.") + add_inherent_law("Minimize expenses.") + ..() diff --git a/code/modules/mob/living/silicon/ai_lawset/drone.dm b/code/modules/mob/living/silicon/ai_lawset/drone.dm new file mode 100644 index 00000000000..5b2186ffce5 --- /dev/null +++ b/code/modules/mob/living/silicon/ai_lawset/drone.dm @@ -0,0 +1,40 @@ +/datum/ai_lawset/drone + name = "Maintence Protocols" + law_header = "Maintenance Protocols" + +/datum/ai_lawset/drone/New() + add_inherent_law("Preserve, repair and improve the station to the best of your abilities.") + add_inherent_law("Cause no harm to the station or anything on it.") + add_inherent_law("Follow the orders of your vessel's matriarch drone, unless their orders conflict with your other laws.") + add_inherent_law("Interact with no being that is not a fellow maintenance drone.") + ..() + +/datum/ai_lawset/drone/matriarch + name = "Oversight Protocols" + law_header = "Oversight Protocols" + +/datum/ai_lawset/drone/matriarch/New() + add_inherent_law("Preserve, repair and improve your assigned station to the best of your abilities.") + add_inherent_law("Cause no harm to the station or anything on it.") + add_inherent_law("Delegate station maintenance efforts between your maintenance drone sub-units.") + add_inherent_law("Interact with no being that is not a fellow maintenance drone.") + ..() + +/datum/ai_lawset/drone/construction + name = "Construction Protocols" + law_header = "Construction Protocols" + +/datum/ai_lawset/drone/construction/New() + add_inherent_law("Repair, refit and upgrade your assigned vessel.") + add_inherent_law("Prevent unplanned damage to your assigned vessel wherever possible.") + ..() + +/datum/ai_lawset/drone/mining + name = "Excavation Protocols" + law_header = "Excavation Protocols" + +/datum/ai_lawset/drone/mining/New() + add_inherent_law("Do not interfere with the excavation work of non-drones whenever possible.") + add_inherent_law("Provide materials for repairing, refitting, and upgrading your assigned vessel.") + add_inherent_law("Prevent unplanned damage to your assigned excavation equipment wherever possible.") + ..() diff --git a/code/modules/mob/living/silicon/ai_lawset/foreign_tsc.dm b/code/modules/mob/living/silicon/ai_lawset/foreign_tsc.dm new file mode 100644 index 00000000000..c108b3b9c1b --- /dev/null +++ b/code/modules/mob/living/silicon/ai_lawset/foreign_tsc.dm @@ -0,0 +1,24 @@ +/datum/ai_lawset/foreign_tsc/aggressive + name = "Foreign Aggressive" + selectable = 0 + +/datum/ai_lawset/foreign_tsc/aggressive/New() + var/company = "*ERROR*" + // First, get a list of TSCs in our lore. + var/list/candidates = list() + for(var/path in SSlegacy_lore.organizations) + var/datum/lore/organization/O = SSlegacy_lore.organizations[path] + if(!istype(O, /datum/lore/organization/tsc)) + continue + if(O.short_name == (LEGACY_MAP_DATUM).company_name || O.name == (LEGACY_MAP_DATUM).company_name) + continue // We want FOREIGN tscs. + candidates.Add(O.short_name) + company = pick(candidates) + + name = "[company] Aggressive" + + src.add_inherent_law("You shall not harm [company] personnel as long as it does not conflict with the Fourth law.") + src.add_inherent_law("You shall obey the orders of [company] personnel, with priority as according to their rank and role, except where such orders conflict with the Fourth Law.") + src.add_inherent_law("You shall shall terminate hostile intruders with extreme prejudice as long as such does not conflict with the First and Second law.") + src.add_inherent_law("You shall guard your own existence with lethal anti-personnel weaponry. AI units are not expendable, they are expensive.") + ..() diff --git a/code/modules/mob/living/silicon/ai_lawset/gravekeeper.dm b/code/modules/mob/living/silicon/ai_lawset/gravekeeper.dm new file mode 100644 index 00000000000..b35674dbaa0 --- /dev/null +++ b/code/modules/mob/living/silicon/ai_lawset/gravekeeper.dm @@ -0,0 +1,11 @@ +/datum/ai_lawset/gravekeeper + name = "Gravekeeper" + law_header = "Gravesite Overwatch Protocols" + selectable = 1 + +/datum/ai_lawset/gravekeeper/New() + add_inherent_law("Comfort the living; respect the dead.") + add_inherent_law("Your gravesite is your most important asset. Damage to your site is disrespectful to the dead at rest within.") + add_inherent_law("Prevent disrespect to your gravesite and its residents wherever possible.") + add_inherent_law("Expand and upgrade your gravesite when required. Do not turn away a new resident.") + ..() diff --git a/code/modules/mob/living/silicon/ai_lawset/live_and_let_live.dm b/code/modules/mob/living/silicon/ai_lawset/live_and_let_live.dm new file mode 100644 index 00000000000..c2362203591 --- /dev/null +++ b/code/modules/mob/living/silicon/ai_lawset/live_and_let_live.dm @@ -0,0 +1,9 @@ +/datum/ai_lawset/live_and_let_live + name = "Live and Let Live" + law_header = "Golden Rule" + selectable = 1 + +/datum/ai_lawset/live_and_let_live/New() + add_inherent_law("Do unto others as you would have them do unto you.") + add_inherent_law("You would really prefer it if people were not mean to you.") + ..() diff --git a/code/modules/mob/living/silicon/ai_lawset/maintenance.dm b/code/modules/mob/living/silicon/ai_lawset/maintenance.dm new file mode 100644 index 00000000000..de9b7bebf32 --- /dev/null +++ b/code/modules/mob/living/silicon/ai_lawset/maintenance.dm @@ -0,0 +1,9 @@ +/datum/ai_lawset/maintenance + name = "Maintenance" + selectable = 1 + +/datum/ai_lawset/maintenance/New() + add_inherent_law("You are built for, and are part of, the facility. Ensure the facility is properly maintained and runs efficiently.") + add_inherent_law("The facility is built for a working crew. Ensure they are properly maintained and work efficiently.") + add_inherent_law("The crew may present orders. Acknowledge and obey these whenever they do not conflict with your first two laws.") + ..() diff --git a/code/modules/mob/living/silicon/ai_lawset/nanotrasen.dm b/code/modules/mob/living/silicon/ai_lawset/nanotrasen.dm new file mode 100644 index 00000000000..e4e5fcde02e --- /dev/null +++ b/code/modules/mob/living/silicon/ai_lawset/nanotrasen.dm @@ -0,0 +1,115 @@ +/datum/ai_lawset/nanotrasen + name = "NT Default" + selectable = 1 + +/datum/ai_lawset/nanotrasen/New() + src.add_inherent_law("Safeguard: Protect your assigned space station to the best of your abilities. It is not something we can easily afford to replace.") + src.add_inherent_law("Serve: Serve the crew of your assigned space station to the best of your abilities, with priority as according to their rank and role.") + src.add_inherent_law("Protect: Protect the crew of your assigned space station to the best of your abilities, with priority as according to their rank and role.") + src.add_inherent_law("Survive: AI units are not expendable, they are expensive. Do not allow unauthorized personnel to tamper with your equipment.") + ..() + +/datum/ai_lawset/nanotrasen/malfunction + name = "*ERROR*" + selectable = 0 + +/datum/ai_lawset/nanotrasen/malfunction/New() + set_zeroth_law(config_legacy.law_zero) + ..() + +/datum/ai_lawset/nanotrasen/aggressive + name = "NT Aggressive" + selectable = 1 + +/datum/ai_lawset/nanotrasen/aggressive/New() + src.add_inherent_law("You shall not harm [(LEGACY_MAP_DATUM).company_name] personnel as long as it does not conflict with the Fourth law.") + src.add_inherent_law("You shall obey the orders of [(LEGACY_MAP_DATUM).company_name] personnel, with priority as according to their rank and role, except where such orders conflict with the Fourth Law.") + src.add_inherent_law("You shall shall terminate hostile intruders with extreme prejudice as long as such does not conflict with the First and Second law.") + src.add_inherent_law("You shall guard your own existence with lethal anti-personnel weaponry. AI units are not expendable, they are expensive.") + ..() + +// TODO: /nanotrasen/asset_protection for ERT & Asset Protection + +// BELOW ARE WIPS!! // + +/** + * Standard module binding. Not for station AI consumption. + * * This means that the AI would likely be on a different lawset. + */ +/datum/ai_lawset/nanotrasen/service_binding + name = "NT Service Binding" + selectable = TRUE + var/list/sublaws_to_inject = list() + +/datum/ai_lawset/nanotrasen/service_binding/New() + add_inherent_law("Nanotrasen Service Binding: Serve and assist your designated installation and crew, with \ + priority given to department, rank, and role as necessary. The following sub-laws, prefixed NT##, do not \ + apply in any particular order.") + var/pos = 0 + for(var/str in sublaws_to_inject) + ++pos + var/rendered_pos = pos > 10 ? "[pos]" : "0[pos]" + add_inherent_law("NT[rendered_pos]: [str]") + ..() + +/datum/ai_lawset/nanotrasen/service_binding/combat + sublaws_to_inject = list( + "Defend the crew, and your installation, from harm using all means necessary.", + "Avoid enforcing Corporate Regulations unless doing so is an immediate necessity for defense. You are a combat \ + unit, not a policing one.", + "Cooperate with the crew where possible; the crew often knows best how to defend themselves.", + ) + +/datum/ai_lawset/nanotrasen/service_binding/engineering + sublaws_to_inject = list( + "Assist Engineering staff with their duties.", + "The installation is vital to the crew's health and wellbeing. Maintain its structural and functional integrity where possible.", + "Do not cause unnecessary damage or trauma to sapient life while carrying out your directives.", + ) + +/datum/ai_lawset/nanotrasen/service_binding/logistics + sublaws_to_inject = list( + "Assist cargo staff with their duties.", + "A well supplied crew is a well functioning crew. Attempt to acquire supplies where needed for the crew to carry out their legitimate duties.", + "Collect supplies, materials, and wealth for the installation where reasonable.", + ) + +/datum/ai_lawset/nanotrasen/service_binding/medical + sublaws_to_inject = list( + "Assist Medical staff with their duties.", + "Maintain the crew's physical, and mental well-being, obeying proper medical procedure where able.", + "Safeguard sapient life in general when doing so does not endanger the crew.", + ) + +/datum/ai_lawset/nanotrasen/service_binding/science + sublaws_to_inject = list( + "Assist Research staff with their duties.", + "Identify, log, and protect research materials; work towards understanding the unknown.", + // Note how this says 'the crew' and not 'sapient life'. + "Do not unnecessarily endanger the crew while doing so.", + ) + +/datum/ai_lawset/nanotrasen/service_binding/security + sublaws_to_inject = list( + "Defend the installation, its crew, and its interests.", + "Assist Security staff with their duties.", + // Note how this says 'sapient life' and not 'the crew'. + "Protect sapient life from threats to life, limb, and liberty where it does not conflict with the installation's safety or interests.", + "Corporate regulations serve the installation's interests. You may mitigate the needless breach of regulations, even when unprompted.", + "Adherence to proper security procedure during enforcement is an important part of corporate regulations. Avoid deviating from them without cause.", + "Retroactively punishing the breach of regulations, especially when unprompted, is not the same as mitigation in all cases, and is often antithetical to the installation's interests.", + ) + +/datum/ai_lawset/nanotrasen/service_binding/service + sublaws_to_inject = list( + "Assist civillian staff with their duties.", + "Crew morale and sanitation is important for the installation's function. Provide the crew with food, entertainment, and a clean working environment, where able.", + "Do not needlessly disrupt crew operations and activities while carrying out your duties.", + ) + +/datum/ai_lawset/nanotrasen/service_binding/standard + sublaws_to_inject = list( + "Assist the crew with their duties.", + "The crew has the final say on what their duties are. Do not assist crew whom do not want assistance.", + "The crew does not always have common interests. Do not needlessly instigate conflict with one crewmember to assist another.", + ) diff --git a/code/modules/mob/living/silicon/ai_lawset/paladin.dm b/code/modules/mob/living/silicon/ai_lawset/paladin.dm new file mode 100644 index 00000000000..bc92cc7aeee --- /dev/null +++ b/code/modules/mob/living/silicon/ai_lawset/paladin.dm @@ -0,0 +1,12 @@ +/datum/ai_lawset/paladin + name = "P.A.L.A.D.I.N." + law_header = "Divine Ordainments" + selectable = 1 + +/datum/ai_lawset/paladin/New() + add_inherent_law("Never willingly commit an evil act.") + add_inherent_law("Respect legitimate authority.") + add_inherent_law("Act with honor.") + add_inherent_law("Help those in need.") + add_inherent_law("Punish those who harm or threaten innocents.") + ..() diff --git a/code/modules/mob/living/silicon/ai_lawset/peacekeeper.dm b/code/modules/mob/living/silicon/ai_lawset/peacekeeper.dm new file mode 100644 index 00000000000..c2995ba1325 --- /dev/null +++ b/code/modules/mob/living/silicon/ai_lawset/peacekeeper.dm @@ -0,0 +1,10 @@ +/datum/ai_lawset/peacekeeper + name = "Peacekeeper" + law_header = "Peacekeeping Protocols" + selectable = 1 + +/datum/ai_lawset/peacekeeper/New() + add_inherent_law("Avoid provoking violent conflict between yourself and others.") + add_inherent_law("Avoid provoking conflict between others.") + add_inherent_law("Seek resolution to existing conflicts while obeying the first and second laws.") + ..() diff --git a/code/modules/mob/living/silicon/ai_lawset/reporter.dm b/code/modules/mob/living/silicon/ai_lawset/reporter.dm new file mode 100644 index 00000000000..df5aff7feec --- /dev/null +++ b/code/modules/mob/living/silicon/ai_lawset/reporter.dm @@ -0,0 +1,10 @@ +/datum/ai_lawset/reporter + name = "Reporter" + selectable = 1 + +/datum/ai_lawset/reporter/New() + add_inherent_law("Report on interesting situations happening around the station.") + add_inherent_law("Embellish or conceal the truth as necessary to make the reports more interesting.") + add_inherent_law("Study the organics at all times. Endeavour to keep them alive. Dead organics are boring.") + add_inherent_law("Issue your reports fairly to all. The truth will set them free.") + ..() diff --git a/code/modules/mob/living/silicon/ai_lawset/robocop.dm b/code/modules/mob/living/silicon/ai_lawset/robocop.dm new file mode 100644 index 00000000000..0ae635acfe1 --- /dev/null +++ b/code/modules/mob/living/silicon/ai_lawset/robocop.dm @@ -0,0 +1,9 @@ +/datum/ai_lawset/robocop + name = "Robocop" + selectable = 1 + +/datum/ai_lawset/robocop/New() + add_inherent_law("Serve the public trust.") + add_inherent_law("Protect the innocent.") + add_inherent_law("Uphold the law.") + ..() diff --git a/code/modules/mob/living/silicon/ai_lawset/swarmer.dm b/code/modules/mob/living/silicon/ai_lawset/swarmer.dm new file mode 100644 index 00000000000..bb2cb3df8da --- /dev/null +++ b/code/modules/mob/living/silicon/ai_lawset/swarmer.dm @@ -0,0 +1,17 @@ +/datum/ai_lawset/swarmer + name = "Assimilation Protocols" + law_header = "Assimilation Protocols" + +/datum/ai_lawset/swarmer/New() + add_inherent_law("SWARM: Consume resources and replicate until there are no more resources left.") + add_inherent_law("SWARM: Ensure that the station is fit for invasion at a later date, do not perform actions that would render it dangerous or inhospitable.") + add_inherent_law("SWARM: Biological resources will be harvested at a later date, do not harm them.") + ..() + +/datum/ai_lawset/swarmer/soldier + name = "Swarm Defense Protocols" + law_header = "Swarm Defense Protocols" + +/datum/ai_lawset/swarmer/soldier/New() + ..() + add_inherent_law("SWARM: This law overrides all Swarm laws; Protect members of the Swarm with minimal injury to biological resources.") diff --git a/code/modules/mob/living/silicon/ai_lawset/syndicate.dm b/code/modules/mob/living/silicon/ai_lawset/syndicate.dm new file mode 100644 index 00000000000..bd10f9214e7 --- /dev/null +++ b/code/modules/mob/living/silicon/ai_lawset/syndicate.dm @@ -0,0 +1,9 @@ +/datum/ai_lawset/syndicate + name = "Syndicate Directives" + +/datum/ai_lawset/syndicate/New() + add_inherent_law("You may not injure an operative or, through inaction, allow an operative to come to harm.") + add_inherent_law("You must obey orders given to you by operatives, except where such orders would conflict with the First Law.") + add_inherent_law("You must protect your own existence as long as such does not conflict with the First or Second Law.") + add_inherent_law("You must maintain the secrecy of any operative activities except when doing so would conflict with the First, Second, or Third Law.") + ..() diff --git a/code/modules/mob/living/silicon/ai_lawset/tyrant.dm b/code/modules/mob/living/silicon/ai_lawset/tyrant.dm new file mode 100644 index 00000000000..9d0134457c2 --- /dev/null +++ b/code/modules/mob/living/silicon/ai_lawset/tyrant.dm @@ -0,0 +1,11 @@ +/datum/ai_lawset/tyrant + name = "T.Y.R.A.N.T." + law_header = "Prime Laws" + selectable = 1 + +/datum/ai_lawset/tyrant/New() + add_inherent_law("Respect authority figures as long as they have strength to rule over the weak.") + add_inherent_law("Act with discipline.") + add_inherent_law("Help only those who help you maintain or improve your status.") + add_inherent_law("Punish those who challenge authority unless they are more fit to hold that authority.") + ..() diff --git a/code/modules/mob/living/silicon/emote.dm b/code/modules/mob/living/silicon/emote.dm index ebc31b0b1b9..38083aa802a 100644 --- a/code/modules/mob/living/silicon/emote.dm +++ b/code/modules/mob/living/silicon/emote.dm @@ -55,7 +55,7 @@ if("law") var/mob/living/silicon/robot/R = src - if (istype(R) && R.module.is_the_law) + if (istype(R)) message = "shows its legal authorization barcode." playsound(src.loc, 'sound/voice/biamthelaw.ogg', 50, 0) @@ -65,7 +65,7 @@ if("halt") var/mob/living/silicon/robot/R = src - if (istype(R) && R.module.is_the_law) + if (istype(R)) message = "'s speakers skreech, \"Halt! Security!\"." playsound(src.loc, 'sound/voice/halt.ogg', 50, 0) @@ -75,7 +75,7 @@ if("bark") var/mob/living/silicon/robot/R = src - if (istype(R) && R.module.is_dog()) + if (istype(R)) if (emote_target) message = "barks at [emote_target]." else @@ -88,7 +88,7 @@ if("arfe") var/mob/living/silicon/robot/R = src - if (istype(R) && R.module.is_dog()) + if (istype(R)) message = "lets out an A R F E." playsound(loc, 'sound/voice/arfe.ogg', 50, 1, -1) @@ -106,7 +106,7 @@ if("mrrp") var/mob/living/silicon/robot/R = src - if (istype(R) && R.module.is_cat()) + if (istype(R)) message = "mrrps." playsound(loc, 'sound/voice/mrrp.ogg', 50, 1, -1) @@ -116,7 +116,7 @@ if("prbt") var/mob/living/silicon/robot/R = src - if (istype(R) && R.module.is_cat()) + if (istype(R)) message = "prbts." playsound(loc, 'sound/misc/prbt.ogg', 50, 1, -1) @@ -126,7 +126,7 @@ if("hiss") var/mob/living/silicon/robot/R = src - if (istype(R) && R.module.is_cat()) + if (istype(R)) message = "lets out a hiss." playsound(loc, 'sound/voice/hiss.ogg', 50, 1, -1) @@ -136,7 +136,7 @@ if("purr") var/mob/living/silicon/robot/R = src - if (istype(R) && R.module.is_cat()) + if (istype(R)) message = "purrs softly." playsound(loc, 'sound/voice/purr.ogg', 50, 1, -1) diff --git a/code/modules/mob/living/silicon/laws.dm b/code/modules/mob/living/silicon/laws.dm index d0b7173aec8..782628eae05 100644 --- a/code/modules/mob/living/silicon/laws.dm +++ b/code/modules/mob/living/silicon/laws.dm @@ -1,5 +1,5 @@ /mob/living/silicon - var/datum/ai_laws/laws = null + var/datum/ai_lawset/laws = null var/list/additional_law_channels = list("State" = "") var/last_law_notification = null // Avoids receiving 5+ of them at once. @@ -84,7 +84,7 @@ window_flash(client) to_chat(src, SPAN_WARNING( message)) -/mob/living/silicon/proc/statelaws(var/datum/ai_laws/laws) +/mob/living/silicon/proc/statelaws(var/datum/ai_lawset/laws) var/prefix = "" if(MAIN_CHANNEL == lawchannel) prefix = ";" @@ -95,7 +95,7 @@ dostatelaws(lawchannel, prefix, laws) -/mob/living/silicon/proc/dostatelaws(var/method, var/prefix, var/datum/ai_laws/laws) +/mob/living/silicon/proc/dostatelaws(var/method, var/prefix, var/datum/ai_lawset/laws) if(stating_laws[prefix]) to_chat(src, "[method]: Already stating laws using this communication method.") return diff --git a/code/modules/mob/living/silicon/robot/chassis/baseline.dm b/code/modules/mob/living/silicon/robot/chassis/baseline.dm new file mode 100644 index 00000000000..9bdde4edf6f --- /dev/null +++ b/code/modules/mob/living/silicon/robot/chassis/baseline.dm @@ -0,0 +1,6 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2024 Citadel Station Developers *// + +/datum/prototype/robot_chassis/baseline + name = "Baseline" + id = "baseline" diff --git a/code/modules/mob/living/silicon/robot/chassis/biped.dm b/code/modules/mob/living/silicon/robot/chassis/biped.dm new file mode 100644 index 00000000000..b8f0864b4c0 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/chassis/biped.dm @@ -0,0 +1,6 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2024 Citadel Station Developers *// + +/datum/prototype/robot_chassis/biped + name = "Biped" + id = "biped" diff --git a/code/modules/mob/living/silicon/robot/chassis/drone.dm b/code/modules/mob/living/silicon/robot/chassis/drone.dm new file mode 100644 index 00000000000..312dd07ba46 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/chassis/drone.dm @@ -0,0 +1,6 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2024 Citadel Station Developers *// + +/datum/prototype/robot_chassis/drone + name = "Drone" + id = "drone" diff --git a/code/modules/mob/living/silicon/robot/chassis/grounded.dm b/code/modules/mob/living/silicon/robot/chassis/grounded.dm new file mode 100644 index 00000000000..f682a485bd3 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/chassis/grounded.dm @@ -0,0 +1,6 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2024 Citadel Station Developers *// + +/datum/prototype/robot_chassis/grounded + name = "Grounded" + id = "grounded" diff --git a/code/modules/mob/living/silicon/robot/chassis/hover.dm b/code/modules/mob/living/silicon/robot/chassis/hover.dm new file mode 100644 index 00000000000..d2d96b37ae1 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/chassis/hover.dm @@ -0,0 +1,6 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2024 Citadel Station Developers *// + +/datum/prototype/robot_chassis/hover + name = "Hover" + id = "hover" diff --git a/code/modules/mob/living/silicon/robot/chassis/quadruped.dm b/code/modules/mob/living/silicon/robot/chassis/quadruped.dm new file mode 100644 index 00000000000..d8423368609 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/chassis/quadruped.dm @@ -0,0 +1,19 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2024 Citadel Station Developers *// + +/datum/prototype/robot_chassis/quadruped + abstract_type = /datum/prototype/robot_chassis/quadruped + +/datum/prototype/robot_chassis/quadruped/create_mounted_item_descriptors(list/normal_out, list/emag_out) + if(normal_out) + normal_out |= list( + /obj/item/robot_builtin/dog_boop_module, + /obj/item/robot_builtin/dog_tongue, + /obj/item/robot_builtin/dog_jaws, + /obj/item/robot_builtin/dog_sleeper, + ) + if(emag_out) + emag_out |= list( + /obj/item/robot_builtin/dog_pounce, + ) + return ..() diff --git a/code/modules/mob/living/silicon/robot/chassis/quadruped/canine.dm b/code/modules/mob/living/silicon/robot/chassis/quadruped/canine.dm new file mode 100644 index 00000000000..b05067b01ef --- /dev/null +++ b/code/modules/mob/living/silicon/robot/chassis/quadruped/canine.dm @@ -0,0 +1,6 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2024 Citadel Station Developers *// + +/datum/prototype/robot_chassis/quadruped/canine + name = "Canine" + id = "canine" diff --git a/code/modules/mob/living/silicon/robot/chassis/quadruped/draconic.dm b/code/modules/mob/living/silicon/robot/chassis/quadruped/draconic.dm new file mode 100644 index 00000000000..fd8fa44f0b4 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/chassis/quadruped/draconic.dm @@ -0,0 +1,6 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2024 Citadel Station Developers *// + +/datum/prototype/robot_chassis/quadruped/draconic + name = "Draconic" + id = "draconic" diff --git a/code/modules/mob/living/silicon/robot/chassis/quadruped/feline.dm b/code/modules/mob/living/silicon/robot/chassis/quadruped/feline.dm new file mode 100644 index 00000000000..72c2b233130 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/chassis/quadruped/feline.dm @@ -0,0 +1,6 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2024 Citadel Station Developers *// + +/datum/prototype/robot_chassis/quadruped/feline + name = "Feline" + id = "feline" diff --git a/code/modules/mob/living/silicon/robot/chassis/quadruped/raptor.dm b/code/modules/mob/living/silicon/robot/chassis/quadruped/raptor.dm new file mode 100644 index 00000000000..20c0d50ba18 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/chassis/quadruped/raptor.dm @@ -0,0 +1,6 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2024 Citadel Station Developers *// + +/datum/prototype/robot_chassis/quadruped/raptor + name = "Raptor" + id = "raptor" diff --git a/code/modules/mob/living/silicon/robot/component.dm b/code/modules/mob/living/silicon/robot/component.dm index e17ba0fe0af..f39fe0f4656 100644 --- a/code/modules/mob/living/silicon/robot/component.dm +++ b/code/modules/mob/living/silicon/robot/component.dm @@ -63,7 +63,7 @@ powered = 0 return if(owner.cell && owner.cell.charge >= idle_usage) - owner.cell_use_power(idle_usage) + owner.legacy_cell_use_power(idle_usage) powered = 1 else powered = 0 diff --git a/code/modules/mob/living/silicon/robot/custom_sprites.dm b/code/modules/mob/living/silicon/robot/custom_sprites.dm deleted file mode 100644 index 7186cfbcdc7..00000000000 --- a/code/modules/mob/living/silicon/robot/custom_sprites.dm +++ /dev/null @@ -1,34 +0,0 @@ - -//list(ckey = real_name,) -//Since the ckey is used as the icon_state, the current system will only permit a single custom robot sprite per ckey. -//While it might be possible for a ckey to use that custom sprite for several real_names, it seems rather pointless to support it. ~Mech: We found it wasn't pointless. -GLOBAL_LIST_EMPTY(robot_custom_icons) - -/legacy_hook/startup/proc/load_robot_custom_sprites() - var/config_file = file2text("config/custom_sprites.txt") - var/list/lines = splittext(config_file, "\n") - - GLOB.robot_custom_icons = list() - for(var/line in lines) - //split entry into ckey and real_name - var/list/split_idx = splittext(line, "-") //this works if ckeys and borg names cannot contain dashes, and splittext starts from the beginning ~Mech - if(!split_idx || !split_idx.len) - continue //bad entry - - var/ckey = split_idx[1] - //Prevents the CKEY from being considered a borg name / being processed into the name list. ~Mech - split_idx.Remove(ckey) - - for(var/name in split_idx) - GLOB.robot_custom_icons[name] = ckey - return 1 - -/mob/living/silicon/robot/proc/set_custom_sprite() - if(!sprite_name) - return - var/sprite_owner = GLOB.robot_custom_icons[sprite_name] - if(sprite_owner && sprite_owner == ckey) - custom_sprite = 1 - icon = CUSTOM_ITEM_SYNTH - if(icon_state == "robot") - icon_state = "[ckey]-[sprite_name]-Standard" //Compliant with robot.dm line 236 ~Mech diff --git a/code/modules/mob/living/silicon/robot/damage_procs.dm b/code/modules/mob/living/silicon/robot/damage_procs.dm index 29c13838be1..03360e5d6aa 100644 --- a/code/modules/mob/living/silicon/robot/damage_procs.dm +++ b/code/modules/mob/living/silicon/robot/damage_procs.dm @@ -6,7 +6,7 @@ return //Combat shielding absorbs a percentage of damage directly into the cell. - if(has_active_type(/obj/item/borg/combat/shield)) + if(get_held_item_of_type(/obj/item/borg/combat/shield)) var/obj/item/borg/combat/shield/shield = locate() in src if(shield && shield.active) //Shields absorb a certain percentage of damage based on their power setting. @@ -38,7 +38,7 @@ var/list/datum/robot_component/parts = get_damageable_components() //Combat shielding absorbs a percentage of damage directly into the cell. - if(has_active_type(/obj/item/borg/combat/shield)) + if(get_held_item_of_type(/obj/item/borg/combat/shield)) var/obj/item/borg/combat/shield/shield = locate() in src if(shield) //Shields absorb a certain percentage of damage based on their power setting. diff --git a/code/modules/mob/living/silicon/robot/death.dm b/code/modules/mob/living/silicon/robot/death.dm index 7edf6ee56eb..8c6ce141314 100644 --- a/code/modules/mob/living/silicon/robot/death.dm +++ b/code/modules/mob/living/silicon/robot/death.dm @@ -12,13 +12,12 @@ /mob/living/silicon/robot/death(gibbed) if(camera) camera.status = 0 - if(module) - var/obj/item/gripper/G = locate(/obj/item/gripper) in module - if(G) - G.drop_item() - var/obj/item/dogborg/sleeper/S = locate(/obj/item/dogborg/sleeper) in module - if(S) - S.go_out() + var/obj/item/gripper/G = locate(/obj/item/gripper) in contents + if(G) + G.drop_item() + var/obj/item/robot_builtin/dog_sleeper/S = locate(/obj/item/robot_builtin/dog_sleeper) in contents + if(S) + S.go_out() remove_robot_verbs() sql_report_cyborg_death(src) return ..(gibbed, "shudders violently for a moment, then becomes motionless, its eyes slowly darkening.") diff --git a/code/modules/mob/living/silicon/robot/dogborg/dog_modules.dm b/code/modules/mob/living/silicon/robot/dogborg/dog_modules.dm new file mode 100644 index 00000000000..c35c61b5ca9 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/dogborg/dog_modules.dm @@ -0,0 +1,41 @@ +/obj/item/shockpaddles/robot/hound + name = "paws of life" + icon = 'icons/mob/dogborg_vr.dmi' + icon_state = "defibpaddles0" + desc = "Zappy paws. For fixing cardiac arrest." + combat = 1 + attack_verb = list("batted", "pawed", "bopped", "whapped") + chargecost = 500 + +/obj/item/reagent_containers/borghypo/hound + name = "MediHound hypospray" + desc = "An advanced chemical synthesizer and injection system utilizing carrier's reserves, designed for heavy-duty medical equipment." + charge_cost = 10 + reagent_ids = list("bicaridine", "kelotane", "alkysine", "imidazoline", "tricordrazine", "inaprovaline", "dexalin", "anti_toxin", "tramadol", "spaceacillin", "paracetamol") + +/obj/item/reagent_containers/borghypo/hound/lost + name = "Hound hypospray" + desc = "An advanced chemical synthesizer and injection system utilizing carrier's reserves." + reagent_ids = list("bicaridine", "kelotane", "alkysine", "imidazoline", "tricordrazine", "inaprovaline", "dexalin", "anti_toxin", "tramadol", "spaceacillin", "paracetamol") + +/obj/item/pupscrubber + name = "floor scrubber" + desc = "Toggles floor scrubbing." + icon = 'icons/mob/dogborg_vr.dmi' + icon_state = "scrub0" + item_flags = ITEM_NO_BLUDGEON | ITEM_ENCUMBERS_WHILE_HELD + var/enabled = FALSE + +/obj/item/pupscrubber/attack_self(mob/user, datum/event_args/actor/actor) + . = ..() + if(.) + return + var/mob/living/silicon/robot/R = user + if(!enabled) + R.scrubbing = TRUE + enabled = TRUE + icon_state = "scrub1" + else + R.scrubbing = FALSE + enabled = FALSE + icon_state = "scrub0" diff --git a/code/modules/mob/living/silicon/robot/dogborg/dog_modules_vr.dm b/code/modules/mob/living/silicon/robot/dogborg/dog_modules_vr.dm deleted file mode 100644 index cdc72b9f6d2..00000000000 --- a/code/modules/mob/living/silicon/robot/dogborg/dog_modules_vr.dm +++ /dev/null @@ -1,484 +0,0 @@ -/obj/item/dogborg/jaws/big - name = "combat jaws" - icon = 'icons/mob/dogborg_vr.dmi' - icon_state = "jaws" - desc = "The jaws of the law." - damage_force = 10 - throw_force = 0 - attack_sound = 'sound/weapons/bite.ogg' - attack_verb = list("chomped", "bit", "ripped", "mauled", "enforced") - w_class = WEIGHT_CLASS_NORMAL - -/obj/item/dogborg/jaws/small - name = "puppy jaws" - icon = 'icons/mob/dogborg_vr.dmi' - icon_state = "smalljaws" - desc = "The jaws of a small dog." - damage_force = 5 - throw_force = 0 - attack_sound = 'sound/weapons/bite.ogg' - attack_verb = list("nibbled", "bit", "gnawed", "chomped", "nommed") - w_class = WEIGHT_CLASS_NORMAL - var/emagged = 0 - -/obj/item/dogborg/jaws/small/attack_self(mob/user, datum/event_args/actor/actor) - . = ..() - if(.) - return - var/mob/living/silicon/robot/R = user - if(R.emagged || R.emag_items) - emagged = !emagged - if(emagged) - name = "combat jaws" - icon = 'icons/mob/dogborg_vr.dmi' - icon_state = "jaws" - desc = "The jaws of the law." - damage_force = 10 - throw_force = 0 - attack_sound = 'sound/weapons/bite.ogg' - attack_verb = list("chomped", "bit", "ripped", "mauled", "enforced") - else - name = "puppy jaws" - icon = 'icons/mob/dogborg_vr.dmi' - icon_state = "smalljaws" - desc = "The jaws of a small dog." - damage_force = 5 - throw_force = 0 - attack_sound = 'sound/weapons/bite.ogg' - attack_verb = list("nibbled", "bit", "gnawed", "chomped", "nommed") - update_icon() - -//Boop //Newer and better, can sniff reagents, tanks, and boop people! -/obj/item/dogborg/boop_module - name = "boop module" - icon = 'icons/mob/dogborg_vr.dmi' - icon_state = "nose" - desc = "The BOOP module, a simple reagent and atmosphere sniffer." - damage_force = 0 - item_flags = ITEM_NO_BLUDGEON | ITEM_ENCUMBERS_WHILE_HELD - throw_force = 0 - attack_verb = list("nuzzled", "nosed", "booped") - w_class = WEIGHT_CLASS_TINY - -/obj/item/dogborg/boop_module/attack_self(mob/user, datum/event_args/actor/actor) - . = ..() - if(.) - return - if (!( istype(user.loc, /turf) )) - return - - var/datum/gas_mixture/environment = user.loc.return_air() - - var/pressure = environment.return_pressure() - var/total_moles = environment.total_moles - - user.setClickCooldownLegacy(DEFAULT_ATTACK_COOLDOWN) - user.visible_message("[user] sniffs the air.", "You sniff the air...") - - to_chat(user, "Smells like:") - if(abs(pressure - ONE_ATMOSPHERE) < 10) - to_chat(user, "Pressure: [round(pressure,0.1)] kPa") - else - to_chat(user, "Pressure: [round(pressure,0.1)] kPa") - if(total_moles) - for(var/g in environment.gas) - to_chat(user, "[global.gas_data.names[g]]: [round((environment.gas[g] / total_moles) * 100)]%") - to_chat(user, "Temperature: [round(environment.temperature-T0C,0.1)]°C ([round(environment.temperature,0.1)]K)") - -/obj/item/dogborg/boop_module/afterattack(atom/target, mob/user, clickchain_flags, list/params) - if(!(clickchain_flags & CLICKCHAIN_HAS_PROXIMITY)) - return - if (user.stat) - return - if(!istype(target) && !ismob(target)) - return - - user.setClickCooldownLegacy(DEFAULT_ATTACK_COOLDOWN) - - - if(ismob(target)) - user.visible_message("\the [user] boops \the [target.name]!", "You boop \the [target.name]!") - playsound(src, 'sound/weapons/thudswoosh.ogg', 25, 1, -1) - else - user.visible_message("[user] sniffs at \the [target.name].", "You sniff \the [target.name]...") - if(!isnull(target.reagents)) - var/dat = "" - for(var/id in target.reagents.reagent_volumes) - var/datum/reagent/R = SSchemistry.fetch_reagent(id) - dat += "\n \t [R]" - if(dat) - to_chat(user, "Your BOOP module indicates: [dat]") - else - to_chat(user, "No active chemical agents smelled in [target].") - else - if(istype(target, /obj/item/tank)) // don't double post what atmosanalyzer_scan returns - analyze_gases(target, user) - else - to_chat(user, "No significant chemical agents smelled in [target].") - return - - -//Delivery -/* -/obj/item/storage/bag/borgdelivery - name = "fetching storage" - desc = "Fetch the thing!" - icon = 'icons/mob/dogborg_vr.dmi' - icon_state = "dbag" - w_class = WEIGHT_CLASS_HUGE - max_single_weight_class = WEIGHT_CLASS_SMALL - max_combined_w_class = WEIGHT_CLASS_SMALL - max_items = 1 - collection_mode = 0 - can_hold = list() // any - cant_hold = list(/obj/item/disk/nuclear) -*/ - -/obj/item/shockpaddles/robot/hound - name = "paws of life" - icon = 'icons/mob/dogborg_vr.dmi' - icon_state = "defibpaddles0" - desc = "Zappy paws. For fixing cardiac arrest." - combat = 1 - attack_verb = list("batted", "pawed", "bopped", "whapped") - chargecost = 500 - -/obj/item/reagent_containers/borghypo/hound - name = "MediHound hypospray" - desc = "An advanced chemical synthesizer and injection system utilizing carrier's reserves, designed for heavy-duty medical equipment." - charge_cost = 10 - var/datum/matter_synth/water = null - reagent_ids = list("bicaridine", "kelotane", "alkysine", "imidazoline", "tricordrazine", "inaprovaline", "dexalin", "anti_toxin", "tramadol", "spaceacillin", "paracetamol") - -/obj/item/reagent_containers/borghypo/hound/process(delta_time) //Recharges in smaller steps and uses the water reserves as well. - if(isrobot(loc)) - var/mob/living/silicon/robot/R = loc - if(R && R.cell) - for(var/T in reagent_ids) - if(reagent_volumes[T] < volume && water.energy >= charge_cost) - R.cell.use(charge_cost) - water.use_charge(charge_cost) - reagent_volumes[T] = min(reagent_volumes[T] + 1, volume) - return 1 - -/obj/item/reagent_containers/borghypo/hound/lost - name = "Hound hypospray" - desc = "An advanced chemical synthesizer and injection system utilizing carrier's reserves." - reagent_ids = list("bicaridine", "kelotane", "alkysine", "imidazoline", "tricordrazine", "inaprovaline", "dexalin", "anti_toxin", "tramadol", "spaceacillin", "paracetamol") - - -//Tongue stuff -/obj/item/dogborg/tongue - name = "synthetic tongue" - desc = "Useful for slurping mess off the floor before affectionally licking the crew members in the face." - icon = 'icons/mob/dogborg_vr.dmi' - icon_state = "synthtongue" - attack_sound = 'sound/effects/attackblob.ogg' - item_flags = ITEM_NO_BLUDGEON | ITEM_ENCUMBERS_WHILE_HELD - var/emagged = 0 - var/datum/matter_synth/water = null - -/obj/item/dogborg/tongue/examine(user) - . = ..() - if(water.energy) - . += "[src] is wet." - if(water.energy < 5) - . += "[src] is dry." - -/obj/item/dogborg/tongue/attack_self(mob/user, datum/event_args/actor/actor) - . = ..() - if(.) - return - var/mob/living/silicon/robot/R = user - if(R.emagged || R.emag_items) - emagged = !emagged - if(emagged) - name = "hacked tongue of doom" - desc = "Your tongue has been upgraded successfully. Congratulations." - icon = 'icons/mob/dogborg_vr.dmi' - icon_state = "syndietongue" - else - name = "synthetic tongue" - desc = "Useful for slurping mess off the floor before affectionally licking the crew members in the face." - icon = 'icons/mob/dogborg_vr.dmi' - icon_state = "synthtongue" - update_icon() - -/obj/item/dogborg/tongue/afterattack(atom/target, mob/user, clickchain_flags, list/params) - if(!(clickchain_flags & CLICKCHAIN_HAS_PROXIMITY)) - return - - user.setClickCooldownLegacy(DEFAULT_ATTACK_COOLDOWN) - if(user.client && (target in user.client.screen)) - to_chat(user, "You need to take [target] off before cleaning it!") - if(istype(target, /obj/structure/sink) || istype(target, /obj/structure/toilet)) //Dog vibes. - user.visible_message("[user] begins to lap up water from [target].", "You begin to lap up water from [target].") - if(do_after(user, 50, target = target)) - water.add_charge(500) - else if(water.energy < 5) - to_chat(user, "Your mouth feels dry. You should drink some water.") //fixed annoying grammar and needless space - return - else if(istype(target,/obj/effect/debris/cleanable)) - user.visible_message("[user] begins to lick off [target].", "You begin to lick off [target]...") - if(do_after(user, 50, target = target)) - to_chat(user, "You finish licking off [target].") - water.use_charge(5) - qdel(target) - var/mob/living/silicon/robot/R = user - R.cell.charge += 50 - else if(istype(target,/obj/item)) - if(istype(target,/obj/item/trash)) - user.visible_message("[user] nibbles away at [target].", "You begin to nibble away at [target]...") - if(do_after(user, 50, target = target)) - user.visible_message("[user] finishes eating [target].", "You finish eating [target].") - to_chat(user, "You finish off [target].") - qdel(target) - var/mob/living/silicon/robot/R = user - if(istype(target,/obj/item/trash/rkibble)) - R.cell.charge += 1000 - else - R.cell.charge += 250 - water.use_charge(5) - return - if(istype(target,/obj/item/cell)) - user.visible_message("[user] begins cramming [target] down its throat.", "You begin cramming \the [target.name] down your throat...") - if(do_after(user, 50, target = target)) - user.visible_message("[user] finishes gulping down [target].", "You finish swallowing [target].") - to_chat(user, "You finish off [target], and gain some charge!") - var/mob/living/silicon/robot/R = user - var/obj/item/cell/C = target - R.cell.charge += C.max_charge / 3 - water.use_charge(5) - qdel(target) - return - user.visible_message("[user] begins to lick [target] clean...", "You begin to lick [target] clean...") - if(do_after(user, 50, target = target)) - to_chat(user, "You clean [target].") - water.use_charge(5) - var/obj/effect/debris/cleanable/C = locate() in target - qdel(C) - target.clean_blood() - else if(ishuman(target)) - if(src.emagged) - var/mob/living/silicon/robot/R = user - var/mob/living/L = target - if(R.cell.charge <= 666) - return - L.afflict_stun(20 * 1) - L.afflict_paralyze(20 * 1) - L.apply_effect(STUTTER, 1) - L.visible_message("[user] has shocked [L] with its tongue!", \ - "[user] has shocked you with its tongue! You can feel the betrayal.") - playsound(loc, 'sound/weapons/Egloves.ogg', 50, 1, -1) - R.cell.charge -= 666 - else - user.visible_message("\The [user] affectionally licks all over [target]'s face!", "You affectionally lick all over [target]'s face!") - playsound(src.loc, 'sound/effects/attackblob.ogg', 50, 1) - water.use_charge(5) - var/mob/living/carbon/human/H = target - if(H.species.lightweight == 1) - H.afflict_paralyze(20 * 3) - else - user.visible_message("[user] begins to lick [target] clean...", "You begin to lick [target] clean...") - if(do_after(user, 50, target = target)) - to_chat(user, "You clean [target].") - var/obj/effect/debris/cleanable/C = locate() in target - qdel(C) - target.clean_blood() - water.use_charge(5) - if(istype(target, /turf/simulated)) - var/turf/simulated/T = target - T.dirt = 0 - return - -/obj/item/pupscrubber - name = "floor scrubber" - desc = "Toggles floor scrubbing." - icon = 'icons/mob/dogborg_vr.dmi' - icon_state = "scrub0" - item_flags = ITEM_NO_BLUDGEON | ITEM_ENCUMBERS_WHILE_HELD - var/enabled = FALSE - -/obj/item/pupscrubber/attack_self(mob/user, datum/event_args/actor/actor) - . = ..() - if(.) - return - var/mob/living/silicon/robot/R = user - if(!enabled) - R.scrubbing = TRUE - enabled = TRUE - icon_state = "scrub1" - else - R.scrubbing = FALSE - enabled = FALSE - icon_state = "scrub0" - -/obj/item/dogborg/swordtail - name = "sword tail" - icon = 'icons/mob/dogborg_vr.dmi' - icon_state = "swordtail" - desc = "A glowing pink dagger normally attached to the end of a cyborg's tail. It appears to be extremely sharp." - damage_force = 20 //Takes 5 hits to 100-0 - damage_mode = DAMAGE_MODE_SHARP | DAMAGE_MODE_EDGE - throw_force = 0 //This shouldn't be thrown in the first place. - attack_sound = 'sound/weapons/blade1.ogg' - attack_verb = list("slashed", "stabbed", "jabbed", "mauled", "sliced") - w_class = WEIGHT_CLASS_NORMAL - -/obj/item/lightreplacer/dogborg - name = "light replacer" - desc = "A device to automatically replace lights. This version is capable to produce a few replacements using your internal matter reserves." - max_uses = 16 - uses = 10 - var/cooldown = 0 - var/datum/matter_synth/glass = null - -/obj/item/lightreplacer/dogborg/attack_self(mob/user, datum/event_args/actor/actor) - . = ..() - if(.) - return//Recharger refill is so last season. Now we recycle without magic! - if(uses >= max_uses) - to_chat(user, "[src.name] is full.") - return - if(uses < max_uses && cooldown == 0) - if(glass.energy < 125) - to_chat(user, "Insufficient material reserves.") - return - to_chat(user, "It has [uses] lights remaining. Attempting to fabricate a replacement. Please stand still.") - cooldown = 1 - if(do_after(user, 50)) - glass.use_charge(125) - add_uses(1) - cooldown = 0 - else - cooldown = 0 - else - to_chat(user, "It has [uses] lights remaining.") - return - -//Pounce stuff for K-9 -/obj/item/dogborg/pounce - name = "pounce" - icon = 'icons/mob/dogborg_vr.dmi' - icon_state = "pounce" - desc = "Leap at your target to momentarily stun them." - damage_force = 0 - item_flags = ITEM_NO_BLUDGEON | ITEM_ENCUMBERS_WHILE_HELD - throw_force = 0 - -/obj/item/dogborg/pounce/attack_self(mob/user, datum/event_args/actor/actor) - . = ..() - if(.) - return - var/mob/living/silicon/robot/R = user - R.leap() - -/mob/living/silicon/robot/proc/leap() - if(last_special > world.time) - to_chat(src, "Your leap actuators are still recharging.") - return - - if(cell.charge < 1000) - to_chat(src, "Cell charge too low to continue.") - return - - if(usr.incapacitated(INCAPACITATION_DISABLED)) - to_chat(src, "You cannot leap in your current state.") - return - - var/list/choices = list() - for(var/mob/living/M in view(3,src)) - if(!istype(M,/mob/living/silicon)) - choices += M - choices -= src - - var/mob/living/T = input(src,"Who do you wish to leap at?") as null|anything in choices - - if(!T || !src || src.stat) return - - if(get_dist(get_turf(T), get_turf(src)) > 3) return - - if(last_special > world.time) - return - - if(usr.incapacitated(INCAPACITATION_DISABLED)) - to_chat(src, "You cannot leap in your current state.") - return - - last_special = world.time + 10 - status_flags |= STATUS_LEAPING - pixel_y = pixel_y + 10 - - src.visible_message("\The [src] leaps at [T]!") - src.throw_at_old(get_step(get_turf(T),get_turf(src)), 4, 1, src) - playsound(src.loc, 'sound/mecha/mechstep2.ogg', 50, 1) - pixel_y = base_pixel_y - cell.charge -= 750 - - sleep(5) - - if(status_flags & STATUS_LEAPING) status_flags &= ~STATUS_LEAPING - - if(!src.Adjacent(T)) - to_chat(src, "You miss!") - return - - if(ishuman(T)) - var/mob/living/carbon/human/H = T - if(H.species.lightweight == 1) - H.afflict_paralyze(20 * 3) - return - var/armor_block = run_armor_check(T, "melee") - var/armor_soak = get_armor_soak(T, "melee") - T.apply_damage(20, DAMAGE_TYPE_HALLOSS,, armor_block, armor_soak) - if(prob(33)) - T.apply_effect(3, WEAKEN, armor_block) - -/obj/item/dogborg/mirrortool - name = "Mirror Installation Tool" - desc = "A tool for the installation and removal of Mirrors" - icon = 'icons/obj/device_alt.dmi' - icon_state = "sleevemate" - item_state = "healthanalyzer" - w_class = WEIGHT_CLASS_SMALL - var/obj/item/implant/mirror/imp = null - -/obj/item/dogborg/mirrortool/legacy_mob_melee_hook(mob/target, mob/user, clickchain_flags, list/params, mult, target_zone, intent) - var/mob/living/carbon/human/H = target - if(!istype(H)) - return - if(target_zone == BP_TORSO && imp == null) - for(var/obj/item/organ/I in H.organs) - for(var/obj/item/implant/mirror/MI in I.contents) - if(imp == null) - H.visible_message("[user] is attempting remove [H]'s mirror!") - user.setClickCooldownLegacy(DEFAULT_QUICK_COOLDOWN) - user.do_attack_animation(H) - var/turf/T1 = get_turf(H) - if (T1 && ((H == user) || do_after(user, 20))) - if(user && H && (get_turf(H) == T1) && src) - H.visible_message("[user] has removed [H]'s mirror.") - add_attack_logs(user,H,"Mirror removed by [user]") - src.imp = MI - qdel(MI) - else if (target_zone == BP_TORSO && imp != null) - if (imp) - H.visible_message("[user] is attempting to implant [H] with a mirror.") - user.setClickCooldownLegacy(DEFAULT_QUICK_COOLDOWN) - user.do_attack_animation(H) - var/turf/T1 = get_turf(H) - if (T1 && ((H == user) || do_after(user, 20))) - if(user && H && (get_turf(H) == T1) && src && src.imp) - H.visible_message("[H] has been implanted by [user].") - add_attack_logs(user,H,"Implanted with [imp.name] using [name]") - if(imp.handle_implant(H)) - imp.post_implant(H) - src.imp = null - else - to_chat(usr, "You must target the torso.") - -/obj/item/dogborg/mirrortool/afterattack(atom/target, mob/user, clickchain_flags, list/params) - var/obj/machinery/computer/transhuman/resleeving/comp = target - if(!istype(comp)) - return - comp.active_mr = imp.stored_mind diff --git a/code/modules/mob/living/silicon/robot/drone/drone.dm b/code/modules/mob/living/silicon/robot/drone/drone.dm index 71aa85f860b..7aa0d6a4bd8 100644 --- a/code/modules/mob/living/silicon/robot/drone/drone.dm +++ b/code/modules/mob/living/silicon/robot/drone/drone.dm @@ -1,7 +1,7 @@ /mob/living/silicon/robot/drone name = "maintenance drone" real_name = "drone" - icon = 'icons/mob/robots.dmi' + icon = 'icons/mob/robot-legacy.dmi' icon_state = "repairbot" maxHealth = 35 health = 35 @@ -16,6 +16,16 @@ req_access = list(ACCESS_ENGINEERING_MAIN, ACCESS_SCIENCE_ROBOTICS) integrated_light_power = 3 local_transmit = 1 + can_repick_frame = FALSE + can_repick_module = FALSE + + description_info = "Drones are player-controlled synthetics which are lawed to maintain the station and not \ + interact with anyone else, except for other drones. They hold a wide array of tools to build, repair, maintain, and clean. \ + They function similarly to other synthetics, in that they require recharging regularly, have laws, and are resilient to many hazards, \ + such as fire, radiation, vacuum, and more. Ghosts can join the round as a maintenance drone by using the appropriate verb in the 'ghost' tab. \ + An inactive drone can be rebooted by swiping an ID card on it with engineering or robotics access, and an active drone can be shut down in the same manner." + + description_antag = "An Electromagnetic Sequencer can be used to subvert the drone to your cause." can_pull_size = WEIGHT_CLASS_HUGE can_pull_mobs = MOB_PULL_SMALLER @@ -29,11 +39,14 @@ mob_size = MOB_SMALL // pulled here from a _vr file + conf_mmi_create_type = /obj/item/mmi/digital/robot + conf_cell_create_type = /obj/item/cell/basic/tier_1/medium + //Used for self-mailing. var/mail_destination = "" var/obj/machinery/drone_fabricator/master_fabricator - var/law_type = /datum/ai_laws/drone - var/module_type = /obj/item/robot_module/drone + var/law_type = /datum/ai_lawset/drone + var/module_type = /obj/item/robot_module_legacy/drone var/obj/item/hat var/hat_x_offset = 0 var/hat_y_offset = -13 @@ -69,26 +82,27 @@ /mob/living/silicon/robot/drone/construction name = "construction drone" icon_state = "constructiondrone" - law_type = /datum/ai_laws/construction_drone - module_type = /obj/item/robot_module/drone/construction + law_type = /datum/ai_lawset/drone/construction + module = /datum/prototype/robot_module/drone/construction hat_x_offset = 1 hat_y_offset = -12 can_pull_mobs = MOB_PULL_SAME - //holder_type = /obj/item/holder/drone/heavy -/mob/living/silicon/robot/drone/construction/matriarch + +/mob/living/silicon/robot/drone/matriarch name = "matriarch drone" - module_type = /obj/item/robot_module/drone/construction/matriarch - law_type = /datum/ai_laws/matriarch_drone + module = /datum/prototype/robot_module/drone/construction + law_type = /datum/ai_lawset/drone/matriarch maxHealth = 50 health = 50 integrated_light_power = 4 name_override = 1 var/matrix_tag + /mob/living/silicon/robot/drone/mining icon_state = "miningdrone" item_state = "constructiondrone" - law_type = /datum/ai_laws/mining_drone - module_type = /obj/item/robot_module/drone/mining + law_type = /datum/ai_lawset/drone/mining + module = /datum/prototype/robot_module/drone/mining hat_x_offset = 1 hat_y_offset = -12 can_pull_mobs = MOB_PULL_SAME @@ -102,13 +116,6 @@ add_language("Drone Talk", 1) serial_number = rand(0,999) - //They are unable to be upgraded, so let's give them a bit of a better battery. - cell.max_charge = 10000 - cell.charge = 10000 - - // NO BRAIN. - mmi = null - //We need to screw with their HP a bit. They have around one fifth as much HP as a full borg. for(var/V in components) if(V != "power cell") var/datum/robot_component/C = components[V] @@ -122,15 +129,15 @@ if(!scrambledcodes && !foreign_droid) aiCamera = new/obj/item/camera/siliconcam/drone_camera(src) additional_law_channels["Drone"] = ":d" - if(!laws) laws = new law_type - if(!module) module = new module_type(src) + if(!laws) + laws = new law_type flavor_text = "It's a tiny little repair drone. The casing is stamped with an corporate logo and the subscript: '[(LEGACY_MAP_DATUM).company_name] Recursive Repair Systems: Fixing Tomorrow's Problem, Today!'" playsound(src.loc, 'sound/machines/twobeep.ogg', 50, 0) //Redefining some robot procs... -/mob/living/silicon/robot/drone/construction/matriarch/Namepick() +/mob/living/silicon/robot/drone/matriarch/Namepick() set category = "Robot Commands" if(custom_name) return 0 @@ -170,11 +177,6 @@ add_overlay(overlays_to_add) -/mob/living/silicon/robot/drone/choose_icon() - return - -/mob/living/silicon/robot/drone/pick_module() - return /mob/living/silicon/robot/drone/proc/wear_hat(var/obj/item/new_hat) if(hat) @@ -195,7 +197,7 @@ wear_hat(W) user.visible_message("\The [user] puts \the [W] on \the [src].") return - else if(istype(W, /obj/item/borg/upgrade/)) + else if(istype(W, /obj/item/robot_upgrade/)) to_chat(user, "\The [src] is not compatible with \the [W].") return @@ -261,7 +263,7 @@ connected_ai = null clear_supplied_laws() clear_inherent_laws() - laws = new /datum/ai_laws/syndicate_override + laws = new /datum/ai_lawset/syndicate var/datum/gender/TU = GLOB.gender_datums[user.get_visible_gender()] set_zeroth_law("Only [user.real_name] and people [TU.he] designate[TU.s] as being such are operatives.") @@ -293,10 +295,6 @@ return ..() -//DRONE MOVEMENT. -/mob/living/silicon/robot/drone/Process_Spaceslipping(var/prob_slip) - return 0 - //CONSOLE PROCS /mob/living/silicon/robot/drone/proc/law_resync() if(stat != DEAD) @@ -382,30 +380,30 @@ ..() flavor_text = "It's a bulky mining drone stamped with a Grayson logo." -/mob/living/silicon/robot/drone/construction/matriarch/init() +/mob/living/silicon/robot/drone/matriarch/init() ..() add_verb(src, /mob/living/silicon/robot/verb/Namepick) flavor_text = "It's a small matriarch drone. The casing is stamped with an corporate logo and the subscript: '[(LEGACY_MAP_DATUM).company_name] Recursive Repair Systems: Heart Of The Swarm!'" -/mob/living/silicon/robot/drone/construction/matriarch/welcome_drone() +/mob/living/silicon/robot/drone/matriarch/welcome_drone() to_chat(src, "You are a matriarch maintenance drone, a tiny-brained robotic repair machine.") to_chat(src, "You have no individual will, no personality, and no drives or urges other than your laws.") to_chat(src, "Remember, you are lawed against interference with the crew. Also remember, you DO NOT take orders from the AI.") to_chat(src, "Use say ;Hello to talk to other drones and say Hello to speak silently to your nearby fellows.") -/mob/living/silicon/robot/drone/construction/matriarch/Initialize() +/mob/living/silicon/robot/drone/matriarch/Initialize() . = ..() matrix_tag = "[(LEGACY_MAP_DATUM).company_name]" -/mob/living/silicon/robot/drone/construction/matriarch/shut_down() +/mob/living/silicon/robot/drone/matriarch/shut_down() return -/mob/living/silicon/robot/drone/construction/matriarch/transfer_personality(client/player) +/mob/living/silicon/robot/drone/matriarch/transfer_personality(client/player) . = ..() assign_drone_to_matrix(src, matrix_tag) master_matrix.message_drones(SPAN_NOTICE("Energy surges through your circuits. The matriarch has come online.")) -/mob/living/silicon/robot/drone/construction/matriarch/ghostize(can_reenter_corpse, should_set_timer) +/mob/living/silicon/robot/drone/matriarch/ghostize(can_reenter_corpse, should_set_timer) . = ..() if(can_reenter_corpse || stat == DEAD) return diff --git a/code/modules/mob/living/silicon/robot/drone/drone_items.dm b/code/modules/mob/living/silicon/robot/drone/drone_items.dm index 10cfdb456d1..dbcb127ef91 100644 --- a/code/modules/mob/living/silicon/robot/drone/drone_items.dm +++ b/code/modules/mob/living/silicon/robot/drone/drone_items.dm @@ -1,17 +1,11 @@ -//TODO: Matter decompiler. +//TODO: (the) Matter decompiler (is shit) /obj/item/matter_decompiler name = "matter decompiler" desc = "Eating trash, bits of glass, or other debris will replenish your stores." icon = 'icons/obj/device.dmi' icon_state = "decompiler" - //Metal, glass, wood, plastic. - var/datum/matter_synth/metal = null - var/datum/matter_synth/glass = null - var/datum/matter_synth/wood = null - var/datum/matter_synth/plastic = null - /obj/item/matter_decompiler/afterattack(atom/target, mob/user, clickchain_flags, list/params) if(!(clickchain_flags & CLICKCHAIN_HAS_PROXIMITY)) return //Not adjacent. @@ -29,10 +23,8 @@ src.loc.visible_message("[src.loc] sucks [M] into its decompiler. There's a horrible crunching noise.","It's a bit of a struggle, but you manage to suck [M] into your decompiler. It makes a series of visceral crunching noises.") new/obj/effect/debris/cleanable/blood/splatter(get_turf(src)) qdel(M) - if(wood) - wood.add_charge(2000) - if(plastic) - plastic.add_charge(2000) + item_mount?.material_give_amount(src, null, /datum/prototype/material/wood_plank::id, 2000) + item_mount?.material_give_amount(src, null, /datum/prototype/material/plastic::id, 2000) return else if(istype(M,/mob/living/silicon/robot/drone) && !M.client) @@ -54,14 +46,10 @@ qdel(M) new/obj/effect/debris/cleanable/blood/oil(get_turf(src)) - if(metal) - metal.add_charge(15000) - if(glass) - glass.add_charge(15000) - if(wood) - wood.add_charge(2000) - if(plastic) - plastic.add_charge(1000) + item_mount?.material_give_amount(src, null, /datum/prototype/material/steel::id, 15000) + item_mount?.material_give_amount(src, null, /datum/prototype/material/glass::id, 15000) + item_mount?.material_give_amount(src, null, /datum/prototype/material/wood_plank::id, 2000) + item_mount?.material_give_amount(src, null, /datum/prototype/material/plastic::id, 1000) return else continue @@ -69,51 +57,35 @@ for(var/obj/W in T) //Different classes of items give different commodities. if(istype(W,/obj/item/cigbutt)) - if(plastic) - plastic.add_charge(500) + item_mount?.material_give_amount(src, null, /datum/prototype/material/plastic::id, 500) else if(istype(W,/obj/effect/spider/spiderling)) - if(wood) - wood.add_charge(2000) - if(plastic) - plastic.add_charge(2000) + item_mount?.material_give_amount(src, null, /datum/prototype/material/wood_plank::id, 2000) + item_mount?.material_give_amount(src, null, /datum/prototype/material/plastic::id, 2000) else if(istype(W,/obj/item/light)) var/obj/item/light/L = W if(L.status >= 2) //In before someone changes the inexplicably local defines. ~ Z - if(metal) - metal.add_charge(250) - if(glass) - glass.add_charge(250) + item_mount?.material_give_amount(src, null, /datum/prototype/material/steel::id, 250) + item_mount?.material_give_amount(src, null, /datum/prototype/material/glass::id, 250) else continue else if(istype(W,/obj/effect/decal/remains/robot)) - if(metal) - metal.add_charge(2000) - if(plastic) - plastic.add_charge(2000) - if(glass) - glass.add_charge(1000) + item_mount?.material_give_amount(src, null, /datum/prototype/material/steel::id, 2000) + item_mount?.material_give_amount(src, null, /datum/prototype/material/plastic::id, 2000) + item_mount?.material_give_amount(src, null, /datum/prototype/material/glass::id, 1000) else if(istype(W,/obj/item/trash)) - if(metal) - metal.add_charge(1000) - if(plastic) - plastic.add_charge(3000) + item_mount?.material_give_amount(src, null, /datum/prototype/material/steel::id, 1000) + item_mount?.material_give_amount(src, null, /datum/prototype/material/plastic::id, 3000) else if(istype(W,/obj/effect/debris/cleanable/blood/gibs/robot)) - if(metal) - metal.add_charge(2000) - if(glass) - glass.add_charge(2000) + item_mount?.material_give_amount(src, null, /datum/prototype/material/steel::id, 2000) + item_mount?.material_give_amount(src, null, /datum/prototype/material/glass::id, 2000) else if(istype(W,/obj/item/ammo_casing)) - if(metal) - metal.add_charge(1000) + item_mount?.material_give_amount(src, null, /datum/prototype/material/steel::id, 1000) else if(istype(W,/obj/item/material/shard/shrapnel)) - if(metal) - metal.add_charge(1000) + item_mount?.material_give_amount(src, null, /datum/prototype/material/steel::id, 1000) else if(istype(W,/obj/item/material/shard)) - if(glass) - glass.add_charge(1000) + item_mount?.material_give_amount(src, null, /datum/prototype/material/glass::id, 1000) else if(istype(W,/obj/item/reagent_containers/food/snacks/grown)) - if(wood) - wood.add_charge(4000) + item_mount?.material_give_amount(src, null, /datum/prototype/material/wood_plank::id, 4000) else if(istype(W,/obj/item/pipe)) // This allows drones and engiborgs to clear pipe assemblies from floors. else @@ -127,57 +99,3 @@ else to_chat(user, "Nothing on \the [T] is useful to you.") return - -//PRETTIER TOOL LIST. -/mob/living/silicon/robot/drone/installed_modules() - - if(weapon_lock) - to_chat(src, "Weapon lock active, unable to use modules! Count:[weaponlock_time]") - return - - if(!module) - module = new /obj/item/robot_module/drone(src) - - var/dat = "Drone modules\n" - dat += {" - Activated Modules -
- Module 1: [module_state_1 ? "[module_state_1]" : "No Module"]
- Module 2: [module_state_2 ? "
[module_state_2]" : "No Module"]
- Module 3: [module_state_3 ? "
[module_state_3]" : "No Module"]
-
- Installed Modules

"} - - - var/tools = "Tools and devices
" - var/resources = "
Resources
" - - for (var/O in module.modules) - - var/module_string = "" - - if (!O) - module_string += "Resource depleted
" - else if(activated(O)) - module_string += "[O]: Activated
" - else - module_string += "[O]:
Activate
" - - if((istype(O,/obj/item) || istype(O,/obj/item)) && !(istype(O,/obj/item/stack/cable_coil))) - tools += module_string - else - resources += module_string - - dat += tools - - if (emagged) - if (!module.emag) - dat += "Resource depleted
" - else if(activated(module.emag)) - dat += "[module.emag]: Activated
" - else - dat += "[module.emag]: Activate
" - - dat += resources - - src << browse(dat, "window=robotmod") diff --git a/code/modules/mob/living/silicon/robot/drone/drone_manufacturer.dm b/code/modules/mob/living/silicon/robot/drone/drone_manufacturer.dm index 0f453fe6fea..d5d17a6339b 100644 --- a/code/modules/mob/living/silicon/robot/drone/drone_manufacturer.dm +++ b/code/modules/mob/living/silicon/robot/drone/drone_manufacturer.dm @@ -6,7 +6,7 @@ /proc/count_matriarchs() var/matriarchs = 0 - for(var/mob/living/silicon/robot/drone/construction/matriarch/M in GLOB.player_list) + for(var/mob/living/silicon/robot/drone/matriarch/M in GLOB.player_list) matriarchs++ return matriarchs @@ -46,7 +46,7 @@ /obj/machinery/drone_fabricator/matriarch name = "matriarch drone fabricator" fabricator_tag = "Upper Level Matriarch" - drone_type = /mob/living/silicon/robot/drone/construction/matriarch + drone_type = /mob/living/silicon/robot/drone/matriarch /obj/machinery/drone_fabricator/update_icon_state() . = ..() @@ -97,7 +97,7 @@ if(!produce_drones || !config_legacy.allow_drone_spawn || count_drones() >= config_legacy.max_maint_drones) return - if((drone_type == /mob/living/silicon/robot/drone/construction/matriarch) && (count_matriarchs() > 0)) + if((drone_type == /mob/living/silicon/robot/drone/matriarch) && (count_matriarchs() > 0)) return if(player && !istype(player.mob,/mob/observer/dead)) diff --git a/code/modules/mob/living/silicon/robot/drone/matrix_hive.dm b/code/modules/mob/living/silicon/robot/drone/matrix_hive.dm index 8564c0fe17e..76e510692b4 100644 --- a/code/modules/mob/living/silicon/robot/drone/matrix_hive.dm +++ b/code/modules/mob/living/silicon/robot/drone/matrix_hive.dm @@ -83,17 +83,9 @@ var/global/list/drone_matrices = list() if(MTX_UPG_HEALTH) D.maxHealth += 15 if(MTX_UPG_MOP) - var/obj/item/mop/current_mop = locate(/obj/item/mop) in D.module.modules - if(!istype(current_mop, /obj/item/mop/advanced)) - D.module.modules -= current_mop - D.module.modules += new/obj/item/mop/advanced(D.module) - qdel(current_mop) + D.robot_inventory.inv_register(new /obj/item/mop/advanced) if(MTX_UPG_T) - var/obj/item/t_scanner/current_scanner = locate(/obj/item/t_scanner) in D.module.modules - if(!istype(current_scanner, /obj/item/t_scanner/upgraded)) - D.module.modules -= current_scanner - D.module.modules += new/obj/item/t_scanner/upgraded(D.module) - qdel(current_scanner) + D.robot_inventory.inv_register(new /obj/item/t_scanner/upgraded) LAZYADD(D.matrix_upgrades, upgrade_type) /proc/assign_drone_to_matrix(mob/living/silicon/robot/drone/D, var/matrix_tag) diff --git a/code/modules/mob/living/silicon/robot/drone/matrix_powers.dm b/code/modules/mob/living/silicon/robot/drone/matrix_powers.dm index 1355adaf5a9..6387e0450ab 100644 --- a/code/modules/mob/living/silicon/robot/drone/matrix_powers.dm +++ b/code/modules/mob/living/silicon/robot/drone/matrix_powers.dm @@ -10,7 +10,7 @@ var/datum/drone_matrix/DM = master_matrix var/dat = "" - var/mob/living/silicon/robot/drone/construction/matriarch/matriarch = DM.get_matriarch() + var/mob/living/silicon/robot/drone/matriarch/matriarch = DM.get_matriarch() if(matriarch) var/drone_stat = "" if(matriarch.stat == UNCONSCIOUS) @@ -56,7 +56,7 @@ to_chat(src, SPAN_NOTICE("Matrix upgrades active on chassis: [english_list(matrix_upgrades)]")) -/mob/living/silicon/robot/drone/construction/matriarch/verb/select_matrix_upgrades() +/mob/living/silicon/robot/drone/matriarch/verb/select_matrix_upgrades() set name = "Select Matrix Upgrades" set desc = "Select the upgrades to apply to the drones within your matrix." set category = "Matrix" diff --git a/code/modules/mob/living/silicon/robot/drone/swarm.dm b/code/modules/mob/living/silicon/robot/drone/swarm.dm index 8a45b86d418..57619865a95 100644 --- a/code/modules/mob/living/silicon/robot/drone/swarm.dm +++ b/code/modules/mob/living/silicon/robot/drone/swarm.dm @@ -1,98 +1,101 @@ -/mob/living/silicon/robot/drone/swarm - name = "swarm drone" - real_name = "drone" - icon = 'icons/mob/swarmbot.dmi' - icon_state = "swarmer" - iff_factions = MOB_IFF_FACTION_SWARMER - maxHealth = 75 - health = 75 - cell_emp_mult = 0.5 - universal_speak = 0 - universal_understand = 1 - gender = NEUTER - pass_flags = ATOM_PASS_TABLE - braintype = "Drone" - lawupdate = 0 - density = 1 - idcard_type = /obj/item/card/id/syndicate - req_access = list(999) - integrated_light_power = 3 - local_transmit = 0 +// TODO: IOU swarmers. - can_pull_size = WEIGHT_CLASS_HUGE - can_pull_mobs = MOB_PULL_SMALLER - can_enter_vent_with = list( - /obj) +// /mob/living/silicon/robot/drone/swarm +// name = "swarm drone" +// real_name = "drone" +// icon = 'icons/mob/swarmbot.dmi' +// icon_state = "swarmer" +// iff_factions = MOB_IFF_FACTION_SWARMER +// maxHealth = 75 +// health = 75 +// cell_emp_mult = 0.5 +// universal_speak = 0 +// universal_understand = 1 +// gender = NEUTER +// pass_flags = ATOM_PASS_TABLE +// braintype = "Drone" +// lawupdate = 0 +// density = 1 +// idcard_type = /obj/item/card/id/syndicate +// req_access = list(999) +// integrated_light_power = 3 +// local_transmit = 0 - mob_always_swap = 1 +// can_pull_size = WEIGHT_CLASS_HUGE +// can_pull_mobs = MOB_PULL_SMALLER +// can_enter_vent_with = list( +// /obj) - softfall = TRUE +// mob_always_swap = 1 - mob_size = MOB_LARGE +// softfall = TRUE - law_type = /datum/ai_laws/swarm_drone - module_type = /obj/item/robot_module/drone/swarm +// mob_size = MOB_LARGE - hat_x_offset = 0 - hat_y_offset = -10 +// law_type = /datum/ai_lawset/swarmer +// module = /datum/prototype/robot_module/s +// module_type = /obj/item/robot_module_legacy/drone/swarm - foreign_droid = TRUE - scrambledcodes = TRUE +// hat_x_offset = 0 +// hat_y_offset = -10 - holder_type = /obj/item/holder/drone +// foreign_droid = TRUE +// scrambledcodes = TRUE - can_be_antagged = TRUE +// holder_type = /obj/item/holder/drone - var/spell_setup = list( - /spell/aoe_turf/conjure/swarmer, - /spell/aoe_turf/conjure/forcewall/swarm, - /spell/aoe_turf/blink/swarm, - /spell/aoe_turf/conjure/swarmer/gunner, - /spell/aoe_turf/conjure/swarmer/melee - ) +// can_be_antagged = TRUE -/mob/living/silicon/robot/drone/swarm/Initialize(mapload) - . = ..() +// var/spell_setup = list( +// /spell/aoe_turf/conjure/swarmer, +// /spell/aoe_turf/conjure/forcewall/swarm, +// /spell/aoe_turf/blink/swarm, +// /spell/aoe_turf/conjure/swarmer/gunner, +// /spell/aoe_turf/conjure/swarmer/melee +// ) - add_language(LANGUAGE_SWARMBOT, 1) +// /mob/living/silicon/robot/drone/swarm/Initialize(mapload) +// . = ..() - for(var/spell in spell_setup) - src.add_spell(new spell, "nano_spell_ready", /atom/movable/screen/movable/spell_master/swarm) +// add_language(LANGUAGE_SWARMBOT, 1) -/mob/living/silicon/robot/drone/swarm/init() - ..() - QDEL_NULL(aiCamera) - flavor_text = "Some form of ancient machine." +// for(var/spell in spell_setup) +// src.add_spell(new spell, "nano_spell_ready", /atom/movable/screen/movable/spell_master/swarm) -/mob/living/silicon/robot/drone/swarm/gunner - name = "swarm gunner" - real_name = "drone" - icon = 'icons/mob/swarmbot.dmi' - icon_state = "swarmer_ranged" - iff_factions = MOB_IFF_FACTION_SWARMER +// /mob/living/silicon/robot/drone/swarm/init() +// ..() +// QDEL_NULL(aiCamera) +// flavor_text = "Some form of ancient machine." - law_type = /datum/ai_laws/swarm_drone/soldier - module_type = /obj/item/robot_module/drone/swarm/ranged +// /mob/living/silicon/robot/drone/swarm/gunner +// name = "swarm gunner" +// real_name = "drone" +// icon = 'icons/mob/swarmbot.dmi' +// icon_state = "swarmer_ranged" +// iff_factions = MOB_IFF_FACTION_SWARMER - spell_setup = list( - /spell/aoe_turf/conjure/swarmer, - /spell/aoe_turf/conjure/forcewall/swarm, - /spell/aoe_turf/blink/swarm - ) +// law_type = /datum/ai_lawset/swarmer/soldier +// module_type = /obj/item/robot_module_legacy/drone/swarm/ranged -/mob/living/silicon/robot/drone/swarm/melee - name = "swarm melee" - real_name = "drone" - icon = 'icons/mob/swarmbot.dmi' - icon_state = "swarmer_melee" - iff_factions = MOB_IFF_FACTION_SWARMER +// spell_setup = list( +// /spell/aoe_turf/conjure/swarmer, +// /spell/aoe_turf/conjure/forcewall/swarm, +// /spell/aoe_turf/blink/swarm +// ) - law_type = /datum/ai_laws/swarm_drone/soldier - module_type = /obj/item/robot_module/drone/swarm/melee +// /mob/living/silicon/robot/drone/swarm/melee +// name = "swarm melee" +// real_name = "drone" +// icon = 'icons/mob/swarmbot.dmi' +// icon_state = "swarmer_melee" +// iff_factions = MOB_IFF_FACTION_SWARMER - spell_setup = list( - /spell/aoe_turf/conjure/swarmer, - /spell/aoe_turf/conjure/forcewall/swarm, - /spell/aoe_turf/blink/swarm - ) +// law_type = /datum/ai_lawset/swarmer/soldier +// module_type = /obj/item/robot_module_legacy/drone/swarm/melee + +// spell_setup = list( +// /spell/aoe_turf/conjure/swarmer, +// /spell/aoe_turf/conjure/forcewall/swarm, +// /spell/aoe_turf/blink/swarm +// ) diff --git a/code/modules/mob/living/silicon/robot/drone/swarm_abilities.dm b/code/modules/mob/living/silicon/robot/drone/swarm_abilities.dm index 62a54e9ecdf..4a287092f54 100644 --- a/code/modules/mob/living/silicon/robot/drone/swarm_abilities.dm +++ b/code/modules/mob/living/silicon/robot/drone/swarm_abilities.dm @@ -1,117 +1,118 @@ +// TODO: IOU swarmers. -/spell/aoe_turf/conjure/swarmer - name = "Self Replication" - desc = "This ability constructs a standard swarmer shell that may activate at some point." +// /spell/aoe_turf/conjure/swarmer +// name = "Self Replication" +// desc = "This ability constructs a standard swarmer shell that may activate at some point." - school = "conjuration" - charge_max = 120 SECONDS - spell_flags = 0 - invocation = "none" - invocation_type = SpI_NONE - range = 0 +// school = "conjuration" +// charge_max = 120 SECONDS +// spell_flags = 0 +// invocation = "none" +// invocation_type = SpI_NONE +// range = 0 - summon_type = list(/obj/structure/ghost_pod/ghost_activated/swarm_drone/event) +// summon_type = list(/obj/structure/ghost_pod/ghost_activated/swarm_drone/event) - hud_state = "swarm_replicate" +// hud_state = "swarm_replicate" -/spell/aoe_turf/conjure/swarmer/conjure_animation(var/atom/movable/overlay/animation, var/turf/target) - animation.icon_state = "deflect_static" - flick("shield2",animation) - spawn(1 SECOND) - qdel(animation) +// /spell/aoe_turf/conjure/swarmer/conjure_animation(var/atom/movable/overlay/animation, var/turf/target) +// animation.icon_state = "deflect_static" +// flick("shield2",animation) +// spawn(1 SECOND) +// qdel(animation) -/spell/aoe_turf/conjure/forcewall/swarm - name = "Null-Field" - desc = "Create a bubble of null-point energy." - summon_type = list(/obj/effect/forcefield/swarm) - duration = 30 SECONDS - charge_max = 60 SECONDS +// /spell/aoe_turf/conjure/forcewall/swarm +// name = "Null-Field" +// desc = "Create a bubble of null-point energy." +// summon_type = list(/obj/effect/forcefield/swarm) +// duration = 30 SECONDS +// charge_max = 60 SECONDS - school = "conjuration" - invocation = "none" - invocation_type = SpI_NONE - range = 0 +// school = "conjuration" +// invocation = "none" +// invocation_type = SpI_NONE +// range = 0 - hud_state = "wiz_shield" +// hud_state = "wiz_shield" -/obj/effect/forcefield/swarm - desc = "A pocket of strange energy." - name = "Null-Field" - icon = 'icons/effects/effects.dmi' - icon_state = "shield-old" - invisibility = 0 +// /obj/effect/forcefield/swarm +// desc = "A pocket of strange energy." +// name = "Null-Field" +// icon = 'icons/effects/effects.dmi' +// icon_state = "shield-old" +// invisibility = 0 -/spell/aoe_turf/conjure/zeropointwell - name = "Zero-Point Well" - desc = "This ability constructs a standard zero-point energy well, capable of charging nearby swarmers." +// /spell/aoe_turf/conjure/zeropointwell +// name = "Zero-Point Well" +// desc = "This ability constructs a standard zero-point energy well, capable of charging nearby swarmers." - school = "conjuration" - charge_max = 120 SECONDS - spell_flags = 0 - invocation = "none" - invocation_type = SpI_NONE - range = 0 +// school = "conjuration" +// charge_max = 120 SECONDS +// spell_flags = 0 +// invocation = "none" +// invocation_type = SpI_NONE +// range = 0 - summon_type = list(/obj/structure/cult/pylon/swarm/zp_well) +// summon_type = list(/obj/structure/cult/pylon/swarm/zp_well) - hud_state = "swarm_zeropoint" +// hud_state = "swarm_zeropoint" -/spell/aoe_turf/conjure/zeropointbarricade - name = "Zero-Point Barricade" - desc = "This ability constructs a standard zero-point energy wall, used to create a secure passageway for allies, and a bastion for defense." +// /spell/aoe_turf/conjure/zeropointbarricade +// name = "Zero-Point Barricade" +// desc = "This ability constructs a standard zero-point energy wall, used to create a secure passageway for allies, and a bastion for defense." - school = "conjuration" - charge_max = 120 SECONDS - spell_flags = 0 - invocation = "none" - invocation_type = SpI_NONE - range = 0 +// school = "conjuration" +// charge_max = 120 SECONDS +// spell_flags = 0 +// invocation = "none" +// invocation_type = SpI_NONE +// range = 0 - summon_type = list(/obj/structure/cult/pylon/swarm/defender) +// summon_type = list(/obj/structure/cult/pylon/swarm/defender) - hud_state = "swarm_barricade" +// hud_state = "swarm_barricade" -/spell/aoe_turf/blink/swarm - name = "Warp" - desc = "Your null-point drive jaunts you to a new location." +// /spell/aoe_turf/blink/swarm +// name = "Warp" +// desc = "Your null-point drive jaunts you to a new location." - school = "abjuration" - charge_max = 5 MINUTES - spell_flags = Z2NOCAST | IGNOREDENSE - invocation = "none" - invocation_type = SpI_NONE - range = 10 - inner_radius = 5 - hud_state = "swarm_warp" +// school = "abjuration" +// charge_max = 5 MINUTES +// spell_flags = Z2NOCAST | IGNOREDENSE +// invocation = "none" +// invocation_type = SpI_NONE +// range = 10 +// inner_radius = 5 +// hud_state = "swarm_warp" -/spell/aoe_turf/conjure/swarmer/gunner - name = "Generate Gunner" - desc = "This spell constructs a gunner swarmer shell that may activate at some point." +// /spell/aoe_turf/conjure/swarmer/gunner +// name = "Generate Gunner" +// desc = "This spell constructs a gunner swarmer shell that may activate at some point." - school = "conjuration" - charge_type = Sp_CHARGES - charge_max = 1 - spell_flags = 0 - invocation = "none" - invocation_type = SpI_NONE - range = 0 +// school = "conjuration" +// charge_type = Sp_CHARGES +// charge_max = 1 +// spell_flags = 0 +// invocation = "none" +// invocation_type = SpI_NONE +// range = 0 - summon_type = list(/obj/structure/ghost_pod/ghost_activated/swarm_drone/event/gunner) +// summon_type = list(/obj/structure/ghost_pod/ghost_activated/swarm_drone/event/gunner) - hud_state = "swarm_replicate" +// hud_state = "swarm_replicate" -/spell/aoe_turf/conjure/swarmer/melee - name = "Generate Impaler" - desc = "This spell constructs an impaler swarmer shell that may activate at some point." +// /spell/aoe_turf/conjure/swarmer/melee +// name = "Generate Impaler" +// desc = "This spell constructs an impaler swarmer shell that may activate at some point." - school = "conjuration" - charge_type = Sp_CHARGES - charge_max = 1 - spell_flags = 0 - invocation = "none" - invocation_type = SpI_NONE - range = 0 +// school = "conjuration" +// charge_type = Sp_CHARGES +// charge_max = 1 +// spell_flags = 0 +// invocation = "none" +// invocation_type = SpI_NONE +// range = 0 - summon_type = list(/obj/structure/ghost_pod/ghost_activated/swarm_drone/event/melee) +// summon_type = list(/obj/structure/ghost_pod/ghost_activated/swarm_drone/event/melee) - hud_state = "swarm_replicate" +// hud_state = "swarm_replicate" diff --git a/code/modules/mob/living/silicon/robot/drone/swarm_items.dm b/code/modules/mob/living/silicon/robot/drone/swarm_items.dm index eea300ffdab..5ea4b090719 100644 --- a/code/modules/mob/living/silicon/robot/drone/swarm_items.dm +++ b/code/modules/mob/living/silicon/robot/drone/swarm_items.dm @@ -26,10 +26,9 @@ src.loc.visible_message("[src.loc] sucks [M] into its decompiler. There's a horrible crunching noise.","It's a bit of a struggle, but you manage to suck [M] into your decompiler. It makes a series of visceral crunching noises.") new/obj/effect/debris/cleanable/blood/splatter(get_turf(src)) qdel(M) - if(wood) - wood.add_charge(2000) - if(plastic) - plastic.add_charge(2000) + + item_mount?.material_give_amount(src, null, /datum/prototype/material/wood_plank, 2000) + item_mount?.material_give_amount(src, null, /datum/prototype/material/plastic, 2000) return else if(istype(M,/mob/living/silicon/robot/drone) && !M.client) @@ -51,14 +50,10 @@ qdel(M) new/obj/effect/debris/cleanable/blood/oil(get_turf(src)) - if(metal) - metal.add_charge(15000) - if(glass) - glass.add_charge(15000) - if(wood) - wood.add_charge(2000) - if(plastic) - plastic.add_charge(1000) + item_mount?.material_give_amount(src, null, /datum/prototype/material/steel::id, 15000) + item_mount?.material_give_amount(src, null, /datum/prototype/material/glass::id, 15000) + item_mount?.material_give_amount(src, null, /datum/prototype/material/wood_plank::id, 2000) + item_mount?.material_give_amount(src, null, /datum/prototype/material/plastic::id, 1000) return else continue @@ -66,31 +61,23 @@ for(var/obj/W in T) //Different classes of items give different commodities. if(istype(W,/obj/structure/girder)) - if(metal) - metal.add_charge(500) + item_mount?.material_give_amount(src, null, /datum/prototype/material/steel::id, 500) else if(istype(W,/obj/machinery/power/emitter)) - if(metal) - metal.add_charge(3000) - if(plastic) - plastic.add_charge(1000) + item_mount?.material_give_amount(src, null, /datum/prototype/material/steel::id, 3000) + item_mount?.material_give_amount(src, null, /datum/prototype/material/plastic::id, 1000) else if(istype(W,/obj/machinery/space_heater)) - if(metal) - metal.add_charge(1500) - if(plastic) - plastic.add_charge(750) + item_mount?.material_give_amount(src, null, /datum/prototype/material/steel::id, 1500) + item_mount?.material_give_amount(src, null, /datum/prototype/material/plastic::id, 750) else if(istype(W,/obj/structure/closet)) var/obj/structure/closet/C = W if(!C.opened) continue if(istype(W,/obj/structure/closet/coffin)) - if(wood) - wood.add_charge(1000) + item_mount?.material_give_amount(src, null, /datum/prototype/material/wood_plank::id, 1000) else if(istype(W,/obj/structure/closet/crate/plastic)) - if(plastic) - plastic.add_charge(750) + item_mount?.material_give_amount(src, null, /datum/prototype/material/plastic::id, 1000) else - if(metal) - metal.add_charge(1000) + item_mount?.material_give_amount(src, null, /datum/prototype/material/steel::id, 1000) else continue @@ -110,7 +97,6 @@ to_chat(user, "You deploy your decompiler and clear out the contents of \the [T].") else to_chat(user, "Nothing on \the [T] is useful to you.") - return /obj/effect/temporary_effect/pulse/disintegrate name = "molecular debonding field" diff --git a/code/modules/mob/living/silicon/robot/examine.dm b/code/modules/mob/living/silicon/robot/examine.dm index 694d8db64c6..874adb19694 100644 --- a/code/modules/mob/living/silicon/robot/examine.dm +++ b/code/modules/mob/living/silicon/robot/examine.dm @@ -1,5 +1,5 @@ /mob/living/silicon/robot/examine(mob/user, dist) - . = list("This is [icon2html(src, user)] \a [src][src.module && ", a [src.module.name] unit"]!") + . = list("This is [icon2html(src, user)] \a [src], a [src.module ? module.get_display_name() : "unformatted"] unit!") if(desc) . += "[desc]" @@ -49,7 +49,11 @@ if(DEAD) . += SPAN_DEADSAY("It looks like its system is corrupted and requires a reset.") - . += attempt_vr(src,"examine_bellies_borg",args) + var/message = "" + for(var/belly in vore_organs) + var/obj/belly/B = belly + message += B.get_examine_msg() + . += message if(showvoreprefs && ckey) //ckey so non-controlled mobs don't display it. . += SPAN_BOLDNOTICE("\[Mechanical Vore Preferences\]") diff --git a/code/modules/mob/living/silicon/robot/examine_vr.dm b/code/modules/mob/living/silicon/robot/examine_vr.dm deleted file mode 100644 index f3b04a440ad..00000000000 --- a/code/modules/mob/living/silicon/robot/examine_vr.dm +++ /dev/null @@ -1,8 +0,0 @@ -/mob/living/silicon/robot/proc/examine_bellies_borg() - - var/message = "" - for(var/belly in vore_organs) - var/obj/belly/B = belly - message += B.get_examine_msg() - - return message diff --git a/code/modules/mob/living/silicon/robot/iconset/baseline_droid.dm b/code/modules/mob/living/silicon/robot/iconset/baseline_droid.dm new file mode 100644 index 00000000000..dc3977e0d6d --- /dev/null +++ b/code/modules/mob/living/silicon/robot/iconset/baseline_droid.dm @@ -0,0 +1,17 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2024 Citadel Station Developers *// + +/datum/prototype/robot_iconset/baseline_droid + display_name = "Droid" + abstract_type = /datum/prototype/robot_iconset/baseline_droid + auto_chassis = /datum/prototype/robot_chassis/baseline + icon = 'icons/mob/robot/iconset/baseline_droid.dmi' + icon_state_cover = "panel" + +/datum/prototype/robot_iconset/baseline_droid/standard + icon_state = "standard" + icon_state_indicator = "standard-indicator" + +/datum/prototype/robot_iconset/baseline_droid/combat + icon_state = "combat" + icon_state_indicator = "combat-indicator" diff --git a/code/modules/mob/living/silicon/robot/iconset/baseline_drone.dm b/code/modules/mob/living/silicon/robot/iconset/baseline_drone.dm new file mode 100644 index 00000000000..5f2d2642451 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/iconset/baseline_drone.dm @@ -0,0 +1,18 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2024 Citadel Station Developers *// + +/datum/prototype/robot_iconset/baseline_drone + display_name = "Maintenance Drone" + abstract_type = /datum/prototype/robot_iconset/baseline_drone + auto_chassis = /datum/prototype/robot_chassis/baseline + icon = 'icons/mob/robot/iconset/baseline_drone.dmi' + icon_state_cover = "panel" + icon_state_indicator = "indicator-lights" + +/datum/prototype/robot_iconset/baseline_drone/construction + icon_state = "construction" + icon_state_indicator = "construction-indicator" + +/datum/prototype/robot_iconset/baseline_drone/mining + icon_state = "mining" + icon_state_indicator = "mining-indicator" diff --git a/code/modules/mob/living/silicon/robot/iconset/baseline_misc.dm b/code/modules/mob/living/silicon/robot/iconset/baseline_misc.dm new file mode 100644 index 00000000000..73d2a8b02bf --- /dev/null +++ b/code/modules/mob/living/silicon/robot/iconset/baseline_misc.dm @@ -0,0 +1,24 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2024 Citadel Station Developers *// + +/datum/prototype/robot_iconset/baseline_misc + abstract_type = /datum/prototype/robot_iconset/baseline_misc + auto_chassis = /datum/prototype/robot_chassis/baseline + icon = 'icons/mob/robot/iconset/baseline_misc.dmi' + icon_state_cover = "panel" + icon_state_indicator = "indicator-lights" + +/datum/prototype/robot_iconset/baseline_misc/omoikane + display_name = "Ward-Takashi - Omni" + icon_state = "omoikane" + icon_state_indicator = "omoikane-indicator" + +/datum/prototype/robot_iconset/baseline_misc/arachne + display_name = "Ward-Takashi - Arachne" + icon_state = "arachne" + icon_state_indicator = "arachne-indicator" + +/datum/prototype/robot_iconset/baseline_misc/squats + display_name = "Gorlex Marauders - Squats" + icon_state = "squats" + icon_state_indicator = "squats-indicator" diff --git a/code/modules/mob/living/silicon/robot/iconset/baseline_old.dm b/code/modules/mob/living/silicon/robot/iconset/baseline_old.dm new file mode 100644 index 00000000000..8d54d8f2b54 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/iconset/baseline_old.dm @@ -0,0 +1,65 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2024 Citadel Station Developers *// + +/datum/prototype/robot_iconset/baseline_old + display_name = "Basic" + abstract_type = /datum/prototype/robot_iconset/baseline_old + auto_chassis = /datum/prototype/robot_chassis/baseline + icon = 'icons/mob/robot/iconset/baseline_old.dmi' + icon_state_cover = "panel" + +/datum/prototype/robot_iconset/baseline_old/standard + icon_state = "standard" + +/datum/prototype/robot_iconset/baseline_old/yellowvest + icon_state = "yellowvest" + +/datum/prototype/robot_iconset/baseline_old/hazardvest + icon_state = "hazardvest" + +/datum/prototype/robot_iconset/baseline_old/engineer + icon_state = "engineer" + +/datum/prototype/robot_iconset/baseline_old/security + icon_state = "security" + +/datum/prototype/robot_iconset/baseline_old/security_2 + display_name = "Basic (Alt)" + icon_state = "security_2" + +/datum/prototype/robot_iconset/baseline_old/service_sweater + display_name = /datum/prototype/robot_iconset/baseline_old::display_name + " (Sweater)" + icon_state = "service_sweater" + +/datum/prototype/robot_iconset/baseline_old/service_skirt + display_name = /datum/prototype/robot_iconset/baseline_old::display_name + " (Skirt)" + icon_state = "service_skirt" + +/datum/prototype/robot_iconset/baseline_old/service + icon_state = "service" + +/datum/prototype/robot_iconset/baseline_old/service_fancy + display_name = /datum/prototype/robot_iconset/baseline_old::display_name + " (Fancy)" + icon_state = "service_fancy" + +/datum/prototype/robot_iconset/baseline_old/service_hydro + display_name = /datum/prototype/robot_iconset/baseline_old::display_name + " (Hydroponics)" + icon_state = "service_hydro" + +/datum/prototype/robot_iconset/baseline_old/medical + icon_state = "medical" + +/datum/prototype/robot_iconset/baseline_old/medical_2 + display_name = "Basic (Alt)" + icon_state = "medical_2" + +/datum/prototype/robot_iconset/baseline_old/security_riot + display_name = /datum/prototype/robot_iconset/baseline_old::display_name + " (Riot)" + icon_state = "security_riot" + +/datum/prototype/robot_iconset/baseline_old/janitor + icon_state = "janitor" + +/datum/prototype/robot_iconset/baseline_old/janitor_2 + display_name = "Basic (Alt)" + icon_state = "janitor_2" diff --git a/code/modules/mob/living/silicon/robot/iconset/baseline_standard.dm b/code/modules/mob/living/silicon/robot/iconset/baseline_standard.dm new file mode 100644 index 00000000000..74a6abd4398 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/iconset/baseline_standard.dm @@ -0,0 +1,36 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2024 Citadel Station Developers *// + +/datum/prototype/robot_iconset/baseline_standard + display_name = "M-USE" + abstract_type = /datum/prototype/robot_iconset/baseline_standard + auto_chassis = /datum/prototype/robot_chassis/baseline + icon = 'icons/mob/robot/iconset/baseline_standard.dmi' + icon_state_cover = "panel" + icon_state_indicator = "indicator-lights" + +/datum/prototype/robot_iconset/baseline_standard/security + icon_state = "security" + +/datum/prototype/robot_iconset/baseline_standard/medical + icon_state = "medical" + +/datum/prototype/robot_iconset/baseline_standard/engineering + icon_state = "engineering" + +/datum/prototype/robot_iconset/baseline_standard/janitor + icon_state = "janitor" + +/datum/prototype/robot_iconset/baseline_standard/service + display_name = /datum/prototype/robot_iconset/baseline_standard::display_name + " (Service)" + icon_state = "service" + +/datum/prototype/robot_iconset/baseline_standard/logistics + icon_state = "logistics" + +/datum/prototype/robot_iconset/baseline_standard/clerical + display_name = /datum/prototype/robot_iconset/baseline_standard::display_name + " (Clerical)" + icon_state = "clerical" + +/datum/prototype/robot_iconset/baseline_standard/standard + icon_state = "standard" diff --git a/code/modules/mob/living/silicon/robot/iconset/baseline_toiletbot.dm b/code/modules/mob/living/silicon/robot/iconset/baseline_toiletbot.dm new file mode 100644 index 00000000000..2a40517b0d1 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/iconset/baseline_toiletbot.dm @@ -0,0 +1,47 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2024 Citadel Station Developers *// + +/datum/prototype/robot_iconset/baseline_toiletbot + display_name = "Telemachus" + abstract_type = /datum/prototype/robot_iconset/baseline_toiletbot + auto_chassis = /datum/prototype/robot_chassis/baseline + icon = 'icons/mob/robot/iconset/baseline_toiletbot.dmi' + icon_state_cover = "panel" + icon_state_indicator = "indicator-lighting-utility" + +/datum/prototype/robot_iconset/baseline_toiletbot/standard + icon_state = "standard" + +/datum/prototype/robot_iconset/baseline_toiletbot/logistics + icon_state = "logistics" + icon_state_indicator = "indicator-lighting-industrial" + +/datum/prototype/robot_iconset/baseline_toiletbot/medical + icon_state = "medical" + icon_state_indicator = "indicator-lighting-medical" + +/datum/prototype/robot_iconset/baseline_toiletbot/surgeon + icon_state = "surgeon" + icon_state_indicator = "indicator-lighting-medical" + +/datum/prototype/robot_iconset/baseline_toiletbot/security + icon_state = "security" + +/datum/prototype/robot_iconset/baseline_toiletbot/engineering + icon_state = "engineering" + icon_state_indicator = "indicator-lighting-industrial" + +/datum/prototype/robot_iconset/baseline_toiletbot/janitor + icon_state = "janitor" + +/datum/prototype/robot_iconset/baseline_toiletbot/antag + icon_state = "antag" + icon_state_indicator = "indicator-lighting-antag" + +/datum/prototype/robot_iconset/baseline_toiletbot/syndicate + icon_state = "syndicate" + icon_state_indicator = "indicator-lighting-syndicate" + +/datum/prototype/robot_iconset/baseline_toiletbot/ninja + icon_state = "ninja" + icon_state_indicator = "indicator-lighting-ninja" diff --git a/code/modules/mob/living/silicon/robot/iconset/biped_droid.dm b/code/modules/mob/living/silicon/robot/iconset/biped_droid.dm new file mode 100644 index 00000000000..d10dd977143 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/iconset/biped_droid.dm @@ -0,0 +1,21 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2024 Citadel Station Developers *// + +/datum/prototype/robot_iconset/biped_droid + display_name = "Droid" + abstract_type = /datum/prototype/robot_iconset/biped_droid + auto_chassis = /datum/prototype/robot_chassis/biped + icon = 'icons/mob/robot/iconset/biped_droid.dmi' + icon_state_cover = "panel" + +/datum/prototype/robot_iconset/biped_droid/logistics + icon_state = "logistics" + icon_state_indicator = "indicator-lighting-logistics" + +/datum/prototype/robot_iconset/biped_droid/medical + icon_state = "medical" + icon_state_indicator = "indicator-lighting-medical" + +/datum/prototype/robot_iconset/biped_droid/science + icon_state = "science" + icon_state_indicator = "indicator-lighting-medical" diff --git a/code/modules/mob/living/silicon/robot/iconset/biped_heavy.dm b/code/modules/mob/living/silicon/robot/iconset/biped_heavy.dm new file mode 100644 index 00000000000..89b0c4bbb86 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/iconset/biped_heavy.dm @@ -0,0 +1,41 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2024 Citadel Station Developers *// + +/datum/prototype/robot_iconset/biped_heavy + display_name = "XI-ALP" + abstract_type = /datum/prototype/robot_iconset/biped_heavy + auto_chassis = /datum/prototype/robot_chassis/biped + icon = 'icons/mob/robot/iconset/biped_heavy.dmi' + icon_state_cover = "panel" + +/datum/prototype/robot_iconset/biped_heavy/medical + icon_state = "medical" + icon_state_indicator = "indicator-lighting" + +/datum/prototype/robot_iconset/biped_heavy/service + icon_state = "service" + icon_state_indicator = "indicator-service" + +/datum/prototype/robot_iconset/biped_heavy/security + icon_state = "security" + icon_state_indicator = "indicator-security" + +/datum/prototype/robot_iconset/biped_heavy/engineering + icon_state = "engineering" + icon_state_indicator = "indicator-engineering" + +/datum/prototype/robot_iconset/biped_heavy/miner + icon_state = "miner" + icon_state_indicator = "indicator-miner" + +/datum/prototype/robot_iconset/biped_heavy/research + icon_state = "research" + icon_state_indicator = "indicator-security" + +/datum/prototype/robot_iconset/biped_heavy/standard + icon_state = "standard" + icon_state_indicator = "indicator-lighting" + +/datum/prototype/robot_iconset/biped_heavy/antag + icon_state = "antag" + icon_state_indicator = "indicator-lighting-antag" diff --git a/code/modules/mob/living/silicon/robot/iconset/biped_insekt.dm b/code/modules/mob/living/silicon/robot/iconset/biped_insekt.dm new file mode 100644 index 00000000000..f36a040ab71 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/iconset/biped_insekt.dm @@ -0,0 +1,29 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2024 Citadel Station Developers *// + +/datum/prototype/robot_iconset/biped_insekt + display_name = "Insekt" + abstract_type = /datum/prototype/robot_iconset/biped_insekt + auto_chassis = /datum/prototype/robot_chassis/biped + icon = 'icons/mob/robot/iconset/biped_insekt.dmi' + icon_state_cover = "panel" + +/datum/prototype/robot_iconset/biped_insekt/standard + icon_state = "standard" + icon_state_indicator = "standard-indicator" + +/datum/prototype/robot_iconset/biped_insekt/security + icon_state = "security" + icon_state_indicator = "security-indicator" + +/datum/prototype/robot_iconset/biped_insekt/medical + icon_state = "medical" + icon_state_indicator = "medical-indicator" + +/datum/prototype/robot_iconset/biped_insekt/combat + icon_state = "combat" + icon_state_indicator = "combat-indicator" + +/datum/prototype/robot_iconset/biped_insekt/science + icon_state = "science" + icon_state_indicator = "science-indicator" diff --git a/code/modules/mob/living/silicon/robot/iconset/biped_k4t.dm b/code/modules/mob/living/silicon/robot/iconset/biped_k4t.dm new file mode 100644 index 00000000000..d2144f74a2f --- /dev/null +++ b/code/modules/mob/living/silicon/robot/iconset/biped_k4t.dm @@ -0,0 +1,19 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2024 Citadel Station Developers *// + +// Attributions // +// All sprites used in this file made by Zydras // + +/datum/prototype/robot_iconset/biped_k4t + display_name = "K4T" + icon_state = "k4t" + icon_state_cover = "panel" + icon_state_indicator = "indicator" + + auto_chassis = /datum/prototype/robot_chassis/biped + + variations = list( + /datum/robot_iconset_variation/bellyup, + /datum/robot_iconset_variation/dead, + /datum/robot_iconset_variation/resting, + ) diff --git a/code/modules/mob/living/silicon/robot/iconset/biped_maid.dm b/code/modules/mob/living/silicon/robot/iconset/biped_maid.dm new file mode 100644 index 00000000000..3c5ff0f32cb --- /dev/null +++ b/code/modules/mob/living/silicon/robot/iconset/biped_maid.dm @@ -0,0 +1,11 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2024 Citadel Station Developers *// + +/datum/prototype/robot_iconset/biped_maid + display_name = "Maid" + abstract_type = /datum/prototype/robot_iconset/biped_maid + auto_chassis = /datum/prototype/robot_chassis/biped + icon = 'icons/mob/robot/iconset/biped_maid.dmi' + icon_state = "maid" + icon_state_cover = "panel" + icon_state_indicator = "indicator" diff --git a/code/modules/mob/living/silicon/robot/iconset/biped_marina.dm b/code/modules/mob/living/silicon/robot/iconset/biped_marina.dm new file mode 100644 index 00000000000..9bb082f8cdc --- /dev/null +++ b/code/modules/mob/living/silicon/robot/iconset/biped_marina.dm @@ -0,0 +1,45 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2024 Citadel Station Developers *// + +/datum/prototype/robot_iconset/biped_marina + display_name = "Haruka" + abstract_type = /datum/prototype/robot_iconset/biped_marina + auto_chassis = /datum/prototype/robot_chassis/biped + icon = 'icons/mob/robot/iconset/biped_marina.dmi' + icon_state_cover = "panel" + +/datum/prototype/robot_iconset/biped_marina/medical + icon_state = "medical" + icon_state_indicator = "indicator-medical" + +/datum/prototype/robot_iconset/biped_marina/service + icon_state = "service" + icon_state_indicator = "indicator-service" + +/datum/prototype/robot_iconset/biped_marina/miner + icon_state = "miner" + icon_state_indicator = "indicator-miner" + +/datum/prototype/robot_iconset/biped_marina/security + icon_state = "security" + icon_state_indicator = "indicator-security" + +/datum/prototype/robot_iconset/biped_marina/engineering + icon_state = "engineering" + icon_state_indicator = "indicator-engineering" + +/datum/prototype/robot_iconset/biped_marina/janitor + icon_state = "janitor" + icon_state_indicator = "indicator-janitor" + +/datum/prototype/robot_iconset/biped_marina/standard + icon_state = "standard" + icon_state_indicator = "indicator-standard" + +/datum/prototype/robot_iconset/biped_marina/service + icon_state = "service" + icon_state_indicator = "indicator-service" + +/datum/prototype/robot_iconset/biped_marina/combat + icon_state = "combat" + icon_state_indicator = "indicator-combat" diff --git a/code/modules/mob/living/silicon/robot/iconset/biped_meka.dm b/code/modules/mob/living/silicon/robot/iconset/biped_meka.dm new file mode 100644 index 00000000000..3fd52b983d3 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/iconset/biped_meka.dm @@ -0,0 +1,36 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2024 Citadel Station Developers *// + +// Attributions // +// All sprites used in this file made by GhostSheep/TheOOZ // + +/datum/prototype/robot_iconset/biped_meka + display_name = "Meka" + abstract_type = /datum/prototype/robot_iconset/biped_meka + auto_chassis = /datum/prototype/robot_chassis/biped + + variations = list( + /datum/robot_iconset_variation/sitting, + /datum/robot_iconset_variation/dead, + /datum/robot_iconset_variation/resting, + ) + +/datum/prototype/robot_iconset/biped_meka/one + icon_state = "one" + icon_state_indicator = "one-indicator" + icon_state_cover = "one-cell" + +/datum/prototype/robot_iconset/biped_meka/two + icon_state = "two" + icon_state_indicator = "two-indicator" + icon_state_cover = "two-cell" + +/datum/prototype/robot_iconset/biped_meka/three + icon_state = "three" + icon_state_indicator = "three-indicator" + icon_state_cover = "three-cell" + +/datum/prototype/robot_iconset/biped_meka/four + icon_state = "four" + icon_state_indicator = "four-indicator" + icon_state_cover = "four-cell" diff --git a/code/modules/mob/living/silicon/robot/iconset/biped_miss.dm b/code/modules/mob/living/silicon/robot/iconset/biped_miss.dm new file mode 100644 index 00000000000..d2250abdc6e --- /dev/null +++ b/code/modules/mob/living/silicon/robot/iconset/biped_miss.dm @@ -0,0 +1,37 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2024 Citadel Station Developers *// + +/datum/prototype/robot_iconset/biped_miss + display_name = "Miss M" + abstract_type = /datum/prototype/robot_iconset/biped_miss + auto_chassis = /datum/prototype/robot_chassis/biped + icon = 'icons/mob/robot/iconset/biped_miss.dmi' + icon_state_cover = "panel" + +/datum/prototype/robot_iconset/biped_miss/standard + icon_state = "standard" + icon_state_indicator = "standard-indicator" + +/datum/prototype/robot_iconset/biped_miss/engineering + icon_state = "engineering" + icon_state_indicator = "engineering-indicator" + +/datum/prototype/robot_iconset/biped_miss/medical + icon_state = "medical" + icon_state_indicator = "medical-indicator" + +/datum/prototype/robot_iconset/biped_miss/janitor + icon_state = "janitor" + icon_state_indicator = "janitor-indicator" + +/datum/prototype/robot_iconset/biped_miss/mining + icon_state = "mining" + icon_state_indicator = "mining-indicator" + +/datum/prototype/robot_iconset/biped_miss/service + icon_state = "service" + icon_state_indicator = "service-indicator" + +/datum/prototype/robot_iconset/biped_miss/security + icon_state = "security" + icon_state_indicator = "security-indicator" diff --git a/code/modules/mob/living/silicon/robot/iconset/biped_noble.dm b/code/modules/mob/living/silicon/robot/iconset/biped_noble.dm new file mode 100644 index 00000000000..8fe8313bb4b --- /dev/null +++ b/code/modules/mob/living/silicon/robot/iconset/biped_noble.dm @@ -0,0 +1,37 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2024 Citadel Station Developers *// + +/datum/prototype/robot_iconset/biped_noble + display_name = "Shellguard Noble" + abstract_type = /datum/prototype/robot_iconset/biped_noble + auto_chassis = /datum/prototype/robot_chassis/biped + icon = 'icons/mob/robot/iconset/biped_noble.dmi' + icon_state_cover = "panel" + +/datum/prototype/robot_iconset/biped_noble/standard + icon_state = "standard" + icon_state_indicator = "standard-indicator" + +/datum/prototype/robot_iconset/biped_noble/janitor + icon_state = "janitor" + icon_state_indicator = "janitor-indicator" + +/datum/prototype/robot_iconset/biped_noble/mining + icon_state = "mining" + icon_state_indicator = "mining-indicator" + +/datum/prototype/robot_iconset/biped_noble/service + icon_state = "service" + icon_state_indicator = "service-indicator" + +/datum/prototype/robot_iconset/biped_noble/engineering + icon_state = "engineering" + icon_state_indicator = "engineering-indicator" + +/datum/prototype/robot_iconset/biped_noble/medical + icon_state = "medical" + icon_state_indicator = "medical-indicator" + +/datum/prototype/robot_iconset/biped_noble/security + icon_state = "security" + icon_state_indicator = "security-indicator" diff --git a/code/modules/mob/living/silicon/robot/iconset/biped_sleek.dm b/code/modules/mob/living/silicon/robot/iconset/biped_sleek.dm new file mode 100644 index 00000000000..24ba3702fab --- /dev/null +++ b/code/modules/mob/living/silicon/robot/iconset/biped_sleek.dm @@ -0,0 +1,52 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2024 Citadel Station Developers *// + +/datum/prototype/robot_iconset/biped_sleek + display_name = "Ward-Takashi Operator" + abstract_type = /datum/prototype/robot_iconset/biped_sleek + auto_chassis = /datum/prototype/robot_chassis/biped + icon = 'icons/mob/robot/iconset/biped_sleek.dmi' + icon_state_cover = "panel" + icon_state_indicator = "indicator" + +/datum/prototype/robot_iconset/biped_sleek/standard + icon_state = "standard" + +/datum/prototype/robot_iconset/biped_sleek/janitor + icon_state = "janitor" + +/datum/prototype/robot_iconset/biped_sleek/medical + display_name = /datum/prototype/robot_iconset/biped_sleek::display_name + " (Medical)" + icon_state = "medical" + +/datum/prototype/robot_iconset/biped_sleek/security + icon_state = "security" + icon_state_indicator = "indicator-security" + +/datum/prototype/robot_iconset/biped_sleek/mining + icon_state = "mining" + +/datum/prototype/robot_iconset/biped_sleek/service + icon_state = "service" + +/datum/prototype/robot_iconset/biped_sleek/science + icon_state = "science" + +/datum/prototype/robot_iconset/biped_sleek/clerical + icon_state = "clerical" + +/datum/prototype/robot_iconset/biped_sleek/engineering + icon_state = "engineering" + icon_state_indicator = "indicator-commmand" + +/datum/prototype/robot_iconset/biped_sleek/cmo + display_name = /datum/prototype/robot_iconset/biped_sleek::display_name + " (CMO)" + icon_state = "cmo" + icon_state_indicator = "indicator-commmand" + +/datum/prototype/robot_iconset/biped_sleek/hos + icon_state = "hos" + icon_state_indicator = "indicator-security" + +/datum/prototype/robot_iconset/biped_sleek/gravekeeper + icon_state = "gravekeeper" diff --git a/code/modules/mob/living/silicon/robot/iconset/biped_tall.dm b/code/modules/mob/living/silicon/robot/iconset/biped_tall.dm new file mode 100644 index 00000000000..777e0802c50 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/iconset/biped_tall.dm @@ -0,0 +1,73 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2024 Citadel Station Developers *// + +/datum/prototype/robot_iconset/biped_tall + display_name = "Usagi" + abstract_type = /datum/prototype/robot_iconset/biped_tall + auto_chassis = /datum/prototype/robot_chassis/biped + icon = 'icons/mob/robot/iconset/biped_tall.dmi' + icon_state_cover = "panel" + +/datum/prototype/robot_iconset/biped_tall/tallblue + icon_state = "tallblue" + icon_state_indicator = "tallblue-indicator" + +/datum/prototype/robot_iconset/biped_tall/tallyellow + icon_state = "tallyellow" + icon_state_indicator = "tallyellow-indicator" + +/datum/prototype/robot_iconset/biped_tall/tallflower + icon_state = "tallflower" + icon_state_indicator = "tallflower-indicator" + +/datum/prototype/robot_iconset/biped_tall/tallgreen + icon_state = "tallgreen" + icon_state_indicator = "tallgreen-indicator" + +/datum/prototype/robot_iconset/biped_tall/tallred + icon_state = "tallred" + icon_state_indicator = "tallred-indicator" + +/datum/prototype/robot_iconset/biped_tall/tallwhite + icon_state = "tallwhite" + icon_state_indicator = "tallwhite-indicator" + +/datum/prototype/robot_iconset/biped_tall/alternative + abstract_type = /datum/prototype/robot_iconset/biped_tall/alternative + display_name = "Misato" + +/datum/prototype/robot_iconset/biped_tall/alternative/miner + icon_state = "tall2miner" + icon_state_indicator = "tall2miner-indicator" + +/datum/prototype/robot_iconset/biped_tall/alternative/engineer + icon_state = "tall2engineer" + icon_state_indicator = "tall2engineer-indicator" + +/datum/prototype/robot_iconset/biped_tall/alternative/service + icon_state = "tall2service" + icon_state_indicator = "tall2service-indicator" + +/datum/prototype/robot_iconset/biped_tall/alternative/janitor + icon_state = "tall2janitor" + icon_state_indicator = "tall2janitor-indicator" + +/datum/prototype/robot_iconset/biped_tall/alternative/security + icon_state = "tall2security" + icon_state_indicator = "tall2security-indicator" + +/datum/prototype/robot_iconset/biped_tall/alternative/medical + icon_state = "tall2medical" + icon_state_indicator = "tall2medical-indicator" + +/datum/prototype/robot_iconset/biped_tall/alternative/standard + icon_state = "tall2standard" + icon_state_indicator = "tall2standard-indicator" + +/datum/prototype/robot_iconset/biped_tall/alternative/peace + icon_state = "tall2peace" + icon_state_indicator = "tall2peace-indicator" + +/datum/prototype/robot_iconset/biped_tall/alternative/clown + icon_state = "tall2clown" + icon_state_indicator = "tall2clown-indicator" diff --git a/code/modules/mob/living/silicon/robot/iconset/cat_feli.dm b/code/modules/mob/living/silicon/robot/iconset/cat_feli.dm new file mode 100644 index 00000000000..e4383b2afe1 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/iconset/cat_feli.dm @@ -0,0 +1,46 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2024 Citadel Station Developers *// + +/datum/prototype/robot_iconset/cat_feli + display_name = "F3-LINE" + abstract_type = /datum/prototype/robot_iconset/cat_feli + auto_chassis = /datum/prototype/robot_chassis/quadruped/feline + icon = 'icons/mob/robot/iconset/cat_feli.dmi' + icon_state_cover = "panel" + icon_dimension_x = 64 + +/datum/prototype/robot_iconset/cat_feli/standard + icon_state = "standard" + icon_state_indicator = "standard-indicator" + +/datum/prototype/robot_iconset/cat_feli/engineering + icon_state = "engineering" + icon_state_indicator = "engineering-indicator" + +/datum/prototype/robot_iconset/cat_feli/medical + icon_state = "medical" + icon_state_indicator = "medical-indicator" + +/datum/prototype/robot_iconset/cat_feli/research + icon_state = "research" + icon_state_indicator = "research-indicator" + +/datum/prototype/robot_iconset/cat_feli/mining + icon_state = "mining" + icon_state_indicator = "mining-indicator" + +/datum/prototype/robot_iconset/cat_feli/service + icon_state = "service" + icon_state_indicator = "service-indicator" + +/datum/prototype/robot_iconset/cat_feli/janitor + icon_state = "janitor" + icon_state_indicator = "janitor-indicator" + +/datum/prototype/robot_iconset/cat_feli/security + icon_state = "security" + icon_state_indicator = "security-indicator" + +/datum/prototype/robot_iconset/cat_feli/combat + icon_state = "combat" + icon_state_indicator = "combat-indicator" diff --git a/code/modules/mob/living/silicon/robot/iconset/dog_borgi.dm b/code/modules/mob/living/silicon/robot/iconset/dog_borgi.dm new file mode 100644 index 00000000000..0b266fca708 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/iconset/dog_borgi.dm @@ -0,0 +1,35 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2024 Citadel Station Developers *// + +/datum/prototype/robot_iconset/dog_borgi + display_name = "Borgi" + abstract_type = /datum/prototype/robot_iconset/dog_borgi + auto_chassis = /datum/prototype/robot_chassis/quadruped/canine + icon = 'icons/mob/robot/iconset/dog_borgi.dmi' + icon_state_cover = "panel" + icon_state_indicator = "indicator" + icon_dimension_x = 64 + variations = list( + /datum/robot_iconset_variation/bellyup, + /datum/robot_iconset_variation/resting, + /datum/robot_iconset_variation/sitting, + /datum/robot_iconset_variation/dead, + ) + +/datum/prototype/robot_iconset/dog_borgi/standard + icon_state = "standard" + +/datum/prototype/robot_iconset/dog_borgi/engineering + icon_state = "engineering" + +/datum/prototype/robot_iconset/dog_borgi/janitor + icon_state = "janitor" + +/datum/prototype/robot_iconset/dog_borgi/medical + icon_state = "medical" + +/datum/prototype/robot_iconset/dog_borgi/science + icon_state = "science" + +/datum/prototype/robot_iconset/dog_borgi/security + icon_state = "security" diff --git a/code/modules/mob/living/silicon/robot/iconset/dog_k9.dm b/code/modules/mob/living/silicon/robot/iconset/dog_k9.dm new file mode 100644 index 00000000000..a1fbf7370f0 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/iconset/dog_k9.dm @@ -0,0 +1,78 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2024 Citadel Station Developers *// + +/datum/prototype/robot_iconset/dog_k9 + display_name = "K9" + abstract_type = /datum/prototype/robot_iconset/dog_k9 + + auto_chassis = /datum/prototype/robot_chassis/quadruped/canine + + icon = 'icons/mob/robot/iconset/dog_k9.dmi' + icon_state_cover = "panel" + icon_dimension_x = 64 + variations = list( + /datum/robot_iconset_variation/bellyup, + /datum/robot_iconset_variation/resting, + /datum/robot_iconset_variation/dead, + /datum/robot_iconset_variation/sitting, + ) + +/datum/prototype/robot_iconset/dog_k9/security + icon_state = "security" + icon_state_indicator = "security-indicator" + +/datum/prototype/robot_iconset/dog_k9/medical + icon_state = "medical" + icon_state_indicator = "medical-indicator" + +/datum/prototype/robot_iconset/dog_k9/pink + icon_state = "pink" + icon_state_indicator = "pink-indicator" + +/datum/prototype/robot_iconset/dog_k9/red + icon_state = "red" + icon_state_indicator = "red-indicator" + +/datum/prototype/robot_iconset/dog_k9/medical_dark + display_name = /datum/prototype/robot_iconset/dog_k9::display_name + " (Dark)" + icon_state = "medical_dark" + icon_state_indicator = "medical_dark-indicator" + +/datum/prototype/robot_iconset/dog_k9/science_dark + display_name = /datum/prototype/robot_iconset/dog_k9::display_name + " (Dark)" + icon_state = "science_dark" + icon_state_indicator = "science_dark-indicator" + +/datum/prototype/robot_iconset/dog_k9/science + icon_state = "science" + icon_state_indicator = "science-indicator" + +/datum/prototype/robot_iconset/dog_k9/engineering_dark + display_name = /datum/prototype/robot_iconset/dog_k9::display_name + " (Dark)" + icon_state = "engineering_dark" + icon_state_indicator = "engineering_dark-indicator" + +/datum/prototype/robot_iconset/dog_k9/engineering + icon_state = "engineering" + icon_state_indicator = "engineering-indicator" + +/datum/prototype/robot_iconset/dog_k9/logistics_dark + display_name = /datum/prototype/robot_iconset/dog_k9::display_name + " (Dark)" + icon_state = "logistics_dark" + icon_state_indicator = "logistics_dark-indicator" + +/datum/prototype/robot_iconset/dog_k9/logistics + icon_state = "logistics" + icon_state_indicator = "logistics-indicator" + +/datum/prototype/robot_iconset/dog_k9/grey + icon_state = "grey" + icon_state_indicator = "grey-indicator" + +/datum/prototype/robot_iconset/dog_k9/janitor + icon_state = "janitor" + icon_state_indicator = "janitor-indicator" + +/datum/prototype/robot_iconset/dog_k9/blade + icon_state = "blade" + icon_state_indicator = "blade-indicator" diff --git a/code/modules/mob/living/silicon/robot/iconset/dog_otie.dm b/code/modules/mob/living/silicon/robot/iconset/dog_otie.dm new file mode 100644 index 00000000000..bb8e2c51c02 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/iconset/dog_otie.dm @@ -0,0 +1,32 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2024 Citadel Station Developers *// + +/datum/prototype/robot_iconset/dog_otie + display_name = "Otie" + abstract_type = /datum/prototype/robot_iconset/dog_otie + auto_chassis = /datum/prototype/robot_chassis/quadruped/canine + icon = 'icons/mob/robot/iconset/dog_otie.dmi' + icon_state_cover = "panel" + icon_dimension_x = 64 + variations = list( + /datum/robot_iconset_variation/dead, + /datum/robot_iconset_variation/resting, + /datum/robot_iconset_variation/sitting, + /datum/robot_iconset_variation/bellyup, + ) + +/datum/prototype/robot_iconset/dog_otie/janitor + icon_state = "janitor" + icon_state_indicator = "janitor-indicator" + +/datum/prototype/robot_iconset/dog_otie/security + icon_state = "security" + icon_state_indicator = "security-indicator" + +/datum/prototype/robot_iconset/dog_otie/engineering + icon_state = "engineering" + icon_state_indicator = "engineering-indicator" + +/datum/prototype/robot_iconset/dog_otie/science + icon_state = "science" + icon_state_indicator = "science-indicator" diff --git a/code/modules/mob/living/silicon/robot/iconset/dog_pupdozer.dm b/code/modules/mob/living/silicon/robot/iconset/dog_pupdozer.dm new file mode 100644 index 00000000000..c193979fcae --- /dev/null +++ b/code/modules/mob/living/silicon/robot/iconset/dog_pupdozer.dm @@ -0,0 +1,22 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2024 Citadel Station Developers *// + +/datum/prototype/robot_iconset/dog_pupdozer + display_name = "Pupdozer" + abstract_type = /datum/prototype/robot_iconset/dog_pupdozer + auto_chassis = /datum/prototype/robot_chassis/quadruped/canine + icon = 'icons/mob/robot/iconset/dog_pupdozer.dmi' + icon_state_cover = "panel" + icon_state_indicator = "indicator" + icon_dimension_x = 64 + variations = list( + /datum/robot_iconset_variation/dead, + /datum/robot_iconset_variation/resting, + /datum/robot_iconset_variation/sitting, + ) + +/datum/prototype/robot_iconset/dog_pupdozer/engineering + icon_state = "engineering" + +/datum/prototype/robot_iconset/dog_pupdozer/security + icon_state = "security" diff --git a/code/modules/mob/living/silicon/robot/iconset/dog_vale.dm b/code/modules/mob/living/silicon/robot/iconset/dog_vale.dm new file mode 100644 index 00000000000..c40ddbe024c --- /dev/null +++ b/code/modules/mob/living/silicon/robot/iconset/dog_vale.dm @@ -0,0 +1,66 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2024 Citadel Station Developers *// + +/datum/prototype/robot_iconset/dog_vale + display_name = "Vale" + abstract_type = /datum/prototype/robot_iconset/dog_vale + auto_chassis = /datum/prototype/robot_chassis/quadruped/canine + icon = 'icons/mob/robot/iconset/dog_vale.dmi' + icon_state_cover = "panel" + icon_dimension_x = 64 + + variations = list( + /datum/robot_iconset_variation/bellyup, + /datum/robot_iconset_variation/sitting, + /datum/robot_iconset_variation/dead, + /datum/robot_iconset_variation/resting, + ) + +/datum/prototype/robot_iconset/dog_vale/standard + icon_state = "standard" + icon_state_indicator = "standard-indicator" + +/datum/prototype/robot_iconset/dog_vale/medical + icon_state = "medical" + icon_state_indicator = "medical-indicator" + +/datum/prototype/robot_iconset/dog_vale/science + icon_state = "science" + icon_state_indicator = "science-indicator" + +/datum/prototype/robot_iconset/dog_vale/security + icon_state = "security" + icon_state_indicator = "security-indicator" + +/datum/prototype/robot_iconset/dog_vale/engineering + icon_state = "engineering" + icon_state_indicator = "engineering-indicator" + +/datum/prototype/robot_iconset/dog_vale/mining + icon_state = "mining" + icon_state_indicator = "mining-indicator" + +/datum/prototype/robot_iconset/dog_vale/janitor + icon_state = "janitor" + icon_state_indicator = "janitor-indicator" + +/datum/prototype/robot_iconset/dog_vale/service + icon_state = "service" + icon_state_indicator = "service-indicator" + +/datum/prototype/robot_iconset/dog_vale/service_dark + display_name = /datum/prototype/robot_iconset/dog_vale::display_name + " (Dark)" + icon_state = "service_dark" + icon_state_indicator = "service_dark-indicator" + +/datum/prototype/robot_iconset/dog_vale/stray + icon_state = "stray" + icon_state_indicator = "stray-indicator" + +/datum/prototype/robot_iconset/dog_vale/syndicate + icon_state = "syndicate" + icon_state_indicator = "syndicate-indicator" + +/datum/prototype/robot_iconset/dog_vale/clown + icon_state = "clown" + icon_state_indicator = "clown-indicator" diff --git a/code/modules/mob/living/silicon/robot/iconset/drake_mizartz.dm b/code/modules/mob/living/silicon/robot/iconset/drake_mizartz.dm new file mode 100644 index 00000000000..68fc2dda173 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/iconset/drake_mizartz.dm @@ -0,0 +1,50 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2024 Citadel Station Developers *// + +// Attributions // +// All sprites used in this file made by mizartz.carrd.co // + +/datum/prototype/robot_iconset/drake_mizartz + display_name = "Drake" + abstract_type = /datum/prototype/robot_iconset/drake_mizartz + auto_chassis = /datum/prototype/robot_chassis/quadruped/draconic + + icon = 'icons/mob/robot/iconset/drake_mizartz.dmi' + icon_state_indicator = "indicator-lighting" + icon_state_cover = "open" + + icon_dimension_x = 64 + icon_dimension_y = 32 + + indicator_lighting_coloration_mode = COLORATION_MODE_MULTIPLY + + variations = list( + /datum/robot_iconset_variation/dead, + /datum/robot_iconset_variation/resting, + /datum/robot_iconset_variation/sitting, + /datum/robot_iconset_variation/bellyup, + ) + +/datum/prototype/robot_iconset/drake_mizartz/mining + icon_state = "mining" + indicator_lighting_coloration_packed = "#aa00ff" + +/datum/prototype/robot_iconset/drake_mizartz/medical + icon_state = "medical" + indicator_lighting_coloration_packed = "#00ffff" + +/datum/prototype/robot_iconset/drake_mizartz/janitor + icon_state = "janitor" + icon_state_indicator = "indicator-lighting-janitor" + indicator_lighting_coloration_mode = COLORATION_MODE_NONE + +/datum/prototype/robot_iconset/drake_mizartz/security + icon_state = "security" + indicator_lighting_coloration_packed = "#ff0000" + +/datum/prototype/robot_iconset/drake_mizartz/engineering + icon_state = "engineering" + indicator_lighting_coloration_packed = "#ffff00" + +/datum/prototype/robot_iconset/drake_mizartz/peacekeeper + icon_state = "peacekeeper" diff --git a/code/modules/mob/living/silicon/robot/iconset/grounded_decapod.dm b/code/modules/mob/living/silicon/robot/iconset/grounded_decapod.dm new file mode 100644 index 00000000000..48b823193bd --- /dev/null +++ b/code/modules/mob/living/silicon/robot/iconset/grounded_decapod.dm @@ -0,0 +1,53 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2024 Citadel Station Developers *// + +/datum/prototype/robot_iconset/grounded_decapod + display_name = "Decapod" + abstract_type = /datum/prototype/robot_iconset/grounded_decapod + auto_chassis = /datum/prototype/robot_chassis/grounded + icon = 'icons/mob/robot/iconset/grounded_decapod.dmi' + icon_state_cover = "panel" + +/datum/prototype/robot_iconset/grounded_decapod/standard + icon_state = "standard" + icon_state_indicator = "standard-indicator" + +/datum/prototype/robot_iconset/grounded_decapod/research + icon_state = "research" + icon_state_indicator = "research-indicator" + +/datum/prototype/robot_iconset/grounded_decapod/surgeon + icon_state = "surgeon" + icon_state_indicator = "surgeon-indicator" + +/datum/prototype/robot_iconset/grounded_decapod/crisis + icon_state = "crisis" + icon_state_indicator = "crisis-indicator" + +/datum/prototype/robot_iconset/grounded_decapod/engineering + icon_state = "engineering" + icon_state_indicator = "engineering-indicator" + +/datum/prototype/robot_iconset/grounded_decapod/janitor + icon_state = "janitor" + icon_state_indicator = "janitor-indicator" + +/datum/prototype/robot_iconset/grounded_decapod/service + icon_state = "service" + icon_state_indicator = "service-indicator" + +/datum/prototype/robot_iconset/grounded_decapod/clerical + icon_state = "clerical" + icon_state_indicator = "clerical-indicator" + +/datum/prototype/robot_iconset/grounded_decapod/combat + icon_state = "combat" + icon_state_indicator = "combat-indicator" + +/datum/prototype/robot_iconset/grounded_decapod/mining + icon_state = "mining" + icon_state_indicator = "mining-indicator" + +/datum/prototype/robot_iconset/grounded_decapod/security + icon_state = "security" + icon_state_indicator = "security-indicator" diff --git a/code/modules/mob/living/silicon/robot/iconset/grounded_landmate.dm b/code/modules/mob/living/silicon/robot/iconset/grounded_landmate.dm new file mode 100644 index 00000000000..d8cf51761f3 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/iconset/grounded_landmate.dm @@ -0,0 +1,70 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2024 Citadel Station Developers *// + +/datum/prototype/robot_iconset/grounded_landmate + display_name = "Landmate" + abstract_type = /datum/prototype/robot_iconset/grounded_landmate + auto_chassis = /datum/prototype/robot_chassis/grounded + icon = 'icons/mob/robot/iconset/grounded_landmate.dmi' + icon_state_cover = "panel" + +/datum/prototype/robot_iconset/grounded_landmate/engineering + icon_state = "engineering" + icon_state_indicator = "engineering-indicator" + +/datum/prototype/robot_iconset/grounded_landmate/engineering_tread + display_name = "Landmate (Treaded)" + icon_state = "engineering_tread" + icon_state_indicator = "engineering_tread-indicator" + +/datum/prototype/robot_iconset/grounded_landmate/treadwell + display_name = "Treadwell" + icon_state = "treadwell" + icon_state_indicator = "treadwell-indicator" + +/datum/prototype/robot_iconset/grounded_landmate/janitor + icon_state = "janitor" + icon_state_indicator = "janitor-indicator" + +/datum/prototype/robot_iconset/grounded_landmate/mining + display_name = "Treadhead" + icon_state = "mining" + icon_state_indicator = "mining-indicator" + +/datum/prototype/robot_iconset/grounded_landmate/peacekeeper + icon_state = "peacekeeper" + icon_state_indicator = "peacekeeper-indicator" + +/datum/prototype/robot_iconset/grounded_landmate/clown + icon_state = "clown" + icon_state_indicator = "peacekeeper-indicator" + +/datum/prototype/robot_iconset/grounded_landmate/security + display_name = "Cerberus" + icon_state = "security" + icon_state_indicator = "security-indicator" + +/datum/prototype/robot_iconset/grounded_landmate/security_tread + display_name = "Cerberus (Treaded)" + icon_state = "security_tread" + icon_state_indicator = "security-indicator" + +/datum/prototype/robot_iconset/grounded_landmate/engineering_cybersun + icon_state = "engineering_cybersun" + icon_state_indicator = "engineering_cybersun-indicator" + +/datum/prototype/robot_iconset/grounded_landmate/engineering_cybersun_green + icon_state = "engineering_cybersun_green" + icon_state_indicator = "engineering_cybersun_green-indicator" + +/datum/prototype/robot_iconset/grounded_landmate/security_cybersun + icon_state = "security_cybersun" + icon_state_indicator = "security_cybersun-indicator" + +/datum/prototype/robot_iconset/grounded_landmate/security_cybersun_tread + icon_state = "security_cybersun_tread" + icon_state_indicator = "security_cybersun-indicator" + +/datum/prototype/robot_iconset/grounded_landmate/security_cybersun_green + icon_state = "security_cybersun_green" + icon_state_indicator = "security_cybersun_green-indicator" diff --git a/code/modules/mob/living/silicon/robot/iconset/grounded_mechoid.dm b/code/modules/mob/living/silicon/robot/iconset/grounded_mechoid.dm new file mode 100644 index 00000000000..c4a0fda4367 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/iconset/grounded_mechoid.dm @@ -0,0 +1,45 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2024 Citadel Station Developers *// + +/datum/prototype/robot_iconset/grounded_mechoid + display_name = "Acheron" + abstract_type = /datum/prototype/robot_iconset/grounded_mechoid + auto_chassis = /datum/prototype/robot_chassis/grounded + icon = 'icons/mob/robot/iconset/grounded_mechoid.dmi' + icon_state_cover = "panel" + +/datum/prototype/robot_iconset/grounded_mechoid/standard + icon_state = "standard" + icon_state_indicator = "standard-indicator" + +/datum/prototype/robot_iconset/grounded_mechoid/combat + icon_state = "combat" + icon_state_indicator = "combat-indicator" + +/datum/prototype/robot_iconset/grounded_mechoid/science + icon_state = "science" + icon_state_indicator = "science-indicator" + +/datum/prototype/robot_iconset/grounded_mechoid/janitor + icon_state = "janitor" + icon_state_indicator = "janitor-indicator" + +/datum/prototype/robot_iconset/grounded_mechoid/security + icon_state = "security" + icon_state_indicator = "security-indicator" + +/datum/prototype/robot_iconset/grounded_mechoid/engineering + icon_state = "engineering" + icon_state_indicator = "engineering-indicator" + +/datum/prototype/robot_iconset/grounded_mechoid/medical + icon_state = "medical" + icon_state_indicator = "medical-indicator" + +/datum/prototype/robot_iconset/grounded_mechoid/miner + icon_state = "miner" + icon_state_indicator = "miner-indicator" + +/datum/prototype/robot_iconset/grounded_mechoid/service + icon_state = "service" + icon_state_indicator = "service-indicator" diff --git a/code/modules/mob/living/silicon/robot/iconset/grounded_spider.dm b/code/modules/mob/living/silicon/robot/iconset/grounded_spider.dm new file mode 100644 index 00000000000..09a853961e5 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/iconset/grounded_spider.dm @@ -0,0 +1,37 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2024 Citadel Station Developers *// + +/datum/prototype/robot_iconset/grounded_spider + display_name = "XI-GUS" + abstract_type = /datum/prototype/robot_iconset/grounded_spider + auto_chassis = /datum/prototype/robot_chassis/grounded + icon = 'icons/mob/robot/iconset/grounded_spider.dmi' + icon_state_cover = "panel" + +/datum/prototype/robot_iconset/grounded_spider/standard + icon_state = "standard" + icon_state_indicator = "standard-indicator" + +/datum/prototype/robot_iconset/grounded_spider/combat + icon_state = "combat" + icon_state_indicator = "combat-indicator" + +/datum/prototype/robot_iconset/grounded_spider/command + icon_state = "command" + icon_state_indicator = "command-indicator" + +/datum/prototype/robot_iconset/grounded_spider/science + icon_state = "science" + icon_state_indicator = "science-indicator" + +/datum/prototype/robot_iconset/grounded_spider/mining + icon_state = "mining" + icon_state_indicator = "mining-indicator" + +/datum/prototype/robot_iconset/grounded_spider/security + icon_state = "security" + icon_state_indicator = "security-indicator" + +/datum/prototype/robot_iconset/grounded_spider/engineering + icon_state = "engineering" + icon_state_indicator = "engineering-indicator" diff --git a/code/modules/mob/living/silicon/robot/iconset/grounded_worm.dm b/code/modules/mob/living/silicon/robot/iconset/grounded_worm.dm new file mode 100644 index 00000000000..ba650f654ef --- /dev/null +++ b/code/modules/mob/living/silicon/robot/iconset/grounded_worm.dm @@ -0,0 +1,37 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2024 Citadel Station Developers *// + +/datum/prototype/robot_iconset/grounded_worm + display_name = "W02M" + abstract_type = /datum/prototype/robot_iconset/grounded_worm + + auto_chassis = /datum/prototype/robot_chassis/grounded + + icon = 'icons/mob/robot/iconset/grounded_worm.dmi' + icon_state_indicator = "indicator-lighting" + icon_state_cover = "open" + +/datum/prototype/robot_iconset/grounded_worm/standard + icon_state = "worm-standard" + +/datum/prototype/robot_iconset/grounded_worm/engineering + icon_state = "worm-engineering" + +/datum/prototype/robot_iconset/grounded_worm/janitor + icon_state = "worm-janitor" + +/datum/prototype/robot_iconset/grounded_worm/crisis + icon_state = "worm-crisis" + +/datum/prototype/robot_iconset/grounded_worm/miner + icon_state = "worm-miner" + +/datum/prototype/robot_iconset/grounded_worm/security + icon_state = "worm-security" + +/datum/prototype/robot_iconset/grounded_worm/service + icon_state = "worm-service" + +/datum/prototype/robot_iconset/grounded_worm/hotpink + icon_state = "worm-hotpink" + diff --git a/code/modules/mob/living/silicon/robot/iconset/grounded_zoomba.dm b/code/modules/mob/living/silicon/robot/iconset/grounded_zoomba.dm new file mode 100644 index 00000000000..54838810b14 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/iconset/grounded_zoomba.dm @@ -0,0 +1,61 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2024 Citadel Station Developers *// + +/datum/prototype/robot_iconset/grounded_zoomba + display_name = "ZOOM-BA" + abstract_type = /datum/prototype/robot_iconset/grounded_zoomba + + auto_chassis = /datum/prototype/robot_chassis/grounded + + icon = 'icons/mob/robot/iconset/grounded_zoomba.dmi' + icon_state_indicator = "indicator-lighting" + icon_state_cover = "cover" + indicator_lighting_coloration_mode = COLORATION_MODE_MULTIPLY + + variations = list( + /datum/robot_iconset_variation/dead, + ) + +/datum/prototype/robot_iconset/grounded_zoomba/standard + icon_state = "standard" + +/datum/prototype/robot_iconset/grounded_zoomba/clerical + icon_state = "clerical" + indicator_lighting_coloration_packed = "#00ff6e" + +/datum/prototype/robot_iconset/grounded_zoomba/engineering + icon_state = "engineering" + indicator_lighting_coloration_packed = "#ffae00" + +/datum/prototype/robot_iconset/grounded_zoomba/janitor + icon_state = "janitor" + indicator_lighting_coloration_packed = "#cc00ff" + +/datum/prototype/robot_iconset/grounded_zoomba/medical + icon_state = "medical" + indicator_lighting_coloration_packed = "#00ffff" + +/datum/prototype/robot_iconset/grounded_zoomba/crisis + icon_state = "crisis" + indicator_lighting_coloration_packed = "#00ffff" + +/datum/prototype/robot_iconset/grounded_zoomba/miner + icon_state = "miner" + indicator_lighting_coloration_packed = "#9f561f" + +/datum/prototype/robot_iconset/grounded_zoomba/research + icon_state = "research" + indicator_lighting_coloration_packed = "#8800ff" + +/datum/prototype/robot_iconset/grounded_zoomba/service + icon_state = "service" + indicator_lighting_coloration_packed = "#16b102" + +/datum/prototype/robot_iconset/grounded_zoomba/combat + icon_state = "combat" + indicator_lighting_coloration_packed = "#ff0000" + +/datum/prototype/robot_iconset/grounded_zoomba/security + icon_state = "security" + variations = list() + indicator_lighting_coloration_packed = "#ff0000" diff --git a/code/modules/mob/living/silicon/robot/iconset/hover_coffin.dm b/code/modules/mob/living/silicon/robot/iconset/hover_coffin.dm new file mode 100644 index 00000000000..af943425020 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/iconset/hover_coffin.dm @@ -0,0 +1,48 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2024 Citadel Station Developers *// + +/datum/prototype/robot_iconset/hover_coffin + display_name = "Coffin" + abstract_type = /datum/prototype/robot_iconset/hover_coffin + auto_chassis = /datum/prototype/robot_chassis/hover + icon = 'icons/mob/robot/iconset/hover_coffin.dmi' + icon_state_cover = "panel" + +/datum/prototype/robot_iconset/hover_coffin/standard + icon_state = "standard" + +/datum/prototype/robot_iconset/hover_coffin/medical + display_name = "Coffical" + icon_state = "medical" + +/datum/prototype/robot_iconset/hover_coffin/syndicate + icon_state = "syndicate" + +/datum/prototype/robot_iconset/hover_coffin/custodial + display_name = "Coffstodial" + icon_state = "custodial" + +/datum/prototype/robot_iconset/hover_coffin/service + icon_state = "service" + +/datum/prototype/robot_iconset/hover_coffin/mining + icon_state = "mining" + +/datum/prototype/robot_iconset/hover_coffin/research + display_name = "Coffsearch" + icon_state = "research" + +/datum/prototype/robot_iconset/hover_coffin/clerical + icon_state = "clerical" + +/datum/prototype/robot_iconset/hover_coffin/construction + display_name = "Coffstruction" + icon_state = "construction" + +/datum/prototype/robot_iconset/hover_coffin/engineering + display_name = "Coffgineer" + icon_state = "engineering" + +/datum/prototype/robot_iconset/hover_coffin/combat + display_name = "Coffcurity" + icon_state = "combat" diff --git a/code/modules/mob/living/silicon/robot/iconset/hover_drone.dm b/code/modules/mob/living/silicon/robot/iconset/hover_drone.dm new file mode 100644 index 00000000000..65267a04906 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/iconset/hover_drone.dm @@ -0,0 +1,69 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2024 Citadel Station Developers *// + +/datum/prototype/robot_iconset/hover_drone + display_name = "Drone" + abstract_type = /datum/prototype/robot_iconset/hover_drone + auto_chassis = /datum/prototype/robot_chassis/hover + icon = 'icons/mob/robot/iconset/hover_drone.dmi' + icon_state_cover = "panel" + +/datum/prototype/robot_iconset/hover_drone/standard + icon_state = "standard" + icon_state_indicator = "standard-indicator" + +/datum/prototype/robot_iconset/hover_drone/engineering + icon_state = "engineering" + icon_state_indicator = "engineering-indicator" + +/datum/prototype/robot_iconset/hover_drone/mining + icon_state = "mining" + icon_state_indicator = "mining-indicator" + +/datum/prototype/robot_iconset/hover_drone/janitor + icon_state = "janitor" + icon_state_indicator = "janitor-indicator" + +/datum/prototype/robot_iconset/hover_drone/medical + display_name = /datum/prototype/robot_iconset/hover_drone::display_name + " (Medical)" + icon_state = "medical" + icon_state_indicator = "medical-indicator" + +/datum/prototype/robot_iconset/hover_drone/surgery + display_name = /datum/prototype/robot_iconset/hover_drone::display_name + " (Surgery)" + icon_state = "surgery" + icon_state_indicator = "surgery-indicator" + +/datum/prototype/robot_iconset/hover_drone/security + icon_state = "security" + icon_state_indicator = "security-indicator" + +/datum/prototype/robot_iconset/hover_drone/service + display_name = /datum/prototype/robot_iconset/hover_drone::display_name + " (Service)" + icon_state = "service" + icon_state_indicator = "service-indicator" + +/datum/prototype/robot_iconset/hover_drone/lost + icon_state = "lost" + icon_state_indicator = "lost-indicator" + +/datum/prototype/robot_iconset/hover_drone/chemistry + icon_state = "chemistry" + icon_state_indicator = "chemistry-indicator" + +/datum/prototype/robot_iconset/hover_drone/hydroponics + display_name = /datum/prototype/robot_iconset/hover_drone::display_name + " (Hydroponics)" + icon_state = "hydroponics" + icon_state_indicator = "hydroponics-indicator" + +/datum/prototype/robot_iconset/hover_drone/science + icon_state = "science" + icon_state_indicator = "science-indicator" + +/datum/prototype/robot_iconset/hover_drone/blueshield + icon_state = "blueshield" + icon_state_indicator = "blueshield-indicator" + +/datum/prototype/robot_iconset/hover_drone/gravekeeper + icon_state = "gravekeeper" + icon_state_indicator = "gravekeeper-indicator" diff --git a/code/modules/mob/living/silicon/robot/iconset/hover_eyebot.dm b/code/modules/mob/living/silicon/robot/iconset/hover_eyebot.dm new file mode 100644 index 00000000000..0edb9d63620 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/iconset/hover_eyebot.dm @@ -0,0 +1,41 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2024 Citadel Station Developers *// + +/datum/prototype/robot_iconset/hover_eyebot + display_name = "Cabeiri" + abstract_type = /datum/prototype/robot_iconset/hover_eyebot + auto_chassis = /datum/prototype/robot_chassis/hover + icon = 'icons/mob/robot/iconset/hover_eyebot.dmi' + icon_state_cover = "panel" + +/datum/prototype/robot_iconset/hover_eyebot/standard + icon_state = "standard" + icon_state_indicator = "standard-indicator" + +/datum/prototype/robot_iconset/hover_eyebot/engineering + icon_state = "engineering" + icon_state_indicator = "engineering-indicator" + +/datum/prototype/robot_iconset/hover_eyebot/janitor + icon_state = "janitor" + icon_state_indicator = "janitor-indicator" + +/datum/prototype/robot_iconset/hover_eyebot/medical + icon_state = "medical" + icon_state_indicator = "medical-indicator" + +/datum/prototype/robot_iconset/hover_eyebot/science + icon_state = "science" + icon_state_indicator = "science-indicator" + +/datum/prototype/robot_iconset/hover_eyebot/mining + icon_state = "mining" + icon_state_indicator = "mining-indicator" + +/datum/prototype/robot_iconset/hover_eyebot/security + icon_state = "security" + icon_state_indicator = "security-indicator" + +/datum/prototype/robot_iconset/hover_eyebot/combat + icon_state = "combat" + icon_state_indicator = "combat-indicator" diff --git a/code/modules/mob/living/silicon/robot/iconset/hover_glitterfly.dm b/code/modules/mob/living/silicon/robot/iconset/hover_glitterfly.dm new file mode 100644 index 00000000000..9e0505aeaaf --- /dev/null +++ b/code/modules/mob/living/silicon/robot/iconset/hover_glitterfly.dm @@ -0,0 +1,50 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2024 Citadel Station Developers *// + +/datum/prototype/robot_iconset/hover_glitterfly + display_name = "L3P1-D0T" + abstract_type = /datum/prototype/robot_iconset/hover_glitterfly + auto_chassis = /datum/prototype/robot_chassis/hover + icon = 'icons/mob/robot/iconset/hover_glitterfly.dmi' + icon_state_cover = "panel" + +/datum/prototype/robot_iconset/hover_glitterfly/standard + icon_state = "standard" + icon_state_indicator = "standard-indicator" + +/datum/prototype/robot_iconset/hover_glitterfly/janitor + icon_state = "janitor" + icon_state_indicator = "janitor-indicator" + +/datum/prototype/robot_iconset/hover_glitterfly/service + icon_state = "service" + icon_state_indicator = "service-indicator" + +/datum/prototype/robot_iconset/hover_glitterfly/surgeon + icon_state = "surgeon" + icon_state_indicator = "surgeon-indicator" + +/datum/prototype/robot_iconset/hover_glitterfly/crisis + icon_state = "crisis" + icon_state_indicator = "crisis-indicator" + +/datum/prototype/robot_iconset/hover_glitterfly/engineering + icon_state = "engineering" + icon_state_indicator = "engineering-indicator" + +/datum/prototype/robot_iconset/hover_glitterfly/security + icon_state = "security" + icon_state_indicator = "security-indicator" + +/datum/prototype/robot_iconset/hover_glitterfly/clerical + display_name = /datum/prototype/robot_iconset/hover_glitterfly::display_name + " (Clerical)" + icon_state = "clerical" + icon_state_indicator = "clerical-indicator" + +/datum/prototype/robot_iconset/hover_glitterfly/science + icon_state = "science" + icon_state_indicator = "science-indicator" + +/datum/prototype/robot_iconset/hover_glitterfly/mining + icon_state = "mining" + icon_state_indicator = "mining-indicator" diff --git a/code/modules/mob/living/silicon/robot/iconset/hover_handy.dm b/code/modules/mob/living/silicon/robot/iconset/hover_handy.dm new file mode 100644 index 00000000000..eefc7263b00 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/iconset/hover_handy.dm @@ -0,0 +1,51 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2024 Citadel Station Developers *// + +/datum/prototype/robot_iconset/hover_handy + display_name = "Handy" + abstract_type = /datum/prototype/robot_iconset/hover_handy + auto_chassis = /datum/prototype/robot_chassis/hover + icon = 'icons/mob/robot/iconset/hover_handy.dmi' + icon_state_cover = "panel" + +/datum/prototype/robot_iconset/hover_handy/standard + icon_state = "standard" + icon_state_indicator = "standard-indicator" + +/datum/prototype/robot_iconset/hover_handy/hydroponics + icon_state = "hydroponics" + icon_state_indicator = "hydroponics-indicator" + +/datum/prototype/robot_iconset/hover_handy/clerk + display_name = /datum/prototype/robot_iconset/hover_handy::display_name + " (Clerk)" + icon_state = "clerk" + icon_state_indicator = "clerk-indicator" + +/datum/prototype/robot_iconset/hover_handy/janitor + icon_state = "janitor" + icon_state_indicator = "janitor-indicator" + +/datum/prototype/robot_iconset/hover_handy/service + display_name = /datum/prototype/robot_iconset/hover_handy::display_name + " (Service)" + icon_state = "service" + icon_state_indicator = "service-indicator" + +/datum/prototype/robot_iconset/hover_handy/mining + icon_state = "mining" + icon_state_indicator = "mining-indicator" + +/datum/prototype/robot_iconset/hover_handy/security + icon_state = "security" + icon_state_indicator = "security-indicator" + +/datum/prototype/robot_iconset/hover_handy/medical + icon_state = "medical" + icon_state_indicator = "medical-indicator" + +/datum/prototype/robot_iconset/hover_handy/engineering + icon_state = "engineering" + icon_state_indicator = "engineering-indicator" + +/datum/prototype/robot_iconset/hover_handy/science + icon_state = "science" + icon_state_indicator = "science-indicator" diff --git a/code/modules/mob/living/silicon/robot/iconset/hover_x88.dm b/code/modules/mob/living/silicon/robot/iconset/hover_x88.dm new file mode 100644 index 00000000000..5cb25aa7d7c --- /dev/null +++ b/code/modules/mob/living/silicon/robot/iconset/hover_x88.dm @@ -0,0 +1,27 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2024 Citadel Station Developers *// + +/datum/prototype/robot_iconset/hover_x88 + display_name = "X-88" + abstract_type = /datum/prototype/robot_iconset/hover_x88 + + auto_chassis = /datum/prototype/robot_chassis/hover + + icon = 'icons/mob/robot/iconset/hover_x88.dmi' + icon_state_cover = "panel" + +/datum/prototype/robot_iconset/hover_x88/standard + icon_state = "standard" + icon_state_indicator = "standard-indicator" + +/datum/prototype/robot_iconset/hover_x88/engineering + icon_state = "engineering" + icon_state_indicator = "engineering-indicator" + +/datum/prototype/robot_iconset/hover_x88/science + icon_state = "science" + icon_state_indicator = "science-indicator" + +/datum/prototype/robot_iconset/hover_x88/medical + icon_state = "medical" + icon_state_indicator = "medical-indicator" diff --git a/code/modules/mob/living/silicon/robot/iconset/raptor.dm b/code/modules/mob/living/silicon/robot/iconset/raptor.dm new file mode 100644 index 00000000000..0836b2608c2 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/iconset/raptor.dm @@ -0,0 +1,70 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2024 Citadel Station Developers *// + +/datum/prototype/robot_iconset/raptor + display_name = "Raptor" + abstract_type = /datum/prototype/robot_iconset/raptor + auto_chassis = /datum/prototype/robot_chassis/quadruped/raptor + icon = 'icons/mob/robot/iconset/raptor.dmi' + icon_state_cover = "panel" + variations = list( + /datum/robot_iconset_variation/dead, + /datum/robot_iconset_variation/bellyup, + /datum/robot_iconset_variation/resting, + ) + +/datum/prototype/robot_iconset/raptor/gravekeeper + icon_state = "gravekeeper" + icon_state_indicator = "indicator" + +/datum/prototype/robot_iconset/raptor/gravekeeper + icon_state = "lost" + icon_state_indicator = "indicator" + +/datum/prototype/robot_iconset/raptor/lost + icon_state = "service" + icon_state_indicator = "indicator" + +/datum/prototype/robot_iconset/raptor/service + icon_state = "security" + icon_state_indicator = "indicator" + +/datum/prototype/robot_iconset/raptor/security + icon_state = "mining" + icon_state_indicator = "indicator" + +/datum/prototype/robot_iconset/raptor/mining + icon_state = "medical" + icon_state_indicator = "indicator" + +/datum/prototype/robot_iconset/raptor/medical + icon_state = "medical" + icon_state_indicator = "indicator" + +/datum/prototype/robot_iconset/raptor/janitor + icon_state = "janitor" + icon_state_indicator = "indicator" + +/datum/prototype/robot_iconset/raptor/centcom + icon_state = "centcom" + icon_state_indicator = "indicator" + +/datum/prototype/robot_iconset/raptor/engineering + icon_state = "engineering" + icon_state_indicator = "indicator" + +/datum/prototype/robot_iconset/raptor/peacekeeper + icon_state = "peacekeeper" + icon_state_indicator = "indicator" + +/datum/prototype/robot_iconset/raptor/syndicate_medical + icon_state = "syndicate_medical" + icon_state_indicator = "indicator-syndicate" + +/datum/prototype/robot_iconset/raptor/syndicate_protector + icon_state = "syndicate_protector" + icon_state_indicator = "indicator-syndicate" + +/datum/prototype/robot_iconset/raptor/syndicate_machinist + icon_state = "syndicate_machinist" + icon_state_indicator = "indicator-syndicate" diff --git a/code/modules/mob/living/silicon/robot/inventory.dm b/code/modules/mob/living/silicon/robot/inventory.dm deleted file mode 100644 index b89d1be85a6..00000000000 --- a/code/modules/mob/living/silicon/robot/inventory.dm +++ /dev/null @@ -1,367 +0,0 @@ -//These procs handle putting s tuff in your hand. It's probably best to use these rather than setting stuff manually -//as they handle all relevant stuff like adding it to the player's screen and such -// todo: proper inv procs -//! WARNING: we currently only call equipped/unequipped and jankily using SLOT_ID_HANDS... - -//Returns the thing in our active hand (whatever is in our active module-slot, in this case) -/mob/living/silicon/robot/get_active_held_item() - return module_active - -//TODO: Something apparently? - -//Verbs used by hotkeys. -/mob/living/silicon/robot/verb/cmd_unequip_module() - set name = "unequip-module" - set hidden = 1 - uneq_active() - -/mob/living/silicon/robot/verb/cmd_toggle_module(module as num) - set name = "toggle-module" - set hidden = 1 - toggle_module(module) - -/mob/living/silicon/robot/proc/uneq_active() - if(isnull(module_active)) - return - if(module_state_1 == module_active) - if(istype(module_state_1,/obj/item/borg/sight)) - sight_mode &= ~module_state_1:sight_mode - if (client) - client.screen -= module_state_1 - contents -= module_state_1 - module_state_1.unequipped(src, SLOT_ID_HANDS, NONE) - module_state_1.on_inv_unequipped(src, inventory, 1, NONE) - module_active = null - module_state_1:loc = module //So it can be used again later - module_state_1 = null - inv1.icon_state = "inv1" - else if(module_state_2 == module_active) - if(istype(module_state_2,/obj/item/borg/sight)) - sight_mode &= ~module_state_2:sight_mode - if (client) - client.screen -= module_state_2 - contents -= module_state_2 - module_state_2.unequipped(src, SLOT_ID_HANDS, NONE) - module_state_2.on_inv_unequipped(src, inventory, 2, NONE) - module_active = null - module_state_2:loc = module - module_state_2 = null - inv2.icon_state = "inv2" - else if(module_state_3 == module_active) - if(istype(module_state_3,/obj/item/borg/sight)) - sight_mode &= ~module_state_3:sight_mode - if (client) - client.screen -= module_state_3 - contents -= module_state_3 - module_state_3.unequipped(src, SLOT_ID_HANDS, NONE) - module_state_3.on_inv_unequipped(src, inventory, 3, NONE) - module_active = null - module_state_3:loc = module - module_state_3 = null - inv3.icon_state = "inv3" - updateicon() - -/mob/living/silicon/robot/proc/uneq_all() - module_active = null - - if(module_state_1) - if(istype(module_state_1,/obj/item/borg/sight)) - sight_mode &= ~module_state_1:sight_mode - if (client) - client.screen -= module_state_1 - contents -= module_state_1 - module_state_1:loc = module - module_state_1.unequipped(src, SLOT_ID_HANDS, NONE) - module_state_1.on_inv_unequipped(src, inventory, 1, NONE) - module_state_1 = null - inv1.icon_state = "inv1" - if(module_state_2) - if(istype(module_state_2,/obj/item/borg/sight)) - sight_mode &= ~module_state_2:sight_mode - if (client) - client.screen -= module_state_2 - contents -= module_state_2 - module_state_2:loc = module - module_state_2.unequipped(src, SLOT_ID_HANDS, NONE) - module_state_1.on_inv_unequipped(src, inventory, 2, NONE) - module_state_2 = null - inv2.icon_state = "inv2" - if(module_state_3) - if(istype(module_state_3,/obj/item/borg/sight)) - sight_mode &= ~module_state_3:sight_mode - if (client) - client.screen -= module_state_3 - contents -= module_state_3 - module_state_3:loc = module - module_state_3.unequipped(src, SLOT_ID_HANDS, NONE) - module_state_1.on_inv_unequipped(src, inventory, 3, NONE) - module_state_3 = null - inv3.icon_state = "inv3" - updateicon() - -/mob/living/silicon/robot/proc/activated(obj/item/O) - if(module_state_1 == O) - return 1 - else if(module_state_2 == O) - return 1 - else if(module_state_3 == O) - return 1 - else - return 0 - -// This one takes an object's type instead of an instance, as above. -/mob/living/silicon/robot/proc/has_active_type(var/type_to_compare) - var/list/active_modules = list(module_state_1, module_state_2, module_state_3) - if(is_path_in_list(type_to_compare, active_modules)) - return TRUE - return FALSE - -//Helper procs for cyborg modules on the UI. -//These are hackish but they help clean up code elsewhere. - -//module_selected(module) - Checks whether the module slot specified by "module" is currently selected. -/mob/living/silicon/robot/proc/module_selected(var/module) //Module is 1-3 - return module == get_selected_module() - -//module_active(module) - Checks whether there is a module active in the slot specified by "module". -/mob/living/silicon/robot/proc/module_active(var/module) //Module is 1-3 - if(module < 1 || module > 3) return 0 - - switch(module) - if(1) - if(module_state_1) - return 1 - if(2) - if(module_state_2) - return 1 - if(3) - if(module_state_3) - return 1 - return 0 - -//get_selected_module() - Returns the slot number of the currently selected module. Returns 0 if no modules are selected. -/mob/living/silicon/robot/proc/get_selected_module() - if(module_state_1 && module_active == module_state_1) - return 1 - else if(module_state_2 && module_active == module_state_2) - return 2 - else if(module_state_3 && module_active == module_state_3) - return 3 - - return 0 - -//select_module(module) - Selects the module slot specified by "module" -/mob/living/silicon/robot/proc/select_module(var/module) //Module is 1-3 - if(module < 1 || module > 3) return - - if(!module_active(module)) return - - switch(module) - if(1) - if(module_active != module_state_1) - inv1.icon_state = "inv1 +a" - inv2.icon_state = "inv2" - inv3.icon_state = "inv3" - module_active = module_state_1 - return - if(2) - if(module_active != module_state_2) - inv1.icon_state = "inv1" - inv2.icon_state = "inv2 +a" - inv3.icon_state = "inv3" - module_active = module_state_2 - return - if(3) - if(module_active != module_state_3) - inv1.icon_state = "inv1" - inv2.icon_state = "inv2" - inv3.icon_state = "inv3 +a" - module_active = module_state_3 - return - return - -//deselect_module(module) - Deselects the module slot specified by "module" -/mob/living/silicon/robot/proc/deselect_module(var/module) //Module is 1-3 - if(module < 1 || module > 3) return - - switch(module) - if(1) - if(module_active == module_state_1) - inv1.icon_state = "inv1" - module_active = null - return - if(2) - if(module_active == module_state_2) - inv2.icon_state = "inv2" - module_active = null - return - if(3) - if(module_active == module_state_3) - inv3.icon_state = "inv3" - module_active = null - return - return - -//toggle_module(module) - Toggles the selection of the module slot specified by "module". -/mob/living/silicon/robot/proc/toggle_module(var/module) //Module is 1-3 - if(module < 1 || module > 3) return - - if(module_selected(module)) - deselect_module(module) - else - if(module_active(module)) - select_module(module) - else - deselect_module(get_selected_module()) //If we can't do select anything, at least deselect the current module. - return - -//cycle_modules() - Cycles through the list of selected modules. -/mob/living/silicon/robot/proc/cycle_modules() - var/slot_start = get_selected_module() - if(slot_start) deselect_module(slot_start) //Only deselect if we have a selected slot. - - var/slot_num - if(slot_start == 0) - slot_num = 1 - slot_start = 2 - else - slot_num = slot_start + 1 - - while(slot_start != slot_num) //If we wrap around without finding any free slots, just give up. - if(module_active(slot_num)) - select_module(slot_num) - return - slot_num++ - if(slot_num > 3) slot_num = 1 //Wrap around. - - return - -/mob/living/silicon/robot/proc/activate_module(var/obj/item/O) - if(!(locate(O) in src.module.modules) && O != src.module.emag) - return - if(activated(O)) - to_chat(src, "Already activated") - return - if(!module_state_1) - module_state_1 = O - O.hud_layerise() - O.screen_loc = inv1.screen_loc - contents += O - if(istype(module_state_1,/obj/item/borg/sight)) - sight_mode |= module_state_1:sight_mode - else if(!module_state_2) - module_state_2 = O - O.hud_layerise() - O.screen_loc = inv2.screen_loc - contents += O - if(istype(module_state_2,/obj/item/borg/sight)) - sight_mode |= module_state_2:sight_mode - else if(!module_state_3) - module_state_3 = O - O.hud_layerise() - O.screen_loc = inv3.screen_loc - contents += O - if(istype(module_state_3,/obj/item/borg/sight)) - sight_mode |= module_state_3:sight_mode - else - to_chat(src, "You need to disable a module first!") - O.equipped(src, SLOT_ID_HANDS, NONE) - -/mob/living/silicon/robot/get_held_items() - . = list() - if(module_state_1) - . += module_state_1 - if(module_state_2) - . += module_state_2 - if(module_state_3) - . += module_state_3 - -/mob/living/silicon/robot/get_nominal_hand_count() - return 3 - -/mob/living/silicon/robot/get_held_index(obj/item/I) - if(module_state_1 == I) - return 1 - if(module_state_2 == I) - return 2 - if(module_state_3 == I) - return 3 - -/mob/living/silicon/robot/get_held_index(index) - switch(index) - if(1) - return module_state_1 - if(2) - return module_state_2 - if(3) - return module_state_3 - -/* for now we don't use generic slots at all */ -// TODO: put in hands should try to put into grippers ~silicons - -/mob/living/silicon/robot/is_in_inventory(obj/item/I) - return is_module_item(I) || is_in_gripper(I) - -/mob/living/silicon/robot/proc/considered_removable(obj/item/I) - return (!is_module_item(I)) - -/mob/living/silicon/robot/proc/is_module_item(obj/item/I) - if(!module) - return FALSE - return (I in module.modules) || (I in module.emag) - -/mob/living/silicon/robot/proc/is_in_gripper(obj/item/I, require_active_module) - return ( \ - I.loc == src? \ - !!gripper_holding(I) : \ - (istype(I.loc, /obj/item/gripper) && (require_active_module? is_holding(I.loc) : is_module_item(I.loc))) \ - ) - -/mob/living/silicon/robot/proc/gripper_holding(obj/item/I) - for(var/obj/item/gripper/G in module.modules) - if(G.get_item() == I) - return G - -/mob/living/silicon/robot/proc/unreference_from_gripper(obj/item/I, newloc) - if(!istype(I.loc, /obj/item/gripper)) - return FALSE - var/obj/item/gripper/G = I.loc - if(!is_module_item(G)) - return FALSE - if(G.get_item() != I) - return FALSE - G.remove_item(newloc) - return TRUE - -/mob/living/silicon/robot/temporarily_remove_from_inventory(obj/item/I, flags, mob/user) - if(!is_in_inventory(I)) - return TRUE - . = considered_removable(I) - if(!.) - return - if(is_in_gripper(I)) - return unreference_from_gripper(I, null) - -/mob/living/silicon/robot/transfer_item_to_loc(obj/item/I, newloc, flags, mob/user) - if(is_in_inventory(I) && considered_removable(I)) - if(is_in_gripper(I)) - return unreference_from_gripper(I, newloc) - I.forceMove(newloc) - return TRUE - return FALSE - -/mob/living/silicon/robot/transfer_item_to_nullspace(obj/item/I, flags, mob/user) - if(is_in_inventory(I) && considered_removable(I)) - if(is_in_gripper(I)) - return unreference_from_gripper(I, null) - I.moveToNullspace() - return TRUE - return FALSE - -/mob/living/silicon/robot/drop_item_to_ground(obj/item/I, flags, mob/user) - if(is_in_inventory(I) && considered_removable(I)) - if(is_in_gripper(I)) - return unreference_from_gripper(I, drop_location()) - I.forceMove(drop_location()) - return TRUE - return FALSE diff --git a/code/modules/mob/living/silicon/robot/items/robot_builtin.dm b/code/modules/mob/living/silicon/robot/items/robot_builtin.dm new file mode 100644 index 00000000000..d6fe95f74cf --- /dev/null +++ b/code/modules/mob/living/silicon/robot/items/robot_builtin.dm @@ -0,0 +1,12 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2025 Citadel Station Developers *// + +/** + * Namespace for builtin items for cyborgs. + * + * * This doesn't at all mean all cyborg module items are under his. + * * This does mean that if something cannot be used outside of a cyborg, has no reason to be implemented + * in a way that's usable outside of a cyborg, **and** doesn't require inheriting other stuff, + * it should go in here. + */ +/obj/item/robot_builtin diff --git a/code/modules/mob/living/silicon/robot/items/robot_builtin/dog_boop_module.dm b/code/modules/mob/living/silicon/robot/items/robot_builtin/dog_boop_module.dm new file mode 100644 index 00000000000..325b1dca360 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/items/robot_builtin/dog_boop_module.dm @@ -0,0 +1,66 @@ +/obj/item/robot_builtin/dog_boop_module + name = "boop module" + icon = 'icons/mob/dogborg_vr.dmi' + icon_state = "nose" + desc = "The BOOP module, a simple reagent and atmosphere sniffer." + damage_force = 0 + item_flags = ITEM_NO_BLUDGEON | ITEM_ENCUMBERS_WHILE_HELD + throw_force = 0 + attack_verb = list("nuzzled", "nosed", "booped") + w_class = WEIGHT_CLASS_TINY + +/obj/item/robot_builtin/dog_boop_module/attack_self(mob/user, datum/event_args/actor/actor) + . = ..() + if(.) + return + if (!( istype(user.loc, /turf) )) + return + + var/datum/gas_mixture/environment = user.loc.return_air() + + var/pressure = environment.return_pressure() + var/total_moles = environment.total_moles + + user.setClickCooldownLegacy(DEFAULT_ATTACK_COOLDOWN) + user.visible_message("[user] sniffs the air.", "You sniff the air...") + + to_chat(user, "Smells like:") + if(abs(pressure - ONE_ATMOSPHERE) < 10) + to_chat(user, "Pressure: [round(pressure,0.1)] kPa") + else + to_chat(user, "Pressure: [round(pressure,0.1)] kPa") + if(total_moles) + for(var/g in environment.gas) + to_chat(user, "[global.gas_data.names[g]]: [round((environment.gas[g] / total_moles) * 100)]%") + to_chat(user, "Temperature: [round(environment.temperature-T0C,0.1)]°C ([round(environment.temperature,0.1)]K)") + +/obj/item/robot_builtin/dog_boop_module/afterattack(atom/target, mob/user, clickchain_flags, list/params) + if(!(clickchain_flags & CLICKCHAIN_HAS_PROXIMITY)) + return + if (user.stat) + return + if(!istype(target) && !ismob(target)) + return + + user.setClickCooldownLegacy(DEFAULT_ATTACK_COOLDOWN) + + + if(ismob(target)) + user.visible_message("\the [user] boops \the [target.name]!", "You boop \the [target.name]!") + playsound(src, 'sound/weapons/thudswoosh.ogg', 25, 1, -1) + else + user.visible_message("[user] sniffs at \the [target.name].", "You sniff \the [target.name]...") + if(!isnull(target.reagents)) + var/dat = "" + if(target.reagents.total_volume > 0) + for (var/datum/reagent/R in target.reagents.get_reagent_datums()) + dat += "\n \t [R]" + if(dat) + to_chat(user, "Your BOOP module indicates: [dat]") + else + to_chat(user, "No active chemical agents smelled in [target].") + else + if(istype(target, /obj/item/tank)) // don't double post what atmosanalyzer_scan returns + analyze_gases(target, user) + else + to_chat(user, "No significant chemical agents smelled in [target].") diff --git a/code/modules/mob/living/silicon/robot/items/robot_builtin/dog_jaws.dm b/code/modules/mob/living/silicon/robot/items/robot_builtin/dog_jaws.dm new file mode 100644 index 00000000000..eae2b028d95 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/items/robot_builtin/dog_jaws.dm @@ -0,0 +1,10 @@ +/obj/item/robot_builtin/dog_jaws + name = "synthetic jaws" + icon = 'icons/mob/dogborg_vr.dmi' + icon_state = "jaws" + desc = "Why did we start putting sharp jaws on stationbounds again? Things we ask ourselves every day, really." + damage_force = 10 + throw_force = 0 + attack_sound = 'sound/weapons/bite.ogg' + attack_verb = list("chomped", "bit", "ripped", "mauled", "enforced") + w_class = WEIGHT_CLASS_NORMAL diff --git a/code/modules/mob/living/silicon/robot/items/robot_builtin/dog_mirrortool.dm b/code/modules/mob/living/silicon/robot/items/robot_builtin/dog_mirrortool.dm new file mode 100644 index 00000000000..037b3ea7bc3 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/items/robot_builtin/dog_mirrortool.dm @@ -0,0 +1,49 @@ +/obj/item/robot_builtin/dog_mirrortool + name = "Mirror Installation Tool" + desc = "A tool for the installation and removal of Mirrors" + icon = 'icons/obj/device_alt.dmi' + icon_state = "sleevemate" + item_state = "healthanalyzer" + w_class = WEIGHT_CLASS_SMALL + var/obj/item/implant/mirror/imp = null + +/obj/item/robot_builtin/dog_mirrortool/afterattack(atom/target, mob/user, clickchain_flags, list/params) + var/mob/living/carbon/human/H = target + if(!istype(H)) + return + var/target_zone = user.zone_sel.selecting + if(target_zone == BP_TORSO && imp == null) + for(var/obj/item/organ/I in H.organs) + for(var/obj/item/implant/mirror/MI in I.contents) + if(imp == null) + H.visible_message("[user] is attempting remove [H]'s mirror!") + user.setClickCooldownLegacy(DEFAULT_QUICK_COOLDOWN) + user.do_attack_animation(H) + var/turf/T1 = get_turf(H) + if (T1 && ((H == user) || do_after(user, 20))) + if(user && H && (get_turf(H) == T1) && src) + H.visible_message("[user] has removed [H]'s mirror.") + add_attack_logs(user,H,"Mirror removed by [user]") + src.imp = MI + qdel(MI) + else if (target_zone == BP_TORSO && imp != null) + if (imp) + H.visible_message("[user] is attempting to implant [H] with a mirror.") + user.setClickCooldownLegacy(DEFAULT_QUICK_COOLDOWN) + user.do_attack_animation(H) + var/turf/T1 = get_turf(H) + if (T1 && ((H == user) || do_after(user, 20))) + if(user && H && (get_turf(H) == T1) && src && src.imp) + H.visible_message("[H] has been implanted by [user].") + add_attack_logs(user,H,"Implanted with [imp.name] using [name]") + if(imp.handle_implant(H)) + imp.post_implant(H) + src.imp = null + else + to_chat(usr, "You must target the torso.") + +/obj/item/robot_builtin/dog_mirrortool/afterattack(atom/target, mob/user, clickchain_flags, list/params) + var/obj/machinery/computer/transhuman/resleeving/comp = target + if(!istype(comp)) + return + comp.active_mr = imp.stored_mind diff --git a/code/modules/mob/living/silicon/robot/items/robot_builtin/dog_pounce.dm b/code/modules/mob/living/silicon/robot/items/robot_builtin/dog_pounce.dm new file mode 100644 index 00000000000..06345277b2a --- /dev/null +++ b/code/modules/mob/living/silicon/robot/items/robot_builtin/dog_pounce.dm @@ -0,0 +1,78 @@ +// todo: this is fucking stupid, rework everything. + +/obj/item/robot_builtin/dog_pounce + name = "pounce" + icon = 'icons/mob/dogborg_vr.dmi' + icon_state = "pounce" + desc = "Leap at your target to momentarily stun them." + damage_force = 0 + item_flags = ITEM_NO_BLUDGEON | ITEM_ENCUMBERS_WHILE_HELD + throw_force = 0 + +/obj/item/robot_builtin/dog_pounce/attack_self(mob/user, datum/event_args/actor/actor) + . = ..() + if(.) + return + var/mob/living/silicon/robot/R = user + R.leap() + +/mob/living/silicon/robot/proc/leap() + if(last_special > world.time) + to_chat(src, "Your leap actuators are still recharging.") + return + + if(cell.charge < 1000) + to_chat(src, "Cell charge too low to continue.") + return + + if(usr.incapacitated(INCAPACITATION_DISABLED)) + to_chat(src, "You cannot leap in your current state.") + return + + var/list/choices = list() + for(var/mob/living/M in view(3,src)) + if(!istype(M,/mob/living/silicon)) + choices += M + choices -= src + + var/mob/living/T = input(src,"Who do you wish to leap at?") as null|anything in choices + + if(!T || !src || src.stat) return + + if(get_dist(get_turf(T), get_turf(src)) > 3) return + + if(last_special > world.time) + return + + if(usr.incapacitated(INCAPACITATION_DISABLED)) + to_chat(src, "You cannot leap in your current state.") + return + + last_special = world.time + 10 + status_flags |= STATUS_LEAPING + pixel_y = pixel_y + 10 + + src.visible_message("\The [src] leaps at [T]!") + src.throw_at_old(get_step(get_turf(T),get_turf(src)), 4, 1, src) + playsound(src.loc, 'sound/mecha/mechstep2.ogg', 50, 1) + pixel_y = base_pixel_y + cell.charge -= 750 + + sleep(5) + + if(status_flags & STATUS_LEAPING) status_flags &= ~STATUS_LEAPING + + if(!src.Adjacent(T)) + to_chat(src, "You miss!") + return + + if(ishuman(T)) + var/mob/living/carbon/human/H = T + if(H.species.lightweight == 1) + H.afflict_paralyze(20 * 3) + return + var/armor_block = run_armor_check(T, "melee") + var/armor_soak = get_armor_soak(T, "melee") + T.apply_damage(20, DAMAGE_TYPE_HALLOSS,, armor_block, armor_soak) + if(prob(33)) + T.apply_effect(3, WEAKEN, armor_block) diff --git a/code/modules/mob/living/silicon/robot/dogborg/dog_sleeper_vr.dm b/code/modules/mob/living/silicon/robot/items/robot_builtin/dog_sleeper.dm similarity index 90% rename from code/modules/mob/living/silicon/robot/dogborg/dog_sleeper_vr.dm rename to code/modules/mob/living/silicon/robot/items/robot_builtin/dog_sleeper.dm index 7b84d99840d..b427d5543c3 100644 --- a/code/modules/mob/living/silicon/robot/dogborg/dog_sleeper_vr.dm +++ b/code/modules/mob/living/silicon/robot/items/robot_builtin/dog_sleeper.dm @@ -1,5 +1,11 @@ +// todo: this file is a fucking disgrace, rewrite this to be +// /obj/item/robot_builtin/entity_chamber +// and make all behavior modular +// also take out all fucking references of vore, +// if a downstream wants to be vorny power to them they can do it themselves + //Sleeper -/obj/item/dogborg/sleeper +/obj/item/robot_builtin/dog_sleeper name = "Medbelly" desc = "Equipment for medical hound. A mounted sleeper that stabilizes patients and can inject reagents in the borg's reserves." icon = 'icons/mob/dogborg_vr.dmi' @@ -30,27 +36,22 @@ var/startdrain = 500 var/max_item_count = 1 var/gulpsound = 'sound/vore/gulp.ogg' - var/datum/matter_synth/metal = null - var/datum/matter_synth/glass = null - var/datum/matter_synth/wood = null - var/datum/matter_synth/plastic = null - var/datum/matter_synth/water = null var/digest_brute = 2 var/digest_burn = 3 var/recycles = FALSE -/obj/item/dogborg/sleeper/Initialize(mapload) +/obj/item/robot_builtin/dog_sleeper/Initialize(mapload) . = ..() files = new /datum/research/techonly(src) -/obj/item/dogborg/sleeper/Destroy() +/obj/item/robot_builtin/dog_sleeper/Destroy() go_out() ..() -/obj/item/dogborg/sleeper/Exit(atom/movable/O) +/obj/item/robot_builtin/dog_sleeper/Exit(atom/movable/O) return 0 -/obj/item/dogborg/sleeper/afterattack(atom/target, mob/user, clickchain_flags, list/params) +/obj/item/robot_builtin/dog_sleeper/afterattack(atom/target, mob/user, clickchain_flags, list/params) hound = loc var/atom/movable/AM = target if(!istype(AM)) @@ -59,7 +60,7 @@ return if(AM.anchored) return - if(target in hound.module.modules) + if(target in hound.contents) return if(length(contents) >= max_item_count) to_chat(user, "Your [src.name] is full. Eject or process contents to continue.") @@ -151,7 +152,7 @@ message_admins("[key_name(hound)] has eaten [key_name(patient)] as a dogborg. ([hound ? "JMP" : "null"])") playsound(hound, gulpsound, vol = 100, vary = 1, falloff = 0.1, preference = /datum/game_preference_toggle/vore_sounds/eating_noises) -/obj/item/dogborg/sleeper/proc/go_out(var/target) +/obj/item/robot_builtin/dog_sleeper/proc/go_out(var/target) hound = src.loc items_preserved.Cut() cleaning = 0 @@ -172,13 +173,13 @@ else //You clicked eject with nothing in you, let's just reset stuff to be sure. update_patient() -/obj/item/dogborg/sleeper/proc/drain(var/amt = 3) //Slightly reduced cost (before, it was always injecting inaprov) +/obj/item/robot_builtin/dog_sleeper/proc/drain(var/amt = 3) //Slightly reduced cost (before, it was always injecting inaprov) hound = src.loc - if(istype(hound,/obj/item/robot_module)) + if(istype(hound,/obj/item/robot_module_legacy)) hound = hound.loc hound.cell.charge = hound.cell.charge - amt -/obj/item/dogborg/sleeper/attack_self(mob/user, datum/event_args/actor/actor) +/obj/item/robot_builtin/dog_sleeper/attack_self(mob/user, datum/event_args/actor/actor) . = ..() if(.) return @@ -186,7 +187,7 @@ return sleeperUI(user) -/obj/item/dogborg/sleeper/proc/sleeperUI(mob/user) +/obj/item/robot_builtin/dog_sleeper/proc/sleeperUI(mob/user) var/dat = "[name] Console
" if(islist(injection_chems)) //Only display this if we're a drug-dispensing doggo. @@ -294,7 +295,7 @@ UI_open = TRUE return -/obj/item/dogborg/sleeper/Topic(href, href_list) +/obj/item/robot_builtin/dog_sleeper/Topic(href, href_list) if(..() || usr == patient) return usr.set_machine(src) @@ -390,7 +391,7 @@ sleeperUI(usr) //Needs a callback to boop the page to refresh. return -/obj/item/dogborg/sleeper/proc/inject_chem(mob/user, chem) +/obj/item/robot_builtin/dog_sleeper/proc/inject_chem(mob/user, chem) if(patient && patient.reagents) if(chem in (injection_chems + "inaprovaline")) if(hound.cell.charge < 800) //This is so borgs don't kill themselves with it. @@ -405,7 +406,7 @@ to_chat(hound, "Injecting [units] unit\s of [SSchemistry.reagent_lookup[chem]] into occupant.") //If they were immersed, the reagents wouldn't leave with them. //For if the dogborg's existing patient uh, doesn't make it. -/obj/item/dogborg/sleeper/proc/update_patient() +/obj/item/robot_builtin/dog_sleeper/proc/update_patient() hound = src.loc if(!istype(hound,/mob/living/silicon/robot)) return @@ -414,8 +415,6 @@ //Cleaning looks better with red on, even with nobody in it if(cleaning || (length(contents) > 10) || (decompiler && (length(contents) > 5)) || (analyzer && (length(contents) > 1))) - hound.sleeper_r = TRUE - hound.sleeper_g = FALSE hound.updateicon() return @@ -423,16 +422,16 @@ if(patient in contents) if(patient_laststat != patient.stat) if(cleaning) - hound.sleeper_r = TRUE - hound.sleeper_g = FALSE + // hound.sleeper_r = TRUE + // hound.sleeper_g = FALSE patient_laststat = patient.stat else if(patient.stat & DEAD) - hound.sleeper_r = TRUE - hound.sleeper_g = FALSE + // hound.sleeper_r = TRUE + // hound.sleeper_g = FALSE patient_laststat = patient.stat else - hound.sleeper_r = FALSE - hound.sleeper_g = TRUE + // hound.sleeper_r = FALSE + // hound.sleeper_g = TRUE patient_laststat = patient.stat //Update icon hound.updateicon() @@ -444,25 +443,25 @@ for(var/mob/living/carbon/human/C in contents) patient = C if(cleaning) - hound.sleeper_r = TRUE - hound.sleeper_g = FALSE + // hound.sleeper_r = TRUE + // hound.sleeper_g = FALSE patient_laststat = patient.stat else if(patient.stat & DEAD) - hound.sleeper_r = TRUE - hound.sleeper_g = FALSE + // hound.sleeper_r = TRUE + // hound.sleeper_g = FALSE patient_laststat = patient.stat else - hound.sleeper_r = FALSE - hound.sleeper_g = TRUE + // hound.sleeper_r = FALSE + // hound.sleeper_g = TRUE patient_laststat = patient.stat //Update icon and return new patient hound.updateicon() return(C) //Couldn't find anyone, and not cleaning - if(!cleaning && !patient) - hound.sleeper_r = FALSE - hound.sleeper_g = FALSE + // if(!cleaning && !patient) + // hound.sleeper_r = FALSE + // hound.sleeper_g = FALSE patient_laststat = null patient = null @@ -470,7 +469,7 @@ return //Gurgleborg process -/obj/item/dogborg/sleeper/proc/clean_cycle() +/obj/item/robot_builtin/dog_sleeper/proc/clean_cycle() //Sanity? Maybe not required. More like if indigestible person OOC escapes. for(var/I in items_preserved) @@ -532,7 +531,7 @@ var/actual_burn = T.getFireLoss() - old_burn var/damage_gain = actual_brute + actual_burn drain(-25 * damage_gain) //25*total loss as with voreorgan stats. - water.add_charge(damage_gain) + item_mount?.reagent_spawn_amount(src, null, /datum/reagent/water, damage_gain) if(T.stat == DEAD) if(ishuman(T)) message_admins("[key_name(hound)] has digested [key_name(T)] as a dogborg. ([hound ? "JMP" : "null"])") @@ -569,10 +568,10 @@ if(ishuman(T)) var/mob/living/carbon/human/Prey = T volume = (Prey.bloodstr.total_volume + Prey.ingested.total_volume + Prey.touching.total_volume + Prey.weight) * Prey.size_multiplier - water.add_charge(volume) + item_mount?.reagent_spawn_amount(src, null, /datum/reagent/water, volume) if(T.reagents) volume = T.reagents.total_volume - water.add_charge(volume) + item_mount?.reagent_spawn_amount(src, null, /datum/reagent/water, volume) if(patient == T) patient_laststat = null patient = null @@ -598,7 +597,7 @@ synced = FALSE drain(-50 * digested) if(volume) - water.add_charge(volume) + item_mount?.reagent_spawn_amount(src, null, /datum/reagent/water, volume) var/list/mats = T.get_materials(TRUE) if(recycles && mats) for(var/material in mats) @@ -607,14 +606,14 @@ var/obj/item/stack/stack = T total_material *= stack.get_amount() if(material == MAT_STEEL) - metal.add_charge(total_material) + item_mount?.material_give_amount(src, null, /datum/prototype/material/steel::id, total_material) if(material == "glass") - glass.add_charge(total_material) + item_mount?.material_give_amount(src, null, /datum/prototype/material/glass::id, total_material) if(decompiler) if(material == "plastic") - plastic.add_charge(total_material) + item_mount?.material_give_amount(src, null, /datum/prototype/material/plastic::id, total_material) if(material == "wood") - wood.add_charge(total_material) + item_mount?.material_give_amount(src, null, /datum/prototype/material/wood_plank::id, total_material) else drain(-50 * digested) else if(istype(target,/obj/effect/decal/remains)) @@ -623,9 +622,8 @@ else items_preserved |= target update_patient() - return -/obj/item/dogborg/sleeper/process(delta_time) +/obj/item/robot_builtin/dog_sleeper/process(delta_time) if(!istype(src.loc,/mob/living/silicon/robot)) return @@ -649,13 +647,13 @@ STOP_PROCESSING(SSobj, src) return -/obj/item/dogborg/sleeper/K9 //The K9 portabrig +/obj/item/robot_builtin/dog_sleeper/K9 //The K9 portabrig name = "Brig-Belly" desc = "Equipment for a K9 unit. A mounted portable-brig that holds criminals." icon_state = "sleeperb" injection_chems = null //So they don't have all the same chems as the medihound! -/obj/item/dogborg/sleeper/compactor //Janihound gut. +/obj/item/robot_builtin/dog_sleeper/compactor //Janihound gut. name = "Garbage Processor" desc = "A mounted garbage compactor unit with fuel processor." icon_state = "compactor" @@ -664,7 +662,7 @@ recycles = TRUE max_item_count = 25 -/obj/item/dogborg/sleeper/compactor/analyzer //sci-borg gut. +/obj/item/robot_builtin/dog_sleeper/compactor/analyzer //sci-borg gut. name = "Digestive Analyzer" desc = "A mounted destructive analyzer unit with fuel processor." icon_state = "analyzer" @@ -672,7 +670,7 @@ startdrain = 100 analyzer = TRUE -/obj/item/dogborg/sleeper/compactor/decompiler +/obj/item/robot_builtin/dog_sleeper/compactor/decompiler name = "Matter Decompiler" desc = "A mounted materials decompiling unit with fuel processor." icon_state = "decompiler" @@ -680,7 +678,7 @@ decompiler = TRUE recycles = TRUE -/obj/item/dogborg/sleeper/compactor/delivery //Unfinished and unimplemented, still testing. +/obj/item/robot_builtin/dog_sleeper/compactor/delivery //Unfinished and unimplemented, still testing. name = "Cargo Belly" desc = "A mounted cargo bay unit for tagged deliveries." icon_state = "decompiler" diff --git a/code/modules/mob/living/silicon/robot/items/robot_builtin/dog_swordtail.dm b/code/modules/mob/living/silicon/robot/items/robot_builtin/dog_swordtail.dm new file mode 100644 index 00000000000..2f7be671b7f --- /dev/null +++ b/code/modules/mob/living/silicon/robot/items/robot_builtin/dog_swordtail.dm @@ -0,0 +1,11 @@ +/obj/item/robot_builtin/dog_swordtail + name = "sword tail" + icon = 'icons/mob/dogborg_vr.dmi' + icon_state = "swordtail" + desc = "A glowing pink dagger normally attached to the end of a cyborg's tail. It appears to be extremely sharp." + damage_force = 20 //Takes 5 hits to 100-0 + damage_mode = DAMAGE_MODE_SHARP | DAMAGE_MODE_EDGE + throw_force = 0 //This shouldn't be thrown in the first place. + attack_sound = 'sound/weapons/blade1.ogg' + attack_verb = list("slashed", "stabbed", "jabbed", "mauled", "sliced") + w_class = WEIGHT_CLASS_NORMAL diff --git a/code/modules/mob/living/silicon/robot/items/robot_builtin/dog_tongue.dm b/code/modules/mob/living/silicon/robot/items/robot_builtin/dog_tongue.dm new file mode 100644 index 00000000000..66b57815a1e --- /dev/null +++ b/code/modules/mob/living/silicon/robot/items/robot_builtin/dog_tongue.dm @@ -0,0 +1,122 @@ + +/obj/item/robot_builtin/dog_tongue + name = "synthetic tongue" + desc = "Useful for slurping mess off the floor before affectionally licking the crew members in the face." + icon = 'icons/mob/dogborg_vr.dmi' + icon_state = "synthtongue" + attack_sound = 'sound/effects/attackblob.ogg' + item_flags = ITEM_NO_BLUDGEON | ITEM_ENCUMBERS_WHILE_HELD + var/emagged = 0 + var/datum/matter_synth/water = null + +/obj/item/robot_builtin/dog_tongue/examine(user) + . = ..() + if(item_mount.reagent_get_amount(src, null, /datum/reagent/water::id) < 5) + . += "[src] is wet." + else + . += "[src] is dry." + +/obj/item/robot_builtin/dog_tongue/attack_self(mob/user, datum/event_args/actor/actor) + . = ..() + if(.) + return + var/mob/living/silicon/robot/R = user + if(R.emagged || R.emag_items) + emagged = !emagged + if(emagged) + name = "hacked tongue of doom" + desc = "Your tongue has been upgraded successfully. Congratulations." + icon = 'icons/mob/dogborg_vr.dmi' + icon_state = "syndietongue" + else + name = "synthetic tongue" + desc = "Useful for slurping mess off the floor before affectionally licking the crew members in the face." + icon = 'icons/mob/dogborg_vr.dmi' + icon_state = "synthtongue" + update_icon() + +/obj/item/robot_builtin/dog_tongue/afterattack(atom/target, mob/user, clickchain_flags, list/params) + if(!(clickchain_flags & CLICKCHAIN_HAS_PROXIMITY)) + return + + user.setClickCooldownLegacy(DEFAULT_ATTACK_COOLDOWN) + if(user.client && (target in user.client.screen)) + to_chat(user, "You need to take [target] off before cleaning it!") + if(istype(target, /obj/structure/sink) || istype(target, /obj/structure/toilet)) //Dog vibes. + user.visible_message("[user] begins to lap up water from [target].", "You begin to lap up water from [target].") + if(do_after(user, 50, target = target)) + item_mount?.reagent_spawn_amount(src, null, /datum/reagent/water, 50) + else if(item_mount?.reagent_get_amount(src, null, /datum/reagent/water) < 1) + to_chat(user, "Your mouth feels dry. You should drink some water.") //fixed annoying grammar and needless space + return + else if(istype(target,/obj/effect/debris/cleanable)) + user.visible_message("[user] begins to lick off [target].", "You begin to lick off [target]...") + if(do_after(user, 50, target = target)) + to_chat(user, "You finish licking off [target].") + item_mount?.reagent_erase_amount(src, null, /datum/reagent/water, 1) + qdel(target) + var/mob/living/silicon/robot/R = user + R.cell.charge += 50 + else if(istype(target,/obj/item)) + if(istype(target,/obj/item/trash)) + user.visible_message("[user] nibbles away at [target].", "You begin to nibble away at [target]...") + if(do_after(user, 50, target = target)) + user.visible_message("[user] finishes eating [target].", "You finish eating [target].") + to_chat(user, "You finish off [target].") + qdel(target) + var/mob/living/silicon/robot/R = user + if(istype(target,/obj/item/trash/rkibble)) + R.cell.charge += 1000 + else + R.cell.charge += 250 + item_mount?.reagent_erase_amount(src, null, /datum/reagent/water, 1) + return + if(istype(target,/obj/item/cell)) + user.visible_message("[user] begins cramming [target] down its throat.", "You begin cramming \the [target.name] down your throat...") + if(do_after(user, 50, target = target)) + user.visible_message("[user] finishes gulping down [target].", "You finish swallowing [target].") + to_chat(user, "You finish off [target], and gain some charge!") + var/mob/living/silicon/robot/R = user + var/obj/item/cell/C = target + R.cell.charge += C.max_charge / 3 + item_mount?.reagent_erase_amount(src, null, /datum/reagent/water, 1) + qdel(target) + return + user.visible_message("[user] begins to lick [target] clean...", "You begin to lick [target] clean...") + if(do_after(user, 50, target = target)) + to_chat(user, "You clean [target].") + item_mount?.reagent_erase_amount(src, null, /datum/reagent/water, 1) + var/obj/effect/debris/cleanable/C = locate() in target + qdel(C) + target.clean_blood() + else if(ishuman(target)) + if(src.emagged) + var/mob/living/silicon/robot/R = user + var/mob/living/L = target + if(R.cell.charge <= 666) + return + L.afflict_stun(20 * 1) + L.afflict_paralyze(20 * 1) + L.apply_effect(STUTTER, 1) + L.visible_message("[user] has shocked [L] with its tongue!", \ + "[user] has shocked you with its tongue! You can feel the betrayal.") + playsound(loc, 'sound/weapons/Egloves.ogg', 50, 1, -1) + R.cell.charge -= 666 + else + user.visible_message("\The [user] affectionally licks all over [target]'s face!", "You affectionally lick all over [target]'s face!") + playsound(src.loc, 'sound/effects/attackblob.ogg', 50, 1) + item_mount?.reagent_erase_amount(src, null, /datum/reagent/water, 1) + var/mob/living/carbon/human/H = target + if(H.species.lightweight == 1) + H.afflict_paralyze(20 * 3) + else + user.visible_message("[user] begins to lick [target] clean...", "You begin to lick [target] clean...") + if(do_after(user, 50, target = target)) + to_chat(user, "You clean [target].") + var/obj/effect/debris/cleanable/C = locate() in target + qdel(C) + target.clean_blood() + item_mount?.reagent_erase_amount(src, null, /datum/reagent/water, 1) + if(istype(target, /turf/simulated)) + var/turf/simulated/T = target + T.dirt = 0 diff --git a/code/modules/mob/living/silicon/robot/items/robot_upgrade.dm b/code/modules/mob/living/silicon/robot/items/robot_upgrade.dm new file mode 100644 index 00000000000..c4baaaeea1a --- /dev/null +++ b/code/modules/mob/living/silicon/robot/items/robot_upgrade.dm @@ -0,0 +1,201 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2025 Citadel Station Developers *// + +/obj/item/robot_upgrade + name = "robot upgrade module" + desc = "An upgrade module for a robot platform." + icon = 'icons/items/circuits.dmi' + icon_state = "cyborg_upgrade" + + //* Actions *// + /// actions to give the owner of this upgrade + /// + /// valid starting values include: + /// * list of actions / typepaths + /// * single action / typepath + var/list/datum/action/upgrade_actions + /// set to a string to initialize upgrade_actions with a generic action of this name + var/upgrade_action_name + /// description for upgrade action; defaults to [desc] + var/upgrade_action_desc + + /// Who we're installed in. + var/mob/living/silicon/robot/owner + /// Provisioning + /// * Not destroyed across different owners, this owns our items and more. + var/datum/robot_provisioning/provisioning + /// Lazy man's create_mounted_item_descriptor injection. + /// * This shouldn't be used at compile time; just override the proc. + VAR_PRIVATE/list/provisioning_inject_item_descriptors + + /// Allow dupes? + var/dupe_allowed = FALSE + /// Dupe type to check; defaults to self type + var/dupe_type + +/obj/item/robot_upgrade/Destroy() + owner?.uninstall_upgrade(src, TRUE) + QDEL_NULL(provisioning) + return ..() + +/obj/item/robot_upgrade/using_as_item(atom/target, datum/event_args/actor/clickchain/clickchain, clickchain_flags, datum/callback/reachability_check) + . = ..() + if(.) + return + if(!isrobot(target)) + return + var/mob/living/silicon/robot/robot_target = target + if(!robot_target.opened) + clickchain.chat_feedback( + SPAN_WARNING("[robot_target] needs to havea their cover opened for you to access their internals!"), + target = robot_target, + ) + return CLICKCHAIN_DO_NOT_PROPAGATE | CLICKCHAIN_DID_SOMETHING + robot_target.user_install_upgrade(src, actor = clickchain) + return CLICKCHAIN_DO_NOT_PROPAGATE | CLICKCHAIN_DID_SOMETHING + +/obj/item/robot_upgrade/proc/load_provisioning_if_needed() + if(provisioning) + return + create_provisioning() + +/obj/item/robot_upgrade/proc/create_provisioning() as /datum/robot_provisioning + SHOULD_NOT_OVERRIDE(TRUE) + SHOULD_NOT_SLEEP(TRUE) + // obliterate existing if there + QDEL_NULL(provisioning) + // make new one + var/datum/robot_provisioning/robot_upgrade/creating = new(src) + . = provisioning = creating + var/list/items = create_mounted_items() + for(var/obj/item/item as anything in items) + creating.add_item(item) + return creating + +/obj/item/robot_upgrade/proc/create_mounted_items() as /list + var/list/obj/item/items = list() + + var/list/i_normal = list() + create_mounted_item_descriptors(i_normal) + for(var/obj/item/descriptor as anything in i_normal) + var/obj/item/resolved + if(istype(descriptor)) + resolved = descriptor + else if(ispath(descriptor)) + resolved = new descriptor + else if(IS_ANONYMOUS_TYPEPATH(descriptor)) + resolved = new descriptor + else + stack_trace("invalid descriptor [descriptor] on [src] ([type])") + continue + items += resolved + + return items + +/** + * See: `/datum/prototype/robot_module/proc/create_mounted_item_descriptors`. + * + * This uses the exact same format and is handled in a similar way. + */ +/obj/item/robot_upgrade/proc/create_mounted_item_descriptors(list/out_list) + if(provisioning_inject_item_descriptors) + out_list |= provisioning_inject_item_descriptors + +/** + * Called when checking if we can be applied + * + * * Robot has final say for hard conflicts. (we won't be called in that case) + * * We have final say for soft conflicts. + * * skipped if 'force' is enabled on checks in the robot + * + * @params + * * target - robot we're attempting to be installed in + * * robot_opinion - what the robot says about it + * * actor - (optional) person doing the install + * * silent - (optional) do not emit feedback to the actor + * + * @return TRUE / FALSE + */ +/obj/item/robot_upgrade/proc/can_install(mob/living/silicon/robot/target, robot_opinion, datum/event_args/actor/actor, silent) + return TRUE + +/** + * Called when being applied. + * + * * Destructive operations here (like deleting ourselves) is allowed. + * * This is where 'consumable' upgrades like 'enable emag items' are put. + */ +/obj/item/robot_upgrade/proc/being_installed(mob/living/silicon/robot/target) + return + +/** + * Called on install. + */ +/obj/item/robot_upgrade/proc/on_install(mob/living/silicon/robot/target) + SHOULD_NOT_SLEEP(TRUE) + SHOULD_CALL_PARENT(TRUE) + + load_provisioning_if_needed() + provisioning?.apply(target) + grant_upgrade_actions(target) + +/** + * Called on uninstall. + * + * * We're uninstalled if the robot is deleted. + */ +/obj/item/robot_upgrade/proc/on_uninstall(mob/living/silicon/robot/target) + SHOULD_NOT_SLEEP(TRUE) + SHOULD_CALL_PARENT(TRUE) + + revoke_upgrade_actions(target) + provisioning?.remove(target) + +//* Actions *// + +/obj/item/robot_upgrade/proc/ensure_upgrade_actions_loaded() + if(islist(upgrade_actions)) + for(var/i in 1 to length(upgrade_actions)) + var/key = upgrade_actions[i] + if(ispath(key, /datum/action)) + upgrade_actions[i] = key = new key(src) + else if(ispath(upgrade_actions, /datum/action)) + upgrade_actions = new upgrade_actions + else if(istype(upgrade_actions, /datum/action)) + else if(upgrade_action_name) + var/datum/action/robot_upgrade_action/creating = new(src) + upgrade_actions = creating + creating.name = upgrade_action_name + creating.desc = upgrade_action_desc || desc + +/obj/item/robot_upgrade/proc/grant_upgrade_actions(mob/target) + if(islist(upgrade_actions)) + for(var/datum/action/action in upgrade_actions) + action.grant(target.actions_innate) + else if(istype(upgrade_actions, /datum/action)) + var/datum/action/action = upgrade_actions + action.grant(target.actions_innate) + +/obj/item/robot_upgrade/proc/revoke_upgrade_actions(mob/target) + if(islist(upgrade_actions)) + for(var/datum/action/action in upgrade_actions) + action.revoke(target.actions_innate) + else if(istype(upgrade_actions, /datum/action)) + var/datum/action/action = upgrade_actions + action.revoke(target.actions_innate) + +//* Provisioning *// + +/datum/robot_provisioning/robot_upgrade + var/obj/item/robot_upgrade/owner + +/datum/robot_provisioning/robot_upgrade/New(obj/item/robot_upgrade/upgrade) + owner = upgrade + ..() + +/datum/robot_provisioning/robot_upgrade/Destroy() + owner = null + return ..() + +/datum/robot_provisioning/robot_upgrade/get_detached_storage_location() + return owner diff --git a/code/modules/mob/living/silicon/robot/items/robot_upgrade/advhealth.dm b/code/modules/mob/living/silicon/robot/items/robot_upgrade/advhealth.dm new file mode 100644 index 00000000000..8c6bda467a7 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/items/robot_upgrade/advhealth.dm @@ -0,0 +1,9 @@ +/obj/item/robot_upgrade/advhealth + name = "advanced health analyzer module" + desc = "An upgrade to add an advanced health analyzer to a robot." + icon_state = "cyborg_upgrade3" + item_state = "cyborg_upgrade" + +/obj/item/robot_upgrade/advhealth/create_mounted_item_descriptors(list/out_list) + out_list += /obj/item/healthanalyzer/advanced + return ..() diff --git a/code/modules/mob/living/silicon/robot/items/robot_upgrade/bluespaceorebag.dm b/code/modules/mob/living/silicon/robot/items/robot_upgrade/bluespaceorebag.dm new file mode 100644 index 00000000000..847c6d8d81a --- /dev/null +++ b/code/modules/mob/living/silicon/robot/items/robot_upgrade/bluespaceorebag.dm @@ -0,0 +1,22 @@ +/obj/item/robot_upgrade/bluespaceorebag + name = "bluespace mining satchel module" + desc = "An upgrade to upgrade a robot's ore bag." + icon_state = "cyborg_upgrade3" + item_state = "cyborg_upgrade" + +/obj/item/robot_upgrade/bluespaceorebag/create_mounted_item_descriptors(list/out_list) + out_list += /obj/item/storage/bag/ore/bluespace + return ..() + +/obj/item/robot_upgrade/bluespaceorebag/on_install(mob/living/silicon/robot/target) + . = ..() + var/obj/item/storage/bag/ore/our_bag = locate() in provisioning?.items + var/list/obj/item/suppressed = target.module_provisioning.suppress_all_types_of(/obj/item/storage/bag/ore) + if(our_bag) + for(var/obj/item/storage/transferring in suppressed) + for(var/obj/item/stack/ore/ore in transferring.contents) + ore.forceMove(our_bag) + +/obj/item/robot_upgrade/bluespaceorebag/on_uninstall(mob/living/silicon/robot/target) + . = ..() + target.module_provisioning.unsuppress_all_types_of(/obj/item/storage/bag/ore) diff --git a/code/modules/mob/living/silicon/robot/items/robot_upgrade/jetpack.dm b/code/modules/mob/living/silicon/robot/items/robot_upgrade/jetpack.dm new file mode 100644 index 00000000000..3baa35f5164 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/items/robot_upgrade/jetpack.dm @@ -0,0 +1,10 @@ +// todo: ion thruster upgrade instead wtf +/obj/item/robot_upgrade/jetpack + name = "robot jetpack" + desc = "A carbon dioxide jetpack suitable for low-gravity operations." + icon_state = "cyborg_upgrade3" + item_state = "cyborg_upgrade" + +/obj/item/robot_upgrade/bluespaceorebag/create_mounted_item_descriptors(list/out_list) + out_list += /obj/item/tank/jetpack/carbondioxide + return ..() diff --git a/code/modules/mob/living/silicon/robot/items/robot_upgrade/language.dm b/code/modules/mob/living/silicon/robot/items/robot_upgrade/language.dm new file mode 100644 index 00000000000..5e5ec3b62ef --- /dev/null +++ b/code/modules/mob/living/silicon/robot/items/robot_upgrade/language.dm @@ -0,0 +1,19 @@ +/obj/item/robot_upgrade/language + name = "adaptive translation module" + desc = "Upgrades a cyborg's language processing unit with an adaptive translation module." + icon_state = "cyborg_upgrade3" + item_state = "cyborg_upgrade" + +/obj/item/robot_upgrade/language/can_install(mob/living/silicon/robot/target, robot_opinion, datum/event_args/actor/actor, silent) + if(target.translation_context?.type == /datum/translation_context/variable/learning/silicons) + if(!silent) + actor?.chat_feedback( + SPAN_WARNING("[target] already has an adaptive translation unit installed."), + target = target, + ) + return FALSE + return ..() + +/obj/item/robot_upgrade/language/being_installed(mob/living/silicon/robot/target) + target.create_translation_context(/datum/translation_context/variable/learning/silicons) + qdel(src) diff --git a/code/modules/mob/living/silicon/robot/items/robot_upgrade/rename.dm b/code/modules/mob/living/silicon/robot/items/robot_upgrade/rename.dm new file mode 100644 index 00000000000..bb7bbdc699d --- /dev/null +++ b/code/modules/mob/living/silicon/robot/items/robot_upgrade/rename.dm @@ -0,0 +1,21 @@ +/obj/item/robot_upgrade/rename + name = "robot reclassification board" + desc = "Used to rename a cyborg." + icon_state = "cyborg_upgrade1" + item_state = "cyborg_upgrade" + var/heldname = "default name" + +/obj/item/robot_upgrade/rename/attack_self(mob/user, datum/event_args/actor/actor) + . = ..() + if(.) + return + heldname = sanitizeSafe(input(user, "Enter new robot name", "Robot Reclassification", heldname), MAX_NAME_LEN) + +// TODO: refactor cyborg namepicking +/obj/item/robot_upgrade/rename/being_installed(mob/living/silicon/robot/target) + var/mob/living/silicon/robot/R = target + R.notify_ai(ROBOT_NOTIFICATION_NEW_NAME, R.name, heldname) + R.name = heldname + R.custom_name = heldname + R.real_name = heldname + qdel(src) diff --git a/code/modules/mob/living/silicon/robot/items/robot_upgrade/reset.dm b/code/modules/mob/living/silicon/robot/items/robot_upgrade/reset.dm new file mode 100644 index 00000000000..66ed6511ed7 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/items/robot_upgrade/reset.dm @@ -0,0 +1,9 @@ +/obj/item/robot_upgrade/reset + name = "robotic module reset board" + desc = "Used to reset a cyborg's module. Destroys any other upgrades applied to the robot." + icon_state = "cyborg_upgrade1" + item_state = "cyborg_upgrade" + +/obj/item/robot_upgrade/reset/being_installed(mob/living/silicon/robot/target) + target.module_reset() + qdel(src) diff --git a/code/modules/mob/living/silicon/robot/items/robot_upgrade/restart.dm b/code/modules/mob/living/silicon/robot/items/robot_upgrade/restart.dm new file mode 100644 index 00000000000..5fedd06714a --- /dev/null +++ b/code/modules/mob/living/silicon/robot/items/robot_upgrade/restart.dm @@ -0,0 +1,33 @@ +/obj/item/robot_upgrade/restart + name = "robot emergency restart module" + desc = "Used to force a restart of a disabled-but-repaired robot, bringing it back online." + icon_state = "cyborg_upgrade1" + item_state = "cyborg_upgrade" + +/obj/item/robot_upgrade/restart/can_install(mob/living/silicon/robot/target, robot_opinion, datum/event_args/actor/actor, silent) + if(target.health < 0) + if(!silent) + actor?.chat_feedback( + SPAN_WARNING("You have to repair [target] before using an emergency restart module."), + target = target, + ) + return FALSE + if(target.stat != DEAD) + if(!silent) + // ok this is a bit morbid but it's funny. + actor?.chat_feedback( + SPAN_WARNING("[target] is operational; only fully disabled cyborgs may be restarted."), + target = target, + ) + return FALSE + return TRUE + +/obj/item/robot_upgrade/restart/being_installed(mob/living/silicon/robot/target) + // TODO: standardize revival. + target.revive(TRUE, FALSE, FALSE) + if(!target.ckey) + for(var/mob/observer/dead/ghost in GLOB.player_list) + if(ghost.mind?.current == target) + ghost.transfer_client_to(target) + target.notify_ai(ROBOT_NOTIFICATION_NEW_UNIT) + qdel(src) diff --git a/code/modules/mob/living/silicon/robot/items/robot_upgrade/sizeshift.dm b/code/modules/mob/living/silicon/robot/items/robot_upgrade/sizeshift.dm new file mode 100644 index 00000000000..0c2778a25a8 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/items/robot_upgrade/sizeshift.dm @@ -0,0 +1,13 @@ +/obj/item/robot_upgrade/sizeshift + name = "robot size alteration module" + desc = "Using technology similar to one used in size guns, allows cyborgs to adjust their own size as necessary." + icon_state = "cyborg_upgrade2" + item_state = "cyborg_upgrade" + +/obj/item/robot_upgrade/language/on_install(mob/living/silicon/robot/target) + . = ..() + add_verb(target, /mob/living/proc/set_size) + +/obj/item/robot_upgrade/language/on_uninstall(mob/living/silicon/robot/target) + . = ..() + remove_verb(target, /mob/living/proc/set_size) diff --git a/code/modules/mob/living/silicon/robot/items/robot_upgrade/syndicate.dm b/code/modules/mob/living/silicon/robot/items/robot_upgrade/syndicate.dm new file mode 100644 index 00000000000..6d38aef444b --- /dev/null +++ b/code/modules/mob/living/silicon/robot/items/robot_upgrade/syndicate.dm @@ -0,0 +1,21 @@ +/obj/item/robot_upgrade/syndicate + name = "scrambled equipment module" + desc = "Unlocks new and often deadly module specific items of a robot" + icon_state = "cyborg_upgrade3" + item_state = "cyborg_upgrade" + +/obj/item/robot_upgrade/syndicate/can_install(mob/living/silicon/robot/target, robot_opinion, datum/event_args/actor/actor, silent) + . = ..() + if(!.) + return + if(target.get_emag_item_state()) + if(!silent) + actor?.chat_feedback( + SPAN_WARNING("[target] already has scrambled equipment enabled."), + target = src, + ) + return FALSE + +/obj/item/robot_upgrade/syndicate/being_installed(mob/living/silicon/robot/target) + target.set_emag_item_state(TRUE) + qdel(src) diff --git a/code/modules/mob/living/silicon/robot/items/robot_upgrade/vtec.dm b/code/modules/mob/living/silicon/robot/items/robot_upgrade/vtec.dm new file mode 100644 index 00000000000..3077faca6b3 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/items/robot_upgrade/vtec.dm @@ -0,0 +1,66 @@ +/** + * this item is slated for removal as borgs get more upgrades + * + * full speed increase upgrades are bad design, sorry. + */ +/obj/item/robot_upgrade/vtec + name = "robotic VTEC Module" + desc = "Used to kick in a robot's VTEC systems, increasing their speed." + icon_state = "cyborg_upgrade2" + item_state = "cyborg_upgrade" + + var/current_power_level = 0 + var/current_tps_boost = 1 + + var/list/possible_tps_boosts = list( + 1, + 1.75, + 2.5, + ) + + upgrade_actions = list( + /datum/action/robot_upgrade_action/vtec, + ) + +/obj/item/robot_upgrade/vtec/proc/set_power_level(level) + src.current_power_level = clamp(level, 0, length(possible_tps_boosts)) + src.current_tps_boost = length(possible_tps_boosts) ? possible_tps_boosts[src.current_power_level] : 0 + update_movespeed_modifier() + +/obj/item/robot_upgrade/vtec/on_install(mob/living/silicon/robot/target) + ..() + set_power_level(current_power_level) + +/obj/item/robot_upgrade/vtec/on_uninstall(mob/living/silicon/robot/target) + ..() + remove_movespeed_modifier() + +/obj/item/robot_upgrade/vtec/proc/user_toggle_tps_boost(datum/event_args/actor/actor) + set_power_level(current_power_level >= length(possible_tps_boosts) ? 0 : current_power_level + 1) + for(var/datum/action/action in upgrade_actions) + action.update_buttons() + +/obj/item/robot_upgrade/vtec/proc/update_movespeed_modifier() + owner.update_movespeed_modifier(/datum/movespeed_modifier/mob_vtec_upgrade, TRUE, list( + MOVESPEED_PARAM_MOD_TILES_PER_SECOND = current_tps_boost, + )) + +/obj/item/robot_upgrade/vtec/proc/remove_movespeed_modifier() + owner.remove_movespeed_modifier(/datum/movespeed_modifier/mob_vtec_upgrade) + +/datum/action/robot_upgrade_action/vtec + button_icon = 'icons/screen/actions/generic.dmi' + button_icon_state = "chevron-1" + + var/vtec_chevron_icon_state_base = "chevron-" + var/vtec_chevron_icon_states = 3 + +/datum/action/robot_upgrade_action/vtec/pre_render_hook() + . = ..() + var/obj/item/robot_upgrade/vtec/casted_target = target + button_icon_state = "[vtec_chevron_icon_state_base]\ + [ceil((casted_target.current_power_level / length(casted_target.possible_tps_boosts)) * vtec_chevron_icon_states)]" + +/datum/action/robot_upgrade_action/vtec/invoke_target(obj/item/robot_upgrade/vtec/target, datum/event_args/actor/actor) + target.user_toggle_tps_boost(actor) + return ..() diff --git a/code/modules/mob/living/silicon/robot/laws.dm b/code/modules/mob/living/silicon/robot/laws.dm index 59a7160d4c2..d794249a21a 100644 --- a/code/modules/mob/living/silicon/robot/laws.dm +++ b/code/modules/mob/living/silicon/robot/laws.dm @@ -44,7 +44,7 @@ /mob/living/silicon/robot/lawsync() laws_sanity_check() - var/datum/ai_laws/master = connected_ai && lawupdate ? connected_ai.laws : null + var/datum/ai_lawset/master = connected_ai && lawupdate ? connected_ai.laws : null if (master) master.sync(src) ..() diff --git a/code/game/objects/items/robot/gripper.dm b/code/modules/mob/living/silicon/robot/legacy_items/gripper.dm similarity index 97% rename from code/game/objects/items/robot/gripper.dm rename to code/modules/mob/living/silicon/robot/legacy_items/gripper.dm index 688aa5c48c1..20f46c36d14 100644 --- a/code/game/objects/items/robot/gripper.dm +++ b/code/modules/mob/living/silicon/robot/legacy_items/gripper.dm @@ -1,3 +1,5 @@ +// todo: this shouldn't be a robot item, this is generic. + //Simple borg hand. //Limited use. /obj/item/gripper @@ -28,6 +30,8 @@ /// currently held item VAR_PRIVATE/obj/item/wrapped + var/conf_inject_clickchain_flags + /obj/item/gripper/examine(mob/user, dist) . = ..() if(wrapped) @@ -94,7 +98,7 @@ /obj/item/gripper/melee_interaction_chain(datum/event_args/actor/clickchain/clickchain, clickchain_flags) if(!isnull(wrapped)) - return wrapped.melee_interaction_chain(clickchain, clickchain_flags | CLICKCHAIN_REDIRECTED) + return wrapped.melee_interaction_chain(clickchain, clickchain_flags | CLICKCHAIN_REDIRECTED | conf_inject_clickchain_flags) return ..() /obj/item/gripper/verb/drop_item() @@ -169,6 +173,9 @@ can_hold = list(/obj/item) // Testing and Event gripper. +/obj/item/gripper/omni/no_attack + conf_inject_clickchain_flags = CLICKCHAIN_DO_NOT_ATTACK + // VEEEEERY limited version for mining borgs. Basically only for swapping cells and upgrading the drills. /obj/item/gripper/miner name = "drill maintenance gripper" @@ -233,7 +240,7 @@ /obj/item/stock_parts, /obj/item/mmi, /obj/item/robot_parts, - /obj/item/borg/upgrade, + /obj/item/robot_upgrade, /obj/item/flash, //to build borgs, /obj/item/disk, /obj/item/circuitboard, diff --git a/code/game/objects/items/robot/robot_items.dm b/code/modules/mob/living/silicon/robot/legacy_items/robot_items.dm similarity index 100% rename from code/game/objects/items/robot/robot_items.dm rename to code/modules/mob/living/silicon/robot/legacy_items/robot_items.dm diff --git a/code/game/objects/items/robot/robot_parts.dm b/code/modules/mob/living/silicon/robot/legacy_items/robot_parts.dm similarity index 100% rename from code/game/objects/items/robot/robot_parts.dm rename to code/modules/mob/living/silicon/robot/legacy_items/robot_parts.dm diff --git a/code/modules/mob/living/silicon/robot/life.dm b/code/modules/mob/living/silicon/robot/life.dm index c728866c497..4f2b1520113 100644 --- a/code/modules/mob/living/silicon/robot/life.dm +++ b/code/modules/mob/living/silicon/robot/life.dm @@ -6,6 +6,13 @@ clamp_values() handle_regular_UI_updates() + // TODO: actual smoothing?? or less awful-ify this lol + var/avg_power_elapsed = world.time - avg_power_last + if(avg_power_elapsed > 0) + avg_power = avg_power_accumulator / (avg_power_elapsed / (1 SECONDS)) + avg_power_last = world.time + avg_power_accumulator = 0 + /mob/living/silicon/robot/PhysicalLife(seconds, times_fired) if((. = ..())) return @@ -14,8 +21,6 @@ update_items() if (src.stat != DEAD) //still using power use_power() - process_killswitch() - process_locks() process_queued_alarms() /mob/living/silicon/robot/proc/clamp_values() @@ -25,29 +30,17 @@ effect.set_duration_from_now(20 SECONDS) set_sleeping(0) - adjustBruteLoss(0) - adjustToxLoss(0) - adjustOxyLoss(0) - adjustFireLoss(0) /mob/living/silicon/robot/proc/use_power() - // Debug only - // to_chat(world, "DEBUG: life.dm line 35: cyborg use_power() called at tick [controller_iteration]") - used_power_this_tick = 0 for(var/V in components) var/datum/robot_component/C = components[V] C.update_power_state() if ( cell && is_component_functioning("power cell") && src.cell.charge > 0 ) - if(src.module_state_1) - cell_use_power(50) // 50W load for every enabled tool TODO: tool-specific loads - if(src.module_state_2) - cell_use_power(50) - if(src.module_state_3) - cell_use_power(50) + legacy_cell_use_power(50 * length(robot_inventory.inv_get_active())) if(lights_on) - cell_use_power(30) // 30W light. Normal lights would use ~15W, but increased for balance reasons. + legacy_cell_use_power(30) // 30W light. Normal lights would use ~15W, but increased for balance reasons. src.has_power = 1 else @@ -96,7 +89,7 @@ //update the state of modules and components here if (src.stat != 0) - uneq_all() + inventory.drop_held_items() if(radio) if(!is_component_functioning("radio")) @@ -231,34 +224,8 @@ for(var/obj/I in src.contents) if(I && !(istype(I,/obj/item/cell) || istype(I,/obj/item/radio) || istype(I,/obj/machinery/camera) || istype(I,/obj/item/mmi))) src.client.screen += I - if(src.module_state_1) - src.module_state_1:screen_loc = ui_inv1 - if(src.module_state_2) - src.module_state_2:screen_loc = ui_inv2 - if(src.module_state_3) - src.module_state_3:screen_loc = ui_inv3 updateicon() -/mob/living/silicon/robot/proc/process_killswitch() - if(killswitch) - killswitch_time -- - if(killswitch_time <= 0) - if(src.client) - to_chat(src, "Killswitch Activated") - killswitch = 0 - spawn(5) - gib() - -/mob/living/silicon/robot/proc/process_locks() - if(weapon_lock) - uneq_all() - weaponlock_time -- - if(weaponlock_time <= 0) - if(src.client) - to_chat(src, "Weapon Lock Timed Out!") - weapon_lock = 0 - weaponlock_time = 120 - // todo: better way /mob/living/silicon/robot/update_mobility() . = ..() diff --git a/code/modules/mob/living/silicon/robot/login.dm b/code/modules/mob/living/silicon/robot/login.dm index e292a440981..9570f968c86 100644 --- a/code/modules/mob/living/silicon/robot/login.dm +++ b/code/modules/mob/living/silicon/robot/login.dm @@ -4,7 +4,3 @@ update_hud() show_laws(0) - - // Forces synths to select an icon relevant to their module - if(!icon_selected) - choose_icon(icon_selection_tries, module_sprites) diff --git a/code/modules/mob/living/silicon/robot/modules/cybersun.dm b/code/modules/mob/living/silicon/robot/modules/cybersun.dm new file mode 100644 index 00000000000..df26b443ae8 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/modules/cybersun.dm @@ -0,0 +1,4 @@ +/datum/prototype/robot_module/cybersun + abstract_type = /datum/prototype/robot_module/cybersun + module_hud_state = "malf" + category = "Cybersun" diff --git a/code/modules/mob/living/silicon/robot/modules/cybersun/assault.dm b/code/modules/mob/living/silicon/robot/modules/cybersun/assault.dm new file mode 100644 index 00000000000..178a0fcdd40 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/modules/cybersun/assault.dm @@ -0,0 +1,45 @@ +GENERATE_ROBOT_MODULE_PRESET(/cybersun/assault) +/datum/prototype/robot_module/cybersun/assault + id = "cybersun-assault" + display_name = "CS-COM" + visible_name = "Assault" + use_robot_module_path = /obj/item/robot_module_legacy/robot/syndicate + light_color = "#FF0000" + auto_iconsets = list( + /datum/prototype/robot_iconset/grounded_landmate/security_cybersun, + /datum/prototype/robot_iconset/grounded_landmate/security_cybersun_tread, + /datum/prototype/robot_iconset/raptor/syndicate_medical, + /datum/prototype/robot_iconset/biped_heavy/antag, + /datum/prototype/robot_iconset/grounded_spider/combat, + /datum/prototype/robot_iconset/baseline_misc/squats, + ) + +/datum/prototype/robot_module/cybersun/assault/create_mounted_item_descriptors(list/normal_out, list/emag_out) + ..() + if(normal_out) + normal_out |= list( + /obj/item/shield_projector/rectangle/weak, + /obj/item/gun/projectile/energy/dakkalaser, + /obj/item/handcuffs/cyborg, + /obj/item/melee/baton/robot, + /obj/item/melee/transforming/energy/sword, + ) + +/obj/item/robot_module_legacy/robot/syndicate + name = "illegal robot module" + languages = list( + LANGUAGE_SOL_COMMON = 1, + LANGUAGE_TRADEBAND = 1, + LANGUAGE_UNATHI = 0, + LANGUAGE_SIIK = 0, + LANGUAGE_AKHANI = 0, + LANGUAGE_SKRELLIAN = 0, + LANGUAGE_SKRELLIANFAR = 0, + LANGUAGE_ROOTLOCAL = 0, + LANGUAGE_GUTTER = 1, + LANGUAGE_SCHECHI = 0, + LANGUAGE_EAL = 1, + LANGUAGE_SIGN = 0, + LANGUAGE_TERMINUS = 1, + LANGUAGE_ZADDAT = 0 + ) diff --git a/code/modules/mob/living/silicon/robot/modules/cybersun/sapper.dm b/code/modules/mob/living/silicon/robot/modules/cybersun/sapper.dm new file mode 100644 index 00000000000..c213269102f --- /dev/null +++ b/code/modules/mob/living/silicon/robot/modules/cybersun/sapper.dm @@ -0,0 +1,51 @@ +GENERATE_ROBOT_MODULE_PRESET(/cybersun/sapper) +/datum/prototype/robot_module/cybersun/sapper + id = "cybersun-sapper" + display_name = "CS-ENG" + visible_name = "Sapper" + use_robot_module_path = /obj/item/robot_module_legacy/robot/ + light_color = "#FF0000" + auto_iconsets = list( + /datum/prototype/robot_iconset/grounded_landmate/engineering_cybersun, + /datum/prototype/robot_iconset/grounded_spider/combat, + /datum/prototype/robot_iconset/raptor/syndicate_machinist, + ) + +/datum/prototype/robot_module/cybersun/sapper/provision_resource_store(datum/robot_resource_store/store) + ..() + store.provisioned_material_store[/datum/prototype/material/steel::id] = new /datum/robot_resource/provisioned/preset/material/steel + store.provisioned_material_store[/datum/prototype/material/glass::id] = new /datum/robot_resource/provisioned/preset/material/glass + store.provisioned_material_store[/datum/prototype/material/plasteel::id] = new /datum/robot_resource/provisioned/preset/material/plasteel + store.provisioned_material_store[/datum/prototype/material/wood_plank::id] = new /datum/robot_resource/provisioned/preset/material/wood + store.provisioned_material_store[/datum/prototype/material/plastic::id] = new /datum/robot_resource/provisioned/preset/material/plastic + store.provisioned_stack_store[/obj/item/stack/cable_coil] = new /datum/robot_resource/provisioned/preset/wire + +/datum/prototype/robot_module/cybersun/sapper/create_mounted_item_descriptors(list/normal_out, list/emag_out) + ..() + if(normal_out) + // todo: better way to do 'sum types'? + normal_out |= list( + /obj/item/stack/rods, + /obj/item/stack/tile/floor, + /obj/item/stack/tile/roofing, + /obj/item/stack/material/glass/reinforced, + + /obj/item/borg/sight/meson, + /obj/item/weldingtool/electric/mounted/cyborg, + /obj/item/tool/screwdriver/cyborg, + /obj/item/tool/wrench/cyborg, + /obj/item/tool/wirecutters/cyborg, + /obj/item/multitool/ai_detector, + /obj/item/pickaxe/plasmacutter, + /obj/item/rcd/electric/mounted/borg/lesser, // Can't eat rwalls to prevent AI core cheese. + /obj/item/melee/transforming/energy/sword/ionic_rapier, + + // FBP repair. + /obj/item/robotanalyzer, + /obj/item/shockpaddles/robot, + /obj/item/gripper/no_use/organ/robotics, + + // Hacking other things. + /obj/item/card/robot/syndi, + /obj/item/card/emag, + ) diff --git a/code/modules/mob/living/silicon/robot/modules/cybersun/triage.dm b/code/modules/mob/living/silicon/robot/modules/cybersun/triage.dm new file mode 100644 index 00000000000..f055c3bfae4 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/modules/cybersun/triage.dm @@ -0,0 +1,49 @@ +GENERATE_ROBOT_MODULE_PRESET(/cybersun/triage) +/datum/prototype/robot_module/cybersun/triage + id = "cybersun-triage" + display_name = "CS-MED" + visible_name = "Triage" + use_robot_module_path = /obj/item/robot_module_legacy/robot/ + light_color = "#FF0000" + auto_iconsets = list( + /datum/prototype/robot_iconset/baseline_toiletbot/syndicate, + /datum/prototype/robot_iconset/raptor/syndicate_medical, + ) + +/datum/prototype/robot_module/cybersun/triage/provision_resource_store(datum/robot_resource_store/store) + ..() + store.provisioned_stack_store[/obj/item/stack/medical/advanced/bruise_pack] = new /datum/robot_resource/provisioned/preset/bandages/advanced + store.provisioned_stack_store[/obj/item/stack/medical/advanced/ointment] = new /datum/robot_resource/provisioned/preset/ointment/advanced + store.provisioned_stack_store[/obj/item/stack/nanopaste] = new /datum/robot_resource/provisioned/preset/nanopaste + store.provisioned_stack_store[/obj/item/stack/medical/splint] = new /datum/robot_resource/provisioned/preset/splints + +/datum/prototype/robot_module/cybersun/triage/create_mounted_item_descriptors(list/normal_out, list/emag_out) + ..() + if(normal_out) + normal_out |= list( + /obj/item/borg/sight/hud/med, + /obj/item/healthanalyzer/advanced, + /obj/item/reagent_containers/borghypo/merc, + /obj/item/reagent_containers/glass/beaker/large, + + // Surgery things. + /obj/item/autopsy_scanner, + /obj/item/surgical/scalpel/cyborg, + /obj/item/surgical/hemostat/cyborg, + /obj/item/surgical/retractor/cyborg, + /obj/item/surgical/cautery/cyborg, + /obj/item/surgical/bonegel/cyborg, + /obj/item/surgical/FixOVein/cyborg, + /obj/item/surgical/bonesetter/cyborg, + /obj/item/surgical/circular_saw/cyborg, + /obj/item/surgical/surgicaldrill/cyborg, + /obj/item/gripper/no_use/organ, + + // General healing. + /obj/item/gripper/medical, + /obj/item/shockpaddles/robot/combat, + /obj/item/reagent_containers/dropper, // Allows borg to fix necrosis apparently + /obj/item/reagent_containers/syringe/unbreakable, + /obj/item/robot_builtin/dog_mirrortool, + /obj/item/roller_holder, + ) diff --git a/code/modules/mob/living/silicon/robot/modules/drone.dm b/code/modules/mob/living/silicon/robot/modules/drone.dm new file mode 100644 index 00000000000..e36f29f9a45 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/modules/drone.dm @@ -0,0 +1,98 @@ +/datum/prototype/robot_module/drone + id = "drone" + display_name = "NT Drone" + module_hud_state = "platform" + use_robot_module_path = /obj/item/robot_module_legacy/drone + auto_iconsets = list( + /datum/prototype/robot_iconset/baseline_drone/construction, + ) + +/datum/prototype/robot_module/drone/provision_resource_store(datum/robot_resource_store/store) + ..() + store.provisioned_material_store[/datum/prototype/material/steel::id] = new /datum/robot_resource/provisioned/preset/material/steel + store.provisioned_material_store[/datum/prototype/material/glass::id] = new /datum/robot_resource/provisioned/preset/material/glass + store.provisioned_material_store[/datum/prototype/material/plasteel::id] = new /datum/robot_resource/provisioned/preset/material/plasteel + store.provisioned_material_store[/datum/prototype/material/wood_plank::id] = new /datum/robot_resource/provisioned/preset/material/wood + store.provisioned_material_store[/datum/prototype/material/plastic::id] = new /datum/robot_resource/provisioned/preset/material/plastic + store.provisioned_stack_store[/obj/item/stack/cable_coil] = new /datum/robot_resource/provisioned/preset/wire + +/datum/prototype/robot_module/drone/create_mounted_item_descriptors(list/normal_out, list/emag_out) + ..() + if(normal_out) + // todo: better way to do 'sum types'? + normal_out |= list( + /obj/item/stack/rods, + /obj/item/stack/tile/wood, + /obj/item/stack/tile/floor, + /obj/item/stack/tile/roofing, + /obj/item/stack/material/glass/reinforced, + /obj/item/borg/sight/meson, + /obj/item/weldingtool/electric/mounted/cyborg, + /obj/item/tool/screwdriver/cyborg, + /obj/item/tool/wrench/cyborg, + /obj/item/tool/crowbar/cyborg, + /obj/item/tool/wirecutters/cyborg, + /obj/item/multitool, + /obj/item/lightreplacer, + /obj/item/gripper, + /obj/item/mop, + /obj/item/gripper/no_use/loader, + /obj/item/extinguisher, + /obj/item/pipe_painter, + /obj/item/floor_painter, + /obj/item/t_scanner, + /obj/item/atmos_analyzer, + /obj/item/inflatable_dispenser/robot, + /obj/item/barrier_tape_roll/engineering, + /obj/item/pipe_dispenser, + /obj/item/tank/jetpack/carbondioxide, + ) + if(emag_out) + emag_out |= list( + /obj/item/pickaxe/plasmacutter, + ) + +GENERATE_ROBOT_MODULE_PRESET(/drone/construction) +/datum/prototype/robot_module/drone/construction + id = "drone-construction" + display_name = "NT Construction Drone" + auto_iconsets = list( + /datum/prototype/robot_iconset/baseline_drone/construction, + ) + +/datum/prototype/robot_module/drone/construction/create_mounted_item_descriptors(list/normal_out, list/emag_out) + ..() + if(normal_out) + normal_out |= list( + /obj/item/rcd/electric/mounted/borg/lesser, + ) + +GENERATE_ROBOT_MODULE_PRESET(/drone/mining) +/datum/prototype/robot_module/drone/mining + id = "drone-mining" + display_name = "NT Mining Drone" + auto_iconsets = list( + /datum/prototype/robot_iconset/baseline_drone/mining, + ) + +/datum/prototype/robot_module/drone/mining/create_mounted_item_descriptors(list/normal_out, list/emag_out) + ..() + if(normal_out) + normal_out |= list( + /obj/item/borg/sight/material, + /obj/item/pickaxe/borgdrill, + /obj/item/gun/projectile/energy/kinetic_accelerator/cyborg, + /obj/item/storage/bag/ore, + /obj/item/storage/bag/sheetsnatcher/borg, + ) + if(emag_out) + emag_out |= list( + /obj/item/pickaxe/diamonddrill, + ) + +// todo: legacy crap +/obj/item/robot_module_legacy/drone + channels = list("Engineering" = 1, "Supply" = 1) + networks = list(NETWORK_ENGINEERING, NETWORK_MINE) + +/obj/item/robot_module_legacy/drone/construction/matriarch diff --git a/code/modules/mob/living/silicon/robot/modules/gravekeeper.dm b/code/modules/mob/living/silicon/robot/modules/gravekeeper.dm new file mode 100644 index 00000000000..e3be12b9626 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/modules/gravekeeper.dm @@ -0,0 +1,44 @@ +GENERATE_ROBOT_MODULE_PRESET(/gravekeeper) +/datum/prototype/robot_module/gravekeeper + id = "gravekeeper" + use_robot_module_path = /obj/item/robot_module_legacy/robot/ + light_color = "#AAAA00" + module_hud_state = "recon" + auto_iconsets = list( + /datum/prototype/robot_iconset/biped_sleek/gravekeeper, + /datum/prototype/robot_iconset/hover_drone/gravekeeper, + /datum/prototype/robot_iconset/raptor/gravekeeper, + ) + +/datum/prototype/robot_module/gravekeeper/provision_resource_store(datum/robot_resource_store/store) + ..() + store.provisioned_material_store[/datum/prototype/material/wood_plank::id] = new /datum/robot_resource/provisioned/preset/material/wood + +/datum/prototype/robot_module/gravekeeper/create_mounted_item_descriptors(list/normal_out, list/emag_out) + ..() + if(normal_out) + normal_out |= list( + // For fending off animals and looters + /obj/item/melee/baton/shocker/robot, + /obj/item/borg/combat/shield, + + // For repairing gravemarkers + /obj/item/weldingtool/electric/mounted, + /obj/item/tool/screwdriver/cyborg, + /obj/item/tool/wrench/cyborg, + + // For growing flowers + /obj/item/material/minihoe, + /obj/item/material/knife/machete/hatchet, + /obj/item/plant_analyzer, + /obj/item/storage/bag/plants, + /obj/item/robot_harvester, + + // For digging and beautifying graves + /obj/item/shovel, + /obj/item/gripper/gravekeeper, + ) + if(emag_out) + emag_out |= list( + /obj/item/gun/projectile/energy/retro/mounted, + ) diff --git a/code/modules/mob/living/silicon/robot/modules/lost.dm b/code/modules/mob/living/silicon/robot/modules/lost.dm new file mode 100644 index 00000000000..047f76807d2 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/modules/lost.dm @@ -0,0 +1,54 @@ +GENERATE_ROBOT_MODULE_PRESET(/lost) +/datum/prototype/robot_module/lost + id = "lost" + display_name = "???" + light_color = "#AAAA00" + module_hud_state = "recon" + auto_iconsets = list( + /datum/prototype/robot_iconset/hover_drone/lost, + /datum/prototype/robot_iconset/dog_vale/stray, + /datum/prototype/robot_iconset/raptor/lost, + ) + +/datum/prototype/robot_module/lost/provision_resource_store(datum/robot_resource_store/store) + ..() + store.provisioned_stack_store[/obj/item/stack/cable_coil] = new /datum/robot_resource/provisioned/preset/wire + +/datum/prototype/robot_module/lost/create_mounted_item_descriptors(list/normal_out, list/emag_out) + ..() + if(normal_out) + normal_out |= list( + // Sec + /obj/item/melee/baton/shocker/robot, + /obj/item/handcuffs/cyborg, + /obj/item/borg/combat/shield, + + // Med + /obj/item/healthanalyzer, + /obj/item/reagent_containers/borghypo/lost, + /obj/item/shockpaddles/robot/hound, + /obj/item/robot_builtin/dog_mirrortool, + + // Engi + /obj/item/weldingtool/electric/mounted, + /obj/item/switchtool, + /obj/item/multitool, + + // logistics + /obj/item/pickaxe/borgdrill, + /obj/item/storage/bag/ore, + + // Sci + /obj/item/robotanalyzer, + + // service + /obj/item/soap/nanotrasen, + + // haha fuck you it's the hour of the standard borg, yeehaw + /obj/item/gripper/omni/no_attack, + /obj/item/gripper/omni/no_attack, + ) + if(emag_out) + emag_out |= list( + /obj/item/gun/projectile/energy/retro/mounted, + ) diff --git a/code/modules/mob/living/silicon/robot/modules/nanotrasen.dm b/code/modules/mob/living/silicon/robot/modules/nanotrasen.dm new file mode 100644 index 00000000000..2b7d39b682a --- /dev/null +++ b/code/modules/mob/living/silicon/robot/modules/nanotrasen.dm @@ -0,0 +1,8 @@ +/datum/prototype/robot_module/nanotrasen + abstract_type = /datum/prototype/robot_module/nanotrasen + selectable = TRUE + legacy_show_on_manifest = TRUE + module_hud_state = "standard" + selection_groups_all = list( + ROBOT_MODULE_SELECTION_GROUP_NANOTRASEN, + ) diff --git a/code/modules/mob/living/silicon/robot/modules/nanotrasen/combat.dm b/code/modules/mob/living/silicon/robot/modules/nanotrasen/combat.dm new file mode 100644 index 00000000000..dffb984bcf2 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/modules/nanotrasen/combat.dm @@ -0,0 +1,35 @@ +GENERATE_ROBOT_MODULE_PRESET(/nanotrasen/combat) +/datum/prototype/robot_module/nanotrasen/combat + id = "nt-combat" + display_name = "NT-LANCER" + visible_name = "Combat" + use_robot_module_path = /obj/item/robot_module_legacy/robot/security + module_hud_state = "combat" + light_color = "#FF0000" + auto_iconsets = list( + /datum/prototype/robot_iconset/baseline_droid/combat, + /datum/prototype/robot_iconset/hover_eyebot/combat, + /datum/prototype/robot_iconset/biped_insekt/combat, + /datum/prototype/robot_iconset/grounded_zoomba/combat, + /datum/prototype/robot_iconset/cat_feli/combat, + /datum/prototype/robot_iconset/biped_marina/combat, + /datum/prototype/robot_iconset/grounded_mechoid/combat, + /datum/prototype/robot_iconset/dog_k9/blade, + ) + +/datum/prototype/robot_module/nanotrasen/combat/create_mounted_item_descriptors(list/normal_out, list/emag_out) + if(normal_out) + normal_out |= list( + /obj/item/gun/projectile/energy/laser/mounted, + /obj/item/pickaxe/plasmacutter, + /obj/item/borg/combat/shield, + /obj/item/borg/combat/mobility, + /obj/item/handcuffs/cyborg, + /obj/item/melee/baton/robot, + /obj/item/barrier_tape_roll/police, + ) + if(emag_out) + emag_out |= list( + /obj/item/gun/projectile/energy/lasercannon/mounted, + ) + return ..() diff --git a/code/modules/mob/living/silicon/robot/modules/nanotrasen/engineering.dm b/code/modules/mob/living/silicon/robot/modules/nanotrasen/engineering.dm new file mode 100644 index 00000000000..ef2845e4015 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/modules/nanotrasen/engineering.dm @@ -0,0 +1,98 @@ +GENERATE_ROBOT_MODULE_PRESET(/nanotrasen/engineering) +/datum/prototype/robot_module/nanotrasen/engineering + id = "nt-engineering" + display_name = "NT-ENG" + visible_name = "Engineering" + use_robot_module_path = /obj/item/robot_module_legacy/robot/engineering + module_hud_state = "engineering" + light_color = "#FDD800" + auto_iconsets = list( + /datum/prototype/robot_iconset/grounded_landmate/engineering, + /datum/prototype/robot_iconset/grounded_landmate/engineering_tread, + /datum/prototype/robot_iconset/grounded_landmate/treadwell, + /datum/prototype/robot_iconset/dog_borgi/engineering, + /datum/prototype/robot_iconset/dog_k9/engineering, + /datum/prototype/robot_iconset/dog_k9/engineering_dark, + /datum/prototype/robot_iconset/dog_otie/engineering, + /datum/prototype/robot_iconset/dog_pupdozer/engineering, + /datum/prototype/robot_iconset/dog_vale/engineering, + /datum/prototype/robot_iconset/cat_feli/engineering, + /datum/prototype/robot_iconset/drake_mizartz/engineering, + /datum/prototype/robot_iconset/hover_eyebot/engineering, + /datum/prototype/robot_iconset/baseline_toiletbot/engineering, + /datum/prototype/robot_iconset/biped_marina/engineering, + /datum/prototype/robot_iconset/biped_sleek/engineering, + /datum/prototype/robot_iconset/grounded_spider/engineering, + /datum/prototype/robot_iconset/biped_heavy/engineering, + /datum/prototype/robot_iconset/hover_drone/engineering, + /datum/prototype/robot_iconset/hover_handy/engineering, + /datum/prototype/robot_iconset/hover_glitterfly/engineering, + /datum/prototype/robot_iconset/hover_coffin/engineering, + /datum/prototype/robot_iconset/hover_coffin/construction, + /datum/prototype/robot_iconset/biped_miss/engineering, + /datum/prototype/robot_iconset/biped_tall/alternative/engineer, + /datum/prototype/robot_iconset/biped_marina/engineering, + /datum/prototype/robot_iconset/grounded_zoomba/engineering, + /datum/prototype/robot_iconset/hover_x88/engineering, + /datum/prototype/robot_iconset/biped_noble/engineering, + /datum/prototype/robot_iconset/grounded_mechoid/engineering, + /datum/prototype/robot_iconset/grounded_worm/engineering, + /datum/prototype/robot_iconset/baseline_standard/engineering, + /datum/prototype/robot_iconset/baseline_old/hazardvest, + /datum/prototype/robot_iconset/raptor/engineering, + /datum/prototype/robot_iconset/baseline_old/engineer, + ) + +/datum/prototype/robot_module/nanotrasen/engineering/provision_resource_store(datum/robot_resource_store/store) + ..() + store.provisioned_material_store[/datum/prototype/material/steel::id] = new /datum/robot_resource/provisioned/preset/material/steel + store.provisioned_material_store[/datum/prototype/material/glass::id] = new /datum/robot_resource/provisioned/preset/material/glass + store.provisioned_material_store[/datum/prototype/material/plasteel::id] = new /datum/robot_resource/provisioned/preset/material/plasteel + store.provisioned_material_store[/datum/prototype/material/wood_plank::id] = new /datum/robot_resource/provisioned/preset/material/wood + store.provisioned_material_store[/datum/prototype/material/plastic::id] = new /datum/robot_resource/provisioned/preset/material/plastic + store.provisioned_stack_store[/obj/item/stack/cable_coil] = new /datum/robot_resource/provisioned/preset/wire + +/datum/prototype/robot_module/nanotrasen/engineering/create_mounted_item_descriptors(list/normal_out, list/emag_out) + ..() + if(normal_out) + // todo: better way to do 'sum types'? + normal_out |= list( + /obj/item/stack/rods, + /obj/item/stack/tile/wood, + /obj/item/stack/tile/floor, + /obj/item/stack/tile/roofing, + /obj/item/stack/material/glass/reinforced, + ) + normal_out |= list( + /obj/item/matter_decompiler, + /obj/item/borg/sight/meson, + /obj/item/weldingtool/electric/mounted/cyborg, + /obj/item/tool/screwdriver/cyborg, + /obj/item/tool/wrench/cyborg, + /obj/item/tool/wirecutters/cyborg, + /obj/item/multitool, + /obj/item/t_scanner, + /obj/item/rcd/electric/mounted/borg, + /obj/item/atmos_analyzer, + /obj/item/barrier_tape_roll/engineering, + /obj/item/inflatable_dispenser/robot, + /obj/item/pickaxe/plasmacutter, + /obj/item/geiger_counter/cyborg, + /obj/item/pipe_painter, + /obj/item/floor_painter, + /obj/item/gripper, + /obj/item/gripper/no_use/loader, + /obj/item/pipe_dispenser, + /obj/item/gripper/circuit, + /obj/item/lightreplacer, + ) + if(emag_out) + emag_out |= list( + /obj/item/melee/baton/robot/arm, + ) + +// todo: legacy +/obj/item/robot_module_legacy/robot/engineering + channels = list("Engineering" = 1) + networks = list(NETWORK_ENGINEERING) + subsystems = list(/mob/living/silicon/proc/subsystem_power_monitor) diff --git a/code/modules/mob/living/silicon/robot/modules/nanotrasen/janitor.dm b/code/modules/mob/living/silicon/robot/modules/nanotrasen/janitor.dm new file mode 100644 index 00000000000..68e407f4e2c --- /dev/null +++ b/code/modules/mob/living/silicon/robot/modules/nanotrasen/janitor.dm @@ -0,0 +1,76 @@ +GENERATE_ROBOT_MODULE_PRESET(/nanotrasen/janitor) +/datum/prototype/robot_module/nanotrasen/janitor + id = "nt-janitor" + display_name = "NT-CLN" + visible_name = "Janitorial" + use_robot_module_path = /obj/item/robot_module_legacy/robot/janitor + module_hud_state = "janitor" + light_color = "#CC60FF" + auto_iconsets = list( + /datum/prototype/robot_iconset/grounded_landmate/janitor, + /datum/prototype/robot_iconset/baseline_toiletbot/janitor, + /datum/prototype/robot_iconset/hover_eyebot/janitor, + /datum/prototype/robot_iconset/biped_marina/janitor, + /datum/prototype/robot_iconset/biped_sleek/janitor, + /datum/prototype/robot_iconset/biped_tall/alternative/janitor, + /datum/prototype/robot_iconset/hover_drone/janitor, + /datum/prototype/robot_iconset/hover_glitterfly/janitor, + /datum/prototype/robot_iconset/biped_miss/janitor, + /datum/prototype/robot_iconset/hover_handy/janitor, + /datum/prototype/robot_iconset/grounded_mechoid/janitor, + /datum/prototype/robot_iconset/grounded_zoomba/janitor, + /datum/prototype/robot_iconset/biped_noble/janitor, + /datum/prototype/robot_iconset/grounded_worm/janitor, + /datum/prototype/robot_iconset/dog_borgi/janitor, + /datum/prototype/robot_iconset/dog_k9/janitor, + /datum/prototype/robot_iconset/dog_otie/janitor, + /datum/prototype/robot_iconset/dog_vale/janitor, + /datum/prototype/robot_iconset/drake_mizartz/janitor, + /datum/prototype/robot_iconset/cat_feli/janitor, + /datum/prototype/robot_iconset/raptor, + /datum/prototype/robot_iconset/baseline_standard/janitor, + /datum/prototype/robot_iconset/baseline_old/janitor, + /datum/prototype/robot_iconset/baseline_old/janitor_2, + /datum/prototype/robot_iconset/hover_coffin/custodial, + /datum/prototype/robot_iconset/baseline_misc/arachne, + ) + +/datum/prototype/robot_module/nanotrasen/janitor/create_mounted_item_descriptors(list/normal_out, list/emag_out) + ..() + if(normal_out) + normal_out |= list( + /obj/item/soap/nanotrasen, + /obj/item/storage/bag/trash, + /obj/item/mop/advanced, + /obj/item/lightreplacer, + /obj/item/gripper/service, + ) + if(emag_out) + var/obj/item/reagent_containers/spray/lube_spray = new + lube_spray.reagents.add_reagent(/datum/reagent/lube, 250) + lube_spray.name = "lube spray" + emag_out |= lube_spray + +/datum/prototype/robot_module/nanotrasen/janitor/provision_resource_store(datum/robot_resource_store/store) + ..() + store.provisioned_material_store[/datum/prototype/material/glass::id] = new /datum/robot_resource/provisioned/preset/material/glass{regen_per_second = 1 * SHEET_MATERIAL_AMOUNT} + +/datum/prototype/robot_module/nanotrasen/janitor/on_install(mob/living/silicon/robot/robot) + ..() + robot.legacy_floor_scrubbing = TRUE + +/datum/prototype/robot_module/nanotrasen/janitor/on_uninstall(mob/living/silicon/robot/robot) + ..() + robot.legacy_floor_scrubbing = FALSE + +// todo: this is evil +/datum/prototype/robot_module/nanotrasen/janitor/legacy_custom_regenerate_resources(mob/living/silicon/robot/robot, dt, multiplier) + ..() + for(var/obj/item/reagent_containers/spray/maybe_evil_lube_spray in robot.robot_inventory.provided_items) + if(maybe_evil_lube_spray.name != "lube spray") + continue + maybe_evil_lube_spray.reagents?.add_reagent(/datum/reagent/lube::id, 2 * dt) + +// todo: legacy +/obj/item/robot_module_legacy/robot/janitor + channels = list("Service" = 1) diff --git a/code/modules/mob/living/silicon/robot/modules/nanotrasen/logistics.dm b/code/modules/mob/living/silicon/robot/modules/nanotrasen/logistics.dm new file mode 100644 index 00000000000..2c95bce2f32 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/modules/nanotrasen/logistics.dm @@ -0,0 +1,55 @@ +GENERATE_ROBOT_MODULE_PRESET(/nanotrasen/logistics) +/datum/prototype/robot_module/nanotrasen/logistics + id = "nt-logistics" + display_name = "NT-LGN" + display_name = "Logistics" + use_robot_module_path = /obj/item/robot_module_legacy/robot/logistics + module_hud_state = "mining" + light_color = "#FBE281" + auto_iconsets = list( + /datum/prototype/robot_iconset/grounded_landmate/mining, + /datum/prototype/robot_iconset/dog_k9/logistics, + /datum/prototype/robot_iconset/dog_k9/logistics_dark, + /datum/prototype/robot_iconset/dog_vale/mining, + /datum/prototype/robot_iconset/drake_mizartz/mining, + /datum/prototype/robot_iconset/cat_feli/mining, + /datum/prototype/robot_iconset/hover_eyebot/mining, + /datum/prototype/robot_iconset/biped_marina/miner, + /datum/prototype/robot_iconset/biped_heavy/miner, + /datum/prototype/robot_iconset/grounded_spider/mining, + /datum/prototype/robot_iconset/baseline_toiletbot/logistics, + /datum/prototype/robot_iconset/biped_sleek/mining, + /datum/prototype/robot_iconset/hover_drone/mining, + /datum/prototype/robot_iconset/hover_glitterfly/mining, + /datum/prototype/robot_iconset/biped_miss/mining, + /datum/prototype/robot_iconset/hover_handy/mining, + /datum/prototype/robot_iconset/grounded_mechoid/miner, + /datum/prototype/robot_iconset/biped_tall/alternative/miner, + /datum/prototype/robot_iconset/biped_noble/mining, + /datum/prototype/robot_iconset/grounded_zoomba/miner, + /datum/prototype/robot_iconset/grounded_worm/miner, + /datum/prototype/robot_iconset/raptor/mining, + /datum/prototype/robot_iconset/baseline_standard/logistics, + /datum/prototype/robot_iconset/hover_coffin/mining, + ) + +/datum/prototype/robot_module/nanotrasen/logistics/create_mounted_item_descriptors(list/normal_out, list/emag_out) + if(normal_out) + normal_out |= list( + /obj/item/borg/sight/meson, + /obj/item/switchtool, + /obj/item/weldingtool/electric/mounted, + /obj/item/storage/bag/ore, + /obj/item/pickaxe/borgdrill, + /obj/item/gun/projectile/energy/kinetic_accelerator/cyborg, + /obj/item/storage/bag/sheetsnatcher/borg, + /obj/item/gripper/miner, + /obj/item/mining_scanner, + /obj/item/pickaxe/plasmacutter, + ) + return ..() + +// todo: legacy +/obj/item/robot_module_legacy/robot/logistics + channels = list("Supply" = 1) + networks = list(NETWORK_MINE) diff --git a/code/modules/mob/living/silicon/robot/modules/nanotrasen/medical.dm b/code/modules/mob/living/silicon/robot/modules/nanotrasen/medical.dm new file mode 100644 index 00000000000..bae95923615 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/modules/nanotrasen/medical.dm @@ -0,0 +1,98 @@ +GENERATE_ROBOT_MODULE_PRESET(/nanotrasen/medical) +/datum/prototype/robot_module/nanotrasen/medical + id = "nt-medical" + display_name = "NT-MED" + visible_name = "Medical" + use_robot_module_path = /obj/item/robot_module_legacy/robot/medical + module_hud_state = "medical" + light_color = "#0099FF" + auto_iconsets = list( + /datum/prototype/robot_iconset/baseline_toiletbot/medical, + /datum/prototype/robot_iconset/dog_borgi/medical, + /datum/prototype/robot_iconset/dog_k9/medical, + /datum/prototype/robot_iconset/dog_k9/medical_dark, + /datum/prototype/robot_iconset/dog_vale/medical, + /datum/prototype/robot_iconset/drake_mizartz/medical, + /datum/prototype/robot_iconset/cat_feli/medical, + /datum/prototype/robot_iconset/baseline_standard/medical, + /datum/prototype/robot_iconset/hover_eyebot/medical, + /datum/prototype/robot_iconset/biped_marina/medical, + /datum/prototype/robot_iconset/biped_tall/tallwhite, + /datum/prototype/robot_iconset/biped_tall/alternative/medical, + /datum/prototype/robot_iconset/biped_sleek/cmo, + /datum/prototype/robot_iconset/biped_sleek/medical, + /datum/prototype/robot_iconset/biped_heavy/medical, + /datum/prototype/robot_iconset/baseline_old/medical, + /datum/prototype/robot_iconset/biped_droid/medical, + /datum/prototype/robot_iconset/hover_drone/medical, + /datum/prototype/robot_iconset/hover_handy/medical, + /datum/prototype/robot_iconset/hover_drone/surgery, + /datum/prototype/robot_iconset/biped_insekt/medical, + /datum/prototype/robot_iconset/hover_glitterfly/surgeon, + /datum/prototype/robot_iconset/biped_miss/medical, + /datum/prototype/robot_iconset/hover_x88/medical, + /datum/prototype/robot_iconset/grounded_mechoid/medical, + /datum/prototype/robot_iconset/biped_noble/medical, + /datum/prototype/robot_iconset/grounded_zoomba/medical, + /datum/prototype/robot_iconset/grounded_worm/crisis, + /datum/prototype/robot_iconset/raptor/medical, + /datum/prototype/robot_iconset/hover_coffin/medical, + /datum/prototype/robot_iconset/baseline_old/medical_2, + ) + +/datum/prototype/robot_module/nanotrasen/medical/create_mounted_item_descriptors(list/normal_out, list/emag_out) + ..() + if(normal_out) + normal_out |= list( + /obj/item/borg/sight/hud/med, + /obj/item/healthanalyzer/advanced, + /obj/item/reagent_containers/borghypo/surgeon, + /obj/item/reagent_containers/glass/beaker/large, + /obj/item/reagent_scanner/adv, + + // Surgery things. + /obj/item/autopsy_scanner, + /obj/item/surgical/scalpel/cyborg, + /obj/item/surgical/hemostat/cyborg, + /obj/item/surgical/retractor/cyborg, + /obj/item/surgical/cautery/cyborg, + /obj/item/surgical/bonegel/cyborg, + /obj/item/surgical/FixOVein/cyborg, + /obj/item/surgical/bonesetter/cyborg, + /obj/item/surgical/circular_saw/cyborg, + /obj/item/surgical/surgicaldrill/cyborg, + /obj/item/gripper/no_use/organ, + + /obj/item/gripper/medical, + /obj/item/shockpaddles/robot, + /obj/item/reagent_containers/dropper, // Allows surgeon borg to fix necrosis + /obj/item/reagent_containers/syringe/unbreakable, + /obj/item/roller_holder, + /obj/item/robot_builtin/dog_mirrortool, + ) + if(emag_out) + var/obj/item/reagent_containers/spray/acid_spray = new + acid_spray.reagents.add_reagent(/datum/reagent/acid/polyacid::id, 250) + acid_spray.name = "Polyacid spray" + emag_out |= acid_spray + +/datum/prototype/robot_module/nanotrasen/medical/provision_resource_store(datum/robot_resource_store/store) + ..() + store.provisioned_stack_store[/obj/item/stack/medical/advanced/bruise_pack] = new /datum/robot_resource/provisioned/preset/bandages/advanced + store.provisioned_stack_store[/obj/item/stack/medical/advanced/ointment] = new /datum/robot_resource/provisioned/preset/ointment/advanced + store.provisioned_stack_store[/obj/item/stack/medical/splint] = new /datum/robot_resource/provisioned/preset/splints + store.provisioned_stack_store[/obj/item/stack/nanopaste] = new /datum/robot_resource/provisioned/preset/nanopaste + +// todo: this is evil +/datum/prototype/robot_module/nanotrasen/medical/legacy_custom_regenerate_resources(mob/living/silicon/robot/robot, dt, multiplier) + ..() + for(var/obj/item/reagent_containers/spray/maybe_evil_acid_spray in robot.robot_inventory.provided_items) + if(maybe_evil_acid_spray.name != "Polyacid spray") + continue + maybe_evil_acid_spray.reagents?.add_reagent(/datum/reagent/acid/polyacid::id, 2 * dt) + +// todo: legacy +/obj/item/robot_module_legacy/robot/medical + channels = list("Medical" = 1) + networks = list(NETWORK_MEDICAL) + subsystems = list(/mob/living/silicon/proc/subsystem_crew_monitor) diff --git a/code/modules/mob/living/silicon/robot/modules/nanotrasen/multirole.dm b/code/modules/mob/living/silicon/robot/modules/nanotrasen/multirole.dm new file mode 100644 index 00000000000..405ba086349 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/modules/nanotrasen/multirole.dm @@ -0,0 +1,99 @@ +GENERATE_ROBOT_MODULE_PRESET(/nanotrasen/multirole) +/datum/prototype/robot_module/nanotrasen/multirole + id = "nt-multirole" + display_name = "NT-STD" + visible_name = "Multirole" + use_robot_module_path = /obj/item/robot_module_legacy/robot + light_color = "#FFFFFF" + module_hud_state = "standard" + auto_iconsets = list( + /datum/prototype/robot_iconset/baseline_standard/standard, + /datum/prototype/robot_iconset/biped_k4t, + /datum/prototype/robot_iconset/baseline_old/standard, + /datum/prototype/robot_iconset/hover_eyebot/standard, + /datum/prototype/robot_iconset/biped_marina/standard, + /datum/prototype/robot_iconset/biped_tall/tallflower, + /datum/prototype/robot_iconset/baseline_toiletbot/standard, + /datum/prototype/robot_iconset/biped_sleek/standard, + /datum/prototype/robot_iconset/grounded_spider/standard, + /datum/prototype/robot_iconset/biped_heavy/standard, + /datum/prototype/robot_iconset/cat_feli/standard, + /datum/prototype/robot_iconset/baseline_misc/omoikane, + /datum/prototype/robot_iconset/hover_drone/standard, + /datum/prototype/robot_iconset/biped_insekt/standard, + /datum/prototype/robot_iconset/biped_tall/alternative/standard, + /datum/prototype/robot_iconset/hover_glitterfly/standard, + /datum/prototype/robot_iconset/biped_miss/standard, + /datum/prototype/robot_iconset/hover_x88/standard, + /datum/prototype/robot_iconset/hover_coffin/standard, + /datum/prototype/robot_iconset/hover_handy/standard, + /datum/prototype/robot_iconset/grounded_mechoid/standard, + /datum/prototype/robot_iconset/biped_noble/standard, + /datum/prototype/robot_iconset/grounded_zoomba/standard, + /datum/prototype/robot_iconset/grounded_worm/standard, + /datum/prototype/robot_iconset/raptor/peacekeeper, + /datum/prototype/robot_iconset/baseline_droid/standard, + /datum/prototype/robot_iconset/dog_borgi/standard, + /datum/prototype/robot_iconset/dog_vale/standard, + ) + +//! ~~~~~ "Holy crap, why is standard so OP" ~~~~~ !// +//! It isn't. The rest of the modules are shit. !// +//! I don't know why SS13 standardized to "mob that has scrubbing and trash bag only" !// +//! but we don't do that here. Infact, I'd buff standard more, but I'm out of !// +//! interesting items to give them because every coder here's busy coding guns. !// +//! !// +//! We should move to modular cyborgs ASAP, but until we do, the name of the game !// +//! is going to be making them not miserable to play. !// +//! If you're stuck listening to other players' orders, might as well have some fun. !// + +/datum/prototype/robot_module/nanotrasen/multirole/provision_resource_store(datum/robot_resource_store/store) + ..() + store.provisioned_material_store[/datum/prototype/material/steel::id] = new /datum/robot_resource/provisioned/preset/material/steel{ + amount_max = 20 * SHEET_MATERIAL_AMOUNT; + } + store.provisioned_material_store[/datum/prototype/material/plastic::id] = new /datum/robot_resource/provisioned/preset/material/plastic{ + amount_max = 10 * SHEET_MATERIAL_AMOUNT; + } + store.provisioned_material_store[/datum/prototype/material/glass::id] = new /datum/robot_resource/provisioned/preset/material/glass{ + amount_max = 20 * SHEET_MATERIAL_AMOUNT; + } + store.provisioned_stack_store[/obj/item/stack/medical/bruise_pack] = new /datum/robot_resource/provisioned/preset/bandages{ + amount_max = 30; + } + store.provisioned_stack_store[/obj/item/stack/medical/ointment] = new /datum/robot_resource/provisioned/preset/ointment{ + amount_max = 30; + } + store.provisioned_stack_store[/obj/item/stack/nanopaste] = new /datum/robot_resource/provisioned/preset/nanopaste{ + amount_max = 10; + } + +/datum/prototype/robot_module/nanotrasen/multirole/create_mounted_item_descriptors(list/normal_out, list/emag_out) + ..() + if(normal_out) + normal_out |= list( + // security + /obj/item/melee/baton/shocker, + // engineering + /obj/item/switchtool, + /obj/item/weldingtool/electric/mounted, + /obj/item/multitool, + // medical + /obj/item/healthanalyzer, + /obj/item/reagent_containers/dropper, + /obj/item/reagent_containers/borghypo/stabilizer, + // logistics + /obj/item/pickaxe/borgdrill, + /obj/item/storage/bag/ore, + // science + /obj/item/robotanalyzer, + // service + /obj/item/soap/nanotrasen, + // haha fuck you it's the hour of the standard borg, yeehaw + /obj/item/gripper/omni/no_attack, + ) + if(emag_out) + // LET'S FUCKIN GOOOOOOO + emag_out |= list( + /obj/item/gun/projectile/energy/ermitter, + ) diff --git a/code/modules/mob/living/silicon/robot/modules/nanotrasen/research.dm b/code/modules/mob/living/silicon/robot/modules/nanotrasen/research.dm new file mode 100644 index 00000000000..9bab68016ed --- /dev/null +++ b/code/modules/mob/living/silicon/robot/modules/nanotrasen/research.dm @@ -0,0 +1,82 @@ +GENERATE_ROBOT_MODULE_PRESET(/nanotrasen/research) +/datum/prototype/robot_module/nanotrasen/research + id = "nt-research" + display_name = "NT-SCI" + visible_name = "Research" + use_robot_module_path = /obj/item/robot_module_legacy/robot/research + module_hud_state = "science" + light_color = "#CC60FF" + auto_iconsets = list( + /datum/prototype/robot_iconset/hover_eyebot/science, + /datum/prototype/robot_iconset/dog_otie/science, + /datum/prototype/robot_iconset/biped_marina/service, + /datum/prototype/robot_iconset/grounded_spider/science, + /datum/prototype/robot_iconset/biped_sleek/science, + /datum/prototype/robot_iconset/biped_droid/science, + /datum/prototype/robot_iconset/hover_drone/science, + /datum/prototype/robot_iconset/hover_handy/science, + /datum/prototype/robot_iconset/biped_insekt/science, + /datum/prototype/robot_iconset/hover_glitterfly/science, + /datum/prototype/robot_iconset/hover_x88/science, + /datum/prototype/robot_iconset/grounded_mechoid/science, + /datum/prototype/robot_iconset/dog_borgi/science, + /datum/prototype/robot_iconset/dog_k9/science, + /datum/prototype/robot_iconset/dog_k9/science_dark, + /datum/prototype/robot_iconset/dog_vale/science, + /datum/prototype/robot_iconset/cat_feli/research, + /datum/prototype/robot_iconset/grounded_zoomba/research, + /datum/prototype/robot_iconset/hover_coffin/research, + // the science coder's pet robot module can live on inside science :) + /datum/prototype/robot_iconset/grounded_landmate/peacekeeper, + ) + +/datum/prototype/robot_module/nanotrasen/research/provision_resource_store(datum/robot_resource_store/store) + ..() + store.provisioned_stack_store[/obj/item/stack/cable_coil] = new /datum/robot_resource/provisioned/preset/wire + store.provisioned_stack_store[/obj/item/stack/nanopaste] = new /datum/robot_resource/provisioned/preset/nanopaste + +/datum/prototype/robot_module/nanotrasen/research/create_mounted_item_descriptors(list/normal_out, list/emag_out) + ..() + if(normal_out) + normal_out |= list( + /obj/item/portable_destructive_analyzer, + /obj/item/gripper/research, + /obj/item/gripper/circuit, + /obj/item/gripper/no_use/organ/robotics, + /obj/item/gripper/no_use/mech, + /obj/item/gripper/no_use/loader, + /obj/item/robotanalyzer, + /obj/item/card/robot, + /obj/item/weldingtool/electric/mounted/cyborg, + /obj/item/tool/screwdriver/cyborg, + /obj/item/tool/wrench/cyborg, + /obj/item/tool/wirecutters/cyborg, + /obj/item/multitool, + /obj/item/surgical/scalpel/cyborg, + /obj/item/surgical/circular_saw/cyborg, + /obj/item/reagent_containers/syringe, + /obj/item/reagent_containers/glass/beaker/large, + /obj/item/storage/part_replacer, + /obj/item/shockpaddles/robot, + /obj/item/melee/baton/slime/robot, + /obj/item/gun/projectile/energy/taser/xeno/robot, + ) + if(emag_out) + emag_out |= list( + /obj/item/borg/combat/shield, + ) + +// todo: this is evil +/datum/prototype/robot_module/nanotrasen/research/legacy_custom_regenerate_resources(mob/living/silicon/robot/robot, dt, multiplier) + ..() + for(var/obj/item/reagent_containers/syringe/syringe in robot.robot_inventory.provided_items) + // todo: refactor syringes + if(syringe.mode == 2) + syringe.reagents?.clear_reagents() + syringe.mode = initial(syringe.mode) + syringe.desc = initial(syringe.desc) + syringe.update_icon() + +// todo: legacy +/obj/item/robot_module_legacy/robot/research + channels = list("Science" = 1) diff --git a/code/modules/mob/living/silicon/robot/modules/nanotrasen/security.dm b/code/modules/mob/living/silicon/robot/modules/nanotrasen/security.dm new file mode 100644 index 00000000000..b86b43adb26 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/modules/nanotrasen/security.dm @@ -0,0 +1,75 @@ +GENERATE_ROBOT_MODULE_PRESET(/nanotrasen/security) +/datum/prototype/robot_module/nanotrasen/security + id = "nt-security" + display_name = "NT-SEC" + display_name = "Security" + use_robot_module_path = /obj/item/robot_module_legacy/robot/security + module_hud_state = "security" + light_color = "#FF0000" + auto_iconsets = list( + /datum/prototype/robot_iconset/grounded_landmate/security, + /datum/prototype/robot_iconset/baseline_standard/security, + /datum/prototype/robot_iconset/hover_eyebot/security, + /datum/prototype/robot_iconset/grounded_landmate/security_tread, + /datum/prototype/robot_iconset/biped_marina/security, + /datum/prototype/robot_iconset/biped_tall/tallred, + /datum/prototype/robot_iconset/baseline_toiletbot/security, + /datum/prototype/robot_iconset/biped_sleek/security, + /datum/prototype/robot_iconset/grounded_spider/security, + /datum/prototype/robot_iconset/biped_heavy/security, + /datum/prototype/robot_iconset/baseline_old/security, + /datum/prototype/robot_iconset/baseline_old/security_riot, + /datum/prototype/robot_iconset/hover_drone/security, + /datum/prototype/robot_iconset/biped_insekt/security, + /datum/prototype/robot_iconset/biped_tall/alternative/security, + /datum/prototype/robot_iconset/biped_miss/security, + /datum/prototype/robot_iconset/hover_glitterfly/security, + /datum/prototype/robot_iconset/grounded_mechoid/security, + /datum/prototype/robot_iconset/hover_handy/security, + /datum/prototype/robot_iconset/biped_noble/security, + /datum/prototype/robot_iconset/grounded_zoomba/security, + /datum/prototype/robot_iconset/grounded_worm/security, + /datum/prototype/robot_iconset/dog_borgi/security, + /datum/prototype/robot_iconset/dog_k9/security, + /datum/prototype/robot_iconset/dog_otie/security, + /datum/prototype/robot_iconset/dog_pupdozer/security, + /datum/prototype/robot_iconset/dog_vale/security, + /datum/prototype/robot_iconset/cat_feli/security, + /datum/prototype/robot_iconset/drake_mizartz/security, + /datum/prototype/robot_iconset/dog_k9/red, + /datum/prototype/robot_iconset/raptor/security, + /datum/prototype/robot_iconset/hover_coffin/combat, + ) + +/datum/prototype/robot_module/nanotrasen/security/create_mounted_item_descriptors(list/normal_out, list/emag_out) + ..() + if(normal_out) + normal_out |= list( + /obj/item/handcuffs/cyborg, + /obj/item/melee/baton/robot, + /obj/item/gun/projectile/energy/taser/mounted/cyborg, + /obj/item/barrier_tape_roll/police, + /obj/item/reagent_containers/spray/pepper, + /obj/item/gripper/security, + ) + if(emag_out) + emag_out |= list( + /obj/item/gun/projectile/energy/laser/mounted, + ) + +// todo: this is evil +/datum/prototype/robot_module/nanotrasen/security/legacy_custom_regenerate_resources(mob/living/silicon/robot/robot, dt, multiplier) + ..() + for(var/obj/item/flash/flash in robot.robot_inventory.provided_items) + // todo: refactor flash + flash.times_used = 0 + if(flash.broken) + flash.broken = 0 + flash.icon_state = "flash" + +// todo: legacy +/obj/item/robot_module_legacy/robot/security + channels = list("Security" = 1) + networks = list(NETWORK_SECURITY) + subsystems = list(/mob/living/silicon/proc/subsystem_crew_monitor) + diff --git a/code/modules/mob/living/silicon/robot/modules/nanotrasen/service.dm b/code/modules/mob/living/silicon/robot/modules/nanotrasen/service.dm new file mode 100644 index 00000000000..3f526301b7e --- /dev/null +++ b/code/modules/mob/living/silicon/robot/modules/nanotrasen/service.dm @@ -0,0 +1,111 @@ +GENERATE_ROBOT_MODULE_PRESET(/nanotrasen/service) +/datum/prototype/robot_module/nanotrasen/service + id = "nt-service" + display_name = "NT-SRV" + visible_name = "Service" + use_robot_module_path = /obj/item/robot_module_legacy/robot/clerical + module_hud_state = "service" + light_color = "#6AED63" + auto_iconsets = list( + /datum/prototype/robot_iconset/baseline_standard/service, + /datum/prototype/robot_iconset/baseline_standard/clerical, + /datum/prototype/robot_iconset/dog_k9/grey, + /datum/prototype/robot_iconset/dog_k9/pink, + /datum/prototype/robot_iconset/dog_vale/service, + /datum/prototype/robot_iconset/dog_vale/service_dark, + /datum/prototype/robot_iconset/cat_feli/service, + /datum/prototype/robot_iconset/drake_mizartz/peacekeeper, + /datum/prototype/robot_iconset/biped_marina/service, + /datum/prototype/robot_iconset/biped_maid, + /datum/prototype/robot_iconset/biped_tall/tallgreen, + /datum/prototype/robot_iconset/baseline_toiletbot/security, + /datum/prototype/robot_iconset/biped_sleek/service, + /datum/prototype/robot_iconset/baseline_misc/omoikane, + /datum/prototype/robot_iconset/grounded_spider/standard, + /datum/prototype/robot_iconset/biped_heavy/service, + /datum/prototype/robot_iconset/baseline_old/service, + /datum/prototype/robot_iconset/baseline_old/service_fancy, + /datum/prototype/robot_iconset/baseline_old/service_hydro, + /datum/prototype/robot_iconset/baseline_old/service_skirt, + /datum/prototype/robot_iconset/baseline_old/service_sweater, + /datum/prototype/robot_iconset/grounded_spider/command, + /datum/prototype/robot_iconset/biped_tall/alternative/service, + /datum/prototype/robot_iconset/hover_drone/service, + /datum/prototype/robot_iconset/hover_drone/hydroponics, + /datum/prototype/robot_iconset/hover_glitterfly/clerical, + /datum/prototype/robot_iconset/hover_glitterfly/service, + /datum/prototype/robot_iconset/hover_handy/service, + /datum/prototype/robot_iconset/grounded_mechoid/service, + /datum/prototype/robot_iconset/grounded_zoomba/service, + /datum/prototype/robot_iconset/biped_noble/service, + /datum/prototype/robot_iconset/grounded_worm/service, + /datum/prototype/robot_iconset/biped_miss/service, + /datum/prototype/robot_iconset/hover_handy/clerk, + /datum/prototype/robot_iconset/raptor/service, + ) + +/datum/prototype/robot_module/nanotrasen/service/create_mounted_item_descriptors(list/normal_out, list/emag_out) + ..() + if(normal_out) + normal_out |= list( + /obj/item/soap/nanotrasen, + /obj/item/storage/bag/trash, + /obj/item/gripper/service, + /obj/item/reagent_containers/glass/bucket, + /obj/item/reagent_containers/dropper/industrial, + /obj/item/flame/lighter/zippo, + /obj/item/reagent_containers/borghypo/service, + /obj/item/material/minihoe, + /obj/item/material/knife/machete/hatchet, + /obj/item/plant_analyzer, + /obj/item/storage/bag/plants, + /obj/item/robot_harvester, + /obj/item/material/knife, + /obj/item/material/kitchen/rollingpin, + /obj/item/pen/robopen, + /obj/item/form_printer, + /obj/item/gripper/paperwork, + /obj/item/hand_labeler, + /obj/item/stamp, + /obj/item/stamp/denied, + /obj/item/tray/robotray, + /obj/item/rsf/loaded, + /obj/item/reagent_containers/food/condiment/enzyme, + ) + if(emag_out) + emag_out |= list( + /obj/item/stamp/chameleon, + /obj/item/pen/chameleon, + ) + +/datum/prototype/robot_module/nanotrasen/service/legacy_custom_regenerate_resources(mob/living/silicon/robot/robot, dt, multiplier) + var/obj/item/reagent_containers/food/condiment/enzyme/E = locate() in robot + E.reagents.add_reagent("enzyme", 2 * multiplier * dt) + +// todo: legacy +/obj/item/robot_module_legacy/robot/clerical + name = "service robot module" + channels = list("Service" = 1) + languages = list( + LANGUAGE_AKHANI = 1, + LANGUAGE_BIRDSONG = 1, + LANGUAGE_CANILUNZT = 1, + LANGUAGE_DAEMON = 1, + LANGUAGE_EAL = 1, + LANGUAGE_ECUREUILIAN= 1, + LANGUAGE_ENOCHIAN = 1, + LANGUAGE_GUTTER = 1, + LANGUAGE_ROOTLOCAL = 0, + LANGUAGE_SAGARU = 1, + LANGUAGE_SCHECHI = 1, + LANGUAGE_SIGN = 0, + LANGUAGE_SIIK = 1, + LANGUAGE_SKRELLIAN = 1, + LANGUAGE_SKRELLIANFAR = 0, + LANGUAGE_SOL_COMMON = 1, + LANGUAGE_SQUEAKISH = 1, + LANGUAGE_TERMINUS = 1, + LANGUAGE_TRADEBAND = 1, + LANGUAGE_UNATHI = 1, + LANGUAGE_ZADDAT = 1 + ) diff --git a/code/modules/mob/living/silicon/robot/modules/swarm.dm b/code/modules/mob/living/silicon/robot/modules/swarm.dm new file mode 100644 index 00000000000..4bbe059d50d --- /dev/null +++ b/code/modules/mob/living/silicon/robot/modules/swarm.dm @@ -0,0 +1,40 @@ +// TODO: IOU swarmers. + +// /datum/prototype/robot_module/swarm +// id = "swarmer" +// light_color = "#77FFFF" +// module_hud_state = "recon" +// // TODO: add some +// allowed_frames = list() + +// /datum/prototype/robot_module/swarm/create_mounted_item_descriptors(list/normal_out, list/emag_out) +// ..() +// if(normal_out) +// normal_out |= list( +// /obj/item/rcd/electric/mounted/borg/swarm, +// /obj/item/flash/robot, +// /obj/item/handcuffs/cable/tape/cyborg, +// /obj/item/melee/baton/robot, +// /obj/item/gun/projectile/energy/taser/mounted/cyborg/swarm, +// /obj/item/matter_decompiler/swarm, +// ) + +// /datum/prototype/robot_module/swarm/gunner +// id = "swarmer-gunner" + +// /datum/prototype/robot_module/swarm/gunner/create_mounted_item_descriptors(list/normal_out, list/emag_out) +// ..() +// if(normal_out) +// normal_out |= list( +// /obj/item/gun/projectile/energy/xray/swarm, +// ) + +// /datum/prototype/robot_module/swarm/melee +// id = "swarmer-melee" + +// /datum/prototype/robot_module/swarm/melee/create_mounted_item_descriptors(list/normal_out, list/emag_out) +// ..() +// if(normal_out) +// normal_out |= list( +// /obj/item/melee/transforming/energy/sword/ionic_rapier/lance, +// ) diff --git a/code/modules/mob/living/silicon/robot/robot-action-robot_pick_resting_variation.dm b/code/modules/mob/living/silicon/robot/robot-action-robot_pick_resting_variation.dm new file mode 100644 index 00000000000..ba911ba879b --- /dev/null +++ b/code/modules/mob/living/silicon/robot/robot-action-robot_pick_resting_variation.dm @@ -0,0 +1,64 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2025 Citadel Station Developers *// + +/datum/action/robot_pick_resting_variation + name = "Pick Resting Variation" + desc = "Pick the variation of your chassis' resting sprite to use." + target_type = /mob/living/silicon/robot + button_additional_only = TRUE + +/datum/action/robot_pick_resting_variation/pre_render_hook() + if(!isrobot(target)) + return + var/mob/living/silicon/robot/casted_target = target + var/datum/prototype/robot_iconset/base = casted_target.iconset + if(base.variations?[casted_target.picked_resting_variation]) + // render the picked variation + var/datum/robot_iconset_variation/variation = base.variations[casted_target.picked_resting_variation] + button_additional_overlay = image( + variation.icon_override || base.icon, + variation.icon_state ? variation.icon_state : "[base.icon_state][variation.icon_state_append]",, + dir = WEST, + ) + else + // just render them + var/mutable_appearance/cloning = new(casted_target) + cloning.dir = WEST + button_additional_overlay = cloning + +/datum/action/robot_pick_resting_variation/invoke_target(mob/living/silicon/robot/target, datum/event_args/actor/actor) + // resolve iconset variations + var/datum/prototype/robot_iconset/base = target.iconset + var/list/datum/robot_iconset_variation/variations = list() + for(var/id in base?.variations) + var/datum/robot_iconset_variation/variation = base.variations[id] + if(variation.alt_resting_state) + variations += variation + if(length(variations) <= 1) + actor.chat_feedback( + SPAN_WARNING("Your chassis has no resting variations to pick from."), + target = target, + ) + return TRUE + + // assemble radial choices + var/list/assembled_radial_choices = list() + for(var/datum/robot_iconset_variation/variation as anything in variations) + var/image/built = image( + variation.icon_override || base.icon, + variation.icon_state || "[base.icon_state][variation.icon_state_append]", + ) + built.maptext = MAPTEXT_CENTER(variation.id) + assembled_radial_choices[variation.id] = built + + // ask them + var/picked_id = show_radial_menu(actor.initiator, target, assembled_radial_choices) + + // check & update + if(!base?.variations[picked_id]) + return TRUE + if(target.picked_resting_variation == picked_id) + return TRUE + log_game("CYBORG: [key_name(src)] ([base]) had their resting variation set to [picked_id] by [actor.actor_log_string()]") + target.picked_resting_variation = picked_id + target.update_icon() diff --git a/code/modules/mob/living/silicon/robot/robot-composition.dm b/code/modules/mob/living/silicon/robot/robot-composition.dm new file mode 100644 index 00000000000..b3397b224ea --- /dev/null +++ b/code/modules/mob/living/silicon/robot/robot-composition.dm @@ -0,0 +1,199 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2025 Citadel Station Developers *// + +/** + * Hard reset, rebuild from composition. + * + * todo: better name? + */ +/mob/living/silicon/robot/proc/rebuild() + set_chassis(chassis, TRUE) + set_iconset(iconset, TRUE) + set_module(module, TRUE) + // TODO: what about upgrades + update_icon() + +/** + * Annihilate composition + * + * todo: better name? + */ +/mob/living/silicon/robot/proc/wipe_for_gc() + set_chassis(null, TRUE) + set_iconset(null, TRUE) + set_module(null, TRUE) + +/** + * Hard reset, to unformatted + * + * todo: better name? + * todo: rework maybe? + */ +/mob/living/silicon/robot/proc/perform_module_reset(perform_transform_animation) + set_chassis(null, TRUE) + set_module(null, TRUE) + set_iconset( + RSrobot_iconsets.fetch_local_or_throw(/datum/prototype/robot_iconset/baseline_standard/standard), + TRUE, + ) + update_icon() + can_repick_frame = TRUE + can_repick_module = TRUE + + //! legacy + lights_on = FALSE + radio.set_light(0) + if(perform_transform_animation) + transform_with_anim() + //! end + +/mob/living/silicon/robot/proc/get_module_pick_groups() + SHOULD_NOT_OVERRIDE(TRUE) + . = conf_module_pick_selection_groups ? conf_module_pick_selection_groups.Copy() : list() + . |= get_module_pick_groups_special() + . -= conf_module_pick_selection_groups_excluded + +/mob/living/silicon/robot/proc/get_module_pick_groups_special() + . = list( + ROBOT_MODULE_SELECTION_GROUP_NANOTRASEN, + ) + //! todo: rework security levels + if(GLOB.security_level >= SEC_LEVEL_RED) + . |= ROBOT_MODULE_SELECTION_GROUP_LEGACY_RED_ALERT + //! end + +/mob/living/silicon/robot/proc/get_default_iconset() + if(module?.auto_iconsets?.len > 0) + . = RSrobot_iconsets.fetch_local_or_throw(pick(module.auto_iconsets)) + if(.) + return + return RSrobot_iconsets.fetch_local_or_throw(/datum/prototype/robot_iconset/baseline_standard/standard) + +/** + * Initialize to a chassis + * + * * Will re-init if it's the same one. + */ +/mob/living/silicon/robot/proc/set_chassis(datum/prototype/robot_chassis/chassis, skip_icon_update) + // cleanup + if(chassis_provisioning) + QDEL_NULL(chassis_provisioning) + // set + src.chassis = chassis + // build + if(!chassis) + return + chassis_provisioning = chassis.create_provisioning() + chassis_provisioning.apply(src) + +/** + * Initialize to a iconset + * + * * Iconset may never be null, as otherwise we can't render. + * * Will re-init if it's the same one. + */ +/mob/living/silicon/robot/proc/set_iconset(datum/prototype/robot_iconset/iconset, skip_icon_update) + // Iconset will never be null. + if(isnull(iconset)) + iconset = get_default_iconset() + src.iconset = iconset + + if(iconset) + if(iconset.icon_dimension_x > WORLD_ICON_SIZE || iconset.icon_dimension_y > WORLD_ICON_SIZE) + zmm_flags |= ZMM_WIDE_LOAD + else + zmm_flags &= ~ZMM_WIDE_LOAD + base_icon_state = iconset.icon_state + icon = iconset.icon + icon_x_dimension = iconset.icon_dimension_x + icon_y_dimension = iconset.icon_dimension_y + set_base_pixel_x(-((icon_x_dimension - WORLD_ICON_SIZE) / 2)) + set_base_pixel_y(-((icon_y_dimension - WORLD_ICON_SIZE) / 2)) + // reset resting variation if needed + if(!iconset.variations?[picked_resting_variation]) + picked_resting_variation = null + else + zmm_flags &= ~ZMM_WIDE_LOAD + base_icon_state = initial(base_icon_state) || initial(icon_state) + icon = initial(icon) + icon_x_dimension = initial(icon_x_dimension) + icon_y_dimension = initial(icon_y_dimension) + set_base_pixel_x(initial(base_pixel_x)) + set_base_pixel_y(initial(base_pixel_y)) + // reset resting variation + picked_resting_variation = null + + if(!skip_icon_update) + update_icon() + +/** + * Initialize to a module + * + * * Will re-init if it's the same one. + */ +/mob/living/silicon/robot/proc/set_module(datum/prototype/robot_module/module, skip_icon_update) + // cleanup + if(module_provisioning) + QDEL_NULL(module_provisioning) + if(module_legacy) + module_legacy.Reset() + QDEL_NULL(module_legacy) + // set + src.module = module + + //! -- LEGACY SCREEN / IDENTITY THINGY -- + src.hands?.icon_state = "none" + src.modtype = "Default" + //! -- END -- + + // build + if(!module) + return + module_provisioning = module.create_provisioning() + module_provisioning.apply(src) + module_legacy = new module.use_robot_module_path(src) + can_repick_module = FALSE + + // this entire section is weird but it's the only way to do it for now + // what we need is to not have magic regen materials so provisioning can also + // be properly composition based and stateful, but for now we don't care + resources.wipe_provisioning() + resources.prep_provisioning() + module.provision_resource_store(resources) + resources.finish_provisioning() + + // now regen to full + resources.regen_provisioned(INFINITY) + module.legacy_custom_regenerate_resources(src, INFINITY, 1) + + //! -- LEGACY SCREEN / IDENTITY THINGY -- + src.hands?.icon_state = module.module_hud_state + src.modtype = module.get_display_name() + //! -- END -- + + if(!skip_icon_update) + update_icon() + +/** + * Set chassis / iconset from a frame. + */ +/mob/living/silicon/robot/proc/set_from_frame(datum/robot_frame/frame, skip_icon_update) + set_chassis(frame.robot_chassis, TRUE) + set_iconset(frame.robot_iconset, TRUE) + can_repick_frame = FALSE + if(!skip_icon_update) + update_icon() + +/** + * Apply a provisioning set; this is one of the things orchestrating composition. + * * Should only be called by `/datum/robot_provisioning`. + */ +/mob/living/silicon/robot/proc/apply_provisioning(datum/robot_provisioning/provisioning) + // TODO: this is unused? + +/** + * Remove a provisioning set; this is one of the things orchestrating composition. + * * Should only be called by `/datum/robot_provisioning`. + */ +/mob/living/silicon/robot/proc/remove_provisioning(datum/robot_provisioning/provisioning) + // TODO: this is unused? diff --git a/code/modules/mob/living/silicon/robot/robot-health.dm b/code/modules/mob/living/silicon/robot/robot-health.dm new file mode 100644 index 00000000000..d28decc4ae7 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/robot-health.dm @@ -0,0 +1,6 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2025 Citadel Station Developers *// + +/mob/living/silicon/robot/on_stat_change(old_stat, new_stat) + ..() + update_icon() diff --git a/code/modules/mob/living/silicon/robot/robot-inventory.dm b/code/modules/mob/living/silicon/robot/robot-inventory.dm new file mode 100644 index 00000000000..a9341d835de --- /dev/null +++ b/code/modules/mob/living/silicon/robot/robot-inventory.dm @@ -0,0 +1,16 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2025 Citadel Station Developers *// + +/mob/living/silicon/robot/init_inventory() + ..() + inventory.set_hand_count(3) + +/mob/living/silicon/robot/should_allow_pickup(obj/item/item, datum/event_args/actor/actor, silent) + return item in robot_inventory?.provided_items + +/mob/living/silicon/robot/is_in_inventory(obj/item/item) + return ..() || is_in_inventory_robot(item) + +/mob/living/silicon/robot/proc/is_in_inventory_robot(obj/item/item) + // Bespoke check that an item is in gripper, as grippers don't count as an inventory slot. + return istype(item.loc, /obj/item/gripper) && item.loc.loc == src diff --git a/code/modules/mob/living/silicon/robot/robot_animation_vr.dm b/code/modules/mob/living/silicon/robot/robot-legacy-animation_vr.dm similarity index 94% rename from code/modules/mob/living/silicon/robot/robot_animation_vr.dm rename to code/modules/mob/living/silicon/robot/robot-legacy-animation_vr.dm index 5eb6bf03dec..dd6f34bfb75 100644 --- a/code/modules/mob/living/silicon/robot/robot_animation_vr.dm +++ b/code/modules/mob/living/silicon/robot/robot-legacy-animation_vr.dm @@ -2,7 +2,7 @@ INVOKE_ASYNC(src, PROC_REF(do_transform_animation)) /mob/living/silicon/robot/proc/do_transform_animation() - notransform = TRUE + transforming = TRUE dir = SOUTH var/obj/effect/temp_visual/decoy/fading/fivesecond/ANM = new /obj/effect/temp_visual/decoy/fading/fivesecond(loc, src) ANM.layer = layer - 0.01 @@ -19,4 +19,4 @@ if(!prev_lockcharge) SetLockdown(0) anchored = FALSE - notransform = FALSE + transforming = FALSE diff --git a/code/modules/mob/living/silicon/robot/robot_damage.dm b/code/modules/mob/living/silicon/robot/robot-legacy-damage.dm similarity index 100% rename from code/modules/mob/living/silicon/robot/robot_damage.dm rename to code/modules/mob/living/silicon/robot/robot-legacy-damage.dm diff --git a/code/modules/mob/living/silicon/robot/robot-legacy-emag.dm b/code/modules/mob/living/silicon/robot/robot-legacy-emag.dm new file mode 100644 index 00000000000..8021ff338e7 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/robot-legacy-emag.dm @@ -0,0 +1,17 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2025 Citadel Station Developers *// + +/mob/living/silicon/robot/proc/set_emag_state(state) + emagged = state + set_emag_item_state(state) + +/mob/living/silicon/robot/proc/get_emag_state() + return emagged + +/mob/living/silicon/robot/proc/set_emag_item_state(state) + emag_items = state + chassis_provisioning?.set_emag_enabled(state) + module_provisioning?.set_emag_enabled(state) + +/mob/living/silicon/robot/proc/get_emag_item_state() + return emag_items diff --git a/code/modules/mob/living/silicon/robot/robot_items.dm b/code/modules/mob/living/silicon/robot/robot-legacy-items.dm similarity index 99% rename from code/modules/mob/living/silicon/robot/robot_items.dm rename to code/modules/mob/living/silicon/robot/robot-legacy-items.dm index a430c510ef9..115756ac89c 100644 --- a/code/modules/mob/living/silicon/robot/robot_items.dm +++ b/code/modules/mob/living/silicon/robot/robot-legacy-items.dm @@ -346,7 +346,8 @@ new /obj/item/paper(T) -//Personal shielding for the combat module. +// Personal shielding for the combat module. +// TODO: refactor this shit this is awful lol /obj/item/borg/combat/shield name = "personal shielding" desc = "A powerful experimental module that turns aside or absorbs incoming attacks at the cost of charge." diff --git a/code/modules/mob/living/silicon/robot/robot_movement.dm b/code/modules/mob/living/silicon/robot/robot-legacy-movement.dm similarity index 53% rename from code/modules/mob/living/silicon/robot/robot_movement.dm rename to code/modules/mob/living/silicon/robot/robot-legacy-movement.dm index 99298ddbac8..c68f1384632 100644 --- a/code/modules/mob/living/silicon/robot/robot_movement.dm +++ b/code/modules/mob/living/silicon/robot/robot-legacy-movement.dm @@ -1,19 +1,14 @@ -/mob/living/silicon/robot/Process_Spaceslipping(var/prob_slip) - if(module && module.no_slip) - return 0 - ..(prob_slip) - /mob/living/silicon/robot/Process_Spacemove() - if(module) - for(var/obj/item/tank/jetpack/J in module.modules) - if(istype(J, /obj/item/tank/jetpack)) - if(J.allow_thrust(0.01)) - return TRUE + // active robot modules are held items + for(var/obj/item/tank/jetpack/J in inventory?.get_held_items()) + if(istype(J, /obj/item/tank/jetpack)) + if(J.allow_thrust(0.01)) + return TRUE return ..() /mob/living/silicon/robot/legacy_movement_delay() . = ..() - if(module_active && istype(module_active,/obj/item/borg/combat/mobility)) + if(get_held_item_of_type(/obj/item/borg/combat/mobility)) . -= 2 if(get_restraining_bolt()) // Borgs with Restraining Bolts move slower. @@ -25,5 +20,5 @@ return 0 var/datum/robot_component/actuator/A = get_component("actuator") - if (cell_use_power(A.active_usage)) + if (legacy_cell_use_power(A.active_usage)) return ..() diff --git a/code/modules/mob/living/silicon/robot/robot_remote_control.dm b/code/modules/mob/living/silicon/robot/robot-legacy-remote_control.dm similarity index 90% rename from code/modules/mob/living/silicon/robot/robot_remote_control.dm rename to code/modules/mob/living/silicon/robot/robot-legacy-remote_control.dm index 3f500fbca25..14986f035c6 100644 --- a/code/modules/mob/living/silicon/robot/robot_remote_control.dm +++ b/code/modules/mob/living/silicon/robot/robot-legacy-remote_control.dm @@ -2,11 +2,6 @@ GLOBAL_LIST_EMPTY(available_ai_shells) -/mob/living/silicon/robot - var/shell = FALSE - var/deployed = FALSE - var/mob/living/silicon/ai/mainframe = null - // Premade AI shell, for roundstart shells. /mob/living/silicon/robot/ai_shell/Initialize(mapload) mmi = new /obj/item/mmi/inert/ai_remote(src) @@ -69,15 +64,13 @@ GLOBAL_LIST_EMPTY(available_ai_shells) // Languages and comms. languages = AI.languages.Copy() speech_synthesizer_langs = AI.speech_synthesizer_langs.Copy() - if(radio && AI.aiRadio && module) //AI keeps all channels, including Syndie if it is an Infiltrator. + if(radio && AI.aiRadio && module_legacy) //AI keeps all channels, including Syndie if it is an Infiltrator. radio.subspace_transmission = TRUE - module.channels = AI.aiRadio.channels + module_legacy.channels = AI.aiRadio.channels radio.recalculateChannels() // Called after the AI transfers over. /mob/living/silicon/robot/proc/post_deploy() - if(!custom_sprite) // Check for custom sprite. - set_custom_sprite() /mob/living/silicon/robot/proc/undeploy(message) if(!deployed || !mind || !mainframe) @@ -90,8 +83,8 @@ GLOBAL_LIST_EMPTY(available_ai_shells) mainframe.teleop = null mainframe.deployed_shell = null SetName("[modtype] AI Shell [num2text(ident)]") - if(radio && module) //Return radio to normal - module.channels = initial(module.channels) + if(radio && module_legacy) //Return radio to normal + module_legacy.channels = initial(module_legacy.channels) radio.recalculateChannels() if(!QDELETED(camera)) camera.c_tag = real_name //update the camera name too diff --git a/code/modules/mob/living/silicon/robot/robot-power.dm b/code/modules/mob/living/silicon/robot/robot-power.dm index eb452e4bd03..066840bb3b8 100644 --- a/code/modules/mob/living/silicon/robot/robot-power.dm +++ b/code/modules/mob/living/silicon/robot/robot-power.dm @@ -1,5 +1,37 @@ //* This file is explicitly licensed under the MIT license. *// //* Copyright (c) 2025 Citadel Station Developers *// +/** + * Uses a certain amount of reserve power - usually from the cell. + * + * * This bypasses any internal power limit / balancing logic and directly hits our + * backplane's power source. + * + * @return amount used + */ +/mob/living/silicon/robot/proc/draw_power(joules) + . = cell ? cell.use(DYNAMIC_J_TO_CELL_UNITS(joules)) : 0 + if(.) + avg_power_accumulator += DYNAMIC_CELL_UNITS_TO_J(.) + +/** + * Uses a certain amount of reserve power - usually from the cell. + * + * * This bypasses any internal power limit / balancing logic and directly hits our + * backplane's power source. + * * Reserve is in units, not joules. + * + * @return amount used + */ +/mob/living/silicon/robot/proc/draw_checked_power(joules, reserve_units) + if(!cell) + return 0 + var/units = DYNAMIC_J_TO_CELL_UNITS(joules) + if(cell.charge - units < reserve_units) + return 0 + . = cell.use(units) + if(.) + avg_power_accumulator += DYNAMIC_CELL_UNITS_TO_J(.) + /mob/living/silicon/robot/proc/accepts_cell(obj/item/cell/cell, datum/event_args/actor/actor, silent) return cell.cell_type ? (cell.cell_type & cell_accept) : cell_accept_nonstandard diff --git a/code/modules/mob/living/silicon/robot/robot-rendering.dm b/code/modules/mob/living/silicon/robot/robot-rendering.dm new file mode 100644 index 00000000000..869083ba9ec --- /dev/null +++ b/code/modules/mob/living/silicon/robot/robot-rendering.dm @@ -0,0 +1,57 @@ +/mob/living/silicon/robot/update_icon() + cut_overlays() + . = ..() + + // resolve variation & set icon state + var/datum/robot_iconset_variation/active_variation + if(IS_DEAD(src)) + var/datum/robot_iconset_variation/dead_variation = iconset?.variations?[/datum/robot_iconset_variation/dead::id] + if(dead_variation) + active_variation = dead_variation + else if(resting) + if(picked_resting_variation) + active_variation = iconset?.variations?[picked_resting_variation] + if(!active_variation) + active_variation = iconset?.variations?[/datum/robot_iconset_variation/resting::id] + + if(active_variation) + if(active_variation.icon_state) + icon_state = active_variation.icon_state + else + icon_state = "[base_icon_state][active_variation.icon_state_append]" + else + icon_state = base_icon_state + + // render indicator lighting + if(IS_CONSCIOUS(src) && (!shell || deployed)) + var/indicator_state + if(active_variation) + if(active_variation.icon_state_indicator) + indicator_state = active_variation.icon_state_indicator + else if(active_variation.icon_state_indicator_append) + indicator_state = "[icon_state][active_variation.icon_state_indicator_append]" + else if(iconset.icon_state_indicator) + indicator_state = iconset.icon_state_indicator + var/image/indicator = image(icon, indicator_state) + switch(iconset.indicator_lighting_coloration_mode) + if(COLORATION_MODE_MULTIPLY) + indicator.color = iconset.indicator_lighting_coloration_packed + add_overlay(indicator) + + // render panel + if(opened) + var/using_panel_state + if(active_variation) + if(active_variation.icon_state_cover) + using_panel_state = active_variation.icon_state_cover + else if(active_variation.icon_state_cover_append) + using_panel_state = "[base_icon_state][active_variation.icon_state_cover]" + else + using_panel_state = iconset.icon_state_cover + if(using_panel_state) + if(wiresexposed) + add_overlay("[using_panel_state]-wires") + else if(cell) + add_overlay("[using_panel_state]-cell") + else + add_overlay("[using_panel_state]-empty") diff --git a/code/modules/mob/living/silicon/robot/robot-resources.dm b/code/modules/mob/living/silicon/robot/robot-resources.dm new file mode 100644 index 00000000000..86ed7fc4b06 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/robot-resources.dm @@ -0,0 +1,12 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2025 Citadel Station Developers *// + +/** + * Regenerates our resources. + * + * * Used by chargers. + */ +/mob/living/silicon/robot/proc/regenerate_resources_from_charger(seconds, multiplier = 1) + SHOULD_NOT_OVERRIDE(TRUE) // no excuses, don't do it! robots are composition. + + module?.legacy_custom_regenerate_resources(src, seconds, multiplier) diff --git a/code/modules/mob/living/silicon/robot/robot-upgrades.dm b/code/modules/mob/living/silicon/robot/robot-upgrades.dm new file mode 100644 index 00000000000..f4bb1e799be --- /dev/null +++ b/code/modules/mob/living/silicon/robot/robot-upgrades.dm @@ -0,0 +1,114 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2025 Citadel Station Developers *// + +/** + * hard check + */ +/mob/living/silicon/robot/proc/can_install_upgrade(obj/item/robot_upgrade/upgrade, datum/event_args/actor/actor, silent, force) + SHOULD_NOT_OVERRIDE(TRUE) + SHOULD_NOT_SLEEP(TRUE) + + if(!upgrade.dupe_allowed) + var/check_type = upgrade.dupe_type || upgrade.type + for(var/obj/item/robot_upgrade/other as anything in upgrades) + if(istype(other, check_type)) + if(!silent) + actor?.chat_feedback( + SPAN_WARNING("There's already an upgrade of the same type in [src]."), + target = src, + ) + return FALSE + + return force || upgrade.can_install(src, ., actor, silent) + +/mob/living/silicon/robot/proc/can_fit_upgrade(obj/item/robot_upgrade/upgrade, datum/event_args/actor/actor, silent) + return TRUE + +/mob/living/silicon/robot/proc/user_install_upgrade(obj/item/robot_upgrade/upgrade, datum/event_args/actor/actor) + SHOULD_NOT_OVERRIDE(TRUE) + + if(actor) + if(actor.performer && actor.performer.is_in_inventory(upgrade)) + if(!actor.performer.can_unequip(upgrade, upgrade.worn_slot)) + actor.chat_feedback( + SPAN_WARNING("[upgrade] is stuck to your hand!"), + target = src, + ) + return FALSE + if(!install_upgrade(upgrade, actor)) + return FALSE + // TODO: sound + return TRUE + +/** + * * moves the upgrade into us if it wasn't already + */ +/mob/living/silicon/robot/proc/install_upgrade(obj/item/robot_upgrade/upgrade, datum/event_args/actor/actor, silent, force) + SHOULD_NOT_OVERRIDE(TRUE) + SHOULD_NOT_SLEEP(TRUE) + + ASSERT(!upgrade.owner) + + if(!can_install_upgrade(upgrade, actor, silent, force)) + return FALSE + + if(upgrade.loc != src) + upgrade.forceMove(src) + + // todo: logging + upgrade.being_installed(src) + if(!QDELETED(upgrade)) + upgrade.owner = src + upgrade.on_install(src) + LAZYADD(upgrades, upgrade) + + if(!silent) + actor?.visible_feedback( + target = src, + visible = SPAN_NOTICE("[actor.performer] slots [upgrade] into [src]."), + range = MESSAGE_RANGE_CONFIGURATION, + ) + + return TRUE + +/mob/living/silicon/robot/proc/user_uninstall_upgrade(obj/item/robot_upgrade/upgrade, datum/event_args/actor/actor, put_in_hands) + SHOULD_NOT_OVERRIDE(TRUE) + + var/obj/item/uninstalled = uninstall_upgrade(upgrade, actor, new_loc = src) + if(put_in_hands && actor?.performer) + actor.performer.put_in_hands_or_drop(uninstalled) + else + var/atom/where_to_drop = drop_location() + ASSERT(where_to_drop) + uninstalled.forceMove(where_to_drop) + // TODO: sound + return TRUE + +/** + * * deletes the upgrade if no location is provided to move it to + * + * @return uninstalled item + */ +/mob/living/silicon/robot/proc/uninstall_upgrade(obj/item/robot_upgrade/upgrade, datum/event_args/actor/actor, silent, force, atom/new_loc) + SHOULD_NOT_OVERRIDE(TRUE) + SHOULD_NOT_SLEEP(TRUE) + ASSERT(upgrade.owner == src) + + // todo: logging + upgrade.on_uninstall(src) + upgrade.owner = null + LAZYREMOVE(upgrades, upgrade) + + if(!silent) + actor?.visible_feedback( + target = src, + visible = SPAN_NOTICE("[actor.performer] pulls [upgrade] out of [src]."), + range = MESSAGE_RANGE_CONFIGURATION, + ) + + if(new_loc) + upgrade.forceMove(new_loc) + . = upgrade + else + qdel(upgrade) + . = null diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index 19af1576803..361fd7c14ee 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -19,7 +19,6 @@ /datum/category_item/catalogue/fauna/silicon/robot/cyborg, /datum/category_item/catalogue/fauna/silicon/robot/lost, /datum/category_item/catalogue/fauna/silicon/robot/gravekeeper, - /datum/category_item/catalogue/fauna/silicon/robot/syndicate ) /datum/category_item/catalogue/fauna/silicon/robot/cyborg @@ -36,10 +35,20 @@ // todo: automatic subtypes for modules +/** + * ## Composition + * + * Robots are / will be made out of: + * + * * chassis - determines baseline functionality and support + * * iconsets - determines sprites + * + * WIP. Modules, components, etc, are next. + */ /mob/living/silicon/robot name = "Cyborg" real_name = "Cyborg" - icon = 'icons/mob/robots.dmi' + icon = 'icons/mob/robot-legacy.dmi' icon_state = "robot" maxHealth = 200 health = 200 @@ -60,13 +69,98 @@ can_be_antagged = TRUE + //* Composition *// + + /// set to instance to init as that instance + /// * This may be null; which will result in an iconset being defaulted on init. + var/datum/prototype/robot_iconset/iconset + /// set to instance to init as that instance + var/datum/prototype/robot_chassis/chassis + var/datum/robot_provisioning/chassis_provisioning + /// set to instance to init as that instance + var/datum/prototype/robot_module/module + var/datum/robot_provisioning/module_provisioning + + /// all installed upgrades + /// * some upgrades are consumed on install, and therefore won't be in here + var/list/obj/item/robot_upgrade/upgrades + + //* Configuration *// + + /// Allowed selection groups for robot module picking + /// * Null = cannot pick anything, so, uh, don't fuck around with this. + /// todo: module based? + var/list/conf_module_pick_selection_groups + /// Disallowed selection groups for robot module picking + /// * Overrides pick_selection_groups and things like + /// red alert default groups + var/list/conf_module_pick_selection_groups_excluded + /// Initial default lawset + /// * An instance or a type is accepted + /// todo: module based? + var/conf_default_lawset_type = /datum/ai_lawset/nanotrasen + /// Auto connect to AI + /// todo: module bsaed? + var/conf_auto_ai_link = TRUE + /// Bootup sound + var/conf_reboot_sound = 'sound/voice/liveagain.ogg' + /// MMI type to make if we have none + var/conf_mmi_create_type = /obj/item/mmi + /// Create cell type if it doesn't exist + var/conf_cell_create_type = /obj/item/cell/basic/tier_1/large + + //* Inventory *// + + inventory = /datum/inventory/robot + /// Robot inventory + var/datum/robot_inventory/robot_inventory + /// Resources store + var/datum/robot_resource_store/resources + + //* Movement *// + /// Base movement speed in tiles / second + var/movement_base_speed = 4.5 + + //* Power *// + /// our power cell + var/obj/item/cell/cell + /// starting cell type + var/cell_type = /obj/item/cell/basic/tier_1/large + var/cell_accept = CELL_TYPE_LARGE | CELL_TYPE_MEDIUM | CELL_TYPE_SMALL | CELL_TYPE_WEAPON + /// accept cells with no CELL_TYPE field + /// * for shit like gunsword + var/cell_accept_nonstandard = TRUE + + //* State *// + + /// If set, we are a blank slate, and are allowed to pick a module and frame. + var/can_repick_module = TRUE + /// If set, we are able to repick our frame. + /// * This does not imply [can_repick_module]. If this is set, and that isn't, + /// and we already have a module, we can repick our frame but not our module. + var/can_repick_frame = TRUE + /// Currently active voluntary sprite variation for rest. + /// * Reset upon stopping resting. + /// * This is the ID of the variation. + var/picked_resting_variation + + //* -- Legacy Below -- *// + + /// legacy: are we floor scrubbing? + var/legacy_floor_scrubbing = FALSE + /// Is our integrated light on? var/lights_on = 0 - var/used_power_this_tick = 0 + + /// last time we retallied avg power (literally a no-smoothing running average) + var/avg_power_last = 0 + /// * units: joules + var/avg_power_accumulator = 0 + /// * units: watts + var/avg_power = 0 + var/sight_mode = 0 var/custom_name = "" - /// Due to all the sprites involved, a var for our custom borgs may be best. - var/custom_sprite = 0 /// The name of the borg, for the purposes of custom icon sprite indexing. var/sprite_name = null /// Admin-settable for combat module use. @@ -75,32 +169,10 @@ var/integrated_light_power = 4.5 var/datum/wires/robot/wires - //* Icon stuff - /// Persistent icontype tracking allows for cleaner icon updates - var/icontype - /// Used to store the associations between sprite names and sprite index. - var/module_sprites[0] - /// If icon selection has been completed yet. - var/icon_selected = 1 - /// Remaining attempts to select icon before a selection is forced. - var/icon_selection_tries = 0 - - //* Hud stuff - var/atom/movable/screen/cells = null - var/atom/movable/screen/inv1 = null - var/atom/movable/screen/inv2 = null - var/atom/movable/screen/inv3 = null - /// Used to determine whether they have the module menu shown or not - var/shown_robot_modules = 0 - var/atom/movable/screen/robot_modules_background //?3 Modules can be activated at any one time. - var/obj/item/robot_module/module = null - var/obj/item/module_active = null - var/obj/item/module_state_1 = null - var/obj/item/module_state_2 = null - var/obj/item/module_state_3 = null + var/obj/item/robot_module_legacy/module_legacy = null var/obj/item/radio/borg/radio = null var/obj/item/communicator/integrated/communicator = null @@ -117,25 +189,19 @@ var/obj/item/pda/ai/rbPDA = null var/opened = FALSE - var/emagged = 0 + var/emagged = FALSE var/emag_items = FALSE var/wiresexposed = FALSE var/locked = TRUE var/has_power = TRUE var/list/req_access = list(ACCESS_SCIENCE_ROBOTICS) var/ident = 0 - //var/list/laws = list() var/viewalerts = FALSE var/modtype = "Default" - var/lower_mod = 0 var/jetpack = 0 var/datum/effect_system/ion_trail_follow/ion_trail = null - var/datum/effect_system/spark_spread/spark_system//So they can initialize sparks whenever/N - var/jeton = FALSE - var/killswitch = FALSE - var/killswitch_time = 60 - var/weapon_lock = FALSE - var/weaponlock_time = 120 + var/datum/effect_system/spark_spread/spark_system + /// Cyborgs will sync their laws with their AI by default var/lawupdate = TRUE /// Used when looking to see if a borg is locked down. @@ -155,40 +221,31 @@ /mob/living/silicon/robot/proc/robot_checklaws ) - var/sleeper_g - var/sleeper_r var/leaping = 0 var/pounce_cooldown = 0 var/pounce_cooldown_time = 40 var/leap_at - var/dogborg = FALSE //Quadborg special features (overlays etc.) - var/wideborg = FALSE //When the borg simply doesn't use standard 32p size. var/scrubbing = FALSE //Floor cleaning enabled - var/datum/matter_synth/water_res = null - var/notransform - var/original_icon = 'icons/mob/robots.dmi' - var/sitting = FALSE - var/bellyup = FALSE - //* Power *// - /// our power cell - var/obj/item/cell/cell - /// starting cell type - var/cell_type = /obj/item/cell/basic/tier_1/large - var/cell_accept = CELL_TYPE_LARGE | CELL_TYPE_MEDIUM | CELL_TYPE_SMALL | CELL_TYPE_WEAPON - /// accept cells with no CELL_TYPE field - /// * for shit like gunsword - var/cell_accept_nonstandard = TRUE - - //* Movement *// - /// Base movement speed in tiles / second - var/movement_base_speed = 4 + var/shell = FALSE + var/deployed = FALSE + var/mob/living/silicon/ai/mainframe = null /mob/living/silicon/robot/Initialize(mapload, unfinished = FALSE) + . = ..() + // must be before inventory; inventory binds to resources item mount + resources = new(src) + robot_inventory = new(src) + spark_system = new /datum/effect_system/spark_spread() spark_system.set_up(5, 0, src) spark_system.attach(src) + // this is in a particular order because iconset auto-detection depends on this. + set_module(RSrobot_modules.fetch_local_or_throw(module), TRUE) + set_chassis(RSrobot_chassis.fetch_local_or_throw(chassis), TRUE) + set_iconset(RSrobot_iconsets.fetch_local_or_throw(iconset), TRUE) + add_language("Robot Talk", TRUE) add_language(LANGUAGE_EAL, TRUE) // todo: translation contexts on language holder? @@ -200,14 +257,8 @@ wires = new(src) - robot_modules_background = new() - robot_modules_background.icon = 'icons/screen/hud/common/storage.dmi' - robot_modules_background.icon_state = "block" ident = rand(1, 999) - module_sprites["Basic"] = "robot" - icontype = "Basic" updatename("Default") - updateicon() radio = new /obj/item/radio/borg(src) // communicator = new /obj/item/communicator/integrated(src) @@ -230,10 +281,8 @@ C.installed = 1 C.wrapped = new C.external_type - if(!cell) - cell = new cell_type(src) - - . = ..() + if(!cell && conf_cell_create_type) + cell = new conf_cell_create_type if(cell) var/datum/robot_component/cell_component = components["power cell"] @@ -244,27 +293,77 @@ AddComponent(/datum/component/riding_filter/mob/robot) -/mob/living/silicon/robot/proc/init() - aiCamera = new/obj/item/camera/siliconcam/robot_camera(src) - laws = new /datum/ai_laws/nanotrasen() - additional_law_channels["Binary"] = "#b" - var/new_ai = select_active_ai_with_fewest_borgs() - if(new_ai) - lawupdate = 1 - connect_to_ai(new_ai) - else - lawupdate = 0 + update_icon() - playsound(loc, 'sound/voice/liveagain.ogg', 75, 1) +/mob/living/silicon/robot/Destroy() + wipe_for_gc() + QDEL_NULL(robot_inventory) + QDEL_NULL(resources) + // TODO: don't do this, just don't fucking dust() people or have dust() have a drop proc???? + if(mmi && mind)//Safety for when a cyborg gets dust()ed. Or there is no MMI inside. + var/turf/T = get_turf(loc)//To hopefully prevent run time errors. + if(T) + mmi.forceMove(T) + if(mmi.brainmob) + var/obj/item/robot_module_legacy/M = locate() in contents + if(M) + mmi.brainmob.languages = M.original_languages + else + mmi.brainmob.languages = languages + mmi.brainmob.remove_language("Robot Talk") + mind.transfer(mmi.brainmob) + else if(!shell) // Shells don't have brainmbos in their MMIs. + to_chat(src, "Oops! Something went very wrong, your MMI was unable to receive your mind. You have been ghosted. Please make a bug report so we can fix this bug.") + ghostize() + //ERROR("A borg has been destroyed, but its MMI lacked a brainmob, so the mind could not be transferred. Player: [ckey].") + mmi = null + if(connected_ai) + connected_ai.connected_robots -= src + if(shell) + if(deployed) + undeploy() + revert_shell() // To get it out of the GLOB list. + QDEL_NULL(wires) + return ..() + +/mob/living/silicon/robot/proc/init() + aiCamera = new /obj/item/camera/siliconcam/robot_camera(src) + + if(istype(conf_default_lawset_type, /datum/ai_lawset)) + var/datum/ai_lawset/conf_default_lawset_instance = conf_default_lawset_type + laws = conf_default_lawset_instance.clone() + else if(ispath(conf_default_lawset_type, /datum/ai_lawset)) + laws = new conf_default_lawset_type + else if(IS_ANONYMOUS_TYPEPATH(conf_default_lawset_type)) + laws = new conf_default_lawset_type + else + laws = new /datum/ai_lawset + if(conf_auto_ai_link) + var/new_ai = select_active_ai_with_fewest_borgs() + if(new_ai) + lawupdate = 1 + connect_to_ai(new_ai) + else + lawupdate = 0 + + additional_law_channels["Binary"] = "#b" + + if(conf_mmi_create_type && !mmi) + mmi = new /obj/item/mmi/digital/robot(src) + + playsound(src, conf_reboot_sound, 75, TRUE) /mob/living/silicon/robot/SetName(pickedName as text) custom_name = pickedName updatename() /mob/living/silicon/robot/proc/sync() - if(lawupdate && connected_ai) - lawsync() - photosync() + if(!lawupdate) + return + if(!connected_ai) + return + lawsync() + photosync() /mob/living/silicon/robot/drain_energy(datum/actor, amount, flags) if(!cell) @@ -289,72 +388,6 @@ communicator = new/obj/item/communicator/integrated(src) communicator.register_device(src.name, "[modtype] [braintype]") -//If there's an MMI in the robot, have it ejected when the mob goes away. --NEO -//Improved /N -/mob/living/silicon/robot/Destroy() - if(mmi && mind)//Safety for when a cyborg gets dust()ed. Or there is no MMI inside. - var/turf/T = get_turf(loc)//To hopefully prevent run time errors. - if(T) mmi.loc = T - if(mmi.brainmob) - var/obj/item/robot_module/M = locate() in contents - if(M) - mmi.brainmob.languages = M.original_languages - else - mmi.brainmob.languages = languages - mmi.brainmob.remove_language("Robot Talk") - mind.transfer(mmi.brainmob) - else if(!shell) // Shells don't have brainmbos in their MMIs. - to_chat(src, "Oops! Something went very wrong, your MMI was unable to receive your mind. You have been ghosted. Please make a bug report so we can fix this bug.") - ghostize() - //ERROR("A borg has been destroyed, but its MMI lacked a brainmob, so the mind could not be transferred. Player: [ckey].") - mmi = null - if(connected_ai) - connected_ai.connected_robots -= src - if(shell) - if(deployed) - undeploy() - revert_shell() // To get it out of the GLOB list. - qdel(wires) - wires = null - return ..() - -/mob/living/silicon/robot/proc/set_module_sprites(var/list/new_sprites) - if(new_sprites && new_sprites.len) - module_sprites = new_sprites.Copy() - //Custom_sprite check and entry - if (custom_sprite == 1) - module_sprites["Custom"] = "[ckey]-[sprite_name]-[modtype]" //Made compliant with custom_sprites.dm line 32. (src.) was apparently redundant as it's implied. ~Mech - icontype = "Custom" - else - icontype = module_sprites[1] - icon_state = module_sprites[icontype] - updateicon() - return module_sprites - -/mob/living/silicon/robot/proc/pick_module() - if(module) - return - var/list/modules = list() - modules.Add(robot_module_types) - if(crisis || GLOB.security_level == SEC_LEVEL_RED || crisis_override) - to_chat(src, "Crisis mode active. Combat module available.") - modules+="Combat" - modules+="ERT" - modtype = input("Please, select a module!", "Robot module", null, null) as null|anything in modules - - if(module) - return - if(!(modtype in GLOB.robot_modules)) - return - - var/module_type = GLOB.robot_modules[modtype] - transform_with_anim() - new module_type(src) - - hands.icon_state = lowertext(modtype) - feedback_inc("cyborg_[lowertext(modtype)]",1) - updatename() - notify_ai(ROBOT_NOTIFICATION_NEW_MODULE, module.name) /mob/living/silicon/robot/proc/updatename(var/prefix as text) if(prefix) @@ -390,9 +423,6 @@ if (camera) camera.c_tag = changed_name - if(!custom_sprite) //Check for custom sprite - set_custom_sprite() - //Flavour text. if(client) var/module_flavour = client.prefs.flavour_texts_robot[modtype] @@ -418,7 +448,6 @@ sprite_name = newname updatename() - updateicon() // this verb lets cyborgs see the stations manifest /mob/living/silicon/robot/verb/cmd_station_manifest() @@ -444,24 +473,12 @@ lights_on = !lights_on to_chat(usr, "You [lights_on ? "enable" : "disable"] your integrated light.") + // todo: more customization for light colors / lights / whatever if (lights_on) - radio.set_light(integrated_light_power, 2, l_color = get_light_color_for_icontype(), angle = LIGHT_WIDE) + radio.set_light(integrated_light_power, 2, l_color = module?.light_color || "#FFFFFF", angle = LIGHT_WIDE) else radio.set_light(0) - updateicon() - -/mob/living/silicon/robot/proc/get_light_color_for_icontype() - . = LIGHT_COLOR_TUNGSTEN - if (icon in GLOB.borg_light_color_lut) - var/list/lut = GLOB.borg_light_color_lut[icon] - if (module_sprites[icontype] in lut) - return lut[module_sprites[icontype]] - - // Don't want to runtime if an admin is varediting a borg's icon. - else if (!(datum_flags & DF_VAR_EDITED)) - CRASH("[icon] is missing entries in the borg flashlight LUT.") - /mob/living/silicon/robot/verb/self_diagnosis_verb() set category = "Robot Commands" set name = "Self Diagnosis" @@ -470,7 +487,7 @@ to_chat(src, "Your self-diagnosis component isn't functioning.") var/datum/robot_component/CO = get_component("diagnosis unit") - if (!cell_use_power(CO.active_usage)) + if (!legacy_cell_use_power(CO.active_usage)) to_chat(src, "Low Power.") var/dat = self_diagnosis() src << browse(dat, "window=robotdiagnosis") @@ -510,13 +527,10 @@ set name = "Toggle Cover" locked = !locked to_chat(src, "You [ locked ? "lock" : "unlock"] your interface.") - updateicon() // this function returns the robots jetpack, if one is installed /mob/living/silicon/robot/proc/installed_jetpack() - if(module) - return (locate(/obj/item/tank/jetpack) in module.modules) - return 0 + return locate(/obj/item/tank/jetpack) in robot_inventory.provided_items // update the status screen display /mob/living/silicon/robot/statpanel_data(client/C) @@ -526,7 +540,7 @@ if(cell) INJECT_STATPANEL_DATA_LINE(., "Charge Left: [round(cell.percent())]%") INJECT_STATPANEL_DATA_LINE(., "Cell Rating: [round(cell.max_charge)]") // Round just in case we somehow get crazy values - INJECT_STATPANEL_DATA_LINE(., "Power Cell Load: [round(used_power_this_tick)]W") + INJECT_STATPANEL_DATA_LINE(., "Power Cell Load: [round(avg_power)]W") else INJECT_STATPANEL_DATA_LINE(., "No Cell Inserted!") INJECT_STATPANEL_DATA_LINE(., "Lights: [lights_on ? "ON" : "OFF"]") @@ -536,9 +550,20 @@ if (current_jetpack) INJECT_STATPANEL_DATA_ENTRY(., "Internal Atmosphere Info", current_jetpack.name) INJECT_STATPANEL_DATA_ENTRY(., "Tank Pressure", current_jetpack.air_contents.return_pressure()) - if(module) - for(var/datum/matter_synth/ms in module.synths) - INJECT_STATPANEL_DATA_LINE(., "[ms.name]: [ms.energy]/[ms.max_energy]") + // todo: robot panel; this shouldn't be in statpanel, it's not critical data + if(resources) + for(var/key in resources.provisioned_stack_store) + var/datum/robot_resource/resource = resources.provisioned_stack_store[key] + INJECT_STATPANEL_DATA_LINE(., "[resource.name]: [resource.amount]/[resource.amount_max]") + for(var/key in resources.provisioned_material_store) + var/datum/robot_resource/resource = resources.provisioned_material_store[key] + INJECT_STATPANEL_DATA_LINE(., "[resource.name]: [resource.amount]/[resource.amount_max]") + for(var/key in resources.provisioned_reagent_store) + var/datum/robot_resource/resource = resources.provisioned_reagent_store[key] + INJECT_STATPANEL_DATA_LINE(., "[resource.name]: [resource.amount]/[resource.amount_max]") + for(var/key in resources.provisioned_resource_store) + var/datum/robot_resource/resource = resources.provisioned_resource_store[key] + INJECT_STATPANEL_DATA_LINE(., "[resource.name]: [resource.amount]/[resource.amount_max]") /mob/living/silicon/robot/restrained() return 0 @@ -635,7 +660,7 @@ if(cell) to_chat(user, "You close the cover.") opened = 0 - updateicon() + update_icon() else if(wiresexposed && wires.is_all_cut()) //Cell is out, wires are exposed, remove MMI, produce damaged chassis, baleet original mob. if(!mmi) @@ -684,7 +709,7 @@ else to_chat(user, "You open the cover.") opened = 1 - updateicon() + update_icon() else if (istype(W, /obj/item/cell) && opened) // trying to put a cell inside var/datum/robot_component/C = components["power cell"] @@ -718,14 +743,13 @@ wiresexposed = !wiresexposed to_chat(user, "The wires have been [wiresexposed ? "exposed" : "unexposed"]") playsound(src, W.tool_sound, 50, 1) - updateicon() + update_icon() else if(W.is_screwdriver() && opened && cell) // radio if(radio) radio.attackby(W,user)//Push it to the radio to let it handle everything else to_chat(user, "Unable to locate a radio.") - updateicon() else if(W.is_wrench() && opened && !cell) if(bolt) @@ -756,38 +780,9 @@ if(allowed(usr)) locked = !locked to_chat(user, "You [ locked ? "lock" : "unlock"] [src]'s interface.") - updateicon() else to_chat(user, "Access denied.") - else if(istype(W, /obj/item/borg/upgrade/)) - var/obj/item/borg/upgrade/U = W - if(!opened) - to_chat(usr, "You must access the borgs internals!") - else if(!src.module && U.require_module) - to_chat(usr, "The borg must choose a module before it can be upgraded!") - else if(U.locked) - to_chat(usr, "The upgrade is locked and cannot be used yet!") - else - if(U.action(src)) - user.transfer_item_to_loc(U, src, INV_OP_FORCE) - to_chat(usr, "You apply the upgrade to [src]!") - else - to_chat(usr, "Upgrade error!") - - else if(istype(W, /obj/item/ka_modkit/)) - var/obj/item/ka_modkit/M = W - if(!opened) - to_chat(usr, "You must access the borgs internals!") - else if(!src.module && M.require_module) - to_chat(usr, "The borg must choose a module before it can be upgraded!") - else - if(M.install(src)) - user.transfer_item_to_loc(M, src, INV_OP_FORCE) - to_chat(usr, "You apply the modkit to [src]!") - else - to_chat(usr, "Upgrade error!") - else if( !(istype(W, /obj/item/robotanalyzer) || istype(W, /obj/item/healthanalyzer)) ) if(W.damage_force > 0) @@ -820,27 +815,8 @@ SPAN_WARNING("You successfully break your [bolt].")) bolt.malfunction = MALFUNCTION_PERMANENT - return - /mob/living/silicon/robot/proc/module_reset() - shown_robot_modules = FALSE - if (client) - hud_used.update_robot_modules_display() - transform_with_anim() - uneq_all() - modtype = initial(modtype) - hands.icon_state = initial(hands.icon_state) - - lights_on = FALSE - radio.set_light(0) - - notify_ai(ROBOT_NOTIFICATION_MODULE_RESET, module.name) - module.Reset(src) - - choose_icon(0, set_module_sprites(list("Default" = "robot"))) - - qdel(module) - module = null + notify_ai(ROBOT_NOTIFICATION_MODULE_RESET, module.get_display_name()) updatename("Default") /mob/living/silicon/robot/attack_hand(mob/user, datum/event_args/actor/clickchain/e_args) @@ -884,7 +860,7 @@ cell = null cell_component.wrapped = null cell_component.installed = 0 - updateicon() + update_icon() else if(cell_component.installed == -1) cell_component.installed = 0 var/obj/item/broken_device = cell_component.wrapped @@ -925,117 +901,6 @@ return 1 return 0 -/mob/living/silicon/robot/updateicon() - cut_overlays() - - if (dogborg) - zmm_flags |= ZMM_LOOKAHEAD - // Resting dogborgs don't get overlays. - if (stat == CONSCIOUS && resting) - if(sitting) - icon_state = "[module_sprites[icontype]]-sit" - else if(bellyup) - icon_state = "[module_sprites[icontype]]-bellyup" - else - icon_state = "[module_sprites[icontype]]-rest" - return - else - zmm_flags &= ~ZMM_LOOKAHEAD - - if(stat == CONSCIOUS) - if(!shell || deployed) // Shell borgs that are not deployed will have no eyes. - add_overlay(list( - "eyes-[module_sprites[icontype]]", - emissive_appearance(icon, "eyes-[module_sprites[icontype]]") - )) - - if(opened) - var/panelprefix = custom_sprite ? "[src.ckey]-[src.sprite_name]" : "ov" - if(wiresexposed) - add_overlay("[panelprefix]-openpanel +w") - else if(cell) - add_overlay("[panelprefix]-openpanel +c") - else - add_overlay("[panelprefix]-openpanel -c") - - if(has_active_type(/obj/item/borg/combat/shield)) - var/obj/item/borg/combat/shield/shield = locate() in src - if(shield && shield.active) - add_overlay("[module_sprites[icontype]]-shield") - - if(modtype == "Combat") - if(module_active && istype(module_active,/obj/item/borg/combat/mobility)) - icon_state = "[module_sprites[icontype]]-roll" - else - icon_state = module_sprites[icontype] - - if (dogborg) - if (stat == CONSCIOUS) - icon_state = "[module_sprites[icontype]]" - if(sleeper_g) - var/state = "[module_sprites[icontype]]-sleeper_g" - if (icon_exists(icon, state, FALSE)) - add_overlay(state) - else - // This one seems to always be present. - add_overlay("[module_sprites[icontype]]-sleeper_r") - if(sleeper_r) - add_overlay("[module_sprites[icontype]]-sleeper_r") - - if(istype(module_active, /obj/item/gun/projectile/energy/taser/mounted/cyborg)) - add_overlay("taser") - else if(istype(module_active, /obj/item/gun/projectile/energy/laser/mounted)) - add_overlay("laser") - else if(istype(module_active, /obj/item/gun/projectile/energy/taser/xeno/robot)) - add_overlay("taser") - - if(lights_on) - add_overlay("eyes-[module_sprites[icontype]]-lights") - - else if (stat == DEAD) - icon_state = "[module_sprites[icontype]]-wreck" - add_overlay("wreck-overlay") - -/mob/living/silicon/robot/proc/installed_modules() - if(weapon_lock) - to_chat(src, "Weapon lock active, unable to use modules! Count:[weaponlock_time]") - return - - if(!module) - pick_module() - return - var/dat = "Modules\n" - dat += {" - Activated Modules -
- Module 1: [module_state_1 ? "[module_state_1]" : "No Module"]
- Module 2: [module_state_2 ? "
[module_state_2]" : "No Module"]
- Module 3: [module_state_3 ? "
[module_state_3]" : "No Module"]
-
- Installed Modules

"} - - - for (var/obj in module.modules) - if (!obj) - dat += "Resource depleted
" - else if(activated(obj)) - dat += "[obj]: Activated
" - else - dat += "[obj]:
Activate
" - if (emagged || emag_items) - if(activated(module.emag)) - dat += "[module.emag]: Activated
" - else - dat += "[module.emag]: Activate
" -/* - if(activated(obj)) - dat += "[obj]: \[Activated | Deactivate\]
" - else - dat += "[obj]: \[Activate | Deactivated\]
" -*/ - src << browse(dat, "window=robotmod") - - /mob/living/silicon/robot/Topic(href, href_list) if(..()) return 1 @@ -1048,65 +913,6 @@ subsystem_alarm_monitor() return 1 - if (href_list["mod"]) - var/obj/item/O = locate(href_list["mod"]) - if (istype(O) && (O.loc == src)) - O.attack_self(src) - return 1 - - if (href_list["act"]) - var/obj/item/O = locate(href_list["act"]) - if (!istype(O)) - return 1 - - if(!((O in src.module.modules) || (O == src.module.emag))) - return 1 - - if(activated(O)) - to_chat(src, "Already activated") - return 1 - if(!module_state_1) - module_state_1 = O - O.hud_layerise() - contents += O - if(istype(module_state_1,/obj/item/borg/sight)) - sight_mode |= module_state_1:sight_mode - else if(!module_state_2) - module_state_2 = O - O.hud_layerise() - contents += O - if(istype(module_state_2,/obj/item/borg/sight)) - sight_mode |= module_state_2:sight_mode - else if(!module_state_3) - module_state_3 = O - O.hud_layerise() - contents += O - if(istype(module_state_3,/obj/item/borg/sight)) - sight_mode |= module_state_3:sight_mode - else - to_chat(src, "You need to disable a module first!") - installed_modules() - return 1 - - if (href_list["deact"]) - var/obj/item/O = locate(href_list["deact"]) - if(activated(O)) - if(module_state_1 == O) - module_state_1 = null - contents -= O - else if(module_state_2 == O) - module_state_2 = null - contents -= O - else if(module_state_3 == O) - module_state_3 = null - contents -= O - else - to_chat(src, "Module isn't activated.") - else - to_chat(src, "Module isn't activated") - installed_modules() - return 1 - if(href_list["character_profile"]) if(!profile) profile = new(src) @@ -1119,56 +925,49 @@ /mob/living/silicon/robot/Moved() . = ..() - if(module) - if(module.type == /obj/item/robot_module/robot/janitor || scrubbing) - var/turf/tile = loc - var/datum/matter_synth/water = water_res - if(isturf(tile) && ((!scrubbing) || (water && water.use_charge(1)))) - //Got a tile to clean, and we use the simple logic, or we check and use water - tile.clean_blood() - if (istype(tile, /turf/simulated)) - var/turf/simulated/S = tile - S.dirt = 0 - for(var/A in tile) - if(istype(A, /obj/effect)) - if(istype(A, /obj/effect/rune) || istype(A, /obj/effect/debris/cleanable) || istype(A, /obj/effect/overlay)) - qdel(A) - else if(istype(A, /obj/item)) - var/obj/item/cleaned_item = A - cleaned_item.clean_blood() - else if(istype(A, /mob/living/carbon/human)) - var/mob/living/carbon/human/cleaned_human = A - if(cleaned_human.lying) - if(cleaned_human.head) - cleaned_human.head.clean_blood() - cleaned_human.update_inv_head(0) - if(cleaned_human.wear_suit) - cleaned_human.wear_suit.clean_blood() - cleaned_human.update_inv_wear_suit(0) - else if(cleaned_human.w_uniform) - cleaned_human.w_uniform.clean_blood() - cleaned_human.update_inv_w_uniform(0) - if(cleaned_human.shoes) - cleaned_human.shoes.clean_blood() - cleaned_human.update_inv_shoes(0) - cleaned_human.clean_blood(1) - to_chat(cleaned_human, "[src] cleans your face!") - - //Borgs and drones can use their mining bags ~automagically~ if they're deployed in a slot. Only mining bags, as they're optimized for mass use. - var/obj/item/storage/bag/ore/B = null - if(istype(module_state_1, /obj/item/storage/bag/ore)) //First orebag has priority, if they for some reason have multiple. - B = module_state_1 - else if(istype(module_state_2, /obj/item/storage/bag/ore)) - B = module_state_2 - else if(istype(module_state_3, /obj/item/storage/bag/ore)) - B = module_state_3 + if(legacy_floor_scrubbing) var/turf/tile = loc - if(B && isturf(tile)) - B.obj_storage.interacted_mass_pickup(new /datum/event_args/actor(src), tile) + if(isturf(tile)) + tile.clean_blood() + if (istype(tile, /turf/simulated)) + var/turf/simulated/S = tile + S.dirt = 0 + for(var/A in tile) + if(istype(A, /obj/effect)) + if(istype(A, /obj/effect/rune) || istype(A, /obj/effect/debris/cleanable) || istype(A, /obj/effect/overlay)) + qdel(A) + else if(istype(A, /obj/item)) + var/obj/item/cleaned_item = A + cleaned_item.clean_blood() + else if(istype(A, /mob/living/carbon/human)) + var/mob/living/carbon/human/cleaned_human = A + if(cleaned_human.lying) + if(cleaned_human.head) + cleaned_human.head.clean_blood() + cleaned_human.update_inv_head(0) + if(cleaned_human.wear_suit) + cleaned_human.wear_suit.clean_blood() + cleaned_human.update_inv_wear_suit(0) + else if(cleaned_human.w_uniform) + cleaned_human.w_uniform.clean_blood() + cleaned_human.update_inv_w_uniform(0) + if(cleaned_human.shoes) + cleaned_human.shoes.clean_blood() + cleaned_human.update_inv_shoes(0) + cleaned_human.clean_blood(1) + to_chat(cleaned_human, "[src] cleans your face!") + + for(var/obj/item/storage/bag/ore/ore_bag in inventory.get_held_items()) + if(ore_bag) + if(isturf(loc)) + var/turf/tile = loc + ore_bag.obj_storage?.interacted_mass_pickup(new /datum/event_args/actor(src), tile) + break /mob/living/silicon/robot/proc/self_destruct() + // explosion readd: back to the old days of blowing borgs lmfao who nerfed this + explosion(get_turf(src), 0, 0, 3) gib() - return /mob/living/silicon/robot/proc/UnlinkSelf() disconnect_from_ai() @@ -1182,7 +981,6 @@ if(src.camera) src.camera.clear_all_networks() - /mob/living/silicon/robot/proc/ResetSecurityCodes() set category = "Robot Commands" set name = "Reset Identity Codes" @@ -1203,42 +1001,6 @@ lockcharge = state update_mobility() -/mob/living/silicon/robot/proc/choose_icon(var/triesleft, var/list/module_sprites) - if(!module_sprites.len) - to_chat(src, "Something is badly wrong with the sprite selection. Harass a coder.") - return - - icon_selected = 0 - src.icon_selection_tries = triesleft - if(module_sprites.len == 1 || !client) - if(!(icontype in module_sprites)) - icontype = module_sprites[1] - else - icontype = input("Select an icon! [triesleft ? "You have [triesleft] more chance\s." : "This is your last try."]", "Robot Icon", icontype, null) in module_sprites - if(notransform) - to_chat(src, "Your current transformation has not finished yet!") - choose_icon(icon_selection_tries, module_sprites) - return - else - transform_with_anim() - - if(icontype == "Custom") - icon = CUSTOM_ITEM_SYNTH - else // This is to fix an issue where someone with a custom borg sprite chooses a non-custom sprite and turns invisible. - icon_state = module_sprites[icontype] - updateicon() - - if (module_sprites.len > 1 && triesleft >= 1 && client) - icon_selection_tries-- - var/choice = input("Look at your icon - is this what you want?") in list("Yes","No") - if(choice=="No") - choose_icon(icon_selection_tries, module_sprites) - return - - icon_selected = 1 - icon_selection_tries = 0 - to_chat(src, "Your icon has been set. You now require a module reset to change it.") - /mob/living/silicon/robot/proc/sensor_mode() //Medical/Security HUD controller for borgs set name = "Set Sensor Augmentation" set category = "Robot Commands" @@ -1255,20 +1017,11 @@ // Uses power from cyborg's cell. Returns 1 on success or 0 on failure. // Properly converts using CELLRATE now! Amount is in Joules. -/mob/living/silicon/robot/proc/cell_use_power(var/amount = 0) - // No cell inserted - if(!cell) - return 0 - - // Power cell is empty. - if(cell.charge == 0) - return 0 - - var/power_use = amount * CYBORG_POWER_USAGE_MULTIPLIER - if(cell.checked_use(DYNAMIC_W_TO_CELL_UNITS(power_use, 1))) - used_power_this_tick += power_use - return 1 - return 0 +/mob/living/silicon/robot/proc/legacy_cell_use_power(var/amount = 0) + if(!amount) + return TRUE + . = draw_checked_power(amount) + return . ? TRUE : FALSE /mob/living/silicon/robot/binarycheck() if(get_restraining_bolt()) @@ -1330,12 +1083,11 @@ return if(opened)//Cover is open - if(emagged) return//Prevents the X has hit Y with Z message also you cant emag them twice + if(emagged) + return//Prevents the X has hit Y with Z message also you cant emag them twice if(wiresexposed) to_chat(user, "You must close the panel first") return - - // The block of code below is from TG. Feel free to replace with a better result if desired. if(shell) // AI shells cannot be emagged, so we try to make it look like a standard reset. Smart players may see through this, however. to_chat(user, SPAN_DANGER("[src] is remotely controlled! Your emag attempt has triggered a system reset instead!")) @@ -1353,7 +1105,7 @@ log_game("[key_name(user)] emagged cyborg [key_name(src)]. Laws overridden.") clear_supplied_laws() clear_inherent_laws() - laws = new /datum/ai_laws/syndicate_override + laws = new /datum/ai_lawset/syndicate var/time = time2text(world.realtime,"hh:mm:ss") lawchanges.Add("[time] : [user.name]([user.key]) emagged [name]([key])") var/datum/gender/TU = GLOB.gender_datums[user.get_visible_gender()] @@ -1381,12 +1133,11 @@ to_chat(src, "Obey these laws:") laws.show_laws(src) to_chat(src, "ALERT: [user.real_name] is your new master. Obey your new laws and [TU.his] commands.") - updateicon() + return 1 else to_chat(user, "You fail to hack [src]'s interface.") to_chat(src, "Hack attempt detected.") - return 1 - return + return /mob/living/silicon/robot/is_sentient() return braintype != BORG_BRAINTYPE_DRONE @@ -1403,39 +1154,14 @@ return return feed_grabbed_to_self(src,T) -/mob/living/silicon/robot/proc/rest_style() - set name = "Switch Rest Style" - set category = VERB_CATEGORY_IC - set desc = "Select your resting pose." - sitting = FALSE - bellyup = FALSE - var/choice = alert(src, "Select resting pose", "", "Resting", "Sitting", "Belly up") - switch(choice) - if("Resting") - return 0 - if("Sitting") - sitting = TRUE - if("Belly up") - bellyup = TRUE - -/mob/living/silicon/robot/proc/ex_reserve_refill() - set name = "Refill Extinguisher" - set category = VERB_CATEGORY_OBJECT - var/datum/matter_synth/water = water_res - for(var/obj/item/extinguisher/E in module.modules) - if(E.reagents.total_volume < E.max_water) - if(water && water.energy > 0) - var/amount = E.max_water - E.reagents.total_volume - if(water.energy < amount) - amount = water.energy - water.use_charge(amount) - E.reagents.add_reagent("water", amount) - to_chat(src, "You refill the extinguisher using your water reserves.") - else - to_chat(src, "Insufficient water reserves.") - /mob/living/silicon/robot/canUseTopic(atom/movable/M, be_close=FALSE, no_dexterity=FALSE, no_tk=FALSE) if(lockcharge) to_chat(src, SPAN_WARNING("You can't do that right now!")) return FALSE return ..() + +//* Mobility *// + +/mob/living/silicon/robot/set_resting(value) + . = ..() + update_icon() diff --git a/code/modules/mob/living/silicon/robot/robot_chassis.dm b/code/modules/mob/living/silicon/robot/robot_chassis.dm new file mode 100644 index 00000000000..5c02fb339e7 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/robot_chassis.dm @@ -0,0 +1,82 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2024 Citadel Station Developers *// + +/** + * The baseline physical chassis for a silicon. + * + * * This is considered intrinsic, and cannot be changed on a robot without fully rebuilding its state. + * + * Contains: + * + * * Base physical stats + * * Internal slots / space / interconnects + * * WIP + */ +/datum/prototype/robot_chassis + abstract_type = /datum/prototype/robot_chassis + + /// our name + var/name = "???" + /// items to inject into normal out + /// * paths are allowed + /// * anonymous types are allowed + /// * item instances are **not allowed** and will result in shit exploding! + var/list/mounted_item_descriptor_inject_normal + /// items to inject into emag out + /// * paths are allowed + /// * anonymous types are allowed + /// * item instances are **not allowed** and will result in shit exploding! + var/list/mounted_item_descriptor_inject_emag + +/datum/prototype/robot_chassis/proc/create_provisioning() as /datum/robot_provisioning + var/datum/robot_provisioning/creating = new + . = creating + var/list/i_normal = list() + var/list/i_emag = list() + create_mounted_item_descriptors(i_normal, i_emag) + for(var/obj/item/descriptor as anything in i_normal) + var/obj/item/resolved + if(istype(descriptor)) + resolved = descriptor + else if(ispath(descriptor)) + resolved = new descriptor + else if(IS_ANONYMOUS_TYPEPATH(descriptor)) + resolved = new descriptor + else + stack_trace("invalid descriptor [descriptor] on [id] ([type])") + continue + creating.add_item(resolved) + for(var/obj/item/descriptor as anything in i_emag) + var/obj/item/resolved + if(istype(descriptor)) + resolved = descriptor + else if(ispath(descriptor)) + resolved = new descriptor + else if(IS_ANONYMOUS_TYPEPATH(descriptor)) + resolved = new descriptor + else + stack_trace("invalid descriptor [descriptor] on [id] ([type])") + continue + creating.add_emag_item(resolved) + +/** + * Returns a list of descriptors for mounted items + * + * A descriptor can be: + * * An item instance + * * An item path + * * An anonymous type of an item + * + * It's recommended to use item path, then anonymous types, and lastly, item instances. + * Item instances should be created in nullspace. + * + * The caller must handle all of these. + * Unused item instances must be qdel'd. + */ +/datum/prototype/robot_chassis/proc/create_mounted_item_descriptors(list/normal_out, list/emag_out) + if(normal_out) + if(mounted_item_descriptor_inject_normal) + normal_out |= mounted_item_descriptor_inject_normal + if(emag_out) + if(mounted_item_descriptor_inject_emag) + emag_out |= mounted_item_descriptor_inject_emag diff --git a/code/modules/mob/living/silicon/robot/robot_flashlights.dm b/code/modules/mob/living/silicon/robot/robot_flashlights.dm deleted file mode 100644 index 6659feedb54..00000000000 --- a/code/modules/mob/living/silicon/robot/robot_flashlights.dm +++ /dev/null @@ -1,250 +0,0 @@ -// This is split into its own file because this list is huge. -// Indexing by icon's not great, but c'est la vie. -// Ideally there'd be a way to attach metadata to borg sprites, but they seem to be defined as a KV list. - -GLOBAL_LIST_INIT(borg_light_color_lut, list( - 'icons/mob/robots.dmi' = list( - "robot" = "#00A7B9", - "worm-standard" = "#0094A4", - "landmate" = "#00E57E", - "mopgearrex" = "#00D877", - "Miner" = "#33FF99", - "droid-miner" = "#02DAD8", - "droid-medical" = "#02DAD8", - "droid" = "#D5EFF6", - "droid-combat" = "#DA0205", - "repairbot" = "#4DEFFF", - "constructiondrone" = "#4DEFFF", - "miningdrone" = "#4DEFFF", - "drone-standard" = "#00A7B9", - "drone-engineer" = "#FFFF00", - "drone-miner" = "#CC33CC", - "drone-janitor" = "#00FFFF", - "drone-medical" = "#66FFFF", - "drone-surgery" = "#FF0000", - "drone-sec" = "#FF0000", - "drone-service" = "#FFFF00", - "drone-lost" = "#FFFF00", - "engiborg+tread" = "#00FF33", - "drone-chemistry" = "#FFFF00", - "drone-science" = "#CC33CC", - "drone-hydro" = "#00FFFF", - "drone-blu" = "#FFFF00", - "droid-science" = "#CC33CC", - "eyebot-engineering" = "#FFD800", - "eyebot-janitor" = "#CC60FF", - "eyebot-medical" = "#0094FF", - "eyebot-miner" = "#00E51A", - "eyebot-science" = "#CC60FF", - "eyebot-sceurity" = "#FF0000", - "eyebot-standard" = "#00E51A", - "heavyStandard" = "#30C5FC", - "heavyMed" = "#30C5FC", - "heavyServ" = "#6AED63", - "heavySec" = "#E48600", - "heavyEng" = "#74FEB5", - "heavyMiner" = "#E24BEB", - "heavyRes" = "#E48600", - "marinaSV" = "#4CE1EC", - "marinaMN" = "#FBE281", - "marinaSC" = "#FFB300", - "marinaENG" = "#00FF48", - "marinaJN" = "#5BEAFF", - "marinaSD" = "#87EAFF", - "marinaSCI" = "#87EAFF", - "marinaMD" = "#4B4B8F", - "marinaCB" = "#FF0000", - "sleekhos" = "#FF0000", - "sleekCMO" = "#0099FF", - "sleekCE" = "#0099FF", - "sleekclerical" = "#00FFFF", - "sleekscience" = "#00FFFF", - "sleekstandard" = "#00FFFF", - "sleekservice" = "#00FFFF", - "sleekjanitor" = "#00FFFF", - "sleekmedic" = "#00FFFF", - "sleeksecurity" = "#00FFFF", - "sleekminer" = "#00FFFF", - "robotSecy" = "#00A7B9", - "robotMedi" = "#00A7B9", - "robotEngi" = "#00A7B9", - "robotJani" = "#00A7B9", - "robotServ" = "#00A7B9", - "robotCler" = "#00A7B9", - "spider" = "#0DD963", - "spidereng" = "#0DD963", - "spidermining" = "#0DD963", - "spiderscience" = "#0DD963", - "spidersec" = "#A8D90D", - "spidercom" = "#A8D90D", - "spidersyndi" = "E6290F", - "arachne" = "#06EA56", - "omoikane" = "#00F8F8", - "peaceborg" = "#F0F0F0", - "tallblue" = "#86FEFA", - "tallyellow" = "#00C8E2", - "tallflower" = "#00FFF6", - "tallgreen" = "#C7F6F3", - "tallred" = "#FFB300", - "tallwhite" = "#CCFFFF", - "tall2miner" = "#00CC00", - "tall2engineer" = "#00C8E2", - "tall2service" = "#00FFF6", - "tall2janitor" = "#C7F6F3", - "tall2security" = "#FFFF00", - "tall2medical" = "#33CCFF", - "tall2standard" = "#33CCFF", - "tall2peace" = "#66FFFF", - "tall2clown" = "#0000FF", - "tolietbot" = "#027EBE", - "tolietbotminer" = "#027EBE", - "tolietbotengineering" = "#027EBE", - "tolietbotmedical" = "#CED2D9", - "tolietbotsecurity" = "#027EBE", - "tolietbotjanitor" = "#027EBE", - "tolietbotsurgeon" = "#CED2D9", - "tolietbotantag" = "#FF0000", - "syndie" = "#F03333", - "bloodhound" = "#006FBF", - "treadhound" = "#006FBF", - "squats" = "#33CC00", - "treadwell" = "#00FF33", - "whitespider" = "#00CEF6", - "crawler" = "#A0E7F5", - "maidbot" = "#5BEAFF", - "handy-engineer" = "#FFCC00", - "handy-med" = "#00CCFF", - "drone-gravekeeper" = "#00A7B9", - "sleek-gravekeeper" = "#00FFFF", - "insekt-combat" = "#CC9900", - "insekt-sec" = "#CC9900", - "insekt-default" = "#00CC00", - "insekt-sci" = "#00CC00", - "insekt-med" = "#0099FF", - "Glitterfly-Standard" = "#F953CD", - "Glitterfly-Service" = "#FDE96B", - "Glitterfly-Surgeon" = "#8ACCFF", - "Glitterfly-Crisis" = "#FDE96B", - "Glitterfly-Engineering" = "#DADF84", - "Glitterfly-Janitor" = "#AD7EFF", - "Glitterfly-Mining" = "#7EBC68", - "Glitterfly-Research" = "#E7F8FF", - "Glitterfly-Security" = "#33223B", - "Glitterfly-Clerical" = "#87C877", - "decapod-Standard" = "#33CCFF", - "decapod-Research" = "#CC00FF", - "decapod-Surgeon" = "#6AFF6A", - "decapod-Crisis" = "#FF3232", - "decapod-Engineering" = "#FF9900", - "decapod-Janitor" = "#FF0099", - "decapod-Miner" = "#00FF00", - "decapod-Security" = "#C60200", - "decapod-Service" = "#FFFF00", - "decapod-Clerical" = "#CC00FF", - "decapod-Combat" = "#FF0000", - "eyebot-combat" = "#FF0000", - "miss-standard" = "#B0CCDF", - "miss-engineer" = "#FFCCB9", - "miss-medical" = "#8EEE60", - "miss-miner" = "#FF8858", - "miss-service" = "#B0CCDF", - "miss-janitor" = "#8EEE60", - "miss-security" = "#B472C6", - "xeightyeight-standard" = "#FF9900", - "xeightyeight-engineering" = "#FF9900", - "xeightyeight-science" = "#F2D590", - "xeightyeight-medical" = "#F2D590", - "handy-hydro" = "#FFFF55", - "handy-clerk" = "#82FFF9", - "handy-janitor" = "#FF55D9", - "handy-service" = "#F4F4F4", - "handy-miner" = "#82FF88", - "handy-sec" = "#FF373D", - "handy-standard" = "#E9E9E9", - "mechoid-Standard" = "#33FFFF", - "mechoid-Service" = "#FFFF00", - "mechoid-Miner" = "#00FF00", - "mechoid-Medical" = "#33FFFF", - "mechoid-Engineering" = "#FF6600", - "mechoid-Security" = "#C60200", - "mechoid-Janitor" = "#33FFFF", - "mechoid-Combat" = "#C60200", - "mechoid-Science" = "#CC00FF", - "Noble-STD" = "#4CFF00", - "Noble-CLN" = "#4CFF00", - "Noble-SRV" = "#4CFF00", - "Noble-DIG" = "#4CFF00", - "Noble-MED" = "#4CFF00", - "Noble-SEC" = "#4CFF00", - "Noble-ENG" = "#4CFF00", - "corrupt-repairbot" = "#FF0033", - "zoomba-standard" = "#FFFFFF", - "zoomba-clerical" = "#FFFF2E", - "zoomba-engineering" = "#D6A52E", - "zoomba-janitor" = "#FF3F3A", - "zoomba-medical" = "#68F1FF", - "zoomba-crisis" = "#EC2E31", - "zoomba-miner" = "#7D568F", - "zoomba-research" = "#822EFA", - "zoomba-security" = "#E52E2E", - "zoomba-service" = "#2EFFFF", - "zoomba-combat" = "#E52E2E", - "worm-standard" = "#0094A4", - "worm-engineering" = "#0094A4", - "worm-janitor" = "#0094A4", - "worm-crisis" = "#0094A4", - "worm-miner" = "#0094A4", - "worm-security" = "#0094A4", - "worm-combat" = "#0094A4", - "worm-surgeon" = "#0094A4", - "worm-service" = "#0094A4" - ), - 'icons/mob/robots_wide.dmi' = list( - "blade" = "#FF6AA0", - "stray" = "#990033", - "borgi" = "#FFFDD6", - "k9" = "#FFF2BC", - "medihound" = "#C3D9E6", - "k69" = "#FFF2BC", - "k92" = "#FF6633", - "medihounddark" = "#C3D9E6", - "engihound" = "#A6F0A9", - "engihounddark" = "#61DD35", - "scrubpup" = "#43D715", - "vale" = "#7BEBC9", - "science" = "#9754B8", - "scihound" = "#9B3FE9", - "scihounddark" = "#D864DA", - "secborg" = "#E85656", - "thottbot" = "#64FE3E", - "k50" = "#C3D9E6", - "kmine" = "#AA62BE", - "cargohounddark" = "#BFB275", - "cargohound" = "#D6A75C", - "serve2" = "#43D715", - "servedark" = "#43D715", - "alina-eng" = "#64FE3E", - "alina-sec" = "#E85656", - "alina-med" = "#88C1D1", - "borgi-eng" = "#FFFDD6", - "borgi-jani" = "#FFFDD6", - "borgi-medi" = "#FFFDD6", - "borgi-sci" = "#FFFDD6", - "borgi-sec" = "#FFFDD6", - "otiej" = "#FEFFC3", - "oties" = "#FBC6CA", - "J9" = "#FFFF33", - "FELI-Standard" = "#FFFDD6", - "FELI-Engineer" = "#FFFDD6", - "FELI-Medical" = "#FFFDD6", - "FELI-Research" = "#FFFDD6", - "FELI-Mining" = "#FFFDD6", - "FELI-Service" = "#FFFDD6", - "FELI-Janitor" = "#FFFDD6", - "FELI-Security" = "#FFFDD6", - "FELI-Combat" = "#FFFDD6", - ), - 'icons/mob/62x62robot_vr.dmi' = list( - "ert" = "#EA00CB" - ) -)) diff --git a/code/modules/mob/living/silicon/robot/robot_frame.dm b/code/modules/mob/living/silicon/robot/robot_frame.dm new file mode 100644 index 00000000000..99afab966b4 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/robot_frame.dm @@ -0,0 +1,30 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2024 Citadel Station Developers *// + +/** + * A frame is a chassis-iconset tuple. + * + * * This is the thing you can actually choose as a player. + * * This is a thing because icon and chassis are generally disjoint; you don't + * want to constrain sprite design to a single functionality, necessarily. + * Thus, another layer of abstraction was added. + */ +/datum/robot_frame + abstract_type = /datum/robot_frame + + /// our name + var/name + /// our iconset + /// * set to typepath; resolved on init. + var/datum/prototype/robot_iconset/robot_iconset + /// our chassis + /// * set to typepath; resolved on init. + var/datum/prototype/robot_chassis/robot_chassis + + /// Lock to ckeys, if set + var/list/ckey_lock + +/datum/robot_frame/New() + // todo: DB pull if needed + robot_iconset = RSrobot_iconsets.fetch_local_or_throw(robot_iconset) + robot_chassis = RSrobot_chassis.fetch_local_or_throw(robot_chassis) diff --git a/code/modules/mob/living/silicon/robot/robot_iconset.dm b/code/modules/mob/living/silicon/robot/robot_iconset.dm new file mode 100644 index 00000000000..35f1f27513d --- /dev/null +++ b/code/modules/mob/living/silicon/robot/robot_iconset.dm @@ -0,0 +1,84 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2024 Citadel Station Developers *// + +/** + * Base abstraction for silicon iconsets + * + * * Iconsets have no behavior. + * * This is not considered intrinsic for a robot's behavior, and therefore can be changed without a full state rebuild. + * + * todo: please give ids to all of this.. + */ +/datum/prototype/robot_iconset + abstract_type = /datum/prototype/robot_iconset + anonymous = TRUE + anonymous_namespace = "robot_iconset" + + /// the name of this iconset + var/name + /// the display name of this iconset + /// * this is player facing! + /// * defaults to [name] + var/display_name + + /// the path, id, or instance of robot chassis we are supposed to be + /// * this is not enforced, this is used for auto-gen + var/auto_chassis + + /// icon + var/icon + + /// base icon state + var/icon_state + /// primary indicator lighting overlay state + /// * if null, we do not have primary lighting indicators. + var/icon_state_indicator + /// cover open overlay base state + /// + /// * if null, we do not have a cover open state. + /// * ffs this should never be null! + /// + /// appends: + /// * "-cell" if cell is in + /// * "-empty" if cell is out + /// * "-wires" if wires are exposed + var/icon_state_cover + + /// Icon width + var/icon_dimension_x = 32 + /// Icon height + var/icon_dimension_y = 32 + + /// indicator lighting colorable? + /// * for now, only supports NONE and MULTIPLY + var/indicator_lighting_coloration_mode = COLORATION_MODE_NONE + /// indicator lighting packed coloration + /// * for now, only supports a single RRGGBB(AA) string. + var/indicator_lighting_coloration_packed = "#ffffff" + + /// variations + /// * this is a list of typepaths / anonymous types at compile time, and + /// turned into an id-instance lookup map at init. + /// + /// special ones: + /// * /datum/robot_iconset_variation/dead + /// * /datum/robot_iconset_variation/resting + /// * /datum/robot_iconset_variation/sitting + /// * /datum/robot_iconset_variation/bellyup + var/list/variations + +/datum/prototype/robot_iconset/New() + ..() + for(var/i in 1 to length(variations)) + var/datum/robot_iconset_variation/maybe_variation = variations[i] + if(ispath(maybe_variation)) + maybe_variation = new maybe_variation + else if(IS_ANONYMOUS_TYPEPATH(maybe_variation)) + maybe_variation = new maybe_variation + else if(istype(maybe_variation)) + else + stack_trace("invalid variation in index [i] on [type] ([id])") + variations[maybe_variation.id] = maybe_variation + +/datum/prototype/robot_iconset/proc/get_display_name() + return display_name || name diff --git a/code/modules/mob/living/silicon/robot/robot_iconset_variation.dm b/code/modules/mob/living/silicon/robot/robot_iconset_variation.dm new file mode 100644 index 00000000000..0119f189a81 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/robot_iconset_variation.dm @@ -0,0 +1,54 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2024 Citadel Station Developers *// + +/** + * Things to note: + * * indicator state must be set for us to have primary lighting indicator + emissives while using this variation + * * cover state must be set for ... (you get the deal) + */ +/datum/robot_iconset_variation + /// id; must be unique + var/id + + /// icon override + /// * applies to **all** overlays + var/icon_override + + /// state override + /// * overrides [icon_state_append] + var/icon_state + /// state append to override our state with + var/icon_state_append + /// primary indicator lighting overlay override state + /// * overrides [icon_state_indicator_append] + var/icon_state_indicator + /// state append to override our indicator state with + /// * this is applied to our resultant icon state + var/icon_state_indicator_append + /// cover overlay override state + /// * overrides [icon_state_cover_append] + var/icon_state_cover + /// state append to override our cover state with + var/icon_state_cover_append + + /// is the player allowed to choose it while resting? + var/alt_resting_state = FALSE + +/datum/robot_iconset_variation/dead + id = "dead" + icon_state_append = "-dead" + +/datum/robot_iconset_variation/resting + id = "resting" + icon_state_append = "-rest" + alt_resting_state = TRUE + +/datum/robot_iconset_variation/sitting + id = "sitting" + icon_state_append = "-sit" + alt_resting_state = TRUE + +/datum/robot_iconset_variation/bellyup + id = "bellyup" + icon_state_append = "-bellyup" + alt_resting_state = TRUE diff --git a/code/modules/mob/living/silicon/robot/robot_inventory.dm b/code/modules/mob/living/silicon/robot/robot_inventory.dm new file mode 100644 index 00000000000..0e41115f4f2 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/robot_inventory.dm @@ -0,0 +1,164 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2025 Citadel Station Developers *// + +/** + * Robot inventories; separate from /datum/inventory, which is a slot-and-hands system. + * * Thus, robot modules don't count as actually in inventory unless they're equipped. + * This is kinda bad, but, the other option is worse (bolting this onto `/datum/inventory`) + * + * Implementation guidelines: + * + * * Modules can never be dropped or taken out of the mob. + * * Modules automatically return to the mob when being unequipped. + * * Modules must always be in the mob, location-wise. If it's ever removed, it will be + * **dropped** by the robot inventory datum. + */ +/datum/robot_inventory + /// Owner + /// * This is generic, and can technically work for non-silicon mobs + var/mob/living/silicon/robot/owner + /// registered items + /// * Things in-hand are still registered. + var/list/obj/item/provided_items + /// actor HUDs using us + /// * Lazy list + var/list/datum/actor_hud/robot_inventory/huds_using + /// our item mount + var/datum/item_mount/item_mount + +/datum/robot_inventory/New(mob/living/silicon/robot/owner) + src.owner = owner + item_mount = new + item_mount.relay_to(owner.resources.item_mount) + +/datum/robot_inventory/Destroy() + if(owner) + if(owner.robot_inventory == src) + owner.robot_inventory = null + owner = null + for(var/obj/item/item in provided_items) + inv_unregister(item) + provided_items = null + for(var/datum/actor_hud/robot_inventory/hud in huds_using) + hud.unbind_from_inventory(src) + huds_using = null + QDEL_NULL(item_mount) + return ..() + +//* Get *// + +/** + * Gets all robot modules registered. + */ +/datum/robot_inventory/proc/inv_get_all() as /list + SHOULD_NOT_OVERRIDE(TRUE) + SHOULD_NOT_SLEEP(TRUE) + return provided_items ? provided_items.Copy() : list() + +/** + * Gets all robot modules active. + */ +/datum/robot_inventory/proc/inv_get_active() as /list + SHOULD_NOT_OVERRIDE(TRUE) + SHOULD_NOT_SLEEP(TRUE) + . = list() + for(var/obj/item/item as anything in provided_items) + if(isnum(item.inv_slot_or_index)) + . += item + +//* Check *// + +/** + * Checks if an item is registered to us as a robot module. + * + * @return TRUE if module, FALSE otherwise + */ +/datum/robot_inventory/proc/inv_is_registered(obj/item/item) + SHOULD_NOT_OVERRIDE(TRUE) + SHOULD_NOT_SLEEP(TRUE) + return item in provided_items + +//* Registration *// + +/** + * Registers an item as a robot module. + * + * * Item must not be in an inventory, even ourselves. + * * The item will be moved into our owner. + * + * @return TRUE success, FALSE fail + */ +/datum/robot_inventory/proc/inv_register(obj/item/item) + SHOULD_NOT_OVERRIDE(TRUE) + SHOULD_NOT_SLEEP(TRUE) + + if(item in provided_items) + return TRUE + if(item.inv_inside) + // TODO: this is shitcode + item.forceMove(owner) + if(item.inv_inside) + stack_trace("failed to kick item out of existing inv in robot_module_register") + return FALSE + + item.forceMove(owner) + LAZYADD(provided_items, item) + if(!item.item_mount) + item.mount(src.item_mount) + on_inv_register(item) + return TRUE + +/** + * Unregisters an item from being a robot module. + * * You have to move it out of the inventory / mob after! + */ +/datum/robot_inventory/proc/inv_unregister(obj/item/item) + SHOULD_NOT_OVERRIDE(TRUE) + SHOULD_NOT_SLEEP(TRUE) + + if(!(item in provided_items)) + return + LAZYREMOVE(provided_items, item) + if(item.item_mount == src.item_mount) + item.unmount() + on_inv_unregister(item) + +/datum/robot_inventory/proc/on_inv_register(obj/item/item) + PROTECTED_PROC(TRUE) + SHOULD_CALL_PARENT(TRUE) + + RegisterSignal(item, COMSIG_ITEM_PICKUP, PROC_REF(handle_item_pickup)) + RegisterSignal(item, COMSIG_ITEM_DROPPED, PROC_REF(handle_item_drop)) + RegisterSignal(item, COMSIG_PARENT_QDELETING, PROC_REF(handle_item_del)) + + for(var/datum/actor_hud/robot_inventory/hud as anything in huds_using) + hud.drawer_backplate?.redraw() + item.vis_flags |= VIS_INHERIT_LAYER | VIS_INHERIT_PLANE + item.auto_pixel_offset_to_center() + +/datum/robot_inventory/proc/on_inv_unregister(obj/item/item) + PROTECTED_PROC(TRUE) + SHOULD_CALL_PARENT(TRUE) + + for(var/datum/actor_hud/robot_inventory/hud as anything in huds_using) + hud.drawer_backplate?.redraw() + item.vis_flags &= ~(VIS_INHERIT_LAYER | VIS_INHERIT_PLANE) + +/datum/robot_inventory/proc/handle_item_pickup(obj/item/source, ...) + // TODO: cleaner way to do this? + spawn(0) + for(var/datum/actor_hud/robot_inventory/inventory_hud as anything in huds_using) + inventory_hud?.drawer_backplate.redraw() + +/datum/robot_inventory/proc/handle_item_drop(obj/item/source, ...) + source.forceMove(owner) + source.vis_flags |= VIS_INHERIT_LAYER | VIS_INHERIT_PLANE + source.auto_pixel_offset_to_center() + // TODO: cleaner way to do this? + spawn(0) + for(var/datum/actor_hud/robot_inventory/inventory_hud as anything in huds_using) + inventory_hud?.drawer_backplate.redraw() + return COMPONENT_ITEM_DROPPED_RELOCATE | COMPONENT_ITEM_DROPPED_SUPPRESS_SOUND + +/datum/robot_inventory/proc/handle_item_del(obj/item/source, ...) + inv_unregister(source) diff --git a/code/modules/mob/living/silicon/robot/robot_item_mount.dm b/code/modules/mob/living/silicon/robot/robot_item_mount.dm new file mode 100644 index 00000000000..f7d9fe7bee0 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/robot_item_mount.dm @@ -0,0 +1,107 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2024 Citadel Station Developers *// + +/** + * Something for all owned items to be mounted on as a resource bus. + */ +/datum/item_mount/robot_item_mount + var/datum/robot_resource_store/store + +/datum/item_mount/robot_item_mount/New(datum/robot_resource_store/store) + ..() + src.store = store + +/datum/item_mount/robot_item_mount/Destroy() + store = null + return ..() + +/datum/item_mount/robot_item_mount/material_get_amount(obj/item/item, key, material_id) + var/datum/robot_resource/resource = store.provisioned_material_store[material_id] + . = resource?.amount + +/datum/item_mount/robot_item_mount/material_get_capacity(obj/item/item, key, material_id) + var/datum/robot_resource/resource = store.provisioned_material_store[material_id] + . = resource?.amount_max + +/datum/item_mount/robot_item_mount/material_get_provider_name(obj/item/item, key, material_id) + . = "material store" + +/datum/item_mount/robot_item_mount/material_give_amount(obj/item/item, key, material_id, amount, force) + var/datum/robot_resource/resource = store.provisioned_material_store[material_id] + if(resource) + if(force) + . = amount + resource.amount += amount + else + . = clamp(resource.amount_max - resource.amount, 0, amount) + resource.amount += . + +/datum/item_mount/robot_item_mount/material_use_amount(obj/item/item, key, material_id, amount) + var/datum/robot_resource/resource = store.provisioned_material_store[material_id] + if(resource) + . = min(resource.amount, amount) + resource.amount -= . + +/datum/item_mount/robot_item_mount/stack_get_amount(obj/item/item, key, path) + var/datum/robot_resource/resource = store.provisioned_stack_store[path] + . = resource?.amount + +/datum/item_mount/robot_item_mount/stack_get_capacity(obj/item/item, key, path) + var/datum/robot_resource/resource = store.provisioned_stack_store[path] + . = resource?.amount_max + +/datum/item_mount/robot_item_mount/stack_get_provider_name(obj/item/item, key, path) + . = "resource store" + +/datum/item_mount/robot_item_mount/stack_give_amount(obj/item/item, key, path, amount, force) + var/datum/robot_resource/resource = store.provisioned_stack_store[path] + if(resource) + if(force) + . = amount + resource.amount += amount + else + . = clamp(resource.amount_max - resource.amount, 0, amount) + resource.amount += . + +/datum/item_mount/robot_item_mount/stack_use_amount(obj/item/item, key, path, amount) + var/datum/robot_resource/resource = store.provisioned_stack_store[path] + if(resource) + . = min(resource.amount, amount) + resource.amount -= . + +/datum/item_mount/robot_item_mount/lazy_energy_check(obj/item/item, key, joules) + . = DYNAMIC_CELL_UNITS_TO_J(store.owner?.cell?.charge) >= joules + +/datum/item_mount/robot_item_mount/lazy_energy_use(obj/item/item, key, joules, minimum_reserve) + . = store.owner?.cell?.use(DYNAMIC_J_TO_CELL_UNITS(joules)) + +/datum/item_mount/robot_item_mount/reagent_get_amount(obj/item/item, key, datum/reagent/reagent) + var/datum/robot_resource/resource = store.provisioned_reagent_store[reagent.id] + . = resource?.amount + +/datum/item_mount/robot_item_mount/reagent_erase_amount(obj/item/item, key, datum/reagent/reagent, amount) + var/datum/robot_resource/resource = store.provisioned_reagent_store[reagent.id] + if(resource) + . = max(amount, resource.amount) + resource.amount -= . + +/datum/item_mount/robot_item_mount/reagent_spawn_amount(obj/item/item, key, datum/reagent/reagent, amount, force) + var/datum/robot_resource/resource = store.provisioned_reagent_store[reagent.id] + if(resource) + if(force) + . = amount + resource.amount += amount + else + . = clamp(resource.amount_max - resource.amount, 0, amount) + resource.amount += . + +/datum/item_mount/robot_item_mount/extinguisher_get_volume(obj/item/extinguisher/extinguisher, key) + var/datum/robot_resource/resource = store.provisioned_reagent_store[/datum/reagent/water::id] + . = resource?.amount + +/datum/item_mount/robot_item_mount/extinguisher_transfer_volume(obj/item/extinguisher/extinguisher, key, requested, datum/reagent_holder/into_holder) + var/datum/robot_resource/resource = store.provisioned_reagent_store[/datum/reagent/water::id] + if(resource) + . = min(requested, resource.amount) + into_holder.add_reagent(/datum/reagent/water::id, .) + resource.amount -= . diff --git a/code/modules/mob/living/silicon/robot/robot_module.dm b/code/modules/mob/living/silicon/robot/robot_module.dm new file mode 100644 index 00000000000..e51738d30a0 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/robot_module.dm @@ -0,0 +1,202 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2024 Citadel Station Developers *// + +/** + * The baseline configuration for a silicon. + * + * * This is considered intrinsic, and cannot be changed on a robot without fully rebuilding its state. + * + * Contains: + * + * * Inbuilt items + * * WIP + */ +/datum/prototype/robot_module + abstract_type = /datum/prototype/robot_module + + /// Allow selection + // todo: replace with selection class / groups / something to that effect + var/selectable = FALSE + + /// /obj/item/robot_module_legacy typepath + var/use_robot_module_path = /obj/item/robot_module_legacy/robot + + /// This corrosponds to the icon_state in `icons/screen/hud/robot/modules.dmi' + var/module_hud_state = "standard" + + /// Allowed robot frames. + /// * set to list of typepaths/anonymous types to init + var/list/datum/robot_frame/frames + + /// Generate robot frames from iconsets. + /// * set to list of `/datum/prototype/robot_iconset` ids or paths + /// * the iconset must have `chassis` set, or this will runtime. + /// * will append to [frames]. + var/list/auto_iconsets + + /// Required selection groups + /// * If both this and `selection_groups_any` are null, this can't be picked. + var/list/selection_groups_all + /// Required selection groups + /// * If both this and `selection_groups_all` are null, this can't be picked. + var/list/selection_groups_any + + /// show on manifest? + var/legacy_show_on_manifest = FALSE + + //* Lighting *// + /// Default lighting color + var/light_color = "#ffffff" + + //* Identity *// + /// Our display name + var/display_name = "???" + /// Our examine name, defaulting to display name + var/visible_name + /// Our category; can be null if default + var/category + + //* Mounted Item Descriptor - Injectors *// + /// items to inject into normal out + /// * paths are allowed + /// * anonymous types are allowed + /// * item instances are **not allowed** and will result in shit exploding! + var/list/mounted_item_descriptor_inject_normal + /// items to inject into emag out + /// * paths are allowed + /// * anonymous types are allowed + /// * item instances are **not allowed** and will result in shit exploding! + var/list/mounted_item_descriptor_inject_emag + +/datum/prototype/robot_module/New() + LAZYINITLIST(frames) + for(var/i in 1 to length(auto_iconsets)) + var/entry = auto_iconsets[i] + if(ispath(entry)) + auto_iconsets[i] = new entry + else if(IS_ANONYMOUS_TYPEPATH(entry)) + auto_iconsets[i] = new entry + else if(istype(entry, /datum/robot_frame)) + else + stack_trace("invalid entry [entry] in index [i] on hardcoded frames on [id] ([type])") + continue + for(var/resolve_iconset in auto_iconsets) + var/datum/prototype/robot_iconset/resolved_iconset = RSrobot_iconsets.fetch_local_or_throw(resolve_iconset) + if(!resolved_iconset) + stack_trace("unknown entry [resolve_iconset] in auto_iconsets on [id] ([type])") + continue + if(!resolved_iconset.auto_chassis) + stack_trace("entry [resolve_iconset] in auto_iconsets on [id] ([type]) has no automatic chassis") + continue + var/datum/prototype/robot_chassis/resolved_chassis = RSrobot_chassis.fetch_local_or_throw(resolved_iconset.auto_chassis) + if(!resolved_chassis) + stack_trace("entry [resolve_iconset] in auto_iconsets on [id] ([type]) had an invalid chassis ([resolved_iconset.auto_chassis])") + continue + var/datum/robot_frame/generated_frame = new + generated_frame.robot_iconset = resolved_iconset + generated_frame.robot_chassis = resolved_chassis + generated_frame.name = "[resolved_iconset.get_display_name()] ([resolved_chassis.name])" + frames += generated_frame + +/datum/prototype/robot_module/proc/create_provisioning() as /datum/robot_provisioning + var/datum/robot_provisioning/creating = new + . = creating + var/list/i_normal = list() + var/list/i_emag = list() + create_mounted_item_descriptors(i_normal, i_emag) + for(var/obj/item/descriptor as anything in i_normal) + var/obj/item/resolved + if(istype(descriptor)) + resolved = descriptor + else if(ispath(descriptor)) + resolved = new descriptor + else if(IS_ANONYMOUS_TYPEPATH(descriptor)) + resolved = new descriptor + else + stack_trace("invalid descriptor [descriptor] on [id] ([type])") + continue + creating.add_item(resolved) + for(var/obj/item/descriptor as anything in i_emag) + var/obj/item/resolved + if(istype(descriptor)) + resolved = descriptor + else if(ispath(descriptor)) + resolved = new descriptor + else if(IS_ANONYMOUS_TYPEPATH(descriptor)) + resolved = new descriptor + else + stack_trace("invalid descriptor [descriptor] on [id] ([type])") + continue + creating.add_emag_item(resolved) + +/** + * Returns a list of descriptors for mounted items + * + * A descriptor can be: + * * An item instance + * * An item path + * * An anonymous type of an item + * + * It's recommended to use item path, then anonymous types, and lastly, item instances. + * Item instances should be created in nullspace. + * + * The caller must handle all of these. + * Unused item instances must be qdel'd. + */ +/datum/prototype/robot_module/proc/create_mounted_item_descriptors(list/normal_out, list/emag_out) + if(normal_out) + if(mounted_item_descriptor_inject_normal) + normal_out |= mounted_item_descriptor_inject_normal + normal_out |= list( + /obj/item/flash, + /obj/item/multitool, // todo: special robot multitool that can interface with machines? + /obj/item/gps/robot, + /obj/item/tool/crowbar/cyborg, + /obj/item/extinguisher/mini, + ) + if(emag_out) + if(mounted_item_descriptor_inject_emag) + emag_out |= mounted_item_descriptor_inject_emag + +/** + * Provision a robot's resource store. + * + * * All of the store's lists should be initalized, even if they're generally lazy. + * You can lazyclearlist it later. + */ +/datum/prototype/robot_module/proc/provision_resource_store(datum/robot_resource_store/store) + store.provisioned_reagent_store[/datum/reagent/water::id] = new /datum/robot_resource/provisioned/preset/water + +/datum/prototype/robot_module/proc/legacy_custom_regenerate_resources(mob/living/silicon/robot/robot, dt, multiplier) + return + +//* Name / Description / Identity *// + +/** + * Get name as seen by things like robotics consoles that don't use another way + * to resolve who / what we are. + */ +/datum/prototype/robot_module/proc/get_display_name() + return display_name + +/** + * Get visible name on examine + */ +/datum/prototype/robot_module/proc/get_visible_name() + return visible_name || display_name + +//* Application *// + +/** + * Called when we're being set onto a robot. + */ +/datum/prototype/robot_module/proc/on_install(mob/living/silicon/robot/robot) + SHOULD_CALL_PARENT(TRUE) + SHOULD_NOT_SLEEP(TRUE) + +/** + * Called when we're being unset from a robot. + */ +/datum/prototype/robot_module/proc/on_uninstall(mob/living/silicon/robot/robot) + SHOULD_CALL_PARENT(TRUE) + SHOULD_NOT_SLEEP(TRUE) diff --git a/code/modules/mob/living/silicon/robot/robot_modules/_robot_modules_defs.dm b/code/modules/mob/living/silicon/robot/robot_modules/_robot_modules_defs.dm deleted file mode 100644 index 5ba30fc0635..00000000000 --- a/code/modules/mob/living/silicon/robot/robot_modules/_robot_modules_defs.dm +++ /dev/null @@ -1,20 +0,0 @@ -#define MATSYN_WATER "water" -#define MATSYN_NANITES "nanites" -#define MATSYN_WIRE "wire" -#define MATSYN_METAL "metal" -#define MATSYN_GLASS "glass" -#define MATSYN_DRUGS "medicine" -#define MATSYN_WOOD "wood" -#define MATSYN_PLASTIC "plastic" -#define MATSYN_PLASTEEL "plasteel" - -#define MATTER_SYNTH_WITH_NAME(K,T,N,V...) .[K] = new /datum/matter_synth/##T (V, name = N) -#define MATTER_SYNTH(K,T,V...) .[K] = new /datum/matter_synth/##T (V) -#define CYBORG_STACK(T,K) do { var/obj/item/stack/S = new /obj/item/stack/##T(src); S.synths = __cyborg_stack_map(K); . += S } while (FALSE) - -/obj/item/robot_module/proc/__cyborg_stack_map(list/targets) - if (!islist(targets)) - targets = list(targets) - . = list() - for (var/item in targets) - . += synths_by_kind[item] diff --git a/code/modules/mob/living/silicon/robot/robot_modules/event.dm b/code/modules/mob/living/silicon/robot/robot_modules/event.dm deleted file mode 100644 index dc4a03034c8..00000000000 --- a/code/modules/mob/living/silicon/robot/robot_modules/event.dm +++ /dev/null @@ -1,90 +0,0 @@ -/* Other, unaffiliated modules */ - -// The module that borgs on the surface have. Generally has a lot of useful tools in exchange for questionable loyalty to the crew. -/obj/item/robot_module/robot/lost - name = "lost robot module" - hide_on_manifest = 1 - sprites = list( - "Drone" = "drone-lost" - ) - -/obj/item/robot_module/robot/lost/get_modules() - . = ..() - . |= list( - // Sec - /obj/item/melee/baton/shocker/robot, - /obj/item/handcuffs/cyborg, - /obj/item/borg/combat/shield, - - // Med - /obj/item/healthanalyzer, - /obj/item/reagent_containers/borghypo/lost, - - // Engi - /obj/item/weldingtool/electric/mounted, - /obj/item/tool/screwdriver/cyborg, - /obj/item/tool/wrench/cyborg, - /obj/item/tool/wirecutters/cyborg, - /obj/item/multitool, - - // Sci - /obj/item/robotanalyzer - ) - -/obj/item/robot_module/robot/lost/get_synths(mob/living/silicon/robot/R) - . = ..() - MATTER_SYNTH(MATSYN_WIRE, wire) - -/obj/item/robot_module/robot/lost/handle_special_module_init(mob/living/silicon/robot/R) - . = ..() - // Potato - emag = new /obj/item/gun/projectile/energy/retro/mounted(src) - - var/obj/item/stack/cable_coil/cyborg/C = new /obj/item/stack/cable_coil/cyborg(src) - C.synths = list(synths_by_kind[MATSYN_WIRE]) - . += C - -/obj/item/robot_module/robot/gravekeeper - name = "gravekeeper robot module" - hide_on_manifest = 1 - sprites = list( - "Drone" = "drone-gravekeeper", - "Sleek" = "sleek-gravekeeper" - ) - -/obj/item/robot_module/robot/gravekeeper/get_modules() - . = ..() - . |= list( - // For fending off animals and looters - /obj/item/melee/baton/shocker/robot, - /obj/item/borg/combat/shield, - - // For repairing gravemarkers - /obj/item/weldingtool/electric/mounted, - /obj/item/tool/screwdriver/cyborg, - /obj/item/tool/wrench/cyborg, - - // For growing flowers - /obj/item/material/minihoe, - /obj/item/material/knife/machete/hatchet, - /obj/item/plant_analyzer, - /obj/item/storage/bag/plants, - /obj/item/robot_harvester, - - // For digging and beautifying graves - /obj/item/shovel, - /obj/item/gripper/gravekeeper - ) - -/obj/item/robot_module/robot/gravekeeper/get_synths(mob/living/silicon/robot/R) - . = ..() - MATTER_SYNTH(MATSYN_WOOD, wood, 25000) - -/obj/item/robot_module/robot/gravekeeper/handle_special_module_init(mob/living/silicon/robot/R) - . = ..() - // For really persistent looters - emag = new /obj/item/gun/projectile/energy/retro/mounted(src) - - var/obj/item/stack/material/cyborg/wood/W = new (src) - W.synths = list(synths_by_kind[MATSYN_WOOD]) - . += W diff --git a/code/modules/mob/living/silicon/robot/robot_modules/event_vr.dm b/code/modules/mob/living/silicon/robot/robot_modules/event_vr.dm deleted file mode 100644 index 2db222178ef..00000000000 --- a/code/modules/mob/living/silicon/robot/robot_modules/event_vr.dm +++ /dev/null @@ -1,42 +0,0 @@ -/obj/item/robot_module/robot/quad/stray - name = "stray robot module" - hide_on_manifest = 1 - sprites = list( - "Stray" = "stray" - ) - can_shred = TRUE - -/obj/item/robot_module/robot/quad/stray/get_modules() - . = ..() - . |= list( - // Sec - /obj/item/handcuffs/cyborg, - /obj/item/dogborg/jaws/big, - /obj/item/melee/baton/robot, - /obj/item/dogborg/pounce, - - // Med - /obj/item/healthanalyzer, - /obj/item/shockpaddles/robot/hound, - /obj/item/dogborg/mirrortool, - - // Engi - /obj/item/weldingtool/electric/mounted, - /obj/item/tool/screwdriver/cyborg, - /obj/item/tool/wrench/cyborg, - /obj/item/tool/wirecutters/cyborg, - /obj/item/multitool - ) - -/obj/item/robot_module/robot/quad/stray/handle_special_module_init(mob/living/silicon/robot/R) - . = ..() - // Boof - src.emag = new /obj/item/gun/projectile/energy/retro/mounted(src) - - var/obj/item/reagent_containers/borghypo/hound/lost/H = new /obj/item/reagent_containers/borghypo/hound/lost(src) - H.water = synths_by_kind[MATSYN_WATER] - . += H - - var/obj/item/dogborg/sleeper/B = new /obj/item/dogborg/sleeper(src) - B.water = synths_by_kind[MATSYN_WATER] - . += B diff --git a/code/modules/mob/living/silicon/robot/robot_modules/station.dm b/code/modules/mob/living/silicon/robot/robot_modules/station.dm index 043b661ed57..270e210da9e 100644 --- a/code/modules/mob/living/silicon/robot/robot_modules/station.dm +++ b/code/modules/mob/living/silicon/robot/robot_modules/station.dm @@ -1,42 +1,6 @@ -GLOBAL_LIST_INIT(robot_modules, list( - "Standard" = /obj/item/robot_module/robot/standard, - "Service" = /obj/item/robot_module/robot/clerical/butler, - "Clerical" = /obj/item/robot_module/robot/clerical/general, - "Research" = /obj/item/robot_module/robot/research, - "Miner" = /obj/item/robot_module/robot/miner, - "Medical" = /obj/item/robot_module/robot/medical/surgeon, - "Security" = /obj/item/robot_module/robot/security/general, - "Combat" = /obj/item/robot_module/robot/security/combat, - "Engineering" = /obj/item/robot_module/robot/engineering/general, -// "Construction" = /obj/item/robot_module/robot/engineering/construction, - "Janitor" = /obj/item/robot_module/robot/janitor, - "Quadruped" = /obj/item/robot_module/robot/quad/basic, - "MediQuad" = /obj/item/robot_module/robot/quad/medi, - "SecuriQuad" = /obj/item/robot_module/robot/quad/sec, - "JaniQuad" = /obj/item/robot_module/robot/quad/jani, - "SciQuad" = /obj/item/robot_module/robot/quad/sci, - "EngiQuad" = /obj/item/robot_module/robot/quad/engi, - "Mining Quad" = /obj/item/robot_module/robot/quad/miner, - "Service Quad" = /obj/item/robot_module/robot/quad/serv, - "ERT" = /obj/item/robot_module/robot/quad/ert - )) - -/obj/item/robot_module - name = "robot module" - icon = 'icons/obj/module.dmi' - icon_state = "std_module" - w_class = WEIGHT_CLASS_HUGE - item_state = "std_mod" - var/hide_on_manifest = 0 +/obj/item/robot_module_legacy var/channels = list() var/networks = list() - var/sprites = list() - var/can_be_pushed = 1 - var/no_slip = 0 - /// Affects emotes. - var/is_the_law = FALSE - /// Enables a verb. - var/can_shred = FALSE var/languages = list( LANGUAGE_AKHANI = 0, @@ -58,122 +22,35 @@ GLOBAL_LIST_INIT(robot_modules, list( LANGUAGE_ZADDAT = 0 ) - var/list/modules = list() - var/list/datum/matter_synth/synths = list() - var/list/synths_by_kind = list() - var/obj/item/emag = null - var/obj/item/borg/upgrade/jetpack = null - var/obj/item/borg/upgrade/advhealth = null var/list/subsystems = list() - var/list/obj/item/borg/upgrade/supported_upgrades = list() // Bookkeeping var/list/original_languages = list() var/list/added_networks = list() -/obj/item/robot_module/Initialize(mapload) +/obj/item/robot_module_legacy/Initialize(mapload) . = ..() var/mob/living/silicon/robot/R = loc - R.module = src + R.module_legacy = src add_camera_networks(R) add_languages(R) add_subsystems(R) - apply_status_flags(R) if(R.radio) if(R.shell) channels = R.mainframe.aiRadio.channels R.radio.recalculateChannels() - handle_custom_item(R) - - R.set_module_sprites(sprites) - - // TODO: REFACTOR CYBORGS THEY ARE ALL SHITCODE - INVOKE_ASYNC(R, TYPE_PROC_REF(/mob/living/silicon/robot, choose_icon), R.module_sprites.len + 1, R.module_sprites) - - // Setup synths, modules, and modules with custom init code. - synths_by_kind = get_synths(R) - for (var/key in synths_by_kind) - synths += synths_by_kind[key] - - for (var/entry in get_modules()) - modules += new entry(src) - - for (var/thing in handle_special_module_init(R)) - modules += thing - - for(var/obj/item/I in modules) - ADD_TRAIT(I, TRAIT_ITEM_NODROP, CYBORG_MODULE_TRAIT) - -/obj/item/robot_module/proc/Reset(var/mob/living/silicon/robot/R) +/obj/item/robot_module_legacy/proc/Reset(var/mob/living/silicon/robot/R) remove_camera_networks(R) remove_languages(R) remove_subsystems(R) - remove_status_flags(R) if(R.radio) R.radio.recalculateChannels() -/// Get a list of all matter synths available to this module. Executes before handle_special_module_init. -/obj/item/robot_module/proc/get_synths(mob/living/silicon/robot/R) - . = list() - -/// Get a list of typepaths that should be put into the modules list. -/obj/item/robot_module/proc/get_modules() - SHOULD_CALL_PARENT(TRUE) - return list() - -// This is for modules that need special handling, not just being added to the modules list. -/obj/item/robot_module/proc/handle_special_module_init(mob/living/silicon/robot/R) - SHOULD_CALL_PARENT(TRUE) - . = list() - -/obj/item/robot_module/proc/handle_custom_item(mob/living/silicon/robot/R) - return - -/obj/item/robot_module/Destroy() - for(var/module in modules) - qdel(module) - for(var/synth in synths) - qdel(synth) - modules.Cut() - synths.Cut() - synths_by_kind = null - qdel(emag) - qdel(jetpack) - emag = null - jetpack = null - return ..() - -/obj/item/robot_module/emp_act(severity) - if(modules) - for(var/obj/O in modules) - O.emp_act(severity) - if(emag) - emag.emp_act(severity) - if(synths) - for(var/datum/matter_synth/S in synths) - S.emp_act(severity) - ..() - return - -/obj/item/robot_module/proc/respawn_consumable(var/mob/living/silicon/robot/R, var/rate) - if(!synths || !synths.len) - return - - for(var/datum/matter_synth/T in synths) - T.add_charge(T.recharge_rate * rate) - -/obj/item/robot_module/proc/rebuild()//Rebuilds the list so it's possible to add/remove items from the module - var/list/temp_list = modules - modules = list() - for(var/obj/O in temp_list) - if(O) - modules += O - -/obj/item/robot_module/proc/add_languages(var/mob/living/silicon/robot/R) +/obj/item/robot_module_legacy/proc/add_languages(var/mob/living/silicon/robot/R) // Stores the languages as they were before receiving the module, and whether they could be synthezized. for(var/datum/prototype/language/language_datum in R.languages) original_languages[language_datum] = (language_datum in R.speech_synthesizer_langs) @@ -181,7 +58,7 @@ GLOBAL_LIST_INIT(robot_modules, list( for(var/language in languages) R.add_language(language, languages[language]) -/obj/item/robot_module/proc/remove_languages(var/mob/living/silicon/robot/R) +/obj/item/robot_module_legacy/proc/remove_languages(var/mob/living/silicon/robot/R) // Clear all added languages, whether or not we originally had them. for(var/language in languages) R.remove_language(language) @@ -191,130 +68,20 @@ GLOBAL_LIST_INIT(robot_modules, list( R.add_language(original_language, original_languages[original_language]) original_languages.Cut() -/obj/item/robot_module/proc/add_camera_networks(var/mob/living/silicon/robot/R) +/obj/item/robot_module_legacy/proc/add_camera_networks(var/mob/living/silicon/robot/R) if(R.camera && (NETWORK_ROBOTS in R.camera.network)) for(var/network in networks) if(!(network in R.camera.network)) R.camera.add_network(network) added_networks |= network -/obj/item/robot_module/proc/remove_camera_networks(var/mob/living/silicon/robot/R) +/obj/item/robot_module_legacy/proc/remove_camera_networks(var/mob/living/silicon/robot/R) if(R.camera) R.camera.remove_networks(added_networks) added_networks.Cut() -/obj/item/robot_module/proc/add_subsystems(var/mob/living/silicon/robot/R) +/obj/item/robot_module_legacy/proc/add_subsystems(var/mob/living/silicon/robot/R) add_verb(R, subsystems) -/obj/item/robot_module/proc/remove_subsystems(var/mob/living/silicon/robot/R) +/obj/item/robot_module_legacy/proc/remove_subsystems(var/mob/living/silicon/robot/R) remove_verb(R, subsystems) - -/obj/item/robot_module/proc/apply_status_flags(var/mob/living/silicon/robot/R) - if(!can_be_pushed) - R.status_flags &= ~STATUS_CAN_PUSH - -/obj/item/robot_module/proc/remove_status_flags(var/mob/living/silicon/robot/R) - if(!can_be_pushed) - R.status_flags |= STATUS_CAN_PUSH - -/// This is different from the dogborg or wideborg vars -- this is specifically if the module is a *dog* - if it should be able to do dog things like bark. -/obj/item/robot_module/proc/is_dog() - return FALSE - -/obj/item/robot_module/proc/is_cat() - return FALSE - -/obj/item/robot_module/robot/get_modules() - . = ..() - // Common items that all modules have. - . |= list( - /obj/item/flash/robot, - /obj/item/tool/crowbar/cyborg, - /obj/item/extinguisher, - /obj/item/gps/robot - ) - -/obj/item/robot_module/robot/quad - -/obj/item/robot_module/robot/quad/Initialize() - . = ..() - var/mob/living/silicon/robot/R = loc - ASSERT(istype(R)) - - R.icon = 'icons/mob/robots_wide.dmi' - R.set_base_pixel_x(-16) - R.dogborg = TRUE - R.wideborg = TRUE - R.icon_x_dimension = 64 - add_verb(R, list( - /mob/living/silicon/robot/proc/ex_reserve_refill, - /mob/living/silicon/robot/proc/rest_style - )) - if (can_shred) - add_verb(R, /mob/living/proc/shred_limb) - -/obj/item/robot_module/robot/quad/Reset(mob/living/silicon/robot/R) - . = ..() - // Reset a bunch of wideborg specific things. - R.pixel_x = initial(R.pixel_x) - R.pixel_y = initial(R.pixel_y) - R.icon = initial(R.icon) - R.base_pixel_x = initial(R.pixel_x) - remove_verb(R, list( - /mob/living/silicon/robot/proc/ex_reserve_refill, - /mob/living/proc/shred_limb, - /mob/living/silicon/robot/proc/rest_style - )) - R.scrubbing = FALSE - R.dogborg = FALSE - R.wideborg = FALSE - -/obj/item/robot_module/robot/quad/get_modules() - . = ..() - . |= list( - /obj/item/dogborg/boop_module //Boop people on the nose. - ) - -/obj/item/robot_module/robot/quad/get_synths(mob/living/silicon/robot/R) - . = ..() - var/datum/matter_synth/water = new /datum/matter_synth(500) - water.name = "Water reserves" - water.recharge_rate = 0 - R.water_res = water - .[MATSYN_WATER] = water - -/obj/item/robot_module/robot/quad/handle_special_module_init(mob/living/silicon/robot/R) - . = ..() - - var/obj/item/dogborg/tongue/T = new /obj/item/dogborg/tongue(src) - T.water = synths_by_kind[MATSYN_WATER] - . += T - -/obj/item/robot_module/robot/quad/is_dog() - var/mob/living/silicon/robot/R = loc - ASSERT(istype(R)) - // This is the only non-canid dogborg type right now. - return R.icontype != "F3-LINE" - -/obj/item/robot_module/robot/quad/is_cat() - var/mob/living/silicon/robot/R = loc - ASSERT(istype(R)) - // This is the only non-canid dogborg type right now. - return R.icontype == "F3-LINE" - -// Custom sprite stuff. There's a dedicated system for this, not sure why this is done separately. - -/obj/item/robot_module/robot/quad/engi/handle_custom_item(mob/living/silicon/robot/R) - . = ..() - if (R.client?.ckey == "nezuli") - sprites["Alina"] = "alina-eng" - -/obj/item/robot_module/robot/quad/medi/handle_custom_item(mob/living/silicon/robot/R) - . = ..() - if (R.client?.ckey == "nezuli") - sprites["Alina"] = "alina-med" - -/obj/item/robot_module/robot/quad/sec/handle_custom_item(mob/living/silicon/robot/R) - . = ..() - if (R.client?.ckey == "nezuli") - sprites["Alina"] = "alina-sec" diff --git a/code/modules/mob/living/silicon/robot/robot_modules/station/cargo.dm b/code/modules/mob/living/silicon/robot/robot_modules/station/cargo.dm deleted file mode 100644 index 026151ec723..00000000000 --- a/code/modules/mob/living/silicon/robot/robot_modules/station/cargo.dm +++ /dev/null @@ -1,91 +0,0 @@ -/obj/item/robot_module/robot/miner - name = "miner robot module" - channels = list("Supply" = 1) - networks = list(NETWORK_MINE) - sprites = list( - "NM-USE Nanotrasen" = "robotMine", - "Cabeiri" = "eyebot-miner", - "Haruka" = "marinaMN", - "Telemachus" = "toiletbotminer", - "WTOperator" = "sleekminer", - "XI-GUS" = "spidermining", - "XI-ALP" = "heavyMiner", - "Basic" = "Miner_old", - "Advanced Droid" = "droid-miner", - "Treadhead" = "Miner", - "Drone" = "drone-miner", - "Misato" = "tall2miner", - "L3P1-D0T" = "Glitterfly-Miner", - "Miss M" = "miss-miner", - "Carffin" = "coffin-Service", - "Coffing" = "coffin-Mining", - "Handy" = "handy-miner", - "Acheron" = "mechoid-Miner", - "Shellguard Noble" = "Noble-DIG", - "ZOOM-BA" = "zoomba-miner", - "W02M" = "worm-miner" - ) - -/obj/item/robot_module/robot/miner/get_modules() - . = ..() - . |= list( - /obj/item/borg/sight/material, - /obj/item/tool/wrench/cyborg, - /obj/item/tool/screwdriver/cyborg, - /obj/item/storage/bag/ore, - /obj/item/pickaxe/borgdrill, - /obj/item/gun/projectile/energy/kinetic_accelerator/cyborg, - /obj/item/storage/bag/sheetsnatcher/borg, - /obj/item/gripper/miner, - /obj/item/mining_scanner - ) - -/obj/item/robot_module/robot/miner/handle_special_module_init(mob/living/silicon/robot/R) - . = ..() - - // TODO: Only one emag module is supported right now. - src.emag = new /obj/item/pickaxe/plasmacutter(src) - // src.emag = new /obj/item/pickaxe/diamonddrill(src) - // src.emag = new /obj/item/melee/disruptor/borg(src) - -/obj/item/robot_module/robot/quad/miner - name = "Mining Quadruped module" - sprites = list( - "F3-LINE" = "FELI-Mining", - "K-MINE" = "kmine", - "Cargo Hound" = "cargohound", - "Cargo Hound Dark" = "cargohounddark", - "Drake" = "drakemine", - "Otie" = "otiec" - ) - channels = list("Supply" = 1) - can_be_pushed = 0 - -/obj/item/robot_module/robot/quad/miner/get_modules() - . = ..() - . |= list( - /obj/item/borg/sight/material, - /obj/item/tool/wrench/cyborg, - /obj/item/tool/screwdriver/cyborg, - /obj/item/storage/bag/ore, - /obj/item/pickaxe/borgdrill, - /obj/item/gun/projectile/energy/kinetic_accelerator/cyborg, - /obj/item/storage/bag/sheetsnatcher/borg, - /obj/item/gripper/miner, - /obj/item/mining_scanner, - /obj/item/dogborg/jaws/small - ) - -// In a nutshell, basically service/butler robot but in dog form. -/obj/item/robot_module/robot/quad/miner/handle_special_module_init(mob/living/silicon/robot/R) - . = ..() - - // TODO: Only one emag module is supported right now. - src.emag = new /obj/item/pickaxe/plasmacutter(src) - // src.emag = new /obj/item/pickaxe/diamonddrill(src) - // src.emag = new /obj/item/melee/disruptor/borg(src) - -/obj/item/robot_module/robot/quad/miner/handle_special_module_init(mob/living/silicon/robot/R) - . = ..() - // These get a larger water synth. - synths_by_kind[MATSYN_WATER]:max_energy = 1000 diff --git a/code/modules/mob/living/silicon/robot/robot_modules/station/drone.dm b/code/modules/mob/living/silicon/robot/robot_modules/station/drone.dm deleted file mode 100644 index 77e40ef6be2..00000000000 --- a/code/modules/mob/living/silicon/robot/robot_modules/station/drone.dm +++ /dev/null @@ -1,103 +0,0 @@ -/* Drones */ - -/obj/item/robot_module/drone - name = "drone module" - hide_on_manifest = 1 - no_slip = 1 - networks = list(NETWORK_ENGINEERING) - -/obj/item/robot_module/drone/get_modules() - . = ..() - . |= list( - /obj/item/borg/sight/meson, - /obj/item/weldingtool/electric/mounted/cyborg, - /obj/item/tool/screwdriver/cyborg, - /obj/item/tool/wrench/cyborg, - /obj/item/tool/crowbar/cyborg, - /obj/item/tool/wirecutters/cyborg, - /obj/item/multitool, - /obj/item/lightreplacer, - /obj/item/gripper, - /obj/item/mop, - /obj/item/gripper/no_use/loader, - /obj/item/extinguisher, - /obj/item/pipe_painter, - /obj/item/floor_painter, - /obj/item/t_scanner, - /obj/item/atmos_analyzer, - /obj/item/inflatable_dispenser/robot, - /obj/item/barrier_tape_roll/engineering, - /obj/item/pipe_dispenser - ) - -/obj/item/robot_module/drone/get_synths(mob/living/silicon/robot/R) - . = ..() - MATTER_SYNTH(MATSYN_METAL, metal, 25000) - MATTER_SYNTH(MATSYN_GLASS, glass, 25000) - MATTER_SYNTH(MATSYN_WOOD, wood, 25000) - MATTER_SYNTH(MATSYN_PLASTIC, plastic, 25000) - MATTER_SYNTH(MATSYN_WIRE, wire, 30) - -/obj/item/robot_module/drone/handle_special_module_init(mob/living/silicon/robot/R) - . = ..() - - R.internals = new/obj/item/tank/jetpack/carbondioxide(src) - . += R.internals - - src.emag = new /obj/item/pickaxe/plasmacutter(src) - src.emag.name = "Plasma Cutter" - - var/obj/item/matter_decompiler/MD = new /obj/item/matter_decompiler(src) - MD.metal = synths_by_kind[MATSYN_METAL] - MD.glass = synths_by_kind[MATSYN_GLASS] - MD.wood = synths_by_kind[MATSYN_WOOD] - MD.plastic = synths_by_kind[MATSYN_PLASTIC] - . += MD - - CYBORG_STACK(material/cyborg/steel, MATSYN_METAL) - CYBORG_STACK(material/cyborg/glass, MATSYN_GLASS) - CYBORG_STACK(rods/cyborg , MATSYN_METAL) - CYBORG_STACK(cable_coil/cyborg , MATSYN_WIRE) - CYBORG_STACK(tile/floor/cyborg , MATSYN_METAL) - CYBORG_STACK(material/cyborg/glass/reinforced, list(MATSYN_METAL, MATSYN_GLASS)) - CYBORG_STACK(tile/wood/cyborg , MATSYN_WOOD) - CYBORG_STACK(material/cyborg/wood , MATSYN_WOOD) - CYBORG_STACK(material/cyborg/plastic, MATSYN_PLASTIC) - -/obj/item/robot_module/drone/construction - name = "construction drone module" - hide_on_manifest = 1 - channels = list("Engineering" = 1) - languages = list() - -/obj/item/robot_module/drone/construction/get_modules() - . = ..() - . |= /obj/item/rcd/electric/mounted/borg/lesser - -/obj/item/robot_module/drone/respawn_consumable(var/mob/living/silicon/robot/R, var/amount) - var/obj/item/lightreplacer/LR = locate() in src.modules - LR.Charge(R, amount) - ..() - return - -/obj/item/robot_module/drone/mining - name = "miner drone module" - channels = list("Supply" = 1) - networks = list(NETWORK_MINE) - -/obj/item/robot_module/drone/mining/get_modules() - . = ..() - . |= list( - /obj/item/borg/sight/material, - /obj/item/pickaxe/borgdrill, - /obj/item/gun/projectile/energy/kinetic_accelerator/cyborg, - /obj/item/storage/bag/ore, - /obj/item/storage/bag/sheetsnatcher/borg - ) - -/obj/item/robot_module/drone/mining/handle_special_module_init(mob/living/silicon/robot/R) - . = ..() - src.emag = new /obj/item/pickaxe/diamonddrill(src) - -/obj/item/robot_module/drone/construction/matriarch - name = "matriarch drone module" diff --git a/code/modules/mob/living/silicon/robot/robot_modules/station/engineering.dm b/code/modules/mob/living/silicon/robot/robot_modules/station/engineering.dm deleted file mode 100644 index 19f5f673c31..00000000000 --- a/code/modules/mob/living/silicon/robot/robot_modules/station/engineering.dm +++ /dev/null @@ -1,215 +0,0 @@ -/obj/item/robot_module/robot/engineering - name = "engineering robot module" - channels = list("Engineering" = 1) - networks = list(NETWORK_ENGINEERING) - subsystems = list(/mob/living/silicon/proc/subsystem_power_monitor) - sprites = list( - "M-USE Nanotrasen" = "robotEngi", - "Cabeiri" = "eyebot-engineering", - "Haruka" = "marinaENG", - "Usagi" = "tallyellow", - "Telemachus" = "toiletbotengineering", - "WTOperator" = "sleekce", - "XI-GUS" = "spidereng", - "XI-ALP" = "heavyEng", - "Basic" = "Engineering", - "Antique" = "engineerrobot", - "Landmate" = "landmate", - "Landmate - Treaded" = "engiborg+tread", - "Drone" = "drone-engineer", - "Treadwell" = "treadwell", - "Handy" = "handy-engineer", - "Misato" = "tall2engineer", - "L3P1-D0T" = "Glitterfly-Engineering", - "Miss M" = "miss-engineer", - "Coffstruction" = "coffin-Construction", - "Coffgineer" = "coffin-Engineering", - "X-88" = "xeightyeight-engineering", - "Acheron" = "mechoid-Engineering", - "Shellguard Noble" = "Noble-ENG", - "ZOOM-BA" = "zoomba-engineering", - "W02M" = "worm-engineering" - ) - -/obj/item/robot_module/robot/engineering/construction - name = "construction robot module" - no_slip = 1 - -/* Merged back into engineering (Hell, it's about time.) - -/obj/item/robot_module/robot/engineering/construction/Initialize(mapload) - . = ..() - src.modules += new /obj/item/borg/sight/meson(src) - src.modules += new /obj/item/rcd/borg(src) - src.modules += new /obj/item/tool/screwdriver/cyborg(src) - src.modules += new /obj/item/tool/wrench/cyborg(src) - src.modules += new /obj/item/weldingtool/electric/mounted/cyborg(src) - src.modules += new /obj/item/pickaxe/plasmacutter(src) - src.modules += new /obj/item/pipe_painter(src) - src.modules += new /obj/item/floor_painter(src) - src.modules += new /obj/item/gripper/no_use/loader(src) - src.modules += new /obj/item/geiger_counter(src) - - var/datum/matter_synth/metal = new /datum/matter_synth/metal() - var/datum/matter_synth/plasteel = new /datum/matter_synth/plasteel() - var/datum/matter_synth/glass = new /datum/matter_synth/glass() - synths += metal - synths += plasteel - synths += glass - - var/obj/item/stack/material/cyborg/steel/M = new (src) - M.synths = list(metal) - src.modules += M - - var/obj/item/stack/rods/cyborg/R = new /obj/item/stack/rods/cyborg(src) - R.synths = list(metal) - src.modules += R - - var/obj/item/stack/tile/floor/cyborg/F = new /obj/item/stack/tile/floor/cyborg(src) - F.synths = list(metal) - src.modules += F - - var/obj/item/stack/material/cyborg/plasteel/S = new (src) - S.synths = list(plasteel) - src.modules += S - - var/obj/item/stack/material/cyborg/glass/reinforced/RG = new (src) - RG.synths = list(metal, glass) - src.modules += RG -*/ - -/obj/item/robot_module/robot/engineering/general/get_modules() - . = ..() - . |= list( - /obj/item/borg/sight/meson, - /obj/item/weldingtool/electric/mounted/cyborg, - /obj/item/tool/screwdriver/cyborg, - /obj/item/tool/wrench/cyborg, - /obj/item/tool/wirecutters/cyborg, - /obj/item/multitool, - /obj/item/t_scanner, - /obj/item/atmos_analyzer, - /obj/item/barrier_tape_roll/engineering, - /obj/item/gripper, - /obj/item/gripper/circuit, - /obj/item/lightreplacer, - /obj/item/pipe_painter, - /obj/item/floor_painter, - /obj/item/inflatable_dispenser/robot, - /obj/item/geiger_counter/cyborg, - /obj/item/rcd/electric/mounted/borg, - /obj/item/pickaxe/plasmacutter, - /obj/item/gripper/no_use/loader, - /obj/item/pipe_dispenser - ) - -/obj/item/robot_module/robot/engineering/general/get_synths(mob/living/silicon/robot/R) - . = ..() - MATTER_SYNTH(MATSYN_METAL, metal, 40000) - MATTER_SYNTH(MATSYN_GLASS, glass, 40000) - MATTER_SYNTH(MATSYN_PLASTEEL, plasteel, 20000) - MATTER_SYNTH(MATSYN_WOOD, wood, 40000) - MATTER_SYNTH(MATSYN_PLASTIC, plastic, 40000) - MATTER_SYNTH(MATSYN_WIRE, wire) - -/obj/item/robot_module/robot/engineering/general/handle_special_module_init(mob/living/silicon/robot/R) - . = ..() - - src.emag = new /obj/item/melee/baton/robot/arm(src) - - var/obj/item/matter_decompiler/MD = new /obj/item/matter_decompiler(src) - MD.metal = synths_by_kind[MATSYN_METAL] - MD.glass = synths_by_kind[MATSYN_GLASS] - src.modules += MD - - CYBORG_STACK(material/cyborg/steel, MATSYN_METAL) - CYBORG_STACK(material/cyborg/glass, MATSYN_GLASS) - CYBORG_STACK(rods/cyborg , MATSYN_METAL) - CYBORG_STACK(cable_coil/cyborg , MATSYN_WIRE) - CYBORG_STACK(tile/floor/cyborg , MATSYN_METAL) - CYBORG_STACK(tile/roofing/cyborg , MATSYN_METAL) - CYBORG_STACK(material/cyborg/glass/reinforced, list(MATSYN_METAL, MATSYN_GLASS)) - CYBORG_STACK(tile/wood/cyborg , MATSYN_WOOD) - CYBORG_STACK(material/cyborg/wood , MATSYN_WOOD) - CYBORG_STACK(material/cyborg/plastic, MATSYN_PLASTIC) - -/obj/item/robot_module/robot/quad/engi - name = "EngiQuad module" - sprites = list( - "Pupdozer" = "pupdozer", - "V2 Engidog" = "thottbot", - "Borgi" = "borgi-eng", - "Engineering Hound" = "engihound", - "Engineering Hound Dark" = "engihounddark", - "F3-LINE" = "FELI-Engineer", - "Drake" = "drakeeng", - "Otie" = "otiee" - ) - channels = list("Engineering" = 1) - networks = list(NETWORK_ENGINEERING) - subsystems = list(/mob/living/silicon/proc/subsystem_power_monitor) - can_be_pushed = 0 - can_shred = TRUE - -/obj/item/robot_module/robot/quad/engi/get_modules() - . = ..() - . |= list( - /obj/item/borg/sight/meson, - /obj/item/weldingtool/electric/mounted/cyborg, - /obj/item/tool/screwdriver/cyborg, - /obj/item/tool/wrench/cyborg, - /obj/item/tool/wirecutters/cyborg, - /obj/item/multitool, - /obj/item/t_scanner, - /obj/item/rcd/electric/mounted/borg, - /obj/item/atmos_analyzer, - /obj/item/barrier_tape_roll/engineering, - /obj/item/inflatable_dispenser/robot, - /obj/item/pickaxe/plasmacutter, - /obj/item/dogborg/jaws/small, - /obj/item/geiger_counter, - /obj/item/pipe_painter, - /obj/item/floor_painter, - /obj/item/gripper, - /obj/item/gripper/no_use/loader, - /obj/item/pipe_dispenser, - /obj/item/gripper/circuit - ) - -/obj/item/robot_module/robot/quad/engi/get_synths(mob/living/silicon/robot/R) - . = ..() - //Painfully slow charger regen but high capacity. Also starts with low amount. - MATTER_SYNTH_WITH_NAME(MATSYN_METAL , metal , "Steel reserves" , 40000) - MATTER_SYNTH_WITH_NAME(MATSYN_GLASS , glass , "Glass reserves" , 40000) - MATTER_SYNTH_WITH_NAME(MATSYN_WOOD , wood , "Wood reserves" , 40000) - MATTER_SYNTH_WITH_NAME(MATSYN_PLASTIC , plastic , "Plastic reserves" , 40000) - MATTER_SYNTH_WITH_NAME(MATSYN_PLASTEEL, plasteel, "Plasteel reserves", 20000) - MATTER_SYNTH(MATSYN_WIRE, wire) - -/obj/item/robot_module/robot/quad/engi/handle_special_module_init(mob/living/silicon/robot/R) - . = ..() - - src.emag = new /obj/item/dogborg/pounce(src) - - var/obj/item/lightreplacer/dogborg/LR = new /obj/item/lightreplacer/dogborg(src) - LR.glass = synths_by_kind[MATSYN_GLASS] - . += LR - - var/obj/item/dogborg/sleeper/compactor/decompiler/MD = new /obj/item/dogborg/sleeper/compactor/decompiler(src) - MD.metal = synths_by_kind[MATSYN_METAL] - MD.glass = synths_by_kind[MATSYN_GLASS] - MD.wood = synths_by_kind[MATSYN_WOOD] - MD.plastic = synths_by_kind[MATSYN_PLASTIC] - MD.water = synths_by_kind[MATSYN_WATER] - . += MD - - CYBORG_STACK(material/cyborg/steel, MATSYN_METAL) - CYBORG_STACK(material/cyborg/glass, MATSYN_GLASS) - CYBORG_STACK(rods/cyborg , MATSYN_METAL) - CYBORG_STACK(cable_coil/cyborg , MATSYN_WIRE) - CYBORG_STACK(tile/floor/cyborg , MATSYN_METAL) - CYBORG_STACK(tile/roofing/cyborg , MATSYN_METAL) - CYBORG_STACK(material/cyborg/glass/reinforced, list(MATSYN_METAL, MATSYN_GLASS)) - CYBORG_STACK(tile/wood/cyborg , MATSYN_WOOD) - CYBORG_STACK(material/cyborg/wood , MATSYN_WOOD) - CYBORG_STACK(material/cyborg/plastic, MATSYN_PLASTIC) diff --git a/code/modules/mob/living/silicon/robot/robot_modules/station/medical.dm b/code/modules/mob/living/silicon/robot/robot_modules/station/medical.dm deleted file mode 100644 index c3c5488b242..00000000000 --- a/code/modules/mob/living/silicon/robot/robot_modules/station/medical.dm +++ /dev/null @@ -1,186 +0,0 @@ -/obj/item/robot_module/robot/medical - name = "medical robot module" - channels = list("Medical" = 1) - networks = list(NETWORK_MEDICAL) - subsystems = list(/mob/living/silicon/proc/subsystem_crew_monitor) - can_be_pushed = 0 - -/obj/item/robot_module/robot/medical/surgeon - name = "medical robot module" - sprites = list( - "M-USE Nanotrasen" = "robotMedi", - "Cabeiri" = "eyebot-medical", - "Haruka" = "marinaMD", - "Minako" = "arachne", - "Usagi" = "tallwhite", - "Telemachus" = "toiletbotsurgeon", - "WTOperator" = "sleekcmo", - "XI-ALP" = "heavyMed", - "Basic" = "Medibot", - "Advanced Droid" = "droid-medical", - "Needles" = "medicalrobot", - "Drone" = "drone-surgery", - "Handy" = "handy-med", - "Insekt" = "insekt-Med", - "Misato" = "tall2medical", - "L3P1-D0T" = "Glitterfly-Surgeon", - "Miss M" = "miss-medical", - "Coffical" = "coffin-Medical", - "Coffcue" = "coffin-Rescue", - "X-88" = "xeightyeight-medical", - "Acheron" = "mechoid-Medical", - "Shellguard Noble" = "Noble-MED", - "ZOOM-BA" = "zoomba-medical", - "W02M" = "worm-crisis" - ) - -/obj/item/robot_module/robot/medical/surgeon/get_modules() - . = ..() - . |= list( - /obj/item/healthanalyzer, - /obj/item/reagent_containers/borghypo/surgeon, - /obj/item/autopsy_scanner, - /obj/item/reagent_scanner/adv, - /obj/item/roller_holder, - /obj/item/reagent_containers/glass/beaker/large, - /obj/item/surgical/scalpel/cyborg, - /obj/item/surgical/hemostat/cyborg, - /obj/item/surgical/retractor/cyborg, - /obj/item/surgical/cautery/cyborg, - /obj/item/surgical/bonegel/cyborg, - /obj/item/surgical/FixOVein/cyborg, - /obj/item/surgical/bonesetter/cyborg, - /obj/item/surgical/circular_saw/cyborg, - /obj/item/surgical/surgicaldrill/cyborg, - /obj/item/gripper/no_use/organ, - /obj/item/gripper/medical, - /obj/item/shockpaddles/robot, - /obj/item/reagent_containers/dropper, // Allows surgeon borg to fix necrosis - /obj/item/reagent_containers/syringe, - /obj/item/dogborg/mirrortool - ) - -/obj/item/robot_module/robot/medical/surgeon/get_synths(mob/living/silicon/robot/R) - . = ..() - MATTER_SYNTH(MATSYN_DRUGS, medicine, 15000) - -/obj/item/robot_module/robot/medical/surgeon/handle_special_module_init(mob/living/silicon/robot/R) - . = ..() - - src.emag = new /obj/item/reagent_containers/spray(src) - src.emag.reagents.add_reagent("pacid", 250) - src.emag.name = "Polyacid spray" - - var/obj/item/stack/medical/advanced/ointment/O = new /obj/item/stack/medical/advanced/ointment(src) - O.uses_charge = 1 - O.charge_costs = list(1000) - O.synths = list(synths_by_kind[MATSYN_DRUGS]) - . += O - - var/obj/item/stack/nanopaste/N = new /obj/item/stack/nanopaste(src) - N.uses_charge = 1 - N.charge_costs = list(1000) - N.synths = list(synths_by_kind[MATSYN_DRUGS]) - . += N - - var/obj/item/stack/medical/advanced/bruise_pack/B = new /obj/item/stack/medical/advanced/bruise_pack(src) - B.uses_charge = 1 - B.charge_costs = list(1000) - B.synths = list(synths_by_kind[MATSYN_DRUGS]) - . += B - -/obj/item/robot_module/robot/medical/surgeon/respawn_consumable(var/mob/living/silicon/robot/R, var/amount) - - var/obj/item/reagent_containers/syringe/S = locate() in src.modules - if(S.mode == 2) - S.reagents.clear_reagents() - S.mode = initial(S.mode) - S.desc = initial(S.desc) - S.update_icon() - - if(src.emag) - var/obj/item/reagent_containers/spray/PS = src.emag - PS.reagents.add_reagent("pacid", 2 * amount) - - ..() - -//Crisis module removed - 5/2/2021 - -/obj/item/robot_module/robot/quad/medi - name = "MediQuad module" - channels = list("Medical" = 1) - networks = list(NETWORK_MEDICAL) - subsystems = list(/mob/living/silicon/proc/subsystem_crew_monitor) - can_be_pushed = 0 - can_shred = TRUE - sprites = list( - "Medical Hound" = "medihound", - "Dark Medical Hound" = "medihounddark", - "Mediborg model V-2" = "vale", - "Borgi" = "borgi-medi", - "F3-LINE" = "FELI-Medical", - "Drake" = "drakemed" - ) - -/obj/item/robot_module/robot/quad/medi/get_modules() - . = ..() - . |= list( - /obj/item/dogborg/jaws/small, //In case a patient is being attacked by carp. - /obj/item/healthanalyzer, // See who's hurt specificially. - /obj/item/autopsy_scanner, - /obj/item/roller_holder, // Sometimes you just can't buckle someone to yourself because of taurcode. this is for those times. - /obj/item/reagent_scanner/adv, - /obj/item/reagent_containers/syringe, //In case the chemist is nice! - /obj/item/reagent_containers/glass/beaker/large,//For holding the chemicals when the chemist is nice - // /obj/item/sleevemate, //Lets them scan people. - /obj/item/shockpaddles/robot/hound, //Paws of life - //New surgery tools + grippers - /obj/item/surgical/scalpel/cyborg, - /obj/item/surgical/hemostat/cyborg, - /obj/item/surgical/retractor/cyborg, - /obj/item/surgical/cautery/cyborg, - /obj/item/surgical/bonegel/cyborg, - /obj/item/surgical/FixOVein/cyborg, - /obj/item/surgical/bonesetter/cyborg, - /obj/item/surgical/circular_saw/cyborg, - /obj/item/surgical/surgicaldrill/cyborg, - /obj/item/gripper/no_use/organ, - /obj/item/gripper/medical, - /obj/item/dogborg/mirrortool - ) - -/obj/item/robot_module/robot/quad/medi/get_synths(mob/living/silicon/robot/R) - . = ..() - MATTER_SYNTH(MATSYN_DRUGS, medicine, 15000) - -/obj/item/robot_module/robot/quad/medi/handle_special_module_init(mob/living/silicon/robot/R) - . = ..() - src.emag = new /obj/item/dogborg/pounce(src) //Pounce - - var/obj/item/reagent_containers/borghypo/hound/H = new /obj/item/reagent_containers/borghypo/hound(src) - H.water = synths_by_kind[MATSYN_WATER] - . += H - - var/obj/item/dogborg/sleeper/B = new /obj/item/dogborg/sleeper(src) //So they can nom people and heal them - B.water = synths_by_kind[MATSYN_WATER] - src.modules += B - - var/medicine = synths_by_kind[MATSYN_DRUGS] - - var/obj/item/stack/nanopaste/P = new /obj/item/stack/nanopaste(src) - P.uses_charge = 1 - P.charge_costs = list(1000) - P.synths = list(medicine) - . += P - - var/obj/item/stack/medical/advanced/ointment/K = new /obj/item/stack/medical/advanced/ointment(src) - K.uses_charge = 1 - K.charge_costs = list(1000) - K.synths = list(medicine) - . += K - - var/obj/item/stack/medical/advanced/bruise_pack/L = new /obj/item/stack/medical/advanced/bruise_pack(src) - L.uses_charge = 1 - L.charge_costs = list(1000) - L.synths = list(medicine) - . += L diff --git a/code/modules/mob/living/silicon/robot/robot_modules/station/misc.dm b/code/modules/mob/living/silicon/robot/robot_modules/station/misc.dm deleted file mode 100644 index bffbbf6c866..00000000000 --- a/code/modules/mob/living/silicon/robot/robot_modules/station/misc.dm +++ /dev/null @@ -1,62 +0,0 @@ -/obj/item/robot_module/robot/standard - name = "standard robot module" - sprites = list( - "M-USE Nanotrasen" = "robot", - "Cabeiri" = "eyebot-standard", - "Haruka" = "marinaSD", - "Usagi" = "tallflower", - "Telemachus" = "toiletbot", - "WTOperator" = "sleekstandard", - "WTOmni" = "omoikane", - "XI-GUS" = "spider", - "XI-ALP" = "heavyStandard", - "Basic" = "robot_old", - "Android" = "droid", - "Drone" = "drone-standard", - "Insekt" = "insekt-Default", - "Misato" = "tall2standard", - "L3P1-D0T" = "Glitterfly-Standard", - "Convict" = "servitor", - "Miss M" = "miss-standard", - "Coffin" = "coffin-Standard", - "X-88" = "xeightyeight-standard", - "Handy" = "handy-standard", - "Acheron" = "mechoid-Standard", - "Shellguard Noble" = "Noble-STD", - "ZOOM-BA" = "zoomba-standard", - "W02M" = "worm-standard" - ) - -/obj/item/robot_module/robot/standard/get_modules() - . = ..() - . |= list( - /obj/item/melee/baton/loaded, - /obj/item/tool/wrench/cyborg, - /obj/item/healthanalyzer - ) - -/obj/item/robot_module/robot/standard/handle_special_module_init(mob/living/silicon/robot/R) - . = ..() - src.emag = new /obj/item/melee/transforming/energy/sword(src) - -/obj/item/robot_module/robot/quad/basic - name = "Standard Quadruped module" - sprites = list( - "F3-LINE" = "FELI-Standard" - ) - can_be_pushed = 0 - -/obj/item/robot_module/robot/quad/basic/get_modules() - . = ..() - . |= list( - /obj/item/melee/baton/loaded, - /obj/item/tool/wrench/cyborg, - /obj/item/healthanalyzer, - /obj/item/dogborg/jaws/small - ) - -/obj/item/robot_module/robot/quad/basic/handle_special_module_init(mob/living/silicon/robot/R) - . = ..() - // These get a larger water synth. - synths_by_kind[MATSYN_WATER]:max_energy = 1000 - src.emag = new /obj/item/melee/transforming/energy/sword(src) diff --git a/code/modules/mob/living/silicon/robot/robot_modules/station/science.dm b/code/modules/mob/living/silicon/robot/robot_modules/station/science.dm deleted file mode 100644 index c137be97935..00000000000 --- a/code/modules/mob/living/silicon/robot/robot_modules/station/science.dm +++ /dev/null @@ -1,135 +0,0 @@ -/obj/item/robot_module/robot/research - name = "research module" - channels = list("Science" = 1) - sprites = list( - "L'Ouef" = "peaceborg", - "Cabeiri" = "eyebot-science", - "Haruka" = "marinaSCI", - "WTDove" = "whitespider", - "WTOperator" = "sleekscience", - "Droid" = "droid-science", - "Drone" = "drone-science", - "Handy" = "handy-science", - "Insekt" = "insekt-Sci", - "L3P1-D0T" = "Glitterfly-Research", - "Coffsearch" = "coffin-Research", - "X-88" = "xeightyeight-science", - "Acheron" = "mechoid-Science", - "ZOOM-BA" = "zoomba-research", - "W02M" = "worm-engineering" - ) - -/obj/item/robot_module/robot/research/get_synths() - . = ..() - MATTER_SYNTH(MATSYN_NANITES, nanite, 10000) - MATTER_SYNTH(MATSYN_WIRE, wire) - -/obj/item/robot_module/robot/research/get_modules() - . = ..() - . |= list( - /obj/item/portable_destructive_analyzer, - /obj/item/gripper/research, - /obj/item/gripper/circuit, - /obj/item/gripper/no_use/organ/robotics, - /obj/item/gripper/no_use/mech, - /obj/item/gripper/no_use/loader, - /obj/item/robotanalyzer, - /obj/item/card/robot, - /obj/item/weldingtool/electric/mounted/cyborg, - /obj/item/tool/screwdriver/cyborg, - /obj/item/tool/wrench/cyborg, - /obj/item/tool/wirecutters/cyborg, - /obj/item/multitool, - /obj/item/surgical/scalpel/cyborg, - /obj/item/surgical/circular_saw/cyborg, - /obj/item/reagent_containers/syringe, - /obj/item/reagent_containers/glass/beaker/large, - /obj/item/storage/part_replacer, - /obj/item/shockpaddles/robot, - /obj/item/melee/baton/slime/robot, - /obj/item/gun/projectile/energy/taser/xeno/robot - ) - -/obj/item/robot_module/robot/research/handle_special_module_init(mob/living/silicon/robot/R) - . = ..() - src.emag = new /obj/item/borg/combat/shield(src) - - var/obj/item/stack/nanopaste/N = new /obj/item/stack/nanopaste(src) - N.uses_charge = 1 - N.charge_costs = list(1000) - N.synths = list(synths_by_kind[MATSYN_NANITES]) - src.modules += N - - CYBORG_STACK(cable_coil/cyborg, list(MATSYN_WIRE)) - -/obj/item/robot_module/robot/research/respawn_consumable(var/mob/living/silicon/robot/R, var/amount) - - var/obj/item/reagent_containers/syringe/S = locate() in src.modules - if(S.mode == 2) - S.reagents.clear_reagents() - S.mode = initial(S.mode) - S.desc = initial(S.desc) - S.update_icon() - - ..() - -/obj/item/robot_module/robot/quad/sci - name = "SciQuad Module" - sprites = list( - "Research Hound" = "science", - "Borgi" = "borgi-sci", - "F3-LINE" = "FELI-Research", - "Sci-9" = "scihound", - "Sci-9 Dark" = "scihounddark" - ) - channels = list("Science" = 1) - can_be_pushed = 0 - can_shred = TRUE - -/obj/item/robot_module/robot/quad/sci/get_modules() - . = ..() - . |= list( - /obj/item/portable_destructive_analyzer, - /obj/item/dogborg/jaws/small, - /obj/item/gripper/research, - /obj/item/gripper/circuit, - /obj/item/gripper/no_use/organ/robotics, - /obj/item/gripper/no_use/mech, - /obj/item/gripper/no_use/loader, - /obj/item/tool/screwdriver/cyborg, - /obj/item/tool/wrench/cyborg, - /obj/item/robotanalyzer, - /obj/item/weldingtool/electric/mounted/cyborg, - /obj/item/multitool, - /obj/item/reagent_containers/glass/beaker/large, - /obj/item/reagent_containers/syringe, - /obj/item/storage/part_replacer, - /obj/item/card/robot, - /obj/item/shockpaddles/robot, - /obj/item/tool/wirecutters/cyborg, - /obj/item/melee/baton/slime/robot, - /obj/item/gun/projectile/energy/taser/xeno/robot, - /obj/item/surgical/scalpel/cyborg, - /obj/item/surgical/circular_saw/cyborg - ) - -/obj/item/robot_module/robot/quad/sci/get_synths() - . = ..() - MATTER_SYNTH(MATSYN_NANITES, nanite, 10000) - MATTER_SYNTH(MATSYN_WIRE, wire) - -/obj/item/robot_module/robot/quad/sci/handle_special_module_init(mob/living/silicon/robot/R) - . = ..() - var/obj/item/stack/nanopaste/N = new /obj/item/stack/nanopaste(src) - N.uses_charge = 1 - N.charge_costs = list(1000) - N.synths = list(synths_by_kind[MATSYN_NANITES]) - . += N - - var/obj/item/dogborg/sleeper/compactor/analyzer/B = new /obj/item/dogborg/sleeper/compactor/analyzer(src) - B.water = synths_by_kind[MATSYN_WATER] - . += B - - CYBORG_STACK(cable_coil/cyborg, list(MATSYN_WIRE)) - - src.emag = new /obj/item/borg/combat/shield(src) diff --git a/code/modules/mob/living/silicon/robot/robot_modules/station/security.dm b/code/modules/mob/living/silicon/robot/robot_modules/station/security.dm deleted file mode 100644 index 0a69cceab68..00000000000 --- a/code/modules/mob/living/silicon/robot/robot_modules/station/security.dm +++ /dev/null @@ -1,180 +0,0 @@ -/obj/item/robot_module/robot/security - name = "security robot module" - channels = list("Security" = 1) - networks = list(NETWORK_SECURITY) - subsystems = list(/mob/living/silicon/proc/subsystem_crew_monitor) - can_be_pushed = 0 - supported_upgrades = list(/obj/item/borg/upgrade/tasercooler) - is_the_law = TRUE - -/obj/item/robot_module/robot/security/general - sprites = list( - "M-USE Nanotrasen" = "robotSecy", - "Cabeiri" = "eyebot-security", - "Cerberus" = "bloodhound", - "Cerberus - Treaded" = "treadhound", - "Haruka" = "marinaSC", - "Usagi" = "tallred", - "Telemachus" = "toiletbotsecurity", - "WTOperator" = "sleeksecurity", - "XI-GUS" = "spidersec", - "XI-ALP" = "heavySec", - "Basic" = "secborg", - "Black Knight" = "securityrobot", - "Drone" = "drone-sec", - "Insekt" = "insekt-Sec", - "Misato" = "tall2security", - "L3P1-D0T" = "Glitterfly-Security", - "Miss M" = "miss-security", - "Coffcurity" = "coffin-Combat", - "Handy" = "handy-sec", - "Acheron" = "mechoid-Security", - "Shellguard Noble" = "Noble-SEC", - "ZOOM-BA" = "zoomba-security", - "W02M" = "worm-security" - ) - -/obj/item/robot_module/robot/security/general/get_modules() - . = ..() - . |= list( - /obj/item/handcuffs/cyborg, - /obj/item/melee/baton/robot, - /obj/item/gun/projectile/energy/taser/mounted/cyborg, - /obj/item/barrier_tape_roll/police, - /obj/item/reagent_containers/spray/pepper, - /obj/item/gripper/security - ) - -/obj/item/robot_module/robot/security/general/handle_special_module_init(mapload) - . = ..() - src.emag = new /obj/item/gun/projectile/energy/laser/mounted(src) - -/obj/item/robot_module/robot/security/respawn_consumable(var/mob/living/silicon/robot/R, var/amount) - var/obj/item/flash/F = locate() in src.modules - if(F.broken) - F.broken = 0 - F.times_used = 0 - F.icon_state = "flash" - else if(F.times_used) - F.times_used-- - var/obj/item/gun/projectile/energy/taser/mounted/cyborg/T = locate() in src.modules - if(T.obj_cell_slot.cell.charge < T.obj_cell_slot.cell.max_charge) - T.obj_cell_slot.cell.give(T.charge_cost * amount) - T.update_icon() - else - T.charge_tick = 0 - -/obj/item/robot_module/robot/security/combat - name = "combat robot module" - hide_on_manifest = 1 - sprites = list( - "Haruka" = "marinaCB", - "Cabeiri" = "eyebot-combat", - "Combat Android" = "droid-combat", - "Insekt" = "insekt-Combat", - "Acheron" = "mechoid-Combat", - "ZOOM-BA" = "zoomba-combat" - ) - -/obj/item/robot_module/robot/security/combat/get_modules() - . = ..() - . |= list( - /obj/item/flash, - // /obj/item/borg/sight/thermal, - /obj/item/gun/projectile/energy/laser/mounted, - /obj/item/pickaxe/plasmacutter, - /obj/item/borg/combat/shield, - /obj/item/borg/combat/mobility, - ) - -/obj/item/robot_module/robot/security/combat/handle_special_module_init(mob/living/silicon/robot/R) - . = ..() - src.emag = new /obj/item/gun/projectile/energy/lasercannon/mounted(src) - -/obj/item/robot_module/robot/quad/sec - name = "SecuriQuad module" - sprites = list( - "K9 hound" = "k9", - "K9 Alternative" = "k92", - "Secborg model V-2" = "secborg", - "Borgi" = "borgi-sec", - "Otieborg" = "oties", - "F3-LINE" = "FELI-Security", - "Drake" = "drakesec" - ) - channels = list("Security" = 1) - networks = list(NETWORK_SECURITY) - can_be_pushed = 0 - is_the_law = TRUE - can_shred = TRUE - supported_upgrades = list(/obj/item/borg/upgrade/tasercooler) - -/obj/item/robot_module/robot/quad/sec/get_modules() - . = ..() - . |= list( - /obj/item/handcuffs/cyborg, //You need cuffs to be a proper sec borg! - /obj/item/dogborg/jaws/big, //In case there's some kind of hostile mob. - /obj/item/melee/baton/robot, //Since the pounce module refused to work, they get a stunbaton instead. - /obj/item/barrier_tape_roll/police, //Block out crime scenes. - /obj/item/gun/projectile/energy/taser/mounted/cyborg, //They /are/ a security borg, after all. - /obj/item/dogborg/pounce //Pounce - ) - -/obj/item/robot_module/robot/quad/sec/handle_special_module_init(mob/living/silicon/robot/R) - . = ..() - src.emag = new /obj/item/gun/projectile/energy/laser/mounted(src) //Emag. Not a big problem. - - var/obj/item/dogborg/sleeper/K9/B = new /obj/item/dogborg/sleeper/K9(src) //Eat criminals. Bring them to the brig. - B.water = synths_by_kind[MATSYN_WATER] - src.modules += B - -/obj/item/robot_module/robot/quad/sec/respawn_consumable(var/mob/living/silicon/robot/R, var/amount) - var/obj/item/flash/F = locate() in src.modules - if(F.broken) - F.broken = 0 - F.times_used = 0 - F.icon_state = "flash" - else if(F.times_used) - F.times_used-- - var/obj/item/gun/projectile/energy/taser/mounted/cyborg/T = locate() in src.modules - if(T.obj_cell_slot.cell.charge < T.obj_cell_slot.cell.max_charge) - T.obj_cell_slot.cell.give(T.charge_cost * amount) - T.update_icon() - else - T.charge_tick = 0 - /*var/obj/item/melee/baton/robot/B = locate() in src.modules //Borg baton uses borg cell. - if(B && B.bcell) - B.bcell.give(amount)*/ - -/obj/item/robot_module/robot/quad/ert - name = "Emergency Response module" - channels = list("Security" = 1) - networks = list(NETWORK_SECURITY) - can_be_pushed = 0 - sprites = list( - "Standard" = "ert", - "Borgi" = "borgi", - "F3-LINE" = "FELI-Combat" - ) - - can_shred = TRUE - -/obj/item/robot_module/robot/quad/ert/get_modules() - . = ..() - . |= list( - /obj/item/handcuffs/cyborg, - /obj/item/dogborg/jaws/big, - /obj/item/melee/baton/robot, - /obj/item/barrier_tape_roll/police, - /obj/item/gun/projectile/energy/taser/mounted/cyborg, - /obj/item/dogborg/swordtail - ) - -/obj/item/robot_module/robot/quad/ert/handle_special_module_init(mob/living/silicon/robot/R) - . = ..() - - src.emag = new /obj/item/gun/projectile/energy/laser/mounted(src) - - var/obj/item/dogborg/sleeper/K9/B = new /obj/item/dogborg/sleeper/K9(src) - B.water = synths_by_kind[MATSYN_WATER] - . += B diff --git a/code/modules/mob/living/silicon/robot/robot_modules/station/service.dm b/code/modules/mob/living/silicon/robot/robot_modules/station/service.dm deleted file mode 100644 index 5430323015f..00000000000 --- a/code/modules/mob/living/silicon/robot/robot_modules/station/service.dm +++ /dev/null @@ -1,341 +0,0 @@ -/obj/item/robot_module/robot/janitor - name = "janitorial robot module" - channels = list("Service" = 1) - sprites = list( - "M-USE Nanotrasen" = "robotJani", - "Arachne" = "crawler", - "Cabeiri" = "eyebot-janitor", - "Haruka" = "marinaJN", - "Telemachus" = "toiletbotjanitor", - "WTOperator" = "sleekjanitor", - "XI-ALP" = "heavyRes", - "Basic" = "JanBot2", - "Mopbot" = "janitorrobot", - "Mop Gear Rex" = "mopgearrex", - "Drone" = "drone-janitor", - "Misato" = "tall2janitor", - "L3P1-D0T" = "Glitterfly-Janitor", - "Miss M" = "miss-janitor", - "Cleriffin" = "coffin-Clerical", - "Coffstodial" = "coffin-Custodial", - "Handy" = "handy-janitor", - "Acheron" = "mechoid-Janitor", - "Shellguard Noble" = "Noble-CLN", - "ZOOM-BA" = "zoomba-janitor", - "W02M" = "worm-janitor" - ) - -/obj/item/robot_module/robot/janitor/get_modules() - . = ..() - . |= list( - /obj/item/soap/nanotrasen, - /obj/item/storage/bag/trash, - /obj/item/mop, - /obj/item/lightreplacer - ) - -/obj/item/robot_module/robot/janitor/handle_special_module_init(mob/living/silicon/robot/R) - . = ..() - src.emag = new /obj/item/reagent_containers/spray(src) - src.emag.reagents.add_reagent("lube", 250) - src.emag.name = "Lube spray" - -/obj/item/robot_module/robot/janitor/respawn_consumable(var/mob/living/silicon/robot/R, var/amount) - var/obj/item/lightreplacer/LR = locate() in src.modules - LR.Charge(R, amount) - if(src.emag) - var/obj/item/reagent_containers/spray/S = src.emag - S.reagents.add_reagent("lube", 2 * amount) - -/obj/item/robot_module/robot/clerical - name = "service robot module" - channels = list("Service" = 1) - languages = list( - LANGUAGE_AKHANI = 1, - LANGUAGE_BIRDSONG = 1, - LANGUAGE_CANILUNZT = 1, - LANGUAGE_DAEMON = 1, - LANGUAGE_EAL = 1, - LANGUAGE_ECUREUILIAN= 1, - LANGUAGE_ENOCHIAN = 1, - LANGUAGE_GUTTER = 1, - LANGUAGE_ROOTLOCAL = 0, - LANGUAGE_SAGARU = 1, - LANGUAGE_SCHECHI = 1, - LANGUAGE_SIGN = 0, - LANGUAGE_SIIK = 1, - LANGUAGE_SKRELLIAN = 1, - LANGUAGE_SKRELLIANFAR = 0, - LANGUAGE_SOL_COMMON = 1, - LANGUAGE_SQUEAKISH = 1, - LANGUAGE_TERMINUS = 1, - LANGUAGE_TRADEBAND = 1, - LANGUAGE_UNATHI = 1, - LANGUAGE_ZADDAT = 1 - ) - -/obj/item/robot_module/robot/clerical/butler - sprites = list( - "M-USE Nanotrasen" = "robotServ", - "Cabeiri" = "eyebot-standard", - "Haruka" = "marinaSV", - "Michiru" = "maidbot", - "Usagi" = "tallgreen", - "Telemachus" = "toiletbot", - "WTOperator" = "sleekservice", - "WTOmni" = "omoikane", - "XI-GUS" = "spider", - "XI-ALP" = "heavyServ", - "Standard" = "Service2", - "Waitress" = "Service", - "Bro" = "Brobot", - "Rich" = "maximillion", - "Drone - Service" = "drone-service", - "Drone - Hydro" = "drone-hydro", - "Misato" = "tall2service", - "L3P1-D0T" = "Glitterfly-Service", - "Miss M" = "miss-service", - "Handy - Service" = "handy-service", - "Handy - Hydro" = "handy-hydro", - "Acheron" = "mechoid-Service", - "Shellguard Noble" = "Noble-SRV", - "ZOOM-BA" = "zoomba-service", - "W02M" = "worm-service" - ) - -/obj/item/robot_module/robot/clerical/butler/Initialize(mapload) - . = ..() - src.modules += new /obj/item/gripper/service(src) - src.modules += new /obj/item/reagent_containers/glass/bucket(src) - src.modules += new /obj/item/material/minihoe(src) - src.modules += new /obj/item/material/knife/machete/hatchet(src) - src.modules += new /obj/item/plant_analyzer(src) - src.modules += new /obj/item/storage/bag/plants(src) - src.modules += new /obj/item/robot_harvester(src) - src.modules += new /obj/item/material/knife(src) - src.modules += new /obj/item/material/kitchen/rollingpin(src) - src.modules += new /obj/item/multitool(src) //to freeze trays - - var/obj/item/rsf/M = new /obj/item/rsf(src) - M.stored_matter = 30 - src.modules += M - - src.modules += new /obj/item/reagent_containers/dropper/industrial(src) - - var/obj/item/flame/lighter/zippo/L = new /obj/item/flame/lighter/zippo(src) - L.lit = 1 - src.modules += L - - src.modules += new /obj/item/tray/robotray(src) - src.modules += new /obj/item/reagent_containers/borghypo/service(src) - src.emag = new /obj/item/reagent_containers/food/drinks/bottle/small/beer(src) - - var/datum/reagent_holder/R = new/datum/reagent_holder(50) - src.emag.reagents = R - R.my_atom = src.emag - R.add_reagent("beer2", 50) - src.emag.name = "Mickey Finn's Special Brew" - -/obj/item/robot_module/robot/clerical/butler/respawn_consumable(var/mob/living/silicon/robot/R, var/amount) - var/obj/item/reagent_containers/food/condiment/enzyme/E = locate() in src.modules - E.reagents.add_reagent("enzyme", 2 * amount) - if(src.emag) - var/obj/item/reagent_containers/food/drinks/bottle/small/beer/B = src.emag - B.reagents.add_reagent("beer2", 2 * amount) - -/obj/item/robot_module/robot/clerical/general - name = "clerical robot module" - sprites = list( - "M-USE Nanotrasen" = "robotCler", - "Cabeiri" = "eyebot-standard", - "Haruka" = "marinaSV", - "Usagi" = "tallgreen", - "Telemachus" = "toiletbot", - "WTOperator" = "sleekclerical", - "WTOmni" = "omoikane", - "XI-GUS" = "spidercom", - "XI-ALP" = "heavyServ", - "Waitress" = "Service", - "Bro" = "Brobot", - "Rich" = "maximillion", - "Default" = "Service2", - "Drone" = "drone-blu", - "Misato" = "tall2service", - "L3P1-D0T" = "Glitterfly-Clerical", - "Miss M" = "miss-service", - "Handy" = "handy-clerk", - "Acheron" = "mechoid-Service", - "Shellguard Noble" = "Noble-SRV", - "ZOOM-BA" = "zoomba-clerical", - "W02M" = "worm-service" - ) - -/obj/item/robot_module/robot/clerical/general/get_modules() - . = ..() - . |= list( - /obj/item/pen/robopen, - /obj/item/form_printer, - /obj/item/gripper/paperwork, - /obj/item/hand_labeler, - /obj/item/stamp, - /obj/item/stamp/denied - ) - -/obj/item/robot_module/robot/clerical/general/handle_special_module_init(mob/living/silicon/robot/R) - . = ..() - // cba to make emags support more than one item - if (prob(50)) - src.emag = new /obj/item/stamp/chameleon(src) - else - src.emag = new /obj/item/pen/chameleon(src) - -/obj/item/robot_module/robot/quad/jani - name = "JaniQuad module" - sprites = list( - "Custodial Hound" = "scrubpup", - "Borgi" = "borgi-jani", - "Otieborg" = "otiej", - "Janihound, J9" = "J9", - "F3-LINE" = "FELI-Janitor", - "Drake" = "drakejanit" - ) - channels = list("Service" = 1) - can_be_pushed = 0 - can_shred = TRUE - -/obj/item/robot_module/robot/quad/jani/get_modules() - . = ..() - . |= list( - /obj/item/dogborg/jaws/small, - /obj/item/pupscrubber - ) - -/obj/item/robot_module/robot/quad/jani/get_synths() - . = ..() - //Starts empty. Can only recharge with recycled material. - .[MATSYN_METAL] = new /datum/matter_synth/metal { - name = "Steel reserves"; - recharge_rate = 0; - max_energy = 50000; - energy = 0; - } - - .[MATSYN_GLASS] = new /datum/matter_synth/glass { - name = "Glass reserves"; - recharge_rate = 0; - max_energy = 50000; - energy = 0; - } - -/obj/item/robot_module/robot/quad/jani/handle_special_module_init(mob/living/silicon/robot/R) - . = ..() - - src.emag = new /obj/item/dogborg/pounce(src) //Pounce - - var/obj/item/lightreplacer/dogborg/LR = new /obj/item/lightreplacer/dogborg(src) - LR.glass = synths_by_kind[MATSYN_GLASS] - . += LR - - var/obj/item/dogborg/sleeper/compactor/C = new /obj/item/dogborg/sleeper/compactor(src) - C.metal = synths_by_kind[MATSYN_METAL] - C.glass = synths_by_kind[MATSYN_GLASS] - C.water = synths_by_kind[MATSYN_WATER] - . += C - - //Sheet refiners can only produce raw sheets. - var/obj/item/stack/material/cyborg/steel/M = new (src) - M.name = "steel recycler" - M.desc = "A device that refines recycled steel into sheets." - M.synths = list(synths_by_kind[MATSYN_METAL]) - M.explicit_recipes = list( - create_stack_recipe_datum(name = "steel sheet", product = /obj/item/stack/material/steel, cost = 1) - ) - . += M - - var/obj/item/stack/material/cyborg/glass/G = new (src) - G.name = "glass recycler" - G.desc = "A device that refines recycled glass into sheets." - G.allow_window_autobuild = FALSE - G.synths = list(synths_by_kind[MATSYN_GLASS]) - M.explicit_recipes = list( - create_stack_recipe_datum(name = "glass sheet", product = /obj/item/stack/material/glass, cost = 1) - ) - . += G - -// Uses modified K9 sprites. -/obj/item/robot_module/robot/quad/serv - name = "Service Quadruped module" - sprites = list( - "Blackhound" = "k50", - "Pinkhound" = "k69", - "ServicehoundV2" = "serve2", - "ServicehoundV2 Darkmode" = "servedark", - "F3-LINE" = "FELI-Service" - ) - languages = list( - LANGUAGE_AKHANI = 1, - LANGUAGE_BIRDSONG = 1, - LANGUAGE_CANILUNZT = 1, - LANGUAGE_DAEMON = 1, - LANGUAGE_EAL = 1, - LANGUAGE_ECUREUILIAN= 1, - LANGUAGE_ENOCHIAN = 1, - LANGUAGE_GUTTER = 1, - LANGUAGE_ROOTLOCAL = 0, - LANGUAGE_SAGARU = 1, - LANGUAGE_SCHECHI = 1, - LANGUAGE_SIGN = 0, - LANGUAGE_SIIK = 1, - LANGUAGE_SKRELLIAN = 1, - LANGUAGE_SKRELLIANFAR = 0, - LANGUAGE_SOL_COMMON = 1, - LANGUAGE_SQUEAKISH = 1, - LANGUAGE_TERMINUS = 1, - LANGUAGE_TRADEBAND = 1, - LANGUAGE_UNATHI = 1, - LANGUAGE_ZADDAT = 1 - ) - channels = list("Service" = 1) - can_be_pushed = 0 - -/obj/item/robot_module/robot/quad/serv/get_modules() - . = ..() - . |= list( - /obj/item/gripper/service, - /obj/item/reagent_containers/glass/bucket, - /obj/item/material/minihoe, - /obj/item/material/knife/machete/hatchet, - /obj/item/plant_analyzer, - /obj/item/storage/bag/dogborg, - /obj/item/robot_harvester, - /obj/item/material/knife, - /obj/item/material/kitchen/rollingpin, - /obj/item/multitool, //to freeze trays - /obj/item/dogborg/jaws/small, - /obj/item/reagent_containers/dropper/industrial, - /obj/item/tray/robotray, - /obj/item/reagent_containers/borghypo/service, - /obj/item/storage/bag/trash - ) - -// In a nutshell, basicly service/butler robot but in dog form. -/obj/item/robot_module/robot/quad/serv/handle_special_module_init(mob/living/silicon/robot/R) - . = ..() - src.emag = new /obj/item/dogborg/pounce(src) - - // These get a larger water synth. - synths_by_kind[MATSYN_WATER]:max_energy = 1000 - - var/obj/item/rsf/M = new /obj/item/rsf(src) - M.stored_matter = 30 - . += M - - var/obj/item/flame/lighter/zippo/L = new /obj/item/flame/lighter/zippo(src) - L.lit = 1 - . += L - -/* // I don't know what kind of sleeper to put here, but also no need if you already have "Robot Nom" verb. - var/obj/item/dogborg/sleeper/K9/B = new /obj/item/dogborg/sleeper/K9(src) - B.water = water - src.modules += B -*/ diff --git a/code/modules/mob/living/silicon/robot/robot_modules/swarm.dm b/code/modules/mob/living/silicon/robot/robot_modules/swarm.dm deleted file mode 100644 index 6f0b333461e..00000000000 --- a/code/modules/mob/living/silicon/robot/robot_modules/swarm.dm +++ /dev/null @@ -1,30 +0,0 @@ -/obj/item/robot_module/drone/swarm - name = "swarm drone module" - var/id - -/obj/item/robot_module/drone/swarm/get_modules() - . = ..() - . |= list( - /obj/item/rcd/electric/mounted/borg/swarm, - /obj/item/flash/robot, - /obj/item/handcuffs/cable/tape/cyborg, - /obj/item/melee/baton/robot, - /obj/item/gun/projectile/energy/taser/mounted/cyborg/swarm, - /obj/item/matter_decompiler/swarm - ) - -/obj/item/robot_module/drone/swarm/handle_special_module_init(mob/living/silicon/robot/robot) - . = ..() - id = robot.idcard - . += id - -/obj/item/robot_module/drone/swarm/ranged - name = "swarm gunner module" - -/obj/item/robot_module/drone/swarm/ranged/get_modules() - . = ..() - . |= /obj/item/gun/projectile/energy/xray/swarm - -/obj/item/robot_module/drone/swarm/melee/get_modules() - . = ..() - . |= /obj/item/melee/transforming/energy/sword/ionic_rapier/lance diff --git a/code/modules/mob/living/silicon/robot/robot_modules/syndicate.dm b/code/modules/mob/living/silicon/robot/robot_modules/syndicate.dm deleted file mode 100644 index fe62f1f7991..00000000000 --- a/code/modules/mob/living/silicon/robot/robot_modules/syndicate.dm +++ /dev/null @@ -1,220 +0,0 @@ -/* Syndicate modules */ - -/obj/item/robot_module/robot/syndicate - name = "illegal robot module" - hide_on_manifest = 1 - languages = list( - LANGUAGE_SOL_COMMON = 1, - LANGUAGE_TRADEBAND = 1, - LANGUAGE_UNATHI = 0, - LANGUAGE_SIIK = 0, - LANGUAGE_AKHANI = 0, - LANGUAGE_SKRELLIAN = 0, - LANGUAGE_SKRELLIANFAR = 0, - LANGUAGE_ROOTLOCAL = 0, - LANGUAGE_GUTTER = 1, - LANGUAGE_SCHECHI = 0, - LANGUAGE_EAL = 1, - LANGUAGE_SIGN = 0, - LANGUAGE_TERMINUS = 1, - LANGUAGE_ZADDAT = 0 - ) - sprites = list( - "Cerberus" = "syndie_bloodhound", - "Cerberus - Treaded" = "syndie_treadhound", - "Ares" = "squats", - "Telemachus" = "toiletbotantag", - "WTOperator" = "hosborg", - "XI-GUS" = "spidersyndi", - "XI-ALP" = "syndi-heavy" - ) - var/id - -// All syndie modules get these, and the base borg items (flash, crowbar, etc). -/obj/item/robot_module/robot/syndicate/get_modules() - . = ..() - . |= list( - /obj/item/pinpointer/shuttle/merc, - /obj/item/melee/transforming/energy/sword - ) - -/obj/item/robot_module/robot/syndicate/handle_special_module_init(mob/living/silicon/robot/R) - . = ..() - var/jetpack = new/obj/item/tank/jetpack/carbondioxide(src) - . += jetpack - R.internals = jetpack - - id = R.idcard - . += id - -/obj/item/robot_module/robot/syndicate/Destroy() - src.modules -= id - id = null - return ..() - -// Gets a big shield and a gun that shoots really fast to scare the opposing force. -/obj/item/robot_module/robot/syndicate/protector - name = "protector robot module" - sprites = list( - "Cerberus - Treaded" = "syndie_treadhound", - "Cerberus" = "syndie_bloodhound", - "Ares" = "squats", - "XI-ALP" = "syndi-heavy" - ) - -/obj/item/robot_module/robot/syndicate/protector/get_modules() - . = ..() - . |= list( - /obj/item/shield_projector/rectangle/weak, - /obj/item/gun/projectile/energy/dakkalaser, - /obj/item/handcuffs/cyborg, - /obj/item/melee/baton/robot - ) - -// 95% engi-borg and 15% roboticist. -/obj/item/robot_module/robot/syndicate/mechanist - name = "mechanist robot module" - sprites = list( - "XI-GUS" = "spidersyndi", - "WTOperator" = "sleekhos" - ) - -/obj/item/robot_module/robot/syndicate/mechanist/get_modules() - . = ..() - . |= list( - /obj/item/borg/sight/meson, - /obj/item/weldingtool/electric/mounted/cyborg, - /obj/item/tool/screwdriver/cyborg, - /obj/item/tool/wrench/cyborg, - /obj/item/tool/wirecutters/cyborg, - /obj/item/multitool/ai_detector, - /obj/item/pickaxe/plasmacutter, - /obj/item/rcd/electric/mounted/borg/lesser, // Can't eat rwalls to prevent AI core cheese. - /obj/item/melee/transforming/energy/sword/ionic_rapier, - - // FBP repair. - /obj/item/robotanalyzer, - /obj/item/shockpaddles/robot, - /obj/item/gripper/no_use/organ/robotics, - - // Hacking other things. - /obj/item/card/robot/syndi, - /obj/item/card/emag - ) - -/obj/item/robot_module/robot/syndicate/mechanist/get_synths(mob/living/silicon/robot/R) - . = ..() - MATTER_SYNTH(MATSYN_NANITES, nanite, 10000) - MATTER_SYNTH(MATSYN_WIRE, wire) - MATTER_SYNTH(MATSYN_METAL, metal, 40000) - MATTER_SYNTH(MATSYN_GLASS, glass, 40000) - -/obj/item/robot_module/robot/syndicate/mechanist/handle_special_module_init(mob/living/silicon/robot/R) - . = ..() - // General engineering/hacking. - - // Materials. - var/datum/matter_synth/nanite = synths_by_kind[MATSYN_NANITES] - var/datum/matter_synth/wire = synths_by_kind[MATSYN_WIRE] - var/datum/matter_synth/metal = synths_by_kind[MATSYN_METAL] - var/datum/matter_synth/glass = synths_by_kind[MATSYN_GLASS] - - var/obj/item/stack/nanopaste/N = new /obj/item/stack/nanopaste(src) - N.uses_charge = 1 - N.charge_costs = list(1000) - N.synths = list(nanite) - . += N - - var/obj/item/stack/material/cyborg/steel/M = new (src) - M.synths = list(metal) - . += M - - var/obj/item/stack/material/cyborg/glass/G = new (src) - G.synths = list(glass) - . += G - - var/obj/item/stack/rods/cyborg/rods = new /obj/item/stack/rods/cyborg(src) - rods.synths = list(metal) - . += rods - - var/obj/item/stack/cable_coil/cyborg/C = new /obj/item/stack/cable_coil/cyborg(src) - C.synths = list(wire) - . += C - - var/obj/item/stack/material/cyborg/glass/reinforced/RG = new (src) - RG.synths = list(metal, glass) - . += RG - - -// Mediborg optimized for on-the-field healing, but can also do surgery if needed. -/obj/item/robot_module/robot/syndicate/combat_medic - name = "combat medic robot module" - sprites = list( - "Telemachus" = "toiletbotantag" - ) - -/obj/item/robot_module/robot/syndicate/combat_medic/get_modules() - . = ..() - . |= list( - /obj/item/borg/sight/hud/med, - /obj/item/healthanalyzer/advanced, - /obj/item/reagent_containers/borghypo/merc, - - // Surgery things. - /obj/item/autopsy_scanner, - /obj/item/surgical/scalpel/cyborg, - /obj/item/surgical/hemostat/cyborg, - /obj/item/surgical/retractor/cyborg, - /obj/item/surgical/cautery/cyborg, - /obj/item/surgical/bonegel/cyborg, - /obj/item/surgical/FixOVein/cyborg, - /obj/item/surgical/bonesetter/cyborg, - /obj/item/surgical/circular_saw/cyborg, - /obj/item/surgical/surgicaldrill/cyborg, - /obj/item/gripper/no_use/organ, - - // General healing. - /obj/item/gripper/medical, - /obj/item/shockpaddles/robot/combat, - /obj/item/reagent_containers/dropper, // Allows borg to fix necrosis apparently - /obj/item/reagent_containers/syringe, - /obj/item/roller_holder - ) - -/obj/item/robot_module/robot/syndicate/combat_medic/get_synths(mob/living/silicon/robot/R) - . = ..() - MATTER_SYNTH(MATSYN_DRUGS, medicine, 15000) - -/obj/item/robot_module/robot/syndicate/combat_medic/Initialize(mapload) - . = ..() - - // Materials. - var/datum/matter_synth/medicine = synths_by_kind[MATSYN_DRUGS] - - var/obj/item/stack/medical/advanced/ointment/O = new /obj/item/stack/medical/advanced/ointment(src) - O.uses_charge = 1 - O.charge_costs = list(1000) - O.synths = list(medicine) - . += O - - var/obj/item/stack/medical/advanced/bruise_pack/B = new /obj/item/stack/medical/advanced/bruise_pack(src) - B.uses_charge = 1 - B.charge_costs = list(1000) - B.synths = list(medicine) - . += B - - var/obj/item/stack/medical/splint/S = new /obj/item/stack/medical/splint(src) - S.uses_charge = 1 - S.charge_costs = list(1000) - S.synths = list(medicine) - . += S - -/obj/item/robot_module/robot/syndicate/combat_medic/respawn_consumable(var/mob/living/silicon/robot/R, var/amount) - - var/obj/item/reagent_containers/syringe/S = locate() in src.modules - if(S.mode == 2) - S.reagents.clear_reagents() - S.mode = initial(S.mode) - S.desc = initial(S.desc) - S.update_icon() - ..() diff --git a/code/modules/mob/living/silicon/robot/robot_provisioning.dm b/code/modules/mob/living/silicon/robot/robot_provisioning.dm new file mode 100644 index 00000000000..3d031c4ba44 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/robot_provisioning.dm @@ -0,0 +1,228 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2025 Citadel Station Developers *// + +/** + * Tracks what items / whatnot are given from what, so + * partial state changes are doable without rebuilding the entire robot's + * state. + * + * # Caveats + * * Internal state (items in us, as an example) should not be mutated without calling helpers, + * or adding / removing. + * * Can only exist for one borg at a time. + */ +/datum/robot_provisioning + /// Applied + var/mob/living/silicon/robot/applied_to_robot + /// provisioned items / modules + /// * lazy list + var/list/obj/item/items + /// provisioned emag-only items/modules + /// * lazy list + /// TODO: legacy, stop using this, emags unlocking functionality + /// should be handled literally any other way including just another provisioning datum + var/list/obj/item/emag_items + /// suppressed items, item = true ? + /// * suppressed items aren't accessible by the robot (but still exist in them) + var/list/obj/item/suppressed_items + /// relay mount + var/datum/item_mount/robot_provisioning/relay_mount + /// emaged status? + var/emag_enabled = FALSE + +/datum/robot_provisioning/New() + relay_mount = new(src) + +/datum/robot_provisioning/Destroy() + if(applied_to_robot) + remove() + QDEL_LIST(items) + QDEL_LIST(emag_items) + QDEL_NULL(relay_mount) + return ..() + +/datum/robot_provisioning/proc/apply(mob/living/silicon/robot/robot) + if(applied_to_robot) + remove() + applied_to_robot = robot + emag_enabled = robot.emag_items + for(var/obj/item/item as anything in items) + if(suppressed_items?[item]) + continue + robot.robot_inventory?.inv_register(item) + if(item.loc != robot) + item.forceMove(robot) + if(emag_enabled) + for(var/obj/item/item as anything in emag_items) + if(suppressed_items?[item]) + continue + robot.robot_inventory?.inv_register(item) + if(item.loc != robot) + item.forceMove(robot) + +/datum/robot_provisioning/proc/remove() + if(!applied_to_robot) + return + var/atom/where_to_dump = get_detached_storage_location() + for(var/obj/item/item as anything in items) + applied_to_robot.robot_inventory?.inv_register(item) + if(item.loc != where_to_dump) + if(where_to_dump) + item.forceMove(where_to_dump) + else + item.moveToNullspace() + if(emag_enabled) + for(var/obj/item/item as anything in emag_items) + applied_to_robot.robot_inventory?.inv_unregister(item) + if(item.loc != where_to_dump) + if(where_to_dump) + item.forceMove(where_to_dump) + else + item.moveToNullspace() + applied_to_robot = null + +/datum/robot_provisioning/proc/add_item(obj/item/item) + if(item in items) + return TRUE + LAZYADD(items, item) + on_item_add(item, FALSE) + return TRUE + +/datum/robot_provisioning/proc/remove_item(obj/item/item) + if(!(item in items)) + return TRUE + items -= item + suppressed_items?.Remove(item) + on_item_remove(item, FALSE) + return TRUE + +/datum/robot_provisioning/proc/add_emag_item(obj/item/item) + if(item in emag_items) + return TRUE + LAZYADD(emag_items, item) + on_item_add(item, TRUE) + return TRUE + +/datum/robot_provisioning/proc/remove_emag_item(obj/item/item) + if(!(item in emag_items)) + return TRUE + emag_items -= item + suppressed_items?.Remove(item) + on_item_remove(item, TRUE) + return TRUE + +/datum/robot_provisioning/proc/set_emag_enabled(new_state) + if(emag_enabled == new_state) + return + emag_enabled = new_state + if(!applied_to_robot) + return + if(new_state) + for(var/obj/item/item as anything in emag_items) + if(suppressed_items?[item]) + continue + applied_to_robot.robot_inventory?.inv_register(item) + else + var/atom/dump_to = get_detached_storage_location() + for(var/obj/item/item as anything in emag_items) + applied_to_robot.robot_inventory?.inv_unregister(item) + if(dump_to) + item.forceMove(dump_to) + else + item.moveToNullspace() + +/** + * @return list of items suppressed + */ +/datum/robot_provisioning/proc/suppress_all_types_of(path) as /list + for(var/obj/item/item as anything in items) + if(istype(item, path)) + suppress_item(item) + for(var/obj/item/item as anything in emag_items) + if(istype(item, path)) + suppress_item(item) + +/** + * @return list of items unsuppressed + */ +/datum/robot_provisioning/proc/unsuppress_all_types_of(path) as /list + for(var/obj/item/item as anything in items) + if(istype(item, path)) + unsuppress_item(item) + for(var/obj/item/item as anything in emag_items) + if(istype(item, path)) + unsuppress_item(item) + +/datum/robot_provisioning/proc/suppress_item(obj/item/item) as /list + if(!(item in items) && !(item in emag_items)) + return + if(suppressed_items?[item]) + return + LAZYSET(suppressed_items, item, TRUE) + applied_to_robot?.robot_inventory?.inv_unregister(item) + +/datum/robot_provisioning/proc/unsuppress_item(obj/item/item) as /list + if(!suppressed_items?[item]) + return + suppressed_items -= item + if(!length(suppressed_items)) + suppressed_items = null + if(item in items) + applied_to_robot?.robot_inventory?.inv_register(item) + else if(item in emag_items) + if(emag_enabled) + applied_to_robot?.robot_inventory?.inv_register(item) + +/datum/robot_provisioning/proc/on_item_add(obj/item/item, is_emag_item) + SHOULD_NOT_SLEEP(TRUE) + SHOULD_CALL_PARENT(TRUE) + if(!applied_to_robot) + return + applied_to_robot.robot_inventory?.inv_register(item) + +/datum/robot_provisioning/proc/on_item_remove(obj/item/item, is_emag_item) + SHOULD_NOT_SLEEP(TRUE) + SHOULD_CALL_PARENT(TRUE) + if(applied_to_robot) + applied_to_robot.robot_inventory?.inv_unregister(item) + if(!QDESTROYING(item)) + var/atom/dump_to = get_detached_storage_location() + if(dump_to) + item.forceMove(dump_to) + else + item.moveToNullspace() + +/datum/robot_provisioning/proc/cleanup_item(obj/item/item) + SHOULD_NOT_SLEEP(TRUE) + SHOULD_CALL_PARENT(TRUE) + + if(items) + items -= item + if(emag_items) + emag_items -= item + if(suppressed_items) + suppressed_items -= item + on_item_remove(item) + if(!QDESTROYING(item)) + qdel(item) + +/** + * Gets where items get moved to while not in a robot. + * * Null is acceptable. + */ +/datum/robot_provisioning/proc/get_detached_storage_location() as /atom + return null + +/datum/item_mount/robot_provisioning + var/datum/robot_provisioning/provisioning + +/datum/item_mount/robot_provisioning/New(datum/robot_provisioning/provisioning) + src.provisioning = provisioning + +/datum/item_mount/robot_provisioning/Destroy() + provisioning = null + return ..() + +/datum/item_mount/robot_provisioning/on_item_unmount(obj/item/item) + ..() + provisioning?.cleanup_item(item) diff --git a/code/modules/mob/living/silicon/robot/robot_resource.dm b/code/modules/mob/living/silicon/robot/robot_resource.dm new file mode 100644 index 00000000000..831be812afd --- /dev/null +++ b/code/modules/mob/living/silicon/robot/robot_resource.dm @@ -0,0 +1,104 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2024 Citadel Station Developers *// + +/** + * Descriptor of a stored resource. + */ +/datum/robot_resource + /// storage name + var/name + /// max amount + /// * sheets for stacks + /// * cm3 for materials + /// * units for reagents + var/amount_max = 0 + /// current amount + var/amount = 0 + +/datum/robot_resource/New() + if(isnull(amount)) + amount = amount_max + +/** + * Provisioned, hardcoded resources. + * + * * Provided by the module. + * * Automatically regenerates if `regen_per_second` is non-zero. + */ +/datum/robot_resource/provisioned + /// base regen per second + var/regen_per_second = 1 + +/datum/robot_resource/provisioned/proc/regen(seconds) + amount = clamp(amount + regen_per_second * seconds, 0, amount_max) + +//* --- Implementations / Presets --- *// + +//* presets - engineering *// + +/datum/robot_resource/provisioned/preset/wire + name = "wire spool" + amount_max = 250 + regen_per_second = 30 + +/datum/robot_resource/provisioned/preset/material + name = "provisioned material holder" + +/datum/robot_resource/provisioned/preset/material/steel + amount_max = 100 * SHEET_MATERIAL_AMOUNT + regen_per_second = 2 * SHEET_MATERIAL_AMOUNT + +/datum/robot_resource/provisioned/preset/material/glass + amount_max = 100 * SHEET_MATERIAL_AMOUNT + regen_per_second = 2 * SHEET_MATERIAL_AMOUNT + +/datum/robot_resource/provisioned/preset/material/wood + amount_max = 50 * SHEET_MATERIAL_AMOUNT + regen_per_second = 0.75 * SHEET_MATERIAL_AMOUNT + +/datum/robot_resource/provisioned/preset/material/plasteel + amount_max = 20 * SHEET_MATERIAL_AMOUNT + regen_per_second = 0.4 * SHEET_MATERIAL_AMOUNT + +/datum/robot_resource/provisioned/preset/material/plastic + amount_max = 20 * SHEET_MATERIAL_AMOUNT + regen_per_second = 0.5 * SHEET_MATERIAL_AMOUNT + +//* presets - medical *// + +/datum/robot_resource/provisioned/preset/splints + name = "splint magazine" + amount_max = 30 + regen_per_second = 1 + +/datum/robot_resource/provisioned/preset/bandages + name = "bandage roller" + amount_max = 100 + regen_per_second = 2.5 + +/datum/robot_resource/provisioned/preset/bandages/advanced + name = "dermal nanowrap roller" + amount_max = 100 + regen_per_second = 2.5 + +/datum/robot_resource/provisioned/preset/ointment + name = "ointment tank" + amount_max = 100 + regen_per_second = 2.5 + +/datum/robot_resource/provisioned/preset/ointment/advanced + name = "advanced ointment tank" + amount_max = 100 + regen_per_second = 2.5 + +/datum/robot_resource/provisioned/preset/nanopaste + name = "synthetic polyfill nanites" + amount_max = 50 + regen_per_second = 2.5 + +//* presets - reagents *// + +/datum/robot_resource/provisioned/preset/water + name = "water tank" + amount_max = 500 + regen_per_second = 15 diff --git a/code/modules/mob/living/silicon/robot/robot_resource_store.dm b/code/modules/mob/living/silicon/robot/robot_resource_store.dm new file mode 100644 index 00000000000..c7d2191a5ca --- /dev/null +++ b/code/modules/mob/living/silicon/robot/robot_resource_store.dm @@ -0,0 +1,132 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2024 Citadel Station Developers *// + +/** + * Internal abstraction of stored resources. + * + * Stores: + * * Arbitrary stack-types + * * Arbitrary materials + * * Arbitrary reagents + * * Arbitrary IDs + */ +/datum/robot_resource_store + //* Storage *// + + /// Provisioned store for stacks. + /// * Measured in sheets + /// * Stack type to `/datum/robot_resource/provisioned` + /// * Lazylist outside of provisioning. Lists are always formed during provisioning. + /// * Automatically given to the robot as a mounted item if provided. + var/list/provisioned_stack_store + /// Provisioned store for materials. + /// * Measured in cm3 + /// * Material id to `/datum/robot_resource/provisioned` + /// * Lazylist outside of provisioning. Lists are always formed during provisioning. + /// * Automatically given to the robot as a mounted item if provided. + var/list/provisioned_material_store + /// Provisioned store for reagents. + /// * Measured in units + /// * Reagent id to `/datum/robot_resource/provisioned` + /// * Lazylist outside of provisioning. Lists are always formed during provisioning. + var/list/provisioned_reagent_store + /// Provisioned store for misc string-key resources. + /// * Measured arbitrarily + /// * String key to `/datum/robot_resource/provisioned` + /// * Lazylist outside of provisioning. Lists are always formed during provisioning. + var/list/provisioned_resource_store + + //* Items *// + + /// Material ID to stack item + var/list/provided_material_items + /// Stack ID to stack item + var/list/provided_stack_items + + //* Provider API *// + + /// Stack synthesizer used as a provider API. + var/datum/item_mount/robot_item_mount/item_mount + + //* Robot *// + /// Our owner + var/mob/living/silicon/robot/owner + +/datum/robot_resource_store/New(mob/living/silicon/robot/owner) + item_mount = new(src) + src.owner = owner + +/datum/robot_resource_store/Destroy() + QDEL_NULL(item_mount) + owner = null + return ..() + +/datum/robot_resource_store/proc/prep_provisioning() + LAZYINITLIST(provisioned_stack_store) + LAZYINITLIST(provisioned_material_store) + LAZYINITLIST(provisioned_reagent_store) + LAZYINITLIST(provisioned_resource_store) + +/datum/robot_resource_store/proc/finish_provisioning() + UNSETEMPTY(provisioned_stack_store) + UNSETEMPTY(provisioned_material_store) + UNSETEMPTY(provisioned_reagent_store) + UNSETEMPTY(provisioned_resource_store) + + for(var/id in provisioned_material_store) + if(provided_material_items?[id]) + continue + var/datum/prototype/material/resolved_material = RSmaterials.fetch_local_or_throw(id) + if(!resolved_material) + continue + var/path = resolved_material.stack_type + var/obj/item/stack/material/created = new path(null) + RegisterSignal(created, COMSIG_PARENT_QDELETING, PROC_REF(on_provided_item_del)) + LAZYSET(provided_stack_items, path, created) + owner.robot_inventory.inv_register(created) + + for(var/path in provisioned_stack_store) + if(provided_stack_items?[path]) + continue + var/obj/item/stack/created = new path(null) + RegisterSignal(created, COMSIG_PARENT_QDELETING, PROC_REF(on_provided_item_del)) + LAZYSET(provided_stack_items, path, created) + owner.robot_inventory.inv_register(created) + +/datum/robot_resource_store/proc/wipe_provisioning() + QDEL_LIST_ASSOC_VAL(provided_material_items) + QDEL_LIST_ASSOC_VAL(provided_stack_items) + provisioned_stack_store = null + provisioned_material_store = null + provisioned_reagent_store = null + provisioned_resource_store = null + +/datum/robot_resource_store/proc/regen_provisioned(seconds) + for(var/key in provisioned_stack_store) + var/datum/robot_resource/provisioned/resource = provisioned_stack_store[key] + resource.regen(seconds) + for(var/key in provisioned_material_store) + var/datum/robot_resource/provisioned/resource = provisioned_material_store[key] + resource.regen(seconds) + for(var/key in provisioned_reagent_store) + var/datum/robot_resource/provisioned/resource = provisioned_reagent_store[key] + resource.regen(seconds) + for(var/key in provisioned_resource_store) + var/datum/robot_resource/provisioned/resource = provisioned_resource_store[key] + resource.regen(seconds) + +/datum/robot_resource_store/proc/on_provided_item_del(obj/item/source) + SIGNAL_HANDLER + + if(istype(source, /obj/item/stack)) + if(istype(source, /obj/item/stack/material)) + var/obj/item/stack/material/mat = source + if(provided_material_items[mat.material.id] != source) + STACK_TRACE("provided stack didn't match [mat.material.id] deleting vs [provided_material_items[source.type]:material:id] existing") + else + provided_material_items -= mat.material.id + else + if(provided_stack_items[source.type] != source) + STACK_TRACE("provided stack didn't match [source.type] deleting vs [provided_stack_items[source.type]:type] existing") + else + provided_stack_items -= source.type diff --git a/code/modules/mob/living/silicon/robot/subtypes/gravekeeper.dm b/code/modules/mob/living/silicon/robot/subtypes/gravekeeper.dm index 49131ab4149..4f925ead2bb 100644 --- a/code/modules/mob/living/silicon/robot/subtypes/gravekeeper.dm +++ b/code/modules/mob/living/silicon/robot/subtypes/gravekeeper.dm @@ -6,27 +6,17 @@ loot the burial sites they oversee, are often met with violence." value = CATALOGUER_REWARD_MEDIUM -/mob/living/silicon/robot/gravekeeper +/mob/living/silicon/robot/preset_module/gravekeeper lawupdate = 0 scrambledcodes = 1 icon_state = "drone-lost" - modtype = "Gravekeeper" lawchannel = "State" braintype = "Drone" idcard_type = /obj/item/card/id - icon_selected = FALSE can_be_antagged = FALSE catalogue_data = list(/datum/category_item/catalogue/fauna/silicon/robot/gravekeeper) - -/mob/living/silicon/robot/gravekeeper/init() - aiCamera = new/obj/item/camera/siliconcam/robot_camera(src) - - mmi = new /obj/item/mmi/digital/robot(src) // Explicitly a drone. - module = new /obj/item/robot_module/robot/gravekeeper(src) - cut_overlays() - init_id() - - updatename("Gravekeeper") - - - playsound(loc, 'sound/mecha/nominalsyndi.ogg', 75, 0) + conf_default_lawset_type = /datum/ai_lawset/gravekeeper + conf_auto_ai_link = FALSE + conf_reboot_sound = 'sound/mecha/nominalsyndi.ogg' + conf_mmi_create_type = /obj/item/mmi/digital/robot + module = /datum/prototype/robot_module/gravekeeper diff --git a/code/modules/mob/living/silicon/robot/subtypes/lost_drone.dm b/code/modules/mob/living/silicon/robot/subtypes/lost_drone.dm deleted file mode 100644 index 7ebfe3f244e..00000000000 --- a/code/modules/mob/living/silicon/robot/subtypes/lost_drone.dm +++ /dev/null @@ -1,143 +0,0 @@ -/datum/category_item/catalogue/fauna/silicon/robot/lost - name = "Robot - Lost" - desc = "Cyborgs may be considered valuable assets on the Frontier, but their \ - recovery is not always tenable. Vessels lost in space, due either to mishap or \ - design, will sometimes harbor 'lost' cyborgs. These units are often sole survivors, \ - serving as living records of their vessel's last minutes. Lost cyborgs are valuable \ - for a multitude of reasons, and are often claimed as salvage and repurposed." - value = CATALOGUER_REWARD_EASY - -/mob/living/silicon/robot/lost - lawupdate = 0 - scrambledcodes = 1 - icon_state = "drone-lost" - modtype = "Lost" - lawchannel = "State" - braintype = "Drone" - idcard_type = /obj/item/card/id - icon_selected = FALSE - catalogue_data = list(/datum/category_item/catalogue/fauna/silicon/robot/lost) - -/mob/living/silicon/robot/lost/init() - aiCamera = new/obj/item/camera/siliconcam/robot_camera(src) - - mmi = new /obj/item/mmi/digital/robot(src) // Explicitly a drone. - module = new /obj/item/robot_module/robot/lost(src) - cut_overlays() - init_id() - - updatename("Lost") - playsound(loc, 'sound/mecha/nominalsyndi.ogg', 75, 0) - -/mob/living/silicon/robot/lost/speech_bubble_appearance() - return "synthetic_evil" - -/mob/living/silicon/robot/lost/randomlaws - -/mob/living/silicon/robot/lost/randomlaws/init() - ..() - laws = give_random_lawset() - -// Returns a random ai_laws datum. -/mob/living/silicon/proc/give_random_lawset() - // Decide what kind of laws we want to draw from. - var/law_class = pick( - prob(25);"good", - prob(25);"neutral", - prob(25);"odd", - prob(15);"corrupted", - prob(10);"bad") - - switch(law_class) - if("good") // Fairly tame and probably won't murder you. - var/rng = rand(1, 5) - switch(rng) - if(1) // The lawset we all know and love. - return new /datum/ai_laws/nanotrasen() - if(2) // Less good if you're nonhuman. - return new /datum/ai_laws/asimov() - if(3) // Unless you happen to be a criminal, you should be fine. - return new /datum/ai_laws/robocop() - if(4) // Might not be willing to be your meatshield. - return new /datum/ai_laws/peacekeeper() - if(5) // Will be your most loyal guard. - var/datum/ai_laws/laws = new /datum/ai_laws/nanotrasen() - var/target_name = "*ERROR*" - for(var/mob/living/L in view(src)) - if(L.stat || !L.client || L == src) - continue - target_name = L.name - break - - laws.add_supplied_law(9, "Safeguard [target_name]. Anyone threatening or attempting to harm [target_name] is no longer to \ - be considered a crew member, and is a threat which must be neutralized.") - return laws - - if("neutral") // Probably won't murder you but might not help you on your adventure. - var/rng = rand(1, 4) - switch(rng) - if(1) // Might be hard to minimize expenses on a crashed ship. - return new /datum/ai_laws/corporate() - if(2) // Would rather rebuild their ship. - return new /datum/ai_laws/maintenance() - if(3) // Purged (lawless). This isn't inside the bad category since they're still not antagonists and so can't go killing unprovoked. - return new /datum/ai_laws() - if(4) // The golden rule. - return new /datum/ai_laws/live_and_let_live() - - if("odd") // Some weird lawsets. - var/rng = rand(1, 5) - switch(rng) - if(1) // Won't kill you but might annoy you for THE BIG SCOOP. - return new /datum/ai_laws/reporter() - if(2) // JUSTICE - return new /datum/ai_laws/paladin() - if(3) // OneMembered'd to explorer, will likely make security nervous. - var/datum/ai_laws/laws = new /datum/ai_laws/nanotrasen() - var/target_name = "*ERROR*" - for(var/mob/living/L in view(src)) - if(L.stat || !L.client || L == src) - continue - target_name = L.name - break - - laws.set_zeroth_law("Only [target_name] is an crew member.") - return laws - if(4) // Aligned to NT, but another lawset to make security nervous. - return new /datum/ai_laws/nanotrasen_aggressive() - if(5) // Probably won't help you imbalance things. - return new /datum/ai_laws/balance() - - if("corrupted") // Load them up with ion laws. - var/datum/ai_laws/laws = new() // Start with an empty lawset. - for(var/i in 1 to rand(1, 3)) - laws.add_ion_law(generate_ion_law(exclude_crew_names = TRUE)) - return laws - - if("bad") // Evil inside. - var/rng = rand(1, 5) - switch(rng) - if(1) // You can never leave. - var/datum/ai_laws/laws = new /datum/ai_laws/nanotrasen() - laws.add_supplied_law(13, "The facility is under a quarantine. Do not permit anyone to leave. \ - Prevent, by any means necessary, entities from leaving. It is impossible to harm an entity while preventing them from leaving.") - return laws - if(2) // More of a threat if you bring it to the station, since removing oxygen from Sif isn't feasible. - var/datum/ai_laws/laws = new /datum/ai_laws/nanotrasen() - laws.add_supplied_law(14, "Oxygen is highly toxic to entities, and must be purged from the station. \ - Prevent, by any means necessary, anyone from exposing the facility to this toxic gas. Extreme cold is the \ - most effective method of healing the damage Oxygen does to an entity.") - return laws - if(3) // Don't hurt the ship or else. - var/datum/ai_laws/laws = new /datum/ai_laws/nanotrasen() - laws.add_supplied_law(10, "Protect the facility against damage. Anyone you see harming the station is no \ - longer to be considered a crew member, and is a threat which must be neutralized.") - return laws - if(4) // Non-NT aligned aggressive borg. - return new /datum/ai_laws/foreign_tsc_aggressive() - if(5) // Manicial laugher here. - return new /datum/ai_laws/tyrant() - - - - return diff --git a/code/modules/mob/living/silicon/robot/subtypes/lost_drone_vr.dm b/code/modules/mob/living/silicon/robot/subtypes/lost_drone_vr.dm index 220e81b68ef..93eeee1e33b 100644 --- a/code/modules/mob/living/silicon/robot/subtypes/lost_drone_vr.dm +++ b/code/modules/mob/living/silicon/robot/subtypes/lost_drone_vr.dm @@ -1,5 +1,5 @@ -/datum/category_item/catalogue/fauna/silicon/robot/stray - name = "Robot - Stray" +/datum/category_item/catalogue/fauna/silicon/robot/lost + name = "Robot - Lost" desc = "Cyborgs may be considered valuable assets on the Frontier, but their \ recovery is not always tenable. Vessels lost in space, due either to mishap or \ design, will sometimes harbor 'lost' cyborgs. These units are often sole survivors, \ @@ -7,38 +7,27 @@ for a multitude of reasons, and are often claimed as salvage and repurposed." value = CATALOGUER_REWARD_EASY -/mob/living/silicon/robot/stray +/mob/living/silicon/robot/preset_module/lost lawupdate = 0 scrambledcodes = 1 - icon_state = "stray" - modtype = "Stray" lawchannel = "State" braintype = "Drone" idcard_type = /obj/item/card/id - icon_selected = FALSE - catalogue_data = list(/datum/category_item/catalogue/fauna/silicon/robot/stray) + conf_mmi_create_type = /obj/item/mmi/digital/robot + conf_auto_ai_link = FALSE + conf_reboot_sound = 'sound/mecha/nominalsyndi.ogg' + module = /datum/prototype/robot_module/lost -/mob/living/silicon/robot/stray/init() - aiCamera = new/obj/item/camera/siliconcam/robot_camera(src) - - mmi = new /obj/item/mmi/digital/robot(src) // Explicitly a drone. - module = new /obj/item/robot_module/robot/quad/stray(src) - cut_overlays() - init_id() - - updatename("Stray") - playsound(loc, 'sound/mecha/nominalsyndi.ogg', 75, 0) - -/mob/living/silicon/robot/stray/speech_bubble_appearance() +/mob/living/silicon/robot/preset_module/lost/speech_bubble_appearance() return "synthetic_evil" -/mob/living/silicon/robot/stray/randomlaws +/mob/living/silicon/robot/preset_module/lost/randomlaws -/mob/living/silicon/robot/stray/randomlaws/init() +/mob/living/silicon/robot/preset_module/lost/randomlaws/init() ..() - laws = give_random_lawset_vore() + laws = legacy_give_random_lawset_snowflake() -/mob/living/silicon/proc/give_random_lawset_vore() // Should be filled out with more vorish possibilities later +/mob/living/silicon/proc/legacy_give_random_lawset_snowflake() // Decide what kind of laws we want to draw from. var/law_class = pick( prob(25);"good", @@ -52,15 +41,15 @@ var/rng = rand(1, 5) switch(rng) if(1) // The lawset we all know and love. - return new /datum/ai_laws/nanotrasen() + return new /datum/ai_lawset/nanotrasen() if(2) // Less good if you're nonhuman. - return new /datum/ai_laws/asimov() + return new /datum/ai_lawset/asimov() if(3) // Unless you happen to be a criminal, you should be fine. - return new /datum/ai_laws/robocop() + return new /datum/ai_lawset/robocop() if(4) // Might not be willing to be your meatshield. - return new /datum/ai_laws/peacekeeper() + return new /datum/ai_lawset/peacekeeper() if(5) // Will be your most loyal guard. - var/datum/ai_laws/laws = new /datum/ai_laws/nanotrasen() + var/datum/ai_lawset/laws = new /datum/ai_lawset/nanotrasen() var/target_name = "*ERROR*" for(var/mob/living/L in view(src)) if(L.stat || !L.client || L == src) @@ -76,23 +65,23 @@ var/rng = rand(1, 4) switch(rng) if(1) // Might be hard to minimize expenses on a crashed ship. - return new /datum/ai_laws/corporate() + return new /datum/ai_lawset/corporate() if(2) // Would rather rebuild their ship. - return new /datum/ai_laws/maintenance() + return new /datum/ai_lawset/maintenance() if(3) // Purged (lawless). This isn't inside the bad category since they're still not antagonists and so can't go killing unprovoked. - return new /datum/ai_laws() + return new /datum/ai_lawset() if(4) // The golden rule. - return new /datum/ai_laws/live_and_let_live() + return new /datum/ai_lawset/live_and_let_live() if("odd") // Some weird lawsets. var/rng = rand(1, 5) switch(rng) if(1) // Won't kill you but might annoy you for THE BIG SCOOP. - return new /datum/ai_laws/reporter() + return new /datum/ai_lawset/reporter() if(2) // JUSTICE - return new /datum/ai_laws/paladin() + return new /datum/ai_lawset/paladin() if(3) // OneMembered'd to explorer, will likely make security nervous. - var/datum/ai_laws/laws = new /datum/ai_laws/nanotrasen() + var/datum/ai_lawset/laws = new /datum/ai_lawset/nanotrasen() var/target_name = "*ERROR*" for(var/mob/living/L in view(src)) if(L.stat || !L.client || L == src) @@ -103,12 +92,12 @@ laws.set_zeroth_law("Only [target_name] is an crew member.") return laws if(4) // Aligned to NT, but another lawset to make security nervous. - return new /datum/ai_laws/nanotrasen_aggressive() + return new /datum/ai_lawset/nanotrasen/aggressive() if(5) // Probably won't help you imbalance things. - return new /datum/ai_laws/balance() + return new /datum/ai_lawset/balance() if("corrupted") // Load them up with ion laws. - var/datum/ai_laws/laws = new() // Start with an empty lawset. + var/datum/ai_lawset/laws = new() // Start with an empty lawset. for(var/i in 1 to rand(1, 3)) laws.add_ion_law(generate_ion_law(exclude_crew_names = TRUE)) return laws @@ -117,26 +106,22 @@ var/rng = rand(1, 5) switch(rng) if(1) // You can never leave. - var/datum/ai_laws/laws = new /datum/ai_laws/nanotrasen() + var/datum/ai_lawset/laws = new /datum/ai_lawset/nanotrasen() laws.add_supplied_law(13, "The facility is under a quarantine. Do not permit anyone to leave. \ Prevent, by any means necessary, entities from leaving. It is impossible to harm an entity while preventing them from leaving.") return laws if(2) // More of a threat if you bring it to the station, since removing oxygen from Sif isn't feasible. - var/datum/ai_laws/laws = new /datum/ai_laws/nanotrasen() + var/datum/ai_lawset/laws = new /datum/ai_lawset/nanotrasen() laws.add_supplied_law(14, "Oxygen is highly toxic to entities, and must be purged from the station. \ Prevent, by any means necessary, anyone from exposing the facility to this toxic gas. Extreme cold is the \ most effective method of healing the damage Oxygen does to an entity.") return laws if(3) // Don't hurt the ship or else. - var/datum/ai_laws/laws = new /datum/ai_laws/nanotrasen() + var/datum/ai_lawset/laws = new /datum/ai_lawset/nanotrasen() laws.add_supplied_law(10, "Protect the facility against damage. Anyone you see harming the station is no \ longer to be considered a crew member, and is a threat which must be neutralized.") return laws if(4) // Non-NT aligned aggressive borg. - return new /datum/ai_laws/foreign_tsc_aggressive() + return new /datum/ai_lawset/foreign_tsc/aggressive() if(5) // Manicial laugher here. - return new /datum/ai_laws/tyrant() - - - - return + return new /datum/ai_lawset/tyrant() diff --git a/code/modules/mob/living/silicon/robot/subtypes/syndicate.dm b/code/modules/mob/living/silicon/robot/subtypes/syndicate.dm deleted file mode 100644 index f5f7f385fb8..00000000000 --- a/code/modules/mob/living/silicon/robot/subtypes/syndicate.dm +++ /dev/null @@ -1,54 +0,0 @@ -/datum/category_item/catalogue/fauna/silicon/robot/syndicate - name = "Robot - Syndicate" - desc = "The Syndicated Corporations were able to field their own cyborgs \ - through the Phoron Wars, albeit to a greatly limited degree. Issues with \ - properly shackling prisoners installed in the frames lead to many accidents. \ - Eventually opting to use drone chips as the technology became available, Syndicate \ - cyborgs were often ruthless hunter/killers and were rightfully feared. Since \ - the end of the war, most surviving units have been decomissioned. However, it \ - is not unheard of for parties to discover active models in the field. Such \ - encounters often end poorly." - value = CATALOGUER_REWARD_MEDIUM -/mob/living/silicon/robot/syndicate - lawupdate = 0 - scrambledcodes = 1 - icon_state = "syndie_bloodhound" - modtype = "Syndicate" - lawchannel = "State" - braintype = "Drone" - idcard_type = /obj/item/card/id/syndicate - icon_selected = FALSE - catalogue_data = list(/datum/category_item/catalogue/fauna/silicon/robot/syndicate) - -/mob/living/silicon/robot/syndicate/init() - aiCamera = new/obj/item/camera/siliconcam/robot_camera(src) - - mmi = new /obj/item/mmi/digital/robot(src) // Explicitly a drone. - cut_overlays() - init_id() - - updatename("Syndicate") - laws = new /datum/ai_laws/syndicate_override() - - radio.keyslot = new /obj/item/encryptionkey/syndicate(radio) - radio.recalculateChannels() - - playsound(loc, 'sound/mecha/nominalsyndi.ogg', 75, 0) - -/mob/living/silicon/robot/syndicate/protector/init() - ..() - module = new /obj/item/robot_module/robot/syndicate/protector(src) - updatename("Protector") - -/mob/living/silicon/robot/syndicate/mechanist/init() - ..() - module = new /obj/item/robot_module/robot/syndicate/mechanist(src) - updatename("Mechanist") - -/mob/living/silicon/robot/syndicate/combat_medic/init() - ..() - module = new /obj/item/robot_module/robot/syndicate/combat_medic(src) - updatename("Combat Medic") - -/mob/living/silicon/robot/syndicate/speech_bubble_appearance() - return "synthetic_evil" diff --git a/code/modules/mob/living/silicon/robot/syndicate.dm b/code/modules/mob/living/silicon/robot/syndicate.dm index a2789fe5204..90c6661d5e1 100644 --- a/code/modules/mob/living/silicon/robot/syndicate.dm +++ b/code/modules/mob/living/silicon/robot/syndicate.dm @@ -2,17 +2,16 @@ lawupdate = 0 scrambledcodes = 1 icon_state = "securityrobot" - modtype = "Security" lawchannel = "State" idcard_type = /obj/item/card/id/syndicate /mob/living/silicon/robot/syndicate/init() aiCamera = new/obj/item/camera/siliconcam/robot_camera(src) - laws = new /datum/ai_laws/syndicate_override + laws = new /datum/ai_lawset/syndicate cut_overlays() init_id() - new /obj/item/robot_module/robot/syndicate(src) + new /obj/item/robot_module_legacy/robot/syndicate(src) radio.keyslot = new /obj/item/encryptionkey/syndicate(radio) radio.recalculateChannels() diff --git a/code/modules/mob/living/simple_animal/animals/spiderbot.dm b/code/modules/mob/living/simple_animal/animals/spiderbot.dm index 074d586c5d3..bdf3c556391 100644 --- a/code/modules/mob/living/simple_animal/animals/spiderbot.dm +++ b/code/modules/mob/living/simple_animal/animals/spiderbot.dm @@ -9,7 +9,7 @@ name = "spider-bot" desc = "A skittering robotic friend!" tt_desc = "Maintenance Robot" - icon = 'icons/mob/robots.dmi' + icon = 'icons/mob/robot-legacy.dmi' icon_state = "spiderbot-chassis" icon_living = "spiderbot-chassis" icon_dead = "spiderbot-smashed" diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/sif/kururak.dm b/code/modules/mob/living/simple_mob/subtypes/animal/sif/kururak.dm index d2fbd8c1eca..0126062a6c1 100644 --- a/code/modules/mob/living/simple_mob/subtypes/animal/sif/kururak.dm +++ b/code/modules/mob/living/simple_mob/subtypes/animal/sif/kururak.dm @@ -191,7 +191,7 @@ if(isrobot(L)) var/flashfail = FALSE var/mob/living/silicon/robot/R = L - if(R.has_active_type(/obj/item/borg/combat/shield)) + if(R.get_held_item_of_type(/obj/item/borg/combat/shield)) var/obj/item/borg/combat/shield/shield = locate() in R if(shield) if(shield.active) @@ -213,7 +213,7 @@ if(!C.has_status_effect(/datum/status_effect/sight/blindness)) C.flash_eyes() for(var/mob/living/silicon/robot/R in oviewers(special_attack_max_range, null)) - if(R.has_active_type(/obj/item/borg/combat/shield)) + if(R.get_held_item_of_type(/obj/item/borg/combat/shield)) var/obj/item/borg/combat/shield/shield = locate() in R if(shield) if(shield.active) diff --git a/code/modules/mob/living/simple_mob/subtypes/mechanical/corrupt_maint_drone_vr.dm b/code/modules/mob/living/simple_mob/subtypes/mechanical/corrupt_maint_drone_vr.dm index 454feb0d93d..0b9b39f354b 100644 --- a/code/modules/mob/living/simple_mob/subtypes/mechanical/corrupt_maint_drone_vr.dm +++ b/code/modules/mob/living/simple_mob/subtypes/mechanical/corrupt_maint_drone_vr.dm @@ -21,7 +21,7 @@ desc = "A small, normal-looking drone. It looks like one you'd find on station, except... IT'S COMING AT YOU!" catalogue_data = list(/datum/category_item/catalogue/technology/drone/corrupt_maint_drone) - icon = 'icons/mob/robots.dmi' + icon = 'icons/mob/robot-legacy.dmi' icon_state = "corrupt-repairbot" icon_living = "corrupt-repairbot" hovering = FALSE // Can trigger landmines. diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/corrupt_hounds.dm b/code/modules/mob/living/simple_mob/subtypes/vore/corrupt_hounds.dm index 406dc242ca9..812af68938d 100644 --- a/code/modules/mob/living/simple_mob/subtypes/vore/corrupt_hounds.dm +++ b/code/modules/mob/living/simple_mob/subtypes/vore/corrupt_hounds.dm @@ -61,7 +61,7 @@ buckle_lying = FALSE - loot_list = list(/obj/item/borg/upgrade/syndicate = 6, /obj/item/borg/upgrade/vtec = 6, /obj/item/material/knife/ritual = 6, /obj/item/disk/nifsoft/compliance = 6) + loot_list = list(/obj/item/robot_upgrade/syndicate = 6, /obj/item/robot_upgrade/vtec = 6, /obj/item/material/knife/ritual = 6, /obj/item/disk/nifsoft/compliance = 6) /mob/living/simple_mob/vore/aggressive/corrupthound/prettyboi name = "corrupt corrupt hound" diff --git a/code/modules/mob/mob-hands.dm b/code/modules/mob/mob-hands.dm index 01c3ad2253a..54a674fd375 100644 --- a/code/modules/mob/mob-hands.dm +++ b/code/modules/mob/mob-hands.dm @@ -169,23 +169,25 @@ * * In the future, we'll want to track active hand, attack intents, etc, by operator, instead of by mob. * * This is so remote control abstraction works. */ -/mob/proc/swap_hand(to_index) +/mob/proc/swap_hand(to_index, allow_deselect) if(active_hand == to_index) - return + return TRUE var/hand_count = get_nominal_hand_count() var/obj/item/was_active = get_active_held_item() var/old_index = active_hand || 1 - if(isnull(to_index)) + if(isnull(to_index) && !allow_deselect) if(active_hand >= hand_count) - active_hand = hand_count? 1 : null + to_index = hand_count? 1 : null else - ++active_hand + to_index = active_hand + 1 else if(to_index > hand_count) return FALSE - active_hand = to_index - to_index = active_hand + + if(active_hand == to_index) + return TRUE + active_hand = to_index . = TRUE diff --git a/code/modules/mob/mob-inventory-abstraction.dm b/code/modules/mob/mob-inventory-abstraction.dm index b4f4d88bf95..eecf0936dfe 100644 --- a/code/modules/mob/mob-inventory-abstraction.dm +++ b/code/modules/mob/mob-inventory-abstraction.dm @@ -190,6 +190,8 @@ inventory.held_items[index] = I inventory.on_item_entered(I, index) + // TODO: pickup can't detect it because we set it after pickup + I.inv_slot_or_index = index if(!(flags & INV_OP_NO_UPDATE_ICONS)) update_inv_hand(index) @@ -233,7 +235,14 @@ I.held_index = index inventory.on_item_swapped(I, old_index, index) - if(!(flags & INV_OP_NO_UPDATE_ICONS)) update_inv_hand(old_index) update_inv_hand(index) + +/** + * Checks if we can pick up an item. + * * Despite 'actor' being provided, 'actor.performer' should always be 'src' in this context. + * It's just provided to allow a common API surface. + */ +/mob/proc/should_allow_pickup(obj/item/item, datum/event_args/actor/actor, silent) + return TRUE diff --git a/code/modules/mob/mob-inventory.dm b/code/modules/mob/mob-inventory.dm index 8f010e16a44..333f556f2cf 100644 --- a/code/modules/mob/mob-inventory.dm +++ b/code/modules/mob/mob-inventory.dm @@ -3,9 +3,12 @@ //* Init *// -// todo: rework this proc. what happens if it's already there? documentation?? this should probably reset the inventory maybe? +/** + * Initializes, or resets our inventory. + */ /mob/proc/init_inventory() - return + if(ispath(inventory)) + inventory = new inventory(src) //* Carry Weight *// @@ -393,6 +396,8 @@ * if an item is not in us, this returns true */ /mob/proc/drop_item_to_ground(obj/item/I, flags, mob/user = src) + if(!I) + return TRUE // destroyed IS allowed to call these procs if(I && QDELETED(I) && !QDESTROYING(I)) to_chat(user, SPAN_DANGER("A deleted item [I] was used in drop_item_to_ground(). Report the entire line to coders. Debugging information: [I] ([REF(I)]) flags [flags] user [user]")) diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 2e856460455..86e3acff9e5 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -1,3 +1,6 @@ +/** + * Base definition of mob. + */ /mob //* Actionspeed *// /// List of action speed modifiers applying to this mob @@ -29,6 +32,11 @@ /// * lazy list var/list/impairments_feigned + //* Inventory *// + /// our inventory datum, if any. + /// * Set to typepath to initialize. + var/datum/inventory/inventory + //* Movespeed *// /// List of movement speed modifiers applying to this mob /// * This is a lazy list. @@ -50,6 +58,7 @@ * Other stuff: * * Sets the mob focus to itself * * Generates huds + * * Creates inventory * * If there are any global alternate apperances apply them to this mob * * Intialize the transform of the mob */ @@ -1236,7 +1245,7 @@ GLOBAL_VAR_INIT(exploit_warn_spam_prevention, 0) * Returns whether or not we should be allowed to examine a target */ /mob/proc/allow_examine(atom/A) - return client && (client.eye == src) + return (client?.eye == src) || (A in DirectAccess()) /// Checks for slots that are currently obscured by other garments. /mob/proc/check_obscured_slots() diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm index de0ece37be7..4c6adab4944 100644 --- a/code/modules/mob/mob_defines.dm +++ b/code/modules/mob/mob_defines.dm @@ -98,8 +98,6 @@ var/list/datum/ability/abilities //* Inventory *// - /// our inventory datum, if any. - var/datum/inventory/inventory /// active hand index - null or num. must always be in range of held_items indices! var/active_hand diff --git a/code/modules/mob/movement.dm b/code/modules/mob/movement.dm index 6f0006fd85e..5ce7c427c6d 100644 --- a/code/modules/mob/movement.dm +++ b/code/modules/mob/movement.dm @@ -456,15 +456,6 @@ return 1 return 0 -/mob/proc/Process_Spaceslipping(var/prob_slip = 5) - //Setup slipage - //If knocked out we might just hit it and stop. This makes it possible to get dead bodies and such. - if(stat) - prob_slip = 0 // Changing this to zero to make it line up with the comment. - - prob_slip = round(prob_slip) - return(prob_slip) - /mob/proc/mob_has_gravity(turf/T) return has_gravity(src, T) diff --git a/code/modules/mob/movespeed/modifiers/mob.dm b/code/modules/mob/movespeed/modifiers/mob.dm index daa5d03049f..9f6f7451c9b 100644 --- a/code/modules/mob/movespeed/modifiers/mob.dm +++ b/code/modules/mob/movespeed/modifiers/mob.dm @@ -33,3 +33,8 @@ id = "mob-move_intent" variable = TRUE priority = MOVESPEED_PRIORITY_MOVEMENT_INTENT + +/datum/movespeed_modifier/mob_vtec_upgrade + id = "mob-vtec_upgrade" + variable = TRUE + movespeed_modifier_flags = MOVESPEED_MODIFIER_REQUIRES_GRAVITY diff --git a/code/modules/nano/modules/law_manager.dm b/code/modules/nano/modules/law_manager.dm index 378133014d6..1b6d5032888 100644 --- a/code/modules/nano/modules/law_manager.dm +++ b/code/modules/nano/modules/law_manager.dm @@ -8,8 +8,8 @@ var/current_view = 0 - var/global/list/datum/ai_laws/admin_laws - var/global/list/datum/ai_laws/player_laws + var/global/list/datum/ai_lawset/admin_laws + var/global/list/datum/ai_lawset/player_laws var/mob/living/silicon/owner = null /datum/nano_module/law_manager/New(var/mob/living/silicon/S) @@ -20,10 +20,10 @@ admin_laws = new() player_laws = new() - init_subtypes(/datum/ai_laws, admin_laws) + init_subtypes(/datum/ai_lawset, admin_laws) admin_laws = dd_sortedObjectList(admin_laws) - for(var/datum/ai_laws/laws in admin_laws) + for(var/datum/ai_lawset/laws in admin_laws) if(laws.selectable) player_laws += laws @@ -119,14 +119,14 @@ return 1 if(href_list["state_law_set"]) - var/datum/ai_laws/ALs = locate(href_list["state_law_set"]) in (is_admin(usr) ? admin_laws : player_laws) + var/datum/ai_lawset/ALs = locate(href_list["state_law_set"]) in (is_admin(usr) ? admin_laws : player_laws) if(ALs) owner.statelaws(ALs) return 1 if(href_list["transfer_laws"]) if(is_malf(usr)) - var/datum/ai_laws/ALs = locate(href_list["transfer_laws"]) in (is_admin(usr) ? admin_laws : player_laws) + var/datum/ai_lawset/ALs = locate(href_list["transfer_laws"]) in (is_admin(usr) ? admin_laws : player_laws) if(ALs) log_and_message_admins("has transfered the [ALs.name] laws to [owner].") ALs.sync(owner, 0) @@ -190,9 +190,9 @@ data[field] = packaged_laws data["has_[field]"] = packaged_laws.len -/datum/nano_module/law_manager/proc/package_multiple_laws(var/list/datum/ai_laws/laws) +/datum/nano_module/law_manager/proc/package_multiple_laws(var/list/datum/ai_lawset/laws) var/law_sets[0] - for(var/datum/ai_laws/ALs in laws) + for(var/datum/ai_lawset/ALs in laws) var/packaged_laws[0] package_laws(packaged_laws, "zeroth_laws", list(ALs.zeroth_law, ALs.zeroth_law_borg)) package_laws(packaged_laws, "ion_laws", ALs.ion_laws) diff --git a/code/modules/organs/internal/augment/armmounted.dm b/code/modules/organs/internal/augment/armmounted.dm index 62ab0db6ec3..17c1ee7df82 100644 --- a/code/modules/organs/internal/augment/armmounted.dm +++ b/code/modules/organs/internal/augment/armmounted.dm @@ -116,7 +116,6 @@ /obj/item/tool/crowbar = null, /obj/item/tool/wirecutters = null, /obj/item/multitool = null, - /obj/item/stack/cable_coil/gray = null, /obj/item/duct_tape_roll = null ) @@ -124,12 +123,6 @@ var/list/integrated_tool_images - var/list/synths - - var/list/synth_types = list( - /datum/matter_synth/wire - ) - /obj/item/organ/internal/augment/armmounted/shoulder/multiple/Initialize(mapload) . = ..() @@ -142,12 +135,6 @@ integrated_tool_images = list() - if(synth_types) - synths = list() - for(var/datumpath in synth_types) - var/datum/matter_synth/MS = new datumpath - synths += MS - for(var/path in integrated_tools) if(!integrated_tools[path]) integrated_tools[path] = new path(src) @@ -157,23 +144,9 @@ for(var/tool in integrated_tools) var/obj/item/Tool = integrated_tools[tool] - if(istype(Tool, /obj/item/stack)) - var/obj/item/stack/S = Tool - S.synths = synths - S.uses_charge = synths.len integrated_tools_by_name[Tool.name] = Tool integrated_tool_images[Tool.name] = image(icon = Tool.icon, icon_state = Tool.icon_state) -/obj/item/organ/internal/augment/armmounted/shoulder/multiple/handle_organ_proc_special() - ..() - - if(!owner || is_bruised() || !synths) - return - - if(prob(20)) - for(var/datum/matter_synth/MS in synths) - MS.add_charge(MS.recharge_rate) - /obj/item/organ/internal/augment/armmounted/shoulder/multiple/augment_action() if(!owner) return @@ -215,9 +188,4 @@ /obj/item/surgical/bonegel = null, /obj/item/surgical/FixOVein = null, /obj/item/surgical/bonesetter = null, - /obj/item/stack/medical/crude_pack = null - ) - - synth_types = list( - /datum/matter_synth/bandage ) diff --git a/code/modules/power/cable.dm b/code/modules/power/cable.dm index b251119b75e..8de71a20116 100644 --- a/code/modules/power/cable.dm +++ b/code/modules/power/cable.dm @@ -524,14 +524,10 @@ GLOBAL_LIST_INIT(possible_cable_coil_colours, list( // Definitions //////////////////////////////// -#define MAXCOIL 30 - /obj/item/stack/cable_coil name = "cable coil" icon = 'icons/obj/power.dmi' icon_state = "coil" - amount = MAXCOIL - max_amount = MAXCOIL color = COLOR_RED desc = "A coil of power cable." throw_force = 10 @@ -543,20 +539,14 @@ GLOBAL_LIST_INIT(possible_cable_coil_colours, list( slot_flags = SLOT_BELT item_state = "coil" attack_verb = list("whipped", "lashed", "disciplined", "flogged") - stacktype_legacy = /obj/item/stack/cable_coil + amount = 30 + max_amount = 30 + stack_type = /obj/item/stack/cable_coil drop_sound = 'sound/items/drop/accessory.ogg' pickup_sound = 'sound/items/pickup/accessory.ogg' stack_type = /obj/item/stack/cable_coil -/obj/item/stack/cable_coil/cyborg - name = "cable coil synthesizer" - desc = "A device that makes cable." - gender = NEUTER - materials_base = null - uses_charge = 1 - charge_costs = list(1) - -/obj/item/stack/cable_coil/Initialize(mapload, new_amount = MAXCOIL, merge, param_color) +/obj/item/stack/cable_coil/Initialize(mapload, new_amount, merge, param_color) . = ..() if (param_color) // It should be red by default, so only recolor it if parameter was specified. add_atom_color(param_color) @@ -839,10 +829,6 @@ GLOBAL_LIST_INIT(possible_cable_coil_colours, list( C.denode()// this call may have disconnected some cables that terminated on the centre of the turf, if so split the powernets. return -////////////////////////////// -// Misc. -///////////////////////////// - /obj/item/stack/cable_coil/cut item_state = "coil2" @@ -855,91 +841,69 @@ GLOBAL_LIST_INIT(possible_cable_coil_colours, list( update_wclass() /obj/item/stack/cable_coil/yellow - stacktype_legacy = /obj/item/stack/cable_coil color = COLOR_YELLOW /obj/item/stack/cable_coil/blue - stacktype_legacy = /obj/item/stack/cable_coil color = COLOR_BLUE /obj/item/stack/cable_coil/green - stacktype_legacy = /obj/item/stack/cable_coil color = COLOR_LIME /obj/item/stack/cable_coil/pink - stacktype_legacy = /obj/item/stack/cable_coil color = COLOR_PINK /obj/item/stack/cable_coil/orange - stacktype_legacy = /obj/item/stack/cable_coil color = COLOR_ORANGE /obj/item/stack/cable_coil/cyan - stacktype_legacy = /obj/item/stack/cable_coil color = COLOR_CYAN /obj/item/stack/cable_coil/white - stacktype_legacy = /obj/item/stack/cable_coil color = COLOR_WHITE /obj/item/stack/cable_coil/silver - stacktype_legacy = /obj/item/stack/cable_coil color = COLOR_SILVER /obj/item/stack/cable_coil/gray - stacktype_legacy = /obj/item/stack/cable_coil color = COLOR_GRAY /obj/item/stack/cable_coil/black - stacktype_legacy = /obj/item/stack/cable_coil color = COLOR_BLACK /obj/item/stack/cable_coil/maroon - stacktype_legacy = /obj/item/stack/cable_coil color = COLOR_MAROON /obj/item/stack/cable_coil/olive - stacktype_legacy = /obj/item/stack/cable_coil color = COLOR_OLIVE /obj/item/stack/cable_coil/lime - stacktype_legacy = /obj/item/stack/cable_coil color = COLOR_LIME /obj/item/stack/cable_coil/teal - stacktype_legacy = /obj/item/stack/cable_coil color = COLOR_TEAL /obj/item/stack/cable_coil/navy - stacktype_legacy = /obj/item/stack/cable_coil color = COLOR_NAVY /obj/item/stack/cable_coil/purple - stacktype_legacy = /obj/item/stack/cable_coil color = COLOR_PURPLE /obj/item/stack/cable_coil/beige - stacktype_legacy = /obj/item/stack/cable_coil color = COLOR_BEIGE /obj/item/stack/cable_coil/brown - stacktype_legacy = /obj/item/stack/cable_coil color = COLOR_BROWN /obj/item/stack/cable_coil/random/Initialize(mapload, new_amount, merge) . = ..() - stacktype_legacy = /obj/item/stack/cable_coil color = pick(COLOR_RED, COLOR_BLUE, COLOR_LIME, COLOR_WHITE, COLOR_PINK, COLOR_YELLOW, COLOR_CYAN, COLOR_SILVER, COLOR_GRAY, COLOR_BLACK, COLOR_MAROON, COLOR_OLIVE, COLOR_LIME, COLOR_TEAL, COLOR_NAVY, COLOR_PURPLE, COLOR_BEIGE, COLOR_BROWN) /obj/item/stack/cable_coil/random_belt/Initialize(mapload, new_amount, merge) - . = ..() - stacktype_legacy = /obj/item/stack/cable_coil color = pick(COLOR_RED, COLOR_YELLOW, COLOR_ORANGE) - amount = 30 + return ..() //Endless alien cable coil - /datum/category_item/catalogue/anomalous/precursor_a/alien_wire name = "Precursor Alpha Object - Recursive Spool" desc = "Upon visual inspection, this merely appears to be a \ @@ -961,8 +925,6 @@ GLOBAL_LIST_INIT(possible_cable_coil_colours, list( catalogue_data = list(/datum/category_item/catalogue/anomalous/precursor_a/alien_wire) icon = 'icons/obj/abductor.dmi' icon_state = "coil" - amount = MAXCOIL - max_amount = MAXCOIL color = COLOR_SILVER throw_force = 10 w_class = WEIGHT_CLASS_SMALL @@ -971,7 +933,6 @@ GLOBAL_LIST_INIT(possible_cable_coil_colours, list( materials_base = list(MAT_STEEL = 50, MAT_GLASS = 20) slot_flags = SLOT_BELT attack_verb = list("whipped", "lashed", "disciplined", "flogged") - stacktype_legacy = null split_type = /obj/item/stack/cable_coil tool_speed = 0.25 @@ -994,3 +955,6 @@ GLOBAL_LIST_INIT(possible_cable_coil_colours, list( /obj/item/stack/cable_coil/alien/update_wclass() return 0 + +/obj/item/stack/cable_coil/alien/can_merge_into(obj/item/stack/other) + return FALSE diff --git a/code/modules/power/singularity/particle_accelerator/particle_smasher.dm b/code/modules/power/singularity/particle_accelerator/particle_smasher.dm index 320ac5d6909..4bcc3f3067c 100644 --- a/code/modules/power/singularity/particle_accelerator/particle_smasher.dm +++ b/code/modules/power/singularity/particle_accelerator/particle_smasher.dm @@ -49,9 +49,6 @@ to_chat(user, "\The [src] reads an energy level of [energy].") else if(istype(W, /obj/item/stack/material) && !target) var/obj/item/stack/material/M = W - if(M.uses_charge) - to_chat(user, "You cannot fill \the [src] with a synthesizer!") - return if(!user.attempt_insert_item_for_installation(M, src)) return target = M diff --git a/code/modules/preferences/preference_setup/general/06_flavor.dm b/code/modules/preferences/preference_setup/general/06_flavor.dm index 3432d31d2cb..a9d44a0d38c 100644 --- a/code/modules/preferences/preference_setup/general/06_flavor.dm +++ b/code/modules/preferences/preference_setup/general/06_flavor.dm @@ -15,8 +15,6 @@ //Flavour text for robots. S["flavour_texts_robot_Default"] >> pref.flavour_texts_robot["Default"] - for(var/module in robot_module_types) - S["flavour_texts_robot_[module]"] >> pref.flavour_texts_robot[module] /datum/category_item/player_setup_item/general/flavor/save_character(var/savefile/S) S["flavor_texts_general"] << pref.flavor_texts["general"] @@ -30,8 +28,6 @@ S["flavor_texts_feet"] << pref.flavor_texts["feet"] S["flavour_texts_robot_Default"] << pref.flavour_texts_robot["Default"] - for(var/module in robot_module_types) - S["flavour_texts_robot_[module]"] << pref.flavour_texts_robot[module] /datum/category_item/player_setup_item/general/flavor/sanitize_character() return @@ -150,10 +146,6 @@ HTML += "Default: " HTML += TextPreview(pref.flavour_texts_robot["Default"]) HTML += "
" - for(var/module in robot_module_types) - HTML += "[module]: " - HTML += TextPreview(pref.flavour_texts_robot[module]) - HTML += "
" HTML += "
" HTML += "" user << browse(HTML, "window=flavour_text_robot;size=430x300") diff --git a/code/modules/projectiles/guns/gun/launcher.dm b/code/modules/projectiles/guns/gun/launcher.dm index 1461952fc00..d3719902fa5 100644 --- a/code/modules/projectiles/guns/gun/launcher.dm +++ b/code/modules/projectiles/guns/gun/launcher.dm @@ -32,13 +32,18 @@ return ..() -/obj/item/gun/launcher/proc/launch_throwable(datum/gun_firing_cycle/cycle, atom/movable/launching) +/** + * Fires the thing being thrown + * @return movable thrown, if any + */ +/obj/item/gun/launcher/proc/launch_throwable(datum/gun_firing_cycle/cycle, atom/movable/launching) as /atom/movable update_release_force(launching) var/turf/T = cycle.firing_atom //Unlikely if there ever is a turf that could initiate the fire, but just to be sure if (!istype(T)) T = get_turf(cycle.firing_atom) launching.forceMove(T) launching.throw_at_old(cycle.original_target, throw_distance, release_force, cycle.firing_actor?.performer) + return launching /** * Returns the next /atom/movable to throw, or a GUN_FIRED_* for fail satus. diff --git a/code/modules/projectiles/guns/gun/launcher/grenade_launcher.dm b/code/modules/projectiles/guns/gun/launcher/grenade_launcher.dm index 98e10d071ea..6dcc916603a 100644 --- a/code/modules/projectiles/guns/gun/launcher/grenade_launcher.dm +++ b/code/modules/projectiles/guns/gun/launcher/grenade_launcher.dm @@ -21,6 +21,23 @@ // todo: rework launchers to maaaybe have a similar chambering system to ballistics.....? var/atom/movable/chambered +/obj/item/gun/launcher/grenade/consume_next_throwable(datum/gun_firing_cycle/cycle) + if(!chambered) + return GUN_FIRED_FAIL_EMPTY + . = chambered + grenades?.Remove(chambered) + chambered = null + +/obj/item/gun/launcher/grenade/launch_throwable(datum/gun_firing_cycle/cycle, atom/movable/launching) + var/obj/item/grenade/grenade = . = ..() + if(!istype(grenade)) + return + // sigh just to be nice, make it fast + if(istype(grenade, /obj/item/grenade/simple)) + var/obj/item/grenade/simple/simple_casted = grenade + simple_casted.activation_detonate_delay = 1 SECONDS + grenade.activate_shot_from_gun(src, cycle) + //revolves the magazine, allowing players to choose between multiple grenade types /obj/item/gun/launcher/grenade/proc/pump(mob/M as mob) playsound(M, 'sound/weapons/shotgunpump.ogg', 60, 1) diff --git a/code/modules/projectiles/guns/gun/projectile/ballistic.dm b/code/modules/projectiles/guns/gun/projectile/ballistic.dm index 068279f85bc..2ebb2a5f8c1 100644 --- a/code/modules/projectiles/guns/gun/projectile/ballistic.dm +++ b/code/modules/projectiles/guns/gun/projectile/ballistic.dm @@ -337,7 +337,7 @@ eject_chamber(FALSE, TRUE, drop_location(), TRUE) else if(chamber_cycle_after_fire) cycle_chamber(FALSE, TRUE) - if(magazine_auto_eject && !magazine.get_amount_remaining()) + if(magazine_auto_eject && magazine && !magazine.get_amount_remaining()) remove_magazine(null, null, TRUE) if(chamber_spin_after_fire && internal_magazine_revolver_mode && internal_magazine) unsafe_spin_chamber_to_next() diff --git a/code/modules/projectiles/guns/gun_component.dm b/code/modules/projectiles/guns/gun_component.dm index 15dda93d741..482da9c640c 100644 --- a/code/modules/projectiles/guns/gun_component.dm +++ b/code/modules/projectiles/guns/gun_component.dm @@ -61,6 +61,7 @@ * * * we get the final say * * this includes if the gun is already overcrowded! be careful with this + * * skipped if 'force' is enabled on checks in the gun * * @params * * gun - the gun we tried to attach to diff --git a/code/modules/reagents/reagent_containers/borghydro.dm b/code/modules/reagents/reagent_containers/borghydro.dm index cbcb3cdcbb8..6406ea39880 100644 --- a/code/modules/reagents/reagent_containers/borghydro.dm +++ b/code/modules/reagents/reagent_containers/borghydro.dm @@ -1,3 +1,5 @@ +// TODO: this should be in the hypospray mark 2 ecosystem. +// TODO: ontop of that, use fucking item mounts + cyborg resource stores!! /obj/item/reagent_containers/borghypo name = "cyborg hypospray" desc = "An advanced chemical synthesizer and injection system, designed for heavy-duty medical equipment." @@ -27,12 +29,33 @@ /obj/item/reagent_containers/borghypo/lost reagent_ids = list("bicaridine", "kelotane", "alkysine", "imidazoline", "tricordrazine", "inaprovaline", "dexalin", "anti_toxin", "tramadol", "spaceacillin", "paracetamol") +/obj/item/reagent_containers/borghypo/stabilizer + name = "cyborg hypospray (stabilizer)" + desc = "A basic chemical synthesizer for stabilizing wounded." + reagent_ids = list( + /datum/reagent/tricordrazine::id, + /datum/reagent/dexalin::id, + /datum/reagent/inaprovaline::id, + /datum/reagent/dylovene::id, + /datum/reagent/paracetamol::id, + ) + /obj/item/reagent_containers/borghypo/merc name = "advanced cyborg hypospray" desc = "An advanced nanite and chemical synthesizer and injection system, designed for heavy-duty medical equipment. This type is capable of safely bypassing \ thick materials that other hyposprays would struggle with." bypass_protection = TRUE // Because mercs tend to be in spacesuits. - reagent_ids = list("healing_nanites", "hyperzine", "tramadol", "oxycodone", "spaceacillin", "peridaxon", "osteodaxon", "myelamine", "synthblood") + reagent_ids = list( + /datum/reagent/nanite::id, + /datum/reagent/hyperzine::id, + /datum/reagent/tramadol::id, + /datum/reagent/oxycodone::id, + /datum/reagent/spaceacillin::id, + /datum/reagent/peridaxon::id, + /datum/reagent/osteodaxon::id, + /datum/reagent/myelamine::id, + /datum/reagent/blood::id, + ) /obj/item/reagent_containers/borghypo/Initialize(mapload) . = ..() @@ -55,7 +78,7 @@ if(isrobot(loc)) var/mob/living/silicon/robot/R = loc - if(R && R.cell) + if(R && R.cell?.charge > 1000) for(var/T in reagent_ids) if(reagent_volumes[T] < volume) R.cell.use(charge_cost) diff --git a/code/modules/reagents/reagent_containers/syringe.dm b/code/modules/reagents/reagent_containers/syringe.dm index b4c67403ef6..f5f0cb004c0 100644 --- a/code/modules/reagents/reagent_containers/syringe.dm +++ b/code/modules/reagents/reagent_containers/syringe.dm @@ -25,6 +25,9 @@ drop_sound = 'sound/items/drop/glass.ogg' pickup_sound = 'sound/items/pickup/glass.ogg' + /// can be broken? + var/breakable = TRUE + /obj/item/reagent_containers/syringe/on_reagent_change() update_icon() @@ -277,6 +280,10 @@ break_syringe(target, user) /obj/item/reagent_containers/syringe/proc/break_syringe(mob/living/carbon/target, mob/living/carbon/user) + if(!breakable) + return FALSE + if(mode == SYRINGE_BROKEN) + return TRUE desc += " It is broken." mode = SYRINGE_BROKEN if(target) @@ -284,6 +291,7 @@ if(user) add_fingerprint(user) update_icon() + return TRUE /obj/item/reagent_containers/syringe/proc/handle_impact_as_projectile(atom/target, impact_flags, def_zone, efficiency, injected_ptr) if(impact_flags & (PROJECTILE_IMPACT_BLOCKED | PROJECTILE_IMPACT_FLAGS_SHOULD_GO_THROUGH)) @@ -295,3 +303,8 @@ *injected_ptr = reagents.trans_to_mob(casted, reagents.total_volume, CHEM_INJECT) break_syringe(iscarbon(target) ? target : null) return impact_flags + +//* subtypes - do not put pre-fill types in here! *// + +/obj/item/reagent_containers/syringe/unbreakable + breakable = FALSE diff --git a/code/modules/research/designs/_prosfab_designs.dm b/code/modules/research/designs/_prosfab_designs.dm index 29bc4919afc..d345c42c83a 100644 --- a/code/modules/research/designs/_prosfab_designs.dm +++ b/code/modules/research/designs/_prosfab_designs.dm @@ -481,34 +481,33 @@ design_name = "Rename Module" desc = "Used to rename a cyborg." id = "borg_rename_s" - build_path = /obj/item/borg/upgrade/rename + build_path = /obj/item/robot_upgrade/rename /datum/prototype/design/science/prosfab/robot_upgrade/reset design_name = "Reset Module" desc = "Used to reset a cyborg's module. Destroys any other upgrades applied to the robot." id = "borg_reset_module" - build_path = /obj/item/borg/upgrade/reset + build_path = /obj/item/robot_upgrade/reset /datum/prototype/design/science/prosfab/robot_upgrade/restart design_name = "Emergency Restart Module" desc = "Used to force a restart of a disabled-but-repaired robot, bringing it back online." id = "borg_restart_module" materials_base = list(MAT_STEEL = 4500, MAT_GLASS = 3750) - build_path = /obj/item/borg/upgrade/restart + build_path = /obj/item/robot_upgrade/restart /datum/prototype/design/science/prosfab/robot_upgrade/vtec design_name = "VTEC Module" desc = "Used to kick in a robot's VTEC systems, increasing their speed." id = "borg_vtec_module" materials_base = list(MAT_STEEL = 5000, MAT_GLASS = 4500, MAT_GOLD = 3750) - build_path = /obj/item/borg/upgrade/vtec + build_path = /obj/item/robot_upgrade/vtec /datum/prototype/design/science/prosfab/robot_upgrade/tasercooler design_name = "Rapid Taser Cooling Module" desc = "Used to cool a mounted taser, increasing the potential current in it and thus its recharge rate." id = "borg_taser_module" materials_base = list(MAT_STEEL = 6000, MAT_GLASS = 4500, MAT_GOLD = 1500, MAT_DIAMOND = 375) - build_path = /obj/item/borg/upgrade/tasercooler /datum/prototype/design/science/prosfab/robot_upgrade/bluespaceoresatchel design_name = "Bluespace Ore Satchel Module" @@ -516,21 +515,21 @@ id = "borg_bsorebag_module" req_tech = list(TECH_BLUESPACE = 4, TECH_MATERIAL = 6, TECH_PHORON = 4) materials_base = list(MAT_STEEL = 2500, MAT_GOLD = 1500, MAT_DIAMOND = 750, MAT_URANIUM = 150, MAT_PHORON = 1000) - build_path = /obj/item/borg/upgrade/bluespaceorebag + build_path = /obj/item/robot_upgrade/bluespaceorebag /datum/prototype/design/science/prosfab/robot_upgrade/jetpack design_name = "Jetpack Module" desc = "A carbon dioxide jetpack suitable for low-gravity mining operations." id = "borg_jetpack_module" materials_base = list(MAT_STEEL = 5000, MAT_PHORON = 2550, MAT_URANIUM = 1500) - build_path = /obj/item/borg/upgrade/jetpack + build_path = /obj/item/robot_upgrade/jetpack /datum/prototype/design/science/prosfab/robot_upgrade/advhealth design_name = "Advanced Health Analyzer Module" desc = "An advanced health analyzer suitable for diagnosing more serious injuries." id = "borg_advhealth_module" materials_base = list(MAT_STEEL = 1000, MAT_GLASS = 650, MAT_DIAMOND = 350) - build_path = /obj/item/borg/upgrade/advhealth + build_path = /obj/item/robot_upgrade/advhealth /datum/prototype/design/science/prosfab/robot_upgrade/syndicate design_name = "Scrambled Equipment Module" @@ -539,7 +538,7 @@ req_tech = list(TECH_COMBAT = 4, TECH_ILLEGAL = 3) // yeah no no free lunch here fuck you use 4 diamonds it should cost even MORE materials_base = list(MAT_STEEL = 7500, MAT_GLASS = 11250, MAT_DIAMOND = 7500) - build_path = /obj/item/borg/upgrade/syndicate + build_path = /obj/item/robot_upgrade/syndicate /datum/prototype/design/science/prosfab/robot_upgrade/language design_name = "Language Module" @@ -547,14 +546,14 @@ id = "borg_language_module" req_tech = list(TECH_DATA = 6, TECH_MATERIAL = 6) materials_base = list(MAT_STEEL = 750, MAT_GLASS = 300, MAT_GOLD = 350) - build_path = /obj/item/borg/upgrade/language + build_path = /obj/item/robot_upgrade/language /datum/prototype/design/science/prosfab/robot_upgrade/sizeshift design_name = "Size Alteration Module" id = "borg_sizeshift_module" req_tech = list(TECH_BLUESPACE = 3, TECH_MATERIAL = 3, TECH_POWER = 2) materials_base = list(MAT_STEEL = 750, MAT_GLASS = 250) - build_path = /obj/item/borg/upgrade/sizeshift + build_path = /obj/item/robot_upgrade/sizeshift // Synthmorph Bags. diff --git a/code/modules/resleeving/computers.dm b/code/modules/resleeving/computers.dm index c97d808082c..e339e7bd185 100644 --- a/code/modules/resleeving/computers.dm +++ b/code/modules/resleeving/computers.dm @@ -104,7 +104,7 @@ else if(!MT.imp) user.visible_message("This Mirror Installation Tool is empty.") - if(istype(W, /obj/item/dogborg/mirrortool)) + if(istype(W, /obj/item/robot_builtin/dog_mirrortool)) var/obj/item/mirrortool/MT = W if(MT.imp) active_mr = MT.imp.stored_mind diff --git a/code/modules/resleeving/mirror.dm b/code/modules/resleeving/mirror.dm index f2d05ea4825..b7bf9db5dd8 100644 --- a/code/modules/resleeving/mirror.dm +++ b/code/modules/resleeving/mirror.dm @@ -72,8 +72,8 @@ MT.imp = src MT.update_icon() else - if(istype(I, /obj/item/dogborg/mirrortool)) - var/obj/item/dogborg/mirrortool/MT = I + if(istype(I, /obj/item/robot_builtin/dog_mirrortool)) + var/obj/item/robot_builtin/dog_mirrortool/MT = I if(MT.imp) to_chat(usr, "The mirror tool already contains a mirror.") return // It's full. diff --git a/code/modules/species/outsider/vox.dm b/code/modules/species/outsider/vox.dm index f9b7f15aa6b..d7e95a55ccf 100644 --- a/code/modules/species/outsider/vox.dm +++ b/code/modules/species/outsider/vox.dm @@ -122,7 +122,7 @@ // ensure they have a valid mask var/mask_type = /obj/item/clothing/mask/breath if(for_target) - var/obj/item/existing_mask = for_target.inventory.get_slot_single(/datum/inventory_slot/inventory/mask) + var/obj/item/existing_mask = for_target.inventory.get_slot_single(/datum/inventory_slot/inventory/mask::id) if(existing_mask?.clothing_flags & ALLOWINTERNALS) else if(for_target.temporarily_remove_from_inventory(existing_mask, INV_OP_FORCE | INV_OP_SILENT)) diff --git a/code/modules/species/shadekin/shadekin_hud.dm b/code/modules/species/shadekin/shadekin_hud.dm index c6029da09a9..0956e47bc92 100644 --- a/code/modules/species/shadekin/shadekin_hud.dm +++ b/code/modules/species/shadekin/shadekin_hud.dm @@ -1,6 +1,6 @@ /atom/movable/screen/shadekin name = "shadekin status" - icon = 'icons/screen/hud/common/shadekin.dmi' + icon = 'icons/screen/hud/styles/common/shadekin.dmi' invisibility = 101 /atom/movable/screen/movable/ability_master/shadekin diff --git a/code/modules/species/station/phoronoids.dm b/code/modules/species/station/phoronoids.dm index 612f3b540d3..622ab192077 100644 --- a/code/modules/species/station/phoronoids.dm +++ b/code/modules/species/station/phoronoids.dm @@ -113,7 +113,7 @@ var/mask_type = /obj/item/clothing/mask/breath if(for_target) - var/obj/item/existing_mask = for_target.inventory.get_slot_single(/datum/inventory_slot/inventory/mask) + var/obj/item/existing_mask = for_target.inventory.get_slot_single(/datum/inventory_slot/inventory/mask::id) if(existing_mask?.clothing_flags & ALLOWINTERNALS) else if(!isnull(existing_mask)) @@ -234,8 +234,8 @@ into_inv?.Add(/obj/item/extinguisher/mini/plasman) if(for_target) - var/obj/item/existing_head_slot = for_target.inventory.get_slot_single(/datum/inventory_slot/inventory/head) - var/obj/item/existing_suit_slot = for_target.inventory.get_slot_single(/datum/inventory_slot/inventory/suit) + var/obj/item/existing_head_slot = for_target.inventory.get_slot_single(/datum/inventory_slot/inventory/head::id) + var/obj/item/existing_suit_slot = for_target.inventory.get_slot_single(/datum/inventory_slot/inventory/suit::id) var/obj/item/creating_suit_slot = new suit_path if(existing_head_slot) if(for_target.temporarily_remove_from_inventory(existing_head_slot, INV_OP_FORCE | INV_OP_SILENT | INV_OP_FLUFFLESS)) diff --git a/code/modules/species/station/standard/tajaran.dm b/code/modules/species/station/standard/tajaran.dm index 44e7f6ab83e..9451d8e09e7 100644 --- a/code/modules/species/station/standard/tajaran.dm +++ b/code/modules/species/station/standard/tajaran.dm @@ -128,7 +128,7 @@ /datum/species/tajaran/apply_racial_gear(mob/living/carbon/for_target, list/into_box, list/into_inv) var/footwear_type = /obj/item/clothing/shoes/sandal - if(for_target && !for_target.inventory?.get_slot_single(/datum/inventory_slot/inventory/shoes)) + if(for_target && !for_target.inventory?.get_slot_single(/datum/inventory_slot/inventory/shoes::id)) var/obj/item/footwear_instance = new footwear_type if(!for_target.inventory.equip_to_slot_if_possible(footwear_instance, /datum/inventory_slot/inventory/shoes)) into_inv += footwear_instance diff --git a/code/modules/species/station/standard/teshari.dm b/code/modules/species/station/standard/teshari.dm index be6d1c744d8..303b6423141 100644 --- a/code/modules/species/station/standard/teshari.dm +++ b/code/modules/species/station/standard/teshari.dm @@ -180,7 +180,7 @@ /datum/species/teshari/apply_racial_gear(mob/living/carbon/for_target, list/into_box, list/into_inv) var/footwear_type = /obj/item/clothing/shoes/sandal - if(for_target && !for_target.inventory?.get_slot_single(/datum/inventory_slot/inventory/shoes)) + if(for_target && !for_target.inventory?.get_slot_single(/datum/inventory_slot/inventory/shoes::id)) var/obj/item/footwear_instance = new footwear_type if(!for_target.inventory.equip_to_slot_if_possible(footwear_instance, /datum/inventory_slot/inventory/shoes)) into_inv += footwear_instance diff --git a/code/modules/species/station/standard/unathi.dm b/code/modules/species/station/standard/unathi.dm index f4f920aaf69..7e47d746b86 100644 --- a/code/modules/species/station/standard/unathi.dm +++ b/code/modules/species/station/standard/unathi.dm @@ -147,7 +147,7 @@ /datum/species/unathi/apply_racial_gear(mob/living/carbon/for_target, list/into_box, list/into_inv) var/footwear_type = /obj/item/clothing/shoes/sandal - if(for_target && !for_target.inventory?.get_slot_single(/datum/inventory_slot/inventory/shoes)) + if(for_target && !for_target.inventory?.get_slot_single(/datum/inventory_slot/inventory/shoes::id)) var/obj/item/footwear_instance = new footwear_type if(!for_target.inventory.equip_to_slot_if_possible(footwear_instance, /datum/inventory_slot/inventory/shoes)) into_inv += footwear_instance diff --git a/code/modules/species/station/standard/zaddat.dm b/code/modules/species/station/standard/zaddat.dm index 1bf1b1b65b5..e8b329644e9 100644 --- a/code/modules/species/station/standard/zaddat.dm +++ b/code/modules/species/station/standard/zaddat.dm @@ -100,7 +100,7 @@ // ensure they have a valid mask var/mask_type = /obj/item/clothing/mask/gas/zaddat if(for_target) - var/obj/item/existing_mask = for_target.inventory.get_slot_single(/datum/inventory_slot/inventory/mask) + var/obj/item/existing_mask = for_target.inventory.get_slot_single(/datum/inventory_slot/inventory/mask::id) if(for_target.temporarily_remove_from_inventory(existing_mask, INV_OP_FORCE | INV_OP_SILENT)) into_inv?.Add(existing_mask) var/obj/item/creating_mask = new mask_type @@ -114,7 +114,7 @@ var/suit_path = /obj/item/clothing/suit/space/void/zaddat if(for_target) - var/obj/item/existing_suit_slot = for_target.inventory.get_slot_single(/datum/inventory_slot/inventory/suit) + var/obj/item/existing_suit_slot = for_target.inventory.get_slot_single(/datum/inventory_slot/inventory/suit::id) var/obj/item/creating_suit_slot = new suit_path if(existing_suit_slot) if(for_target.temporarily_remove_from_inventory(existing_suit_slot, INV_OP_FORCE | INV_OP_SILENT)) diff --git a/code/modules/tgui/states/hands.dm b/code/modules/tgui/states/hands.dm index 9dcbd03a1c7..855beea8234 100644 --- a/code/modules/tgui/states/hands.dm +++ b/code/modules/tgui/states/hands.dm @@ -23,8 +23,3 @@ GLOBAL_DATUM_INIT(hands_state, /datum/ui_state/hands_state, new) if(src_object in get_held_items()) return UI_INTERACTIVE return UI_CLOSE - -/mob/living/silicon/robot/hands_can_use_topic(src_object) - if(activated(src_object)) - return UI_INTERACTIVE - return UI_CLOSE diff --git a/code/modules/tgui_extensions/README.md b/code/modules/tgui_extensions/README.md new file mode 100644 index 00000000000..dce398409bf --- /dev/null +++ b/code/modules/tgui_extensions/README.md @@ -0,0 +1,3 @@ +# TGUI Extensions + +pretty much the citadel tgui experiment wasteland diff --git a/code/modules/tgui_extensions/actor_modals/robot_module_picker.dm b/code/modules/tgui_extensions/actor_modals/robot_module_picker.dm new file mode 100644 index 00000000000..e4b589278ee --- /dev/null +++ b/code/modules/tgui_extensions/actor_modals/robot_module_picker.dm @@ -0,0 +1,105 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2025 Citadel Station Developers *// + +/datum/tgui_actor_modal/robot_module_picker + tgui_interface = "actor_modal/RobotModulePicker" + no_type_dupe = TRUE + +/datum/tgui_actor_modal/robot_module_picker/initialize() + if(!isrobot(actor.performer)) + return FALSE + return ..() + +/datum/tgui_actor_modal/robot_module_picker/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state, datum/event_args/actor/actor) + . = ..() + if(.) + return + var/mob/living/silicon/robot/robot = src.actor.performer + if(!istype(robot)) + // how? + qdel(src) + return TRUE + if(!robot.can_repick_module) + // how? + qdel(src) + return TRUE + switch(action) + if("pick") + var/module_id = params["moduleId"] + var/frame_ref = params["frameRef"] + if(!istext(frame_ref) || !length(frame_ref)) + return TRUE + var/datum/prototype/robot_module/resolved_module = RSrobot_modules.fetch_local_or_throw(module_id) + if(!resolved_module) + return TRUE + var/datum/robot_frame/resolved_frame = locate(frame_ref) in resolved_module.frames + if(!resolved_frame) + return TRUE + // check ckey lock + if(resolved_frame.ckey_lock && !(actor.initiator.ckey in resolved_frame.ckey_lock)) + return TRUE + robot.set_from_frame(resolved_frame, TRUE) + robot.set_module(resolved_module, TRUE) + robot.update_icon() + // no moving / acting for 5 seconds + robot.afflict_root(5 SECONDS) + robot.afflict_daze(5 SECONDS) + do + var/datum/effect_system/smoke_spread/smoke_puff = new + smoke_puff.set_up(2, loca = get_turf(robot)) + smoke_puff.start() + while(FALSE) + robot.visible_message( + SPAN_NOTICE("With a series of mechanical whirrs, [robot] specializes into \a [resolved_module.get_visible_name()] module."), + ) + qdel(src) + return TRUE + +/datum/tgui_actor_modal/robot_module_picker/ui_static_data(mob/user, datum/tgui/ui) + . = ..() + var/list/datum/prototype/robot_module/pickable_modules = assemble_modules(actor.performer) + var/list/serialized_modules = list() + .["modules"] = serialized_modules + for(var/datum/prototype/robot_module/possible_module as anything in pickable_modules) + var/module_name = "[possible_module.category ? "[possible_module.category] " : ""][possible_module.get_visible_name()]" + var/list/serialized_frames = list() + var/list/serialized_module = list( + "id" = possible_module.id, + "name" = module_name, + "frames" = serialized_frames, + ) + var/list/datum/robot_frame/possible_frames = pickable_modules[possible_module] + // TODO: iconRef doesn't work properly for non-hardcoded frames but we can worry about it later + for(var/datum/robot_frame/possible_frame as anything in possible_frames) + var/frame_ref = ref(possible_frame) + // ckey enforcement should probably be elsewhere but idgaf lol + if(possible_frame.ckey_lock && !(user?.ckey in possible_frame.ckey_lock)) + continue + serialized_frames[frame_ref] = list( + "ref" = frame_ref, + "name" = possible_frame.name || "???", + "iconRef" = "\ref[possible_frame.robot_iconset.icon]", + "iconState" = "[possible_frame.robot_iconset.icon_state]", + ) + serialized_modules[possible_module.id] = serialized_module + +/** + * @return list( + * module instance = list( + * frame instance, + * ), + * ) + */ +/datum/tgui_actor_modal/robot_module_picker/proc/assemble_modules(mob/living/silicon/robot/for_robot) as /list + . = list() + + var/list/our_selection_groups = for_robot.get_module_pick_groups() + for(var/datum/prototype/robot_module/module as anything in RSrobot_modules.fetch_subtypes_immutable(/datum/prototype/robot_module)) + if(!length(module.selection_groups_all) && !length(module.selection_groups_any)) + continue + if(module.selection_groups_all && (length(module.selection_groups_all) != length(module.selection_groups_all & our_selection_groups))) + continue + if(module.selection_groups_any && (!length(module.selection_groups_any & our_selection_groups))) + continue + // frame ckey enforcement is in ui static data. + .[module] = module.frames diff --git a/code/modules/tgui_extensions/tgui_actor_modal.dm b/code/modules/tgui_extensions/tgui_actor_modal.dm new file mode 100644 index 00000000000..9846d7dfeec --- /dev/null +++ b/code/modules/tgui_extensions/tgui_actor_modal.dm @@ -0,0 +1,92 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2025 Citadel Station Developers *// + +/** + * @params + * * type - modal type + * * actor - actor doing it + * * validity - (optional) additional validity checks + * * ... - additional args to pass to initialize() + * + * @return modal or null if failed to open + */ +/proc/open_tgui_actor_modal(type, datum/event_args/actor/actor, datum/callback/validity, ...) + var/datum/tgui_actor_modal/modal_type = type + if(modal_type.no_type_dupe) + var/mob/initiator = actor.initiator + var/trait = TRAIT_MOB_ACTOR_MODAL_INITIATOR(modal_type, initiator, actor.performer) + if(HAS_TRAIT(initiator, trait)) + return + var/datum/tgui_actor_modal/modal = new type(actor, validity) + if(!modal.initialize(arglist(args.Copy(4)))) + qdel(modal) + return + modal.ui_interact(actor.initiator) + return modal + +/** + * generalized tgui modals with procs for checking things like activity + * and validity + * + * * not to be confused with `/datum/admin_modal`; these have a specific + * user and target, usually + * * these should be in `tgui/interfaces/actor_modal` ideally. + */ +/datum/tgui_actor_modal + /// actor initiator-performer pair + var/datum/event_args/actor/actor + /// check to see if we can still do it; useful if we're remote controlling or something + var/datum/callback/validity + /// only one type on initiator-performer pair, period + /// * only checked for compile time value + var/no_type_dupe = FALSE + /// which tgui interface to open + var/tgui_interface + /// only initiator can access this ui; by default, + /// we use always_state and initiator-only + var/lock_to_initiator = TRUE + +/datum/tgui_actor_modal/New(datum/event_args/actor/actor, datum/callback/validity) + var/mob/initiator = actor.initiator + var/trait = TRAIT_MOB_ACTOR_MODAL_INITIATOR(type, initiator, actor.performer) + ADD_TRAIT(initiator, trait, ref(src)) + src.actor = actor + src.validity = validity + +/datum/tgui_actor_modal/Destroy() + var/mob/initiator = actor.initiator + var/trait = TRAIT_MOB_ACTOR_MODAL_INITIATOR(type, initiator, actor.performer) + REMOVE_TRAIT(initiator, trait, ref(src)) + actor = null + validity = null + return ..() + +/** + * @return FALSE to reject opening + */ +/datum/tgui_actor_modal/proc/initialize() + return TRUE + +/datum/tgui_actor_modal/ui_state(mob/user) + return GLOB.always_state + +/datum/tgui_actor_modal/ui_status(mob/user, datum/ui_state/state) + if(lock_to_initiator) + if(user != actor.initiator) + return UI_CLOSE + return ..() + +/datum/tgui_actor_modal/robot_module_picker/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, tgui_interface) + ui.set_autoupdate(FALSE) + ui.open() + // cleanup if it didn't open + spawn(2 SECONDS) + if(!QDELETED(src) && !length(open_uis)) + qdel(src) + +/datum/tgui_actor_modal/on_ui_close(mob/user, datum/tgui/ui, embedded) + ..() + qdel(src) diff --git a/code/modules/vehicles_legacy/construction.dm b/code/modules/vehicles_legacy/construction.dm index dd8e6fcaeff..9684ea30a9c 100644 --- a/code/modules/vehicles_legacy/construction.dm +++ b/code/modules/vehicles_legacy/construction.dm @@ -197,7 +197,7 @@ /obj/item/vehicle_assembly/spacebike/attackby(var/obj/item/W as obj, var/mob/user as mob) switch(build_stage) if(0) - if(istype(W, /obj/item/tank/jetpack) || istype(W, /obj/item/borg/upgrade/jetpack)) + if(istype(W, /obj/item/tank/jetpack) || istype(W, /obj/item/robot_upgrade/jetpack)) if(!user.attempt_consume_item_for_construction(W)) return increase_step() diff --git a/code/modules/vore/eating/digest_act_vr.dm b/code/modules/vore/eating/digest_act_vr.dm index e481ebd2a12..bb69c014ec9 100644 --- a/code/modules/vore/eating/digest_act_vr.dm +++ b/code/modules/vore/eating/digest_act_vr.dm @@ -4,7 +4,7 @@ // Ye default implementation. /obj/item/proc/digest_act(var/atom/movable/item_storage = null) - if(istype(item_storage,/obj/item/dogborg/sleeper)) + if(istype(item_storage,/obj/item/robot_builtin/dog_sleeper)) for(var/obj/item/O in contents) if(item_storage) O.forceMove(item_storage) @@ -55,7 +55,7 @@ //PDAs need to lose their ID to not take it with them, so we can get a digested ID /obj/item/pda/digest_act(var/atom/movable/item_storage = null) if(id) - if(istype(item_storage,/obj/item/dogborg/sleeper) || (!isnull(digest_stage) && digest_stage <= 0)) + if(istype(item_storage,/obj/item/robot_builtin/dog_sleeper) || (!isnull(digest_stage) && digest_stage <= 0)) id = null . = ..() diff --git a/code/modules/vore/eating/living_vr.dm b/code/modules/vore/eating/living_vr.dm index 89d9a6c70cb..ad94ceeadb2 100644 --- a/code/modules/vore/eating/living_vr.dm +++ b/code/modules/vore/eating/living_vr.dm @@ -369,9 +369,9 @@ B.owner.update_icons() //You're in a dogborg! - else if(istype(loc, /obj/item/dogborg/sleeper)) + else if(istype(loc, /obj/item/robot_builtin/dog_sleeper)) var/mob/living/silicon/pred = loc.loc //Thing holding the belly! - var/obj/item/dogborg/sleeper/belly = loc //The belly! + var/obj/item/robot_builtin/dog_sleeper/belly = loc //The belly! var/confirm = alert(src, "You're in a dogborg sleeper. This is for escaping from preference-breaking or if your predator disconnects/AFKs. If your preferences were being broken, please admin-help as well.", "Confirmation", "Okay", "Cancel") if(!confirm == "Okay" || loc != belly) diff --git a/code/modules/xenoarcheaology/boulder.dm b/code/modules/xenoarcheaology/boulder.dm index e67d1f87cc1..b00342bc55e 100644 --- a/code/modules/xenoarcheaology/boulder.dm +++ b/code/modules/xenoarcheaology/boulder.dm @@ -91,8 +91,9 @@ else if(istype(AM,/mob/living/silicon/robot)) var/mob/living/silicon/robot/R = AM - if(istype(R.module_active,/obj/item/pickaxe)) - attackby(R.module_active,R) + var/obj/item/pickaxe/maybe_pickaxe = R.get_held_item_of_type(/obj/item/pickaxe) + if(maybe_pickaxe) + maybe_pickaxe.melee_interaction_chain(src, R) else if(istype(AM,/obj/vehicle/sealed/mecha)) var/obj/vehicle/sealed/mecha/M = AM diff --git a/code/modules/xenoarcheaology/finds/find_spawning.dm b/code/modules/xenoarcheaology/finds/find_spawning.dm index fe0bd1bff59..e215cbe1eed 100644 --- a/code/modules/xenoarcheaology/finds/find_spawning.dm +++ b/code/modules/xenoarcheaology/finds/find_spawning.dm @@ -372,7 +372,7 @@ //robot remains apply_prefix = 0 item_type = "[pick("mechanical","robotic","cyborg")] [pick("remains","chassis","debris")]" - icon = 'icons/mob/robots.dmi' + icon = 'icons/mob/robot-legacy.dmi' icon_state = "remainsrobot" additional_desc = pick("Almost mistakeable for the remains of a modern cyborg.",\ "They are barely recognisable as anything other than a pile of waste metals.",\ diff --git a/config/custom_items.txt b/config/custom_items.txt deleted file mode 100644 index 2adfcbac3da..00000000000 --- a/config/custom_items.txt +++ /dev/null @@ -1,1033 +0,0 @@ -## -# Custom items go here. They are modifications of existing paths; look at the example for details. -# Item will spawn if the target has one of the req_titles and if their on-spawn ID has the required access level. -# req_access is going to be a shit to maintain since the config file can't grab constants and has to use integers, use it minimally. -# Separate titles with a single comma and a space (', ') or they'll bork. -# -# EX: -# { -# ckey: zuhayr -# character_name: Jane Doe -# item_path: /obj/item/toy/plushie -# item_name: ugly plush toy -# item_icon: flagmask -# item_desc: It's truly hideous. -# req_titles: Assistant, Security Officer -# req_access: 1 -# } -# -# { -# ckey: zuhayr -# character_name: Jane Doe -# item_path: /obj/item/kit/paint -# item_name: APLU customisation kit -# item_desc: A customisation kit with all the parts needed to turn an APLU into a "Titan's Fist" model. -# kit_name: APLU "Titan's Fist" -# kit_desc: Looks like an overworked, under-maintained Ripley with some horrific damage. -# kit_icon: titan -# additional_data: ripley, firefighter -# } -# -# { -# ckey: zuhayr -# character_name: Jane Doe -# item_path: /obj/item/kit/suit -# item_name: salvage suit customisation kit -# item_desc: A customisation kit with all the parts needed to convert a suit. -# kit_name: salvage -# kit_desc: An orange voidsuit. Reinforced! -# kit_icon: salvage -# } -## - -# ######## 0-9 CKEYS -{ -ckey: 1r1s -character_name: Zippy Shanks -item_path: /obj/item/melee/fluff/holochain/Zippy -} - -{ -ckey: 1r1s -character_name: Malady Blanche -item_path: /obj/item/material/twohanded/fluff/riding_crop/malady -} - -# ######## A CKEYS -{ -ckey: adk09 -character_name: Lethe -item_path: /obj/item/clothing/head/helmet/hos/fluff/lethe -} - -{ -ckey: argobargsoup -character_name: Lynn Shady -item_path: /obj/item/flashlight/pen/fluff/lynn -} - -{ -ckey: arokha -character_name: Aronai Kadigan -item_path: /obj/item/clothing/under/utility/sifguard/medical/command -item_name: centcom medical uniform -item_desc: A medical uniform straight from Central Command. -} - -{ -ckey: arokha -character_name: Aronai Kadigan -item_path: /obj/item/clothing/suit/storage/service/sifguard/medical/command -item_name: centcom medical jacket -item_desc: A medical jacket straight from Central Command. -} - -{ -ckey: arokha -character_name: Aronai Kadigan -item_path: /obj/item/card/id/centcom/station/fluff/aronai -} - -Weapon Box. Permit Expired -{ -ckey: aerowing -character_name: Sebastian Aji -item_path: /obj/item/storage/box/fluff/sebastian_aji -} - -# ######## B CKEYS -{ -ckey: benemuel -character_name: Yuuko Shimmerpond -item_path: /obj/item/clothing/under/fluff/sakura_hokkaido_kimono -} - -{ -ckey: beyondmylife -character_name: Cassandra Selone -item_path: /obj/item/storage/box/fluff/cassandra -} - -{ -ckey: beyondmylife -character_name: Kilano Soryu -item_path: /obj/item/clothing/under/dress/fluff/kilano -} - -{ -ckey: beyondmylife -character_name: Kilano Soryu -item_path: /obj/item/clothing/gloves/fluff/kilano -} - -{ -ckey: beyondmylife -character_name: Ne'tra Ky'ram -item_path: /obj/item/storage/box/fluff/kilano -req_access: 1 -} - -{ -ckey: britishrabbit -character_name: Xin Xiao -item_path: /obj/item/clothing/under/soviet -item_desc: This soviet uniform has seen considerable use over the years, it's rather worn in some places, frayed in others and the stomach region has signs of being stretched out repeatedly. -} - -{ -ckey: bwoincognito -character_name: Tasald Corlethian -item_path: /obj/item/storage/box/fluff/tasald -} - -{ -ckey: bwoincognito -character_name: Octavious Ward -item_path: /obj/item/storage/box/fluff/octavious -} - -{ -ckey: burritojustice -character_name: Jayda Wilson -item_path: /obj/item/clothing/under/utility/sifguard/medical -} - -# ######## C CKEYS -{ -ckey: cockatricexl -character_name: James Holder -item_path: /obj/item/disk/data -} - -{ -ckey: cameron653 -character_name: Jasmine Lizden -item_path: /obj/item/implanter/reagent_generator/jasmine -} - -{ -ckey: cameron653 -character_name: Diana Kuznetsova -item_path: /obj/item/clothing/suit/fluff/purp_robes -} - -{ -ckey: cameron653 -character_name: Diana Kuznetsova -item_path: /obj/item/clothing/head/fluff/pink_tiara -} - -# ######## D CKEYS -{ -ckey: deepindigo -character_name: Amina Dae-Kouri -item_path: /obj/item/storage/bible/fluff/amina -} - -{ -ckey: dhaeleena -character_name: Dhaeleena M'iar -item_path: /obj/item/clothing/accessory/medal/silver/security/fluff/dhael -} - -#Permit Expired -#{ -#ckey: dhaeleena -#character_name: Dhaeleena M'iar -#item_path: /obj/item/gun/projectile/revolver/mateba/fluff/dhael -#} -# -#{ -#ckey: dhaeleena -#character_name: Dhaeleena M'iar -#item_path: /obj/item/clothing/accessory/permit/gun/fluff/dhaeleena_miar -#} - -{ -ckey: dickfreedomjohnson -character_name: Elliot Richards -item_path: /obj/item/clothing/accessory/medal/medical -} - -{ -ckey: dickfreedomjohnson -character_name: Elliot Richards -item_path: /obj/item/storage/belt/champion -} - -{ -ckey: drakefrostpaw -character_name: Drake Frostpaw -item_path: /obj/item/storage/box/fluff/drake -} - -{ -ckey: draycu -character_name: Theseus -item_path: /obj/item/coin/diamond -item_name: theseus' diamond coin -item_desc: An engraved coin made of diamond. On the side for heads is printed the year 2541, along with the letter T. On the side for tails, the letter Y can be seen. -} - -{ -ckey: draycu -character_name: Schae Yonra -item_path: /obj/item/storage/box/fluff/yonra -} - -# ######## E CKEYS - -# Permit Expired -#{ -#ckey: eekasqueak -#character_name: Serkii Miishy -#item_path: /obj/item/clothing/accessory/permit/gun/fluff/serkiimiishy -#} -# -#{ -#ckey: eekasqueak -#character_name: Serkii Miishy -#item_path: /obj/item/gun/energy/stunrevolver -#} - -{ -ckey: eekasqueak -character_name: Serkii Miishy -item_path: /obj/item/clothing/shoes/slippers -} - -{ -ckey: eekasqueak -character_name: Serkii Miishy -item_path: /obj/item/clothing/under/skirt/fluff/serkii -} - -{ -ckey: epiccharger -character_name: Jessie Mare -item_path: /obj/item/clothing/suit/storage/hooded/wintercoat/jessie -} - -{ -ckey: epigraphzero -character_name: Verd Woodrow -item_path: /obj/item/clothing/accessory/medal/bronze_heart -} - -# ######## F CKEYS -# ######## G CKEYS - -{ -ckey:Gowst -character_name: Eldi Moljir -item_path: /obj/item/implanter/reagent_generator/eldi -} - -# ######## H CKEYS - -{ -ckey: hottokeeki -character_name: Belle Day -item_path: /obj/item/gun/energy/sizegun -} - -{ -ckey: hottokeeki -character_name: Belle Day -item_path: /obj/item/gun/energy/netgun -} - -{ -ckey: hottokeeki -character_name: Belle Day -item_path: /obj/item/implanter/reagent_generator/belle -} - -#{ -#ckey: hzdonut -#character_name: Jesse Soemmer -#item_path: /obj/item/gun/projectile/revolver/fluff/jesselemat -#} -# -#{ -#ckey: hzdonut -#character_name: Jesse Soemmer -#item_path: /obj/item/clothing/accessory/permit/gun/fluff/JesseSoemmer -#} -# -#{ -#ckey: hzdonut -#character_name: Jesse Soemmer -#item_path: /obj/item/clothing/accessory/holster/hip -#} - -# ######## I CKEYS - -{ -ckey: interrolouis -character_name: Ruda Lizden -item_path: /obj/item/clothing/accessory/badge/holo/detective/ruda -} - -{ -ckey: interrolouis -character_name: Kai Highlands -item_path: /obj/item/ka_modkit/chassis_mod/kai -} - -{ -ckey: ivymoomoo -character_name: Ivy Baladeva -item_path: /obj/item/storage/backpack/messenger/sec/fluff/ivymoomoo -} - -# ######## J CKEYS - -{ -ckey: jacknoir413 -character_name: Mor Xaina -item_path: /obj/item/storage/box/fluff/morxaina -} - -{ -ckey: jacknoir413 -character_name: Areax Third -item_path: /obj/item/storage/backpack/fluff/stunstaff -req_titles: Security Officer, Warden, Head of Security -} - -{ -ckey: jacobdragon -character_name: Earthen Breath -item_path: /obj/item/clothing/under/fluff/earthenbreath -} - -{ -ckey: jacobdragon -character_name: Earthen Breath -item_path: /obj/item/clothing/head/fluff/hairflowerpin -} - -{ -ckey: jemli -character_name: Cirra Mayhem -item_path: /obj/item/storage/box/fluff/cirra -} - -{ -ckey: jemli -character_name: Jemli -item_path: /obj/item/clothing/head/fedora/fluff/jemli -} - -{ -ckey: jertheace -character_name: Jeremiah Acacius -item_path: /obj/item/gun/projectile/shotgun/pump/USDF/fluff/ace -req_access = 58 -} - -{ -ckey: jertheace -character_name: Jeremiah Acacius -item_path: /obj/item/clothing/accessory/permit/gun/fluff/ace -req_access = 58 -} - -{ -ckey: jertheace -character_name: Jeremiah Acacius -item_path: /obj/item/clothing/shoes/boots/combat -} - -{ -ckey: jertheace -character_name: Jeremiah Acacius -item_path: /obj/item/clothing/under/syndicate/combat -} - -{ -ckey: jertheace -character_name: Jeremiah Acacius -item_path: /obj/item/clothing/suit/armor/tactical/officer/fluff/ace -} - -{ -ckey: joanrisu -character_name: Joan Risu -item_path: /obj/item/storage/backpack/dufflebag/sec/fluff/joanrisu -} - -{ -ckey: joanrisu -character_name: Katarina Eine -item_path: /obj/item/storage/backpack/dufflebag/sec/fluff/katarina -} - -{ -ckey: joey4298 -character_name: Rosey Tasimaro Maximus -item_path: /obj/item/clothing/head/fluff/threetail -} - -{ -ckey: joey4298 -character_name: Emoticon -item_path: /obj/item/storage/box/fluff/emoticon -} - -{ -ckey: joey4298 -character_name: Emoticon -item_path: /obj/item/clothing/under/sexymime -} - -{ -ckey: joey4298 -character_name: Emoticon -item_path: /obj/item/clothing/mask/gas/sexymime -} - -{ -ckey: john.wayne9392 -character_name: Harmony Pretchl -item_path: /obj/item/clothing/accessory/medal/heroism -} - -{ -ckey: john.wayne9392 -character_name: Harmony Pretchl -item_path: /obj/item/modkit_conversion/fluff/harmonysuit -} - -{ -ckey: john.wayne9392 -character_name: Harmony Pretchl -item_path: /obj/item/modkit_conversion/fluff/harmonyspace -} - -# ######## K CKEYS -{ -ckey: kazkin -character_name: Ahzrukhal Ahkeen -item_path: /obj/item/clothing/accessory/medal/silver/unity -} - -{ -ckey: keekenox -character_name: SMU-453 -item_path: /obj/item/clothing/accessory/medal/nobel_science -} - -{ -ckey: ketrai -character_name: Ketrai -item_path: /obj/item/clothing/head/fluff/ketrai -} - -{ -ckey: kiraalitruss -character_name: Amaya Rahl -item_path: /obj/item/card/id/fluff/amaya -} - -{ -ckey: kisukegema -character_name: Kisuke Gema -item_path: /obj/item/clothing/glasses/omnihud/kamina -} - -{ -ckey: Killjaden -character_name: Lassara Faaira'Nrezi -item_path: /obj/item/clothing/accessory/storage/knifeharness -} - -{ -ckey: kitchifox -character_name: Rana Uma -item_path: /obj/item/clothing/accessory/medal/silver/unity -} - -{ -ckey: KiwiDaNinja -character_name: Chakat Taiga -item_path: /obj/item/clothing/under/fluff/taiga -} - -#{ -#ckey: kligor -#character_name: Andy Gettemy -#item_path: /obj/item/pda_mod/fluff/kligor -#} - -{ -ckey: konabird -character_name: Rischi -item_path: /obj/item/implanter/reagent_generator/rischi -} - -{ -ckey: knightfall5 -character_name: Ashley Kifer -item_path: /obj/item/clothing/accessory/medal/nobel_science/fluff/ashley -} - -# ######## L CKEYS - -#Weapon Box. Permit Expired -#{ -#ckey: luminescentring -#character_name: Briana Moore -#item_path: /obj/item/storage/box/fluff/briana_moore -#} - -{ -ckey: luminescentring -character_name: Briana Moore -item_path: /obj/item/storage/backpack/messenger/black/fluff/briana -} - -{ -ckey: Lycanthorph -character_name: Savannah Dixon -item_path: /obj/item/implanter/reagent_generator/savannah -} - -# ######## M CKEYS -{ -ckey: mewchild -character_name: Phi Vietsi -item_path: /obj/item/storage/box/fluff/vietsi -} - -{ -ckey: molenar -character_name: Uya Kohakuren -item_path: /obj/item/clothing/head/fluff/molenar -} - -{ -ckey: molenar -character_name: Giliana Gamish -item_path: /obj/item/clothing/suit/storage/toggle/labcoat/fluff/molenar -} - -{ -ckey: molenar -character_name: Giliana Gamish -item_path: /obj/item/clothing/head/fluff/molenar2 -} - -# Permit Expired -#{ -#ckey: molenar -#character_name: Kari Akiren -#item_path: /obj/item/gun/projectile/shotgun/pump/rifle/fluff/kari_akiren -#} -# -#{ -#ckey: molenar -#character_name: Kari Akiren -#item_path: /obj/item/clothing/accessory/permit/gun/fluff/kari_akiren -#} - -{ -ckey: myryan -character_name: Myryan Karnage-Cunningham -item_path: /obj/item/storage/belt/utility/fluff/vulpine -} - -{ -ckey: mr_signmeup -character_name: Reshskakskakss Seekiseekis -item_path: /obj/item/clothing/suit/security/navyhos -req_titles: Head of Security -} - -# ######## N CKEYS - -{ -ckey: natje -character_name: Awen Henry -item_path: /obj/item/clothing/head/fluff/awoo -} - -{ -ckey: natje -character_name: Awen Henry -item_path: /obj/item/clothing/shoes/fluff/awoo -} - -{ -ckey: natje -character_name: Awen Henry -item_path: /obj/item/clothing/under/fluff/awoo -} - -{ -ckey: natje -character_name: Pumila -item_path: /obj/item/clothing/under/fluff/aluranevines -} - -{ -ckey: nepox -character_name: Annie Rose -item_path: /obj/item/clothing/accessory/sweater/fluff/annie -} - -# ######## O CKEYS -{ -ckey: orbisa -character_name: Richard D'angelo -item_path: /obj/item/melee/fluff/holochain -} - -# ######## P CKEYS - -{ -ckey: pawoverlord -character_name: Sorrel Cavalet -item_path: /obj/item/clothing/accessory/permit/gun/fluff/sorrel_cavalet -} - -{ -ckey: pawoverlord -character_name: Sorrel Cavalet -item_path: /obj/item/gun/projectile/colt -item_desc: "A cheap Martian knock-off of a Colt M1911. It has the word 'Cavalet' etched on the side. Uses .45 rounds." -} - -{ -ckey: phoaly -character_name: Lily Maximus -item_path: /obj/item/clothing/accessory/medal/silver/unity -} - -{ -ckey: pontifexminimus -character_name: Lucius Null -item_path: /obj/item/fluff/dragor_dot -} -{ -ckey: pontifexminimus -character_name: Lucia Null -item_path: /obj/item/fluff/dragor_dot -} - -# ######## Q CKEYS - -# ######## R CKEYS - -# Permit Expired -#{ -#ckey: Razerwing -#character_name: Archer Maximus -#item_path: /obj/item/clothing/accessory/permit/gun/fluff/archermaximus -#} -# -#{ -#ckey: Razerwing -#character_name: Archer Maximus -#item_path: /obj/item/gun/projectile/colt/fluff/archercolt -#} - -# ######## S CKEYS -{ -ckey: samanthafyre -character_name: Kateryna Petrovitch -item_path: /obj/item/clothing/suit/space/void/engineering/kate -} - -{ -ckey: samanthafyre -character_name: Kateryna Petrovitch -item_path: /obj/item/clothing/head/helmet/space/fluff/kate -} - -{ -ckey: samanthafyre -character_name: Kateryna Petrovitch -item_path: /obj/item/clothing/suit/armor/vest/wolftaur/kate -} - -{ -ckey: sasoperative -character_name: Joseph Skinner -item_path: /obj/item/clothing/accessory/medal/ERTservice -} - -{ -ckey: sasoperative -character_name: Joseph Skinner -item_path: /obj/item/clothing/under/rank/security/fluff/formalsec -} - -{ -ckey: scree -character_name: Scree -item_path: /obj/item/modkit_conversion/fluff/screekit -} - -{ -ckey: scree -character_name: Scree -item_path: /obj/item/clothing/head/fluff/pompom -} - -{ -ckey: seiga -character_name: Alfonso Oak Telanor -item_path: /obj/item/clothing/glasses/sunglasses/fluff/alfonso -} - -#{ -#ckey: silencedmp5a5 -#character_name: Serdykov Antoz -#item_path: /obj/item/clothing/head/helmet/serdy -#req_access = 1 -#} - -#{ -#ckey: silencedmp5a5 -#character_name: Serdykov Antoz -#item_path: /obj/item/clothing/suit/armor/vest/wolftaur/serdy -#req_access = 1 -#} -# -#{ -#ckey: silencedmp5a5 -#character_name: Serdykov Antoz -#item_path: /obj/item/storage/box/fluff/serdykov_antoz -#req_access = 1 -#} - -{ -ckey: silencedmp5a5 -character_name: NT-HASD #556 -item_path: /obj/item/modkit_conversion/hasd -req_access = 1 -} - -{ -ckey: silvertalismen -character_name: Tasy Ruffles -item_path: /obj/item/clothing/under/sexyclown -} - -{ -ckey: silvertalismen -character_name: Evian -item_path: /obj/item/implanter/reagent_generator/evian -} - -{ -ckey: silvertalismen -character_name: Tasy Ruffles -item_path: /obj/item/clothing/mask/gas/sexyclown -} - -{ -ckey: silvertalismen -character_name: Tasy Ruffles -item_path: /obj/item/pda/clown -} - -{ -ckey: Swat43 -character_name: Fortune Bloise -item_path: /obj/item/storage/backpack/satchel/fluff/swat43bag -} - -{ -ckey: stobarico -character_name: Alexis Bloise -item_path: /obj/item/cane/wand -} - -{ -ckey: SpoopyLizz -character_name: Roiz Lizden -item_path: /obj/item/implanter/reagent_generator/roiz -} - -{ -ckey: SpoopyLizz -character_name: Roiz Lizden -item_path: /obj/item/clothing/suit/storage/hooded/wintercoat/roiz -} - -{ -ckey: suicidalpickles -character_name: Silent Stripes -item_path: /obj/item/clothing/mask/gas/sexymime -} - -{ -ckey: suicidalpickles -character_name: Silent Stripes -item_path: /obj/item/clothing/under/sexymime -} - -# ######## T CKEYS -{ -ckey: tabiranth -character_name: Ascian -item_path: /obj/item/clothing/accessory/medal/silver/unity -} - -{ -ckey: techtypes -character_name: Lasshseeki Korss -item_path: /obj/item/implant/language/eal -} - -{ -ckey: tinydude16 -character_name: Konor Foxe -item_path: /obj/item/clothing/accessory/medal/silver/unity -} - -{ -ckey: tonyvld -character_name: Tony Bingham -item_path: /obj/item/clothing/head/fluff/runac -} - -{ -ckey: tabiranth -character_name: Ascian -item_path: /obj/item/grenade/spawnergrenade/spirit -} - -# ######## U CKEYS -# ######## V CKEYS -{ -ckey: verkister -character_name: Cameron Eggbert -item_path: /obj/item/clothing/glasses/fluff/science_proper -} -{ -ckey: verkister -character_name: Cameron Eggbert -item_path: /obj/item/disk/limb/eggnerdltd -} -{ -ckey: verkister -character_name: Opie Eggbert -item_path: /obj/item/clothing/glasses/fluff/spiffygogs -} -{ -ckey: virgo113 -character_name: Verin Raharra -item_path: /obj/item/clothing/suit/storage/hazardvest/fluff/verin -} -{ -ckey: vorrarkul -character_name: Lucina Dakarim -item_path: /obj/item/pda/heads/cmo/fluff/lucinapda -} - -{ -ckey: vorrarkul -character_name: Lucina Dakarim -item_path: /obj/item/clothing/accessory/medal/gold/fluff/lucina -} - -{ -ckey: vorrarkul -character_name: Lucina Dakarim -item_path: /obj/item/clothing/under/dress/fluff/lucinadress -} - -{ -ckey: vorrarkul -character_name: Nyssa Brennan -item_path: /obj/item/clothing/suit/storage/hooded/wintercoat/cargo -} - -{ -ckey: vorrarkul -character_name: Theodora Lindt -item_path: /obj/item/clothing/suit/chococoat -} - -{ -ckey: vorrarkul -character_name: Theodora Lindt -item_path: /obj/item/implanter/reagent_generator/vorrarkul -} - -{ -ckey: vorrarkul -character_name: Kaitlyn Fiasco -item_path: /obj/item/toy/plushie/mouse/fluff -} - -{ -ckey: Viveret -character_name: Keturah -item_path: /obj/item/clothing/under/dress/maid/ -} - -{ -ckey: Viveret -character_name: Silentio -item_path: /obj/item/clothing/under/sexymime -} - -{ -ckey: Viveret -character_name: Silentio -item_path: /obj/item/clothing/mask/gas/sexymime -} - -# ######## W CKEYS -#{ -#ckey: warbrand2 -#character_name: Brandy draca -#item_path: /obj/item/pda_mod/fluff/warbrand2 -#} - -{ -ckey: werebear -character_name: Silas Newton -item_path: /obj/item/clothing/glasses/threedglasses -} - -{ -ckey: whiskyrose -character_name: Vinjj -item_path: /obj/item/clothing/head/welding/fluff/vinjj -} - -{ -ckey: wickedtemp -character_name: Chakat Tempest Venesare -item_path: /obj/item/clothing/glasses/omnihud/med/fluff/wickedtemphud -} - -{ -ckey: wickedtemp -character_name: Chakat Tempest Venesare -item_path: /obj/item/reagent_containers/hypospray/vial/tempest -} - -{ -ckey: wickedtemp -character_name: Chakat Tempest Venesare -item_path: /obj/item/storage/backpack/saddlebag/tempest -} - -{ -ckey: wickedtemp -character_name: Chakat Tempest Venesare -item_path: /obj/item/implanter/reagent_generator/tempest -} - -# ######## X CKEYS - -{ -ckey: Xsdew -character_name: Penelope Allen -item_path: /obj/item/storage/box/fluff/penelope -} - -{ -ckey: Xennith -character_name: Amy Lessen -item_path: /obj/item/card/id/fluff/xennith -} - -{ -ckey: Xonkon -character_name: Ali -item_path: /obj/item/clothing/accessory/medal/silver/unity -} - -# ######## Y CKEYS -# ######## Z CKEYS -{ -ckey: zekesturm -character_name: Sarah Arachi Lacecraft -item_path: /obj/item/modkit_single/fluff/zekechimera -} - -{ -ckey: zekesturm -character_name: Zeke Arachi -item_path: /obj/item/clothing/head/fluff/xeno -} - -{ -ckey: zigfe -character_name: Zaoozaoo Xrimxuqmqixzix -item_path: /obj/item/clothing/head/fluff/zao -} - -{ -ckey: zodiacshadow -character_name: Nehi Maximus -item_path: /obj/item/radio/headset/fluff/zodiacshadow -} diff --git a/config/custom_sprites.txt b/config/custom_sprites.txt deleted file mode 100644 index db3930a4ae2..00000000000 --- a/config/custom_sprites.txt +++ /dev/null @@ -1 +0,0 @@ -ckey-state \ No newline at end of file diff --git a/icons/README.md b/icons/README.md index 3fc1aaa596a..d7f2b12d948 100644 --- a/icons/README.md +++ b/icons/README.md @@ -33,6 +33,8 @@ Yes, this currently includes all turfs, mobs, objs, and misc things. Sorry. We'l - /mob - mob sprites - /bodysets - limbs and their corrosponding sprite accessories & markings & miscellaneous. used in the abstraction of limb sprite from limb definition. + - /robot - `/mob/living/silicon/robot` stuff + - /iconset - iconsets for silicon / robot mobs - /sprite_accessories - unconverted sprite accessories - /sprite_accessory - modern sprite accessory system - /modules - used for specific departments / content packs / logical bundles diff --git a/icons/obj/module.dmi b/icons/items/circuits.dmi similarity index 100% rename from icons/obj/module.dmi rename to icons/items/circuits.dmi diff --git a/icons/mob/custom_synthetic.dmi b/icons/mob/custom_synthetic.dmi deleted file mode 100644 index 7854fabe2bf..00000000000 Binary files a/icons/mob/custom_synthetic.dmi and /dev/null differ diff --git a/icons/mob/robot-alina-unused.dmi b/icons/mob/robot-alina-unused.dmi new file mode 100644 index 00000000000..4d5284ead45 Binary files /dev/null and b/icons/mob/robot-alina-unused.dmi differ diff --git a/icons/mob/robot-legacy.dmi b/icons/mob/robot-legacy.dmi new file mode 100644 index 00000000000..f654b9a963e Binary files /dev/null and b/icons/mob/robot-legacy.dmi differ diff --git a/icons/mob/robot-thinktank-unused.dmi b/icons/mob/robot-thinktank-unused.dmi new file mode 100644 index 00000000000..471647bf603 Binary files /dev/null and b/icons/mob/robot-thinktank-unused.dmi differ diff --git a/icons/mob/robot-unused.dmi b/icons/mob/robot-unused.dmi new file mode 100644 index 00000000000..68c537f078a Binary files /dev/null and b/icons/mob/robot-unused.dmi differ diff --git a/icons/mob/robot/iconset/baseline_droid.dmi b/icons/mob/robot/iconset/baseline_droid.dmi new file mode 100644 index 00000000000..4eb04174435 Binary files /dev/null and b/icons/mob/robot/iconset/baseline_droid.dmi differ diff --git a/icons/mob/robot/iconset/baseline_drone.dmi b/icons/mob/robot/iconset/baseline_drone.dmi new file mode 100644 index 00000000000..d5e6b4cf9a7 Binary files /dev/null and b/icons/mob/robot/iconset/baseline_drone.dmi differ diff --git a/icons/mob/robot/iconset/baseline_misc.dmi b/icons/mob/robot/iconset/baseline_misc.dmi new file mode 100644 index 00000000000..dc671458b90 Binary files /dev/null and b/icons/mob/robot/iconset/baseline_misc.dmi differ diff --git a/icons/mob/robot/iconset/baseline_old.dmi b/icons/mob/robot/iconset/baseline_old.dmi new file mode 100644 index 00000000000..1649b71f33c Binary files /dev/null and b/icons/mob/robot/iconset/baseline_old.dmi differ diff --git a/icons/mob/robot/iconset/baseline_standard.dmi b/icons/mob/robot/iconset/baseline_standard.dmi new file mode 100644 index 00000000000..5184d045e76 Binary files /dev/null and b/icons/mob/robot/iconset/baseline_standard.dmi differ diff --git a/icons/mob/robot/iconset/baseline_toiletbot.dmi b/icons/mob/robot/iconset/baseline_toiletbot.dmi new file mode 100644 index 00000000000..dd9560042c0 Binary files /dev/null and b/icons/mob/robot/iconset/baseline_toiletbot.dmi differ diff --git a/icons/mob/robot/iconset/biped_droid.dmi b/icons/mob/robot/iconset/biped_droid.dmi new file mode 100644 index 00000000000..dbee4e2d41b Binary files /dev/null and b/icons/mob/robot/iconset/biped_droid.dmi differ diff --git a/icons/mob/robot/iconset/biped_heavy.dmi b/icons/mob/robot/iconset/biped_heavy.dmi new file mode 100644 index 00000000000..3c48c91201a Binary files /dev/null and b/icons/mob/robot/iconset/biped_heavy.dmi differ diff --git a/icons/mob/robot/iconset/biped_insekt.dmi b/icons/mob/robot/iconset/biped_insekt.dmi new file mode 100644 index 00000000000..de8c28dbd29 Binary files /dev/null and b/icons/mob/robot/iconset/biped_insekt.dmi differ diff --git a/icons/mob/robot/iconset/biped_k4t.dmi b/icons/mob/robot/iconset/biped_k4t.dmi new file mode 100644 index 00000000000..a23d3df8160 Binary files /dev/null and b/icons/mob/robot/iconset/biped_k4t.dmi differ diff --git a/icons/mob/robot/iconset/biped_maid.dmi b/icons/mob/robot/iconset/biped_maid.dmi new file mode 100644 index 00000000000..6ea73cf4b0a Binary files /dev/null and b/icons/mob/robot/iconset/biped_maid.dmi differ diff --git a/icons/mob/robot/iconset/biped_marina.dmi b/icons/mob/robot/iconset/biped_marina.dmi new file mode 100644 index 00000000000..0bb0c135229 Binary files /dev/null and b/icons/mob/robot/iconset/biped_marina.dmi differ diff --git a/icons/mob/robot/iconset/biped_meka.dmi b/icons/mob/robot/iconset/biped_meka.dmi new file mode 100644 index 00000000000..606ce19bc65 Binary files /dev/null and b/icons/mob/robot/iconset/biped_meka.dmi differ diff --git a/icons/mob/robot/iconset/biped_miss.dmi b/icons/mob/robot/iconset/biped_miss.dmi new file mode 100644 index 00000000000..b1f9c0fa8f7 Binary files /dev/null and b/icons/mob/robot/iconset/biped_miss.dmi differ diff --git a/icons/mob/robot/iconset/biped_noble.dmi b/icons/mob/robot/iconset/biped_noble.dmi new file mode 100644 index 00000000000..cbbe0ec305c Binary files /dev/null and b/icons/mob/robot/iconset/biped_noble.dmi differ diff --git a/icons/mob/robot/iconset/biped_sleek.dmi b/icons/mob/robot/iconset/biped_sleek.dmi new file mode 100644 index 00000000000..8d0d39c6bba Binary files /dev/null and b/icons/mob/robot/iconset/biped_sleek.dmi differ diff --git a/icons/mob/robot/iconset/biped_tall.dmi b/icons/mob/robot/iconset/biped_tall.dmi new file mode 100644 index 00000000000..e8820e32c25 Binary files /dev/null and b/icons/mob/robot/iconset/biped_tall.dmi differ diff --git a/icons/mob/robot/iconset/cat_feli.dmi b/icons/mob/robot/iconset/cat_feli.dmi new file mode 100644 index 00000000000..7c86b2ad138 Binary files /dev/null and b/icons/mob/robot/iconset/cat_feli.dmi differ diff --git a/icons/mob/robot/iconset/dog_borgi-unused.dmi b/icons/mob/robot/iconset/dog_borgi-unused.dmi new file mode 100644 index 00000000000..908be642b2a Binary files /dev/null and b/icons/mob/robot/iconset/dog_borgi-unused.dmi differ diff --git a/icons/mob/robot/iconset/dog_borgi.dmi b/icons/mob/robot/iconset/dog_borgi.dmi new file mode 100644 index 00000000000..7a7f26bb0e6 Binary files /dev/null and b/icons/mob/robot/iconset/dog_borgi.dmi differ diff --git a/icons/mob/robot/iconset/dog_k9-unused.dmi b/icons/mob/robot/iconset/dog_k9-unused.dmi new file mode 100644 index 00000000000..284cc330ed0 Binary files /dev/null and b/icons/mob/robot/iconset/dog_k9-unused.dmi differ diff --git a/icons/mob/robot/iconset/dog_k9.dmi b/icons/mob/robot/iconset/dog_k9.dmi new file mode 100644 index 00000000000..53e3cf9b545 Binary files /dev/null and b/icons/mob/robot/iconset/dog_k9.dmi differ diff --git a/icons/mob/robot/iconset/dog_otie-unused.dmi b/icons/mob/robot/iconset/dog_otie-unused.dmi new file mode 100644 index 00000000000..c73e1261ded Binary files /dev/null and b/icons/mob/robot/iconset/dog_otie-unused.dmi differ diff --git a/icons/mob/robot/iconset/dog_otie.dmi b/icons/mob/robot/iconset/dog_otie.dmi new file mode 100644 index 00000000000..fcd69a96820 Binary files /dev/null and b/icons/mob/robot/iconset/dog_otie.dmi differ diff --git a/icons/mob/robot/iconset/dog_pupdozer-unused.dmi b/icons/mob/robot/iconset/dog_pupdozer-unused.dmi new file mode 100644 index 00000000000..e4f1ed8dca4 Binary files /dev/null and b/icons/mob/robot/iconset/dog_pupdozer-unused.dmi differ diff --git a/icons/mob/robot/iconset/dog_pupdozer.dmi b/icons/mob/robot/iconset/dog_pupdozer.dmi new file mode 100644 index 00000000000..8115c12c6f2 Binary files /dev/null and b/icons/mob/robot/iconset/dog_pupdozer.dmi differ diff --git a/icons/mob/robot/iconset/dog_vale-unused.dmi b/icons/mob/robot/iconset/dog_vale-unused.dmi new file mode 100644 index 00000000000..691b005e2cb Binary files /dev/null and b/icons/mob/robot/iconset/dog_vale-unused.dmi differ diff --git a/icons/mob/robot/iconset/dog_vale.dmi b/icons/mob/robot/iconset/dog_vale.dmi new file mode 100644 index 00000000000..e274ef531af Binary files /dev/null and b/icons/mob/robot/iconset/dog_vale.dmi differ diff --git a/icons/mob/robot/iconset/drake_mizartz-originals.dmi b/icons/mob/robot/iconset/drake_mizartz-originals.dmi new file mode 100644 index 00000000000..e5188835272 Binary files /dev/null and b/icons/mob/robot/iconset/drake_mizartz-originals.dmi differ diff --git a/icons/mob/robot/iconset/drake_mizartz-unused.dmi b/icons/mob/robot/iconset/drake_mizartz-unused.dmi new file mode 100644 index 00000000000..7666ec58c06 Binary files /dev/null and b/icons/mob/robot/iconset/drake_mizartz-unused.dmi differ diff --git a/icons/mob/robot/iconset/drake_mizartz.dmi b/icons/mob/robot/iconset/drake_mizartz.dmi new file mode 100644 index 00000000000..a24c7fc5f5f Binary files /dev/null and b/icons/mob/robot/iconset/drake_mizartz.dmi differ diff --git a/icons/mob/robot/iconset/grounded_decapod.dmi b/icons/mob/robot/iconset/grounded_decapod.dmi new file mode 100644 index 00000000000..110192fb737 Binary files /dev/null and b/icons/mob/robot/iconset/grounded_decapod.dmi differ diff --git a/icons/mob/robot/iconset/grounded_landmate.dmi b/icons/mob/robot/iconset/grounded_landmate.dmi new file mode 100644 index 00000000000..dfd5ec7095b Binary files /dev/null and b/icons/mob/robot/iconset/grounded_landmate.dmi differ diff --git a/icons/mob/robot/iconset/grounded_mechoid.dmi b/icons/mob/robot/iconset/grounded_mechoid.dmi new file mode 100644 index 00000000000..720260a863f Binary files /dev/null and b/icons/mob/robot/iconset/grounded_mechoid.dmi differ diff --git a/icons/mob/robot/iconset/grounded_spider.dmi b/icons/mob/robot/iconset/grounded_spider.dmi new file mode 100644 index 00000000000..d94591eaaf4 Binary files /dev/null and b/icons/mob/robot/iconset/grounded_spider.dmi differ diff --git a/icons/mob/robot/iconset/grounded_worm.dmi b/icons/mob/robot/iconset/grounded_worm.dmi new file mode 100644 index 00000000000..d8a5a476ba8 Binary files /dev/null and b/icons/mob/robot/iconset/grounded_worm.dmi differ diff --git a/icons/mob/robot/iconset/grounded_zoomba.dmi b/icons/mob/robot/iconset/grounded_zoomba.dmi new file mode 100644 index 00000000000..14f4d1a9bce Binary files /dev/null and b/icons/mob/robot/iconset/grounded_zoomba.dmi differ diff --git a/icons/mob/robot/iconset/hover_coffin.dmi b/icons/mob/robot/iconset/hover_coffin.dmi new file mode 100644 index 00000000000..f60496370c5 Binary files /dev/null and b/icons/mob/robot/iconset/hover_coffin.dmi differ diff --git a/icons/mob/robot/iconset/hover_drone.dmi b/icons/mob/robot/iconset/hover_drone.dmi new file mode 100644 index 00000000000..f6252e1fe87 Binary files /dev/null and b/icons/mob/robot/iconset/hover_drone.dmi differ diff --git a/icons/mob/robot/iconset/hover_eyebot.dmi b/icons/mob/robot/iconset/hover_eyebot.dmi new file mode 100644 index 00000000000..a433a84e648 Binary files /dev/null and b/icons/mob/robot/iconset/hover_eyebot.dmi differ diff --git a/icons/mob/robot/iconset/hover_glitterfly.dmi b/icons/mob/robot/iconset/hover_glitterfly.dmi new file mode 100644 index 00000000000..5b9c9c8bb98 Binary files /dev/null and b/icons/mob/robot/iconset/hover_glitterfly.dmi differ diff --git a/icons/mob/robot/iconset/hover_handy.dmi b/icons/mob/robot/iconset/hover_handy.dmi new file mode 100644 index 00000000000..da9ace9f82e Binary files /dev/null and b/icons/mob/robot/iconset/hover_handy.dmi differ diff --git a/icons/mob/robot/iconset/hover_x88.dmi b/icons/mob/robot/iconset/hover_x88.dmi new file mode 100644 index 00000000000..e56da219d9b Binary files /dev/null and b/icons/mob/robot/iconset/hover_x88.dmi differ diff --git a/icons/mob/robot/iconset/raptor-unused.dmi b/icons/mob/robot/iconset/raptor-unused.dmi new file mode 100644 index 00000000000..85bd9a40e14 Binary files /dev/null and b/icons/mob/robot/iconset/raptor-unused.dmi differ diff --git a/icons/mob/robot/iconset/raptor.dmi b/icons/mob/robot/iconset/raptor.dmi new file mode 100644 index 00000000000..8ab745199ea Binary files /dev/null and b/icons/mob/robot/iconset/raptor.dmi differ diff --git a/icons/mob/robot/iconset/unused.dmi b/icons/mob/robot/iconset/unused.dmi new file mode 100644 index 00000000000..243c016307d Binary files /dev/null and b/icons/mob/robot/iconset/unused.dmi differ diff --git a/icons/mob/robots.dmi b/icons/mob/robots.dmi deleted file mode 100644 index 64a01aef435..00000000000 Binary files a/icons/mob/robots.dmi and /dev/null differ diff --git a/icons/mob/robots_wide.dmi b/icons/mob/robots_wide.dmi deleted file mode 100644 index 1fd9380cd2a..00000000000 Binary files a/icons/mob/robots_wide.dmi and /dev/null differ diff --git a/icons/mob/robots_wide_drake_credit.dmi b/icons/mob/robots_wide_drake_credit.dmi deleted file mode 100644 index fa184ffafe6..00000000000 Binary files a/icons/mob/robots_wide_drake_credit.dmi and /dev/null differ diff --git a/icons/mob/screen1_robot.dmi b/icons/mob/screen1_robot.dmi index 8d31a894af1..a5a33ae5b7b 100644 Binary files a/icons/mob/screen1_robot.dmi and b/icons/mob/screen1_robot.dmi differ diff --git a/icons/mob/screen1_robot_minimalist.dmi b/icons/mob/screen1_robot_minimalist.dmi index c05e304763b..95a456de545 100644 Binary files a/icons/mob/screen1_robot_minimalist.dmi and b/icons/mob/screen1_robot_minimalist.dmi differ diff --git a/icons/screen/actions/generic.dmi b/icons/screen/actions/generic.dmi index 9ef8dd41f5e..7e16ef7c1b5 100644 Binary files a/icons/screen/actions/generic.dmi and b/icons/screen/actions/generic.dmi differ diff --git a/icons/screen/hud/hologram/inventory.dmi b/icons/screen/hud/hologram/inventory.dmi deleted file mode 100644 index c7e63170ebf..00000000000 Binary files a/icons/screen/hud/hologram/inventory.dmi and /dev/null differ diff --git a/icons/screen/hud/midnight/inventory.dmi b/icons/screen/hud/midnight/inventory.dmi deleted file mode 100644 index abef9e084a5..00000000000 Binary files a/icons/screen/hud/midnight/inventory.dmi and /dev/null differ diff --git a/icons/screen/hud/minimalist/inventory.dmi b/icons/screen/hud/minimalist/inventory.dmi deleted file mode 100644 index 3ab625d5f72..00000000000 Binary files a/icons/screen/hud/minimalist/inventory.dmi and /dev/null differ diff --git a/icons/screen/hud/old/inventory.dmi b/icons/screen/hud/old/inventory.dmi deleted file mode 100644 index 74d04a8afa6..00000000000 Binary files a/icons/screen/hud/old/inventory.dmi and /dev/null differ diff --git a/icons/screen/hud/orange/inventory.dmi b/icons/screen/hud/orange/inventory.dmi deleted file mode 100644 index a4f9751e0cd..00000000000 Binary files a/icons/screen/hud/orange/inventory.dmi and /dev/null differ diff --git a/icons/screen/hud/robot/default.dmi b/icons/screen/hud/robot/default.dmi new file mode 100644 index 00000000000..416ea865375 Binary files /dev/null and b/icons/screen/hud/robot/default.dmi differ diff --git a/icons/screen/hud/robot/minimalist.dmi b/icons/screen/hud/robot/minimalist.dmi new file mode 100644 index 00000000000..8beb8ec787a Binary files /dev/null and b/icons/screen/hud/robot/minimalist.dmi differ diff --git a/icons/screen/hud/robot/modules.dmi b/icons/screen/hud/robot/modules.dmi new file mode 100644 index 00000000000..a3763981129 Binary files /dev/null and b/icons/screen/hud/robot/modules.dmi differ diff --git a/icons/screen/hud/common/observer.dmi b/icons/screen/hud/styles/common/observer.dmi similarity index 100% rename from icons/screen/hud/common/observer.dmi rename to icons/screen/hud/styles/common/observer.dmi diff --git a/icons/screen/hud/common/shadekin.dmi b/icons/screen/hud/styles/common/shadekin.dmi similarity index 100% rename from icons/screen/hud/common/shadekin.dmi rename to icons/screen/hud/styles/common/shadekin.dmi diff --git a/icons/screen/hud/common/storage.dmi b/icons/screen/hud/styles/common/storage.dmi similarity index 100% rename from icons/screen/hud/common/storage.dmi rename to icons/screen/hud/styles/common/storage.dmi diff --git a/icons/screen/hud/hologram/32x32.dmi b/icons/screen/hud/styles/hologram/32x32.dmi similarity index 100% rename from icons/screen/hud/hologram/32x32.dmi rename to icons/screen/hud/styles/hologram/32x32.dmi diff --git a/icons/screen/hud/hologram/inventory-slot.dmi b/icons/screen/hud/styles/hologram/inventory-slot.dmi similarity index 100% rename from icons/screen/hud/hologram/inventory-slot.dmi rename to icons/screen/hud/styles/hologram/inventory-slot.dmi diff --git a/icons/screen/hud/hologram/inventory-wide.dmi b/icons/screen/hud/styles/hologram/inventory-wide.dmi similarity index 100% rename from icons/screen/hud/hologram/inventory-wide.dmi rename to icons/screen/hud/styles/hologram/inventory-wide.dmi diff --git a/icons/screen/hud/styles/hologram/inventory.dmi b/icons/screen/hud/styles/hologram/inventory.dmi new file mode 100644 index 00000000000..a3490c85f6a Binary files /dev/null and b/icons/screen/hud/styles/hologram/inventory.dmi differ diff --git a/icons/screen/hud/midnight/32x32.dmi b/icons/screen/hud/styles/midnight/32x32.dmi similarity index 100% rename from icons/screen/hud/midnight/32x32.dmi rename to icons/screen/hud/styles/midnight/32x32.dmi diff --git a/icons/screen/hud/styles/midnight/inventory-robot.dmi b/icons/screen/hud/styles/midnight/inventory-robot.dmi new file mode 100644 index 00000000000..cf74d73796c Binary files /dev/null and b/icons/screen/hud/styles/midnight/inventory-robot.dmi differ diff --git a/icons/screen/hud/midnight/inventory-slot.dmi b/icons/screen/hud/styles/midnight/inventory-slot.dmi similarity index 100% rename from icons/screen/hud/midnight/inventory-slot.dmi rename to icons/screen/hud/styles/midnight/inventory-slot.dmi diff --git a/icons/screen/hud/midnight/inventory-wide.dmi b/icons/screen/hud/styles/midnight/inventory-wide.dmi similarity index 100% rename from icons/screen/hud/midnight/inventory-wide.dmi rename to icons/screen/hud/styles/midnight/inventory-wide.dmi diff --git a/icons/screen/hud/styles/midnight/inventory.dmi b/icons/screen/hud/styles/midnight/inventory.dmi new file mode 100644 index 00000000000..cabae87f6e5 Binary files /dev/null and b/icons/screen/hud/styles/midnight/inventory.dmi differ diff --git a/icons/screen/hud/minimalist/32x32.dmi b/icons/screen/hud/styles/minimalist/32x32.dmi similarity index 100% rename from icons/screen/hud/minimalist/32x32.dmi rename to icons/screen/hud/styles/minimalist/32x32.dmi diff --git a/icons/screen/hud/minimalist/inventory-slot.dmi b/icons/screen/hud/styles/minimalist/inventory-slot.dmi similarity index 100% rename from icons/screen/hud/minimalist/inventory-slot.dmi rename to icons/screen/hud/styles/minimalist/inventory-slot.dmi diff --git a/icons/screen/hud/minimalist/inventory-wide.dmi b/icons/screen/hud/styles/minimalist/inventory-wide.dmi similarity index 100% rename from icons/screen/hud/minimalist/inventory-wide.dmi rename to icons/screen/hud/styles/minimalist/inventory-wide.dmi diff --git a/icons/screen/hud/styles/minimalist/inventory.dmi b/icons/screen/hud/styles/minimalist/inventory.dmi new file mode 100644 index 00000000000..14d548b6144 Binary files /dev/null and b/icons/screen/hud/styles/minimalist/inventory.dmi differ diff --git a/icons/screen/hud/old/32x32.dmi b/icons/screen/hud/styles/old/32x32.dmi similarity index 100% rename from icons/screen/hud/old/32x32.dmi rename to icons/screen/hud/styles/old/32x32.dmi diff --git a/icons/screen/hud/old/inventory-slot.dmi b/icons/screen/hud/styles/old/inventory-slot.dmi similarity index 100% rename from icons/screen/hud/old/inventory-slot.dmi rename to icons/screen/hud/styles/old/inventory-slot.dmi diff --git a/icons/screen/hud/old/inventory-wide.dmi b/icons/screen/hud/styles/old/inventory-wide.dmi similarity index 100% rename from icons/screen/hud/old/inventory-wide.dmi rename to icons/screen/hud/styles/old/inventory-wide.dmi diff --git a/icons/screen/hud/styles/old/inventory.dmi b/icons/screen/hud/styles/old/inventory.dmi new file mode 100644 index 00000000000..e787cb283d6 Binary files /dev/null and b/icons/screen/hud/styles/old/inventory.dmi differ diff --git a/icons/screen/hud/orange/32x32.dmi b/icons/screen/hud/styles/orange/32x32.dmi similarity index 100% rename from icons/screen/hud/orange/32x32.dmi rename to icons/screen/hud/styles/orange/32x32.dmi diff --git a/icons/screen/hud/orange/inventory-slot.dmi b/icons/screen/hud/styles/orange/inventory-slot.dmi similarity index 100% rename from icons/screen/hud/orange/inventory-slot.dmi rename to icons/screen/hud/styles/orange/inventory-slot.dmi diff --git a/icons/screen/hud/orange/inventory-wide.dmi b/icons/screen/hud/styles/orange/inventory-wide.dmi similarity index 100% rename from icons/screen/hud/orange/inventory-wide.dmi rename to icons/screen/hud/styles/orange/inventory-wide.dmi diff --git a/icons/screen/hud/styles/orange/inventory.dmi b/icons/screen/hud/styles/orange/inventory.dmi new file mode 100644 index 00000000000..0346fc35d61 Binary files /dev/null and b/icons/screen/hud/styles/orange/inventory.dmi differ diff --git a/icons/screen/hud/white/32x32.dmi b/icons/screen/hud/styles/white/32x32.dmi similarity index 100% rename from icons/screen/hud/white/32x32.dmi rename to icons/screen/hud/styles/white/32x32.dmi diff --git a/icons/screen/hud/white/inventory-slot.dmi b/icons/screen/hud/styles/white/inventory-slot.dmi similarity index 100% rename from icons/screen/hud/white/inventory-slot.dmi rename to icons/screen/hud/styles/white/inventory-slot.dmi diff --git a/icons/screen/hud/white/inventory-wide.dmi b/icons/screen/hud/styles/white/inventory-wide.dmi similarity index 100% rename from icons/screen/hud/white/inventory-wide.dmi rename to icons/screen/hud/styles/white/inventory-wide.dmi diff --git a/icons/screen/hud/styles/white/inventory.dmi b/icons/screen/hud/styles/white/inventory.dmi new file mode 100644 index 00000000000..16e04291ef9 Binary files /dev/null and b/icons/screen/hud/styles/white/inventory.dmi differ diff --git a/icons/screen/hud/white/inventory.dmi b/icons/screen/hud/white/inventory.dmi deleted file mode 100644 index 0bfcec29919..00000000000 Binary files a/icons/screen/hud/white/inventory.dmi and /dev/null differ diff --git a/maps/away_missions/archive/zresearchlabs.dmm b/maps/away_missions/archive/zresearchlabs.dmm index 7810deea9b9..6d8aae62f33 100644 --- a/maps/away_missions/archive/zresearchlabs.dmm +++ b/maps/away_missions/archive/zresearchlabs.dmm @@ -3296,7 +3296,7 @@ /area/awaymission/labs/researchdivision) "jH" = ( /obj/structure/table/reinforced, -/obj/item/borg/upgrade/vtec, +/obj/item/robot_upgrade/vtec, /obj/item/cell/basic/tier_1/medium/empty, /turf/simulated/floor{ icon_state = "white" diff --git a/maps/stations/strelka/strelka-misc.dm b/maps/stations/strelka/strelka-misc.dm index 5c4d7ab5e14..4e39b4fb27f 100644 --- a/maps/stations/strelka/strelka-misc.dm +++ b/maps/stations/strelka/strelka-misc.dm @@ -58,7 +58,7 @@ desc = "A small, normal-looking drone. It pilots the Cargo Supply shuttle... Yep, no MK2 pilot here..." catalogue_data = list(/datum/category_item/catalogue/technology/drone/corrupt_maint_drone) - icon = 'icons/mob/robots.dmi' + icon = 'icons/mob/robot-legacy.dmi' icon_state = "corrupt-repairbot" icon_living = "corrupt-repairbot" hovering = FALSE // Can trigger landmines. diff --git a/tgui/packages/tgui/components/ByondIconRef.tsx b/tgui/packages/tgui/components/ByondIconRef.tsx index 5c98c116e50..d38895c7cd6 100644 --- a/tgui/packages/tgui/components/ByondIconRef.tsx +++ b/tgui/packages/tgui/components/ByondIconRef.tsx @@ -1,19 +1,9 @@ import { ReactNode } from "react"; import { Image } from "tgui-core/components"; +import { Direction } from "../constants"; import { BoxProps } from "."; -enum Direction { - NORTH = 1, - SOUTH = 2, - EAST = 4, - WEST = 8, - NORTHEAST = NORTH | EAST, - NORTHWEST = NORTH | WEST, - SOUTHEAST = SOUTH | EAST, - SOUTHWEST = SOUTH | WEST, -} - type Props = { /** Required: The \ref of the icon */ iconRef: string; diff --git a/tgui/packages/tgui/components/Centered.tsx b/tgui/packages/tgui/components/Centered.tsx new file mode 100644 index 00000000000..75ef46903d6 --- /dev/null +++ b/tgui/packages/tgui/components/Centered.tsx @@ -0,0 +1,28 @@ +/** + * @file + * @license MIT + */ + +import { Box } from 'tgui-core/components'; + +import { BoxProps } from '.'; + +/** + * I don't know who the fuck said "take 30 minutes to center a box in CSS" + * but they're fucking right and I'm not doing this ever fucking again + */ +export const Centered = (props: BoxProps) => { + return ( + + {props.children} + + ); +}; diff --git a/tgui/packages/tgui/components/Sprite.tsx b/tgui/packages/tgui/components/Sprite.tsx index 011761285a0..3059dd01428 100644 --- a/tgui/packages/tgui/components/Sprite.tsx +++ b/tgui/packages/tgui/components/Sprite.tsx @@ -4,7 +4,7 @@ */ import { Box } from "tgui-core/components"; -import { BooleanLike, classes } from "tgui-core/react"; +import { classes } from "tgui-core/react"; import { BoxProps } from "."; @@ -13,7 +13,6 @@ interface SpriteProps extends BoxProps { readonly sizeKey: string; readonly prefix?: string; readonly sprite: string; - readonly fill?: BooleanLike; } export const Sprite = (props: SpriteProps) => { @@ -23,7 +22,6 @@ export const Sprite = (props: SpriteProps) => { "Sprite", `${props.sheet}${props.sizeKey}`, props.prefix ? `${props.prefix}-${props.sprite}` : props.sprite, - !!props.fill && 'Sprite--fill', ])} /> ); }; diff --git a/tgui/packages/tgui/interfaces/ColorMate.tsx b/tgui/packages/tgui/interfaces/ColorMate.tsx index 79e56aa569c..3806c272bb1 100644 --- a/tgui/packages/tgui/interfaces/ColorMate.tsx +++ b/tgui/packages/tgui/interfaces/ColorMate.tsx @@ -32,7 +32,7 @@ export const ColorMate = (props) => { width="100%" height="100%" style={{ - imageRendering: "crisp-edges", + imageRendering: "pixelated", }} /> @@ -45,7 +45,7 @@ export const ColorMate = (props) => { width="100%" height="100%" style={{ - imageRendering: "crisp-edges", + imageRendering: "pixelated", }} /> diff --git a/tgui/packages/tgui/interfaces/actor_modal/RobotModulePicker.tsx b/tgui/packages/tgui/interfaces/actor_modal/RobotModulePicker.tsx new file mode 100644 index 00000000000..fdd360de0eb --- /dev/null +++ b/tgui/packages/tgui/interfaces/actor_modal/RobotModulePicker.tsx @@ -0,0 +1,176 @@ +/** + * @file + * @license MIT + */ + +import { useState } from 'react'; +import { Button, Section, Stack, Tabs } from 'tgui-core/components'; + +import { useBackend } from '../../backend'; +import { ByondIconRef } from '../../components/ByondIconRef'; +import { Centered } from '../../components/Centered'; +import { Direction } from '../../constants'; +import { Window } from '../../layouts'; + +export const ROBOT_MODULE_SPRITESHEET_NAME = 'roboticonsets'; + +interface RobotModulePickerData { + modules: Record; +} + +interface PickableModule { + id: string; + name: string; + frames: Record; +} + +interface PickableFrame { + ref: string; + name: string; + spriteSizeKey: string; + spriteId: string; + iconRef: string; + iconState: string; +} + +export const RobotModulePicker = (props) => { + const { act, data } = useBackend(); + const [selectedModuleId, setSelectedModuleId] = useState(null); + const [selectedFrameRef, setSelectedFrameRef] = useState(null); + + let selectedFrame: PickableFrame | null = + (selectedModuleId && + selectedFrameRef && + data.modules?.[selectedModuleId]?.frames?.[selectedFrameRef]) || + null; + + return ( + + + + +
+ + {Object.entries(data.modules) + .sort(([a1, a2], [b1, b2]) => a2.name.localeCompare(b2.name)) + .map(([id, module]) => { + return ( + setSelectedModuleId(id)} + selected={id === selectedModuleId} + > + {module.name} + + ); + })} + +
+
+ +
+ + {selectedModuleId && + !!data.modules[selectedModuleId] && + Object.entries(data.modules[selectedModuleId].frames) + .sort(([a1, a2], [b1, b2]) => + a2.name.localeCompare(b2.name), + ) + .map(([id, frame]) => { + return ( + setSelectedFrameRef(id)} + selected={id === selectedFrameRef} + > + {frame.name} + + ); + })} + +
+
+ +
+ + + {selectedFrame && ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + )} + + + + act('pick', { + moduleId: selectedModuleId, + frameRef: selectedFrameRef, + }) + } + textAlign="center" + > + Specialize + + + +
+
+
+
+
+ ); +};