Skip to content

Commit

Permalink
Initial Commit, reconstructed and updated version of my original 2023 PR
Browse files Browse the repository at this point in the history
  • Loading branch information
LynxSolstice committed Aug 9, 2024
1 parent 08990e2 commit 5113822
Show file tree
Hide file tree
Showing 14 changed files with 206 additions and 36 deletions.
2 changes: 1 addition & 1 deletion code/__DEFINES/traits.dm
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@
#define TRAIT_TOOL_SIMPLE_BLOWTORCH "t_tool_simple_blowtorch"

#define TRAIT_TOOL_PEN "t_tool_pen"

#define TRAIT_TOOL_SHOVEL "t_tool_shovel"
/// Can lockout blackmarket from ASRS console circuits.
#define TRAIT_TOOL_TRADEBAND "t_tool_tradeband"

Expand Down
2 changes: 1 addition & 1 deletion code/__HELPERS/unsorted.dm
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
//Returns 1 if the given item is capable of popping things like balloons, inflatable barriers, or cutting police tape.
// For the record, WHAT THE HELL IS THIS METHOD OF DOING IT?
#define can_puncture(W) (isitem(W) && (W.sharp || W.heat_source >= 400 || \
HAS_TRAIT(W, TRAIT_TOOL_SCREWDRIVER) || istype(W, /obj/item/tool/pen ) || istype(W, /obj/item/tool/shovel)) \
HAS_TRAIT(W, TRAIT_TOOL_SCREWDRIVER) || istype(W, /obj/item/tool/pen ) || HAS_TRAIT(W, TRAIT_TOOL_SHOVEL)) \
)

