Files
VOREStation/code/modules/flufftext/fake_attacker.dm
T
84dc5535dc var/global/list -> GLOB. conversion (#17928)
* These two are easy

* !!!runlevel_flags

the fact it was global.runlevel_flags.len has me a bit...iffy on this.

* !!!json_cache

Same as above. used global.

* player_list & observer_mob_list

* mechas_list

* this wasn't even used

* surgery_steps

* event_triggers

* landmarks_list

* dead_mob_list

* living_mob_list

* ai_list

* cable_list

* cleanbot_reserved_turfs

* listening_objects

* silicon_mob_list

* human_mob_list

* Update global_lists.dm

* joblist

* mob_list

* Update global_lists.dm

* holomap_markers

* mapping_units

* mapping_beacons

* hair_styles_list

* facial_hair_styles_list

* Update global_lists.dm

* facial_hair_styles_male_list

* facial_hair_styles_female_list

* body_marking_styles_list

* body_marking_nopersist_list

* ear_styles_list

* hair_styles_male_list

* tail_styles_list

* wing_styles_list

* escape_list & rune_list & endgame_exits

these were all really small

* endgame_safespawns

* stool_cache

* emotes_by_key

* random_maps & map_count

* item_tf_spawnpoints

* narsie_list

* active_radio_jammers

* unused

* paikeys

* pai_software_by_key & default_pai_software

* plant_seed_sprites

* magazine_icondata_keys  & magazine_icondata_states

* unused

* ashtray_cache

* light_type_cache

* HOLIDAY!!!

this one was annoying

* faction stuff (red?!)

* Update preferences_factions.dm

* vs edit removal

* backbaglist, pdachoicelist, exclude_jobs

* item_digestion_blacklist, edible_tech, blacklisted_artifact_effect, selectable_footstep, hexNums, syndicate_access

* string_slot_flags and hexdigits->hexNums

* possible_changeling_IDs

* vr_mob_tf_options

* vr_mob_spawner_options

* pipe_colors

* vr_mob_spawner_options

* common_tools

* newscaster_standard_feeds

* Update periodic_news.dm

* changeling_fabricated_clothing

* semirandom_mob_spawner_decisions

* id_card_states

* Update syndicate_ids.dm

* overlay_cache & gear_distributed_to

* more

* radio_channels_by_freq

* Update global_lists.dm

* proper

* default_medbay_channels & default_internal_channels

default_internal_channels is weird as it has a mapbased proc() but that proc is never called...

* valid_ringtones

* move this

* possible_plants

* more

* separate these

moves xeno2chemlist from a hook to a new global list.

* tube_dir_list

* valid_bloodreagents & monitor_states

* Junk

* valid_bloodtypes

* breach_burn_descriptors & burn

* more!!

appliance_available_recipes seems uber cursed, re-look at later

* Appliance code is cursed

* wide_chassis & flying_chassis

* allows_eye_color

* all_tooltip_styles

* direction_table

* gun_choices

* severity_to_string

* old event_viruses

* description_icons

* MOVE_KEY_MAPPINGS

* more more

* pai & robot modules

* Update global_lists.dm

* GEOSAMPLES

Also swaps a .len to LAZYLEN()

* shieldgens

* reagent recipies

* global ammo types

* rad collector

* old file and unused global

* nif_look_messages

* FESH

* nifsoft

* chamelion

* the death of sortAtom

* globulins

* lazylen that

* Update global_lists.dm

* LAZY

* Theese too

* quick fix

---------

Co-authored-by: Kashargul <144968721+Kashargul@users.noreply.github.com>
2025-07-14 20:14:31 +02:00

221 lines
6.5 KiB
Plaintext

/obj/effect/fake_attacker // I did want to use /image/client_only but this needs to be somewhat more complex
name = ""
desc = ""
density = FALSE
anchored = TRUE
opacity = 0
VAR_PRIVATE/list/clients = list()
VAR_PRIVATE/list/image/dir_images = list()
/obj/effect/fake_attacker/process()
. = ..()
// Passive cleanup
for(var/datum/weakref/C in clients)
var/client/CW = C?.resolve()
if(isnull(CW))
clients.Remove(C)
if(!clients.len)
qdel(src)
/obj/effect/fake_attacker/set_dir(newdir)
if(!(newdir in GLOB.cardinal))
newdir &= ~(EAST|WEST) // Don't allow diagonals, prefer north/south
if(!newdir)
newdir = SOUTH
var/updatesprite = (dir != newdir)
. = ..()
if(updatesprite)
for(var/datum/weakref/C in clients)
var/client/CW = C?.resolve()
clear_images_from_client(CW)
assign_image_to_client(CW)
/obj/effect/fake_attacker/Moved(atom/old_loc, direction, forced, movetime)
. = ..()
var/turf_move = isturf(loc) && isturf(old_loc)
for(var/img in dir_images)
var/image/G = dir_images[img]
G.loc = loc
if(turf_move)
var/MT = 0.7 SECONDS
G.pixel_x = (old_loc.x - loc.x) * WORLD_ICON_SIZE
G.pixel_y = (old_loc.y - loc.y) * WORLD_ICON_SIZE
animate(G, pixel_x = 0, time = MT, flags = ANIMATION_PARALLEL)
animate(G, pixel_y = 0, time = MT, flags = ANIMATION_PARALLEL)
/obj/effect/fake_attacker/Destroy(force)
. = ..()
clear_every_clients_images()
qdel_all_images()
/obj/effect/fake_attacker/proc/create_images_from(var/atom/clone)
SHOULD_NOT_OVERRIDE(TRUE)
dir_images["[NORTH]"] = image(clone,dir = NORTH)
dir_images["[SOUTH]"] = image(clone,dir = SOUTH)
dir_images["[EAST]"] = image(clone,dir = EAST)
dir_images["[WEST]"] = image(clone,dir = WEST)
for(var/img in dir_images)
var/image/G = dir_images[img]
G.layer = clone.layer
G.plane = clone.plane
G.appearance_flags = clone.appearance_flags
G.mouse_opacity = MOUSE_OPACITY_TRANSPARENT
G.loc = loc
/obj/effect/fake_attacker/proc/append_client(var/client/C)
SHOULD_NOT_OVERRIDE(TRUE)
clients.Add(WEAKREF(C))
assign_image_to_client(C)
/obj/effect/fake_attacker/proc/assign_image_to_client(var/client/C)
PRIVATE_PROC(TRUE)
SHOULD_NOT_OVERRIDE(TRUE)
if(!C)
return
if(!dir_images.len)
return
var/image/I = dir_images["[dir]"]
if(I)
C.images += I
/obj/effect/fake_attacker/proc/clear_every_clients_images()
for(var/datum/weakref/C in clients)
clear_images_from_client(C?.resolve())
/obj/effect/fake_attacker/proc/clear_images_from_client(var/client/C)
PRIVATE_PROC(TRUE)
SHOULD_NOT_OVERRIDE(TRUE)
if(!C)
return
if(!dir_images.len)
return
for(var/img in dir_images)
C.images -= dir_images[img]
/obj/effect/fake_attacker/proc/qdel_all_images()
PRIVATE_PROC(TRUE)
SHOULD_NOT_OVERRIDE(TRUE)
for(var/img in dir_images)
qdel_null(dir_images[img])
dir_images.Cut()
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Hallucination attackers with AI behaviors
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
/mob/proc/create_hallucination_attacker(var/turf/T = null,var/mob/living/carbon/human/clone = null, var/forced_type = null)
SHOULD_NOT_OVERRIDE(TRUE)
if(!client)
return null
if(!clone)
// Get a randomized clone from the living mob's list, must be standing
var/list/possible_clones = new/list()
for(var/mob/living/carbon/human/H in GLOB.living_mob_list)
if(H.stat || H.lying)
continue
possible_clones += H
if(!possible_clones.len)
return null
clone = pick(possible_clones)
if(!clone)
return null
if(!T)
// Get the target's turf, then make some random steps to get away from them, respecting walls
T = get_turf(clone)
var/turf/CT = T
for(var/i = 0 to 8)
if(!CT) // Emergency exit
return null
var/Cdir = pick(GLOB.cardinal)
if(prob(30))
Cdir = clone.dir // Results in hallucinations somewhat being in front of you
var/turf/NT = get_step(CT,Cdir)
if(NT && !NT.density)
CT = NT
T = CT
if(!forced_type)
// Picking from all available options
var/list/get_types = subtypesof(/obj/effect/fake_attacker/human)
forced_type = pick(get_types)
// Finally! After a thousand years I'm finally free to conquer EARTH!
return new forced_type(T,src,clone)
/obj/effect/fake_attacker/human
VAR_PROTECTED/datum/weakref/target = null
var/requires_hallucinating = TRUE // Mob will qdel if the target is not hallucinating if this is true
/obj/effect/fake_attacker/human/Initialize(mapload,var/mob/targeting_mob,var/atom/clone_appearance_from)
. = ..()
START_PROCESSING(SSobj, src)
set_target(targeting_mob)
create_images_from(clone_appearance_from)
append_client(targeting_mob.client)
name = clone_appearance_from.name
// Usually we want to face our target for maximum spooky effect
set_dir(get_dir(src,targeting_mob))
/obj/effect/fake_attacker/human/Destroy()
STOP_PROCESSING(SSobj, src)
. = ..()
/obj/effect/fake_attacker/human/process()
// check if valid
var/mob/living/M = target?.resolve()
if(!M)
qdel(src)
return null
if(requires_hallucinating)
if(!ishuman(M))
qdel(src)
return null
var/mob/living/carbon/human/H = M
if(!H.hallucination)
qdel(src)
return null
return M
/obj/effect/fake_attacker/human/proc/set_target(var/mob/M)
target = WEAKREF(M)
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Attacker: Performs hostile shoves and attacks
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
/obj/effect/fake_attacker/human/attacker/process()
var/mob/living/M = ..()
if(get_dist(src,M) > 1)
step_towards(src,M)
else if(prob(15))
M << sound(pick('sound/weapons/punch1.ogg','sound/weapons/punch2.ogg','sound/weapons/punch3.ogg','sound/weapons/punch4.ogg'))
M.show_message(span_bolddanger("\The [src] has punched \the [M]!"), 1)
M.halloss += 4
if(prob(15))
step_away(src,M)
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Fleeing: Runs away when you get close
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
/obj/effect/fake_attacker/human/fleeing
VAR_PRIVATE/flee = FALSE
/obj/effect/fake_attacker/human/fleeing/process()
var/mob/living/M = ..()
set_dir(get_dir(src,M))
if(get_dist(src,M) < 6 || flee)
flee = TRUE
step_away(src,M)
if(get_dist(src,M) > 10 || get_dist(src,M) < 2 || (flee && prob(10)))
target = null
qdel(src)