diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm index d89743d2d2..d595abd3ec 100644 --- a/code/__DEFINES/misc.dm +++ b/code/__DEFINES/misc.dm @@ -427,6 +427,7 @@ GLOBAL_LIST_INIT(pda_reskins, list(PDA_SKIN_CLASSIC = 'icons/obj/pda.dmi', PDA_S //Dummy mob reserve slots #define DUMMY_HUMAN_SLOT_PREFERENCES "dummy_preference_preview" +#define DUMMY_HUMAN_SLOT_HOLOFORM "dummy_holoform_generation" #define DUMMY_HUMAN_SLOT_ADMIN "admintools" #define DUMMY_HUMAN_SLOT_MANIFEST "dummy_manifest_generation" @@ -529,4 +530,10 @@ GLOBAL_LIST_INIT(pda_reskins, list(PDA_SKIN_CLASSIC = 'icons/obj/pda.dmi', PDA_S #define CRYOMOBS 'icons/obj/cryo_mobs.dmi' +#define CUSTOM_HOLOFORM_DELAY 10 SECONDS //prevents spamming to make lag. it's pretty expensive to do this. + +#define HOLOFORM_FILTER_AI "FILTER_AI" +#define HOLOFORM_FILTER_PAI "FILTER_PAI" +#define HOLOFORM_FILTER_STATIC "FILTER_STATIC" + #define CANT_REENTER_ROUND -1 diff --git a/code/__HELPERS/custom_holoforms.dm b/code/__HELPERS/custom_holoforms.dm new file mode 100644 index 0000000000..0e97314f1f --- /dev/null +++ b/code/__HELPERS/custom_holoforms.dm @@ -0,0 +1,62 @@ +// Generates a holoform appearance +// Equipment list is slot = path. +/proc/generate_custom_holoform_from_prefs(datum/preferences/prefs, list/equipment_by_slot, list/inhand_equipment, copy_job = FALSE, apply_loadout = FALSE) + ASSERT(prefs) + var/mob/living/carbon/human/dummy/mannequin = generate_or_wait_for_human_dummy(DUMMY_HUMAN_SLOT_HOLOFORM) + prefs.copy_to(mannequin) + if(apply_loadout && prefs.parent) + SSjob.equip_loadout(prefs.parent.mob, mannequin, bypass_prereqs = TRUE) + if(copy_job) + var/datum/job/highest = prefs.get_highest_job() + if(highest && !istype(highest, /datum/job/ai) && !istype(highest, /datum/job/cyborg)) + highest.equip(mannequin, TRUE, preference_source = prefs.parent) + + if(length(equipment_by_slot)) + for(var/slot in equipment_by_slot) + var/obj/item/I = new equipment_by_slot[slot] + mannequin.equip_to_slot_if_possible(I, slot, TRUE, TRUE, TRUE, TRUE) + if(length(inhand_equipment)) + for(var/path in inhand_equipment) + var/obj/item/I = new path + mannequin.equip_to_slot_if_possible(I, SLOT_HANDS, TRUE, TRUE, TRUE, TRUE) + + + var/icon/combined = new + for(var/d in GLOB.cardinals) + mannequin.setDir(d) + COMPILE_OVERLAYS(mannequin) + CHECK_TICK + var/icon/capture = getFlatIcon(mannequin) + CHECK_TICK + combined.Insert(capture, dir = d) + CHECK_TICK + + unset_busy_human_dummy(DUMMY_HUMAN_SLOT_HOLOFORM) + return combined + +/proc/process_holoform_icon_filter(icon/I, filter_type, clone = TRUE) + if(clone) + I = icon(I) //Clone + switch(filter_type) + if(HOLOFORM_FILTER_AI) + I = getHologramIcon(I) + if(HOLOFORM_FILTER_STATIC) + I = getStaticIcon(I) + if(HOLOFORM_FILTER_PAI) + I = getPAIHologramIcon(I) + return I + +//Errors go to user. +/proc/generate_custom_holoform_from_prefs_safe(datum/preferences/prefs, mob/user) + if(user) + if(user.client.prefs.last_custom_holoform > world.time - CUSTOM_HOLOFORM_DELAY) + to_chat(user, "You are attempting to set your custom holoform too fast!") + return + return generate_custom_holoform_from_prefs(prefs, null, null, TRUE, TRUE) + +//Prompts this client for custom holoform parameters. +/proc/user_interface_custom_holoform(client/C) + var/datum/preferences/target_prefs = C.prefs + ASSERT(target_prefs) + //In the future, maybe add custom path allowances a la admin create outfit but for now.. + return generate_custom_holoform_from_prefs_safe(target_prefs, C.mob) diff --git a/code/__HELPERS/icons.dm b/code/__HELPERS/icons.dm index 5fb64004c0..1af3143d9d 100644 --- a/code/__HELPERS/icons.dm +++ b/code/__HELPERS/icons.dm @@ -939,7 +939,7 @@ world I.pixel_y++ add_overlay(I)//And finally add the overlay. -/proc/getHologramIcon(icon/A, safety=1)//If safety is on, a new icon is not created. +/proc/getHologramIcon(icon/A, safety = TRUE)//If safety is on, a new icon is not created. var/icon/flat_icon = safety ? A : new(A)//Has to be a new icon to not constantly change the same icon. flat_icon.ColorTone(rgb(125,180,225))//Let's make it bluish. flat_icon.ChangeOpacity(0.5)//Make it half transparent. @@ -947,6 +947,14 @@ world flat_icon.AddAlphaMask(alpha_mask)//Finally, let's mix in a distortion effect. return flat_icon +/proc/getPAIHologramIcon(icon/A, safety = TRUE) + var/icon/flat_icon = safety? A : new(A) + flat_icon.SetIntensity(0.75, 1, 0.75) + flat_icon.ChangeOpacity(0.7) + var/icon/alpha_mask = new('icons/effects/effects.dmi', "scanlineslow")//Scanline effect. + flat_icon.AddAlphaMask(alpha_mask)//Finally, let's mix in a distortion effect. + return flat_icon + //What the mob looks like as animated static //By vg's ComicIronic /proc/getStaticIcon(icon/A, safety = TRUE) diff --git a/code/controllers/configuration/entries/game_options.dm b/code/controllers/configuration/entries/game_options.dm index 61b5788ef8..b95ef43d37 100644 --- a/code/controllers/configuration/entries/game_options.dm +++ b/code/controllers/configuration/entries/game_options.dm @@ -386,6 +386,8 @@ config_entry_value = 72000 min_val = 0 +/datum/config_entry/flag/pai_custom_holoforms + /datum/config_entry/number/marauder_delay_non_reebe config_entry_value = 1800 min_val = 0 diff --git a/code/controllers/subsystem/job.dm b/code/controllers/subsystem/job.dm index af7ae825f4..7597a9229a 100644 --- a/code/controllers/subsystem/job.dm +++ b/code/controllers/subsystem/job.dm @@ -658,7 +658,7 @@ SUBSYSTEM_DEF(job) message_admins(msg) CRASH(msg) -/datum/controller/subsystem/job/proc/equip_loadout(mob/dead/new_player/N, mob/living/M, equipbackpackstuff) +/datum/controller/subsystem/job/proc/equip_loadout(mob/dead/new_player/N, mob/living/M, equipbackpackstuff, bypass_prereqs = FALSE) var/mob/the_mob = N if(!the_mob) the_mob = M // cause this doesn't get assigned if player is a latejoiner @@ -671,7 +671,7 @@ SUBSYSTEM_DEF(job) if(!G) continue var/permitted = TRUE - if(G.restricted_roles && G.restricted_roles.len && !(M.mind.assigned_role in G.restricted_roles)) + if(!bypass_prereqs && G.restricted_roles && G.restricted_roles.len && !(M.mind.assigned_role in G.restricted_roles)) permitted = FALSE if(G.donoritem && !G.donator_ckey_check(the_mob.client.ckey)) permitted = FALSE diff --git a/code/datums/emotes.dm b/code/datums/emotes.dm index f0fca5db5a..599c492d4c 100644 --- a/code/datums/emotes.dm +++ b/code/datums/emotes.dm @@ -136,9 +136,10 @@ /datum/emote/sound var/sound //Sound to play when emote is called var/vary = FALSE //used for the honk borg emote + var/volume = 50 mob_type_allowed_typecache = list(/mob/living/brain, /mob/living/silicon) /datum/emote/sound/run_emote(mob/user, params) . = ..() if(.) - playsound(user.loc, sound, 50, vary) + playsound(user.loc, sound, volume, vary) diff --git a/code/game/machinery/hologram.dm b/code/game/machinery/hologram.dm index 1e7d720ee9..b1783ba940 100644 --- a/code/game/machinery/hologram.dm +++ b/code/game/machinery/hologram.dm @@ -500,7 +500,7 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/ else return FALSE -/obj/machinery/holopad/proc/move_hologram(mob/living/user, turf/new_turf) +/obj/machinery/holopad/proc/move_hologram(mob/living/user, turf/new_turf, direction) if(LAZYLEN(masters) && masters[user]) var/obj/effect/overlay/holo_pad_hologram/holo = masters[user] var/transfered = FALSE @@ -512,6 +512,8 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/ transfered = TRUE //All is good. holo.forceMove(new_turf) + if(direction) + holo.setDir(direction) if(!transfered) update_holoray(user,new_turf) return TRUE diff --git a/code/game/objects/buckling.dm b/code/game/objects/buckling.dm index 9c3df5395f..416644cada 100644 --- a/code/game/objects/buckling.dm +++ b/code/game/objects/buckling.dm @@ -107,7 +107,7 @@ //Wrapper procs that handle sanity and user feedback /atom/movable/proc/user_buckle_mob(mob/living/M, mob/user, check_loc = TRUE) - if(!in_range(user, src) || !isturf(user.loc) || user.incapacitated() || M.anchored) + if(!in_range(user, src) || !isturf(user.loc) || user.incapacitated() || M.anchored || !user.can_buckle_others(M, src)) return FALSE add_fingerprint(user) diff --git a/code/game/objects/items/devices/paicard.dm b/code/game/objects/items/devices/paicard.dm index 7dc2f1d60b..3ee4a14a91 100644 --- a/code/game/objects/items/devices/paicard.dm +++ b/code/game/objects/items/devices/paicard.dm @@ -8,7 +8,8 @@ w_class = WEIGHT_CLASS_SMALL slot_flags = ITEM_SLOT_BELT var/mob/living/silicon/pai/pai - resistance_flags = FIRE_PROOF | ACID_PROOF | INDESTRUCTIBLE + resistance_flags = FIRE_PROOF | ACID_PROOF + max_integrity = 200 /obj/item/paicard/suicide_act(mob/living/user) user.visible_message("[user] is staring sadly at [src]! [user.p_they()] can't keep living without real human intimacy!") @@ -45,6 +46,8 @@ dat += "Radio Uplink
" dat += "Transmit: [(pai.radio.wires.is_cut(WIRE_TX)) ? "Disabled" : "Enabled"]
" dat += "Receive: [(pai.radio.wires.is_cut(WIRE_RX)) ? "Disabled" : "Enabled"]
" + if(pai.radio_short) + dat += "Reset radio short: \[RESET\]
" else dat += "Radio Uplink
" dat += "Radio firmware not loaded. Please install a pAI personality to load firmware.
" @@ -82,7 +85,6 @@ pai.master = M.real_name pai.master_dna = M.dna.unique_enzymes to_chat(pai, "You have been bound to a new master.") - pai.emittersemicd = FALSE if(href_list["wipe"]) var/confirm = input("Are you CERTAIN you wish to delete the current personality? This action cannot be undone.", "Personality Wipe") in list("Yes", "No") if(confirm == "Yes") @@ -96,6 +98,8 @@ var/wire = text2num(href_list["wires"]) if(pai.radio) pai.radio.wires.cut(wire) + if(href_list["reset_radio_short"]) + pai.unshort_radio() if(href_list["setlaws"]) var/newlaws = copytext(sanitize(input("Enter any additional directives you would like your pAI personality to follow. Note that these directives will not override the personality's allegiance to its imprinted master. Conflicting directives will be ignored.", "pAI Directive Configuration", pai.laws.supplied[1]) as message),1,MAX_MESSAGE_LEN) if(newlaws && pai) diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index 96a32d50e6..7b7cf3413e 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -21,6 +21,10 @@ GLOBAL_LIST_EMPTY(preferences_datums) var/last_ip var/last_id + var/icon/custom_holoform_icon + var/list/cached_holoform_icons + var/last_custom_holoform = 0 + //Cooldowns for saving/loading. These are four are all separate due to loading code calling these one after another var/saveprefcooldown var/loadprefcooldown @@ -2422,3 +2426,11 @@ GLOBAL_LIST_EMPTY(preferences_datums) return else custom_names[name_id] = sanitized_name + +/datum/preferences/proc/get_filtered_holoform(filter_type) + if(!custom_holoform_icon) + return + LAZYINITLIST(cached_holoform_icons) + if(!cached_holoform_icons[filter_type]) + cached_holoform_icons[filter_type] = process_holoform_icon_filter(custom_holoform_icon, filter_type) + return cached_holoform_icons[filter_type] diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm index d9e967e54d..6fd1584e75 100644 --- a/code/modules/clothing/clothing.dm +++ b/code/modules/clothing/clothing.dm @@ -57,7 +57,6 @@ //No idea what this is but eh -tori var/force_alternate_icon = FALSE - /obj/item/clothing/Initialize() . = ..() if(CHECK_BITFIELD(clothing_flags, VOICEBOX_TOGGLABLE)) diff --git a/code/modules/mob/dead/new_player/preferences_setup.dm b/code/modules/mob/dead/new_player/preferences_setup.dm index 7aae26526e..5b664dc01a 100644 --- a/code/modules/mob/dead/new_player/preferences_setup.dm +++ b/code/modules/mob/dead/new_player/preferences_setup.dm @@ -27,12 +27,7 @@ /datum/preferences/proc/update_preview_icon(equip_job = TRUE) // Determine what job is marked as 'High' priority, and dress them up as such. - var/datum/job/previewJob - var/highest_pref = 0 - for(var/job in job_preferences) - if(job_preferences["[job]"] > highest_pref) - previewJob = SSjob.GetJob(job) - highest_pref = job_preferences["[job]"] + var/datum/job/previewJob = get_highest_job() if(previewJob) // Silicons only need a very basic preview since there is no customization for them. @@ -57,3 +52,11 @@ parent.show_character_previews(new /mutable_appearance(mannequin)) unset_busy_human_dummy(DUMMY_HUMAN_SLOT_PREFERENCES) +/datum/preferences/proc/get_highest_job() + var/highest_pref = 0 + var/datum/job/highest_job + for(var/job in job_preferences) + if(job_preferences["[job]"] > highest_pref) + highest_job = SSjob.GetJob(job) + highest_pref = job_preferences["[job]"] + return highest_job diff --git a/code/modules/mob/living/carbon/alien/larva/larva.dm b/code/modules/mob/living/carbon/alien/larva/larva.dm index e1e079cbae..8e1e5aab8d 100644 --- a/code/modules/mob/living/carbon/alien/larva/larva.dm +++ b/code/modules/mob/living/carbon/alien/larva/larva.dm @@ -14,10 +14,9 @@ var/max_grown = 100 var/time_of_birth - rotate_on_lying = 0 + rotate_on_lying = FALSE bodyparts = list(/obj/item/bodypart/chest/larva, /obj/item/bodypart/head/larva) - //This is fine right now, if we're adding organ specific damage this needs to be updated /mob/living/carbon/alien/larva/Initialize() diff --git a/code/modules/mob/living/carbon/carbon_defines.dm b/code/modules/mob/living/carbon/carbon_defines.dm index a1184613fe..9629dc3484 100644 --- a/code/modules/mob/living/carbon/carbon_defines.dm +++ b/code/modules/mob/living/carbon/carbon_defines.dm @@ -40,7 +40,7 @@ var/gib_type = /obj/effect/decal/cleanable/blood/gibs - var/rotate_on_lying = 1 + rotate_on_lying = TRUE var/tinttotal = 0 // Total level of visualy impairing items diff --git a/code/modules/mob/living/carbon/emote.dm b/code/modules/mob/living/carbon/emote.dm index 345279df29..559c2ebcdd 100644 --- a/code/modules/mob/living/carbon/emote.dm +++ b/code/modules/mob/living/carbon/emote.dm @@ -22,6 +22,7 @@ muzzle_ignore = TRUE restraint_check = TRUE emote_type = EMOTE_AUDIBLE + mob_type_allowed_typecache = list(/mob/living/carbon, /mob/living/silicon/pai) /datum/emote/living/carbon/clap/run_emote(mob/living/user, params) . = ..() diff --git a/code/modules/mob/living/carbon/update_icons.dm b/code/modules/mob/living/carbon/update_icons.dm index 66be8058f1..0155f2575d 100644 --- a/code/modules/mob/living/carbon/update_icons.dm +++ b/code/modules/mob/living/carbon/update_icons.dm @@ -1,31 +1,3 @@ -//IMPORTANT: Multiple animate() calls do not stack well, so try to do them all at once if you can. -/mob/living/carbon/update_transform() - var/matrix/ntransform = matrix(transform) //aka transform.Copy() - var/final_pixel_y = pixel_y - var/final_dir = dir - var/changed = 0 - if(lying != lying_prev && rotate_on_lying) - changed++ - ntransform.TurnTo(lying_prev,lying) - if(lying == 0) //Lying to standing - final_pixel_y = get_standard_pixel_y_offset() - else //if(lying != 0) - if(lying_prev == 0) //Standing to lying - pixel_y = get_standard_pixel_y_offset() - final_pixel_y = get_standard_pixel_y_offset(lying) - if(dir & (EAST|WEST)) //Facing east or west - final_dir = pick(NORTH, SOUTH) //So you fall on your side rather than your face or ass - - if(resize != RESIZE_DEFAULT_SIZE) - changed++ - ntransform.Scale(resize) - resize = RESIZE_DEFAULT_SIZE - - if(changed) - animate(src, transform = ntransform, time = 2, pixel_y = final_pixel_y, dir = final_dir, easing = EASE_IN|EASE_OUT) - setMovetype(movement_type & ~FLOATING) // If we were without gravity, the bouncing animation got stopped, so we make sure we restart it in next life(). - - /mob/living/carbon var/list/overlays_standing[TOTAL_LAYERS] diff --git a/code/modules/mob/living/living_defines.dm b/code/modules/mob/living/living_defines.dm index 4d2a36907d..783e044492 100644 --- a/code/modules/mob/living/living_defines.dm +++ b/code/modules/mob/living/living_defines.dm @@ -111,4 +111,6 @@ var/list/diseases = list() // list of all diseases in a mob var/list/disease_resistances = list() - var/drag_slowdown = TRUE //Whether the mob is slowed down when dragging another prone mob \ No newline at end of file + var/drag_slowdown = TRUE //Whether the mob is slowed down when dragging another prone mob + + var/rotate_on_lying = FALSE \ No newline at end of file diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm index ac67d16d35..1694d04b82 100644 --- a/code/modules/mob/living/silicon/ai/ai.dm +++ b/code/modules/mob/living/silicon/ai/ai.dm @@ -672,18 +672,23 @@ "green face" = 'icons/mob/ai.dmi', "xeno queen" = 'icons/mob/alien.dmi', "horror" = 'icons/mob/ai.dmi', - "creature" = 'icons/mob/ai.dmi' + "creature" = 'icons/mob/ai.dmi', + "custom" ) input = input("Please select a hologram:") as null|anything in icon_list if(input) qdel(holo_icon) switch(input) - if("xeno queen") + if("custom") + if(client?.prefs?.custom_holoform_icon) + holo_icon = client.prefs.get_filtered_holoform(HOLOFORM_FILTER_AI) + else + holo_icon = getHologramIcon(icon('icons/mob/ai.dmi', "female")) + else if("xeno queen") holo_icon = getHologramIcon(icon(icon_list[input],"alienq")) else holo_icon = getHologramIcon(icon(icon_list[input], input)) - return /mob/living/silicon/ai/proc/corereturn() set category = "Malfunction" diff --git a/code/modules/mob/living/silicon/ai/freelook/eye.dm b/code/modules/mob/living/silicon/ai/freelook/eye.dm index 7477ba7713..38afaf8313 100644 --- a/code/modules/mob/living/silicon/ai/freelook/eye.dm +++ b/code/modules/mob/living/silicon/ai/freelook/eye.dm @@ -68,7 +68,7 @@ // Use this when setting the aiEye's location. // It will also stream the chunk that the new loc is in. -/mob/camera/aiEye/proc/setLoc(T, force_update = FALSE) +/mob/camera/aiEye/proc/setLoc(T, force_update = FALSE, dir) if(ai) if(!isturf(ai.loc)) return @@ -88,7 +88,7 @@ //Holopad if(istype(ai.current, /obj/machinery/holopad)) var/obj/machinery/holopad/H = ai.current - H.move_hologram(ai, T) + H.move_hologram(ai, T, dir) if(ai.camera_light_on) ai.light_cameras() if(ai.master_multicam) @@ -139,7 +139,7 @@ for(var/i = 0; i < max(user.sprint, initial); i += 20) var/turf/step = get_turf(get_step(user.eyeobj, direct)) if(step) - user.eyeobj.setLoc(step) + user.eyeobj.setLoc(step, null, direct) user.cooldown = world.timeofday + 5 if(user.acceleration) diff --git a/code/modules/mob/living/silicon/custom_holoform.dm b/code/modules/mob/living/silicon/custom_holoform.dm new file mode 100644 index 0000000000..8ce6e9a29a --- /dev/null +++ b/code/modules/mob/living/silicon/custom_holoform.dm @@ -0,0 +1,28 @@ +/mob/living/silicon/verb/clear_custom_holoform() + set name = "Clear Custom Holoform" + set desc = "Clear your current custom holoform" + set category = "OOC" + + if(!client.prefs) + to_chat(src, "No preferences datum on your client, contact an admin/coder!") + return + client.prefs.custom_holoform_icon = null + client.prefs.cached_holoform_icons = null + to_chat(src, "Holoform removed.") + +/mob/living/silicon/verb/set_custom_holoform() + set name = "Set Custom Holoform" + set desc = "Set your custom holoform using your current preferences slot and a specified set of gear." + set category = "OOC" + + if(!client.prefs) + to_chat(src, "No preferences datum on your client, contact an admin/coder!") + return + if(client.prefs.last_custom_holoform > world.time - CUSTOM_HOLOFORM_DELAY) + to_chat(src, "You are attempting to change custom holoforms too fast!") + var/icon/new_holoform = user_interface_custom_holoform(client) + if(new_holoform) + client.prefs.custom_holoform_icon = new_holoform + client.prefs.cached_holoform_icons = null + client.prefs.last_custom_holoform = world.time + to_chat(src, "Holoform set.") diff --git a/code/modules/mob/living/silicon/pai/pai.dm b/code/modules/mob/living/silicon/pai/pai.dm index 7ec63cf415..7055838039 100644 --- a/code/modules/mob/living/silicon/pai/pai.dm +++ b/code/modules/mob/living/silicon/pai/pai.dm @@ -58,10 +58,12 @@ var/canholo = TRUE var/obj/item/card/id/access_card = null var/chassis = "repairbot" - var/list/possible_chassis = list("cat" = TRUE, "mouse" = TRUE, "monkey" = TRUE, "corgi" = FALSE, - "fox" = FALSE, "repairbot" = TRUE, "rabbit" = TRUE, "borgi" = FALSE , - "parrot" = FALSE, "bear" = FALSE , "mushroom" = FALSE, "crow" = FALSE , - "fairy" = FALSE , "spiderbot" = FALSE) //assoc value is whether it can be picked up. + var/dynamic_chassis + var/dynamic_chassis_sit = FALSE //whether we're sitting instead of resting spritewise + var/dynamic_chassis_bellyup = FALSE //whether we're lying down bellyup + var/list/possible_chassis //initialized in initialize. + var/list/dynamic_chassis_icons //ditto. + var/list/chassis_pixel_offsets_x //stupid dogborgs var/static/item_head_icon = 'icons/mob/pai_item_head.dmi' var/static/item_lh_icon = 'icons/mob/pai_item_lh.dmi' var/static/item_rh_icon = 'icons/mob/pai_item_rh.dmi' @@ -69,22 +71,20 @@ var/emitterhealth = 20 var/emittermaxhealth = 20 var/emitterregen = 0.25 + var/emitter_next_use = 0 + var/emitter_emp_cd = 300 var/emittercd = 50 var/emitteroverloadcd = 100 - var/emittersemicd = FALSE - var/overload_ventcrawl = 0 - var/overload_bulletblock = 0 //Why is this a good idea? - var/overload_maxhealth = 0 + var/radio_short = FALSE + var/radio_short_cooldown = 5 MINUTES + var/radio_short_timerid + canmove = FALSE var/silent = FALSE var/brightness_power = 5 -/mob/living/silicon/pai/can_unbuckle() - return FALSE - -/mob/living/silicon/pai/can_buckle() - return FALSE + var/icon/custom_holoform_icon /mob/living/silicon/pai/Destroy() if (loc != card) @@ -118,6 +118,13 @@ pda.owner = text("[]", src) pda.name = pda.owner + " (" + pda.ownjob + ")" + possible_chassis = typelist(NAMEOF(src, possible_chassis), list("cat" = TRUE, "mouse" = TRUE, "monkey" = TRUE, "corgi" = FALSE, + "fox" = FALSE, "repairbot" = TRUE, "rabbit" = TRUE, "borgi" = FALSE , + "parrot" = FALSE, "bear" = FALSE , "mushroom" = FALSE, "crow" = FALSE , + "fairy" = FALSE , "spiderbot" = FALSE)) //assoc value is whether it can be picked up. + dynamic_chassis_icons = typelist(NAMEOF(src, dynamic_chassis_icons), initialize_dynamic_chassis_icons()) + chassis_pixel_offsets_x = typelist(NAMEOF(src, chassis_pixel_offsets_x), default_chassis_pixel_offsets_x()) + . = ..() var/datum/action/innate/pai/software/SW = new @@ -133,8 +140,7 @@ AR.Grant(src) AL.Grant(src) ALM.Grant(src) - emittersemicd = TRUE - addtimer(CALLBACK(src, .proc/emittercool), 600) + emitter_next_use = world.time + 10 SECONDS /mob/living/silicon/pai/Life() if(hacking) @@ -228,7 +234,7 @@ /datum/action/innate/pai/shell/Trigger() ..() if(P.holoform) - P.fold_in(0) + P.fold_in(FALSE) else P.fold_out() @@ -292,3 +298,132 @@ /mob/living/silicon/pai/process() emitterhealth = CLAMP((emitterhealth + emitterregen), -50, emittermaxhealth) + +/mob/living/silicon/pai/proc/short_radio() + if(radio_short_timerid) + deltimer(radio_short_timerid) + radio_short = TRUE + to_chat(src, "Your radio shorts out!") + radio_short_timerid = addtimer(CALLBACK(src, .proc/unshort_radio), radio_short_cooldown, flags = TIMER_STOPPABLE) + +/mob/living/silicon/pai/proc/unshort_radio() + radio_short = FALSE + to_chat(src, "You feel your radio is operational once more.") + if(radio_short_timerid) + deltimer(radio_short_timerid) + +/mob/living/silicon/pai/proc/initialize_dynamic_chassis_icons() + . = list() + var/icon/curr //for inserts + + //This is a horrible system and I wish I was not as lazy and did something smarter, like just generating a new icon in memory which is probably more efficient. + + //Basic /tg/ cyborgs + .["Cyborg - Engineering (default)"] = process_holoform_icon_filter(icon('icons/mob/robots.dmi', "engineer"), HOLOFORM_FILTER_PAI, FALSE) + .["Cyborg - Engineering (loaderborg)"] = process_holoform_icon_filter(icon('modular_citadel/icons/mob/robots.dmi', "loaderborg"), HOLOFORM_FILTER_PAI, FALSE) + .["Cyborg - Engineering (handyeng)"] = process_holoform_icon_filter(icon('modular_citadel/icons/mob/robots.dmi', "handyeng"), HOLOFORM_FILTER_PAI, FALSE) + .["Cyborg - Engineering (sleekeng)"] = process_holoform_icon_filter(icon('modular_citadel/icons/mob/robots.dmi', "sleekeng"), HOLOFORM_FILTER_PAI, FALSE) + .["Cyborg - Engineering (marinaeng)"] = process_holoform_icon_filter(icon('modular_citadel/icons/mob/robots.dmi', "marinaeng"), HOLOFORM_FILTER_PAI, FALSE) + .["Cyborg - Medical (default)"] = process_holoform_icon_filter(icon('icons/mob/robots.dmi', "medical"), HOLOFORM_FILTER_PAI, FALSE) + .["Cyborg - Medical (marinamed)"] = process_holoform_icon_filter(icon('modular_citadel/icons/mob/robots.dmi', "marinamed"), HOLOFORM_FILTER_PAI, FALSE) + .["Cyborg - Medical (eyebotmed)"] = process_holoform_icon_filter(icon('modular_citadel/icons/mob/robots.dmi', "eyebotmed"), HOLOFORM_FILTER_PAI, FALSE) + .["Cyborg - Security (default)"] = process_holoform_icon_filter(icon('icons/mob/robots.dmi', "sec"), HOLOFORM_FILTER_PAI, FALSE) + .["Cyborg - Security (sleeksec)"] = process_holoform_icon_filter(icon('modular_citadel/icons/mob/robots.dmi', "sleeksec"), HOLOFORM_FILTER_PAI, FALSE) + .["Cyborg - Security (marinasec)"] = process_holoform_icon_filter(icon('modular_citadel/icons/mob/robots.dmi', "marinasec"), HOLOFORM_FILTER_PAI, FALSE) + .["Cyborg - Clown (default)"] = process_holoform_icon_filter(icon('icons/mob/robots.dmi', "clown"), HOLOFORM_FILTER_PAI, FALSE) + + //Citadel dogborgs + //Engi + curr = icon('modular_citadel/icons/mob/widerobot.dmi', "valeeng") + curr.Insert(icon('modular_citadel/icons/mob/widerobot.dmi', "valeeng-rest"), "rest") + curr.Insert(icon('modular_citadel/icons/mob/widerobot.dmi', "valeeng-sit"), "sit") + curr.Insert(icon('modular_citadel/icons/mob/widerobot.dmi', "valeeng-bellyup"), "bellyup") + process_holoform_icon_filter(curr, HOLOFORM_FILTER_PAI, FALSE) + .["Cyborg - Engineering (dog - valeeng)"] = curr + curr = icon('modular_citadel/icons/mob/widerobot.dmi', "pupdozer") + curr.Insert(icon('modular_citadel/icons/mob/widerobot.dmi', "pupdozer-rest"), "rest") + curr.Insert(icon('modular_citadel/icons/mob/widerobot.dmi', "pupdozer-sit"), "sit") + curr.Insert(icon('modular_citadel/icons/mob/widerobot.dmi', "pupdozer-bellyup"), "bellyup") + process_holoform_icon_filter(curr, HOLOFORM_FILTER_PAI, FALSE) + .["Cyborg - Engineering (dog - pupdozer)"] = curr + //Med + curr = icon('modular_citadel/icons/mob/widerobot.dmi', "medihound") + curr.Insert(icon('modular_citadel/icons/mob/widerobot.dmi', "medihound-rest"), "rest") + curr.Insert(icon('modular_citadel/icons/mob/widerobot.dmi', "medihound-sit"), "sit") + curr.Insert(icon('modular_citadel/icons/mob/widerobot.dmi', "medihound-bellyup"), "bellyup") + process_holoform_icon_filter(curr, HOLOFORM_FILTER_PAI, FALSE) + .["Cyborg - Medical (dog - medihound)"] = curr + curr = icon('modular_citadel/icons/mob/widerobot.dmi', "medihounddark") + curr.Insert(icon('modular_citadel/icons/mob/widerobot.dmi', "medihounddark-rest"), "rest") + curr.Insert(icon('modular_citadel/icons/mob/widerobot.dmi', "medihounddark-sit"), "sit") + curr.Insert(icon('modular_citadel/icons/mob/widerobot.dmi', "medihounddark-bellyup"), "bellyup") + process_holoform_icon_filter(curr, HOLOFORM_FILTER_PAI, FALSE) + .["Cyborg - Medical (dog - medihounddark)"] = curr + curr = icon('modular_citadel/icons/mob/widerobot.dmi', "valemed") + curr.Insert(icon('modular_citadel/icons/mob/widerobot.dmi', "valemed-rest"), "rest") + curr.Insert(icon('modular_citadel/icons/mob/widerobot.dmi', "valemed-sit"), "sit") + curr.Insert(icon('modular_citadel/icons/mob/widerobot.dmi', "valemed-bellyup"), "bellyup") + process_holoform_icon_filter(curr, HOLOFORM_FILTER_PAI, FALSE) + .["Cyborg - Medical (dog - valemed)"] = curr + //Sec + curr = icon('modular_citadel/icons/mob/widerobot.dmi', "k9") + curr.Insert(icon('modular_citadel/icons/mob/widerobot.dmi', "k9-rest"), "rest") + curr.Insert(icon('modular_citadel/icons/mob/widerobot.dmi', "k9-sit"), "sit") + curr.Insert(icon('modular_citadel/icons/mob/widerobot.dmi', "k9-bellyup"), "bellyup") + process_holoform_icon_filter(curr, HOLOFORM_FILTER_PAI, FALSE) + .["Cyborg - Security (dog - k9)"] = curr + curr = icon('modular_citadel/icons/mob/widerobot.dmi', "k9dark") + curr.Insert(icon('modular_citadel/icons/mob/widerobot.dmi', "k9dark-rest"), "rest") + curr.Insert(icon('modular_citadel/icons/mob/widerobot.dmi', "k9dark-sit"), "sit") + curr.Insert(icon('modular_citadel/icons/mob/widerobot.dmi', "k9dark-bellyup"), "bellyup") + process_holoform_icon_filter(curr, HOLOFORM_FILTER_PAI, FALSE) + .["Cyborg - Security (dog - k9dark)"] = curr + curr = icon('modular_citadel/icons/mob/widerobot.dmi', "valesec") + curr.Insert(icon('modular_citadel/icons/mob/widerobot.dmi', "valesec-rest"), "rest") + curr.Insert(icon('modular_citadel/icons/mob/widerobot.dmi', "valesec-sit"), "sit") + curr.Insert(icon('modular_citadel/icons/mob/widerobot.dmi', "valesec-bellyup"), "bellyup") + process_holoform_icon_filter(curr, HOLOFORM_FILTER_PAI, FALSE) + .["Cyborg - Security (dog - valesec)"] = curr + //Service + curr = icon('modular_citadel/icons/mob/widerobot.dmi', "valeserv") + curr.Insert(icon('modular_citadel/icons/mob/widerobot.dmi', "valeserv-rest"), "rest") + curr.Insert(icon('modular_citadel/icons/mob/widerobot.dmi', "valeserv-sit"), "sit") + curr.Insert(icon('modular_citadel/icons/mob/widerobot.dmi', "valeserv-bellyup"), "bellyup") + process_holoform_icon_filter(curr, HOLOFORM_FILTER_PAI, FALSE) + .["Cyborg - Service (dog - valeserv)"] = curr + curr = icon('modular_citadel/icons/mob/widerobot.dmi', "valeservdark") + curr.Insert(icon('modular_citadel/icons/mob/widerobot.dmi', "valeservdark-rest"), "rest") + curr.Insert(icon('modular_citadel/icons/mob/widerobot.dmi', "valeservdark-sit"), "sit") + curr.Insert(icon('modular_citadel/icons/mob/widerobot.dmi', "valeservdark-bellyup"), "bellyup") + process_holoform_icon_filter(curr, HOLOFORM_FILTER_PAI, FALSE) + .["Cyborg - Service (dog - valeservdark)"] = curr + //Sci + curr = icon('modular_citadel/icons/mob/widerobot.dmi', "valesci") + curr.Insert(icon('modular_citadel/icons/mob/widerobot.dmi', "valesci-rest"), "rest") + curr.Insert(icon('modular_citadel/icons/mob/widerobot.dmi', "valesci-sit"), "sit") + curr.Insert(icon('modular_citadel/icons/mob/widerobot.dmi', "valesci-bellyup"), "bellyup") + process_holoform_icon_filter(curr, HOLOFORM_FILTER_PAI, FALSE) + .["Cyborg - Science (dog - valesci)"] = curr + //Misc + .["Cyborg - Misc (dog - blade)"] = process_holoform_icon_filter(icon('modular_citadel/icons/mob/widerobot.dmi', "blade"), HOLOFORM_FILTER_PAI, FALSE) + +/mob/living/silicon/pai/proc/default_chassis_pixel_offsets_x() + . = list() + //Engi + .["Cyborg - Engineering (dog - valeeng)"] = -16 + .["Cyborg - Engineering (dog - pupdozer)"] = -16 + //Med + .["Cyborg - Medical (dog - medihound)"] = -16 + .["Cyborg - Medical (dog - medihounddark)"] = -16 + .["Cyborg - Medical (dog - valemed)"] = -16 + //Sec + .["Cyborg - Security (dog - k9)"] = -16 + .["Cyborg - Security (dog - valesec)"] = -16 + .["Cyborg - Security (dog - k9dark)"] = -16 + //Service + .["Cyborg - Service (dog - valeserv)"] = -16 + .["Cyborg - Service (dog - valeservdark)"] = -16 + //Sci + .["Cyborg - Security (dog - valesci)"] = -16 + //Misc + .["Cyborg - Misc (dog - blade)"] = -16 diff --git a/code/modules/mob/living/silicon/pai/pai_defense.dm b/code/modules/mob/living/silicon/pai/pai_defense.dm index 5ac841326b..c727e100d8 100644 --- a/code/modules/mob/living/silicon/pai/pai_defense.dm +++ b/code/modules/mob/living/silicon/pai/pai_defense.dm @@ -8,9 +8,10 @@ return take_holo_damage(50/severity) Knockdown(400/severity) - silent = max(30/severity, silent) + silent = max((3 MINUTES)/severity, silent) if(holoform) fold_in(force = TRUE) + emitter_next_use = world.time + emitter_emp_cd //Need more effects that aren't instadeath or permanent law corruption. /mob/living/silicon/pai/ex_act(severity, target) diff --git a/code/modules/mob/living/silicon/pai/pai_shell.dm b/code/modules/mob/living/silicon/pai/pai_shell.dm index 164a3e7389..6577c26402 100644 --- a/code/modules/mob/living/silicon/pai/pai_shell.dm +++ b/code/modules/mob/living/silicon/pai/pai_shell.dm @@ -12,12 +12,11 @@ . = fold_in(force) return - if(emittersemicd) + if(world.time < emitter_next_use) to_chat(src, "Error: Holochassis emitters recycling. Please try again later.") return FALSE - emittersemicd = TRUE - addtimer(CALLBACK(src, .proc/emittercool), emittercd) + emitter_next_use = world.time + emittercd canmove = TRUE density = TRUE if(istype(card.loc, /obj/item/pda)) @@ -46,20 +45,17 @@ visible_message("[src] folds out its holochassis emitter and forms a holoshell around itself!") holoform = TRUE -/mob/living/silicon/pai/proc/emittercool() - emittersemicd = FALSE - /mob/living/silicon/pai/proc/fold_in(force = FALSE) - emittersemicd = TRUE - if(!force) - addtimer(CALLBACK(src, .proc/emittercool), emittercd) - else - addtimer(CALLBACK(src, .proc/emittercool), emitteroverloadcd) + emitter_next_use = world.time + (force? emitteroverloadcd : emittercd) icon_state = "[chassis]" if(!holoform) . = fold_out(force) return - visible_message("[src] deactivates its holochassis emitter and folds back into a compact card!") + if(force) + short_radio() + visible_message("[src] shorts out, collapsing back into their storage card, sparks emitted from their radio antenna!") + else + visible_message("[src] deactivates its holochassis emitter and folds back into a compact card!") stop_pulling() if(client) client.perspective = EYE_PERSPECTIVE @@ -78,28 +74,39 @@ if(!isturf(loc) && loc != card) to_chat(src, "You can not change your holochassis composite while not on the ground or in your card!") return FALSE - var/choice = input(src, "What would you like to use for your holochassis composite?") as null|anything in possible_chassis - if(!choice) + var/list/choices = list("Preset - Basic", "Preset - Dynamic") + if(CONFIG_GET(flag/pai_custom_holoforms)) + choices += "Custom" + var/choicetype = input(src, "What type of chassis do you want to use?") as null|anything in choices + if(!choicetype) return FALSE - chassis = choice - icon_state = "[chassis]" - if(resting) - icon_state = "[chassis]_rest" + switch(choicetype) + if("Custom") + chassis = "custom" + if("Preset - Basic") + var/choice = input(src, "What would you like to use for your holochassis composite?") as null|anything in possible_chassis + if(!choice) + return FALSE + chassis = choice + if("Preset - Dynamic") + var/choice = input(src, "What would you like to use for your holochassis composite?") as null|anything in dynamic_chassis_icons + if(!choice) + return FALSE + chassis = "dynamic" + dynamic_chassis = choice + resist_a_rest(FALSE, TRUE) + update_icon() to_chat(src, "You switch your holochassis projection composite to [chassis]") /mob/living/silicon/pai/lay_down() - ..() - update_resting_icon(resting) - -/mob/living/silicon/pai/proc/update_resting_icon(rest) - if(rest) - icon_state = "[chassis]_rest" - else - icon_state = "[chassis]" + . = ..() if(loc != card) - visible_message("[src] [rest? "lays down for a moment..." : "perks up from the ground"]") + visible_message("[src] [resting? "lays down for a moment..." : "perks up from the ground"]") + update_icon() -/mob/living/silicon/pai/start_pulling(atom/movable/AM) +/mob/living/silicon/pai/start_pulling(atom/movable/AM, gs) + if(ispAI(AM)) + return ..() return FALSE /mob/living/silicon/pai/proc/toggle_integrated_light() @@ -122,3 +129,22 @@ to_chat(user, "[src]'s current form isn't able to be carried!") return FALSE return ..() + +/mob/living/silicon/pai/verb/toggle_chassis_sit() + set name = "Toggle Chassis Sit" + set category = "IC" + set desc = "Whether or not to try to use a sitting icon versus a resting icon. Takes priority over belly-up resting." + dynamic_chassis_sit = !dynamic_chassis_sit + to_chat(usr, "You are now [dynamic_chassis_sit? "sitting" : "lying down"].") + update_icon() + +/mob/living/silicon/pai/verb/toggle_chassis_bellyup() + set name = "Toggle Chassis Belly Up" + set category = "IC" + set desc = "Whether or not to try to use a belly up icon while resting. Overridden by sitting." + dynamic_chassis_bellyup = !dynamic_chassis_bellyup + to_chat(usr, "You are now lying on your [dynamic_chassis_bellyup? "back" : "front"].") + update_icon() + +/mob/living/silicon/pai/can_buckle_others(mob/living/target, atom/buckle_to) + return ispAI(target) && ..() diff --git a/code/modules/mob/living/silicon/pai/say.dm b/code/modules/mob/living/silicon/pai/say.dm index 9f07900a25..deedaa1382 100644 --- a/code/modules/mob/living/silicon/pai/say.dm +++ b/code/modules/mob/living/silicon/pai/say.dm @@ -5,4 +5,11 @@ ..(message) /mob/living/silicon/pai/binarycheck() - return 0 + return FALSE + +/mob/living/silicon/pai/radio(message, message_mode, list/spans, language) + if((message_mode == "robot") || (message_mode in GLOB.radiochannels)) + if(radio_short) + to_chat(src, "Your radio is shorted out!") + return ITALICS | REDUCE_RANGE + return ..() diff --git a/code/modules/mob/living/silicon/pai/software.dm b/code/modules/mob/living/silicon/pai/software.dm index 9882d028d1..3ea018ccf6 100644 --- a/code/modules/mob/living/silicon/pai/software.dm +++ b/code/modules/mob/living/silicon/pai/software.dm @@ -283,7 +283,10 @@ dat += "Refresh
" // Built-in dat += "Directives
" - dat += "Radio Configuration
" + if(radio_short) + dat += "\[RADIO SHORTED - Recalibrating!\]" + else + dat += "Radio Configuration
" dat += "Screen Display
" //dat += "Text Messaging
" dat += "
" diff --git a/code/modules/mob/living/silicon/pai/update_icon.dm b/code/modules/mob/living/silicon/pai/update_icon.dm new file mode 100644 index 0000000000..9e40b71c5d --- /dev/null +++ b/code/modules/mob/living/silicon/pai/update_icon.dm @@ -0,0 +1,27 @@ +/mob/living/silicon/pai/update_icon() + if(chassis == "custom") //Make sure custom exists if it's set to custom + custom_holoform_icon = client?.prefs?.get_filtered_holoform(HOLOFORM_FILTER_PAI) + if(!custom_holoform_icon) + chassis = pick(possible_chassis - "custom") + if(chassis == "dynamic") //handle dynamic generated icons + icon = dynamic_chassis_icons[dynamic_chassis] + var/list/states = icon_states(icon) + icon_state = "" + if(resting) //The next line is some bullshit but I can make it worse if you want and make it a single line instead of four.. :) + if(dynamic_chassis_sit && ("sit") in states) + icon_state = "sit" + else if(dynamic_chassis_bellyup && ("bellyup") in states) + icon_state = "bellyup" + else if("rest" in states) + icon_state = "rest" + rotate_on_lying = FALSE + else if(chassis == "custom") + icon = custom_holoform_icon + icon_state = "" + rotate_on_lying = TRUE + else + icon = initial(icon) + icon_state = "[chassis][resting? "_rest" : (stat == DEAD? "_dead" : "")]" + rotate_on_lying = FALSE + pixel_x = ((chassis == "dynamic") && chassis_pixel_offsets_x[dynamic_chassis]) || 0 + update_transform() diff --git a/code/modules/mob/living/update_icons.dm b/code/modules/mob/living/update_icons.dm new file mode 100644 index 0000000000..8bf0dc98a9 --- /dev/null +++ b/code/modules/mob/living/update_icons.dm @@ -0,0 +1,26 @@ +//IMPORTANT: Multiple animate() calls do not stack well, so try to do them all at once if you can. +/mob/living/update_transform() + var/matrix/ntransform = matrix(transform) //aka transform.Copy() + var/final_pixel_y = pixel_y + var/final_dir = dir + var/changed = 0 + if(lying != lying_prev && rotate_on_lying) + changed++ + ntransform.TurnTo(lying_prev,lying) + if(lying == 0) //Lying to standing + final_pixel_y = get_standard_pixel_y_offset() + else //if(lying != 0) + if(lying_prev == 0) //Standing to lying + pixel_y = get_standard_pixel_y_offset() + final_pixel_y = get_standard_pixel_y_offset(lying) + if(dir & (EAST|WEST)) //Facing east or west + final_dir = pick(NORTH, SOUTH) //So you fall on your side rather than your face or ass + + if(resize != RESIZE_DEFAULT_SIZE) + changed++ + ntransform.Scale(resize) + resize = RESIZE_DEFAULT_SIZE + + if(changed) + animate(src, transform = ntransform, time = 2, pixel_y = final_pixel_y, dir = final_dir, easing = EASE_IN|EASE_OUT) + setMovetype(movement_type & ~FLOATING) // If we were without gravity, the bouncing animation got stopped, so we make sure we restart it in next life(). diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 427e30f2e2..fad9431b61 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -802,11 +802,14 @@ GLOBAL_VAR_INIT(exploit_warn_spam_prevention, 0) //can the mob be buckled to something by default? /mob/proc/can_buckle() - return 1 + return TRUE //can the mob be unbuckled from something by default? /mob/proc/can_unbuckle() - return 1 + return TRUE + +/mob/proc/can_buckle_others(mob/living/target, atom/buckle_to) + return TRUE //Can the mob interact() with an atom? /mob/proc/can_interact_with(atom/A) diff --git a/icons/effects/effects.dmi b/icons/effects/effects.dmi index e13ce10347..51e9453087 100644 Binary files a/icons/effects/effects.dmi and b/icons/effects/effects.dmi differ diff --git a/modular_citadel/code/modules/mob/cit_emotes.dm b/modular_citadel/code/modules/mob/cit_emotes.dm index 7e7a77538a..d0ad0d3232 100644 --- a/modular_citadel/code/modules/mob/cit_emotes.dm +++ b/modular_citadel/code/modules/mob/cit_emotes.dm @@ -70,113 +70,124 @@ message = "makes a very loud noise." . = ..() -/datum/emote/sound/carbon/snap - key = "snap" - key_third_person = "snaps" - muzzle_ignore = TRUE - restraint_check = TRUE - emote_type = EMOTE_AUDIBLE - sound = 'sound/effects/snap01.ogg' - mob_type_allowed_typecache = list(/mob/living/carbon/) - - /datum/emote/living/snap key = "snap" key_third_person = "snaps" message = "snaps their fingers." emote_type = EMOTE_AUDIBLE + muzzle_ignore = TRUE + restraint_check = TRUE + mob_type_allowed_typecache = list(/mob/living/carbon, /mob/living/silicon/pai) /datum/emote/living/snap/run_emote(mob/living/user, params) - if(ishuman(user)) - if(user.nextsoundemote >= world.time) - return - user.nextsoundemote = world.time + 7 - playsound(user, 'modular_citadel/sound/voice/snap.ogg', 50, 1, -1) - . = ..() + if(!(. = ..())) + return + if(user.nextsoundemote >= world.time) + return + user.nextsoundemote = world.time + 7 + playsound(user, 'modular_citadel/sound/voice/snap.ogg', 50, 1, -1) /datum/emote/living/snap2 key = "snap2" key_third_person = "snaps twice" message = "snaps twice." emote_type = EMOTE_AUDIBLE + muzzle_ignore = TRUE + restraint_check = TRUE + mob_type_allowed_typecache = list(/mob/living/carbon, /mob/living/silicon/pai) /datum/emote/living/snap2/run_emote(mob/living/user, params) - if(ishuman(user)) - if(user.nextsoundemote >= world.time) - return - user.nextsoundemote = world.time + 7 - playsound(user, 'modular_citadel/sound/voice/snap2.ogg', 50, 1, -1) - . = ..() + if(!(. = ..())) + return + if(user.nextsoundemote >= world.time) + return + user.nextsoundemote = world.time + 7 + playsound(user, 'modular_citadel/sound/voice/snap2.ogg', 50, 1, -1) /datum/emote/living/snap3 key = "snap3" key_third_person = "snaps thrice" message = "snaps thrice." emote_type = EMOTE_AUDIBLE + muzzle_ignore = TRUE + restraint_check = TRUE + mob_type_allowed_typecache = list(/mob/living/carbon, /mob/living/silicon/pai) /datum/emote/living/snap3/run_emote(mob/living/user, params) - if(ishuman(user)) - if(user.nextsoundemote >= world.time) - return - user.nextsoundemote = world.time + 7 - playsound(user, 'modular_citadel/sound/voice/snap3.ogg', 50, 1, -1) - . = ..() + if(!(. = ..())) + return + if(user.nextsoundemote >= world.time) + return + user.nextsoundemote = world.time + 7 + playsound(user, 'modular_citadel/sound/voice/snap3.ogg', 50, 1, -1) /datum/emote/living/awoo key = "awoo" key_third_person = "lets out an awoo" message = "lets out an awoo!" emote_type = EMOTE_AUDIBLE + muzzle_ignore = FALSE + restraint_check = FALSE + mob_type_allowed_typecache = list(/mob/living/carbon, /mob/living/silicon/pai) /datum/emote/living/awoo/run_emote(mob/living/user, params) - if(ishuman(user)) - if(user.nextsoundemote >= world.time) - return - user.nextsoundemote = world.time + 7 - playsound(user, 'modular_citadel/sound/voice/awoo.ogg', 50, 1, -1) - . = ..() + if(!(. = ..())) + return + if(user.nextsoundemote >= world.time) + return + user.nextsoundemote = world.time + 7 + playsound(user, 'modular_citadel/sound/voice/awoo.ogg', 50, 1, -1) /datum/emote/living/nya key = "nya" key_third_person = "lets out a nya" message = "lets out a nya!" emote_type = EMOTE_AUDIBLE + muzzle_ignore = FALSE + restraint_check = FALSE + mob_type_allowed_typecache = list(/mob/living/carbon, /mob/living/silicon/pai) /datum/emote/living/nya/run_emote(mob/living/user, params) - if(ishuman(user)) - if(user.nextsoundemote >= world.time) - return - user.nextsoundemote = world.time + 7 - playsound(user, 'modular_citadel/sound/voice/nya.ogg', 50, 1, -1) - . = ..() + if(!(. = ..())) + return + if(user.nextsoundemote >= world.time) + return + user.nextsoundemote = world.time + 7 + playsound(user, 'modular_citadel/sound/voice/nya.ogg', 50, 1, -1) /datum/emote/living/weh key = "weh" key_third_person = "lets out a weh" message = "lets out a weh!" emote_type = EMOTE_AUDIBLE + muzzle_ignore = FALSE + restraint_check = FALSE + mob_type_allowed_typecache = list(/mob/living/carbon, /mob/living/silicon/pai) /datum/emote/living/weh/run_emote(mob/living/user, params) - if(ishuman(user)) - if(user.nextsoundemote >= world.time) - return - user.nextsoundemote = world.time + 7 - playsound(user, 'modular_citadel/sound/voice/weh.ogg', 50, 1, -1) - . = ..() + if(!(. = ..())) + return + if(user.nextsoundemote >= world.time) + return + user.nextsoundemote = world.time + 7 + playsound(user, 'modular_citadel/sound/voice/weh.ogg', 50, 1, -1) /datum/emote/living/peep key = "peep" key_third_person = "peeps like a bird" message = "peeps like a bird!" emote_type = EMOTE_AUDIBLE + muzzle_ignore = FALSE + restraint_check = FALSE + mob_type_allowed_typecache = list(/mob/living/carbon, /mob/living/silicon/pai) /datum/emote/living/peep/run_emote(mob/living/user, params) - if(ishuman(user)) - if(user.nextsoundemote >= world.time) - return - user.nextsoundemote = world.time + 7 - playsound(user, 'modular_citadel/sound/voice/peep.ogg', 50, 1, -1) - . = ..() + if(!(. = ..())) + return + if(user.nextsoundemote >= world.time) + return + user.nextsoundemote = world.time + 7 + playsound(user, 'modular_citadel/sound/voice/peep.ogg', 50, 1, -1) /datum/emote/living/dab key = "dab" @@ -190,41 +201,49 @@ key_third_person = "lets out a tiny squeak" message = "lets out a tiny squeak!" emote_type = EMOTE_AUDIBLE - mob_type_allowed_typecache = list(/mob/living/carbon) + muzzle_ignore = FALSE + restraint_check = FALSE + mob_type_allowed_typecache = list(/mob/living/carbon, /mob/living/silicon/pai) /datum/emote/living/mothsqueak/run_emote(mob/living/user, params) - if(ishuman(user)) - if(user.nextsoundemote >= world.time) - return - user.nextsoundemote = world.time + 7 - playsound(user, 'modular_citadel/sound/voice/mothsqueak.ogg', 50, 1, -1) - . = ..() + if(!(. = ..())) + return + if(user.nextsoundemote >= world.time) + return + user.nextsoundemote = world.time + 7 + playsound(user, 'modular_citadel/sound/voice/mothsqueak.ogg', 50, 1, -1) /datum/emote/living/merp key = "merp" key_third_person = "merps" message = "merps!" emote_type = EMOTE_AUDIBLE + muzzle_ignore = FALSE + restraint_check = FALSE + mob_type_allowed_typecache = list(/mob/living/carbon, /mob/living/silicon/pai) /datum/emote/living/merp/run_emote(mob/living/user, params) - if(ishuman(user)) - if(user.nextsoundemote >= world.time) - return - user.nextsoundemote = world.time + 7 - playsound(user, 'modular_citadel/sound/voice/merp.ogg', 50, 1, -1) - . = ..() + if(!(. = ..())) + return + if(user.nextsoundemote >= world.time) + return + user.nextsoundemote = world.time + 7 + playsound(user, 'modular_citadel/sound/voice/merp.ogg', 50, 1, -1) /datum/emote/living/bark key = "bark" key_third_person = "barks" message = "barks!" emote_type = EMOTE_AUDIBLE + muzzle_ignore = FALSE + restraint_check = FALSE + mob_type_allowed_typecache = list(/mob/living/carbon, /mob/living/silicon/pai) /datum/emote/living/bark/run_emote(mob/living/user, params) - if(ishuman(user)) - if(user.nextsoundemote >= world.time) - return - user.nextsoundemote = world.time + 7 - var/sound = pick('modular_citadel/sound/voice/bark1.ogg', 'modular_citadel/sound/voice/bark2.ogg') - playsound(user, sound, 50, 1, -1) - . = ..() \ No newline at end of file + if(!(. = ..())) + return + if(user.nextsoundemote >= world.time) + return + user.nextsoundemote = world.time + 7 + var/sound = pick('modular_citadel/sound/voice/bark1.ogg', 'modular_citadel/sound/voice/bark2.ogg') + playsound(user, sound, 50, 1, -1) diff --git a/tgstation.dme b/tgstation.dme index 30fcc602ce..7e7d69d6f1 100755 --- a/tgstation.dme +++ b/tgstation.dme @@ -120,6 +120,7 @@ #include "code\__HELPERS\areas.dm" #include "code\__HELPERS\AStar.dm" #include "code\__HELPERS\cmp.dm" +#include "code\__HELPERS\custom_holoforms.dm" #include "code\__HELPERS\dates.dm" #include "code\__HELPERS\donator_groupings.dm" #include "code\__HELPERS\files.dm" @@ -2111,6 +2112,7 @@ #include "code\modules\mob\living\say.dm" #include "code\modules\mob\living\status_procs.dm" #include "code\modules\mob\living\taste.dm" +#include "code\modules\mob\living\update_icons.dm" #include "code\modules\mob\living\ventcrawling.dm" #include "code\modules\mob\living\brain\brain.dm" #include "code\modules\mob\living\brain\brain_item.dm" @@ -2217,6 +2219,7 @@ #include "code\modules\mob\living\carbon\monkey\monkey_defense.dm" #include "code\modules\mob\living\carbon\monkey\punpun.dm" #include "code\modules\mob\living\carbon\monkey\update_icons.dm" +#include "code\modules\mob\living\silicon\custom_holoform.dm" #include "code\modules\mob\living\silicon\damage_procs.dm" #include "code\modules\mob\living\silicon\death.dm" #include "code\modules\mob\living\silicon\examine.dm" @@ -2248,6 +2251,7 @@ #include "code\modules\mob\living\silicon\pai\personality.dm" #include "code\modules\mob\living\silicon\pai\say.dm" #include "code\modules\mob\living\silicon\pai\software.dm" +#include "code\modules\mob\living\silicon\pai\update_icon.dm" #include "code\modules\mob\living\silicon\robot\death.dm" #include "code\modules\mob\living\silicon\robot\emote.dm" #include "code\modules\mob\living\silicon\robot\examine.dm"