diff --git a/code/__DEFINES/move_force.dm b/code/__DEFINES/move_force.dm new file mode 100644 index 00000000000..750821bd898 --- /dev/null +++ b/code/__DEFINES/move_force.dm @@ -0,0 +1,19 @@ +//Defaults +#define MOVE_FORCE_DEFAULT 1000 +#define MOVE_RESIST_DEFAULT 1000 +#define PULL_FORCE_DEFAULT 1000 + + //Factors/modifiers +#define MOVE_FORCE_PULL_RATIO 1 //Same move force to pull objects +#define MOVE_FORCE_PUSH_RATIO 1 //Same move force to normally push +#define MOVE_FORCE_FORCEPUSH_RATIO 2 //2x move force to forcefully push +#define MOVE_FORCE_CRUSH_RATIO 3 //3x move force to do things like crush objects +#define MOVE_FORCE_THROW_RATIO 1 //Same force throw as resist to throw objects +#define MOVE_FORCE_OVERPOWERING MOVE_FORCE_DEFAULT * MOVE_FORCE_CRUSH_RATIO * 10 +#define MOVE_FORCE_EXTREMELY_STRONG MOVE_FORCE_DEFAULT * MOVE_FORCE_CRUSH_RATIO * 3 +#define MOVE_FORCE_VERY_STRONG (MOVE_FORCE_DEFAULT * MOVE_FORCE_CRUSH_RATIO) - 1 +#define MOVE_FORCE_STRONG MOVE_FORCE_DEFAULT * 2 +#define MOVE_FORCE_NORMAL MOVE_FORCE_DEFAULT +#define MOVE_FORCE_WEAK MOVE_FORCE_DEFAULT / 2 +#define MOVE_FORCE_VERY_WEAK (MOVE_FORCE_DEFAULT / MOVE_FORCE_CRUSH_RATIO) + 1 +#define MOVE_FORCE_EXTREMELY_WEAK MOVE_FORCE_DEFAULT / (MOVE_FORCE_CRUSH_RATIO * 3) \ No newline at end of file diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm index 6ce486bdc05..44522f89e8e 100644 --- a/code/__HELPERS/unsorted.dm +++ b/code/__HELPERS/unsorted.dm @@ -1495,7 +1495,7 @@ var/mob/dview/dview_mob = new invisibility = 101 density = 0 - anchored = 1 + move_resist = INFINITY simulated = 0 see_in_dark = 1e6 diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm index 8ce2177751c..7b700ad4c6d 100644 --- a/code/_onclick/click.dm +++ b/code/_onclick/click.dm @@ -285,12 +285,12 @@ /mob/proc/CtrlClickOn(var/atom/A) A.CtrlClick(src) return -/atom/proc/CtrlClick(var/mob/user) - return -/atom/movable/CtrlClick(var/mob/user) - if(Adjacent(user)) - user.start_pulling(src) +/atom/proc/CtrlClick(mob/user) + SEND_SIGNAL(src, COMSIG_CLICK_CTRL, user) + var/mob/living/ML = user + if(istype(ML)) + ML.pulled(src) /* Alt click diff --git a/code/controllers/subsystem/throwing.dm b/code/controllers/subsystem/throwing.dm index b74e3a1a6c9..fb32991b42b 100644 --- a/code/controllers/subsystem/throwing.dm +++ b/code/controllers/subsystem/throwing.dm @@ -53,6 +53,7 @@ SUBSYSTEM_DEF(throwing) var/dist_y var/dx var/dy + var/force = MOVE_FORCE_DEFAULT var/pure_diagonal var/diagonal_error var/datum/callback/callback diff --git a/code/datums/spell.dm b/code/datums/spell.dm index 89ead867c24..cc29da42a43 100644 --- a/code/datums/spell.dm +++ b/code/datums/spell.dm @@ -144,7 +144,7 @@ var/list/spells = typesof(/obj/effect/proc_holder/spell) //needed for the badmin if(!istype(H.wear_suit, /obj/item/clothing/suit/wizrobe) && !istype(H.wear_suit, /obj/item/clothing/suit/space/hardsuit/wizard) && !istype(H.wear_suit, /obj/item/clothing/suit/space/eva/plasmaman/wizard)) to_chat(user, "I don't feel strong enough without my robe.") return 0 - if(!istype(H.shoes, /obj/item/clothing/shoes/sandal)) + if(!istype(H.shoes, /obj/item/clothing/shoes/sandal) && !istype(H.shoes, /obj/item/clothing/shoes/magboots/wizard)) to_chat(user, "I don't feel strong enough without my sandals.") return 0 if(!istype(H.head, /obj/item/clothing/head/wizard) && !istype(H.head, /obj/item/clothing/head/helmet/space/hardsuit/wizard) && !istype(H.head, /obj/item/clothing/head/helmet/space/eva/plasmaman/wizard)) @@ -459,11 +459,11 @@ var/list/spells = typesof(/obj/effect/proc_holder/spell) //needed for the badmin var/clothcheck = locate(/obj/effect/proc_holder/spell/noclothes) in user.mob_spell_list var/clothcheck2 = user.mind && (locate(/obj/effect/proc_holder/spell/noclothes) in user.mind.spell_list) if(clothes_req && !clothcheck && !clothcheck2) //clothes check - if(!istype(H.wear_suit, /obj/item/clothing/suit/wizrobe) && !istype(H.wear_suit, /obj/item/clothing/suit/space/hardsuit/wizard)) + if(!istype(H.wear_suit, /obj/item/clothing/suit/wizrobe) && !istype(H.wear_suit, /obj/item/clothing/suit/space/hardsuit/wizard) && !istype(H.wear_suit, /obj/item/clothing/suit/space/eva/plasmaman/wizard)) return 0 - if(!istype(H.shoes, /obj/item/clothing/shoes/sandal)) + if(!istype(H.shoes, /obj/item/clothing/shoes/sandal) && !istype(H.shoes, /obj/item/clothing/shoes/magboots/wizard)) return 0 - if(!istype(H.head, /obj/item/clothing/head/wizard) && !istype(H.head, /obj/item/clothing/head/helmet/space/hardsuit/wizard)) + if(!istype(H.head, /obj/item/clothing/head/wizard) && !istype(H.head, /obj/item/clothing/head/helmet/space/hardsuit/wizard) && !istype(H.head, /obj/item/clothing/head/helmet/space/eva/plasmaman/wizard)) return 0 else if(clothes_req || human_req) diff --git a/code/datums/uplink_item.dm b/code/datums/uplink_item.dm index e9c6ed12c8e..c91f3417d0d 100644 --- a/code/datums/uplink_item.dm +++ b/code/datums/uplink_item.dm @@ -531,15 +531,6 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) item = /obj/item/batterer cost = 5 -/datum/uplink_item/dangerous/manhacks - name = "Viscerator Delivery Grenade" - desc = "A unique grenade that deploys a swarm of viscerators upon activation, which will chase down and shred any non-operatives in the area." - reference = "VDG" - item = /obj/item/grenade/spawnergrenade/manhacks - cost = 6 - gamemodes = list(/datum/game_mode/nuclear) - surplus = 35 - /datum/uplink_item/ammo/bioterror name = "Box of Bioterror Syringes" desc = "A box full of preloaded syringes, containing various chemicals that seize up the victim's motor and broca system , making it impossible for them to move or speak while in their system." @@ -548,46 +539,6 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) cost = 5 gamemodes = list(/datum/game_mode/nuclear) -/datum/uplink_item/dangerous/saringrenades - name = "Sarin Gas Grenades" - desc = "A box of four (4) grenades filled with Sarin, a deadly neurotoxin. Use extreme caution when handling and be sure to vacate the premise after using; ensure communication is maintained with team to avoid accidental gassings." - reference = "TGG" - item = /obj/item/storage/box/syndie_kit/sarin - cost = 12 - gamemodes = list(/datum/game_mode/nuclear) - surplus = 0 - -/datum/uplink_item/dangerous/atmosgrenades - name = "Atmos Grenades" - desc = "A box of two (2) grenades that wreak havoc with the atmosphere of the target area. Capable of engulfing a large area in lit plasma, or N2O. Deploy with extreme caution!" - reference = "AGG" - item = /obj/item/storage/box/syndie_kit/atmosgasgrenades - cost = 11 - surplus = 0 - -/datum/uplink_item/dangerous/grenadier - name = "Grenadier's belt" - desc = "A belt containing 25 lethally dangerous and destructive grenades." - item = /obj/item/storage/belt/grenade/full - cost = 30 - surplus = 0 - gamemodes = list(/datum/game_mode/nuclear) - -/datum/uplink_item/dangerous/emp - name = "EMP Grenades and Implanter Kit" - desc = "A box that contains two EMP grenades and an EMP implant. Useful to disrupt communication, \ - security's energy weapons, and silicon lifeforms when you're in a tight spot." - reference = "EMPK" - item = /obj/item/storage/box/syndie_kit/emp - cost = 2 - -/datum/uplink_item/dangerous/syndicate_minibomb - name = "Syndicate Minibomb" - desc = "The minibomb is a grenade with a five-second fuse." - reference = "SMB" - item = /obj/item/grenade/syndieminibomb - cost = 6 - /datum/uplink_item/dangerous/gygax name = "Gygax Exosuit" desc = "A lightweight exosuit, painted in a dark scheme. Its speed and equipment selection make it excellent for hit-and-run style attacks. \ @@ -891,13 +842,6 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) cost = 4 gamemodes = list(/datum/game_mode/nuclear) -/datum/uplink_item/stealthy_weapons/detomatix - name = "Detomatix PDA Cartridge" - desc = "When inserted into a personal digital assistant, this cartridge gives you five opportunities to detonate PDAs of crewmembers who have their message feature enabled. The concussive effect from the explosion will knock the recipient out for a short period, and deafen them for longer. It has a chance to detonate your PDA." - reference = "DEPC" - item = /obj/item/cartridge/syndicate - cost = 6 - /datum/uplink_item/stealthy_weapons/silencer name = "Universal Suppressor" desc = "Fitted for use on any small caliber weapon with a threaded barrel, this suppressor will silence the shots of the weapon for increased stealth and superior ambushing capability." @@ -906,14 +850,6 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) cost = 1 surplus = 10 -/datum/uplink_item/stealthy_weapons/pizza_bomb - name = "Pizza Bomb" - desc = "A pizza box with a bomb taped inside of it. The timer needs to be set by opening the box; afterwards, opening the box again will trigger the detonation." - reference = "PB" - item = /obj/item/pizza_bomb - cost = 5 - surplus = 8 - /datum/uplink_item/stealthy_weapons/dehy_carp name = "Dehydrated Space Carp" desc = "Just add water to make your very own hostile to everything space carp. It looks just like a plushie. The first person to squeeze it will be registered as its owner, who it will not attack. If no owner is registered, it'll just attack everyone." @@ -928,13 +864,105 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) item = /obj/item/clothing/glasses/hud/security/chameleon cost = 2 -/datum/uplink_item/stealthy_weapons/chameleonflag +// GRENADES AND EXPLOSIVES + +/datum/uplink_item/explosives + category = "Grenades and Explosives" + +/datum/uplink_item/explosives/plastic_explosives + name = "Composition C-4" + desc = "C-4 is plastic explosive of the common variety Composition C. You can use it to breach walls or connect an assembly to its wiring to make it remotely detonable. It has a modifiable timer with a minimum setting of 10 seconds." + reference = "C4" + item = /obj/item/grenade/plastic/c4 + cost = 1 + +/datum/uplink_item/explosives/breaching_charge + name = "Composition X-4" + desc = "X-4 is a shaped charge designed to be safe to the user while causing maximum damage to the occupants of the room beach breached. It has a modifiable timer with a minimum setting of 10 seconds." + reference = "X4" + item = /obj/item/grenade/plastic/x4 + cost = 2 + gamemodes = list(/datum/game_mode/nuclear) + +/datum/uplink_item/explosives/syndicate_bomb + name = "Syndicate Bomb" + desc = "The Syndicate Bomb has an adjustable timer with a minimum setting of 60 seconds. Ordering the bomb sends you a small beacon, which will teleport the explosive to your location when you activate it. \ + You can wrench the bomb down to prevent removal. The crew may attempt to defuse the bomb." + reference = "SB" + item = /obj/item/radio/beacon/syndicate/bomb + cost = 11 + +/datum/uplink_item/explosives/syndicate_minibomb + name = "Syndicate Minibomb" + desc = "The minibomb is a grenade with a five-second fuse." + reference = "SMB" + item = /obj/item/grenade/syndieminibomb + cost = 6 + +/datum/uplink_item/explosives/detomatix + name = "Detomatix PDA Cartridge" + desc = "When inserted into a personal digital assistant, this cartridge gives you five opportunities to detonate PDAs of crewmembers who have their message feature enabled. The concussive effect from the explosion will knock the recipient out for a short period, and deafen them for longer. It has a chance to detonate your PDA." + reference = "DEPC" + item = /obj/item/cartridge/syndicate + cost = 6 + +/datum/uplink_item/explosives/pizza_bomb + name = "Pizza Bomb" + desc = "A pizza box with a bomb taped inside of it. The timer needs to be set by opening the box; afterwards, opening the box again will trigger the detonation." + reference = "PB" + item = /obj/item/pizza_bomb + cost = 5 + surplus = 8 + +/datum/uplink_item/explosives/chameleonflag name = "Chameleon Flag" desc = "A flag that can be disguised as any other known flag. There is a heat sensitive bomb loaded into the pole that will be detonated if the flag is lit on fire." reference = "CHFLAG" item = /obj/item/flag/chameleon cost = 7 +/datum/uplink_item/explosives/grenadier + name = "Grenadier's belt" + desc = "A belt containing 25 lethally dangerous and destructive grenades." + item = /obj/item/storage/belt/grenade/full + cost = 30 + surplus = 0 + gamemodes = list(/datum/game_mode/nuclear) + +/datum/uplink_item/explosives/manhacks + name = "Viscerator Delivery Grenade" + desc = "A unique grenade that deploys a swarm of viscerators upon activation, which will chase down and shred any non-operatives in the area." + reference = "VDG" + item = /obj/item/grenade/spawnergrenade/manhacks + cost = 6 + gamemodes = list(/datum/game_mode/nuclear) + surplus = 35 + +/datum/uplink_item/explosives/saringrenades + name = "Sarin Gas Grenades" + desc = "A box of four (4) grenades filled with Sarin, a deadly neurotoxin. Use extreme caution when handling and be sure to vacate the premise after using; ensure communication is maintained with team to avoid accidental gassings." + reference = "TGG" + item = /obj/item/storage/box/syndie_kit/sarin + cost = 12 + gamemodes = list(/datum/game_mode/nuclear) + surplus = 0 + +/datum/uplink_item/explosives/atmosgrenades + name = "Atmos Grenades" + desc = "A box of two (2) grenades that wreak havoc with the atmosphere of the target area. Capable of engulfing a large area in lit plasma, or N2O. Deploy with extreme caution!" + reference = "AGG" + item = /obj/item/storage/box/syndie_kit/atmosgasgrenades + cost = 11 + surplus = 0 + +/datum/uplink_item/explosives/emp + name = "EMP Grenades and Implanter Kit" + desc = "A box that contains two EMP grenades and an EMP implant. Useful to disrupt communication, \ + security's energy weapons, and silicon lifeforms when you're in a tight spot." + reference = "EMPK" + item = /obj/item/storage/box/syndie_kit/emp + cost = 2 + // STEALTHY TOOLS /datum/uplink_item/stealthy_tools @@ -1227,21 +1255,6 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) excludefrom = list() gamemodes = list(/datum/game_mode/nuclear) -/datum/uplink_item/device_tools/plastic_explosives - name = "Composition C-4" - desc = "C-4 is plastic explosive of the common variety Composition C. You can use it to breach walls or connect an assembly to its wiring to make it remotely detonable. It has a modifiable timer with a minimum setting of 10 seconds." - reference = "C4" - item = /obj/item/grenade/plastic/c4 - cost = 1 - -/datum/uplink_item/device_tools/breaching_charge - name = "Composition X-4" - desc = "X-4 is a shaped charge designed to be safe to the user while causing maximum damage to the occupants of the room beach breached. It has a modifiable timer with a minimum setting of 10 seconds." - reference = "X4" - item = /obj/item/grenade/plastic/x4 - cost = 2 - gamemodes = list(/datum/game_mode/nuclear) - /datum/uplink_item/device_tools/powersink name = "Power Sink" desc = "When screwed to wiring attached to an electric grid, then activated, this large device places excessive load on the grid, causing a stationwide blackout. The sink cannot be carried because of its excessive size. Ordering this sends you a small beacon that will teleport the power sink to your location on activation." @@ -1269,14 +1282,6 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) excludefrom = list() gamemodes = list(/datum/game_mode/nuclear) -/datum/uplink_item/device_tools/syndicate_bomb - name = "Syndicate Bomb" - desc = "The Syndicate Bomb has an adjustable timer with a minimum setting of 60 seconds. Ordering the bomb sends you a small beacon, which will teleport the explosive to your location when you activate it. \ - You can wrench the bomb down to prevent removal. The crew may attempt to defuse the bomb." - reference = "SB" - item = /obj/item/radio/beacon/syndicate/bomb - cost = 11 - /datum/uplink_item/device_tools/syndicate_detonator name = "Syndicate Detonator" desc = "The Syndicate Detonator is a companion device to the Syndicate Bomb. Simply press the included button and an encrypted radio frequency will instruct all live syndicate bombs to detonate. \ diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 30b901875b3..58197cbadf1 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -86,7 +86,7 @@ if(opacity && isturf(loc)) var/turf/T = loc T.has_opaque_atom = TRUE // No need to recalculate it in this case, it's guranteed to be on afterwards anyways. - + if(loc) loc.InitializedOn(src) // Used for poolcontroller / pool to improve performance greatly. However it also open up path to other usage of observer pattern on turfs. @@ -324,7 +324,7 @@ // Atoms that return TRUE prevent RPDs placing any kind of pipes on their turf. return FALSE -/atom/proc/hitby(atom/movable/AM, skipcatch, hitpush, blocked) +/atom/proc/hitby(atom/movable/AM, skipcatch, hitpush, blocked, datum/thrownthing/throwingdatum) if(density && !has_gravity(AM)) //thrown stuff bounces off dense stuff in no grav, unless the thrown stuff ends up inside what it hit(embedding, bola, etc...). addtimer(CALLBACK(src, .proc/hitby_react, AM), 2) diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index a5d2366c46c..46b86a05ecc 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -3,6 +3,9 @@ appearance_flags = TILE_BOUND var/last_move = null var/anchored = 0 + var/move_resist = MOVE_RESIST_DEFAULT + var/move_force = MOVE_FORCE_DEFAULT + var/pull_force = PULL_FORCE_DEFAULT // var/elevation = 2 - not used anywhere var/move_speed = 10 var/l_move_time = 1 @@ -13,6 +16,8 @@ var/no_spin_thrown = 0 var/moved_recently = 0 var/mob/pulledby = null + var/atom/movable/pulling + var/canmove = 1 var/inertia_dir = 0 var/atom/inertia_last_loc @@ -55,6 +60,70 @@ pulledby = null return ..() +/atom/movable/proc/start_pulling(atom/movable/AM, state, force = move_force, supress_message = FALSE) + if(QDELETED(AM)) + return FALSE + if(!(AM.can_be_pulled(src, state, force))) + return FALSE + + // If we're pulling something then drop what we're currently pulling and pull this instead. + if(pulling) + if(state == 0) + stop_pulling() + return FALSE + // Are we trying to pull something we are already pulling? Then enter grab cycle and end. + if(AM == pulling) + if(isliving(AM)) + var/mob/living/AMob = AM + AMob.grabbedby(src) + return TRUE + stop_pulling() + if(AM.pulledby) + add_attack_logs(AM, AM.pulledby, "pulled from", ATKLOG_ALMOSTALL) + AM.pulledby.stop_pulling() //an object can't be pulled by two mobs at once. + pulling = AM + AM.pulledby = src + if(ismob(AM)) + var/mob/M = AM + add_attack_logs(src, M, "passively grabbed", ATKLOG_ALMOSTALL) + if(!supress_message) + visible_message("[src] has grabbed [M] passively!") + return TRUE + +/atom/movable/proc/stop_pulling() + if(pulling) + pulling.pulledby = null + var/mob/living/ex_pulled = pulling + pulling = null + if(isliving(ex_pulled)) + var/mob/living/L = ex_pulled + L.update_canmove()// mob gets up if it was lyng down in a chokehold + +/atom/movable/proc/check_pulling() + if(pulling) + var/atom/movable/pullee = pulling + if(pullee && get_dist(src, pullee) > 1) + stop_pulling() + return + if(!isturf(loc)) + stop_pulling() + return + if(pullee && !isturf(pullee.loc) && pullee.loc != loc) //to be removed once all code that changes an object's loc uses forceMove(). + log_game("DEBUG:[src]'s pull on [pullee] wasn't broken despite [pullee] being in [pullee.loc]. Pull stopped manually.") + stop_pulling() + return + if(pulling.anchored) + stop_pulling() + return + +/atom/movable/proc/can_be_pulled(user, grab_state, force) + if(src == user || !isturf(loc)) + return FALSE + if(anchored || throwing) + return FALSE + if(force < (move_resist * MOVE_FORCE_PULL_RATIO)) + return FALSE + return TRUE // Used in shuttle movement and AI eye stuff. // Primarily used to notify objects being moved by a shuttle/bluespace fuckup. /atom/movable/proc/setLoc(var/T, var/teleported=0) @@ -218,12 +287,12 @@ if(!QDELETED(hit_atom)) return hit_atom.hitby(src) -/atom/movable/hitby(atom/movable/AM, skipcatch, hitpush = 1, blocked) - if(!anchored && hitpush) +/atom/movable/hitby(atom/movable/AM, skipcatch, hitpush = 1, blocked, datum/thrownthing/throwingdatum) + if(!anchored && hitpush && (!throwingdatum || (throwingdatum.force >= (move_resist * MOVE_FORCE_PUSH_RATIO)))) step(src, AM.dir) ..() -/atom/movable/proc/throw_at(atom/target, range, speed, mob/thrower, spin = TRUE, diagonals_first = FALSE, var/datum/callback/callback) +/atom/movable/proc/throw_at(atom/target, range, speed, mob/thrower, spin = TRUE, diagonals_first = FALSE, datum/callback/callback, force = INFINITY) if(!target || (flags & NODROP) || speed <= 0) return 0 @@ -330,6 +399,22 @@ return 0 return 1 +/atom/movable/proc/force_pushed(atom/movable/pusher, force = MOVE_FORCE_DEFAULT, direction) + return FALSE + +/atom/movable/proc/force_push(atom/movable/AM, force = move_force, direction, silent = FALSE) + . = AM.force_pushed(src, force, direction) + if(!silent && .) + visible_message("[src] forcefully pushes against [AM]!", "You forcefully push against [AM]!") + +/atom/movable/proc/move_crush(atom/movable/AM, force = move_force, direction, silent = FALSE) + . = AM.move_crushed(src, force, direction) + if(!silent && .) + visible_message("[src] crushes past [AM]!", "You crush [AM]!") + +/atom/movable/proc/move_crushed(atom/movable/pusher, force = MOVE_FORCE_DEFAULT, direction) + return FALSE + /atom/movable/CanPass(atom/movable/mover, turf/target, height=1.5) if(buckled_mob == mover) return 1 diff --git a/code/game/gamemodes/miniantags/bot_swarm/swarmer.dm b/code/game/gamemodes/miniantags/bot_swarm/swarmer.dm index 9a8ead8b289..82a018d9902 100644 --- a/code/game/gamemodes/miniantags/bot_swarm/swarmer.dm +++ b/code/game/gamemodes/miniantags/bot_swarm/swarmer.dm @@ -311,7 +311,7 @@ to_chat(S, "Destroying this machine while it is occupied would result in biological and sentient resources to be harmed. Aborting.") return ..() - + /mob/living/swarmer_act(mob/living/simple_animal/hostile/swarmer/S) S.DisperseTarget(src) diff --git a/code/game/gamemodes/miniantags/guardian/guardian.dm b/code/game/gamemodes/miniantags/guardian/guardian.dm index d4f57e7b7f4..f95a22402e9 100644 --- a/code/game/gamemodes/miniantags/guardian/guardian.dm +++ b/code/game/gamemodes/miniantags/guardian/guardian.dm @@ -161,8 +161,12 @@ buckled = null cooldown = world.time + 30 -/mob/living/simple_animal/hostile/guardian/proc/Communicate() - var/input = stripped_input(src, "Please enter a message to tell your summoner.", "Guardian", "") +/mob/living/simple_animal/hostile/guardian/proc/Communicate(message) + var/input + if(!message) + input = stripped_input(src, "Please enter a message to tell your summoner.", "Guardian", "") + else + input = message if(!input) return for(var/mob/M in GLOB.mob_list) @@ -173,6 +177,13 @@ to_chat(M, "Guardian Communication from [src] ([ghost_follow_link(src, ghost=M)]): [input]") to_chat(src, "[src]: [input]") +//override set to true if message should be passed through instead of going to host communication +/mob/living/simple_animal/hostile/guardian/say(message, override = FALSE) + if(adminseal || override)//if it's an admin-spawned guardian without a host it can still talk normally + return ..(message) + Communicate(message) + + /mob/living/simple_animal/hostile/guardian/proc/ToggleMode() to_chat(src, "You dont have another mode!") diff --git a/code/game/gamemodes/miniantags/guardian/types/standard.dm b/code/game/gamemodes/miniantags/guardian/types/standard.dm index 8dfc3d39796..1380c4a2e95 100644 --- a/code/game/gamemodes/miniantags/guardian/types/standard.dm +++ b/code/game/gamemodes/miniantags/guardian/types/standard.dm @@ -24,7 +24,7 @@ if(length(battlecry) > 11)//no more then 11 letters in a battle cry. visible_message("[src] punches [target]!") else - say("[battlecry][battlecry][battlecry][battlecry][battlecry]") + say("[battlecry][battlecry][battlecry][battlecry][battlecry]", TRUE) playsound(loc, attack_sound, 50, 1, 1) playsound(loc, attack_sound, 50, 1, 1) playsound(loc, attack_sound, 50, 1, 1) diff --git a/code/game/gamemodes/miniantags/revenant/revenant.dm b/code/game/gamemodes/miniantags/revenant/revenant.dm index fe7d02488d6..45402fe5fc9 100644 --- a/code/game/gamemodes/miniantags/revenant/revenant.dm +++ b/code/game/gamemodes/miniantags/revenant/revenant.dm @@ -32,7 +32,7 @@ wander = 0 density = 0 flying = 1 - anchored = 1 + move_resist = INFINITY mob_size = MOB_SIZE_TINY pass_flags = PASSTABLE | PASSGRILLE | PASSMOB speed = 1 @@ -130,7 +130,7 @@ else message_admins("Revenant was created but has no mind. Put a ghost inside, or a poll will be made in one minute.") addtimer(CALLBACK(src, .proc/setupOrDelete), 1 MINUTES) - + /mob/living/simple_animal/revenant/proc/setupOrDelete() if(mind) giveObjectivesandGoals() diff --git a/code/game/gamemodes/miniantags/slaughter/bloodcrawl.dm b/code/game/gamemodes/miniantags/slaughter/bloodcrawl.dm index 51f3d277598..d769c2f6807 100644 --- a/code/game/gamemodes/miniantags/slaughter/bloodcrawl.dm +++ b/code/game/gamemodes/miniantags/slaughter/bloodcrawl.dm @@ -154,7 +154,6 @@ name = "odd blood" icon = 'icons/effects/effects.dmi' icon_state = "nothing" - var/canmove = 1 density = 0 anchored = 1 invisibility = 60 diff --git a/code/game/gamemodes/nuclear/nuclear.dm b/code/game/gamemodes/nuclear/nuclear.dm index cc96f206aba..9690a81fb68 100644 --- a/code/game/gamemodes/nuclear/nuclear.dm +++ b/code/game/gamemodes/nuclear/nuclear.dm @@ -242,9 +242,8 @@ proc/issyndicate(mob/living/M as mob) synd_mob.equip_or_collect(new /obj/item/clothing/gloves/combat(synd_mob), slot_gloves) synd_mob.equip_to_slot_or_del(new /obj/item/card/id/syndicate(synd_mob), slot_wear_id) synd_mob.equip_to_slot_or_del(new /obj/item/storage/backpack(synd_mob), slot_back) - synd_mob.equip_to_slot_or_del(new /obj/item/reagent_containers/food/pill/initropidril(synd_mob), slot_in_backpack) synd_mob.equip_to_slot_or_del(new /obj/item/gun/projectile/automatic/pistol(synd_mob), slot_belt) - synd_mob.equip_to_slot_or_del(new /obj/item/storage/box/engineer(synd_mob.back), slot_in_backpack) + synd_mob.equip_to_slot_or_del(new /obj/item/storage/box/survival_syndi(synd_mob.back), slot_in_backpack) var/obj/item/radio/uplink/U = new /obj/item/radio/uplink(synd_mob) U.hidden_uplink.uplink_owner="[synd_mob.key]" diff --git a/code/game/gamemodes/wizard/spellbook.dm b/code/game/gamemodes/wizard/spellbook.dm index 7b81518526a..0cc5fcf0ca5 100644 --- a/code/game/gamemodes/wizard/spellbook.dm +++ b/code/game/gamemodes/wizard/spellbook.dm @@ -353,7 +353,7 @@ /datum/spellbook_entry/item/armor name = "Mastercrafted Armor Set" - desc = "An artefact suit of armor that allows you to cast spells while providing more protection against attacks and the void of space." + desc = "An artefact suit of armor that allows you to cast spells while providing more protection against attacks and the void of space. Comes bundled with Boots of Gripping." item_path = /obj/item/clothing/suit/space/hardsuit/wizard log_name = "HS" category = "Defensive" @@ -361,7 +361,7 @@ /datum/spellbook_entry/item/armor/Buy(var/mob/living/carbon/human/user,var/obj/item/spellbook/book) . = ..() if(.) - new /obj/item/clothing/shoes/sandal(get_turf(user)) //In case they've lost them. + new /obj/item/clothing/shoes/magboots/wizard(get_turf(user)) new /obj/item/clothing/gloves/color/purple(get_turf(user))//To complete the outfit new /obj/item/clothing/head/helmet/space/hardsuit/wizard(get_turf(user)) diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm index 8d9b17ef7c2..902b0af771f 100644 --- a/code/game/machinery/doors/airlock.dm +++ b/code/game/machinery/doors/airlock.dm @@ -43,6 +43,7 @@ var/list/airlock_overlays = list() name = "airlock" icon = 'icons/obj/doors/airlocks/station/public.dmi' icon_state = "closed" + anchored = 1 max_integrity = 300 integrity_failure = 70 damage_deflection = AIRLOCK_DAMAGE_DEFLECTION_N diff --git a/code/game/machinery/magnet.dm b/code/game/machinery/magnet.dm index 6a11662fc33..3af76895428 100644 --- a/code/game/machinery/magnet.dm +++ b/code/game/machinery/magnet.dm @@ -22,7 +22,7 @@ var/code = 0 // frequency code, they should be different unless you have a group of magnets working together or something var/turf/center // the center of magnetic attraction var/on = 0 - var/pulling = 0 + var/magpulling = 0 // x, y modifiers to the center turf; (0, 0) is centered on the magnet, whereas (1, -1) is one tile right, one tile down var/center_x = 0 @@ -154,10 +154,10 @@ /obj/machinery/magnetic_module/proc/magnetic_process() // proc that actually does the pulling - if(pulling) return + if(magpulling) return while(on) - pulling = 1 + magpulling = 1 center = locate(x+center_x, y+center_y, z) if(center) for(var/obj/M in orange(magnetic_field, center)) @@ -171,7 +171,7 @@ use_power(electricity_level * 5) sleep(13 - electricity_level) - pulling = 0 + magpulling = 0 /obj/machinery/magnetic_controller name = "Magnetic Control Console" diff --git a/code/game/machinery/shieldgen.dm b/code/game/machinery/shieldgen.dm index b655635ba1a..de3088ae60d 100644 --- a/code/game/machinery/shieldgen.dm +++ b/code/game/machinery/shieldgen.dm @@ -154,6 +154,7 @@ active = 1 update_icon() + anchored = 1 for(var/turf/target_tile in range(2, src)) if(istype(target_tile,/turf/space) && !(locate(/obj/machinery/shield) in target_tile)) @@ -166,6 +167,7 @@ active = 0 update_icon() + anchored = 0 for(var/obj/machinery/shield/shield_tile in deployed_shields) qdel(shield_tile) diff --git a/code/game/machinery/vending.dm b/code/game/machinery/vending.dm index fcdd81a30e1..a2da0576261 100644 --- a/code/game/machinery/vending.dm +++ b/code/game/machinery/vending.dm @@ -1196,7 +1196,7 @@ /obj/item/clothing/head/cueball = 1,/obj/item/clothing/under/scratch = 1, /obj/item/clothing/under/victdress = 1, /obj/item/clothing/under/victdress/red = 1, /obj/item/clothing/suit/victcoat = 1, /obj/item/clothing/suit/victcoat/red = 1, /obj/item/clothing/under/victsuit = 1, /obj/item/clothing/under/victsuit/redblk = 1, /obj/item/clothing/under/victsuit/red = 1, /obj/item/clothing/suit/tailcoat = 1, - /obj/item/clothing/suit/draculacoat = 1) + /obj/item/clothing/suit/draculacoat = 1, /obj/item/clothing/head/zepelli = 1) contraband = list(/obj/item/clothing/suit/judgerobe = 1,/obj/item/clothing/head/powdered_wig = 1,/obj/item/gun/magic/wand = 1, /obj/item/clothing/mask/balaclava=1, /obj/item/clothing/mask/horsehead = 2) premium = list(/obj/item/clothing/suit/hgpirate = 1, /obj/item/clothing/head/hgpiratecap = 1, /obj/item/clothing/head/helmet/roman = 1, /obj/item/clothing/head/helmet/roman/legionaire = 1, /obj/item/clothing/under/roman = 1, /obj/item/clothing/shoes/roman = 1, /obj/item/shield/riot/roman = 1) refill_canister = /obj/item/vending_refill/autodrobe diff --git a/code/game/mecha/equipment/weapons/weapons.dm b/code/game/mecha/equipment/weapons/weapons.dm index f5fdecea3f6..64c5c18177c 100644 --- a/code/game/mecha/equipment/weapons/weapons.dm +++ b/code/game/mecha/equipment/weapons/weapons.dm @@ -346,7 +346,7 @@ if(heavy_missile) M.heavy_missile = 1 playsound(chassis, fire_sound, 50, 1) - M.throw_at(target, missile_range, missile_speed) + M.throw_at(target, missile_range, missile_speed, spin = FALSE) projectiles-- log_message("Fired from [name], targeting [target].") var/turf/T = get_turf(src) diff --git a/code/game/objects/effects/effects.dm b/code/game/objects/effects/effects.dm index 5836136401e..a08e7fac021 100644 --- a/code/game/objects/effects/effects.dm +++ b/code/game/objects/effects/effects.dm @@ -6,6 +6,7 @@ icon = 'icons/effects/effects.dmi' burn_state = LAVA_PROOF | FIRE_PROOF resistance_flags = INDESTRUCTIBLE + anchored = 1 can_be_hit = FALSE /obj/effect/take_damage(damage_amount, damage_type = BRUTE, damage_flag = 0, sound_effect = 1, attack_dir) diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index e3812286714..cd50f079b0c 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -532,10 +532,10 @@ var/global/image/fire_overlay = image("icon" = 'icons/goonstation/effects/fire.d itempush = 0 // too light to push anything return A.hitby(src, 0, itempush) -/obj/item/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback) +/obj/item/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback, force) thrownby = thrower callback = CALLBACK(src, .proc/after_throw, callback) //replace their callback with our own - . = ..(target, range, speed, thrower, spin, diagonals_first, callback) + . = ..(target, range, speed, thrower, spin, diagonals_first, callback, force) /obj/item/proc/after_throw(datum/callback/callback) if(callback) //call the original callback diff --git a/code/game/objects/items/weapons/storage/belt.dm b/code/game/objects/items/weapons/storage/belt.dm index 83494366d38..e902b0d3500 100644 --- a/code/game/objects/items/weapons/storage/belt.dm +++ b/code/game/objects/items/weapons/storage/belt.dm @@ -88,7 +88,7 @@ update_icon() /obj/item/storage/belt/utility/chief - name = "Chief Engineer's toolbelt" + name = "advanced toolbelt" desc = "Holds tools, looks snazzy" icon_state = "utilitybelt_ce" item_state = "utility_ce" @@ -139,7 +139,7 @@ max_w_class = WEIGHT_CLASS_NORMAL max_combined_w_class = 17 use_to_pickup = 1 - name = "Surgical Belt" + name = "surgical belt" desc = "Can hold various surgical tools." storage_slots = 9 use_item_overlays = 1 diff --git a/code/game/objects/items/weapons/storage/boxes.dm b/code/game/objects/items/weapons/storage/boxes.dm index b566dc81e37..d7fae3f266c 100644 --- a/code/game/objects/items/weapons/storage/boxes.dm +++ b/code/game/objects/items/weapons/storage/boxes.dm @@ -114,6 +114,17 @@ new /obj/item/crowbar/red(src) new /obj/item/reagent_containers/hypospray/autoinjector(src) +/obj/item/storage/box/survival_syndi + icon_state = "box_syndi" + New() + ..() + contents = list() + new /obj/item/clothing/mask/gas/syndicate(src) + new /obj/item/tank/emergency_oxygen/syndi(src) + new /obj/item/reagent_containers/hypospray/autoinjector(src) + new /obj/item/reagent_containers/food/pill/initropidril(src) + new /obj/item/flashlight/glowstick/red(src) + /obj/item/storage/box/gloves name = "box of latex gloves" desc = "Contains white gloves." diff --git a/code/game/objects/items/weapons/storage/toolbox.dm b/code/game/objects/items/weapons/storage/toolbox.dm index 02544974442..aa3b824d40d 100644 --- a/code/game/objects/items/weapons/storage/toolbox.dm +++ b/code/game/objects/items/weapons/storage/toolbox.dm @@ -94,6 +94,12 @@ new /obj/item/multitool(src) new /obj/item/clothing/gloves/combat(src) +/obj/item/storage/toolbox/fakesyndi + name = "suspicous looking toolbox" + icon_state = "syndicate" + item_state = "toolbox_syndi" + desc = "Danger. Very Robust. The paint is still wet." + /obj/item/storage/toolbox/drone name = "mechanical toolbox" icon_state = "blue" diff --git a/code/game/objects/obj_defense.dm b/code/game/objects/obj_defense.dm index 572ff92c4fa..3ab8de69f7f 100644 --- a/code/game/objects/obj_defense.dm +++ b/code/game/objects/obj_defense.dm @@ -87,6 +87,17 @@ return TRUE return FALSE +/obj/force_pushed(atom/movable/pusher, force = MOVE_FORCE_DEFAULT, direction) + return TRUE + +/obj/move_crushed(atom/movable/pusher, force = MOVE_FORCE_DEFAULT, direction) + collision_damage(pusher, force, direction) + return TRUE + +/obj/proc/collision_damage(atom/movable/pusher, force = MOVE_FORCE_DEFAULT, direction) + var/amt = max(0, ((force - (move_resist * MOVE_FORCE_CRUSH_RATIO)) / (move_resist * MOVE_FORCE_CRUSH_RATIO)) * 10) + take_damage(amt, BRUTE) + /obj/blob_act(obj/structure/blob/B) if(isturf(loc)) var/turf/T = loc diff --git a/code/modules/clothing/head/misc.dm b/code/modules/clothing/head/misc.dm index 6a7a4b26358..e5c81eb8d18 100644 --- a/code/modules/clothing/head/misc.dm +++ b/code/modules/clothing/head/misc.dm @@ -472,3 +472,9 @@ name = "magnificent crown" desc = "A crown worn by only the highest emperors of the land." icon_state = "fancycrown" + +/obj/item/clothing/head/zepelli + name = "chequered diamond hat" + desc = "Wearing this makes you feel like a real mozzarella cheeseball. " + icon_state = "zepelli" + item_state = "zepelli" \ No newline at end of file diff --git a/code/modules/clothing/shoes/magboots.dm b/code/modules/clothing/shoes/magboots.dm index 3156b617c03..8cfcb2b1c5f 100644 --- a/code/modules/clothing/shoes/magboots.dm +++ b/code/modules/clothing/shoes/magboots.dm @@ -7,6 +7,7 @@ var/magpulse = 0 var/slowdown_active = 2 var/slowdown_passive = SHOES_SLOWDOWN + var/magpulse_name = "mag-pulse traction system" actions_types = list(/datum/action/item_action/toggle) strip_delay = 70 put_on_delay = 70 @@ -21,7 +22,7 @@ slowdown = slowdown_active magpulse = !magpulse icon_state = "[magboot_state][magpulse]" - to_chat(user, "You [magpulse ? "enable" : "disable"] the mag-pulse traction system.") + to_chat(user, "You [magpulse ? "enable" : "disable"] the [magpulse_name].") user.update_inv_shoes() //so our mob-overlays update user.update_gravity(user.mob_has_gravity()) for(var/X in actions) @@ -33,7 +34,7 @@ /obj/item/clothing/shoes/magboots/examine(mob/user) ..(user) - to_chat(user, "Its mag-pulse traction system appears to be [magpulse ? "enabled" : "disabled"].") + to_chat(user, "Its [magpulse_name] appears to be [magpulse ? "enabled" : "disabled"].") /obj/item/clothing/shoes/magboots/advance @@ -65,7 +66,27 @@ obj/item/clothing/shoes/magboots/syndie/advance //For the Syndicate Strike Team slowdown = SHOES_SLOWDOWN+1 slowdown_active = SHOES_SLOWDOWN+1 slowdown_passive = SHOES_SLOWDOWN+1 + magpulse_name = "honk-powered traction system" item_color = "clown" silence_steps = 1 shoe_sound = "clownstep" - origin_tech = "magnets=4;syndicate=2" \ No newline at end of file + origin_tech = "magnets=4;syndicate=2" + +/obj/item/clothing/shoes/magboots/wizard //bundled with the wiz hardsuit + name = "boots of gripping" + desc = "These magical boots, once activated, will stay gripped to any surface without slowing you down." + icon_state = "wizmag0" + magboot_state = "wizmag" + slowdown_active = SHOES_SLOWDOWN //wiz hardsuit already slows you down, no need to double it + magpulse_name = "gripping ability" + +/obj/item/clothing/shoes/magboots/wizard/attack_self(mob/user) + if(user) + if(user.mind in ticker.mode.wizards) + if(magpulse) //faint blue light when shoes are turned on gives a reason to turn them off when not needed in maint + set_light(0) + else + set_light(2, 1, LIGHT_COLOR_LIGHTBLUE) + ..() + else + to_chat(user, "You poke the gem on [src]. Nothing happens.") \ No newline at end of file diff --git a/code/modules/crafting/recipes.dm b/code/modules/crafting/recipes.dm index 65ca57696c8..a5783f5ab3f 100644 --- a/code/modules/crafting/recipes.dm +++ b/code/modules/crafting/recipes.dm @@ -396,4 +396,14 @@ /obj/item/stack/rods = 2, /obj/item/assembly/prox_sensor = 1) // Not a timer because the system sees a diamond drill as a drill too, letting you make both otherwise. tools = list(/obj/item/screwdriver, /obj/item/wrench) + category = CAT_MISC + +/datum/crafting_recipe/faketoolbox + name = "Black and Red toolbox" + result = /obj/item/storage/toolbox/fakesyndi + time = 40 + reqs = list(/datum/reagent/paint/red = 10, + /datum/reagent/paint/black = 30, + /obj/item/storage/toolbox = 1) //Paint in reagents so it doesnt take the container up, yet still take it from the beaker + tools = list(/obj/item/reagent_containers/glass/rag = 1) //need something to paint with it category = CAT_MISC \ No newline at end of file diff --git a/code/modules/food_and_drinks/food/foods/baked_goods.dm b/code/modules/food_and_drinks/food/foods/baked_goods.dm index 9da07f4f0b8..1aedaf3f4c7 100644 --- a/code/modules/food_and_drinks/food/foods/baked_goods.dm +++ b/code/modules/food_and_drinks/food/foods/baked_goods.dm @@ -88,6 +88,23 @@ trash = /obj/item/trash/plate filling_color = "#FADA8E" +/obj/item/reagent_containers/food/snacks/sliceable/bananacake + name = "banana cake" + desc = "A cake with added bananas." + icon_state = "bananacake" + slice_path = /obj/item/reagent_containers/food/snacks/bananacakeslice + slices_num = 5 + bitesize = 3 + filling_color = "#FADA8E" + list_reagents = list("nutriment" = 20, "vitamin" = 5) + +/obj/item/reagent_containers/food/snacks/bananacakeslice + name = "banana cake slice" + desc = "Just a slice of cake, it is enough for everyone." + icon_state = "bananacake_slice" + trash = /obj/item/trash/plate + filling_color = "#FADA8E" + /obj/item/reagent_containers/food/snacks/sliceable/limecake name = "lime cake" desc = "A cake with added lime." diff --git a/code/modules/food_and_drinks/recipes/recipes_oven.dm b/code/modules/food_and_drinks/recipes/recipes_oven.dm index 7dcfe199ded..a6e08ad8569 100644 --- a/code/modules/food_and_drinks/recipes/recipes_oven.dm +++ b/code/modules/food_and_drinks/recipes/recipes_oven.dm @@ -355,6 +355,17 @@ ) result = /obj/item/reagent_containers/food/snacks/sliceable/orangecake +/datum/recipe/oven/bananacake + reagents = list("milk" = 5) + items = list( + /obj/item/reagent_containers/food/snacks/dough, + /obj/item/reagent_containers/food/snacks/dough, + /obj/item/reagent_containers/food/snacks/dough, + /obj/item/reagent_containers/food/snacks/grown/banana, + /obj/item/reagent_containers/food/snacks/grown/banana + ) + result = /obj/item/reagent_containers/food/snacks/sliceable/bananacake + /datum/recipe/oven/limecake reagents = list("milk" = 5) items = list( diff --git a/code/modules/mob/camera/camera.dm b/code/modules/mob/camera/camera.dm index 38b5e81a87b..a5bfcb02e4b 100644 --- a/code/modules/mob/camera/camera.dm +++ b/code/modules/mob/camera/camera.dm @@ -3,7 +3,8 @@ /mob/camera name = "camera mob" density = 0 - anchored = 1 + move_force = INFINITY + move_resist = INFINITY status_flags = GODMODE // You can't damage it. mouse_opacity = MOUSE_OPACITY_TRANSPARENT see_in_dark = 7 diff --git a/code/modules/mob/dead/death.dm b/code/modules/mob/dead/death.dm index 48a04a834c7..704a61abbba 100644 --- a/code/modules/mob/dead/death.dm +++ b/code/modules/mob/dead/death.dm @@ -3,3 +3,6 @@ /mob/dead/gib() //ghosts can't be gibbed. return + +/mob/dead + move_resist = INFINITY \ No newline at end of file diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm index 7e583216475..cb2bc013154 100644 --- a/code/modules/mob/dead/observer/observer.dm +++ b/code/modules/mob/dead/observer/observer.dm @@ -13,7 +13,7 @@ var/list/image/ghost_darkness_images = list() //this is a list of images for thi density = 0 canmove = 0 alpha = 127 - anchored = 1 // don't get pushed around + move_resist = INFINITY // don't get pushed around invisibility = INVISIBILITY_OBSERVER var/can_reenter_corpse var/bootime = 0 @@ -706,6 +706,6 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp set name = "Mob spawners menu" set desc = "See all currently available ghost spawners" set category = "Ghost" - + var/datum/spawners_menu/menu = new /datum/spawners_menu(src) menu.ui_interact(src) diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index e9b09ba1f2b..ca791c9e400 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -574,7 +574,7 @@ var/list/ventcrawl_machinery = list(/obj/machinery/atmospherics/unary/vent_pump, if(thrown_thing) visible_message("[src] has thrown [thrown_thing].") newtonian_move(get_dir(target, src)) - thrown_thing.throw_at(target, thrown_thing.throw_range, thrown_thing.throw_speed, src) + thrown_thing.throw_at(target, thrown_thing.throw_range, thrown_thing.throw_speed, src, null, null, null, move_force) /mob/living/carbon/can_use_hands() if(handcuffed) diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index bf49d5b2598..62b9cf6cd65 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -50,7 +50,7 @@ if(ObjBump(A)) return if(istype(A, /atom/movable)) - if(PushAM(A)) + if(PushAM(A, move_force)) return //Called when we bump into a mob @@ -127,32 +127,41 @@ return //Called when we want to push an atom/movable -/mob/living/proc/PushAM(atom/movable/AM) +/mob/living/proc/PushAM(atom/movable/AM, force = move_force) if(now_pushing) - return 1 + return TRUE if(moving_diagonally) // no pushing during diagonal moves - return 1 + return TRUE if(!client && (mob_size < MOB_SIZE_SMALL)) return - if(!AM.anchored) - now_pushing = 1 - var/t = get_dir(src, AM) - if(istype(AM, /obj/structure/window)) - var/obj/structure/window/W = AM - if(W.fulltile) - for(var/obj/structure/window/win in get_step(W, t)) - now_pushing = 0 - return - if(pulling == AM) - stop_pulling() - var/current_dir - if(isliving(AM)) - current_dir = AM.dir - step(AM, t) - if(current_dir) - AM.setDir(current_dir) - now_pushing = 0 - + now_pushing = TRUE + var/t = get_dir(src, AM) + var/push_anchored = FALSE + if((AM.move_resist * MOVE_FORCE_CRUSH_RATIO) <= force) + if(move_crush(AM, move_force, t)) + push_anchored = TRUE + if((AM.move_resist * MOVE_FORCE_FORCEPUSH_RATIO) <= force) //trigger move_crush and/or force_push regardless of if we can push it normally + if(force_push(AM, move_force, t, push_anchored)) + push_anchored = TRUE + if((AM.anchored && !push_anchored) || (force < (AM.move_resist * MOVE_FORCE_PUSH_RATIO))) + now_pushing = FALSE + return + if(istype(AM, /obj/structure/window)) + var/obj/structure/window/W = AM + if(W.fulltile) + for(var/obj/structure/window/win in get_step(W,t)) + now_pushing = FALSE + return + if(pulling == AM) + stop_pulling() + var/current_dir + if(isliving(AM)) + current_dir = AM.dir + if(step(AM, t)) + step(src, t) + if(current_dir) + AM.setDir(current_dir) + now_pushing = FALSE /mob/living/Stat() . = ..() @@ -187,9 +196,20 @@ set name = "Pull" set category = "Object" - if(AM.Adjacent(src)) + if(istype(AM) && Adjacent(AM)) start_pulling(AM) - return + else + stop_pulling() + +/mob/living/stop_pulling() + ..() + if(pullin) + pullin.update_icon(src) + +/mob/living/verb/stop_pulling1() + set name = "Stop Pulling" + set category = "IC" + stop_pulling() //same as above /mob/living/pointed(atom/A as mob|obj|turf in view()) @@ -852,6 +872,37 @@ return 0 return 1 +/mob/living/start_pulling(atom/movable/AM, state, force = pull_force, supress_message = FALSE) + if(!AM || !src) + return FALSE + if(!(AM.can_be_pulled(src, state, force))) + return FALSE + if(incapacitated()) + return + // If we're pulling something then drop what we're currently pulling and pull this instead. + AM.add_fingerprint(src) + if(pulling) + if(AM == pulling)// Are we trying to pull something we are already pulling? Then just stop here, no need to continue. + return + stop_pulling() + if(AM.pulledby) + visible_message("[src] has pulled [AM] from [AM.pulledby]'s grip.") + AM.pulledby.stop_pulling() //an object can't be pulled by two mobs at once. + pulling = AM + AM.pulledby = src + if(pullin) + pullin.update_icon(src) + if(ismob(AM)) + var/mob/M = AM + if(!iscarbon(src)) + M.LAssailant = null + else + M.LAssailant = usr + +/mob/living/proc/check_pull() + if(pulling && !(pulling in orange(1))) + stop_pulling() + /mob/living/proc/get_taste_sensitivity() return 1 diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index f766a1f53ce..cfe35b58983 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -73,7 +73,7 @@ return 0 //this proc handles being hit by a thrown atom -/mob/living/hitby(atom/movable/AM, skipcatch, hitpush = 1, blocked = 0)//Standardization and logging -Sieve +/mob/living/hitby(atom/movable/AM, skipcatch, hitpush = 1, blocked = 0, datum/thrownthing/throwingdatum)//Standardization and logging -Sieve if(istype(AM, /obj/item)) var/obj/item/I = AM var/zone = ran_zone("chest", 65)//Hits a random part of the body, geared towards the chest @@ -229,7 +229,7 @@ // End BS12 momentum-transfer code. -/mob/living/proc/grabbedby(mob/living/carbon/user, supress_message = 0) +/mob/living/proc/grabbedby(mob/living/carbon/user, supress_message = FALSE) if(user == src || anchored) return 0 if(!(status_flags & CANPUSH)) diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm index 2f9ad47399b..239fec3b246 100644 --- a/code/modules/mob/living/silicon/ai/ai.dm +++ b/code/modules/mob/living/silicon/ai/ai.dm @@ -38,7 +38,7 @@ var/list/ai_verbs_default = list( name = "AI" icon = 'icons/mob/AI.dmi'// icon_state = "ai" - anchored = 1 // -- TLE + move_resist = MOVE_FORCE_VERY_STRONG density = 1 status_flags = CANSTUN|CANPARALYSE|CANPUSH mob_size = MOB_SIZE_LARGE @@ -533,9 +533,14 @@ var/list/ai_verbs_default = list( if(!isturf(loc)) // if their location isn't a turf return // stop - anchored = !anchored // Toggles the anchor + var/is_anchored = FALSE + if(move_resist == MOVE_FORCE_VERY_STRONG) + move_resist = MOVE_FORCE_VERY_STRONG + else + is_anchored = TRUE + move_resist = MOVE_FORCE_NORMAL - to_chat(src, "[anchored ? "You are now anchored." : "You are now unanchored."]") + to_chat(src, "[is_anchored ? "You are now anchored." : "You are now unanchored."]") /mob/living/silicon/ai/update_canmove() return FALSE diff --git a/code/modules/mob/living/silicon/pai/pai.dm b/code/modules/mob/living/silicon/pai/pai.dm index eeaa920c83a..e7028ea4422 100644 --- a/code/modules/mob/living/silicon/pai/pai.dm +++ b/code/modules/mob/living/silicon/pai/pai.dm @@ -517,12 +517,8 @@ /mob/living/silicon/pai/Bumped() return -/mob/living/silicon/pai/start_pulling(var/atom/movable/AM) - if(stat || sleeping || paralysis || weakened) - return - if(istype(AM,/obj/item)) - to_chat(src, "You are far too small to pull anything!") - return +/mob/living/silicon/pai/start_pulling(atom/movable/AM, state, force = move_force, supress_message = FALSE) + return FALSE /mob/living/silicon/pai/update_canmove(delay_action_updates = 0) . = ..() diff --git a/code/modules/mob/living/simple_animal/bot/mulebot.dm b/code/modules/mob/living/simple_animal/bot/mulebot.dm index 103e443d7e7..49a3b2718db 100644 --- a/code/modules/mob/living/simple_animal/bot/mulebot.dm +++ b/code/modules/mob/living/simple_animal/bot/mulebot.dm @@ -11,8 +11,8 @@ desc = "A Multiple Utility Load Effector bot." icon_state = "mulebot0" density = 1 - anchored = 1 - animate_movement=1 + move_resist = MOVE_FORCE_STRONG + animate_movement = 1 health = 50 maxHealth = 50 damage_coeff = list(BRUTE = 0.5, BURN = 0.7, TOX = 0, CLONE = 0, STAMINA = 0, OXY = 0) diff --git a/code/modules/mob/living/simple_animal/friendly/mouse.dm b/code/modules/mob/living/simple_animal/friendly/mouse.dm index 5ebaf47afb2..e6cc5fb8dc8 100644 --- a/code/modules/mob/living/simple_animal/friendly/mouse.dm +++ b/code/modules/mob/living/simple_animal/friendly/mouse.dm @@ -6,9 +6,10 @@ icon_living = "mouse_gray" icon_dead = "mouse_gray_dead" speak = list("Squeek!","SQUEEK!","Squeek?") - speak_emote = list("squeeks","squeeks","squiks") + speak_emote = list("squeeks","squeaks","squiks") emote_hear = list("squeeks","squeaks","squiks") emote_see = list("runs in a circle", "shakes", "scritches at something") + var/squeak_sound = 'sound/effects/mousesqueek.ogg' speak_chance = 1 turns_per_move = 5 see_in_dark = 6 @@ -40,7 +41,7 @@ ..() if(prob(speak_chance)) for(var/mob/M in view()) - M << 'sound/effects/mousesqueek.ogg' + M << squeak_sound /mob/living/simple_animal/mouse/Life(seconds, times_fired) . = ..() @@ -71,6 +72,7 @@ desc = "It's a small [mouse_color] rodent, often seen hiding in maintenance areas and making a nuisance of itself." /mob/living/simple_animal/mouse/proc/splat() + playsound(src, squeak_sound, 40, 1) src.health = 0 src.stat = DEAD src.icon_dead = "mouse_[mouse_color]_splat" @@ -93,7 +95,7 @@ if(stat == CONSCIOUS) var/mob/M = AM to_chat(M, "[bicon(src)] Squeek!") - SEND_SOUND(M, 'sound/effects/mousesqueek.ogg') + SEND_SOUND(M, squeak_sound) ..() /mob/living/simple_animal/mouse/death(gibbed) @@ -105,6 +107,31 @@ if(client) client.time_died_as_mouse = world.time +/mob/living/simple_animal/mouse/emote(act, m_type=1, message = null) + if(stat != CONSCIOUS) + return + + var/on_CD = 0 + act = lowertext(act) + switch(act) + if("squeak") //Mouse time + on_CD = handle_emote_CD() + else + on_CD = 0 + + if(on_CD == 1) + return + + switch(act) + if("squeak") + message = "\The [src] squeaks!" + m_type = 2 //audible + playsound(src, squeak_sound, 40, 1) + if("help") + to_chat(src, "scream, squeak") + + ..() + /* * Mouse types */ diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/megafauna.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/megafauna.dm index 6a6e44a5852..870b3bf62cc 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/megafauna.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/megafauna.dm @@ -38,7 +38,9 @@ var/elimination = 0 var/anger_modifier = 0 var/obj/item/gps/internal_gps - anchored = TRUE + move_force = MOVE_FORCE_OVERPOWERING + move_resist = MOVE_FORCE_OVERPOWERING + pull_force = MOVE_FORCE_OVERPOWERING mob_size = MOB_SIZE_LARGE layer = MOB_LAYER + 0.5 //Looks weird with them slipping under mineral walls and cameras and shit otherwise mouse_opacity = MOUSE_OPACITY_OPAQUE // Easier to click on in melee, they're giant targets anyway diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs.dm index 39799d6e493..0f37482b3e2 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs.dm @@ -136,7 +136,9 @@ throw_message = "does nothing to the rocky hide of the" aggro_vision_range = 9 idle_vision_range = 5 - anchored = 1 //Stays anchored until death as to be unpullable + move_force = MOVE_FORCE_VERY_STRONG + move_resist = MOVE_FORCE_VERY_STRONG + pull_force = MOVE_FORCE_VERY_STRONG var/pre_attack = 0 loot = list(/obj/item/asteroid/goliath_hide{layer = 4.1}) @@ -152,7 +154,9 @@ icon_state = "Goliath_preattack" /mob/living/simple_animal/hostile/asteroid/goliath/revive() - anchored = 1 + move_force = MOVE_FORCE_VERY_STRONG + move_resist = MOVE_FORCE_VERY_STRONG + pull_force = MOVE_FORCE_VERY_STRONG ..() /mob/living/simple_animal/hostile/asteroid/goliath/OpenFire() diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/kangaroo.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/kangaroo.dm new file mode 100644 index 00000000000..0bd75fa4185 --- /dev/null +++ b/code/modules/mob/living/simple_animal/hostile/retaliate/kangaroo.dm @@ -0,0 +1,62 @@ +/mob/living/simple_animal/hostile/retaliate/kangaroo + name = "Kangaroo" + real_name = "Kangaroo" + voice_name = "unidentifiable voice" + desc = "A large marsupial herbivore. It has powerful hind legs, with nails that resemble long claws." + icon_state = "kangaroo" // Credit: FoS + icon_living = "kangaroo" + icon_dead = "kangaroo_dead" + icon_gib = "kangaroo_dead" + turns_per_move = 8 + response_help = "pets" + emote_hear = list("bark") + maxHealth = 150 + health = 150 + harm_intent_damage = 3 + melee_damage_lower = 5 // avg damage 12.5 without kick, (12.5+12.5+60)/3=25 with kick + melee_damage_upper = 20 + attacktext = "slashes" + attack_sound = 'sound/weapons/bladeslice.ogg' // they have nails that work like claws, so, slashing sound + atmos_requirements = list("min_oxy" = 5, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 2, "min_co2" = 0, "max_co2" = 5, "min_n2" = 0, "max_n2" = 0) + move_to_delay = 4 // at 20ticks/sec, this is 5 tile/sec movespeed, about the same as a 'fast human'. + speed = -1 // '-1' converts to 1.5 total move delay, or 6.6 tiles/sec movespeed + var/attack_cycles = 0 + var/attack_cycles_max = 3 + +/mob/living/simple_animal/hostile/retaliate/kangaroo/New() + . = ..() + // Leap spell, player-only usage + AddSpell(new /obj/effect/proc_holder/spell/targeted/leap) + +/mob/living/simple_animal/hostile/retaliate/kangaroo/AttackingTarget() + if(client && a_intent != INTENT_HARM) + return ..() // Do not allow player-controlled roos on non-attack intents to 'prime' their kick by nuzzling people. + + var/mob/living/L = target + if(!istype(L)) + return ..() // Do not do further checks if we somehow end up attacking something not alive (like a window). + + if(L.stat == DEAD) + return ..() // Do not allow player-controlled roos to prime their kick by attacking corpses. + + attack_cycles++ + if(attack_cycles < attack_cycles_max) + // Most of the time, do a standard attack... + return ..() + + // ... but, every attack_cycles_max attacks on a living mob, do a powerful disemboweling kick instead + attack_cycles = 0 + attacktext = "VICIOUSLY KICKS" + melee_damage_lower = 60 + melee_damage_upper = 60 + . = ..() + + var/rookick_dir = get_dir(src, L) + var/turf/general_direction = get_edge_target_turf(L, rookick_dir) + L.visible_message("[L] is kicked hard!", "The kangaroo kick sends you flying mate!") + L.throw_at(general_direction, 10, 2) + + attacktext = initial(attacktext) + melee_damage_lower = initial(melee_damage_lower) + melee_damage_upper = initial(melee_damage_upper) + diff --git a/code/modules/mob/living/simple_animal/hostile/statue.dm b/code/modules/mob/living/simple_animal/hostile/statue.dm index 88326747247..b293c1de974 100644 --- a/code/modules/mob/living/simple_animal/hostile/statue.dm +++ b/code/modules/mob/living/simple_animal/hostile/statue.dm @@ -42,7 +42,9 @@ see_invisible = SEE_INVISIBLE_OBSERVER_NOLIGHTING sight = SEE_SELF|SEE_MOBS|SEE_OBJS|SEE_TURFS - anchored = 1 + move_force = MOVE_FORCE_EXTREMELY_STRONG + move_resist = MOVE_FORCE_EXTREMELY_STRONG + pull_force = MOVE_FORCE_EXTREMELY_STRONG status_flags = GODMODE // Cannot push also var/cannot_be_seen = 1 diff --git a/code/modules/mob/living/simple_animal/spawner.dm b/code/modules/mob/living/simple_animal/spawner.dm index 22b5fb705a9..7a17dfb202b 100644 --- a/code/modules/mob/living/simple_animal/spawner.dm +++ b/code/modules/mob/living/simple_animal/spawner.dm @@ -10,7 +10,7 @@ var/mob_type = /mob/living/simple_animal/hostile/carp var/spawn_text = "emerges from" status_flags = 0 - anchored = 1 + move_resist = MOVE_FORCE_VERY_STRONG AIStatus = AI_OFF a_intent = INTENT_HARM stop_automated_movement = 1 diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm index bfe9ac7484a..3de413ef8a1 100644 --- a/code/modules/mob/mob_defines.dm +++ b/code/modules/mob/mob_defines.dm @@ -35,7 +35,6 @@ var/obj/machinery/machine = null var/other_mobs = null var/memory = "" - var/atom/movable/pulling = null var/next_move = null var/notransform = null //Carbon var/other = 0.0 @@ -48,7 +47,6 @@ var/bhunger = 0 //Carbon var/lying = 0 var/lying_prev = 0 - var/canmove = 1 var/lastpuke = 0 var/unacidable = 0 var/can_strip = 1 diff --git a/code/modules/mob/new_player/new_player.dm b/code/modules/mob/new_player/new_player.dm index 6d636f0328e..ec57d9d6200 100644 --- a/code/modules/mob/new_player/new_player.dm +++ b/code/modules/mob/new_player/new_player.dm @@ -12,8 +12,6 @@ stat = 2 canmove = 0 - anchored = 1 // don't get pushed around - /mob/new_player/New() GLOB.mob_list += src diff --git a/code/modules/mob/pulling.dm b/code/modules/mob/pulling.dm deleted file mode 100644 index f5cb9eecbe2..00000000000 --- a/code/modules/mob/pulling.dm +++ /dev/null @@ -1,46 +0,0 @@ -//this and stop_pulling really ought to be /mob/living procs -/mob/proc/start_pulling(atom/movable/AM) - if(src == AM) // Trying to pull yourself is a shortcut to stop pulling - stop_pulling() - return - if(!AM || !isturf(AM.loc)) //if there's no object or the object being pulled is inside something: abort! - return - if(incapacitated()) - return - if(!(AM.anchored)) - AM.add_fingerprint(src) - - // If we're pulling something then drop what we're currently pulling and pull this instead. - if(pulling) - // Are we trying to pull something we are already pulling? Then just stop here, no need to continue. - if(AM == pulling) - return - stop_pulling() - if(AM.pulledby) - visible_message("[src] has pulled [AM] from [AM.pulledby]'s grip.") - AM.pulledby.stop_pulling() //an object can't be pulled by two mobs at once. - - pulling = AM - AM.pulledby = src - if(pullin) - pullin.update_icon(src) - if(ismob(AM)) - var/mob/M = AM - if(!iscarbon(src)) - M.LAssailant = null - else - M.LAssailant = usr - -/mob/verb/stop_pulling() - set name = "Stop Pulling" - set category = "IC" - - if(pulling) - pulling.pulledby = null - pulling = null - if(pullin) - pullin.update_icon(src) - -/mob/living/proc/check_pull() - if(pulling && !(pulling in orange(1))) - stop_pulling() diff --git a/code/modules/recycling/conveyor2.dm b/code/modules/recycling/conveyor2.dm index 64c201a319f..6e1fbb8a842 100644 --- a/code/modules/recycling/conveyor2.dm +++ b/code/modules/recycling/conveyor2.dm @@ -16,6 +16,7 @@ GLOBAL_LIST_INIT(conveyor_switches, list()) desc = "It's a conveyor belt, commonly used to transport large numbers of items elsewhere quite quickly." layer = CONVEYOR_LAYER // so they appear under stuff but not below stuff like vents anchored = TRUE + move_force = MOVE_FORCE_DEFAULT var/operating = FALSE //NB: this can be TRUE while the belt doesn't go var/forwards // The direction the conveyor sends you in var/backwards // hopefully self-explanatory @@ -183,9 +184,12 @@ GLOBAL_LIST_INIT(conveyor_switches, list()) ..() /obj/machinery/conveyor/proc/move_thing(atom/movable/AM) + if(move_force < (AM.move_resist)) + return FALSE if(!AM.anchored && AM.loc == loc) step(AM, forwards) + /obj/machinery/conveyor/proc/can_conveyor_run() if(stat & BROKEN) return FALSE diff --git a/code/modules/research/designs/bluespace_designs.dm b/code/modules/research/designs/bluespace_designs.dm index 9a44b10d40c..cdb6be6ebdd 100644 --- a/code/modules/research/designs/bluespace_designs.dm +++ b/code/modules/research/designs/bluespace_designs.dm @@ -81,7 +81,7 @@ build_path = /obj/item/radio/beacon category = list("Bluespace") -/datum/design/rpd +/datum/design/brpd name = "Bluespace Rapid Pipe Dispenser (BRPD)" desc = "Similar to the Rapid Pipe Dispenser, lets you rapidly dispense pipes. Now at long range!" req_tech = list("bluespace" = 3, "toxins" = 6) @@ -89,4 +89,4 @@ build_type = PROTOLATHE materials = list(MAT_METAL = 75000, MAT_GLASS = 37500, MAT_SILVER = 3000) build_path = /obj/item/rpd/bluespace - category = list("Bluespace") \ No newline at end of file + category = list("Bluespace") diff --git a/code/modules/response_team/ert_outfits.dm b/code/modules/response_team/ert_outfits.dm index 8948fd80dbb..368868770c7 100644 --- a/code/modules/response_team/ert_outfits.dm +++ b/code/modules/response_team/ert_outfits.dm @@ -52,7 +52,8 @@ /obj/item/clothing/head/helmet/ert/command = 1, /obj/item/clothing/mask/gas/sechailer = 1, /obj/item/restraints/handcuffs = 1, - /obj/item/storage/lockbox/mindshield = 1 + /obj/item/storage/lockbox/mindshield = 1, + /obj/item/flashlight = 1 ) /datum/outfit/job/centcom/response_team/commander/red @@ -216,7 +217,8 @@ /obj/item/clothing/mask/gas = 1, /obj/item/t_scanner = 1, /obj/item/stack/sheet/glass/fifty = 1, - /obj/item/stack/sheet/metal/fifty = 1 + /obj/item/stack/sheet/metal/fifty = 1, + /obj/item/flashlight = 1 ) /datum/outfit/job/centcom/response_team/engineer/red @@ -224,7 +226,7 @@ shoes = /obj/item/clothing/shoes/magboots/advance gloves = /obj/item/clothing/gloves/color/yellow belt = /obj/item/storage/belt/utility/chief/full - suit = /obj/item/clothing/suit/space/hardsuit/ert/engineer + suit = /obj/item/clothing/suit/space/hardsuit/ert/engineer/gamma suit_store = /obj/item/tank/emergency_oxygen/engi glasses = /obj/item/clothing/glasses/meson cybernetic_implants = list( @@ -235,7 +237,7 @@ r_pocket = /obj/item/melee/classic_baton/telescopic backpack_contents = list( - /obj/item/clothing/head/helmet/space/hardsuit/ert/engineer = 1, + /obj/item/clothing/head/helmet/space/hardsuit/ert/engineer/gamma = 1, /obj/item/clothing/mask/gas = 1, /obj/item/rcd/preloaded = 1, /obj/item/rcd_ammo = 3, @@ -302,7 +304,9 @@ /obj/item/storage/firstaid/regular = 1, /obj/item/storage/box/autoinjectors = 1, /obj/item/roller = 1, - /obj/item/storage/pill_bottle/ert = 1 + /obj/item/storage/pill_bottle/ert = 1, + /obj/item/flashlight = 1, + /obj/item/healthupgrade = 1 ) /datum/outfit/job/centcom/response_team/medic/red @@ -330,7 +334,8 @@ /obj/item/storage/box/autoinjectors = 1, /obj/item/roller = 1, /obj/item/clothing/shoes/magboots = 1, - /obj/item/bodyanalyzer = 1 + /obj/item/bodyanalyzer = 1, + /obj/item/healthupgrade = 1 ) /datum/outfit/job/centcom/response_team/medic/gamma @@ -351,8 +356,9 @@ /obj/item/clothing/mask/gas/sechailer/swat = 1, /obj/item/bodyanalyzer/advanced = 1, /obj/item/extinguisher/mini = 1, - /obj/item/storage/belt/medical/surgery/loaded = 1, - /obj/item/roller = 1 + /obj/item/roller = 1, + /obj/item/healthanalyzer/advanced = 1 + ) cybernetic_implants = list( @@ -379,7 +385,8 @@ pda = /obj/item/pda/centcom backpack_contents = list( /obj/item/clothing/mask/gas/sechailer/swat = 1, - /obj/item/storage/box/zipties = 1 + /obj/item/storage/box/zipties = 1, + /obj/item/flashlight/seclite = 1 ) /datum/outfit/job/centcom/response_team/paranormal/amber diff --git a/code/modules/security_levels/keycard authentication.dm b/code/modules/security_levels/keycard authentication.dm index 8203394f09a..3f074c1246c 100644 --- a/code/modules/security_levels/keycard authentication.dm +++ b/code/modules/security_levels/keycard authentication.dm @@ -154,6 +154,12 @@ if("Revoke Emergency Maintenance Access") revoke_maint_all_access() feedback_inc("alert_keycard_auth_maintRevoke",1) + if("Activate Station-Wide Emergency Access") + make_station_all_access() + feedback_inc("alert_keycard_auth_stationGrant",1) + if("Deactivate Station-Wide Emergency Access") + revoke_station_all_access() + feedback_inc("alert_keycard_auth_stationRevoke",1) if("Emergency Response Team") if(is_ert_blocked()) to_chat(usr, "All Emergency Response Teams are dispatched and can not be called at this time.") @@ -180,6 +186,7 @@ return ticker.mode && ticker.mode.ert_disabled var/global/maint_all_access = 0 +var/global/station_all_access = 0 /proc/make_maint_all_access() for(var/area/maintenance/A in world) @@ -196,3 +203,19 @@ var/global/maint_all_access = 0 D.update_icon(0) minor_announcement.Announce("Access restrictions on maintenance and external airlocks have been re-added.") maint_all_access = 0 + +/proc/make_station_all_access() + for(var/obj/machinery/door/airlock/D in GLOB.airlocks) + if(is_station_level(D.z)) + D.emergency = 1 + D.update_icon(0) + minor_announcement.Announce("Access restrictions on all station airlocks have been removed due to an ongoing crisis. Trespassing laws still apply unless ordered otherwise by Command staff.") + station_all_access = 1 + +/proc/revoke_station_all_access() + for(var/obj/machinery/door/airlock/D in GLOB.airlocks) + if(is_station_level(D.z)) + D.emergency = 0 + D.update_icon(0) + minor_announcement.Announce("Access restrictions on all station airlocks have been re-added. Seek station AI or a colleague's assistance if you are stuck.") + station_all_access = 0 \ No newline at end of file diff --git a/html/changelog.html b/html/changelog.html index 9c2e10201c3..f5b451261ef 100644 --- a/html/changelog.html +++ b/html/changelog.html @@ -56,6 +56,72 @@ -->
+

28 December 2018

+

AzuleUtama updated:

+ +

Ionward updated:

+ +

Kyep updated:

+ +

Mitchs98 updated:

+ +

Spartan updated:

+ +

TDSSS updated:

+ +

Tails2091 updated:

+ +

datlo updated:

+ +

improvedname updated:

+ +

name here updated:

+ +

uraniummeltdown updated:

+ +

v0idp updated:

+ +

26 December 2018

Shadow-Quill updated: