Skip to content

Commit

Permalink
[MIRROR] Certain ID trims affect secbot response [MDB IGNORE] (#25360) (
Browse files Browse the repository at this point in the history
#913)

* Certain ID trims affect secbot response (#79980)

## About The Pull Request

A prior refactor of how ID cards worked removed (without commentary?)
the long-previously-existing behaviour that Agent IDs cause a
subtraction from the level of suspicion that security bots see from you.
I have not only restored this behaviour, but applied it to a handful of
other ID cards (based on trim).

When Beepsky looks at you he will make an assessment based on various
factors controlled by his bot settings:

- If Beepsky is set to check ID and your identity is concealed (you
appear as "Unknown") add 4 points.
- If Beepsky is set to check Weapons and you are holding a restricted
weapon without a permit, add 4 points.
- If Beepsky is set to check Weapons and you are wearing a restricted
weapon on your belt or back without a permit, add 2 points.
- If Beepsky is set to check records and you are set to Arrest, add 5
points.
- If Beepsky is set to check records and you have some other
non-innocent status, add 2 points.
- If you are wearing a wizard's hat, add 2 points.
- If you are not human, add 1 point (police are racist).
- If you are loyalty implanted, subtract 1 point.

Factors added or restored in this PR based on your ID now are:

- If you are wearing an Agent ID, subtract 5 points.
- If you are wearing a Cybercop ID, subtract 1 point.
- If you are wearing a Centcomm ID, subtract 10 points.
- If you are wearing an Admin ID, subtract infinite points.
- If you are wearing a prisoner ID, add 1 point.
- If you are wearing a Syndicate or Battlecruiser ID, add 5 or 10
points.

If Beepsky is _emagged_ then he will view all targets as having 10
threat, regardless of their ID card.
If you complete this process with >4 points he will attempt to arrest
you.

The upshot of my changes are:
Wearing an Agent ID card will cause Beepsky to overlook the fact that
you are carrying a gun in your hands without a permit, unless you are
also set to arrest.
Wearing an Agent ID card will cause Beepsky to overlook the fact that
you are set to arrest, unless you are carrying a gun in your hands.
Wearing a prisoner ID while not human will cause Beepsky to try and
arrest you if you have a weapon on your belt or back (if he is set to
care about weapons permits or unless you have one).
Wearing a centcomm ID card will cause Beepsky to treat you as above the
law in basically all circumstances, up to and including when you try and
beat him to death. He will simply sit there and take it.

In addition to this, this information forwarded to AI is now also
available to player secbots upon examine.
Players can't become secbots very easily because you can't upload PAIs
into them or enable their sentience in the panel, but it sometimes
happens via random event or admin intervention.

## Why It's Good For The Game

I think this was removed by mistake? It wasn't included in the changelog
and everyone I talked to thought it was still true.
It's a fun feature which makes agent IDs marginally more useful.
I think Beepsky and pals judging you based on your job makes sense, even
if it is mostly applied to fluff roles.

## Changelog

:cl:
add: Agent IDs once more trick Beepsky into treating you more leniently.
add: Prisoner IDs make Beepsky treat you somewhat more suspiciously, as
do Syndicate IDs. Wearing a Centcomm ID means that Beepsky is aware that
you are above the law.
add: Player-controlled security bots can view someone's assessed threat
level by examining them.
/:cl:

* Certain ID trims affect secbot response

* Quick pass on Skyrat based ID_trims

---------

Co-authored-by: SkyratBot <[email protected]>
Co-authored-by: Jacquerel <[email protected]>
Co-authored-by: SomeRandomOwl <[email protected]>
  • Loading branch information
4 people authored Dec 2, 2023
1 parent 6c93d22 commit 10fa406
Show file tree
Hide file tree
Showing 20 changed files with 106 additions and 45 deletions.
2 changes: 2 additions & 0 deletions code/__DEFINES/dcs/signals/signals_mob/signals_mob_main.dm
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,8 @@
#define COMSIG_MOB_ATTACK_ALIEN "mob_attack_alien"
///from base of /mob/throw_item(): (atom/target)
#define COMSIG_MOB_THROW "mob_throw"
///from base of /mob/verb/examinate(): (atom/target, list/examine_strings)
#define COMSIG_MOB_EXAMINING "mob_examining"
///from base of /mob/verb/examinate(): (atom/target)
#define COMSIG_MOB_EXAMINATE "mob_examinate"
///from /mob/living/handle_eye_contact(): (mob/living/other_mob)
Expand Down
5 changes: 5 additions & 0 deletions code/__DEFINES/robots.dm
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,11 @@ GLOBAL_LIST_EMPTY(cyborg_all_models_icon_list)
#define JUDGE_WEAPONCHECK (1<<2)
#define JUDGE_RECORDCHECK (1<<3)

/// Above this level of assessed threat, Beepsky will attack you
#define THREAT_ASSESS_DANGEROUS 4
/// Above this level of assessed threat, you are extremely threatening
#define THREAT_ASSESS_MAXIMUM 10

//SecBOT defines on arresting
///Whether arrests should be broadcasted over the Security radio
#define SECBOT_DECLARE_ARRESTS (1<<0)
Expand Down
38 changes: 38 additions & 0 deletions code/datums/components/security_vision.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/// This component allows you to judge someone's level of criminal activity by examining them
/datum/component/security_vision
/// Bitfield containing what things we want to judge based upon
var/judgement_criteria
/// Optional callback which will modify the value of `judgement_criteria` before we make the check
var/datum/callback/update_judgement_criteria

/datum/component/security_vision/Initialize(judgement_criteria, datum/callback/update_judgement_criteria)
. = ..()
if (!ismob(parent))
return COMPONENT_INCOMPATIBLE
src.judgement_criteria = judgement_criteria
src.update_judgement_criteria = update_judgement_criteria

/datum/component/security_vision/RegisterWithParent()
RegisterSignal(parent, COMSIG_MOB_EXAMINING, PROC_REF(on_examining))

/datum/component/security_vision/UnregisterFromParent()
UnregisterSignal(parent, COMSIG_MOB_EXAMINING)

/// When we examine something, check if we have any extra data to add
/datum/component/security_vision/proc/on_examining(mob/source, atom/target, list/examine_strings)
SIGNAL_HANDLER
if (!isliving(target))
return
var/mob/living/perp = target
judgement_criteria = update_judgement_criteria?.Invoke() || judgement_criteria

var/threat_level = perp.assess_threat(judgement_criteria)
switch(threat_level)
if (THREAT_ASSESS_MAXIMUM to INFINITY)
examine_strings += span_boldwarning("Assessed threat level of [threat_level]! Extreme danger of criminal activity!")
if (THREAT_ASSESS_DANGEROUS to THREAT_ASSESS_MAXIMUM)
examine_strings += span_warning("Assessed threat level of [threat_level]. Criminal scum detected!")
if (1 to THREAT_ASSESS_DANGEROUS)
examine_strings += span_notice("Assessed threat level of [threat_level]. Probably not dangerous... yet.")
else
examine_strings += span_notice("Seems to be a trustworthy individual.")
2 changes: 2 additions & 0 deletions code/datums/id_trim/_id_trim.dm
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
var/intern_alt_name = null
/// The icon_state associated with this trim, as it will show on the security HUD.
var/sechud_icon_state = SECHUD_UNKNOWN
/// How threatened does a security bot feel when scanning this ID? A negative value may cause them to forgive things which would otherwise cause aggro.
var/threat_modifier = 0

/// Accesses that this trim unlocks on a card it is imprinted on. These accesses never take wildcard slots and can be added and removed at will.
var/list/access = list()
Expand Down
2 changes: 2 additions & 0 deletions code/datums/id_trim/admin.dm
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
trim_state = "trim_janitor"
department_color = COLOR_CENTCOM_BLUE
subdepartment_color = COLOR_SERVICE_LIME
threat_modifier = -INFINITY

/datum/id_trim/admin/New()
. = ..()
// Every single access in the game, all on one handy trim.
Expand Down
1 change: 1 addition & 0 deletions code/datums/id_trim/centcom.dm
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
sechud_icon_state = SECHUD_CENTCOM
department_color = COLOR_CENTCOM_BLUE
subdepartment_color = COLOR_CENTCOM_BLUE
threat_modifier = -10 // Centcom are legally allowed to do whatever they want

/// Trim for Centcom VIPs
/datum/id_trim/centcom/vip
Expand Down
1 change: 1 addition & 0 deletions code/datums/id_trim/jobs.dm
Original file line number Diff line number Diff line change
Expand Up @@ -775,6 +775,7 @@
ACCESS_HOS,
)
job = /datum/job/prisoner
threat_modifier = 1 // I'm watching you

/datum/id_trim/job/prisoner/one
trim_state = "trim_prisoner_1"
Expand Down
1 change: 1 addition & 0 deletions code/datums/id_trim/outfits.dm
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@
trim_state = "trim_deathcommando"
department_color = COLOR_BLACK
subdepartment_color = COLOR_GREEN
threat_modifier = -1 // Cops recognise cops

/datum/id_trim/cyber_police/New()
. = ..()
Expand Down
3 changes: 3 additions & 0 deletions code/datums/id_trim/syndicate.dm
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
subdepartment_color = COLOR_SYNDIE_RED
sechud_icon_state = SECHUD_SYNDICATE
access = list(ACCESS_SYNDICATE)
threat_modifier = 5 // Bad guy on deck

/// Trim for Syndicate mobs, outfits and corpses.
/datum/id_trim/syndicom/crew
Expand Down Expand Up @@ -53,6 +54,7 @@
assignment = "Syndicate Battlecruiser Crew"
trim_state = "trim_syndicate"
access = list(ACCESS_SYNDICATE)
threat_modifier = 10

/// Trim for Syndicate mobs, outfits and corpses.
/datum/id_trim/battlecruiser/captain
Expand All @@ -63,6 +65,7 @@
/datum/id_trim/chameleon
assignment = "Unknown"
access = list(ACCESS_SYNDICATE, ACCESS_MAINT_TUNNELS)
threat_modifier = -5 // This guy seems legit

/// Trim for Chameleon ID cards. Many outfits, nuke ops and some corpses hold Chameleon ID cards.
/datum/id_trim/chameleon/operative
Expand Down
3 changes: 3 additions & 0 deletions code/modules/mob/living/basic/trooper/nanotrasen.dm
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
loot = list(/obj/effect/mob_spawn/corpse/human/nanotrasensoldier)
mob_spawner = /obj/effect/mob_spawn/corpse/human/nanotrasensoldier

/mob/living/basic/trooper/nanotrasen/assess_threat(judgement_criteria, lasercolor, datum/callback/weaponcheck)
return -10 // Respect our troops

/// A variant that calls for reinforcements on spotting a target
/mob/living/basic/trooper/nanotrasen/screaming
ai_controller = /datum/ai_controller/basic_controller/trooper/calls_reinforcements
Expand Down
16 changes: 10 additions & 6 deletions code/modules/mob/living/carbon/human/human.dm
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,8 @@
var/obj/item/bodypart/the_part = isbodypart(target_zone) ? target_zone : get_bodypart(check_zone(target_zone)) //keep these synced
to_chat(user, span_alert("There is no exposed flesh or thin material on [p_their()] [the_part.name]."))

#define CHECK_PERMIT(item) (item && item.item_flags & NEEDS_PERMIT)

/mob/living/carbon/human/assess_threat(judgement_criteria, lasercolor = "", datum/callback/weaponcheck=null)
if(judgement_criteria & JUDGE_EMAGGED)
return 10 //Everyone is a criminal!
Expand Down Expand Up @@ -411,16 +413,17 @@

//Check for ID
var/obj/item/card/id/idcard = get_idcard(FALSE)
if( (judgement_criteria & JUDGE_IDCHECK) && !idcard && name == "Unknown")
threatcount += idcard?.trim.threat_modifier || 0
if((judgement_criteria & JUDGE_IDCHECK) && isnull(idcard) && name == "Unknown")
threatcount += 4

//Check for weapons
if( (judgement_criteria & JUDGE_WEAPONCHECK) && weaponcheck)
if(!idcard || !(ACCESS_WEAPONS in idcard.access))
for(var/obj/item/I in held_items) //if they're holding a gun
if(weaponcheck.Invoke(I))
if((judgement_criteria & JUDGE_WEAPONCHECK))
if(isnull(idcard) || !(ACCESS_WEAPONS in idcard.access))
for(var/obj/item/toy_gun in held_items) //if they're holding a gun
if(CHECK_PERMIT(toy_gun))
threatcount += 4
if(weaponcheck.Invoke(belt) || weaponcheck.Invoke(back)) //if a weapon is present in the belt or back slot
if(CHECK_PERMIT(belt) || CHECK_PERMIT(back)) //if a weapon is present in the belt or back slot
threatcount += 2 //not enough to trigger look_for_perp() on it's own unless they also have criminal status.

//Check for arrest warrant
Expand Down Expand Up @@ -454,6 +457,7 @@

return threatcount

#undef CHECK_PERMIT

//Used for new human mobs created by cloning/goleming/podding
/mob/living/carbon/human/proc/set_cloned_appearance()
Expand Down
30 changes: 13 additions & 17 deletions code/modules/mob/living/simple_animal/bot/SuperBeepsky.dm
Original file line number Diff line number Diff line change
Expand Up @@ -117,25 +117,21 @@
if((C.name == oldtarget_name) && (world.time < last_found + 100))
continue

threatlevel = C.assess_threat(judgement_criteria, weaponcheck=CALLBACK(src, PROC_REF(check_for_weapons)))
threatlevel = C.assess_threat(judgement_criteria)

if(!threatlevel)
continue

else if(threatlevel >= 4)
target = C
oldtarget_name = C.name
speak("Level [threatlevel] infraction alert!")
playsound(src, pick('sound/voice/beepsky/criminal.ogg', 'sound/voice/beepsky/justice.ogg', 'sound/voice/beepsky/freeze.ogg'), 50, FALSE)
playsound(src,'sound/weapons/saberon.ogg',50,TRUE,-1)
visible_message(span_warning("[src] ignites his energy swords!"))
icon_state = "grievous-c"
visible_message("<b>[src]</b> points at [C.name]!")
mode = BOT_HUNT
INVOKE_ASYNC(src, PROC_REF(handle_automated_action))
break
else
if (threatlevel < THREAT_ASSESS_DANGEROUS)
continue
target = C
oldtarget_name = C.name
speak("Level [threatlevel] infraction alert!")
playsound(src, pick('sound/voice/beepsky/criminal.ogg', 'sound/voice/beepsky/justice.ogg', 'sound/voice/beepsky/freeze.ogg'), 50, FALSE)
playsound(src,'sound/weapons/saberon.ogg',50,TRUE,-1)
visible_message(span_warning("[src] ignites his energy swords!"))
icon_state = "grievous-c"
visible_message("<b>[src]</b> points at [C.name]!")
mode = BOT_HUNT
INVOKE_ASYNC(src, PROC_REF(handle_automated_action))
break

/mob/living/simple_animal/bot/secbot/grievous/explode()
var/atom/Tsec = drop_location()
Expand Down
4 changes: 2 additions & 2 deletions code/modules/mob/living/simple_animal/bot/ed209bot.dm
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@
var/threatlevel = 0
if(nearby_carbon.incapacitated())
continue
threatlevel = nearby_carbon.assess_threat(judgement_criteria, weaponcheck=CALLBACK(src, PROC_REF(check_for_weapons)))
if(threatlevel < 4 )
threatlevel = nearby_carbon.assess_threat(judgement_criteria)
if(threatlevel < THREAT_ASSESS_DANGEROUS)
continue
var/dst = get_dist(src, nearby_carbon)
if(dst <= 1 || dst > 7)
Expand Down
36 changes: 17 additions & 19 deletions code/modules/mob/living/simple_animal/bot/secbot.dm
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@
COMSIG_ATOM_ENTERED = PROC_REF(on_entered),
)
AddElement(/datum/element/connect_loc, loc_connections)
AddComponent(/datum/component/security_vision, judgement_criteria = NONE, update_judgement_criteria = CALLBACK(src, PROC_REF(judgement_criteria)))

