diff --git a/code/__DEFINES/DNA.dm b/code/__DEFINES/DNA.dm index fefc8d17f086..a36b278666d5 100644 --- a/code/__DEFINES/DNA.dm +++ b/code/__DEFINES/DNA.dm @@ -90,6 +90,7 @@ #define ORGAN_SLOT_STOMACH "stomach" #define ORGAN_SLOT_STOMACH_AID "stomach_aid" #define ORGAN_SLOT_THRUSTERS "thrusters" +#define ORGAN_SLOT_TRACTOR_FIELD "tractor_field" // NON-MODULE CHANGE #define ORGAN_SLOT_TONGUE "tongue" #define ORGAN_SLOT_VOICE "vocal_cords" #define ORGAN_SLOT_ZOMBIE "zombie_infection" @@ -149,6 +150,7 @@ GLOBAL_LIST_INIT(organ_process_order, list( ORGAN_SLOT_HEART, ORGAN_SLOT_ZOMBIE, ORGAN_SLOT_THRUSTERS, + ORGAN_SLOT_TRACTOR_FIELD, // NON-MODULE CHANGE ORGAN_SLOT_HUD, ORGAN_SLOT_LIVER, ORGAN_SLOT_TONGUE, diff --git a/maplestation.dme b/maplestation.dme index 23db9621d556..2ea1aeaff106 100644 --- a/maplestation.dme +++ b/maplestation.dme @@ -6530,6 +6530,7 @@ #include "maplestation_modules\story_content\story_posters\code\contraband.dm" #include "maplestation_modules\story_content\stranger_equipment\code\strangerclothing.dm" #include "maplestation_modules\story_content\volkan_equipment\code\sunitems.dm" +#include "maplestation_modules\story_content\volkan_equipment\code\volkancomponents.dm" #include "maplestation_modules\story_content\volkan_equipment\code\volkanitems.dm" #include "maplestation_modules\story_content\volkan_equipment\code\volkanpets.dm" #include "maplestation_modules\story_content\volkan_equipment\code\volkanpets_ai.dm" diff --git a/maplestation_modules/story_content/volkan_equipment/audio/attribution.txt b/maplestation_modules/story_content/volkan_equipment/audio/attribution.txt index 400a8ac82140..7d2ddcd0bedb 100644 --- a/maplestation_modules/story_content/volkan_equipment/audio/attribution.txt +++ b/maplestation_modules/story_content/volkan_equipment/audio/attribution.txt @@ -1 +1,5 @@ -bot_startup.ogg is a snippet from https://freesound.org/people/wtermini/sounds/546450/ +1) bot_startup.ogg is a snippet from https://freesound.org/people/wtermini/sounds/546450/ + +2) All vroomba sounds were created by Constellado with Beepbox.co (yes. really.) +This has the instruments all set up for it if you want to use it to add more vroomba noises: +https://www.beepbox.co/#9n21sbk0l00e00t43a7g00j07r1i0o43T0v0u00f10u2qw02d03w5h0E0T1v0u01f0qw03d03A0F0BfQ0000PffffE0T3v0u03f0qw00d03SUUM0A060n0U07M0E0b4hp140000 diff --git a/maplestation_modules/story_content/volkan_equipment/audio/vroomba_accept.ogg b/maplestation_modules/story_content/volkan_equipment/audio/vroomba_accept.ogg new file mode 100644 index 000000000000..3e0fa3dd265c Binary files /dev/null and b/maplestation_modules/story_content/volkan_equipment/audio/vroomba_accept.ogg differ diff --git a/maplestation_modules/story_content/volkan_equipment/audio/vroomba_chatter.ogg b/maplestation_modules/story_content/volkan_equipment/audio/vroomba_chatter.ogg new file mode 100644 index 000000000000..21f398745a64 Binary files /dev/null and b/maplestation_modules/story_content/volkan_equipment/audio/vroomba_chatter.ogg differ diff --git a/maplestation_modules/story_content/volkan_equipment/audio/vroomba_combat_mode.ogg b/maplestation_modules/story_content/volkan_equipment/audio/vroomba_combat_mode.ogg new file mode 100644 index 000000000000..4e183cdcba18 Binary files /dev/null and b/maplestation_modules/story_content/volkan_equipment/audio/vroomba_combat_mode.ogg differ diff --git a/maplestation_modules/story_content/volkan_equipment/audio/vroomba_decline.ogg b/maplestation_modules/story_content/volkan_equipment/audio/vroomba_decline.ogg new file mode 100644 index 000000000000..7ccee8435a89 Binary files /dev/null and b/maplestation_modules/story_content/volkan_equipment/audio/vroomba_decline.ogg differ diff --git a/maplestation_modules/story_content/volkan_equipment/audio/vroomba_laugh.ogg b/maplestation_modules/story_content/volkan_equipment/audio/vroomba_laugh.ogg new file mode 100644 index 000000000000..c9128c80789e Binary files /dev/null and b/maplestation_modules/story_content/volkan_equipment/audio/vroomba_laugh.ogg differ diff --git a/maplestation_modules/story_content/volkan_equipment/audio/vroomba_scan.ogg b/maplestation_modules/story_content/volkan_equipment/audio/vroomba_scan.ogg new file mode 100644 index 000000000000..dc5bacc3444e Binary files /dev/null and b/maplestation_modules/story_content/volkan_equipment/audio/vroomba_scan.ogg differ diff --git a/maplestation_modules/story_content/volkan_equipment/audio/vroomba_stop.ogg b/maplestation_modules/story_content/volkan_equipment/audio/vroomba_stop.ogg new file mode 100644 index 000000000000..4fe5341fcff6 Binary files /dev/null and b/maplestation_modules/story_content/volkan_equipment/audio/vroomba_stop.ogg differ diff --git a/maplestation_modules/story_content/volkan_equipment/code/volkancomponents.dm b/maplestation_modules/story_content/volkan_equipment/code/volkancomponents.dm new file mode 100644 index 000000000000..a45c437fe80b --- /dev/null +++ b/maplestation_modules/story_content/volkan_equipment/code/volkancomponents.dm @@ -0,0 +1,264 @@ +/* + * # Components for Volkan pets or others! + * This file has a bunch of components as well as various things like HUDs and things like that. + * Ones not named for a specific mob is made to be used in more than one mob. Maybe. + */ + +///signal for the vroomba's tools to know if it is in combat mode +#define COMSIG_COMBAT_MODE "combat_mode_active" + +/* + * # Tractor field component + * A very important and complicated piece of Vtech (Volkan and Co technology). + * Invented by CaLE, based on gravity generators. + * In game it will basically act like telekinesis. + * Add it to a mob if the mob has tractor field Vtech inside. + */ + +///A piece of Vtech. Like a tractor beam, but its a whole field around the object instead. +/datum/component/tractorfield + ///the maximum range the tractorfield has influence over + var/max_range = 6 + ///the damage the tractor field does when doing a force attack. Shouldn't be not much damage. + var/damage = 5 + ///The pushing force does the tractor field has. + var/force = 4 + + ///Stuff tractor field cannot interact with + var/static/list/blacklisted_atoms = typecacheof(list(/atom/movable/screen)) + +/datum/component/tractorfield/RegisterWithParent() + RegisterSignal(parent, COMSIG_MOB_ATTACK_RANGED, PROC_REF(on_ranged_attack)) + RegisterSignal(parent, COMSIG_LIVING_UNARMED_ATTACK, PROC_REF(on_unarmed_attack)) + + +/datum/component/tractorfield/UnregisterFromParent() + UnregisterSignal(parent, list(COMSIG_MOB_ATTACK_RANGED,COMSIG_LIVING_UNARMED_ATTACK)) + + +///Checks if clicked on item is in tractor field's influence. +/datum/component/tractorfield/proc/tractorRangeCheck(mob/user, atom/target) + var/d = get_dist(user, target) + if(d > max_range) + user.balloon_alert(user, "can't lift, too far!") + return + return TRUE + +///Same as /datum/component/tractorfield/proc/tractorRangeCheck() but for the telekinetic grab object instead. +/obj/item/tk_grab/tractor/proc/tractorRangeCheck(mob/user, atom/target) //Melbert if you know how to combine this with above one plz tell me. It works though. + var/d = get_dist(user, target) + if(d > max_range) + user.balloon_alert(user, "can't move, too far!") + return + return TRUE + +///Manages all the stuff a tractor field can do from a distance. +/datum/component/tractorfield/proc/on_ranged_attack(mob/source, atom/target, src) + SIGNAL_HANDLER + if(is_type_in_typecache(target, blacklisted_atoms)) + return + if(!tractorRangeCheck(source, target) || source.z != target.z) + return + if(ismob(target)) //atacking mobs + return target.attack_tractor(source, target, damage, force) + if(isitem(target)) + return tractor_grab(source, target) + return on_unarmed_attack(source, target, TRUE) + +//Grabs the item with the tractor field at a distance +/datum/component/tractorfield/proc/tractor_grab(mob/user, target) + var/obj/item/tk_grab/tractor/O = new(target) + O.tk_user = user + O.max_range = max_range + force //it can throw things just a little bit further than it can pick up + if(!O.focus_object(target)) + return + INVOKE_ASYNC(O, TYPE_PROC_REF(/atom, attack_hand), user) + return COMPONENT_CANCEL_ATTACK_CHAIN + +///Tractor Field's "Telekinetic" grab object +/obj/item/tk_grab/tractor + name = "Tractor Field Grab" + desc = "Lifting things with complex gravity technology" + + ///The speed the tractor field moves things at. + var/speed = 6 + ///The maximum range a tractor field can move an object + var/max_range = 7 + +/obj/item/tk_grab/tractor/focus_object(obj/target) + if(!check_if_focusable(target)) + return + focus = target + ADD_TRAIT(focus, TRAIT_TELEKINESIS_CONTROLLED, REF(tk_user)) + update_appearance() + apply_focus_overlay() + return TRUE + +/obj/item/tk_grab/tractor/check_if_focusable(obj/target) + if(!tk_user || QDELETED(target) || !istype(target)) + qdel(src) + return + if(!tractorRangeCheck(tk_user, target) || target.anchored || !isturf(target.loc)) + qdel(src) + return + return TRUE + +/obj/item/tk_grab/tractor/afterattack(atom/target, mob/user, proximity, params) + . = ..() + move_object(user, target) + +///Moving an object around +/obj/item/tk_grab/tractor/proc/move_object(mob/user, atom/target) + if(!focus) + return + if(!tractorRangeCheck(user, target)) + return + apply_focus_overlay() + focus.throw_at(get_turf(target), 10, speed, thrower = user) + var/turf/start_turf = get_turf(focus) + var/turf/end_turf = get_turf(target) + user.log_message("has thrown [focus] from [AREACOORD(start_turf)] towards [AREACOORD(end_turf)] using a tractor field!", LOG_ATTACK) + update_appearance() + +/// Interact with items at range. replaces on_unarmed_attack. +/datum/component/tractorfield/proc/on_unarmed_attack(mob/living/hand_haver, atom/target, proximity, modifiers) + SIGNAL_HANDLER + if (!proximity && target.loc != hand_haver) + var/obj/item/obj_item = target + if (istype(obj_item) && !obj_item.atom_storage && !(obj_item.item_flags & IN_STORAGE)) + return NONE + if (LAZYACCESS(modifiers, RIGHT_CLICK)) + INVOKE_ASYNC(target, TYPE_PROC_REF(/atom, attack_hand_secondary), hand_haver, modifiers) + else + INVOKE_ASYNC(target, TYPE_PROC_REF(/atom, attack_hand), hand_haver, modifiers) + INVOKE_ASYNC(hand_haver, TYPE_PROC_REF(/mob, update_held_items)) + return COMPONENT_CANCEL_ATTACK_CHAIN + +///Ranged attacking with the tractor field. +/atom/proc/attack_tractor(mob/user, mob/target, damage, force) + new /obj/effect/temp_visual/telekinesis(get_turf(src)) + user.changeNext_move(CLICK_CD_MELEE) + //push them to where you are facing!! + target.throw_at(get_edge_target_turf(target, user.dir), force, damage, thrower = user) + balloon_alert(target, "gravity shifts!") // It essentially rotates gravity to the side for its target. + visible_message(span_danger("[user] pushes [target] back with an unknown force!")) + user.log_message("has attacked [target] using a tractor field!", LOG_ATTACK) //for the admins + + return COMPONENT_CANCEL_ATTACK_CHAIN + +/* + * # Broken tractor field + * This one is just fucked IC. Should feel chaotic to use. + */ +/datum/component/tractorfield/broken + max_range = 4 + //less damage, throws things less far + damage = 2 + force = 2 + +///throw yourself around if you try to touch something far away +/datum/component/tractorfield/broken/tractorRangeCheck(mob/user, atom/target) + var/d = get_dist(user, target) + if(d > max_range) + user.balloon_alert(user, "you feel something in your chest pull against you!") + new /obj/effect/temp_visual/telekinesis(get_turf(src)) + user.throw_at(get_edge_target_turf(user, rand(0,8)), force, damage, thrower = user) + return + return TRUE + +/datum/component/tractorfield/broken/on_ranged_attack(mob/source, atom/target, src) + if(is_type_in_typecache(target, blacklisted_atoms)) + return + if(!tractorRangeCheck(source, target) || source.z != target.z) + return + if(ismob(target)) //atacking mobs + return target.attack_tractor_broken(source, target, damage, force) + if(isitem(target)) + return target.throw_tractor_broken(source, target, damage, force) //ittl just throw it + return on_unarmed_attack(source, target, TRUE) + +///A tractor field attack fro the broken tractor field +/atom/proc/attack_tractor_broken(mob/user, mob/target, damage, force) + new /obj/effect/temp_visual/telekinesis(get_turf(src)) + user.changeNext_move(CLICK_CD_MELEE) + + //throw people against eachother! + user.throw_at(get_turf(target), force, damage, thrower = user) + target.throw_at(get_turf(user), force, damage, thrower = user) + + user.balloon_alert(target, "gravity shifts!") + user.balloon_alert(user, "you feel something in your chest pull you forward!") + balloon_alert(target, "gravity shifts uncomfortably!") // It essentially rotates gravity to the side for its target. + visible_message(span_danger("[user] pushes [target] with an unknown force!")) + user.log_message("has attacked [target] using a broken tractor field!", LOG_ATTACK) //for the admins + return COMPONENT_CANCEL_ATTACK_CHAIN + +///A broken grab. Instead, it just throws the object around. +/atom/proc/throw_tractor_broken(mob/user, obj/item/target, damage, force, random = FALSE) + new /obj/effect/temp_visual/telekinesis(get_turf(src)) + user.changeNext_move(CLICK_CD_MELEE) + target.throw_at(get_edge_target_turf(user, rand(0,8)), force + rand(force), damage, thrower = user)// randomly throws it, stronger than it would with a person. + visible_message(span_danger("[user] throws the [target] with an unknown force chaotically!")) + return COMPONENT_CANCEL_ATTACK_CHAIN + +/* + * # Vroomba only stuff + * Components just for the vroomba. + */ +///The vroomba's hud! +/datum/hud/vroomba/New(mob/owner) + . = ..() + var/atom/movable/screen/using + + using = new /atom/movable/screen/drop(null, src) + using.icon = ui_style + using.screen_loc = ui_drone_drop + static_inventory += using + + pull_icon = new /atom/movable/screen/pull(null, src) + pull_icon.icon = ui_style + pull_icon.update_appearance() + pull_icon.screen_loc = ui_drone_pull + static_inventory += pull_icon + + build_hand_slots() + + action_intent = new /atom/movable/screen/combattoggle/flashy(null, src) + action_intent.icon = ui_style + action_intent.screen_loc = ui_combat_toggle + static_inventory += action_intent + + zone_select = new /atom/movable/screen/zone_sel(null, src) + zone_select.icon = ui_style + zone_select.update_appearance() + static_inventory += zone_select + + using = new /atom/movable/screen/area_creator(null, src) + using.icon = ui_style + static_inventory += using + + mymob.canon_client?.clear_screen() + +///The vroombas cleaner for when it is not in combat. +/datum/component/cleaner/vroomba/RegisterWithParent() + . = ..() + RegisterSignal(parent, COMSIG_COMBAT_MODE, PROC_REF(remove_self)) + +/datum/component/cleaner/vroomba/proc/remove_self() + SIGNAL_HANDLER + + qdel(src) + +///this tractor field removes itself when combat mode is deactivated. +/datum/component/tractorfield/vroomba + max_range = 3 + force = 2 + +/datum/component/tractorfield/vroomba/RegisterWithParent() + . = ..() + RegisterSignal(parent, COMSIG_COMBAT_MODE, PROC_REF(remove_self)) + +/datum/component/tractorfield/vroomba/proc/remove_self() + SIGNAL_HANDLER + + qdel(src) diff --git a/maplestation_modules/story_content/volkan_equipment/code/volkanitems.dm b/maplestation_modules/story_content/volkan_equipment/code/volkanitems.dm index 5620e70e0337..e26f7002989b 100644 --- a/maplestation_modules/story_content/volkan_equipment/code/volkanitems.dm +++ b/maplestation_modules/story_content/volkan_equipment/code/volkanitems.dm @@ -99,6 +99,7 @@ mobtype = /mob/living/basic/volkan/shoulder_pet + //--other misc-- //Imprint Key //A key used to imprint a Volkan bot to whoever has it. @@ -114,7 +115,6 @@ //---------------------cool boxes!----------------------- - //Unfoldable Box. //A box designed to hold both a pet and the communication chips for transit. It is easy to unfold once the items inside has been taken out. /obj/item/storage/box/volkan/unfoldable_box @@ -141,6 +141,7 @@ ) generate_items_inside(items_inside, src) + //Chip box //Designed to hold communication chips /obj/item/storage/box/volkan/chip_box @@ -186,3 +187,35 @@ atom_storage.numerical_stacking = TRUE atom_storage.max_total_storage = 6 atom_storage.max_slots = 2 // I expect trades to only have two items max right now. + + +/* + * # Tractor field item + * A very important and complicated piece of Vtech (Volkan and Co technology). + * Invented by CaLE, based on gravity generators. + * In game it will basically act like telekinesis. + * Gives the tractor field component + */ + +/obj/item/organ/internal/cyberimp/chest/tractorfield + name = "intricate metal toroid" + desc = "A strange toroid shaped mechanism with intricate machined metal shapes interlocked together. Two cables are sticking out from the inside." + icon = 'maplestation_modules/story_content/volkan_equipment/icons/misc_items.dmi' + icon_state = "tractor_field_component" + w_class = WEIGHT_CLASS_NORMAL + slot = ORGAN_SLOT_TRACTOR_FIELD + +/obj/item/organ/internal/cyberimp/chest/tractorfield/on_mob_insert(mob/living/owner) + + if (iscyborg(owner) || (owner.mob_biotypes & MOB_ROBOTIC)) + owner.AddComponent(/datum/component/tractorfield) + else + owner.AddComponent(/datum/component/tractorfield/broken) //fleshy beings cannot control it... + . = ..() + +/obj/item/organ/internal/cyberimp/chest/tractorfield/on_mob_remove(mob/living/carbon/organ_owner, special) + if (iscyborg(owner) || (owner.mob_biotypes & MOB_ROBOTIC)) + qdel(owner.GetComponent(/datum/component/tractorfield)) + else + qdel(owner.GetComponent(/datum/component/tractorfield/broken)) + . = ..() diff --git a/maplestation_modules/story_content/volkan_equipment/code/volkanpets.dm b/maplestation_modules/story_content/volkan_equipment/code/volkanpets.dm index 838753010bc2..c7f506c30b75 100644 --- a/maplestation_modules/story_content/volkan_equipment/code/volkanpets.dm +++ b/maplestation_modules/story_content/volkan_equipment/code/volkanpets.dm @@ -1,8 +1,8 @@ +//HOLY MOLY WHAT DID I GET MYSELF INTO?? /* * # Volkan's companion. * A cool pet for volkan! Basically a better poly. Quiet, efficient, and will sit on his shoulder all the time. */ -//HOLY MOLY WHAT DID I GET MYSELF INTO?? /mob/living/basic/volkan/shoulder_pet name = "Companion" desc = "An intricate, flying robot. It looks at you inquisitively." @@ -80,6 +80,210 @@ unique = FALSE) AddComponent(/datum/component/obeys_commands, pet_commands) // follows pet command + + ///Proc to run once imprinted /mob/living/basic/volkan/shoulder_pet/proc/tamed(mob/living/tamer) visible_message(span_notice("[src] beeps and turns its head toward [tamer] with its head tilted.")) + +/* + * # The Vroomba! + * A roomba, that has combat functionality! It will have two modes, cleaner mode, which is similar to a cleanbot, and combat mode, where it will float and have various attacks, and have telekinesis! + */ + +//lines it can say +#define VROOMBA_LAUGH "makes a robotic laughing sound!*" +#define VROOMBA_ACCEPT "Accepted." +#define VROOMBA_DECLINE "Declined." +#define VROOMBA_STOP "makes an annoyed sounding whine.*" +#define VROOMBA_CHATTER "makes a happy chattering noise!*" + +/mob/living/basic/bot/cleanbot/vroomba + name = "\improper Strange Roomba" + desc = "A little cleaning robot, So circular! It looks like it is out of plasteel." + icon = 'maplestation_modules/story_content/volkan_equipment/icons/companions.dmi' + base_icon_state = "vroomba2_drive" + icon_state = "vroomba2_drive" + icon_living = "vroomba2_drive" + base_icon = "vroomba2_drive" + pass_flags = PASSMOB | PASSFLAPS | PASSTABLE + density = FALSE + anchored = FALSE + layer = ABOVE_NORMAL_TURF_LAYER + + health = 100 + maxHealth = 100 + damage_coeff = list(BRUTE = 0.7, BURN = 1, TOX = 0, STAMINA = 0, OXY = 0) //It's secretly a combat drone. This thing is tanky. + + melee_damage_upper = 5 + melee_damage_lower = 1 + + maints_access_required = list(ACCESS_ROBOTICS, ACCESS_JANITOR, ACCESS_ENGINEERING) + radio_key = /obj/item/encryptionkey/ai + radio_channel = RADIO_CHANNEL_SERVICE + bot_type = CLEAN_BOT + hackables = " software" + additional_access = /datum/id_trim/job/janitor + possessed_message = "You are a roomba! Clean the station to the best of your ability! Protect your master! Don't let anybody boss YOU around!" + ai_controller = /datum/ai_controller/basic_controller/bot/cleanbot + path_image_color = "#ddda2a" + + hud_type = /datum/hud/vroomba + + melee_damage_lower = 10 + melee_damage_upper = 20 + ///basic hat offset + var/static/list/hat_offsets = list(0,-9) + + ///the icon state for when it is flying + var/flying_icon = "vroomba2_float" + + ///speed it goes in combat mode. lower is faster. + var/combat_speed = 0.5 + + ///50 percent chance to drop a special item... + var/tractor_field = /obj/item/organ/internal/cyberimp/chest/tractorfield + + ///the sound the vroomba makes when entering combat mode. + var/combat_sound = 'maplestation_modules/story_content/volkan_equipment/audio/vroomba_combat_mode.ogg' + + ///player chosen sounds the Vroomba can make. + var/static/list/announcements = list( + VROOMBA_LAUGH = 'maplestation_modules/story_content/volkan_equipment/audio/vroomba_laugh.ogg', + VROOMBA_ACCEPT = 'maplestation_modules/story_content/volkan_equipment/audio/vroomba_accept.ogg', + VROOMBA_DECLINE = 'maplestation_modules/story_content/volkan_equipment/audio/vroomba_decline.ogg', + VROOMBA_STOP = 'maplestation_modules/story_content/volkan_equipment/audio/vroomba_stop.ogg', + VROOMBA_CHATTER = 'maplestation_modules/story_content/volkan_equipment/audio/vroomba_chatter.ogg', + ) + +/mob/living/basic/bot/cleanbot/vroomba/Initialize(mapload) + . = ..() + qdel(GetComponent(/datum/component/cleaner)) //we don't want the default cleaner because it doesn't have the stuff we want (doesnt remove itself when in combat mode) + + AddElement(/datum/element/dextrous) + AddComponent(/datum/component/basic_inhands) + + change_number_of_hands(0) //it only has hands when it is in combat mode, so start with no usable hands while still having the components + + AddElement(/datum/element/hat_wearer,\ + offsets = hat_offsets,) + + AddComponent(/datum/component/cleaner/vroomba, \ + base_cleaning_duration = 2 SECONDS, \ + pre_clean_callback = CALLBACK(src, PROC_REF(update_bot_mode), BOT_CLEANING), \ + on_cleaned_callback = CALLBACK(src, PROC_REF(update_bot_mode), BOT_IDLE), \ + ) + prepare_huds() + +//it will not get job titles like cleanbots. +/mob/living/basic/bot/cleanbot/vroomba/update_title(new_job_title) + return + +//boom boom +/mob/living/basic/bot/cleanbot/vroomba/explode() + visible_message(span_boldnotice("[src] blows apart!")) + do_sparks(3, TRUE, src) + explosion(src, heavy_impact_range = 0, light_impact_range = 4) + + var/atom/location_destroyed = drop_location() + if(prob(50)) + drop_part(tractor_field, location_destroyed) + +//the sprite doesn't show up unless I do this +/mob/living/basic/bot/cleanbot/vroomba/update_icon_state() + SHOULD_CALL_PARENT(FALSE) + return SEND_SIGNAL(src, COMSIG_ATOM_UPDATE_ICON_STATE) + +/mob/living/basic/bot/cleanbot/vroomba/set_combat_mode(new_mode, silent) + . = ..() + SEND_SIGNAL(src, COMSIG_COMBAT_MODE) + if(combat_mode) + go_angry() + else + calm_down() + + prepare_huds() + +///The vroomba activating its hidden combat capabilities! +/mob/living/basic/bot/cleanbot/vroomba/proc/go_angry() + icon_state = flying_icon + set_varspeed(combat_speed) + layer = MOB_LAYER + + ADD_TRAIT(src, TRAIT_MOVE_FLYING, ELEMENT_TRAIT(type)) + + AddComponent(/datum/component/tractorfield/vroomba) //this one removes itself when it is not in combat mode to avoid bugs. :) + + change_number_of_hands(2) + + balloon_alert_to_viewers("gravity shifts!", vision_distance = 4) //When it turns on, it will make gravity feel funny. + playsound(src, combat_sound, 70, ignore_walls = FALSE) + + +///the vroomba hiding its combat capabilities! +/mob/living/basic/bot/cleanbot/vroomba/proc/calm_down() + icon_state = base_icon_state + set_varspeed(3) + layer = ABOVE_NORMAL_TURF_LAYER + + AddComponent(/datum/component/cleaner/vroomba, \ + base_cleaning_duration = 2 SECONDS, \ + pre_clean_callback = CALLBACK(src, PROC_REF(update_bot_mode), BOT_CLEANING), \ + on_cleaned_callback = CALLBACK(src, PROC_REF(update_bot_mode), BOT_IDLE), \ + ) + REMOVE_TRAIT(src, TRAIT_MOVE_FLYING, ELEMENT_TRAIT(type)) + + change_number_of_hands(0) + +///The vroomba is not killed by EMPs but it does stun it for a short moment. +/mob/living/basic/bot/cleanbot/vroomba/emp_act(severity) + . = ..() + switch(severity) + if(EMP_LIGHT) + visible_message(span_danger("[src] jitters, but is unharmed!")) + Stun(0.5 SECONDS) + Shake(duration = 0.5 SECONDS) + if(EMP_HEAVY) + visible_message(span_danger("[src] readjusts some servos!")) + Stun(3 SECONDS) + Shake(duration = 3 SECONDS) + to_chat(src, span_danger("WARN: EMP DETECTED.")) + +/mob/living/basic/bot/cleanbot/vroomba/generate_speak_list() + var/static/list/finalized_speak_list = (announcements) + return finalized_speak_list + +//default one doesn't work as intended. +/mob/living/basic/bot/cleanbot/vroomba/change_number_of_hands(amt) + if(amt < held_items.len) + if(amt == 0) + for(var/i in held_items.len to amt+1 step -1) + dropItemToGround(held_items[i]) + else + for(var/i in held_items.len to amt step -1) + dropItemToGround(held_items[i]) + held_items.len = amt + if(hud_used) + hud_used.build_hand_slots() + +//default one sprays acid on people, this removes it. +/mob/living/basic/bot/cleanbot/vroomba/pre_attack(mob/living/source, atom/target, proximity, modifiers) + if(!proximity || !can_unarmed_attack()) + return NONE + + if(is_type_in_typecache(target, huntable_pests) && !isnull(our_mop)) + INVOKE_ASYNC(our_mop, TYPE_PROC_REF(/obj/item, melee_attack_chain), src, target) + target.acid_act(75, 10) + return COMPONENT_CANCEL_ATTACK_CHAIN + + if(!iscarbon(target) && !is_type_in_typecache(target, huntable_trash)) + return NONE + + if(combat_mode) + melee_attack(target) + + return NONE + +/mob/living/basic/bot/cleanbot/vroomba/melee_attack(atom/target, list/modifiers, ignore_cooldown = FALSE) + . = ..() + visible_message(span_danger("[src] flies into [target]!")) diff --git a/maplestation_modules/story_content/volkan_equipment/icons/companions.dmi b/maplestation_modules/story_content/volkan_equipment/icons/companions.dmi index c3f5fa3b2011..3eeb51645e80 100644 Binary files a/maplestation_modules/story_content/volkan_equipment/icons/companions.dmi and b/maplestation_modules/story_content/volkan_equipment/icons/companions.dmi differ diff --git a/maplestation_modules/story_content/volkan_equipment/icons/misc_items.dmi b/maplestation_modules/story_content/volkan_equipment/icons/misc_items.dmi index 925cb9640a17..9bc2dd9624c4 100644 Binary files a/maplestation_modules/story_content/volkan_equipment/icons/misc_items.dmi and b/maplestation_modules/story_content/volkan_equipment/icons/misc_items.dmi differ