Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Various KNPC fixes and tweaks #2714

Merged
merged 7 commits into from
Dec 17, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
97 changes: 66 additions & 31 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,9 +382,10 @@ 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))
Bokkiewokkie marked this conversation as resolved.
Show resolved Hide resolved
Expand All @@ -376,7 +406,13 @@ 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
target_item = locate(/obj/item/gun) in T.contents
if(H.put_in_hands(target_item))
return TRUE
//Otherwise, is there a gun already on our person?
Bokkiewokkie marked this conversation as resolved.
Show resolved Hide resolved
if(S)
var/list/expanded_contents = S.contents + H.contents
target_item = locate(/obj/item/gun) in expanded_contents
Expand All @@ -386,7 +422,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 +483,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
Loading