//Offuscate x for coord system
Expand Down
1 change: 1 addition & 0 deletions code/game/machinery/vending/vendor_types/requisitions.dm
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
list("EXPLOSIVES", -1, null, null),
list("M15 Fragmentation Grenade", floor(scale * 2), /obj/item/explosive/grenade/high_explosive/m15, VENDOR_ITEM_REGULAR),
list("M20 Claymore Anti-Personnel Mine", floor(scale * 4), /obj/item/explosive/mine, VENDOR_ITEM_REGULAR),
list("M19 Anti-Tank Mine", round(scale * 2), /obj/item/explosive/mine/bury/antitank, VENDOR_ITEM_REGULAR),
list("M40 HEDP Grenade", floor(scale * 25), /obj/item/explosive/grenade/high_explosive, VENDOR_ITEM_REGULAR),
list("M40 HIDP Incendiary Grenade", floor(scale * 4), /obj/item/explosive/grenade/incendiary, VENDOR_ITEM_REGULAR),
list("M40 HPDP White Phosphorus Smoke Grenade", floor(scale * 4), /obj/item/explosive/grenade/phosphorus, VENDOR_ITEM_REGULAR),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ GLOBAL_LIST_INIT(cm_vending_gear_engi, list(
list("M74 AGM-Smoke Airburst Packet (x3 airburst grenades)", 10, /obj/item/storage/box/packet/airburst_smoke, null, VENDOR_ITEM_REGULAR),
list("M74 AGM-Hornet Airburst Packet (x3 airburst grenades", 20, /obj/item/storage/box/packet/hornet, null, VENDOR_ITEM_REGULAR),
list("M20 Mine Box (x4 mines)", 18, /obj/item/storage/box/explosive_mines, null, VENDOR_ITEM_REGULAR),
list("M19 Anti Tank Mine", 18, /obj/item/explosive/mine/bury/antitank, null, VENDOR_ITEM_REGULAR),
list("M40 MFHS Metal Foam Grenade", 5, /obj/item/explosive/grenade/metal_foam, null, VENDOR_ITEM_REGULAR),
list("G2 Electroshock Grenade Packet (x3 grenades)", 16, /obj/item/storage/box/packet/sebb, null, VENDOR_ITEM_REGULAR),

Expand Down Expand Up @@ -155,7 +156,7 @@ GLOBAL_LIST_INIT(cm_vending_clothing_engi, list(
list("Pistol Pouch", 0, /obj/item/storage/pouch/pistol, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR),
list("Tools Pouch (Full)", 0, /obj/item/storage/pouch/tools/full, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR),
list("Engineer kit Pouch", 0, /obj/item/storage/pouch/engikit, MARINE_CAN_BUY_POUCH, VENDOR_ITEM_REGULAR),


list("ACCESSORIES (CHOOSE 1)", 0, null, null, null),
list("Black Webbing Vest", 0, /obj/item/clothing/accessory/storage/black_vest, MARINE_CAN_BUY_ACCESSORY, VENDOR_ITEM_REGULAR),
Expand Down
218 changes: 192 additions & 26 deletions code/game/objects/items/explosives/mine.dm
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@
icon_state = "m20"
force = 5
w_class = SIZE_SMALL
//layer = MOB_LAYER - 0.1 //You can't just randomly hide claymores under boxes. Booby-trapping bodies is fine though
layer = ABOVE_LYING_MOB_LAYER - 0.1 //You can't just randomly hide claymores under boxes. Booby-trapping bodies is fine though
throwforce = 5
health = 60
throw_range = 6
throw_speed = SPEED_VERY_FAST
unacidable = TRUE
Expand All @@ -23,22 +24,58 @@
)
angle = 60
use_dir = TRUE
/// How much shrapnel is distributed when it explodes
var/shrapnel_count = 12
/// How big of a boom that happens when this detonates?
var/explosive_power = 60
var/iff_signal = FACTION_MARINE
var/triggered = FALSE
var/hard_iff_lock = FALSE
var/obj/effect/mine_tripwire/tripwire

var/map_deployed = FALSE
/// Whether or not tripwires are enabled
var/use_tripwire = TRUE
/// If the mine needs to be buried.
var/needs_digging = FALSE
/// Is it buried?
var/buried = FALSE
/// Whether or not the mine is prespawned
var/map_prespawn = FALSE
/// After being deployed, how long does the mine take to be armed and ready? Leave false to disable. Use defines
var/arming_time = FALSE
/// If the trigger discriminates on "heavy" targets such as t3s
var/heavy_trigger = FALSE
/// How long should it take to deploy
var/deploy_time = 4 SECONDS

/obj/item/explosive/mine/get_examine_text(mob/user)
. = ..()
if(buried)
. += "This is buried."
if(heavy_trigger)
. += "It has a heavy trigger."

/obj/item/explosive/mine/Initialize()
. = ..()
if(map_deployed)
if(map_prespawn)
deploy_mine(null)

/obj/item/explosive/mine/Destroy()
QDEL_NULL(tripwire)
. = ..()

// Mines are NOT bullet proof
/obj/item/explosive/mine/bullet_act(obj/projectile/bullet)
..()
health -= bullet.damage
healthcheck()
return TRUE
/**
* Simply checks the health of the mine, if its zero or below, prime it.
*/
/obj/item/explosive/mine/proc/healthcheck()
if(health <= 0)
prime()

/obj/item/explosive/mine/ex_act()
prime() //We don't care about how strong the explosion was.

Expand Down Expand Up @@ -66,6 +103,9 @@
if(!..())
return

if(needs_digging && is_mainship_level(user.z))
to_chat(user, SPAN_WARNING("This mine needs to be buried in suitable terrain!"))
return
if(check_for_obstacles(user))
return

Expand All @@ -90,9 +130,19 @@
if(check_for_obstacles(user))
return

user.visible_message(SPAN_NOTICE("[user] finishes deploying [src]."), \
if(needs_digging)
playsound(loc, 'sound/weapons/flipblade.ogg', 25, 1)
user.visible_message(SPAN_NOTICE("[user] pulls the pin on [src]."), \
SPAN_NOTICE("You pull the activation pin and prepare it to be buried."))
user.drop_inv_item_on_ground(src)
anchored = TRUE
return
else
user.visible_message(SPAN_NOTICE("[user] finishes deploying [src]."), \
SPAN_NOTICE("You finish deploying [src]."))

if(user)
user.drop_inv_item_on_ground(src)
setDir(user ? user.dir : dir) //The direction it is planted in is the direction the user faces at that time
deploy_mine(user)

/obj/item/explosive/mine/proc/deploy_mine(mob/user)
Expand All @@ -102,15 +152,25 @@
cause_data = create_cause_data(initial(name), user)
anchored = TRUE
playsound(loc, 'sound/weapons/mine_armed.ogg', 25, 1)
if(user)
user.drop_inv_item_on_ground(src)
setDir(user ? user.dir : dir) //The direction it is planted in is the direction the user faces at that time
activate_sensors()
update_icon()


//Disarming

/obj/item/explosive/mine/attackby(obj/item/W, mob/user)
if(needs_digging && HAS_TRAIT(W, TRAIT_TOOL_SHOVEL) && !active && anchored && !buried)
user.visible_message(SPAN_NOTICE("[user] starts burying [src]."), \
SPAN_NOTICE("You start burying [src]."))
playsound(user.loc, 'sound/effects/thud.ogg', 40, 1, 6)
if(!do_after(user, 3 SECONDS, INTERRUPT_NO_NEEDHAND, BUSY_ICON_BUILD))
user.visible_message(SPAN_WARNING("[user] stops burying [src]."), \
SPAN_WARNING("You stop burying [src]."))
return
user.visible_message(SPAN_NOTICE("[user] finished burying [src]."), \
SPAN_NOTICE("You finish burying [src]."))
buried = TRUE
addtimer(CALLBACK(src, PROC_REF(deploy_mine), user), arming_time)
//Disarming
if(HAS_TRAIT(W, TRAIT_TOOL_MULTITOOL))
if(active)
if(user.action_busy)
Expand Down Expand Up @@ -148,6 +208,7 @@
anchored = FALSE
active = FALSE
triggered = FALSE
buried = FALSE
update_icon()
QDEL_NULL(tripwire)

Expand Down Expand Up @@ -195,28 +256,53 @@
/obj/item/explosive/mine/Collided(atom/movable/AM)
try_to_prime(AM)

/**
* Proc that notifies a heavy trigger failing to detonate
*/
/obj/item/explosive/mine/proc/heavy_trigger_notify(mob/living/unfortunate_soul)
unfortunate_soul.visible_message(SPAN_DANGER("[icon2html(src, viewers(src))] [name] clicks as [unfortunate_soul] moves on top of it."), \
SPAN_DANGER("[icon2html(src, unfortunate_soul)] [name] clicks as you move on top of it."), \
SPAN_DANGER("You hear a click."))

/obj/item/explosive/mine/proc/try_to_prime(mob/living/L)
/**
* Proc that runs checks before priming occurs
*/
/obj/item/explosive/mine/proc/try_to_prime(mob/living/unfortunate_soul)
if(!active || triggered || (customizable && !detonator))
return
if(!istype(L))
if(!istype(unfortunate_soul))
return
if(L.stat == DEAD)
if(unfortunate_soul.stat == DEAD)
return
if(L.get_target_lock(iff_signal))
if(unfortunate_soul.get_target_lock(iff_signal) || issynth(unfortunate_soul))
return
if(HAS_TRAIT(L, TRAIT_ABILITY_BURROWED))
if(HAS_TRAIT(unfortunate_soul, TRAIT_ABILITY_BURROWED))
return
L.visible_message(SPAN_DANGER("[icon2html(src, viewers(src))] The [name] clicks as [L] moves in front of it."), \
SPAN_DANGER("[icon2html(src, L)] The [name] clicks as you move in front of it."), \
if(heavy_trigger && buried)
playsound(loc, 'sound/weapons/flipblade.ogg', 35, 1)
if(isxeno(unfortunate_soul))
var/mob/living/carbon/xenomorph/xeno = unfortunate_soul
if(xeno.mob_size < MOB_SIZE_BIG)
heavy_trigger_notify(unfortunate_soul)
return
if(prob(75) && ishuman(unfortunate_soul))
var/mob/living/carbon/human/human = unfortunate_soul
if(!human.wear_suit)
heavy_trigger_notify(unfortunate_soul)
return
if(human.wear_suit.slowdown > SLOWDOWN_ARMOR_HEAVY) // "Nice hustle, 'tons-a-fun'! Next time, eat a salad!"
heavy_trigger_notify(unfortunate_soul)
return


unfortunate_soul.visible_message(SPAN_DANGER("[icon2html(src, viewers(src))] [name] clicks as [unfortunate_soul] moves on top of it."), \
SPAN_DANGER("[icon2html(src, unfortunate_soul)] [name] clicks as you move on top of it."), \
SPAN_DANGER("You hear a click."))

triggered = TRUE
playsound(loc, 'sound/weapons/mine_tripped.ogg', 25, 1)
prime()



//Note : May not be actual explosion depending on linked method
/obj/item/explosive/mine/prime()
set waitfor = 0
Expand All @@ -236,13 +322,24 @@
return XENO_NO_DELAY_ACTION

if(M.a_intent == INTENT_HELP)
to_chat(M, SPAN_XENONOTICE("If you hit this hard enough, it would probably explode."))
if(buried)
to_chat(M, SPAN_XENONOTICE("This is buried, you need to dig it out to damage it!"))
else
to_chat(M, SPAN_XENONOTICE("If you hit this hard enough, it would probably explode."))
return XENO_NO_DELAY_ACTION

M.animation_attack_on(src)
M.visible_message(SPAN_DANGER("[M] has slashed [src]!"), \
if(buried)
M.animation_attack_on(src)
M.visible_message(SPAN_NOTICE("[M] starts digging up [src]."), \
SPAN_NOTICE("You start digging up [src]. This might end badly..."))
if(!do_after(M, deploy_time * 1.5, INTERRUPT_NO_NEEDHAND, BUSY_ICON_FRIENDLY))
M.visible_message(SPAN_WARNING("[M] stops disarming [src]."), \
SPAN_WARNING("You stop disarming [src]."))
return
else
M.animation_attack_on(src)
M.visible_message(SPAN_DANGER("[M] has slashed [src]!"), \
SPAN_DANGER("You slash [src]!"))
playsound(loc, 'sound/weapons/slice.ogg', 25, 1)
playsound(loc, 'sound/weapons/slice.ogg', 25, 1)

//We move the tripwire randomly in either of the four cardinal directions
triggered = TRUE
Expand Down Expand Up @@ -295,14 +392,83 @@
/obj/item/explosive/mine/active
icon_state = "m20_active"
base_icon_state = "m20"
map_deployed = TRUE
map_prespawn = TRUE

/obj/item/explosive/mine/no_iff
iff_signal = null

/obj/item/explosive/mine/active/no_iff
iff_signal = null

// Subtype from this to create buried mines.
/obj/item/explosive/mine/bury
use_tripwire = FALSE
needs_digging = TRUE
map_prespawn = FALSE
buried = FALSE
arming_time = 3 SECONDS
use_dir = FALSE
unacidable = TRUE
var/datum/effect_system/spark_spread/sparks = new

/obj/item/explosive/mine/bury/examine(mob/user)
. = ..()
if(!buried)
. += "\n A small label on the bottom reads: 'To deploy: simply pull the pin to activate it and dig it in with your standard issue e-tool. This munition will automatically arm in [arming_time] seconds after being buried.' "
else
. += SPAN_DANGER("\n This unit is armed and ready")

/obj/item/explosive/mine/bury/Destroy()
. = ..()
QDEL_NULL(sparks)

/obj/item/explosive/mine/bury/Initialize(mapload, ...)
. = ..()
sparks.set_up(5, 0, src)
sparks.attach(src)

/obj/item/explosive/mine/bury/disarm()
. = ..()
QDEL_NULL(sparks)


/obj/item/explosive/mine/bury/prime()
. = ..()
QDEL_NULL(sparks)

/obj/item/explosive/mine/bury/antitank
name = "\improper M19 Anti-Tank Mine"
desc = "This older anti tank mine design from the 21st century was rolled back into service simply due to the currently-used M307 EMP anti tank mines being unable to trigger against the minimally armored vehicles commonly used by CLF. Featuring a 250 pound minimum detonation threshold, it can be employed against all but the lightest of vehicles. Despite being outdated, it can still pack a punch against APCs and lighter vehicles, while its plastic construction prevents detection by simple methods."
icon_state = "antitank_mine"
w_class = SIZE_LARGE
layer = ABOVE_LYING_MOB_LAYER - 0.1 //You can't just randomly hide claymores under boxes. Booby-trapping bodies is fine though
explosive_power = 150
heavy_trigger = TRUE

/obj/item/explosive/mine/bury/antitank/prime()
set waitfor = 0
create_shrapnel(loc, shrapnel_count, , ,/datum/ammo/bullet/shrapnel, cause_data)
cell_explosion(loc, explosive_power, 25, EXPLOSION_FALLOFF_SHAPE_EXPONENTIAL_HALF, dir, cause_data)
for(var/mob/living/carbon/M in oview(1, src))
M.AdjustStun(4)
M.KnockDown(4)
to_chat(M, SPAN_HIGHDANGER("Molten copper rips through your lower body!"))
M.apply_damage(50,BURN)
if(ishuman(M))
sparks.start()
var/mob/living/carbon/human/H = M
var/obj/limb/L = H.get_limb("l_leg")
var/obj/limb/R = H.get_limb("r_leg")
R.droplimb()
L.droplimb()
playsound(M.loc, "bone_break", 45, TRUE)
playsound(M.loc, "bone_break", 45, TRUE)
for(var/mob/living/living_mob in viewers(7, src))
if(living_mob.client)
shake_camera(living_mob, 10, 1)
qdel(src)
if(!QDELETED(src))
disarm()

/obj/item/explosive/mine/pmc
name = "\improper M20P Claymore anti-personnel mine"
Expand All @@ -314,7 +480,7 @@
/obj/item/explosive/mine/pmc/active
icon_state = "m20p_active"
base_icon_state = "m20p"
map_deployed = TRUE
map_prespawn = TRUE

/obj/item/explosive/mine/custom
name = "custom mine"
Expand Down
2 changes: 1 addition & 1 deletion code/game/objects/items/stacks/sandbags.dm
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
stack_id = "empty sandbags"

/obj/item/stack/sandbags_empty/attackby(obj/item/W, mob/user)
if (istype(W, /obj/item/tool/shovel))
if (HAS_TRAIT(W, TRAIT_TOOL_SHOVEL))
var/obj/item/tool/shovel/ET = W
if(ET.dirt_amt)
ET.dirt_amt--
Expand Down
2 changes: 1 addition & 1 deletion code/game/objects/items/stacks/snow.dm
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ GLOBAL_LIST_INIT(snow_recipes, list(
return ..()

/obj/item/stack/snow/attackby(obj/item/W, mob/user)
if(istype(W, /obj/item/tool/shovel))
if(HAS_TRAIT(W, TRAIT_TOOL_SHOVEL))
var/obj/item/tool/shovel/ET = W
if(isturf(loc))
if(ET.dirt_amt)
Expand Down
Loading

0 comments on commit 5113822

Please sign in to comment.