Skip to content

Crime Watchers - TFN Police Reporting & Open Carrying PRs - #1487

Open
Stutternov wants to merge 2 commits into
DarkPack13:masterfrom
Stutternov:Crime-Watch
Open

Crime Watchers - TFN Police Reporting & Open Carrying PRs#1487
Stutternov wants to merge 2 commits into
DarkPack13:masterfrom
Stutternov:Crime-Watch

Conversation

@Stutternov

@Stutternov Stutternov commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

About The Pull Request

Ports over two TFN PRs to upstream.
The-Final-Nights/The-Final-Nights-Rebase#280
The-Final-Nights/The-Final-Nights-Rebase#403

The first PR adds in GPS tracking to crimes to lead police to the general location of the crime reported, it changes NPC deaths to not be reported unless there is a witness; similar for assaults, etc. NPCs now actively call the police to report the crime, letting you stop an NPC reporting the crime by interrupting them from doing so. Battery has been added as a crime, reducing fire-fight calls over batteries. This also adds in a vague description of the suspect, calling in a piece of worn clothing when reported.

The second PR mainly adds consequence to open carrying firearms etc; making players have to hide their weapons if they want to be carrying them around.

Why It's Good For The Game

Overall this provided a QOL for police, redoes the police radio for the better while also not causing NPCs who are killed in some closed room or out-of-sight area from immediately being reported to police with locations.

This also provides feedback to players for when the cops will be called on them, encouraging people to change outfits given their coat, their boots, their glasses, etc could be used as the description given to the police.

Changelog

🆑
add: Adds police radio navigation to police calls.
add: Adds NPC 911 reporting.
add: Adds suspect description of random piece of clothing to 911 calls.
add: Open carrying firearms will now net in 911 calls.
/:cl:

@Stutternov
Stutternov requested a review from a team as a code owner August 30, 2026 19:22
@github-actions

Copy link
Copy Markdown
Contributor

You currently have a negative Fix/Feature pull request delta of -64. Maintainers may close this PR at will. Fixing issues or improving the codebase will improve this score.

@kimesik

kimesik commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

Would be nice if Police Captain had a way to "authorise" people for open-carry, in case somebody joins the police force mid-round, so that NPCs don't report rookies for openly carrying firearms.

image

Also, if it's not a problem, could you change the lines that directly mention the current year? IIRC not all of DarkPack's downstreams are actually set in 2016.

@kimesik

kimesik commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

Would be nice if Police Captain had a way to "authorise" people for open-carry, in case somebody joins the police force mid-round, so that NPCs don't report rookies for openly carrying firearms.

Or, alternatively, make NPCs check if the suspect is wearing police or military uniforms, letting people disguise as cops and avoid open carry charges.

@FalloutFalcon FalloutFalcon left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

idk. this whole code is messy but the feature is nice...

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this whole override and replace its usecase in this pr with create_navigation_line()

This was buffy copying the whole proc just to override the initial choice option so i just broke it up into two procs so you call the line creation directly.

Upon checking, she doesn't even use this 😿

Comment on lines +367 to +378
/obj/item/proc/is_scary_weapon() // NPCs don't like seeing scary weapons
if(istype(src, /obj/item/instrument))
return FALSE
if(force > 20)
return TRUE
var/obj/item/storage/belt/sheath/sword_sheath = astype(src, /obj/item/storage/belt/sheath)
var/obj/item/gun/ballistic/gun = astype(src, /obj/item/gun/ballistic)
if(sword_sheath)
return !isnull(sword_sheath.stored_blade)
if(gun)
return !isnull(gun.serial_type) // we check for a serial number so NPCs dont freak out over donksoft foam guns
return FALSE

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

two things here.
istype or astype checks of src like this here is flavcode/snowflaky and its really just better syntax to but it on the type itself so IT decides its own behavoir

more robust checks, if your checking a sheathe, check the blade inside of it instead of using the precense of a blade as being scary so wooden sticks dont count.
Im frankly uncertain we need a force check at all and instead should check if it needs a permit or is outwardly masquerade violating.

Suggested change
/obj/item/proc/is_scary_weapon() // NPCs don't like seeing scary weapons
if(istype(src, /obj/item/instrument))
return FALSE
if(force > 20)
return TRUE
var/obj/item/storage/belt/sheath/sword_sheath = astype(src, /obj/item/storage/belt/sheath)
var/obj/item/gun/ballistic/gun = astype(src, /obj/item/gun/ballistic)
if(sword_sheath)
return !isnull(sword_sheath.stored_blade)
if(gun)
return !isnull(gun.serial_type) // we check for a serial number so NPCs dont freak out over donksoft foam guns
return FALSE
/obj/item/proc/is_scary_weapon() // NPCs don't like seeing scary weapons
if(item_flags & NEEDS_PERMIT)
return TRUE
if(masquerade_violating)
return TRUE
return FALSE
/obj/item/instrument/is_scary_weapon()
return FALSE
/obj/item/storage/belt/sheath/is_scary_weapon()
return stored_blade?.is_scary_weapon()
/obj/item/gun/ballistic/is_scary_weapon()
// we check for a serial number so NPCs dont freak out over donksoft foam guns
// This is kinda mid tho and the lack of a serial number is a terrible check for "scary gun"
return !!serial_type
// What i will acctually suggest is removing it entirely in favor of checking for permit or masquerade violating instead.

