diff --git a/code/__DEFINES/mobs.dm b/code/__DEFINES/mobs.dm index 284b0e4d745..608fcfcce20 100644 --- a/code/__DEFINES/mobs.dm +++ b/code/__DEFINES/mobs.dm @@ -187,6 +187,7 @@ #define isswarmer(A) (istype((A), /mob/living/simple_animal/hostile/swarmer)) #define isguardian(A) (istype((A), /mob/living/simple_animal/hostile/guardian)) #define isnymph(A) (istype((A), /mob/living/simple_animal/diona)) +#define ishostile(A) (istype(A, /mob/living/simple_animal/hostile)) #define issilicon(A) (istype((A), /mob/living/silicon)) #define isAI(A) (istype((A), /mob/living/silicon/ai)) diff --git a/code/__DEFINES/status_effects.dm b/code/__DEFINES/status_effects.dm index e5d5bb723c1..f451a34a8b7 100644 --- a/code/__DEFINES/status_effects.dm +++ b/code/__DEFINES/status_effects.dm @@ -26,7 +26,7 @@ //#define STATUS_EFFECT_WISH_GRANTERS_GIFT /datum/status_effect/wish_granters_gift //If you're currently resurrecting with the Wish Granter -//#define STATUS_EFFECT_BLOODDRUNK /datum/status_effect/blooddrunk //Stun immunity and greatly reduced damage taken +#define STATUS_EFFECT_BLOODDRUNK /datum/status_effect/blooddrunk //Stun immunity and greatly reduced damage taken ///////////// // DEBUFFS // @@ -52,7 +52,7 @@ #define STATUS_EFFECT_SUMMONEDGHOST /datum/status_effect/cultghost //is a cult ghost and can't use manifest runes -//#define STATUS_EFFECT_CRUSHERMARK /datum/status_effect/crusher_mark //if struck with a proto-kinetic crusher, takes a ton of damage +#define STATUS_EFFECT_CRUSHERMARK /datum/status_effect/crusher_mark //if struck with a proto-kinetic crusher, takes a ton of damage #define STATUS_EFFECT_SAWBLEED /datum/status_effect/saw_bleed //if the bleed builds up enough, takes a ton of damage @@ -74,6 +74,6 @@ //#define STATUS_EFFECT_SIGILMARK /datum/status_effect/sigil_mark -//#define STATUS_EFFECT_CRUSHERDAMAGETRACKING /datum/status_effect/crusher_damage //tracks total kinetic crusher damage on a target +#define STATUS_EFFECT_CRUSHERDAMAGETRACKING /datum/status_effect/crusher_damage //tracks total kinetic crusher damage on a target -//#define STATUS_EFFECT_SYPHONMARK /datum/status_effect/syphon_mark //tracks kills for the KA death syphon module \ No newline at end of file +#define STATUS_EFFECT_SYPHONMARK /datum/status_effect/syphon_mark //tracks kills for the KA death syphon module \ No newline at end of file diff --git a/code/datums/components/paintable.dm b/code/datums/components/paintable.dm new file mode 100644 index 00000000000..ef9a2923cc6 --- /dev/null +++ b/code/datums/components/paintable.dm @@ -0,0 +1,31 @@ +/datum/component/spraycan_paintable + var/current_paint + +/datum/component/spraycan_paintable/Initialize() + RegisterSignal(parent, COMSIG_PARENT_ATTACKBY, .proc/Repaint) + +/datum/component/spraycan_paintable/Destroy() + RemoveCurrentCoat() + return ..() + +/datum/component/spraycan_paintable/proc/RemoveCurrentCoat() + var/atom/A = parent + A.remove_atom_colour(FIXED_COLOUR_PRIORITY, current_paint) + +/datum/component/spraycan_paintable/proc/Repaint(datum/source, obj/item/toy/crayon/spraycan/spraycan, mob/living/user) + if(!istype(spraycan) || user.a_intent == INTENT_HARM) + return + . = COMPONENT_NO_AFTERATTACK + if(spraycan.capped) + to_chat(user, "Take the cap off first!") + return + if(spraycan.uses < 2) + to_chat(user, "There is not enough paint in the can!") + return + RemoveCurrentCoat() + var/colour = spraycan.colour + current_paint = colour + var/atom/A = parent + A.add_atom_colour(colour, FIXED_COLOUR_PRIORITY) + playsound(spraycan, 'sound/effects/spray.ogg', 5, 1, 5) + to_chat(user, "You spray [spraycan] on [A], painting it.") diff --git a/code/datums/status_effects/buffs.dm b/code/datums/status_effects/buffs.dm index 387cc70f992..fb336192b38 100644 --- a/code/datums/status_effects/buffs.dm +++ b/code/datums/status_effects/buffs.dm @@ -40,6 +40,132 @@ playsound(owner, 'sound/weapons/bite.ogg', 50, 1) owner.adjustBruteLoss(3) +/datum/status_effect/blooddrunk + id = "blooddrunk" + duration = 10 + tick_interval = 0 + alert_type = /obj/screen/alert/status_effect/blooddrunk + var/last_health = 0 + var/last_bruteloss = 0 + var/last_fireloss = 0 + var/last_toxloss = 0 + var/last_oxyloss = 0 + var/last_cloneloss = 0 + var/last_staminaloss = 0 + +/obj/screen/alert/status_effect/blooddrunk + name = "Blood-Drunk" + desc = "You are drunk on blood! Your pulse thunders in your ears! Nothing can harm you!" //not true, and the item description mentions its actual effect + icon_state = "blooddrunk" + +/datum/status_effect/blooddrunk/on_apply() + . = ..() + if(.) + owner.maxHealth *= 10 + owner.bruteloss *= 10 + owner.fireloss *= 10 + if(ishuman(owner)) + var/mob/living/carbon/human/H = owner + for(var/X in H.bodyparts) + var/obj/item/organ/external/BP = X + BP.max_damage *= 10 + BP.min_broken_damage *= 10 + BP.brute_dam *= 10 + BP.burn_dam *= 10 + owner.toxloss *= 10 + owner.oxyloss *= 10 + owner.cloneloss *= 10 + owner.staminaloss *= 10 + owner.updatehealth() + last_health = owner.health + last_bruteloss = owner.getBruteLoss() + last_fireloss = owner.getFireLoss() + last_toxloss = owner.getToxLoss() + last_oxyloss = owner.getOxyLoss() + last_cloneloss = owner.getCloneLoss() + last_staminaloss = owner.getStaminaLoss() + add_attack_logs(owner, owner, "gained blood-drunk stun immunity") + var/status = CANSTUN | CANWEAKEN | CANPARALYSE | IGNORESLOWDOWN + owner.status_flags &= ~status + owner.playsound_local(get_turf(owner), 'sound/effects/singlebeat.ogg', 40, 1) + +/datum/status_effect/blooddrunk/tick() //multiply the effect of healing by 10 + if(owner.health > last_health) + var/needs_health_update = FALSE + var/new_bruteloss = owner.getBruteLoss() + if(new_bruteloss < last_bruteloss) + var/heal_amount = (new_bruteloss - last_bruteloss) * 10 + owner.adjustBruteLoss(heal_amount, updating_health = FALSE) + new_bruteloss = owner.getBruteLoss() + needs_health_update = TRUE + last_bruteloss = new_bruteloss + + var/new_fireloss = owner.getFireLoss() + if(new_fireloss < last_fireloss) + var/heal_amount = (new_fireloss - last_fireloss) * 10 + owner.adjustFireLoss(heal_amount, updating_health = FALSE) + new_fireloss = owner.getFireLoss() + needs_health_update = TRUE + last_fireloss = new_fireloss + + var/new_toxloss = owner.getToxLoss() + if(new_toxloss < last_toxloss) + var/heal_amount = (new_toxloss - last_toxloss) * 10 + owner.adjustToxLoss(heal_amount, updating_health = FALSE) + new_toxloss = owner.getToxLoss() + needs_health_update = TRUE + last_toxloss = new_toxloss + + var/new_oxyloss = owner.getOxyLoss() + if(new_oxyloss < last_oxyloss) + var/heal_amount = (new_oxyloss - last_oxyloss) * 10 + owner.adjustOxyLoss(heal_amount, updating_health = FALSE) + new_oxyloss = owner.getOxyLoss() + needs_health_update = TRUE + last_oxyloss = new_oxyloss + + var/new_cloneloss = owner.getCloneLoss() + if(new_cloneloss < last_cloneloss) + var/heal_amount = (new_cloneloss - last_cloneloss) * 10 + owner.adjustCloneLoss(heal_amount, updating_health = FALSE) + new_cloneloss = owner.getCloneLoss() + needs_health_update = TRUE + last_cloneloss = new_cloneloss + + var/new_staminaloss = owner.getStaminaLoss() + if(new_staminaloss < last_staminaloss) + var/heal_amount = (new_staminaloss - last_staminaloss) * 10 + owner.adjustStaminaLoss(heal_amount, updating_health = FALSE) + new_staminaloss = owner.getStaminaLoss() + needs_health_update = TRUE + last_staminaloss = new_staminaloss + + if(needs_health_update) + owner.updatehealth() + owner.playsound_local(get_turf(owner), 'sound/effects/singlebeat.ogg', 40, 1) + last_health = owner.health + +/datum/status_effect/blooddrunk/on_remove() + tick() + owner.maxHealth *= 0.1 + owner.bruteloss *= 0.1 + owner.fireloss *= 0.1 + if(ishuman(owner)) + var/mob/living/carbon/human/H = owner + for(var/X in H.bodyparts) + var/obj/item/organ/external/BP = X + BP.brute_dam *= 0.1 + BP.burn_dam *= 0.1 + BP.max_damage /= 10 + BP.min_broken_damage /= 10 + owner.toxloss *= 0.1 + owner.oxyloss *= 0.1 + owner.cloneloss *= 0.1 + owner.staminaloss *= 0.1 + owner.updatehealth() + add_attack_logs(owner, owner, "lost blood-drunk stun immunity") + owner.status_flags |= CANSTUN | CANWEAKEN | CANPARALYSE | IGNORESLOWDOWN + /datum/status_effect/exercised id = "Exercised" duration = 1200 diff --git a/code/datums/status_effects/debuffs.dm b/code/datums/status_effects/debuffs.dm index 6e809b32606..3ce68f85250 100644 --- a/code/datums/status_effects/debuffs.dm +++ b/code/datums/status_effects/debuffs.dm @@ -9,6 +9,39 @@ if(owner.reagents) owner.reagents.del_reagent("holywater") //can't be deconverted +/datum/status_effect/crusher_mark + id = "crusher_mark" + duration = 300 //if you leave for 30 seconds you lose the mark, deal with it + status_type = STATUS_EFFECT_REPLACE + alert_type = null + var/mutable_appearance/marked_underlay + var/obj/item/twohanded/kinetic_crusher/hammer_synced + +/datum/status_effect/crusher_mark/on_creation(mob/living/new_owner, obj/item/twohanded/kinetic_crusher/new_hammer_synced) + . = ..() + if(.) + hammer_synced = new_hammer_synced + +/datum/status_effect/crusher_mark/on_apply() + if(owner.mob_size >= MOB_SIZE_LARGE) + marked_underlay = mutable_appearance('icons/effects/effects.dmi', "shield2") + marked_underlay.pixel_x = -owner.pixel_x + marked_underlay.pixel_y = -owner.pixel_y + owner.underlays += marked_underlay + return TRUE + return FALSE + +/datum/status_effect/crusher_mark/Destroy() + hammer_synced = null + if(owner) + owner.underlays -= marked_underlay + QDEL_NULL(marked_underlay) + return ..() + +/datum/status_effect/crusher_mark/be_replaced() + owner.underlays -= marked_underlay //if this is being called, we should have an owner at this point. + ..() + /datum/status_effect/saw_bleed id = "saw_bleed" duration = -1 //removed under specific conditions diff --git a/code/datums/status_effects/neutral.dm b/code/datums/status_effects/neutral.dm index eaa14c4d0b0..8f5023e4a74 100644 --- a/code/datums/status_effects/neutral.dm +++ b/code/datums/status_effects/neutral.dm @@ -1,5 +1,43 @@ //entirely neutral or internal status effects go here +/datum/status_effect/crusher_damage //tracks the damage dealt to this mob by kinetic crushers + id = "crusher_damage" + duration = -1 + status_type = STATUS_EFFECT_UNIQUE + alert_type = null + var/total_damage = 0 + +/datum/status_effect/syphon_mark + id = "syphon_mark" + duration = 50 + status_type = STATUS_EFFECT_MULTIPLE + alert_type = null + on_remove_on_mob_delete = TRUE + var/obj/item/borg/upgrade/modkit/bounty/reward_target + +/datum/status_effect/syphon_mark/on_creation(mob/living/new_owner, obj/item/borg/upgrade/modkit/bounty/new_reward_target) + . = ..() + if(.) + reward_target = new_reward_target + +/datum/status_effect/syphon_mark/on_apply() + if(owner.stat == DEAD) + return FALSE + return ..() + +/datum/status_effect/syphon_mark/proc/get_kill() + if(!QDELETED(reward_target)) + reward_target.get_kill(owner) + +/datum/status_effect/syphon_mark/tick() + if(owner.stat == DEAD) + get_kill() + qdel(src) + +/datum/status_effect/syphon_mark/on_remove() + get_kill() + . = ..() + /datum/status_effect/high_five id = "high_five" duration = 40 diff --git a/code/game/objects/effects/temporary_visuals/miscellaneous.dm b/code/game/objects/effects/temporary_visuals/miscellaneous.dm index d349d0b1cd7..7f1683ba415 100644 --- a/code/game/objects/effects/temporary_visuals/miscellaneous.dm +++ b/code/game/objects/effects/temporary_visuals/miscellaneous.dm @@ -140,6 +140,20 @@ ..() animate(src, alpha = 0, time = duration) +/obj/effect/temp_visual/fire + icon = 'icons/goonstation/effects/fire.dmi' + icon_state = "3" + light_range = LIGHT_RANGE_FIRE + light_color = LIGHT_COLOR_FIRE + duration = 10 + layer = MASSIVE_OBJ_LAYER + alpha = 250 + blend_mode = BLEND_ADD + +/obj/effect/temp_visual/fire/New(loc) + color = heat2color(FIRE_MINIMUM_TEMPERATURE_TO_EXIST) + ..() + /obj/effect/temp_visual/revenant name = "spooky lights" icon_state = "purplesparkles" diff --git a/code/modules/mining/equipment/kinetic_crusher.dm b/code/modules/mining/equipment/kinetic_crusher.dm new file mode 100644 index 00000000000..47b3fb01501 --- /dev/null +++ b/code/modules/mining/equipment/kinetic_crusher.dm @@ -0,0 +1,439 @@ +/*********************Mining Hammer****************/ +/obj/item/twohanded/kinetic_crusher + icon = 'icons/obj/mining.dmi' + icon_state = "crusher" + item_state = "crusher0" + name = "proto-kinetic crusher" + desc = "An early design of the proto-kinetic accelerator, it is little more than a combination of various mining tools cobbled together, forming a high-tech club. \ + While it is an effective mining tool, it did little to aid any but the most skilled and/or suicidal miners against local fauna." + force = 0 //You can't hit stuff unless wielded + w_class = WEIGHT_CLASS_BULKY + slot_flags = SLOT_BACK + force_unwielded = 0 + force_wielded = 20 + throwforce = 5 + throw_speed = 4 + armour_penetration = 10 + materials = list(MAT_METAL = 1150, MAT_GLASS = 2075) + hitsound = 'sound/weapons/bladeslice.ogg' + attack_verb = list("smashed", "crushed", "cleaved", "chopped", "pulped") + sharp = TRUE + actions_types = list(/datum/action/item_action/toggle_light) + var/list/trophies = list() + var/charged = TRUE + var/charge_time = 15 + var/detonation_damage = 50 + var/backstab_bonus = 30 + var/light_on = FALSE + var/brightness_on = 5 + +/obj/item/twohanded/kinetic_crusher/Destroy() + QDEL_LIST(trophies) + return ..() + +/obj/item/twohanded/kinetic_crusher/examine(mob/living/user) + ..() + to_chat(user, "Mark a large creature with the destabilizing force, then hit them in melee to do [force + detonation_damage] damage.") + to_chat(user, "Does [force + detonation_damage + backstab_bonus] damage if the target is backstabbed, instead of [force + detonation_damage].") + for(var/t in trophies) + var/obj/item/crusher_trophy/T = t + to_chat(user, "It has \a [T] attached, which causes [T.effect_desc()].") + +/obj/item/twohanded/kinetic_crusher/attackby(obj/item/I, mob/living/user) + if(iscrowbar(I)) + if(LAZYLEN(trophies)) + to_chat(user, "You remove [src]'s trophies.") + playsound(loc, I.usesound, 100, 1) + for(var/t in trophies) + var/obj/item/crusher_trophy/T = t + T.remove_from(src, user) + else + to_chat(user, "There are no trophies on [src].") + else if(istype(I, /obj/item/crusher_trophy)) + var/obj/item/crusher_trophy/T = I + T.add_to(src, user) + else + return ..() + +/obj/item/twohanded/kinetic_crusher/attack(mob/living/target, mob/living/carbon/user) + if(!wielded) + to_chat(user, "[src] is too heavy to use with one hand. You fumble and drop everything.") + user.drop_r_hand() + user.drop_l_hand() + return + var/datum/status_effect/crusher_damage/C = target.has_status_effect(STATUS_EFFECT_CRUSHERDAMAGETRACKING) + var/target_health = target.health + ..() + for(var/t in trophies) + if(!QDELETED(target)) + var/obj/item/crusher_trophy/T = t + T.on_melee_hit(target, user) + if(!QDELETED(C) && !QDELETED(target)) + C.total_damage += target_health - target.health //we did some damage, but let's not assume how much we did + +/obj/item/twohanded/kinetic_crusher/afterattack(atom/target, mob/living/user, proximity_flag, clickparams) + . = ..() + if(!wielded) + return + if(!proximity_flag && charged)//Mark a target, or mine a tile. + var/turf/proj_turf = user.loc + if(!isturf(proj_turf)) + return + var/obj/item/projectile/destabilizer/D = new /obj/item/projectile/destabilizer(proj_turf) + for(var/t in trophies) + var/obj/item/crusher_trophy/T = t + T.on_projectile_fire(D, user) + D.preparePixelProjectile(target, get_turf(target), user, clickparams) + D.firer = user + D.hammer_synced = src + playsound(user, 'sound/weapons/plasma_cutter.ogg', 100, 1) + D.fire() + charged = FALSE + update_icon() + addtimer(CALLBACK(src, .proc/Recharge), charge_time) + return + if(proximity_flag && isliving(target)) + var/mob/living/L = target + var/datum/status_effect/crusher_mark/CM = L.has_status_effect(STATUS_EFFECT_CRUSHERMARK) + if(!CM || CM.hammer_synced != src || !L.remove_status_effect(STATUS_EFFECT_CRUSHERMARK)) + return + var/datum/status_effect/crusher_damage/C = L.has_status_effect(STATUS_EFFECT_CRUSHERDAMAGETRACKING) + var/target_health = L.health + for(var/t in trophies) + var/obj/item/crusher_trophy/T = t + T.on_mark_detonation(target, user) + if(!QDELETED(L)) + 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/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) + playsound(user, 'sound/weapons/kenetic_accel.ogg', 100, 1) //Seriously who spelled it wrong + else + if(!QDELETED(C)) + C.total_damage += detonation_damage + L.apply_damage(detonation_damage, BRUTE, blocked = def_check) + +/obj/item/twohanded/kinetic_crusher/proc/Recharge() + if(!charged) + charged = TRUE + update_icon() + playsound(src.loc, 'sound/weapons/kenetic_reload.ogg', 60, 1) + +/obj/item/twohanded/kinetic_crusher/ui_action_click(mob/user, actiontype) + light_on = !light_on + playsound(user, 'sound/weapons/empty.ogg', 100, TRUE) + update_brightness(user) + update_icon() + +/obj/item/twohanded/kinetic_crusher/proc/update_brightness(mob/user = null) + if(light_on) + set_light(brightness_on) + else + set_light(0) + +/obj/item/twohanded/kinetic_crusher/update_icon() + ..() + cut_overlays() + if(!charged) + add_overlay("[icon_state]_uncharged") + if(light_on) + add_overlay("[icon_state]_lit") + spawn(1) + for(var/X in actions) + var/datum/action/A = X + A.UpdateButtonIcon() + item_state = "crusher[wielded]" + +//destablizing force +/obj/item/projectile/destabilizer + name = "destabilizing force" + icon_state = "pulse1" + nodamage = TRUE + damage = 0 //We're just here to mark people. This is still a melee weapon. + damage_type = BRUTE + flag = "bomb" + range = 6 + log_override = TRUE + var/obj/item/twohanded/kinetic_crusher/hammer_synced + +/obj/item/projectile/destabilizer/Destroy() + hammer_synced = null + return ..() + +/obj/item/projectile/destabilizer/on_hit(atom/target, blocked = FALSE) + if(isliving(target)) + var/mob/living/L = target + var/had_effect = (L.has_status_effect(STATUS_EFFECT_CRUSHERMARK)) //used as a boolean + var/datum/status_effect/crusher_mark/CM = L.apply_status_effect(STATUS_EFFECT_CRUSHERMARK, hammer_synced) + if(hammer_synced) + for(var/t in hammer_synced.trophies) + var/obj/item/crusher_trophy/T = t + T.on_mark_application(target, CM, had_effect) + var/target_turf = get_turf(target) + if(ismineralturf(target_turf)) + var/turf/simulated/mineral/M = target_turf + new /obj/effect/temp_visual/kinetic_blast(M) + M.gets_drilled(firer) + ..() + +//trophies +/obj/item/crusher_trophy + name = "tail spike" + desc = "A strange spike with no usage." + icon = 'icons/obj/lavaland/artefacts.dmi' + icon_state = "tail_spike" + var/bonus_value = 10 //if it has a bonus effect, this is how much that effect is + var/denied_type = /obj/item/crusher_trophy + +/obj/item/crusher_trophy/examine(mob/living/user) + ..() + to_chat(user, "Causes [effect_desc()] when attached to a kinetic crusher.") + +/obj/item/crusher_trophy/proc/effect_desc() + return "errors" + +/obj/item/crusher_trophy/attackby(obj/item/A, mob/living/user) + if(istype(A, /obj/item/twohanded/kinetic_crusher)) + add_to(A, user) + else + ..() + +/obj/item/crusher_trophy/proc/add_to(obj/item/twohanded/kinetic_crusher/H, mob/living/user) + for(var/t in H.trophies) + var/obj/item/crusher_trophy/T = t + if(istype(T, denied_type) || istype(src, T.denied_type)) + to_chat(user, "You can't seem to attach [src] to [H]. Maybe remove a few trophies?") + return FALSE + if(!user.drop_item()) + return + forceMove(H) + H.trophies += src + to_chat(user, "You attach [src] to [H].") + return TRUE + +/obj/item/crusher_trophy/proc/remove_from(obj/item/twohanded/kinetic_crusher/H, mob/living/user) + forceMove(get_turf(H)) + H.trophies -= src + return TRUE + +/obj/item/crusher_trophy/proc/on_melee_hit(mob/living/target, mob/living/user) //the target and the user + +/obj/item/crusher_trophy/proc/on_projectile_fire(obj/item/projectile/destabilizer/marker, mob/living/user) //the projectile fired and the user + +/obj/item/crusher_trophy/proc/on_mark_application(mob/living/target, datum/status_effect/crusher_mark/mark, had_mark) //the target, the mark applied, and if the target had a mark before + +/obj/item/crusher_trophy/proc/on_mark_detonation(mob/living/target, mob/living/user) //the target and the user + +//goliath +/obj/item/crusher_trophy/goliath_tentacle + name = "goliath tentacle" + desc = "A sliced-off goliath tentacle. Suitable as a trophy for a kinetic crusher." + icon_state = "goliath_tentacle" + denied_type = /obj/item/crusher_trophy/goliath_tentacle + bonus_value = 2 + var/missing_health_ratio = 0.1 + var/missing_health_desc = 10 + +/obj/item/crusher_trophy/goliath_tentacle/effect_desc() + return "mark detonation to do [bonus_value] more damage for every [missing_health_desc] health you are missing" + +/obj/item/crusher_trophy/goliath_tentacle/on_mark_detonation(mob/living/target, mob/living/user) + var/missing_health = user.health - user.maxHealth + missing_health *= missing_health_ratio //bonus is active at all times, even if you're above 90 health + missing_health *= bonus_value //multiply the remaining amount by bonus_value + if(missing_health > 0) + target.adjustBruteLoss(missing_health) //and do that much damage + +//watcher +/obj/item/crusher_trophy/watcher_wing + name = "watcher wing" + desc = "A wing ripped from a watcher. Suitable as a trophy for a kinetic crusher." + icon_state = "watcher_wing" + denied_type = /obj/item/crusher_trophy/watcher_wing + bonus_value = 5 + +/obj/item/crusher_trophy/watcher_wing/effect_desc() + return "mark detonation to prevent certain creatures from using certain attacks for [bonus_value*0.1] second\s" + +/obj/item/crusher_trophy/watcher_wing/on_mark_detonation(mob/living/target, mob/living/user) + if(ishostile(target)) + var/mob/living/simple_animal/hostile/H = target + if(H.ranged) //briefly delay ranged attacks + if(H.ranged_cooldown >= world.time) + H.ranged_cooldown += bonus_value + else + H.ranged_cooldown = bonus_value + world.time + +//magmawing watcher +/obj/item/crusher_trophy/blaster_tubes/magma_wing + name = "magmawing watcher wing" + desc = "A still-searing wing from a magmawing watcher. Suitable as a trophy for a kinetic crusher." + icon_state = "magma_wing" + gender = NEUTER + bonus_value = 5 + +/obj/item/crusher_trophy/blaster_tubes/magma_wing/effect_desc() + return "mark detonation to make the next destabilizer shot deal [bonus_value] damage" + +/obj/item/crusher_trophy/blaster_tubes/magma_wing/on_projectile_fire(obj/item/projectile/destabilizer/marker, mob/living/user) + if(deadly_shot) + marker.name = "heated [marker.name]" + marker.icon_state = "lava" + marker.damage = bonus_value + marker.nodamage = FALSE + deadly_shot = FALSE + +//icewing watcher +/obj/item/crusher_trophy/watcher_wing/ice_wing + name = "icewing watcher wing" + desc = "A carefully preserved frozen wing from an icewing watcher. Suitable as a trophy for a kinetic crusher." + icon_state = "ice_wing" + bonus_value = 8 + +//legion +/obj/item/crusher_trophy/legion_skull + name = "legion skull" + desc = "A dead and lifeless legion skull. Suitable as a trophy for a kinetic crusher." + icon_state = "legion_skull" + denied_type = /obj/item/crusher_trophy/legion_skull + bonus_value = 3 + +/obj/item/crusher_trophy/legion_skull/effect_desc() + return "a kinetic crusher to recharge [bonus_value*0.1] second\s faster" + +/obj/item/crusher_trophy/legion_skull/add_to(obj/item/twohanded/kinetic_crusher/H, mob/living/user) + . = ..() + if(.) + H.charge_time -= bonus_value + +/obj/item/crusher_trophy/legion_skull/remove_from(obj/item/twohanded/kinetic_crusher/H, mob/living/user) + . = ..() + if(.) + H.charge_time += bonus_value + +//blood-drunk hunter +/obj/item/crusher_trophy/miner_eye + name = "eye of a blood-drunk hunter" + desc = "Its pupil is collapsed and turned to mush. Suitable as a trophy for a kinetic crusher." + icon_state = "hunter_eye" + denied_type = /obj/item/crusher_trophy/miner_eye + +/obj/item/crusher_trophy/miner_eye/effect_desc() + return "mark detonation to grant stun immunity and 90% damage reduction for 1 second" + +/obj/item/crusher_trophy/miner_eye/on_mark_detonation(mob/living/target, mob/living/user) + user.apply_status_effect(STATUS_EFFECT_BLOODDRUNK) + +//ash drake +/obj/item/crusher_trophy/tail_spike + desc = "A spike taken from an ash drake's tail. Suitable as a trophy for a kinetic crusher." + denied_type = /obj/item/crusher_trophy/tail_spike + bonus_value = 5 + +/obj/item/crusher_trophy/tail_spike/effect_desc() + return "mark detonation to do [bonus_value] damage to nearby creatures and push them back" + +/obj/item/crusher_trophy/tail_spike/on_mark_detonation(mob/living/target, mob/living/user) + for(var/mob/living/L in oview(2, user)) + if(L.stat == DEAD) + continue + playsound(L, 'sound/magic/fireball.ogg', 20, 1) + new /obj/effect/temp_visual/fire(L.loc) + addtimer(CALLBACK(src, .proc/pushback, L, user), 1) //no free backstabs, we push AFTER module stuff is done + L.adjustFireLoss(bonus_value) + +/obj/item/crusher_trophy/tail_spike/proc/pushback(mob/living/target, mob/living/user) + if(!QDELETED(target) && !QDELETED(user) && (!target.anchored || ismegafauna(target))) //megafauna will always be pushed + step(target, get_dir(user, target)) + +//bubblegum +/obj/item/crusher_trophy/demon_claws + name = "demon claws" + desc = "A set of blood-drenched claws from a massive demon's hand. Suitable as a trophy for a kinetic crusher." + icon_state = "demon_claws" + gender = PLURAL + denied_type = /obj/item/crusher_trophy/demon_claws + bonus_value = 10 + var/static/list/damage_heal_order = list(BRUTE, BURN, OXY) + +/obj/item/crusher_trophy/demon_claws/effect_desc() + return "melee hits to do [bonus_value * 0.2] more damage and heal you for [bonus_value * 0.1], with 5X effect on mark detonation" + +/obj/item/crusher_trophy/demon_claws/add_to(obj/item/twohanded/kinetic_crusher/H, mob/living/user) + . = ..() + if(.) + H.force += bonus_value * 0.2 + H.force_unwielded += bonus_value * 0.2 + H.force_wielded += bonus_value * 0.2 + H.detonation_damage += bonus_value * 0.8 + +/obj/item/crusher_trophy/demon_claws/remove_from(obj/item/twohanded/kinetic_crusher/H, mob/living/user) + . = ..() + if(.) + H.force -= bonus_value * 0.2 + H.force_unwielded -= bonus_value * 0.2 + H.force_wielded -= bonus_value * 0.2 + H.detonation_damage -= bonus_value * 0.8 + +/obj/item/crusher_trophy/demon_claws/on_melee_hit(mob/living/target, mob/living/user) + user.heal_ordered_damage(bonus_value * 0.1, damage_heal_order) + +/obj/item/crusher_trophy/demon_claws/on_mark_detonation(mob/living/target, mob/living/user) + user.heal_ordered_damage(bonus_value * 0.4, damage_heal_order) + +//colossus +/obj/item/crusher_trophy/blaster_tubes + name = "blaster tubes" + desc = "The blaster tubes from a colossus's arm. Suitable as a trophy for a kinetic crusher." + icon_state = "blaster_tubes" + gender = PLURAL + denied_type = /obj/item/crusher_trophy/blaster_tubes + bonus_value = 15 + var/deadly_shot = FALSE + +/obj/item/crusher_trophy/blaster_tubes/effect_desc() + return "mark detonation to make the next destabilizer shot deal [bonus_value] damage but move slower" + +/obj/item/crusher_trophy/blaster_tubes/on_projectile_fire(obj/item/projectile/destabilizer/marker, mob/living/user) + if(deadly_shot) + marker.name = "deadly [marker.name]" + marker.icon_state = "chronobolt" + marker.damage = bonus_value + marker.nodamage = FALSE + marker.speed = 2 + deadly_shot = FALSE + +/obj/item/crusher_trophy/blaster_tubes/on_mark_detonation(mob/living/target, mob/living/user) + deadly_shot = TRUE + addtimer(CALLBACK(src, .proc/reset_deadly_shot), 300, TIMER_UNIQUE|TIMER_OVERRIDE) + +/obj/item/crusher_trophy/blaster_tubes/proc/reset_deadly_shot() + deadly_shot = FALSE + +//hierophant +/obj/item/crusher_trophy/vortex_talisman + name = "vortex talisman" + desc = "A glowing trinket that was originally the Hierophant's beacon. Suitable as a trophy for a kinetic crusher." + icon_state = "vortex_talisman" + denied_type = /obj/item/crusher_trophy/vortex_talisman + +/obj/item/crusher_trophy/vortex_talisman/effect_desc() + return "mark detonation to create a barrier you can pass" + +/obj/item/crusher_trophy/vortex_talisman/on_mark_detonation(mob/living/target, mob/living/user) + var/turf/T = get_turf(user) + new /obj/effect/temp_visual/hierophant/wall/crusher(T, user) //a wall only you can pass! + var/turf/otherT = get_step(T, turn(user.dir, 90)) + if(otherT) + new /obj/effect/temp_visual/hierophant/wall/crusher(otherT, user) + otherT = get_step(T, turn(user.dir, -90)) + if(otherT) + new /obj/effect/temp_visual/hierophant/wall/crusher(otherT, user) + +/obj/effect/temp_visual/hierophant/wall/crusher + duration = 75 \ No newline at end of file diff --git a/code/modules/mining/equipment_locker.dm b/code/modules/mining/equipment_locker.dm index c821bf84baa..ee42d12a53f 100644 --- a/code/modules/mining/equipment_locker.dm +++ b/code/modules/mining/equipment_locker.dm @@ -421,7 +421,7 @@ new /datum/data/mining_equipment("Brute First-Aid Kit", /obj/item/storage/firstaid/brute, 600), new /datum/data/mining_equipment("Tracking Implant Kit", /obj/item/storage/box/minertracker, 600), new /datum/data/mining_equipment("Jaunter", /obj/item/wormhole_jaunter, 750), - new /datum/data/mining_equipment("Kinetic Crusher", /obj/item/twohanded/required/kinetic_crusher, 750), + new /datum/data/mining_equipment("Kinetic Crusher", /obj/item/twohanded/kinetic_crusher, 750), new /datum/data/mining_equipment("Kinetic Accelerator", /obj/item/gun/energy/kinetic_accelerator, 750), new /datum/data/mining_equipment("Advanced Scanner", /obj/item/t_scanner/adv_mining_scanner, 800), new /datum/data/mining_equipment("Resonator", /obj/item/resonator, 800), @@ -625,7 +625,7 @@ // new /obj/item/stack/marker_beacon/thirty(drop_location) if("Crusher Kit") new /obj/item/extinguisher/mini(drop_location) - new /obj/item/twohanded/required/kinetic_crusher(drop_location) + new /obj/item/twohanded/kinetic_crusher(drop_location) if("Mining Conscription Kit") new /obj/item/storage/backpack/duffel/mining_conscript(drop_location) @@ -1148,103 +1148,4 @@ return ..() C.preserved = 1 to_chat(user, "You inject the hivelord core with the stabilizer. It will no longer go inert.") - qdel(src) - -/*********************Mining Hammer****************/ -/obj/item/twohanded/required/kinetic_crusher - icon = 'icons/obj/mining.dmi' - icon_state = "mining_hammer1" - item_state = "mining_hammer1" - name = "proto-kinetic crusher" - desc = "An early design of the proto-kinetic accelerator, it is little more than an combination of various mining tools cobbled together, forming a high-tech club.\ - While it is an effective mining tool, it did little to aid any but the most skilled and/or suicidal miners against local fauna. \ - \nMark a mob with the destabilizing force, then hit them in melee to activate it for extra damage. Extra damage if backstabbed in this fashion. \ - This weapon is only particularly effective against large creatures." - force = 20 //As much as a bone spear, but this is significantly more annoying to carry around due to requiring the use of both hands at all times - w_class = WEIGHT_CLASS_BULKY - slot_flags = SLOT_BACK - force_unwielded = 20 //It's never not wielded so these are the same - force_wielded = 20 - throwforce = 5 - throw_speed = 4 - light_range = 4 - armour_penetration = 10 - materials = list(MAT_METAL=1150, MAT_GLASS=2075) - hitsound = 'sound/weapons/bladeslice.ogg' - attack_verb = list("smashes", "crushes", "cleaves", "chops", "pulps") - sharp = 1 - var/charged = 1 - var/charge_time = 16 - var/atom/mark = null - var/marked_image = null - -/obj/item/projectile/destabilizer - name = "destabilizing force" - icon_state = "pulse1" - damage = 0 //We're just here to mark people. This is still a melee weapon. - damage_type = BRUTE - flag = "bomb" - range = 6 - var/obj/item/twohanded/required/kinetic_crusher/hammer_synced = null - -/obj/item/projectile/destabilizer/on_hit(atom/target, blocked = 0, hit_zone) - if(hammer_synced) - if(hammer_synced.mark == target) - return ..() - if(isliving(target)) - if(hammer_synced.mark && hammer_synced.marked_image) - hammer_synced.mark.underlays -= hammer_synced.marked_image - hammer_synced.marked_image = null - var/mob/living/L = target - if(L.mob_size >= MOB_SIZE_LARGE) - hammer_synced.mark = L - var/image/I = image('icons/effects/effects.dmi', loc = L, icon_state = "shield2",pixel_y = (-L.pixel_y),pixel_x = (-L.pixel_x)) - L.underlays += I - hammer_synced.marked_image = I - var/target_turf = get_turf(target) - if(istype(target_turf, /turf/simulated/mineral)) - var/turf/simulated/mineral/M = target_turf - new /obj/effect/temp_visual/kinetic_blast(M) - M.gets_drilled(firer) - ..() - -/obj/item/twohanded/required/kinetic_crusher/afterattack(atom/target, mob/user, proximity_flag) - if(!proximity_flag && charged)//Mark a target, or mine a tile. - var/turf/proj_turf = get_turf(src) - if(!istype(proj_turf, /turf)) - return - var/datum/gas_mixture/environment = proj_turf.return_air() - var/pressure = environment.return_pressure() - if(pressure > 50) - playsound(user, 'sound/weapons/empty.ogg', 100, 1) - return - var/obj/item/projectile/destabilizer/D = new /obj/item/projectile/destabilizer(user.loc) - D.preparePixelProjectile(target,get_turf(target), user) - D.hammer_synced = src - playsound(user, 'sound/weapons/plasma_cutter.ogg', 100, 1) - D.fire() - charged = 0 - icon_state = "mining_hammer1_uncharged" - spawn(charge_time) - Recharge() - return - if(proximity_flag && target == mark && isliving(target)) - var/mob/living/L = target - new /obj/effect/temp_visual/kinetic_blast(get_turf(L)) - mark = 0 - if(L.mob_size >= MOB_SIZE_LARGE) - L.underlays -= marked_image - QDEL_NULL(marked_image) - var/backstab = check_target_facings(user, L) - var/def_check = L.getarmor(type = "bomb") - if(backstab == FACING_INIT_FACING_TARGET_TARGET_FACING_PERPENDICULAR || backstab == FACING_SAME_DIR) - L.apply_damage(80, BRUTE, blocked = def_check) - playsound(user, 'sound/weapons/kenetic_accel.ogg', 100, 1) //Seriously who spelled it wrong - else - L.apply_damage(50, BRUTE, blocked = def_check) - -/obj/item/twohanded/required/kinetic_crusher/proc/Recharge() - if(!charged) - charged = 1 - icon_state = "mining_hammer1" - playsound(loc, 'sound/weapons/kenetic_reload.ogg', 60, 1) \ No newline at end of file + qdel(src) \ No newline at end of file diff --git a/code/modules/mining/explorer_gear.dm b/code/modules/mining/explorer_gear.dm index a9464efe959..566694d480d 100644 --- a/code/modules/mining/explorer_gear.dm +++ b/code/modules/mining/explorer_gear.dm @@ -41,4 +41,57 @@ "Drask" = 'icons/mob/species/drask/head.dmi', "Grey" = 'icons/mob/species/grey/head.dmi', "Skrell" = 'icons/mob/species/skrell/head.dmi' - ) \ No newline at end of file + ) + +/obj/item/clothing/suit/space/hostile_environment + name = "H.E.C.K. suit" + desc = "Hostile Environment Cross-Kinetic Suit: A suit designed to withstand the wide variety of hazards from Lavaland. It wasn't enough for its last owner." + icon_state = "hostile_env" + item_state = "hostile_env" + flags = THICKMATERIAL //not spaceproof + max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT + burn_state = FIRE_PROOF | LAVA_PROOF + slowdown = 0 + armor = list(melee = 70, bullet = 40, laser = 10, energy = 10, bomb = 50, bio = 100, rad = 100) + allowed = list(/obj/item/flashlight, /obj/item/tank, /obj/item/resonator, /obj/item/mining_scanner, /obj/item/t_scanner/adv_mining_scanner, /obj/item/gun/energy/kinetic_accelerator, /obj/item/pickaxe) + +/obj/item/clothing/suit/space/hostile_environment/New() + ..() + AddComponent(/datum/component/spraycan_paintable) + START_PROCESSING(SSobj, src) + +/obj/item/clothing/suit/space/hostile_environment/Destroy() + STOP_PROCESSING(SSobj, src) + return ..() + +/obj/item/clothing/suit/space/hostile_environment/process() + var/mob/living/carbon/C = loc + if(istype(C) && prob(2)) //cursed by bubblegum + if(prob(15)) + new /obj/effect/hallucination/oh_yeah(get_turf(C), C) + to_chat(C, "[pick("I AM IMMORTAL.","I SHALL TAKE BACK WHAT'S MINE.","I SEE YOU.","YOU CANNOT ESCAPE ME FOREVER.","DEATH CANNOT HOLD ME.")]") + else + to_chat(C, "[pick("You hear faint whispers.","You smell ash.","You feel hot.","You hear a roar in the distance.")]") + +/obj/item/clothing/head/helmet/space/hostile_environment + name = "H.E.C.K. helmet" + desc = "Hostile Environiment Cross-Kinetic Helmet: A helmet designed to withstand the wide variety of hazards from Lavaland. It wasn't enough for its last owner." + icon_state = "hostile_env" + item_state = "hostile_env" + w_class = WEIGHT_CLASS_NORMAL + max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT + flags = THICKMATERIAL // no space protection + armor = list(melee = 70, bullet = 40, laser = 10, energy = 10, bomb = 50, bio = 100, rad = 100) + burn_state = FIRE_PROOF | LAVA_PROOF + +/obj/item/clothing/head/helmet/space/hostile_environment/New() + ..() + AddComponent(/datum/component/spraycan_paintable) + update_icon() + +/obj/item/clothing/head/helmet/space/hostile_environment/update_icon() + ..() + cut_overlays() + var/mutable_appearance/glass_overlay = mutable_appearance(icon, "hostile_env_glass") + glass_overlay.appearance_flags = RESET_COLOR + add_overlay(glass_overlay) \ No newline at end of file diff --git a/code/modules/mining/lavaland/loot/ashdragon_loot.dm b/code/modules/mining/lavaland/loot/ashdragon_loot.dm index 4f8f01498d0..6a30c565547 100644 --- a/code/modules/mining/lavaland/loot/ashdragon_loot.dm +++ b/code/modules/mining/lavaland/loot/ashdragon_loot.dm @@ -15,6 +15,15 @@ if(4) new /obj/item/dragons_blood(src) + +/obj/structure/closet/crate/necropolis/dragon/crusher + name = "firey dragon chest" + +/obj/structure/closet/crate/necropolis/dragon/crusher/New() + ..() + new /obj/item/crusher_trophy/tail_spike(src) + + // Spectral Blade /obj/item/melee/ghost_sword diff --git a/code/modules/mining/lavaland/loot/bubblegum_loot.dm b/code/modules/mining/lavaland/loot/bubblegum_loot.dm index bb0031ea77d..6cc33e1ad92 100644 --- a/code/modules/mining/lavaland/loot/bubblegum_loot.dm +++ b/code/modules/mining/lavaland/loot/bubblegum_loot.dm @@ -3,6 +3,8 @@ /obj/structure/closet/crate/necropolis/bubblegum/New() ..() + new /obj/item/clothing/suit/space/hostile_environment(src) + new /obj/item/clothing/head/helmet/space/hostile_environment(src) var/loot = rand(1,3) switch(loot) if(1) @@ -12,6 +14,13 @@ if(3) new /obj/item/gun/magic/staff/spellblade(src) +/obj/structure/closet/crate/necropolis/bubblegum/crusher + name = "bloody bubblegum chest" + +/obj/structure/closet/crate/necropolis/bubblegum/crusher/New() + ..() + new /obj/item/crusher_trophy/demon_claws(src) + // Mayhem /obj/item/mayhem diff --git a/code/modules/mining/lavaland/loot/colossus_loot.dm b/code/modules/mining/lavaland/loot/colossus_loot.dm index 2490f6f48db..9b6bd8c5893 100644 --- a/code/modules/mining/lavaland/loot/colossus_loot.dm +++ b/code/modules/mining/lavaland/loot/colossus_loot.dm @@ -1,3 +1,22 @@ +//Colossus +/obj/structure/closet/crate/necropolis/colossus + name = "colossus chest" + +/obj/structure/closet/crate/necropolis/colossus/New() + ..() + var/list/choices = subtypesof(/obj/machinery/anomalous_crystal) + var/random_crystal = pick(choices) + new random_crystal(src) + new /obj/item/organ/internal/vocal_cords/colossus(src) + +/obj/structure/closet/crate/necropolis/colossus/crusher + name = "angelic colossus chest" + +/obj/structure/closet/crate/necropolis/colossus/crusher/New() + ..() + new /obj/item/crusher_trophy/blaster_tubes(src) + + //Black Box /obj/machinery/smartfridge/black_box diff --git a/code/modules/mining/lavaland/necropolis_chests.dm b/code/modules/mining/lavaland/necropolis_chests.dm index 76f4637473a..ab9b7979d03 100644 --- a/code/modules/mining/lavaland/necropolis_chests.dm +++ b/code/modules/mining/lavaland/necropolis_chests.dm @@ -57,7 +57,10 @@ if(15) new /obj/item/guardiancreator(src) if(16) - new /obj/item/disk/design_disk/modkit_disc/mob_and_turf_aoe(src) + if(prob(50)) + new /obj/item/disk/design_disk/modkit_disc/mob_and_turf_aoe(src) + else + new /obj/item/disk/design_disk/modkit_disc/bounty(src) if(17) new /obj/item/warp_cube/red(src) if(18) @@ -118,6 +121,10 @@ name = "Resonator Blast Mod Disk" modkit_design = /datum/design/unique_modkit/resonator_blast +/obj/item/disk/design_disk/modkit_disc/bounty + name = "Death Syphon Mod Disk" + modkit_design = /datum/design/unique_modkit/bounty + /datum/design/unique_modkit category = list("Mining", "Cyborg Upgrade Modules") //can't be normally obtained build_type = PROTOLATHE | MECHFAB @@ -141,4 +148,12 @@ desc = "A device which causes kinetic accelerators to fire shots that leave and detonate resonator blasts." id = "resonatormod" materials = list(MAT_METAL = 5000, MAT_GLASS = 5000, MAT_SILVER= 5000, MAT_URANIUM = 5000) - build_path = /obj/item/borg/upgrade/modkit/resonator_blasts \ No newline at end of file + build_path = /obj/item/borg/upgrade/modkit/resonator_blasts + +/datum/design/unique_modkit/bounty + name = "Kinetic Accelerator Death Syphon Mod" + desc = "A device which causes kinetic accelerators to permanently gain damage against creature types killed with it." + id = "bountymod" + materials = list(MAT_METAL = 4000, MAT_SILVER = 4000, MAT_GOLD = 4000, MAT_BLUESPACE = 4000) + reagents_list = list("blood" = 40) + build_path = /obj/item/borg/upgrade/modkit/bounty \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm index 73a76e00420..d573d2a8191 100644 --- a/code/modules/mob/living/carbon/human/update_icons.dm +++ b/code/modules/mob/living/carbon/human/update_icons.dm @@ -586,7 +586,8 @@ var/global/list/damage_icon_parts = list() standing.overlays += image("icon" = A.sprite_sheets[dna.species.name], "icon_state" = "[A.icon_state]") else standing.overlays += image("icon" = 'icons/mob/ties.dmi', "icon_state" = "[tie_color]") - + standing.alpha = w_uniform.alpha + standing.color = w_uniform.color overlays_standing[UNIFORM_LAYER] = standing else // Automatically drop anything in store / id / belt if you're not wearing a uniform. //CHECK IF NECESARRY @@ -769,6 +770,8 @@ var/global/list/damage_icon_parts = list() var/image/bloodsies = image("icon" = dna.species.blood_mask, "icon_state" = "shoeblood") bloodsies.color = shoes.blood_color standing.overlays += bloodsies + standing.alpha = shoes.alpha + standing.color = shoes.color overlays_standing[SHOES_LAYER] = standing else if(feet_blood_DNA) @@ -819,6 +822,8 @@ var/global/list/damage_icon_parts = list() var/image/bloodsies = image("icon" = dna.species.blood_mask, "icon_state" = "helmetblood") bloodsies.color = head.blood_color standing.overlays += bloodsies + standing.alpha = head.alpha + standing.color = head.color overlays_standing[HEAD_LAYER] = standing apply_overlay(HEAD_LAYER) @@ -886,6 +891,8 @@ var/global/list/damage_icon_parts = list() bloodsies.color = wear_suit.blood_color standing.overlays += bloodsies + standing.alpha = wear_suit.alpha + standing.color = wear_suit.color overlays_standing[SUIT_LAYER] = standing apply_overlay(SUIT_LAYER) @@ -951,6 +958,8 @@ var/global/list/damage_icon_parts = list() var/image/bloodsies = image("icon" = dna.species.blood_mask, "icon_state" = "maskblood") bloodsies.color = wear_mask.blood_color standing.overlays += bloodsies + standing.alpha = wear_mask.alpha + standing.color = wear_mask.color overlays_standing[FACEMASK_LAYER] = standing apply_overlay(FACEMASK_LAYER) @@ -973,6 +982,8 @@ var/global/list/damage_icon_parts = list() standing = mutable_appearance('icons/mob/back.dmi', "[back.icon_state]", layer = -BACK_LAYER) //create the image + standing.alpha = back.alpha + standing.color = back.color overlays_standing[BACK_LAYER] = standing apply_overlay(BACK_LAYER) diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner.dm index 7fd32bd71ec..d45e6f6ead8 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner.dm @@ -37,6 +37,7 @@ Difficulty: Medium ranged = 1 ranged_cooldown_time = 16 pixel_x = -16 + crusher_loot = list(/obj/item/melee/energy/cleaving_saw, /obj/item/gun/energy/kinetic_accelerator, /obj/item/crusher_trophy/miner_eye) loot = list(/obj/item/melee/energy/cleaving_saw, /obj/item/gun/energy/kinetic_accelerator) wander = FALSE del_on_death = TRUE @@ -48,7 +49,7 @@ Difficulty: Medium var/guidance = FALSE deathmessage = "falls to the ground, decaying into glowing particles." death_sound = "bodyfall" - + /obj/item/gps/internal/miner icon_state = null gpstag = "Resonant Signal" diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm index a53b8092e54..ac5e40025c6 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm @@ -42,6 +42,7 @@ Difficulty: Hard ranged = 1 pixel_x = -32 del_on_death = 1 + crusher_loot = list(/obj/structure/closet/crate/necropolis/bubblegum/crusher) loot = list(/obj/structure/closet/crate/necropolis/bubblegum) var/charging = 0 medal_type = BOSS_MEDAL_BUBBLEGUM diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm index 5d66061335c..3ebea47e353 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm @@ -45,7 +45,8 @@ Difficulty: Very Hard del_on_death = 1 medal_type = BOSS_MEDAL_COLOSSUS score_type = COLOSSUS_SCORE - loot = list(/obj/machinery/anomalous_crystal/random, /obj/item/organ/internal/vocal_cords/colossus) + crusher_loot = list(/obj/structure/closet/crate/necropolis/colossus/crusher) + loot = list(/obj/structure/closet/crate/necropolis/colossus) butcher_results = list(/obj/item/stack/ore/diamond = 5, /obj/item/stack/sheet/sinew = 5, /obj/item/stack/sheet/animalhide/ashdrake = 10, /obj/item/stack/sheet/bone = 30) deathmessage = "disintegrates, leaving a glowing core in its wake." death_sound = 'sound/misc/demon_dies.ogg' diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm index 68db8cb1274..0789d00832d 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm @@ -43,6 +43,7 @@ Difficulty: Medium move_to_delay = 10 ranged = 1 pixel_x = -16 + crusher_loot = list(/obj/structure/closet/crate/necropolis/dragon/crusher) loot = list(/obj/structure/closet/crate/necropolis/dragon) butcher_results = list(/obj/item/stack/ore/diamond = 5, /obj/item/stack/sheet/sinew = 5, /obj/item/stack/sheet/animalhide/ashdrake = 10, /obj/item/stack/sheet/bone = 30) var/swooping = 0 @@ -271,6 +272,7 @@ Difficulty: Medium melee_damage_lower = 30 damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 1, CLONE = 1, STAMINA = 0, OXY = 1) loot = list() + crusher_loot = list() /mob/living/simple_animal/hostile/megafauna/dragon/lesser/grant_achievement(medaltype,scoretype) return \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm index 7f974149556..bb4e9297605 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm @@ -53,6 +53,7 @@ Difficulty: Hard ranged_cooldown_time = 40 aggro_vision_range = 23 loot = list(/obj/item/hierophant_staff) + crusher_loot = list(/obj/item/hierophant_staff, /obj/item/crusher_trophy/vortex_talisman) wander = FALSE var/burst_range = 3 //range on burst aoe var/beam_range = 5 //range on cross blast beams @@ -556,6 +557,37 @@ Difficulty: Hard playsound(M,'sound/weapons/sear.ogg', 50, 1, -4) M.take_damage(damage, BURN, 0, 0) +/obj/effect/temp_visual/hierophant/wall //smoothing and pooling were not friends, but pooling is dead. + name = "vortex wall" + icon = 'icons/turf/walls/hierophant_wall_temp.dmi' + icon_state = "wall" + light_range = MINIMUM_USEFUL_LIGHT_RANGE + duration = 100 + smooth = SMOOTH_TRUE + +/obj/effect/temp_visual/hierophant/wall/New(loc, new_caster) + ..() + queue_smooth_neighbors(src) + queue_smooth(src) + +/obj/effect/temp_visual/hierophant/wall/Destroy() + queue_smooth_neighbors(src) + return ..() + +/obj/effect/temp_visual/hierophant/wall/CanPass(atom/movable/mover, turf/target) + if(QDELETED(caster)) + return FALSE + if(mover == caster.pulledby) + return TRUE + if(istype(mover, /obj/item/projectile)) + var/obj/item/projectile/P = mover + if(P.firer == caster) + return TRUE + if(mover == caster) + return TRUE + return FALSE + + /obj/effect/hierophant name = "hierophant rune" desc = "A powerful magic mark allowing whomever attunes themself to it to return to it at will." diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/megafauna.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/megafauna.dm index a32aceb33e3..f57559d549a 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/megafauna.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/megafauna.dm @@ -31,6 +31,7 @@ /obj/structure/barricade, /obj/machinery/field, /obj/machinery/power/emitter) + var/list/crusher_loot var/medal_type var/score_type = BOSS_SCORE var/elimination = 0 @@ -43,6 +44,10 @@ layer = LARGE_MOB_LAYER //Looks weird with them slipping under mineral walls and cameras and shit otherwise mouse_opacity = MOUSE_OPACITY_OPAQUE // Easier to click on in melee, they're giant targets anyway +/mob/living/simple_animal/hostile/megafauna/New() + ..() + apply_status_effect(STATUS_EFFECT_CRUSHERDAMAGETRACKING) + /mob/living/simple_animal/hostile/megafauna/Destroy() QDEL_NULL(internal_gps) . = ..() @@ -53,11 +58,17 @@ /mob/living/simple_animal/hostile/megafauna/death(gibbed) // this happens before the parent call because `del_on_death` may be set if(can_die() && !admin_spawned) - feedback_set_details("megafauna_kills","[initial(name)]") + var/datum/status_effect/crusher_damage/C = has_status_effect(STATUS_EFFECT_CRUSHERDAMAGETRACKING) + if(C && crusher_loot && C.total_damage >= maxHealth * 0.6) + spawn_crusher_loot() if(!elimination) //used so the achievment only occurs for the last legion to die. grant_achievement(medal_type,score_type) + feedback_set_details("megafauna_kills","[initial(name)]") return ..() +/mob/living/simple_animal/hostile/megafauna/proc/spawn_crusher_loot() + loot = crusher_loot + /mob/living/simple_animal/hostile/megafauna/AttackingTarget() ..() if(isliving(target)) diff --git a/code/modules/mob/living/simple_animal/hostile/mining/basilisk.dm b/code/modules/mob/living/simple_animal/hostile/mining/basilisk.dm index 28aacd37a73..ad8dcf44699 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining/basilisk.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining/basilisk.dm @@ -77,6 +77,7 @@ stat_attack = 1 flying = TRUE robust_searching = 1 + crusher_loot = /obj/item/crusher_trophy/watcher_wing loot = list() butcher_results = list(/obj/item/stack/ore/diamond = 2, /obj/item/stack/sheet/sinew = 2, /obj/item/stack/sheet/bone = 1) @@ -102,6 +103,8 @@ light_power = 2.5 light_color = LIGHT_COLOR_ORANGE projectiletype = /obj/item/projectile/temp/basilisk/magmawing + crusher_loot = /obj/item/crusher_trophy/blaster_tubes/magma_wing + crusher_drop_mod = 60 /mob/living/simple_animal/hostile/asteroid/basilisk/watcher/icewing name = "icewing watcher" @@ -114,6 +117,8 @@ health = 170 projectiletype = /obj/item/projectile/temp/basilisk/icewing butcher_results = list(/obj/item/stack/ore/diamond = 5, /obj/item/stack/sheet/bone = 1) //No sinew; the wings are too fragile to be usable + crusher_loot = /obj/item/crusher_trophy/watcher_wing/ice_wing + crusher_drop_mod = 30 /obj/item/projectile/temp/basilisk/magmawing name = "scorching blast" diff --git a/code/modules/mob/living/simple_animal/hostile/mining/goliath.dm b/code/modules/mob/living/simple_animal/hostile/mining/goliath.dm index a1c488b4068..dae7a688cb3 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining/goliath.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining/goliath.dm @@ -83,6 +83,7 @@ icon_dead = "goliath_dead" throw_message = "does nothing to the tough hide of the" pre_attack_icon = "goliath2" + crusher_loot = /obj/item/crusher_trophy/goliath_tentacle butcher_results = list(/obj/item/reagent_containers/food/snacks/goliath = 2, /obj/item/stack/sheet/animalhide/goliath_hide = 1, /obj/item/stack/sheet/bone = 2) loot = list() stat_attack = TRUE diff --git a/code/modules/mob/living/simple_animal/hostile/mining/hivelord.dm b/code/modules/mob/living/simple_animal/hostile/mining/hivelord.dm index 60c1f5e08e7..44ff6049a71 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining/hivelord.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining/hivelord.dm @@ -45,6 +45,9 @@ /mob/living/simple_animal/hostile/asteroid/hivelord/AttackingTarget() OpenFire() +/mob/living/simple_animal/hostile/asteroid/hivelord/spawn_crusher_loot() + loot += crusher_loot //we don't butcher + /mob/living/simple_animal/hostile/asteroid/hivelord/death(gibbed) // Only execute the below if we successfully died . = ..(gibbed) @@ -231,6 +234,7 @@ speak_emote = list("echoes") attack_sound = 'sound/weapons/pierce.ogg' throw_message = "bounces harmlessly off of" + crusher_loot = /obj/item/crusher_trophy/legion_skull loot = list(/obj/item/organ/internal/hivelord_core/legion) brood_type = /mob/living/simple_animal/hostile/asteroid/hivelordbrood/legion del_on_death = 1 diff --git a/code/modules/mob/living/simple_animal/hostile/mining/mining.dm b/code/modules/mob/living/simple_animal/hostile/mining/mining.dm index e23624a5a9d..434869c1d6d 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining/mining.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining/mining.dm @@ -1,4 +1,4 @@ -/mob/living/simple_animal/hostile/asteroid/ +/mob/living/simple_animal/hostile/asteroid vision_range = 2 atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) unsuitable_atmos_damage = 15 @@ -13,12 +13,18 @@ response_harm = "strikes" status_flags = 0 a_intent = INTENT_HARM + var/crusher_loot var/throw_message = "bounces off of" var/icon_aggro = null // for swapping to when we get aggressive var/fromtendril = FALSE see_in_dark = 8 see_invisible = SEE_INVISIBLE_MINIMUM mob_size = MOB_SIZE_LARGE + var/crusher_drop_mod = 25 + +/mob/living/simple_animal/hostile/asteroid/New() + ..() + apply_status_effect(STATUS_EFFECT_CRUSHERDAMAGETRACKING) /mob/living/simple_animal/hostile/asteroid/Aggro() ..() @@ -46,3 +52,12 @@ visible_message("The [T.name] [src.throw_message] [src.name]!") return ..() + +/mob/living/simple_animal/hostile/asteroid/death(gibbed) + var/datum/status_effect/crusher_damage/C = has_status_effect(STATUS_EFFECT_CRUSHERDAMAGETRACKING) + if(C && crusher_loot && prob((C.total_damage/maxHealth) * crusher_drop_mod)) //on average, you'll need to kill 4 creatures before getting the item + spawn_crusher_loot() + ..(gibbed) + +/mob/living/simple_animal/hostile/asteroid/proc/spawn_crusher_loot() + butcher_results[crusher_loot] = 1 \ No newline at end of file diff --git a/code/modules/projectiles/guns/energy/kinetic_accelerator.dm b/code/modules/projectiles/guns/energy/kinetic_accelerator.dm index 4662062a56e..ff65b67e11c 100644 --- a/code/modules/projectiles/guns/energy/kinetic_accelerator.dm +++ b/code/modules/projectiles/guns/energy/kinetic_accelerator.dm @@ -474,6 +474,45 @@ return new /obj/effect/temp_visual/resonance(target_turf, K.firer, null, 30) +/obj/item/borg/upgrade/modkit/bounty + name = "death syphon" + desc = "Killing or assisting in killing a creature permanently increases your damage against that type of creature." + denied_type = /obj/item/borg/upgrade/modkit/bounty + modifier = 1.25 + cost = 30 + var/maximum_bounty = 25 + var/list/bounties_reaped = list() + +/obj/item/borg/upgrade/modkit/bounty/projectile_prehit(obj/item/projectile/kinetic/K, atom/target, obj/item/gun/energy/kinetic_accelerator/KA) + if(isliving(target)) + var/mob/living/L = target + var/list/existing_marks = L.has_status_effect_list(STATUS_EFFECT_SYPHONMARK) + for(var/i in existing_marks) + var/datum/status_effect/syphon_mark/SM = i + if(SM.reward_target == src) //we want to allow multiple people with bounty modkits to use them, but we need to replace our own marks so we don't multi-reward + SM.reward_target = null + qdel(SM) + L.apply_status_effect(STATUS_EFFECT_SYPHONMARK, src) + +/obj/item/borg/upgrade/modkit/bounty/projectile_strike(obj/item/projectile/kinetic/K, turf/target_turf, atom/target, obj/item/gun/energy/kinetic_accelerator/KA) + if(isliving(target)) + var/mob/living/L = target + if(bounties_reaped[L.type]) + var/kill_modifier = 1 + if(K.pressure_decrease_active) + kill_modifier *= K.pressure_decrease + var/armor = L.run_armor_check(K.def_zone, K.flag, "", "", K.armour_penetration) + L.apply_damage(bounties_reaped[L.type]*kill_modifier, K.damage_type, K.def_zone, armor) + +/obj/item/borg/upgrade/modkit/bounty/proc/get_kill(mob/living/L) + var/bonus_mod = 1 + if(ismegafauna(L)) //megafauna reward + bonus_mod = 4 + if(!bounties_reaped[L.type]) + bounties_reaped[L.type] = min(modifier * bonus_mod, maximum_bounty) + else + bounties_reaped[L.type] = min(bounties_reaped[L.type] + (modifier * bonus_mod), maximum_bounty) + //Indoors /obj/item/borg/upgrade/modkit/indoors name = "decrease pressure penalty" diff --git a/icons/mob/head.dmi b/icons/mob/head.dmi index 7f84b29d04e..4bc39d8f80b 100644 Binary files a/icons/mob/head.dmi and b/icons/mob/head.dmi differ diff --git a/icons/mob/inhands/items_lefthand.dmi b/icons/mob/inhands/items_lefthand.dmi index 47cb86a2c89..97d2750029e 100644 Binary files a/icons/mob/inhands/items_lefthand.dmi and b/icons/mob/inhands/items_lefthand.dmi differ diff --git a/icons/mob/inhands/items_righthand.dmi b/icons/mob/inhands/items_righthand.dmi index e4630c2764e..15100e9112e 100644 Binary files a/icons/mob/inhands/items_righthand.dmi and b/icons/mob/inhands/items_righthand.dmi differ diff --git a/icons/mob/screen_alert.dmi b/icons/mob/screen_alert.dmi index b18cb799817..cb6a2c6bd64 100644 Binary files a/icons/mob/screen_alert.dmi and b/icons/mob/screen_alert.dmi differ diff --git a/icons/mob/suit.dmi b/icons/mob/suit.dmi index f79ca1fb338..abce25ab86f 100644 Binary files a/icons/mob/suit.dmi and b/icons/mob/suit.dmi differ diff --git a/icons/obj/clothing/hats.dmi b/icons/obj/clothing/hats.dmi index a20cf61eb33..a3d66d4d921 100644 Binary files a/icons/obj/clothing/hats.dmi and b/icons/obj/clothing/hats.dmi differ diff --git a/icons/obj/clothing/suits.dmi b/icons/obj/clothing/suits.dmi index 8e5a4b8e879..8371295985f 100644 Binary files a/icons/obj/clothing/suits.dmi and b/icons/obj/clothing/suits.dmi differ diff --git a/icons/obj/lavaland/artefacts.dmi b/icons/obj/lavaland/artefacts.dmi index cd2c6da08ee..8e91b20368f 100644 Binary files a/icons/obj/lavaland/artefacts.dmi and b/icons/obj/lavaland/artefacts.dmi differ diff --git a/icons/obj/mining.dmi b/icons/obj/mining.dmi index 29196e625ae..82ab4786c37 100644 Binary files a/icons/obj/mining.dmi and b/icons/obj/mining.dmi differ diff --git a/icons/turf/walls/hierophant_wall_temp.dmi b/icons/turf/walls/hierophant_wall_temp.dmi new file mode 100644 index 00000000000..9f0d4b8d23c Binary files /dev/null and b/icons/turf/walls/hierophant_wall_temp.dmi differ diff --git a/paradise.dme b/paradise.dme index 86eb2825b04..4475b56343b 100644 --- a/paradise.dme +++ b/paradise.dme @@ -278,6 +278,7 @@ #include "code\datums\components\ducttape.dm" #include "code\datums\components\jestosterone.dm" #include "code\datums\components\material_container.dm" +#include "code\datums\components\paintable.dm" #include "code\datums\components\squeak.dm" #include "code\datums\components\waddling.dm" #include "code\datums\diseases\_disease.dm" @@ -1651,6 +1652,7 @@ #include "code\modules\mining\ore.dm" #include "code\modules\mining\satchel_ore_boxdm.dm" #include "code\modules\mining\shelters.dm" +#include "code\modules\mining\equipment\kinetic_crusher.dm" #include "code\modules\mining\equipment\marker_beacons.dm" #include "code\modules\mining\equipment\survival_pod.dm" #include "code\modules\mining\laborcamp\laborshuttle.dm"