From 342eae84cd1039ce4ee88a7d223c281ecb57948d Mon Sep 17 00:00:00 2001 From: FalloutFalcon Date: Wed, 1 May 2024 22:49:30 -0500 Subject: [PATCH] improvments to thrown so you can target items and stuff --- code/__DEFINES/flags.dm | 1 + code/_globalvars/bitfields.dm | 1 + code/controllers/subsystem/throwing.dm | 61 ++++++++++--------- code/game/atoms_movable.dm | 4 +- code/game/objects/items/devices/mines.dm | 11 ++-- code/modules/food_and_drinks/drinks/drinks.dm | 37 ++++++----- 6 files changed, 64 insertions(+), 51 deletions(-) diff --git a/code/__DEFINES/flags.dm b/code/__DEFINES/flags.dm index e0ac4b177001..c27a78ffd2de 100644 --- a/code/__DEFINES/flags.dm +++ b/code/__DEFINES/flags.dm @@ -123,6 +123,7 @@ GLOBAL_LIST_INIT(bitflags, list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 204 #define FLOATING (1<<3) /// When moving, will Cross()/Uncross() everything, but won't stop or Bump() anything. #define PHASING (1<<4) +#define THROWN (1<<5) //Fire and Acid stuff, for resistance_flags #define LAVA_PROOF (1<<0) diff --git a/code/_globalvars/bitfields.dm b/code/_globalvars/bitfields.dm index 406f0bb0b101..52ffff0401ac 100644 --- a/code/_globalvars/bitfields.dm +++ b/code/_globalvars/bitfields.dm @@ -190,6 +190,7 @@ DEFINE_BITFIELD(movement_type, list( "GROUND" = GROUND, "PHASING" = PHASING, "VENTCRAWLING" = VENTCRAWLING, + "THROWN" = THROWN, )) DEFINE_BITFIELD(obj_flags, list( diff --git a/code/controllers/subsystem/throwing.dm b/code/controllers/subsystem/throwing.dm index 0260e952d10d..e8cd514eb48b 100644 --- a/code/controllers/subsystem/throwing.dm +++ b/code/controllers/subsystem/throwing.dm @@ -47,7 +47,7 @@ SUBSYSTEM_DEF(throwing) /datum/thrownthing var/atom/movable/thrownthing - var/atom/target + var/datum/weakref/initial_target var/turf/target_turf var/target_zone var/init_dir @@ -71,12 +71,13 @@ SUBSYSTEM_DEF(throwing) var/last_move = 0 -/datum/thrownthing/New(thrownthing, target, target_turf, init_dir, maxrange, speed, thrower, diagonals_first, force, gentle, callback, target_zone) +/datum/thrownthing/New(thrownthing, target, init_dir, maxrange, speed, thrower, diagonals_first, force, gentle, callback, target_zone) . = ..() src.thrownthing = thrownthing RegisterSignal(thrownthing, COMSIG_PARENT_QDELETING, PROC_REF(on_thrownthing_qdel)) - src.target = target - src.target_turf = target_turf + src.target_turf = get_turf(target) + if(target_turf != target) + src.initial_target = WEAKREF(target) src.init_dir = init_dir src.maxrange = maxrange src.speed = speed @@ -87,14 +88,13 @@ SUBSYSTEM_DEF(throwing) src.callback = callback src.target_zone = target_zone - /datum/thrownthing/Destroy() SSthrowing.processing -= thrownthing SSthrowing.currentrun -= thrownthing thrownthing.throwing = null thrownthing = null - target = null thrower = null + initial_target = null if(callback) QDEL_NULL(callback) //It stores a reference to the thrownthing, its source. Let's clean that. return ..() @@ -109,6 +109,7 @@ SUBSYSTEM_DEF(throwing) /datum/thrownthing/proc/tick() var/atom/movable/AM = thrownthing + AM.setMovetype(AM.movement_type | THROWN) if (!isturf(AM.loc) || !AM.throwing) finalize() return @@ -117,9 +118,17 @@ SUBSYSTEM_DEF(throwing) delayed_time += world.time - last_move return - if (dist_travelled && hitcheck()) //to catch sneaky things moving on our tile while we slept - finalize() - return + var/atom/movable/actual_target = initial_target?.resolve() + + if(dist_travelled) //to catch sneaky things moving on our tile while we slept + for(var/atom/movable/obstacle as anything in get_turf(thrownthing)) + if (obstacle == thrownthing || (obstacle == thrower && !ismob(thrownthing))) + continue + if(obstacle.pass_flags_self & LETPASSTHROW) + continue + if (obstacle == actual_target || (obstacle.density && !(obstacle.flags_1 & ON_BORDER_1))) + finalize(TRUE, obstacle) + return var/atom/step @@ -146,10 +155,15 @@ SUBSYSTEM_DEF(throwing) finalize() return - AM.Move(step, get_dir(AM, step), DELAY_TO_GLIDE_SIZE(1 / speed)) + if(!AM.Move(step, get_dir(AM, step), DELAY_TO_GLIDE_SIZE(1 / speed))) // we hit something during our move... + if(AM.throwing) // ...but finalize() wasn't called on Bump() because of a higher level definition that doesn't always call parent. + finalize() + return - if (!AM.throwing) // we hit something during our move - finalize(hit = TRUE) + dist_travelled++ + + if(actual_target && !(actual_target.pass_flags_self & LETPASSTHROW) && actual_target.loc == AM.loc) // we crossed a movable with no density (e.g. a mouse or APC) we intend to hit anyway. + finalize(TRUE, actual_target) return dist_travelled++ @@ -158,18 +172,19 @@ SUBSYSTEM_DEF(throwing) finalize() return -/datum/thrownthing/proc/finalize(hit = FALSE, target=null) +//If the target hasent been hit search for it in the turf we landed on. +/datum/thrownthing/proc/finalize(hit = FALSE, target = null) set waitfor = FALSE //done throwing, either because it hit something or it finished moving if(!thrownthing) return thrownthing.throwing = null + thrownthing.setMovetype(thrownthing.movement_type & ~THROWN) if (!hit) - for (var/thing in get_turf(thrownthing)) //looking for our target on the turf we land on. - var/atom/A = thing - if (A == target) + for (var/atom/movable/obstacle as anything in get_turf(thrownthing)) //looking for our target on the turf we land on. + if (obstacle == target) hit = TRUE - thrownthing.throw_impact(A, src) + thrownthing.throw_impact(obstacle, src) if(QDELETED(thrownthing)) //throw_impact can delete things, such as glasses smashing return //deletion should already be handled by on_thrownthing_qdel() break @@ -195,15 +210,3 @@ SUBSYSTEM_DEF(throwing) T.zFall(thrownthing) qdel(src) - -/datum/thrownthing/proc/hit_atom(atom/A) - finalize(hit=TRUE, target=A) - -/datum/thrownthing/proc/hitcheck() - for (var/thing in get_turf(thrownthing)) - var/atom/movable/AM = thing - if (AM == thrownthing || (AM == thrower && !ismob(thrownthing))) - continue - if (AM.density && !(AM.pass_flags_self & LETPASSTHROW) && !(AM.flags_1 & ON_BORDER_1)) - finalize(hit=TRUE, target=AM) - return TRUE diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index 989db20efd1f..7702d75b98f4 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -624,7 +624,7 @@ SEND_SIGNAL(src, COMSIG_MOVABLE_BUMP, A) . = ..() if(!QDELETED(throwing)) - throwing.hit_atom(A) + throwing.finalize(hit = TRUE, target = A) . = TRUE if(QDELETED(A)) return @@ -883,7 +883,7 @@ else target_zone = thrower.zone_selected - var/datum/thrownthing/TT = new(src, target, get_turf(target), get_dir(src, target), range, speed, thrower, diagonals_first, force, gentle, callback, target_zone) + var/datum/thrownthing/TT = new(src, target, get_dir(src, target), range, speed, thrower, diagonals_first, force, gentle, callback, target_zone) var/dist_x = abs(target.x - src.x) var/dist_y = abs(target.y - src.y) diff --git a/code/game/objects/items/devices/mines.dm b/code/game/objects/items/devices/mines.dm index 112e26e1303b..1772cbf497c3 100644 --- a/code/game/objects/items/devices/mines.dm +++ b/code/game/objects/items/devices/mines.dm @@ -212,11 +212,8 @@ SIGNAL_HANDLER if(!can_trigger(arrived)) return - // Flying = can't step on a mine - if(arrived.movement_type & FLYING) - return - //no cheap disarming - if(arrived.throwing && isitem(arrived)) + // All other movment types rn can easily avoid it + if(!(arrived.movement_type == GROUND)) return // Someone already on it if(foot_on_mine?.resolve()) @@ -257,6 +254,10 @@ clicked = FALSE . = ..() +/obj/item/mine/pressure/hitby(atom/movable/AM, skipcatch, hitpush, blocked, datum/thrownthing/throwingdatum) + trigger_mine(AM) + ..() + //handles disarming(and failing to disarm) /obj/item/mine/pressure/attackby(obj/item/I, mob/user) if(I.tool_behaviour == TOOL_SCREWDRIVER) diff --git a/code/modules/food_and_drinks/drinks/drinks.dm b/code/modules/food_and_drinks/drinks/drinks.dm index 8f88924930f4..51d17efbd04d 100644 --- a/code/modules/food_and_drinks/drinks/drinks.dm +++ b/code/modules/food_and_drinks/drinks/drinks.dm @@ -120,27 +120,34 @@ if(!.) //if the bottle wasn't caught smash(hit_atom, throwingdatum?.thrower, TRUE) -/obj/item/reagent_containers/food/drinks/proc/smash(atom/target, mob/thrower, ranged = FALSE) +/obj/item/reagent_containers/food/drinks/hitby(atom/movable/AM, skipcatch, hitpush, blocked, datum/thrownthing/throwingdatum) + smash() + ..() + +/obj/item/reagent_containers/food/drinks/proc/smash(atom/target = FALSE, mob/thrower = FALSE, ranged = FALSE) if(!isGlass) return - if(QDELING(src) || !target || !(flags_1 & INITIALIZED_1)) //Invalid loc - return - if(bartender_check(target) && ranged) + if(QDELING(src) || !(flags_1 & INITIALIZED_1)) //Invalid loc return - var/obj/item/broken_bottle/B = new (loc) - B.icon_state = icon_state - var/icon/I = new(icon, icon_state) - I.Blend(B.broken_outline, ICON_OVERLAY, rand(5), 1) - I.SwapColor(rgb(255, 0, 220, 255), rgb(0, 0, 0, 0)) - B.icon = I - B.name = "broken [name]" + if(target) + if(bartender_check(target) && ranged) + return + var/obj/item/broken_bottle/smashed_bottle = new (loc) + smashed_bottle.icon_state = icon_state + var/icon/new_icon = new(icon, icon_state) + new_icon.Blend(smashed_bottle.broken_outline, ICON_OVERLAY, rand(5), 1) + new_icon.SwapColor(rgb(255, 0, 220, 255), rgb(0, 0, 0, 0)) + smashed_bottle.icon = new_icon + smashed_bottle.name = "broken [name]" if(prob(33)) - var/obj/item/shard/S = new(drop_location()) - target.Bumped(S) + var/obj/item/shard/new_shard = new(drop_location()) + if(target) + target.Bumped(new_shard) playsound(src, "shatter", 70, TRUE) - transfer_fingerprints_to(B) + transfer_fingerprints_to(smashed_bottle) qdel(src) - target.Bumped(B) + if(target) + target.Bumped(smashed_bottle) /obj/item/reagent_containers/food/drinks/bullet_act(obj/projectile/P) . = ..()