diff --git a/code/__DEFINES/logging.dm b/code/__DEFINES/logging.dm index 2784f9d782b..67264694034 100644 --- a/code/__DEFINES/logging.dm +++ b/code/__DEFINES/logging.dm @@ -16,6 +16,7 @@ #define INVESTIGATE_EXONET "exonet" #define INVESTIGATE_NANITES "nanites" #define INVESTIGATE_CIRCUIT "circuit" +#define INVESTIGATE_PRESENTS "presents" // Logging types for log_message() #define LOG_ATTACK (1 << 0) diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm index 962634f35df..2eb7107601a 100644 --- a/code/__DEFINES/traits.dm +++ b/code/__DEFINES/traits.dm @@ -57,6 +57,8 @@ #define TRAIT_PARALYSIS_R_ARM "para-r-arm" #define TRAIT_PARALYSIS_L_LEG "para-l-leg" #define TRAIT_PARALYSIS_R_LEG "para-r-leg" +#define TRAIT_CANNOT_OPEN_PRESENTS "cannot-open-presents" +#define TRAIT_PRESENT_VISION "present-vision" #define TRAIT_DISK_VERIFIER "disk-verifier" #define TRAIT_NOMOBSWAP "no-mob-swap" #define TRAIT_XRAY_VISION "xray_vision" @@ -108,6 +110,7 @@ #define GENETICS_SPELL "genetics_spell" #define EYES_COVERED "eyes_covered" #define CULT_EYES "cult_eyes" +#define TRAIT_SANTA "santa" #define SCRYING_ORB "scrying-orb" #define ABDUCTOR_ANTAGONIST "abductor-antagonist" #define NUKEOP_TRAIT "nuke-op" diff --git a/code/_globalvars/lists/flavor_misc.dm b/code/_globalvars/lists/flavor_misc.dm index 35f548261bf..20554d476f8 100644 --- a/code/_globalvars/lists/flavor_misc.dm +++ b/code/_globalvars/lists/flavor_misc.dm @@ -36,7 +36,7 @@ GLOBAL_LIST_EMPTY(wings_open_list) GLOBAL_LIST_EMPTY(r_wings_list) GLOBAL_LIST_EMPTY(moth_wings_list) GLOBAL_LIST_EMPTY(caps_list) - + GLOBAL_LIST_INIT(color_list_ethereal, list("F Class(Green)" = "97ee63", "F2 Class (Light Green)" = "00fa9a", "F3 Class (Dark Green)" = "37835b", "M Class (Red)" = "9c3030", "M1 Class (Purple)" = "ee82ee", "G Class (Yellow)" = "fbdf56", "O Class (Blue)" = "3399ff", "A Class (Cyan)" = "00ffff")) GLOBAL_LIST_INIT(ghost_forms_with_directions_list, list("ghost")) //stores the ghost forms that support directional sprites diff --git a/code/_globalvars/lists/mobs.dm b/code/_globalvars/lists/mobs.dm index 44741758cf2..3400079d3d9 100644 --- a/code/_globalvars/lists/mobs.dm +++ b/code/_globalvars/lists/mobs.dm @@ -38,6 +38,7 @@ GLOBAL_LIST_EMPTY(latejoin_ai_cores) GLOBAL_LIST_EMPTY(mob_config_movespeed_type_lookup) + /proc/update_config_movespeed_type_lookup(update_mobs = TRUE) var/list/mob_types = list() var/list/entry_value = CONFIG_GET(keyed_list/multiplicative_movespeed) diff --git a/code/datums/components/storage/storage.dm b/code/datums/components/storage/storage.dm index 862f0f12c3c..64d1fe4f27a 100644 --- a/code/datums/components/storage/storage.dm +++ b/code/datums/components/storage/storage.dm @@ -588,7 +588,8 @@ to_chat(M, "[IP] cannot hold [I] as it's a storage item of the same size!") return FALSE //To prevent the stacking of same sized storage items. if(I.item_flags & NODROP) //SHOULD be handled in unEquip, but better safe than sorry. - to_chat(M, "\the [I] is stuck to your hand, you can't put it in \the [host]!") + if(!stop_messages) + to_chat(M, "\the [I] is stuck to your hand, you can't put it in \the [host]!") return FALSE var/datum/component/storage/concrete/master = master() if(!istype(master)) @@ -599,7 +600,7 @@ return FALSE //This proc handles items being inserted. It does not perform any checks of whether an item can or can't be inserted. That's done by can_be_inserted() -//The stop_warning parameter will stop the insertion message from being displayed. It is intended for cases where you are inserting multiple items at once, +//The prevent_warning parameter will stop the insertion message from being displayed. It is intended for cases where you are inserting multiple items at once, //such as when picking up all the items on a tile with one click. /datum/component/storage/proc/handle_item_insertion(obj/item/I, prevent_warning = FALSE, mob/M, datum/component/storage/remote) var/atom/parent = src.parent diff --git a/code/datums/outfit.dm b/code/datums/outfit.dm index 1f5c28d3c2a..68165af956b 100755 --- a/code/datums/outfit.dm +++ b/code/datums/outfit.dm @@ -21,6 +21,7 @@ var/l_hand = null var/internals_slot = null //ID of slot containing a gas tank var/list/backpack_contents = null // In the list(path=count,otherpath=count) format + var/box // Internals box. Will be inserted at the start of backpack_contents var/list/implants = null var/accessory = null @@ -83,6 +84,13 @@ H.equip_to_slot_or_del(new l_pocket(H),SLOT_L_STORE) if(r_pocket) H.equip_to_slot_or_del(new r_pocket(H),SLOT_R_STORE) + + if(box) + if(!backpack_contents) + backpack_contents = list() + backpack_contents.Insert(1, box) + backpack_contents[box] = 1 + if(backpack_contents) for(var/path in backpack_contents) var/number = backpack_contents[path] diff --git a/code/game/objects/items/gift.dm b/code/game/objects/items/gift.dm index f97b3f99d6f..ab728949abb 100644 --- a/code/game/objects/items/gift.dm +++ b/code/game/objects/items/gift.dm @@ -18,25 +18,35 @@ GLOBAL_LIST_EMPTY(possible_gifts) item_state = "gift" resistance_flags = FLAMMABLE -/obj/item/a_gift/New() - ..() + var/obj/item/contains_type + +/obj/item/a_gift/Initialize() + . = ..() pixel_x = rand(-10,10) pixel_y = rand(-10,10) icon_state = "giftdeliverypackage[rand(1,5)]" + contains_type = get_gift_type() + /obj/item/a_gift/suicide_act(mob/user) user.visible_message("[user] peeks inside [src] and cries [user.p_them()]self to death! It looks like [user.p_they()] [user.p_were()] on the naughty list...") return (BRUTELOSS) +/obj/item/a_gift/examine(mob/M) + . = ..() + if(M.has_trait(TRAIT_PRESENT_VISION) || isobserver(M)) + to_chat(M, "It contains \a [initial(contains_type.name)].") + /obj/item/a_gift/attack_self(mob/M) - if(M && M.mind && M.mind.special_role == "Santa") + if(M.has_trait(TRAIT_CANNOT_OPEN_PRESENTS)) to_chat(M, "You're supposed to be spreading gifts, not opening them yourself!") return - var/gift_type = get_gift_type() - qdel(src) - var/obj/item/I = new gift_type(M) + + var/obj/item/I = new contains_type(get_turf(M)) + M.visible_message("[M] unwraps \the [src], finding \a [I] inside!") + I.investigate_log("([I.type]) was found in a present by [key_name(M)].", INVESTIGATE_PRESENTS) M.put_in_hands(I) I.add_fingerprint(M) diff --git a/code/game/objects/items/storage/backpack.dm b/code/game/objects/items/storage/backpack.dm index 7905217af67..5db76fd2d89 100644 --- a/code/game/objects/items/storage/backpack.dm +++ b/code/game/objects/items/storage/backpack.dm @@ -65,20 +65,22 @@ sleep(20) playsound(src, "rustle", 50, 1, -5) qdel(user) - return /obj/item/storage/backpack/holding/singularity_act(current_size) var/dist = max((current_size - 2),1) explosion(src.loc,(dist),(dist*2),(dist*4)) - return /obj/item/storage/backpack/santabag name = "Santa's Gift Bag" - desc = "Space Santa uses this to deliver toys to all the nice children in space in Christmas! Wow, it's pretty big!" + desc = "Space Santa uses this to deliver presents to all the nice children in space in Christmas! Wow, it's pretty big!" icon_state = "giftbag0" item_state = "giftbag" w_class = WEIGHT_CLASS_BULKY +/obj/item/storage/backpack/santabag/Initialize() + . = ..() + regenerate_presents() + /obj/item/storage/backpack/santabag/ComponentInitialize() . = ..() GET_COMPONENT(STR, /datum/component/storage) @@ -89,6 +91,22 @@ user.visible_message("[user] places [src] over [user.p_their()] head and pulls it tight! It looks like [user.p_they()] [user.p_are()]n't in the Christmas spirit...") return (OXYLOSS) +/obj/item/storage/backpack/santabag/proc/regenerate_presents() + addtimer(CALLBACK(src, .proc/regenerate_presents), rand(30 SECONDS, 60 SECONDS)) + + var/mob/M = get(loc, /mob) + if(!istype(M)) + return + if(M.has_trait(TRAIT_CANNOT_OPEN_PRESENTS)) + GET_COMPONENT(STR, /datum/component/storage) + var/turf/floor = get_turf(src) + var/obj/item/I = new /obj/item/a_gift/anything(floor) + if(STR.can_be_inserted(I, stop_messages=TRUE)) + STR.handle_item_insertion(I, prevent_warning=TRUE) + else + qdel(I) + + /obj/item/storage/backpack/cultpack name = "trophy rack" desc = "It's useful for both carrying extra gear and proudly declaring your insanity." diff --git a/code/game/objects/structures/flora.dm b/code/game/objects/structures/flora.dm index 7c73a1fd8cc..0b7d3e0bd49 100644 --- a/code/game/objects/structures/flora.dm +++ b/code/game/objects/structures/flora.dm @@ -63,7 +63,13 @@ icon_state = "pinepresents" desc = "A wondrous decorated Christmas tree. It has presents!" var/gift_type = /obj/item/a_gift/anything - var/list/ckeys_that_took = list() + var/unlimited = FALSE + var/static/list/took_presents //shared between all xmas trees + +/obj/structure/flora/tree/pine/xmas/presents/Initialize() + . = ..() + if(!took_presents) + took_presents = list() /obj/structure/flora/tree/pine/xmas/presents/attack_hand(mob/living/user) . = ..() @@ -72,14 +78,21 @@ if(!user.ckey) return - if(ckeys_that_took[user.ckey]) + if(took_presents[user.ckey] && !unlimited) to_chat(user, "There are no presents with your name on.") return to_chat(user, "After a bit of rummaging, you locate a gift with your name on it!") - ckeys_that_took[user.ckey] = TRUE + + if(!unlimited) + took_presents[user.ckey] = TRUE + var/obj/item/G = new gift_type(src) user.put_in_hands(G) +/obj/structure/flora/tree/pine/xmas/presents/unlimited + desc = "A wonderous decorated Christmas tree. It has a seemly endless supply of presents!" + unlimited = TRUE + /obj/structure/flora/tree/dead icon = 'icons/obj/flora/deadtrees.dmi' desc = "A dead tree. How it died, you know not." diff --git a/code/modules/admin/admin_investigate.dm b/code/modules/admin/admin_investigate.dm index ebbef58cbb5..6285b14c686 100644 --- a/code/modules/admin/admin_investigate.dm +++ b/code/modules/admin/admin_investigate.dm @@ -4,7 +4,7 @@ var/F = file("[GLOB.log_directory]/[subject].html") WRITE_FILE(F, "[time_stamp()] [REF(src)] ([x],[y],[z]) || [src] [message]
") -/client/proc/investigate_show(subject in list("notes, memos, watchlist", INVESTIGATE_RESEARCH, INVESTIGATE_EXONET, INVESTIGATE_PORTAL, INVESTIGATE_SINGULO, INVESTIGATE_WIRES, INVESTIGATE_TELESCI, INVESTIGATE_GRAVITY, INVESTIGATE_RECORDS, INVESTIGATE_CARGO, INVESTIGATE_SUPERMATTER, INVESTIGATE_ATMOS, INVESTIGATE_EXPERIMENTOR, INVESTIGATE_BOTANY, INVESTIGATE_HALLUCINATIONS, INVESTIGATE_RADIATION, INVESTIGATE_CIRCUIT, INVESTIGATE_NANITES) ) +/client/proc/investigate_show(subject in list("notes, memos, watchlist", INVESTIGATE_RESEARCH, INVESTIGATE_EXONET, INVESTIGATE_PORTAL, INVESTIGATE_SINGULO, INVESTIGATE_WIRES, INVESTIGATE_TELESCI, INVESTIGATE_GRAVITY, INVESTIGATE_RECORDS, INVESTIGATE_CARGO, INVESTIGATE_SUPERMATTER, INVESTIGATE_ATMOS, INVESTIGATE_EXPERIMENTOR, INVESTIGATE_BOTANY, INVESTIGATE_HALLUCINATIONS, INVESTIGATE_RADIATION, INVESTIGATE_CIRCUIT, INVESTIGATE_NANITES, INVESTIGATE_PRESENTS) ) set name = "Investigate" set category = "Admin" if(!holder) diff --git a/code/modules/antagonists/santa/santa.dm b/code/modules/antagonists/santa/santa.dm index ea334ad6653..83dd08f2b1a 100644 --- a/code/modules/antagonists/santa/santa.dm +++ b/code/modules/antagonists/santa/santa.dm @@ -8,24 +8,24 @@ give_equipment() give_objective() + owner.add_trait(TRAIT_CANNOT_OPEN_PRESENTS, TRAIT_SANTA) + owner.add_trait(TRAIT_PRESENT_VISION, TRAIT_SANTA) + /datum/antagonist/santa/greet() . = ..() - to_chat(owner, "You are Santa! Your objective is to bring joy to the people on this station. You can conjure more presents using a spell, and there are several presents in your bag.") + to_chat(owner, "You are Santa! Your objective is to bring joy to the people on this station. You have a magical bag, which generates presents as long as you have it! You can examine the presents to take a peek inside, to make sure that you give the right gift to the right person.") /datum/antagonist/santa/proc/give_equipment() var/mob/living/carbon/human/H = owner.current if(istype(H)) H.equipOutfit(/datum/outfit/santa) + H.dna.update_dna_identity() - owner.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/conjure/presents) - var/obj/effect/proc_holder/spell/targeted/area_teleport/teleport/telespell = new - telespell.clothes_req = 0 //santa robes aren't actually magical. - owner.AddSpell(telespell) //does the station have chimneys? WHO KNOWS! + owner.AddSpell(new /obj/effect/proc_holder/spell/targeted/area_teleport/teleport/santa) /datum/antagonist/santa/proc/give_objective() var/datum/objective/santa_objective = new() santa_objective.explanation_text = "Bring joy and presents to the station!" - santa_objective.completed = 1 //lets cut our santas some slack. + santa_objective.completed = TRUE //lets cut our santas some slack. santa_objective.owner = owner objectives |= santa_objective - diff --git a/code/modules/clothing/outfits/event.dm b/code/modules/clothing/outfits/event.dm index 347fc5c2d72..70d16f3ae96 100644 --- a/code/modules/clothing/outfits/event.dm +++ b/code/modules/clothing/outfits/event.dm @@ -6,11 +6,11 @@ suit = /obj/item/clothing/suit/space/santa head = /obj/item/clothing/head/santa back = /obj/item/storage/backpack/santabag - mask = /obj/item/clothing/mask/breath r_pocket = /obj/item/flashlight gloves = /obj/item/clothing/gloves/color/red - belt = /obj/item/tank/internals/emergency_oxygen/double - id = /obj/item/card/id/gold + + box = /obj/item/storage/box/engineer + backpack_contents = list(/obj/item/a_gift/anything = 5) /datum/outfit/santa/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE) if(visualsOnly) @@ -19,12 +19,8 @@ H.mind.assigned_role = "Santa" H.mind.special_role = "Santa" - H.hair_style = "Long Hair" - H.facial_hair_style = "Full Beard" + H.hair_style = "Long Hair 3" + H.facial_hair_style = "Beard (Full)" H.hair_color = "FFF" H.facial_hair_color = "FFF" - - var/obj/item/storage/backpack/bag = H.back - var/obj/item/a_gift/gift = new(H) - while(SEND_SIGNAL(bag, COMSIG_TRY_STORAGE_INSERT, gift, null, TRUE, FALSE)) - gift = new(H) + H.update_hair() diff --git a/code/modules/events/holiday/xmas.dm b/code/modules/events/holiday/xmas.dm index c0da7534c59..dc9a4824ac7 100644 --- a/code/modules/events/holiday/xmas.dm +++ b/code/modules/events/holiday/xmas.dm @@ -63,7 +63,7 @@ christmas_tree = null /datum/round_event_control/santa - name = "Santa is coming to town! (Christmas)" + name = "Vist by Santa" holidayID = CHRISTMAS typepath = /datum/round_event/santa weight = 20 diff --git a/code/modules/jobs/job_types/job.dm b/code/modules/jobs/job_types/job.dm index 9242000636d..59ea5c00fc4 100644 --- a/code/modules/jobs/job_types/job.dm +++ b/code/modules/jobs/job_types/job.dm @@ -158,11 +158,11 @@ belt = /obj/item/pda back = /obj/item/storage/backpack shoes = /obj/item/clothing/shoes/sneakers/black + box = /obj/item/storage/box/survival var/backpack = /obj/item/storage/backpack var/satchel = /obj/item/storage/backpack/satchel var/duffelbag = /obj/item/storage/backpack/duffelbag - var/box = /obj/item/storage/box/survival var/pda_slot = SLOT_BELT @@ -183,12 +183,6 @@ else back = backpack //Department backpack - if(box) - if(!backpack_contents) - backpack_contents = list() - backpack_contents.Insert(1, box) // Box always takes a first slot in backpack - backpack_contents[box] = 1 - /datum/outfit/job/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE) if(visualsOnly) return diff --git a/code/modules/reagents/chemistry/reagents/other_reagents.dm b/code/modules/reagents/chemistry/reagents/other_reagents.dm index f35177fe68b..8aab5376795 100644 --- a/code/modules/reagents/chemistry/reagents/other_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/other_reagents.dm @@ -1546,7 +1546,7 @@ if(M && ishuman(M)) var/mob/living/carbon/human/H = M H.hair_style = "Very Long Hair" - H.facial_hair_style = "Very Long Beard" + H.facial_hair_style = "Beard (Very Long)" H.update_hair() /datum/reagent/saltpetre diff --git a/code/modules/spells/spell_types/area_teleport.dm b/code/modules/spells/spell_types/area_teleport.dm index 83f17969735..84e1eec2eae 100644 --- a/code/modules/spells/spell_types/area_teleport.dm +++ b/code/modules/spells/spell_types/area_teleport.dm @@ -8,6 +8,8 @@ var/sound1 = 'sound/weapons/zapbang.ogg' var/sound2 = 'sound/weapons/zapbang.ogg' + var/say_destination = TRUE + /obj/effect/proc_holder/spell/targeted/area_teleport/perform(list/targets, recharge = 1,mob/living/user = usr) var/thearea = before_cast(targets) if(!thearea || !cast_check(1)) @@ -69,20 +71,22 @@ do_teleport(target, L, forceMove = TRUE, channel = TELEPORT_CHANNEL_MAGIC) playsound(get_turf(user), sound2, 50,1) - return - /obj/effect/proc_holder/spell/targeted/area_teleport/invocation(area/chosenarea = null,mob/user = usr) if(!invocation_area || !chosenarea) ..() else + var/words + if(say_destination) + words = "[invocation] [uppertext(chosenarea.name)]" + else + words = "[invocation]" + switch(invocation_type) if("shout") - user.say("[invocation] [uppertext(chosenarea.name)]", forced = "spell") + user.say(words, forced = "spell") if(user.gender==MALE) playsound(user.loc, pick('sound/misc/null.ogg','sound/misc/null.ogg'), 100, 1) else playsound(user.loc, pick('sound/misc/null.ogg','sound/misc/null.ogg'), 100, 1) if("whisper") - user.whisper("[invocation] [uppertext(chosenarea.name)]", forced = "spell") - - return + user.whisper(words, forced = "spell") diff --git a/code/modules/spells/spell_types/wizard.dm b/code/modules/spells/spell_types/wizard.dm index 563ae028c46..2a67febb739 100644 --- a/code/modules/spells/spell_types/wizard.dm +++ b/code/modules/spells/spell_types/wizard.dm @@ -151,6 +151,13 @@ sound1 = 'sound/magic/teleport_diss.ogg' sound2 = 'sound/magic/teleport_app.ogg' +/obj/effect/proc_holder/spell/targeted/area_teleport/teleport/santa + name = "Santa Teleport" + + invocation = "HO HO HO" + clothes_req = FALSE + say_destination = FALSE // Santa moves in mysterious ways + /obj/effect/proc_holder/spell/aoe_turf/conjure/timestop name = "Stop Time" desc = "This spell stops time for everyone except for you, allowing you to move freely while your enemies and even projectiles are frozen."