/mob/living/simple_animal/bot/secbot/Destroy()
QDEL_NULL(weapon)
Expand Down Expand Up @@ -195,11 +196,14 @@

/mob/living/simple_animal/bot/secbot/proc/retaliate(mob/living/carbon/human/attacking_human)
var/judgement_criteria = judgement_criteria()
threatlevel = attacking_human.assess_threat(judgement_criteria, weaponcheck = CALLBACK(src, PROC_REF(check_for_weapons)))
threatlevel = attacking_human.assess_threat(judgement_criteria)
threatlevel += 6
if(threatlevel >= 4)
if(threatlevel >= THREAT_ASSESS_DANGEROUS)
target = attacking_human
mode = BOT_HUNT
if(threatlevel < 0 && prob(5))
manual_emote("salutes.")
speak("Thank you sir.")

/mob/living/simple_animal/bot/secbot/proc/judgement_criteria()
var/final = FALSE
Expand Down Expand Up @@ -329,11 +333,11 @@
current_target.set_stutter(10 SECONDS)
current_target.Paralyze(60) // SKYRAT EDIT CHANGE - original was current_target.Paralyze(100)
var/mob/living/carbon/human/human_target = current_target
threat = human_target.assess_threat(judgement_criteria, weaponcheck = CALLBACK(src, PROC_REF(check_for_weapons)))
threat = human_target.assess_threat(judgement_criteria)
else
current_target.Paralyze(60) // SKYRAT EDIT CHANGE - original was current_target.Paralyze(100)
current_target.set_stutter(10 SECONDS)
threat = current_target.assess_threat(judgement_criteria, weaponcheck = CALLBACK(src, PROC_REF(check_for_weapons)))
threat = current_target.assess_threat(judgement_criteria)

