mirror of
https://github.com/CHOMPStation2/CHOMPStation2.git
synced 2025-12-30 12:04:08 +00:00
221 lines
6.5 KiB
Plaintext
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)
|