Files
Bubberstation/code/game/objects/items/devices/camera_bug.dm
carnie 05b76b123e TimSort for byond:
RESULTS:
sorting 10 random lists of length 3 to 303 in increments of 3
(Meh, I forgot to refresh this one, there were only 338 trials rather than 1010, can't be bothered to recode the test)
                                    Profile results (total time)
Proc Name                                             Self CPU    Total CPU    Real Time        Calls
-------------------------------------------------    ---------    ---------    ---------    ---------
/proc/sortList                                           0.672       16.141       16.243       171226  <--TG's current mergesort(recursive, hence the higher number of calls)
/proc/sortTim                                            0.008        3.278        3.274          338  <--TimSort
/proc/sortMerge                                          0.011        2.839        2.855          338  <--new mergesort
/proc/sortInsert                                         0.010        2.124        2.103          338  <--binary insertion

Sorting 10 presorted lists with 3 inversions (3 elements shuffled up), Lists of length 3 to 303 (increments of 3)
                                    Profile results (total time)
Proc Name                                             Self CPU    Total CPU    Real Time        Calls
-------------------------------------------------    ---------    ---------    ---------    ---------
/proc/sortList                                           1.290       23.056       23.254       308050	<--rather cataclysmic
/proc/sortMerge                                          0.015        4.077        4.068         1010	<--
/proc/sortInsert                                         2.639        3.472        3.464         1010	<--
/proc/sortTim                                            0.014        1.567        1.576         1010	<--TimSort is faaar more effective in these cases,
Timsort can exploit runs effectively

sorting 10 presorted lists which have been reversed
                                    Profile results (total time)
Proc Name                                             Self CPU    Total CPU    Real Time        Calls
-------------------------------------------------    ---------    ---------    ---------    ---------
/proc/sortList                                           1.234       23.193       23.295       308050
/proc/sortMerge                                          0.023        4.681        4.686         1010
/proc/sortInsert                                         2.875        3.750        3.765         1010
/proc/sortTim                                            0.020        3.294        3.284         1010	//This can be lower by using a different comparison method
 *Corrected: /proc/sortTim                                0.017        0.665        0.663         1010	//Using a non-strictly ascending comparison

sorting 10 presorted lists
                                    Profile results (total time)
Proc Name                                             Self CPU    Total CPU    Real Time        Calls
-------------------------------------------------    ---------    ---------    ---------    ---------
/proc/sortList                                           1.199       21.391       21.517       308050
/proc/sortMerge                                          0.018        3.724        3.729         1010
/proc/sortInsert                                         2.497        3.302        3.309         1010
/proc/sortTim                                            0.024        0.586        0.584         1010

Summary, all the new procs are faster than the old ones. TimSort is ever so slightly slower than Insertion and Merging on random lists. But on lists with natural runs (partially sorted data) it is far faster than all others.

The old merge sort was removed and replaced with timSort. Other algorithms are provided as alternatives.

All algorithms use a central datum, so accept many of the same parameters. For instance, setting associative=1 will make them sort associative lists by their associated values, rather than keys.
They also accept a cmp argument. This allows sorting of lists of datums, text, numbers or whatever. The pre-existing helpers in lists.dm were rewritten as examples.
2014-09-01 11:29:49 +01:00

370 lines
11 KiB
Plaintext

#define VANILLA_BUG 0
#define UNIVERSAL_BUG 1
#define NETWORK_BUG 2
#define SABOTAGE_BUG 3
#define ADVANCED_BUG 4
#define ADMIN_BUG 5
#define BUGMODE_LIST 0
#define BUGMODE_MONITOR 1
#define BUGMODE_TRACK 2
/obj/item/device/camera_bug
name = "camera bug"
desc = "For illicit snooping through the camera network."
icon = 'icons/obj/device.dmi'
icon_state = "camera_bug"
w_class = 1.0
item_state = "camera_bug"
throw_speed = 4
throw_range = 20
var/obj/machinery/camera/current = null
var/obj/item/expansion = null
var/bugtype = VANILLA_BUG
var/last_net_update = 0
var/last_bugtype = VANILLA_BUG
var/list/bugged_cameras = list()
var/skip_bugcheck = 0
var/track_mode = BUGMODE_LIST
var/last_tracked = 0
var/refresh_interval = 50
var/tracked_name = null
var/atom/tracking = null
var/last_found = null
var/last_seen = null
/obj/item/device/camera_bug/New()
..()
processing_objects += src
/obj/item/device/camera_bug/Destroy()
if(expansion)
qdel(expansion)
expansion = null
del(src)
/* Easier to just call del() than this nonsense
get_cameras()
for(var/cam_tag in bugged_cameras)
var/obj/machinery/camera/camera = bugged_cameras[cam_tag]
if(camera.bug == src)
camera.bug = null
bugged_cameras = list()
if(tracking)
tracking = null
..()
*/
/obj/item/device/camera_bug/interact(var/mob/user = usr)
var/datum/browser/popup = new(user, "camerabug","Camera Bug",nref=src)
popup.set_content(menu(get_cameras()))
popup.open()
/obj/item/device/camera_bug/attack_self(mob/user as mob)
user.set_machine(src)
interact(user)
/obj/item/device/camera_bug/check_eye(var/mob/user as mob)
if (user.stat || loc != user || !user.canmove || user.blinded || !current)
user.reset_view(null)
user.unset_machine()
return null
var/turf/T = get_turf(user.loc)
if(T.z != current.z || (!skip_bugcheck && current.bug != src) || !current.can_use())
user << "<span class='danger'>[src] has lost the signal.</span>"
current = null
user.reset_view(null)
user.unset_machine()
return null
return 1
/obj/item/device/camera_bug/proc/get_cameras()
if(bugtype != last_bugtype || ( (bugtype in list(UNIVERSAL_BUG,NETWORK_BUG,ADMIN_BUG)) && world.time > (last_net_update + 100)))
bugged_cameras = list()
last_bugtype = bugtype
for(var/obj/machinery/camera/camera in cameranet.cameras)
if(camera.stat || !camera.can_use())
continue
switch(bugtype)
if(VANILLA_BUG,SABOTAGE_BUG,ADVANCED_BUG)
if(camera.bug == src)
bugged_cameras[camera.c_tag] = camera
if(UNIVERSAL_BUG)
if(camera.bug)
bugged_cameras[camera.c_tag] = camera
if(NETWORK_BUG,ADMIN_BUG)
if(length(list("SS13","MINE")&camera.network))
bugged_cameras[camera.c_tag] = camera
sortList(bugged_cameras)
return bugged_cameras
/obj/item/device/camera_bug/proc/menu(var/list/cameras)
if(!cameras || !cameras.len)
return "No bugged cameras found."
var/html
switch(track_mode)
if(BUGMODE_LIST)
html = "<h3>Select a camera:</h3> <a href='?src=\ref[src];view'>\[Cancel camera view\]</a><hr><table>"
for(var/entry in cameras)
var/obj/machinery/camera/C = cameras[entry]
var/functions = ""
switch(bugtype)
if(SABOTAGE_BUG)
functions = " - <a href='?src=\ref[src];emp=\ref[C]'>\[Disable\]</a>"
if(ADVANCED_BUG)
functions = " - <a href='?src=\ref[src];monitor=\ref[C]'>\[Monitor\]</a>"
if(ADMIN_BUG)
if(C.bug == src)
functions = " - <a href='?src=\ref[src];monitor=\ref[C]'>\[Monitor\]</a> <a href='?src=\ref[src];emp=\ref[C]'>\[Disable\]</a>"
else
functions = " - <a href='?src=\ref[src];monitor=\ref[C]'>\[Monitor\]</a>"
html += "<tr><td><a href='?src=\ref[src];view=\ref[C]'>[entry]</a></td><td>[functions]</td></tr>"
if(BUGMODE_MONITOR)
if(current)
html = "Analyzing Camera '[current.c_tag]' <a href='?\ref[src];mode=0'>\[Select Camera\]</a><br>"
html += camera_report()
else
track_mode = BUGMODE_LIST
return .(cameras)
if(BUGMODE_TRACK)
if(tracking)
html = "Tracking '[tracked_name]' <a href='?\ref[src];mode=0'>\[Cancel Tracking\]</a> <a href='?src=\ref[src];view'>\[Cancel camera view\]</a><br>"
if(last_found)
var/time_diff = round((world.time - last_seen) / 150)
var/obj/machinery/camera/C = bugged_cameras[last_found]
var/outstring
if(C)
outstring = "<a href='?\ref[src];view=\ref[C]'>[last_found]</a>"
else
outstring = last_found
if(!time_diff)
html += "Last seen near [outstring] (now)<br>"
else
// 15 second intervals ~ 1/4 minute
var/m = round(time_diff/4)
var/s = (time_diff - 4*m) * 15
if(!s) s = "00"
html += "Last seen near [outstring] ([m]:[s] minute\s ago)<br>"
else
html += "Not yet seen."
else
track_mode = BUGMODE_LIST
return .(cameras)
return html
/obj/item/device/camera_bug/proc/camera_report()
// this should only be called if current exists
var/dat = ""
if(current && current.can_use())
var/list/seen = current.can_see()
var/list/names = list()
for(var/obj/machinery/singularity/S in seen) // god help you if you see more than one
if(S.name in names)
names[S.name]++
dat += "[S.name] ([names[S.name]])"
else
names[S.name] = 1
dat += "[S.name]"
var/stage = round(S.current_size / 2)+1
dat += " (Stage [stage])"
dat += " <a href='?\ref[src];track=\ref[S]'>\[Track\]</a><br>"
for(var/obj/mecha/M in seen)
if(M.name in names)
names[M.name]++
dat += "[M.name] ([names[M.name]])"
else
names[M.name] = 1
dat += "[M.name]"
dat += " <a href='?\ref[src];track=\ref[M]'>\[Track\]</a><br>"
for(var/mob/living/M in seen)
if(M.name in names)
names[M.name]++
dat += "[M.name] ([names[M.name]])"
else
names[M.name] = 1
dat += "[M.name]"
if(M.buckled && !M.lying)
dat += " (Sitting)"
if(M.lying)
dat += " (Laying down)"
dat += " <a href='?\ref[src];track=\ref[M]'>\[Track\]</a><br>"
if(length(dat) == 0)
dat += "No motion detected."
return dat
else
return "Camera Offline<br>"
/obj/item/device/camera_bug/Topic(var/href,var/list/href_list)
if(usr != loc)
usr.unset_machine()
usr.reset_view(null)
usr << browse(null, "window=camerabug")
return
usr.set_machine(src)
if("mode" in href_list)
track_mode = text2num(href_list["mode"])
if("monitor" in href_list)
var/obj/machinery/camera/C = locate(href_list["monitor"])
if(C)
track_mode = BUGMODE_MONITOR
current = C
usr.reset_view(null)
interact()
if("track" in href_list)
var/atom/A = locate(href_list["track"])
if(A)
tracking = A
tracked_name = A.name
last_found = current.c_tag
last_seen = world.time
track_mode = BUGMODE_TRACK
if("emp" in href_list)
var/obj/machinery/camera/C = locate(href_list["emp"])
if(istype(C) && C.bug == src)
C.emp_act(1)
C.bug = null
bugged_cameras -= C.c_tag
interact()
return
if("close" in href_list)
usr.reset_view(null)
usr.unset_machine()
current = null
return // I do not <- I do not remember what I was going to write in this comment -Sayu, sometime later
if("view" in href_list)
var/obj/machinery/camera/C = locate(href_list["view"])
if(istype(C))
if(!C.can_use())
usr << "<span class='danger'>Something's wrong with that camera. You can't get a feed.</span>"
return
var/turf/T = get_turf(loc)
if(!T || C.z != T.z)
usr << "<span class='danger'>You can't get a signal.</span>"
return
current = C
spawn(6)
if(src.check_eye(usr))
usr.reset_view(C)
interact()
else
usr.unset_machine()
usr.reset_view(null)
usr << browse(null, "window=camerabug")
return
else
usr.unset_machine()
usr.reset_view(null)
interact()
/obj/item/device/camera_bug/process()
if(track_mode == BUGMODE_LIST || (world.time < (last_tracked + refresh_interval)))
return
last_tracked = world.time
if(track_mode == BUGMODE_TRACK ) // search for user
// Note that it will be tricked if your name appears to change.
// This is not optimal but it is better than tracking you relentlessly despite everything.
if(!tracking)
src.updateSelfDialog()
return
if(tracking.name != tracked_name) // Hiding their identity, tricksy
var/mob/M = tracking
if(istype(M))
if(!(tracked_name == "Unknown" && findtext(tracking.name,"Unknown"))) // we saw then disguised before
if(!(tracked_name == M.real_name && findtext(tracking.name,M.real_name))) // or they're still ID'd
src.updateSelfDialog()//But if it's neither of those cases
return // you won't find em on the cameras
else
src.updateSelfDialog()
return
var/list/tracking_cams = list()
var/list/b_cams = get_cameras()
for(var/entry in b_cams)
tracking_cams += b_cams[entry]
var/list/target_region = view(tracking)
for(var/obj/machinery/camera/C in (target_region & tracking_cams))
if(!can_see(C,tracking)) // target may have xray, that doesn't make them visible to cameras
continue
if(C.can_use())
last_found = C.c_tag
last_seen = world.time
break
src.updateSelfDialog()
/obj/item/device/camera_bug/attackby(var/obj/item/W as obj,var/mob/living/user as mob)
if(istype(W,/obj/item/weapon/screwdriver) && expansion)
expansion.loc = get_turf(loc)
user << "You unscrew [expansion]."
user.put_in_inactive_hand(expansion)
expansion = null
bugtype = VANILLA_BUG
skip_bugcheck = 0
track_mode = BUGMODE_LIST
tracking = null
return
if(expansion || !W)
return ..(W,user)
// I am not sure that this list is or should be final
// really I do not know what to do here.
var/static/list/expandables = list(
/obj/item/weapon/research = ADMIN_BUG, // could have been anything spawn-only
// these are all so hackish I am sorry
/obj/item/device/analyzer = UNIVERSAL_BUG,
/obj/item/weapon/stock_parts/subspace/analyzer = UNIVERSAL_BUG,
/obj/item/device/assembly/igniter = SABOTAGE_BUG,
/obj/item/device/assembly/infra = SABOTAGE_BUG, // ir blaster to disable camera
/obj/item/weapon/stock_parts/subspace/amplifier = SABOTAGE_BUG,
/obj/item/device/radio = NETWORK_BUG,
/obj/item/device/assembly/signaler = NETWORK_BUG,
/obj/item/weapon/stock_parts/subspace/transmitter = NETWORK_BUG,
/obj/item/device/detective_scanner = ADVANCED_BUG,
/obj/item/device/paicard = ADVANCED_BUG,
/obj/item/weapon/stock_parts/scanning_module = ADVANCED_BUG
)
for(var/entry in expandables)
if(istype(W,entry))
bugtype = expandables[entry]
user.drop_item()
W.loc = src
expansion = W
user << "You add [W] to [src]."
get_cameras() // the tracking code will want to know the new camera list
if(bugtype in list(UNIVERSAL_BUG,NETWORK_BUG,ADMIN_BUG))
skip_bugcheck = 1
return
#undef VANILLA_BUG
#undef UNIVERSAL_BUG
#undef NETWORK_BUG
#undef SABOTAGE_BUG
#undef ADVANCED_BUG
#undef ADMIN_BUG
#undef BUGMODE_LIST
#undef BUGMODE_MONITOR
#undef BUGMODE_TRACK