From 3fa79f8d5195dbe128e12fe66a6ecf19bfa64959 Mon Sep 17 00:00:00 2001 From: Kelenius Date: Sat, 9 May 2015 17:27:19 +0300 Subject: [PATCH 01/21] Removes click cooldowns almost everywhere. Still have: doors, windoors, cameras, windows, grilles, blobs, resisting, alien stuff, mechas, spray bottles. Setting changeNextMove is now responsibility of the item being attacked. Adds a config option to eliminate click cooldowns completely. Intended to be used by devs. --- code/_onclick/ai.dm | 4 +- code/_onclick/click.dm | 99 +++++++------------ code/_onclick/cyborg.dm | 12 +-- code/_onclick/hud/screen_objects.dm | 11 +-- code/_onclick/item_attack.dm | 2 + code/_onclick/observer.dm | 4 +- code/_onclick/other_mobs.dm | 9 -- code/_onclick/telekinesis.dm | 20 ++-- code/controllers/configuration.dm | 4 + code/game/gamemodes/blob/theblob.dm | 1 + code/game/machinery/camera/camera.dm | 1 + code/game/machinery/deployable.dm | 1 + code/game/machinery/doors/door.dm | 1 + code/game/machinery/doors/windowdoor.dm | 1 + code/game/machinery/portable_turret.dm | 2 +- code/game/mecha/mecha.dm | 3 + code/game/objects/effects/aliens.dm | 3 + code/game/objects/items.dm | 1 - .../structures/crates_lockers/closets.dm | 7 +- code/game/objects/structures/grille.dm | 3 + code/game/objects/structures/window.dm | 3 + code/game/turfs/simulated/walls.dm | 2 + code/modules/mob/living/carbon/human/human.dm | 5 +- code/modules/mob/living/carbon/resist.dm | 23 ++--- code/modules/mob/living/living.dm | 6 +- .../simple_animal/borer/borer_captive.dm | 2 +- .../mob/living/simple_animal/simple_animal.dm | 2 - code/modules/mob/mob.dm | 6 +- code/modules/mob/mob_grab.dm | 4 +- code/modules/projectiles/gun.dm | 4 +- .../projectiles/guns/launcher/rocket.dm | 2 +- .../reagents/reagent_containers/spray.dm | 2 + code/setup.dm | 4 - 33 files changed, 110 insertions(+), 144 deletions(-) diff --git a/code/_onclick/ai.dm b/code/_onclick/ai.dm index e05cbeb9ba..4dee15388d 100644 --- a/code/_onclick/ai.dm +++ b/code/_onclick/ai.dm @@ -15,7 +15,6 @@ return if(control_disabled || stat) return - next_move = world.time + 9 if(ismob(A)) ai_actual_track(A) @@ -52,9 +51,8 @@ CtrlClickOn(A) return - if(world.time <= next_move) + if(!canClick()) return - next_move = world.time + 9 if(aiCamera.in_camera_mode) aiCamera.camera_mode_off() diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm index b8caa45399..5169676ad4 100644 --- a/code/_onclick/click.dm +++ b/code/_onclick/click.dm @@ -4,7 +4,7 @@ */ // 1 decisecond click delay (above and beyond mob/next_move) -/mob/var/next_click = 0 +/mob/var/next_click = 0 /* Before anything else, defer these calls to a per-mobtype handler. This allows us to @@ -15,12 +15,14 @@ Note that this proc can be overridden, and is in the case of screen objects. */ -/atom/Click(location,control,params) + +/atom/Click(var/location, var/control, var/params) // This is their reaction to being clicked on (standard proc) if(src) usr.ClickOn(src, params) -/atom/DblClick(location,control,params) + +/atom/DblClick(var/location, var/control, var/params) if(src) - usr.DblClickOn(src,params) + usr.DblClickOn(src, params) /* Standard mob ClickOn() @@ -35,8 +37,8 @@ * item/afterattack(atom,user,adjacent,params) - used both ranged and adjacent * mob/RangedAttack(atom,params) - used only ranged, only used for tk and laser eyes but could be changed */ -/mob/proc/ClickOn( var/atom/A, var/params ) - if(world.time <= next_click) +/mob/proc/ClickOn(var/atom/A, var/params) + if(world.time <= next_click) // Hard check, before anything else, to avoid crashing return next_click = world.time + 1 @@ -66,16 +68,17 @@ face_atom(A) // change direction to face what you clicked on - if(next_move > world.time) // in the year 2000... + if(!canClick()) // in the year 2000... return - if(istype(loc,/obj/mecha)) - if(!locate(/turf) in list(A,A.loc)) // Prevents inventory from being drilled + if(istype(loc, /obj/mecha)) + if(!locate(/turf) in list(A, A.loc)) // Prevents inventory from being drilled return var/obj/mecha/M = loc - return M.click_action(A,src) + return M.click_action(A, src) if(restrained()) + changeNextMove(10) RestrainedClickOn(A) return @@ -83,79 +86,65 @@ throw_item(A) return - if(!istype(A,/obj/item/weapon/gun) && !isturf(A) && !istype(A,/obj/screen)) + if(!istype(A, /obj/item/weapon/gun) && !isturf(A) && !istype(A, /obj/screen)) last_target_click = world.time var/obj/item/W = get_active_hand() - if(W == A) - next_move = world.time + 6 - if(W.flags&USEDELAY) - next_move += 5 + if(W == A) // Handle attack_self W.attack_self(src) if(hand) update_inv_l_hand(0) else update_inv_r_hand(0) - return - // operate two STORAGE levels deep here (item in backpack in src; NOT item in box in backpack in src) - var/sdepth = A.storage_depth(src) - if(A == loc || (A in loc) || (sdepth != -1 && sdepth <= 1)) - - // faster access to objects already on you - if(A in contents) - next_move = world.time + 6 // on your person - else - next_move = world.time + 8 // in a box/bag or in your square - - // No adjacency needed + // A is your location but is not a turf; or is on you (backpack); or is on something on you (box in backpack); but not next to you and not in a box in a backpack on you + if(!isturf(A) && A == loc || (A in contents) || (A.loc in contents)) if(W) - if(W.flags&USEDELAY) - next_move += 5 - - var/resolved = A.attackby(W,src) + var/resolved = A.attackby(W, src) if(!resolved && A && W) - W.afterattack(A,src,1,params) // 1 indicates adjacency + W.afterattack(A, src, 1, params) // 1 indicates adjacency else + if(ismob(A)) // No instant mob attacking + changeNextMove(8) UnarmedAttack(A, 1) return if(!isturf(loc)) // This is going to stop you from telekinesing from inside a closet, but I don't shed many tears for that return - // Allows you to click on a box's contents, if that box is on the ground, but no deeper than that - sdepth = A.storage_depth_turf() - if(isturf(A) || isturf(A.loc) || (sdepth != -1 && sdepth <= 1)) - next_move = world.time + 10 - + // A is a turf or is on a turf, or in something on a turf (pen in a box); but not something in something on a turf (pen in a box in a backpack) + if(isturf(A) || isturf(A.loc) || isturf(A.loc.loc)) if(A.Adjacent(src)) // see adjacent.dm if(W) - if(W.flags&USEDELAY) - next_move += 5 - - // Return 1 in attackby() to prevent afterattack() effects (when safely moving items for example) - var/resolved = A.attackby(W,src) + var/resolved = A.attackby(W, src) // Return 1 in attackby() to prevent afterattack() effects (when safely moving items for example) if(!resolved && A && W) - W.afterattack(A,src,1,params) // 1: clicking something Adjacent + W.afterattack(A, src, 1, params) // 1: clicking something Adjacent else + if(ismob(A)) // No instant mob attacking + changeNextMove(8) UnarmedAttack(A, 1) return else // non-adjacent click if(W) - W.afterattack(A,src,0,params) // 0: not Adjacent + W.afterattack(A, src, 0, params) // 0: not Adjacent else RangedAttack(A, params) return -/mob/proc/changeNext_move(num) +/mob/proc/changeNextMove(var/num) next_move = world.time + num -// Default behavior: ignore double clicks, consider them normal clicks instead +/mob/proc/canClick() + if(config.no_click_cooldown || next_move <= world.time) + return 1 + return 0 + +// Default behavior: ignore double clicks, the second click that makes the doubleclick call already calls for a normal click /mob/proc/DblClickOn(var/atom/A, var/params) - ClickOn(A,params) + return /* Translates into attack_hand, etc. @@ -198,17 +187,6 @@ if((LASER in mutations) && a_intent == I_HURT) LaserEyes(A) // moved into a proc below else if(TK in mutations) - switch(get_dist(src,A)) - if(0) - ; - if(1 to 5) // not adjacent may mean blocked by window - next_move += 2 - if(5 to 7) - next_move += 5 - if(8 to tk_maxrange) - next_move += 10 - else - return A.attack_tk(src) /* Restrained ClickOn @@ -234,8 +212,7 @@ if(back) var/obj/item/weapon/rig/rig = back if(istype(rig) && rig.selected_module) - if(world.time <= next_move) return - next_move = world.time + 8 + if(!canClick()) return rig.selected_module.engage(A) return @@ -316,7 +293,7 @@ return /mob/living/LaserEyes(atom/A) - next_move = world.time + 6 + changeNextMove(4) var/turf/T = get_turf(src) var/turf/U = get_turf(A) diff --git a/code/_onclick/cyborg.dm b/code/_onclick/cyborg.dm index 5986011688..414071a964 100644 --- a/code/_onclick/cyborg.dm +++ b/code/_onclick/cyborg.dm @@ -35,7 +35,7 @@ if(stat || lockcharge || weakened || stunned || paralysis) return - if(next_move >= world.time) + if(!canClick()) return face_atom(A) // change direction to face what you clicked on @@ -68,9 +68,6 @@ return if(W == A) - next_move = world.time + 8 - if(W.flags&USEDELAY) - next_move += 5 W.attack_self(src) return @@ -78,9 +75,6 @@ // cyborgs are prohibited from using storage items so we can I think safely remove (A.loc in contents) if(A == loc || (A in loc) || (A in contents)) // No adjacency checks - next_move = world.time + 8 - if(W.flags&USEDELAY) - next_move += 5 var/resolved = A.attackby(W,src) if(!resolved && A && W) @@ -93,16 +87,12 @@ // cyborgs are prohibited from using storage items so we can I think safely remove (A.loc && isturf(A.loc.loc)) if(isturf(A) || isturf(A.loc)) if(A.Adjacent(src)) // see adjacent.dm - next_move = world.time + 10 - if(W.flags&USEDELAY) - next_move += 5 var/resolved = A.attackby(W, src) if(!resolved && A && W) W.afterattack(A, src, 1, params) return else - next_move = world.time + 10 W.afterattack(A, src, 0, params) return return diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm index 4a7d6f2acb..03f97187c3 100644 --- a/code/_onclick/hud/screen_objects.dm +++ b/code/_onclick/hud/screen_objects.dm @@ -48,9 +48,8 @@ /obj/screen/item_action/Click() if(!usr || !owner) return 1 - if(usr.next_move >= world.time) + if(!usr.canClick()) return - usr.next_move = world.time + 6 if(usr.stat || usr.restrained() || usr.stunned || usr.lying) return 1 @@ -85,7 +84,7 @@ name = "storage" /obj/screen/storage/Click() - if(world.time <= usr.next_move) + if(!usr.canClick()) return 1 if(usr.stat || usr.paralysis || usr.stunned || usr.weakened) return 1 @@ -95,7 +94,6 @@ var/obj/item/I = usr.get_active_hand() if(I) usr.ClickOn(master) - usr.next_move = world.time+2 return 1 /obj/screen/gun @@ -481,7 +479,7 @@ /obj/screen/inventory/Click() // At this point in client Click() code we have passed the 1/10 sec check and little else // We don't even know if it's a middle click - if(world.time <= usr.next_move) + if(!usr.canClick()) return 1 if(usr.stat || usr.paralysis || usr.stunned || usr.weakened) return 1 @@ -492,12 +490,10 @@ if(iscarbon(usr)) var/mob/living/carbon/C = usr C.activate_hand("r") - usr.next_move = world.time+2 if("l_hand") if(iscarbon(usr)) var/mob/living/carbon/C = usr C.activate_hand("l") - usr.next_move = world.time+2 if("swap") usr:swap_hand() if("hand") @@ -506,5 +502,4 @@ if(usr.attack_ui(slot_id)) usr.update_inv_l_hand(0) usr.update_inv_r_hand(0) - usr.next_move = world.time+6 return 1 diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm index 1d68fb54e8..1b548c6596 100644 --- a/code/_onclick/item_attack.dm +++ b/code/_onclick/item_attack.dm @@ -6,11 +6,13 @@ // No comment /atom/proc/attackby(obj/item/W, mob/user) return + /atom/movable/attackby(obj/item/W, mob/user) if(!(W.flags&NOBLUDGEON)) visible_message("[src] has been hit by [user] with [W].") /mob/living/attackby(obj/item/I, mob/user) + user.changeNextMove(8) if(istype(I) && ismob(user)) I.attack(src, user) diff --git a/code/_onclick/observer.dm b/code/_onclick/observer.dm index 168ae47c86..585949d410 100644 --- a/code/_onclick/observer.dm +++ b/code/_onclick/observer.dm @@ -32,8 +32,8 @@ if(client.buildmode) build_click(src, client.buildmode, params, A) return - if(world.time <= next_move) return - next_move = world.time + 8 + if(!canClick()) return + changeNextMove(4) // You are responsible for checking config.ghost_interaction when you override this function // Not all of them require checking, see below A.attack_ghost(src) diff --git a/code/_onclick/other_mobs.dm b/code/_onclick/other_mobs.dm index 477fb04b7a..f772666651 100644 --- a/code/_onclick/other_mobs.dm +++ b/code/_onclick/other_mobs.dm @@ -38,15 +38,6 @@ return else if(TK in mutations) - switch(get_dist(src,A)) - if(1 to 5) // not adjacent may mean blocked by window - next_move += 2 - if(5 to 7) - next_move += 5 - if(8 to 15) - next_move += 10 - if(16 to 128) - return A.attack_tk(src) /mob/living/RestrainedClickOn(var/atom/A) diff --git a/code/_onclick/telekinesis.dm b/code/_onclick/telekinesis.dm index ae57895cd6..920db53fa6 100644 --- a/code/_onclick/telekinesis.dm +++ b/code/_onclick/telekinesis.dm @@ -108,20 +108,12 @@ var/const/tk_maxrange = 15 return var/d = get_dist(user, target) - if(focus) d = max(d,get_dist(user,focus)) // whichever is further - switch(d) - if(0) - ; - if(1 to 5) // not adjacent may mean blocked by window - if(!proximity) - user.next_move += 2 - if(5 to 7) - user.next_move += 5 - if(8 to tk_maxrange) - user.next_move += 10 - else - user << "\blue Your mind won't reach that far." - return + if(focus) + d = max(d,get_dist(user,focus)) // whichever is further + + if(d > tk_maxrange) + user << "Your mind won't reach that far." + return if(!focus) focus_object(target, user) diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm index 171080fb32..c99ed82786 100644 --- a/code/controllers/configuration.dm +++ b/code/controllers/configuration.dm @@ -126,6 +126,7 @@ var/list/gamemode_cache = list() var/welder_vision = 1 var/generate_asteroid = 0 + var/no_click_cooldown = 0 //Used for modifying movement speed for mobs. //Unversal modifiers @@ -316,6 +317,9 @@ var/list/gamemode_cache = list() if ("generate_asteroid") config.generate_asteroid = 1 + if ("no_click_cooldown") + config.no_click_cooldown = 1 + if("allow_admin_ooccolor") config.allow_admin_ooccolor = 1 diff --git a/code/game/gamemodes/blob/theblob.dm b/code/game/gamemodes/blob/theblob.dm index 6e9c3d9b68..df3b8e5aee 100644 --- a/code/game/gamemodes/blob/theblob.dm +++ b/code/game/gamemodes/blob/theblob.dm @@ -157,6 +157,7 @@ attackby(var/obj/item/weapon/W, var/mob/user) + user.changeNextMove(8) playsound(src.loc, 'sound/effects/attackblob.ogg', 50, 1) src.visible_message("The [src.name] has been attacked with \the [W][(user ? " by [user]." : ".")]") var/damage = 0 diff --git a/code/game/machinery/camera/camera.dm b/code/game/machinery/camera/camera.dm index 5670ef2060..e60b634ac9 100644 --- a/code/game/machinery/camera/camera.dm +++ b/code/game/machinery/camera/camera.dm @@ -187,6 +187,7 @@ src.bugged = 1 else if(W.damtype == BRUTE || W.damtype == BURN) //bashing cameras + user.changeNextMove(8) if (W.force >= src.toughness) visible_message("[src] has been [pick(W.attack_verb)] with [W] by [user]!") if (istype(W, /obj/item)) //is it even possible to get into attackby() with non-items? diff --git a/code/game/machinery/deployable.dm b/code/game/machinery/deployable.dm index e49fb26283..7a5e2706c9 100644 --- a/code/game/machinery/deployable.dm +++ b/code/game/machinery/deployable.dm @@ -80,6 +80,7 @@ for reference: return return else + user.changeNextMove(8) switch(W.damtype) if("fire") src.health -= W.force * 1 diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm index e02be363f4..7f87c65199 100644 --- a/code/game/machinery/doors/door.dm +++ b/code/game/machinery/doors/door.dm @@ -263,6 +263,7 @@ //psa to whoever coded this, there are plenty of objects that need to call attack() on doors without bludgeoning them. if(src.density && istype(I, /obj/item/weapon) && user.a_intent == I_HURT && !istype(I, /obj/item/weapon/card)) var/obj/item/weapon/W = I + user.changeNextMove(8) if(W.damtype == BRUTE || W.damtype == BURN) if(W.force < min_force) user.visible_message("\red \The [user] hits \the [src] with \the [W] with no visible effect." ) diff --git a/code/game/machinery/doors/windowdoor.dm b/code/game/machinery/doors/windowdoor.dm index b91270ad60..ae4ea0214e 100644 --- a/code/game/machinery/doors/windowdoor.dm +++ b/code/game/machinery/doors/windowdoor.dm @@ -225,6 +225,7 @@ //If it's a weapon, smash windoor. Unless it's an id card, agent card, ect.. then ignore it (Cards really shouldnt damage a door anyway) if(src.density && istype(I, /obj/item/weapon) && !istype(I, /obj/item/weapon/card)) + user.changeNextMove(8) var/aforce = I.force playsound(src.loc, 'sound/effects/Glasshit.ogg', 75, 1) visible_message("\red [src] was hit by [I].") diff --git a/code/game/machinery/portable_turret.dm b/code/game/machinery/portable_turret.dm index a056cbc0f9..3e36f080c0 100644 --- a/code/game/machinery/portable_turret.dm +++ b/code/game/machinery/portable_turret.dm @@ -331,7 +331,7 @@ else //if the turret was attacked with the intention of harming it: - user.changeNext_move(NEXT_MOVE_DELAY) + user.changeNextMove(8) take_damage(I.force * 0.5) if(I.force * 0.5 > 1) //if the force of impact dealt at least 1 damage, the turret gets pissed off if(!attacked && !emagged) diff --git a/code/game/mecha/mecha.dm b/code/game/mecha/mecha.dm index 479d55cb8b..5cbc013f3b 100644 --- a/code/game/mecha/mecha.dm +++ b/code/game/mecha/mecha.dm @@ -511,6 +511,7 @@ return /obj/mecha/attack_hand(mob/user as mob) + user.changeNextMove(8) src.log_message("Attack by hand/paw. Attacker - [user].",1) if(istype(user,/mob/living/carbon/human)) @@ -674,6 +675,7 @@ return /obj/mecha/proc/dynattackby(obj/item/weapon/W as obj, mob/user as mob) + user.changeNextMove(8) src.log_message("Attacked by [W]. Attacker - [user]") if(prob(src.deflect_chance)) user << "\red \The [W] bounces off [src.name]." @@ -1788,6 +1790,7 @@ /obj/mecha/attack_generic(var/mob/user, var/damage, var/attack_message) + user.changeNextMove(8) if(!damage) return 0 diff --git a/code/game/objects/effects/aliens.dm b/code/game/objects/effects/aliens.dm index e6b166792f..93e578d55f 100644 --- a/code/game/objects/effects/aliens.dm +++ b/code/game/objects/effects/aliens.dm @@ -103,6 +103,7 @@ return /obj/effect/alien/resin/attack_hand() + usr.changeNextMove(8) if (HULK in usr.mutations) usr << "\blue You easily destroy the [name]." for(var/mob/O in oviewers(src)) @@ -129,6 +130,7 @@ /obj/effect/alien/resin/attackby(obj/item/weapon/W as obj, mob/user as mob) + user.changeNextMove(8) var/aforce = W.force health = max(0, health - aforce) playsound(loc, 'sound/effects/attackblob.ogg', 100, 1) @@ -236,6 +238,7 @@ Alien plants should do something if theres a lot of poison return /obj/effect/alien/weeds/attackby(var/obj/item/weapon/W, var/mob/user) + user.changeNextMove(8) if(W.attack_verb.len) visible_message("\red \The [src] have been [pick(W.attack_verb)] with \the [W][(user ? " by [user]." : ".")]") else diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index 1c29aa8088..500979572e 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -159,7 +159,6 @@ else if(isliving(src.loc)) return - user.next_move = max(user.next_move+2,world.time + 2) user.put_in_active_hand(src) if(src.loc == user) src.pickup(user) diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm index 5e1a551cec..d703608ea7 100644 --- a/code/game/objects/structures/crates_lockers/closets.dm +++ b/code/game/objects/structures/crates_lockers/closets.dm @@ -325,9 +325,12 @@ if(!req_breakout()) return + if(!escapee.canClick()) + return + + escapee.changeNextMove(100) + //okay, so the closet is either welded or locked... resist!!! - escapee.next_move = world.time + 100 - escapee.last_special = world.time + 100 escapee << "You lean on the back of \the [src] and start pushing the door open. (this will take about [breakout_time] minutes)" visible_message("The [src] begins to shake violently!") diff --git a/code/game/objects/structures/grille.dm b/code/game/objects/structures/grille.dm index b18658d4a6..eced285512 100644 --- a/code/game/objects/structures/grille.dm +++ b/code/game/objects/structures/grille.dm @@ -33,6 +33,7 @@ /obj/structure/grille/attack_hand(mob/user as mob) + user.changeNextMove(8) playsound(loc, 'sound/effects/grillehit.ogg', 80, 1) var/damage_dealt = 1 @@ -154,8 +155,10 @@ //window placing end else if(istype(W, /obj/item/weapon/shard)) + user.changeNextMove(8) health -= W.force * 0.1 else if(!shock(user, 70)) + user.changeNextMove(8) playsound(loc, 'sound/effects/grillehit.ogg', 80, 1) switch(W.damtype) if("fire") diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm index 36d5bcc657..5ccd7efa21 100644 --- a/code/game/objects/structures/window.dm +++ b/code/game/objects/structures/window.dm @@ -175,6 +175,7 @@ playsound(loc, 'sound/effects/Glasshit.ogg', 50, 1) /obj/structure/window/attack_hand(mob/user as mob) + user.changeNextMove(8) if(HULK in user.mutations) user.say(pick(";RAAAAAAAARGH!", ";HNNNNNNNNNGGGGGGH!", ";GWAAAAAAAARRRHHH!", "NNNNNNNNGGGGGGGGHH!", ";AAAAAAARRRGH!")) user.visible_message("[user] smashes through [src]!") @@ -200,6 +201,7 @@ return /obj/structure/window/attack_generic(var/mob/user, var/damage) + user.changeNextMove(8) if(!damage) return if(damage >= 10) @@ -268,6 +270,7 @@ new glasstype(loc) qdel(src) else + user.changeNextMove(8) if(W.damtype == BRUTE || W.damtype == BURN) hit(W.force) if(health <= 7) diff --git a/code/game/turfs/simulated/walls.dm b/code/game/turfs/simulated/walls.dm index ef7dd74e8f..2d8fe8ca2b 100644 --- a/code/game/turfs/simulated/walls.dm +++ b/code/game/turfs/simulated/walls.dm @@ -272,6 +272,7 @@ //Interactions /turf/simulated/wall/attack_hand(mob/user as mob) + user.changeNextMove(8) if (HULK in user.mutations) if (prob(hulk_destroy_prob) || rotting) usr << text("\blue You smash through the wall.") @@ -298,6 +299,7 @@ return 0 /turf/simulated/wall/attack_generic(var/mob/user, var/damage, var/attack_message, var/wallbreaker) + user.changeNextMove(8) if(!damage || !wallbreaker) user << "You push the wall but nothing happens." return diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 498b46345d..1b40b9fa00 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -1311,9 +1311,10 @@ set desc = "Pop a joint back into place. Extremely painful." set src in view(1) - if(!isliving(usr) || usr.next_move > world.time) + if(!isliving(usr) || !usr.canClick()) return - usr.next_move = world.time + 20 + + usr.changeNextMove(20) if(usr.stat > 0) usr << "You are unconcious and cannot do that!" diff --git a/code/modules/mob/living/carbon/resist.dm b/code/modules/mob/living/carbon/resist.dm index 95ee36b1f6..5724c11997 100644 --- a/code/modules/mob/living/carbon/resist.dm +++ b/code/modules/mob/living/carbon/resist.dm @@ -27,10 +27,10 @@ ..() /mob/living/carbon/proc/escape_handcuffs() - if(!(last_special <= world.time)) return - - next_move = world.time + 100 - last_special = world.time + 100 + if(!canClick()) + return + + changeNextMove(100) if(can_break_cuffs()) //Don't want to do a lot of logic gating here. break_handcuffs() @@ -61,10 +61,10 @@ drop_from_inventory(handcuffed) /mob/living/carbon/proc/escape_legcuffs() - if(!(last_special <= world.time)) return - - next_move = world.time + 100 - last_special = world.time + 100 + if(!canClick()) + return + + changeNextMove(100) if(can_break_cuffs()) //Don't want to do a lot of logic gating here. break_legcuffs() @@ -149,14 +149,15 @@ return ..() /mob/living/carbon/escape_buckle() + if(!canClick()) + return + + changeNextMove(100) if(!buckled) return - if(!(last_special <= world.time)) return if(!restrained()) ..() else - next_move = world.time + 100 - last_special = world.time + 100 visible_message( "[usr] attempts to unbuckle themself!", "You attempt to unbuckle yourself. (This will take around 2 minutes and you need to stand still)" diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index d723cb5556..dc6923db6d 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -572,7 +572,7 @@ default behaviour is: set category = "IC" if(can_resist()) - next_move = world.time + 20 + changeNextMove(20) process_resist() /mob/living/proc/can_resist() @@ -580,7 +580,7 @@ default behaviour is: //so just check weakened instead. if(stat || weakened) return 0 - if(next_move > world.time) + if(!canClick()) return 0 return 1 @@ -605,7 +605,7 @@ default behaviour is: /mob/living/proc/escape_inventory(obj/item/weapon/holder/H) if(H != src.loc) return - + var/mob/M = H.loc //Get our mob holder (if any). if(istype(M)) diff --git a/code/modules/mob/living/simple_animal/borer/borer_captive.dm b/code/modules/mob/living/simple_animal/borer/borer_captive.dm index c0b2999b2f..e666f7ac71 100644 --- a/code/modules/mob/living/simple_animal/borer/borer_captive.dm +++ b/code/modules/mob/living/simple_animal/borer/borer_captive.dm @@ -35,7 +35,7 @@ return /mob/living/captive_brain/can_resist() - return !(stat || next_move > world.time) + return !(stat || !canClick()) /mob/living/captive_brain/process_resist() //Resisting control by an alien mind. diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm index 881cb2d76a..74094fcbfd 100644 --- a/code/modules/mob/living/simple_animal/simple_animal.dm +++ b/code/modules/mob/living/simple_animal/simple_animal.dm @@ -266,7 +266,6 @@ /mob/living/simple_animal/attackby(var/obj/item/O, var/mob/user) if(istype(O, /obj/item/stack/medical)) - user.changeNext_move(4) if(stat != DEAD) var/obj/item/stack/medical/MED = O if(health < maxHealth) @@ -284,7 +283,6 @@ if(istype(O, /obj/item/weapon/kitchenknife) || istype(O, /obj/item/weapon/butch)) harvest(user) else - user.changeNext_move(8) if(O.force > resistance) var/damage = O.force if (O.damtype == HALLOSS) diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index e9cae30755..d31fe2c6f6 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -241,8 +241,6 @@ if (W) W.attack_self(src) update_inv_r_hand() - if(next_move < world.time) - next_move = world.time + 2 return /* @@ -945,9 +943,9 @@ mob/proc/yank_out_object() set desc = "Remove an embedded item at the cost of bleeding and pain." set src in view(1) - if(!isliving(usr) || usr.next_move > world.time) + if(!isliving(usr) || !usr.canClick()) return - usr.next_move = world.time + 20 + usr.changeNextMove(20) if(usr.stat == 1) usr << "You are unconcious and cannot do that!" diff --git a/code/modules/mob/mob_grab.dm b/code/modules/mob/mob_grab.dm index 73c5ee1de7..31e6ee65a0 100644 --- a/code/modules/mob/mob_grab.dm +++ b/code/modules/mob/mob_grab.dm @@ -120,7 +120,7 @@ return if(state == GRAB_UPGRADING) return - if(assailant.next_move > world.time) + if(!assailant.canClick()) return if(world.time < (last_upgrade + UPGRADE_COOLDOWN)) return @@ -170,7 +170,7 @@ assailant.attack_log += "\[[time_stamp()]\] Strangled (kill intent) [affecting.name] ([affecting.ckey])" msg_admin_attack("[key_name(assailant)] strangled (kill intent) [key_name(affecting)]") - assailant.next_move = world.time + 10 + affecting.changeNextMove(10) affecting.losebreath += 1 else assailant.visible_message("[assailant] was unable to tighten \his grip on [affecting]'s neck!") diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index 2f17c0783d..89cda207f3 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -169,7 +169,7 @@ var/_move_delay = firemode.move_delay var/shoot_time = (_burst - 1)*_burst_delay - user.next_move = world.time + shoot_time //no clicking on things while shooting + user.changeNextMove(shoot_time) if(user.client) user.client.move_delay = world.time + shoot_time //no moving while shooting either next_fire_time = world.time + shoot_time @@ -202,7 +202,7 @@ update_held_icon() //update timing - user.next_move = world.time + 4 + user.changeNextMove(4) if(user.client) user.client.move_delay = world.time + _move_delay next_fire_time = world.time + _fire_delay diff --git a/code/modules/projectiles/guns/launcher/rocket.dm b/code/modules/projectiles/guns/launcher/rocket.dm index fd86302fb8..f468431bdd 100644 --- a/code/modules/projectiles/guns/launcher/rocket.dm +++ b/code/modules/projectiles/guns/launcher/rocket.dm @@ -7,7 +7,7 @@ throw_speed = 2 throw_range = 10 force = 5.0 - flags = CONDUCT | USEDELAY + flags = CONDUCT slot_flags = 0 origin_tech = "combat=8;materials=5" fire_sound = 'sound/effects/bang.ogg' diff --git a/code/modules/reagents/reagent_containers/spray.dm b/code/modules/reagents/reagent_containers/spray.dm index 2e929c6d12..62e24b83e2 100644 --- a/code/modules/reagents/reagent_containers/spray.dm +++ b/code/modules/reagents/reagent_containers/spray.dm @@ -50,6 +50,8 @@ playsound(src.loc, 'sound/effects/spray2.ogg', 50, 1, -6) + user.changeNextMove(4) + if(reagents.has_reagent("sacid")) message_admins("[key_name_admin(user)] fired sulphuric acid from \a [src].") log_game("[key_name(user)] fired sulphuric acid from \a [src].") diff --git a/code/setup.dm b/code/setup.dm index 68c2b94c75..3e2328f596 100644 --- a/code/setup.dm +++ b/code/setup.dm @@ -190,12 +190,10 @@ // To successfully stop you taking all pressure damage you must have both a suit and head item with this flag. #define NOBLUDGEON 2 // When an item has this it produces no "X has been hit by Y with Z" message with the default handler. #define AIRTIGHT 4 // Functions with internals. -#define USEDELAY 8 // 1 second extra delay on use. (Can be used once every 2s) #define NOSHIELD 16 // Weapon not affected by shield. #define CONDUCT 32 // Conducts electricity. (metal etc.) #define ON_BORDER 64 // Item has priority to check when entering or leaving. #define NOBLOODY 512 // Used for items if they don't want to get a blood overlay. -#define NODELAY 8192 // 1 second attack-by delay skipped (Can be used once every 0.2s). Most objects have a 1s attack-by delay, which doesn't require a flag. //Use these flags to indicate if an item obscures the specified slots from view, whereas body_parts_covered seems to be used to indicate what body parts the item protects. #define GLASSESCOVERSEYES 256 @@ -865,8 +863,6 @@ var/list/be_special_flags = list( #define ALLMOBS (HUMAN|MONKEY|ALIEN|ROBOT|SLIME|SIMPLE_ANIMAL) -#define NEXT_MOVE_DELAY 8 - #define DROPLIMB_EDGE 0 #define DROPLIMB_BLUNT 1 #define DROPLIMB_BURN 2 From 027275a7cb4433c547363cb3de83c0f7d546c89b Mon Sep 17 00:00:00 2001 From: Kelenius Date: Sat, 9 May 2015 20:53:00 +0300 Subject: [PATCH 02/21] Re-adds click cooldowns to trays and vines --- code/modules/hydroponics/spreading/spreading.dm | 1 + code/modules/hydroponics/trays/tray.dm | 1 + 2 files changed, 2 insertions(+) diff --git a/code/modules/hydroponics/spreading/spreading.dm b/code/modules/hydroponics/spreading/spreading.dm index 7edcca6303..0a8857d1ac 100644 --- a/code/modules/hydroponics/spreading/spreading.dm +++ b/code/modules/hydroponics/spreading/spreading.dm @@ -221,6 +221,7 @@ /obj/effect/plant/attackby(var/obj/item/weapon/W, var/mob/user) + user.changeNextMove(8) plant_controller.add_plant(src) if(istype(W, /obj/item/weapon/wirecutters) || istype(W, /obj/item/weapon/scalpel)) diff --git a/code/modules/hydroponics/trays/tray.dm b/code/modules/hydroponics/trays/tray.dm index f8b7a82be4..4e688ecc4c 100644 --- a/code/modules/hydroponics/trays/tray.dm +++ b/code/modules/hydroponics/trays/tray.dm @@ -530,6 +530,7 @@ A.hydrotray_type = src.type qdel(src) else if(O.force && seed) + user.changeNextMove(8) user.visible_message("\The [seed.display_name] has been attacked by [user] with \the [O]!") if(!dead) health -= O.force From 695392e1508947fbb3f7165ed60a2547bd2f4612 Mon Sep 17 00:00:00 2001 From: Kelenius Date: Sun, 10 May 2015 15:11:32 +0300 Subject: [PATCH 03/21] Fixes webbings and coats --- code/_onclick/click.dm | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm index 5169676ad4..0b453ff215 100644 --- a/code/_onclick/click.dm +++ b/code/_onclick/click.dm @@ -99,8 +99,9 @@ update_inv_r_hand(0) return - // A is your location but is not a turf; or is on you (backpack); or is on something on you (box in backpack); but not next to you and not in a box in a backpack on you - if(!isturf(A) && A == loc || (A in contents) || (A.loc in contents)) + // A is your location but is not a turf; or is on you (backpack); or is on something on you (box in backpack); sdepth is needed here because webbings and coat pockets are hacky + var/sdepth = A.storage_depth(src) + if(!isturf(A) && A == loc || (sdepth != -1 && sdepth <= 1)) if(W) var/resolved = A.attackby(W, src) if(!resolved && A && W) @@ -115,7 +116,8 @@ return // A is a turf or is on a turf, or in something on a turf (pen in a box); but not something in something on a turf (pen in a box in a backpack) - if(isturf(A) || isturf(A.loc) || isturf(A.loc.loc)) + sdepth = A.storage_depth_turf() + if(isturf(A) || isturf(A.loc) || (sdepth != -1 && sdepth <= 1)) if(A.Adjacent(src)) // see adjacent.dm if(W) var/resolved = A.attackby(W, src) // Return 1 in attackby() to prevent afterattack() effects (when safely moving items for example) From 32b95445e3810b8d78fb58c10d14cd30bcc7b333 Mon Sep 17 00:00:00 2001 From: mwerezak Date: Sun, 28 Jun 2015 23:07:58 -0400 Subject: [PATCH 04/21] Gives changeNextMove() a better name, default define --- code/__defines/mobs.dm | 3 +++ code/_onclick/click.dm | 12 ++++++------ code/_onclick/item_attack.dm | 2 +- code/_onclick/observer.dm | 2 +- code/_onclick/rig.dm | 2 +- code/game/gamemodes/blob/theblob.dm | 2 +- code/game/machinery/camera/camera.dm | 2 +- code/game/machinery/deployable.dm | 2 +- code/game/machinery/doors/door.dm | 2 +- code/game/machinery/doors/windowdoor.dm | 2 +- code/game/machinery/portable_turret.dm | 2 +- code/game/mecha/mecha.dm | 6 +++--- code/game/objects/effects/aliens.dm | 6 +++--- .../objects/structures/crates_lockers/closets.dm | 2 +- code/game/objects/structures/grille.dm | 4 ++-- code/game/objects/structures/window.dm | 6 +++--- code/game/turfs/simulated/wall_attacks.dm | 6 +++--- code/modules/hydroponics/spreading/spreading.dm | 2 +- code/modules/hydroponics/trays/tray.dm | 2 +- code/modules/mob/living/carbon/human/human.dm | 2 +- code/modules/mob/living/carbon/resist.dm | 6 +++--- code/modules/mob/living/living.dm | 2 +- .../mob/living/simple_animal/simple_animal.dm | 2 +- code/modules/mob/mob.dm | 2 +- code/modules/mob/mob_grab.dm | 2 +- code/modules/projectiles/gun.dm | 4 ++-- code/modules/reagents/reagent_containers/spray.dm | 2 +- 27 files changed, 46 insertions(+), 43 deletions(-) diff --git a/code/__defines/mobs.dm b/code/__defines/mobs.dm index d7874d2b04..bcecfa7d86 100644 --- a/code/__defines/mobs.dm +++ b/code/__defines/mobs.dm @@ -79,6 +79,9 @@ #define APPEARANCE_ALL_HAIR (APPEARANCE_HAIR|APPEARANCE_HAIR_COLOR|APPEARANCE_FACIAL_HAIR|APPEARANCE_FACIAL_HAIR_COLOR) #define APPEARANCE_ALL 511 +// Click cooldown +#define DEFAULT_ATTACK_COOLDOWN 8 //Default timeout for aggressive actions + #define MIN_SUPPLIED_LAW_NUMBER 15 #define MAX_SUPPLIED_LAW_NUMBER 50 \ No newline at end of file diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm index 3218212dda..a250b12e43 100644 --- a/code/_onclick/click.dm +++ b/code/_onclick/click.dm @@ -78,7 +78,7 @@ return M.click_action(A, src) if(restrained()) - changeNextMove(10) + setClickCooldown(10) RestrainedClickOn(A) return @@ -108,7 +108,7 @@ W.afterattack(A, src, 1, params) // 1 indicates adjacency else if(ismob(A)) // No instant mob attacking - changeNextMove(8) + setClickCooldown(DEFAULT_ATTACK_COOLDOWN) UnarmedAttack(A, 1) return @@ -126,7 +126,7 @@ W.afterattack(A, src, 1, params) // 1: clicking something Adjacent else if(ismob(A)) // No instant mob attacking - changeNextMove(8) + setClickCooldown(DEFAULT_ATTACK_COOLDOWN) UnarmedAttack(A, 1) return else // non-adjacent click @@ -137,8 +137,8 @@ return -/mob/proc/changeNextMove(var/num) - next_move = world.time + num +/mob/proc/setClickCooldown(var/timeout) + next_move = max(world.time + timeout, next_move) /mob/proc/canClick() if(config.no_click_cooldown || next_move <= world.time) @@ -285,7 +285,7 @@ return /mob/living/LaserEyes(atom/A) - changeNextMove(4) + setClickCooldown(4) var/turf/T = get_turf(src) var/turf/U = get_turf(A) diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm index 977b4d2334..0cca5569c2 100644 --- a/code/_onclick/item_attack.dm +++ b/code/_onclick/item_attack.dm @@ -12,7 +12,7 @@ visible_message("[src] has been hit by [user] with [W].") /mob/living/attackby(obj/item/I, mob/user) - user.changeNextMove(8) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) if(istype(I) && ismob(user)) I.attack(src, user) diff --git a/code/_onclick/observer.dm b/code/_onclick/observer.dm index 4323747496..324dcc234d 100644 --- a/code/_onclick/observer.dm +++ b/code/_onclick/observer.dm @@ -33,7 +33,7 @@ build_click(src, client.buildmode, params, A) return if(!canClick()) return - changeNextMove(4) + setClickCooldown(4) // You are responsible for checking config.ghost_interaction when you override this function // Not all of them require checking, see below A.attack_ghost(src) diff --git a/code/_onclick/rig.dm b/code/_onclick/rig.dm index 6087cf2c29..600d8c5619 100644 --- a/code/_onclick/rig.dm +++ b/code/_onclick/rig.dm @@ -55,7 +55,7 @@ if(istype(rig) && rig.selected_module) rig.selected_module.engage(A) if(ismob(A)) // No instant mob attacking - though modules have their own cooldowns - changeNextMove(8) + setClickCooldown(DEFAULT_ATTACK_COOLDOWN) return 1 return 0 diff --git a/code/game/gamemodes/blob/theblob.dm b/code/game/gamemodes/blob/theblob.dm index 2d8891bb0b..123bb97a3f 100644 --- a/code/game/gamemodes/blob/theblob.dm +++ b/code/game/gamemodes/blob/theblob.dm @@ -157,7 +157,7 @@ attackby(var/obj/item/weapon/W, var/mob/user) - user.changeNextMove(8) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) playsound(src.loc, 'sound/effects/attackblob.ogg', 50, 1) src.visible_message("The [src.name] has been attacked with \the [W][(user ? " by [user]." : ".")]") var/damage = 0 diff --git a/code/game/machinery/camera/camera.dm b/code/game/machinery/camera/camera.dm index 649a11b60d..a96e94eb0c 100644 --- a/code/game/machinery/camera/camera.dm +++ b/code/game/machinery/camera/camera.dm @@ -190,7 +190,7 @@ src.bugged = 1 else if(W.damtype == BRUTE || W.damtype == BURN) //bashing cameras - user.changeNextMove(8) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) if (W.force >= src.toughness) user.do_attack_animation(src) visible_message("[src] has been [pick(W.attack_verb)] with [W] by [user]!") diff --git a/code/game/machinery/deployable.dm b/code/game/machinery/deployable.dm index cb77a513a4..bce1ac5b57 100644 --- a/code/game/machinery/deployable.dm +++ b/code/game/machinery/deployable.dm @@ -97,7 +97,7 @@ for reference: return return else - user.changeNextMove(8) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) switch(W.damtype) if("fire") src.health -= W.force * 1 diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm index 4a246a9327..077bd4ff9b 100644 --- a/code/game/machinery/doors/door.dm +++ b/code/game/machinery/doors/door.dm @@ -260,7 +260,7 @@ //psa to whoever coded this, there are plenty of objects that need to call attack() on doors without bludgeoning them. if(src.density && istype(I, /obj/item/weapon) && user.a_intent == I_HURT && !istype(I, /obj/item/weapon/card)) var/obj/item/weapon/W = I - user.changeNextMove(8) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) if(W.damtype == BRUTE || W.damtype == BURN) user.do_attack_animation(src) if(W.force < min_force) diff --git a/code/game/machinery/doors/windowdoor.dm b/code/game/machinery/doors/windowdoor.dm index 8b7094b772..e50af2bcf0 100644 --- a/code/game/machinery/doors/windowdoor.dm +++ b/code/game/machinery/doors/windowdoor.dm @@ -229,7 +229,7 @@ //If it's a weapon, smash windoor. Unless it's an id card, agent card, ect.. then ignore it (Cards really shouldnt damage a door anyway) if(src.density && istype(I, /obj/item/weapon) && !istype(I, /obj/item/weapon/card)) - user.changeNextMove(8) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) var/aforce = I.force playsound(src.loc, 'sound/effects/Glasshit.ogg', 75, 1) visible_message("[src] was hit by [I].") diff --git a/code/game/machinery/portable_turret.dm b/code/game/machinery/portable_turret.dm index 655108cc3c..04b4dffe3c 100644 --- a/code/game/machinery/portable_turret.dm +++ b/code/game/machinery/portable_turret.dm @@ -322,7 +322,7 @@ else //if the turret was attacked with the intention of harming it: - user.changeNextMove(8) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) take_damage(I.force * 0.5) if(I.force * 0.5 > 1) //if the force of impact dealt at least 1 damage, the turret gets pissed off if(!attacked && !emagged) diff --git a/code/game/mecha/mecha.dm b/code/game/mecha/mecha.dm index e1c898da18..573ede3fb0 100644 --- a/code/game/mecha/mecha.dm +++ b/code/game/mecha/mecha.dm @@ -505,7 +505,7 @@ return /obj/mecha/attack_hand(mob/user as mob) - user.changeNextMove(8) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) src.log_message("Attack by hand/paw. Attacker - [user].",1) if(istype(user,/mob/living/carbon/human)) @@ -665,7 +665,7 @@ return /obj/mecha/proc/dynattackby(obj/item/weapon/W as obj, mob/user as mob) - user.changeNextMove(8) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) src.log_message("Attacked by [W]. Attacker - [user]") if(prob(src.deflect_chance)) user << "\The [W] bounces off [src.name]." @@ -1685,7 +1685,7 @@ /obj/mecha/attack_generic(var/mob/user, var/damage, var/attack_message) - user.changeNextMove(8) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) if(!damage) return 0 diff --git a/code/game/objects/effects/aliens.dm b/code/game/objects/effects/aliens.dm index 58ac1ee3a6..27d29b3cd6 100644 --- a/code/game/objects/effects/aliens.dm +++ b/code/game/objects/effects/aliens.dm @@ -98,7 +98,7 @@ return /obj/effect/alien/resin/attack_hand() - usr.changeNextMove(8) + usr.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) if (HULK in usr.mutations) usr << "You easily destroy the [name]." for(var/mob/O in oviewers(src)) @@ -125,7 +125,7 @@ /obj/effect/alien/resin/attackby(obj/item/weapon/W as obj, mob/user as mob) - user.changeNextMove(8) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) var/aforce = W.force health = max(0, health - aforce) playsound(loc, 'sound/effects/attackblob.ogg', 100, 1) @@ -233,7 +233,7 @@ Alien plants should do something if theres a lot of poison return /obj/effect/alien/weeds/attackby(var/obj/item/weapon/W, var/mob/user) - user.changeNextMove(8) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) if(W.attack_verb.len) visible_message("\The [src] have been [pick(W.attack_verb)] with \the [W][(user ? " by [user]." : ".")]") else diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm index 84224bff4b..891f280520 100644 --- a/code/game/objects/structures/crates_lockers/closets.dm +++ b/code/game/objects/structures/crates_lockers/closets.dm @@ -349,7 +349,7 @@ if(!escapee.canClick()) return - escapee.changeNextMove(100) + escapee.setClickCooldown(100) //okay, so the closet is either welded or locked... resist!!! escapee << "You lean on the back of \the [src] and start pushing the door open. (this will take about [breakout_time] minutes)" diff --git a/code/game/objects/structures/grille.dm b/code/game/objects/structures/grille.dm index 126aa6eac2..ff540c46ba 100644 --- a/code/game/objects/structures/grille.dm +++ b/code/game/objects/structures/grille.dm @@ -30,7 +30,7 @@ /obj/structure/grille/attack_hand(mob/user as mob) - user.changeNextMove(8) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) playsound(loc, 'sound/effects/grillehit.ogg', 80, 1) user.do_attack_animation(src) @@ -156,7 +156,7 @@ //window placing end else if(!(W.flags & CONDUCT) || !shock(user, 70)) - user.changeNextMove(8) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) user.do_attack_animation(src) playsound(loc, 'sound/effects/grillehit.ogg', 80, 1) switch(W.damtype) diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm index 6a82e64f37..8574054263 100644 --- a/code/game/objects/structures/window.dm +++ b/code/game/objects/structures/window.dm @@ -171,7 +171,7 @@ playsound(loc, 'sound/effects/Glasshit.ogg', 50, 1) /obj/structure/window/attack_hand(mob/user as mob) - user.changeNextMove(8) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) if(HULK in user.mutations) user.say(pick(";RAAAAAAAARGH!", ";HNNNNNNNNNGGGGGGH!", ";GWAAAAAAAARRRHHH!", "NNNNNNNNGGGGGGGGHH!", ";AAAAAAARRRGH!")) user.visible_message("[user] smashes through [src]!") @@ -199,7 +199,7 @@ return /obj/structure/window/attack_generic(var/mob/user, var/damage) - user.changeNextMove(8) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) if(!damage) return if(damage >= 10) @@ -269,7 +269,7 @@ new glasstype(loc) qdel(src) else - user.changeNextMove(8) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) if(W.damtype == BRUTE || W.damtype == BURN) user.do_attack_animation(src) hit(W.force) diff --git a/code/game/turfs/simulated/wall_attacks.dm b/code/game/turfs/simulated/wall_attacks.dm index 9ebd9cee87..dc56061218 100644 --- a/code/game/turfs/simulated/wall_attacks.dm +++ b/code/game/turfs/simulated/wall_attacks.dm @@ -56,7 +56,7 @@ radiate() add_fingerprint(user) - user.changeNextMove(8) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) var/rotting = (locate(/obj/effect/overlay/wallrot) in src) if (HULK in user.mutations) if (rotting || !prob(material.hardness)) @@ -70,7 +70,7 @@ /turf/simulated/wall/attack_generic(var/mob/user, var/damage, var/attack_message, var/wallbreaker) radiate() - user.changeNextMove(8) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) var/rotting = (locate(/obj/effect/overlay/wallrot) in src) if(!damage || !wallbreaker) try_touch(user, rotting) @@ -88,7 +88,7 @@ /turf/simulated/wall/attackby(obj/item/weapon/W as obj, mob/user as mob) - user.changeNextMove(8) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) if (!user.) user << "You don't have the dexterity to do this!" return diff --git a/code/modules/hydroponics/spreading/spreading.dm b/code/modules/hydroponics/spreading/spreading.dm index b50ac8c1f1..d9b477ba28 100644 --- a/code/modules/hydroponics/spreading/spreading.dm +++ b/code/modules/hydroponics/spreading/spreading.dm @@ -234,7 +234,7 @@ /obj/effect/plant/attackby(var/obj/item/weapon/W, var/mob/user) - user.changeNextMove(8) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) plant_controller.add_plant(src) if(istype(W, /obj/item/weapon/wirecutters) || istype(W, /obj/item/weapon/scalpel)) diff --git a/code/modules/hydroponics/trays/tray.dm b/code/modules/hydroponics/trays/tray.dm index 7bfe605b45..b8a92cdff9 100644 --- a/code/modules/hydroponics/trays/tray.dm +++ b/code/modules/hydroponics/trays/tray.dm @@ -545,7 +545,7 @@ A.hydrotray_type = src.type qdel(src) else if(O.force && seed) - user.changeNextMove(8) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) user.visible_message("\The [seed.display_name] has been attacked by [user] with \the [O]!") if(!dead) health -= O.force diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 658e7d3284..8bc4558839 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -1308,7 +1308,7 @@ if(!isliving(usr) || !usr.canClick()) return - usr.changeNextMove(20) + usr.setClickCooldown(20) if(usr.stat > 0) usr << "You are unconcious and cannot do that!" diff --git a/code/modules/mob/living/carbon/resist.dm b/code/modules/mob/living/carbon/resist.dm index 0b43a98058..a5ad3f5845 100644 --- a/code/modules/mob/living/carbon/resist.dm +++ b/code/modules/mob/living/carbon/resist.dm @@ -31,7 +31,7 @@ //These two lines represent a significant buff to grabs... if(!canClick()) return - changeNextMove(100) + setClickCooldown(100) if(can_break_cuffs()) //Don't want to do a lot of logic gating here. break_handcuffs() @@ -65,7 +65,7 @@ if(!canClick()) return - changeNextMove(100) + setClickCooldown(100) if(can_break_cuffs()) //Don't want to do a lot of logic gating here. break_legcuffs() @@ -153,7 +153,7 @@ if(!canClick()) return - changeNextMove(100) + setClickCooldown(100) if(!buckled) return if(!restrained()) diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index fb85edd73b..f8b199cb9d 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -575,7 +575,7 @@ default behaviour is: set category = "IC" if(can_resist()) - changeNextMove(20) + setClickCooldown(20) process_resist() /mob/living/proc/can_resist() diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm index c5035eb447..875bb4c1ce 100644 --- a/code/modules/mob/living/simple_animal/simple_animal.dm +++ b/code/modules/mob/living/simple_animal/simple_animal.dm @@ -290,7 +290,7 @@ //TODO: refactor mob attackby(), attacked_by(), and friends. /mob/living/simple_animal/proc/attacked_with_item(var/obj/item/O, var/mob/user) - user.changeNextMove(8) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) if(!O.force) visible_message("[user] gently taps [src] with \the [O].") return diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 3acd11ae69..f722bc31ed 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -843,7 +843,7 @@ mob/proc/yank_out_object() if(!isliving(usr) || !usr.canClick()) return - usr.changeNextMove(20) + usr.setClickCooldown(20) if(usr.stat == 1) usr << "You are unconcious and cannot do that!" diff --git a/code/modules/mob/mob_grab.dm b/code/modules/mob/mob_grab.dm index d25cd59925..b5ba0a0c4f 100644 --- a/code/modules/mob/mob_grab.dm +++ b/code/modules/mob/mob_grab.dm @@ -259,7 +259,7 @@ assailant.attack_log += "\[[time_stamp()]\] Strangled (kill intent) [affecting.name] ([affecting.ckey])" msg_admin_attack("[key_name(assailant)] strangled (kill intent) [key_name(affecting)]") - affecting.changeNextMove(10) + affecting.setClickCooldown(10) affecting.losebreath += 1 affecting.set_dir(WEST) adjust_position() diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index 7de74612f2..3c3af1f19d 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -169,7 +169,7 @@ var/_move_delay = firemode.move_delay var/shoot_time = (_burst - 1)*_burst_delay - user.changeNextMove(shoot_time) + user.setClickCooldown(shoot_time) if(user.client) user.client.move_delay = world.time + shoot_time //no moving while shooting either next_fire_time = world.time + shoot_time @@ -202,7 +202,7 @@ update_held_icon() //update timing - user.changeNextMove(4) + user.setClickCooldown(4) if(user.client) user.client.move_delay = world.time + _move_delay next_fire_time = world.time + _fire_delay diff --git a/code/modules/reagents/reagent_containers/spray.dm b/code/modules/reagents/reagent_containers/spray.dm index 8d9e8b9869..b4dee5f366 100644 --- a/code/modules/reagents/reagent_containers/spray.dm +++ b/code/modules/reagents/reagent_containers/spray.dm @@ -39,7 +39,7 @@ playsound(src.loc, 'sound/effects/spray2.ogg', 50, 1, -6) - user.changeNextMove(4) + user.setClickCooldown(4) if(reagents.has_reagent("sacid")) message_admins("[key_name_admin(user)] fired sulphuric acid from \a [src].") From 06000a69844e7a6e379d7d405a4f309896c78e98 Mon Sep 17 00:00:00 2001 From: mwerezak Date: Sun, 28 Jun 2015 23:12:11 -0400 Subject: [PATCH 05/21] Adds setMoveCooldown() --- code/ZAS/Airflow.dm | 5 +++-- code/modules/mob/mob_movement.dm | 3 +++ code/modules/projectiles/gun.dm | 4 ++-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/code/ZAS/Airflow.dm b/code/ZAS/Airflow.dm index 9f6451adf9..70c3c0651e 100644 --- a/code/ZAS/Airflow.dm +++ b/code/ZAS/Airflow.dm @@ -116,8 +116,9 @@ obj/item/check_airflow_movable(n) if(!istype(loc, /turf)) break step_towards(src, src.airflow_dest) - if(ismob(src) && src:client) - src:client:move_delay = world.time + vsc.airflow_mob_slowdown + if(ismob(src)) + var/mob/M = src + M.setMoveCooldown(vsc.airflow_mob_slowdown) airflow_dest = null airflow_speed = 0 airflow_time = 0 diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm index 8ba66ffe31..b37192ed76 100644 --- a/code/modules/mob/mob_movement.dm +++ b/code/modules/mob/mob_movement.dm @@ -10,6 +10,9 @@ return (!mover.density || !density || lying) return +/mob/setMoveCooldown(var/timeout) + if(client) + client.move_delay = max(world.time + timeout, client.move_delay) /client/North() ..() diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index 3c3af1f19d..922e5debf4 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -170,7 +170,7 @@ var/shoot_time = (_burst - 1)*_burst_delay user.setClickCooldown(shoot_time) - if(user.client) user.client.move_delay = world.time + shoot_time //no moving while shooting either + user.setMoveCooldown(shoot_time) //no moving while shooting either next_fire_time = world.time + shoot_time //actually attempt to shoot @@ -203,7 +203,7 @@ //update timing user.setClickCooldown(4) - if(user.client) user.client.move_delay = world.time + _move_delay + user.setMoveCooldown(_move_delay) next_fire_time = world.time + _fire_delay if(muzzle_flash) From 92a3d3f9ae59ccecc4074acc2dd64da62614fb81 Mon Sep 17 00:00:00 2001 From: PsiOmegaDelta Date: Fri, 3 Jul 2015 09:46:02 +0200 Subject: [PATCH 06/21] An active AI core now provides camera coverage. --- baystation12.dme | 1 + code/_helpers/unsorted.dm | 5 ++- code/game/machinery/camera/camera.dm | 3 ++ code/modules/mob/freelook/ai/chunk.dm | 16 +++++++++ .../mob/freelook/ai/update_triggers.dm | 34 ++++++++++++++++--- code/modules/mob/freelook/eye.dm | 8 +++-- code/modules/mob/freelook/mask/chunk.dm | 17 ++++------ .../mob/living/silicon/ai/ai_movement.dm | 2 ++ 8 files changed, 69 insertions(+), 17 deletions(-) create mode 100644 code/modules/mob/living/silicon/ai/ai_movement.dm diff --git a/baystation12.dme b/baystation12.dme index ba02f28f65..0e8eb3aaeb 100644 --- a/baystation12.dme +++ b/baystation12.dme @@ -1264,6 +1264,7 @@ #include "code\modules\mob\living\silicon\silicon.dm" #include "code\modules\mob\living\silicon\subystems.dm" #include "code\modules\mob\living\silicon\ai\ai.dm" +#include "code\modules\mob\living\silicon\ai\ai_movement.dm" #include "code\modules\mob\living\silicon\ai\death.dm" #include "code\modules\mob\living\silicon\ai\examine.dm" #include "code\modules\mob\living\silicon\ai\icons.dm" diff --git a/code/_helpers/unsorted.dm b/code/_helpers/unsorted.dm index e44a60ebc2..94b23b2b16 100644 --- a/code/_helpers/unsorted.dm +++ b/code/_helpers/unsorted.dm @@ -579,10 +579,13 @@ proc/anim(turf/location as turf,target as mob|obj,a_icon,a_icon_state as text,fl return toReturn //Step-towards method of determining whether one atom can see another. Similar to viewers() -/proc/can_see(var/atom/source, var/atom/target, var/length=5) // I couldnt be arsed to do actual raycasting :I This is horribly inaccurate. +/proc/can_see(var/atom/source, var/atom/target, var/length=5) // I couldn't be arsed to do actual raycasting :I This is horribly inaccurate. var/turf/current = get_turf(source) var/turf/target_turf = get_turf(target) var/steps = 0 + + if(!current || !target_turf) + return 0 while(current != target_turf) if(steps > length) return 0 diff --git a/code/game/machinery/camera/camera.dm b/code/game/machinery/camera/camera.dm index 4be8749588..c5553d09b5 100644 --- a/code/game/machinery/camera/camera.dm +++ b/code/game/machinery/camera/camera.dm @@ -305,6 +305,9 @@ /obj/machinery/camera/proc/can_see() var/list/see = null var/turf/pos = get_turf(src) + if(!pos) + return list() + if(isXRay()) see = range(view_range, pos) else diff --git a/code/modules/mob/freelook/ai/chunk.dm b/code/modules/mob/freelook/ai/chunk.dm index 89a07bb465..5d82f66d66 100644 --- a/code/modules/mob/freelook/ai/chunk.dm +++ b/code/modules/mob/freelook/ai/chunk.dm @@ -24,6 +24,10 @@ for(var/turf/t in c.can_see()) visible[t] = t + for(var/mob/living/silicon/ai/AI in living_mob_list) + for(var/turf/t in AI.seen_camera_turfs()) + visible[t] = t + // Create a new camera chunk, since the chunks are made as they are needed. /datum/chunk/camera/New(loc, x, y, z) @@ -31,3 +35,15 @@ if(c.can_use()) cameras += c ..() + +/mob/living/silicon/proc/provides_camera_vision() + return 0 + +/mob/living/silicon/ai/provides_camera_vision() + return stat != DEAD + +/mob/living/silicon/robot/provides_camera_vision() + return src.camera && src.camera.network.len + +/mob/living/silicon/ai/proc/seen_camera_turfs() + return seen_turfs_in_range(src, world.view) diff --git a/code/modules/mob/freelook/ai/update_triggers.dm b/code/modules/mob/freelook/ai/update_triggers.dm index 8a91d0540e..f4fea0aa58 100644 --- a/code/modules/mob/freelook/ai/update_triggers.dm +++ b/code/modules/mob/freelook/ai/update_triggers.dm @@ -4,13 +4,13 @@ // Update the portable camera everytime the Robot moves. // This might be laggy, comment it out if there are problems. -/mob/living/silicon/robot/var/updating = 0 +/mob/living/silicon/var/updating = 0 /mob/living/silicon/robot/Move() var/oldLoc = src.loc . = ..() if(.) - if(src.camera && src.camera.network.len) + if(provides_camera_vision()) if(!updating) updating = 1 spawn(BORG_CAMERA_BUFFER) @@ -18,6 +18,21 @@ cameranet.updatePortableCamera(src.camera) updating = 0 +/mob/living/silicon/AI/Move() + var/oldLoc = src.loc + . = ..() + if(.) + if(provides_camera_vision()) + if(!updating) + updating = 1 + spawn(BORG_CAMERA_BUFFER) + if(oldLoc != src.loc) + cameranet.updateVisibility(oldLoc, 0) + cameranet.updateVisibility(loc, 0) + updating = 0 + +#undef BORG_CAMERA_BUFFER + // CAMERA // An addition to deactivate which removes/adds the camera from the chunk list based on if it works or not. @@ -42,8 +57,19 @@ update_coverage(1) /obj/machinery/camera/Destroy() - cameranet.cameras -= src clear_all_networks() + cameranet.cameras -= src ..() -#undef BORG_CAMERA_BUFFER +// Mobs +/mob/living/silicon/ai/rejuvenate() + var/was_dead = stat == DEAD + ..() + if(was_dead && stat != DEAD) + // Arise! + cameranet.updateVisibility(src, 0) + +/mob/living/silicon/ai/death(gibbed) + if(..()) + // If true, the mob went from living to dead (assuming everyone has been overriding as they should...) + cameranet.updateVisibility(src, 0) diff --git a/code/modules/mob/freelook/eye.dm b/code/modules/mob/freelook/eye.dm index fb2b04a434..437b2979dc 100644 --- a/code/modules/mob/freelook/eye.dm +++ b/code/modules/mob/freelook/eye.dm @@ -41,12 +41,15 @@ mob/eye/Destroy() updateallghostimages() ..() -// Movement code. Returns 0 to stop air movement from moving it. /mob/eye/Move(n, direct) if(owner == src) - EyeMove(n, direct) + return EyeMove(n, direct) return 0 +/mob/eye/airflow_hit(atom/A) + airflow_speed = 0 + airflow_dest = null + /mob/eye/examinate() set popup_menu = 0 set src = usr.contents @@ -110,3 +113,4 @@ mob/eye/Destroy() sprint = min(sprint + 0.5, max_sprint) else sprint = initial + return 1 diff --git a/code/modules/mob/freelook/mask/chunk.dm b/code/modules/mob/freelook/mask/chunk.dm index b0973951cc..f98a9b936b 100644 --- a/code/modules/mob/freelook/mask/chunk.dm +++ b/code/modules/mob/freelook/mask/chunk.dm @@ -11,27 +11,24 @@ /datum/chunk/cult/acquireVisibleTurfs(var/list/visible) for(var/mob/living/L in living_mob_list) - for(var/turf/t in L.seen_turfs()) + for(var/turf/t in L.seen_cult_turfs()) visible[t] = t -/mob/living/proc/seen_turfs() +/mob/living/proc/seen_cult_turfs() return seen_turfs_in_range(src, 3) -/mob/living/carbon/human/seen_turfs() - /*if(src.isSynthetic()) - return list()*/ - +/mob/living/carbon/human/seen_cult_turfs() if(mind in cult.current_antagonists) - return seen_turfs_in_range(src, client ? client.view : 7) + return seen_turfs_in_range(src, world.view) return ..() -/mob/living/silicon/seen_turfs() +/mob/living/silicon/seen_cult_turfs() return list() -/mob/living/simple_animal/seen_turfs() +/mob/living/simple_animal/seen_cult_turfs() return seen_turfs_in_range(src, 1) -/mob/living/simple_animal/shade/narsie/seen_turfs() +/mob/living/simple_animal/shade/narsie/seen_cult_turfs() return view(2, src) /proc/seen_turfs_in_range(var/source, var/range) diff --git a/code/modules/mob/living/silicon/ai/ai_movement.dm b/code/modules/mob/living/silicon/ai/ai_movement.dm new file mode 100644 index 0000000000..456d11a981 --- /dev/null +++ b/code/modules/mob/living/silicon/ai/ai_movement.dm @@ -0,0 +1,2 @@ +/mob/living/silicon/ai/SelfMove(turf/n, direct) + return 0 From 06466abdb5101b715a496f426626ca890e50d15a Mon Sep 17 00:00:00 2001 From: PsiOmegaDelta Date: Fri, 3 Jul 2015 09:48:21 +0200 Subject: [PATCH 07/21] Changelog entry. --- html/changelogs/PsiOmegaDelta-AISight.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 html/changelogs/PsiOmegaDelta-AISight.yml diff --git a/html/changelogs/PsiOmegaDelta-AISight.yml b/html/changelogs/PsiOmegaDelta-AISight.yml new file mode 100644 index 0000000000..329cda695d --- /dev/null +++ b/html/changelogs/PsiOmegaDelta-AISight.yml @@ -0,0 +1,5 @@ +author: PsiOmegaDelta +delete-after: True + +changes: + - tweak: "Active AI cores now provides coverage on the AI camera network. Does not utilize actual cameras, thus will not show up on security consoles." From 94685082268d69ec2981a7ac2dcc5bb16d4a852c Mon Sep 17 00:00:00 2001 From: mwerezak Date: Sun, 5 Jul 2015 12:51:55 -0400 Subject: [PATCH 08/21] Adds move cooldown for inventory management, clicking on adjacent atoms --- code/_onclick/click.dm | 23 +++++++++++++++++++++-- code/modules/mob/mob_movement.dm | 2 +- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm index a250b12e43..763ee91f8d 100644 --- a/code/_onclick/click.dm +++ b/code/_onclick/click.dm @@ -99,9 +99,16 @@ update_inv_r_hand(0) return - // A is your location but is not a turf; or is on you (backpack); or is on something on you (box in backpack); sdepth is needed here because webbings and coat pockets are hacky + //Atoms on your person + // A is your location but is not a turf; or is on you (backpack); or is on something on you (box in backpack); sdepth is needed here because contents depth does not equate inventory storage depth. var/sdepth = A.storage_depth(src) - if(!isturf(A) && A == loc || (sdepth != -1 && sdepth <= 1)) + if((!isturf(A) && A == loc) || (sdepth != -1 && sdepth <= 1)) + // faster access to objects already on you + if(A in contents) + setMoveCooldown(5) //taking an item off of an inventory slot + else + setMoveCooldown(10) //getting something out of a backpack + if(W) var/resolved = W.resolve_attackby(A, src) if(!resolved && A && W) @@ -115,10 +122,13 @@ if(!isturf(loc)) // This is going to stop you from telekinesing from inside a closet, but I don't shed many tears for that return + //Atoms on turfs (not on your person) // A is a turf or is on a turf, or in something on a turf (pen in a box); but not something in something on a turf (pen in a box in a backpack) sdepth = A.storage_depth_turf() if(isturf(A) || isturf(A.loc) || (sdepth != -1 && sdepth <= 1)) if(A.Adjacent(src)) // see adjacent.dm + setMoveCooldown(10) + if(W) // Return 1 in attackby() to prevent afterattack() effects (when safely moving items for example) var/resolved = W.resolve_attackby(A,src) @@ -190,6 +200,15 @@ if((LASER in mutations) && a_intent == I_HURT) LaserEyes(A) // moved into a proc below else if(TK in mutations) + switch(get_dist(src,A)) + if(1 to 5) // not adjacent may mean blocked by window + setMoveCooldown(2) + if(5 to 7) + setMoveCooldown(5) + if(8 to tk_maxrange) + setMoveCooldown(10) + else + return A.attack_tk(src) /* Restrained ClickOn diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm index b37192ed76..7da4f731e8 100644 --- a/code/modules/mob/mob_movement.dm +++ b/code/modules/mob/mob_movement.dm @@ -10,7 +10,7 @@ return (!mover.density || !density || lying) return -/mob/setMoveCooldown(var/timeout) +/mob/proc/setMoveCooldown(var/timeout) if(client) client.move_delay = max(world.time + timeout, client.move_delay) From 0adebcb2bfd24198ff8509fab92507e3d0c8057f Mon Sep 17 00:00:00 2001 From: PsiOmega Date: Sun, 5 Jul 2015 20:53:33 +0200 Subject: [PATCH 09/21] Admin secrets refactor. Turns the entries in the secret admin secrets panel into datums, which will make it much easier to add, edit, and remove new entries. This initial commit only contains an initial proof of concept entry implementation and the supporting code. Next commit will contain all relevant entries. --- baystation12.dme | 2 + code/modules/admin/admin.dm | 114 +--- code/modules/admin/admin_secrets.dm | 66 +++ code/modules/admin/secrets/gravity.dm | 29 + code/modules/admin/topic.dm | 736 +------------------------- 5 files changed, 111 insertions(+), 836 deletions(-) create mode 100644 code/modules/admin/admin_secrets.dm create mode 100644 code/modules/admin/secrets/gravity.dm diff --git a/baystation12.dme b/baystation12.dme index ba02f28f65..7bc13ae072 100644 --- a/baystation12.dme +++ b/baystation12.dme @@ -828,6 +828,7 @@ #include "code\modules\admin\admin_investigate.dm" #include "code\modules\admin\admin_memo.dm" #include "code\modules\admin\admin_ranks.dm" +#include "code\modules\admin\admin_secrets.dm" #include "code\modules\admin\admin_verbs.dm" #include "code\modules\admin\banjob.dm" #include "code\modules\admin\create_mob.dm" @@ -842,6 +843,7 @@ #include "code\modules\admin\ToRban.dm" #include "code\modules\admin\DB ban\functions.dm" #include "code\modules\admin\permissionverbs\permissionedit.dm" +#include "code\modules\admin\secrets\gravity.dm" #include "code\modules\admin\verbs\adminhelp.dm" #include "code\modules\admin\verbs\adminjump.dm" #include "code\modules\admin\verbs\adminpm.dm" diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm index 447178ecb3..dba6519296 100644 --- a/code/modules/admin/admin.dm +++ b/code/modules/admin/admin.dm @@ -604,109 +604,17 @@ proc/admin_notice(var/message, var/rights) if(!check_rights(0)) return var/dat = "The first rule of adminbuse is: you don't talk about the adminbuse.
" - - if(check_rights(R_ADMIN,0)) - dat += {" - Admin Secrets
-
- Bombing List
- Show current traitors and objectives
- Show last [length(lastsignalers)] signalers
- Show last [length(lawchanges)] law changes
- Show AI Laws
- Show Game Mode
- Show Crew Manifest
- List DNA (Blood)
- List Fingerprints

