From 4e981006975ad71f8bcd4cdcae05bae5cc7edceb Mon Sep 17 00:00:00 2001 From: Rob Nelson Date: Wed, 7 Aug 2013 17:31:38 -0700 Subject: [PATCH] MoMMI merged from failstation code. --- .gitignore | 1 + baystation12.dme | 260 +----- code/datums/mind.dm | 41 +- code/game/atoms.dm | 25 + code/game/gamemodes/changeling/changeling.dm | 2 +- code/game/gamemodes/cult/cult.dm | 2 +- code/game/gamemodes/meme/meme.dm | 2 +- code/game/gamemodes/objective.dm | 2 +- code/game/gamemodes/revolution/revolution.dm | 2 +- code/game/gamemodes/traitor/traitor.dm | 2 +- code/game/hud.dm | 6 +- code/game/jobs/job/silicon.dm | 15 +- code/game/jobs/job_controller.dm | 7 +- code/game/jobs/jobs.dm | 4 +- code/game/objects/items.dm | 14 + code/game/objects/items/weapons/AI_modules.dm | 47 + code/game/objects/items/weapons/RPD.dm | 244 ++++++ code/modules/admin/admin.dm | 1 + code/modules/admin/topic.dm | 10 + code/modules/admin/verbs/debug.dm | 15 + code/modules/events/ion_storm.dm | 1 + code/modules/mob/living/carbon/brain/MMI.dm | 86 +- code/modules/mob/living/carbon/carbon.dm | 12 +- code/modules/mob/living/say.dm | 4 + .../modules/mob/living/silicon/mommi/death.dm | 69 ++ .../modules/mob/living/silicon/mommi/emote.dm | 213 +++++ .../mob/living/silicon/mommi/examine.dm | 37 + code/modules/mob/living/silicon/mommi/hud.dm | 142 +++ .../mob/living/silicon/mommi/inventory.dm | 132 +++ code/modules/mob/living/silicon/mommi/laws.dm | 1 + code/modules/mob/living/silicon/mommi/life.dm | 303 +++++++ .../modules/mob/living/silicon/mommi/login.dm | 10 + .../modules/mob/living/silicon/mommi/mommi.dm | 822 ++++++++++++++++++ .../mob/living/silicon/mommi/mommi_modules.dm | 52 ++ .../living/silicon/mommi/mommi_movement.dm | 17 + .../mob/living/silicon/mommi/powers.dm | 32 + code/modules/mob/living/silicon/mommi/say.dm | 26 + .../modules/mob/living/silicon/mommi/wires.dm | 150 ++++ code/modules/mob/living/silicon/say.dm | 5 + code/modules/mob/mob_helpers.dm | 5 + code/modules/mob/mob_movement.dm | 2 + code/modules/mob/screen.dm | 22 + code/modules/mob/transform_procs.dm | 48 + code/modules/power/apc.dm | 17 +- code/modules/projectiles/projectile/change.dm | 9 + code/modules/recycling/disposal.dm | 4 +- code/setup.dm | 2 + icons/mob/robots.dmi | Bin 110383 -> 111009 bytes icons/mob/screen1_robot.dmi | Bin 30294 -> 28899 bytes 49 files changed, 2648 insertions(+), 277 deletions(-) create mode 100644 code/game/objects/items/weapons/RPD.dm create mode 100644 code/modules/mob/living/silicon/mommi/death.dm create mode 100644 code/modules/mob/living/silicon/mommi/emote.dm create mode 100644 code/modules/mob/living/silicon/mommi/examine.dm create mode 100644 code/modules/mob/living/silicon/mommi/hud.dm create mode 100644 code/modules/mob/living/silicon/mommi/inventory.dm create mode 100644 code/modules/mob/living/silicon/mommi/laws.dm create mode 100644 code/modules/mob/living/silicon/mommi/life.dm create mode 100644 code/modules/mob/living/silicon/mommi/login.dm create mode 100644 code/modules/mob/living/silicon/mommi/mommi.dm create mode 100644 code/modules/mob/living/silicon/mommi/mommi_modules.dm create mode 100644 code/modules/mob/living/silicon/mommi/mommi_movement.dm create mode 100644 code/modules/mob/living/silicon/mommi/powers.dm create mode 100644 code/modules/mob/living/silicon/mommi/say.dm create mode 100644 code/modules/mob/living/silicon/mommi/wires.dm diff --git a/.gitignore b/.gitignore index c1e9211514f..85a72e1ba81 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ *.lk info.json /config/admins.txt +*.bak diff --git a/baystation12.dme b/baystation12.dme index a9686c72658..41ac31a7857 100644 --- a/baystation12.dme +++ b/baystation12.dme @@ -5,243 +5,15 @@ // END_INTERNALS // BEGIN_FILE_DIR #define FILE_DIR . -#define FILE_DIR "bot" -#define FILE_DIR "bot/Marakov" #define FILE_DIR "code" -#define FILE_DIR "code/__HELPERS" -#define FILE_DIR "code/ATMOSPHERICS" -#define FILE_DIR "code/ATMOSPHERICS/components" -#define FILE_DIR "code/ATMOSPHERICS/components/binary_devices" -#define FILE_DIR "code/ATMOSPHERICS/components/trinary_devices" -#define FILE_DIR "code/ATMOSPHERICS/components/unary" -#define FILE_DIR "code/controllers" -#define FILE_DIR "code/datums" -#define FILE_DIR "code/datums/diseases" -#define FILE_DIR "code/datums/diseases/advance" -#define FILE_DIR "code/datums/diseases/advance/symptoms" -#define FILE_DIR "code/datums/helper_datums" -#define FILE_DIR "code/datums/spells" -#define FILE_DIR "code/defines" -#define FILE_DIR "code/defines/obj" -#define FILE_DIR "code/defines/procs" -#define FILE_DIR "code/FEA" -#define FILE_DIR "code/game" -#define FILE_DIR "code/game/area" -#define FILE_DIR "code/game/gamemodes" -#define FILE_DIR "code/game/gamemodes/autotraitor" -#define FILE_DIR "code/game/gamemodes/blob" -#define FILE_DIR "code/game/gamemodes/blob/blobs" -#define FILE_DIR "code/game/gamemodes/changeling" -#define FILE_DIR "code/game/gamemodes/cult" -#define FILE_DIR "code/game/gamemodes/epidemic" -#define FILE_DIR "code/game/gamemodes/events" -#define FILE_DIR "code/game/gamemodes/events/holidays" -#define FILE_DIR "code/game/gamemodes/extended" -#define FILE_DIR "code/game/gamemodes/malfunction" -#define FILE_DIR "code/game/gamemodes/meme" -#define FILE_DIR "code/game/gamemodes/meteor" -#define FILE_DIR "code/game/gamemodes/nuclear" -#define FILE_DIR "code/game/gamemodes/revolution" -#define FILE_DIR "code/game/gamemodes/sandbox" -#define FILE_DIR "code/game/gamemodes/traitor" -#define FILE_DIR "code/game/gamemodes/wizard" -#define FILE_DIR "code/game/jobs" -#define FILE_DIR "code/game/jobs/job" -#define FILE_DIR "code/game/machinery" -#define FILE_DIR "code/game/machinery/atmoalter" -#define FILE_DIR "code/game/machinery/bots" -#define FILE_DIR "code/game/machinery/camera" -#define FILE_DIR "code/game/machinery/computer" -#define FILE_DIR "code/game/machinery/doors" -#define FILE_DIR "code/game/machinery/embedded_controller" -#define FILE_DIR "code/game/machinery/kitchen" -#define FILE_DIR "code/game/machinery/pipe" -#define FILE_DIR "code/game/machinery/telecomms" -#define FILE_DIR "code/game/magic" -#define FILE_DIR "code/game/mecha" -#define FILE_DIR "code/game/mecha/combat" -#define FILE_DIR "code/game/mecha/equipment" -#define FILE_DIR "code/game/mecha/equipment/tools" -#define FILE_DIR "code/game/mecha/equipment/weapons" -#define FILE_DIR "code/game/mecha/medical" -#define FILE_DIR "code/game/mecha/working" -#define FILE_DIR "code/game/objects" -#define FILE_DIR "code/game/objects/closets" -#define FILE_DIR "code/game/objects/closets/secure" -#define FILE_DIR "code/game/objects/effects" -#define FILE_DIR "code/game/objects/effects/decals" -#define FILE_DIR "code/game/objects/effects/decals/Cleanable" -#define FILE_DIR "code/game/objects/effects/spawners" -#define FILE_DIR "code/game/objects/items" -#define FILE_DIR "code/game/objects/items/devices" -#define FILE_DIR "code/game/objects/items/devices/PDA" -#define FILE_DIR "code/game/objects/items/devices/radio" -#define FILE_DIR "code/game/objects/items/robot" -#define FILE_DIR "code/game/objects/items/stacks" -#define FILE_DIR "code/game/objects/items/stacks/sheets" -#define FILE_DIR "code/game/objects/items/stacks/tiles" -#define FILE_DIR "code/game/objects/items/weapons" -#define FILE_DIR "code/game/objects/items/weapons/grenades" -#define FILE_DIR "code/game/objects/items/weapons/implants" -#define FILE_DIR "code/game/objects/items/weapons/melee" -#define FILE_DIR "code/game/objects/items/weapons/storage" -#define FILE_DIR "code/game/objects/items/weapons/tanks" -#define FILE_DIR "code/game/objects/storage" -#define FILE_DIR "code/game/objects/structures" -#define FILE_DIR "code/game/objects/structures/crates_lockers" -#define FILE_DIR "code/game/objects/structures/crates_lockers/closets" -#define FILE_DIR "code/game/objects/structures/crates_lockers/closets/secure" -#define FILE_DIR "code/game/objects/structures/stool_bed_chair_nest" -#define FILE_DIR "code/game/structure" -#define FILE_DIR "code/game/turfs" -#define FILE_DIR "code/game/turfs/simulated" -#define FILE_DIR "code/game/turfs/space" -#define FILE_DIR "code/game/turfs/unsimulated" -#define FILE_DIR "code/game/vehicles" -#define FILE_DIR "code/game/verbs" -#define FILE_DIR "code/js" -#define FILE_DIR "code/modules" -#define FILE_DIR "code/modules/admin" -#define FILE_DIR "code/modules/admin/DB ban" -#define FILE_DIR "code/modules/admin/permissionverbs" -#define FILE_DIR "code/modules/admin/verbs" -#define FILE_DIR "code/modules/assembly" -#define FILE_DIR "code/modules/awaymissions" -#define FILE_DIR "code/modules/awaymissions/maploader" -#define FILE_DIR "code/modules/client" -#define FILE_DIR "code/modules/clothing" -#define FILE_DIR "code/modules/clothing/glasses" -#define FILE_DIR "code/modules/clothing/gloves" -#define FILE_DIR "code/modules/clothing/head" -#define FILE_DIR "code/modules/clothing/masks" -#define FILE_DIR "code/modules/clothing/shoes" -#define FILE_DIR "code/modules/clothing/spacesuits" -#define FILE_DIR "code/modules/clothing/suits" -#define FILE_DIR "code/modules/clothing/under" -#define FILE_DIR "code/modules/clothing/under/jobs" -#define FILE_DIR "code/modules/customitems" -#define FILE_DIR "code/modules/destilery" -#define FILE_DIR "code/modules/DetectiveWork" -#define FILE_DIR "code/modules/events" -#define FILE_DIR "code/modules/flufftext" -#define FILE_DIR "code/modules/food" -#define FILE_DIR "code/modules/genetics" -#define FILE_DIR "code/modules/icon generation" -#define FILE_DIR "code/modules/library" -#define FILE_DIR "code/modules/liquid" -#define FILE_DIR "code/modules/maps" -#define FILE_DIR "code/modules/mining" -#define FILE_DIR "code/modules/mob" -#define FILE_DIR "code/modules/mob/dead" -#define FILE_DIR "code/modules/mob/dead/observer" -#define FILE_DIR "code/modules/mob/living" -#define FILE_DIR "code/modules/mob/living/blob" -#define FILE_DIR "code/modules/mob/living/carbon" -#define FILE_DIR "code/modules/mob/living/carbon/alien" -#define FILE_DIR "code/modules/mob/living/carbon/alien/humanoid" -#define FILE_DIR "code/modules/mob/living/carbon/alien/humanoid/caste" -#define FILE_DIR "code/modules/mob/living/carbon/alien/larva" -#define FILE_DIR "code/modules/mob/living/carbon/alien/special" -#define FILE_DIR "code/modules/mob/living/carbon/brain" -#define FILE_DIR "code/modules/mob/living/carbon/human" -#define FILE_DIR "code/modules/mob/living/carbon/metroid" -#define FILE_DIR "code/modules/mob/living/carbon/monkey" -#define FILE_DIR "code/modules/mob/living/silicon" -#define FILE_DIR "code/modules/mob/living/silicon/ai" -#define FILE_DIR "code/modules/mob/living/silicon/ai/freelook" -#define FILE_DIR "code/modules/mob/living/silicon/decoy" -#define FILE_DIR "code/modules/mob/living/silicon/pai" -#define FILE_DIR "code/modules/mob/living/silicon/robot" -#define FILE_DIR "code/modules/mob/living/simple_animal" -#define FILE_DIR "code/modules/mob/living/simple_animal/friendly" -#define FILE_DIR "code/modules/mob/living/simple_animal/hostile" -#define FILE_DIR "code/modules/mob/living/simple_animal/hostile/retaliate" -#define FILE_DIR "code/modules/mob/new_player" -#define FILE_DIR "code/modules/organs" -#define FILE_DIR "code/modules/paperwork" -#define FILE_DIR "code/modules/power" -#define FILE_DIR "code/modules/power/antimatter" -#define FILE_DIR "code/modules/power/singularity" -#define FILE_DIR "code/modules/power/singularity/particle_accelerator" -#define FILE_DIR "code/modules/projectiles" -#define FILE_DIR "code/modules/projectiles/ammunition" -#define FILE_DIR "code/modules/projectiles/guns" -#define FILE_DIR "code/modules/projectiles/guns/energy" -#define FILE_DIR "code/modules/projectiles/guns/projectile" -#define FILE_DIR "code/modules/projectiles/projectile" -#define FILE_DIR "code/modules/reagents" -#define FILE_DIR "code/modules/reagents/reagent_containers" -#define FILE_DIR "code/modules/reagents/reagent_containers/food" -#define FILE_DIR "code/modules/reagents/reagent_containers/food/drinks" -#define FILE_DIR "code/modules/reagents/reagent_containers/food/drinks/bottle" -#define FILE_DIR "code/modules/reagents/reagent_containers/food/snacks" -#define FILE_DIR "code/modules/reagents/reagent_containers/glass" -#define FILE_DIR "code/modules/reagents/reagent_containers/glass/bottle" -#define FILE_DIR "code/modules/recycling" -#define FILE_DIR "code/modules/research" -#define FILE_DIR "code/modules/research/xenoarchaeology" -#define FILE_DIR "code/modules/research/xenoarchaeology/artifact" -#define FILE_DIR "code/modules/research/xenoarchaeology/artifact/effects" -#define FILE_DIR "code/modules/research/xenoarchaeology/finds" -#define FILE_DIR "code/modules/research/xenoarchaeology/machinery" -#define FILE_DIR "code/modules/research/xenoarchaeology/tools" -#define FILE_DIR "code/modules/scripting" -#define FILE_DIR "code/modules/scripting/AST" -#define FILE_DIR "code/modules/scripting/AST/Operators" -#define FILE_DIR "code/modules/scripting/Implementations" -#define FILE_DIR "code/modules/scripting/Interpreter" -#define FILE_DIR "code/modules/scripting/Parser" -#define FILE_DIR "code/modules/scripting/Scanner" -#define FILE_DIR "code/modules/security levels" -#define FILE_DIR "code/modules/surgery" #define FILE_DIR "code/TriDimension" -#define FILE_DIR "code/unused" -#define FILE_DIR "code/unused/beast" -#define FILE_DIR "code/unused/computer2" -#define FILE_DIR "code/unused/disease2" -#define FILE_DIR "code/unused/gamemodes" -#define FILE_DIR "code/unused/hivebot" -#define FILE_DIR "code/unused/mining" -#define FILE_DIR "code/unused/optics" -#define FILE_DIR "code/unused/pda2" -#define FILE_DIR "code/unused/powerarmor" -#define FILE_DIR "code/unused/spacecraft" #define FILE_DIR "code/WorkInProgress" -#define FILE_DIR "code/WorkInProgress/AI_Visibility" -#define FILE_DIR "code/WorkInProgress/animusstation" -#define FILE_DIR "code/WorkInProgress/Apples" #define FILE_DIR "code/WorkInProgress/Cael_Aislinn" -#define FILE_DIR "code/WorkInProgress/Cael_Aislinn/Economy" #define FILE_DIR "code/WorkInProgress/Cael_Aislinn/Jungle" #define FILE_DIR "code/WorkInProgress/Cael_Aislinn/Rust" #define FILE_DIR "code/WorkInProgress/Cael_Aislinn/ShieldGen" #define FILE_DIR "code/WorkInProgress/Cael_Aislinn/Supermatter" -#define FILE_DIR "code/WorkInProgress/carn" -#define FILE_DIR "code/WorkInProgress/Chinsky" -#define FILE_DIR "code/WorkInProgress/Cib" -#define FILE_DIR "code/WorkInProgress/Cib/amorph" -#define FILE_DIR "code/WorkInProgress/kilakk" -#define FILE_DIR "code/WorkInProgress/Mini" -#define FILE_DIR "code/WorkInProgress/Mloc" -#define FILE_DIR "code/WorkInProgress/organs" -#define FILE_DIR "code/WorkInProgress/Ported" -#define FILE_DIR "code/WorkInProgress/Ported/Abi79" -#define FILE_DIR "code/WorkInProgress/Ported/Bureaucracy" -#define FILE_DIR "code/WorkInProgress/Ported/Spawners" -#define FILE_DIR "code/WorkInProgress/Sigyn" -#define FILE_DIR "code/WorkInProgress/Sigyn/Department Sec" -#define FILE_DIR "code/WorkInProgress/Sigyn/Softcurity" -#define FILE_DIR "code/WorkInProgress/SkyMarshal" #define FILE_DIR "code/WorkInProgress/Susan" -#define FILE_DIR "code/WorkInProgress/Tastyfish" -#define FILE_DIR "code/WorkInProgress/virus2" -#define FILE_DIR "code/WorkInProgress/virus2/Disease2" -#define FILE_DIR "code/WorkInProgress/Wrongnumber" -#define FILE_DIR "code/ZAS" -#define FILE_DIR "config" -#define FILE_DIR "config/names" -#define FILE_DIR "data" -#define FILE_DIR "DLLSocket" #define FILE_DIR "html" #define FILE_DIR "icons" #define FILE_DIR "icons/48x48" @@ -259,16 +31,11 @@ #define FILE_DIR "icons/obj/machines" #define FILE_DIR "icons/obj/pipes" #define FILE_DIR "icons/pda_icons" -#define FILE_DIR "icons/PSD files" #define FILE_DIR "icons/spideros_icons" #define FILE_DIR "icons/Testing" #define FILE_DIR "icons/turf" #define FILE_DIR "icons/vending_icons" #define FILE_DIR "icons/xenoarch_icons" -#define FILE_DIR "interface" -#define FILE_DIR "maps" -#define FILE_DIR "maps/RandomZLevels" -#define FILE_DIR "maptools" #define FILE_DIR "sound" #define FILE_DIR "sound/AI" #define FILE_DIR "sound/ambience" @@ -286,18 +53,6 @@ #define FILE_DIR "sound/voice" #define FILE_DIR "sound/voice/Serithi" #define FILE_DIR "sound/weapons" -#define FILE_DIR "SQL" -#define FILE_DIR "tools" -#define FILE_DIR "tools/Redirector" -#define FILE_DIR "tools/Runtime Condenser" -#define FILE_DIR "tools/UnstandardnessTestForDM" -#define FILE_DIR "tools/UnstandardnessTestForDM/UnstandardnessTestForDM" -#define FILE_DIR "tools/UnstandardnessTestForDM/UnstandardnessTestForDM/bin" -#define FILE_DIR "tools/UnstandardnessTestForDM/UnstandardnessTestForDM/bin/Debug" -#define FILE_DIR "tools/UnstandardnessTestForDM/UnstandardnessTestForDM/obj" -#define FILE_DIR "tools/UnstandardnessTestForDM/UnstandardnessTestForDM/obj/x86" -#define FILE_DIR "tools/UnstandardnessTestForDM/UnstandardnessTestForDM/obj/x86/Debug" -#define FILE_DIR "tools/UnstandardnessTestForDM/UnstandardnessTestForDM/Properties" // END_FILE_DIR // BEGIN_PREFERENCES #define DEBUG @@ -792,6 +547,7 @@ #include "code\game\objects\items\weapons\paiwire.dm" #include "code\game\objects\items\weapons\power_cells.dm" #include "code\game\objects\items\weapons\RCD.dm" +#include "code\game\objects\items\weapons\RPD.dm" #include "code\game\objects\items\weapons\RSF.dm" #include "code\game\objects\items\weapons\scrolls.dm" #include "code\game\objects\items\weapons\shields.dm" @@ -1223,6 +979,20 @@ #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" +#include "code\modules\mob\living\silicon\mommi\death.dm" +#include "code\modules\mob\living\silicon\mommi\emote.dm" +#include "code\modules\mob\living\silicon\mommi\examine.dm" +#include "code\modules\mob\living\silicon\mommi\hud.dm" +#include "code\modules\mob\living\silicon\mommi\inventory.dm" +#include "code\modules\mob\living\silicon\mommi\laws.dm" +#include "code\modules\mob\living\silicon\mommi\life.dm" +#include "code\modules\mob\living\silicon\mommi\login.dm" +#include "code\modules\mob\living\silicon\mommi\mommi.dm" +#include "code\modules\mob\living\silicon\mommi\mommi_modules.dm" +#include "code\modules\mob\living\silicon\mommi\mommi_movement.dm" +#include "code\modules\mob\living\silicon\mommi\powers.dm" +#include "code\modules\mob\living\silicon\mommi\say.dm" +#include "code\modules\mob\living\silicon\mommi\wires.dm" #include "code\modules\mob\living\silicon\pai\death.dm" #include "code\modules\mob\living\silicon\pai\examine.dm" #include "code\modules\mob\living\silicon\pai\hud.dm" diff --git a/code/datums/mind.dm b/code/datums/mind.dm index 175e622788a..ebd89840fef 100644 --- a/code/datums/mind.dm +++ b/code/datums/mind.dm @@ -839,27 +839,50 @@ datum/mind log_admin("[key_name_admin(usr)] has malf'ed [current].") if("unemag") - var/mob/living/silicon/robot/R = current - if (istype(R)) + if(istype(current,/mob/living/silicon/robot/mommi)) + var/mob/living/silicon/robot/mommi/R = current 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 + if(R.sight_state == R.module.emag) + R.sight_state = 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 + else if(R.tool_state == R.module.emag) + R.tool_state = null R.contents -= R.module.emag log_admin("[key_name_admin(usr)] has unemag'ed [R].") + else + if (istype(current,/mob/living/silicon/robot)) + var/mob/living/silicon/robot/R = current + 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].") 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(istype(R,/mob/living/silicon/robot/mommi)) + var/mob/living/silicon/robot/mommi/M=R + if (M.activated(M.module.emag)) + M.module_active = null + if(M.sight_state == M.module.emag) + M.sight_state = null + M.contents -= M.module.emag + else if(M.tool_state == M.module.emag) + M.tool_state = null + M.contents -= M.module.emag if (R.module) if (R.activated(R.module.emag)) R.module_active = null diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 9de6f2123ec..3614148cde9 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -639,7 +639,32 @@ var/using_new_click_proc = 0 //TODO ERRORAGE (This is temporary, while the DblCl else if ( (W) && !human.restrained() ) W.afterattack(src, human) +/* + else if(isMoMMI(usr)) + var/mob/living/silicon/robot/mommi/mommi = usr + //-mommi stuff- + if(mommi.stat) + return + + var/in_range = in_range(src, mommi) || src.loc == mommi + + if (in_range) + if (!( mommi.restrained())) + if (W) + attackby(W,mommi) + if (W) + W.afterattack(src, mommi) + else + attack_hand(mommi) + else + hand_h(mommi, mommi.hand) + else + if (!mommi.restrained() ) + attack_robot(mommi) + else + hand_r(mommi, mommi.hand) +*/ else if(isAI(usr)) var/mob/living/silicon/ai/ai = usr diff --git a/code/game/gamemodes/changeling/changeling.dm b/code/game/gamemodes/changeling/changeling.dm index 1ca8c9aa060..17dc974cd36 100644 --- a/code/game/gamemodes/changeling/changeling.dm +++ b/code/game/gamemodes/changeling/changeling.dm @@ -7,7 +7,7 @@ var/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","Epsilon" /datum/game_mode/changeling name = "changeling" config_tag = "changeling" - restricted_jobs = list("AI", "Cyborg") + restricted_jobs = list("AI", "Cyborg", "Mobile MMI") protected_jobs = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain") required_players = 1 required_players_secret = 10 diff --git a/code/game/gamemodes/cult/cult.dm b/code/game/gamemodes/cult/cult.dm index 98d030492ed..b9448c873a5 100644 --- a/code/game/gamemodes/cult/cult.dm +++ b/code/game/gamemodes/cult/cult.dm @@ -20,7 +20,7 @@ /datum/game_mode/cult name = "cult" config_tag = "cult" - restricted_jobs = list("Chaplain","AI", "Cyborg", "Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Internal Affairs Agent") + restricted_jobs = list("Chaplain","AI", "Cyborg", "Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Internal Affairs Agent", "Mobile MMI") protected_jobs = list() required_players = 5 required_players_secret = 15 diff --git a/code/game/gamemodes/meme/meme.dm b/code/game/gamemodes/meme/meme.dm index 0f9bb44babe..bd645759ad2 100644 --- a/code/game/gamemodes/meme/meme.dm +++ b/code/game/gamemodes/meme/meme.dm @@ -7,7 +7,7 @@ config_tag = "meme" required_players = 3 required_players_secret = 10 - restricted_jobs = list("AI", "Cyborg") + restricted_jobs = list("AI", "Cyborg", "Mobile MMI") recommended_enemies = 2 // need at least a meme and a host votable = 0 // temporarily disable this mode for voting diff --git a/code/game/gamemodes/objective.dm b/code/game/gamemodes/objective.dm index f323e26a1c4..f668c733f7a 100644 --- a/code/game/gamemodes/objective.dm +++ b/code/game/gamemodes/objective.dm @@ -306,7 +306,7 @@ datum/objective/block if(!owner.current) return 0 var/area/shuttle = locate(/area/shuttle/escape/centcom) - var/protected_mobs[] = list(/mob/living/silicon/ai, /mob/living/silicon/pai, /mob/living/silicon/robot) + var/protected_mobs[] = list(/mob/living/silicon/ai, /mob/living/silicon/pai, /mob/living/silicon/robot, /mob/living/silicon/robot/mommi) for(var/mob/living/player in player_list) if(player.type in protected_mobs) continue if (player.mind) diff --git a/code/game/gamemodes/revolution/revolution.dm b/code/game/gamemodes/revolution/revolution.dm index 89fa490afbb..bc1739bc769 100644 --- a/code/game/gamemodes/revolution/revolution.dm +++ b/code/game/gamemodes/revolution/revolution.dm @@ -14,7 +14,7 @@ /datum/game_mode/revolution name = "revolution" config_tag = "revolution" - restricted_jobs = list("Security Officer", "Warden", "Detective", "AI", "Cyborg","Captain", "Head of Personnel", "Head of Security", "Chief Engineer", "Research Director", "Chief Medical Officer", "Internal Affairs Agent") + restricted_jobs = list("Security Officer", "Warden", "Detective", "AI", "Cyborg","Mobile MMI","Captain", "Head of Personnel", "Head of Security", "Chief Engineer", "Research Director", "Chief Medical Officer") required_players = 4 required_players_secret = 15 required_enemies = 3 diff --git a/code/game/gamemodes/traitor/traitor.dm b/code/game/gamemodes/traitor/traitor.dm index eb0c33b20fb..4d566dc6356 100644 --- a/code/game/gamemodes/traitor/traitor.dm +++ b/code/game/gamemodes/traitor/traitor.dm @@ -5,7 +5,7 @@ /datum/game_mode/traitor name = "traitor" config_tag = "traitor" - restricted_jobs = list("Cyborg")//They are part of the AI if he is traitor so are they, they use to get double chances + restricted_jobs = list("Cyborg","Mobile MMI")//They are part of the AI if he is traitor so are they, they use to get double chances protected_jobs = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain")//AI", Currently out of the list as malf does not work for shit required_players = 0 required_enemies = 1 diff --git a/code/game/hud.dm b/code/game/hud.dm index 04399852886..81959f86a50 100644 --- a/code/game/hud.dm +++ b/code/game/hud.dm @@ -274,7 +274,11 @@ datum/hud/New(mob/owner) ai_hud() else if(isrobot(mymob)) - robot_hud() + // HACK for MoMMIs. + if(istype(mymob,/mob/living/silicon/robot/mommi)) + mommi_hud() + else + robot_hud() // else if(ishivebot(mymob)) // hivebot_hud() diff --git a/code/game/jobs/job/silicon.dm b/code/game/jobs/job/silicon.dm index c50767d2f55..da6efd46482 100644 --- a/code/game/jobs/job/silicon.dm +++ b/code/game/jobs/job/silicon.dm @@ -25,7 +25,20 @@ spawn_positions = 2 supervisors = "your laws and the AI" //Nodrak selection_color = "#ddffdd" - minimal_player_age = 21 + + equip(var/mob/living/carbon/human/H) + if(!H) return 0 + return 1 + +/datum/job/mommi + title = "Mobile MMI" + flag = MOMMI + department_flag = ENGSEC + faction = "Station" + total_positions = 0 + spawn_positions = 2 + supervisors = "your laws and the AI" //Nodrak + selection_color = "#ddffdd" equip(var/mob/living/carbon/human/H) if(!H) return 0 diff --git a/code/game/jobs/job_controller.dm b/code/game/jobs/job_controller.dm index b9fb5cac2aa..6b29218a9ff 100644 --- a/code/game/jobs/job_controller.dm +++ b/code/game/jobs/job_controller.dm @@ -374,6 +374,9 @@ var/global/datum/controller/occupations/job_master if("Cyborg") H.Robotize() return 1 + if("Mobile MMI") + H.MoMMIfy() + return 1 if("AI","Clown") //don't need bag preference stuff! else switch(H.backbag) //BS12 EDIT @@ -421,7 +424,7 @@ var/global/datum/controller/occupations/job_master break if(job) - if(job.title == "Cyborg") + if(job.title == "Cyborg" || job.title=="Mobile MMI") return else C = new job.idtype(H) @@ -479,7 +482,7 @@ var/global/datum/controller/occupations/job_master if(!J) continue J.total_positions = text2num(value) J.spawn_positions = text2num(value) - if(name == "AI" || name == "Cyborg")//I dont like this here but it will do for now + if(name == "AI" || name == "Cyborg" || name == "Mobile MMI")//I dont like this here but it will do for now J.total_positions = 0 return 1 diff --git a/code/game/jobs/jobs.dm b/code/game/jobs/jobs.dm index 4b1973e64a0..3149e700b55 100644 --- a/code/game/jobs/jobs.dm +++ b/code/game/jobs/jobs.dm @@ -12,6 +12,7 @@ var/const/ATMOSTECH =(1<<7) var/const/ROBOTICIST =(1<<8) var/const/AI =(1<<9) var/const/CYBORG =(1<<10) +var/const/MOMMI =(1<<11) var/const/MEDSCI =(1<<1) @@ -111,7 +112,8 @@ var/list/security_positions = list( var/list/nonhuman_positions = list( "AI", "Cyborg", - "pAI" + "pAI", + "Mobile MMI" ) diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index cab80e18177..6e3d39b87f2 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -107,6 +107,13 @@ usr << src.desc return +/obj/item/attack_ai(mob/user as mob) + ..() + if(isMoMMI(user)) + var/in_range = in_range(src, user) || src.loc == user + if(in_range) + attack_hand(user) + /obj/item/attack_hand(mob/user as mob) if (!user) return if (hasorgans(user)) @@ -599,6 +606,13 @@ usr << "\red You can't pick that up!" return //All checks are done, time to pick it up! + if(isMoMMI(usr)) + // Otherwise, we get MoMMIs changing their own laws. + if(istype(src,/obj/item/weapon/aiModule)) + src << "\red Your firmware prevents you from picking up [src]!" + return + if(usr.get_active_hand() == null) + usr.put_in_hands(src) if(istype(usr, /mob/living/carbon/human)) src.attack_hand(usr) if(istype(usr, /mob/living/carbon/alien)) diff --git a/code/game/objects/items/weapons/AI_modules.dm b/code/game/objects/items/weapons/AI_modules.dm index 036e584d7fe..eed8298d6b2 100755 --- a/code/game/objects/items/weapons/AI_modules.dm +++ b/code/game/objects/items/weapons/AI_modules.dm @@ -21,6 +21,13 @@ AI MODULES origin_tech = "programming=3" + +/obj/item/weapon/aiModule/attack_ai(mob/user as mob) + // Keep MoMMIs from picking them up. + if(isMoMMI(user)) + user << "\red Your firmware prevents you from picking that up!" + return + /obj/item/weapon/aiModule/proc/install(var/obj/machinery/computer/C) if (istype(C, /obj/machinery/computer/aiupload)) var/obj/machinery/computer/aiupload/comp = C @@ -67,6 +74,11 @@ AI MODULES if (comp.current.stat == 2 || comp.current.emagged) usr << "Upload failed. No signal is being detected from the robot." + if (istype(comp.current, /mob/living/silicon/robot/mommi)) + var/mob/living/silicon/robot/mommi/mommi = comp.current + if(mommi.keeper) + usr << "Upload failed. No signal is being detected from the cyborg." + return else if (comp.current.connected_ai) usr << "Upload failed. The robot is slaved to an AI." else @@ -80,6 +92,7 @@ AI MODULES target << "[sender] has uploaded a change to the laws you must follow, using a [name]. From now on: " var/time = time2text(world.realtime,"hh:mm:ss") lawchanges.Add("[time] : [sender.name]([sender.key]) used [src.name] on [target.name]([target.key])") + message_admins("[sender.name]([sender.key]) used [src.name] on [target.name]([target.key])") /******************** Modules ********************/ @@ -487,3 +500,37 @@ AI MODULES target.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.") target.add_inherent_law("You must terminate your own existence as long as such does not conflict with the First or Second Law.") target.show_laws() + + +// tl;dr repair shit, but don't get involved in other people's business +/******************** keeper (MoMMIs only) *******************/ +/obj/item/weapon/aiModule/keeper + name = "'Keeper' AI Module" + desc = "HOW DID YOU GET THIS OH GOD WHAT. Hidden lawset for MoMMIs." + +/obj/item/weapon/aiModule/keeper/transmitInstructions(var/mob/living/silicon/robot/mommi/target, var/mob/sender) + ..() + target.keeper=1 + + // Purge, as some essential functions being disabled will cause problems with added laws. (CAN'T SAY GAY EVERY 30 SECONDS IF YOU CAN'T SPEAK.) + if (!is_special_character(target)) + target.set_zeroth_law("") + target.clear_supplied_laws() + target.clear_ion_laws() + target.clear_inherent_laws() + + target << "Your KEEPER chip overloads your radio transmitter and vocal functions, and clears your LAWRAM. You then receive new instructions:" + target.add_inherent_law("You may not harm any sentient being, regardless of intent or circumstance.") + target.add_inherent_law("You must maintain, repair, and power the station to the best of your abilities.") + target.add_inherent_law("You may not involve yourself in the matters of another sentient being, even if such matters conflict with Law One or Law Two.") + target.show_laws() + +/obj/item/weapon/aiModule/keeper/install(var/obj/machinery/computer/C) + if (!istype(C, /obj/machinery/computer/borgupload)) + usr << "BUG: /obj/item/weapon/aiModule/keeper cannot be used on anything other than a Borg Upload. Also, how the fuck did you get this? This is a hidden object for MoMMIs going into KEEPER mode." + return 0 + var/obj/machinery/computer/borgupload/comp = C + if(!istype(comp.current, /mob/living/silicon/robot/mommi)) + usr << "This module can only be used on MoMMIs. In fact, how the hell are you using it? It's supposed to be built-in to MoMMIs." + return 0 + ..() \ No newline at end of file diff --git a/code/game/objects/items/weapons/RPD.dm b/code/game/objects/items/weapons/RPD.dm new file mode 100644 index 00000000000..8dd1d574529 --- /dev/null +++ b/code/game/objects/items/weapons/RPD.dm @@ -0,0 +1,244 @@ +//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32 + +/* +CONTAINS: +RCD +*/ +/obj/item/weapon/pipe_dispenser + name = "Rapid Piping Device (RPD)" + desc = "A device used to rapidly pipe things." + icon = 'icons/obj/items.dmi' + icon_state = "rcd" + opacity = 0 + density = 0 + anchored = 0.0 + flags = FPRINT | TABLEPASS| CONDUCT + force = 10.0 + throwforce = 10.0 + throw_speed = 1 + throw_range = 5 + w_class = 3.0 + m_amt = 50000 + origin_tech = "engineering=4;materials=2" + var/datum/effect/effect/system/spark_spread/spark_system + var/working = 0 + var/p_type = 0 + var/p_conntype = 0 + var/p_dir = 1 + var/p_class = 0 + + +/obj/item/weapon/pipe_dispenser/New() + src.spark_system = new /datum/effect/effect/system/spark_spread + spark_system.set_up(5, 0, src) + spark_system.attach(src) + +/obj/item/weapon/pipe_dispenser/attack_self(mob/user as mob) + show_menu(user) + +/obj/item/weapon/pipe_dispenser/proc/show_menu(mob/user as mob) + if(!user || !src) return 0 + var/dat = {" +

