Skip to content

Commit

Permalink
Various KNPC fixes and tweaks (#2714)
Browse files Browse the repository at this point in the history
  • Loading branch information
Bokkiewokkie authored Dec 17, 2024
1 parent 8cd8c9d commit 29d678d
Show file tree
Hide file tree
Showing 7 changed files with 112 additions and 58 deletions.
23 changes: 14 additions & 9 deletions code/__HELPERS/path.dm
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@
if(!start || !end)
stack_trace("Invalid A* start or destination")
return
if(start.z != end.z || start == end ) //no pathfinding between z levels
if(start == end) //no pathfinding between z levels //NSV13 we DO want pathfinding between z levels. removed "start.z != end.z || " from the check
return
if(max_distance && (max_distance < get_dist(start, end))) //if start turf is farther than max_distance from end turf, no need to do anything
return
Expand Down Expand Up @@ -337,16 +337,21 @@
* * ID: An ID card that decides if we can gain access to doors that would otherwise block a turf
* * simulated_only: Do we only worry about turfs with simulated atmos, most notably things that aren't space?
*/
//NSV13 refactored this to use a typecache for directional objects in src
/turf/proc/LinkBlockedWithAccess(turf/destination_turf, caller, ID)
var/actual_dir = get_dir(src, destination_turf)

for(var/obj/structure/window/iter_window in src)
if(!iter_window.CanAStarPass(ID, actual_dir))
return TRUE

for(var/obj/machinery/door/window/iter_windoor in src)
if(!iter_windoor.CanAStarPass(ID, actual_dir))
return TRUE
var/static/list/directionals = typecacheof(list(
/obj/structure/window,
/obj/machinery/door/window,
/obj/structure/railing,
/obj/structure/barricade,
/obj/machinery/door/firedoor
))

for(var/obj/iter_object in src)
if(directionals[iter_object.type])
if(!iter_object.CanAStarPass(ID, actual_dir, caller))
return TRUE

var/reverse_dir = get_dir(destination_turf, src)
for(var/obj/iter_object in destination_turf)
Expand Down
2 changes: 1 addition & 1 deletion code/game/points_of_interest.dm
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
var/list/pois = list()
for(var/mob/M in mobs)
if(skip_mindless && (!M.mind && !M.ckey))
if(!isbot(M) && !iscameramob(M) && !ismegafauna(M))
if(!isbot(M) && !iscameramob(M) && !ismegafauna(M) && !isknpc(M)) //NSV13 add KNPCs
continue
if(M.client && M.client.holder && M.client.holder.fakekey) //stealthmins
continue
Expand Down
4 changes: 2 additions & 2 deletions code/modules/mob/living/carbon/human/examine.dm
Original file line number Diff line number Diff line change
Expand Up @@ -310,9 +310,9 @@
if(InCritical())
msg += "[t_He] [t_is] barely conscious.\n"
if(getorgan(/obj/item/organ/brain))
if(ai_controller?.ai_status == AI_STATUS_ON)
if(ai_controller?.ai_status == AI_STATUS_ON || isknpc(src)) //NSV13 added KNPCs
msg += "<span class='deadsay'>[t_He] do[t_es]n't appear to be [t_him]self.</span>\n"
if(!key)
else if(!key)
msg += "<span class='deadsay'>[t_He] [t_is] totally catatonic. The stresses of life in deep-space must have been too much for [t_him]. Any recovery is unlikely.</span>\n"
else if(!client)
msg += "[t_He] [t_has] a blank, absent-minded stare and appears completely unresponsive to anything. [t_He] may snap out of it soon.\n"
Expand Down
30 changes: 19 additions & 11 deletions nsv13/code/game/objects/structures/barricade.dm
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
/obj/structure/peacekeeper_barricade //CREDIT TO CM FOR THIS. Cleanup up by Kmc.
icon = 'nsv13/icons/obj/barricades.dmi'
climbable = FALSE //Disable climbing.
anchored = TRUE
density = TRUE
layer = BELOW_OBJ_LAYER
climbable = TRUE
climb_time = 20 //Leaping a barricade is universally much faster than clumsily climbing on a table or rack
climb_stun = 0
var/stack_type //The type of stack the barricade dropped when disassembled if any.
Expand All @@ -13,7 +13,6 @@
var/base_acid_damage = 2
var/barricade_resistance = 5 //How much force an item needs to even damage it at all.
var/barricade_hitsound

var/barricade_type = "barricade" //"metal", "plasteel", etc.
var/can_change_dmg_state = TRUE
var/damage_state = 0
Expand Down Expand Up @@ -49,7 +48,6 @@
barricade_type = "plasteel"
density = FALSE
closed = TRUE
can_wire = TRUE

/obj/structure/peacekeeper_barricade/metal/plasteel/deployable //Preset one that starts unanchored and placed down.
icon_state = "plasteel_0"
Expand All @@ -58,16 +56,17 @@
anchored = FALSE
build_state = 0

/* You can reenable this when you fix it, KMC.
/obj/structure/peacekeeper_barricade/do_climb(var/mob/living/user)
if(is_wired) //Ohhh boy this is gonna hurt...
if(is_wired) //Even trying this is gonna hurt...
user.apply_damage(10)
user.Stun(20) //Leaping into barbed wire is VERY bad
if(get_turf(user) == get_turf(src))
usr.forceMove(get_step(src, src.dir))
user.Stun(20) //Scaling barbed wire is VERY bad
if(loc == user.loc)
density = FALSE
. = step(user,get_step(src,src.dir))
density = TRUE
else
usr.forceMove(get_turf(src))
*/
. = ..()

/obj/structure/peacekeeper_barricade/metal/plasteel/attack_hand(mob/user as mob)
. = ..()
if(.)
Expand Down Expand Up @@ -218,7 +217,6 @@
update_health()
can_wire = FALSE
is_wired = TRUE
// climbable = FALSE
return FALSE

if(I.tool_behaviour == TOOL_WIRECUTTER)
Expand Down Expand Up @@ -451,6 +449,16 @@
setDir(turn(dir, 270))
return

/obj/structure/peacekeeper_barricade/CanAStarPass(obj/item/card/id/ID, to_dir, atom/movable/caller)
. = ..()
if(.)
return
if(!(dir in to_dir))
return TRUE
if(isknpc(caller)) //They can climb
return TRUE
return FALSE

/obj/item/stack/barbed_wire
name = "barbed wire"
desc = "A spiky length of wire."
Expand Down
106 changes: 72 additions & 34 deletions nsv13/code/modules/overmap/knpc.dm
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,19 @@ GLOBAL_LIST_EMPTY(knpcs)
var/obj/effect/landmark/patrol_node/last_node = null //What was the last patrol node we visited?
var/stealing_id = FALSE
var/next_internals_attempt = 0
var/static/list/climbable = typecacheof(list(/obj/structure/table, /obj/structure/railing)) // climbable structures
var/static/list/climbable = typecacheof(list(
/obj/structure/table,
/obj/structure/railing,
/obj/structure/peacekeeper_barricade,
/obj/item/ship_weapon/ammunition
)) // climbable things
var/pathfind_timeout = 0 //If pathfinding fails, it is püt in timeout for a while to avoid spamming the server with pathfinding calls.
var/timeout_stacks = 0 //Consecutive pathfind fails add additional delay stacks to further counteract the effects of knpcs in unreachable locations.

/mob/living/carbon/human/ai_boarder
faction = list("Neutral")
var/move_delay = 4 //How quickly do the boys travel?
var/action_delay = 6 //How long we delay between actions
var/move_delay = 4 //How quickly do the boys travel?
var/action_delay = 9 //How long we delay between actions
var/knpc_traits = KNPC_IS_DODGER | KNPC_IS_MERCIFUL | KNPC_IS_AREA_SPECIFIC
var/difficulty_override = FALSE //Whether to ignore overmap difficulty or not
var/list/outfit = list (
Expand Down Expand Up @@ -143,39 +148,62 @@ GLOBAL_LIST_EMPTY(knpcs)
if(length(path) > 1)
var/turf/next_turf = get_step_towards(H, path[1])
var/turf/this_turf = get_turf(H)
var/move_dir = get_dir(this_turf, next_turf)
var/reverse_dir = get_dir(next_turf, this_turf)
//Walk when you see a wet floor
if(next_turf.GetComponent(/datum/component/wet_floor))
H.m_intent = MOVE_INTENT_WALK
else
H.m_intent = MOVE_INTENT_RUN

for(var/obj/machinery/door/firedoor/blocking_firelock in next_turf)
if((blocking_firelock.flags_1 & ON_BORDER_1) && !(blocking_firelock.dir in dir_to_cardinal_dirs(get_dir(next_turf, this_turf))))
if((blocking_firelock.flags_1 & ON_BORDER_1) && !(blocking_firelock.dir in dir_to_cardinal_dirs(reverse_dir))) //Here, only firelocks on the border matter since fulltile firelocks let you exit.
continue
if(!blocking_firelock.density || blocking_firelock.operating)
if(!blocking_firelock.density || blocking_firelock.powered())
continue
if(blocking_firelock.welded)
if((blocking_firelock.welded))
break //If at least one firedoor in our way is welded shut, welp!
blocking_firelock.open() //Open one firelock per tile per try.
break
for(var/obj/machinery/door/firedoor/blocking_firelock in this_turf)
if(!((blocking_firelock.flags_1 & ON_BORDER_1) && (blocking_firelock.dir in dir_to_cardinal_dirs(get_dir(this_turf, next_turf))))) //Here, only firelocks on the border matter since fulltile firelocks let you exit.
if(!((blocking_firelock.flags_1 & ON_BORDER_1) && (blocking_firelock.dir in dir_to_cardinal_dirs(move_dir))))
continue
if(!blocking_firelock.density || blocking_firelock.operating)
if(!blocking_firelock.density || blocking_firelock.powered())
continue
if(blocking_firelock.welded)
break //If at least one firedoor in our way is welded shut, welp!
blocking_firelock.open() //Open one firelock per tile per try.
break
for(var/obj/structure/possible_barrier in next_turf) //If we're stuck
if(!climbable.Find(possible_barrier.type))
if(!climbable[possible_barrier.type])
continue
if(possible_barrier.dir == reverse_dir || istype(possible_barrier, /obj/structure/table))
var/obj/item/dropped_it
if(H.get_active_held_item())
dropped_it = H.get_active_held_item()
possible_barrier.climb_structure(H)
if(dropped_it) //Don't forget to pick up your stuff
H.put_in_hands(dropped_it, forced=TRUE)
else
continue
H.forceMove(next_turf)
H.visible_message("<span class='warning'>[H] climbs onto [possible_barrier]!</span>")
H.Stun(2 SECONDS) //Table.
if(get_turf(H) == path[1])
increment_path()
return TRUE
return TRUE
for(var/obj/structure/possible_barrier in this_turf)
if(!climbable[possible_barrier.type])
continue
if(possible_barrier.dir == move_dir || istype(possible_barrier, /obj/structure/table))
var/obj/item/dropped_it
if(H.get_active_held_item())
dropped_it = H.get_active_held_item()
possible_barrier.climb_structure(H)
if(dropped_it) //Don't forget to pick up your stuff
H.put_in_hands(dropped_it, forced=TRUE)
else
continue
if(get_turf(H) == path[1])
increment_path()
return TRUE
step_towards(H, path[1])
if(get_turf(H) == path[1]) //Successful move
increment_path()
Expand Down Expand Up @@ -255,6 +283,7 @@ GLOBAL_LIST_EMPTY(knpcs)
if(length(path))
next_path_step()
else //They should always be pathing somewhere...
next_path_step()
dest = null
tries = 0
path = list()
Expand Down Expand Up @@ -298,7 +327,7 @@ of a specific action goes up, to encourage skynet to go for that one instead.
var/list/guessed_objects = view(HA.guess_range, HA.parent)
for(var/mob/living/M in guessed_objects)
//Invis is a no go. Non-human, -cyborg or -hostile mobs are ignored.
if(M.invisibility >= INVISIBILITY_ABSTRACT || M.alpha <= 0 || (!ishuman(M) && !iscyborg(M) && !ishostile(M)))
if(M.invisibility >= INVISIBILITY_ABSTRACT || M.alpha <= 0 || (!ishuman(M) && !iscyborg(M))) //Removed && !ishostile(M) temporarily because of Sgt. Araneus
continue
// Dead mobs are ignored.
if(CHECK_BITFIELD(H.knpc_traits, KNPC_IS_MERCIFUL) && M.stat >= UNCONSCIOUS)
Expand Down Expand Up @@ -353,13 +382,14 @@ This is to account for sec Ju-Jitsuing boarding commandos.
if(!..())
return 0
var/mob/living/carbon/human/H = HA.parent
var/obj/item/gun/G = H.get_active_held_item()
var/obj/A = H.get_active_held_item()
var/obj/B = H.get_inactive_held_item() //check your other hand, just in case.
//We already have a gun
if(G && istype(G))
if((A && istype(A, /obj/item/gun)) || (B && istype(B, /obj/item/gun)))
return 0
var/obj/item/gun/G_New = locate(/obj/item/gun) in oview(HA.view_range, H)
if(G_New && gun_suitable(H, G_New))
return AI_SCORE_CRITICAL //There is a gun really obviously in the open....
for(var/obj/item/gun/G in view(HA.view_range, H))
if(gun_suitable(H, G))
return AI_SCORE_CRITICAL //There is a gun really obviously in the open....
return score

/datum/ai_goal/human/proc/CheckFriendlyFire(mob/living/us, mob/living/them)
Expand All @@ -376,7 +406,16 @@ This is to account for sec Ju-Jitsuing boarding commandos.
var/mob/living/carbon/human/H = HA.parent
var/obj/item/storage/S = H.back
var/obj/item/gun/target_item = null
//Okay first off, is the gun already on our person?
//We must have lost our gun somehow, get it from the floor if we simply dropped it.
if(istype(H.loc, /turf))
var/turf/T = H.loc
for(var/obj/item/gun/G in T.contents)
if(gun_suitable(H, G))
target_item = G
break
if(target_item && H.put_in_hands(target_item))
return TRUE
//Otherwise, is there a gun already on our person?
if(S)
var/list/expanded_contents = S.contents + H.contents
target_item = locate(/obj/item/gun) in expanded_contents
Expand All @@ -386,7 +425,7 @@ This is to account for sec Ju-Jitsuing boarding commandos.
target_item.forceMove(get_turf(H)) //Put it on the floor so they can grab it
if(H.put_in_hands(target_item))
return TRUE //We're done!
//Now we run the more expensive check to find a gun laying on the ground.
//Now we run the more expensive check to find a gun farther away.
var/best_distance = world.maxx
for(var/obj/O in oview(HA.view_range, H))
var/dist = get_dist(O, H)
Expand Down Expand Up @@ -447,34 +486,33 @@ This is to account for sec Ju-Jitsuing boarding commandos.
if(E.selfcharge) //Okay good, it self charges we can just wait.
return TRUE
else //Discard it, we're not gonna teach them to use rechargers yet.
E.forceMove(get_turf(H))
H.dropItemToGround(E)
return FALSE
if(istype(gun, /obj/item/gun/ballistic))
var/obj/item/gun/ballistic/B = gun
if(istype(B.mag_type, /obj/item/ammo_box/magazine/internal))
//Not dealing with this. They'll just ditch the revolver when they're done with it.
B.forceMove(get_turf(H))
H.dropItemToGround(B)
return FALSE
///message_admins("Issa gun")
var/obj/item/storage/S = H.back
var/obj/item/storage/backpack = H.back
//Okay first off, is the gun already on our person?
var/list/expanded_contents = H.contents
if(S)
expanded_contents = S.contents + H.contents
if(backpack)
expanded_contents = backpack.contents + H.contents
var/obj/item/ammo_box/magazine/target_mag = locate(B.mag_type) in expanded_contents
//message_admins("Found [target_mag]")
if(target_mag)
//Dump that old mag
H.put_in_inactive_hand(target_mag)
B?.magazine?.forceMove(get_turf(H))
B.attackby(target_mag, H)
B.eject_magazine(H, FALSE, target_mag) //Tacticool reloads
H.dropItemToGround(H.get_inactive_held_item()) //We don't need that magazine anymore
B.attack_self(H) //Rack the bolt.
else
if(!S)
gun.forceMove(get_turf(H))
if(!backpack)
H.dropItemToGround(B)
return FALSE
gun.forceMove(S)

backpack.melee_attack_chain(src, B)
if(H.is_holding(B)) //No space in the backpack, this is useless to us so drop it
H.dropItemToGround(B)

/datum/ai_goal/human/engage_targets/action(datum/component/knpc/HA)
if(!can_action(HA))
Expand Down
2 changes: 2 additions & 0 deletions nsv13/code/modules/overmap/shieldgen.dm
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,8 @@
var/obj/structure/cable/cable = null //Connected cable
var/mutable_appearance/c_screen

/obj/machinery/shield_generator/update_icon()
cut_overlays()

/obj/machinery/shield_generator/proc/absorb_hit(obj/item/projectile/proj)
var/damage = proj.damage
Expand Down
3 changes: 2 additions & 1 deletion nsv13/code/modules/squads/squad_items.dm
Original file line number Diff line number Diff line change
Expand Up @@ -406,7 +406,8 @@
. = ..()
if(torn)
return
inflate(get_turf(target), user)
if(in_range(target, user))
inflate(get_turf(target), user)

/obj/item/inflatable/proc/inflate(turf/target, mob/user)
playsound(loc, 'sound/items/zip.ogg', 75, 1)
Expand Down

0 comments on commit 29d678d

Please sign in to comment.