From 002407ed7a457f36b79581c40e02787526cd9273 Mon Sep 17 00:00:00 2001 From: shadowlord13 Date: Wed, 18 Jun 2008 21:06:31 +0000 Subject: [PATCH] Implemented canReach for verbs, added calls to it to the verbs which needed it --- Code/Machinery/Atmoalter/canister.dm | 2 +- Code/Machinery/Computer/atmosphere.dm | 21 +- Code/Machinery/Computer/communications.dm | 8 + Code/Machinery/Computer/data.dm | 16 + Code/Machinery/Computer/hologram.dm | 4 +- Code/Machinery/Computer/prision_shuttle.dm | 14 +- Code/Machinery/Computer/shuttle.dm | 12 +- Code/Machinery/cryocell.dm | 17 +- Code/Machinery/pod.dm | 28 +- Code/Machinery/recon.dm | 16 +- Code/Machinery/sleeper.dm | 8 +- Code/demo.dm | 27 +- Code/dna.dm | 20 +- Code/items.dm | 408 +++++----- Code/mob.dm | 872 +++++++++++---------- Code/mob/ai.dm | 50 +- Code/mob/drone.dm | 72 +- Code/shuttle.dm | 10 +- Code/weap_sat.dm | 28 +- Code/weapons.dm | 29 +- Icons/stationobjs.dmi | Bin 26067 -> 26767 bytes 21 files changed, 981 insertions(+), 681 deletions(-) diff --git a/Code/Machinery/Atmoalter/canister.dm b/Code/Machinery/Atmoalter/canister.dm index 9fd7047..e1ad6ee 100644 --- a/Code/Machinery/Atmoalter/canister.dm +++ b/Code/Machinery/Atmoalter/canister.dm @@ -252,7 +252,7 @@ Pipe Valve Status: [ct]
// Process topic link from interaction window Topic(href, href_list) - usr.client_mob() << "Topic on canister, usr is [usr], src is [src], usr.client_mob() is [usr.client_mob()], href is ([href]), href_list is ([href_list])." + //debug message: //usr.client_mob() << "Topic on canister, usr is [usr], src is [src], usr.client_mob() is [usr.client_mob()], href is ([href]), href_list is ([href_list])." ..() if (usr.stat || usr.restrained()) diff --git a/Code/Machinery/Computer/atmosphere.dm b/Code/Machinery/Computer/atmosphere.dm index 73c2096..3d806ee 100644 --- a/Code/Machinery/Computer/atmosphere.dm +++ b/Code/Machinery/Computer/atmosphere.dm @@ -57,8 +57,11 @@ obj/machinery/computer/atmosphere verb/siphon_all() set src in oview(1) if(stat & NOPOWER) return - if (usr.stat) + var/result = src.canReach(usr, null, 1) + if (result==0) + usr.client_mob() << "You can't reach [src]." return + usr.client_mob() << "Starting all siphon systems." for(var/obj/machinery/atmoalter/siphs/S in src.returnarea()) S.reset(1, 0) @@ -70,7 +73,9 @@ obj/machinery/computer/atmosphere verb/stop_all() set src in oview(1) if(stat & NOPOWER) return - if (usr.stat) + var/result = src.canReach(usr, null, 1) + if (result==0) + usr.client_mob() << "You can't reach [src]." return usr.client_mob() << "Stopping all siphon systems." for(var/obj/machinery/atmoalter/siphs/S in src.returnarea()) @@ -83,7 +88,9 @@ obj/machinery/computer/atmosphere verb/auto_on() set src in oview(1) if(stat & NOPOWER) return - if (usr.stat) + var/result = src.canReach(usr, null, 1) + if (result==0) + usr.client_mob() << "You can't reach [src]." return usr.client_mob() << "Starting automatic air control systems." for(var/obj/machinery/atmoalter/siphs/S in src.returnarea()) @@ -97,7 +104,9 @@ obj/machinery/computer/atmosphere set src in oview(1) if(stat & NOPOWER) return - if (usr.stat) + var/result = src.canReach(usr, null, 1) + if (result==0) + usr.client_mob() << "You can't reach [src]." return usr.client_mob() << "Releasing all scrubber toxins." for(var/obj/machinery/atmoalter/siphs/scrubbers/S in src.returnarea()) @@ -110,7 +119,9 @@ obj/machinery/computer/atmosphere verb/release_all() set src in oview(1) if(stat & NOPOWER) return - if (usr.stat) + var/result = src.canReach(usr, null, 1) + if (result==0) + usr.client_mob() << "You can't reach [src]." return usr.client_mob() << "Releasing all stored air." for(var/obj/machinery/atmoalter/siphs/S in src.returnarea()) diff --git a/Code/Machinery/Computer/communications.dm b/Code/Machinery/Computer/communications.dm index b82c183..3ff9d37 100644 --- a/Code/Machinery/Computer/communications.dm +++ b/Code/Machinery/Computer/communications.dm @@ -14,6 +14,10 @@ obj/machinery/computer/communications verb/call_shuttle() set src in oview(1) + var/result = src.canReach(usr, null, 1) + if (result==0) + usr.client_mob() << "You can't reach [src]." + return src.add_fingerprint(usr) if(stat & NOPOWER) return call_shuttle_proc(usr) @@ -22,6 +26,10 @@ obj/machinery/computer/communications verb/cancel_call() set src in oview(1) + var/result = src.canReach(usr, null, 1) + if (result==0) + usr.client_mob() << "You can't reach [src]." + return src.add_fingerprint(usr) if(stat & NOPOWER) return cancel_call_proc(usr) diff --git a/Code/Machinery/Computer/data.dm b/Code/Machinery/Computer/data.dm index 9b695cd..d58e599 100644 --- a/Code/Machinery/Computer/data.dm +++ b/Code/Machinery/Computer/data.dm @@ -19,6 +19,10 @@ obj/machinery/computer/data verb/display() set src in oview(1) + var/result = src.canReach(usr, null, 1) + if (result==0) + usr.client_mob() << "You can't reach [src]." + return for(var/x in src.topics) usr.client_mob() << "[x], \..." @@ -32,6 +36,10 @@ obj/machinery/computer/data verb/read(topic as text) set src in oview(1) + var/result = src.canReach(usr, null, 1) + if (result==0) + usr.client_mob() << "You can't reach [src]." + return if (src.topics[text("[]", topic)]) usr.client_mob() << "[topic]\n\t [src.topics["[topic]"]]" @@ -80,6 +88,10 @@ obj/machinery/computer/data display() set src in oview(1) + var/result = src.canReach(usr, null, 1) + if (result==0) + usr.client_mob() << "You can't reach [src]." + return usr.client_mob() << "Research Information:" ..() @@ -107,6 +119,10 @@ obj/machinery/computer/data display() set src in oview(1) + var/result = src.canReach(usr, null, 1) + if (result==0) + usr.client_mob() << "You can't reach [src]." + return usr.client_mob() << "Research Log:" ..() diff --git a/Code/Machinery/Computer/hologram.dm b/Code/Machinery/Computer/hologram.dm index 6be021f..a949d6a 100644 --- a/Code/Machinery/Computer/hologram.dm +++ b/Code/Machinery/Computer/hologram.dm @@ -131,7 +131,9 @@ Blue (0-255): \[0\] Restabilizing prison shuttle atmosphere!" diff --git a/Code/Machinery/Computer/shuttle.dm b/Code/Machinery/Computer/shuttle.dm index 4efb57f..f5098f7 100644 --- a/Code/Machinery/Computer/shuttle.dm +++ b/Code/Machinery/Computer/shuttle.dm @@ -16,11 +16,15 @@ obj/machinery/computer/shuttle access = "2000" // ID card access level needed to authorize - // Restabalize verb + // Restabilize verb // Set all shuttle locations to standard atmosphere - verb/restabalize() + verb/restabilize() set src in oview(1) + var/result = src.canReach(usr, null, 1) + if (result==0) + usr.client_mob() << "You can't reach [src]." + return world << "\red Restabilizing shuttle atmosphere!" var/A = locate(/area/shuttle) @@ -55,6 +59,10 @@ obj/machinery/computer/shuttle verb/hijack() set src in oview(1) + var/result = src.canReach(usr, null, 1) + if (result==0) + usr.client_mob() << "You can't reach [src]." + return if ((!( ticker ) || ticker.shuttle_location != shuttle_z)) return diff --git a/Code/Machinery/cryocell.dm b/Code/Machinery/cryocell.dm index 01f9727..e6dfe8f 100644 --- a/Code/Machinery/cryocell.dm +++ b/Code/Machinery/cryocell.dm @@ -155,9 +155,11 @@ obj/machinery/cryo_cell verb/move_eject() set src in oview(1) - - if (usr.stat != 0) + var/result = src.canReach(usr, null, 1) + if (result==0) + usr.client_mob() << "You can't reach [src]." return + src.go_out() add_fingerprint(usr) @@ -168,7 +170,10 @@ obj/machinery/cryo_cell verb/move_inside() set src in oview(1) - + var/result = src.canReach(usr, null, 1) + if (result==0) + usr.client_mob() << "You can't reach [src]." + return if (usr.stat != 0 || stat & NOPOWER) return if (src.occupant) @@ -227,9 +232,9 @@ obj/machinery/cryo_cell // AI interact attack_ai(mob/user) return src.attack_hand(user) - + // Human interact, show status window of machine and occupant - + attack_hand(mob/user) if(stat & NOPOWER) @@ -347,7 +352,7 @@ obj/machinery/cryo_cell else usr.client_mob() << "User too far?" return - + // Called to remove the occupant of a cell // Reset the view back to normal diff --git a/Code/Machinery/pod.dm b/Code/Machinery/pod.dm index 27ec197..3c75223 100644 --- a/Code/Machinery/pod.dm +++ b/Code/Machinery/pod.dm @@ -84,7 +84,9 @@ obj/machinery/pod verb/eject() set src = usr.loc - if (usr.stat) + var/result = src.canReach(usr, null, 1) + if (result==0) + usr << "You can't reach [src]." return var/mob/M = usr M.loc = src.loc @@ -99,14 +101,16 @@ obj/machinery/pod verb/board() set src in oview(1) - if (usr.stat) + var/result = src.canReach(usr, null, 1) + if (result==0) + usr << "You can't reach [src]." return var/mob/M = usr if (M.client) M.client.perspective = EYE_PERSPECTIVE M.client.eye = src M.loc = src - return + // Load pod - whatever the player is pulling gets loaded into the pod (including other players) @@ -125,6 +129,15 @@ obj/machinery/pod if (ismob(H.pulling)) var/mob/M = H.pulling + var/result = src.canReach(H, null, 1) + if (result==0) + usr << "You can't reach [src]." + return + result = H.pulling.canReach(H, null, 1) + if (result==0) + usr << "You can't reach [H.pulling]." + return + if (M.client) M.client.perspective = EYE_PERSPECTIVE M.client.eye = src @@ -141,8 +154,15 @@ obj/machinery/pod verb/unload(var/atom/movable/A in src.contents) set src in oview(1) - if (usr.stat) + var/result = src.canReach(usr, null, 1) + if (result==0) + usr << "You can't reach [src]." return + result = src.canReach(usr, null, 1) + if (result==0) + usr << "You can't reach [src]." + return + if (istype(A, /atom/movable)) A.loc = src.loc for(var/mob/O in viewers(src, null)) diff --git a/Code/Machinery/recon.dm b/Code/Machinery/recon.dm index 7c31601..73c5d9d 100644 --- a/Code/Machinery/recon.dm +++ b/Code/Machinery/recon.dm @@ -79,7 +79,9 @@ obj/machinery/recon verb/eject() set src = usr.loc - if (usr.stat) + var/result = src.canReach(usr, null, 1) + if (result==0) + usr << "You can't reach [src]." return var/mob/M = usr M.loc = src.loc @@ -93,7 +95,9 @@ obj/machinery/recon verb/board() set src in oview(1) - if (usr.stat) + var/result = src.canReach(usr, null, 1) + if (result==0) + usr << "You can't reach [src]." return if (locate(/mob, src)) usr.client_mob() << "There is no room! You can only fit one person." @@ -111,7 +115,9 @@ obj/machinery/recon verb/load() set src in oview(1) - if (usr.stat) + var/result = src.canReach(usr, null, 1) + if (result==0) + usr << "You can't reach [src]." return if ((( istype(usr, /mob/human) ) && (!( ticker ) || (ticker && ticker.mode != "monkey")))) var/mob/human/H = usr @@ -141,7 +147,9 @@ obj/machinery/recon verb/unload(atom/movable/A in src) set src in oview(1) - if (usr.stat) + var/result = src.canReach(usr, null, 1) + if (result==0) + usr << "You can't reach [src]." return if (istype(A, /atom/movable)) A.loc = src.loc diff --git a/Code/Machinery/sleeper.dm b/Code/Machinery/sleeper.dm index 24e745a..6413ea2 100644 --- a/Code/Machinery/sleeper.dm +++ b/Code/Machinery/sleeper.dm @@ -30,7 +30,9 @@ obj/machinery/sleeper verb/eject() set src in oview(1) - if (usr.stat != 0) + var/result = src.canReach(usr, null, 1) + if (result==0) + usr << "You can't reach [src]." return src.go_out() add_fingerprint(usr) @@ -43,7 +45,9 @@ obj/machinery/sleeper verb/move_inside() set src in oview(1) - if (usr.stat != 0) + var/result = src.canReach(usr, null, 1) + if (result==0) + usr << "You can't reach [src]." return if (src.occupant) usr.client_mob() << "\blue The sleeper is already occupied!" diff --git a/Code/demo.dm b/Code/demo.dm index 249727d..f8492b0 100644 --- a/Code/demo.dm +++ b/Code/demo.dm @@ -115,7 +115,7 @@ M.stunned = time M.stat = 1 for(var/mob/O in viewers(M, null)) - if ((!( O.blinded ))) + if (O.hasClient() && (!( O.blinded ))) O.client_mob() << text("\red [] has been knocked unconscious!", M) //Foreach goto(169) M.client_mob() << text("\red This was a []% hit. Roleplay it! (personality/memory change if the hit was severe enough)", time * 100 / 120) @@ -1512,7 +1512,11 @@ /obj/stool/chair/e_chair/verb/toggle_power() set src in oview(1) - + var/result = src.canReach(usr, null, 1) + if (result==0) + usr.client_mob() << "You can't reach [src]." + return + if ((usr.stat || usr.restrained() || !( usr.canmove ) || usr.lying)) return src.on = !( src.on ) @@ -1618,7 +1622,11 @@ /obj/stool/chair/verb/rotate() set src in oview(1) - + var/result = src.canReach(usr, null, 1) + if (result==0) + usr.client_mob() << "You can't reach [src]." + return + src.dir = turn(src.dir, 90) if (src.dir == NORTH) src.layer = FLY_LAYER @@ -1661,10 +1669,9 @@ /obj/stool/chair/attack_hand(mob/user as mob) if (istype(user, /mob/drone)) - if (istype(user, /mob/drone)) - if (user.equipped()) - user.client_mob() << "You need to be using the gripper to buckle someone in." - return + if (user.equipped()) + user.client_mob() << "You need to be using the gripper to buckle someone in." + return for(var/mob/M in src.loc) if (M.buckled) if (M != user) @@ -1957,7 +1964,11 @@ /obj/window/verb/rotate() set src in oview(1) - + var/result = src.canReach(usr, null, 1) + if (result==0) + usr.client_mob() << "You can't reach [src]." + return + if (src.anchored) usr.client_mob() << "It is fastened to the floor; therefore, you can't rotate it!" return 0 diff --git a/Code/dna.dm b/Code/dna.dm index c4891f9..a13dd64 100644 --- a/Code/dna.dm +++ b/Code/dna.dm @@ -246,7 +246,11 @@ /obj/machinery/dna_scanner/verb/move_inside() set src in oview(1) - + var/result = src.canReach(usr, null, 1) + if (result==0) + usr.client_mob() << "You can't reach [src]." + return + if (usr.stat != 0) return if (src.occupant) @@ -718,7 +722,7 @@ /obj/machinery/restruct/verb/eject() set src in oview(1) - + if (usr.stat != 0) return src.go_out() @@ -727,7 +731,11 @@ /obj/machinery/restruct/verb/operate() set src in oview(1) - + var/result = src.canReach(usr, null, 1) + if (result==0) + usr.client_mob() << "You can't reach [src]." + return + src.add_fingerprint(usr) if ((src.occupant && src.occupant.primary)) switch(src.occupant.primary.spec_identity) @@ -884,7 +892,11 @@ /obj/machinery/restruct/verb/move_inside() set src in oview(1) - + var/result = src.canReach(usr, null, 1) + if (result==0) + usr.client_mob() << "You can't reach [src]." + return + if (usr.stat != 0) return if (src.occupant) diff --git a/Code/items.dm b/Code/items.dm index 1ce450b..1ff11b2 100644 --- a/Code/items.dm +++ b/Code/items.dm @@ -778,7 +778,6 @@ for(var/obj/item/weapon/cloaking_device/S in M) S.active = 0 S.icon_state = "shield0" - //Foreach goto(72) if ((get_dist(M, T) <= 2 || src.loc == M.loc || src.loc == M)) flick("e_flash", M.flash) M.stunned = 10 @@ -928,7 +927,6 @@ for(var/obj/item/weapon/cloaking_device/S in M) S.active = 0 S.icon_state = "shield0" - //Foreach goto(201) if (M.hasClient()) var/mob/CM = M.client_mob() var/safety = null @@ -4357,24 +4355,43 @@ //Foreach goto(203) for(var/mob/O in crackle) O.show_message(text("\icon[] Crackle,Crackle", src), 2) - //Foreach goto(233) + //Foreach goto(233) + var/speakerType = M.type if (istype(M, /mob/human) || (istype(M, /mob/ai))) for(var/mob/O in receive) - if (istype(O, /mob/human) || (istype(O, /mob/ai))) + var/mobType = O.type + if (istype(O, /mob/drone)) + var/mob/drone/Mdrone = O + var/mob/Mowner = Mdrone.controlledBy + if (Mowner!=null) + mobType = Mowner.type + if (istype(O, /mob/human) || (istype(O, /mob/ai)) || (istype(O, /mob/drone) && mobType==speakerType)) O.show_message(text("[]-\icon[]\[[]\]-broadcasts: []", M.rname, src, src.freq, msg), 2) else O.show_message(text("[]-\icon[]\[[]\]-broadcasts: []", M.rname, src, src.freq, stars(msg)), 2) //Foreach goto(284) if (src.freq == 5) for(var/mob/O in receive) - if (istype(O, /mob/human) || (istype(O, /mob/ai))) + var/mobType = O.type + if (istype(O, /mob/drone)) + var/mob/drone/Mdrone = O + var/mob/Mowner = Mdrone.controlledBy + if (Mowner!=null) + mobType = Mowner.type + if (istype(O, /mob/human) || (istype(O, /mob/ai)) || (istype(O, /mob/drone) && istype(mobType, speakerType))) O.show_message(text("[]-\icon[]\[[]\]-broadcasts (over PA): []", M.rname, src, src.freq, msg), 2) else O.show_message(text("[]-\icon[]\[[]\]-broadcasts (over PA): []", M.rname, src, src.freq, stars(msg)), 2) //Foreach goto(393) else for(var/mob/O in receive) - if (istype(O, M)) + var/mobType = O.type + if (istype(O, /mob/drone)) + var/mob/drone/Mdrone = O + var/mob/Mowner = Mdrone.controlledBy + if (Mowner!=null) + mobType = Mowner.type + if (istype(O, M) || (istype(O, /mob/drone) && istype(mobType, speakerType))) O.show_message(text("The monkey-\icon[]\[[]\]-broadcasts: []", src, src.freq, msg), 2) else O.show_message(text("The monkey-\icon[]\[[]\]-broadcasts: chimpering", src, src.freq), 2) @@ -4897,7 +4914,7 @@ M.health = 100 - M.oxyloss - M.toxloss - M.fireloss - M.bruteloss src.amount-- else - usr.client_mob() << text("\red The [] only works on humans.", src) + user.client_mob() << text("\red The [] only works on humans.", src) return /obj/item/weapon/brutepack/examine() @@ -5654,6 +5671,183 @@ return ..() return + +/* + Proc name: canReach + Purpose: To indicate whether something - a turf, a mob, an object, whatever - can be reached from the user's location. + Parameters: + user - the mob who will be doing the attempted touching + usingWeapon - the weapon the mob is using to reach src. This is important if they're actually trying to *shoot* someone. + ignoreNextMoveTime - Normally this would be 0, and if world.time wasn't < next_time, the proc would return 0. If it was < next_time, prev_time and next_time would be changed (next_time being set to world.time + 10). + If, instead, ignoreNextMoveTime is 1, next_time, world.time, and prev_time will not be examined or changed. + + Return value: + This returns 0 if, for some reason, the user can't reach src. If not, the return value is a set of 3 bitflags: + 1: CANREACH_USINGWEAPON: If set, user is using a "weapon" (passed in as usingWeapon) on src. (This is kind of semi-useless to check, since the only case currently where this would be 0 when you had passed in a weapon would be if the user was a drone, and the weapon was the AI interface, and the drone was controlled by the AI player, in which case if you cared you would already be checking for it anyways because you would need to be changing the user and setting the weapon to null yourself.) + 2: CANREACH_CANTOUCH: If set, src can be touched by user (which was called t5 in DblClick). This is set if (get_dist(src, user) <= 1 || src.loc == user), or if the user is the AI, or if the user is a drone controlled by an AI using the AI interface tool. + 4: CANREACH_ALLOWED: If set, src is reachable by user, or the attempt is allowed for another reason. This is always set if the return value is valid. This differs from cantouch because this will be set if the user is using a gun on someone distant, whereas cantouch will not be set in that case. It's also theoretically possible to have a return value which contains only 4 for some /obj/screen objects, if the code in /atom/DblClick wasn't just overly paranoid. + + Valid combinations of those are: 0, 4, 5, 6, or 7. (You won't ever have 1 or 2 set if 4 isn't set) + + Detail on what's checked: + The user has to be able to move unless they are an AI, and their stat has to be 0 (alive and awake). + If the src is not in user's inventory, we MIGHT return 0: + If src is not a turf, and it is not on a turf, and it is inside something else which is not in a turf: + We return 0, it cannot be reached. + If not, if the user is inside some item instead of on a turf, and src is not in the same place as the user, and src is not a screen object, and src is not inside an item in user's inventory: + We return 0, it cannot be reached. + (Otherwise we continue) + And some other difficult to explain stuff is done here. + + Either CANREACH_CANTOUCH will be true, or the user must be using a weapon which has flag 16 set, or src is an /obj/screen. + Checks to determine if there are obstacles in the way (windows, etc) are done unless src is an /obj/screen. +*/ + +#define CANREACH_USINGWEAPON 1 +#define CANREACH_CANTOUCH 2 +#define CANREACH_ALLOWED 4 + +/* Note: CANREACH_USINGWEAPON and CANREACH_CANTOUCH are not referenced in canReach because those are set by just a something&1 and a (something&1)<<1 */ + +/atom/proc/canReach(mob/user, obj/item/weapon/usingWeapon, ignoreNextMoveTime) + if (((!user.canmove) && (!istype(user, /mob/ai))) || user.stat != 0) + return 0 + /* This line broke my mental parser. --Stephen001 */ + if ((!(src in user.contents) && (((!(isturf(src)) && (!(isturf(src.loc)) && (src.loc && !(isturf(src.loc.loc))))) || !(isturf(user.loc))) && (src.loc != user.loc && (!(istype(src, /obj/screen)) && !(user.contents.Find(src.loc))))))) + return 0 + /* Breaks double-clicking on an equipment slot to place an item there, unfortunately. */ + /* + //If the dclicked item is not in our inventory + if (!(src in user.contents)) + //If the item is not a turf, and it is not on a turf, and it is inside something else which is not in a turf + if (!(isturf(src)) && (!(isturf(src.loc)) && (src.loc && !(isturf(src.loc.loc))))) + return + //If not, if we are inside some item instead of on a turf, and the dclicked item is not in the same place as us, and the dclicked item is not a screen object, and the dclicked item is not inside an item in our inventory. + else if ((!(isturf(user.loc))) && (src.loc != user.loc && (!(istype(src, /obj/screen)) && !(user.contents.Find(src.loc))))) + return + */ + + /* That's checking to see if it's being held/worn or something like that, methinks */ + var/t5 = (get_dist(src, user) <= 1 || src.loc == user) + if (istype(user, /mob/ai)) + t5 = 1 + else if (istype(user, /mob/drone)) + if (user:selectedTool == user:aiInterface) + if (istype(user:controlledBy, /mob/ai)) + t5 = 1 + user = user:controlledBy + usingWeapon = null + + if ((istype(src, /obj/item/weapon/organ) && src in user.contents)) + var/mob/human/H = user + if (istype(user, /mob/human)) + if (!(src == H.l_store || src == H.r_store)) + return 0 + else + return 0 + /* Suggested fix by shadowlord13 for Bug #1952091. --Stephen001 */ + var/turf/turfLoc = (istype(src, /turf) ? src : src.loc) + + /* Seems like a pretty important expression. Dare I fathom what it checks? --Stephen001 */ + /* flag 16 in this case apparently disables the distance check and the alternate 'is in contents' check in the var/t5 line. + It's used on guns, for instance. --shadowlord13 */ + if (((t5 || (usingWeapon && (usingWeapon.flags & 16))) && !(istype(src, /obj/screen)))) + if (ignoreNextMoveTime!=0) + if (user.next_move < world.time) + user.prev_move = user.next_move + user.next_move = world.time + 10 + else + return 0 + if ((turfLoc && (get_dist(src, user) < 2 || turfLoc == user.loc))) + var/direct = get_dir(user, src) + var/obj/item/weapon/dummy/D = new /obj/item/weapon/dummy(user.loc) + var/ok = 0 + if ((direct - 1) & direct) + var/turf/T + switch(direct) + if(5.0) + T = get_step(user, NORTH) + if (T.Enter(D, src)) + D.loc = T + T = turfLoc + if (T.Enter(D, src)) + ok = 1 + else + T = get_step(user, EAST) + if (T.Enter(D, src)) + D.loc = T + T = turfLoc + if (T.Enter(D, src)) + ok = 1 + if(6.0) + T = get_step(user, SOUTH) + if (T.Enter(D, src)) + D.loc = T + T = turfLoc + if (T.Enter(D, src)) + ok = 1 + else + T = get_step(user, EAST) + if (T.Enter(D, src)) + D.loc = T + T = turfLoc + if (T.Enter(D, src)) + ok = 1 + if(9.0) + T = get_step(user, NORTH) + if (T.Enter(D, src)) + D.loc = T + T = turfLoc + if (T.Enter(D, src)) + ok = 1 + else + T = get_step(user, WEST) + if (T.Enter(D, src)) + D.loc = T + T = turfLoc + if (T.Enter(D, src)) + ok = 1 + if(10.0) + T = get_step(user, SOUTH) + if (T.Enter(D, src)) + D.loc = T + T = turfLoc + if (T.Enter(D, src)) + ok = 1 + else + T = get_step(user, WEST) + if (T.Enter(D, src)) + D.loc = T + T = turfLoc + if (T.Enter(D, src)) + ok = 1 + else + else + if (turfLoc.Enter(D, src)) + ok = 1 + else + if ((src.flags & 512 && get_dir(src, user) & src.dir)) + ok = 1 + if (user.loc != turfLoc) + for(var/atom/A in user.loc) + if ((!A.CheckExit(user, src.loc)) && A != user) + ok = 0 + del(D) + if (!(ok)) + return 0 + //user << "Debug message: usingWeapon [usingWeapon] t5 [t5] src [src] user [user]" + + return (((t5!=0)&1)<<1) | ((usingWeapon!=0)&1) | CANREACH_ALLOWED + else + if (istype(src, /obj/screen)) + if (ignoreNextMoveTime!=0) + if (user.next_move < world.time) + user.prev_move = user.next_move + user.next_move = world.time + 10 + else + return 0 + return (((t5!=0)&1)<<1) | ((usingWeapon!=0)&1) | CANREACH_ALLOWED + return 0 /atom/Click() if (!usr.disable_one_click) @@ -5679,197 +5873,53 @@ var/obj/item/weapon/tool = user:checkIsOurTool(src) if (tool!=null) if (tool==W) - user.client_mob() << "user clicked their active tool." + //user.client_mob() << "Debug message: user clicked their active tool." spawn(0) W.attack_self(user) user:updateToolIcon(W) return else - user.client_mob() << "user switched tools from [W] to [tool]" + //user.client_mob() << "Debug message: user switched tools from [W] to [tool]" user:selectTool(tool) return else - user.client_mob() << "That's not one of our tools" + //user.client_mob() << "Debug message: That's not one of our tools" user:pressIfDroneButton(src) if (W == src) - user.client_mob() << "user clicked their active item." + //user.client_mob() << "Debug message: user clicked their active item." spawn(0) W.attack_self(user) - return + return - if (((!user.canmove) && (!istype(user, /mob/ai))) || user.stat != 0) - - return - if ((!(src in user.contents) && (((!(isturf(src)) && (!(isturf(src.loc)) && (src.loc && !(isturf(src.loc.loc))))) || !(isturf(user.loc))) && (src.loc != user.loc && (!(istype(src, /obj/screen)) && !(user.contents.Find(src.loc))))))) - return - /* Breaks double-clicking on an equipment slot to place an item there, unfortunately. */ - /* - // If the dclicked item is in our inventory - if (!(src in user.contents)) - // If the item is not a turf, and it is not on a turf, and it is inside something else which is not in a turf - if (!(isturf(src)) && (!(isturf(src.loc)) && (src.loc && !(isturf(src.loc.loc))))) - return - // If not, if we are inside some item instead of on a turf, and the dclicked item is not in the same place as us, and the dclicked item is not a screen object, - // and the dclicked item is not inside an item in our inventory. - else if ((!(isturf(user.loc))) && (src.loc != user.loc && (!(istype(src, /obj/screen)) && !(user.contents.Find(src.loc))))) - return - */ - - /* That's checking to see if it's being held/worn or something like that, methinks. */ - var/t5 = (get_dist(src, user) <= 1 || src.loc == user) - if (istype(user, /mob/ai)) - t5 = 1 - else if (istype(user, /mob/drone)) + var/retval = src.canReach(user, W, 0) + + if (retval==0) + return + + if (istype(user, /mob/drone)) if (user:selectedTool == user:aiInterface) if (istype(user:controlledBy, /mob/ai)) - t5 = 1 user = user:controlledBy W = null - - if ((istype(src, /obj/item/weapon/organ) && src in user.contents)) - var/mob/human/H = user - user.client_mob() << "Betchya think you're really smart trying to remove your own body parts aren't ya!" - if (istype(user, /mob/human)) - if (!(src == H.l_store || src == H.r_store)) - return - else - return - /* Suggested fix for Bug #1952091. */ - var/turf/turfLoc = (istype(src, /turf) ? src : src.loc) - - /* flag 16 in this case apparently disables the distance check and the alternate 'is in contents' check in the var/t5 line. It's used on guns, for instance. */ - if (((t5 || (W && (W.flags & 16))) && !(istype(src, /obj/screen)))) - if (user.next_move < world.time) - user.prev_move = user.next_move - user.next_move = world.time + 10 - else - return - if ((turfLoc && (get_dist(src, user) < 2 || turfLoc == user.loc))) - var/direct = get_dir(user, src) - var/obj/item/weapon/dummy/D = new /obj/item/weapon/dummy(user.loc) - var/ok = 0 - if ((direct - 1) & direct) - var/turf/T - switch(direct) - if(5.0) - T = get_step(user, NORTH) - if (T.Enter(D, src)) - D.loc = T - T = turfLoc - if (T.Enter(D, src)) - ok = 1 - else - T = get_step(user, EAST) - if (T.Enter(D, src)) - D.loc = T - T = turfLoc - if (T.Enter(D, src)) - ok = 1 - if(6.0) - T = get_step(user, SOUTH) - if (T.Enter(D, src)) - D.loc = T - T = turfLoc - if (T.Enter(D, src)) - ok = 1 - else - T = get_step(user, EAST) - if (T.Enter(D, src)) - D.loc = T - T = turfLoc - if (T.Enter(D, src)) - ok = 1 - if(9.0) - T = get_step(user, NORTH) - if (T.Enter(D, src)) - D.loc = T - T = turfLoc - if (T.Enter(D, src)) - ok = 1 - else - T = get_step(user, WEST) - if (T.Enter(D, src)) - D.loc = T - T = turfLoc - if (T.Enter(D, src)) - ok = 1 - if(10.0) - T = get_step(user, SOUTH) - if (T.Enter(D, src)) - D.loc = T - T = turfLoc - if (T.Enter(D, src)) - ok = 1 - else - T = get_step(user, WEST) - if (T.Enter(D, src)) - D.loc = T - T = turfLoc - if (T.Enter(D, src)) - ok = 1 - else - else - if (turfLoc.Enter(D, src)) - ok = 1 - else - if ((src.flags & 512 && get_dir(src, user) & src.dir)) - ok = 1 - if (user.loc != turfLoc) - for(var/atom/A in user.loc) - if ((!A.CheckExit(user, src.loc)) && A != user) - ok = 0 - del(D) - if (!(ok)) - return 0 - if (!user.restrained()) - if (W) - if (t5) - src.attackby(W, user) + + if (!(retval & CANREACH_USINGWEAPON)) + W = null + + //if (((t5 || (usingWeapon && (usingWeapon.flags & 16))) && !(istype(src, /obj/screen)))) + + if (retval & CANREACH_ALLOWED) + if (!(istype(src, /obj/screen))) + if (!user.restrained()) if (W) - W.afterattack(src, user, (t5 ? 1 : 0)) - else - if (istype(user, /mob/human) || istype(user, /mob/drone)) - src.attack_hand(user, user.hand) - else - if (istype(user, /mob/monkey)) - src.attack_paw(user, user.hand) - else - if (istype(user, /mob/ai)) - src.attack_ai(user, user.hand) - else - if (istype(user, /mob/human)) - src.hand_h(user, user.hand) - else - if (istype(user, /mob/monkey)) - src.hand_p(user, user.hand) - else - if (istype(user, /mob/ai)) - src.hand_a(user, user.hand) - - else - if (istype(src, /obj/screen)) - user.prev_move = user.next_move - if (user.next_move < world.time) - user.next_move = world.time + 10 - else - return - if (!( user.restrained() )) - if ((W && !( istype(src, /obj/screen) ))) - src.attackby(W, user) + if (retval & CANREACH_CANTOUCH) + src.attackby(W, user) if (W) - W.afterattack(src, user) + W.afterattack(src, user, ((retval & CANREACH_CANTOUCH) ? 1 : 0)) else - if (istype(user, /mob/human)) + if (istype(user, /mob/human) || istype(user, /mob/drone)) src.attack_hand(user, user.hand) else if (istype(user, /mob/monkey)) src.attack_paw(user, user.hand) - else - if (istype(user, /mob/human)) - src.hand_h(user, user.hand) - else - if (istype(user, /mob/monkey)) - src.hand_p(user, user.hand) - return /obj/proc/updateDialog() @@ -5893,4 +5943,10 @@ for(var/mob/M in nearby) if ((M.client && M.machine == src)) src:attack_self(M) - AutoUpdateAI(src, 1) + +//Used for infra_sensor, etc +/obj/proc/updateSelfDialog(atom/origin) + var/list/nearby = viewers(1, origin) + for(var/mob/M in nearby) + if (M.client) + src:attack_self(M) diff --git a/Code/mob.dm b/Code/mob.dm index b77ae09..253436f 100644 --- a/Code/mob.dm +++ b/Code/mob.dm @@ -1087,8 +1087,8 @@ if ((src.item && src.source.equipped() != src.item)) return if ((src.source.restrained() || src.source.stat)) - return - + return + switch(src.place) if("mask") if (src.target.wear_mask) @@ -1866,7 +1866,7 @@ return /mob/human/proc/monkeyize() - if (src.currentDrone!=null) + if (src.currentDrone!=null) src.currentDrone:releaseControl(0) if (src.monkeyizing) return @@ -2385,8 +2385,8 @@ //src.paralysis += 1 src.show_message("\red The blob attacks you!") - src.damage_anywhere(damage) - + src.damage_anywhere(damage) + /mob/human/proc/damage_anywhere(damage) var/list/zones = list("head","chest","chest", "diaper", "l_arm", "r_arm", "l_hand", "r_hand", "l_leg", "r_leg", "l_foot", "r_foot") @@ -2732,68 +2732,68 @@ src.sdisabilities = 0 src.stat = 0 -*/ - +*/ + /* IMPORTANT NOTE: Both humans and drones have a copy of this code. If the code is modified to fix a bug or whatever, it will need to be modified in BOTH of them. Monkeys also have some of this code, but not all of it. (Moving the code into a shared method or two wasn't feasible because of where the ..() calls are and such) --shadowlord13 */ /mob/human/Move(a, b, flag) - if (src.buckled) - return - if (src.restrained()) - src.pulling = null - var/t7 = 1 - if (src.restrained()) - for(var/mob/M in range(src, 1)) - if ((M.pulling == src && M.stat == 0 && !( M.restrained() ))) - t7 = null - //Foreach goto(62) - if ((t7 && (src.pulling && ((get_dist(src, src.pulling) <= 1 || src.pulling.loc == src.loc) && (src.client && src.client.moving))))) - var/turf/T = src.loc - . = ..() - if (!( isturf(src.pulling.loc) )) - src.pulling = null - return - ////// - if (src.pulling.anchored) - src.pulling = null - return - if (istype(src.pulling, /mob/drone) && config.walkable_not_pullable_drones) - src.pulling = null - return - ////// - if (!( src.restrained() )) - var/diag = get_dir(src, src.pulling) - if ((diag - 1) & diag) - else - diag = null - if ((get_dist(src, src.pulling) > 1 || diag)) - if (ismob(src.pulling)) - var/mob/M = src.pulling - var/ok = 1 - if (locate(/obj/item/weapon/grab, M.grabbed_by.len)) - if (prob(75)) - var/obj/item/weapon/grab/G = pick(M.grabbed_by) - if (istype(G, /obj/item/weapon/grab)) - for(var/mob/O in viewers(M, null)) - O.show_message(text("\red [] has been pulled from []'s grip by []", G.affecting, G.assailant, src), 1) - //Foreach goto(354) - //G = null - del(G) - else - ok = 0 - if (locate(/obj/item/weapon/grab, M.grabbed_by.len)) - ok = 0 - if (ok) - var/t = M.pulling - M.pulling = null - step(src.pulling, get_dir(src.pulling.loc, T)) - M.pulling = t - else - step(src.pulling, get_dir(src.pulling.loc, T)) - else - src.pulling = null - . = ..() - if ((src.s_active && !( s_active in src.contents ) )) - src.s_active.close(src) + if (src.buckled) + return + if (src.restrained()) + src.pulling = null + var/t7 = 1 + if (src.restrained()) + for(var/mob/M in range(src, 1)) + if ((M.pulling == src && M.stat == 0 && !( M.restrained() ))) + t7 = null + //Foreach goto(62) + if ((t7 && (src.pulling && ((get_dist(src, src.pulling) <= 1 || src.pulling.loc == src.loc) && (src.client && src.client.moving))))) + var/turf/T = src.loc + . = ..() + if (!( isturf(src.pulling.loc) )) + src.pulling = null + return + ////// + if (src.pulling.anchored) + src.pulling = null + return + if (istype(src.pulling, /mob/drone) && config.walkable_not_pullable_drones) + src.pulling = null + return + ////// + if (!( src.restrained() )) + var/diag = get_dir(src, src.pulling) + if ((diag - 1) & diag) + else + diag = null + if ((get_dist(src, src.pulling) > 1 || diag)) + if (ismob(src.pulling)) + var/mob/M = src.pulling + var/ok = 1 + if (locate(/obj/item/weapon/grab, M.grabbed_by.len)) + if (prob(75)) + var/obj/item/weapon/grab/G = pick(M.grabbed_by) + if (istype(G, /obj/item/weapon/grab)) + for(var/mob/O in viewers(M, null)) + O.show_message(text("\red [] has been pulled from []'s grip by []", G.affecting, G.assailant, src), 1) + //Foreach goto(354) + //G = null + del(G) + else + ok = 0 + if (locate(/obj/item/weapon/grab, M.grabbed_by.len)) + ok = 0 + if (ok) + var/t = M.pulling + M.pulling = null + step(src.pulling, get_dir(src.pulling.loc, T)) + M.pulling = t + else + step(src.pulling, get_dir(src.pulling.loc, T)) + else + src.pulling = null + . = ..() + if ((src.s_active && !( s_active in src.contents ) )) + src.s_active.close(src) return /mob/human/examine() @@ -2837,7 +2837,7 @@ /mob/human/Logout() - if (src.droneTransitioning==1) + if (src.droneTransitioning==1) return if(config.logaccess) world.log << "LOGOUT: [src.key]" if (!( src.start )) @@ -2928,10 +2928,10 @@ return /mob/human/Login() - if (src.droneTransitioning==1) - ..() - return - + if (src.droneTransitioning==1) + ..() + return + if(config.logaccess) world.log << "LOGIN: [src.key] from [src.client.address]" src.lastKnownIP = src.client.address @@ -3057,6 +3057,9 @@ src.verbs += /proc/Vars src << text("\blue []", world_message) src << browse(text("[]", changes), "window=changes") + if (!( isturf(src.loc) )) + src.client.eye = src.loc + src.client.perspective = EYE_PERSPECTIVE if (!( src.start )) src.savefile_load() ShowChoices() @@ -3068,30 +3071,30 @@ //Foreach goto(1473) src.loc = pick(L) - + return /mob/human/Bump(atom/movable/AM as mob|obj, yes) - spawn( 0 ) - if ((!( yes ) || src.now_pushing)) - return - ..() + spawn( 0 ) + if ((!( yes ) || src.now_pushing)) + return + ..() src.PushingBump(AM, yes) return - -/mob/proc/PushingBump(atom/movable/AM as mob|obj, yes) - if (!( istype(AM, /atom/movable) )) - return - if (!( src.now_pushing )) - src.now_pushing = 1 - if (!( AM.anchored )) - /* If it's a drone and walkable_not_pullable_drones is set, you CAN'T pull it. --shadowlord13 */ - if (!(istype(src, /mob/drone) && config.walkable_not_pullable_drones)) - var/t = get_dir(src, AM) - step(AM, t) - src.now_pushing = null - return - + +/mob/proc/PushingBump(atom/movable/AM as mob|obj, yes) + if (!( istype(AM, /atom/movable) )) + return + if (!( src.now_pushing )) + src.now_pushing = 1 + if (!( AM.anchored )) + /* If it's a drone and walkable_not_pullable_drones is set, you CAN'T pull it. --shadowlord13 */ + if (!(istype(src, /mob/drone) && config.walkable_not_pullable_drones)) + var/t = get_dir(src, AM) + step(AM, t) + src.now_pushing = null + return + /mob/human/death() if (src.currentDrone!=null) src.currentDrone:releaseControl() @@ -3142,9 +3145,9 @@ if (src.shoes.chained) tally += 15 else - tally += -1.0 - if (src.pulling) - if (istype(src.pulling, /mob/drone)) + tally += -1.0 + if (src.pulling) + if (istype(src.pulling, /mob/drone)) tally += 5 return tally @@ -3698,7 +3701,7 @@ else src.screenOrBackupRemove(src.hud_used.blurry) if (src.stat != 2) - if (src.client) + if (src.client) if (src.machine) if (!( src.machine.check_eye(src) )) src.reset_view(null) @@ -3908,6 +3911,10 @@ L += hearers(1, null) obj_range = 1 italics = 1 + else if (pre == "\[d\]" && usr.currentDrone) + message = copytext(message, 4, length(message) + 1) + L += hearers(1, null) + usr = usr.currentDrone else if (pre == "\[l\]") message = copytext(message, 4, length(message) + 1) @@ -3952,8 +3959,20 @@ if (italics) message = text("[]", message) if (((src.oxygen && src.oxygen.icon_state == "oxy0") || (!( (istype(T, /turf) || istype(T, /obj/move)) ) || T.oxygen > 0))) + var/speakerType = src.type + if (istype(src, /mob/drone)) + var/mob/drone/drone = src + var/mob/owner = drone.controlledBy + if (owner!=null) + speakerType = owner.type for(var/mob/M in L) - if (istype(M, src.type) || istype(M, /mob/ai)) + var/mobType = M.type + if (istype(M, /mob/drone)) + var/mob/drone/Mdrone = M + var/mob/Mowner = Mdrone.controlledBy + if (Mowner!=null) + mobType = Mowner.type + if (istype(M, speakerType) || istype(M, /mob/ai) || (istype(M, /mob/drone) && mobType==speakerType)) M.show_message(text("[][]: []", src.rname, alt_name, message), 2) else M.show_message(text("The human: []", stars(message)), 2) @@ -3970,11 +3989,11 @@ return /mob/human/UpdateClothing() - + ..() if (src.monkeyizing) - return - + return + if (!( src.w_uniform )) var/obj/item/weapon/W = src.r_store if (W) @@ -4378,51 +4397,51 @@ /mob/human/attack_hand(mob/M as mob) if (!ticker) M << "You cannot attack people before the game has started." - return - - var/intentToApply = M.a_intent - var/aiControllingBonus = 0 - var/corruptedIntent = 0 - - if (istype(M, /mob/drone)) - var/mob/owner = M:controlledBy - if (owner!=null && istype(owner, /mob/ai)) - aiControllingBonus = 1 - else - if (M.a_intent=="help") - corruptedIntent = prob(50) - if (corruptedIntent) - if (prob(75)) //push down - intentToApply = "disarm" - else - intentToApply = "hurt" - else if (M.a_intent == "grab") - corruptedIntent = prob(50) - if (corruptedIntent) - if (prob(10)) //push down - intentToApply = "disarm" - else - intentToApply = "hurt" - else if (M.a_intent == "hurt") - corruptedIntent = prob(30) - if (corruptedIntent) - if (prob(20)) //push down - intentToApply = "disarm" - else - intentToApply = "grab" - else //disarm - corruptedIntent = prob(50) - if (corruptedIntent) - if (prob(50)) - M.client_mob() << "You tried to disarm them, but managed to miss entirely." - for(var/mob/O in viewers(src, null)) - O.show_message(text("\blue [] attempted to disarm [], but completely missed!", M, src), 1) - return - //otherwise we push them down - + return + + var/intentToApply = M.a_intent + var/aiControllingBonus = 0 + var/corruptedIntent = 0 + + if (istype(M, /mob/drone)) + var/mob/owner = M:controlledBy + if (owner!=null && istype(owner, /mob/ai)) + aiControllingBonus = 1 + else + if (M.a_intent=="help") + corruptedIntent = prob(50) + if (corruptedIntent) + if (prob(75)) //push down + intentToApply = "disarm" + else + intentToApply = "hurt" + else if (M.a_intent == "grab") + corruptedIntent = prob(50) + if (corruptedIntent) + if (prob(10)) //push down + intentToApply = "disarm" + else + intentToApply = "hurt" + else if (M.a_intent == "hurt") + corruptedIntent = prob(30) + if (corruptedIntent) + if (prob(20)) //push down + intentToApply = "disarm" + else + intentToApply = "grab" + else //disarm + corruptedIntent = prob(50) + if (corruptedIntent) + if (prob(50)) + M.client_mob() << "You tried to disarm them, but managed to miss entirely." + for(var/mob/O in viewers(src, null)) + O.show_message(text("\blue [] attempted to disarm [], but completely missed!", M, src), 1) + return + //otherwise we push them down + if (intentToApply == "help") - if (istype(M, /mob/human)) - var/mob/human/H = M + if (istype(M, /mob/human)) + var/mob/human/H = M if (src.health > 0) if (src.w_uniform) src.w_uniform.add_fingerprint(M) @@ -4446,16 +4465,16 @@ spawn( 0 ) O.process() return - else if (istype(M, /mob/drone)) - if (src.health > 0) - if (src.w_uniform) - src.w_uniform.add_fingerprint(M) - src.sleeping = 0 - src.resting = 0 - for(var/mob/O in viewers(src, null)) - O.show_message(text("\blue [] shakes [] trying to wake [] up!", M, src, src), 1) - //Foreach goto(80) - else + else if (istype(M, /mob/drone)) + if (src.health > 0) + if (src.w_uniform) + src.w_uniform.add_fingerprint(M) + src.sleeping = 0 + src.resting = 0 + for(var/mob/O in viewers(src, null)) + O.show_message(text("\blue [] shakes [] trying to wake [] up!", M, src, src), 1) + //Foreach goto(80) + else M << "They need CPR, and you can't perform it through this drone!" else if (intentToApply == "grab") @@ -4479,10 +4498,13 @@ else if (M.stat < 2) if (intentToApply == "hurt") - if (istype(M, /mob/human)) + if (istype(M, /mob/human)) if (src.w_uniform) src.w_uniform.add_fingerprint(M) var/damage = rand(1, 9) + //This gives a damage bonus when the AI is controlling the drone. For now, it doesn't check their weapon or target zone. + if (aiControllingBonus && (!corruptedIntent)) + damage += rand(9, 18) var/obj/item/weapon/organ/external/affecting = src.organs["chest"] var/t = M.zone_sel.selecting if ((t in list( "hair", "eyes", "mouth", "neck" ))) @@ -4559,16 +4581,16 @@ O.show_message(text("\red [] has attempted to punch []!", M, src), 1) //Foreach goto(1419) return - else if (istype(M, /mob/drone)) - var/damage = 0 - if (corruptedIntent) - damage = rand(0, 5) - else - damage = rand(5, 14) - for(var/mob/O in viewers(src, null)) - O.show_message(text("\red [] has smacked [] with its arm!", M, src), 1) - if (corruptedIntent) - M << "Oops! You've accidentally hit them." + else if (istype(M, /mob/drone)) + var/damage = 0 + if (corruptedIntent) + damage = rand(0, 5) + else + damage = rand(5, 14) + for(var/mob/O in viewers(src, null)) + O.show_message(text("\red [] has smacked [] with its arm!", M, src), 1) + if (corruptedIntent) + M << "Oops! You've accidentally hit them." src.damage_anywhere(damage) else if (!( src.lying )) @@ -4589,11 +4611,11 @@ else for(var/mob/O in viewers(src, null)) O.show_message(text("\red [] has attempted to disarm []!", M, src), 1) - //Foreach goto(1643) - if (corruptedIntent) - if (M.a_intent == "help") - M.client_mob() << "You failed to help [src] due to poor control over the drone, and may have knocked \him down, but at least you have not hurt \him." - else if (M.a_intent == "grab") + //Foreach goto(1643) + if (corruptedIntent) + if (M.a_intent == "help") + M.client_mob() << "You failed to help [src] due to poor control over the drone, and may have knocked \him down, but at least you have not hurt \him." + else if (M.a_intent == "grab") M.client_mob() << "You failed to grab [src] due to poor control over the drone, and may have knocked \him down, but at least you have not hurt \him." return @@ -4835,10 +4857,11 @@ return /mob/human/show_inv(mob/user as mob) - user.machine = src - var/dat = text("
\n[]\n\tHead(Mask): []\n\t\tHeadset: []\n\tLeft Hand: []\n\tRight Hand: []\n\tGloves: []\n\tEyes: []\n\tEars: []\n\tHead: []\n\tShoes: []\n\tBelt: []\n\tUniform: []\n\t(Exo)Suit: []\n\tBack: [] []\n\tID: []\n\t[]\n\t[]\n\tEmpty Pockets\nClose\n
", src.name, src, (src.wear_mask ? text("[]", src.wear_mask) : "Nothing"), src, (src.w_radio ? text("[]", src.w_radio) : "Nothing"), src, (src.l_hand ? text("[]", src.l_hand) : "Nothing"), src, (src.r_hand ? text("[]", src.r_hand) : "Nothing"), src, (src.gloves ? text("[]", src.gloves) : "Nothing"), src, (src.glasses ? text("[]", src.glasses) : "Nothing"), src, (src.ears ? text("[]", src.ears) : "Nothing"), src, (src.head ? text("[]", src.head) : "Nothing"), src, (src.shoes ? text("[]", src.shoes) : "Nothing"), src, (src.belt ? text("[]", src.belt) : "Nothing"), src, (src.w_uniform ? text("[]", src.w_uniform) : "Nothing"), src, (src.wear_suit ? text("[]", src.wear_suit) : "Nothing"), src, (src.back ? text("[]", src.back) : "Nothing"), ((istype(src.wear_mask, /obj/item/weapon/clothing/mask) && istype(src.back, /obj/item/weapon/tank) && !( src.internal )) ? text(" Set Internal", src) : ""), src, (src.wear_id ? text("[]", src.wear_id) : "Nothing"), (src.handcuffed ? text("Handcuffed", src) : text("Not Handcuffed", src)), (src.internal ? text("Remove Internal", src) : ""), src, user, url_encode(src.name)) - user << browse(dat, text("window=mob[];size=300x600", url_encode(src.name))) - return + if (istype(user, /mob/human) || istype(user, /mob/monkey) || (istype(user, /mob/drone) && user.equipped()==null)) //AI should not be able to do this, and drone can only do it if they're using the gripper + user.machine = src + var/dat = text("
\n[]\n\tHead(Mask): []\n\t\tHeadset: []\n\tLeft Hand: []\n\tRight Hand: []\n\tGloves: []\n\tEyes: []\n\tEars: []\n\tHead: []\n\tShoes: []\n\tBelt: []\n\tUniform: []\n\t(Exo)Suit: []\n\tBack: [] []\n\tID: []\n\t[]\n\t[]\n\tEmpty Pockets\nClose\n
", src.name, src, (src.wear_mask ? text("[]", src.wear_mask) : "Nothing"), src, (src.w_radio ? text("[]", src.w_radio) : "Nothing"), src, (src.l_hand ? text("[]", src.l_hand) : "Nothing"), src, (src.r_hand ? text("[]", src.r_hand) : "Nothing"), src, (src.gloves ? text("[]", src.gloves) : "Nothing"), src, (src.glasses ? text("[]", src.glasses) : "Nothing"), src, (src.ears ? text("[]", src.ears) : "Nothing"), src, (src.head ? text("[]", src.head) : "Nothing"), src, (src.shoes ? text("[]", src.shoes) : "Nothing"), src, (src.belt ? text("[]", src.belt) : "Nothing"), src, (src.w_uniform ? text("[]", src.w_uniform) : "Nothing"), src, (src.wear_suit ? text("[]", src.wear_suit) : "Nothing"), src, (src.back ? text("[]", src.back) : "Nothing"), ((istype(src.wear_mask, /obj/item/weapon/clothing/mask) && istype(src.back, /obj/item/weapon/tank) && !( src.internal )) ? text(" Set Internal", src) : ""), src, (src.wear_id ? text("[]", src.wear_id) : "Nothing"), (src.handcuffed ? text("Handcuffed", src) : text("Not Handcuffed", src)), (src.internal ? text("Remove Internal", src) : ""), src, user, url_encode(src.name)) + user << browse(dat, text("window=mob[];size=300x600", url_encode(src.name))) + return /mob/proc/show_message(msg, type, alt, alt_type) @@ -5029,11 +5052,10 @@ return /mob/proc/show_inv(mob/user as mob) - - user.machine = src - var/dat = text("\n[]
\n\tHead(Mask): []
\n\tLeft Hand: []
\n\tRight Hand: []
\n\tBack: []
\n\t[]
\n\t[]
\n\t[]
\n\tEmpty Pockets
\nClose
\n
", src.name, src, (src.wear_mask ? text("[]", src.wear_mask) : "Nothing"), src, (src.l_hand ? text("[]", src.l_hand) : "Nothing"), src, (src.r_hand ? text("[]", src.r_hand) : "Nothing"), src, (src.back ? text("[]", src.back) : "Nothing"), ((istype(src.wear_mask, /obj/item/weapon/clothing/mask) && istype(src.back, /obj/item/weapon/tank) && !( src.internal )) ? text(" Set Internal", src) : ""), (src.internal ? text("Remove Internal", src) : ""), (src.handcuffed ? text("Handcuffed", src) : text("Not Handcuffed", src)), src, user, src.name) - user << browse(dat, text("window=mob[]", html_encode(src.name))) - return + if (istype(user, /mob/human) || istype(user, /mob/monkey) || (istype(user, /mob/drone) && user.equipped()==null)) //AI should not be able to do this, and drone can only do it if they're using the gripper + user.machine = src + var/dat = text("\n[]
\n\tHead(Mask): []
\n\tLeft Hand: []
\n\tRight Hand: []
\n\tBack: []
\n\t[]
\n\t[]
\n\t[]
\n\tEmpty Pockets
\nClose
\n
", src.name, src, (src.wear_mask ? text("[]", src.wear_mask) : "Nothing"), src, (src.l_hand ? text("[]", src.l_hand) : "Nothing"), src, (src.r_hand ? text("[]", src.r_hand) : "Nothing"), src, (src.back ? text("[]", src.back) : "Nothing"), ((istype(src.wear_mask, /obj/item/weapon/clothing/mask) && istype(src.back, /obj/item/weapon/tank) && !( src.internal )) ? text(" Set Internal", src) : ""), (src.internal ? text("Remove Internal", src) : ""), (src.handcuffed ? text("Handcuffed", src) : text("Not Handcuffed", src)), src, user, src.name) + user << browse(dat, text("window=mob[]", url_encode(src.name))) /mob/proc/u_equip(W as obj) @@ -5273,8 +5295,8 @@ del(O) //Foreach goto(20) var/mob/monkey/O = new /mob/monkey( M.loc ) - if (M.currentDrone!=null) - M.currentDrone:releaseControl(0) + if (M.currentDrone!=null) + M.currentDrone:releaseControl(0) M.client.mob = O O.loc = M.loc //M = null @@ -5621,52 +5643,52 @@ src << "If you had changed the HUD before the game started, your savefile would be updated to remember that you prefer that HUD." src.client.screen -= src.hud_used.adding src.client.screen += src.hud_used.adding - return - + return + /mob/Login() if(ticker && master_mode == "sandbox" && src.sandbox==null) src.CanBuild() src.sight |= SEE_SELF - if (CanAdmin()) - if (src.droneTransitioning==0) - src << text("\blue The game ip is byond://[]:[] !", world.address, world.port) - src.verbs += /mob/proc/mute - src.verbs += /mob/proc/changemessage - src.verbs += /mob/proc/boot - src.verbs += /mob/proc/changemode - src.verbs += /mob/proc/restart - src.verbs += /mob/proc/who - src.verbs += /mob/proc/change_name - src.verbs += /mob/proc/show_help - src.verbs += /mob/proc/toggle_ooc - src.verbs += /mob/proc/toggle_abandon - src.verbs += /mob/proc/toggle_enter - src.verbs += /mob/proc/toggle_ai - src.verbs += /mob/proc/toggle_shuttle - src.verbs += /mob/proc/delay_start - src.verbs += /mob/proc/start_now - src.verbs += /mob/proc/worldsize - src.verbs += /mob/proc/make_gift - src.verbs += /mob/proc/make_flag - src.verbs += /mob/proc/make_pill - src.verbs += /mob/proc/show_ctf - src.verbs += /mob/proc/ban - src.verbs += /mob/proc/unban - src.verbs += /mob/proc/secrets - src.verbs += /mob/proc/carboncopy - src.verbs += /mob/proc/toggle_alter - src.verbs += /mob/proc/list_dna - src.verbs += /proc/Vars - - ..() + if (CanAdmin()) + if (src.droneTransitioning==0) + src << text("\blue The game ip is byond://[]:[] !", world.address, world.port) + src.verbs += /mob/proc/mute + src.verbs += /mob/proc/changemessage + src.verbs += /mob/proc/boot + src.verbs += /mob/proc/changemode + src.verbs += /mob/proc/restart + src.verbs += /mob/proc/who + src.verbs += /mob/proc/change_name + src.verbs += /mob/proc/show_help + src.verbs += /mob/proc/toggle_ooc + src.verbs += /mob/proc/toggle_abandon + src.verbs += /mob/proc/toggle_enter + src.verbs += /mob/proc/toggle_ai + src.verbs += /mob/proc/toggle_shuttle + src.verbs += /mob/proc/delay_start + src.verbs += /mob/proc/start_now + src.verbs += /mob/proc/worldsize + src.verbs += /mob/proc/make_gift + src.verbs += /mob/proc/make_flag + src.verbs += /mob/proc/make_pill + src.verbs += /mob/proc/show_ctf + src.verbs += /mob/proc/ban + src.verbs += /mob/proc/unban + src.verbs += /mob/proc/secrets + src.verbs += /mob/proc/carboncopy + src.verbs += /mob/proc/toggle_alter + src.verbs += /mob/proc/list_dna + src.verbs += /proc/Vars + + ..() return /mob/CheckPass(mob/M as mob) if (istype(M, /mob)) //BYOND calls functions even when the passed parameters are not the specified types - if (config.walkable_not_pullable_drones) - if (istype(src, /mob) && (istype(src, /mob/drone) ^ istype(M, /mob/drone))) - return 1 + if (config.walkable_not_pullable_drones) + if (istype(src, /mob) && (istype(src, /mob/drone) ^ istype(M, /mob/drone))) + return 1 if ((src.other_mobs && ismob(M) && M.other_mobs)) return 1 else @@ -5957,11 +5979,11 @@ return /mob/monkey/Bump(atom/movable/AM as mob|obj, yes) - spawn( 0 ) - if ((!( yes ) || src.now_pushing)) - return - ..() - src.PushingBump(AM, yes) + spawn( 0 ) + if ((!( yes ) || src.now_pushing)) + return + ..() + src.PushingBump(AM, yes) return /mob/monkey/Topic(href, href_list) @@ -6063,49 +6085,49 @@ return /mob/monkey/attack_hand(mob/M as mob) - if (!ticker) - M << "You cannot attack people before the game has started." - return - var/intentToApply = M.a_intent - var/aiControllingBonus = 0 - var/corruptedIntent = 0 - - if (istype(M, /mob/drone)) - var/mob/owner = M:controlledBy - if (owner!=null && istype(owner, /mob/ai)) - aiControllingBonus = 1 - else - if (M.a_intent=="help") - corruptedIntent = prob(50) - if (corruptedIntent) - if (prob(75)) //push down - intentToApply = "disarm" - else - intentToApply = "hurt" - else if (M.a_intent == "grab") - corruptedIntent = prob(50) - if (corruptedIntent) - if (prob(10)) //push down - intentToApply = "disarm" - else - intentToApply = "hurt" - else if (M.a_intent == "hurt") - corruptedIntent = prob(30) - if (corruptedIntent) - if (prob(20)) //push down - intentToApply = "disarm" - else - intentToApply = "grab" - else //disarm - corruptedIntent = prob(50) - if (corruptedIntent) - if (prob(50)) - M.client_mob() << "You tried to disarm them, but managed to miss entirely." - for(var/mob/O in viewers(src, null)) - O.show_message(text("\blue [] attempted to disarm [], but completely missed!", M, src), 1) - return - //otherwise we push them down - + if (!ticker) + M << "You cannot attack people before the game has started." + return + var/intentToApply = M.a_intent + var/aiControllingBonus = 0 + var/corruptedIntent = 0 + + if (istype(M, /mob/drone)) + var/mob/owner = M:controlledBy + if (owner!=null && istype(owner, /mob/ai)) + aiControllingBonus = 1 + else + if (M.a_intent=="help") + corruptedIntent = prob(50) + if (corruptedIntent) + if (prob(75)) //push down + intentToApply = "disarm" + else + intentToApply = "hurt" + else if (M.a_intent == "grab") + corruptedIntent = prob(50) + if (corruptedIntent) + if (prob(10)) //push down + intentToApply = "disarm" + else + intentToApply = "hurt" + else if (M.a_intent == "hurt") + corruptedIntent = prob(30) + if (corruptedIntent) + if (prob(20)) //push down + intentToApply = "disarm" + else + intentToApply = "grab" + else //disarm + corruptedIntent = prob(50) + if (corruptedIntent) + if (prob(50)) + M.client_mob() << "You tried to disarm them, but managed to miss entirely." + for(var/mob/O in viewers(src, null)) + O.show_message(text("\blue [] attempted to disarm [], but completely missed!", M, src), 1) + return + //otherwise we push them down + if (intentToApply == "help") src.sleeping = 0 src.resting = 0 @@ -6115,7 +6137,7 @@ //Foreach goto(47) else if (intentToApply == "hurt") - if (istype(M, /mob/human)) + if (istype(M, /mob/human)) if ((prob(75) && src.health > 0)) for(var/mob/O in viewers(src, null)) if ((O.hasClient() && !( O.blinded ))) @@ -6132,24 +6154,27 @@ O.show_message(text("\red [] has knocked out the monkey!", M), 1) //Foreach goto(248) return + //This gives a damage bonus when the AI is controlling the drone. For now, it doesn't check their weapon or target zone. + if (aiControllingBonus && (!corruptedIntent)) + damage += rand(9, 18) src.bruteloss += damage src.health = 100 - src.oxyloss - src.toxloss - src.fireloss - src.bruteloss else for(var/mob/O in viewers(src, null)) if ((O.hasClient() && !( O.blinded ))) O.show_message(text("\red [] has attempted to punch the monkey!", M), 1) - //Foreach goto(336) - else if (istype(M, /mob/drone)) - var/damage = 0 - if (corruptedIntent) - damage = rand(0, 5) - else - damage = rand(5, 14) - for(var/mob/O in viewers(src, null)) - O.show_message(text("\red [] has smacked the monkey!", M), 1) - if (corruptedIntent) - M << "Oops! You've accidentally hit them." - src.bruteloss += damage + //Foreach goto(336) + else if (istype(M, /mob/drone)) + var/damage = 0 + if (corruptedIntent) + damage = rand(0, 5) + else + damage = rand(5, 14) + for(var/mob/O in viewers(src, null)) + O.show_message(text("\red [] has smacked the monkey!", M), 1) + if (corruptedIntent) + M << "Oops! You've accidentally hit them." + src.bruteloss += damage src.health = 100 - src.oxyloss - src.toxloss - src.fireloss - src.bruteloss else if (intentToApply == "grab") @@ -6181,12 +6206,12 @@ for(var/mob/O in viewers(src, null)) if ((O.hasClient() && !( O.blinded ))) O.show_message(text("\red [] has disarmed the monkey!", M), 1) - //Foreach goto(638) - - if (corruptedIntent) - if (M.a_intent == "help") - M.client_mob() << "You failed to help [src] due to poor control over the drone, and may have knocked \him down, but at least you have not hurt \him." - else if (M.a_intent == "grab") + //Foreach goto(638) + + if (corruptedIntent) + if (M.a_intent == "help") + M.client_mob() << "You failed to help [src] due to poor control over the drone, and may have knocked \him down, but at least you have not hurt \him." + else if (M.a_intent == "grab") M.client_mob() << "You failed to grab [src] due to poor control over the drone, and may have knocked \him down, but at least you have not hurt \him." return @@ -6268,10 +6293,10 @@ return /mob/monkey/Login() - if (src.droneTransitioning==1) - ..() - return - + if (src.droneTransitioning==1) + ..() + return + if (banned.Find(src.ckey)) //src.client = null del(src.client) @@ -6296,8 +6321,8 @@ src.hands = new /obj/screen( null ) src.sleep = new /obj/screen( null ) src.rest = new /obj/screen( null ) - - ..() + + ..() UpdateClothing() src.oxygen.icon_state = "oxy0" src.i_select.icon_state = "selector" @@ -6407,15 +6432,15 @@ src.loc = pick(L) //src << browse('help.htm', "window=help") src << text("\blue []", world_message) - if (src.loc!=null && (!( isturf(src.loc) ))) - src.client.eye = src.loc - src.client.perspective = EYE_PERSPECTIVE + if (src.loc!=null && (!( isturf(src.loc) ))) + src.client.eye = src.loc + src.client.perspective = EYE_PERSPECTIVE src.name = text("monkey ([])", copytext(md5(src.primary.uni_identity), 2, 6)) return - + /* This code is not identical to the code in /mob/human/Move or /mob/drone/Move, but it is similar. It lacks some things, it appears. --shadowlord13 */ /mob/monkey/Move() - + if ((!( src.buckled ) || src.buckled.loc != src.loc)) src.buckled = null if (src.buckled) @@ -6430,8 +6455,8 @@ //Foreach goto(93) if ((t7 && src.pulling && get_dist(src, src.pulling) <= 1)) if (src.pulling.anchored) - src.pulling = null - if (istype(src.pulling, /mob/drone) && config.walkable_not_pullable_drones) + src.pulling = null + if (istype(src.pulling, /mob/drone) && config.walkable_not_pullable_drones) src.pulling = null var/T = src.loc . = ..() @@ -7088,11 +7113,28 @@ L += src if (italics) message = text("[]", message) + var/mob/speakerType = src.type + if (istype(src, /mob/drone)) + var/mob/drone/drone = src + var/mob/owner = drone.controlledBy + if (owner!=null) + speakerType = owner.type for(var/mob/M in L) - if (istype(M, src.type)) + var/mobType = M.type + if (istype(M, /mob/drone)) + var/mob/drone/Mdrone = M + var/mob/Mowner = Mdrone.controlledBy + if (Mowner!=null) + mobType = Mowner.type + if (istype(M, speakerType) || (istype(M, /mob/drone) && mobType==speakerType)) M.show_message(text("[]: []", src, message), 2) - else - M.show_message(text("[] chimpers.", src), 2) + else if (istype(M, /mob/monkey)) + if (istype(src, /mob/drone)) + M.show_message(text("[] plays chimpering sounds from its speakers.", src), 2) + else + M.show_message(text("[] chimpers.", src), 2) + + //Foreach goto(503) for(var/obj/O in view(obj_range, null)) spawn( 0 ) @@ -7204,9 +7246,9 @@ if (!( usr )) return - if (!( src.anchored )) - /* If it's a drone and walkable_not_pullable_drones is set, you CAN'T pull it. --shadowlord13 */ - if (!(istype(src, /mob/drone) && config.walkable_not_pullable_drones)) + if (!( src.anchored )) + /* If it's a drone and walkable_not_pullable_drones is set, you CAN'T pull it. --shadowlord13 */ + if (!(istype(src, /mob/drone) && config.walkable_not_pullable_drones)) usr.pulling = src return @@ -7474,118 +7516,118 @@ return /client/Topic(href, href_list[], hsrc) - //Checking for us using a drone without the drone being our client's mob (won't happen unless we add things which are remote-controlled without the user's client transferring), and changing usr to the drone if so - src << "client/Topic(href is ([href]) href_list is ([href_list]) hsrc is ([hsrc])." - if (src.mob!=null) - src << "src.mob is [src.mob]." - if (src.mob.currentDrone!=null) - if (!istype(src.mob.currentDrone:equipped(), /obj/item/weapon/drone/aiInterface)) - src << "src.mob.currentDrone is [src.mob.currentDrone]. Setting usr." - usr = src.mob.currentDrone - src << "usr is [usr]." + //Checking for us using a drone without the drone being our client's mob (won't happen unless we add things which are remote-controlled without the user's client transferring), and changing usr to the drone if so + //src << "Debug message: client/Topic(href is ([href]) href_list is ([href_list]) hsrc is ([hsrc])." + if (src.mob!=null) + //src << "Debug message: src.mob is [src.mob]." + if (src.mob.currentDrone!=null) + if (!istype(src.mob.currentDrone:equipped(), /obj/item/weapon/drone/aiInterface)) + //src << "Debug message: src.mob.currentDrone is [src.mob.currentDrone]. Setting usr." + usr = src.mob.currentDrone + //src << "Debug message: usr is [usr]." ..() - -/* The primary purpose of client/proc/screenOrBackup, client/proc/screenOrBackupAdd, client/proc/screenOrBackupRemove, and mob/proc/client_mob (and overloaded mob/somesubclass/client_mob) is to provide a single point of change if, in the future, we need the capability to have a mob remote-controlling another mob or object without the mob's client being changed, if we want the client to have only HUD icons related to the thing they are controlling, without stopping their actual mob from having its appearance updated. An example would someone remote-controlling a torpedo. - -src.screenOrBackupAdd(value) replaces src.screen += value, and src.screenOrBackupRemove(value) replaces src.screen -= value. (All instances of that which were relevant were changed. Some which only occured during login or char setup may have been ignored.) - -Originally the robot drone was being implemented in this manner, but I didn't find any way to make verbs work, so I preserved this and switched over to changing the client while controlling a drone instead. It was tested while the drone was working in this fashion, and did work. ---shadowlord13 */ - -/client/proc/screenOrBackup() - if (src.mob!=null) - if (src.mob.currentDrone!=null) - return src.mob.currentDrone:savedDroneIcons - else if (istype(src.mob, /mob/drone)) - return src.mob:savedDroneIcons - return screen - -/client/proc/screenOrBackupAdd(value) - var/list/L = src.screenOrBackup() - L += value - -/client/proc/screenOrBackupRemove(value) - var/list/L = src.screenOrBackup() - L -= value - -/mob/proc/screenOrBackupAdd(value) - var/client/client = alwaysClient() - if (client) - client.screenOrBackupAdd(value) - -/mob/proc/screenOrBackupRemove(value) - var/client/client = alwaysClient() - if (client) - client.screenOrBackupRemove(value) - -/* These are perhaps a bit better than the screenOrBackupAdd and screenOrBackupRemove. If the mob has a client, it uses screen. If not, it checks currentDrone and uses current_mob. If it doesn't have either, it does nothing. This can replace several statements with one function call. */ -/mob/proc/eitherScreenRemove(value) - if (src.client) - src.client.screen -= value - else - src.screenOrBackupRemove(value) - -/mob/proc/eitherScreenAdd(value) - if (src.client) - src.client.screen += value - else - src.screenOrBackupAdd(value) - -/* client_mob returns the mob belonging to the actual client associated with this mob. To explain that more sensibly: - A player whose key is 'foo' joins the game, and makes a character named 'bar'. - Bar takes control of a drone. This changes foo's client from bar to the drone, but sets foo.currentDrone to bar, and sets bar.controlledBy to foo. - If you call client_mob() on bar, it will return the drone. If you call it on the drone, it will still return the drone. - - In the future, if we add remote-controlled objects or mobs which the controller's client doesn't transfer to, this should also handle that as well. Additionally, code is already in-place and fairly tested (there's one known bug: it can't push obstructions out of the way) in client/Move for supporting forwarding movement requests to the remote-controlled mob and such as well. - - --shadowlord13 -*/ -/mob/proc/client_mob() - if (src.client!=null) - return src - else - var/mob/owner = src.currentDrone - if (owner!=null) - return owner - else - return src - -/mob/proc/clientMob() - return src.client_mob() - -/mob/proc/alwaysClient() - var/mob/mob = src.client_mob() - return mob.client - -/* This is intended for use in places which loop through all the mobs in the world to find clients. It will result in those functions selecting/examining/whatever the original mobs instead of drones - if the player is controlling a drone, the player's original mob will have a non-null cliented() return value, but the drone will have null. - If called on a normal player with a client, this returns their client. - If called on a drone, this will return null whether it's controlled by a player or not. - If called on the mob which is controlling a drone, and that drone has a client, this will return that client. (If the player took control of a drone and then logged out, this will return null) - - This would be used like so: - if(M.cliented()) - M.client_mob() << browse(null, "window=vote") - M.cliented().showvote = 0 - - The old version of that was: - if(M.client) - M << browse(null, "window=vote") - M.client.showvote = 0 - - --shadowlord13 -*/ -/mob/proc/cliented() - if (src.currentDrone!=null) - return src.currentDrone:client - else if (istype(src, /mob/drone)) - return null - else - return src.client - -/mob/proc/hasClient() - if (src.client!=null) - return 1 - else if (src.currentDrone!=null && src.currentDrone:client!=null) - return 1 - else - return 0 + +/* The primary purpose of client/proc/screenOrBackup, client/proc/screenOrBackupAdd, client/proc/screenOrBackupRemove, and mob/proc/client_mob (and overloaded mob/somesubclass/client_mob) is to provide a single point of change if, in the future, we need the capability to have a mob remote-controlling another mob or object without the mob's client being changed, if we want the client to have only HUD icons related to the thing they are controlling, without stopping their actual mob from having its appearance updated. An example would someone remote-controlling a torpedo. + +src.screenOrBackupAdd(value) replaces src.screen += value, and src.screenOrBackupRemove(value) replaces src.screen -= value. (All instances of that which were relevant were changed. Some which only occured during login or char setup may have been ignored.) + +Originally the robot drone was being implemented in this manner, but I didn't find any way to make verbs work, so I preserved this and switched over to changing the client while controlling a drone instead. It was tested while the drone was working in this fashion, and did work. +--shadowlord13 */ + +/client/proc/screenOrBackup() + if (src.mob!=null) + if (src.mob.currentDrone!=null) + return src.mob.currentDrone:savedDroneIcons + else if (istype(src.mob, /mob/drone)) + return src.mob:savedDroneIcons + return screen + +/client/proc/screenOrBackupAdd(value) + var/list/L = src.screenOrBackup() + L += value + +/client/proc/screenOrBackupRemove(value) + var/list/L = src.screenOrBackup() + L -= value + +/mob/proc/screenOrBackupAdd(value) + var/client/client = alwaysClient() + if (client) + client.screenOrBackupAdd(value) + +/mob/proc/screenOrBackupRemove(value) + var/client/client = alwaysClient() + if (client) + client.screenOrBackupRemove(value) + +/* These are perhaps a bit better than the screenOrBackupAdd and screenOrBackupRemove. If the mob has a client, it uses screen. If not, it checks currentDrone and uses current_mob. If it doesn't have either, it does nothing. This can replace several statements with one function call. */ +/mob/proc/eitherScreenRemove(value) + if (src.client) + src.client.screen -= value + else + src.screenOrBackupRemove(value) + +/mob/proc/eitherScreenAdd(value) + if (src.client) + src.client.screen += value + else + src.screenOrBackupAdd(value) + +/* client_mob returns the mob belonging to the actual client associated with this mob. To explain that more sensibly: + A player whose key is 'foo' joins the game, and makes a character named 'bar'. + Bar takes control of a drone. This changes foo's client from bar to the drone, but sets foo.currentDrone to bar, and sets bar.controlledBy to foo. + If you call client_mob() on bar, it will return the drone. If you call it on the drone, it will still return the drone. + + In the future, if we add remote-controlled objects or mobs which the controller's client doesn't transfer to, this should also handle that as well. Additionally, code is already in-place and fairly tested (there's one known bug: it can't push obstructions out of the way) in client/Move for supporting forwarding movement requests to the remote-controlled mob and such as well. + + --shadowlord13 +*/ +/mob/proc/client_mob() + if (src.client!=null) + return src + else + var/mob/owner = src.currentDrone + if (owner!=null) + return owner + else + return src + +/mob/proc/clientMob() + return src.client_mob() + +/mob/proc/alwaysClient() + var/mob/mob = src.client_mob() + return mob.client + +/* This is intended for use in places which loop through all the mobs in the world to find clients. It will result in those functions selecting/examining/whatever the original mobs instead of drones - if the player is controlling a drone, the player's original mob will have a non-null cliented() return value, but the drone will have null. + If called on a normal player with a client, this returns their client. + If called on a drone, this will return null whether it's controlled by a player or not. + If called on the mob which is controlling a drone, and that drone has a client, this will return that client. (If the player took control of a drone and then logged out, this will return null) + + This would be used like so: + if(M.cliented()) + M.client_mob() << browse(null, "window=vote") + M.cliented().showvote = 0 + + The old version of that was: + if(M.client) + M << browse(null, "window=vote") + M.client.showvote = 0 + + --shadowlord13 +*/ +/mob/proc/cliented() + if (src.currentDrone!=null) + return src.currentDrone:client + else if (istype(src, /mob/drone)) + return null + else + return src.client + +/mob/proc/hasClient() + if (src.client!=null) + return 1 + else if (src.currentDrone!=null && src.currentDrone:client!=null) + return 1 + else + return 0 diff --git a/Code/mob/ai.dm b/Code/mob/ai.dm index 01739ab..12a9cf8 100644 --- a/Code/mob/ai.dm +++ b/Code/mob/ai.dm @@ -14,7 +14,7 @@ var/aiRestorePowerRoutine = 0 var/list/laws = list() flags = 258.0 - + proc/ai_camera_follow(mob/target as mob in world) set category = "AI Commands" if (usr.stat>0) @@ -25,7 +25,7 @@ usr << "You can't use the follow camera while controlling a drone." usr:cameraFollow = null return - + usr:cameraFollow = target usr << text("Follow camera mode is now following [].", target.rname) if (usr.machine == null) @@ -116,6 +116,9 @@ b_loss += 30 else return + src.bruteloss += b_loss + src.fireloss += f_loss + src.health = 100 - src.oxyloss - src.toxloss - src.fireloss - src.bruteloss examine() set src in oview() @@ -209,14 +212,14 @@ src.fire.icon_state = "fire1" else if (src.fire) src.fire.icon_state = "fire0" - - + + if (src.health <= -100.0) death() return else if (src.health < 0) src.oxyloss++ - + if (src.mach) if (src.machine) src.mach.icon_state = "mach1" @@ -257,7 +260,7 @@ spawn(1) while (src.oxyloss>0 && stat!=2) sleep(50) - src.oxyloss-=5 + src.oxyloss-=1 src.oxyloss = 0 return else if (src:aiRestorePowerRoutine==3) @@ -266,13 +269,13 @@ spawn(1) while (src.oxyloss>0 && stat!=2) sleep(50) - src.oxyloss-=5 + src.oxyloss-=1 src.oxyloss = 0 return src.toxin.icon_state = "pow0" else src.toxin.icon_state = "pow1" - + //stage = 6 src.blind.screen_loc = "1,1 to 15,15" if (src.blind.layer!=18) @@ -294,7 +297,7 @@ src.addLaw(index, "") spawn(50) while ((src:aiRestorePowerRoutine!=0) && stat!=2) - src.oxyloss += 5 + src.oxyloss += 1 sleep(50) spawn(20) @@ -516,7 +519,7 @@ src.client.screen -= list( src.oxygen, src.i_select, src.m_select, src.toxin, src.internals, src.fire, src.hands, src.healths, src.pullin, src.blind, src.flash, src.rest, src.sleep, src.mach ) src.client.screen -= list( src.zone_sel, src.oxygen, src.i_select, src.m_select, src.toxin, src.internals, src.fire, src.hands, src.healths, src.pullin, src.blind, src.flash, src.rest, src.sleep, src.mach ) src.client.screen += list( src.toxin, src.fire, src.healths ) - + if (!( isturf(src.loc) )) src.client.eye = src.loc src.client.perspective = EYE_PERSPECTIVE @@ -542,10 +545,10 @@ return - + m_delay() return 0 - + say(message as text) if(config.logsay) world.log << "SAY: [src.name]/[src.key] : [message]" @@ -570,6 +573,7 @@ var/pre = copytext(message, 1, 4) var/italics = 0 var/obj_range = null + /* //might be used in the future for looking into the bug(s) with hearing/saying things inside objects var/source = src //Didn't want to risk infinite recursion if someone somehow was outside the map, if that's possible, but did want to allow people being in closets in pods and such. -shadowlord13 if (!istype(src.loc, /turf)) @@ -578,7 +582,7 @@ source = src.loc if (!istype(src.loc, /turf)) source = src.loc - + */ if (pre == "\[w\]") message = copytext(message, 4, length(message) + 1) L += hearers(1, null) @@ -658,7 +662,7 @@ attack_paw(mob/M as mob) src.attack_hand(M) - + attack_hand(mob/M as mob) if (!ticker) M << "You cannot attack people before the game has started." @@ -684,7 +688,7 @@ M:UpdateDamageIcon() M.health = 100 - src.oxyloss - src.toxloss - src.fireloss - src.bruteloss - + else var/damage = rand(5, 10) if (prob(40)) @@ -693,7 +697,7 @@ src.health = 100 - src.oxyloss - src.fireloss - src.bruteloss for(var/mob/O in viewers(src, null)) O.show_message(text("\red [] is attacking []!", M, src), 1) - + meteorhit(obj/O as obj) for(var/mob/M in viewers(src, null)) @@ -751,7 +755,7 @@ user.machine = null user.reset_view(null) return 0 - + if (t == "Cancel") user.machine = null user.reset_view(null) @@ -767,7 +771,7 @@ spawn( 5 ) attack_ai(user) return - + else if (istype(selected, /mob/drone)) user.machine = null user.reset_view(null) @@ -813,8 +817,8 @@ var/total = 0 total += 0.25 return total - - + + switch_hud() if (src.hud_used == main_hud) src.fire.icon = 'screen.dmi' @@ -829,12 +833,12 @@ src.healths.icon = 'screen1.dmi' src.toxin.icon = 'screen1.dmi' return - + //block the take-off/put-on dialog show_inv(mob/user as mob) return - + /mob/human/proc/AIize() if (src.monkeyizing) @@ -859,7 +863,7 @@ src.toxin.screen_loc = "15,10" src.fire.screen_loc = "15,8" src.healths.screen_loc = "15,5" - + src.monkeyizing = 1 src.canmove = 0 src.icon = null diff --git a/Code/mob/drone.dm b/Code/mob/drone.dm index b227cc9..d0c8981 100644 --- a/Code/mob/drone.dm +++ b/Code/mob/drone.dm @@ -2,8 +2,8 @@ //Todo: /* + re-test: Drone hears garbled speech. Add throw button, intent buttons to drone GUI, button for releasing pull - Drone needs meteor damage, explosion damage, and laser damage Drone pull/grab should only work if gripper is empty Take-off dialog for taking things off others should work, except humans controlling a drone should have a high chance of failure and harming the person instead. should lose drone control upon going unconscious (it's already lost upon death), and also if the user is pulled/moves away from the control station @@ -16,15 +16,17 @@ Held jetpack with flight system turned on doesn't work for drone - appears to be due to lack of internal air + (Before these are implemented, the AI just has a damage bonus applied when it is controlling a drone) Implement AI-controlled drone precision attacks: - screwdriver to heart? protected by armor (may break screwdriver tool permanently), reduced damage from other suits. - lit welder to eyes? protected by helmets? - crowbar to whack items out of opponents' hands, when there's anything in them, and send them flying. If not, does damage normally to the normal area. - wrench targets kneecaps for bonus damage, knocking down, etc. + when using screwdriver, auto-aim for heart? protected by armor (may break screwdriver tool permanently), reduced damage from other suits. + when using welder, auto-aim for eyes? protected by helmets? + when using crowbar, auto-aim to whack/pull items out of opponents' hands, when there's anything in them, and send them flying. If not, does damage normally to the normal area. + when using wrench, auto-aim for kneecaps for bonus damage, knocking down, etc. wirecutters don't have a precision attack or even work well for attacking at all (one would think), and are likely to break if used. If drone gets ahold of a laser gun or loaded revolver, an AI controller will be able to precision aim it as well. Note to be very clear: If a human is controlling the drone, they do not get any of those precision bonus attacks. Those are only applied if the AI is controlling the drone. - + + Todo: When attempting to speak while controlling a drone, it should send the speech from the controller, unless you use [d], in which case the drone should say it. */ /mob/drone @@ -397,6 +399,12 @@ abiotic() return 1 + + say(message as text) + if (src.controlledBy) + if (istype(src.controlledBy, /mob/human) || istype(src.controlledBy, /mob/monkey) || istype(src.controlledBy, /mob/ai)) + usr = src.controlledBy + src.controlledBy.say(message) proc/takeControl(var/mob/user) if (user.client) @@ -673,7 +681,59 @@ show_inv(mob/user as mob) return + meteorhit(obj/O as obj) + for(var/mob/M in viewers(src, null)) + M.show_message(text("\red [] has been hit by []", src, O), 1) + //Foreach goto(19) + if (src.health > 0) + src.bruteloss += 30 + if ((O.icon_state == "flaming")) + src.fireloss += 40 + src.health = 100 - src.oxyloss - src.toxloss - src.fireloss - src.bruteloss + return + + las_act(flag) + if (flag == "bullet") + if (src.stat != 2) + src.bruteloss += 60 + src.health = 100 - src.oxyloss - src.toxloss - src.fireloss - src.bruteloss + src.weakened = 10 + if (flag) + if (prob(75)) + src.stunned = 15 + else + src.weakened = 15 + else + if (src.stat != 2) + src.bruteloss += 20 + src.health = 100 - src.oxyloss - src.toxloss - src.fireloss - src.bruteloss + if (prob(25)) + src.stunned = 1 + return + ex_act(severity) + flick("flash", src.flash) + + var/b_loss = 0 + var/f_loss = 0 + switch(severity) + if(1.0) + if (src.stat != 2) + b_loss += 100 + f_loss += 100 + if(2.0) + if (src.stat != 2) + b_loss += 60 + f_loss += 60 + if(3.0) + if (src.stat != 2) + b_loss += 30 + else + return + src.bruteloss += b_loss + src.fireloss += f_loss + src.health = 100 - src.oxyloss - src.toxloss - src.fireloss - src.bruteloss + /obj/item/weapon/drone/aiInterface name = "AI Interface" icon = 'drone.dmi' diff --git a/Code/shuttle.dm b/Code/shuttle.dm index 89f6750..621f3ef 100644 --- a/Code/shuttle.dm +++ b/Code/shuttle.dm @@ -94,7 +94,11 @@ /obj/shuttle/door/verb/open() set src in oview(1) - + var/result = src.canReach(usr, null, 1) + if (result==0) + usr.client_mob() << "You can't reach [src]." + return + src.add_fingerprint(usr) if (src.operating) return @@ -114,6 +118,10 @@ /obj/shuttle/door/proc/close() set src in oview(1) + var/result = src.canReach(usr, null, 1) + if (result==0) + usr.client_mob() << "You can't reach [src]." + return src.add_fingerprint(usr) if (src.operating) diff --git a/Code/weap_sat.dm b/Code/weap_sat.dm index de6e035..7dee730 100644 --- a/Code/weap_sat.dm +++ b/Code/weap_sat.dm @@ -33,7 +33,11 @@ if(stat & (NOPOWER|BROKEN) ) return - + var/result = src.canReach(usr, null, 1) + if (result==0) + usr.client_mob() << "You can't reach [src]." + return + var/list/L = list( ) for(var/obj/item/weapon/radio/R in world) if (R.freq != freq) @@ -67,6 +71,10 @@ if(stat & (NOPOWER|BROKEN) ) return + var/result = src.canReach(usr, null, 1) + if (result==0) + usr.client_mob() << "You can't reach [src]." + return if (t) src.id = t return @@ -136,7 +144,11 @@ /obj/machinery/teleport/station/verb/engage() set src in oview(1) if(stat & NOPOWER) return - + var/result = src.canReach(usr, null, 1) + if (result==0) + usr.client_mob() << "You can't reach [src]." + return + var/atom/l = src.loc var/atom/com = locate(/obj/machinery/teleport/hub, locate(l.x + 1, l.y, l.z)) if (com) @@ -151,7 +163,11 @@ /obj/machinery/teleport/station/verb/disengage() set src in oview(1) if(stat & NOPOWER) return - + var/result = src.canReach(usr, null, 1) + if (result==0) + usr.client_mob() << "You can't reach [src]." + return + var/atom/l = src.loc var/atom/com = locate(/obj/machinery/teleport/hub, locate(l.x + 1, l.y, l.z)) if (com) @@ -166,7 +182,11 @@ set src in oview(1) if(stat & NOPOWER) return - + var/result = src.canReach(usr, null, 1) + if (result==0) + usr.client_mob() << "You can't reach [src]." + return + var/atom/l = src.loc var/obj/machinery/teleport/hub/com = locate(/obj/machinery/teleport/hub, locate(l.x + 1, l.y, l.z)) if (com && !active) diff --git a/Code/weapons.dm b/Code/weapons.dm index a499e0a..6e1c2bb 100644 --- a/Code/weapons.dm +++ b/Code/weapons.dm @@ -63,12 +63,12 @@ if (istype(src.loc, /mob)) attack_self(src.loc) else - src.updateDialog() + src.updateSelfDialog(src) else if (istype(src.master.loc, /mob)) src.attack_self(src.master.loc) else - src.updateDialog() + src.updateSelfDialog(src.master) src.add_fingerprint(usr) else usr.client_mob() << browse(null, "window=infra_sensor") @@ -178,15 +178,12 @@ if (istype(src.loc, /mob)) attack_self(src.loc) else - src.updateDialog() + src.updateSelfDialog(src) else if (istype(src.master.loc, /mob)) src.attack_self(src.master.loc) else - for(var/mob/M in viewers(1, src.master)) - if (M.client) - src.attack_self(M) - //Foreach goto(310) + src.updateSelfDialog(src.master) else usr.client_mob() << browse(null, "window=prox") return @@ -321,12 +318,12 @@ if (istype(src.loc, /mob)) attack_self(src.loc) else - src.updateDialog() + src.updateSelfDialog(src) else if (istype(src.master.loc, /mob)) src.attack_self(src.master.loc) else - src.updateDialog() + src.updateSelfDialog(src.master) else usr.client_mob() << browse(null, "window=infra") return @@ -407,12 +404,12 @@ if (istype(src.loc, /mob)) attack_self(src.loc) else - updateDialog() + src.updateSelfDialog(src) else if (istype(src.master.loc, /mob)) src.attack_self(src.master.loc) else - src.updateDialog() + src.updateSelfDialog(src.master) else //If it's not timing, reset the icon so it doesn't look like it's still about to go off. src.c_state(0) @@ -507,12 +504,12 @@ if (istype(src.loc, /mob)) attack_self(src.loc) else - src.updateDialog() + src.updateSelfDialog(src) else if (istype(src.master.loc, /mob)) src.attack_self(src.master.loc) else - src.updateDialog() + src.updateSelfDialog(src.master) src.add_fingerprint(usr) else usr.client_mob() << browse(null, "window=timer") @@ -989,7 +986,11 @@ /obj/item/weapon/assembly/m_i_ptank/verb/Arm() set src in view(1) - + var/result = src.canReach(usr, null, 1) + if (result==0) + usr.client_mob() << "You can't reach [src]." + return + usr.show_message("\blue The proximity sensor has been armed with a delay of 15 seconds.", 1) src.icon_state = "m_i_ptank2" diff --git a/Icons/stationobjs.dmi b/Icons/stationobjs.dmi index 57ee176806f01a69c76bb5b2f9f76c570c45e082..fbca6e1d0d9f4f855d62e3172753414a9d82f850 100644 GIT binary patch literal 26767 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 literal 26067 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