Christmas code changes (#41763)

* Christmas code changes

🆑 coiax
add: Santa can now examine presents to see what's inside.
del: Santa no longer has a mass summon presents spell, because of his
new regenerating bag!
add: Santa's bag regenerates presents as long as Santa is holding it.
balance: You can only find one gift under a christmas tree per round, no
matter how many trees you search.
balance: Santa's teleport does not announce where he's going.
fix: Fixed Santa not having a full head and beard of white hair.
fix: Fixed Santa not being genetically white-haired.
fix: Fixed Concentrated Barber's Aid not growing extreme amounts of
hair.
/🆑

The `box` var has been moved down from `/datum/outfit/job` to
`/datum/outfit`.

Added unlimited christmas tree with presents, for testing.

Santa's restriction against opening presents is now done by
TRAIT_CANNOT_OPEN_PRESENTS. Santa's ability to see inside presents is
done by the TRAIT_PRESENT_VISION, which also determines if Santa's Bag
will regenerate presents every 30 to 60 seconds.

Santa no longer starts with a breath mask and O2 tank, but instead has
an internals box. Santa no longer has a no-access gold ID, he can
teleport from room to room!

Gifts determine what type is inside them on initialization, rather than
when unwrapped.

- Reasoning -

Unlike last year, there are various possible methods of accessing
christmas trees spawners, allowing for an unlimited number of anything
presents. Cutting down the presents to one per round regardless of tree
count will avoid this.

Santa should be able to see what he's giving, because then he can reward
the naughty and nice children with different gifts.

* Missed a merge

* Adds present investigate logs, and visible messages

* Use the body+mind checking of mob.has_trait

* Less globals, more static vars on types; also event renaming
This commit is contained in:
coiax
2018-12-16 12:44:53 +13:00
committed by oranges
parent 5b0f978d59
commit d27c64c3a8
17 changed files with 104 additions and 48 deletions
+1
View File
@@ -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)
+3
View File
@@ -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"
+1 -1
View File
@@ -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
+1
View File
@@ -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)
+3 -2
View File
@@ -588,7 +588,8 @@
to_chat(M, "<span class='warning'>[IP] cannot hold [I] as it's a storage item of the same size!</span>")
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, "<span class='warning'>\the [I] is stuck to your hand, you can't put it in \the [host]!</span>")
if(!stop_messages)
to_chat(M, "<span class='warning'>\the [I] is stuck to your hand, you can't put it in \the [host]!</span>")
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
+8
View File
@@ -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]
+16 -6
View File
@@ -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("<span class='suicide'>[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...</span>")
return (BRUTELOSS)
/obj/item/a_gift/examine(mob/M)
. = ..()
if(M.has_trait(TRAIT_PRESENT_VISION) || isobserver(M))
to_chat(M, "<span class='notice'>It contains \a [initial(contains_type.name)].</span>")
/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, "<span class='warning'>You're supposed to be spreading gifts, not opening them yourself!</span>")
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("<span class='notice'>[M] unwraps \the [src], finding \a [I] inside!</span>")
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)
+21 -3
View File
@@ -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("<span class='suicide'>[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...</span>")
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."
+16 -3
View File
@@ -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, "<span class='warning'>There are no presents with your name on.</span>")
return
to_chat(user, "<span class='warning'>After a bit of rummaging, you locate a gift with your name on it!</span>")
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."
+1 -1
View File
@@ -4,7 +4,7 @@
var/F = file("[GLOB.log_directory]/[subject].html")
WRITE_FILE(F, "<small>[time_stamp()] [REF(src)] ([x],[y],[z])</small> || [src] [message]<br>")
/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)
+7 -7
View File
@@ -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, "<span class='boldannounce'>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.</span>")
to_chat(owner, "<span class='boldannounce'>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.</span>")
/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
+6 -10
View File
@@ -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()
+1 -1
View File
@@ -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
+1 -7
View File
@@ -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
@@ -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
@@ -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")
@@ -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."