Comment on lines +383 to +384
if(entered_job?.departments_bitflags & DEPARTMENT_BITFLAG_POLICE)
return 0 // dont call 911 on the police

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is something i've wanted to do for a minute but imo there should be a helper for "is this guy a cop visually" (ditto for doctors) that pools together there worn outfit as points towards if they count. the badge being the bulk of the check. allowing impersonation of a cop or punishing FULLY plainclothes cops is badass.

if(!warrant)
return
if(witnessed_crimes == 0)
to_chat(src, span_info("(APB) The police call off their search for you. You are no longer wanted."))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wtf does apb mean???

Comment on lines +1 to +10
SUBSYSTEM_DEF(police_gps)
name = "Police GPS"
wait = 5 MINUTES
priority = FIRE_PRIORITY_DEFAULT

var/list/wanted

/datum/controller/subsystem/police_gps/Initialize(start_timeofday)
wanted = list()
return SS_INIT_SUCCESS

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

???

Suggested change
SUBSYSTEM_DEF(police_gps)
name = "Police GPS"
wait = 5 MINUTES
priority = FIRE_PRIORITY_DEFAULT
var/list/wanted
/datum/controller/subsystem/police_gps/Initialize(start_timeofday)
wanted = list()
return SS_INIT_SUCCESS
SUBSYSTEM_DEF(police_gps)
name = "Police GPS"
wait = 5 MINUTES
ss_flags = SS_NO_INIT
priority = FIRE_PRIORITY_DEFAULT
var/list/wanted = list()

var/severity = check_criminal_violation(entered_mob)
if(!severity)
return
var/call_chance = severity - (entered_mob.st_get_stat(STAT_CHARISMA) + entered_mob.st_get_stat(STAT_INTIMIDATION))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

because this is just a flat prob, charaisma and intimidation have MUCH less impact then they really ought to. Consider making this an actual roll, likely one thats hidden however. That or multiply there values atleast a LITTLE.

Comment on lines +318 to +319
if(!istype(l_store, /obj/item/smartphone) && !istype(r_store, /obj/item/smartphone))
return

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see why there backpack wouldn't count..

Suggested change
if(!istype(l_store, /obj/item/smartphone) && !istype(r_store, /obj/item/smartphone))
return
if(!length(get_all_contents(/obj/item/smartphone)))
return

cut_overlays()
switch(target_dist)
if(0 to 1)
icon_state = "runed_sense2"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if we are really doing the cult/blood hunt tracker code, PLEASE find a better icon... I would be happier with codersprites that are vaguely radar pilled.

Comment on lines +331 to +337
var/list/worn = list()
if(H.head) worn += H.head
if(H.wear_suit) worn += H.wear_suit
if(H.w_uniform) worn += H.w_uniform
if(H.shoes) worn += H.shoes
if(length(worn))
clothing_desc = pick(worn):name

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seemed like it deserved expanded behavior. Sorry if this doesn't compile on the first try..

Suggested change
var/list/worn = list()
if(H.head) worn += H.head
if(H.wear_suit) worn += H.wear_suit
if(H.w_uniform) worn += H.w_uniform
if(H.shoes) worn += H.shoes
if(length(worn))
clothing_desc = pick(worn):name
var/list/worn = list()
var/list/visible_items = H.get_visible_items()
for(var/obj/item/worn_item in H.get_equipped_items())
if(worn_item in H.visible_items())
var/importance = 1
if(worn_item in (H.head + H.wear_suit + H.w_uniform))
importance = 5
worn[worn_item] = importance
var/list/seen_items = list()
var/items_to_spot = rand(1, st_get_stat(STAT_PERCEPTION))
for(var/i in 1 to items_to_spot)
if(!length(worn))
break
var/obj/item/picked_item = pick_weight(worn)
worn[picked_item] = null
seen_items += picked_item
if(length(seen_items))
clothing_desc = english_list(seen_items)

if(H)
H.witnessed_crimes += 1
addtimer(CALLBACK(H, TYPE_PROC_REF(/mob/living/carbon/human, remove_crime_stack)), 1 MINUTES)
if(H.witnessed_crimes >= 10 && !H.warrant)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this code seems to ignore ignores_warrant
tho in general we could stand to genercize this with how our other code displays crimes...

Image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants