mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-01-13 02:13:06 +00:00
* [IDB IGNORE] The Great Sweep: Moving dmis into subfolders (part 1) * Fixes all the conflicts and all of our modular files using core icon files with broken paths Co-authored-by: tattle <66640614+dragomagol@users.noreply.github.com> Co-authored-by: GoldenAlpharex <jerego1234@hotmail.com> Co-authored-by: GoldenAlpharex <58045821+GoldenAlpharex@users.noreply.github.com>
294 lines
12 KiB
Plaintext
294 lines
12 KiB
Plaintext
// the different states of the mystery box
|
|
/// Closed, can't interact
|
|
#define MYSTERY_BOX_COOLING_DOWN 0
|
|
/// Closed, ready to be interacted with
|
|
#define MYSTERY_BOX_STANDBY 1
|
|
/// The box is choosing the prize
|
|
#define MYSTERY_BOX_CHOOSING 2
|
|
/// The box is presenting the prize, for someone to claim it
|
|
#define MYSTERY_BOX_PRESENTING 3
|
|
|
|
// delays for the different stages of the box's state, the visuals, and the audio
|
|
/// How long the box takes to decide what the prize is
|
|
#define MBOX_DURATION_CHOOSING 5 SECONDS
|
|
/// How long the box takes to start expiring the offer, though it's still valid until MBOX_DURATION_EXPIRING finishes. Timed to the sound clips
|
|
#define MBOX_DURATION_PRESENTING 3.5 SECONDS
|
|
/// How long the box takes to start lowering the prize back into itself. When this finishes, the prize is gone
|
|
#define MBOX_DURATION_EXPIRING 4.5 SECONDS
|
|
/// How long after the box closes until it can go again
|
|
#define MBOX_DURATION_STANDBY 2.7 SECONDS
|
|
|
|
GLOBAL_LIST_INIT(mystery_box_guns, list(
|
|
/obj/item/gun/energy/lasercannon,
|
|
/obj/item/gun/energy/recharge/ebow/large,
|
|
/obj/item/gun/energy/e_gun,
|
|
/obj/item/gun/energy/e_gun/advtaser,
|
|
/obj/item/gun/energy/e_gun/nuclear,
|
|
/obj/item/gun/energy/e_gun/turret,
|
|
/obj/item/gun/energy/laser,
|
|
/obj/item/gun/energy/laser/hellgun,
|
|
/obj/item/gun/energy/laser/captain,
|
|
/obj/item/gun/energy/laser/scatter,
|
|
/obj/item/gun/energy/temperature,
|
|
/obj/item/gun/ballistic/revolver/detective,
|
|
/obj/item/gun/ballistic/revolver/mateba,
|
|
/obj/item/gun/ballistic/automatic/pistol/deagle/camo,
|
|
/obj/item/gun/ballistic/automatic/pistol/suppressed,
|
|
/obj/item/gun/energy/pulse/carbine,
|
|
/obj/item/gun/energy/pulse/pistol,
|
|
/obj/item/gun/ballistic/shotgun/lethal,
|
|
/obj/item/gun/ballistic/shotgun/automatic/combat,
|
|
/obj/item/gun/ballistic/shotgun/bulldog,
|
|
/obj/item/gun/ballistic/rifle/boltaction,
|
|
/obj/item/gun/ballistic/automatic/ar,
|
|
/obj/item/gun/ballistic/automatic/proto,
|
|
/obj/item/gun/ballistic/automatic/c20r,
|
|
/obj/item/gun/ballistic/automatic/l6_saw,
|
|
/obj/item/gun/ballistic/automatic/m90,
|
|
/obj/item/gun/ballistic/automatic/tommygun,
|
|
/obj/item/gun/ballistic/automatic/wt550,
|
|
/obj/item/gun/ballistic/automatic/sniper_rifle,
|
|
/obj/item/gun/ballistic/rifle/boltaction/brand_new,
|
|
))
|
|
|
|
GLOBAL_LIST_INIT(mystery_box_extended, list(
|
|
/obj/item/clothing/gloves/tackler/combat,
|
|
/obj/item/clothing/gloves/race,
|
|
/obj/item/clothing/gloves/rapid,
|
|
/obj/item/shield/riot/flash,
|
|
/obj/item/grenade/stingbang/mega,
|
|
/obj/item/storage/belt/sabre,
|
|
/obj/item/knife/combat,
|
|
/obj/item/melee/baton/security/loaded,
|
|
/obj/item/reagent_containers/hypospray/combat,
|
|
/obj/item/defibrillator/compact/combat/loaded/nanotrasen,
|
|
/obj/item/melee/energy/sword/saber,
|
|
/obj/item/spear,
|
|
/obj/item/circular_saw,
|
|
))
|
|
|
|
|
|
/obj/structure/mystery_box
|
|
name = "mystery box"
|
|
desc = "A wooden crate that seems equally magical and mysterious, capable of granting the user all kinds of different pieces of gear."
|
|
icon = 'icons/obj/storage/crates.dmi'
|
|
icon_state = "wooden"
|
|
pixel_y = -4
|
|
anchored = TRUE
|
|
density = TRUE
|
|
max_integrity = 99999
|
|
damage_deflection = 100
|
|
|
|
var/crate_open_sound = 'sound/machines/crate_open.ogg'
|
|
var/crate_close_sound = 'sound/machines/crate_close.ogg'
|
|
var/open_sound = 'sound/effects/mysterybox/mbox_full.ogg'
|
|
var/grant_sound = 'sound/effects/mysterybox/mbox_end.ogg'
|
|
/// The box's current state, and whether it can be interacted with in different ways
|
|
var/box_state = MYSTERY_BOX_STANDBY
|
|
/// The object that represents the rapidly changing item that will be granted upon being claimed. Is not, itself, an item.
|
|
var/obj/mystery_box_item/presented_item
|
|
/// A timer for how long it takes for the box to start its expire animation
|
|
var/box_expire_timer
|
|
/// A timer for how long it takes for the box to close itself
|
|
var/box_close_timer
|
|
/// Every type that's a child of this that has an icon, icon_state, and isn't ABSTRACT is fair game. More granularity to come
|
|
var/selectable_base_type = /obj/item
|
|
/// The instantiated list that contains all of the valid items that can be chosen from. Generated in [/obj/structure/mystery_box/proc/generate_valid_types]
|
|
var/list/valid_types
|
|
/// If the prize is a ballistic gun with an external magazine, should we grant the user a spare mag?
|
|
var/grant_extra_mag = TRUE
|
|
/// Stores the current sound channel we're using so we can cut off our own sounds as needed. Randomized after each roll
|
|
var/current_sound_channel
|
|
|
|
/obj/structure/mystery_box/Initialize(mapload)
|
|
. = ..()
|
|
generate_valid_types()
|
|
|
|
/obj/structure/mystery_box/Destroy()
|
|
QDEL_NULL(presented_item)
|
|
if(current_sound_channel)
|
|
SSsounds.free_sound_channel(current_sound_channel)
|
|
return ..()
|
|
|
|
/obj/structure/mystery_box/attack_hand(mob/living/user, list/modifiers)
|
|
. = ..()
|
|
switch(box_state)
|
|
if(MYSTERY_BOX_STANDBY)
|
|
activate(user)
|
|
|
|
if(MYSTERY_BOX_PRESENTING)
|
|
if(presented_item.claimable)
|
|
grant_weapon(user)
|
|
|
|
/obj/structure/mystery_box/update_icon_state()
|
|
icon_state = "[initial(icon_state)][box_state > MYSTERY_BOX_STANDBY ? "open" : ""]"
|
|
return ..()
|
|
|
|
/// This proc is used to define what item types valid_types is filled with
|
|
/obj/structure/mystery_box/proc/generate_valid_types()
|
|
valid_types = list()
|
|
|
|
for(var/iter_path in typesof(selectable_base_type))
|
|
if(!ispath(iter_path, /obj/item))
|
|
continue
|
|
var/obj/item/iter_item = iter_path
|
|
if((initial(iter_item.item_flags) & ABSTRACT) || !initial(iter_item.icon_state) || !initial(iter_item.inhand_icon_state))
|
|
continue
|
|
valid_types += iter_path
|
|
|
|
/// The box has been activated, play the sound and spawn the prop item
|
|
/obj/structure/mystery_box/proc/activate(mob/living/user)
|
|
box_state = MYSTERY_BOX_CHOOSING
|
|
update_icon_state()
|
|
presented_item = new(loc)
|
|
presented_item.start_animation(src)
|
|
current_sound_channel = SSsounds.reserve_sound_channel(src)
|
|
playsound(src, open_sound, 70, FALSE, channel = current_sound_channel, falloff_exponent = 10)
|
|
playsound(src, crate_open_sound, 80)
|
|
|
|
/// The box has finished choosing, mark it as available for grabbing
|
|
/obj/structure/mystery_box/proc/present_weapon()
|
|
visible_message(span_notice("[src] presents [presented_item]!"), vision_distance = COMBAT_MESSAGE_RANGE)
|
|
box_state = MYSTERY_BOX_PRESENTING
|
|
box_expire_timer = addtimer(CALLBACK(src, .proc/start_expire_offer), MBOX_DURATION_PRESENTING, TIMER_STOPPABLE)
|
|
|
|
/// The prize is still claimable, but the animation will show it start to recede back into the box
|
|
/obj/structure/mystery_box/proc/start_expire_offer()
|
|
presented_item.expire_animation()
|
|
box_close_timer = addtimer(CALLBACK(src, .proc/close_box), MBOX_DURATION_EXPIRING, TIMER_STOPPABLE)
|
|
|
|
/// The box is closed, whether because the prize fully expired, or it was claimed. Start resetting all of the state stuff
|
|
/obj/structure/mystery_box/proc/close_box()
|
|
box_state = MYSTERY_BOX_COOLING_DOWN
|
|
update_icon_state()
|
|
QDEL_NULL(presented_item)
|
|
deltimer(box_close_timer)
|
|
deltimer(box_expire_timer)
|
|
playsound(src, crate_close_sound, 100)
|
|
box_close_timer = null
|
|
box_expire_timer = null
|
|
addtimer(CALLBACK(src, .proc/ready_again), MBOX_DURATION_STANDBY)
|
|
|
|
/// The cooldown between activations has finished, shake to show that
|
|
/obj/structure/mystery_box/proc/ready_again()
|
|
SSsounds.free_sound_channel(current_sound_channel)
|
|
current_sound_channel = null
|
|
box_state = MYSTERY_BOX_STANDBY
|
|
Shake(10, 0, 0.5 SECONDS)
|
|
|
|
/// Someone attacked the box with an empty hand, spawn the shown prize and give it to them, then close the box
|
|
/obj/structure/mystery_box/proc/grant_weapon(mob/living/user)
|
|
var/obj/item/instantiated_weapon = new presented_item.selected_path(src)
|
|
user.put_in_hands(instantiated_weapon)
|
|
|
|
if(isgun(instantiated_weapon)) // handle pins + possibly extra ammo
|
|
var/obj/item/gun/instantiated_gun = instantiated_weapon
|
|
instantiated_gun.unlock()
|
|
if(grant_extra_mag && istype(instantiated_gun, /obj/item/gun/ballistic))
|
|
var/obj/item/gun/ballistic/instantiated_ballistic = instantiated_gun
|
|
if(!instantiated_ballistic.internal_magazine)
|
|
var/obj/item/ammo_box/magazine/extra_mag = new instantiated_ballistic.mag_type(loc)
|
|
user.put_in_hands(extra_mag)
|
|
|
|
user.visible_message(span_notice("[user] takes [presented_item] from [src]."), span_notice("You take [presented_item] from [src]."), vision_distance = COMBAT_MESSAGE_RANGE)
|
|
playsound(src, grant_sound, 70, FALSE, channel = current_sound_channel, falloff_exponent = 10)
|
|
close_box()
|
|
|
|
|
|
/obj/structure/mystery_box/guns
|
|
desc = "A wooden crate that seems equally magical and mysterious, capable of granting the user all kinds of different pieces of gear. This one seems focused on firearms."
|
|
|
|
/obj/structure/mystery_box/guns/generate_valid_types()
|
|
valid_types = GLOB.summoned_guns
|
|
|
|
/obj/structure/mystery_box/tdome
|
|
desc = "A wooden crate that seems equally magical and mysterious, capable of granting the user all kinds of different pieces of gear. This one has an extended array of weaponry."
|
|
|
|
/obj/structure/mystery_box/tdome/generate_valid_types()
|
|
valid_types = GLOB.mystery_box_guns + GLOB.mystery_box_extended
|
|
|
|
|
|
/// This represents the item that comes out of the box and is constantly changing before the box finishes deciding. Can probably be just an /atom or /movable.
|
|
/obj/mystery_box_item
|
|
name = "???"
|
|
desc = "Who knows what it'll be??"
|
|
icon = 'icons/obj/weapons/guns/ballistic.dmi'
|
|
icon_state = "detective"
|
|
pixel_y = -8
|
|
uses_integrity = FALSE
|
|
|
|
/// The currently selected item. Constantly changes while choosing, determines what is spawned if the prize is claimed, and its current icon
|
|
var/selected_path = /obj/item/gun/ballistic/revolver/detective
|
|
/// The box that spawned this
|
|
var/obj/structure/mystery_box/parent_box
|
|
/// Whether this prize is currently claimable
|
|
var/claimable = FALSE
|
|
|
|
|
|
/obj/mystery_box_item/Initialize(mapload)
|
|
. = ..()
|
|
var/matrix/starting = matrix()
|
|
starting.Scale(0.5,0.5)
|
|
transform = starting
|
|
add_filter("weapon_rays", 3, list("type" = "rays", "size" = 28, "color" = COLOR_VIVID_YELLOW))
|
|
|
|
/obj/mystery_box_item/Destroy(force)
|
|
parent_box = null
|
|
return ..()
|
|
|
|
// this way, clicking on the prize will work the same as clicking on the box
|
|
/obj/mystery_box_item/attack_hand(mob/living/user, list/modifiers)
|
|
. = ..()
|
|
if(claimable)
|
|
parent_box.grant_weapon(user)
|
|
|
|
/// Start pushing the prize up
|
|
/obj/mystery_box_item/proc/start_animation(atom/parent)
|
|
parent_box = parent
|
|
loop_icon_changes()
|
|
|
|
/// Keep changing the icon and selected path
|
|
/obj/mystery_box_item/proc/loop_icon_changes()
|
|
var/change_delay = 1 // the running count of the delay
|
|
var/change_delay_delta = 1 // How much to increment the delay per step so the changing slows down
|
|
var/change_counter = 0 // The running count of the running count
|
|
|
|
var/matrix/starting = matrix()
|
|
animate(src, pixel_y = 6, transform = starting, time = MBOX_DURATION_CHOOSING, easing = QUAD_EASING | EASE_OUT)
|
|
|
|
while((change_counter + change_delay_delta + change_delay) < MBOX_DURATION_CHOOSING)
|
|
change_delay += change_delay_delta
|
|
change_counter += change_delay
|
|
selected_path = pick(parent_box.valid_types)
|
|
addtimer(CALLBACK(src, .proc/update_random_icon, selected_path), change_counter)
|
|
|
|
addtimer(CALLBACK(src, .proc/present_item), MBOX_DURATION_CHOOSING)
|
|
|
|
/// animate() isn't up to the task for queueing up icon changes, so this is the proc we call with timers to update our icon
|
|
/obj/mystery_box_item/proc/update_random_icon(new_item_type)
|
|
var/obj/item/new_item = new_item_type
|
|
icon = initial(new_item.icon)
|
|
icon_state = initial(new_item.icon_state)
|
|
|
|
/obj/mystery_box_item/proc/present_item()
|
|
var/obj/item/selected_item = selected_path
|
|
add_filter("ready_outline", 2, list("type" = "outline", "color" = "#FBFF23", "size" = 0.2))
|
|
name = initial(selected_item.name)
|
|
parent_box.present_weapon()
|
|
claimable = TRUE
|
|
|
|
/// Sink back into the box
|
|
/obj/mystery_box_item/proc/expire_animation()
|
|
var/matrix/shrink_back = matrix()
|
|
shrink_back.Scale(0.5,0.5)
|
|
animate(src, pixel_y = -8, transform = shrink_back, time = MBOX_DURATION_EXPIRING)
|
|
|
|
#undef MYSTERY_BOX_COOLING_DOWN
|
|
#undef MYSTERY_BOX_STANDBY
|
|
#undef MYSTERY_BOX_CHOOSING
|
|
#undef MYSTERY_BOX_PRESENTING
|
|
#undef MBOX_DURATION_CHOOSING
|
|
#undef MBOX_DURATION_PRESENTING
|
|
#undef MBOX_DURATION_EXPIRING
|
|
#undef MBOX_DURATION_STANDBY
|