log_combat(src, current_target, "stunned")
if(security_mode_flags & SECBOT_DECLARE_ARRESTS)
Expand Down Expand Up @@ -457,30 +461,24 @@
if((nearby_carbons.name == oldtarget_name) && (world.time < last_found + 100))
continue

threatlevel = nearby_carbons.assess_threat(judgement_criteria, weaponcheck = CALLBACK(src, PROC_REF(check_for_weapons)))
threatlevel = nearby_carbons.assess_threat(judgement_criteria)

if(!threatlevel)
if(threatlevel < THREAT_ASSESS_DANGEROUS)
continue

if(threatlevel >= 4)
target = nearby_carbons
oldtarget_name = nearby_carbons.name
threat_react(threatlevel)
visible_message("<b>[src]</b> points at [nearby_carbons.name]!")
mode = BOT_HUNT
INVOKE_ASYNC(src, PROC_REF(handle_automated_action))
break
target = nearby_carbons
oldtarget_name = nearby_carbons.name
threat_react(threatlevel)
visible_message("<b>[src]</b> points at [nearby_carbons.name]!")
mode = BOT_HUNT
INVOKE_ASYNC(src, PROC_REF(handle_automated_action))
break

/// React to detecting criminal scum by making some kind of noise
/mob/living/simple_animal/bot/secbot/proc/threat_react(threatlevel)
speak("Level [threatlevel] infraction alert!")
playsound(src, pick('sound/voice/beepsky/criminal.ogg', 'sound/voice/beepsky/justice.ogg', 'sound/voice/beepsky/freeze.ogg'), 50, FALSE)

