mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-24 05:30:05 +01:00
[MIRROR] Miner Style Points 2: Style on Everyone [MDB IGNORE] (#20826)
* Miner Style Points 2: Style on Everyone (#74690) ## About The Pull Request A re-open of https://github.com/tgstation/tgstation/pull/66326 with Fikou's permission Adds the style meter, it can be bought from the mining vendor for 1500 points, it is an attachment to your glasses. The style meter creates a display on your hud, with your recent actions, like attacking enemies, killing them, mining ore etc. Actions like spinning or flipping increase your score multiplier, making you get more points. Your style meter affects how much ore you get from mining rocks. By default with the meter, you get 20% less ore, but at the highest, you can get 1.2x the ore from mining. In addition, on B-tier or above, you can "hotswap" items, by attacking an item in your backpack with one in your hand (should it fit and all that). Also features a leaderboard for highest style point count! New streamable: https://streamable.com/eewi6l The following are sources of points: - Killing things - Killing big things - Killing small things - Punching things - Melee'ing things - Mining rocks and ores - Having matrix traps detonate - Hit, defuse, and detonate gibtonite - Detonate crusher marks - Scan geysers - Parry projectiles (others or your own) Oh, right. While wearing the style meter, you're able to parry any lavaland-based projectile by clicking on it or the tile it is on, which reflects it back in a 7 degree arc, making it 20% faster and 15% more damaging. Usually not very easy. Maybe-plan in the future for some syndicate variant of this (with bullet parrying and appropriate style sources, etc.), but not for this PR Thanks to Arcane, multitooling the style meter will make it play some sounds on rank-up.  https://streamable.com/nheaky Parrying in action ## Why It's Good For The Game Makes miners bring more ore in a fun way. ## Changelog 🆑 Fikou, Zonespace, Arcane for voicing add: The mining vendor now has a style meter. This meter gauges your style points and uses them to improve your ore yield. /🆑 --------- Co-authored-by: Fikou <23585223+Fikou@ users.noreply.github.com> * Miner Style Points 2: Style on Everyone --------- Co-authored-by: Zonespace <41448081+Zonespace27@users.noreply.github.com> Co-authored-by: Fikou <23585223+Fikou@ users.noreply.github.com>
This commit is contained in:
co-authored by
Fikou
Zonespace
parent
655bda28f9
commit
9c2e07ee7c
@@ -122,6 +122,9 @@
|
||||
// DB ID for intento score
|
||||
#define INTENTO_SCORE "Intento Score"
|
||||
|
||||
// DB ID for style point count
|
||||
#define STYLE_SCORE "Style Score"
|
||||
|
||||
// Tourist related achievements and scores
|
||||
|
||||
//centcom grades (achievement)
|
||||
|
||||
@@ -139,3 +139,25 @@
|
||||
|
||||
/// From /mob/living/unfriend() : (mob/living/old_friend)
|
||||
#define COMSIG_LIVING_UNFRIENDED "living_unfriended"
|
||||
|
||||
/// From /obj/effect/temp_visual/resonance/burst() : (mob/creator, mob/living/hit_living)
|
||||
#define COMSIG_LIVING_RESONATOR_BURST "living_resonator_burst"
|
||||
|
||||
/// From /obj/projectile/attempt_parry() : (obj/projectile/parried_projectile)
|
||||
#define COMSIG_LIVING_PROJECTILE_PARRYING "living_projectile_parrying"
|
||||
/// Return to allow the parry to happen
|
||||
#define ALLOW_PARRY (1<<0)
|
||||
|
||||
/// From /obj/projectile/on_parry() : (obj/projectile/parried_projectile)
|
||||
#define COMSIG_LIVING_PROJECTILE_PARRIED "living_projectile_parried"
|
||||
/// Return to prevent the projectile from executing any code in on_parry()
|
||||
#define INTERCEPT_PARRY_EFFECTS (1<<0)
|
||||
|
||||
/// From /turf/closed/mineral/gibtonite/defuse() : (det_time)
|
||||
#define COMSIG_LIVING_DEFUSED_GIBTONITE "living_defused_gibtonite"
|
||||
|
||||
/// From /obj/item/kinetic_crusher/afterattack() : (mob/living/target, obj/item/kinetic_crusher/crusher, backstabbed)
|
||||
#define COMSIG_LIVING_CRUSHER_DETONATE "living_crusher_detonate"
|
||||
|
||||
/// From /obj/structure/geyser/attackby() : (obj/structure/geyser/geyser)
|
||||
#define COMSIG_LIVING_DISCOVERED_GEYSER "living_discovered_geyser"
|
||||
|
||||
@@ -173,6 +173,8 @@
|
||||
#define COMSIG_MOB_AUTOMUTE_CHECK "client_automute_check" // The check is performed by the client.
|
||||
/// Prevents the automute system checking this client for repeated messages.
|
||||
#define WAIVE_AUTOMUTE_CHECK (1<<0)
|
||||
///From base of /turf/closed/mineral/proc/gets_drilled(): (turf/closed/mineral/rock, give_exp)
|
||||
#define COMSIG_MOB_MINED "mob_mined"
|
||||
|
||||
///from living/flash_act(), when a mob is successfully flashed.
|
||||
#define COMSIG_MOB_FLASHED "mob_flashed"
|
||||
|
||||
@@ -249,6 +249,7 @@
|
||||
#define CRIT_LAYER 5
|
||||
#define CURSE_LAYER 6
|
||||
#define ECHO_LAYER 7
|
||||
#define PARRY_LAYER 8
|
||||
|
||||
#define FOV_EFFECT_LAYER 100
|
||||
|
||||
|
||||
@@ -118,6 +118,9 @@
|
||||
icon_state = "oxydamageoverlay"
|
||||
layer = BLIND_LAYER
|
||||
|
||||
/atom/movable/screen/fullscreen/crit/projectile_parry
|
||||
layer = PARRY_LAYER
|
||||
|
||||
/atom/movable/screen/fullscreen/blind
|
||||
icon_state = "blackimageoverlay"
|
||||
layer = BLIND_LAYER
|
||||
|
||||
@@ -15,3 +15,9 @@
|
||||
name = "Intento Score"
|
||||
desc = "A blast from the future?"
|
||||
database_id = INTENTO_SCORE
|
||||
|
||||
/// What's the highest amount of style points we've gotten?
|
||||
/datum/award/score/style_score
|
||||
name = "Style Score"
|
||||
desc = "You might not be a robot, but you were damn close."
|
||||
database_id = STYLE_SCORE
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
/// Add to a living mob to allow them to "parry" projectiles by clicking on their tile, sending them back at the firer.
|
||||
/datum/component/projectile_parry
|
||||
/// typecache of valid projectiles to be able to parry
|
||||
var/list/parryable_projectiles
|
||||
|
||||
|
||||
/datum/component/projectile_parry/Initialize(list/projectiles_to_parry)
|
||||
if(!isliving(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
|
||||
parryable_projectiles = typecacheof(projectiles_to_parry)
|
||||
|
||||
|
||||
/datum/component/projectile_parry/RegisterWithParent()
|
||||
RegisterSignal(parent, COMSIG_LIVING_PROJECTILE_PARRYING, PROC_REF(parrying_projectile))
|
||||
RegisterSignal(parent, COMSIG_LIVING_PROJECTILE_PARRIED, PROC_REF(parried_projectile))
|
||||
|
||||
|
||||
/datum/component/projectile_parry/UnregisterFromParent()
|
||||
UnregisterSignal(parent, list(COMSIG_LIVING_PROJECTILE_PARRYING, COMSIG_LIVING_PROJECTILE_PARRIED))
|
||||
|
||||
|
||||
/datum/component/projectile_parry/proc/parrying_projectile(datum/source, obj/projectile/parried_projectile)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(is_type_in_typecache(parried_projectile, parryable_projectiles))
|
||||
return ALLOW_PARRY
|
||||
|
||||
|
||||
/datum/component/projectile_parry/proc/parried_projectile(datum/source, obj/projectile/parried_projectile)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
var/mob/living/living_parent = parent
|
||||
|
||||
living_parent.playsound_local(get_turf(parried_projectile), 'sound/effects/parry.ogg', 50, TRUE)
|
||||
living_parent.overlay_fullscreen("projectile_parry", /atom/movable/screen/fullscreen/crit/projectile_parry, 2)
|
||||
addtimer(CALLBACK(living_parent, TYPE_PROC_REF(/mob, clear_fullscreen), "projectile_parry"), 0.25 SECONDS)
|
||||
living_parent.visible_message(span_warning("[living_parent] expertly parries [parried_projectile] with [living_parent.p_their()] bare hand!"), span_warning("You parry [parried_projectile] with your hand!"))
|
||||
@@ -0,0 +1,496 @@
|
||||
#define STYLE_DULL 1
|
||||
#define STYLE_COOL 2
|
||||
#define STYLE_BRUTAL 3
|
||||
#define STYLE_ABSOLUTE 4
|
||||
#define STYLE_SPACED 5
|
||||
|
||||
#define ACTION_KILL "KILL"
|
||||
#define ACTION_MINOR_KILL "MINOR KILL"
|
||||
#define ACTION_MAJOR_KILL "MAJOR KILL"
|
||||
#define ACTION_DISRESPECT "DISRESPECT"
|
||||
#define ACTION_MELEED "MELEE'D"
|
||||
#define ACTION_ROCK_MINED "ROCK MINED"
|
||||
#define ACTION_ORE_MINED "ORE MINED"
|
||||
#define ACTION_TRAPPER "TRAPPER"
|
||||
#define ACTION_PARRIED "PARRIED"
|
||||
#define ACTION_PROJECTILE_BOOST "PROJECTILE BOOST"
|
||||
#define ACTION_GIBTONITE_HIT "GIBTONITE HIT"
|
||||
#define ACTION_GIBTONITE_BOOM "GIBTONITE BOOM"
|
||||
#define ACTION_GIBTONITE_DEFUSED "GIBTONITE DEFUSED"
|
||||
#define ACTION_MARK_DETONATED "MARK DETONATED"
|
||||
#define ACTION_GEYSER_MARKED "GEYSER MARKED"
|
||||
|
||||
/datum/component/style
|
||||
/// Amount of style we have.
|
||||
var/style_points = -1
|
||||
/// Our style point multiplier.
|
||||
var/point_multiplier = 1
|
||||
/// The current rank we have.
|
||||
var/rank = STYLE_DULL
|
||||
/// The last point affecting actions we've done
|
||||
var/list/actions = list()
|
||||
/// The style meter shown on screen.
|
||||
var/atom/movable/screen/style_meter_background/meter
|
||||
/// The image of the style meter.
|
||||
var/atom/movable/screen/style_meter/meter_image
|
||||
/// The timer for meter updating
|
||||
var/timerid
|
||||
/// Highest score attained by this component, to avoid as much overhead when considering to award a high score to the client
|
||||
var/high_score = 0
|
||||
/// Weakref to the added projectile parry component
|
||||
var/datum/weakref/projectile_parry
|
||||
/// What rank, minimum, the user needs to be to hotswap items
|
||||
var/hotswap_rank = STYLE_BRUTAL
|
||||
/// If this is multitooled, making it make funny noises on the user's rank going up
|
||||
var/multitooled = FALSE
|
||||
/// A static list of lists of all the possible sounds to play when multitooled, in numerical order
|
||||
var/static/list/rankup_sounds = list(
|
||||
list(
|
||||
'sound/items/style/combo_dull1.ogg',
|
||||
'sound/items/style/combo_dull2.ogg',
|
||||
'sound/items/style/combo_dull3.ogg',
|
||||
),
|
||||
list(
|
||||
'sound/items/style/combo_cool1.ogg',
|
||||
'sound/items/style/combo_cool2.ogg',
|
||||
'sound/items/style/combo_cool3.ogg',
|
||||
),
|
||||
list(
|
||||
'sound/items/style/combo_brutal1.ogg',
|
||||
'sound/items/style/combo_brutal2.ogg',
|
||||
'sound/items/style/combo_brutal3.ogg',
|
||||
),
|
||||
list(
|
||||
'sound/items/style/combo_absolute1.ogg',
|
||||
'sound/items/style/combo_absolute2.ogg',
|
||||
'sound/items/style/combo_absolute3.ogg',
|
||||
),
|
||||
list(
|
||||
'sound/items/style/combo_spaced1.ogg',
|
||||
'sound/items/style/combo_spaced2.ogg',
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
/datum/component/style/Initialize(multitooled = FALSE)
|
||||
if(!ismob(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
|
||||
var/mob/mob_parent = parent
|
||||
|
||||
meter = new()
|
||||
meter_image = new()
|
||||
meter.vis_contents += meter_image
|
||||
meter_image.add_filter("meter_mask", 1, list(type = "alpha", icon = icon('icons/hud/style_meter.dmi', "style_meter"), flags = MASK_INVERSE))
|
||||
meter.update_appearance()
|
||||
meter_image.update_appearance()
|
||||
|
||||
update_screen()
|
||||
|
||||
if(mob_parent.hud_used)
|
||||
mob_parent.hud_used.static_inventory += meter
|
||||
mob_parent.hud_used.show_hud(mob_parent.hud_used.hud_version)
|
||||
|
||||
START_PROCESSING(SSdcs, src)
|
||||
|
||||
if(multitooled)
|
||||
src.multitooled = multitooled
|
||||
|
||||
RegisterSignal(src, COMSIG_ATOM_TOOL_ACT(TOOL_MULTITOOL), PROC_REF(on_parent_multitool))
|
||||
|
||||
/datum/component/style/RegisterWithParent()
|
||||
RegisterSignal(parent, COMSIG_MOB_ITEM_AFTERATTACK, PROC_REF(hotswap))
|
||||
RegisterSignal(parent, COMSIG_MOB_MINED, PROC_REF(on_mine))
|
||||
RegisterSignal(parent, COMSIG_MOB_APPLY_DAMAGE, PROC_REF(on_take_damage))
|
||||
RegisterSignal(parent, COMSIG_MOB_EMOTED("flip"), PROC_REF(on_flip))
|
||||
RegisterSignal(parent, COMSIG_MOB_EMOTED("spin"), PROC_REF(on_spin))
|
||||
RegisterSignal(parent, COMSIG_MOB_ITEM_ATTACK, PROC_REF(on_attack))
|
||||
RegisterSignal(parent, COMSIG_HUMAN_MELEE_UNARMED_ATTACK, PROC_REF(on_punch))
|
||||
RegisterSignal(SSdcs, COMSIG_GLOB_MOB_DEATH, PROC_REF(on_death))
|
||||
RegisterSignal(parent, COMSIG_LIVING_RESONATOR_BURST, PROC_REF(on_resonator_burst))
|
||||
RegisterSignal(parent, COMSIG_LIVING_PROJECTILE_PARRIED, PROC_REF(on_projectile_parry))
|
||||
RegisterSignal(parent, COMSIG_LIVING_DEFUSED_GIBTONITE, PROC_REF(on_gibtonite_defuse))
|
||||
RegisterSignal(parent, COMSIG_LIVING_CRUSHER_DETONATE, PROC_REF(on_crusher_detonate))
|
||||
RegisterSignal(parent, COMSIG_LIVING_DISCOVERED_GEYSER, PROC_REF(on_geyser_discover))
|
||||
|
||||
projectile_parry = WEAKREF(AddComponent(\
|
||||
/datum/component/projectile_parry,\
|
||||
list(\
|
||||
/obj/projectile/colossus,\
|
||||
/obj/projectile/temp/basilisk,\
|
||||
/obj/projectile/kinetic,\
|
||||
/obj/projectile/bileworm_acid,\
|
||||
/obj/projectile/herald,\
|
||||
)\
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
/datum/component/style/UnregisterFromParent()
|
||||
UnregisterSignal(parent, COMSIG_MOB_ITEM_AFTERATTACK)
|
||||
UnregisterSignal(parent, COMSIG_MOB_MINED)
|
||||
UnregisterSignal(parent, COMSIG_MOB_APPLY_DAMAGE)
|
||||
UnregisterSignal(parent, list(COMSIG_MOB_EMOTED("flip"), COMSIG_MOB_EMOTED("spin")))
|
||||
UnregisterSignal(parent, list(COMSIG_MOB_ITEM_ATTACK, COMSIG_HUMAN_MELEE_UNARMED_ATTACK))
|
||||
UnregisterSignal(SSdcs, COMSIG_GLOB_MOB_DEATH)
|
||||
UnregisterSignal(parent, COMSIG_LIVING_RESONATOR_BURST)
|
||||
UnregisterSignal(parent, COMSIG_LIVING_PROJECTILE_PARRIED)
|
||||
UnregisterSignal(parent, COMSIG_LIVING_DEFUSED_GIBTONITE)
|
||||
UnregisterSignal(parent, COMSIG_LIVING_CRUSHER_DETONATE)
|
||||
UnregisterSignal(parent, COMSIG_LIVING_DISCOVERED_GEYSER)
|
||||
|
||||
if(projectile_parry)
|
||||
qdel(projectile_parry.resolve())
|
||||
|
||||
|
||||
/datum/component/style/Destroy(force, silent)
|
||||
STOP_PROCESSING(SSdcs, src)
|
||||
var/mob/mob_parent = parent
|
||||
if(mob_parent.hud_used)
|
||||
mob_parent.hud_used.static_inventory -= meter
|
||||
mob_parent.hud_used.show_hud(mob_parent.hud_used.hud_version)
|
||||
return ..()
|
||||
|
||||
|
||||
/datum/component/style/process(seconds_per_tick)
|
||||
point_multiplier = round(max(point_multiplier - 0.2 * seconds_per_tick, 1), 0.1)
|
||||
change_points(-5 * seconds_per_tick * ROUND_UP((style_points + 1) / 200), use_multiplier = FALSE)
|
||||
update_screen()
|
||||
|
||||
|
||||
|
||||
/datum/component/style/proc/add_action(action, amount)
|
||||
if(length(actions) > 9)
|
||||
actions.Cut(1, 2)
|
||||
if(length(actions))
|
||||
var/last_action = actions[length(actions)]
|
||||
if(action == actions[last_action])
|
||||
amount *= 0.5
|
||||
var/id
|
||||
while(!id || (id in actions))
|
||||
id = "action[rand(1, 1000)]"
|
||||
actions[id] = action
|
||||
change_points(amount)
|
||||
addtimer(CALLBACK(src, PROC_REF(remove_action), id), 10 SECONDS)
|
||||
|
||||
/datum/component/style/proc/remove_action(action_id)
|
||||
actions -= action_id
|
||||
update_screen()
|
||||
|
||||
/datum/component/style/proc/change_points(amount, use_multiplier = TRUE)
|
||||
if(!amount)
|
||||
return
|
||||
|
||||
var/modified_amount = amount * (amount > 0 ? 1 - 0.1 * rank : 1) * (use_multiplier ? point_multiplier : 1)
|
||||
style_points = max(style_points + modified_amount, -1)
|
||||
update_screen()
|
||||
|
||||
if(style_points > high_score)
|
||||
var/mob/mob_parent = parent
|
||||
if((mob_parent.flags_1 & ADMIN_SPAWNED_1) || (mob_parent.datum_flags & DF_VAR_EDITED) || (datum_flags & DF_VAR_EDITED) || !SSachievements.achievements_enabled || !mob_parent.client) // No varediting/spawning this or the owner
|
||||
return
|
||||
|
||||
var/award_status = mob_parent.client.get_award_status(/datum/award/score/style_score)
|
||||
|
||||
if(award_status >= style_points)
|
||||
high_score = style_points
|
||||
return
|
||||
|
||||
mob_parent.client.give_award(/datum/award/score/style_score, mob_parent, style_points - award_status)
|
||||
high_score = style_points
|
||||
|
||||
/datum/component/style/proc/update_screen(rank_changed)
|
||||
var/go_back = null
|
||||
if(!isnull(rank_changed))
|
||||
timerid = null
|
||||
if(rank_changed == point_to_rank())
|
||||
go_back = rank > rank_changed ? 100 : 0
|
||||
|
||||
if(multitooled && (rank_changed > rank)) // make funny noises
|
||||
var/mob/mob_parent = parent
|
||||
mob_parent.playsound_local(get_turf(mob_parent), pick(rankup_sounds[rank_changed]), 70, vary = FALSE)
|
||||
|
||||
if((rank < hotswap_rank) && (rank_changed >= hotswap_rank))
|
||||
var/mob/mob_parent = parent
|
||||
mob_parent.balloon_alert(mob_parent, "hotswapping enabled")
|
||||
|
||||
else if((rank >= hotswap_rank) && (rank_changed < hotswap_rank))
|
||||
var/mob/mob_parent = parent
|
||||
mob_parent.balloon_alert(mob_parent, "hotswapping disabled")
|
||||
|
||||
rank = rank_changed
|
||||
meter.maptext = "[format_rank_string(rank)][generate_multiplier()][generate_actions()]"
|
||||
meter.maptext_y = 100 - 9 * length(actions)
|
||||
update_meter(point_to_rank(), go_back)
|
||||
|
||||
/datum/component/style/proc/update_meter(new_rank, go_back)
|
||||
if(!isnull(go_back))
|
||||
animate(meter_image.get_filter("meter_mask"), time = 0 SECONDS, flags = ANIMATION_END_NOW, x = go_back)
|
||||
animate(meter_image.get_filter("meter_mask"), time = 1 SECONDS, x = (rank > new_rank ? 0 : (rank < new_rank ? 100 : (style_points % 100) + 1)))
|
||||
if(!isnull(new_rank) && new_rank != rank && !timerid)
|
||||
timerid = addtimer(CALLBACK(src, PROC_REF(update_screen), new_rank), 1 SECONDS)
|
||||
|
||||
/datum/component/style/proc/rank_to_color(new_rank)
|
||||
switch(new_rank)
|
||||
if(STYLE_DULL)
|
||||
return "#aaaaaa"
|
||||
if(STYLE_COOL)
|
||||
return "#aaaaff"
|
||||
if(STYLE_BRUTAL)
|
||||
return "#aaffff"
|
||||
if(STYLE_ABSOLUTE)
|
||||
return "#66ffff"
|
||||
if(STYLE_SPACED)
|
||||
return "#ffaa00"
|
||||
|
||||
/datum/component/style/proc/point_to_rank()
|
||||
switch(style_points)
|
||||
if(-1 to 99)
|
||||
return STYLE_DULL
|
||||
if(100 to 199)
|
||||
return STYLE_COOL
|
||||
if(200 to 299)
|
||||
return STYLE_BRUTAL
|
||||
if(300 to 399)
|
||||
return STYLE_ABSOLUTE
|
||||
if(400 to INFINITY)
|
||||
return STYLE_SPACED
|
||||
|
||||
|
||||
/datum/component/style/proc/rank_to_string(new_rank)
|
||||
switch(new_rank)
|
||||
if(STYLE_DULL)
|
||||
return "DULL"
|
||||
if(STYLE_COOL)
|
||||
return "COOL"
|
||||
if(STYLE_BRUTAL)
|
||||
return "BRUTAL"
|
||||
if(STYLE_ABSOLUTE)
|
||||
return "ABSOLUTE"
|
||||
if(STYLE_SPACED)
|
||||
return "SPACED!"
|
||||
|
||||
/datum/component/style/proc/format_rank_string(new_rank)
|
||||
var/rank_string = rank_to_string(new_rank)
|
||||
var/final_string = ""
|
||||
final_string += "<span class='maptext' style='font-size: 8px'><font color='[rank_to_color(new_rank)]'><b>[rank_string[1]]</b>"
|
||||
final_string += "<span style='font-size: 7px'>[copytext(rank_string, 2)]</span></font></span>"
|
||||
return final_string
|
||||
|
||||
/datum/component/style/proc/generate_multiplier()
|
||||
return "<br><span class='maptext' style='font-size: 7px'>MULTIPLIER: [point_multiplier]X</span>"
|
||||
|
||||
/datum/component/style/proc/generate_actions()
|
||||
var/action_string = ""
|
||||
for(var/action in actions)
|
||||
action_string += "<br><span class='maptext'>+ <font color='[action_to_color(actions[action])]'>[actions[action]]</font></span>"
|
||||
return action_string
|
||||
|
||||
/datum/component/style/proc/action_to_color(action)
|
||||
switch(action)
|
||||
if(ACTION_KILL)
|
||||
return "#ff0000"
|
||||
if(ACTION_MINOR_KILL)
|
||||
return "#ff6666"
|
||||
if(ACTION_MAJOR_KILL)
|
||||
return "#ffaa00"
|
||||
if(ACTION_DISRESPECT)
|
||||
return "#990000"
|
||||
if(ACTION_MELEED)
|
||||
return "#660033"
|
||||
if(ACTION_ROCK_MINED)
|
||||
return "#664433"
|
||||
if(ACTION_ORE_MINED)
|
||||
return "#663366"
|
||||
if(ACTION_TRAPPER)
|
||||
return "#363366"
|
||||
if(ACTION_PARRIED)
|
||||
return "#591324"
|
||||
if(ACTION_PROJECTILE_BOOST)
|
||||
return "#80112c"
|
||||
if(ACTION_GIBTONITE_HIT)
|
||||
return "#201d40"
|
||||
if(ACTION_GIBTONITE_BOOM)
|
||||
return "#1e176e"
|
||||
if(ACTION_GIBTONITE_DEFUSED)
|
||||
return "#2b2573"
|
||||
if(ACTION_MARK_DETONATED)
|
||||
return "#ac870e"
|
||||
if(ACTION_GEYSER_MARKED)
|
||||
return "#364866"
|
||||
|
||||
/// A proc that lets a user, when their rank >= `hotswap_rank`, swap items in storage with what's in their hands, simply by clicking on the stored item with a held item
|
||||
/datum/component/style/proc/hotswap(mob/living/source, atom/target, obj/item/weapon, proximity_flag, click_parameters)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if((rank < hotswap_rank) || !isitem(target) || !(target in source.get_all_contents()))
|
||||
return
|
||||
|
||||
var/obj/item/item_target = target
|
||||
|
||||
if(!(item_target.item_flags & IN_STORAGE))
|
||||
return
|
||||
|
||||
var/datum/storage/atom_storage = item_target.loc.atom_storage
|
||||
|
||||
if(!atom_storage.can_insert(weapon, source, messages = FALSE))
|
||||
source.balloon_alert(source, "unable to hotswap!")
|
||||
return
|
||||
|
||||
atom_storage.attempt_insert(weapon, source, override = TRUE)
|
||||
INVOKE_ASYNC(source, TYPE_PROC_REF(/mob/living, put_in_hands), target)
|
||||
source.visible_message(span_notice("[source] quickly swaps [weapon] out with [target]!"), span_notice("You quickly swap [weapon] with [target]."))
|
||||
|
||||
|
||||
/datum/component/style/proc/on_parent_multitool(datum/source, mob/living/user, obj/item/tool, list/recipes)
|
||||
multitooled = !multitooled
|
||||
user.balloon_alert(user, "meter [multitooled ? "" : "un"]hacked")
|
||||
|
||||
|
||||
// Point givers
|
||||
/datum/component/style/proc/on_punch(mob/living/carbon/human/punching_person, atom/attacked_atom, proximity)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(!proximity || !punching_person.combat_mode || !isliving(attacked_atom))
|
||||
return
|
||||
|
||||
var/mob/living/disrespected = attacked_atom
|
||||
if(disrespected.stat || faction_check(punching_person.faction, disrespected.faction) || !(FACTION_MINING in disrespected.faction))
|
||||
return
|
||||
|
||||
add_action(ACTION_DISRESPECT, 60 * (ismegafauna(disrespected) ? 2 : 1))
|
||||
|
||||
/datum/component/style/proc/on_attack(mob/living/attacking_person, mob/living/attacked_mob)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(!istype(attacked_mob) || attacked_mob.stat)
|
||||
return
|
||||
|
||||
var/mob/living/attacked = attacked_mob
|
||||
var/mob/mob_parent = parent
|
||||
if(faction_check(attacking_person.faction, attacked.faction) || !(FACTION_MINING in attacked.faction) || (istype(mob_parent.get_active_held_item(), /obj/item/kinetic_crusher) && attacked.has_status_effect(/datum/status_effect/crusher_mark)))
|
||||
return
|
||||
|
||||
add_action(ACTION_MELEED, 50 * (ismegafauna(attacked) ? 1.5 : 1))
|
||||
|
||||
/datum/component/style/proc/on_mine(datum/source, turf/closed/mineral/rock, give_exp)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(istype(rock, /turf/closed/mineral/gibtonite))
|
||||
var/turf/closed/mineral/gibtonite/gib_rock = rock
|
||||
switch(gib_rock.stage)
|
||||
if(GIBTONITE_UNSTRUCK)
|
||||
add_action(ACTION_GIBTONITE_HIT, 40)
|
||||
return
|
||||
|
||||
if(GIBTONITE_ACTIVE)
|
||||
add_action(ACTION_GIBTONITE_BOOM, 50)
|
||||
return
|
||||
|
||||
if(GIBTONITE_DETONATE)
|
||||
add_action(ACTION_GIBTONITE_BOOM, 50)
|
||||
return
|
||||
|
||||
if(rock.mineralType)
|
||||
if(give_exp)
|
||||
add_action(ACTION_ORE_MINED, 40)
|
||||
rock.mineralAmt = ROUND_UP(rock.mineralAmt * (1 + ((rank * 0.1) - 0.3))) // You start out getting 20% less ore, but it goes up to 20% more at S-tier
|
||||
|
||||
else if(give_exp)
|
||||
add_action(ACTION_ROCK_MINED, 25)
|
||||
|
||||
/datum/component/style/proc/on_resonator_burst(datum/source, mob/creator, mob/living/hit_living)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(faction_check(creator.faction, hit_living.faction) || (hit_living.stat != CONSCIOUS) || !(FACTION_MINING in hit_living.faction))
|
||||
return
|
||||
|
||||
add_action(ACTION_TRAPPER, 70)
|
||||
|
||||
/datum/component/style/proc/on_projectile_parry(datum/source, obj/projectile/parried)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(parried.firer == parent)
|
||||
add_action(ACTION_PROJECTILE_BOOST, 160) // This is genuinely really impressive
|
||||
else
|
||||
add_action(ACTION_PARRIED, 110)
|
||||
|
||||
/datum/component/style/proc/on_gibtonite_defuse(datum/source, det_time)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
add_action(ACTION_GIBTONITE_DEFUSED, min(40, 20 * (10 - det_time))) // 40 to 180 points depending on speed
|
||||
|
||||
/datum/component/style/proc/on_crusher_detonate(datum/source, mob/living/target, obj/item/kinetic_crusher/crusher, backstabbed)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
var/has_brimdemon_trophy = locate(/obj/item/crusher_trophy/brimdemon_fang) in crusher.trophies
|
||||
|
||||
add_action(ACTION_MARK_DETONATED, round((backstabbed ? 60 : 30) * (ismegafauna(target) ? 1.5 : 1) * (has_brimdemon_trophy ? 1.25 : 1)))
|
||||
|
||||
|
||||
/datum/component/style/proc/on_geyser_discover(datum/source, obj/structure/geyser/geyser)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
add_action(ACTION_GEYSER_MARKED, 100)
|
||||
|
||||
|
||||
// Emote-based multipliers
|
||||
/datum/component/style/proc/on_flip()
|
||||
SIGNAL_HANDLER
|
||||
|
||||
point_multiplier = round(min(point_multiplier + 0.5, 3), 0.1)
|
||||
update_screen()
|
||||
|
||||
/datum/component/style/proc/on_spin()
|
||||
SIGNAL_HANDLER
|
||||
|
||||
point_multiplier = round(min(point_multiplier + 0.3, 3), 0.1)
|
||||
update_screen()
|
||||
|
||||
|
||||
// Negative effects
|
||||
/datum/component/style/proc/on_take_damage()
|
||||
SIGNAL_HANDLER
|
||||
|
||||
point_multiplier = round(max(point_multiplier - 0.3, 1), 0.1)
|
||||
change_points(-30, use_multiplier = FALSE)
|
||||
|
||||
/datum/component/style/proc/on_death(datum/source, mob/living/died, gibbed)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
var/mob/mob_parent = parent
|
||||
if(died == parent)
|
||||
change_points(-500, use_multiplier = FALSE)
|
||||
return
|
||||
else if(faction_check(mob_parent.faction, died.faction) || !(FACTION_MINING in died.faction) || (died.z != mob_parent.z) || !(died in view(mob_parent.client?.view, get_turf(mob_parent))))
|
||||
return
|
||||
if(ismegafauna(died))
|
||||
add_action(ACTION_MAJOR_KILL, 350)
|
||||
|
||||
else if(died.maxHealth >= 75) //at least legions
|
||||
add_action(ACTION_KILL, 125)
|
||||
|
||||
else if(died.maxHealth >= 30) //at least goliath children, dont count legion skulls
|
||||
add_action(ACTION_MINOR_KILL, 75)
|
||||
|
||||
#undef STYLE_DULL
|
||||
#undef STYLE_COOL
|
||||
#undef STYLE_BRUTAL
|
||||
#undef STYLE_ABSOLUTE
|
||||
#undef STYLE_SPACED
|
||||
|
||||
#undef ACTION_KILL
|
||||
#undef ACTION_MINOR_KILL
|
||||
#undef ACTION_MAJOR_KILL
|
||||
#undef ACTION_DISRESPECT
|
||||
#undef ACTION_MELEED
|
||||
#undef ACTION_ROCK_MINED
|
||||
#undef ACTION_ORE_MINED
|
||||
#undef ACTION_TRAPPER
|
||||
#undef ACTION_PARRIED
|
||||
#undef ACTION_PROJECTILE_BOOST
|
||||
#undef ACTION_GIBTONITE_HIT
|
||||
#undef ACTION_GIBTONITE_BOOM
|
||||
#undef ACTION_GIBTONITE_DEFUSED
|
||||
#undef ACTION_MARK_DETONATED
|
||||
#undef ACTION_GEYSER_MARKED
|
||||
@@ -0,0 +1,139 @@
|
||||
/obj/item/style_meter
|
||||
name = "style meter attachment"
|
||||
desc = "Attach this to a pair of glasses to install a style meter system in them. \
|
||||
You get style points from performing stylish acts and lose them for breaking your style. \
|
||||
The style affects the quality of your mining, with you being able to mine ore better during a good chain. \
|
||||
A responsive data HUD gives you the ability to reflect lavaland-based projectiles by punching them with an empty hand. \
|
||||
In addition, at high style, you are able to swap an item in your hand with one in your backpack by <b>hitting</b> one with another."
|
||||
icon_state = "style_meter"
|
||||
icon = 'icons/obj/clothing/glasses.dmi'
|
||||
/// The style meter component we give.
|
||||
var/datum/component/style/style_meter
|
||||
/// Mutable appearance added to the attached glasses
|
||||
var/mutable_appearance/meter_appearance
|
||||
/// If this is multitooled, which is passed onto the component on-creation, if one doesn't currently exist
|
||||
var/multitooled = FALSE
|
||||
|
||||
/obj/item/style_meter/Initialize(mapload)
|
||||
. = ..()
|
||||
meter_appearance = mutable_appearance(icon, icon_state)
|
||||
RegisterSignal(src, COMSIG_ATOM_TOOL_ACT(TOOL_MULTITOOL), PROC_REF(on_multitool))
|
||||
|
||||
/obj/item/style_meter/Destroy(force)
|
||||
if(istype(loc, /obj/item/clothing/glasses))
|
||||
clean_up(loc)
|
||||
return ..()
|
||||
|
||||
/obj/item/style_meter/examine(mob/user)
|
||||
. = ..()
|
||||
. += span_notice("You feel like a <b>multitool</b> could be used on this.")
|
||||
|
||||
/obj/item/style_meter/afterattack(atom/movable/attacked_atom, mob/user, proximity_flag, click_parameters)
|
||||
. = ..()
|
||||
if(!istype(attacked_atom, /obj/item/clothing/glasses))
|
||||
return
|
||||
|
||||
forceMove(attacked_atom)
|
||||
attacked_atom.add_overlay(meter_appearance)
|
||||
RegisterSignal(attacked_atom, COMSIG_ITEM_EQUIPPED, PROC_REF(check_wearing))
|
||||
RegisterSignal(attacked_atom, COMSIG_ITEM_DROPPED, PROC_REF(on_drop))
|
||||
RegisterSignal(attacked_atom, COMSIG_PARENT_EXAMINE, PROC_REF(on_examine))
|
||||
RegisterSignal(attacked_atom, COMSIG_CLICK_ALT, PROC_REF(on_altclick))
|
||||
RegisterSignal(attacked_atom, COMSIG_ATOM_TOOL_ACT(TOOL_MULTITOOL), PROC_REF(on_multitool))
|
||||
balloon_alert(user, "style meter attached")
|
||||
playsound(src, 'sound/machines/click.ogg', 30, TRUE)
|
||||
if(!iscarbon(attacked_atom.loc))
|
||||
return
|
||||
|
||||
var/mob/living/carbon/carbon_wearer = attacked_atom.loc
|
||||
if(carbon_wearer.glasses != attacked_atom)
|
||||
return
|
||||
|
||||
style_meter = carbon_wearer.AddComponent(/datum/component/style, multitooled)
|
||||
|
||||
/obj/item/style_meter/Moved(atom/old_loc, Dir, momentum_change)
|
||||
. = ..()
|
||||
if(!istype(old_loc, /obj/item/clothing/glasses))
|
||||
return
|
||||
clean_up(old_loc)
|
||||
|
||||
|
||||
/// Check if the glasses that this meter is linked with are being worn
|
||||
/obj/item/style_meter/proc/check_wearing(datum/source, mob/equipper, slot)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(!(slot & ITEM_SLOT_EYES))
|
||||
if(style_meter)
|
||||
QDEL_NULL(style_meter)
|
||||
return
|
||||
|
||||
style_meter = equipper.AddComponent(/datum/component/style, multitooled)
|
||||
|
||||
|
||||
/// Signal proc for when the meter-holding glasses are dropped/unequipped
|
||||
/obj/item/style_meter/proc/on_drop(datum/source, mob/user)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(!style_meter)
|
||||
return
|
||||
|
||||
QDEL_NULL(style_meter)
|
||||
|
||||
|
||||
/// Signal proc for on-examine
|
||||
/obj/item/style_meter/proc/on_examine(datum/source, mob/user, list/examine_list)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
examine_list += span_notice("You feel like a <b>multitool</b> could be used on this.")
|
||||
examine_list += span_notice("<b>Alt-click</b> to remove the style meter.")
|
||||
|
||||
|
||||
/// Signal proc to remove from glasses
|
||||
/obj/item/style_meter/proc/on_altclick(datum/source, mob/user)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(istype(loc, /obj/item/clothing/glasses))
|
||||
clean_up()
|
||||
forceMove(get_turf(src))
|
||||
|
||||
return COMPONENT_CANCEL_CLICK_ALT
|
||||
|
||||
|
||||
/// Signal proc for when the glasses or the meter is multitooled
|
||||
/obj/item/style_meter/proc/on_multitool(datum/source, mob/living/user, obj/item/tool, list/recipes)
|
||||
multitooled = !multitooled
|
||||
if(style_meter)
|
||||
SEND_SIGNAL(style_meter, COMSIG_ATOM_TOOL_ACT(TOOL_MULTITOOL), user, tool, recipes)
|
||||
else
|
||||
balloon_alert(user, "meter [multitooled ? "" : "un"]hacked")
|
||||
|
||||
|
||||
/// Unregister signals and just generally clean up ourselves after being removed from glasses
|
||||
/obj/item/style_meter/proc/clean_up(atom/movable/old_location)
|
||||
old_location.cut_overlay(meter_appearance)
|
||||
UnregisterSignal(old_location, COMSIG_ITEM_EQUIPPED)
|
||||
UnregisterSignal(old_location, COMSIG_ITEM_DROPPED)
|
||||
UnregisterSignal(old_location, COMSIG_PARENT_EXAMINE)
|
||||
UnregisterSignal(old_location, COMSIG_ATOM_TOOL_ACT(TOOL_MULTITOOL))
|
||||
if(!style_meter)
|
||||
return
|
||||
QDEL_NULL(style_meter)
|
||||
|
||||
|
||||
/atom/movable/screen/style_meter_background
|
||||
icon_state = "style_meter_background"
|
||||
icon = 'icons/hud/style_meter.dmi'
|
||||
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
screen_loc = "WEST,CENTER:16"
|
||||
maptext_height = 120
|
||||
maptext_width = 105
|
||||
maptext_x = 5
|
||||
maptext_y = 100
|
||||
maptext = ""
|
||||
layer = SCREENTIP_LAYER
|
||||
|
||||
/atom/movable/screen/style_meter
|
||||
icon_state = "style_meter"
|
||||
icon = 'icons/hud/style_meter.dmi'
|
||||
layer = SCREENTIP_LAYER
|
||||
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
@@ -97,3 +97,7 @@
|
||||
/datum/orderable_item/mining/hiking_boots
|
||||
item_path = /obj/item/clothing/shoes/winterboots/ice_boots
|
||||
cost_per_order = 2500
|
||||
|
||||
/datum/orderable_item/mining/style_meter
|
||||
item_path = /obj/item/style_meter
|
||||
cost_per_order = 1500
|
||||
|
||||
@@ -67,6 +67,7 @@
|
||||
return
|
||||
|
||||
to_chat(user, span_notice("You discovered the geyser and mark it on the GPS system!"))
|
||||
SEND_SIGNAL(user, COMSIG_LIVING_DISCOVERED_GEYSER, src)
|
||||
if(discovery_message)
|
||||
to_chat(user, discovery_message)
|
||||
|
||||
|
||||
@@ -134,7 +134,9 @@
|
||||
if(user.Adjacent(src))
|
||||
attack_hand(user)
|
||||
|
||||
/turf/closed/mineral/proc/gets_drilled(user, give_exp = FALSE)
|
||||
/turf/closed/mineral/proc/gets_drilled(mob/user, give_exp = FALSE)
|
||||
if(istype(user))
|
||||
SEND_SIGNAL(user, COMSIG_MOB_MINED, src, give_exp)
|
||||
if (mineralType && (mineralAmt > 0))
|
||||
new mineralType(src, mineralAmt)
|
||||
SSblackbox.record_feedback("tally", "ore_mined", mineralAmt, mineralType)
|
||||
@@ -674,7 +676,7 @@
|
||||
var/previous_stage = stage
|
||||
if(istype(attacking_item, /obj/item/mining_scanner) || istype(attacking_item, /obj/item/t_scanner/adv_mining_scanner) && stage == GIBTONITE_ACTIVE)
|
||||
user.visible_message(span_notice("[user] holds [attacking_item] to [src]..."), span_notice("You use [attacking_item] to locate where to cut off the chain reaction and attempt to stop it..."))
|
||||
defuse()
|
||||
defuse(user)
|
||||
..()
|
||||
if(istype(attacking_item, /obj/item/clothing/gloves/gauntlets) && previous_stage == GIBTONITE_UNSTRUCK && stage == GIBTONITE_ACTIVE && istype(user))
|
||||
user.Immobilize(0.5 SECONDS)
|
||||
@@ -713,7 +715,7 @@
|
||||
stage = GIBTONITE_DETONATE
|
||||
explosion(bombturf, devastation_range = 1, heavy_impact_range = 3, light_impact_range = 5, adminlog = notify_admins, explosion_cause = src)
|
||||
|
||||
/turf/closed/mineral/gibtonite/proc/defuse()
|
||||
/turf/closed/mineral/gibtonite/proc/defuse(mob/living/defuser)
|
||||
if(stage == GIBTONITE_ACTIVE)
|
||||
cut_overlay(activated_overlay)
|
||||
activated_overlay.icon_state = "rock_Gibtonite_inactive"
|
||||
@@ -723,8 +725,13 @@
|
||||
if(det_time < 0)
|
||||
det_time = 0
|
||||
visible_message(span_notice("The chain reaction stopped! The gibtonite had [det_time] reactions left till the explosion!"))
|
||||
if(defuser)
|
||||
SEND_SIGNAL(defuser, COMSIG_LIVING_DEFUSED_GIBTONITE, det_time)
|
||||
|
||||
/turf/closed/mineral/gibtonite/gets_drilled(mob/user, give_exp = FALSE, triggered_by_explosion = FALSE)
|
||||
if(istype(user))
|
||||
SEND_SIGNAL(user, COMSIG_MOB_MINED, src, give_exp)
|
||||
|
||||
if(stage == GIBTONITE_UNSTRUCK && mineralAmt >= 1) //Gibtonite deposit is activated
|
||||
playsound(src,'sound/effects/hit_on_shattered_glass.ogg',50,TRUE)
|
||||
explosive_reaction(user)
|
||||
@@ -794,6 +801,9 @@
|
||||
|
||||
|
||||
/turf/closed/mineral/strong/gets_drilled(mob/user, give_exp = FALSE)
|
||||
if(istype(user))
|
||||
SEND_SIGNAL(user, COMSIG_MOB_MINED, src, give_exp)
|
||||
|
||||
if(!ishuman(user))
|
||||
return // see attackby
|
||||
var/mob/living/carbon/human/H = user
|
||||
|
||||
@@ -919,7 +919,7 @@ Striking a noncultist, however, will tear their flesh."}
|
||||
for(var/turf/T in get_line(targets_from,temp_target))
|
||||
if (locate(/obj/effect/blessing, T))
|
||||
temp_target = T
|
||||
playsound(T, 'sound/machines/clockcult/ark_damage.ogg', 50, TRUE)
|
||||
playsound(T, 'sound/effects/parry.ogg', 50, TRUE)
|
||||
new /obj/effect/temp_visual/at_shield(T, T)
|
||||
break
|
||||
T.narsie_act(TRUE, TRUE)
|
||||
|
||||
@@ -101,17 +101,21 @@
|
||||
if(!QDELETED(C))
|
||||
C.total_damage += target_health - L.health //we did some damage, but let's not assume how much we did
|
||||
new /obj/effect/temp_visual/kinetic_blast(get_turf(L))
|
||||
var/backstabbed = FALSE
|
||||
var/combined_damage = detonation_damage
|
||||
var/backstab_dir = get_dir(user, L)
|
||||
var/def_check = L.getarmor(type = BOMB)
|
||||
if((user.dir & backstab_dir) && (L.dir & backstab_dir))
|
||||
if(!QDELETED(C))
|
||||
C.total_damage += detonation_damage + backstab_bonus //cheat a little and add the total before killing it, so certain mobs don't have much lower chances of giving an item
|
||||
L.apply_damage(detonation_damage + backstab_bonus, BRUTE, blocked = def_check)
|
||||
backstabbed = TRUE
|
||||
combined_damage += backstab_bonus
|
||||
playsound(user, 'sound/weapons/kenetic_accel.ogg', 100, TRUE) //Seriously who spelled it wrong
|
||||
else
|
||||
if(!QDELETED(C))
|
||||
C.total_damage += detonation_damage
|
||||
L.apply_damage(detonation_damage, BRUTE, blocked = def_check)
|
||||
|
||||
if(!QDELETED(C))
|
||||
C.total_damage += combined_damage
|
||||
|
||||
|
||||
SEND_SIGNAL(user, COMSIG_LIVING_CRUSHER_DETONATE, L, src, backstabbed)
|
||||
L.apply_damage(combined_damage, BRUTE, blocked = def_check)
|
||||
|
||||
/obj/item/kinetic_crusher/attack_secondary(atom/target, mob/living/user, clickparams)
|
||||
return SECONDARY_ATTACK_CONTINUE_CHAIN
|
||||
|
||||
@@ -60,7 +60,7 @@
|
||||
/// the modifier to resonance_damage; affected by the quick_burst_mod from the resonator
|
||||
var/damage_multiplier = 1
|
||||
/// the parent creator (user) of this field
|
||||
var/creator
|
||||
var/mob/creator
|
||||
/// the parent resonator of this field
|
||||
var/obj/item/resonator/parent_resonator
|
||||
/// whether the field is rupturing currently or not (to prevent recursion)
|
||||
@@ -127,6 +127,7 @@
|
||||
for(var/mob/living/attacked_living in src_turf)
|
||||
if(creator)
|
||||
log_combat(creator, attacked_living, "used a resonator field on", "resonator")
|
||||
SEND_SIGNAL(creator, COMSIG_LIVING_RESONATOR_BURST, creator, attacked_living)
|
||||
to_chat(attacked_living, span_userdanger("[src] ruptured with you in it!"))
|
||||
attacked_living.apply_damage(resonance_damage, BRUTE)
|
||||
attacked_living.add_movespeed_modifier(/datum/movespeed_modifier/resonance)
|
||||
|
||||
@@ -203,6 +203,8 @@
|
||||
|
||||
/// If true directly targeted turfs can be hit
|
||||
var/can_hit_turfs = FALSE
|
||||
/// If this projectile has been parried before
|
||||
var/parried = FALSE
|
||||
|
||||
/obj/projectile/Initialize(mapload)
|
||||
. = ..()
|
||||
@@ -210,6 +212,7 @@
|
||||
if(embedding)
|
||||
updateEmbedding()
|
||||
AddElement(/datum/element/connect_loc, projectile_connections)
|
||||
RegisterSignal(src, COMSIG_MOVABLE_MOVED, PROC_REF(on_enter))
|
||||
|
||||
/obj/projectile/proc/Range()
|
||||
range--
|
||||
@@ -381,6 +384,41 @@
|
||||
return
|
||||
Impact(A)
|
||||
|
||||
/// Signal proc for when a projectile enters a turf.
|
||||
/obj/projectile/proc/on_enter(datum/source, atom/old_loc, dir, forced, list/old_locs)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
UnregisterSignal(old_loc, COMSIG_ATOM_ATTACK_HAND)
|
||||
|
||||
if(isturf(loc))
|
||||
RegisterSignal(loc, COMSIG_ATOM_ATTACK_HAND, PROC_REF(attempt_parry))
|
||||
|
||||
/// Signal proc for when a mob attempts to attack this projectile or the turf it's on with an empty hand.
|
||||
/obj/projectile/proc/attempt_parry(datum/source, mob/user, list/modifiers)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(parried)
|
||||
return FALSE
|
||||
|
||||
if(SEND_SIGNAL(user, COMSIG_LIVING_PROJECTILE_PARRYING, src) & ALLOW_PARRY)
|
||||
on_parry(user, modifiers)
|
||||
return TRUE
|
||||
|
||||
return FALSE
|
||||
|
||||
|
||||
/// Called when a mob with PARRY_TRAIT clicks on this projectile or the tile its on, reflecting the projectile within 17 degrees and increasing the bullet's stats.
|
||||
/obj/projectile/proc/on_parry(mob/user, list/modifiers)
|
||||
if(SEND_SIGNAL(user, COMSIG_LIVING_PROJECTILE_PARRIED, src) & INTERCEPT_PARRY_EFFECTS)
|
||||
return
|
||||
|
||||
parried = TRUE
|
||||
set_angle(dir2angle(user.dir) + rand(-3, 3))
|
||||
speed *= 0.8 // Go 20% faster when parried
|
||||
damage *= 1.15 // And do 15% more damage
|
||||
add_atom_colour(COLOR_RED_LIGHT, TEMPORARY_COLOUR_PRIORITY)
|
||||
|
||||
|
||||
/**
|
||||
* Called when the projectile hits something
|
||||
* This can either be from it bumping something,
|
||||
@@ -745,6 +783,7 @@
|
||||
fired = TRUE
|
||||
play_fov_effect(starting, 6, "gunfire", dir = NORTH, angle = Angle)
|
||||
SEND_SIGNAL(src, COMSIG_PROJECTILE_FIRE)
|
||||
RegisterSignal(src, COMSIG_ATOM_ATTACK_HAND, PROC_REF(attempt_parry))
|
||||
if(hitscan)
|
||||
process_hitscan()
|
||||
if(!(datum_flags & DF_ISPROCESSING))
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 794 B |
Binary file not shown.
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1034,6 +1034,7 @@
|
||||
#include "code\datums\components\orbiter.dm"
|
||||
#include "code\datums\components\overlay_lighting.dm"
|
||||
#include "code\datums\components\palette.dm"
|
||||
#include "code\datums\components\parry.dm"
|
||||
#include "code\datums\components\payment.dm"
|
||||
#include "code\datums\components\pellet_cloud.dm"
|
||||
#include "code\datums\components\phylactery.dm"
|
||||
@@ -1151,6 +1152,8 @@
|
||||
#include "code\datums\components\riding\riding.dm"
|
||||
#include "code\datums\components\riding\riding_mob.dm"
|
||||
#include "code\datums\components\riding\riding_vehicle.dm"
|
||||
#include "code\datums\components\style\style.dm"
|
||||
#include "code\datums\components\style\style_meter.dm"
|
||||
#include "code\datums\diseases\_disease.dm"
|
||||
#include "code\datums\diseases\_MobProcs.dm"
|
||||
#include "code\datums\diseases\adrenal_crisis.dm"
|
||||
|
||||
Reference in New Issue
Block a user