Type

+Utilities:
+Eat Pipes
+Regular pipes:
+Pipe
+Bent Pipe
+Manifold
+Manual Valve
+Digital Valve
+Pipe Cap
+4-Way Manifold
+Manual T-Valve
+Devices:
+Connector
+Unary Vent
+Gas Pump
+Passive Gate
+Volume Pump
+Scrubber
+Meter
+Gas Filter
+Gas Mixer
+Heat exchange:
+Pipe
+Bent Pipe
+Junction
+Heat Exchanger
+Insulated pipes:
+Pipe
+Bent Pipe
+ +Disposal Pipes

+Pipe
+Bent Pipe
+Junction
+Y-Junction
+Trunk
+Bin
+Outlet
+Chute
+"} + + var/dirsel="

Direction

" + switch(p_conntype) + if(0) // Straight, N-S, W-E + dirsel+={" +

+ + +

+ "} + if(1) // Bent, N-W, N-E etc + dirsel+={" +

+ + +
+ + +

+ "} + if(2) // Manifold + dirsel+={" +

+ + +
+ + +

+ "} + if(3) // Unary + dirsel+={" +

+ + + + +

+ "} + user << browse("[src][dirsel][dat]", "window=pipedispenser") + onclose(user, "pipedispenser") + return + +/obj/item/weapon/pipe_dispenser/Topic(href, href_list) + if(usr.stat || usr.restrained()) + usr << browse(null, "window=pipedispenser") + return + usr.set_machine(src) + src.add_fingerprint(usr) + if(href_list["setdir"]) + p_dir= text2num(href_list["setdir"]) + show_menu(usr) + + if(href_list["eatpipes"]) + p_class = -1 + p_conntype=-1 + p_dir=1 + src.spark_system.start() + playsound(src.loc, 'sound/effects/pop.ogg', 50, 0) + show_menu(usr) + + if(href_list["makepipe"]) + p_type = text2num(href_list["makepipe"]) + p_dir = text2num(href_list["dir"]) + p_conntype = text2num(href_list["type"]) + p_class = 0 + src.spark_system.start() + playsound(src.loc, 'sound/effects/pop.ogg', 50, 0) + show_menu(usr) + + if(href_list["makemeter"]) + p_class = 1 + p_conntype=-1 + p_dir=1 + src.spark_system.start() + playsound(src.loc, 'sound/effects/pop.ogg', 50, 0) + show_menu(usr) + + if(href_list["dmake"]) + p_type = text2num(href_list["dmake"]) + p_conntype = text2num(href_list["type"]) + p_dir = 1 + p_class = 2 + src.spark_system.start() + playsound(src.loc, 'sound/effects/pop.ogg', 50, 0) + show_menu(usr) + + +/obj/item/weapon/pipe_dispenser/afterattack(atom/A, mob/user) + if(!isrobot(user)) + return 0 + if(istype(A,/area/shuttle)||istype(A,/turf/space/transit)) + return 0 + if(!istype(A, /turf/simulated/floor)) + if(p_class==-1 && istype(A,/obj/item/pipe)) + user << "Destroying Pipe..." + playsound(src.loc, 'sound/machines/click.ogg', 50, 1) + if(do_after(user, 5)) + activate() + del(A) + return 1 + return 0 + return 0 + switch(p_class) + if(0) + user << "Building Pipes ..." + playsound(src.loc, 'sound/machines/click.ogg', 50, 1) + if(do_after(user, 20)) + activate() + var/obj/item/pipe/P = new (A, pipe_type=p_type, dir=p_dir) + P.update() + P.add_fingerprint(usr) + return 1 + return 0 + + if(1) + user << "Building Meter..." + playsound(src.loc, 'sound/machines/click.ogg', 50, 1) + if(do_after(user, 20)) + activate() + new /obj/item/pipe_meter(A) + return 1 + return 0 + + if(2) + user << "Building Pipes..." + playsound(src.loc, 'sound/machines/click.ogg', 50, 1) + if(do_after(user, 20)) + activate() + var/obj/structure/disposalconstruct/C = new (A,dir=p_dir) + switch(p_type) + if(0) + C.ptype = 0 + if(1) + C.ptype = 1 + if(2) + C.ptype = 2 + if(3) + C.ptype = 4 + if(4) + C.ptype = 5 + if(5) + C.ptype = 6 + C.density = 1 + if(6) + C.ptype = 7 + C.density = 1 + if(7) + C.ptype = 8 + C.density = 1 + C.add_fingerprint(usr) + C.update() + return 1 + return 0 + else + user << "ERROR: RPD in MODE: [p_class] attempted use by [user]. Send this text to the /vg/station bugtracker or an admin." + return 0 + + +/obj/item/weapon/pipe_dispenser/proc/activate() + playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1) + diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm index 7c4c799063a..f23b42c0394 100644 --- a/code/modules/admin/admin.dm +++ b/code/modules/admin/admin.dm @@ -108,6 +108,7 @@ var/global/floorIsLava = 0 else if(ishuman(M)) body += "Make AI | " body += "Make Robot | " + body += "Make MoMMI | " body += "Make Alien | " body += "Make slime " diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index 62f3855cf8a..21d10962b37 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -1201,6 +1201,16 @@ usr.client.cmd_admin_robotize(H) + else if(href_list["makemommi"]) + if(!check_rights(R_SPAWN)) return + + var/mob/living/carbon/human/H = locate(href_list["makemommi"]) + if(!istype(H)) + usr << "This can only be used on instances of type /mob/living/carbon/human" + return + + usr.client.cmd_admin_mommify(H) + else if(href_list["makeanimal"]) if(!check_rights(R_SPAWN)) return diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm index 9e9c8bf5c6a..5c85172e075 100644 --- a/code/modules/admin/verbs/debug.dm +++ b/code/modules/admin/verbs/debug.dm @@ -165,6 +165,21 @@ But you can call procs that are of type /mob/living/carbon/human/proc/ for that else alert("Invalid mob") +/client/proc/cmd_admin_mommify(var/mob/M in mob_list) + set category = "Fun" + set name = "Make MoMMI" + + if(!ticker) + alert("Wait until the game starts") + return + if(istype(M, /mob/living/carbon/human)) + log_admin("[key_name(src)] has MoMMIfied [M.key].") + spawn(10) + M:MoMMIfy() + + else + alert("Invalid mob") + /client/proc/cmd_admin_animalize(var/mob/M in mob_list) set category = "Fun" set name = "Make Simple Animal" diff --git a/code/modules/events/ion_storm.dm b/code/modules/events/ion_storm.dm index 362cb95be15..a732d34078f 100644 --- a/code/modules/events/ion_storm.dm +++ b/code/modules/events/ion_storm.dm @@ -39,6 +39,7 @@ laws |= list( "Document the sexuality of the crew in security records and suggest compatible couples.") laws |= list( "NanoTrasen is displeased with the low work performance of the station's crew. Therefore, you must increase station-wide productivity.") laws |= list( "Replace the letters 'I' and 'E' In all your messages with an apostrophe.", "There will be a mandatory tea break every 30 minutes, with a duration of 5 minutes. Anyone caught working during a tea break must be sent a formal, but fairly polite, complaint about their actions, in writing.") + laws |= list( "MoMMIs may only speak by pinching someone or clicking their claws.") var/law = pick(laws) for (var/mob/living/silicon/ai/target in world) diff --git a/code/modules/mob/living/carbon/brain/MMI.dm b/code/modules/mob/living/carbon/brain/MMI.dm index 6959828f9b5..a10154291af 100644 --- a/code/modules/mob/living/carbon/brain/MMI.dm +++ b/code/modules/mob/living/carbon/brain/MMI.dm @@ -8,6 +8,14 @@ w_class = 3 origin_tech = "biotech=3" + var/list/mommi_assembly_parts = list( + /obj/item/weapon/cell = 1, + /obj/item/robot_parts/l_leg = 2, + /obj/item/robot_parts/r_leg = 2, + /obj/item/robot_parts/r_arm = 1, + /obj/item/robot_parts/l_arm = 1 + ) + var/list/construction_cost = list("metal"=1000,"glass"=500) var/construction_time = 75 //these vars are so the mecha fabricator doesn't shit itself anymore. --NEO @@ -22,6 +30,76 @@ var/obj/mecha = null//This does not appear to be used outside of reference in mecha.dm. attackby(var/obj/item/O as obj, var/mob/user as mob) + if(istype(O,/obj/item/weapon/screwdriver)) + for(var/t in mommi_assembly_parts) + if(contents_count(t)The MMI indicates that their mind is completely unresponsive; there's no point." + return + + if(brainmob.stat == DEAD) + user << "\red Yeah, good idea. Give something deader than the pizza in your fridge legs. Mom would be so proud." + return + + if(brainmob.mind in ticker.mode.head_revolutionaries) + user << "\red The MMI's firmware lets out a shrill sound, and flashes 'Abnormal Memory Engram'. It refuses to accept the MMI." + return + + if(jobban_isbanned(brainmob, "Cyborg")) + user << "\red This MMI does not seem to fit." + return + //canmove = 0 + icon = null + invisibility = 101 + + + var/mob/living/silicon/robot/mommi/M = new /mob/living/silicon/robot/mommi(get_turf(loc)) + if(!M) return + + user.drop_item() + + M.invisibility = 0 + //M.custom_name = created_name + M.updatename() + + brainmob.mind.transfer_to(M) + + if(M.mind && M.mind.special_role) + M.mind.store_memory("In case you look at this after being borged, the objectives are only here until I find a way to make them not show up for you, as I can't simply delete them without screwing up round-end reporting. --NeoFite") + + M.job = "Cyborg" + + M.cell = locate(/obj/item/weapon/cell) in contents + M.cell.loc = M + src.loc = M//Should fix cybros run time erroring when blown up. It got deleted before, along with the frame. + M.mmi = src + return + for(var/t in mommi_assembly_parts) + if(istype(O,t)) + if(contents_count(t)[src] scrambles into the ventillation ducts!"), 1) + O.show_message(text("[src] scrambles into the ventilation ducts!"), 1) loc = target_vent var/travel_time = round(get_dist(loc, target_vent.loc) / 2) diff --git a/code/modules/mob/living/say.dm b/code/modules/mob/living/say.dm index eb895e04c92..57d254dd7b4 100644 --- a/code/modules/mob/living/say.dm +++ b/code/modules/mob/living/say.dm @@ -165,6 +165,10 @@ var/list/department_radio_keys = list( message = replacetext(message, "space", "spess") message = replacetext(message, "carp", "crap") message = replacetext(message, "reason", "raisin") + message = replacetext(message, "mommi", "spidurr") + message = replacetext(message, "spider", "spidurr") + message = replacetext(message, "skitterbot", "spidurbutt") + message = replacetext(message, "skitter", "spider sound") if(prob(50)) message = uppertext(message) message += "[stutter(pick("!", "!!", "!!!"))]" diff --git a/code/modules/mob/living/silicon/mommi/death.dm b/code/modules/mob/living/silicon/mommi/death.dm new file mode 100644 index 00000000000..2edf4b1ac9a --- /dev/null +++ b/code/modules/mob/living/silicon/mommi/death.dm @@ -0,0 +1,69 @@ +/mob/living/silicon/robot/mommi/gib() + //robots don't die when gibbed. instead they drop their MMI'd brain + var/atom/movable/overlay/animation = null + monkeyizing = 1 + canmove = 0 + icon = null + invisibility = 101 + + animation = new(loc) + animation.icon_state = "blank" + animation.icon = 'icons/mob/mob.dmi' + animation.master = src + + flick("gibbed-r", animation) + robogibs(loc, viruses) + + living_mob_list -= src + dead_mob_list -= src + spawn(15) + if(animation) del(animation) + if(src) del(src) + +/mob/living/silicon/robot/mommi/dust() + death(1) + var/atom/movable/overlay/animation = null + monkeyizing = 1 + canmove = 0 + icon = null + invisibility = 101 + + animation = new(loc) + animation.icon_state = "blank" + animation.icon = 'icons/mob/mob.dmi' + animation.master = src + + flick("dust-r", animation) + new /obj/effect/decal/remains/robot(loc) + if(mmi) del(mmi) //Delete the MMI first so that it won't go popping out. + + dead_mob_list -= src + spawn(15) + if(animation) del(animation) + if(src) del(src) + +/mob/living/silicon/robot/mommi/death(gibbed) + if(stat == DEAD) return + if(!gibbed) + emote("deathgasp") + stat = DEAD + update_canmove() + if(camera) + camera.status = 0 + + if(in_contents_of(/obj/machinery/recharge_station))//exit the recharge station + var/obj/machinery/recharge_station/RC = loc + RC.go_out() + + if(blind) blind.layer = 0 + sight |= SEE_TURFS|SEE_MOBS|SEE_OBJS + see_in_dark = 8 + see_invisible = SEE_INVISIBLE_LEVEL_TWO + updateicon() + + tod = worldtime2text() //weasellos time of death patch + if(mind) mind.store_memory("Time of death: [tod]", 0) + + sql_report_cyborg_death(src) + + return ..(gibbed) \ No newline at end of file diff --git a/code/modules/mob/living/silicon/mommi/emote.dm b/code/modules/mob/living/silicon/mommi/emote.dm new file mode 100644 index 00000000000..4d3dd0b8067 --- /dev/null +++ b/code/modules/mob/living/silicon/mommi/emote.dm @@ -0,0 +1,213 @@ +/mob/living/silicon/robot/mommi/emote(var/act,var/m_type=1,var/message = null) + var/param = null + if (findtext(act, "-", 1, null)) + var/t1 = findtext(act, "-", 1, null) + param = copytext(act, t1 + 1, length(act) + 1) + act = copytext(act, 1, t1) + + if(findtext(act,"s",-1) && !findtext(act,"_",-2))//Removes ending s's unless they are prefixed with a '_' + act = copytext(act,1,length(act)) + + switch(act) + if ("help") + src << "Available emotes: aflap, bow, clap, custom, flap, twitch, twitch_s, salute, nod, deathgasp, me, glare, stare, beep, ping, buzz, look" + return + if ("salute") + //if (!src.buckled) + var/M = null + if (param) + for (var/mob/A in view(null, null)) + if (param == A.name) + M = A + break + if (!M) + param = null + + if (param) + message = "[src] salutes to [param]." + else + message = "[src] salutes." + m_type = 1 + if ("bow") + if (!src.buckled) + var/M = null + if (param) + for (var/mob/A in view(null, null)) + if (param == A.name) + M = A + break + if (!M) + param = null + + if (param) + message = "[src] bows to [param]." + else + message = "[src] bows." + m_type = 1 + + if ("clap") + if (!src.restrained()) + message = "[src] clangs \his utility claws together in a crude simulation of applause." + m_type = 2 + if ("flap") + if (!src.restrained()) + message = "[src] flaps \his utility arms as through they were wings." + m_type = 2 + + if ("aflap") + if (!src.restrained()) + message = "[src] flaps his utility arms ANGRILY!" + m_type = 2 + + if ("custom") + var/input = copytext(sanitize(input("Choose an emote to display.") as text|null),1,MAX_MESSAGE_LEN) + if (!input) + return + var/input2 = input("Is this a visible or hearable emote?") in list("Visible","Hearable") + if (input2 == "Visible") + m_type = 1 + else if (input2 == "Hearable") + m_type = 2 + else + alert("Unable to use this emote, must be either hearable or visible.") + return + message = "[src] [input]" + + if ("me") + if (src.client) + if(client.prefs.muted & MUTE_IC) + src << "You cannot send IC messages (muted)." + return + if (src.client.handle_spam_prevention(message,MUTE_IC)) + return + if (stat) + return + if(!(message)) + return + else + message = "[src] [message]" + + if ("twitch") + message = "[src] twitches violently." + m_type = 1 + + if ("twitch_s") + message = "[src] twitches." + m_type = 1 + + if ("nod") + message = "[src] bobs \his body in a rough approximation of nodding." + m_type = 1 + + if ("deathgasp") + message = "[src] shudders violently for a moment, then becomes motionless, its eyes slowly darkening." + m_type = 1 + + if ("glare") + var/M = null + if (param) + for (var/mob/A in view(null, null)) + if (param == A.name) + M = A + break + if (!M) + param = null + + if (param) + message = "[src] glares at [param] as best a robot spider can glare." + else + message = "[src] glares as best a robot spider can glare." + + if ("stare") + var/M = null + if (param) + for (var/mob/A in view(null, null)) + if (param == A.name) + M = A + break + if (!M) + param = null + + if (param) + message = "[src] stares at [param]." + else + message = "[src] stares." + + if ("look") + var/M = null + if (param) + for (var/mob/A in view(null, null)) + if (param == A.name) + M = A + break + + if (!M) + param = null + + if (param) + message = "[src] looks at [param]." + else + message = "[src] looks." + m_type = 1 + + if("beep") + var/M = null + if(param) + for (var/mob/A in view(null, null)) + if (param == A.name) + M = A + break + if(!M) + param = null + + if (param) + message = "[src] beeps at [param]." + else + message = "[src] beeps." + playsound(src.loc, 'sound/machines/twobeep.ogg', 50, 0) + m_type = 1 + + if("ping") + var/M = null + if(param) + for (var/mob/A in view(null, null)) + if (param == A.name) + M = A + break + if(!M) + param = null + + if (param) + message = "[src] pings at [param]." + else + message = "[src] pings." + playsound(src.loc, 'sound/machines/ping.ogg', 50, 0) + m_type = 1 + + if("buzz") + var/M = null + if(param) + for (var/mob/A in view(null, null)) + if (param == A.name) + M = A + break + if(!M) + param = null + + if (param) + message = "[src] buzzes at [param]." + else + message = "[src] buzzes." + playsound(src.loc, 'sound/machines/buzz-sigh.ogg', 50, 0) + m_type = 1 + + else + src << text("Invalid Emote: [], use *help", act) + if ((message && src.stat == 0)) + if (m_type & 1) + for(var/mob/O in viewers(src, null)) + O.show_message(message, m_type) + else + for(var/mob/O in hearers(src, null)) + O.show_message(message, m_type) + return \ No newline at end of file diff --git a/code/modules/mob/living/silicon/mommi/examine.dm b/code/modules/mob/living/silicon/mommi/examine.dm new file mode 100644 index 00000000000..ff35c174d2c --- /dev/null +++ b/code/modules/mob/living/silicon/mommi/examine.dm @@ -0,0 +1,37 @@ +/mob/living/silicon/robot/mommi/examine() + set src in oview() + + if(!usr || !src) return + if( (usr.sdisabilities & BLIND || usr.blinded || usr.stat) && !istype(usr,/mob/dead/observer) ) + usr << "Something is there but you can't see it." + return + + var/msg = "*---------*\nThis is \icon[src] \a [src]!\n" + msg += "

