From a67f8798a3f678a4ecc9a6ee8995eb4a7f275f5c Mon Sep 17 00:00:00 2001 From: ShiftyRail <31417754+ShiftyRail@users.noreply.github.com> Date: Wed, 25 Mar 2020 20:20:29 +0100 Subject: [PATCH] Tracker for projectiles (#26026) --- code/datums/datumvars.dm | 43 +++++++++++++++++++++++ code/game/atoms_movable.dm | 42 +++++++++++++++++++++++ code/modules/admin/admin.dm | 14 ++++++++ code/modules/admin/admin_verbs.dm | 11 +++++- code/modules/admin/topic.dm | 24 +++++++++++++ code/modules/events/immovablerod.dm | 36 ++++++++++++++++++++ code/modules/projectiles/projectile.dm | 47 ++++++++++++++++++++++++++ 7 files changed, 216 insertions(+), 1 deletion(-) diff --git a/code/datums/datumvars.dm b/code/datums/datumvars.dm index d86c38401b3..b3f5a8021c4 100644 --- a/code/datums/datumvars.dm +++ b/code/datums/datumvars.dm @@ -133,6 +133,7 @@ if(istype(D,/atom/movable)) body += "" + body += "" if(istype(D,/atom)) body += "" @@ -834,6 +835,48 @@ function loadPage(list) { A.alpha = 0 animate(A, alpha = 255, time = stealthy_level) + else if(href_list["throw_a_fucking_rod_at_it"]) + if(!check_rights(R_FUN)) + to_chat(usr, "You do not have sufficient permissions to do this.") + return + + var/atom/movable/A = locate(href_list["throw_a_fucking_rod_at_it"]) + if(!istype(A)) + to_chat(usr, "This can only be done to instances of movable atoms.") + return + + var/rod_size = input("What type of rod do you want to throw?","Throwing an Immovable Rod",null) as null|anything in list("Normal", "Pillar", "Monolith") + var/rod_type + + if (!rod_size) + return + + switch (rod_size) + if ("Normal") + rod_type = /obj/item/projectile/immovablerod + if ("Pillar") + rod_type = /obj/item/projectile/immovablerod/big + if ("Monolith") + rod_type = /obj/item/projectile/immovablerod/hyper + + if(alert("Are you sure you want to do this?","Confirm","Yes","No") != "Yes") + return + + var/obj/item/projectile/immovablerod/rod = new rod_type(random_start_turf(A.z)) + rod.tracking = TRUE + rod.throw_at(A) + + var/log_data = "[A]" + if (ismob(A)) + var/mob/M = A + if (M.client) + log_data += " ([M.client.ckey])" + + log_admin("[key_name(usr)] threw a rod at [log_data].") + message_admins("[key_name(usr)] threw a rod at [log_data].") + to_chat(usr, "If you changed your mind, you can always stop the tracking by using the verb 'VIEW-ALL-RODS' and click the 'Untrack' link.") + return + else if(href_list["teleport_to"]) if(!check_rights(0)) return diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index 038e8109d06..8984057f892 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -57,6 +57,8 @@ var/last_explosion_push = 0 + var/list/datum/tracker/trackers = list() + /atom/movable/New() . = ..() if((flags & HEAR) && !ismob(src)) @@ -1060,3 +1062,43 @@ forceMove(F) return TRUE return FALSE + +// -- trackers + +/atom/movable/proc/add_tracker(var/datum/tracker/T) + on_moved.Add(T, "recieve_position") + +/datum/tracker + var/name = "Tracker" + var/active = TRUE + var/changed = FALSE + + var/turf/target + + var/tick_refresh = 5 // The number of moved events before we update the position. + var/current_tick = 1 + + var/lost_position_probability = 0 // Probability of losing the target + var/lost_position_distance = 0 // Distance at which the tracker loses the target + +/datum/tracker/proc/recieve_position(var/list/loc) + + ASSERT(loc) + + if (!active) + return + if (current_tick < tick_refresh) + current_tick++ + return + + if (prob(lost_position_probability)) + active = FALSE + return + + var/target_loc = loc["loc"] + if (target != target_loc) + changed = TRUE + + target = get_turf(target_loc) + + current_tick = 1 \ No newline at end of file diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm index 134c38dec89..fd79cbe0429 100644 --- a/code/modules/admin/admin.dm +++ b/code/modules/admin/admin.dm @@ -1618,3 +1618,17 @@ proc/formatPlayerPanel(var/mob/U,var/text="PP") dat += "Max [T.max_per_turf] per turf. Lasts up to [T.max_age] rounds.
" usr << browse(dat, "window=persistencepanel;size=350x600") + +/datum/admins/proc/ViewAllRods() + if(!check_rights(0)) + return + + var/dat = "
View all active rods

" + + for (var/obj/item/projectile/immovablerod/rod in all_rods) + dat += "[rod] in z = [rod.z] (\[VV\])" + if (rod.tracking) + dat += "- (UNTRACK)" + dat += "
" + + usr << browse(dat, "window=rodswindow;size=350x300") \ No newline at end of file diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index 6021036ab35..e3cfd047251 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -128,7 +128,8 @@ var/list/admin_verbs_fun = list( /client/proc/makepAI, /client/proc/set_blob_looks, /client/proc/set_teleport_pref, - /client/proc/deadchat_singularity + /client/proc/deadchat_singularity, + /client/proc/view_all_rods, ) var/list/admin_verbs_spawn = list( /datum/admins/proc/spawn_atom, // Allows us to spawn instances @@ -1265,3 +1266,11 @@ var/list/admin_verbs_mod = list( holder.PersistencePanel() feedback_add_details("admin_verb","PEP") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! return + +/client/proc/view_all_rods() + set name = "VIEW-ALL-RODS" + set category = "Fun" + if(holder) + holder.ViewAllRods() + feedback_add_details("admin_verb","V-ROD") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + return \ No newline at end of file diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index fb04e4d30be..993fc7abd90 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -5375,6 +5375,30 @@ PersistencePanel() //refresh! + // --- Rod tracking + + else if (href_list["rod_to_untrack"]) + if(!check_rights(R_FUN)) + return + var/obj/item/projectile/P = locate(href_list["rod_to_untrack"]) + + if (!P) + return + + P.tracking = FALSE + P.tracker_datum = null + qdel(P.tracker_datum) + + var/log_data = "[P.original]" + if (ismob(P.original)) + var/mob/M = P.original + if (M.client) + log_data += " (M.client.ckey)" + + log_admin("[key_name(usr)] stopped a rod thrown at [log_data].") + message_admins("[key_name(usr)] stopped a rod thrown at [log_data].") + + ViewAllRods() // ----- Religion and stuff else if(href_list["ashpaper"]) diff --git a/code/modules/events/immovablerod.dm b/code/modules/events/immovablerod.dm index fade845ff5f..d3cba83952e 100644 --- a/code/modules/events/immovablerod.dm +++ b/code/modules/events/immovablerod.dm @@ -4,6 +4,8 @@ //As well as hurting all dense mobs //Recoded as a projectile for better movement/appearance +var/list/all_rods = list() + /datum/event/immovable_rod announceWhen = 1 @@ -71,6 +73,14 @@ lock_angle = 1 clongSound = 'sound/effects/immovablerod_clong.ogg' +/obj/item/projectile/immovablerod/New() + all_rods += src + ..() + +/obj/item/projectile/immovablerod/Destroy() + all_rods -= src + ..() + /obj/item/projectile/immovablerod/hyper/New() ..() var/image/I = image('icons/obj/objects_96x96.dmi',"immrod_bottom") @@ -188,3 +198,29 @@ for (var/mob/M in range(loc,20)) to_chat(M,"CLANG!") M.playsound_local(loc, clongSound, 100 - (get_dist(src,M)*5), 1) + +/proc/random_start_turf(var/z) + var/startx + var/starty + var/chosen_dir = pick(NORTH, SOUTH, EAST, WEST) + + switch(chosen_dir) + + if(NORTH) //North, along the y = max edge + starty = world.maxy - (TRANSITIONEDGE + 2) + startx = rand((TRANSITIONEDGE + 2), world.maxx - (TRANSITIONEDGE + 2)) + + if(SOUTH) //South, along the y = 0 edge + starty = (TRANSITIONEDGE + 2) + startx = rand((TRANSITIONEDGE + 2), world.maxx - (TRANSITIONEDGE + 2)) + + if(EAST) //East, along the x = max edge + starty = rand((TRANSITIONEDGE + 2), world.maxy - (TRANSITIONEDGE + 2)) + startx = world.maxx - (TRANSITIONEDGE + 2) + + if(WEST) //West, along the x = 0 edge + starty = rand((TRANSITIONEDGE + 2), world.maxy - (TRANSITIONEDGE + 2)) + startx = (TRANSITIONEDGE + 2) + + var/turf/T = locate(startx, starty, z) + return T \ No newline at end of file diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm index 7084b6e5660..b776b53ac5a 100644 --- a/code/modules/projectiles/projectile.dm +++ b/code/modules/projectiles/projectile.dm @@ -71,6 +71,9 @@ var/list/impact_master = list() var/inaccurate = 0 var/turf/target = null + var/datum/tracker/tracker_datum = null + var/tracking = FALSE + var/dist_x = 0 var/dist_y = 0 var/dx = 0 @@ -115,6 +118,10 @@ var/list/impact_master = list() X.apply_effects(stun, weaken, paralyze, irradiate, stutter, eyeblur, drowsy, agony, blocked) /obj/item/projectile/proc/on_hit(var/atom/atarget, var/blocked = 0) + + qdel(tracker_datum) + tracker_datum = null + if(blocked >= 100) return 0//Full block if(!isliving(atarget)) @@ -362,6 +369,16 @@ var/list/impact_master = list() /obj/item/projectile/proc/OnFired(var/proj_target = original) //if assigned, allows for code when the projectile gets fired target = get_turf(proj_target) + + if (tracking) + if (istype(proj_target, /atom/movable)) + var/atom/movable/the_target = proj_target + var/datum/tracker/T = new + T.name = "[src] tracker on [proj_target]" + T.target = target + src.tracker_datum = T + the_target.add_tracker(T) + dist_x = abs(target.x - starting.x) dist_y = abs(target.y - starting.y) @@ -419,6 +436,36 @@ var/list/impact_master = list() bumped = 0 + if (tracker_datum && tracker_datum.changed) + tracker_datum.changed = FALSE + var/dist = get_dist(tracker_datum.target, src) + if (tracker_datum.lost_position_distance && (dist > tracker_datum.lost_position_distance)) + tracker_datum.active = FALSE + else + target = tracker_datum.target + var/turf/current = get_turf(src) + + // recalculate trajectory based on new tracker data + if (target.x > current.x) + dx = EAST + else + dx = WEST + + if (target.y > current.y) + dy = NORTH + else + dy = SOUTH + + dist_x = abs(target.x - current.x) + dist_y = abs(target.y - current.y) + + if(dist_x > dist_y) + error = dist_x/2 - dist_y + else + error = dist_y/2 - dist_x + if(rotate) + target_angle = round(Get_Angle(current,target)) + sleep(projectile_speed)