/mob/living/simple_animal/bot/secbot/proc/check_for_weapons(obj/item/slot_item)
if(slot_item && (slot_item.item_flags & NEEDS_PERMIT))
return TRUE
return FALSE

/mob/living/simple_animal/bot/secbot/explode()
var/atom/Tsec = drop_location()
switch(bot_type)
Expand Down
2 changes: 1 addition & 1 deletion code/modules/mob/mob.dm
Original file line number Diff line number Diff line change
Expand Up @@ -609,6 +609,7 @@
result += span_notice("<i>You examine [examinify] closer, but find nothing of interest...</i>")
else
result = examinify.examine(src)
SEND_SIGNAL(src, COMSIG_MOB_EXAMINING, examinify, result)
client.recent_examines[ref_to_atom] = world.time // set to when we last normal examine'd them
addtimer(CALLBACK(src, PROC_REF(clear_from_recent_examines), ref_to_atom), RECENT_EXAMINE_MAX_WINDOW)
handle_eye_contact(examinify)
Expand All @@ -630,7 +631,6 @@
to_chat(src, examine_block("<span class='infoplain'>[result.Join()]</span>"))
SEND_SIGNAL(src, COMSIG_MOB_EXAMINATE, examinify)


/mob/proc/blind_examine_check(atom/examined_thing)
return TRUE //The non-living will always succeed at this check.