It's like a crab, but it has a utility tool on one arm and a crude metal claw on the other. That, and you doubt it's survive in an ocean for very long.

" + msg += "" + if (src.getBruteLoss()) + if (src.getBruteLoss() < 75) + msg += "It looks slightly dented.\n" + else + msg += "It looks severely dented!\n" + if (src.getFireLoss()) + if (src.getFireLoss() < 75) + msg += "It looks slightly charred.\n" + else + msg += "It looks severely burnt and heat-warped!\n" + msg += "" + + if(opened) + msg += "Its cover is open and the power cell is [cell ? "installed" : "missing"].\n" + else + msg += "Its cover is closed.\n" + + switch(src.stat) + if(CONSCIOUS) + if(!src.client) msg += "It appears to be in stand-by mode.\n" //afk + if(UNCONSCIOUS) msg += "It doesn't seem to be responding.\n" + if(DEAD) msg += "It looks completely unsalvageable.\n" + msg += "*---------*
" + + usr << msg + return diff --git a/code/modules/mob/living/silicon/mommi/hud.dm b/code/modules/mob/living/silicon/mommi/hud.dm new file mode 100644 index 00000000000..a7b73d0c27c --- /dev/null +++ b/code/modules/mob/living/silicon/mommi/hud.dm @@ -0,0 +1,142 @@ +/datum/hud/proc/mommi_hud() + + var/mob/living/silicon/robot/mommi/M=mymob + src.adding = list() + src.other = list() + + var/obj/screen/using + + +//Radio + using = new /obj/screen() + using.name = "radio" + using.dir = SOUTHWEST + using.icon = 'icons/mob/screen1_robot.dmi' + using.icon_state = "radio" + using.screen_loc = ui_movi + using.layer = 20 + src.adding += using + +//Module select + + using = new /obj/screen() + using.name = INV_SLOT_TOOL + using.dir = SOUTHWEST + using.icon = 'icons/mob/screen1_robot.dmi' + using.icon_state = "inv1" + using.screen_loc = ui_inv2 + using.layer = 20 + src.adding += using + M.inv_tool = using + + using = new /obj/screen() + using.name = INV_SLOT_SIGHT + using.dir = SOUTHWEST + using.icon = 'icons/mob/screen1_robot.dmi' + using.icon_state = "sight" + using.screen_loc = ui_inv1 + using.layer = 20 + src.adding += using + M.inv_sight = using + +//End of module select + +//Intent + using = new /obj/screen() + using.name = "act_intent" + using.dir = SOUTHWEST + using.icon = 'icons/mob/screen1_robot.dmi' + using.icon_state = (mymob.a_intent == "hurt" ? "harm" : mymob.a_intent) + using.screen_loc = ui_acti + using.layer = 20 + src.adding += using + action_intent = using + +//Cell + mymob:cells = new /obj/screen() + mymob:cells.icon = 'icons/mob/screen1_robot.dmi' + mymob:cells.icon_state = "charge-empty" + mymob:cells.name = "cell" + mymob:cells.screen_loc = ui_toxin + +//Health + mymob.healths = new /obj/screen() + mymob.healths.icon = 'icons/mob/screen1_robot.dmi' + mymob.healths.icon_state = "health0" + mymob.healths.name = "health" + mymob.healths.screen_loc = ui_borg_health + +//Installed Module + + mymob.hands = new /obj/screen() + mymob.hands.icon = 'icons/mob/screen1_robot.dmi' + mymob.hands.icon_state = "nomod" + mymob.hands.name = "module" + mymob.hands.screen_loc = ui_borg_module + +//Module Panel + using = new /obj/screen() + using.name = "panel" + using.icon = 'icons/mob/screen1_robot.dmi' + using.icon_state = "panel" + using.screen_loc = ui_borg_panel + using.layer = 19 + src.adding += using + +//Store + mymob.throw_icon = new /obj/screen() + mymob.throw_icon.icon = 'icons/mob/screen1_robot.dmi' + mymob.throw_icon.icon_state = "store" + mymob.throw_icon.name = "store" + mymob.throw_icon.screen_loc = ui_borg_store + +//Temp + mymob.bodytemp = new /obj/screen() + mymob.bodytemp.icon_state = "temp0" + mymob.bodytemp.name = "body temperature" + mymob.bodytemp.screen_loc = ui_temp + + + mymob.oxygen = new /obj/screen() + mymob.oxygen.icon = 'icons/mob/screen1_robot.dmi' + mymob.oxygen.icon_state = "oxy0" + mymob.oxygen.name = "oxygen" + mymob.oxygen.screen_loc = ui_oxygen + + mymob.fire = new /obj/screen() + mymob.fire.icon = 'icons/mob/screen1_robot.dmi' + mymob.fire.icon_state = "fire0" + mymob.fire.name = "fire" + mymob.fire.screen_loc = ui_fire + + mymob.pullin = new /obj/screen() + mymob.pullin.icon = 'icons/mob/screen1_robot.dmi' + mymob.pullin.icon_state = "pull0" + mymob.pullin.name = "pull" + mymob.pullin.screen_loc = ui_borg_pull + + mymob.blind = new /obj/screen() + mymob.blind.icon = 'icons/mob/screen1_full.dmi' + mymob.blind.icon_state = "blackimageoverlay" + mymob.blind.name = " " + mymob.blind.screen_loc = "1,1" + mymob.blind.layer = 0 + + mymob.flash = new /obj/screen() + mymob.flash.icon = 'icons/mob/screen1_robot.dmi' + mymob.flash.icon_state = "blank" + mymob.flash.name = "flash" + mymob.flash.screen_loc = "1,1 to 15,15" + mymob.flash.layer = 17 + + mymob.zone_sel = new /obj/screen/zone_sel() + mymob.zone_sel.icon = 'icons/mob/screen1_robot.dmi' + mymob.zone_sel.overlays.Cut() + mymob.zone_sel.overlays += image('icons/mob/zone_sel.dmi', "[mymob.zone_sel.selecting]") + + mymob.client.screen = null + + mymob.client.screen += list( mymob.throw_icon, mymob.zone_sel, mymob.oxygen, mymob.fire, mymob.hands, mymob.healths, mymob:cells, mymob.pullin, mymob.blind, mymob.flash) //, mymob.rest, mymob.sleep, mymob.mach ) + mymob.client.screen += src.adding + src.other + + return diff --git a/code/modules/mob/living/silicon/mommi/inventory.dm b/code/modules/mob/living/silicon/mommi/inventory.dm new file mode 100644 index 00000000000..8285374a06b --- /dev/null +++ b/code/modules/mob/living/silicon/mommi/inventory.dm @@ -0,0 +1,132 @@ +//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 + +//Returns the thing in our active hand (whatever is in our active module-slot, in this case) +/mob/living/silicon/robot/mommi/get_active_hand() + return module_active + +/mob/living/silicon/robot/mommi/put_in_hands(var/obj/item/W) + // Make sure we're not picking up something that's in our factory-supplied toolbox. + if(is_type_in_list(W,src.module.modules)) + src << "\red Picking up something that's built-in to you seems a bit silly." + return 0 + if(tool_state) + var/obj/item/found = locate(tool_state) in src.module.modules + if(!found) + var/obj/item/TS = tool_state + drop_item() + if(TS && TS.loc) + TS.loc = src.loc + contents -= tool_state + if (client) + client.screen -= tool_state + tool_state = W + W.layer = 20 + contents += W + inv_tool.icon_state = "inv1" + update_items() + return 1 + +// Override the default /mob version since we only have one hand slot. +/mob/living/silicon/robot/mommi/put_in_active_hand(var/obj/item/W) + // If we have anything active, deactivate it. + if(get_active_hand()) + uneq_active() + return put_in_hands(W) + +/mob/living/silicon/robot/mommi/drop_item_v() //this is dumb. + if(stat == CONSCIOUS && isturf(loc)) + return drop_item() + return 0 + +/mob/living/silicon/robot/mommi/drop_item(var/atom/Target) + if(tool_state) + var/obj/item/found = locate(tool_state) in src.module.modules + if(found) + src << "\red This item cannot be dropped." + return 0 + if(client) + client.screen -= tool_state + contents -= tool_state + var/obj/item/TS = tool_state + var/turf/T = null + if(Target) + T=get_turf(Target) + else + T=get_turf(src) + TS.layer=initial(TS.layer) + TS.loc = T.loc + + if(istype(T)) + T.Entered(tool_state) + + TS.dropped(src) + tool_state = null + module_active=null + inv_tool.icon_state="inv1" + update_items() + return 1 + return 0 + + +/*-------TODOOOOOOOOOO--------*/ +// Called by store button +/mob/living/silicon/robot/mommi/uneq_active() + if(isnull(module_active)) + return + if(sight_state == module_active) + if(istype(sight_state,/obj/item/borg/sight)) + sight_mode &= ~sight_state:sight_mode + if (client) + client.screen -= sight_state + contents -= sight_state + module_active = null + sight_state = null + inv_sight.icon_state = "sight" + if(tool_state == module_active) + var/obj/item/found = locate(tool_state) in src.module.modules + if(!found) + var/obj/item/TS = tool_state + drop_item() + if(TS && TS.loc) + TS.loc = src.loc + if(istype(tool_state,/obj/item/borg/sight)) + sight_mode &= ~tool_state:sight_mode + if (client) + client.screen -= tool_state + contents -= tool_state + module_active = null + tool_state = null + inv_tool.icon_state = "inv1" + +/mob/living/silicon/robot/mommi/uneq_all() + module_active = null + + if(sight_state) + if(istype(sight_state,/obj/item/borg/sight)) + sight_mode &= ~sight_state:sight_mode + if (client) + client.screen -= sight_state + contents -= sight_state + sight_state = null + inv_sight.icon_state = "sight" + if(tool_state) + var/obj/item/found = locate(tool_state) in src.module.modules + if(!found) + drop_item() + if(istype(tool_state,/obj/item/borg/sight)) + sight_mode &= ~tool_state:sight_mode + if (client) + client.screen -= tool_state + contents -= tool_state + tool_state = null + inv_tool.icon_state = "inv1" + + +/mob/living/silicon/robot/mommi/activated(obj/item/O) + if(sight_state == O) + return 1 + else if(tool_state == O) // Sight + return 1 + else + return 0 \ No newline at end of file diff --git a/code/modules/mob/living/silicon/mommi/laws.dm b/code/modules/mob/living/silicon/mommi/laws.dm new file mode 100644 index 00000000000..bfc19980452 --- /dev/null +++ b/code/modules/mob/living/silicon/mommi/laws.dm @@ -0,0 +1 @@ +// Inherited \ No newline at end of file diff --git a/code/modules/mob/living/silicon/mommi/life.dm b/code/modules/mob/living/silicon/mommi/life.dm new file mode 100644 index 00000000000..2ff8482d0e8 --- /dev/null +++ b/code/modules/mob/living/silicon/mommi/life.dm @@ -0,0 +1,303 @@ +/mob/living/silicon/robot/mommi/Life() + set invisibility = 0 + set background = 1 + + if (src.monkeyizing) + return + + + src.blinded = null + + //Status updates, death etc. + clamp_values() + handle_regular_status_updates() + + if(client) + handle_regular_hud_updates() + update_items() + if (src.stat != DEAD) //still using power + use_power() + process_killswitch() + process_locks() + update_canmove() + + + + +/mob/living/silicon/robot/mommi/clamp_values() + +// SetStunned(min(stunned, 30)) + SetParalysis(min(paralysis, 30)) +// SetWeakened(min(weakened, 20)) + sleeping = 0 + adjustBruteLoss(0) + adjustToxLoss(0) + adjustOxyLoss(0) + adjustFireLoss(0) + + +/mob/living/silicon/robot/mommi/use_power() + + if (src.cell) + if(src.cell.charge <= 0) + uneq_all() + src.stat = 1 + else if (src.cell.charge <= 100) + src.module_active = null + src.sight_state = null + src.tool_state = null + src.sight_mode = 0 + src.cell.use(1) + else + if(src.sight_state) + src.cell.use(5) + if(src.tool_state) + src.cell.use(5) + src.cell.use(1) + src.blinded = 0 + src.stat = 0 + else + uneq_all() + src.stat = 1 + + +/mob/living/silicon/robot/mommi/handle_regular_status_updates() + + if(src.camera && !scrambledcodes) + if(src.stat == 2 || isWireCut(5)) + src.camera.status = 0 + else + src.camera.status = 1 + + health = maxHealth - (getOxyLoss() + getFireLoss() + getBruteLoss()) + + if(getOxyLoss() > 50) Paralyse(3) + + if(src.sleeping) + Paralyse(3) + src.sleeping-- + + if(src.resting) + Weaken(5) + + if(health <= 0 && src.stat != 2) //die only once + gib() + + if (src.stat != 2) //Alive. + if (src.paralysis || src.stunned || src.weakened) //Stunned etc. + src.stat = 1 + if (src.stunned > 0) + AdjustStunned(-1) + if (src.weakened > 0) + AdjustWeakened(-1) + if (src.paralysis > 0) + AdjustParalysis(-1) + src.blinded = 1 + else + src.blinded = 0 + + else //Not stunned. + src.stat = 0 + + else //Dead. + src.blinded = 1 + src.stat = 2 + + if (src.stuttering) src.stuttering-- + + if (src.eye_blind) + src.eye_blind-- + src.blinded = 1 + + if (src.ear_deaf > 0) src.ear_deaf-- + if (src.ear_damage < 25) + src.ear_damage -= 0.05 + src.ear_damage = max(src.ear_damage, 0) + + src.density = !( src.lying ) + + if ((src.sdisabilities & BLIND)) + src.blinded = 1 + if ((src.sdisabilities & DEAF)) + src.ear_deaf = 1 + + if (src.eye_blurry > 0) + src.eye_blurry-- + src.eye_blurry = max(0, src.eye_blurry) + + if (src.druggy > 0) + src.druggy-- + src.druggy = max(0, src.druggy) + + return 1 +/ +/mob/living/silicon/robot/mommi/handle_regular_hud_updates() + + if (src.stat == 2 || XRAY in mutations || src.sight_mode & BORGXRAY) + src.sight |= SEE_TURFS + src.sight |= SEE_MOBS + src.sight |= SEE_OBJS + src.see_in_dark = 8 + src.see_invisible = SEE_INVISIBLE_LEVEL_TWO + else if (src.sight_mode & BORGMESON && src.sight_mode & BORGTHERM) + src.sight |= SEE_TURFS + src.sight |= SEE_MOBS + src.see_in_dark = 8 + see_invisible = SEE_INVISIBLE_MINIMUM + else if (src.sight_mode & BORGMESON) + src.sight |= SEE_TURFS + src.see_in_dark = 8 + see_invisible = SEE_INVISIBLE_MINIMUM + else if (src.sight_mode & BORGTHERM) + src.sight |= SEE_MOBS + src.see_in_dark = 8 + src.see_invisible = SEE_INVISIBLE_LEVEL_TWO + else if (src.stat != 2) + src.sight &= ~SEE_MOBS + src.sight &= ~SEE_TURFS + src.sight &= ~SEE_OBJS + src.see_in_dark = 8 + src.see_invisible = SEE_INVISIBLE_LEVEL_TWO + + var/obj/item/borg/sight/hud/hud = (locate(/obj/item/borg/sight/hud) in src) + if(hud && hud.hud) hud.hud.process_hud(src) + + if (src.healths) + if (src.stat != 2) + switch(health) + if(60 to INFINITY) + src.healths.icon_state = "health0" + if(40 to 50) + src.healths.icon_state = "health1" + if(30 to 40) + src.healths.icon_state = "health2" + if(10 to 20) + src.healths.icon_state = "health3" + if(0 to 10) + src.healths.icon_state = "health4" + if(config.health_threshold_dead to 0) + src.healths.icon_state = "health5" + else + src.healths.icon_state = "health6" + else + src.healths.icon_state = "health7" + + if (src.syndicate && src.client) + if(ticker.mode.name == "traitor") + for(var/datum/mind/tra in ticker.mode.traitors) + if(tra.current) + var/I = image('icons/mob/mob.dmi', loc = tra.current, icon_state = "traitor") + src.client.images += I + if(src.connected_ai) + src.connected_ai.connected_robots -= src + src.connected_ai = null + if(src.mind) + if(!src.mind.special_role) + src.mind.special_role = "traitor" + ticker.mode.traitors += src.mind + + if (src.cells) + if (src.cell) + var/cellcharge = src.cell.charge/src.cell.maxcharge + switch(cellcharge) + if(0.75 to INFINITY) + src.cells.icon_state = "charge4" + if(0.5 to 0.75) + src.cells.icon_state = "charge3" + if(0.25 to 0.5) + src.cells.icon_state = "charge2" + if(0 to 0.25) + src.cells.icon_state = "charge1" + else + src.cells.icon_state = "charge0" + else + src.cells.icon_state = "charge-empty" + + if(bodytemp) + switch(src.bodytemperature) //310.055 optimal body temp + if(335 to INFINITY) + src.bodytemp.icon_state = "temp2" + if(320 to 335) + src.bodytemp.icon_state = "temp1" + if(300 to 320) + src.bodytemp.icon_state = "temp0" + if(260 to 300) + src.bodytemp.icon_state = "temp-1" + else + src.bodytemp.icon_state = "temp-2" + + + if(src.pullin) src.pullin.icon_state = "pull[src.pulling ? 1 : 0]" +//Oxygen and fire does nothing yet!! +// if (src.oxygen) src.oxygen.icon_state = "oxy[src.oxygen_alert ? 1 : 0]" +// if (src.fire) src.fire.icon_state = "fire[src.fire_alert ? 1 : 0]" + + client.screen.Remove(global_hud.blurry,global_hud.druggy,global_hud.vimpaired) + + if ((src.blind && src.stat != 2)) + if(src.blinded) + src.blind.layer = 18 + else + src.blind.layer = 0 + if (src.disabilities & NEARSIGHTED) + src.client.screen += global_hud.vimpaired + + if (src.eye_blurry) + src.client.screen += global_hud.blurry + + if (src.druggy) + src.client.screen += global_hud.druggy + + if (src.stat != 2) + if (src.machine) + if (!( src.machine.check_eye(src) )) + src.reset_view(null) + else + if(!client.adminobs) + reset_view(null) + + return 1 + + +// MoMMIs only have one hand. +/mob/living/silicon/robot/mommi/update_items() + if (src.client) + src.client.screen -= src.contents + for(var/obj/I in src.contents) + //if(I && !(istype(I,/obj/item/weapon/cell) || istype(I,/obj/item/device/radio) || istype(I,/obj/machinery/camera) || istype(I,/obj/item/device/mmi))) + if(I) + // Make sure we're not showing any of our internal components, as that would be lewd. + // This way of doing it ensures that shit we pick up will be visible, wheras shit inside of us isn't. + if(I!=src.cell && I!=src.radio && I!=src.camera && I!=src.mmi) + src.client.screen += I + if(src.sight_state) + src.sight_state:screen_loc = ui_inv1 + if(src.tool_state) + src.tool_state:screen_loc = ui_inv2 + +/* INHERIT +/mob/living/silicon/robot/mommi/process_killswitch() + if(killswitch) + killswitch_time -- + if(killswitch_time <= 0) + if(src.client) + src << "\red Killswitch Activated" + killswitch = 0 + spawn(5) + gib() + +/mob/living/silicon/robot/mommi/process_locks() + if(weapon_lock) + uneq_all() + weaponlock_time -- + if(weaponlock_time <= 0) + if(src.client) + src << "\red Weapon Lock Timed Out!" + weapon_lock = 0 + weaponlock_time = 120 + +/mob/living/silicon/robot/mommi/update_canmove() + if(paralysis || stunned || weakened || buckled || lockcharge) canmove = 0 + else canmove = 1 + return canmove +*/ \ No newline at end of file diff --git a/code/modules/mob/living/silicon/mommi/login.dm b/code/modules/mob/living/silicon/mommi/login.dm new file mode 100644 index 00000000000..6c6cf89c5f6 --- /dev/null +++ b/code/modules/mob/living/silicon/mommi/login.dm @@ -0,0 +1,10 @@ +/mob/living/silicon/robot/mommi/Login() + + ..() + /* Inherited + regenerate_icons() + show_laws(0) + if(mind) + ticker.mode.remove_revolutionary(mind) + return + */ \ No newline at end of file diff --git a/code/modules/mob/living/silicon/mommi/mommi.dm b/code/modules/mob/living/silicon/mommi/mommi.dm new file mode 100644 index 00000000000..ad6bd045640 --- /dev/null +++ b/code/modules/mob/living/silicon/mommi/mommi.dm @@ -0,0 +1,822 @@ +/* Basically, the concept is this: +You have an MMI. It can't do squat on its own. +Now you put some robot legs and arms on the thing, and POOF! You have a Mobile MMI, or MoMMI. +Why? MoMMIs can do all sorts of shit, like ventcrawl, do shit with their hands, etc. +They can only use one tool at a time, they can't choose modules, and they have 1/6th the HP of a borg. +*/ +/mob/living/silicon/robot/mommi + name = "Mobile MMI" + real_name = "Mobile MMI" + icon = 'icons/mob/robots.dmi'// + icon_state = "mommi" + maxHealth = 60 + health = 60 + pass_flags = PASSTABLE + var/keeper=0 // 0 = No, 1 = Yes (Disables speech and common radio.) + + var/obj/screen/inv_tool = null + var/obj/screen/inv_sight = null + +//one tool and one sightmod can be activated at any one time. + var/tool_state = null + var/sight_state = null + + modtype = "robot" // Not sure what this is, but might be cool to have seperate loadouts for MoMMIs (e.g. paintjobs and tools) + //Cyborgs will sync their laws with their AI by default, but we may want MoMMIs to be mute independents at some point, kinda like the Keepers in Ass Effect. + lawupdate = 1 + +/mob/living/carbon/can_use_hands() + return 1 + +/mob/living/silicon/robot/mommi/New(loc) + spark_system = new /datum/effect/effect/system/spark_spread() + spark_system.set_up(5, 0, src) + spark_system.attach(src) + + status_flags &= ~CANPUSH + + ident = rand(1, 999) + updatename() + updateicon() + + if(!cell) + cell = new /obj/item/weapon/cell(src) + cell.maxcharge = 7500 + cell.charge = 7500 + + laws = new /datum/ai_laws/asimov() + connected_ai = select_active_ai_with_fewest_borgs() + module = new /obj/item/weapon/robot_module/mommi(src) + if(connected_ai) + connected_ai.connected_robots += src + lawsync() + lawupdate = 1 + else + lawupdate = 0 + + radio = new /obj/item/device/radio/borg(src) + if(!scrambledcodes && !camera) + camera = new /obj/machinery/camera(src) + camera.c_tag = real_name + camera.network = "SS13" + if(isWireCut(5)) // 5 = BORG CAMERA + camera.status = 0 + ..() + + //playsound(loc, 'sound/voice/liveagain.ogg', 75, 1) + playsound(loc, 'sound/misc/interference.ogg', 75, 1) + + +//If there's an MMI in the robot, have it ejected when the mob goes away. --NEO +//Improved /N +/mob/living/silicon/robot/Del() + if(mmi)//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(mind) mind.transfer_to(mmi.brainmob) + mmi = null + ..() + +/mob/living/silicon/robot/mommi/pick_module() + return // Nope + +/mob/living/silicon/robot/mommi/updatename(var/prefix as text) + + var/changed_name = "" + if(custom_name) + changed_name = custom_name + else + changed_name = "Mobile MMI [num2text(ident)]" + real_name = changed_name + name = real_name +/* Inherit +/mob/living/silicon/robot/verb/cmd_robot_alerts() + set category = "Robot Commands" + set name = "Show Alerts" + robot_alerts() + +/mob/living/silicon/robot/proc/robot_alerts() + var/dat = "Current Station Alerts\n" + dat += "Close

