diff --git a/code/__DEFINES/flags.dm b/code/__DEFINES/flags.dm index 9ddae527eec..0da4f75e1bf 100644 --- a/code/__DEFINES/flags.dm +++ b/code/__DEFINES/flags.dm @@ -42,11 +42,12 @@ the atom/checkpass() proc uses them (tables will call movable atom checkpass(PASSTABLE) for example) */ //flags for pass_flags -#define PASSTABLE 1 -#define PASSGLASS 2 -#define PASSGRILLE 4 -#define PASSBLOB 8 -#define PASSMOB 16 +#define PASSTABLE 1 +#define PASSGLASS 2 +#define PASSGRILLE 4 +#define PASSBLOB 8 +#define PASSMOB 16 +#define LETPASSTHROW 32 //flags for species diff --git a/code/_onclick/adjacent.dm b/code/_onclick/adjacent.dm index f1db0379efc..2c2b87f9c5f 100644 --- a/code/_onclick/adjacent.dm +++ b/code/_onclick/adjacent.dm @@ -23,7 +23,7 @@ * If you are in the same turf, always true * If you are vertically/horizontally adjacent, ensure there are no border objects * If you are diagonally adjacent, ensure you can pass through at least one of the mutually adjacent square. - * Passing through in this case ignores anything with the throwpass flag, such as tables, racks, and morgue trays. + * Passing through in this case ignores anything with the LETPASSTHROW pass flag, such as tables, racks, and morgue trays. */ /turf/Adjacent(var/atom/neighbor, var/atom/target = null) var/turf/T0 = get_turf(neighbor) @@ -80,28 +80,18 @@ /* This checks if you there is uninterrupted airspace between that turf and this one. - This is defined as any dense ON_BORDER object, or any dense object without throwpass. + This is defined as any dense ON_BORDER object, or any dense object without LETPASSTHROW. The border_only flag allows you to not objects (for source and destination squares) */ /turf/proc/ClickCross(target_dir, border_only, target_atom = null) for(var/obj/O in src) - if( !O.density || O == target_atom || O.throwpass) //check if there's a dense object present on the turf - continue // throwpass is used for anything you can click through (or the firedoor special case, see above) + if( !O.density || O == target_atom || (O.pass_flags & LETPASSTHROW)) //check if there's a dense object present on the turf + continue // LETPASSTHROW is used for anything you can click through (or the firedoor special case, see above) - if( O.flags&ON_BORDER) // windows have throwpass but are on border, check them first + if( O.flags&ON_BORDER) // windows are on border, check them first if( O.dir & target_dir || O.dir & (O.dir-1) ) // full tile windows are just diagonals mechanically return 0 //O.dir&(O.dir-1) is false for any cardinal direction, but true for diagonal ones else if( !border_only ) // dense, not on border, cannot pass over return 0 return 1 - -/* - Aside: throwpass does not do what I thought it did originally, and is only used for checking whether or not - a thrown object should stop after already successfully entering a square. Currently the throw code involved - only seems to affect hitting mobs, because the checks performed against objects are already performed when - entering or leaving the square. Since throwpass isn't used on mobs, but only on objects, it is effectively - useless. Throwpass may later need to be removed and replaced with a passcheck (bitfield on movable atom passflags). - - Since I don't want to complicate the click code rework by messing with unrelated systems it won't be changed here. -*/ \ No newline at end of file diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 5d29949d6d7..ba8f7708085 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -6,8 +6,6 @@ var/list/fingerprintshidden var/fingerprintslast = null var/list/blood_DNA - var/last_bumped = 0 - var/throwpass = 0 ///Chemistry. var/datum/reagents/reagents = null @@ -50,26 +48,6 @@ return 0 -/atom/proc/throw_impact(atom/hit_atom,mob/thrower) - if(istype(hit_atom,/mob/living)) - var/mob/living/M = hit_atom - M.hitby(src,thrower) - - else if(isobj(hit_atom)) - var/obj/O = hit_atom - if(!O.anchored) - step(O, src.dir) - O.hitby(src) - - else if(isturf(hit_atom)) - var/turf/T = hit_atom - if(T.density) - spawn(2) - step(src, turn(src.dir, 180)) - if(istype(src,/mob/living)) - var/mob/living/M = src - M.take_organ_damage(20) - /atom/proc/attack_hulk(mob/living/carbon/human/hulk, do_attack_animation = 0) if(do_attack_animation) hulk.changeNext_move(CLICK_CD_MELEE) @@ -280,9 +258,10 @@ its easier to just keep the beam vertical. /atom/proc/fire_act() return -/atom/proc/hitby(atom/movable/AM as mob|obj) - return - +/atom/proc/hitby(atom/movable/AM, skip, var/hitpush) + if(density && !has_gravity(AM)) //thrown stuff bounces off dense stuff in no grav. + spawn(2) + step(AM, turn(AM.dir, 180)) var/list/blood_splatter_icons = list() diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index d1a70ec7e96..8a24343e0bb 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -93,12 +93,12 @@ /atom/movable/Crossed(atom/movable/AM) return -/atom/movable/Bump(var/atom/A as mob|obj|turf|area, yes) - if(throwing) - throw_impact(A) - throwing = 0 - if ((A && yes)) - A.last_bumped = world.time +/atom/movable/Bump(atom/A, yes) //the "yes" arg is to differentiate our Bump proc from byond's, without it every Bump() call would become a double Bump(). + if((A && yes)) + if(throwing) + throwing = 0 + throw_impact(A) + . = 1 A.Bumped(src) @@ -143,7 +143,6 @@ if(!direction) return 1 - var/old_dir = dir . = step(src, direction) dir = old_dir @@ -151,70 +150,92 @@ /atom/movable/proc/checkpass(passflag) return pass_flags&passflag -/atom/movable/proc/hit_check(mob/thrower) // todo: this is partly obsolete due to passflags already, add throwing stuff to mob CanPass and finish it - if(src.throwing) - for(var/atom/A in get_turf(src)) - if(A == src) continue - if(istype(A,/mob/living)) - if(A:lying) continue - src.throw_impact(A,thrower) - if(src.throwing == 1) - src.throwing = 0 - if(isobj(A)) - if(A.density && !A.throwpass) // **TODO: Better behaviour for windows which are dense, but shouldn't always stop movement - src.throw_impact(A,thrower) - src.throwing = 0 +/atom/movable/proc/throw_impact(atom/hit_atom) + return hit_atom.hitby(src) -/atom/movable/proc/throw_at(atom/target, range, speed, mob/thrower, var/spin = 1) +/atom/movable/hitby(atom/movable/AM, skip, var/hitpush = 1) + if(!anchored && hitpush) + step(src, AM.dir) + return ..() + +/atom/movable/proc/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0) if(!target || !src || (flags & NODROP)) return 0 //use a modified version of Bresenham's algorithm to get from the atom's current position to that of the target - src.throwing = 1 - if(spin) // turns out 1000+ spinning objects being thrown at the singularity creates lag - Iamgoofball + throwing = 1 + if(spin) //if we don't want the /atom/movable to spin. SpinAnimation(5, 1) + + var/dist_travelled = 0 + var/dist_since_sleep = 0 + var/dist_x = abs(target.x - src.x) var/dist_y = abs(target.y - src.y) var/dx = (target.x > src.x) ? EAST : WEST var/dy = (target.y > src.y) ? NORTH : SOUTH - var/dist_travelled = 0 - var/dist_since_sleep = 0 - var/tdist_x = dist_x; - var/tdist_y = dist_y; - var/tdx = dx; - var/tdy = dy; + var/pure_diagonal = 0 + if(dist_x == dist_y) + pure_diagonal = 1 if(dist_x <= dist_y) - tdist_x = dist_y; - tdist_y = dist_x; - tdx = dy; - tdy = dx; + var/olddist_x = dist_x + var/olddx = dx + dist_x = dist_y + dist_y = olddist_x + dx = dy + dy = olddx - var/error = tdist_x/2 - tdist_y - while(target && (((((dist_x > dist_y) && ((src.x < target.x && dx == EAST) || (src.x > target.x && dx == WEST))) || ((dist_x <= dist_y) && ((src.y < target.y && dy == NORTH) || (src.y > target.y && dy == SOUTH))) || (src.x > target.x && dx == WEST)) && dist_travelled < range) || !has_gravity(src))) - // only stop when we've gone the whole distance (or max throw range) and are on a non-space tile, or hit something, or hit the end of the map, or someone picks it up - if(!src.throwing) break - if(!istype(src.loc, /turf)) break + var/error = dist_x/2 - dist_y + var/atom/finalturf = get_turf(target) + var/hit = 0 - var/atom/step = get_step(src, (error < 0) ? tdy : tdx) + while(target && ((dist_travelled < range && loc != finalturf) || !has_gravity(src))) //stop if we reached our destination (or max range) and aren't floating + + if(!istype(loc, /turf)) + hit = 1 + break + + var/atom/step = get_step(src, get_dir(src, target)) + if(!pure_diagonal && !diagonals_first) // not a purely diagonal trajectory and we don't want all diagonal moves to be done first + if(error >= 0 && get_dist(src, finalturf) > 1) + step = get_step(src, dx) + error += (error < 0) ? dist_x/2 : -dist_y if(!step) // going off the edge of the map makes get_step return null, don't let things go off the edge break - src.Move(step, get_dir(loc, step)) - hit_check(thrower) - error += (error < 0) ? tdist_x : -tdist_y; + Move(step, get_dir(loc, step)) + if(!throwing) // we hit something during our move + hit = 1 + break dist_travelled++ dist_since_sleep++ if(dist_since_sleep >= speed) dist_since_sleep = 0 sleep(1) - //done throwing, either because it hit something or it finished moving - src.throwing = 0 - if(isobj(src)) - src.throw_impact(get_turf(src),thrower) + if(!dist_since_sleep && hitcheck()) //to catch sneaky things moving on our tile during our sleep(1) + hit = 1 + break + //done throwing, either because it hit something or it finished moving + throwing = 0 + if(!hit) + for(var/atom/A in get_turf(src)) //looking for our target on the turf we land on. + if(A == target) + hit = 1 + throw_impact(A) + return 1 + + throw_impact(get_turf(src)) // we haven't hit something yet and we still must, let's hit the ground. return 1 +/atom/movable/proc/hitcheck() + for(var/atom/movable/AM in get_turf(src)) + if(AM == src) + continue + if(AM.density && !(AM.pass_flags & LETPASSTHROW) && !(AM.flags & ON_BORDER)) + throw_impact(AM) + return 1 //Overlays /atom/movable/overlay diff --git a/code/game/gamemodes/cult/cult_structures.dm b/code/game/gamemodes/cult/cult_structures.dm index 01bab649c0c..aaac82f87df 100644 --- a/code/game/gamemodes/cult/cult_structures.dm +++ b/code/game/gamemodes/cult/cult_structures.dm @@ -24,17 +24,6 @@ name = "desk" desc = "A desk covered in arcane manuscripts and tomes in unknown languages. Looking at the text makes your skin crawl" icon_state = "tomealtar" -// luminosity = 5 - -//sprites for this no longer exist -Pete -//(they were stolen from another game anyway) -/* -/obj/structure/cult/pillar - name = "Pillar" - desc = "This should not exist" - icon_state = "pillar" - icon = 'magic_pillar.dmi' -*/ /obj/effect/gateway name = "gateway" @@ -44,13 +33,3 @@ density = 1 unacidable = 1 anchored = 1.0 - -/obj/effect/gateway/Bumped(mob/M as mob|obj) - spawn(0) - return - return - -/obj/effect/gateway/Crossed(AM as mob|obj) - spawn(0) - return - return \ No newline at end of file diff --git a/code/game/machinery/bots/ed209bot.dm b/code/game/machinery/bots/ed209bot.dm index 8aaf4173d49..140fc457c41 100644 --- a/code/game/machinery/bots/ed209bot.dm +++ b/code/game/machinery/bots/ed209bot.dm @@ -397,14 +397,6 @@ Auto Patrol[]"}, return 1 return 0 -/* terrible -/obj/machinery/bot/ed209/Bumped(atom/movable/M as mob|obj) - spawn(0) - if (M) - var/turf/T = get_turf(src) - M:loc = T -*/ - /obj/machinery/bot/ed209/explode() walk_to(src,0) visible_message("[src] blows apart!") diff --git a/code/game/machinery/computer/HolodeckControl.dm b/code/game/machinery/computer/HolodeckControl.dm index ffaecb88a14..6a96b8ac0fb 100644 --- a/code/game/machinery/computer/HolodeckControl.dm +++ b/code/game/machinery/computer/HolodeckControl.dm @@ -410,6 +410,7 @@ var/mob/living/carbon/M = hit_atom playsound(src, 'sound/items/dodgeball.ogg', 50, 1) M.apply_damage(10, STAMINA) + loc = get_turf(hit_atom) //drop at the target's feet if(prob(5)) M.Weaken(3) visible_message("[M] is knocked right off \his feet!", 3) @@ -421,7 +422,6 @@ icon_state = "hoop" anchored = 1 density = 1 - throwpass = 1 /obj/structure/holohoop/attackby(obj/item/weapon/W, mob/user, params) if (istype(W, /obj/item/weapon/grab) && get_dist(src,user)<2) diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm index 87ad6c9728c..129d03039b9 100644 --- a/code/game/machinery/doors/door.dm +++ b/code/game/machinery/doors/door.dm @@ -45,8 +45,8 @@ /obj/machinery/door/Bumped(atom/AM) if(operating || emagged) return - if(ismob(AM)) - var/mob/M = AM + if(isliving(AM)) + var/mob/living/M = AM if(world.time - M.last_bumped <= 10) return //Can bump-open one airlock per second. This is to prevent shock spam. M.last_bumped = world.time if(!M.restrained()) diff --git a/code/game/machinery/doors/firedoor.dm b/code/game/machinery/doors/firedoor.dm index d60c8bf9e9b..27f01b8c864 100644 --- a/code/game/machinery/doors/firedoor.dm +++ b/code/game/machinery/doors/firedoor.dm @@ -16,8 +16,10 @@ closingLayer = 3.11 /obj/machinery/door/firedoor/Bumped(atom/AM) - if(p_open || operating) return - if(!density) return ..() + if(p_open || operating) + return + if(!density) + return ..() return 0 diff --git a/code/game/machinery/recycler.dm b/code/game/machinery/recycler.dm index 38fe78bd912..9e4b3da49d0 100644 --- a/code/game/machinery/recycler.dm +++ b/code/game/machinery/recycler.dm @@ -101,6 +101,8 @@ var/const/SAFETY_COOLDOWN = 100 if(stat & (BROKEN|NOPOWER)) return + if(!anchored) + return if(safety_mode) return diff --git a/code/game/objects/effects/mines.dm b/code/game/objects/effects/mines.dm index e1c0f16074a..4c159f7a431 100644 --- a/code/game/objects/effects/mines.dm +++ b/code/game/objects/effects/mines.dm @@ -15,17 +15,14 @@ if(isanimal(AM)) var/mob/living/simple_animal/SA = AM if(!SA.flying) - Bumped(SA) + triggermine(SA) else - Bumped(AM) - -/obj/effect/mine/Bumped(AM as mob|obj) - - if(triggered) return - visible_message("[AM] sets off \icon[src] [src]!") - triggermine(AM) + triggermine(AM) /obj/effect/mine/proc/triggermine(mob/victim) + if(triggered) + return + visible_message("[victim] sets off \icon[src] [src]!") var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread s.set_up(3, 1, src) s.start() diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index 2b1e95fc358..ce2a1fc1875 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -55,6 +55,8 @@ var/global/image/fire_overlay = image("icon" = 'icons/effects/fire.dmi', "icon_s var/suittoggled = 0 var/hooded = 0 + var/mob/thrownby = null + /obj/item/mouse_drag_pointer = MOUSE_ACTIVE_POINTER //the icon to indicate this object is being dragged //So items can have custom embedd values @@ -469,26 +471,17 @@ var/global/image/fire_overlay = image("icon" = 'icons/effects/fire.dmi', "icon_s if(!findtext(desc, "it looks slightly melted...")) //it looks slightly melted... it looks slightly melted... it looks slightly melted... etc. desc += " it looks slightly melted..." //needs a space at the start, formatting +/obj/item/throw_impact(atom/A) + var/itempush = 1 + if(w_class < 4) + itempush = 0 //too light to push anything + return A.hitby(src,thrownby, 0, itempush) - -/obj/item/throw_impact(A) - if(throw_speed >= EMBED_THROWSPEED_THRESHOLD) - if(istype(A, /mob/living/carbon/human)) - var/mob/living/carbon/human/H = A - if(can_embed(src)) - if(prob(embed_chance) && !(PIERCEIMMUNE in H.dna.species.specflags)) - H.throw_alert("embeddedobject") - var/obj/item/organ/limb/L = pick(H.organs) - L.embedded_objects |= src - add_blood(H)//it embedded itself in you, of course it's bloody! - loc = H - L.take_damage(w_class*embedded_impact_pain_multiplier) - H.visible_message("\the [name] embeds itself in [H]'s [L.getDisplayName()]!","\the [name] embeds itself in your [L.getDisplayName()]!") - return - - //Reset regardless of if we hit a human. +/obj/item/throw_at(atom/target, range, speed, mob/thrower, spin=1) + thrownby = thrower + . = ..() throw_speed = initial(throw_speed) //explosions change this. - ..() + /obj/item/proc/remove_item_from_storage(atom/newLoc) //please use this if you're going to snowflake an item out of a obj/item/weapon/storage if(!newLoc) diff --git a/code/game/objects/items/toys.dm b/code/game/objects/items/toys.dm index 0b1b452afc5..a340ca49274 100644 --- a/code/game/objects/items/toys.dm +++ b/code/game/objects/items/toys.dm @@ -44,41 +44,40 @@ /obj/item/toy/balloon/afterattack(atom/A as mob|obj, mob/user, proximity) if(!proximity) return - if (istype(A, /obj/structure/reagent_dispensers/watertank) && get_dist(src,A) <= 1) - A.reagents.trans_to(src, 10) - user << "You fill the balloon with the contents of [A]." - src.desc = "A translucent balloon with some form of liquid sloshing around in it." - src.update_icon() - return + if (istype(A, /obj/structure/reagent_dispensers)) + var/obj/structure/reagent_dispensers/RD = A + if(RD.reagents.total_volume <= 0) + user << "[RD] is empty." + else if(reagents.total_volume >= 10) + user << "[src] is full." + else + A.reagents.trans_to(src, 10) + user << "You fill the balloon with the contents of [A]." + desc = "A translucent balloon with some form of liquid sloshing around in it." + update_icon() /obj/item/toy/balloon/attackby(obj/O, mob/user, params) if(istype(O, /obj/item/weapon/reagent_containers/glass)) if(O.reagents) - if(O.reagents.total_volume < 1) - user << "The [O] is empty." - else if(O.reagents.total_volume >= 1) - if(O.reagents.has_reagent("facid", 1)) - user << "The acid chews through the balloon!" - O.reagents.reaction(user) - qdel(src) - else - src.desc = "A translucent balloon with some form of liquid sloshing around in it." - user << "You fill the balloon with the contents of [O]." - O.reagents.trans_to(src, 10) - src.update_icon() - return + if(O.reagents.total_volume <= 0) + user << "[O] is empty." + else if(reagents.total_volume >= 10) + user << "[src] is full." + else + desc = "A translucent balloon with some form of liquid sloshing around in it." + user << "You fill the balloon with the contents of [O]." + O.reagents.trans_to(src, 10) + update_icon() /obj/item/toy/balloon/throw_impact(atom/hit_atom) - if(src.reagents.total_volume >= 1) - src.visible_message("\The [src] bursts!","You hear a pop and a splash.") - src.reagents.reaction(get_turf(hit_atom)) - for(var/atom/A in get_turf(hit_atom)) - src.reagents.reaction(A) - src.icon_state = "burst" - spawn(5) - if(src) - qdel(src) - return + if(!..()) //was it caught by a mob? + if(reagents.total_volume >= 1) + visible_message("[src] bursts!","You hear a pop and a splash.") + reagents.reaction(get_turf(hit_atom)) + for(var/atom/A in get_turf(hit_atom)) + reagents.reaction(A) + icon_state = "burst" + qdel(src) /obj/item/toy/balloon/update_icon() if(src.reagents.total_volume >= 1) @@ -514,20 +513,24 @@ icon_state = "snappop" w_class = 1 -/obj/item/toy/snappop/fire_act() - throw_impact() - return - -/obj/item/toy/snappop/throw_impact(atom/hit_atom) - ..() +/obj/item/toy/snappop/proc/pop_burst() var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread s.set_up(3, 1, src) s.start() - new /obj/effect/decal/cleanable/ash(src.loc) - src.visible_message("The [src.name] explodes!","You hear a snap!") + new /obj/effect/decal/cleanable/ash(loc) + visible_message("The [src.name] explodes!","You hear a snap!") playsound(src, 'sound/effects/snap.ogg', 50, 1) qdel(src) +/obj/item/toy/snappop/fire_act() + pop_burst() + return + +/obj/item/toy/snappop/throw_impact(atom/hit_atom) + if(!..()) + pop_burst() + + /obj/item/toy/snappop/Crossed(H as mob|obj) if((ishuman(H))) //i guess carp and shit shouldn't set them off var/mob/living/carbon/M = H @@ -1100,12 +1103,12 @@ w_class = 2.0 /obj/item/toy/minimeteor/throw_impact(atom/hit_atom) - ..() - playsound(src, 'sound/effects/meteorimpact.ogg', 40, 1) - for(var/mob/M in range(10, src)) - if(!M.stat && !istype(M, /mob/living/silicon/ai))\ - shake_camera(M, 3, 1) - qdel(src) + if(!..()) + playsound(src, 'sound/effects/meteorimpact.ogg', 40, 1) + for(var/mob/M in range(10, src)) + if(!M.stat && !istype(M, /mob/living/silicon/ai))\ + shake_camera(M, 3, 1) + qdel(src) /* * Carp plushie diff --git a/code/game/objects/items/weapons/dice.dm b/code/game/objects/items/weapons/dice.dm index 11490f263d4..3d5800ae934 100644 --- a/code/game/objects/items/weapons/dice.dm +++ b/code/game/objects/items/weapons/dice.dm @@ -56,7 +56,7 @@ /obj/item/weapon/dice/attack_self(mob/user) diceroll(user) -/obj/item/weapon/dice/throw_at(atom/target, range, speed, mob/user) +/obj/item/weapon/dice/throw_at(atom/target, range, speed, mob/user, spin=1) if(!..()) return diceroll(user) diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm index a72592a458e..e41fac7870f 100644 --- a/code/game/objects/structures/crates_lockers/closets.dm +++ b/code/game/objects/structures/crates_lockers/closets.dm @@ -79,15 +79,20 @@ return 1 /obj/structure/closet/proc/dump_contents() - for(var/obj/O in src) O.loc = loc + if(throwing) //you keep some momentum when getting out of a thrown closet + step(O, dir) for(var/mob/M in src) M.loc = loc if(M.client) M.client.eye = M.client.mob M.client.perspective = MOB_PERSPECTIVE + if(throwing) + step(M, dir) + if(throwing) + throwing = 0 /obj/structure/closet/proc/take_contents() @@ -100,14 +105,13 @@ return 0 if(!can_open()) return 0 - dump_contents() - opened = 1 if(istype(src, /obj/structure/closet/body_bag)) playsound(loc, 'sound/items/zip.ogg', 15, 1, -3) else playsound(loc, 'sound/machines/click.ogg', 15, 1, -3) density = 0 + dump_contents() update_icon() return 1 diff --git a/code/game/objects/structures/mineral_doors.dm b/code/game/objects/structures/mineral_doors.dm index 23be1ce7c31..fe14690944a 100644 --- a/code/game/objects/structures/mineral_doors.dm +++ b/code/game/objects/structures/mineral_doors.dm @@ -65,9 +65,9 @@ /obj/structure/mineral_door/proc/TryToSwitchState(atom/user) if(isSwitchingStates) return - if(ismob(user)) - var/mob/M = user - if(world.time - user.last_bumped <= 60) return //NOTE do we really need that? + if(isliving(user)) + var/mob/living/M = user + if(world.time - M.last_bumped <= 60) return //NOTE do we really need that? if(M.client) if(iscarbon(M)) var/mob/living/carbon/C = M diff --git a/code/game/objects/structures/morgue.dm b/code/game/objects/structures/morgue.dm index d3565376d41..3bd5ef645d2 100644 --- a/code/game/objects/structures/morgue.dm +++ b/code/game/objects/structures/morgue.dm @@ -226,7 +226,7 @@ Crematorium Switch layer = 2.9 var/obj/structure/bodycontainer/connected = null anchored = 1.0 - throwpass = 1 + pass_flags = LETPASSTHROW /obj/structure/tray/Destroy() if(connected) @@ -278,3 +278,12 @@ Crematorium Switch desc = "Apply corpse before closing." icon_state = "morguet" +/obj/structure/tray/m_tray/CanPass(atom/movable/mover, turf/target, height=0) + if(height==0) return 1 + + if(istype(mover) && mover.checkpass(PASSTABLE)) + return 1 + if(locate(/obj/structure/table) in get_turf(mover)) + return 1 + else + return 0 diff --git a/code/game/objects/structures/tables_racks.dm b/code/game/objects/structures/tables_racks.dm index 1dbf75a2ee8..47eef2e9eb7 100644 --- a/code/game/objects/structures/tables_racks.dm +++ b/code/game/objects/structures/tables_racks.dm @@ -20,7 +20,7 @@ density = 1 anchored = 1.0 layer = 2.8 - throwpass = 1 //You can throw objects over this, despite it's density.") + pass_flags = LETPASSTHROW //You can throw objects over this, despite it's density.") var/frame = /obj/structure/table_frame var/framestack = /obj/item/stack/rods var/buildstack = /obj/item/stack/sheet/metal @@ -364,7 +364,7 @@ icon_state = "rack" density = 1 anchored = 1.0 - throwpass = 1 //You can throw objects over this, despite it's density. + pass_flags = LETPASSTHROW //You can throw objects over this, despite it's density. var/health = 5 /obj/structure/rack/ex_act(severity, target) diff --git a/code/game/objects/weapons.dm b/code/game/objects/weapons.dm index 803f29cb1aa..e85375ba5ed 100644 --- a/code/game/objects/weapons.dm +++ b/code/game/objects/weapons.dm @@ -9,8 +9,3 @@ hitsound = 'sound/items/welder.ogg' if(damtype == "brute") hitsound = "swing_hit" - -/obj/item/weapon/Bump(mob/M) - spawn(0) - ..() - return \ No newline at end of file diff --git a/code/modules/flufftext/Hallucination.dm b/code/modules/flufftext/Hallucination.dm index c819175a48e..8ad8c75980a 100644 --- a/code/modules/flufftext/Hallucination.dm +++ b/code/modules/flufftext/Hallucination.dm @@ -171,47 +171,6 @@ Gunshots/explosions/opening doors/less rare audio (done) name = "alien hunter ([rand(1, 1000)])" return -/obj/effect/hallucination/simple/xeno/throw_at(atom/target, range, speed) // TODO : Make diagonal trhow into proc/property - if(!target || !src || (flags & NODROP)) return 0 - - src.throwing = 1 - - var/dist_x = abs(target.x - src.x) - var/dist_y = abs(target.y - src.y) - var/dist_travelled = 0 - var/dist_since_sleep = 0 - - var/tdist_x = dist_x; - var/tdist_y = dist_y; - - if(dist_x <= dist_y) - tdist_x = dist_y; - tdist_y = dist_x; - - var/error = tdist_x/2 - tdist_y - while(target && (((((dist_x > dist_y) && ((src.x < target.x) || (src.x > target.x))) || ((dist_x <= dist_y) && ((src.y < target.y) || (src.y > target.y))) || (src.x > target.x)) && dist_travelled < range) || !has_gravity(src))) - - if(!src.throwing) break - if(!istype(src.loc, /turf)) break - - var/atom/step = get_step(src, get_dir(src,target)) - if(!step) - break - src.Move(step, get_dir(src, step)) - hit_check() - error += (error < 0) ? tdist_x : -tdist_y; - dist_travelled++ - dist_since_sleep++ - if(dist_since_sleep >= speed) - dist_since_sleep = 0 - sleep(1) - - - src.throwing = 0 - src.throw_impact(get_turf(src)) - - return 1 - /obj/effect/hallucination/simple/xeno/throw_impact(A) update_icon("alienh_pounce") if(A == target) @@ -232,10 +191,10 @@ Gunshots/explosions/opening doors/less rare audio (done) xeno = new(pump.loc,target) sleep(10) xeno.update_icon("alienh_leap",'icons/mob/alienleap.dmi',-32,-32) - xeno.throw_at(target,7,1) + xeno.throw_at(target,7,1, spin = 0, diagonals_first = 1) sleep(10) xeno.update_icon("alienh_leap",'icons/mob/alienleap.dmi',-32,-32) - xeno.throw_at(pump,7,1) + xeno.throw_at(pump,7,1, spin = 0, diagonals_first = 1) sleep(10) var/xeno_name = xeno.name target << "[xeno_name] begins climbing into the ventilation system..." diff --git a/code/modules/food&drinks/food/snacks_egg.dm b/code/modules/food&drinks/food/snacks_egg.dm index 6a17202d6f0..473ad4ebde5 100644 --- a/code/modules/food&drinks/food/snacks_egg.dm +++ b/code/modules/food&drinks/food/snacks_egg.dm @@ -18,10 +18,11 @@ filling_color = "#F0E68C" /obj/item/weapon/reagent_containers/food/snacks/egg/throw_impact(atom/hit_atom) - ..() - new/obj/effect/decal/cleanable/egg_smudge(src.loc) - reagents.reaction(hit_atom, TOUCH) - del(src) // Not qdel, because it'll hit other mobs then the floor for runtimes. + if(!..()) //was it caught by a mob? + var/turf/T = get_turf(hit_atom) + new/obj/effect/decal/cleanable/egg_smudge(T) + reagents.reaction(hit_atom, TOUCH) + qdel(src) /obj/item/weapon/reagent_containers/food/snacks/egg/attackby(obj/item/weapon/W, mob/user, params) if(istype( W, /obj/item/toy/crayon )) diff --git a/code/modules/food&drinks/food/snacks_pie.dm b/code/modules/food&drinks/food/snacks_pie.dm index e4fe6700f67..6a9be926630 100644 --- a/code/modules/food&drinks/food/snacks_pie.dm +++ b/code/modules/food&drinks/food/snacks_pie.dm @@ -23,10 +23,11 @@ list_reagents = list("nutriment" = 6, "banana" = 5, "vitamin" = 2) /obj/item/weapon/reagent_containers/food/snacks/pie/cream/throw_impact(atom/hit_atom) - ..() - new/obj/effect/decal/cleanable/pie_smudge(src.loc) - reagents.reaction(hit_atom, TOUCH) - del(src) // Not qdel, because it'll hit other mobs then the floor for runtimes. + if(!..()) //was it caught by a mob? + var/turf/T = get_turf(hit_atom) + new/obj/effect/decal/cleanable/pie_smudge(T) + reagents.reaction(hit_atom, TOUCH) + qdel(src) /obj/item/weapon/reagent_containers/food/snacks/pie/berryclafoutis diff --git a/code/modules/hydroponics/grown.dm b/code/modules/hydroponics/grown.dm index 6c11a41934e..f27866be2d2 100644 --- a/code/modules/hydroponics/grown.dm +++ b/code/modules/hydroponics/grown.dm @@ -806,17 +806,16 @@ obj/item/weapon/reagent_containers/food/snacks/grown/shell/eggy/add_juice() bitesize = 1 + round(reagents.total_volume / 2, 1) /obj/item/weapon/reagent_containers/food/snacks/grown/tomato/proc/squish(atom/target) - new splat(src.loc) - src.visible_message("The [src.name] has been squashed.","You hear a smack.") + var/turf/T = get_turf(target) + new splat(T) + visible_message("The [src.name] has been squashed.","You hear a smack.") for(var/atom/A in get_turf(target)) - src.reagents.reaction(A) + reagents.reaction(A) /obj/item/weapon/reagent_containers/food/snacks/grown/tomato/throw_impact(atom/hit_atom) - ..() - squish(hit_atom) - del(src) // Not qdel, because it'll hit other mobs then the floor for runtimes. - return - + if(!..()) //was it caught by a mob? + squish(hit_atom) + qdel(src) /obj/item/weapon/reagent_containers/food/snacks/grown/tomato/killer seed = /obj/item/seeds/killertomatoseed @@ -906,7 +905,8 @@ obj/item/weapon/reagent_containers/food/snacks/grown/shell/eggy/add_juice() ..() var/teleport_radius = potency / 10 if(isliving(squishee)) - new /obj/effect/decal/cleanable/molten_item(squishee.loc) //Leave a pile of goo behind for dramatic effect... + var/turf/T = get_turf(squishee) + new /obj/effect/decal/cleanable/molten_item(T) //Leave a pile of goo behind for dramatic effect... do_teleport(squishee, get_turf(squishee), teleport_radius) diff --git a/code/modules/mob/living/carbon/alien/alien_defense.dm b/code/modules/mob/living/carbon/alien/alien_defense.dm index fa0f58d7f07..7f1e5337575 100644 --- a/code/modules/mob/living/carbon/alien/alien_defense.dm +++ b/code/modules/mob/living/carbon/alien/alien_defense.dm @@ -1,5 +1,5 @@ /mob/living/carbon/alien/hitby(atom/movable/AM) - ..(AM, 1) + ..(AM, skip = 1) /*Code for aliens attacking aliens. Because aliens act on a hivemind, I don't see them as very aggressive with each other. diff --git a/code/modules/mob/living/carbon/alien/humanoid/caste/hunter.dm b/code/modules/mob/living/carbon/alien/humanoid/caste/hunter.dm index 68fda08c934..dd900163da0 100644 --- a/code/modules/mob/living/carbon/alien/humanoid/caste/hunter.dm +++ b/code/modules/mob/living/carbon/alien/humanoid/caste/hunter.dm @@ -82,11 +82,11 @@ else //Maybe uses plasma in the future, although that wouldn't make any sense... leaping = 1 update_icons() - throw_at(A,MAX_ALIEN_LEAP_DIST,1) + throw_at(A,MAX_ALIEN_LEAP_DIST,1, spin=0, diagonals_first = 1) leaping = 0 update_icons() -/mob/living/carbon/alien/humanoid/hunter/throw_impact(A) +/mob/living/carbon/alien/humanoid/hunter/throw_impact(atom/A) if(!leaping) return ..() @@ -103,60 +103,19 @@ pounce_cooldown = !pounce_cooldown spawn(pounce_cooldown_time) //3s by default pounce_cooldown = !pounce_cooldown - else + else if(A.density && !A.CanPass(src)) visible_message("[src] smashes into [A]!", "[src] smashes into [A]!") weakened = 2 if(leaping) leaping = 0 + update_icons() update_canmove() - /mob/living/carbon/alien/humanoid/float(on) if(leaping) return ..() -//Modified throw_at() that will use diagonal dirs where appropriate -//instead of locking it to cardinal dirs -/mob/living/carbon/alien/humanoid/throw_at(atom/target, range, speed) - if(!target || !src || (flags & NODROP)) return 0 - - src.throwing = 1 - - var/dist_x = abs(target.x - src.x) - var/dist_y = abs(target.y - src.y) - var/dist_travelled = 0 - var/dist_since_sleep = 0 - - var/tdist_x = dist_x; - var/tdist_y = dist_y; - - if(dist_x <= dist_y) - tdist_x = dist_y; - tdist_y = dist_x; - - var/error = tdist_x/2 - tdist_y - while(target && (((((dist_x > dist_y) && ((src.x < target.x) || (src.x > target.x))) || ((dist_x <= dist_y) && ((src.y < target.y) || (src.y > target.y))) || (src.x > target.x)) && dist_travelled < range) || !has_gravity(src))) - - if(!src.throwing) break - if(!istype(src.loc, /turf)) break - - var/atom/step = get_step(src, get_dir(src,target)) - if(!step) - break - src.Move(step, get_dir(src, step)) - hit_check() - error += (error < 0) ? tdist_x : -tdist_y; - dist_travelled++ - dist_since_sleep++ - if(dist_since_sleep >= speed) - dist_since_sleep = 0 - sleep(1) - - - src.throwing = 0 - - return 1 diff --git a/code/modules/mob/living/carbon/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm index 7ef10003c95..9b705841a82 100644 --- a/code/modules/mob/living/carbon/carbon_defense.dm +++ b/code/modules/mob/living/carbon/carbon_defense.dm @@ -8,8 +8,8 @@ put_in_active_hand(I) visible_message("[src] catches [I]!") throw_mode_off() - return - ..() + return 1 + return ..() /mob/living/carbon/attackby(obj/item/I, mob/user, params) diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index 72a5d682d0c..01787095f8b 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -455,4 +455,18 @@ emp_act else ..() - return +/mob/living/carbon/human/hitby(atom/movable/AM) + if(throw_speed >= EMBED_THROWSPEED_THRESHOLD) + if(istype(AM, /obj/item)) + var/obj/item/I = AM + if(can_embed(I)) + if(prob(I.embed_chance) && !(dna && (PIERCEIMMUNE in dna.species.specflags))) + throw_alert("embeddedobject") + var/obj/item/organ/limb/L = pick(organs) + L.embedded_objects |= I + I.add_blood(src)//it embedded itself in you, of course it's bloody! + I.loc = src + L.take_damage(I.w_class*I.embedded_impact_pain_multiplier) + visible_message("\the [I.name] embeds itself in [src]'s [L.getDisplayName()]!","\the [I.name] embeds itself in your [L.getDisplayName()]!") + return + return ..() diff --git a/code/modules/mob/living/carbon/human/human_movement.dm b/code/modules/mob/living/carbon/human/human_movement.dm index b0078a13719..664933c175b 100644 --- a/code/modules/mob/living/carbon/human/human_movement.dm +++ b/code/modules/mob/living/carbon/human/human_movement.dm @@ -45,7 +45,7 @@ return shoes && shoes.negates_gravity() /mob/living/carbon/human/Move(NewLoc, direct) - ..() + . = ..() if(dna) for(var/datum/mutation/human/HM in dna.mutations) HM.on_move(src, NewLoc) diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index ea570bc40b7..bbcdc72c6aa 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -52,13 +52,14 @@ Sorry Giacom. Please don't be mad :( //Generic Bump(). Override MobBump() and ObjBump() instead of this. /mob/living/Bump(atom/A, yes) + if(..()) //we are thrown onto something + return if (buckled || !yes || now_pushing) return if(ismob(A)) var/mob/M = A if(MobBump(M)) return - ..() if(isobj(A)) var/obj/O = A if(ObjBump(O)) @@ -68,6 +69,10 @@ Sorry Giacom. Please don't be mad :( if(PushAM(AM)) return +/mob/living/Bumped(atom/movable/AM) + ..() + last_bumped = world.time + //Called when we bump onto a mob /mob/living/proc/MobBump(mob/M) //Even if we don't push/swap places, we "touched" them, so spread fire diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index c620bda6767..43e2c2735bf 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -44,7 +44,13 @@ else return 0 -/mob/living/hitby(atom/movable/AM,mob/thrower)//Standardization and logging -Sieve +/mob/living/throw_impact(atom/hit_atom) + . = ..() + if(hit_atom.density) + Weaken(1) + take_organ_damage(10) + +/mob/living/hitby(atom/movable/AM) if(istype(AM, /obj/item)) var/obj/item/I = AM var/zone = ran_zone("chest", 65)//Hits a random part of the body, geared towards the chest @@ -71,9 +77,11 @@ "[src] has been hit by [I].") var/armor = run_armor_check(zone, "melee", "Your armor has protected your [parse_zone(zone)].", "Your armor has softened hit to your [parse_zone(zone)].",I.armour_penetration) apply_damage(I.throwforce, dtype, zone, armor, I) - - if(thrower) - add_logs(thrower, src, "hit", I) + if(I.thrownby) + add_logs(I.thrownby, src, "hit", I) + else + playsound(loc, 'sound/weapons/genhit.ogg', 50, 1, -1) + return ..() /mob/living/mech_melee_attack(obj/mecha/M) if(M.occupant.a_intent == "harm") diff --git a/code/modules/mob/living/living_defines.dm b/code/modules/mob/living/living_defines.dm index 096da4e0b0d..56c0426c5bc 100644 --- a/code/modules/mob/living/living_defines.dm +++ b/code/modules/mob/living/living_defines.dm @@ -47,4 +47,6 @@ var/smoke_delay = 0 //used to prevent spam with smoke reagent reaction on mob. - var/list/say_log = list() //a log of what we've said, plain text, no spans or junk, essentially just each individual "message" \ No newline at end of file + var/list/say_log = list() //a log of what we've said, plain text, no spans or junk, essentially just each individual "message" + + var/last_bumped = 0 diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm index c5f8a272d8b..d65438f65e7 100644 --- a/code/modules/mob/mob_movement.dm +++ b/code/modules/mob/mob_movement.dm @@ -1,18 +1,16 @@ /mob/CanPass(atom/movable/mover, turf/target, height=0) - if(height==0) return 1 - - if(istype(mover) && mover.checkpass(PASSMOB)) + if(height==0) return 1 - if(istype(mover, /obj/item/projectile)) + if(istype(mover, /obj/item/projectile) || mover.throwing) return (!density || lying) + if(mover.checkpass(PASSMOB)) + return 1 if(ismob(mover)) var/mob/moving_mob = mover if ((other_mobs && moving_mob.other_mobs)) return 1 - return (!mover.density || !density || lying) - else - return (!mover.density || !density || lying) - return + return (!mover.density || !density || lying) + /client/Northeast() diff --git a/code/modules/power/singularity/containment_field.dm b/code/modules/power/singularity/containment_field.dm index fb0a69a9be2..08278a00ea7 100644 --- a/code/modules/power/singularity/containment_field.dm +++ b/code/modules/power/singularity/containment_field.dm @@ -43,7 +43,7 @@ /obj/machinery/field/containment/Crossed(obj/mover) if(istype(mover, /obj/machinery) || istype(mover, /obj/structure) || istype(mover, /obj/mecha)) - bump(mover) + bump_field(mover) /obj/machinery/field/containment/proc/set_master(master1,master2) if(!master1 || !master2) @@ -77,7 +77,7 @@ if((istype(mover, /obj/machinery) && !istype(mover, /obj/singularity)) || \ istype(mover, /obj/structure) || \ istype(mover, /obj/mecha)) - bump(mover) + bump_field(mover) return 0 return ..() @@ -106,13 +106,13 @@ "You hear an electrical crack.") user.updatehealth() - bump(user) + bump_field(user) spawn(5) hasShocked = 0 return -/obj/machinery/field/proc/bump(atom/movable/AM as mob|obj) +/obj/machinery/field/proc/bump_field(atom/movable/AM as mob|obj) var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread s.set_up(5, 1, AM.loc) s.start() diff --git a/code/modules/power/singularity/field_generator.dm b/code/modules/power/singularity/field_generator.dm index 9c9f3c0f948..550567bca53 100644 --- a/code/modules/power/singularity/field_generator.dm +++ b/code/modules/power/singularity/field_generator.dm @@ -356,6 +356,6 @@ field_generator power level display if(fields.len) ..() -/obj/machinery/field/generator/bump(atom/movable/AM as mob|obj) +/obj/machinery/field/generator/bump_field(atom/movable/AM as mob|obj) if(fields.len) ..() diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm index 29931e4e7bc..0a1eddc7eb5 100644 --- a/code/modules/projectiles/projectile.dm +++ b/code/modules/projectiles/projectile.dm @@ -92,7 +92,7 @@ return 50 //if the projectile doesn't do damage, play its hitsound at 50% volume /obj/item/projectile/Bump(atom/A, yes) - if(!yes) //prevents multi bumps. + if(!yes) //prevents double bumps. return if(A == firer || A == src) loc = A.loc diff --git a/code/modules/reagents/reagent_containers.dm b/code/modules/reagents/reagent_containers.dm index c75e6c3e82d..b64d21f6c14 100644 --- a/code/modules/reagents/reagent_containers.dm +++ b/code/modules/reagents/reagent_containers.dm @@ -79,8 +79,8 @@ reagents.handle_reactions() ..() -/obj/item/weapon/reagent_containers/throw_impact(atom/target,mob/thrower) - ..() +/obj/item/weapon/reagent_containers/throw_impact(atom/target) + . = ..() if(!reagents.total_volume || !spillable) return @@ -96,12 +96,11 @@ R += A.id + " (" R += num2text(A.volume) + ")," - + if(thrownby) + add_logs(thrownby, M, "splashed", R) reagents.reaction(target, TOUCH) - if(thrower) - add_logs(thrower, M, "splashed", R) - else if((!target.density || target.throwpass) && thrower && thrower.mind && thrower.mind.assigned_role == "Bartender") + else if((target.CanPass(src, get_turf(src))) && thrownby && thrownby.mind && thrownby.mind.assigned_role == "Bartender") visible_message("[src] lands onto the [target.name] without spilling a single drop.") return diff --git a/code/modules/telesci/bscrystal.dm b/code/modules/telesci/bscrystal.dm index 589731a3635..811ef4d991f 100644 --- a/code/modules/telesci/bscrystal.dm +++ b/code/modules/telesci/bscrystal.dm @@ -28,13 +28,14 @@ do_teleport(L, get_turf(L), blink_range, asoundin = 'sound/effects/phasein.ogg') /obj/item/bluespace_crystal/throw_impact(atom/hit_atom) - ..() - visible_message("[src] fizzles and disappears upon impact!") - PoolOrNew(/obj/effect/effect/sparks, loc) - playsound(src.loc, "sparks", 50, 1) - if(isliving(hit_atom)) - blink_mob(hit_atom) - qdel(src) + if(!..()) // not caught in mid-air + visible_message("[src] fizzles and disappears upon impact!") + var/turf/T = get_turf(hit_atom) + PoolOrNew(/obj/effect/effect/sparks, T) + playsound(src.loc, "sparks", 50, 1) + if(isliving(hit_atom)) + blink_mob(hit_atom) + qdel(src) // Artifical bluespace crystal, doesn't give you much research. diff --git a/html/changelogs/phil235-CatchThrownPieFix.yml b/html/changelogs/phil235-CatchThrownPieFix.yml new file mode 100644 index 00000000000..4f467b01345 --- /dev/null +++ b/html/changelogs/phil235-CatchThrownPieFix.yml @@ -0,0 +1,8 @@ + +author: phil235 + +# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again. +delete-after: True + +changes: + - tweak: "Thrown things no longer bounces off walls, unless they're in no gravity. Heavy items and mobs thrown can push the mobs and non anchored objects they land on. Throwing a mob onto a mob in no gravity will push each one in opposite direction. Thrown mobs landing on wall, or dense object or mob gets stunned and a bit injured. The damage when mob hit a wall is nerfed."