Expand Down
1 change: 1 addition & 0 deletions modular_skyrat/master_files/code/datums/id_trim/solfed.dm
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
department_color = COLOR_SOLFED_GOLD
subdepartment_color = COLOR_SOLFED_GOLD
sechud_icon_state = SECHUD_SOLFED
threat_modifier = -5 // Solfed Count as a police force

/datum/id_trim/solfed/atmos/New()
. = ..()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
trim_state = "trim_unknown"
department_color = COLOR_ASSEMBLY_BLACK
subdepartment_color = COLOR_SYNDIE_RED
threat_modifier = 5 // Matching the syndicate threat level since DS2 is a syndicate station.

/datum/id_trim/syndicom/skyrat/ds2/prisoner
trim_icon = 'modular_skyrat/master_files/icons/obj/card.dmi' // I can't put this on the basetype AAAAAA
Expand Down
1 change: 1 addition & 0 deletions modular_skyrat/modules/encounters/code/nri_raiders.dm
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ GLOBAL_VAR(first_officer)
subdepartment_color = COLOR_NRI_POLICE_SILVER
sechud_icon_state = "hud_nri_police"
access = list(ACCESS_SYNDICATE, ACCESS_MAINT_TUNNELS)
threat_modifier = 2 // Not as treatening as syndicate, but still potentially harmful to the station

/obj/item/gun/energy/e_gun/advtaser/normal
w_class = WEIGHT_CLASS_NORMAL
Expand Down
1 change: 1 addition & 0 deletions modular_skyrat/modules/novaya_ert/code/id.dm
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
department_color = COLOR_RED_LIGHT
subdepartment_color = COLOR_COMMAND_BLUE
sechud_icon_state = "hud_nri"
threat_modifier = 2 // Matching the nri_police threat modifier

/datum/id_trim/nri/New()
. = ..()
Expand Down
1 change: 1 addition & 0 deletions tgstation.dme
Original file line number Diff line number Diff line change
Expand Up @@ -1224,6 +1224,7 @@
#include "code\datums\components\scope.dm"
#include "code\datums\components\seclight_attachable.dm"
#include "code\datums\components\sect_nullrod_bonus.dm"
#include "code\datums\components\security_vision.dm"
#include "code\datums\components\seethrough.dm"
#include "code\datums\components\seethrough_mob.dm"
#include "code\datums\components\shell.dm"
Expand Down

0 comments on commit 10fa406

Please sign in to comment.