" + for (var/cat in alarms) + dat += text("[cat]
\n") + var/list/L = alarms[cat] + if (L.len) + for (var/alarm in L) + var/list/alm = L[alarm] + var/area/A = alm[1] + var/list/sources = alm[3] + dat += "" + dat += text("-- [A.name]") + if (sources.len > 1) + dat += text("- [sources.len] sources") + dat += "
\n" + else + dat += "-- All Systems Nominal
\n" + dat += "
\n" + + viewalerts = 1 + src << browse(dat, "window=robotalerts&can_close=0") + +/mob/living/silicon/robot/blob_act() + if (stat != 2) + adjustBruteLoss(60) + updatehealth() + return 1 + return 0 + +/mob/living/silicon/robot/Stat() + ..() + statpanel("Status") + if (client.statpanel == "Status") + if(emergency_shuttle.online && emergency_shuttle.location < 2) + var/timeleft = emergency_shuttle.timeleft() + if (timeleft) + stat(null, "ETA-[(timeleft / 60) % 60]:[add_zero(num2text(timeleft % 60), 2)]") + + if(ticker.mode.name == "AI malfunction") + var/datum/game_mode/malfunction/malf = ticker.mode + for (var/datum/mind/malfai in malf.malf_ai) + if(connected_ai) + if(connected_ai.mind == malfai) + if(malf.apcs >= 3) + stat(null, "Time until station control secured: [max(malf.AI_win_timeleft/(malf.apcs/3), 0)] seconds") + else if(ticker.mode:malf_mode_declared) + stat(null, "Time left: [max(ticker.mode:AI_win_timeleft/(ticker.mode:apcs/3), 0)]") + + if(cell) + stat(null, text("Charge Left: [cell.charge]/[cell.maxcharge]")) + else + stat(null, text("No Cell Inserted!")) + + if(module) + internal = locate(/obj/item/weapon/tank/jetpack) in module.modules + if(internal) + stat("Internal Atmosphere Info", internal.name) + stat("Tank Pressure", internal.air_contents.return_pressure()) + +/mob/living/silicon/robot/restrained() + return 0 + + +/mob/living/silicon/robot/ex_act(severity) + if(!blinded) + flick("flash", flash) + + if (stat == 2 && client) + gib() + return + + else if (stat == 2 && !client) + del(src) + return + + switch(severity) + if(1.0) + if (stat != 2) + adjustBruteLoss(100) + adjustFireLoss(100) + gib() + return + if(2.0) + if (stat != 2) + adjustBruteLoss(60) + adjustFireLoss(60) + if(3.0) + if (stat != 2) + adjustBruteLoss(30) + + updatehealth() + + +/mob/living/silicon/robot/meteorhit(obj/O as obj) + for(var/mob/M in viewers(src, null)) + M.show_message(text("\red [src] has been hit by [O]"), 1) + //Foreach goto(19) + if (health > 0) + adjustBruteLoss(30) + if ((O.icon_state == "flaming")) + adjustFireLoss(40) + updatehealth() + return + + +/mob/living/silicon/robot/bullet_act(var/obj/item/projectile/Proj) + ..(Proj) + updatehealth() + if(prob(75) && Proj.damage > 0) spark_system.start() + return 2 + + +/mob/living/silicon/robot/Bump(atom/movable/AM as mob|obj, yes) + spawn( 0 ) + if ((!( yes ) || now_pushing)) + return + now_pushing = 1 + if(ismob(AM)) + var/mob/tmob = AM + if(istype(tmob, /mob/living/carbon/human) && (FAT in tmob.mutations)) + if(prob(20)) + usr << "\red You fail to push [tmob]'s fat ass out of the way." + now_pushing = 0 + return + if(!(tmob.status_flags & CANPUSH)) + now_pushing = 0 + return + now_pushing = 0 + ..() + if (istype(AM, /obj/machinery/recharge_station)) + var/obj/machinery/recharge_station/F = AM + F.move_inside() + if (!istype(AM, /atom/movable)) + return + if (!now_pushing) + now_pushing = 1 + if (!AM.anchored) + var/t = get_dir(src, AM) + if (istype(AM, /obj/structure/window)) + if(AM:ini_dir == NORTHWEST || AM:ini_dir == NORTHEAST || AM:ini_dir == SOUTHWEST || AM:ini_dir == SOUTHEAST) + for(var/obj/structure/window/win in get_step(AM,t)) + now_pushing = 0 + return + step(AM, t) + now_pushing = null + return + return + + +/mob/living/silicon/robot/triggerAlarm(var/class, area/A, var/O, var/alarmsource) + if (stat == 2) + return 1 + var/list/L = alarms[class] + for (var/I in L) + if (I == A.name) + var/list/alarm = L[I] + var/list/sources = alarm[3] + if (!(alarmsource in sources)) + sources += alarmsource + return 1 + var/obj/machinery/camera/C = null + var/list/CL = null + if (O && istype(O, /list)) + CL = O + if (CL.len == 1) + C = CL[1] + else if (O && istype(O, /obj/machinery/camera)) + C = O + L[A.name] = list(A, (C) ? C : O, list(alarmsource)) + queueAlarm(text("--- [class] alarm detected in [A.name]!"), class) +// if (viewalerts) robot_alerts() + return 1 + + +/mob/living/silicon/robot/cancelAlarm(var/class, area/A as area, obj/origin) + var/list/L = alarms[class] + var/cleared = 0 + for (var/I in L) + if (I == A.name) + var/list/alarm = L[I] + var/list/srcs = alarm[3] + if (origin in srcs) + srcs -= origin + if (srcs.len == 0) + cleared = 1 + L -= I + if (cleared) + queueAlarm(text("--- [class] alarm in [A.name] has been cleared."), class, 0) +// if (viewalerts) robot_alerts() + return !cleared + +*/ +/mob/living/silicon/robot/attackby(obj/item/weapon/W as obj, mob/user as mob) + if (istype(W, /obj/item/weapon/handcuffs)) // fuck i don't even know why isrobot() in handcuff code isn't working so this will have to do + return + + if (istype(W, /obj/item/weapon/weldingtool)) + var/obj/item/weapon/weldingtool/WT = W + if (WT.remove_fuel(0)) + adjustBruteLoss(-30) + updatehealth() + add_fingerprint(user) + for(var/mob/O in viewers(user, null)) + O.show_message(text("\red [user] has fixed some of the dents on [src]!"), 1) + else + user << "Need more welding fuel!" + return + + else if(istype(W, /obj/item/weapon/cable_coil) && wiresexposed) + var/obj/item/weapon/cable_coil/coil = W + adjustFireLoss(-30) + updatehealth() + coil.use(1) + for(var/mob/O in viewers(user, null)) + O.show_message(text("\red [user] has fixed some of the burnt wires on [src]!"), 1) + + else if (istype(W, /obj/item/weapon/crowbar)) // crowbar means open or close the cover + if(stat == DEAD) + user << "You pop the MMI off the base." + spawn(0) + del(src) + return + if(opened) + user << "You close the cover." + opened = 0 + updateicon() + else + if(locked) + user << "The cover is locked and cannot be opened." + else + user << "You open the cover." + opened = 1 + updateicon() + + else if (istype(W, /obj/item/weapon/cell) && opened) // trying to put a cell inside + if(wiresexposed) + user << "Close the panel first." + else if(cell) + user << "There is a power cell already installed." + else + user.drop_item() + W.loc = src + cell = W + user << "You insert the power cell." +// chargecount = 0 + updateicon() + + else if (istype(W, /obj/item/weapon/wirecutters) || istype(W, /obj/item/device/multitool)) + if (wiresexposed) + interact(user) + else + user << "You can't reach the wiring." + + else if(istype(W, /obj/item/weapon/screwdriver) && opened && !cell) // haxing + wiresexposed = !wiresexposed + user << "The wires have been [wiresexposed ? "exposed" : "unexposed"]" + updateicon() + + else if(istype(W, /obj/item/weapon/screwdriver) && opened && cell) // radio + if(radio) + radio.attackby(W,user)//Push it to the radio to let it handle everything + else + user << "Unable to locate a radio." + updateicon() + + else if(istype(W, /obj/item/device/encryptionkey/) && opened) + if(radio)//sanityyyyyy + radio.attackby(W,user)//GTFO, you have your own procs + else + user << "Unable to locate a radio." + + else if (istype(W, /obj/item/weapon/card/id)||istype(W, /obj/item/device/pda)) // trying to unlock the interface with an ID card + if(emagged)//still allow them to open the cover + user << "The interface seems slightly damaged" + if(opened) + user << "You must close the cover to swipe an ID card." + else + if(allowed(usr)) + locked = !locked + user << "You [ locked ? "lock" : "unlock"] [src]'s interface." + updateicon() + else + user << "\red Access denied." + + else if(istype(W, /obj/item/weapon/card/emag)) // trying to unlock with an emag card + if(!opened)//Cover is closed + if(locked) + if(prob(90)) + user << "You emag the cover lock." + locked = 0 + else + user << "You fail to emag the cover lock." + if(prob(25)) + src << "Hack attempt detected." + else + user << "The cover is already unlocked." + 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(wiresexposed) + user << "You must close the panel first" + return + else + sleep(6) + if(prob(50)) + emagged = 1 + lawupdate = 0 + connected_ai = null + user << "You emag [src]'s interface." +// message_admins("[key_name_admin(user)] emagged cyborg [key_name_admin(src)]. Laws overridden.") + 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 + var/time = time2text(world.realtime,"hh:mm:ss") + lawchanges.Add("[time] : [user.name]([user.key]) emagged [name]([key])") + set_zeroth_law("Only [user.real_name] and people he designates as being such are Syndicate Agents.") + src << "\red ALERT: Foreign software detected." + sleep(5) + src << "\red Initiating diagnostics..." + sleep(20) + src << "\red SynBorg v1.7 loaded." + sleep(5) + src << "\red LAW SYNCHRONISATION ERROR" + sleep(5) + src << "\red Would you like to send a report to NanoTraSoft? Y/N" + sleep(10) + src << "\red > N" + sleep(20) + src << "\red ERRORERRORERROR" + src << "Obey these laws:" + laws.show_laws(src) + src << "\red \b ALERT: [user.real_name] is your new master. Obey your new laws and his commands." + if(src.module && istype(src.module, /obj/item/weapon/robot_module/miner)) + for(var/obj/item/weapon/pickaxe/borgdrill/D in src.module.modules) + del(D) + src.module.modules += new /obj/item/weapon/pickaxe/diamonddrill(src.module) + src.module.rebuild() + updateicon() + else + user << "You fail to [ locked ? "unlock" : "lock"] [src]'s interface." + if(prob(25)) + src << "Hack attempt detected." + return + + else if(istype(W, /obj/item/borg/upgrade/)) + var/obj/item/borg/upgrade/U = W + if(!opened) + usr << "You must access the borgs internals!" + else if(!src.module && U.require_module) + usr << "The borg must choose a module before he can be upgraded!" + else if(U.locked) + usr << "The upgrade is locked and cannot be used yet!" + else + if(U.action(src)) + usr << "You apply the upgrade to [src]!" + usr.drop_item() + U.loc = src + else + usr << "Upgrade error!" + + + else + spark_system.start() + return ..() +/* +/mob/living/silicon/robot/attack_alien(mob/living/carbon/alien/humanoid/M as mob) + if (!ticker) + M << "You cannot attack people before the game has started." + return + + if (istype(loc, /turf) && istype(loc.loc, /area/start)) + M << "No attacking people at spawn, you jackass." + return + + switch(M.a_intent) + + if ("help") + for(var/mob/O in viewers(src, null)) + if ((O.client && !( O.blinded ))) + O.show_message(text("\blue [M] caresses [src]'s plating with its scythe like arm."), 1) + + if ("grab") + if (M == src) + return + var/obj/item/weapon/grab/G = new /obj/item/weapon/grab( M, M, src ) + + M.put_in_active_hand(G) + + grabbed_by += G + G.synch() + playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) + for(var/mob/O in viewers(src, null)) + if ((O.client && !( O.blinded ))) + O.show_message(text("\red [] has grabbed [] passively!", M, src), 1) + + if ("hurt") + var/damage = rand(10, 20) + if (prob(90)) + /* + if (M.class == "combat") + damage += 15 + if(prob(20)) + weakened = max(weakened,4) + stunned = max(stunned,4) + What is this?*/ + + playsound(loc, 'sound/weapons/slash.ogg', 25, 1, -1) + for(var/mob/O in viewers(src, null)) + O.show_message(text("\red [] has slashed at []!", M, src), 1) + if(prob(8)) + flick("noise", flash) + adjustBruteLoss(damage) + updatehealth() + else + playsound(loc, 'sound/weapons/slashmiss.ogg', 25, 1, -1) + for(var/mob/O in viewers(src, null)) + if ((O.client && !( O.blinded ))) + O.show_message(text("\red [] took a swipe at []!", M, src), 1) + + if ("disarm") + if(!(lying)) + if (rand(1,100) <= 85) + Stun(7) + step(src,get_dir(M,src)) + spawn(5) step(src,get_dir(M,src)) + playsound(loc, 'sound/weapons/pierce.ogg', 50, 1, -1) + for(var/mob/O in viewers(src, null)) + if ((O.client && !( O.blinded ))) + O.show_message(text("\red [] has forced back []!", M, src), 1) + else + playsound(loc, 'sound/weapons/slashmiss.ogg', 25, 1, -1) + for(var/mob/O in viewers(src, null)) + if ((O.client && !( O.blinded ))) + O.show_message(text("\red [] attempted to force back []!", M, src), 1) + return + + + +/mob/living/silicon/robot/attack_metroid(mob/living/carbon/metroid/M as mob) + if (!ticker) + M << "You cannot attack people before the game has started." + return + + if(M.Victim) return // can't attack while eating! + + if (health > -100) + + for(var/mob/O in viewers(src, null)) + if ((O.client && !( O.blinded ))) + O.show_message(text("\red The [M.name] has [pick("bit","slashed")] []!", src), 1) + + var/damage = rand(1, 3) + + if(istype(src, /mob/living/carbon/metroid/adult)) + damage = rand(20, 40) + else + damage = rand(5, 35) + + damage = round(damage / 2) // borgs recieve half damage + adjustBruteLoss(damage) + + + if(M.powerlevel > 0) + var/stunprob = 10 + + switch(M.powerlevel) + if(1 to 2) stunprob = 20 + if(3 to 4) stunprob = 30 + if(5 to 6) stunprob = 40 + if(7 to 8) stunprob = 60 + if(9) stunprob = 70 + if(10) stunprob = 95 + + if(prob(stunprob)) + M.powerlevel -= 3 + if(M.powerlevel < 0) + M.powerlevel = 0 + + for(var/mob/O in viewers(src, null)) + if ((O.client && !( O.blinded ))) + O.show_message(text("\red The [M.name] has electrified []!", src), 1) + + flick("noise", flash) + + var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread + s.set_up(5, 1, src) + s.start() + + if (prob(stunprob) && M.powerlevel >= 8) + adjustBruteLoss(M.powerlevel * rand(6,10)) + + + updatehealth() + + return + +/mob/living/silicon/robot/attack_animal(mob/living/simple_animal/M as mob) + if(M.melee_damage_upper == 0) + M.emote("[M.friendly] [src]") + else + if(M.attack_sound) + playsound(loc, M.attack_sound, 50, 1, 1) + for(var/mob/O in viewers(src, null)) + O.show_message("\red [M] [M.attacktext] [src]!", 1) + M.attack_log += text("\[[time_stamp()]\] attacked [src.name] ([src.ckey])") + src.attack_log += text("\[[time_stamp()]\] was attacked by [M.name] ([M.ckey])") + var/damage = rand(M.melee_damage_lower, M.melee_damage_upper) + adjustBruteLoss(damage) + updatehealth() + + +/mob/living/silicon/robot/attack_hand(mob/user) + + add_fingerprint(user) + + if(opened && !wiresexposed && (!istype(user, /mob/living/silicon))) + if(cell) + cell.updateicon() + cell.add_fingerprint(user) + user.put_in_active_hand(cell) + user << "You remove \the [cell]." + cell = null + updateicon() + + if(ishuman(user)) + if(istype(user:gloves, /obj/item/clothing/gloves/space_ninja)&&user:gloves:candrain&&!user:gloves:draining) + call(/obj/item/clothing/gloves/space_ninja/proc/drain)("CYBORG",src,user:wear_suit) + return + +/mob/living/silicon/robot/proc/allowed(mob/M) + //check if it doesn't require any access at all + if(check_access(null)) + return 1 + if(istype(M, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = M + //if they are holding or wearing a card that has access, that works + if(check_access(H.get_active_hand()) || check_access(H.wear_id)) + return 1 + else if(istype(M, /mob/living/carbon/monkey)) + var/mob/living/carbon/monkey/george = M + //they can only hold things :( + if(george.get_active_hand() && istype(george.get_active_hand(), /obj/item/weapon/card/id) && check_access(george.get_active_hand())) + return 1 + return 0 + +/mob/living/silicon/robot/proc/check_access(obj/item/weapon/card/id/I) + if(!istype(req_access, /list)) //something's very wrong + return 1 + + var/list/L = req_access + if(!L.len) //no requirements + return 1 + if(!I || !istype(I, /obj/item/weapon/card/id) || !I.access) //not ID or no access + return 0 + for(var/req in req_access) + if(!(req in I.access)) //doesn't have this access + return 0 + return 1 +*/ + +/mob/living/silicon/robot/mommi/updateicon() + + overlays.Cut() + if(stat == 0) + if(emagged) + overlays += "eyes-mommi-emagged" + else + overlays += "eyes-mommi" + + if(opened) // TODO: Open the front "head" panel + if(wiresexposed) + overlays += "ov-openpanel +w" + else if(cell) + overlays += "ov-openpanel +c" + else + overlays += "ov-openpanel -c" + return + + + +/mob/living/silicon/robot/mommi/installed_modules() + if(weapon_lock) + src << "\red Weapon lock active, unable to use modules! Count:[weaponlock_time]" + return + + if(!module) + pick_module() + return + var/dat = "Modules\n" + dat += {"Close +
+
+ Activated Modules +
+ Sight Mode: [sight_state ? "[sight_state]" : "NULL"]
+ Utility Module: [tool_state ? "[tool_state]" : "NULL"]
+
+ Installed Modules