-
- "} - - if(check_rights(R_FUN,0)) - dat += {" - 'Random' Events
-
- Toggle station artificial gravity
- Spawn a wave of meteors (aka lagocolyptic shower)
- Spawn a gravitational anomaly (aka lagitational anomolag)
- Spawn wormholes
- Spawn blob
- Trigger a Xenomorph infestation
- Trigger a Cortical Borer infestation
- Spawn an Alien silently
- Trigger a Spider infestation
- Send in a space ninja
- Send in a strike team
- Trigger an Carp migration
- Irradiate the station
- Trigger a Prison Break
- Trigger a Virus Outbreak
- Spawn an Immovable Rod
- Toggle a "lights out" event
- Spawn an Ion Storm
- Spawn Space-Vines
- Trigger a communication blackout
-
- Fun Secrets
-
- Remove 'internal' clothing
- Remove ALL clothing
- Turn all humans into monkeys
- Remove firesuits, grilles, and pods
- Make all areas powered
- Make all areas unpowered
- Power all SMES
- Toggle Prison Shuttle Status(Use with S/R)
- Send Prison Shuttle
- Return Prison Shuttle
- Warp all Players to Prison
- Triple AI mode (needs to be used in the lobby)
- Everyone is the traitor
- There can only be one!
- Ghost Mode
- Make all players retarded
- Make all items look like guns
- Paintball Mode
- Japanese Animes Mode
- Egalitarian Station Mode
- Launch a shuttle
- Force launch a shuttle
- Jump a shuttle
- Move a shuttle
- Break all lights
- Fix all lights
- Best Friend AI
- The floor is lava! (DANGEROUS: extremely lame)
- "} - - if(check_rights(R_SERVER,0)) - dat += "Toggle bomb cap
" - - if(check_rights(R_SERVER|R_FUN,0)) - dat += {" -
- Final Solutions
- (Warning, these will end the round!)
-
- Summon Nar-Sie
- Start a Supermatter Cascade
- "} - - dat += "
" - - if(check_rights(R_DEBUG,0)) - dat += {" - Security Level Elevated
-
- Change all maintenance doors to engie/brig access only
- Change all maintenance doors to brig access only
- Remove cap on security officers
-
- Coder Secrets
-
- Show Job Debug
- Admin Log
-
- "} + for(var/datum/admin_secret_category/category in admin_secrets.categories) + if(!category.can_view(usr)) + continue + dat += "[category.name]
" + if(category.desc) + dat += "[category.desc]
" + dat += "
" + for(var/datum/admin_secret_item/item in category.items) + if(!item.can_execute(usr)) + continue + dat += "[item.name]
" usr << browse(dat, "window=secrets") return diff --git a/code/modules/admin/admin_secrets.dm b/code/modules/admin/admin_secrets.dm new file mode 100644 index 0000000000..87c04ea625 --- /dev/null +++ b/code/modules/admin/admin_secrets.dm @@ -0,0 +1,66 @@ +var/datum/admin_secrets/admin_secrets = new() + +/datum/admin_secrets + var/list/datum/admin_secret_category/categories + var/list/datum/admin_secret_item/items + +/datum/admin_secrets/New() + ..() + categories = init_subtypes(/datum/admin_secret_category) + items = list() + var/list/category_assoc = list() + for(var/datum/category in categories) + category_assoc[category.type] = category + + for(var/item_type in (typesof(/datum/admin_secret_item) - /datum/admin_secret_item)) + var/datum/admin_secret_item/secret_item = item_type + if(!initial(secret_item.name)) + continue + + var/datum/admin_secret_item/item = new item_type() + var/datum/admin_secret_category/category = category_assoc[item.category] + category.items += item + items += item + +/datum/admin_secret_category + var/name = "" + var/desc = "" + var/list/datum/admin_secret_item/items + +/datum/admin_secret_category + ..() + items = list() + +/datum/admin_secret_category/proc/can_view(var/mob/user) + for(var/datum/admin_secret_item/item in items) + if(item.can_execute(user)) + return 1 + return 0 + +/datum/admin_secret_item + var/name = "" + var/category = null + var/permissions = R_HOST + +/datum/admin_secret_item/proc/can_execute(var/mob/user) + return check_rights(permissions, 0, user) + +/datum/admin_secret_item/proc/execute(var/mob/user) + if(!can_execute(user)) + return 0 + + log_admin("[key_name(user)] used secret [name]") + return 1 + +/************************* +* Pre-defined categories * +*************************/ +/datum/admin_secret_category/random_events + name = "'Random' Events" + +/************************* +* Pre-defined base items * +*************************/ +/datum/admin_secret_item/random_event + category = /datum/admin_secret_category/random_events + permissions = R_FUN diff --git a/code/modules/admin/secrets/gravity.dm b/code/modules/admin/secrets/gravity.dm new file mode 100644 index 0000000000..8ff9c915d4 --- /dev/null +++ b/code/modules/admin/secrets/gravity.dm @@ -0,0 +1,29 @@ +/********** +* Gravity * +**********/ +/datum/admin_secret_item/random_event/gravity + name = "Toggle station artificial gravity" + +/datum/admin_secret_item/random_event/gravity/execute(var/mob/user) + . = ..() + if(!.) + return + + if(!(ticker && ticker.mode)) + user << "Please wait until the game starts! Not sure how it will work otherwise." + return + + gravity_is_on = !gravity_is_on + for(var/area/A in world) + A.gravitychange(gravity_is_on,A) + + feedback_inc("admin_secrets_fun_used",1) + feedback_add_details("admin_secrets_fun_used","Grav") + if(gravity_is_on) + log_admin("[key_name(usr)] toggled gravity on.", 1) + message_admins("\blue [key_name_admin(usr)] toggled gravity on.", 1) + command_announcement.Announce("Gravity generators are again functioning within normal parameters. Sorry for any inconvenience.") + else + log_admin("[key_name(usr)] toggled gravity off.", 1) + message_admins("\blue [key_name_admin(usr)] toggled gravity off.", 1) + command_announcement.Announce("Feedback surge detected in mass-distributions systems. Artificial gravity has been disabled whilst the system reinitializes. Further failures may result in a gravitational collapse and formation of blackholes. Have a nice day.") diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index e681c9ba95..7f46170b5e 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -1645,739 +1645,9 @@ break return - else if(href_list["secretsfun"]) - if(!check_rights(R_FUN)) return - - var/ok = 0 - switch(href_list["secretsfun"]) - if("sec_clothes") - feedback_inc("admin_secrets_fun_used",1) - feedback_add_details("admin_secrets_fun_used","SC") - for(var/obj/item/clothing/under/O in world) - qdel(O) - ok = 1 - if("sec_all_clothes") - feedback_inc("admin_secrets_fun_used",1) - feedback_add_details("admin_secrets_fun_used","SAC") - for(var/obj/item/clothing/O in world) - qdel(O) - ok = 1 - if("sec_classic1") - feedback_inc("admin_secrets_fun_used",1) - feedback_add_details("admin_secrets_fun_used","SC1") - for(var/obj/item/clothing/suit/fire/O in world) - qdel(O) - for(var/obj/structure/grille/O in world) - qdel(O) -/* for(var/obj/machinery/vehicle/pod/O in world) - for(var/mob/M in src) - M.loc = src.loc - if (M.client) - M.client.perspective = MOB_PERSPECTIVE - M.client.eye = M - qdel(O) - ok = 1*/ - if("monkey") - feedback_inc("admin_secrets_fun_used",1) - feedback_add_details("admin_secrets_fun_used","M") - for(var/mob/living/carbon/human/H in mob_list) - spawn(0) - H.monkeyize() - ok = 1 - if("corgi") - feedback_inc("admin_secrets_fun_used",1) - feedback_add_details("admin_secrets_fun_used","M") - for(var/mob/living/carbon/human/H in mob_list) - spawn(0) - H.corgize() - ok = 1 - if("striketeam") - if(usr.client.strike_team()) - feedback_inc("admin_secrets_fun_used",1) - feedback_add_details("admin_secrets_fun_used","Strike") - if("tripleAI") - usr.client.triple_ai() - feedback_inc("admin_secrets_fun_used",1) - feedback_add_details("admin_secrets_fun_used","TriAI") - if("gravity") - if(!(ticker && ticker.mode)) - usr << "Please wait until the game starts! Not sure how it will work otherwise." - return - gravity_is_on = !gravity_is_on - for(var/area/A in world) - A.gravitychange(gravity_is_on,A) - feedback_inc("admin_secrets_fun_used",1) - feedback_add_details("admin_secrets_fun_used","Grav") - if(gravity_is_on) - log_admin("[key_name(usr)] toggled gravity on.", 1) - message_admins("\blue [key_name_admin(usr)] toggled gravity on.", 1) - command_announcement.Announce("Gravity generators are again functioning within normal parameters. Sorry for any inconvenience.") - else - log_admin("[key_name(usr)] toggled gravity off.", 1) - message_admins("\blue [key_name_admin(usr)] toggled gravity off.", 1) - command_announcement.Announce("Feedback surge detected in mass-distributions systems. Artifical gravity has been disabled whilst the system reinitializes. Further failures may result in a gravitational collapse and formation of blackholes. Have a nice day.") - if("wave") - feedback_inc("admin_secrets_fun_used",1) - feedback_add_details("admin_secrets_fun_used","Meteor") - log_admin("[key_name(usr)] spawned a meteor wave", 1) - message_admins("\blue [key_name_admin(usr)] spawned a meteor wave.", 1) - new /datum/event/meteor_wave - if("goblob") - feedback_inc("admin_secrets_fun_used",1) - feedback_add_details("admin_secrets_fun_used","Blob") - log_admin("[key_name(usr)] spawned a blob", 1) - message_admins("\blue [key_name_admin(usr)] spawned a blob.", 1) - new /datum/event/blob - - if("aliens") - feedback_inc("admin_secrets_fun_used",1) - feedback_add_details("admin_secrets_fun_used","Aliens") - log_admin("[key_name(usr)] spawned an alien infestation", 1) - message_admins("\blue [key_name_admin(usr)] attempted an alien infestation", 1) - xenomorphs.attempt_random_spawn() - if("borers") - feedback_inc("admin_secrets_fun_used",1) - feedback_add_details("admin_secrets_fun_used","Borers") - log_admin("[key_name(usr)] spawned a cortical borer infestation.", 1) - message_admins("\blue [key_name_admin(usr)] spawned a cortical borer infestation.", 1) - borers.attempt_random_spawn() - - if("power") - feedback_inc("admin_secrets_fun_used",1) - feedback_add_details("admin_secrets_fun_used","P") - log_admin("[key_name(usr)] made all areas powered", 1) - message_admins("\blue [key_name_admin(usr)] made all areas powered", 1) - power_restore() - if("unpower") - feedback_inc("admin_secrets_fun_used",1) - feedback_add_details("admin_secrets_fun_used","UP") - log_admin("[key_name(usr)] made all areas unpowered", 1) - message_admins("\blue [key_name_admin(usr)] made all areas unpowered", 1) - power_failure() - if("quickpower") - feedback_inc("admin_secrets_fun_used",1) - feedback_add_details("admin_secrets_fun_used","QP") - log_admin("[key_name(usr)] made all SMESs powered", 1) - message_admins("\blue [key_name_admin(usr)] made all SMESs powered", 1) - power_restore_quick() - if("activateprison") - feedback_inc("admin_secrets_fun_used",1) - feedback_add_details("admin_secrets_fun_used","AP") - world << "\blue Transit signature detected." - world << "\blue Incoming shuttle." - /* - var/A = locate(/area/shuttle_prison) - for(var/atom/movable/AM as mob|obj in A) - AM.z = 1 - AM.Move() - */ - message_admins("\blue [key_name_admin(usr)] sent the prison shuttle to the station.", 1) - if("deactivateprison") - /* - feedback_inc("admin_secrets_fun_used",1) - feedback_add_details("admin_secrets_fun_used","DP") - var/A = locate(/area/shuttle_prison) - for(var/atom/movable/AM as mob|obj in A) - AM.z = 2 - AM.Move() - */ - message_admins("\blue [key_name_admin(usr)] sent the prison shuttle back.", 1) - if("toggleprisonstatus") - feedback_inc("admin_secrets_fun_used",1) - feedback_add_details("admin_secrets_fun_used","TPS") - for(var/obj/machinery/computer/prison_shuttle/PS in world) - PS.allowedtocall = !(PS.allowedtocall) - message_admins("\blue [key_name_admin(usr)] toggled status of prison shuttle to [PS.allowedtocall].", 1) - if("prisonwarp") - if(!ticker) - alert("The game hasn't started yet!", null, null, null, null, null) - return - feedback_inc("admin_secrets_fun_used",1) - feedback_add_details("admin_secrets_fun_used","PW") - message_admins("\blue [key_name_admin(usr)] teleported all players to the prison station.", 1) - for(var/mob/living/carbon/human/H in mob_list) - var/turf/loc = find_loc(H) - var/security = 0 - if(loc.z > 1 || prisonwarped.Find(H)) -//don't warp them if they aren't ready or are already there - continue - H.Paralyse(5) - if(H.wear_id) - var/obj/item/weapon/card/id/id = H.get_idcard() - for(var/A in id.access) - if(A == access_security) - security++ - if(!security) - //strip their stuff before they teleport into a cell :downs: - for(var/obj/item/weapon/W in H) - if(istype(W, /obj/item/organ/external)) - continue - //don't strip organs - H.drop_from_inventory(W) - //teleport person to cell - H.loc = pick(prisonwarp) - H.equip_to_slot_or_del(new /obj/item/clothing/under/color/orange(H), slot_w_uniform) - H.equip_to_slot_or_del(new /obj/item/clothing/shoes/orange(H), slot_shoes) - else - //teleport security person - H.loc = pick(prisonsecuritywarp) - prisonwarped += H - if("launchshuttle") - if(!shuttle_controller) return // Something is very wrong, the shuttle controller has not been created. - - feedback_inc("admin_secrets_fun_used",1) - feedback_add_details("admin_secrets_fun_used","ShL") - - var/list/valid_shuttles = list() - for (var/shuttle_tag in shuttle_controller.shuttles) - if (istype(shuttle_controller.shuttles[shuttle_tag], /datum/shuttle/ferry)) - valid_shuttles += shuttle_tag - - var/shuttle_tag = input("Which shuttle do you want to launch?") as null|anything in valid_shuttles - - if (!shuttle_tag) - return - - var/datum/shuttle/ferry/S = shuttle_controller.shuttles[shuttle_tag] - if (S.can_launch()) - S.launch(usr) - message_admins("\blue [key_name_admin(usr)] launched the [shuttle_tag] shuttle", 1) - log_admin("[key_name(usr)] launched the [shuttle_tag] shuttle") - else - alert("The [shuttle_tag] shuttle cannot be launched at this time. It's probably busy.") - - if("forcelaunchshuttle") - if(!shuttle_controller) return // Something is very wrong, the shuttle controller has not been created. - - feedback_inc("admin_secrets_fun_used",1) - feedback_add_details("admin_secrets_fun_used","ShFL") - - var/list/valid_shuttles = list() - for (var/shuttle_tag in shuttle_controller.shuttles) - if (istype(shuttle_controller.shuttles[shuttle_tag], /datum/shuttle/ferry)) - valid_shuttles += shuttle_tag - - var/shuttle_tag = input("Which shuttle's launch do you want to force?") as null|anything in valid_shuttles - - if (!shuttle_tag) - return - - var/datum/shuttle/ferry/S = shuttle_controller.shuttles[shuttle_tag] - if (S.can_force()) - S.force_launch(usr) - message_admins("\blue [key_name_admin(usr)] has forced the [shuttle_tag] shuttle launch", 1) - log_admin("[key_name(usr)] has forced the [shuttle_tag] shuttle launch") - else - alert("The [shuttle_tag] shuttle launch cannot be forced at this time. It's busy, or hasn't been launched yet.") - - if("jumpshuttle") - if(!shuttle_controller) return // Something is very wrong, the shuttle controller has not been created. - - feedback_inc("admin_secrets_fun_used",1) - feedback_add_details("admin_secrets_fun_used","ShJ") - - var/shuttle_tag = input("Which shuttle do you want to jump?") as null|anything in shuttle_controller.shuttles - if (!shuttle_tag) return - - var/datum/shuttle/S = shuttle_controller.shuttles[shuttle_tag] - - var/origin_area = input("Which area is the shuttle at now? (MAKE SURE THIS IS CORRECT OR THINGS WILL BREAK)") as null|area in world - if (!origin_area) return - - var/destination_area = input("Which area is the shuttle at now? (MAKE SURE THIS IS CORRECT OR THINGS WILL BREAK)") as null|area in world - if (!destination_area) return - - var/long_jump = alert("Is there a transition area for this jump?","", "Yes", "No") - if (long_jump == "Yes") - var/transition_area = input("Which area is the transition area? (MAKE SURE THIS IS CORRECT OR THINGS WILL BREAK)") as null|area in world - if (!transition_area) return - - var/move_duration = input("How many seconds will this jump take?") as num - - S.long_jump(origin_area, destination_area, transition_area, move_duration) - message_admins("\blue [key_name_admin(usr)] has initiated a jump from [origin_area] to [destination_area] lasting [move_duration] seconds for the [shuttle_tag] shuttle", 1) - log_admin("[key_name_admin(usr)] has initiated a jump from [origin_area] to [destination_area] lasting [move_duration] seconds for the [shuttle_tag] shuttle") - else - S.short_jump(origin_area, destination_area) - message_admins("\blue [key_name_admin(usr)] has initiated a jump from [origin_area] to [destination_area] for the [shuttle_tag] shuttle", 1) - log_admin("[key_name_admin(usr)] has initiated a jump from [origin_area] to [destination_area] for the [shuttle_tag] shuttle") - - if("moveshuttle") - - if(!shuttle_controller) return // Something is very wrong, the shuttle controller has not been created. - - feedback_inc("admin_secrets_fun_used",1) - feedback_add_details("admin_secrets_fun_used","ShM") - - var/confirm = alert("This command directly moves a shuttle from one area to another. DO NOT USE THIS UNLESS YOU ARE DEBUGGING A SHUTTLE AND YOU KNOW WHAT YOU ARE DOING.", "Are you sure?", "Ok", "Cancel") - if (confirm == "Cancel") - return - - var/shuttle_tag = input("Which shuttle do you want to jump?") as null|anything in shuttle_controller.shuttles - if (!shuttle_tag) return - - var/datum/shuttle/S = shuttle_controller.shuttles[shuttle_tag] - - var/origin_area = input("Which area is the shuttle at now? (MAKE SURE THIS IS CORRECT OR THINGS WILL BREAK)") as null|area in world - if (!origin_area) return - - var/destination_area = input("Which area is the shuttle at now? (MAKE SURE THIS IS CORRECT OR THINGS WILL BREAK)") as null|area in world - if (!destination_area) return - - S.move(origin_area, destination_area) - message_admins("\blue [key_name_admin(usr)] moved the [shuttle_tag] shuttle", 1) - log_admin("[key_name(usr)] moved the [shuttle_tag] shuttle") - - if("togglebombcap") - feedback_inc("admin_secrets_fun_used",1) - feedback_add_details("admin_secrets_fun_used","BC") - switch(max_explosion_range) - if(14) max_explosion_range = 16 - if(16) max_explosion_range = 20 - if(20) max_explosion_range = 28 - if(28) max_explosion_range = 56 - if(56) max_explosion_range = 128 - if(128) max_explosion_range = 14 - var/range_dev = max_explosion_range *0.25 - var/range_high = max_explosion_range *0.5 - var/range_low = max_explosion_range - message_admins("\red [key_name_admin(usr)] changed the bomb cap to [range_dev], [range_high], [range_low]", 1) - log_admin("[key_name_admin(usr)] changed the bomb cap to [max_explosion_range]") - - if("flicklights") - feedback_inc("admin_secrets_fun_used",1) - feedback_add_details("admin_secrets_fun_used","FL") - while(!usr.stat) -//knock yourself out to stop the ghosts - for(var/mob/M in player_list) - if(M.stat != 2 && prob(25)) - var/area/AffectedArea = get_area(M) - if(AffectedArea.name != "Space" && AffectedArea.name != "Engine Walls" && AffectedArea.name != "Chemical Lab Test Chamber" && AffectedArea.name != "Escape Shuttle" && AffectedArea.name != "Arrival Area" && AffectedArea.name != "Arrival Shuttle" && AffectedArea.name != "start area" && AffectedArea.name != "Engine Combustion Chamber") - AffectedArea.power_light = 0 - AffectedArea.power_change() - spawn(rand(55,185)) - AffectedArea.power_light = 1 - AffectedArea.power_change() - var/Message = rand(1,4) - switch(Message) - if(1) - M.show_message(text("\blue You shudder as if cold..."), 1) - if(2) - M.show_message(text("\blue You feel something gliding across your back..."), 1) - if(3) - M.show_message(text("\blue Your eyes twitch, you feel like something you can't see is here..."), 1) - if(4) - M.show_message(text("\blue You notice something moving out of the corner of your eye, but nothing is there..."), 1) - for(var/obj/W in orange(5,M)) - if(prob(25) && !W.anchored) - step_rand(W) - sleep(rand(100,1000)) - for(var/mob/M in player_list) - if(M.stat != 2) - M.show_message(text("\blue The chilling wind suddenly stops..."), 1) -/* if("shockwave") - ok = 1 - world << "\red ALERT: STATION STRESS CRITICAL" - sleep(60) - world << "\red ALERT: STATION STRESS CRITICAL. TOLERABLE LEVELS EXCEEDED!" - sleep(80) - world << "\red ALERT: STATION STRUCTURAL STRESS CRITICAL. SAFETY MECHANISMS FAILED!" - sleep(40) - for(var/mob/M in world) - shake_camera(M, 400, 1) - for(var/obj/structure/window/W in world) - spawn(0) - sleep(rand(10,400)) - W.ex_act(rand(2,1)) - for(var/obj/structure/grille/G in world) - spawn(0) - sleep(rand(20,400)) - G.ex_act(rand(2,1)) - for(var/obj/machinery/door/D in world) - spawn(0) - sleep(rand(20,400)) - D.ex_act(rand(2,1)) - for(var/turf/station/floor/Floor in world) - spawn(0) - sleep(rand(30,400)) - Floor.ex_act(rand(2,1)) - for(var/obj/structure/cable/Cable in world) - spawn(0) - sleep(rand(30,400)) - Cable.ex_act(rand(2,1)) - for(var/obj/structure/closet/Closet in world) - spawn(0) - sleep(rand(30,400)) - Closet.ex_act(rand(2,1)) - for(var/obj/machinery/Machinery in world) - spawn(0) - sleep(rand(30,400)) - Machinery.ex_act(rand(1,3)) - for(var/turf/station/wall/Wall in world) - spawn(0) - sleep(rand(30,400)) - Wall.ex_act(rand(2,1)) */ - if("wave") - feedback_inc("admin_secrets_fun_used",1) - feedback_add_details("admin_secrets_fun_used","MW") - new /datum/event/meteor_wave - - if("gravanomalies") - feedback_inc("admin_secrets_fun_used",1) - feedback_add_details("admin_secrets_fun_used","GA") - command_announcement.Announce("Gravitational anomalies detected on the station. There is no additional data.", "Anomaly Alert", 'sound/AI/granomalies.ogg') - var/turf/T = pick(blobstart) - var/obj/effect/bhole/bh = new /obj/effect/bhole( T.loc, 30 ) - spawn(rand(100, 600)) - qdel(bh) - - if("timeanomalies") //dear god this code was awful :P Still needs further optimisation - feedback_inc("admin_secrets_fun_used",1) - feedback_add_details("admin_secrets_fun_used","STA") - //moved to its own dm so I could split it up and prevent the spawns copying variables over and over - //can be found in code\game\game_modes\events\wormholes.dm - wormhole_event() - - if("goblob") - feedback_inc("admin_secrets_fun_used",1) - feedback_add_details("admin_secrets_fun_used","BL") - mini_blob_event() - message_admins("[key_name_admin(usr)] has spawned blob", 1) - if("aliens") - feedback_inc("admin_secrets_fun_used",1) - feedback_add_details("admin_secrets_fun_used","AL") - if(xenomorphs.attempt_random_spawn()) - message_admins("[key_name_admin(usr)] has spawned aliens", 1) - if("spiders") - feedback_inc("admin_secrets_fun_used",1) - feedback_add_details("admin_secrets_fun_used","SL") - new /datum/event/spider_infestation - message_admins("[key_name_admin(usr)] has spawned spiders", 1) - if("comms_blackout") - feedback_inc("admin_secrets_fun_used",1) - feedback_add_details("admin_secrets_fun_used","CB") - var/answer = alert(usr, "Would you like to alert the crew?", "Alert", "Yes", "No") - if(answer == "Yes") - communications_blackout(0) - else - communications_blackout(1) - message_admins("[key_name_admin(usr)] triggered a communications blackout.", 1) - if("carp") - feedback_inc("admin_secrets_fun_used",1) - feedback_add_details("admin_secrets_fun_used","C") - var/choice = input("You sure you want to spawn carp?") in list("Badmin", "Cancel") - if(choice == "Badmin") - message_admins("[key_name_admin(usr)] has spawned carp.", 1) - new /datum/event/carp_migration - if("radiation") - feedback_inc("admin_secrets_fun_used",1) - feedback_add_details("admin_secrets_fun_used","R") - message_admins("[key_name_admin(usr)] has has irradiated the station", 1) - new /datum/event/radiation_storm - if("immovable") - feedback_inc("admin_secrets_fun_used",1) - feedback_add_details("admin_secrets_fun_used","IR") - message_admins("[key_name_admin(usr)] has sent an immovable rod to the station", 1) - immovablerod() - if("prison_break") - feedback_inc("admin_secrets_fun_used",1) - feedback_add_details("admin_secrets_fun_used","PB") - message_admins("[key_name_admin(usr)] has allowed a prison break", 1) - prison_break() - if("lightout") - feedback_inc("admin_secrets_fun_used",1) - feedback_add_details("admin_secrets_fun_used","LO") - message_admins("[key_name_admin(usr)] has broke a lot of lights", 1) - lightsout(1,2) - if("blackout") - feedback_inc("admin_secrets_fun_used",1) - feedback_add_details("admin_secrets_fun_used","BO") - message_admins("[key_name_admin(usr)] broke all lights", 1) - lightsout(0,0) - if("whiteout") - feedback_inc("admin_secrets_fun_used",1) - feedback_add_details("admin_secrets_fun_used","WO") - for(var/obj/machinery/light/L in world) - L.fix() - message_admins("[key_name_admin(usr)] fixed all lights", 1) - if("friendai") - feedback_inc("admin_secrets_fun_used",1) - feedback_add_details("admin_secrets_fun_used","FA") - for(var/mob/aiEye/aE in mob_list) - aE.icon_state = "ai_friend" - for(var/obj/machinery/M in machines) - if(istype(M, /obj/machinery/ai_status_display)) - var/obj/machinery/ai_status_display/A = M - A.emotion = "Friend Computer" - else if(istype(M, /obj/machinery/status_display)) - var/obj/machinery/status_display/A = M - A.friendc = 1 - message_admins("[key_name_admin(usr)] turned all AIs into best friends.", 1) - if("floorlava") - if(floorIsLava) - usr << "The floor is lava already." - return - feedback_inc("admin_secrets_fun_used",1) - feedback_add_details("admin_secrets_fun_used","LF") - - //Options - var/length = input(usr, "How long will the lava last? (in seconds)", "Length", 180) as num - length = min(abs(length), 1200) - - var/damage = input(usr, "How deadly will the lava be?", "Damage", 2) as num - damage = min(abs(damage), 100) - - var/sure = alert(usr, "Are you sure you want to do this?", "Confirmation", "YES!", "Nah") - if(sure == "Nah") - return - floorIsLava = 1 - - message_admins("[key_name_admin(usr)] made the floor LAVA! It'll last [length] seconds and it will deal [damage] damage to everyone.", 1) - - for(var/turf/simulated/floor/F in world) - if(F.z in config.station_levels) - F.name = "lava" - F.desc = "The floor is LAVA!" - F.overlays += "lava" - F.lava = 1 - - spawn(0) - for(var/i = i, i < length, i++) // 180 = 3 minutes - if(damage) - for(var/mob/living/carbon/L in living_mob_list) - if(istype(L.loc, /turf/simulated/floor)) // Are they on LAVA?! - var/turf/simulated/floor/F = L.loc - if(F.lava) - var/safe = 0 - for(var/obj/structure/O in F.contents) - if(O.level > F.level && !istype(O, /obj/structure/window)) // Something to stand on and it isn't under the floor! - safe = 1 - break - if(!safe) - L.adjustFireLoss(damage) - - - sleep(10) - - for(var/turf/simulated/floor/F in world) // Reset everything. - if(F.z in config.station_levels) - F.name = initial(F.name) - F.desc = initial(F.desc) - F.overlays.Cut() - F.lava = 0 - F.update_icon() - floorIsLava = 0 - return - if("virus") - feedback_inc("admin_secrets_fun_used",1) - feedback_add_details("admin_secrets_fun_used","V") - var/answer = alert("Do you want this to be a greater disease or a lesser one?",,"Greater","Lesser") - if(answer=="Lesser") - virus2_lesser_infection() - message_admins("[key_name_admin(usr)] has triggered a lesser virus outbreak.", 1) - else - virus2_greater_infection() - message_admins("[key_name_admin(usr)] has triggered a greater virus outbreak.", 1) - if("retardify") - feedback_inc("admin_secrets_fun_used",1) - feedback_add_details("admin_secrets_fun_used","RET") - for(var/mob/living/carbon/human/H in player_list) - H << "\red You suddenly feel stupid." - H.setBrainLoss(60) - message_admins("[key_name_admin(usr)] made everybody retarded") - if("fakeguns") - feedback_inc("admin_secrets_fun_used",1) - feedback_add_details("admin_secrets_fun_used","FG") - for(var/obj/item/W in world) - if(istype(W, /obj/item/clothing) || istype(W, /obj/item/weapon/card/id) || istype(W, /obj/item/weapon/disk) || istype(W, /obj/item/weapon/tank)) - continue - W.icon = 'icons/obj/gun.dmi' - W.icon_state = "revolver" - W.item_state = "gun" - message_admins("[key_name_admin(usr)] made every item look like a gun") - if("schoolgirl") - feedback_inc("admin_secrets_fun_used",1) - feedback_add_details("admin_secrets_fun_used","SG") - for(var/obj/item/clothing/under/W in world) - W.icon_state = "schoolgirl" - W.item_state = "w_suit" - message_admins("[key_name_admin(usr)] activated Japanese Animes mode") - world << sound('sound/AI/animes.ogg') - if("paintball") - feedback_inc("admin_secrets_fun_used",1) - feedback_add_details("admin_secrets_fun_used","PB") - for(var/species in all_species) - var/datum/species/S = all_species[species] - S.blood_color = "rainbow" - for(var/obj/effect/decal/cleanable/blood/B in world) - B.basecolor = "rainbow" - B.update_icon() - message_admins("[key_name_admin(usr)] activated Paintball mode") - if("eagles")//SCRAW - feedback_inc("admin_secrets_fun_used",1) - feedback_add_details("admin_secrets_fun_used","EgL") - for(var/obj/machinery/door/airlock/W in world) - if(W.z in config.station_levels && !istype(get_area(W), /area/bridge) && !istype(get_area(W), /area/crew_quarters) && !istype(get_area(W), /area/security/prison)) - W.req_access = list() - message_admins("[key_name_admin(usr)] activated Egalitarian Station mode") - command_announcement.Announce("Centcomm airlock control override activated. Please take this time to get acquainted with your coworkers.", new_sound = 'sound/AI/commandreport.ogg') - if("dorf") - feedback_inc("admin_secrets_fun_used",1) - feedback_add_details("admin_secrets_fun_used","DF") - for(var/mob/living/carbon/human/B in mob_list) - B.f_style = "Dward Beard" - B.update_hair() - message_admins("[key_name_admin(usr)] activated dorf mode") - if("ionstorm") - feedback_inc("admin_secrets_fun_used",1) - feedback_add_details("admin_secrets_fun_used","I") - IonStorm() - message_admins("[key_name_admin(usr)] triggered an ion storm") - var/show_log = alert(usr, "Show ion message?", "Message", "Yes", "No") - if(show_log == "Yes") - command_announcement.Announce("Ion storm detected near the station. Please check all AI-controlled equipment for errors.", "Anomaly Alert", new_sound = 'sound/AI/ionstorm.ogg') - if("onlyone") - feedback_inc("admin_secrets_fun_used",1) - feedback_add_details("admin_secrets_fun_used","OO") - only_one() - message_admins("[key_name_admin(usr)] has triggered a battle to the death (only one)") - - if("togglenarsie") - feedback_inc("admin_secrets_fun_used",1) - feedback_add_details("admin_secrets_fun_used","NA") - var/choice = input("How do you wish for narsie to interact with her surroundings?") in list("CultStation13", "Nar-Singulo") - if(choice == "CultStation13") - message_admins("[key_name_admin(usr)] has set narsie's behaviour to \"CultStation13\".") - narsie_behaviour = "CultStation13" - if(choice == "Nar-Singulo") - message_admins("[key_name_admin(usr)] has set narsie's behaviour to \"Nar-Singulo\".") - narsie_behaviour = "Nar-Singulo" - if("hellonearth") - feedback_inc("admin_secrets_fun_used",1) - feedback_add_details("admin_secrets_fun_used","NS") - var/choice = input("You sure you want to end the round and summon narsie at your location? Misuse of this could result in removal of flags or hilarity.") in list("PRAISE SATAN", "Cancel") - if(choice == "PRAISE SATAN") - new /obj/singularity/narsie/large(get_turf(usr)) - message_admins("[key_name_admin(usr)] has summoned narsie and brought about a new realm of suffering.") - if("supermattercascade") - feedback_inc("admin_secrets_fun_used",1) - feedback_add_details("admin_secrets_fun_used","SC") - var/choice = input("You sure you want to destroy the universe and create a large explosion at your location? Misuse of this could result in removal of flags or hilarity.") in list("NO TIME TO EXPLAIN", "Cancel") - if(choice == "NO TIME TO EXPLAIN") - explosion(get_turf(usr), 8, 16, 24, 32, 1) - new /turf/unsimulated/wall/supermatter(get_turf(usr)) - SetUniversalState(/datum/universal_state/supermatter_cascade) - message_admins("[key_name_admin(usr)] has managed to destroy the universe with a supermatter cascade. Good job, [key_name_admin(usr)]") - if(usr) - log_admin("[key_name(usr)] used secret [href_list["secretsfun"]]") - if (ok) - world << text("A secret has been activated by []!", usr.key) - - else if(href_list["secretsadmin"]) - if(!check_rights(R_ADMIN)) return - - var/ok = 0 - switch(href_list["secretsadmin"]) - if("clear_bombs") - //I do nothing - if("list_bombers") - var/dat = "Bombing List
" - for(var/l in bombers) - dat += text("[l]
") - usr << browse(dat, "window=bombers") - if("list_signalers") - var/dat = "Showing last [length(lastsignalers)] signalers.
" - for(var/sig in lastsignalers) - dat += "[sig]
" - usr << browse(dat, "window=lastsignalers;size=800x500") - if("list_lawchanges") - var/dat = "Showing last [length(lawchanges)] law changes.
" - for(var/sig in lawchanges) - dat += "[sig]
" - usr << browse(dat, "window=lawchanges;size=800x500") - if("list_job_debug") - var/dat = "Job Debug info.
" - if(job_master) - for(var/line in job_master.job_debug) - dat += "[line]
" - dat+= "*******

