Skip to content

Commit

Permalink
[MIRROR] Basic Space Dragon [MDB IGNORE] (#24340)
Browse files Browse the repository at this point in the history
* Basic Space Dragon (#78979)

* Basic Space Dragon

---------

Co-authored-by: Jacquerel <[email protected]>
  • Loading branch information
2 people authored and Iajret committed Oct 15, 2023
1 parent 3ab93db commit ab98a39
Show file tree
Hide file tree
Showing 44 changed files with 765 additions and 209 deletions.
1 change: 1 addition & 0 deletions code/__DEFINES/colors.dm
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
#define COLOR_SOFT_RED "#FA8282"
#define COLOR_CULT_RED "#960000"
#define COLOR_BUBBLEGUM_RED "#950A0A"
#define COLOR_CARP_RIFT_RED "#ff330030"

#define COLOR_YELLOW "#FFFF00"
#define COLOR_VIVID_YELLOW "#FBFF23"
Expand Down
4 changes: 4 additions & 0 deletions code/__DEFINES/dcs/signals/signals_atom/signals_atom_x_act.dm
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
// When the signal is called: (signal arguments)
// All signals send the source datum of the signal as the first argument

///from the [EX_ACT] wrapper macro: (severity, target)
#define COMSIG_ATOM_PRE_EX_ACT "atom_pre_ex_act"
/// if returned, don't let the explosion act on this atom
#define COMPONENT_CANCEL_EX_ACT (1<<0)
///from the [EX_ACT] wrapper macro: (severity, target)
#define COMSIG_ATOM_EX_ACT "atom_ex_act"
///from base of atom/emp_act(): (severity). return EMP protection flags
Expand Down
6 changes: 4 additions & 2 deletions code/__DEFINES/explosions.dm
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,10 @@
if(!(target.flags_1 & PREVENT_CONTENTS_EXPLOSION_1)) { \
target.contents_explosion(##args);\
};\
SEND_SIGNAL(target, COMSIG_ATOM_EX_ACT, ##args);\
target.ex_act(##args);
if(!(SEND_SIGNAL(target, COMSIG_ATOM_PRE_EX_ACT, ##args) & COMPONENT_CANCEL_EX_ACT)) { \
SEND_SIGNAL(target, COMSIG_ATOM_EX_ACT, ##args);\
target.ex_act(##args);\
}

// Internal explosion argument list keys.
// Must match the arguments to [/datum/controller/subsystem/explosions/proc/propagate_blastwave]
Expand Down
4 changes: 4 additions & 0 deletions code/__DEFINES/megafauna.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/// Temperature of drake fire hotspots
#define DRAKE_FIRE_TEMP 500
/// Volume of drake fire hotspots
#define DRAKE_FIRE_EXPOSURE 50
7 changes: 7 additions & 0 deletions code/__DEFINES/traits.dm
Original file line number Diff line number Diff line change
Expand Up @@ -1317,3 +1317,10 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai

///Trait given by /datum/element/relay_attacker
#define TRAIT_RELAYING_ATTACKER "relaying_attacker"

/// Trait given while using /datum/action/cooldown/mob_cooldown/wing_buffet
#define TRAIT_WING_BUFFET "wing_buffet"
/// Trait given while tired after using /datum/action/cooldown/mob_cooldown/wing_buffet
#define TRAIT_WING_BUFFET_TIRED "wing_buffet_tired"
/// Trait given to a dragon who fails to defend their rifts
#define TRAIT_RIFT_FAILURE "fail_dragon_loser"
108 changes: 83 additions & 25 deletions code/datums/actions/mobs/fire_breath.dm
Original file line number Diff line number Diff line change
Expand Up @@ -2,63 +2,121 @@
name = "Fire Breath"
button_icon = 'icons/effects/magic.dmi'
button_icon_state = "fireball"
desc = "Allows you to shoot fire towards a target."
desc = "Breathe a line of flames towards the target."
cooldown_time = 3 SECONDS
/// The range of the fire
var/fire_range = 15
/// The sound played when you use this ability
var/fire_sound = 'sound/magic/fireball.ogg'
/// If the fire should be icey fire
var/ice_breath = FALSE
/// Time to wait between spawning each fire turf
var/fire_delay = 1.5 DECISECONDS
/// How hot is our fire
var/fire_temperature = DRAKE_FIRE_TEMP
/// 'How much' fire do we expose the turf to?
var/fire_volume = DRAKE_FIRE_EXPOSURE
/// How much damage do you take when engulfed?
var/fire_damage = 20
/// How much damage to mechs take when engulfed?
var/mech_damage = 45

/datum/action/cooldown/mob_cooldown/fire_breath/Activate(atom/target_atom)
StartCooldown(360 SECONDS, 360 SECONDS)
attack_sequence(target_atom)
StartCooldown()
return TRUE

/// Apply our specific fire breathing shape, in proc form so we can override it in subtypes
/datum/action/cooldown/mob_cooldown/fire_breath/proc/attack_sequence(atom/target)
playsound(owner.loc, fire_sound, 200, TRUE)
fire_line(target, 0)
fire_line(target)

/// Breathe fire in a line towards the target, optionally rotated at an offset from the target
/datum/action/cooldown/mob_cooldown/fire_breath/proc/fire_line(atom/target, offset)
SLEEP_CHECK_DEATH(0, owner)
var/list/turfs = line_target(offset, fire_range, target)
// This proc sleeps
INVOKE_ASYNC(GLOBAL_PROC, GLOBAL_PROC_REF(dragon_fire_line), owner, /* burn_turfs = */ turfs, /* frozen = */ ice_breath)
if (isnull(target))
return
var/turf/target_turf = get_ranged_target_turf_direct(owner, target, fire_range, offset)
var/list/turfs = get_line(owner, target_turf) - get_turf(owner)
INVOKE_ASYNC(src, PROC_REF(progressive_fire_line), turfs)

/datum/action/cooldown/mob_cooldown/fire_breath/proc/line_target(offset, range, atom/target)
if(!target)
/// Creates fire with a delay on the list of targetted turfs
/datum/action/cooldown/mob_cooldown/fire_breath/proc/progressive_fire_line(list/burn_turfs)
if (QDELETED(owner) || owner.stat == DEAD)
return
var/turf/T = get_ranged_target_turf_direct(owner, target, range, offset)
return (get_line(owner, T) - get_turf(owner))
// Guys we have already hit, no double dipping
var/list/hit_list = list(owner) // also don't burn ourselves
for(var/turf/target_turf in burn_turfs)
if (target_turf.is_blocked_turf(exclude_mobs = TRUE))
return
burn_turf(target_turf, hit_list, owner)
sleep(fire_delay)

/// Finally spawn the actual fire, spawns the fire hotspot in case you want to recolour it or something
/datum/action/cooldown/mob_cooldown/fire_breath/proc/burn_turf(turf/fire_turf, list/hit_list, mob/living/source)
var/obj/effect/hotspot/fire_hotspot = new /obj/effect/hotspot(fire_turf)
fire_turf.hotspot_expose(fire_temperature, fire_volume, TRUE)

for(var/mob/living/barbecued in fire_turf.contents)
if(barbecued in hit_list)
continue
hit_list |= barbecued
on_burn_mob(barbecued, source)

for(var/obj/vehicle/sealed/mecha/robotron in fire_turf.contents)
if(robotron in hit_list)
continue
hit_list |= robotron
robotron.take_damage(mech_damage, BURN, FIRE)

return fire_hotspot

/// Do something unpleasant to someone we set on fire
/datum/action/cooldown/mob_cooldown/fire_breath/proc/on_burn_mob(mob/living/barbecued, mob/living/source)
to_chat(barbecued, span_userdanger("You are burned by [source]'s fire breath!"))
barbecued.adjustFireLoss(fire_damage)

/// Shoot three lines of fire in a sort of fork pattern approximating a cone
/datum/action/cooldown/mob_cooldown/fire_breath/cone
name = "Fire Cone"
desc = "Allows you to shoot fire towards a target with surrounding lines of fire."
desc = "Breathe several lines of fire directed at a target."
/// The angles relative to the target that shoot lines of fire
var/list/angles = list(-40, 0, 40)

/datum/action/cooldown/mob_cooldown/fire_breath/cone/attack_sequence(atom/target)
playsound(owner.loc, fire_sound, 200, TRUE)
for(var/offset in angles)
INVOKE_ASYNC(src, PROC_REF(fire_line), target, offset)
fire_line(target, offset)

/// Shoot fire in a whole bunch of directions
/datum/action/cooldown/mob_cooldown/fire_breath/mass_fire
name = "Mass Fire"
button_icon = 'icons/effects/fire.dmi'
button_icon_state = "1"
desc = "Allows you to shoot fire in all directions."
desc = "Breathe flames in all directions."
cooldown_time = 3 SECONDS
click_to_activate = FALSE
/// How many fire lines do we produce to turn a full circle?
var/sectors = 12
/// How long do we wait between each spin?
var/breath_delay = 2.5 SECONDS
/// How many full circles do we perform?
var/total_spins = 3

/datum/action/cooldown/mob_cooldown/fire_breath/mass_fire/Activate(atom/target_atom)
target_atom = get_step(owner, owner.dir) // Just shoot it forwards, we don't need to click on someone for this one
return ..()

/datum/action/cooldown/mob_cooldown/fire_breath/mass_fire/attack_sequence(atom/target)
shoot_mass_fire(target, 12, 2.5 SECONDS, 3)
var/queued_spins = 0
for (var/i in 1 to total_spins)
var/delay = queued_spins * breath_delay
queued_spins++
addtimer(CALLBACK(src, PROC_REF(fire_spin), target, queued_spins), delay)

/datum/action/cooldown/mob_cooldown/fire_breath/mass_fire/proc/shoot_mass_fire(atom/target, spiral_count, delay_time, times)
SLEEP_CHECK_DEATH(0, owner)
for(var/i = 1 to times)
playsound(owner.loc, fire_sound, 200, TRUE)
var/increment = 360 / spiral_count
for(var/j = 1 to spiral_count)
INVOKE_ASYNC(src, PROC_REF(fire_line), target, j * increment + i * increment / 2)
SLEEP_CHECK_DEATH(delay_time, owner)
/// Breathe fire in a circle, with a slight angle offset based on which of our several circles it is
/datum/action/cooldown/mob_cooldown/fire_breath/mass_fire/proc/fire_spin(target, spin_count)
if (QDELETED(owner) || owner.stat == DEAD)
return // Too dead to spin
playsound(owner.loc, fire_sound, 200, TRUE)
var/angle_increment = 360 / sectors
var/additional_offset = spin_count * angle_increment / 2
for (var/i in 1 to sectors)
fire_line(target, (angle_increment * i) + (additional_offset))
2 changes: 1 addition & 1 deletion code/datums/actions/mobs/mobcooldown.dm
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
button_icon = 'icons/mob/actions/actions_items.dmi'
button_icon_state = "sniper_zoom"
desc = "Click this ability to attack."
check_flags = AB_CHECK_CONSCIOUS
check_flags = AB_CHECK_CONSCIOUS | AB_CHECK_INCAPACITATED
cooldown_time = 5 SECONDS
text_cooldown = TRUE
click_to_activate = TRUE
Expand Down
1 change: 0 additions & 1 deletion code/datums/actions/mobs/sneak.dm
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
button_icon_state = "sniper_zoom"
background_icon_state = "bg_alien"
overlay_icon_state = "bg_alien_border"
check_flags = AB_CHECK_CONSCIOUS | AB_CHECK_INCAPACITATED | AB_CHECK_INCAPACITATED
cooldown_time = 0.5 SECONDS
melee_cooldown_time = 0 SECONDS
click_to_activate = FALSE
Expand Down
52 changes: 0 additions & 52 deletions code/datums/components/pry_open_door.dm

This file was deleted.

99 changes: 99 additions & 0 deletions code/datums/components/torn_wall.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@

#define TORN_WALL_RUINED 2
#define TORN_WALL_DAMAGED 1
#define TORN_WALL_INITIAL 0

/**
* Component applied to a wall to progressively destroy it.
* If component is applied to something which already has it, stage increases.
* Wall is destroyed on third application.
* Can be fixed using a welder
*/
/datum/component/torn_wall
dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS
var/current_stage = TORN_WALL_INITIAL

/datum/component/torn_wall/Initialize()
. = ..()
if (!iswallturf(parent) || isindestructiblewall(parent))
return COMPONENT_INCOMPATIBLE

/datum/component/torn_wall/RegisterWithParent()
RegisterSignal(parent, COMSIG_ATOM_EXAMINE, PROC_REF(on_examined))
RegisterSignal(parent, COMSIG_ATOM_TOOL_ACT(TOOL_WELDER), PROC_REF(on_welded))
RegisterSignal(parent, COMSIG_ATOM_UPDATE_OVERLAYS, PROC_REF(on_update_overlays))
RegisterSignal(parent, COMSIG_TURF_CHANGE, PROC_REF(on_turf_changed))
apply_visuals()

/datum/component/torn_wall/UnregisterFromParent()
var/atom/atom_parent = parent
UnregisterSignal(parent, list(
COMSIG_ATOM_EXAMINE,
COMSIG_ATOM_TOOL_ACT(TOOL_WELDER),
COMSIG_ATOM_UPDATE_OVERLAYS,
COMSIG_TURF_CHANGE,
))
atom_parent.update_appearance(UPDATE_ICON)

/datum/component/torn_wall/InheritComponent(datum/component/C, i_am_original)
increase_stage()

/// Play a fun animation and make our wall look damaged
/datum/component/torn_wall/proc/apply_visuals()
var/atom/atom_parent = parent
playsound(atom_parent, 'sound/effects/bang.ogg', 50, vary = TRUE)
atom_parent.update_appearance(UPDATE_ICON)
atom_parent.Shake(shake_interval = 0.1 SECONDS, duration = 0.5 SECONDS)

/// Make the effect more dramatic
/datum/component/torn_wall/proc/increase_stage()
current_stage++
if (current_stage != TORN_WALL_RUINED)
apply_visuals()
return
var/turf/closed/wall/attached_wall = parent
playsound(attached_wall, 'sound/effects/meteorimpact.ogg', 100, vary = TRUE)
attached_wall.dismantle_wall(devastated = TRUE)

/// Fix it up on weld
/datum/component/torn_wall/proc/on_welded(atom/source, mob/user, obj/item/tool)
SIGNAL_HANDLER
INVOKE_ASYNC(src, PROC_REF(try_repair), source, user, tool)
return COMPONENT_BLOCK_TOOL_ATTACK

/// Fix us up
/datum/component/torn_wall/proc/try_repair(atom/source, mob/user, obj/item/tool)
source.balloon_alert(user, "repairing...")
if(!tool.use_tool(source, user, 5 SECONDS, amount = 2, volume = 50))
source.balloon_alert(user, "interrupted!")
return
current_stage--
if (current_stage < TORN_WALL_INITIAL)
qdel(src)
return
source.update_appearance(UPDATE_ICON)
source.tool_act(user, tool, TOOL_WELDER, is_right_clicking = FALSE) // Keep going

/// Give them a hint
/datum/component/torn_wall/proc/on_examined(atom/source, mob/user, list/examine_list)
SIGNAL_HANDLER
var/intensity = (current_stage == TORN_WALL_INITIAL) ? "slightly" : "badly"
examine_list += span_notice("It looks [intensity] damaged.")
examine_list += span_info("You may be able to repair it using a welding tool.")

/// Show a little crack on here
/datum/component/torn_wall/proc/on_update_overlays(turf/source, list/overlays)
SIGNAL_HANDLER
var/mutable_appearance/crack = mutable_appearance('icons/turf/overlays.dmi', "explodable", source.layer + 0.1)
if (current_stage == TORN_WALL_INITIAL)
crack.alpha *= 0.5
overlays += crack

/// If the wall becomes any other turf, delete us. Transforming into a different works fine as a fix.
/datum/component/torn_wall/proc/on_turf_changed()
SIGNAL_HANDLER
qdel(src)

#undef TORN_WALL_RUINED
#undef TORN_WALL_DAMAGED
#undef TORN_WALL_INITIAL
Loading

0 comments on commit ab98a39

Please sign in to comment.