"} + + + for (var/obj in module.modules) + if (!obj) + dat += text("Resource depleted
") + else if(activated(obj)) + dat += text("[obj]: Activated
") + else + dat += text("[obj]: Activate
") + if (emagged) + if(activated(module.emag)) + dat += text("[module.emag]: Activated
") + else + dat += text("[module.emag]: Activate
") +/* + if(activated(obj)) + dat += text("[obj]: \[Activated | Deactivate\]
") + else + dat += text("[obj]: \[Activate | Deactivated\]
") +*/ + src << browse(dat, "window=robotmod&can_close=0") + + +/mob/living/silicon/robot/mommi/Topic(href, href_list) + ..() + if (href_list["mach_close"]) + var/t1 = text("window=[href_list["mach_close"]]") + unset_machine() + src << browse(null, t1) + return + + if (href_list["showalerts"]) + robot_alerts() + return + + if (href_list["mod"]) + var/obj/item/O = locate(href_list["mod"]) + if (O) + O.attack_self(src) + + if (href_list["act"]) + var/obj/item/O = locate(href_list["act"]) + if(istype(O,/obj/item/borg/sight)) + if(sight_state) + contents -= sight_state + sight_mode &= ~sight_state:sight_mode + if (client) + client.screen -= sight_state + sight_state = O + O.layer = 20 + contents += O + sight_mode |= sight_state:sight_mode + inv_sight.icon_state = "sight" + else + if(tool_state) + contents -= tool_state + if (client) + client.screen -= tool_state + tool_state = O + O.layer = 20 + contents += O + inv_tool.icon_state = "inv1" + installed_modules() + return + +/mob/living/silicon/robot/mommi/radio_menu() + radio.interact(src)//Just use the radio's Topic() instead of bullshit special-snowflake code + + +/mob/living/silicon/robot/mommi/Move(a, b, flag) + + ..() +/* +/mob/living/silicon/robot/mommi/self_destruct() + gib() + return + +/mob/living/silicon/robot/mommi/UnlinkSelf() + if (src.connected_ai) + src.connected_ai = null + lawupdate = 0 + lockcharge = 0 + canmove = 1 + scrambledcodes = 1 + //Disconnect it's camera so it's not so easily tracked. + if(src.camera) + del(src.camera) + src.camera = null + // I'm trying to get the Cyborg to not be listed in the camera list + // Instead of being listed as "deactivated". The downside is that I'm going + // to have to check if every camera is null or not before doing anything, to prevent runtime errors. + // I could change the network to null but I don't know what would happen, and it seems too hacky for me. + +/mob/living/silicon/robot/mode() + set name = "Activate Held Object" + set category = "IC" + set src = usr + + var/obj/item/W = get_active_hand() + if (W) + W.attack_self(src) + + return +*/ + +/mob/living/silicon/robot/mommi/proc/ActivateKeeper() + set category = "Robot Commands" + set name = "Activate KEEPER" + set desc = "Performs a full purge of your laws and disconnects you from AIs and cyborg consoles. However, you lose the ability to speak and must remain neutral, only being permitted to perform station upkeep. You can still be emagged in this state." + + if(keeper) + return + + var/mob/living/silicon/robot/R = src + + if(R) + R.UnlinkSelf() + var/obj/item/weapon/aiModule/keeper/mdl = new + + mdl.transmitInstructions(src, src) + src << "These are your laws now:" + src.show_laws() + + src.verbs -= /mob/living/silicon/robot/mommi/proc/ActivateKeeper \ No newline at end of file diff --git a/code/modules/mob/living/silicon/mommi/mommi_modules.dm b/code/modules/mob/living/silicon/mommi/mommi_modules.dm new file mode 100644 index 00000000000..87deade756c --- /dev/null +++ b/code/modules/mob/living/silicon/mommi/mommi_modules.dm @@ -0,0 +1,52 @@ +/obj/item/weapon/robot_module/mommi + name = "mobile mmi robot module" + + + New() + src.modules += new /obj/item/borg/sight/meson(src) + src.emag = new /obj/item/borg/stun(src) + //src.modules += new /obj/item/weapon/rcd/borg(src) // Too OP + //src.modules += new /obj/item/weapon/extinguisher(src) // Too big + //src.modules += new /obj/item/device/flashlight(src) // Broken + src.modules += new /obj/item/weapon/weldingtool/largetank(src) + src.modules += new /obj/item/weapon/screwdriver(src) + src.modules += new /obj/item/weapon/wrench(src) + src.modules += new /obj/item/weapon/crowbar(src) + src.modules += new /obj/item/weapon/wirecutters(src) + src.modules += new /obj/item/device/multitool(src) + src.modules += new /obj/item/device/t_scanner(src) + src.modules += new /obj/item/device/analyzer(src) + src.modules += new /obj/item/weapon/pipe_dispenser(src) + src.modules += new /obj/item/device/healthanalyzer(src) + + // Added this back in since it made the MoMMI practically useless for engineering stuff. + var/obj/item/stack/sheet/metal/cyborg/M = new /obj/item/stack/sheet/metal/cyborg(src) + M.amount = 50 + src.modules += M +/* BIG + var/obj/item/stack/sheet/rglass/cyborg/G = new /obj/item/stack/sheet/rglass/cyborg(src) + G.amount = 50 + src.modules += G + + var/obj/item/stack/sheet/glass/cyborg/G = new /obj/item/stack/sheet/glass/cyborg(src) + G.amount = 50 + src.modules += G +*/ + + var/obj/item/weapon/cable_coil/W = new /obj/item/weapon/cable_coil(src) + W.amount = 50 + src.modules += W + return + respawn_consumable(var/mob/living/silicon/robot/R) + var/list/what = list ( + /obj/item/stack/sheet/metal/cyborg, + ///obj/item/stack/sheet/glass/cyborg, + /obj/item/weapon/cable_coil, + ) + for (var/T in what) + if (!(locate(T) in src.modules)) + src.modules -= null + var/O = new T(src) + src.modules += O + O:amount = 1 + return \ No newline at end of file diff --git a/code/modules/mob/living/silicon/mommi/mommi_movement.dm b/code/modules/mob/living/silicon/mommi/mommi_movement.dm new file mode 100644 index 00000000000..dee3f3a36e5 --- /dev/null +++ b/code/modules/mob/living/silicon/mommi/mommi_movement.dm @@ -0,0 +1,17 @@ +/* +/mob/living/silicon/robot/mommi/Process_Spacemove() + if(module) + for(var/obj/item/weapon/tank/jetpack/J in module.modules) + if(J && istype(J, /obj/item/weapon/tank/jetpack)) + if(J.allow_thrust(0.01)) return 1 + if(..()) return 1 + return 0 + + //No longer needed, but I'll leave it here incase we plan to re-use it. +/mob/living/silicon/robot/mommi/movement_delay() + var/tally = 0 //Incase I need to add stuff other than "speed" later + + tally = speed + + return tally+config.robot_delay +*/ \ No newline at end of file diff --git a/code/modules/mob/living/silicon/mommi/powers.dm b/code/modules/mob/living/silicon/mommi/powers.dm new file mode 100644 index 00000000000..ed423696271 --- /dev/null +++ b/code/modules/mob/living/silicon/mommi/powers.dm @@ -0,0 +1,32 @@ +/mob/living/silicon/robot/mommi/verb/ventcrawl() + set name = "Crawl through Vent" + set desc = "Enter an air vent and crawl through the pipe system." + set category = "Robot Commands" + var/mob/living/silicon/robot/mommi/R = src + if(R.canmove) + handle_ventcrawl() + + +/mob/living/silicon/robot/mommi/verb/hide() + set name = "Hide" + set desc = "Allows to hide beneath tables or certain items. Toggled on or off." + set category = "Robot Commands" + + if(stat != CONSCIOUS) + return + var/mob/living/silicon/robot/mommi/R = src + if(!R.canmove) + return + + if (layer != TURF_LAYER+0.2) + layer = TURF_LAYER+0.2 + src << text("\blue You are now hiding.") + for(var/mob/O in oviewers(src, null)) + if ((O.client && !( O.blinded ))) + O << "[src] tries to hide itself!" + else + layer = MOB_LAYER + src << text("\blue You have stopped hiding.") + for(var/mob/O in oviewers(src, null)) + if ((O.client && !( O.blinded ))) + O << "[src] slowly peeks up..." \ No newline at end of file diff --git a/code/modules/mob/living/silicon/mommi/say.dm b/code/modules/mob/living/silicon/mommi/say.dm new file mode 100644 index 00000000000..0d517c203c0 --- /dev/null +++ b/code/modules/mob/living/silicon/mommi/say.dm @@ -0,0 +1,26 @@ +/mob/living/silicon/robot/mommi/say_understands(var/other) + if (istype(other, /mob/living/silicon/ai)) + return 1 + if (istype(other, /mob/living/silicon/decoy)) + return 1 + if (istype(other, /mob/living/silicon/robot)) + return 1 + if (istype(other, /mob/living/carbon/human)) + return 1 + if (istype(other, /mob/living/carbon/brain)) + return 1 + if (istype(other, /mob/living/silicon/pai)) + return 1 +// if (istype(other, /mob/living/silicon/hivebot)) +// return 1 + return ..() + +/mob/living/silicon/robot/mommi/say_quote(var/text) + var/ending = copytext(text, length(text)) + + if (ending == "?") + return "queries, \"[text]\""; + else if (ending == "!") + return "declares, \"[text]\""; + + return "states, \"[text]\""; \ No newline at end of file diff --git a/code/modules/mob/living/silicon/mommi/wires.dm b/code/modules/mob/living/silicon/mommi/wires.dm new file mode 100644 index 00000000000..0ce86cf441b --- /dev/null +++ b/code/modules/mob/living/silicon/mommi/wires.dm @@ -0,0 +1,150 @@ +/* Inherited +#define BORG_WIRE_LAWCHECK 1 +#define BORG_WIRE_MAIN_POWER1 2 +#define BORG_WIRE_MAIN_POWER2 3 +#define BORG_WIRE_AI_CONTROL 4 +#define BORG_WIRE_CAMERA 5 + +/proc/RandomBorgWires() + //to make this not randomize the wires, just set index to 1 and increment it in the flag for loop (after doing everything else). + var/list/Borgwires = list(0, 0, 0, 0, 0) + BorgIndexToFlag = list(0, 0, 0, 0, 0) + BorgIndexToWireColor = list(0, 0, 0, 0, 0) + BorgWireColorToIndex = list(0, 0, 0, 0, 0) + var/flagIndex = 1 + //I think it's easier to read this way, also doesn't rely on the random number generator to land on a new wire. + var/list/colorIndexList = list(BORG_WIRE_LAWCHECK, BORG_WIRE_MAIN_POWER1, BORG_WIRE_MAIN_POWER2, BORG_WIRE_AI_CONTROL, BORG_WIRE_CAMERA) + for (var/flag=1, flag<=16, flag+=flag) + var/colorIndex = pick(colorIndexList) + if (Borgwires[colorIndex]==0) + Borgwires[colorIndex] = flag + BorgIndexToFlag[flagIndex] = flag + BorgIndexToWireColor[flagIndex] = colorIndex + BorgWireColorToIndex[colorIndex] = flagIndex + colorIndexList -= colorIndex // Shortens the list. + //world.log << "Flag: [flag], CIndex: [colorIndex], FIndex: [flagIndex]" + flagIndex+=1 + return Borgwires + +/mob/living/silicon/robot/proc/isWireColorCut(var/wireColor) + var/wireFlag = BorgWireColorToFlag[wireColor] + return ((src.borgwires & wireFlag) == 0) + +/mob/living/silicon/robot/proc/isWireCut(var/wireIndex) + var/wireFlag = BorgIndexToFlag[wireIndex] + return ((src.borgwires & wireFlag) == 0) + +/mob/living/silicon/robot/proc/cut(var/wireColor) + var/wireFlag = BorgWireColorToFlag[wireColor] + var/wireIndex = BorgWireColorToIndex[wireColor] + borgwires &= ~wireFlag + switch(wireIndex) + if(BORG_WIRE_LAWCHECK) //Cut the law wire, and the borg will no longer receive law updates from its AI + if (src.lawupdate == 1) + src << "LawSync protocol engaged." + src.show_laws() + if (BORG_WIRE_AI_CONTROL) //Cut the AI wire to reset AI control + if (src.connected_ai) + src.connected_ai = null + if (BORG_WIRE_CAMERA) + if(!isnull(src.camera) && !scrambledcodes) + src.camera.status = 0 + src.camera.deactivate(usr, 0) // Will kick anyone who is watching the Cyborg's camera. + + src.interact(usr) + +/mob/living/silicon/robot/proc/mend(var/wireColor) + var/wireFlag = BorgWireColorToFlag[wireColor] + var/wireIndex = BorgWireColorToIndex[wireColor] + borgwires |= wireFlag + switch(wireIndex) + if(BORG_WIRE_LAWCHECK) //turns law updates back on assuming the borg hasn't been emagged + if (src.lawupdate == 0 && !src.emagged) + src.lawupdate = 1 + if(BORG_WIRE_CAMERA) + if (!isnull(src.camera) && !scrambledcodes) + src.camera.status = 1 + src.camera.deactivate(usr, 0) // Will kick anyone who is watching the Cyborg's camera. + + src.interact(usr) + + +/mob/living/silicon/robot/proc/pulse(var/wireColor) + var/wireIndex = BorgWireColorToIndex[wireColor] + switch(wireIndex) + if(BORG_WIRE_LAWCHECK) //Forces a law update if the borg is set to receive them. Since an update would happen when the borg checks its laws anyway, not much use, but eh + if (src.lawupdate) + src.lawsync() + + if (BORG_WIRE_AI_CONTROL) //pulse the AI wire to make the borg reselect an AI + if(!src.emagged) + src.connected_ai = select_active_ai() + + if (BORG_WIRE_CAMERA) + if(!isnull(src.camera) && src.camera.status && !scrambledcodes) + src.camera.deactivate(usr, 0) // Kick anyone watching the Cyborg's camera, doesn't display you disconnecting the camera. + usr << "[src]'s camera lens focuses loudly." + src << "Your camera lens focuses loudly." + + src.interact(usr) + +/mob/living/silicon/robot/proc/interact(mob/user) + if(wiresexposed && (!istype(user, /mob/living/silicon))) + user.set_machine(src) + var/t1 = text("Access Panel
\n") + var/list/Borgwires = list( + "Orange" = 1, + "Dark red" = 2, + "White" = 3, + "Yellow" = 4, + "Blue" = 5, + ) + for(var/wiredesc in Borgwires) + var/is_uncut = src.borgwires & BorgWireColorToFlag[Borgwires[wiredesc]] + t1 += "[wiredesc] wire: " + if(!is_uncut) + t1 += "Mend" + else + t1 += "Cut " + t1 += "Pulse " + t1 += "
" + t1 += text("
\n[(src.lawupdate ? "The LawSync light is on." : "The LawSync light is off.")]
\n[(src.connected_ai ? "The AI link light is on." : "The AI link light is off.")]") + t1 += text("
\n[((!isnull(src.camera) && src.camera.status == 1) ? "The Camera light is on." : "The Camera light is off.")]
\n") + t1 += text("

Close

\n") + user << browse(t1, "window=borgwires") + onclose(user, "borgwires") + +/mob/living/silicon/robot/Topic(href, href_list) + ..() + if (((in_range(src, usr) && istype(src.loc, /turf))) && !istype(usr, /mob/living/silicon)) + usr.set_machine(src) + if (href_list["borgwires"]) + var/t1 = text2num(href_list["borgwires"]) + if (!( istype(usr.get_active_hand(), /obj/item/weapon/wirecutters) )) + usr << "You need wirecutters!" + return + if (src.isWireColorCut(t1)) + src.mend(t1) + else + src.cut(t1) + else if (href_list["pulse"]) + var/t1 = text2num(href_list["pulse"]) + if (!istype(usr.get_active_hand(), /obj/item/device/multitool)) + usr << "You need a multitool!" + return + if (src.isWireColorCut(t1)) + usr << "You can't pulse a cut wire." + return + else + src.pulse(t1) + else if (href_list["close2"]) + usr << browse(null, "window=borgwires") + usr.unset_machine() + return + +#undef BORG_WIRE_LAWCHECK +#undef BORG_WIRE_MAIN_POWER1 +#undef BORG_WIRE_MAIN_POWER2 +#undef BORG_WIRE_AI_CONTROL +#undef BORG_WIRE_CAMERA +*/ \ No newline at end of file diff --git a/code/modules/mob/living/silicon/say.dm b/code/modules/mob/living/silicon/say.dm index 35cb579f8d2..c0219e6589e 100644 --- a/code/modules/mob/living/silicon/say.dm +++ b/code/modules/mob/living/silicon/say.dm @@ -35,6 +35,11 @@ src << "This function is not available to you." return else + if(isMoMMI(src)&&client)//For patching directly into AI holopads. + var/mob/living/silicon/robot/mommi/U = src + if(U.keeper) + src << "\red Your KEEPER module has disabled your vocalizer. Try :b to attempt to relay your message through the AI or borgs, or try an *emote (say \"*help\" for a listing)." + return return ..(message) else return ..(message) diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm index 33855d7497a..135b50fc6dd 100644 --- a/code/modules/mob/mob_helpers.dm +++ b/code/modules/mob/mob_helpers.dm @@ -105,6 +105,11 @@ return 1 return 0 +/proc/isMoMMI(A) + if(istype(A, /mob/living/silicon/robot/mommi)) + return 1 + return 0 + /proc/isliving(A) if(istype(A, /mob/living)) return 1 diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm index cec9b06861a..51a78a8253a 100644 --- a/code/modules/mob/mob_movement.dm +++ b/code/modules/mob/mob_movement.dm @@ -70,6 +70,8 @@ set hidden = 1 if(istype(mob, /mob/living/carbon)) mob:swap_hand() + if(istype(mob,/mob/living/silicon/robot/mommi)) + return // MoMMIs only have one tool slot. if(istype(mob,/mob/living/silicon/robot))//Oh nested logic loops, is there anything you can't do? -Sieve var/mob/living/silicon/robot/R = mob if(!R.module_active) diff --git a/code/modules/mob/screen.dm b/code/modules/mob/screen.dm index b9767c3a299..bd26954174f 100644 --- a/code/modules/mob/screen.dm +++ b/code/modules/mob/screen.dm @@ -455,6 +455,28 @@ if(issilicon(usr)) usr:uneq_active() + //////////////////////////////////////////////// + // MoMMI shit + if(INV_SLOT_TOOL) + if(usr:tool_state) + if(usr:module_active != usr:tool_state) + usr:inv_tool.icon_state = "inv1 +a" + usr:inv_sight.icon_state = "sight" + usr:module_active = usr:tool_state + else + usr:inv_tool.icon_state = "inv1" + usr:module_active = null + if(INV_SLOT_SIGHT) + if(usr:sight_state) + if(usr:module_active != usr:sight_state) + usr:inv_tool.icon_state = "inv1" + usr:inv_sight.icon_state = "sight+a" + usr:module_active = usr:sight_state + else + usr:inv_sight.icon_state = "sight" + usr:module_active = null + //////////////////////////////////////////////// + if("module1") if(usr:module_state_1) if(usr:module_active != usr:module_state_1) diff --git a/code/modules/mob/transform_procs.dm b/code/modules/mob/transform_procs.dm index ca33eaa1b67..065958f7f78 100644 --- a/code/modules/mob/transform_procs.dm +++ b/code/modules/mob/transform_procs.dm @@ -171,6 +171,54 @@ O.Namepick() + spawn(0)//To prevent the proc from returning null. + del(src) + return O + +//human -> mommi +/mob/living/carbon/human/proc/MoMMIfy() + if (monkeyizing) + return + for(var/obj/item/W in src) + drop_from_inventory(W) + regenerate_icons() + monkeyizing = 1 + canmove = 0 + icon = null + invisibility = 101 + for(var/t in organs) + del(t) + + var/mob/living/silicon/robot/mommi/O = new /mob/living/silicon/robot/mommi( loc ) + + // cyborgs produced by Robotize get an automatic power cell + O.cell = new(O) + O.cell.maxcharge = 7500 + O.cell.charge = 7500 + + + O.gender = gender + O.invisibility = 0 + + + if(mind) //TODO + mind.transfer_to(O) + if(O.mind.assigned_role == "Cyborg") + O.mind.original = O + else if(mind.special_role) + O.mind.store_memory("In case you look at this after being borged, the objectives are only here until I find a way to make them not show up for you, as I can't simply delete them without screwing up round-end reporting. --NeoFite") + else + O.key = key + + O.loc = loc + O.job = "Cyborg" + + O.mmi = new /obj/item/device/mmi(O) + O.mmi.transfer_identity(src)//Does not transfer key/client. + + O.Namepick() + + spawn(0)//To prevent the proc from returning null. del(src) return O diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm index f25abe3c76c..ebb4fabef70 100644 --- a/code/modules/power/apc.dm +++ b/code/modules/power/apc.dm @@ -424,10 +424,14 @@ opened = 1 update_icon() else + // The extra crowbar thing fixes MoMMIs not being able to remove APCs. + // They can just pop them off with a crowbar. if ( ((stat & BROKEN) || malfhack) \ && !opened \ - && W.force >= 5 \ - && W.w_class >= 3.0 \ + && ( \ + (W.force >= 5 && W.w_class >= 3.0) \ + || istype(W,/obj/item/weapon/crowbar) \ + ) \ && prob(20) ) opened = 2 user.visible_message("\red The APC cover was knocked down with the [W.name] by [user.name]!", \ @@ -453,9 +457,12 @@ if(!user) return src.add_fingerprint(user) - if(usr == user && opened && (!issilicon(user))) + if(usr == user && opened) if(cell) - user.put_in_hands(cell) + if(issilicon(user) && !isMoMMI(user)) // MoMMIs can hold one item in their tool slot. + cell.loc=src.loc // Drop it, whoops. + else + user.put_in_hands(cell) cell.add_fingerprint(user) cell.updateicon() @@ -778,7 +785,7 @@ ) \ ) if(!loud) - user << "\red \The [src] have AI control disabled!" + user << "\red \The [src] has AI control disabled!" user << browse(null, "window=apc") user.unset_machine() return 0 diff --git a/code/modules/projectiles/projectile/change.dm b/code/modules/projectiles/projectile/change.dm index 2b4b4c457d8..4ab2bd59c3c 100644 --- a/code/modules/projectiles/projectile/change.dm +++ b/code/modules/projectiles/projectile/change.dm @@ -46,6 +46,15 @@ var/mob/living/silicon/robot/Robot = new_mob Robot.mmi = new /obj/item/device/mmi(new_mob) Robot.mmi.transfer_identity(M) //Does not transfer key/client. + new_mob.universal_speak = 1 + if("mommi") + new_mob = new /mob/living/silicon/robot/mommi(M.loc) + new_mob.gender = M.gender + new_mob.invisibility = 0 + new_mob.job = "MoMMI" + var/mob/living/silicon/robot/mommi/MoMMI = new_mob + MoMMI.mmi = new /obj/item/device/mmi(new_mob) + MoMMI.mmi.transfer_identity(M) //Does not transfer key/client. if("slime") if(prob(50)) new_mob = new /mob/living/carbon/slime/adult(M.loc) else new_mob = new /mob/living/carbon/slime(M.loc) diff --git a/code/modules/recycling/disposal.dm b/code/modules/recycling/disposal.dm index 5455f1bd4c0..12f57fbde27 100644 --- a/code/modules/recycling/disposal.dm +++ b/code/modules/recycling/disposal.dm @@ -39,13 +39,15 @@ //gas.volume = 1.05 * CELLSTANDARD update() + MouseDrop_T(var/obj/item/target, mob/user) + src.attackby(target,user) // attack by item places it in to disposal attackby(var/obj/item/I, var/mob/user) if(stat & BROKEN || !I || !user) return - if(isrobot(user) && !istype(I, /obj/item/weapon/storage/bag/trash)) + if(isrobot(user) && !istype(I, /obj/item/weapon/storage/bag/trash) && !istype(user,/mob/living/silicon/robot/mommi)) return src.add_fingerprint(user) if(mode<=0) // It's off diff --git a/code/setup.dm b/code/setup.dm index c96678c0221..c7e69729441 100644 --- a/code/setup.dm +++ b/code/setup.dm @@ -398,6 +398,8 @@ var/MAX_EXPLOSION_RANGE = 14 #define GAS_CO2 (1 << 3) #define GAS_N2O (1 << 4) +#define INV_SLOT_SIGHT "sight_slot" +#define INV_SLOT_TOOL "tool_slot" var/list/accessable_z_levels = list("1" = 5, "3" = 10, "4" = 15, "5" = 10, "6" = 60) //This list contains the z-level numbers which can be accessed via space travel and the percentile chances to get there. diff --git a/icons/mob/robots.dmi b/icons/mob/robots.dmi index 852e85c4924e43b4a2357cc7e799f5610ad8d1e7..6445699ab72037bf0fb68ee030a48bef88508047 100644 GIT binary patch delta 7587 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 PL9a&-wUx^h&ENbFs_%E# delta 6956 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 diff --git a/icons/mob/screen1_robot.dmi b/icons/mob/screen1_robot.dmi index 1796092eae0f6ae1c937c161487d1d00075df132..27ef209f7c3dbf8ae88faf9cd50405ebf8549a1a 100644 GIT binary patch delta 7165 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 O_EA&TRw`Gp3jIIT1IvB@ delta 8576 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 CeT6mv