" - for(var/datum/job/job in job_master.occupations) - if(!job) continue - dat += "job: [job.title], current_positions: [job.current_positions], total_positions: [job.total_positions]
" - usr << browse(dat, "window=jobdebug;size=600x500") - if("showailaws") - output_ai_laws() - if("showgm") - if(!ticker) - alert("The game hasn't started yet!") - else if (ticker.mode) - alert("The game mode is [ticker.mode.name]") - else alert("For some reason there's a ticker, but not a game mode") - if("manifest") - var/dat = "Showing Crew Manifest.
" - dat += "" - for(var/mob/living/carbon/human/H in mob_list) - if(H.ckey) - dat += text("", H.name, H.get_assignment()) - dat += "
NamePosition
[][]
" - usr << browse(dat, "window=manifest;size=440x410") - if("check_antagonist") - check_antagonists() - if("DNA") - var/dat = "Showing DNA from blood.
" - dat += "" - for(var/mob/living/carbon/human/H in mob_list) - if(H.dna && H.ckey) - dat += "" - dat += "
NameDNABlood Type
[H][H.dna.unique_enzymes][H.b_type]
" - usr << browse(dat, "window=DNA;size=440x410") - if("fingerprints") - var/dat = "Showing Fingerprints.
" - dat += "" - for(var/mob/living/carbon/human/H in mob_list) - if(H.ckey) - if(H.dna && H.dna.uni_identity) - dat += "" - else if(H.dna && !H.dna.uni_identity) - dat += "" - else if(!H.dna) - dat += "" - dat += "
NameFingerprints
[H][md5(H.dna.uni_identity)]
[H]H.dna.uni_identity = null
[H]H.dna = null
" - usr << browse(dat, "window=fingerprints;size=440x410") - else - if (usr) - log_admin("[key_name(usr)] used secret [href_list["secretsadmin"]]") - if (ok) - world << text("A secret has been activated by []!", usr.key) - - else if(href_list["secretscoder"]) - if(!check_rights(R_DEBUG)) return - - switch(href_list["secretscoder"]) - if("spawn_objects") - var/dat = "Admin Log
" - for(var/l in admin_log) - dat += "
  • [l]
  • " - if(!admin_log.len) - dat += "No-one has done anything this round!" - usr << browse(dat, "window=admin_log") - if("maint_access_brig") - for(var/obj/machinery/door/airlock/maintenance/M in world) - if (access_maint_tunnels in M.req_access) - M.req_access = list(access_brig) - message_admins("[key_name_admin(usr)] made all maint doors brig access-only.") - if("maint_access_engiebrig") - for(var/obj/machinery/door/airlock/maintenance/M in world) - if (access_maint_tunnels in M.req_access) - M.req_access = list() - M.req_one_access = list(access_brig,access_engine) - message_admins("[key_name_admin(usr)] made all maint doors engineering and brig access-only.") - if("infinite_sec") - var/datum/job/J = job_master.GetJob("Security Officer") - if(!J) return - J.total_positions = -1 - J.spawn_positions = -1 - message_admins("[key_name_admin(usr)] has removed the cap on security officers.") + else if(href_list["admin_secrets"]) + var/datum/admin_secret_item/item = locate(href_list["admin_secrets"]) in admin_secrets.items + item.execute(usr) else if(href_list["ac_view_wanted"]) //Admin newscaster Topic() stuff be here src.admincaster_screen = 18 //The ac_ prefix before the hrefs stands for AdminCaster. From 7f24dc948e476aac557aa212c4946d471b7d00ee Mon Sep 17 00:00:00 2001 From: PsiOmegaDelta Date: Mon, 6 Jul 2015 14:58:27 +0200 Subject: [PATCH 10/21] Re-implements Admin secrets as datums. --- baystation12.dme | 11 ++++++++++- code/modules/admin/admin.dm | 5 ++--- code/modules/admin/admin_secrets.dm | 16 +++++++++++++++- .../secrets/admin_secrets/bombing_list.dm | 12 ++++++++++++ .../admin/secrets/admin_secrets/list_dna.dm | 14 ++++++++++++++ .../admin_secrets/list_fingerprints.dm | 19 +++++++++++++++++++ .../secrets/admin_secrets/show_ai_laws.dm | 7 +++++++ .../admin_secrets/show_crew_manifest.dm | 12 ++++++++++++ .../secrets/admin_secrets/show_game_mode.dm | 14 ++++++++++++++ .../secrets/admin_secrets/show_law_changes.dm | 15 +++++++++++++++ .../secrets/admin_secrets/show_signalers.dm | 15 +++++++++++++++ .../admin_secrets/traitors_and_objectives.dm | 7 +++++++ .../secrets/{ => random_events}/gravity.dm | 10 ++++++---- code/modules/mob/dead/observer/observer.dm | 2 +- 14 files changed, 149 insertions(+), 10 deletions(-) create mode 100644 code/modules/admin/secrets/admin_secrets/bombing_list.dm create mode 100644 code/modules/admin/secrets/admin_secrets/list_dna.dm create mode 100644 code/modules/admin/secrets/admin_secrets/list_fingerprints.dm create mode 100644 code/modules/admin/secrets/admin_secrets/show_ai_laws.dm create mode 100644 code/modules/admin/secrets/admin_secrets/show_crew_manifest.dm create mode 100644 code/modules/admin/secrets/admin_secrets/show_game_mode.dm create mode 100644 code/modules/admin/secrets/admin_secrets/show_law_changes.dm create mode 100644 code/modules/admin/secrets/admin_secrets/show_signalers.dm create mode 100644 code/modules/admin/secrets/admin_secrets/traitors_and_objectives.dm rename code/modules/admin/secrets/{ => random_events}/gravity.dm (89%) diff --git a/baystation12.dme b/baystation12.dme index 7bc13ae072..b45515e6d0 100644 --- a/baystation12.dme +++ b/baystation12.dme @@ -843,7 +843,16 @@ #include "code\modules\admin\ToRban.dm" #include "code\modules\admin\DB ban\functions.dm" #include "code\modules\admin\permissionverbs\permissionedit.dm" -#include "code\modules\admin\secrets\gravity.dm" +#include "code\modules\admin\secrets\admin_secrets\bombing_list.dm" +#include "code\modules\admin\secrets\admin_secrets\list_dna.dm" +#include "code\modules\admin\secrets\admin_secrets\list_fingerprints.dm" +#include "code\modules\admin\secrets\admin_secrets\show_ai_laws.dm" +#include "code\modules\admin\secrets\admin_secrets\show_crew_manifest.dm" +#include "code\modules\admin\secrets\admin_secrets\show_game_mode.dm" +#include "code\modules\admin\secrets\admin_secrets\show_law_changes.dm" +#include "code\modules\admin\secrets\admin_secrets\show_signalers.dm" +#include "code\modules\admin\secrets\admin_secrets\traitors_and_objectives.dm" +#include "code\modules\admin\secrets\random_events\gravity.dm" #include "code\modules\admin\verbs\adminhelp.dm" #include "code\modules\admin\verbs\adminjump.dm" #include "code\modules\admin\verbs\adminpm.dm" diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm index dba6519296..06adf11b57 100644 --- a/code/modules/admin/admin.dm +++ b/code/modules/admin/admin.dm @@ -610,12 +610,11 @@ proc/admin_notice(var/message, var/rights) dat += "[category.name]
    " if(category.desc) dat += "[category.desc]
    " - dat += "
    " for(var/datum/admin_secret_item/item in category.items) if(!item.can_execute(usr)) continue - dat += "[item.name]
    " - + dat += "[item.name()]
    " + dat += "
    " usr << browse(dat, "window=secrets") return diff --git a/code/modules/admin/admin_secrets.dm b/code/modules/admin/admin_secrets.dm index 87c04ea625..b8c4b2ef6b 100644 --- a/code/modules/admin/admin_secrets.dm +++ b/code/modules/admin/admin_secrets.dm @@ -40,8 +40,12 @@ var/datum/admin_secrets/admin_secrets = new() /datum/admin_secret_item var/name = "" var/category = null + var/log = 1 var/permissions = R_HOST +/datum/admin_secret_item/proc/name() + return name + /datum/admin_secret_item/proc/can_execute(var/mob/user) return check_rights(permissions, 0, user) @@ -49,18 +53,28 @@ var/datum/admin_secrets/admin_secrets = new() if(!can_execute(user)) return 0 - log_admin("[key_name(user)] used secret [name]") + if(log) + log_admin("[key_name(user)] used secret '[name()]'") return 1 /************************* * Pre-defined categories * *************************/ +/datum/admin_secret_category/admin_secrets + name = "Admin Secrets" + /datum/admin_secret_category/random_events name = "'Random' Events" /************************* * Pre-defined base items * *************************/ +/datum/admin_secret_item/admin_secret + category = /datum/admin_secret_category/admin_secrets + log = 0 + permissions = R_ADMIN + + /datum/admin_secret_item/random_event category = /datum/admin_secret_category/random_events permissions = R_FUN diff --git a/code/modules/admin/secrets/admin_secrets/bombing_list.dm b/code/modules/admin/secrets/admin_secrets/bombing_list.dm new file mode 100644 index 0000000000..fa3f268396 --- /dev/null +++ b/code/modules/admin/secrets/admin_secrets/bombing_list.dm @@ -0,0 +1,12 @@ +/datum/admin_secret_item/admin_secret/bombing_list + name = "Bombing List" + +/datum/admin_secret_item/admin_secret/bombing_list/execute(var/mob/user) + . = ..() + if(!.) + return + + var/dat = "Bombing List
    " + for(var/l in bombers) + dat += text("[l]
    ") + user << browse(dat, "window=bombers") diff --git a/code/modules/admin/secrets/admin_secrets/list_dna.dm b/code/modules/admin/secrets/admin_secrets/list_dna.dm new file mode 100644 index 0000000000..f1c49f4897 --- /dev/null +++ b/code/modules/admin/secrets/admin_secrets/list_dna.dm @@ -0,0 +1,14 @@ +/datum/admin_secret_item/admin_secret/list_dna + name = "List DNA (Blood)" + +/datum/admin_secret_item/admin_secret/list_dna/execute(var/mob/user) + . = ..() + if(!.) + return + var/dat = "Showing DNA from blood.
    " + dat += "" + for(var/mob/living/carbon/human/H in mob_list) + if(H.dna && H.ckey) + dat += "" + dat += "
    NameDNABlood Type
    [H][H.dna.unique_enzymes][H.b_type]
    " + user << browse(dat, "window=DNA;size=440x410") diff --git a/code/modules/admin/secrets/admin_secrets/list_fingerprints.dm b/code/modules/admin/secrets/admin_secrets/list_fingerprints.dm new file mode 100644 index 0000000000..710cdaf4fe --- /dev/null +++ b/code/modules/admin/secrets/admin_secrets/list_fingerprints.dm @@ -0,0 +1,19 @@ +/datum/admin_secret_item/admin_secret/list_fingerprints + name = "List Fingerprints" + +/datum/admin_secret_item/admin_secret/list_fingerprints/execute(var/mob/user) + . = ..() + if(!.) + return + var/dat = "Showing Fingerprints.
    " + dat += "" + for(var/mob/living/carbon/human/H in mob_list) + if(H.ckey) + if(H.dna && H.dna.uni_identity) + dat += "" + else if(H.dna && !H.dna.uni_identity) + dat += "" + else if(!H.dna) + dat += "" + dat += "
    NameFingerprints
    [H][md5(H.dna.uni_identity)]
    [H]H.dna.uni_identity = null
    [H]H.dna = null
    " + usr << browse(dat, "window=fingerprints;size=440x410") diff --git a/code/modules/admin/secrets/admin_secrets/show_ai_laws.dm b/code/modules/admin/secrets/admin_secrets/show_ai_laws.dm new file mode 100644 index 0000000000..c76ff2d9c1 --- /dev/null +++ b/code/modules/admin/secrets/admin_secrets/show_ai_laws.dm @@ -0,0 +1,7 @@ +/datum/admin_secret_item/admin_secret/show_ai_laws + name = "Show AI laws" + +/datum/admin_secret_item/admin_secret/show_ai_laws/execute(var/mob/user) + . = ..() + if(.) + user.client.holder.output_ai_laws() diff --git a/code/modules/admin/secrets/admin_secrets/show_crew_manifest.dm b/code/modules/admin/secrets/admin_secrets/show_crew_manifest.dm new file mode 100644 index 0000000000..f4bb82224b --- /dev/null +++ b/code/modules/admin/secrets/admin_secrets/show_crew_manifest.dm @@ -0,0 +1,12 @@ +/datum/admin_secret_item/admin_secret/show_crew_manifest + name = "Show Crew Manifest" + +/datum/admin_secret_item/admin_secret/show_crew_manifest/execute(var/mob/user) + . = ..() + if(!.) + return + var/dat + dat += "

    Crew Manifest

    " + dat += data_core.get_manifest() + + user << browse(dat, "window=manifest;size=370x420;can_close=1") diff --git a/code/modules/admin/secrets/admin_secrets/show_game_mode.dm b/code/modules/admin/secrets/admin_secrets/show_game_mode.dm new file mode 100644 index 0000000000..b586e10846 --- /dev/null +++ b/code/modules/admin/secrets/admin_secrets/show_game_mode.dm @@ -0,0 +1,14 @@ +/datum/admin_secret_item/admin_secret/show_game_mode + name = "Show Game Mode" + +/datum/admin_secret_item/admin_secret/show_game_mode/can_execute(var/mob/user) + if(!ticker) + return 0 + return ..() + +/datum/admin_secret_item/admin_secret/show_game_mode/execute(var/mob/user) + . = ..() + if(!.) + return + if (ticker.mode) alert("The game mode is [ticker.mode.name]") + else alert("For some reason there's a ticker, but not a game mode") diff --git a/code/modules/admin/secrets/admin_secrets/show_law_changes.dm b/code/modules/admin/secrets/admin_secrets/show_law_changes.dm new file mode 100644 index 0000000000..190de7b47a --- /dev/null +++ b/code/modules/admin/secrets/admin_secrets/show_law_changes.dm @@ -0,0 +1,15 @@ +/datum/admin_secret_item/admin_secret/show_law_changes + name = "Show law changes" + +/datum/admin_secret_item/admin_secret/show_law_changes/name() + return "Show last [length(lawchanges)] law changes" + +/datum/admin_secret_item/admin_secret/show_law_changes/execute(var/mob/user) + . = ..() + if(!.) + return + + var/dat = "Showing last [length(lawchanges)] law changes.
    " + for(var/sig in lawchanges) + dat += "[sig]
    " + user << browse(dat, "window=lawchanges;size=800x500") diff --git a/code/modules/admin/secrets/admin_secrets/show_signalers.dm b/code/modules/admin/secrets/admin_secrets/show_signalers.dm new file mode 100644 index 0000000000..0e1269ea37 --- /dev/null +++ b/code/modules/admin/secrets/admin_secrets/show_signalers.dm @@ -0,0 +1,15 @@ +/datum/admin_secret_item/admin_secret/show_signalers + name = "Show last signalers" + +/datum/admin_secret_item/admin_secret/show_signalers/name() + return "Show last [length(lastsignalers)] signalers" + +/datum/admin_secret_item/admin_secret/show_signalers/execute(var/mob/user) + . = ..() + if(!.) + return + + var/dat = "Showing last [length(lastsignalers)] signalers.
    " + for(var/sig in lastsignalers) + dat += "[sig]
    " + user << browse(dat, "window=lastsignalers;size=800x500") diff --git a/code/modules/admin/secrets/admin_secrets/traitors_and_objectives.dm b/code/modules/admin/secrets/admin_secrets/traitors_and_objectives.dm new file mode 100644 index 0000000000..591c13bd3f --- /dev/null +++ b/code/modules/admin/secrets/admin_secrets/traitors_and_objectives.dm @@ -0,0 +1,7 @@ +/datum/admin_secret_item/admin_secret/traitors_and_objectives + name = "Show current traitors and objectives" + +/datum/admin_secret_item/admin_secret/traitors_and_objectives/execute(var/mob/user) + . = ..() + if(.) + user.client.holder.check_antagonists() diff --git a/code/modules/admin/secrets/gravity.dm b/code/modules/admin/secrets/random_events/gravity.dm similarity index 89% rename from code/modules/admin/secrets/gravity.dm rename to code/modules/admin/secrets/random_events/gravity.dm index 8ff9c915d4..51f8f1d187 100644 --- a/code/modules/admin/secrets/gravity.dm +++ b/code/modules/admin/secrets/random_events/gravity.dm @@ -4,15 +4,17 @@ /datum/admin_secret_item/random_event/gravity name = "Toggle station artificial gravity" +/datum/admin_secret_item/random_event/gravity/can_execute(var/mob/user) + if(!(ticker && ticker.mode)) + return 0 + + return ..() + /datum/admin_secret_item/random_event/gravity/execute(var/mob/user) . = ..() if(!.) return - if(!(ticker && ticker.mode)) - user << "Please wait until the game starts! Not sure how it will work otherwise." - return - gravity_is_on = !gravity_is_on for(var/area/A in world) A.gravitychange(gravity_is_on,A) diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm index 85b71aef4f..edf8ae950e 100644 --- a/code/modules/mob/dead/observer/observer.dm +++ b/code/modules/mob/dead/observer/observer.dm @@ -464,7 +464,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp host << "You are now a mouse. Try to avoid interaction with players, and do not give hints away that you are more than a simple rodent." /mob/dead/observer/verb/view_manfiest() - set name = "View Crew Manifest" + set name = "Show Crew Manifest" set category = "Ghost" var/dat From 5703fdfe851fd0753cc8f4fd8170fd3c909e40b0 Mon Sep 17 00:00:00 2001 From: PsiOmegaDelta Date: Mon, 6 Jul 2015 15:59:26 +0200 Subject: [PATCH 11/21] Re-implements admin fun events as datums. --- baystation12.dme | 24 ++++++++++ baystation12.int | 15 +++--- code/controllers/Processes/initialize.dm | 31 ++++++++++++ code/modules/admin/admin_secrets.dm | 25 ++++++++-- .../secrets/admin_secrets/alter_narsie.dm | 14 ++++++ .../secrets/admin_secrets/jump_shuttle.dm | 36 ++++++++++++++ .../secrets/admin_secrets/launch_shutter.dm | 26 ++++++++++ .../admin_secrets/launch_shuttle_forced.dm | 26 ++++++++++ .../secrets/admin_secrets/move_shuttle.dm | 28 +++++++++++ .../secrets/admin_secrets/prison_warp.dm | 38 +++++++++++++++ .../secrets/admin_secrets/show_law_changes.dm | 2 +- .../secrets/admin_secrets/show_signalers.dm | 4 +- .../secrets/fun_secrets/break_all_lights.dm | 7 +++ .../secrets/fun_secrets/break_some_lights.dm | 7 +++ .../secrets/fun_secrets/fix_all_lights.dm | 10 ++++ .../admin/secrets/fun_secrets/ghost_mode.dm | 48 +++++++++++++++++++ .../fun_secrets/make_all_areas_powered.dm | 7 +++ .../fun_secrets/make_all_areas_unpowered.dm | 7 +++ .../admin/secrets/fun_secrets/only_one.dm | 7 +++ .../secrets/fun_secrets/paintball_mode.dm | 14 ++++++ .../secrets/fun_secrets/power_all_smes.dm | 7 +++ .../fun_secrets/remove_all_clothing.dm | 10 ++++ .../fun_secrets/remove_internal_clothing.dm | 10 ++++ .../secrets/fun_secrets/send_strike_team.dm | 11 +++++ .../secrets/fun_secrets/toggle_bomb_cap.dm | 21 ++++++++ .../secrets/fun_secrets/triple_ai_mode.dm | 13 +++++ .../fun_secrets/turn_humans_into_corgies.dm | 11 +++++ .../fun_secrets/turn_humans_into_monkeys.dm | 11 +++++ .../admin/secrets/random_events/gravity.dm | 2 +- .../trigger_cordical_borer_infestation.dm | 7 +++ .../trigger_xenomorph_infestation.dm | 7 +++ 31 files changed, 472 insertions(+), 14 deletions(-) create mode 100644 code/controllers/Processes/initialize.dm create mode 100644 code/modules/admin/secrets/admin_secrets/alter_narsie.dm create mode 100644 code/modules/admin/secrets/admin_secrets/jump_shuttle.dm create mode 100644 code/modules/admin/secrets/admin_secrets/launch_shutter.dm create mode 100644 code/modules/admin/secrets/admin_secrets/launch_shuttle_forced.dm create mode 100644 code/modules/admin/secrets/admin_secrets/move_shuttle.dm create mode 100644 code/modules/admin/secrets/admin_secrets/prison_warp.dm create mode 100644 code/modules/admin/secrets/fun_secrets/break_all_lights.dm create mode 100644 code/modules/admin/secrets/fun_secrets/break_some_lights.dm create mode 100644 code/modules/admin/secrets/fun_secrets/fix_all_lights.dm create mode 100644 code/modules/admin/secrets/fun_secrets/ghost_mode.dm create mode 100644 code/modules/admin/secrets/fun_secrets/make_all_areas_powered.dm create mode 100644 code/modules/admin/secrets/fun_secrets/make_all_areas_unpowered.dm create mode 100644 code/modules/admin/secrets/fun_secrets/only_one.dm create mode 100644 code/modules/admin/secrets/fun_secrets/paintball_mode.dm create mode 100644 code/modules/admin/secrets/fun_secrets/power_all_smes.dm create mode 100644 code/modules/admin/secrets/fun_secrets/remove_all_clothing.dm create mode 100644 code/modules/admin/secrets/fun_secrets/remove_internal_clothing.dm create mode 100644 code/modules/admin/secrets/fun_secrets/send_strike_team.dm create mode 100644 code/modules/admin/secrets/fun_secrets/toggle_bomb_cap.dm create mode 100644 code/modules/admin/secrets/fun_secrets/triple_ai_mode.dm create mode 100644 code/modules/admin/secrets/fun_secrets/turn_humans_into_corgies.dm create mode 100644 code/modules/admin/secrets/fun_secrets/turn_humans_into_monkeys.dm create mode 100644 code/modules/admin/secrets/random_events/trigger_cordical_borer_infestation.dm create mode 100644 code/modules/admin/secrets/random_events/trigger_xenomorph_infestation.dm diff --git a/baystation12.dme b/baystation12.dme index b45515e6d0..9946956dfb 100644 --- a/baystation12.dme +++ b/baystation12.dme @@ -843,16 +843,40 @@ #include "code\modules\admin\ToRban.dm" #include "code\modules\admin\DB ban\functions.dm" #include "code\modules\admin\permissionverbs\permissionedit.dm" +#include "code\modules\admin\secrets\admin_secrets\alter_narsie.dm" #include "code\modules\admin\secrets\admin_secrets\bombing_list.dm" +#include "code\modules\admin\secrets\admin_secrets\jump_shuttle.dm" +#include "code\modules\admin\secrets\admin_secrets\launch_shutter.dm" +#include "code\modules\admin\secrets\admin_secrets\launch_shuttle_forced.dm" #include "code\modules\admin\secrets\admin_secrets\list_dna.dm" #include "code\modules\admin\secrets\admin_secrets\list_fingerprints.dm" +#include "code\modules\admin\secrets\admin_secrets\move_shuttle.dm" +#include "code\modules\admin\secrets\admin_secrets\prison_warp.dm" #include "code\modules\admin\secrets\admin_secrets\show_ai_laws.dm" #include "code\modules\admin\secrets\admin_secrets\show_crew_manifest.dm" #include "code\modules\admin\secrets\admin_secrets\show_game_mode.dm" #include "code\modules\admin\secrets\admin_secrets\show_law_changes.dm" #include "code\modules\admin\secrets\admin_secrets\show_signalers.dm" #include "code\modules\admin\secrets\admin_secrets\traitors_and_objectives.dm" +#include "code\modules\admin\secrets\fun_secrets\break_all_lights.dm" +#include "code\modules\admin\secrets\fun_secrets\break_some_lights.dm" +#include "code\modules\admin\secrets\fun_secrets\fix_all_lights.dm" +#include "code\modules\admin\secrets\fun_secrets\ghost_mode.dm" +#include "code\modules\admin\secrets\fun_secrets\make_all_areas_powered.dm" +#include "code\modules\admin\secrets\fun_secrets\make_all_areas_unpowered.dm" +#include "code\modules\admin\secrets\fun_secrets\only_one.dm" +#include "code\modules\admin\secrets\fun_secrets\paintball_mode.dm" +#include "code\modules\admin\secrets\fun_secrets\power_all_smes.dm" +#include "code\modules\admin\secrets\fun_secrets\remove_all_clothing.dm" +#include "code\modules\admin\secrets\fun_secrets\remove_internal_clothing.dm" +#include "code\modules\admin\secrets\fun_secrets\send_strike_team.dm" +#include "code\modules\admin\secrets\fun_secrets\toggle_bomb_cap.dm" +#include "code\modules\admin\secrets\fun_secrets\triple_ai_mode.dm" +#include "code\modules\admin\secrets\fun_secrets\turn_humans_into_corgies.dm" +#include "code\modules\admin\secrets\fun_secrets\turn_humans_into_monkeys.dm" #include "code\modules\admin\secrets\random_events\gravity.dm" +#include "code\modules\admin\secrets\random_events\trigger_cordical_borer_infestation.dm" +#include "code\modules\admin\secrets\random_events\trigger_xenomorph_infestation.dm" #include "code\modules\admin\verbs\adminhelp.dm" #include "code\modules\admin\verbs\adminjump.dm" #include "code\modules\admin\verbs\adminpm.dm" diff --git a/baystation12.int b/baystation12.int index b82874fded..cfd9890d63 100644 --- a/baystation12.int +++ b/baystation12.int @@ -1,6 +1,9 @@ -// BEGIN_INTERNALS -/* -MAP_ICON_TYPE: 0 -AUTO_FILE_DIR: OFF -*/ -// END_INTERNALS +// BEGIN_INTERNALS +/* +DIR: code code\modules code\modules\mob code\modules\mob\freelook code\modules\mob\living code\modules\mob\living\carbon code\modules\mob\living\carbon\alien code\modules\mob\living\carbon\alien\diona code\modules\mob\living\carbon\alien\larva code\modules\mob\living\carbon\human +AUTO_FILE_DIR: OFF +MAP_ICON_TYPE: 0 +WINDOW: code\modules\mob\living\carbon\human\life.dm +FILE: code\modules\mob\living\carbon\human\life.dm +*/ +// END_INTERNALS diff --git a/code/controllers/Processes/initialize.dm b/code/controllers/Processes/initialize.dm new file mode 100644 index 0000000000..055a056bed --- /dev/null +++ b/code/controllers/Processes/initialize.dm @@ -0,0 +1,31 @@ +var/list/pending_init_objects + +/datum/controller/process/initialize + var/list/objects_to_initialize + +/datum/controller/process/initialize/setup() + name = "init" + schedule_interval = 1 // Every tick, scary + objects_to_initialize = pending_init_objects + +/datum/controller/process/initialize/doWork() + for(var/atom/movable/A in objects_to_initialize) + A.initialize() + scheck() + objects_to_initialize.Remove(A) + + if(!objects_to_initialize.len) + disable() + +/proc/initialize_object(var/atom/movable/obj_to_init) + if(processScheduler.hasProcess("init")) + var/datum/controller/process/initialize/init = processScheduler.getProcess("init") + init.objects_to_initialize += obj_to_init + init.enable() + else + world.log << "Not yet" + if(!pending_init_objects) pending_init_objects = list() + pending_init_objects += obj_to_init + +/datum/controller/process/initialize/getStatName() + return ..()+"([objects_to_initialize.len])" diff --git a/code/modules/admin/admin_secrets.dm b/code/modules/admin/admin_secrets.dm index b8c4b2ef6b..2ce43a7962 100644 --- a/code/modules/admin/admin_secrets.dm +++ b/code/modules/admin/admin_secrets.dm @@ -9,7 +9,7 @@ var/datum/admin_secrets/admin_secrets = new() categories = init_subtypes(/datum/admin_secret_category) items = list() var/list/category_assoc = list() - for(var/datum/category in categories) + for(var/datum/admin_secret_category/category in categories) category_assoc[category.type] = category for(var/item_type in (typesof(/datum/admin_secret_item) - /datum/admin_secret_item)) @@ -19,7 +19,7 @@ var/datum/admin_secrets/admin_secrets = new() var/datum/admin_secret_item/item = new item_type() var/datum/admin_secret_category/category = category_assoc[item.category] - category.items += item + dd_insertObjectList(category.items, item) items += item /datum/admin_secret_category @@ -41,6 +41,7 @@ var/datum/admin_secrets/admin_secrets = new() var/name = "" var/category = null var/log = 1 + var/feedback = 1 var/permissions = R_HOST /datum/admin_secret_item/proc/name() @@ -54,7 +55,10 @@ var/datum/admin_secrets/admin_secrets = new() return 0 if(log) - log_admin("[key_name(user)] used secret '[name()]'") + log_and_message_admins("used secret '[name]'", user) + if(feedback) + feedback_inc("admin_secrets_used",1) + feedback_add_details("admin_secrets_used","[name]") return 1 /************************* @@ -66,6 +70,12 @@ var/datum/admin_secrets/admin_secrets = new() /datum/admin_secret_category/random_events name = "'Random' Events" +/datum/admin_secret_category/fun_secrets + name = "Fun Secrets" + +/datum/admin_secret_category/final_solutions + name = "Final Solutions" + /************************* * Pre-defined base items * *************************/ @@ -74,7 +84,14 @@ var/datum/admin_secrets/admin_secrets = new() log = 0 permissions = R_ADMIN - /datum/admin_secret_item/random_event category = /datum/admin_secret_category/random_events permissions = R_FUN + +/datum/admin_secret_item/fun_secret + category = /datum/admin_secret_category/fun_secrets + permissions = R_FUN + +/datum/admin_secret_item/final_solution + category = /datum/admin_secret_category/final_solutions + permissions = R_FUN|R_SERVER|R_ADMIN diff --git a/code/modules/admin/secrets/admin_secrets/alter_narsie.dm b/code/modules/admin/secrets/admin_secrets/alter_narsie.dm new file mode 100644 index 0000000000..75281adca8 --- /dev/null +++ b/code/modules/admin/secrets/admin_secrets/alter_narsie.dm @@ -0,0 +1,14 @@ +/datum/admin_secret_item/admin_secret/alter_narise + name = "Alter Nar-Sie" + +/datum/admin_secret_item/admin_secret/alter_narise/execute(var/mob/user) + . = ..() + if(!.) + return + var/choice = input(user, "How do you wish for Nar-Sie to interact with its surroundings?") as null|anything in list("CultStation13", "Nar-Singulo") + if(choice == "CultStation13") + log_and_message_admins("has set narsie's behaviour to \"CultStation13\".", user) + narsie_behaviour = choice + if(choice == "Nar-Singulo") + log_and_message_admins("has set narsie's behaviour to \"Nar-Singulo\".", user) + narsie_behaviour = choice diff --git a/code/modules/admin/secrets/admin_secrets/jump_shuttle.dm b/code/modules/admin/secrets/admin_secrets/jump_shuttle.dm new file mode 100644 index 0000000000..1453ae35ce --- /dev/null +++ b/code/modules/admin/secrets/admin_secrets/jump_shuttle.dm @@ -0,0 +1,36 @@ +/datum/admin_secret_item/admin_secret/jump_shuttle + name = "Jump a Shuttle" + +/datum/admin_secret_item/admin_secret/jump_shuttle/can_execute(var/mob/user) + if(!shuttle_controller) return 0 + return ..() + +/datum/admin_secret_item/admin_secret/jump_shuttle/execute(var/mob/user) + . = ..() + if(!.) + return + var/shuttle_tag = input("Which shuttle do you want to jump?") as null|anything in shuttle_controller.shuttles + if (!shuttle_tag) return + + var/datum/shuttle/S = shuttle_controller.shuttles[shuttle_tag] + + var/origin_area = input("Which area is the shuttle at now? (MAKE SURE THIS IS CORRECT OR THINGS WILL BREAK)") as null|area in world + if (!origin_area) return + + var/destination_area = input("Which area is the shuttle at now? (MAKE SURE THIS IS CORRECT OR THINGS WILL BREAK)") as null|area in world + if (!destination_area) return + + var/long_jump = alert("Is there a transition area for this jump?","", "Yes", "No") + if (long_jump == "Yes") + var/transition_area = input("Which area is the transition area? (MAKE SURE THIS IS CORRECT OR THINGS WILL BREAK)") as null|area in world + if (!transition_area) return + + var/move_duration = input("How many seconds will this jump take?") as num + + S.long_jump(origin_area, destination_area, transition_area, move_duration) + message_admins("[key_name_admin(usr)] has initiated a jump from [origin_area] to [destination_area] lasting [move_duration] seconds for the [shuttle_tag] shuttle", 1) + log_admin("[key_name_admin(usr)] has initiated a jump from [origin_area] to [destination_area] lasting [move_duration] seconds for the [shuttle_tag] shuttle") + else + S.short_jump(origin_area, destination_area) + message_admins("[key_name_admin(usr)] has initiated a jump from [origin_area] to [destination_area] for the [shuttle_tag] shuttle", 1) + log_admin("[key_name_admin(usr)] has initiated a jump from [origin_area] to [destination_area] for the [shuttle_tag] shuttle") diff --git a/code/modules/admin/secrets/admin_secrets/launch_shutter.dm b/code/modules/admin/secrets/admin_secrets/launch_shutter.dm new file mode 100644 index 0000000000..30867fca05 --- /dev/null +++ b/code/modules/admin/secrets/admin_secrets/launch_shutter.dm @@ -0,0 +1,26 @@ +/datum/admin_secret_item/admin_secret/launch_shuttle + name = "Launch a Shuttle" + +/datum/admin_secret_item/admin_secret/launch_shuttle/can_execute(var/mob/user) + if(!shuttle_controller) return 0 + return ..() + +/datum/admin_secret_item/admin_secret/launch_shuttle/execute(var/mob/user) + . = ..() + if(!.) + return + var/list/valid_shuttles = list() + for (var/shuttle_tag in shuttle_controller.shuttles) + if (istype(shuttle_controller.shuttles[shuttle_tag], /datum/shuttle/ferry)) + valid_shuttles += shuttle_tag + + var/shuttle_tag = input("Which shuttle do you want to launch?") as null|anything in valid_shuttles + if (!shuttle_tag) + return + + var/datum/shuttle/ferry/S = shuttle_controller.shuttles[shuttle_tag] + if (S.can_launch()) + S.launch(usr) + log_and_message_admins("launched the [shuttle_tag] shuttle", user) + else + alert("The [shuttle_tag] shuttle cannot be launched at this time. It's probably busy.") diff --git a/code/modules/admin/secrets/admin_secrets/launch_shuttle_forced.dm b/code/modules/admin/secrets/admin_secrets/launch_shuttle_forced.dm new file mode 100644 index 0000000000..250d04b044 --- /dev/null +++ b/code/modules/admin/secrets/admin_secrets/launch_shuttle_forced.dm @@ -0,0 +1,26 @@ +/datum/admin_secret_item/admin_secret/launch_shuttle_forced + name = "Launch a Shuttle (Forced)" + +/datum/admin_secret_item/admin_secret/launch_shuttle_forced/can_execute(var/mob/user) + if(!shuttle_controller) return 0 + return ..() + +/datum/admin_secret_item/admin_secret/launch_shuttle_forced/execute(var/mob/user) + . = ..() + if(!.) + return + var/list/valid_shuttles = list() + for (var/shuttle_tag in shuttle_controller.shuttles) + if (istype(shuttle_controller.shuttles[shuttle_tag], /datum/shuttle/ferry)) + valid_shuttles += shuttle_tag + + var/shuttle_tag = input("Which shuttle's launch do you want to force?") as null|anything in valid_shuttles + if (!shuttle_tag) + return + + var/datum/shuttle/ferry/S = shuttle_controller.shuttles[shuttle_tag] + if (S.can_force()) + S.force_launch(usr) + log_and_message_admins("forced the [shuttle_tag] shuttle", user) + else + alert("The [shuttle_tag] shuttle launch cannot be forced at this time. It's busy, or hasn't been launched yet.") diff --git a/code/modules/admin/secrets/admin_secrets/move_shuttle.dm b/code/modules/admin/secrets/admin_secrets/move_shuttle.dm new file mode 100644 index 0000000000..e58863afde --- /dev/null +++ b/code/modules/admin/secrets/admin_secrets/move_shuttle.dm @@ -0,0 +1,28 @@ +/datum/admin_secret_item/admin_secret/move_shuttle + name = "Move a Shuttle" + +/datum/admin_secret_item/admin_secret/move_shuttle/can_execute(var/mob/user) + if(!shuttle_controller) return 0 + return ..() + +/datum/admin_secret_item/admin_secret/move_shuttle/execute(var/mob/user) + . = ..() + if(!.) + return + var/confirm = alert("This command directly moves a shuttle from one area to another. DO NOT USE THIS UNLESS YOU ARE DEBUGGING A SHUTTLE AND YOU KNOW WHAT YOU ARE DOING.", "Are you sure?", "Ok", "Cancel") + if (confirm == "Cancel") + return + + var/shuttle_tag = input("Which shuttle do you want to jump?") as null|anything in shuttle_controller.shuttles + if (!shuttle_tag) return + + var/datum/shuttle/S = shuttle_controller.shuttles[shuttle_tag] + + var/origin_area = input("Which area is the shuttle at now? (MAKE SURE THIS IS CORRECT OR THINGS WILL BREAK)") as null|area in world + if (!origin_area) return + + var/destination_area = input("Which area is the shuttle at now? (MAKE SURE THIS IS CORRECT OR THINGS WILL BREAK)") as null|area in world + if (!destination_area) return + + S.move(origin_area, destination_area) + log_and_message_admins("[key_name_admin(usr)] moved the [shuttle_tag] shuttle", user) diff --git a/code/modules/admin/secrets/admin_secrets/prison_warp.dm b/code/modules/admin/secrets/admin_secrets/prison_warp.dm new file mode 100644 index 0000000000..eec85c2f04 --- /dev/null +++ b/code/modules/admin/secrets/admin_secrets/prison_warp.dm @@ -0,0 +1,38 @@ +/datum/admin_secret_item/admin_secret/prison_warp + name = "Prison Warp" + +/datum/admin_secret_item/admin_secret/prison_warp/can_execute(var/mob/user) + if(!ticker) return 0 + return ..() + +/datum/admin_secret_item/admin_secret/prison_warp/execute(var/mob/user) + . = ..() + if(!.) + return + for(var/mob/living/carbon/human/H in mob_list) + var/turf/T = get_turf(H) + var/security = 0 + if((T && T in config.admin_levels) || prisonwarped.Find(H)) + //don't warp them if they aren't ready or are already there + continue + H.Paralyse(5) + if(H.wear_id) + var/obj/item/weapon/card/id/id = H.get_idcard() + for(var/A in id.access) + if(A == access_security) + security++ + if(!security) + //strip their stuff before they teleport into a cell :downs: + for(var/obj/item/weapon/W in H) + if(istype(W, /obj/item/organ/external)) + continue + //don't strip organs + H.drop_from_inventory(W) + //teleport person to cell + H.loc = pick(prisonwarp) + H.equip_to_slot_or_del(new /obj/item/clothing/under/color/orange(H), slot_w_uniform) + H.equip_to_slot_or_del(new /obj/item/clothing/shoes/orange(H), slot_shoes) + else + //teleport security person + H.loc = pick(prisonsecuritywarp) + prisonwarped += H diff --git a/code/modules/admin/secrets/admin_secrets/show_law_changes.dm b/code/modules/admin/secrets/admin_secrets/show_law_changes.dm index 190de7b47a..877e2c217d 100644 --- a/code/modules/admin/secrets/admin_secrets/show_law_changes.dm +++ b/code/modules/admin/secrets/admin_secrets/show_law_changes.dm @@ -2,7 +2,7 @@ name = "Show law changes" /datum/admin_secret_item/admin_secret/show_law_changes/name() - return "Show last [length(lawchanges)] law changes" + return "Show Last [length(lawchanges)] Law change\s" /datum/admin_secret_item/admin_secret/show_law_changes/execute(var/mob/user) . = ..() diff --git a/code/modules/admin/secrets/admin_secrets/show_signalers.dm b/code/modules/admin/secrets/admin_secrets/show_signalers.dm index 0e1269ea37..32a77cbef2 100644 --- a/code/modules/admin/secrets/admin_secrets/show_signalers.dm +++ b/code/modules/admin/secrets/admin_secrets/show_signalers.dm @@ -1,8 +1,8 @@ /datum/admin_secret_item/admin_secret/show_signalers - name = "Show last signalers" + name = "Show Last Signalers" /datum/admin_secret_item/admin_secret/show_signalers/name() - return "Show last [length(lastsignalers)] signalers" + return "Show Last [length(lastsignalers)] Signaler\s" /datum/admin_secret_item/admin_secret/show_signalers/execute(var/mob/user) . = ..() diff --git a/code/modules/admin/secrets/fun_secrets/break_all_lights.dm b/code/modules/admin/secrets/fun_secrets/break_all_lights.dm new file mode 100644 index 0000000000..5c65e389af --- /dev/null +++ b/code/modules/admin/secrets/fun_secrets/break_all_lights.dm @@ -0,0 +1,7 @@ +/datum/admin_secret_item/fun_secret/break_all_lights + name = "Break All Lights" + +/datum/admin_secret_item/fun_secret/make_all_areas_powered/execute(var/mob/user) + . = ..() + if(.) + lightsout(0,0) diff --git a/code/modules/admin/secrets/fun_secrets/break_some_lights.dm b/code/modules/admin/secrets/fun_secrets/break_some_lights.dm new file mode 100644 index 0000000000..0c9aae1b16 --- /dev/null +++ b/code/modules/admin/secrets/fun_secrets/break_some_lights.dm @@ -0,0 +1,7 @@ +/datum/admin_secret_item/fun_secret/break_some_lights + name = "Break Some Lights" + +/datum/admin_secret_item/fun_secret/break_some_lights/execute(var/mob/user) + . = ..() + if(.) + lightsout(1,2) diff --git a/code/modules/admin/secrets/fun_secrets/fix_all_lights.dm b/code/modules/admin/secrets/fun_secrets/fix_all_lights.dm new file mode 100644 index 0000000000..387f6d3ce7 --- /dev/null +++ b/code/modules/admin/secrets/fun_secrets/fix_all_lights.dm @@ -0,0 +1,10 @@ +/datum/admin_secret_item/fun_secret/fix_all_lights + name = "Fix All Lights" + +/datum/admin_secret_item/fun_secret/fix_all_lights/execute(var/mob/user) + . = ..() + if(!.) + return + + for(var/obj/machinery/light/L in world) + L.fix() diff --git a/code/modules/admin/secrets/fun_secrets/ghost_mode.dm b/code/modules/admin/secrets/fun_secrets/ghost_mode.dm new file mode 100644 index 0000000000..dfa84e4cf6 --- /dev/null +++ b/code/modules/admin/secrets/fun_secrets/ghost_mode.dm @@ -0,0 +1,48 @@ +/datum/admin_secret_item/fun_secret/ghost_mode + name = "Ghost Mode" + var/list/affected_mobs + +/datum/admin_secret_item/fun_secret/ghost_mode/New() + ..() + affected_mobs = list() + +/datum/admin_secret_item/fun_secret/ghost_mode/execute(var/mob/user) + . = ..() + if(!.) + return + + var/list/affected_areas = list() + for(var/mob/M in living_mob_list) + if(M.stat == CONSCIOUS && !(M in affected_mobs)) + affected_mobs |= M + switch(rand(1,4)) + if(1) + M.show_message(text("You shudder as if cold..."), 1) + if(2) + M.show_message(text("You feel something gliding across your back..."), 1) + if(3) + M.show_message(text("Your eyes twitch, you feel like something you can't see is here..."), 1) + if(4) + M.show_message(text("You notice something moving out of the corner of your eye, but nothing is there..."), 1) + + for(var/obj/W in orange(5,M)) + if(prob(25) && !W.anchored) + step_rand(W) + + var/area/A = get_area(M) + if(A.requires_power && !A.always_unpowered && A.power_light && (A.z in config.player_levels)) + affected_areas |= get_area(M) + + affected_mobs |= user + for(var/area/AffectedArea in affected_areas) + AffectedArea.power_light = 0 + AffectedArea.power_change() + spawn(rand(25,50)) + AffectedArea.power_light = 1 + AffectedArea.power_change() + + sleep(100) + for(var/mob/M in affected_mobs) + M.show_message(text("The chilling wind suddenly stops..."), 1) + affected_mobs.Cut() + affected_areas.Cut() diff --git a/code/modules/admin/secrets/fun_secrets/make_all_areas_powered.dm b/code/modules/admin/secrets/fun_secrets/make_all_areas_powered.dm new file mode 100644 index 0000000000..3309190028 --- /dev/null +++ b/code/modules/admin/secrets/fun_secrets/make_all_areas_powered.dm @@ -0,0 +1,7 @@ +/datum/admin_secret_item/fun_secret/make_all_areas_powered + name = "Make All Areas Powered" + +/datum/admin_secret_item/fun_secret/make_all_areas_powered/execute(var/mob/user) + . = ..() + if(.) + power_restore() diff --git a/code/modules/admin/secrets/fun_secrets/make_all_areas_unpowered.dm b/code/modules/admin/secrets/fun_secrets/make_all_areas_unpowered.dm new file mode 100644 index 0000000000..a840006a23 --- /dev/null +++ b/code/modules/admin/secrets/fun_secrets/make_all_areas_unpowered.dm @@ -0,0 +1,7 @@ +/datum/admin_secret_item/fun_secret/make_all_areas_unpowered + name = "Make All Areas Unpowered" + +/datum/admin_secret_item/fun_secret/make_all_areas_unpowered/execute(var/mob/user) + . = ..() + if(.) + power_failure() diff --git a/code/modules/admin/secrets/fun_secrets/only_one.dm b/code/modules/admin/secrets/fun_secrets/only_one.dm new file mode 100644 index 0000000000..bc0c962b29 --- /dev/null +++ b/code/modules/admin/secrets/fun_secrets/only_one.dm @@ -0,0 +1,7 @@ +/datum/admin_secret_item/fun_secret/only_one + name = "There Can Be Only One" + +/datum/admin_secret_item/fun_secret/only_one/execute(var/mob/user) + . = ..() + if(.) + only_one() diff --git a/code/modules/admin/secrets/fun_secrets/paintball_mode.dm b/code/modules/admin/secrets/fun_secrets/paintball_mode.dm new file mode 100644 index 0000000000..8225b96b29 --- /dev/null +++ b/code/modules/admin/secrets/fun_secrets/paintball_mode.dm @@ -0,0 +1,14 @@ +/datum/admin_secret_item/fun_secret/paintbal_mode + name = "Paintball Mode" + +/datum/admin_secret_item/fun_secret/paintbal_mode/execute(var/mob/user) + . = ..() + if(!.) + return + + for(var/species in all_species) + var/datum/species/S = all_species[species] + S.blood_color = "rainbow" + for(var/obj/effect/decal/cleanable/blood/B in world) + B.basecolor = "rainbow" + B.update_icon() diff --git a/code/modules/admin/secrets/fun_secrets/power_all_smes.dm b/code/modules/admin/secrets/fun_secrets/power_all_smes.dm new file mode 100644 index 0000000000..277edd5a43 --- /dev/null +++ b/code/modules/admin/secrets/fun_secrets/power_all_smes.dm @@ -0,0 +1,7 @@ +/datum/admin_secret_item/fun_secret/power_all_smes + name = "Power All SMES" + +/datum/admin_secret_item/fun_secret/power_all_smes/execute(var/mob/user) + . = ..() + if(.) + power_restore_quick() diff --git a/code/modules/admin/secrets/fun_secrets/remove_all_clothing.dm b/code/modules/admin/secrets/fun_secrets/remove_all_clothing.dm new file mode 100644 index 0000000000..28e9497f53 --- /dev/null +++ b/code/modules/admin/secrets/fun_secrets/remove_all_clothing.dm @@ -0,0 +1,10 @@ +/datum/admin_secret_item/fun_secret/remove_all_clothing + name = "Remove ALL Clothing" + +/datum/admin_secret_item/fun_secret/remove_all_clothing/execute(var/mob/user) + . = ..() + if(!.) + return + + for(var/obj/item/clothing/O in world) + qdel(O) diff --git a/code/modules/admin/secrets/fun_secrets/remove_internal_clothing.dm b/code/modules/admin/secrets/fun_secrets/remove_internal_clothing.dm new file mode 100644 index 0000000000..73dba4ce4f --- /dev/null +++ b/code/modules/admin/secrets/fun_secrets/remove_internal_clothing.dm @@ -0,0 +1,10 @@ +/datum/admin_secret_item/fun_secret/remove_internal_clothing + name = "Remove 'Internal' Clothing" + +/datum/admin_secret_item/fun_secret/remove_internal_clothing/execute(var/mob/user) + . = ..() + if(!.) + return + + for(var/obj/item/clothing/under/O in world) + qdel(O) diff --git a/code/modules/admin/secrets/fun_secrets/send_strike_team.dm b/code/modules/admin/secrets/fun_secrets/send_strike_team.dm new file mode 100644 index 0000000000..3ec1bacb2c --- /dev/null +++ b/code/modules/admin/secrets/fun_secrets/send_strike_team.dm @@ -0,0 +1,11 @@ +/datum/admin_secret_item/fun_secret/send_strike_team + name = "Send Strike Team" + +/datum/admin_secret_item/fun_secret/send_strike_team/can_execute(var/mob/user) + if(!ticker) return 0 + return ..() + +/datum/admin_secret_item/fun_secret/send_strike_team/execute(var/mob/user) + . = ..() + if(.) + return user.client.strike_team() diff --git a/code/modules/admin/secrets/fun_secrets/toggle_bomb_cap.dm b/code/modules/admin/secrets/fun_secrets/toggle_bomb_cap.dm new file mode 100644 index 0000000000..28cd3327c4 --- /dev/null +++ b/code/modules/admin/secrets/fun_secrets/toggle_bomb_cap.dm @@ -0,0 +1,21 @@ +/datum/admin_secret_item/fun_secret/toggle_bomb_cap + name = "Toggle Bomb Cap" + permissions = R_SERVER + +/datum/admin_secret_item/fun_secret/toggle_bomb_cap/execute(var/mob/user) + . = ..() + if(!.) + return + + switch(max_explosion_range) + if(14) max_explosion_range = 16 + if(16) max_explosion_range = 20 + if(20) max_explosion_range = 28 + if(28) max_explosion_range = 56 + if(56) max_explosion_range = 128 + if(128) max_explosion_range = 14 + var/range_dev = max_explosion_range *0.25 + var/range_high = max_explosion_range *0.5 + var/range_low = max_explosion_range + message_admins("[key_name_admin(usr)] changed the bomb cap to [range_dev], [range_high], [range_low]", 1) + log_admin("[key_name_admin(usr)] changed the bomb cap to [max_explosion_range]") diff --git a/code/modules/admin/secrets/fun_secrets/triple_ai_mode.dm b/code/modules/admin/secrets/fun_secrets/triple_ai_mode.dm new file mode 100644 index 0000000000..81b77eabb6 --- /dev/null +++ b/code/modules/admin/secrets/fun_secrets/triple_ai_mode.dm @@ -0,0 +1,13 @@ +/datum/admin_secret_item/fun_secret/triple_ai_mode + name = "Triple AI Mode" + +/datum/admin_secret_item/fun_secret/triple_ai_mode/can_execute(var/mob/user) + if(ticker && ticker.current_state > GAME_STATE_PREGAME) + return 0 + + return ..() + +/datum/admin_secret_item/admin_secret/triple_ai_mode/execute(var/mob/user) + . = ..() + if(.) + user.client.triple_ai() diff --git a/code/modules/admin/secrets/fun_secrets/turn_humans_into_corgies.dm b/code/modules/admin/secrets/fun_secrets/turn_humans_into_corgies.dm new file mode 100644 index 0000000000..ae6f36a1ac --- /dev/null +++ b/code/modules/admin/secrets/fun_secrets/turn_humans_into_corgies.dm @@ -0,0 +1,11 @@ +/datum/admin_secret_item/fun_secret/turn_humans_into_corgies + name = "Turn All Humans Into Corgies" + +/datum/admin_secret_item/fun_secret/turn_humans_into_corgies/execute(var/mob/user) + . = ..() + if(!.) + return + + for(var/mob/living/carbon/human/H in mob_list) + spawn(0) + H.corgize() diff --git a/code/modules/admin/secrets/fun_secrets/turn_humans_into_monkeys.dm b/code/modules/admin/secrets/fun_secrets/turn_humans_into_monkeys.dm new file mode 100644 index 0000000000..99b1573ade --- /dev/null +++ b/code/modules/admin/secrets/fun_secrets/turn_humans_into_monkeys.dm @@ -0,0 +1,11 @@ +/datum/admin_secret_item/fun_secret/turn_humans_into_monkeys + name = "Turn All Humans Into Monkeys" + +/datum/admin_secret_item/fun_secret/turn_humans_into_monkeys/execute(var/mob/user) + . = ..() + if(!.) + return + + for(var/mob/living/carbon/human/H in mob_list) + spawn(0) + H.monkeyize() diff --git a/code/modules/admin/secrets/random_events/gravity.dm b/code/modules/admin/secrets/random_events/gravity.dm index 51f8f1d187..637bb7129f 100644 --- a/code/modules/admin/secrets/random_events/gravity.dm +++ b/code/modules/admin/secrets/random_events/gravity.dm @@ -2,7 +2,7 @@ * Gravity * **********/ /datum/admin_secret_item/random_event/gravity - name = "Toggle station artificial gravity" + name = "Toggle Station Artificial Gravity" /datum/admin_secret_item/random_event/gravity/can_execute(var/mob/user) if(!(ticker && ticker.mode)) diff --git a/code/modules/admin/secrets/random_events/trigger_cordical_borer_infestation.dm b/code/modules/admin/secrets/random_events/trigger_cordical_borer_infestation.dm new file mode 100644 index 0000000000..f96004565d --- /dev/null +++ b/code/modules/admin/secrets/random_events/trigger_cordical_borer_infestation.dm @@ -0,0 +1,7 @@ +/datum/admin_secret_item/random_event/trigger_cordical_borer_infestation + name = "Trigger a Cortical Borer infestation" + +/datum/admin_secret_item/random_event/trigger_cordical_borer_infestation/execute(var/mob/user) + . = ..() + if(.) + return borers.attempt_random_spawn() diff --git a/code/modules/admin/secrets/random_events/trigger_xenomorph_infestation.dm b/code/modules/admin/secrets/random_events/trigger_xenomorph_infestation.dm new file mode 100644 index 0000000000..11dad2e84c --- /dev/null +++ b/code/modules/admin/secrets/random_events/trigger_xenomorph_infestation.dm @@ -0,0 +1,7 @@ +/datum/admin_secret_item/random_event/trigger_xenomorph_infestation + name = "Trigger a Xenomorph Infestation" + +/datum/admin_secret_item/random_event/trigger_xenomorph_infestation/execute(var/mob/user) + . = ..() + if(.) + return xenomorphs.attempt_random_spawn() From 457987046b9a1355f2eadff6817bae8fc891dc42 Mon Sep 17 00:00:00 2001 From: PsiOmegaDelta Date: Tue, 7 Jul 2015 11:24:09 +0200 Subject: [PATCH 12/21] Re-implements world end events as datums. --- baystation12.dme | 5 ++++- baystation12.int | 15 ++++++-------- code/_helpers/lists.dm | 2 +- code/modules/admin/admin_secrets.dm | 4 ++++ .../admin/secrets/admin_secrets/admin_logs.dm | 13 ++++++++++++ .../secrets/admin_secrets/jump_shuttle.dm | 20 +++++++++---------- .../{launch_shutter.dm => launch_shuttle.dm} | 6 +++--- .../admin_secrets/launch_shuttle_forced.dm | 6 +++--- .../admin_secrets/list_fingerprints.dm | 2 +- .../secrets/admin_secrets/move_shuttle.dm | 10 +++++----- .../secrets/final_solutions/summon_narsie.dm | 11 ++++++++++ .../final_solutions/supermatter_cascade.dm | 13 ++++++++++++ .../secrets/fun_secrets/break_all_lights.dm | 2 +- .../secrets/fun_secrets/toggle_bomb_cap.dm | 4 ++-- .../admin/secrets/random_events/gravity.dm | 12 +++++------ 15 files changed, 83 insertions(+), 42 deletions(-) create mode 100644 code/modules/admin/secrets/admin_secrets/admin_logs.dm rename code/modules/admin/secrets/admin_secrets/{launch_shutter.dm => launch_shuttle.dm} (74%) create mode 100644 code/modules/admin/secrets/final_solutions/summon_narsie.dm create mode 100644 code/modules/admin/secrets/final_solutions/supermatter_cascade.dm diff --git a/baystation12.dme b/baystation12.dme index 9946956dfb..a8b4f311ef 100644 --- a/baystation12.dme +++ b/baystation12.dme @@ -843,10 +843,11 @@ #include "code\modules\admin\ToRban.dm" #include "code\modules\admin\DB ban\functions.dm" #include "code\modules\admin\permissionverbs\permissionedit.dm" +#include "code\modules\admin\secrets\admin_secrets\admin_logs.dm" #include "code\modules\admin\secrets\admin_secrets\alter_narsie.dm" #include "code\modules\admin\secrets\admin_secrets\bombing_list.dm" #include "code\modules\admin\secrets\admin_secrets\jump_shuttle.dm" -#include "code\modules\admin\secrets\admin_secrets\launch_shutter.dm" +#include "code\modules\admin\secrets\admin_secrets\launch_shuttle.dm" #include "code\modules\admin\secrets\admin_secrets\launch_shuttle_forced.dm" #include "code\modules\admin\secrets\admin_secrets\list_dna.dm" #include "code\modules\admin\secrets\admin_secrets\list_fingerprints.dm" @@ -858,6 +859,8 @@ #include "code\modules\admin\secrets\admin_secrets\show_law_changes.dm" #include "code\modules\admin\secrets\admin_secrets\show_signalers.dm" #include "code\modules\admin\secrets\admin_secrets\traitors_and_objectives.dm" +#include "code\modules\admin\secrets\final_solutions\summon_narsie.dm" +#include "code\modules\admin\secrets\final_solutions\supermatter_cascade.dm" #include "code\modules\admin\secrets\fun_secrets\break_all_lights.dm" #include "code\modules\admin\secrets\fun_secrets\break_some_lights.dm" #include "code\modules\admin\secrets\fun_secrets\fix_all_lights.dm" diff --git a/baystation12.int b/baystation12.int index cfd9890d63..b82874fded 100644 --- a/baystation12.int +++ b/baystation12.int @@ -1,9 +1,6 @@ -// BEGIN_INTERNALS -/* -DIR: code code\modules code\modules\mob code\modules\mob\freelook code\modules\mob\living code\modules\mob\living\carbon code\modules\mob\living\carbon\alien code\modules\mob\living\carbon\alien\diona code\modules\mob\living\carbon\alien\larva code\modules\mob\living\carbon\human -AUTO_FILE_DIR: OFF -MAP_ICON_TYPE: 0 -WINDOW: code\modules\mob\living\carbon\human\life.dm -FILE: code\modules\mob\living\carbon\human\life.dm -*/ -// END_INTERNALS +// BEGIN_INTERNALS +/* +MAP_ICON_TYPE: 0 +AUTO_FILE_DIR: OFF +*/ +// END_INTERNALS diff --git a/code/_helpers/lists.dm b/code/_helpers/lists.dm index fb4cd3874e..b4f70b32b1 100644 --- a/code/_helpers/lists.dm +++ b/code/_helpers/lists.dm @@ -592,7 +592,7 @@ proc/dd_sortedTextList(list/incoming) return dd_sortedtextlist(incoming, case_sensitive) -datum/proc/dd_SortValue() +/datum/proc/dd_SortValue() return "[src]" /obj/machinery/dd_SortValue() diff --git a/code/modules/admin/admin_secrets.dm b/code/modules/admin/admin_secrets.dm index 2ce43a7962..88a58ff6e8 100644 --- a/code/modules/admin/admin_secrets.dm +++ b/code/modules/admin/admin_secrets.dm @@ -44,6 +44,9 @@ var/datum/admin_secrets/admin_secrets = new() var/feedback = 1 var/permissions = R_HOST +/datum/admin_secret_item/dd_SortValue() + return "[name]" + /datum/admin_secret_item/proc/name() return name @@ -75,6 +78,7 @@ var/datum/admin_secrets/admin_secrets = new() /datum/admin_secret_category/final_solutions name = "Final Solutions" + desc = "(Warning, these will end the round!)" /************************* * Pre-defined base items * diff --git a/code/modules/admin/secrets/admin_secrets/admin_logs.dm b/code/modules/admin/secrets/admin_secrets/admin_logs.dm new file mode 100644 index 0000000000..d2664f1e2b --- /dev/null +++ b/code/modules/admin/secrets/admin_secrets/admin_logs.dm @@ -0,0 +1,13 @@ +/datum/admin_secret_item/admin_secret/admin_logs + name = "Admin Logs" + +/datum/admin_secret_item/admin_secret/admin_logs/execute(var/mob/user) + . = ..() + if(!.) + return + var/dat = "Admin Log
    " + for(var/l in admin_log) + dat += "
  • [l]
  • " + if(!admin_log.len) + dat += "No-one has done anything this round!" + user << browse(dat, "window=admin_log") diff --git a/code/modules/admin/secrets/admin_secrets/jump_shuttle.dm b/code/modules/admin/secrets/admin_secrets/jump_shuttle.dm index 1453ae35ce..4097632aa3 100644 --- a/code/modules/admin/secrets/admin_secrets/jump_shuttle.dm +++ b/code/modules/admin/secrets/admin_secrets/jump_shuttle.dm @@ -9,28 +9,28 @@ . = ..() if(!.) return - var/shuttle_tag = input("Which shuttle do you want to jump?") as null|anything in shuttle_controller.shuttles + var/shuttle_tag = input(user, "Which shuttle do you want to jump?") as null|anything in shuttle_controller.shuttles if (!shuttle_tag) return var/datum/shuttle/S = shuttle_controller.shuttles[shuttle_tag] - var/origin_area = input("Which area is the shuttle at now? (MAKE SURE THIS IS CORRECT OR THINGS WILL BREAK)") as null|area in world + var/origin_area = input(user, "Which area is the shuttle at now? (MAKE SURE THIS IS CORRECT OR THINGS WILL BREAK)") as null|area in world if (!origin_area) return - var/destination_area = input("Which area is the shuttle at now? (MAKE SURE THIS IS CORRECT OR THINGS WILL BREAK)") as null|area in world + var/destination_area = input(user, "Which area is the shuttle at now? (MAKE SURE THIS IS CORRECT OR THINGS WILL BREAK)") as null|area in world if (!destination_area) return - var/long_jump = alert("Is there a transition area for this jump?","", "Yes", "No") + var/long_jump = alert(user, "Is there a transition area for this jump?","", "Yes", "No") if (long_jump == "Yes") - var/transition_area = input("Which area is the transition area? (MAKE SURE THIS IS CORRECT OR THINGS WILL BREAK)") as null|area in world + var/transition_area = input(user, "Which area is the transition area? (MAKE SURE THIS IS CORRECT OR THINGS WILL BREAK)") as null|area in world if (!transition_area) return - var/move_duration = input("How many seconds will this jump take?") as num + var/move_duration = input(user, "How many seconds will this jump take?") as num S.long_jump(origin_area, destination_area, transition_area, move_duration) - message_admins("[key_name_admin(usr)] has initiated a jump from [origin_area] to [destination_area] lasting [move_duration] seconds for the [shuttle_tag] shuttle", 1) - log_admin("[key_name_admin(usr)] has initiated a jump from [origin_area] to [destination_area] lasting [move_duration] seconds for the [shuttle_tag] shuttle") + message_admins("[key_name_admin(user)] has initiated a jump from [origin_area] to [destination_area] lasting [move_duration] seconds for the [shuttle_tag] shuttle", 1) + log_admin("[key_name_admin(user)] has initiated a jump from [origin_area] to [destination_area] lasting [move_duration] seconds for the [shuttle_tag] shuttle") else S.short_jump(origin_area, destination_area) - message_admins("[key_name_admin(usr)] has initiated a jump from [origin_area] to [destination_area] for the [shuttle_tag] shuttle", 1) - log_admin("[key_name_admin(usr)] has initiated a jump from [origin_area] to [destination_area] for the [shuttle_tag] shuttle") + message_admins("[key_name_admin(user)] has initiated a jump from [origin_area] to [destination_area] for the [shuttle_tag] shuttle", 1) + log_admin("[key_name_admin(user)] has initiated a jump from [origin_area] to [destination_area] for the [shuttle_tag] shuttle") diff --git a/code/modules/admin/secrets/admin_secrets/launch_shutter.dm b/code/modules/admin/secrets/admin_secrets/launch_shuttle.dm similarity index 74% rename from code/modules/admin/secrets/admin_secrets/launch_shutter.dm rename to code/modules/admin/secrets/admin_secrets/launch_shuttle.dm index 30867fca05..9d6ce44a2d 100644 --- a/code/modules/admin/secrets/admin_secrets/launch_shutter.dm +++ b/code/modules/admin/secrets/admin_secrets/launch_shuttle.dm @@ -14,13 +14,13 @@ if (istype(shuttle_controller.shuttles[shuttle_tag], /datum/shuttle/ferry)) valid_shuttles += shuttle_tag - var/shuttle_tag = input("Which shuttle do you want to launch?") as null|anything in valid_shuttles + var/shuttle_tag = input(user, "Which shuttle do you want to launch?") as null|anything in valid_shuttles if (!shuttle_tag) return var/datum/shuttle/ferry/S = shuttle_controller.shuttles[shuttle_tag] if (S.can_launch()) - S.launch(usr) + S.launch(user) log_and_message_admins("launched the [shuttle_tag] shuttle", user) else - alert("The [shuttle_tag] shuttle cannot be launched at this time. It's probably busy.") + alert(user, "The [shuttle_tag] shuttle cannot be launched at this time. It's probably busy.") diff --git a/code/modules/admin/secrets/admin_secrets/launch_shuttle_forced.dm b/code/modules/admin/secrets/admin_secrets/launch_shuttle_forced.dm index 250d04b044..d1a86fec98 100644 --- a/code/modules/admin/secrets/admin_secrets/launch_shuttle_forced.dm +++ b/code/modules/admin/secrets/admin_secrets/launch_shuttle_forced.dm @@ -14,13 +14,13 @@ if (istype(shuttle_controller.shuttles[shuttle_tag], /datum/shuttle/ferry)) valid_shuttles += shuttle_tag - var/shuttle_tag = input("Which shuttle's launch do you want to force?") as null|anything in valid_shuttles + var/shuttle_tag = input(user, "Which shuttle's launch do you want to force?") as null|anything in valid_shuttles if (!shuttle_tag) return var/datum/shuttle/ferry/S = shuttle_controller.shuttles[shuttle_tag] if (S.can_force()) - S.force_launch(usr) + S.force_launch(user) log_and_message_admins("forced the [shuttle_tag] shuttle", user) else - alert("The [shuttle_tag] shuttle launch cannot be forced at this time. It's busy, or hasn't been launched yet.") + alert(user, "The [shuttle_tag] shuttle launch cannot be forced at this time. It's busy, or hasn't been launched yet.") diff --git a/code/modules/admin/secrets/admin_secrets/list_fingerprints.dm b/code/modules/admin/secrets/admin_secrets/list_fingerprints.dm index 710cdaf4fe..03cb9701c4 100644 --- a/code/modules/admin/secrets/admin_secrets/list_fingerprints.dm +++ b/code/modules/admin/secrets/admin_secrets/list_fingerprints.dm @@ -16,4 +16,4 @@ else if(!H.dna) dat += "[H]H.dna = null" dat += "" - usr << browse(dat, "window=fingerprints;size=440x410") + user << browse(dat, "window=fingerprints;size=440x410") diff --git a/code/modules/admin/secrets/admin_secrets/move_shuttle.dm b/code/modules/admin/secrets/admin_secrets/move_shuttle.dm index e58863afde..5772bbed54 100644 --- a/code/modules/admin/secrets/admin_secrets/move_shuttle.dm +++ b/code/modules/admin/secrets/admin_secrets/move_shuttle.dm @@ -9,20 +9,20 @@ . = ..() if(!.) return - var/confirm = alert("This command directly moves a shuttle from one area to another. DO NOT USE THIS UNLESS YOU ARE DEBUGGING A SHUTTLE AND YOU KNOW WHAT YOU ARE DOING.", "Are you sure?", "Ok", "Cancel") + var/confirm = alert(user, "This command directly moves a shuttle from one area to another. DO NOT USE THIS UNLESS YOU ARE DEBUGGING A SHUTTLE AND YOU KNOW WHAT YOU ARE DOING.", "Are you sure?", "Ok", "Cancel") if (confirm == "Cancel") return - var/shuttle_tag = input("Which shuttle do you want to jump?") as null|anything in shuttle_controller.shuttles + var/shuttle_tag = input(user, "Which shuttle do you want to jump?") as null|anything in shuttle_controller.shuttles if (!shuttle_tag) return var/datum/shuttle/S = shuttle_controller.shuttles[shuttle_tag] - var/origin_area = input("Which area is the shuttle at now? (MAKE SURE THIS IS CORRECT OR THINGS WILL BREAK)") as null|area in world + var/origin_area = input(user, "Which area is the shuttle at now? (MAKE SURE THIS IS CORRECT OR THINGS WILL BREAK)") as null|area in world if (!origin_area) return - var/destination_area = input("Which area is the shuttle at now? (MAKE SURE THIS IS CORRECT OR THINGS WILL BREAK)") as null|area in world + var/destination_area = input(user, "Which area is the shuttle at now? (MAKE SURE THIS IS CORRECT OR THINGS WILL BREAK)") as null|area in world if (!destination_area) return S.move(origin_area, destination_area) - log_and_message_admins("[key_name_admin(usr)] moved the [shuttle_tag] shuttle", user) + log_and_message_admins("moved the [shuttle_tag] shuttle", user) diff --git a/code/modules/admin/secrets/final_solutions/summon_narsie.dm b/code/modules/admin/secrets/final_solutions/summon_narsie.dm new file mode 100644 index 0000000000..8062f76752 --- /dev/null +++ b/code/modules/admin/secrets/final_solutions/summon_narsie.dm @@ -0,0 +1,11 @@ +/datum/admin_secret_item/final_solution/summon_narsie + name = "Summon Nar-Sie" + +/datum/admin_secret_item/final_solution/summon_narsie/execute(var/mob/user) + . = ..() + if(!.) + return + var/choice = input(user, "You sure you want to end the round and summon Nar-Sie at your location? Misuse of this could result in removal of flags or hilarity.") in list("PRAISE SATAN", "Cancel") + if(choice == "PRAISE SATAN") + new /obj/singularity/narsie/large(get_turf(user)) + log_and_message_admins("has summoned Nar-Sie and brought about a new realm of suffering.", user) diff --git a/code/modules/admin/secrets/final_solutions/supermatter_cascade.dm b/code/modules/admin/secrets/final_solutions/supermatter_cascade.dm new file mode 100644 index 0000000000..a50596985c --- /dev/null +++ b/code/modules/admin/secrets/final_solutions/supermatter_cascade.dm @@ -0,0 +1,13 @@ +/datum/admin_secret_item/final_solution/supermatter_cascade + name = "Supermatter Cascade" + +/datum/admin_secret_item/final_solution/supermatter_cascade/execute(var/mob/user) + . = ..() + if(!.) + return + var/choice = input(user, "You sure you want to destroy the universe and create a large explosion at your location? Misuse of this could result in removal of flags or hilarity.") in list("NO TIME TO EXPLAIN", "Cancel") + if(choice == "NO TIME TO EXPLAIN") + explosion(get_turf(user), 8, 16, 24, 32, 1) + new /turf/unsimulated/wall/supermatter(get_turf(user)) + SetUniversalState(/datum/universal_state/supermatter_cascade) + message_admins("[key_name_admin(user)] has managed to destroy the universe with a supermatter cascade. Good job, [key_name_admin(user)]") diff --git a/code/modules/admin/secrets/fun_secrets/break_all_lights.dm b/code/modules/admin/secrets/fun_secrets/break_all_lights.dm index 5c65e389af..ea54952a7e 100644 --- a/code/modules/admin/secrets/fun_secrets/break_all_lights.dm +++ b/code/modules/admin/secrets/fun_secrets/break_all_lights.dm @@ -1,7 +1,7 @@ /datum/admin_secret_item/fun_secret/break_all_lights name = "Break All Lights" -/datum/admin_secret_item/fun_secret/make_all_areas_powered/execute(var/mob/user) +/datum/admin_secret_item/fun_secret/break_all_lights/execute(var/mob/user) . = ..() if(.) lightsout(0,0) diff --git a/code/modules/admin/secrets/fun_secrets/toggle_bomb_cap.dm b/code/modules/admin/secrets/fun_secrets/toggle_bomb_cap.dm index 28cd3327c4..33ba8a861c 100644 --- a/code/modules/admin/secrets/fun_secrets/toggle_bomb_cap.dm +++ b/code/modules/admin/secrets/fun_secrets/toggle_bomb_cap.dm @@ -17,5 +17,5 @@ var/range_dev = max_explosion_range *0.25 var/range_high = max_explosion_range *0.5 var/range_low = max_explosion_range - message_admins("[key_name_admin(usr)] changed the bomb cap to [range_dev], [range_high], [range_low]", 1) - log_admin("[key_name_admin(usr)] changed the bomb cap to [max_explosion_range]") + message_admins("[key_name_admin(user)] changed the bomb cap to [range_dev], [range_high], [range_low]", 1) + log_admin("[key_name_admin(user)] changed the bomb cap to [max_explosion_range]") diff --git a/code/modules/admin/secrets/random_events/gravity.dm b/code/modules/admin/secrets/random_events/gravity.dm index 637bb7129f..8d4cad4960 100644 --- a/code/modules/admin/secrets/random_events/gravity.dm +++ b/code/modules/admin/secrets/random_events/gravity.dm @@ -22,10 +22,10 @@ feedback_inc("admin_secrets_fun_used",1) feedback_add_details("admin_secrets_fun_used","Grav") if(gravity_is_on) - log_admin("[key_name(usr)] toggled gravity on.", 1) - message_admins("\blue [key_name_admin(usr)] toggled gravity on.", 1) - command_announcement.Announce("Gravity generators are again functioning within normal parameters. Sorry for any inconvenience.") + log_admin("[key_name(user)] toggled gravity on.", 1) + message_admins("[key_name_admin(user)] toggled gravity on.", 1) + command_announcement.Announce("Gravity generators are again functioning within normal parameters. Sorry for any inconvenience.") else - log_admin("[key_name(usr)] toggled gravity off.", 1) - message_admins("\blue [key_name_admin(usr)] toggled gravity off.", 1) - command_announcement.Announce("Feedback surge detected in mass-distributions systems. Artificial gravity has been disabled whilst the system reinitializes. Further failures may result in a gravitational collapse and formation of blackholes. Have a nice day.") + log_admin("[key_name(user)] toggled gravity off.", 1) + message_admins("[key_name_admin(usr)] toggled gravity off.", 1) + command_announcement.Announce("Feedback surge detected in mass-distributions systems. Artificial gravity has been disabled whilst the system reinitializes. Further failures may result in a gravitational collapse and formation of blackholes. Have a nice day.") From 39825d6810eee4c3d33a7a78d641de646c70cd1d Mon Sep 17 00:00:00 2001 From: PsiOmegaDelta Date: Tue, 11 Aug 2015 15:03:57 +0200 Subject: [PATCH 13/21] Secret entries can now give a warning before being triggered. --- code/modules/admin/admin.dm | 2 +- code/modules/admin/admin_secrets.dm | 13 +++++++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm index 06adf11b57..3ed148c6b1 100644 --- a/code/modules/admin/admin.dm +++ b/code/modules/admin/admin.dm @@ -611,7 +611,7 @@ proc/admin_notice(var/message, var/rights) if(category.desc) dat += "[category.desc]
    " for(var/datum/admin_secret_item/item in category.items) - if(!item.can_execute(usr)) + if(!item.can_view(usr)) continue dat += "[item.name()]
    " dat += "
    " diff --git a/code/modules/admin/admin_secrets.dm b/code/modules/admin/admin_secrets.dm index 88a58ff6e8..38bebb844a 100644 --- a/code/modules/admin/admin_secrets.dm +++ b/code/modules/admin/admin_secrets.dm @@ -33,7 +33,7 @@ var/datum/admin_secrets/admin_secrets = new() /datum/admin_secret_category/proc/can_view(var/mob/user) for(var/datum/admin_secret_item/item in items) - if(item.can_execute(user)) + if(item.can_view(user)) return 1 return 0 @@ -43,6 +43,7 @@ var/datum/admin_secrets/admin_secrets = new() var/log = 1 var/feedback = 1 var/permissions = R_HOST + var/warn_before_use = 0 /datum/admin_secret_item/dd_SortValue() return "[name]" @@ -50,9 +51,15 @@ var/datum/admin_secrets/admin_secrets = new() /datum/admin_secret_item/proc/name() return name -/datum/admin_secret_item/proc/can_execute(var/mob/user) +/datum/admin_secret_item/proc/can_view(var/mob/user) return check_rights(permissions, 0, user) +/datum/admin_secret_item/proc/can_execute(var/mob/user) + if(can_view(user)) + if(!warn_before_use || alert("Execute the command '[name]'?", name, "No","Yes") == "Yes") + return 1 + return 0 + /datum/admin_secret_item/proc/execute(var/mob/user) if(!can_execute(user)) return 0 @@ -91,10 +98,12 @@ var/datum/admin_secrets/admin_secrets = new() /datum/admin_secret_item/random_event category = /datum/admin_secret_category/random_events permissions = R_FUN + warn_before_use = 1 /datum/admin_secret_item/fun_secret category = /datum/admin_secret_category/fun_secrets permissions = R_FUN + warn_before_use = 1 /datum/admin_secret_item/final_solution category = /datum/admin_secret_category/final_solutions From 0d4152f9d95d3d5fb90dbee46998857e84532e40 Mon Sep 17 00:00:00 2001 From: Kelenius Date: Thu, 13 Aug 2015 09:05:06 +0300 Subject: [PATCH 14/21] Changelog --- html/changelogs/Kelenius-ofClicksAndCooldowns.yml | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 html/changelogs/Kelenius-ofClicksAndCooldowns.yml diff --git a/html/changelogs/Kelenius-ofClicksAndCooldowns.yml b/html/changelogs/Kelenius-ofClicksAndCooldowns.yml new file mode 100644 index 0000000000..a6768a8573 --- /dev/null +++ b/html/changelogs/Kelenius-ofClicksAndCooldowns.yml @@ -0,0 +1,6 @@ +author: Kelenius + +delete-after: True + +changes: + - experiment: "Click cooldowns have been removed on pretty much everything that isn't an attack." From bb8f7069431d924fb51e32c3d3b99357b068f774 Mon Sep 17 00:00:00 2001 From: mwerezak Date: Wed, 17 Jun 2015 20:11:01 -0400 Subject: [PATCH 15/21] Adds armor penetration system --- code/game/objects/objs.dm | 1 + .../mob/living/carbon/human/human_defense.dm | 4 ++-- code/modules/mob/living/living_defense.dm | 17 +++++++++++++---- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm index cb3214122a..d86952d863 100644 --- a/code/game/objects/objs.dm +++ b/code/game/objects/objs.dm @@ -13,6 +13,7 @@ var/damtype = "brute" var/force = 0 + var/armorpen = 0 /obj/Destroy() processing_objects -= src diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index cdaad1c42f..d59a8ce859 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -227,7 +227,7 @@ emp_act else visible_message("\red [src] has been attacked in the [hit_area] with [I.name] by [user]!") - var/armor = run_armor_check(affecting, "melee", "Your armor has protected your [hit_area].", "Your armor has softened hit to your [hit_area].") + var/armor = run_armor_check(affecting, "melee", I.armorpen, "Your armor has protected your [hit_area].", "Your armor has softened hit to your [hit_area].") var/weapon_sharp = is_sharp(I) var/weapon_edge = has_edge(I) if ((weapon_sharp || weapon_edge) && prob(getarmor(target_zone, "melee"))) @@ -342,7 +342,7 @@ emp_act var/hit_area = affecting.name src.visible_message("\red [src] has been hit in the [hit_area] by [O].") - var/armor = run_armor_check(affecting, "melee", "Your armor has protected your [hit_area].", "Your armor has softened hit to your [hit_area].") //I guess "melee" is the best fit here + var/armor = run_armor_check(affecting, "melee", O.armorpen, "Your armor has protected your [hit_area].", "Your armor has softened hit to your [hit_area].") //I guess "melee" is the best fit here if(armor < 2) apply_damage(throw_damage, dtype, zone, armor, is_sharp(O), has_edge(O), O) diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index 2a64304401..190083f227 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -10,24 +10,33 @@ 1 - halfblock 2 - fullblock */ -/mob/living/proc/run_armor_check(var/def_zone = null, var/attack_flag = "melee", var/absorb_text = null, var/soften_text = null) +/mob/living/proc/run_armor_check(var/def_zone = null, var/attack_flag = "melee", var/armour_pen = 0, var/absorb_text = null, var/soften_text = null) var/armor = getarmor(def_zone, attack_flag) var/absorb = 0 + + //Roll armour if(prob(armor)) absorb += 1 if(prob(armor)) absorb += 1 + + //Roll penetration + if(prob(armour_pen)) + absorb -= 1 + if(prob(armour_pen)) + absorb -= 1 + if(absorb >= 2) if(absorb_text) show_message("[absorb_text]") else - show_message("\red Your armor absorbs the blow!") + show_message("Your armor absorbs the blow!") return 2 if(absorb == 1) if(absorb_text) show_message("[soften_text]",4) else - show_message("\red Your armor softens the blow!") + show_message("Your armor softens the blow!") return 1 return 0 @@ -64,7 +73,7 @@ return //Armor - var/absorb = run_armor_check(def_zone, P.check_armour) + var/absorb = run_armor_check(def_zone, P.check_armour, P.armorpen) var/proj_sharp = is_sharp(P) var/proj_edge = has_edge(P) if ((proj_sharp || proj_edge) && prob(getarmor(def_zone, P.check_armour))) From 0cf21df8b590be79a2840b101f02a4be12a1de23 Mon Sep 17 00:00:00 2001 From: mwerezak Date: Wed, 17 Jun 2015 20:59:56 -0400 Subject: [PATCH 16/21] Adjusts projectile values --- code/modules/projectiles/guns/energy/laser.dm | 7 +++---- code/modules/projectiles/projectile/beams.dm | 12 ++++++++++-- code/modules/projectiles/projectile/bullets.dm | 18 +++++++++++------- 3 files changed, 24 insertions(+), 13 deletions(-) diff --git a/code/modules/projectiles/guns/energy/laser.dm b/code/modules/projectiles/guns/energy/laser.dm index b1c47fd605..3b53c8b5f4 100644 --- a/code/modules/projectiles/guns/energy/laser.dm +++ b/code/modules/projectiles/guns/energy/laser.dm @@ -7,10 +7,9 @@ slot_flags = SLOT_BELT|SLOT_BACK w_class = 3 force = 10 - origin_tech = list(TECH_COMBAT = 3, TECH_MAGNET = 2) - matter = list(DEFAULT_WALL_MATERIAL = 2000) - projectile_type = /obj/item/projectile/beam - fire_delay = 1 //rapid fire + origin_tech = list(TECH_COMBAT = 3, TECH_MAGNET = 2) + matter = list(DEFAULT_WALL_MATERIAL = 2000) + projectile_type = /obj/item/projectile/beam/midlaser /obj/item/weapon/gun/energy/laser/mounted self_recharge = 1 diff --git a/code/modules/projectiles/projectile/beams.dm b/code/modules/projectiles/projectile/beams.dm index 8aa493404a..68c61c9d3a 100644 --- a/code/modules/projectiles/projectile/beams.dm +++ b/code/modules/projectiles/projectile/beams.dm @@ -23,10 +23,15 @@ check_armour = "laser" eyeblur = 2 +/obj/item/projectile/beam/midlaser + damage = 40 + armorpen = 10 + /obj/item/projectile/beam/heavylaser name = "heavy laser" icon_state = "heavylaser" damage = 60 + armorpen = 30 muzzle_type = /obj/effect/projectile/laser_heavy/muzzle tracer_type = /obj/effect/projectile/laser_heavy/tracer @@ -35,7 +40,8 @@ /obj/item/projectile/beam/xray name = "xray beam" icon_state = "xray" - damage = 30 + damage = 25 + armorpen = 50 muzzle_type = /obj/effect/projectile/xray/muzzle tracer_type = /obj/effect/projectile/xray/tracer @@ -45,6 +51,7 @@ name = "pulse" icon_state = "u_laser" damage = 50 + armorpen = 30 muzzle_type = /obj/effect/projectile/laser_pulse/muzzle tracer_type = /obj/effect/projectile/laser_pulse/tracer @@ -122,7 +129,8 @@ /obj/item/projectile/beam/sniper name = "sniper beam" icon_state = "xray" - damage = 60 + damage = 50 + armorpen = 10 stun = 3 weaken = 3 stutter = 3 diff --git a/code/modules/projectiles/projectile/bullets.dm b/code/modules/projectiles/projectile/bullets.dm index 2038d718e0..7a8f44e7f9 100644 --- a/code/modules/projectiles/projectile/bullets.dm +++ b/code/modules/projectiles/projectile/bullets.dm @@ -119,7 +119,8 @@ /obj/item/projectile/bullet/shotgun name = "slug" - damage = 60 + damage = 50 + armorpen = 15 /obj/item/projectile/bullet/shotgun/beanbag //because beanbags are not bullets name = "beanbag" @@ -139,21 +140,24 @@ /* "Rifle" rounds */ -/obj/item/projectile/bullet/rifle/a762 - damage = 30 +/obj/item/projectile/bullet/rifle + armorpen = 20 penetrating = 1 +/obj/item/projectile/bullet/rifle/a762 + damage = 25 + +/obj/item/projectile/bullet/rifle/a556 + damage = 35 + /obj/item/projectile/bullet/rifle/a145 damage = 80 stun = 3 weaken = 3 penetrating = 5 + armorpen = 50 hitscan = 1 //so the PTR isn't useless as a sniper weapon -/obj/item/projectile/bullet/rifle/a556 - damage = 40 - penetrating = 1 - /* Miscellaneous */ /obj/item/projectile/bullet/suffocationbullet//How does this even work? From 2e8f927085b8560ae6429a8c1c39a4fdc3af70e2 Mon Sep 17 00:00:00 2001 From: HarpyEagle Date: Thu, 18 Jun 2015 13:01:51 -0400 Subject: [PATCH 17/21] More descriptive variable name Renames armorpen to armor_penetration --- code/game/objects/objs.dm | 2 +- code/modules/mob/living/carbon/human/human_defense.dm | 4 ++-- code/modules/mob/living/living_defense.dm | 2 +- code/modules/projectiles/projectile/beams.dm | 10 +++++----- code/modules/projectiles/projectile/bullets.dm | 6 +++--- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm index d86952d863..27bf3b3e63 100644 --- a/code/game/objects/objs.dm +++ b/code/game/objects/objs.dm @@ -13,7 +13,7 @@ var/damtype = "brute" var/force = 0 - var/armorpen = 0 + var/armor_penetration = 0 /obj/Destroy() processing_objects -= src diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index d59a8ce859..f16dd51e36 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -227,7 +227,7 @@ emp_act else visible_message("\red [src] has been attacked in the [hit_area] with [I.name] by [user]!") - var/armor = run_armor_check(affecting, "melee", I.armorpen, "Your armor has protected your [hit_area].", "Your armor has softened hit to your [hit_area].") + var/armor = run_armor_check(affecting, "melee", I.armor_penetration, "Your armor has protected your [hit_area].", "Your armor has softened hit to your [hit_area].") var/weapon_sharp = is_sharp(I) var/weapon_edge = has_edge(I) if ((weapon_sharp || weapon_edge) && prob(getarmor(target_zone, "melee"))) @@ -342,7 +342,7 @@ emp_act var/hit_area = affecting.name src.visible_message("\red [src] has been hit in the [hit_area] by [O].") - var/armor = run_armor_check(affecting, "melee", O.armorpen, "Your armor has protected your [hit_area].", "Your armor has softened hit to your [hit_area].") //I guess "melee" is the best fit here + var/armor = run_armor_check(affecting, "melee", O.armor_penetration, "Your armor has protected your [hit_area].", "Your armor has softened hit to your [hit_area].") //I guess "melee" is the best fit here if(armor < 2) apply_damage(throw_damage, dtype, zone, armor, is_sharp(O), has_edge(O), O) diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index 190083f227..462e47b4f8 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -73,7 +73,7 @@ return //Armor - var/absorb = run_armor_check(def_zone, P.check_armour, P.armorpen) + var/absorb = run_armor_check(def_zone, P.check_armour, P.armor_penetration) var/proj_sharp = is_sharp(P) var/proj_edge = has_edge(P) if ((proj_sharp || proj_edge) && prob(getarmor(def_zone, P.check_armour))) diff --git a/code/modules/projectiles/projectile/beams.dm b/code/modules/projectiles/projectile/beams.dm index 68c61c9d3a..af93e5cefd 100644 --- a/code/modules/projectiles/projectile/beams.dm +++ b/code/modules/projectiles/projectile/beams.dm @@ -25,13 +25,13 @@ /obj/item/projectile/beam/midlaser damage = 40 - armorpen = 10 + armor_penetration = 10 /obj/item/projectile/beam/heavylaser name = "heavy laser" icon_state = "heavylaser" damage = 60 - armorpen = 30 + armor_penetration = 30 muzzle_type = /obj/effect/projectile/laser_heavy/muzzle tracer_type = /obj/effect/projectile/laser_heavy/tracer @@ -41,7 +41,7 @@ name = "xray beam" icon_state = "xray" damage = 25 - armorpen = 50 + armor_penetration = 50 muzzle_type = /obj/effect/projectile/xray/muzzle tracer_type = /obj/effect/projectile/xray/tracer @@ -51,7 +51,7 @@ name = "pulse" icon_state = "u_laser" damage = 50 - armorpen = 30 + armor_penetration = 30 muzzle_type = /obj/effect/projectile/laser_pulse/muzzle tracer_type = /obj/effect/projectile/laser_pulse/tracer @@ -130,7 +130,7 @@ name = "sniper beam" icon_state = "xray" damage = 50 - armorpen = 10 + armor_penetration = 10 stun = 3 weaken = 3 stutter = 3 diff --git a/code/modules/projectiles/projectile/bullets.dm b/code/modules/projectiles/projectile/bullets.dm index 7a8f44e7f9..292fd44034 100644 --- a/code/modules/projectiles/projectile/bullets.dm +++ b/code/modules/projectiles/projectile/bullets.dm @@ -120,7 +120,7 @@ /obj/item/projectile/bullet/shotgun name = "slug" damage = 50 - armorpen = 15 + armor_penetration = 15 /obj/item/projectile/bullet/shotgun/beanbag //because beanbags are not bullets name = "beanbag" @@ -141,7 +141,7 @@ /* "Rifle" rounds */ /obj/item/projectile/bullet/rifle - armorpen = 20 + armor_penetration = 20 penetrating = 1 /obj/item/projectile/bullet/rifle/a762 @@ -155,7 +155,7 @@ stun = 3 weaken = 3 penetrating = 5 - armorpen = 50 + armor_penetration = 50 hitscan = 1 //so the PTR isn't useless as a sniper weapon /* Miscellaneous */ From 76b6b902990fea4a495b5b2879fa5e4e5f18686a Mon Sep 17 00:00:00 2001 From: mwerezak Date: Fri, 26 Jun 2015 23:33:43 -0400 Subject: [PATCH 18/21] Adds armor_penetration values to energy weapons --- code/game/objects/items/weapons/melee/energy.dm | 4 +++- code/modules/mob/living/living_defense.dm | 3 +++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/code/game/objects/items/weapons/melee/energy.dm b/code/game/objects/items/weapons/melee/energy.dm index 6876310343..d53760211a 100644 --- a/code/game/objects/items/weapons/melee/energy.dm +++ b/code/game/objects/items/weapons/melee/energy.dm @@ -5,6 +5,7 @@ var/active_w_class sharp = 0 edge = 0 + armor_penetration = 50 flags = NOBLOODY /obj/item/weapon/melee/energy/proc/activate(mob/living/user) @@ -173,7 +174,8 @@ name = "energy blade" desc = "A concentrated beam of energy in the shape of a blade. Very stylish... and lethal." icon_state = "blade" - force = 70.0//Normal attacks deal very high damage. + force = 40 //Normal attacks deal very high damage - about the same as wielded fire axe + armor_penetration = 100 sharp = 1 edge = 1 anchored = 1 // Never spawned outside of inventory, should be fine. diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index 462e47b4f8..a605a5f850 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -11,6 +11,9 @@ 2 - fullblock */ /mob/living/proc/run_armor_check(var/def_zone = null, var/attack_flag = "melee", var/armour_pen = 0, var/absorb_text = null, var/soften_text = null) + if(armour_pen >= 100) + return 0 //might as well just skip the processing + var/armor = getarmor(def_zone, attack_flag) var/absorb = 0 From 6404d02c38c2a5f143ec2b963c2a47c830579f4f Mon Sep 17 00:00:00 2001 From: HarpyEagle Date: Thu, 13 Aug 2015 18:11:34 -0400 Subject: [PATCH 19/21] Adds changelog and tweaks PTR penetration. --- .../modules/projectiles/projectile/bullets.dm | 2 +- html/changelogs/HarpyEagle-armourpen.yml | 34 +++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 html/changelogs/HarpyEagle-armourpen.yml diff --git a/code/modules/projectiles/projectile/bullets.dm b/code/modules/projectiles/projectile/bullets.dm index 292fd44034..cc18d93d87 100644 --- a/code/modules/projectiles/projectile/bullets.dm +++ b/code/modules/projectiles/projectile/bullets.dm @@ -155,7 +155,7 @@ stun = 3 weaken = 3 penetrating = 5 - armor_penetration = 50 + armor_penetration = 80 hitscan = 1 //so the PTR isn't useless as a sniper weapon /* Miscellaneous */ diff --git a/html/changelogs/HarpyEagle-armourpen.yml b/html/changelogs/HarpyEagle-armourpen.yml new file mode 100644 index 0000000000..28599d484f --- /dev/null +++ b/html/changelogs/HarpyEagle-armourpen.yml @@ -0,0 +1,34 @@ +################################ +# Example Changelog File +# +# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb. +# +# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.) +# When it is, any changes listed below will disappear. +# +# Valid Prefixes: +# bugfix +# wip (For works in progress) +# tweak +# soundadd +# sounddel +# rscadd (general adding of nice things) +# rscdel (general deleting of nice things) +# imageadd +# imagedel +# maptweak +# spellcheck (typo fixes) +# experiment +################################# + +# Your name. +author: HarpyEagle + +# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again. +delete-after: True + +changes: + - rscadd: "Adds armour penetration mechanic for projectiles and melee weapons." + - rscadd: "Laser carbines, LWAP, and shotgun now have a small amount of armour penetration, ballistic rifles (not SMGs) have moderate amounts, laser cannon has high armour penetration, and the PTR mostly ignores body armour." + - tweak: "Shotgun slugs and Z8/STS damage has been lowered slightly to accomodate for their higher penetration. In general ballistics deal less damage but have higher penetration than comparable laser weapons. Notable exception: X-Ray lasers have had their damage lowered slightly but gain very high armour penetration." + - rscadd: "Energy swords now have very high armour penetration. Ninja blades do less damage but ignore armour completely." From c1a0661ebae5463c5d4f24537d11bb4e7a3473d1 Mon Sep 17 00:00:00 2001 From: Kelenius Date: Fri, 21 Aug 2015 16:19:09 +0300 Subject: [PATCH 20/21] Accidentally commited before saving the file. --- code/__defines/items_clothing.dm | 1 - 1 file changed, 1 deletion(-) diff --git a/code/__defines/items_clothing.dm b/code/__defines/items_clothing.dm index 658e0d7bb2..aa32b0016e 100644 --- a/code/__defines/items_clothing.dm +++ b/code/__defines/items_clothing.dm @@ -39,7 +39,6 @@ #define NOSLIP 0x8 // Prevents from slipping on wet floors, in space, etc. #define BLOCK_GAS_SMOKE_EFFECT 0x10 // Blocks the effect that chemical clouds would have on a mob -- glasses, mask and helmets ONLY! (NOTE: flag shared with ONESIZEFITSALL) #define FLEXIBLEMATERIAL 0x20 // At the moment, masks with this flag will not prevent eating even if they are covering your face. ->>>>>>> dev // Flags for pass_flags. #define PASSTABLE 0x1 From 545e465dfc0b461cacf4a2bac77b624532ea5bf9 Mon Sep 17 00:00:00 2001 From: Zuhayr Date: Sat, 22 Aug 2015 02:00:08 +0930 Subject: [PATCH 21/21] Added paper shredders from Minijar. --- baystation12.dme | 1 + code/modules/paperwork/papershredder.dm | 139 ++++++++++++++++++++++++ icons/obj/bureaucracy.dmi | Bin 13803 -> 14870 bytes sound/items/pshred.ogg | Bin 0 -> 57059 bytes 4 files changed, 140 insertions(+) create mode 100644 code/modules/paperwork/papershredder.dm create mode 100644 sound/items/pshred.ogg diff --git a/baystation12.dme b/baystation12.dme index 803c6cb0e5..4643c895da 100644 --- a/baystation12.dme +++ b/baystation12.dme @@ -1427,6 +1427,7 @@ #include "code\modules\paperwork\paper.dm" #include "code\modules\paperwork\paper_bundle.dm" #include "code\modules\paperwork\paperbin.dm" +#include "code\modules\paperwork\papershredder.dm" #include "code\modules\paperwork\pen.dm" #include "code\modules\paperwork\photocopier.dm" #include "code\modules\paperwork\photography.dm" diff --git a/code/modules/paperwork/papershredder.dm b/code/modules/paperwork/papershredder.dm new file mode 100644 index 0000000000..37cfdaa86b --- /dev/null +++ b/code/modules/paperwork/papershredder.dm @@ -0,0 +1,139 @@ +/obj/machinery/papershredder + name = "paper shredder" + desc = "For those documents you don't want seen." + icon = 'icons/obj/bureaucracy.dmi' + icon_state = "papershredder0" + density = 1 + anchored = 1 + var/max_paper = 10 + var/paperamount = 0 + var/list/shred_amounts = list( + /obj/item/weapon/photo = 1, + /obj/item/weapon/shreddedp = 1, + /obj/item/weapon/paper = 1, + /obj/item/weapon/newspaper = 3, + /obj/item/weapon/card/id = 3, + /obj/item/weapon/paper_bundle = 3, + ) + +/obj/machinery/papershredder/attackby(var/obj/item/W, var/mob/user) + + if(istype(W, /obj/item/weapon/storage)) + empty_bin(user, W) + return + else + var/paper_result + for(var/shred_type in shred_amounts) + if(istype(W, shred_type)) + paper_result = shred_amounts[shred_type] + if(paper_result) + if(paperamount == max_paper) + user << "\The [src] is full; please empty it before you continue." + return + paperamount += paper_result + user.drop_from_inventory(W) + qdel(W) + playsound(src.loc, 'sound/items/pshred.ogg', 75, 1) + if(paperamount > max_paper) + user <<"\The [src] was too full, and shredded paper goes everywhere!" + for(var/i=(paperamount-max_paper);i>0;i--) + var/obj/item/weapon/shreddedp/SP = get_shredded_paper() + SP.loc = get_turf(src) + SP.throw_at(get_edge_target_turf(src,pick(alldirs)),1,5) + paperamount = max_paper + update_icon() + return + return ..() + +/obj/machinery/papershredder/verb/empty_contents() + set name = "Empty bin" + set category = "Object" + set src in range(1) + + if(usr.stat || usr.restrained() || usr.weakened || usr.paralysis || usr.lying || usr.stunned) + return + + if(!paperamount) + usr << "\The [src] is empty." + return + + empty_bin(usr) + +/obj/machinery/papershredder/proc/empty_bin(var/mob/living/user, var/obj/item/weapon/storage/empty_into) + + // Sanity. + if(empty_into && !istype(empty_into)) + empty_into = null + + if(empty_into && empty_into.contents.len >= empty_into.storage_slots) + user << "\The [empty_into] is full." + return + + while(paperamount) + var/obj/item/weapon/shreddedp/SP = get_shredded_paper() + if(!SP) break + if(empty_into) + empty_into.handle_item_insertion(SP) + if(empty_into.contents.len >= empty_into.storage_slots) + break + if(empty_into) + if(paperamount) + user << "You fill \the [empty_into] with as much shredded paper as it will carry." + else + user << "You empty \the [src] into \the [empty_into]." + + else + user << "You empty \the [src]." + update_icon() + +/obj/machinery/papershredder/proc/get_shredded_paper() + if(!paperamount) + return + paperamount-- + return PoolOrNew(/obj/item/weapon/shreddedp, get_turf(src)) + +/obj/machinery/papershredder/update_icon() + icon_state = "papershredder[max(0,min(5,Floor(paperamount/2)))]" + +/obj/item/weapon/shreddedp/attackby(var/obj/item/W as obj, var/mob/user) + if(istype(W, /obj/item/weapon/flame/lighter)) + burnpaper(W, user) + else + ..() + +/obj/item/weapon/shreddedp/proc/burnpaper(var/obj/item/weapon/flame/lighter/P, var/mob/user) + if(user.restrained()) + return + if(!P.lit) + user << "\The [P] is not lit." + return + user.visible_message("\The [user] holds \the [P] up to \the [src]. It looks like \he's trying to burn it!", \ + "You hold \the [P] up to \the [src], burning it slowly.") + if(!do_after(user,20)) + user << "You must hold \the [P] steady to burn \the [src]." + return + user.visible_message("\The [user] burns right through \the [src], turning it to ash. It flutters through the air before settling on the floor in a heap.", \ + "You burn right through \the [src], turning it to ash. It flutters through the air before settling on the floor in a heap.") + FireBurn() + +/obj/item/weapon/shreddedp/proc/FireBurn() + var/mob/living/M = loc + if(istype(M)) + M.drop_from_inventory(src) + PoolOrNew(/obj/effect/decal/cleanable/ash,get_turf(src)) + qdel(src) + +/obj/item/weapon/shreddedp + name = "shredded paper" + icon = 'icons/obj/bureaucracy.dmi' + icon_state = "shredp" + throwforce = 0 + w_class = 1 + throw_range = 3 + throw_speed = 1 + +/obj/item/weapon/shreddedp/New() + ..() + pixel_x = rand(-5,5) + pixel_y = rand(-5,5) + if(prob(65)) color = pick("#BABABA","#7F7F7F") diff --git a/icons/obj/bureaucracy.dmi b/icons/obj/bureaucracy.dmi index a2a99f01f8d03a5a98f90351ca3befad023404c6..cc54c091e1b0d9bb3992b10c2353e06cb2cb6368 100644 GIT binary patch literal 14870 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 literal 13803 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 BR__1+ diff --git a/sound/items/pshred.ogg b/sound/items/pshred.ogg new file mode 100644 index 0000000000000000000000000000000000000000..a722f3006899297efbcc597d99f5e365d9699264 GIT binary patch literal 57059 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