diff --git a/code/__DEFINES/dcs/signals.dm b/code/__DEFINES/dcs/signals.dm index 88f9759940..5e36abac15 100644 --- a/code/__DEFINES/dcs/signals.dm +++ b/code/__DEFINES/dcs/signals.dm @@ -83,6 +83,8 @@ #define COMSIG_ATOM_EXIT "atom_exit" //from base of atom/Exit(): (/atom/movable/exiting, /atom/newloc) #define COMPONENT_ATOM_BLOCK_EXIT 1 #define COMSIG_ATOM_EXITED "atom_exited" //from base of atom/Exited(): (atom/movable/exiting, atom/newloc) +/// From base of atom/wave_ex_act(): (datum/wave_explosion/explosion, args) +#define COMSIG_ATOM_WAVE_EX_ACT "atom_wave_ex_act" ///from base of atom/ex_act(): (severity, target) #define COMSIG_ATOM_EX_ACT "atom_ex_act" ///from base of atom/emp_act(): (severity) diff --git a/code/__DEFINES/explosion.dm b/code/__DEFINES/explosion.dm new file mode 100644 index 0000000000..adba852ff1 --- /dev/null +++ b/code/__DEFINES/explosion.dm @@ -0,0 +1,86 @@ +// THIS IS INSANITY +// These are how wave explosions track when there's not only one direction to keep track of (diagonals, etc) +#define WEX_DIR_NORTH NORTH +#define WEX_DIR_SOUTH SOUTH +#define WEX_DIR_EAST EAST +#define WEX_DIR_WEST WEST +#define WEX_ALLDIRS (WEX_DIR_NORTH | WEX_DIR_SOUTH | WEX_DIR_EAST | WEX_DIR_WEST) + +/// Default explosion power to consider an explosion over +#define EXPLOSION_POWER_DEAD 2.5 +/// Default explosion falloff +#define EXPLOSION_DEFAULT_FALLOFF_MULTIPLY 0.98 +/// Default explosion constant falloff +#define EXPLOSION_DEFAULT_FALLOFF_SUBTRACT 5 +/// Block amount at which point having 0 block resistance will result in a full block +#define EXPLOSION_POWER_NO_RESIST_THRESHOLD 5 + +/// Explosion power quantization +#define EXPLOSION_POWER_QUANTIZATION_ACCURACY 0.1 + +// [explosion_flags] variable on /atom +/// No blocking if we're not dense +#define EXPLOSION_FLAG_DENSITY_DEPENDENT (1<<0) +/// If we survive the explosion, we block ALL the power and ignore the results of wave_ex_act(). +#define EXPLOSION_FLAG_HARD_OBSTACLE (1<<1) + +// Standardized explosion powers +/// Maxcap +#define EXPLOSION_POWER_MAXCAP 500 +/// erases shreds from explosions/item damage +#define EXPLOSION_POWER_ERASE_SHREDS 400 +/// Gibs most mobs +#define EXPLOSION_POWER_NORMAL_MOB_GIB 400 + +// Walls +#define EXPLOSION_POWER_WALL_SCRAPE 400 +#define EXPLOSION_POWER_WALL_DISMANTLE 300 +#define EXPLOSION_POWER_WALL_MINIMUM_DISMANTLE 200 + +#define EXPLOSION_POWER_RWALL_SCRAPE 450 +#define EXPLOSION_POWER_RWALL_DISMANTLE 400 +#define EXPLOSION_POWER_RWALL_MINIMUM_DISMANTLE 300 + +// Floors +#define EXPLOSION_POWER_FLOOR_TILE_BREAK 50 +#define EXPLOSION_POWER_FLOOR_MINIMUM_TURF_BREAK 125 +#define EXPLOSION_POWER_FLOOR_TURF_BREAK_BONUS 225 +#define EXPLOSION_POWER_FLOOR_TURF_BREAK 350 +#define EXPLOSION_POWER_FLOOR_TURF_SCRAPE 425 +#define EXPLOSION_POWER_FLOOR_SHIELDED_IMMUNITY 250 + +// Helpers +/// Explosion power to object damage (without taking into consideration armor) +#define EXPLOSION_POWER_STANDARD_SCALE_OBJECT_DAMAGE(power, multiplier) (power>500)?(10*(power**0.6)*multiplier):(0.1*(power**1.3)*multiplier) +/// Explosion power to object damage for hard obstacles +#define EXPLOSION_POWER_STANDARD_SCALE_HARD_OBSTACLE_DAMAGE(power, multiplier) (power>500)?(10*(power**0.6)*multiplier):(0.15*(power**1.3)*multiplier) +/// Explosion power to object damage for windows +#define EXPLOSION_POWER_STANDARD_SCALE_WINDOW_DAMAGE(power, multiplier) (power>500)?(10*(power**0.6)*multiplier):(0.2*(power**1.3)*multiplier) +/// Default brute damage to do to living things +#define EXPLOSION_POWER_STANDARD_SCALE_MOB_DAMAGE(power, multiplier) ((power / 2) * multiplier) + +// Damage factors +/// Factor to multiply damage to a door by if it's open (and therefore not blocking the explosion) +#define EXPLOSION_DAMAGE_OPEN_DOOR_FACTOR 0.25 + +// Standardized explosion constant blocks +#define EXPLOSION_BLOCK_WINDOW 10 +#define EXPLOSION_BLOCK_MACHINE 20 +#define EXPLOSION_BLOCK_SPACE 20 +#define EXPLOSION_BLOCK_REINFORCED_WINDOW 50 +#define EXPLOSION_BLOCK_DENSE_FILLER 50 +#define EXPLOSION_BLOCK_WALL 75 +#define EXPLOSION_BLOCK_BLAST_PROOF 250 +#define EXPLOSION_BLOCK_BOROSILICATE_WINDOW 250 +#define EXPLOSION_BLOCK_EXTREME 250 + +// Standardized explosion factor blocks +#define EXPLOSION_DAMPEN_MACHINE 0.95 +#define EXPLOSION_DAMPEN_SPACE 0.95 +#define EXPLOSION_DAMPEN_WINDOW 0.95 +#define EXPLOSION_DAMPEN_REINFORCED_WINDOW 0.9 +#define EXPLOSION_DAMPEN_DENSE_FILLER 0.85 +#define EXPLOSION_DAMPEN_WALL 0.8 +#define EXPLOSION_DAMPEN_BOROSILICATE_WINDOW 0.65 +#define EXPLOSION_DAMPEN_BLAST_PROOF 0.65 +#define EXPLOSION_DAMPEN_EXTREME 0.5 diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm index deb578464f..2c8001b086 100644 --- a/code/__DEFINES/subsystems.dm +++ b/code/__DEFINES/subsystems.dm @@ -180,6 +180,7 @@ #define FIRE_PRIORITY_PROJECTILES 200 #define FIRE_PRIORITY_TICKER 200 #define FIRE_PRIORITY_ATMOS_ADJACENCY 300 +#define FIRE_PRIORITY_EXPLOSIONS 350 #define FIRE_PRIORITY_STATPANEL 390 #define FIRE_PRIORITY_CHAT 400 #define FIRE_PRIORITY_RUNECHAT 410 @@ -219,7 +220,6 @@ A.flags_1 &= ~OVERLAY_QUEUED_1;\ } while(FALSE) - /** Create a new timer and add it to the queue. * Arguments: diff --git a/code/controllers/subsystem/explosions.dm b/code/controllers/subsystem/explosions.dm new file mode 100644 index 0000000000..30a05a7505 --- /dev/null +++ b/code/controllers/subsystem/explosions.dm @@ -0,0 +1,23 @@ +SUBSYSTEM_DEF(explosions) + name = "Explosions" + wait = 1 + flags = SS_TICKER + priority = FIRE_PRIORITY_EXPLOSIONS + var/static/list/datum/wave_explosion/wave_explosions = list() + var/static/list/datum/wave_explosion/active_wave_explosions = list() + var/static/list/datum/wave_explosion/currentrun = list() + +/datum/controller/subsystem/explosions/fire(resumed) + if(!resumed) + currentrun = active_wave_explosions.Copy() + var/datum/wave_explosion/E + var/ran = 0 + while(length(currentrun) && !MC_TICK_CHECK) + ran = 0 + for(var/i in currentrun) + E = i + if(E.tick()) + currentrun -= E + ran++ + if(!ran) + break diff --git a/code/datums/explosion2.dm b/code/datums/explosion2.dm new file mode 100644 index 0000000000..75f65e4b23 --- /dev/null +++ b/code/datums/explosion2.dm @@ -0,0 +1,378 @@ +/// Creates a wave explosion at a certain place +/proc/wave_explosion(turf/target, power, factor = EXPLOSION_DEFAULT_FALLOFF_MULTIPLY, constant = EXPLOSION_DEFAULT_FALLOFF_SUBTRACT, flash = 0, fire = 0, atom/source, speed = 0, + silent = FALSE, bypass_logging = FALSE, block_resistance = 1, start_immediately = TRUE) + if(!istype(target) || (power <= EXPLOSION_POWER_DEAD)) + return + if(!bypass_logging) + var/logstring = "Wave explosion at [COORD(target)]: [power]/[factor]/[constant]/[flash]/[fire]/[speed] initial/factor/constant/flash/fire/speed" + log_game(logstring) + message_admins(logstring) + return new /datum/wave_explosion(target, power, factor, constant, flash, fire, source, speed, silent, start_immediately, block_resistance) + +/** + * New force-blastwave explosion system + */ +/datum/wave_explosion + /// Next unique numerical ID + var/static/next_id = 0 + /// Our unique nuumerical ID + var/id + /// world.time we started at + var/start_time + /// Are we currently running? + var/running = FALSE + /// Are we currently finished? + var/finished = FALSE + /// What atom we originated from, if any + var/atom/source + + /// Explosion power at which point to consider to be a dead expansion + var/power_considered_dead = EXPLOSION_POWER_DEAD + /// Explosion power we were initially at + var/power_initial + /// Base explosion power falloff multiplier (applied first) + var/power_falloff_factor = EXPLOSION_DEFAULT_FALLOFF_MULTIPLY + /// Base explosion power falloff subtract (applied second) + var/power_falloff_constant = EXPLOSION_DEFAULT_FALLOFF_SUBTRACT + /// Flash range + var/flash_range = 0 + /// Fire probability per tile + var/fire_probability = 0 + /// Are we silent/do we make the screenshake/sounds? + var/silent = FALSE + + // Modifications + /// Object damage mod + var/object_damage_mod = 1 + /// Hard obstcales get this mod INSTEAD of object damage mod + var/hard_obstacle_mod = 1 + /// Window shatter mod. Overrides both [hard_obstcale_mod] and [object_damage_mod] + var/window_shatter_mod = 1 + /// Wall destruction mod + var/wall_destroy_mod = 1 + /// Mob damage mod + var/mob_damage_mod = 1 + /// Mob gib mod + var/mob_gib_mod = 1 + /// Mob deafen mod + var/mob_deafen_mod = 1 + /// block = block / this, if 0 any block is absolute + var/block_resistance = 1 + + // Rewrite count: 2 + // Each cycle is a "perfect ring". + // We run into the problem that diagonal hitboxes don't exist on 2d grid games. + // How we deal with this is this: + // The first half of each cycle explodes cardinal directions awaiting expansion first + // Diagonals get added to a potential diagonals list. + // The second half of each cycle checks the potential diagonals list. If something isn't on the exploded list, + // we know it's a valid diagonal and explode it. + // Then all exploded turfs are flushed to exploded_last and it continues. + // Direction bitflags use the WEX_DIR_X flags so we can keep track of more than one direction in a single field + // The insanity begins when I realized that doing cardinals are easy but diagonals require: + // - Tallying the explosive power that should go into it + // - Exploding it afterwards using the tallied power rather than passed power (so corners aren't far weaker unless there's one side of it blocked) + // Expanding the explosion power of the now exploded diagonal into the two dirs its cardinals are in + // If this is done using a perfect algorithm it should be relatively efficient and result in a near-perfect shockwave simulation. + + /// The last ring that's been exploded. Any turfs in this will completely ignore the current cycle. Turf = TRUE + var/list/turf/exploded_last = list() + /// The "edges" + dirs that need to be processed this cycle. turf = dir flags + var/list/turf/edges = list() + /// The powers of the current turf edges. turf = power + var/list/turf/powers = list() + + /// What cycle are we on? + var/cycle + /// When we started the current cycle + var/cycle_start + /// Time to wait between cycles + var/cycle_speed = 0 + /// Current index for list + var/index = 1 + +/datum/wave_explosion/New(turf/initial, power, factor = EXPLOSION_DEFAULT_FALLOFF_MULTIPLY, constant = EXPLOSION_DEFAULT_FALLOFF_SUBTRACT, flash = 0, fire = 0, atom/source, speed = 0, silent = FALSE, autostart = TRUE, block_resistance = 1) + id = ++next_id + if(next_id > SHORT_REAL_LIMIT) + next_id = 0 + SSexplosions.wave_explosions += src + src.power_initial = power + src.power_falloff_factor = factor + src.power_falloff_constant = constant + src.flash_range = flash + src.fire_probability = fire + src.source = source + src.cycle_speed = speed + src.silent = silent + src.block_resistance = block_resistance + if(!istype(initial)) + stack_trace("Wave explosion created without a turf. This better be for debugging purposes.") + return + if(autostart) + start(initial) + +/datum/wave_explosion/Destroy() + if(running) + stop(FALSE) + return ..() + +/datum/wave_explosion/proc/start(list/turf/_starting) + if(running) + CRASH("Attempted to start() a running wave explosion") + if(!islist(_starting)) + _starting = list(_starting) + var/list/mob/to_flash = list() + var/list/feedback = list() + var/list/mob/mob_potential_shake = list() + var/list/mob/closest_to = list() + for(var/i in 1 to _starting.len) + var/turf/starting = _starting[i] + edges[starting] = WEX_ALLDIRS + powers[starting] = power_initial + var/x0 = starting.x + var/y0 = starting.y + var/z0 = starting.z + var/area/areatype = get_area(starting) + feedback += list(list("power" = power_initial, factor = "factor", constant = "constant", flash = "flash", fire = "fire", speed = "speed", "x" = x0, "y" = y0, "z" = z0, "area" = areatype.type, "time" = TIME_STAMP("YYYY-MM-DD hh:mm:ss", 1))) + // Play sounds; we want sounds to be different depending on distance so we will manually do it ourselves. + // Stereo users will also hear the direction of the explosion! + + // Calculate far explosion sound range. Only allow the sound effect for heavy/devastating explosions. + // 3/7/14 will calculate to 80 + 35 + + if(!silent) + for(var/mob/M in GLOB.player_list) + // Double check for client + var/turf/M_turf = get_turf(M) + if(M_turf && M_turf.z == z0) + var/dist = get_dist(M_turf, starting) + if(isnull(mob_potential_shake[M])) + mob_potential_shake[M] = dist + closest_to[M] = starting + else if(mob_potential_shake[M] < dist) + mob_potential_shake[M] = dist + closest_to[M] = starting + + for(var/array in GLOB.doppler_arrays) + var/obj/machinery/doppler_array/A = array + A.sense_wave_explosion(starting, power_initial, cycle_speed) + + // Flash mobs + if(flash_range) + for(var/mob/living/L in viewers(flash_range, starting)) + to_flash |= L + + if(!silent) + var/frequency = get_rand_frequency() + var/sound/explosion_sound = sound(get_sfx("explosion")) + var/sound/far_explosion_sound = sound('sound/effects/explosionfar.ogg') + + var/far_dist = sqrt(power_initial) * 7.5 + + for(var/mob/M in mob_potential_shake) + var/dist = mob_potential_shake[M] + var/baseshakeamount + if(sqrt(power_initial) - dist > 0) + baseshakeamount = sqrt((sqrt(power_initial) - dist)*0.1) + // If inside the blast radius + world.view - 2 + if(dist <= round(2 * sqrt(power_initial) + world.view - 2, 1)) + M.playsound_local(closest_to[M], null, 100, 1, frequency, max_distance = 5, S = explosion_sound) + if(baseshakeamount > 0) + shake_camera(M, 25, clamp(baseshakeamount, 0, 10)) + // You hear a far explosion if you're outside the blast radius. Small bombs shouldn't be heard all over the station. + else if(dist <= far_dist) + var/far_volume = clamp(far_dist, 30, 50) // Volume is based on explosion size and dist + far_volume += (dist <= far_dist * 0.5 ? 50 : 0) // add 50 volume if the mob is pretty close to the explosion + M.playsound_local(closest_to[M], null, far_volume, 1, frequency, max_distance = 5, S = far_explosion_sound) + if(baseshakeamount > 0) + shake_camera(M, 10, clamp(baseshakeamount*0.25, 0, 2.5)) + + for(var/i in 1 to to_flash.len) + var/mob/living/L = to_flash[i] + L.flash_act() + + SSblackbox.record_feedback("associative", "wave_explosion", 1, feedback) + + if(!cycle) + cycle = 1 + SSexplosions.active_wave_explosions += src + running = TRUE + cycle_start = world.time - cycle_speed + tick() + +/datum/wave_explosion/proc/stop(delete = TRUE) + SSexplosions.active_wave_explosions -= src + SSexplosions.currentrun -= src + edges = null + powers = null + exploded_last = null + cycle = null + running = FALSE + qdel(src) + +#define SHOULD_SUSPEND ((cycle_start + cycle_speed) > world.time) + +/** + * Called by SSexplosions to propagate this. + * Return TRUE if postponed + */ +/datum/wave_explosion/proc/tick() + /// Each tick goes through one full cycle. + // This can be changed to a "continuous process" system where indexes are tracked if needed. + if(!src.edges.len) + // we're done + finished = TRUE + stop(TRUE) + return TRUE + if(SHOULD_SUSPEND) + return TRUE + // Set up variables + var/turf/T + var/turf/expanding + var/power + var/returned + var/blocked + var/dir + // insanity define to explode a turf with a certain amount of power, direction, and set returned. +#define WEX_ACT(_T, _P, _D) \ + returned = max(0, _T.wave_explode(_P, src, _D)); \ + blocked = _P - returned; \ + if(!block_resistance) { \ + if(blocked > EXPLOSION_POWER_NO_RESIST_THRESHOLD) { \ + returned = 0; \ + } \ + } \ + else if(blocked) { \ + returned = _P - (blocked / block_resistance); \ + }; \ + returned = round((returned * power_falloff_factor) - power_falloff_constant, EXPLOSION_POWER_QUANTIZATION_ACCURACY); \ + if(prob(fire_probability)) { \ + new /obj/effect/hotspot(_T); \ + }; + + // Cache hot lists + var/list/turf/edges = src.edges + var/list/turf/powers = src.powers + var/list/turf/exploded_last = src.exploded_last + + // prepare expansions + var/list/turf/edges_next = list() + var/list/turf/powers_next = list() + var/list/turf/powers_returned = list() + var/list/turf/diagonals = list() + var/list/turf/diagonal_powers = list() + var/list/turf/diagonal_powers_max = list() + + // to_chat(world, "DEBUG: cycle start edges [english_list_assoc(edges)]") + + // Process cardinals: + // Explode all cardinals and expand in directions, gathering all cardinals it should go to. + // Power for when things meet in the middle should be the greatest of the two. + for(var/i in edges) + T = i + power = powers[T] + dir = edges[T] + WEX_ACT(T, power, dir) + if(returned < power_considered_dead) + continue + powers_returned[T] = returned + // diagonal power calc when multiple things hit one diagonal +#define CALCULATE_DIAGONAL_POWER(existing, adding, maximum) min(maximum, existing + adding) + // diagonal hitting cardinal expansion +#define CALCULATE_DIAGONAL_CROSS_POWER(existing, adding) max(existing, adding) + // insanity define to mark the next set of cardinals. +#define CARDINAL_MARK(ndir, cdir, edir) \ + if(edir & cdir) { \ + CARDINAL_MARK_NOCHECK(ndir, cdir, edir); \ + }; + +#define CARDINAL_MARK_NOCHECK(ndir, cdir, edir) \ + expanding = get_step(T,ndir); \ + if(expanding && !exploded_last[expanding] && !edges[expanding]) { \ + powers_next[expanding] = max(powers_next[expanding], returned); \ + edges_next[expanding] = (cdir | edges_next[expanding]); \ + }; + + // insanity define to do diagonal marking as 2 substeps +#define DIAGONAL_SUBSTEP(ndir, cdir, edir) \ + expanding = get_step(T,ndir); \ + if(expanding && !exploded_last[expanding] && !edges[expanding]) { \ + if(!edges_next[expanding]) { \ + diagonal_powers_max[expanding] = max(diagonal_powers_max[expanding], returned, powers[T]); \ + diagonal_powers[expanding] = CALCULATE_DIAGONAL_POWER(diagonal_powers[expanding], returned, diagonal_powers_max[expanding]); \ + diagonals[expanding] = (cdir | diagonals[expanding]); \ + }; \ + else { \ + powers_next[expanding] = CALCULATE_DIAGONAL_CROSS_POWER(powers_next[expanding], returned); \ + }; \ + }; + + // insanity define to mark the diagonals that would otherwise be missed +#define DIAGONAL_MARK(ndir, cdir, edir) \ + if(edir & cdir) { \ + DIAGONAL_MARK_NOCHECK(ndir, cdir, edir); \ + }; + + // this only works because right now, WEX_DIR_X is the same as a byond dir + // and we know we're only passing in one dir at a time. + // if this ever stops being the case, and explosions break when you touch this, now you know why. +#define DIAGONAL_MARK_NOCHECK(ndir, cdir, edir) \ + DIAGONAL_SUBSTEP(turn(ndir, 90), turn(cdir, 90), edir); \ + DIAGONAL_SUBSTEP(turn(ndir, -90), turn(cdir, -90), edir); + + // mark +#define MARK(ndir, cdir, edir) \ + if(edir & cdir) { \ + CARDINAL_MARK_NOCHECK(ndir, cdir, edir); \ + DIAGONAL_MARK_NOCHECK(ndir, cdir, edir); \ + }; + CARDINAL_MARK(NORTH, WEX_DIR_NORTH, dir) + CARDINAL_MARK(SOUTH, WEX_DIR_SOUTH, dir) + CARDINAL_MARK(EAST, WEX_DIR_EAST, dir) + CARDINAL_MARK(WEST, WEX_DIR_WEST, dir) + + // to_chat(world, "DEBUG: cycle mid edges_next [english_list_assoc(edges_next)]") + + // Sweep after cardinals for diagonals + for(var/i in edges) + T = i + power = powers[T] + dir = edges[T] + returned = powers_returned[T] + DIAGONAL_MARK(NORTH, WEX_DIR_NORTH, dir) + DIAGONAL_MARK(SOUTH, WEX_DIR_SOUTH, dir) + DIAGONAL_MARK(EAST, WEX_DIR_EAST, dir) + DIAGONAL_MARK(WEST, WEX_DIR_WEST, dir) + + // to_chat(world, "DEBUG: cycle mid diagonals [english_list_assoc(diagonals)]") + + // Process diagonals: + for(var/i in diagonals) + T = i + power = diagonal_powers[T] + dir = diagonals[T] + WEX_ACT(T, power, dir) + if(returned < power_considered_dead) + continue + CARDINAL_MARK(NORTH, WEX_DIR_NORTH, dir) + CARDINAL_MARK(SOUTH, WEX_DIR_SOUTH, dir) + CARDINAL_MARK(EAST, WEX_DIR_EAST, dir) + CARDINAL_MARK(WEST, WEX_DIR_WEST, dir) + + // to_chat(world, "DEBUG: cycle end edges_next [english_list_assoc(edges_next)]") + + // flush lists + src.exploded_last = edges + diagonals + src.edges = edges_next + src.powers = powers_next + cycle++ + cycle_start = world.time + +#undef SHOULD_SUSPEND + +#undef WEX_ACT + +#undef DIAGONAL_SUBSTEP +#undef DIAGONAL_MARK +#undef CARDINAL_MARK +#undef MARK diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 18674cdb17..3009831da7 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -36,6 +36,14 @@ ///Value used to increment ex_act() if reactionary_explosions is on var/explosion_block = 0 + /// Flags for explosions + var/explosion_flags = NONE + /// Amount to decrease wave explosions by + var/wave_explosion_block = 0 + /// Amount to multiply wave explosions by + var/wave_explosion_multiply = 1 + + //its inherent color, the colored paint applied on it, special color effect etc... /** * used to store the different colors on an atom * @@ -43,7 +51,6 @@ */ var/list/atom_colours - /// a very temporary list of overlays to remove var/list/remove_overlays /// a very temporary list of overlays to add @@ -556,6 +563,34 @@ contents_explosion(severity, target) SEND_SIGNAL(src, COMSIG_ATOM_EX_ACT, severity, target) +/** + * Called when a wave explosion hits this atom. Do not override this. + * + * Returns explosion power to "allow through". + */ +/atom/proc/wave_explode(power, datum/wave_explosion/explosion, dir) + set waitfor = FALSE + // SHOULD_NOT_SLEEP(TRUE) + SHOULD_NOT_OVERRIDE(TRUE) + SEND_SIGNAL(src, COMSIG_ATOM_WAVE_EX_ACT, args) + . = wave_ex_act(power, explosion, dir) // this must happen first for stuff like destruction/damage to tick. + if(isnull(.)) + stack_trace("wave_ex_act on [type] failed to return a number. defaulting to no blocking.") + return power + if((explosion_flags & EXPLOSION_FLAG_DENSITY_DEPENDENT) && !density) + return power // no block + else if((explosion_flags & EXPLOSION_FLAG_HARD_OBSTACLE) && !QDELETED(src)) + return 0 // fully blocked + +/** + * Called when a wave explosion hits this atom. + * + * Returns explosion power to "allow through". Standard handling and flag overrides in [wave_explode()]. + */ +/atom/proc/wave_ex_act(power, datum/wave_explosion/explosion, dir) + // SHOULD_NOT_SLEEP(TRUE) + return power * wave_explosion_multiply - wave_explosion_block + /atom/proc/blob_act(obj/structure/blob/B) SEND_SIGNAL(src, COMSIG_ATOM_BLOB_ACT, B) return diff --git a/code/game/machinery/_machinery.dm b/code/game/machinery/_machinery.dm index d26f8c5639..2ccf7d317d 100644 --- a/code/game/machinery/_machinery.dm +++ b/code/game/machinery/_machinery.dm @@ -96,6 +96,10 @@ Class Procs: flags_ricochet = RICOCHET_HARD ricochet_chance_mod = 0.3 + explosion_flags = EXPLOSION_FLAG_DENSITY_DEPENDENT + wave_explosion_block = EXPLOSION_BLOCK_MACHINE + wave_explosion_multiply = EXPLOSION_DAMPEN_MACHINE + anchored = TRUE interaction_flags_atom = INTERACT_ATOM_ATTACK_HAND | INTERACT_ATOM_UI_INTERACT diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm index f4a65ce984..4eed168ad6 100644 --- a/code/game/machinery/doors/airlock.dm +++ b/code/game/machinery/doors/airlock.dm @@ -54,6 +54,8 @@ assemblytype = /obj/structure/door_assembly normalspeed = 1 explosion_block = 1 + wave_explosion_block = EXPLOSION_BLOCK_WALL + wave_explosion_multiply = EXPLOSION_DAMPEN_WALL hud_possible = list(DIAG_AIRLOCK_HUD) interaction_flags_machine = INTERACT_MACHINE_WIRES_IF_OPEN | INTERACT_MACHINE_ALLOW_SILICON | INTERACT_MACHINE_OPEN_SILICON | INTERACT_MACHINE_REQUIRES_SILICON | INTERACT_MACHINE_OPEN diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm index 63a8ad22d4..a20374f878 100644 --- a/code/game/machinery/doors/door.dm +++ b/code/game/machinery/doors/door.dm @@ -16,6 +16,11 @@ interaction_flags_atom = INTERACT_ATOM_UI_INTERACT + wave_explosion_block = EXPLOSION_BLOCK_DENSE_FILLER + wave_explosion_multiply = EXPLOSION_DAMPEN_DENSE_FILLER + + explosion_flags = EXPLOSION_FLAG_HARD_OBSTACLE | EXPLOSION_FLAG_DENSITY_DEPENDENT + var/secondsElectrified = 0 var/air_tight = FALSE //TRUE means density will be set as soon as the door begins to close var/shockedby @@ -412,3 +417,8 @@ /obj/machinery/door/GetExplosionBlock() return density ? real_explosion_block : 0 + +/obj/machinery/door/wave_explosion_damage(power, datum/wave_explosion/explosion) + . = ..() + if(!density) + return . * EXPLOSION_DAMAGE_OPEN_DOOR_FACTOR diff --git a/code/game/machinery/doors/passworddoor.dm b/code/game/machinery/doors/passworddoor.dm index 1ec5b3c373..0c64151bca 100644 --- a/code/game/machinery/doors/passworddoor.dm +++ b/code/game/machinery/doors/passworddoor.dm @@ -71,3 +71,6 @@ /obj/machinery/door/password/ex_act(severity, target) return + +/obj/machinery/door/password/wave_ex_act(power, datum/wave_explosion/explosion, dir) + return 0 //no. diff --git a/code/game/machinery/doors/poddoor.dm b/code/game/machinery/doors/poddoor.dm index 4226d8a439..8c7fc692bc 100644 --- a/code/game/machinery/doors/poddoor.dm +++ b/code/game/machinery/doors/poddoor.dm @@ -8,6 +8,8 @@ closingLayer = CLOSED_BLASTDOOR_LAYER sub_door = TRUE explosion_block = 3 + wave_explosion_block = EXPLOSION_BLOCK_BLAST_PROOF + wave_explosion_multiply = EXPLOSION_DAMPEN_BLAST_PROOF heat_proof = TRUE safe = FALSE max_integrity = 600 diff --git a/code/game/machinery/doors/windowdoor.dm b/code/game/machinery/doors/windowdoor.dm index dd885542c9..af7545d3c9 100644 --- a/code/game/machinery/doors/windowdoor.dm +++ b/code/game/machinery/doors/windowdoor.dm @@ -360,6 +360,8 @@ max_integrity = 300 //Stronger doors for prison (regular window door health is 200) reinf = 1 explosion_block = 1 + wave_explosion_block = EXPLOSION_BLOCK_REINFORCED_WINDOW + wave_explosion_multiply = EXPLOSION_DAMPEN_REINFORCED_WINDOW /obj/machinery/door/window/brigdoor/security/cell name = "cell door" diff --git a/code/game/machinery/doppler_array.dm b/code/game/machinery/doppler_array.dm index 1cdb81ee1d..2066e88f85 100644 --- a/code/game/machinery/doppler_array.dm +++ b/code/game/machinery/doppler_array.dm @@ -114,6 +114,44 @@ GLOBAL_LIST_EMPTY(doppler_arrays) LAZYADD(message_log, messages.Join(" ")) return TRUE +/obj/machinery/doppler_array/proc/sense_wave_explosion(turf/epicenter, power, speed) + if(stat & NOPOWER) + return FALSE + var/turf/zone = get_turf(src) + if(zone.z != epicenter.z) + return FALSE + + if(next_announce > world.time) + return FALSE + next_announce = world.time + cooldown + + var/distance = get_dist(epicenter, zone) + var/direct = get_dir(zone, epicenter) + + if(distance > max_dist) + return FALSE + if(!(direct & dir) && !integrated) + return FALSE + + + var/list/messages = list("Explosive shockwave detected.", \ + "Epicenter at: grid ([epicenter.x],[epicenter.y]). Shockwave expanding at a theoretical speed of [speed] m/s.", \ + "Wave energy: [power]MJ.") + + if(integrated) + var/obj/item/clothing/head/helmet/space/hardsuit/helm = loc + if(!helm || !istype(helm, /obj/item/clothing/head/helmet/space/hardsuit)) + return FALSE + helm.display_visor_message("Waveform explosion detected! Wave energy: [power]MJ.") + else + for(var/message in messages) + say(message) + if(LAZYLEN(message_log) > list_limit) + say("Storage buffer is full! Clearing buffers...") + LAZYCLEARLIST(message_log) + LAZYADD(message_log, messages.Join(" ")) + return TRUE + /obj/machinery/doppler_array/examine(mob/user) . = ..() . += "Its dish is facing to the [dir2text(dir)]." diff --git a/code/game/objects/effects/decals/cleanable/misc.dm b/code/game/objects/effects/decals/cleanable/misc.dm index bb566f4d87..fe4ab20617 100644 --- a/code/game/objects/effects/decals/cleanable/misc.dm +++ b/code/game/objects/effects/decals/cleanable/misc.dm @@ -50,6 +50,10 @@ /obj/effect/decal/cleanable/glass/ex_act() qdel(src) +/obj/effect/decal/cleanable/glass/wave_ex_act(power, datum/wave_explosion/explosion, dir) + qdel(src) + return power + /obj/effect/decal/cleanable/glass/plasma icon_state = "plasmatiny" @@ -131,6 +135,9 @@ /obj/effect/decal/cleanable/greenglow/ex_act() return +/obj/effect/decal/cleanable/greenglow/wave_ex_act(power, datum/wave_explosion/explosion, dir) + return power + /obj/effect/decal/cleanable/cobweb name = "cobweb" desc = "Somebody should remove that." @@ -253,6 +260,11 @@ if(severity == 1) //so shreds created during an explosion aren't deleted by the explosion. qdel(src) +/obj/effect/decal/cleanable/shreds/wave_ex_act(power, datum/wave_explosion/explosion, dir) + if(power > EXPLOSION_POWER_ERASE_SHREDS) + qdel(src) + return power // no block + /obj/effect/decal/cleanable/shreds/Initialize() pixel_x = rand(-10, 10) pixel_y = rand(-10, 10) diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index 8a09bca0bf..5089d26c88 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -248,6 +248,14 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb loc = null loc = T +/obj/item/wave_ex_act(power, datum/wave_explosion/explosion, dir) + . = ..() + if(!anchored) + var/throw_dist = round(rand(3, max(3, 2.5 * sqrt(power))), 1) + throw_speed = EXPLOSION_THROW_SPEED + var/turf/target = get_ranged_target_turf(src, dir, throw_dist) + throw_at(target, throw_dist, EXPLOSION_THROW_SPEED) + /obj/item/examine(mob/user) //This might be spammy. Remove? . = ..() diff --git a/code/game/objects/items/crayons.dm b/code/game/objects/items/crayons.dm index e584cad9e8..aa48930d6c 100644 --- a/code/game/objects/items/crayons.dm +++ b/code/game/objects/items/crayons.dm @@ -649,6 +649,9 @@ pre_noise = TRUE post_noise = FALSE + var/stun_delay = 0 // how long it takes for you to be able to stun someone with the spraycan again + var/last_stun_time = 0 + /obj/item/toy/crayon/spraycan/isValidSurface(surface) return (istype(surface, /turf/open/floor) || istype(surface, /turf/closed/wall)) @@ -716,7 +719,8 @@ if(C.client) C.blur_eyes(3) C.blind_eyes(1) - if(C.get_eye_protection() <= 0) // no eye protection? ARGH IT BURNS. + if(C.get_eye_protection() <= 0 && (last_stun_time + stun_delay) <= world.time) // no eye protection? ARGH IT BURNS. + last_stun_time = world.time C.confused = max(C.confused, 3) C.DefaultCombatKnockdown(60) if(ishuman(C) && actually_paints) @@ -771,6 +775,7 @@ name = "cyborg spraycan" desc = "A metallic container containing shiny synthesised paint." charges = -1 + stun_delay = 5 SECONDS /obj/item/toy/crayon/spraycan/borg/draw_on(atom/target,mob/user,proximity, params) var/diff = ..() diff --git a/code/game/objects/obj_defense.dm b/code/game/objects/obj_defense.dm index 73a21e4a25..02f2009667 100644 --- a/code/game/objects/obj_defense.dm +++ b/code/game/objects/obj_defense.dm @@ -71,6 +71,19 @@ if(3) take_damage(rand(10, 90), BRUTE, "bomb", 0) +/obj/wave_ex_act(power, datum/wave_explosion/explosion, dir) + if(resistance_flags & INDESTRUCTIBLE) + return power + . = ..() + if(explosion.source == src) + obj_integrity = 0 + qdel(src) + return + take_damage(wave_explosion_damage(power, explosion), BRUTE, "bomb", 0) + +/obj/proc/wave_explosion_damage(power, datum/wave_explosion/explosion) + return (explosion_flags & EXPLOSION_FLAG_HARD_OBSTACLE)? EXPLOSION_POWER_STANDARD_SCALE_HARD_OBSTACLE_DAMAGE(power, explosion.hard_obstacle_mod) : EXPLOSION_POWER_STANDARD_SCALE_OBJECT_DAMAGE(power, explosion.object_damage_mod) + /obj/bullet_act(obj/item/projectile/P) . = ..() playsound(src, P.hitsound, 50, 1) diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm index 53bcd28fa1..e40e158895 100644 --- a/code/game/objects/structures/window.dm +++ b/code/game/objects/structures/window.dm @@ -43,6 +43,10 @@ GLOBAL_LIST_EMPTY(electrochromatic_window_lookup) attack_hand_speed = CLICK_CD_MELEE attack_hand_is_action = TRUE + explosion_flags = EXPLOSION_FLAG_HARD_OBSTACLE + wave_explosion_block = EXPLOSION_BLOCK_WINDOW + wave_explosion_multiply = EXPLOSION_DAMPEN_WINDOW + /// Electrochromatic status var/electrochromatic_status = NOT_ELECTROCHROMATIC /// Electrochromatic ID. Set the first character to ! to replace with a SSmapping generated pseudorandom obfuscated ID for mapping purposes. @@ -111,6 +115,9 @@ GLOBAL_LIST_EMPTY(electrochromatic_window_lookup) return TRUE return FALSE +/obj/structure/window/wave_explosion_damage(power, datum/wave_explosion/explosion) + return EXPLOSION_POWER_STANDARD_SCALE_WINDOW_DAMAGE(power, explosion.window_shatter_mod) + /obj/structure/window/narsie_act() add_atom_colour(NARSIE_WINDOW_COLOUR, FIXED_COLOUR_PRIORITY) @@ -520,6 +527,8 @@ GLOBAL_LIST_EMPTY(electrochromatic_window_lookup) armor = list("melee" = 50, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 25, "bio" = 100, "rad" = 100, "fire" = 80, "acid" = 100) max_integrity = 50 explosion_block = 1 + wave_explosion_block = EXPLOSION_BLOCK_REINFORCED_WINDOW + wave_explosion_multiply = EXPLOSION_DAMPEN_REINFORCED_WINDOW glass_type = /obj/item/stack/sheet/rglass rad_insulation = RAD_HEAVY_INSULATION ricochet_chance_mod = 0.8 @@ -545,6 +554,8 @@ GLOBAL_LIST_EMPTY(electrochromatic_window_lookup) armor = list("melee" = 75, "bullet" = 5, "laser" = 0, "energy" = 0, "bomb" = 45, "bio" = 100, "rad" = 100, "fire" = 99, "acid" = 100) max_integrity = 150 explosion_block = 1 + wave_explosion_block = EXPLOSION_BLOCK_BOROSILICATE_WINDOW + wave_explosion_multiply = EXPLOSION_DAMPEN_BOROSILICATE_WINDOW glass_type = /obj/item/stack/sheet/plasmaglass cleanable_type = /obj/effect/decal/cleanable/glass/plasma rad_insulation = RAD_NO_INSULATION @@ -570,6 +581,8 @@ GLOBAL_LIST_EMPTY(electrochromatic_window_lookup) armor = list("melee" = 85, "bullet" = 20, "laser" = 0, "energy" = 0, "bomb" = 60, "bio" = 100, "rad" = 100, "fire" = 99, "acid" = 100) max_integrity = 500 explosion_block = 2 + wave_explosion_block = EXPLOSION_BLOCK_EXTREME + wave_explosion_multiply = EXPLOSION_BLOCK_EXTREME glass_type = /obj/item/stack/sheet/plasmarglass /obj/structure/window/plasma/reinforced/spawner/east @@ -742,6 +755,8 @@ GLOBAL_LIST_EMPTY(electrochromatic_window_lookup) max_integrity = 80 armor = list("melee" = 60, "bullet" = 25, "laser" = 0, "energy" = 0, "bomb" = 25, "bio" = 100, "rad" = 100, "fire" = 80, "acid" = 100) explosion_block = 2 //fancy AND hard to destroy. the most useful combination. + wave_explosion_block = EXPLOSION_BLOCK_BOROSILICATE_WINDOW + wave_explosion_multiply = EXPLOSION_DAMPEN_BOROSILICATE_WINDOW decon_speed = 40 glass_type = /obj/item/stack/tile/brass glass_amount = 1 diff --git a/code/game/turfs/closed.dm b/code/game/turfs/closed.dm index be0c444541..91a8ba4f46 100644 --- a/code/game/turfs/closed.dm +++ b/code/game/turfs/closed.dm @@ -6,6 +6,8 @@ blocks_air = 1 rad_flags = RAD_PROTECT_CONTENTS | RAD_NO_CONTAMINATE rad_insulation = RAD_MEDIUM_INSULATION + wave_explosion_block = 10 + wave_explosion_multiply = 0.75 /turf/closed/Initialize() . = ..() @@ -28,6 +30,7 @@ name = "wall" icon = 'icons/turf/walls.dmi' explosion_block = 50 + wave_explosion_block = INFINITY /turf/closed/indestructible/rust_heretic_act() return diff --git a/code/game/turfs/simulated/floor.dm b/code/game/turfs/simulated/floor.dm index 565d5640e3..e5034e4b2f 100644 --- a/code/game/turfs/simulated/floor.dm +++ b/code/game/turfs/simulated/floor.dm @@ -12,6 +12,19 @@ clawfootstep = FOOTSTEP_HARD_CLAW heavyfootstep = FOOTSTEP_GENERIC_HEAVY + /// Minimum explosion power to break tile + var/explosion_power_break_tile = EXPLOSION_POWER_FLOOR_TILE_BREAK + /// Minimum explosion power to break turf + var/explosion_power_break_turf = EXPLOSION_POWER_FLOOR_TURF_BREAK + //// Minimum explosion power to scrape away the floor + var/explosion_power_turf_scrape = EXPLOSION_POWER_FLOOR_TURF_SCRAPE + //// Shielded turfs are completely protected from anything under this + var/explosion_power_protect_shielded = EXPLOSION_POWER_FLOOR_SHIELDED_IMMUNITY + /// Starting from here, there's a chance for this to break + var/explosion_power_minimum_chance_break = EXPLOSION_POWER_FLOOR_MINIMUM_TURF_BREAK + /// Starting from here, +20% chance to break turf. + var/explosion_power_break_turf_bonus = EXPLOSION_POWER_FLOOR_TURF_BREAK_BONUS + var/icon_regular_floor = "floor" //used to remember what icon the tile should have by default var/icon_plating = "plating" thermal_conductivity = 0.004 @@ -98,6 +111,48 @@ src.break_tile() src.hotspot_expose(1000,CELL_VOLUME) +/turf/open/floor/wave_ex_act(power, datum/wave_explosion/explosion, dir) + var/shielded = is_shielded() + . = ..() + if(shielded) + if(power < explosion_power_protect_shielded) + return + else + power -= explosion_power_protect_shielded + hotspot_expose(1000, CELL_VOLUME) + if(power < explosion_power_break_tile) + return + if(power < explosion_power_minimum_chance_break) + if(prob(33 + ((explosion_power_break_turf - power) / (explosion_power_break_turf - explosion_power_break_tile)))) + break_tile() + return + if((power < explosion_power_turf_scrape) && ((power >= explosion_power_break_turf) || prob((1 - ((explosion_power_break_turf - power) / (explosion_power_break_turf - explosion_power_minimum_chance_break))) * 100 + ((power > explosion_power_break_turf_bonus)? 20 : 0)))) + switch(pick(1, 2;75, 3)) + if(1) + if(!length(baseturfs) || !ispath(baseturfs[baseturfs.len-1], /turf/open/floor)) + ScrapeAway(flags = CHANGETURF_INHERIT_AIR) + ReplaceWithLattice() + else + ScrapeAway(2, flags = CHANGETURF_INHERIT_AIR) + if(prob(33)) + new /obj/item/stack/sheet/metal(src) + return + if(2) + ScrapeAway(2, flags = CHANGETURF_INHERIT_AIR) + return + if(3) + if(prob(80)) + ScrapeAway(flags = CHANGETURF_INHERIT_AIR) + return + else + break_tile() + hotspot_expose(1000,CELL_VOLUME) + if(prob(33)) + new /obj/item/stack/sheet/metal(src) + if(power >= explosion_power_turf_scrape) + ScrapeAway(2, flags = CHANGETURF_INHERIT_AIR) + return + /turf/open/floor/is_shielded() for(var/obj/structure/A in contents) if(A.level == 3) diff --git a/code/game/turfs/simulated/wall/reinf_walls.dm b/code/game/turfs/simulated/wall/reinf_walls.dm index 03d5cecc26..620c9adfc8 100644 --- a/code/game/turfs/simulated/wall/reinf_walls.dm +++ b/code/game/turfs/simulated/wall/reinf_walls.dm @@ -12,6 +12,11 @@ sheet_amount = 1 girder_type = /obj/structure/girder/reinforced explosion_block = 2 + wave_explosion_block = EXPLOSION_BLOCK_BLAST_PROOF + wave_explosion_multiply = EXPLOSION_DAMPEN_BLAST_PROOF + explosion_power_to_scrape = EXPLOSION_POWER_RWALL_SCRAPE + explosion_power_to_dismantle = EXPLOSION_POWER_RWALL_DISMANTLE + explosion_power_minimum_chance_dismantle = EXPLOSION_POWER_RWALL_MINIMUM_DISMANTLE rad_insulation = RAD_HEAVY_INSULATION /turf/closed/wall/r_wall/deconstruction_hints(mob/user) diff --git a/code/game/turfs/simulated/walls.dm b/code/game/turfs/simulated/walls.dm index 79ca5add10..76dc6533b6 100644 --- a/code/game/turfs/simulated/walls.dm +++ b/code/game/turfs/simulated/walls.dm @@ -6,6 +6,8 @@ icon = 'icons/turf/walls/wall.dmi' icon_state = "wall" explosion_block = 1 + wave_explosion_block = EXPLOSION_BLOCK_WALL + wave_explosion_multiply = EXPLOSION_DAMPEN_WALL flags_1 = DEFAULT_RICOCHET_1 flags_ricochet = RICOCHET_HARD thermal_conductivity = WALL_HEAT_TRANSFER_COEFFICIENT @@ -15,6 +17,14 @@ baseturfs = /turf/open/floor/plating + explosion_flags = EXPLOSION_FLAG_HARD_OBSTACLE + /// Explosion power to disintegrate the wall + var/explosion_power_to_scrape = EXPLOSION_POWER_WALL_SCRAPE + /// Explosion power to dismantle the wall + var/explosion_power_to_dismantle = EXPLOSION_POWER_WALL_DISMANTLE + /// Explosion power to potentially dismantle the wall + var/explosion_power_minimum_chance_dismantle = EXPLOSION_POWER_WALL_MINIMUM_DISMANTLE + var/hardness = 40 //lower numbers are harder. Used to determine the probability of a hulk smashing through. var/slicing_duration = 100 //default time taken to slice the wall var/sheet_type = /obj/item/stack/sheet/metal @@ -91,6 +101,13 @@ if(!density) ..() +/turf/closed/wall/wave_ex_act(power, datum/wave_explosion/explosion, dir) + . = ..() + var/resultant_power = power * explosion.wall_destroy_mod + if(resultant_power >= explosion_power_to_scrape) + ScrapeAway() + else if((resultant_power >= explosion_power_to_dismantle) || ((resultant_power >= explosion_power_minimum_chance_dismantle) && prob(((resultant_power - explosion_power_minimum_chance_dismantle) / (explosion_power_to_dismantle - explosion_power_minimum_chance_dismantle)) * 100))) + dismantle_wall(prob((resultant_power - explosion_power_to_dismantle)/(explosion_power_to_scrape - explosion_power_to_dismantle)), TRUE) /turf/closed/wall/blob_act(obj/structure/blob/B) if(prob(50)) diff --git a/code/game/turfs/space/space.dm b/code/game/turfs/space/space.dm index 0905fb2e9c..b1a4efc97e 100644 --- a/code/game/turfs/space/space.dm +++ b/code/game/turfs/space/space.dm @@ -8,6 +8,8 @@ temperature = TCMB thermal_conductivity = OPEN_HEAT_TRANSFER_COEFFICIENT heat_capacity = 700000 + wave_explosion_multiply = EXPLOSION_DAMPEN_SPACE + wave_explosion_block = EXPLOSION_BLOCK_SPACE var/destination_z var/destination_x diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm index 0808408192..93735f1079 100755 --- a/code/game/turfs/turf.dm +++ b/code/game/turfs/turf.dm @@ -462,6 +462,24 @@ GLOBAL_LIST_EMPTY(station_turfs) A.ex_act(severity, target) CHECK_TICK +/turf/wave_ex_act(power, datum/wave_explosion/explosion, dir) + . = ..() + var/affecting_level + if(is_shielded()) + affecting_level = 3 + else if(intact) + affecting_level = 2 + else + affecting_level = 1 + var/atom/A + for(var/i in contents) + if(. <= 0) + return 0 + A = i + if(!QDELETED(A) && A.level >= affecting_level) + . = A.wave_explode(., explosion, dir) + maptext = "[.]" + /turf/narsie_act(force, ignore_mobs, probability = 20) . = (prob(probability) || force) for(var/I in src) diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index 96eb4e4a0f..9e784e72cb 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -96,6 +96,7 @@ GLOBAL_LIST_INIT(admin_verbs_fun, list( /client/proc/cmd_select_equipment, /client/proc/cmd_admin_gib_self, /client/proc/drop_bomb, + /client/proc/drop_wave_explosion, /client/proc/set_dynex_scale, /client/proc/drop_dynex_bomb, /client/proc/cinematic, @@ -550,6 +551,51 @@ GLOBAL_PROTECT(admin_verbs_hideable) log_admin("[key_name(usr)] created an admin explosion at [epicenter.loc].") SSblackbox.record_feedback("tally", "admin_verb", 1, "Drop Bomb") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! +/client/proc/drop_wave_explosion() + set category = "Special Verbs" + set name = "Drop Wave Explosion" + set desc = "Cause an explosive shockwave at your location." + + var/power = input(src, "Wave initial power", "Power", 50) as num|null + if(isnull(power)) + return + var/falloff = input(src, "Wave innate falloff factor", "Falloff", EXPLOSION_DEFAULT_FALLOFF_MULTIPLY) as num|null + if(isnull(falloff)) + return + falloff = max(0, falloff) + if(falloff > 1) + to_chat(src, "Aborting: Falloff cannot be higher tahn 1.") + return + var/constant = input(src, "Wave innate falloff constant", "Constant", EXPLOSION_DEFAULT_FALLOFF_SUBTRACT) as num|null + if(isnull(constant)) + return + if(constant < 0) + to_chat(src, "Aborting: Falloff constant cannot be less than 0.") + return + var/fire = input(src, "Probability per tile of fire?", "Fire Probability", 0) as num|null + if(isnull(fire)) + return + var/speed = input(src, "Speed in ticks to wait between cycles? 0 for fast as possible", "Wait", 0) as num|null + if(isnull(speed)) + return + var/block_resistance = input(src, "DANGEROUS: Block resistance? USE 1 IF YOU DO NOT KNOW WHAT YOU ARE DOING.", "Block Negation", 1) as num|null + if(isnull(block_resistance)) + return + block_resistance = max(0, block_resistance) + if(power > 500) + var/sure = alert(src, "Explosion power is extremely high. Are you absolutely sure?", "Uhh...", "No", "Yes") + if(sure != "Yes") + return + // point of no return + var/turf/target = get_turf(mob) + if(!target) + to_chat(src, "Cannot proceed. Not on turf.") + return + message_admins("[ADMIN_LOOKUPFLW(usr)] creating an admin explosion at [target.loc].") + log_admin("[key_name(usr)] created an admin explosion at [target.loc].") + SSblackbox.record_feedback("tally", "admin_verb", 1, "Drop Wave Explosion") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + wave_explosion(target, power, falloff, constant, null, fire, speed = speed, block_resistance = block_resistance) + /client/proc/drop_dynex_bomb() set category = "Admin.Fun" set name = "Drop DynEx Bomb" diff --git a/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm b/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm index 7d669e5c41..eb98635e65 100644 --- a/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm +++ b/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm @@ -633,7 +633,7 @@ This is here to make the tiles around the station mininuke change when it's arme AddComponent(/datum/component/stationloving, !fake) /obj/item/disk/nuclear/process() - ++process_tick + process_tick++ if(fake) STOP_PROCESSING(SSobj, src) CRASH("A fake nuke disk tried to call process(). Who the fuck and how the fuck") @@ -650,7 +650,7 @@ This is here to make the tiles around the station mininuke change when it's arme disk_comfort_level++ if(disk_comfort_level >= 2) //Sleep tight, disky. - if(process_tick % 30) + if(!(process_tick % 30)) visible_message("[src] sleeps soundly. Sleep tight, disky.") if(last_disk_move < world.time - 5000 && prob((world.time - 5000 - last_disk_move)*0.0001)) var/datum/round_event_control/operative/loneop = locate(/datum/round_event_control/operative) in SSevents.control diff --git a/code/modules/antagonists/revenant/revenant.dm b/code/modules/antagonists/revenant/revenant.dm index 7e4c5c5343..31989fe241 100644 --- a/code/modules/antagonists/revenant/revenant.dm +++ b/code/modules/antagonists/revenant/revenant.dm @@ -177,6 +177,9 @@ /mob/living/simple_animal/revenant/ex_act(severity, target) return 1 //Immune to the effects of explosions. +/mob/living/simple_animal/revenant/wave_ex_act(power, datum/wave_explosion/explosion, dir) + return power + /mob/living/simple_animal/revenant/blob_act(obj/structure/blob/B) return //blah blah blobs aren't in tune with the spirit world, or something. diff --git a/code/modules/awaymissions/gateway.dm b/code/modules/awaymissions/gateway.dm index 36ceabe3b4..551c1c5536 100644 --- a/code/modules/awaymissions/gateway.dm +++ b/code/modules/awaymissions/gateway.dm @@ -172,13 +172,15 @@ GLOBAL_LIST_EMPTY(gateway_destinations) /// bumper object, the thing that starts actual teleport var/obj/effect/gateway_portal_bumper/portal /// Visual object for handling the viscontents - var/obj/effect/gateway_portal_effect/portal_visuals + /// DISABLED DUE TO BYOND BUG CAUSING STACK OVERFLOWS OF ANY HUMAN INSTANTIATION NEAR AN ACTIVATED GATEWAY. + /// Probably due to it referencing each other through the gateway (there's a deep loop, maybe BYOND isn't catching something when it usually would) + // var/obj/effect/gateway_portal_effect/portal_visuals /obj/machinery/gateway/Initialize() generate_destination() update_icon() - portal_visuals = new - vis_contents += portal_visuals + // portal_visuals = new + // vis_contents += portal_visuals return ..() /obj/machinery/gateway/proc/generate_destination() @@ -195,7 +197,7 @@ GLOBAL_LIST_EMPTY(gateway_destinations) if(use_power == ACTIVE_POWER_USE) use_power = IDLE_POWER_USE update_icon() - portal_visuals.reset_visuals() + // portal_visuals.reset_visuals() /obj/machinery/gateway/process() if((stat & (NOPOWER)) && use_power) @@ -215,7 +217,7 @@ GLOBAL_LIST_EMPTY(gateway_destinations) return target = D target.activate(destination) - portal_visuals.setup_visuals(target) + // portal_visuals.setup_visuals(target) generate_bumper() use_power = ACTIVE_POWER_USE update_icon() diff --git a/code/modules/food_and_drinks/recipes/drinks_recipes.dm b/code/modules/food_and_drinks/recipes/drinks_recipes.dm index 972f9a8cc3..943f421a64 100644 --- a/code/modules/food_and_drinks/recipes/drinks_recipes.dm +++ b/code/modules/food_and_drinks/recipes/drinks_recipes.dm @@ -604,6 +604,14 @@ mix_message = "You hear faint sounds of gears turning as it mixes." mix_sound = 'sound/machines/clockcult/steam_whoosh.ogg' +/datum/chemical_reaction/pinotmort + name = "Pinot Mort" + id = /datum/reagent/consumable/ethanol/pinotmort + results = list(/datum/reagent/consumable/ethanol/pinotmort = 4) + required_reagents = list(/datum/reagent/ash = 2, /datum/reagent/consumable/ethanol/lizardwine = 1, /datum/reagent/consumable/vitfro = 1) + mix_message = "You hear an undescribable scream as it mixes... You're not sure how to feel about this." + mix_sound = 'sound/effects/tendril_destroyed.ogg' + /datum/chemical_reaction/quadruplesec name = "Quadruple Sec" id = /datum/reagent/consumable/ethanol/quadruple_sec diff --git a/code/modules/holiday/halloween/halloween.dm b/code/modules/holiday/halloween/halloween.dm index d44b94aaf3..f468022918 100644 --- a/code/modules/holiday/halloween/halloween.dm +++ b/code/modules/holiday/halloween/halloween.dm @@ -206,6 +206,9 @@ /mob/living/simple_animal/hostile/retaliate/clown/insane/ex_act() return +/mob/living/simple_animal/hostile/retaliate/clown/insane/wave_ex_act(power, datum/wave_explosion/explosion, dir) + return power + /mob/living/simple_animal/hostile/retaliate/clown/insane/Life() timer-- if(target) diff --git a/code/modules/mob/dead/new_player/sprite_accessories/ears.dm b/code/modules/mob/dead/new_player/sprite_accessories/ears.dm index e09a0386ee..8fb735e10a 100644 --- a/code/modules/mob/dead/new_player/sprite_accessories/ears.dm +++ b/code/modules/mob/dead/new_player/sprite_accessories/ears.dm @@ -67,6 +67,13 @@ matrixed_sections = MATRIX_RED_GREEN icon = 'modular_citadel/icons/mob/mam_ears.dmi' +/datum/sprite_accessory/ears/bunnyalt + name = "Bunny (Vegas)" + icon_state = "bunnyalt" + color_src = MATRIXED + matrixed_sections = MATRIX_RED_GREEN + icon = 'modular_citadel/icons/mob/mam_ears.dmi' + /datum/sprite_accessory/ears/cat name = "Cat" icon_state = "cat" @@ -258,6 +265,11 @@ icon_state = "bunny" matrixed_sections = MATRIX_RED_GREEN +/datum/sprite_accessory/ears/mam_ears/bunnyalt + name = "Bunny (Vegas)" + icon_state = "bunnyalt" + matrixed_sections = MATRIX_RED_GREEN + /datum/sprite_accessory/ears/mam_ears/cat name = "Cat" icon_state = "cat" diff --git a/code/modules/mob/living/bloodcrawl.dm b/code/modules/mob/living/bloodcrawl.dm index 24d456bf8f..b66158db8a 100644 --- a/code/modules/mob/living/bloodcrawl.dm +++ b/code/modules/mob/living/bloodcrawl.dm @@ -13,6 +13,10 @@ /obj/effect/dummy/phased_mob/slaughter/ex_act() return + +/obj/effect/dummy/phased_mob/slaughter/wave_ex_act(power, datum/wave_explosion/explosion, dir) + return power + /obj/effect/dummy/phased_mob/slaughter/bullet_act() return BULLET_ACT_FORCE_PIERCE diff --git a/code/modules/mob/living/brain/brain.dm b/code/modules/mob/living/brain/brain.dm index be03827695..8ffcce248b 100644 --- a/code/modules/mob/living/brain/brain.dm +++ b/code/modules/mob/living/brain/brain.dm @@ -46,6 +46,9 @@ /mob/living/brain/ex_act() //you cant blow up brainmobs because it makes transfer_to() freak out when borgs blow up. return +/mob/living/brain/wave_ex_act(power, datum/wave_explosion/explosion, dir) + return power + /mob/living/brain/blob_act(obj/structure/blob/B) return diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 6f5109c90b..c1110af267 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -370,7 +370,7 @@ breakouttime = 50 visible_message("[src] is trying to break [I]!") to_chat(src, "You attempt to break [I]... (This will take around 5 seconds and you need to stand still.)") - if(do_after(src, breakouttime, 0, target = src)) + if(do_after(src, breakouttime, 0, target = src, required_mobility_flags = MOBILITY_RESIST)) clear_cuffs(I, cuff_break) else to_chat(src, "You fail to break [I]!") diff --git a/code/modules/mob/living/carbon/human/species_types/anthromorph.dm b/code/modules/mob/living/carbon/human/species_types/anthropomorph.dm similarity index 97% rename from code/modules/mob/living/carbon/human/species_types/anthromorph.dm rename to code/modules/mob/living/carbon/human/species_types/anthropomorph.dm index d718db818c..328a557931 100644 --- a/code/modules/mob/living/carbon/human/species_types/anthromorph.dm +++ b/code/modules/mob/living/carbon/human/species_types/anthropomorph.dm @@ -1,5 +1,5 @@ /datum/species/mammal - name = "Anthromorph" + name = "Anthropomorph" id = SPECIES_MAMMAL default_color = "4B4B4B" species_traits = list(MUTCOLORS,EYECOLOR,LIPS,HAIR,HORNCOLOR,WINGCOLOR,HAS_FLESH,HAS_BONE) @@ -20,7 +20,7 @@ allowed_limb_ids = list("mammal","aquatic","avian") /datum/species/mammal/synthetic - name = "Synthetic Anthromorph" + name = "Synthetic Anthropomorph" id = SPECIES_MAMMAL_SYNTHETIC species_traits = list(MUTCOLORS,NOTRANSSTING,EYECOLOR,LIPS,HAIR,ROBOTIC_LIMBS,HAS_FLESH,HAS_BONE,WINGCOLOR,HORNCOLOR) diff --git a/code/modules/mob/living/carbon/human/species_types/bugmen.dm b/code/modules/mob/living/carbon/human/species_types/bugmen.dm index 773651d464..c649339fe3 100644 --- a/code/modules/mob/living/carbon/human/species_types/bugmen.dm +++ b/code/modules/mob/living/carbon/human/species_types/bugmen.dm @@ -1,5 +1,5 @@ /datum/species/insect - name = "Anthromorphic Insect" + name = "Anthropomorphic Insect" id = SPECIES_INSECT say_mod = "chitters" default_color = "00FF00" diff --git a/code/modules/mob/living/carbon/human/species_types/flypeople.dm b/code/modules/mob/living/carbon/human/species_types/flypeople.dm index c3e406244b..5a185cbeb8 100644 --- a/code/modules/mob/living/carbon/human/species_types/flypeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/flypeople.dm @@ -1,5 +1,5 @@ /datum/species/fly - name = "Anthromorphic Fly" + name = "Anthropomorphic Fly" id = SPECIES_FLY say_mod = "buzzes" species_traits = list(NOEYES,HAS_FLESH,HAS_BONE) diff --git a/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm b/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm index 40645b13d4..cfbb8c31c0 100644 --- a/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm @@ -1,6 +1,6 @@ /datum/species/lizard // Reptilian humanoids with scaled skin and tails. - name = "Anthromorphic Lizard" + name = "Anthropomorphic Lizard" id = SPECIES_LIZARD say_mod = "hisses" default_color = "00FF00" diff --git a/code/modules/mob/living/carbon/human/species_types/mushpeople.dm b/code/modules/mob/living/carbon/human/species_types/mushpeople.dm index dcbdf91485..0655b28197 100644 --- a/code/modules/mob/living/carbon/human/species_types/mushpeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/mushpeople.dm @@ -1,5 +1,5 @@ /datum/species/mush //mush mush codecuck - name = "Anthromorphic Mushroom" + name = "Anthropomorphic Mushroom" id = SPECIES_MUSHROOM mutant_bodyparts = list("caps" = "Round") diff --git a/code/modules/mob/living/carbon/human/species_types/podpeople.dm b/code/modules/mob/living/carbon/human/species_types/podpeople.dm index 697c3db35e..0fcafaa208 100644 --- a/code/modules/mob/living/carbon/human/species_types/podpeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/podpeople.dm @@ -1,6 +1,6 @@ /datum/species/pod // A mutation caused by a human being ressurected in a revival pod. These regain health in light, and begin to wither in darkness. - name = "Anthromorphic Plant" + name = "Anthropomorphic Plant" id = SPECIES_POD default_color = "59CE00" species_traits = list(MUTCOLORS,EYECOLOR,CAN_SCAR,HAS_FLESH,HAS_BONE) @@ -71,7 +71,7 @@ H.emote("spin") /datum/species/pod/pseudo_weak - name = "Anthromorphic Plant" + name = "Anthropomorphic Plant" id = SPECIES_POD_WEAK species_traits = list(EYECOLOR,HAIR,FACEHAIR,LIPS,MUTCOLORS,CAN_SCAR,HAS_FLESH,HAS_BONE) mutant_bodyparts = list("mcolor" = "FFFFFF","mcolor2" = "FFFFFF","mcolor3" = "FFFFFF", "mam_snouts" = "Husky", "mam_tail" = "Husky", "mam_ears" = "Husky", "mam_body_markings" = "Husky", "taur" = "None", "legs" = "Normal Legs") diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index 5f3f530437..4c6ede3904 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -438,6 +438,12 @@ return ..() +/mob/living/wave_ex_act(power, datum/wave_explosion/explosion, dir) + if(power > EXPLOSION_POWER_NORMAL_MOB_GIB) + gib() + adjustBruteLoss(EXPLOSION_POWER_STANDARD_SCALE_MOB_DAMAGE(power, explosion.mob_damage_mod)) + return power + //Looking for irradiate()? It's been moved to radiation.dm under the rad_act() for mobs. /mob/living/acid_act(acidpwr, acid_volume) diff --git a/code/modules/mob/living/simple_animal/guardian/guardian.dm b/code/modules/mob/living/simple_animal/guardian/guardian.dm index 012515d0e9..7c7ff3779c 100644 --- a/code/modules/mob/living/simple_animal/guardian/guardian.dm +++ b/code/modules/mob/living/simple_animal/guardian/guardian.dm @@ -280,6 +280,9 @@ GLOBAL_LIST_EMPTY(parasites) //all currently existing/living guardians if(3) adjustBruteLoss(30) +/mob/living/simple_animal/hostile/guardian/wave_ex_act(power, datum/wave_explosion/explosion, dir) + adjustBruteLoss(EXPLOSION_POWER_STANDARD_SCALE_MOB_DAMAGE(power, explosion.mob_damage_mod * 0.33)) + /mob/living/simple_animal/hostile/guardian/gib() if(summoner) to_chat(summoner, "Your [src] was blown up!") 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 e2d6602a88..3940388625 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/megafauna.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/megafauna.dm @@ -149,6 +149,9 @@ if(EXPLODE_LIGHT) adjustBruteLoss(50) +/mob/living/simple_animal/hostile/megafauna/wave_ex_act(power, datum/wave_explosion/explosion, dir) + adjustBruteLoss(EXPLOSION_POWER_STANDARD_SCALE_MOB_DAMAGE(power, explosion.mob_damage_mod) / 2) + /// Sets the next time the megafauna can use a melee or ranged attack, in deciseconds /mob/living/simple_animal/hostile/megafauna/proc/SetRecoveryTime(buffer_time, ranged_buffer_time) recovery_time = world.time + buffer_time diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/basilisk.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/basilisk.dm index cee7e2979d..bda898ef17 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/basilisk.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/basilisk.dm @@ -59,6 +59,13 @@ if(3) adjustBruteLoss(110) +/mob/living/simple_animal/hostile/asteroid/basilisk/wave_ex_act(power, datum/wave_explosion/explosion, dir) + . = ..() + if(power > EXPLOSION_POWER_NORMAL_MOB_GIB) + gib() + else + adjustBruteLoss(EXPLOSION_POWER_STANDARD_SCALE_MOB_DAMAGE(power, explosion.mob_damage_mod)) + //Watcher /mob/living/simple_animal/hostile/asteroid/basilisk/watcher name = "watcher" diff --git a/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm b/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm index aae21464b1..f53ac7ac40 100644 --- a/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm @@ -1490,6 +1490,25 @@ All effects don't start immediately, but rather get worse over time; the rate is M.stuttering = min(M.stuttering + 3, 3) ..() +/datum/reagent/consumable/ethanol/pinotmort + name = "Pinot Mort" + description = "If you just can't get enough of lavaland." + color = rgb(167, 36, 36) + boozepwr = 20 + quality = DRINK_FANTASTIC + taste_description = "death, ash and lizards" + glass_icon_state = "pinotmort" + glass_name = "Pinot Mort" + glass_desc = "The taste of Lavaland served in a legion skull. You feel like you might regret drinking this." + value = REAGENT_VALUE_UNCOMMON + +/datum/reagent/consumable/ethanol/pinotmort/on_mob_life(mob/living/carbon/M) + if((islizard(M) && M.mind.assigned_role == "Ash Walker") || ispodperson(M) && M.mind.assigned_role == "Lifebringer" || isgolem(M)) + M.heal_bodypart_damage(1, 1) + M.adjustBruteLoss(-2,0) + . = 1 + return ..() + /datum/reagent/consumable/ethanol/triple_sec name = "Triple Sec" description = "A sweet and vibrant orange liqueur." diff --git a/code/modules/spells/spell_types/ethereal_jaunt.dm b/code/modules/spells/spell_types/ethereal_jaunt.dm index 9d91b6534d..7a05583071 100644 --- a/code/modules/spells/spell_types/ethereal_jaunt.dm +++ b/code/modules/spells/spell_types/ethereal_jaunt.dm @@ -108,5 +108,8 @@ /obj/effect/dummy/phased_mob/spell_jaunt/ex_act(blah) return +/obj/effect/dummy/phased_mob/spell_jaunt/wave_ex_act(power, datum/wave_explosion/explosion, dir) + return power + /obj/effect/dummy/phased_mob/spell_jaunt/bullet_act(blah) return BULLET_ACT_FORCE_PIERCE diff --git a/code/modules/spells/spell_types/shadow_walk.dm b/code/modules/spells/spell_types/shadow_walk.dm index 8436de2119..821bf73425 100644 --- a/code/modules/spells/spell_types/shadow_walk.dm +++ b/code/modules/spells/spell_types/shadow_walk.dm @@ -90,6 +90,9 @@ /obj/effect/dummy/phased_mob/shadow/ex_act() return +/obj/effect/dummy/phased_mob/shadow/wave_ex_act(power, datum/wave_explosion/explosion, dir) + return power + /obj/effect/dummy/phased_mob/shadow/bullet_act() return BULLET_ACT_FORCE_PIERCE diff --git a/code/modules/surgery/organs/vocal_cords.dm b/code/modules/surgery/organs/vocal_cords.dm index 0e6456e8b0..12e282200c 100644 --- a/code/modules/surgery/organs/vocal_cords.dm +++ b/code/modules/surgery/organs/vocal_cords.dm @@ -751,7 +751,6 @@ //phase 2 var/static/regex/awoo_words = regex("howl|awoo|bark") var/static/regex/nya_words = regex("nya|meow|mewl") - var/static/regex/sleep_words = regex("sleep|slumber|rest") var/static/regex/strip_words = regex("strip|derobe|nude|at ease|suit off") var/static/regex/walk_words = regex("slow down|walk") var/static/regex/run_words = regex("run|speed up") @@ -1096,17 +1095,6 @@ H.emote("me", EMOTE_VISIBLE, "lets out a nya!") E.cooldown += 1 - //SLEEP - else if((findtext(message, sleep_words))) - for(var/mob/living/carbon/C in listeners) - var/datum/status_effect/chem/enthrall/E = C.has_status_effect(/datum/status_effect/chem/enthrall) - switch(E.phase) - if(2 to INFINITY) - C.Sleeping(45 * power_multiplier) - E.cooldown += 10 - addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, C, "Drowsiness suddenly overwhelms you as you fall asleep!"), 5) - to_chat(user, "You send [C] to sleep.") - //STRIP else if((findtext(message, strip_words))) for(var/V in listeners) diff --git a/code/modules/uplink/uplink_items/uplink_stealth.dm b/code/modules/uplink/uplink_items/uplink_stealth.dm index 63d70b9141..f401514542 100644 --- a/code/modules/uplink/uplink_items/uplink_stealth.dm +++ b/code/modules/uplink/uplink_items/uplink_stealth.dm @@ -9,7 +9,7 @@ /datum/uplink_item/stealthy_weapons/telescopicbat name = "Telescopic Baseball Bat" - desc = "A robust telescopic baseball bat that hits like a truck and can be consealed when collapsed." + desc = "A robust telescopic baseball bat that hits like a truck and can be concealed when collapsed." item = /obj/item/melee/baseball_bat/telescopic cost = 2 diff --git a/html/changelog.html b/html/changelog.html index 61681621e7..7e3f24bf3b 100644 --- a/html/changelog.html +++ b/html/changelog.html @@ -50,6 +50,46 @@ -->
+

14 May 2021

+

keronshb updated:

+
    +
  • Removes VOG sleep command since it was an undocumented readd.
  • +
+

zeroisthebiggay updated:

+
    +
  • consealed
  • +
+ +

13 May 2021

+

Linzolle updated:

+
    +
  • anthromorphic -> anthropomorphic
  • +
+

WanderingFox95 updated:

+
    +
  • Pinot Mort (Necropolis Wine), a new, (totally healthy) mixed drink!
  • +
+

qweq12yt updated:

+
    +
  • Fixed sleeping disky spam (it still sleeps soundly, but every minute instead of every two seconds)
  • +
  • Fixed Hulks not breaking cuffs, zipties, restraints.
  • +
+

silicons updated:

+
    +
  • A deterministic wave explosion system has been added. Use it with wave_explosion().
  • +
+

zeroisthebiggay updated:

+
    +
  • vegas style bunny ears
  • +
+ +

12 May 2021

+

DeltaFire15 updated:

+
    +
  • find_safe_turf no longer always fails on safe oxygen levels(??)
  • +
  • Heretic bladeshatters now actually take the heretic's z into account as intended, instead of always being station z tweak: Message for failing the bladeshatter despite succeeding the do_after tweak: Improves bladeshatter a bit by making it safer codewise
  • +
+

11 May 2021

LetterN updated:

    @@ -755,22 +795,6 @@
    • Fixes cosmetic augments missing their foot sprites.
    - -

    12 March 2021

    -

    R3dtail updated:

    -
      -
    • Adds Periods and moves some words around.
    • -
    - -

    10 March 2021

    -

    Hatterhat updated:

    -
      -
    • The femur breaker now actually breaks legs by applying a compound fracture.
    • -
    -

    Putnam3145 updated:

    -
      -
    • uncapped TEG power, buffing high-temp TEGs
    • -
GoonStation 13 Development Team diff --git a/html/changelogs/.all_changelog.yml b/html/changelogs/.all_changelog.yml index ae29db429c..ca2426d1f0 100644 --- a/html/changelogs/.all_changelog.yml +++ b/html/changelogs/.all_changelog.yml @@ -29276,3 +29276,28 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py. bunny232: - rscadd: Delta station xenobiology department has received enhanced scrubbing and ventilation capabilities similar to box and meta +2021-05-12: + DeltaFire15: + - bugfix: find_safe_turf no longer always fails on safe oxygen levels(??) + - bugfix: 'Heretic bladeshatters now actually take the heretic''s z into account + as intended, instead of always being station z tweak: Message for failing the + bladeshatter despite succeeding the do_after tweak: Improves bladeshatter a + bit by making it safer codewise' +2021-05-13: + Linzolle: + - spellcheck: anthromorphic -> anthropomorphic + WanderingFox95: + - rscadd: Pinot Mort (Necropolis Wine), a new, (totally healthy) mixed drink! + qweq12yt: + - bugfix: Fixed sleeping disky spam (it still sleeps soundly, but every minute instead + of every two seconds) + - bugfix: Fixed Hulks not breaking cuffs, zipties, restraints. + silicons: + - code_imp: A deterministic wave explosion system has been added. Use it with wave_explosion(). + zeroisthebiggay: + - rscadd: vegas style bunny ears +2021-05-14: + keronshb: + - balance: Removes VOG sleep command since it was an undocumented readd. + zeroisthebiggay: + - spellcheck: consealed diff --git a/html/changelogs/AutoChangeLog-pr-14627.yml b/html/changelogs/AutoChangeLog-pr-14627.yml new file mode 100644 index 0000000000..cde6b62174 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-14627.yml @@ -0,0 +1,4 @@ +author: "timothyteakettle" +delete-after: True +changes: + - balance: "borg spraycans have a five second delay before being able to knock someone down again" diff --git a/html/changelogs/AutoChangeLog-pr-14706.yml b/html/changelogs/AutoChangeLog-pr-14706.yml deleted file mode 100644 index ecea6647ec..0000000000 --- a/html/changelogs/AutoChangeLog-pr-14706.yml +++ /dev/null @@ -1,7 +0,0 @@ -author: "DeltaFire15" -delete-after: True -changes: - - bugfix: "find_safe_turf no longer always fails on safe oxygen levels(??)" - - bugfix: "Heretic bladeshatters now actually take the heretic's z into account as intended, instead of always being station z -tweak: Message for failing the bladeshatter despite succeeding the do_after -tweak: Improves bladeshatter a bit by making it safer codewise" diff --git a/icons/obj/drinks.dmi b/icons/obj/drinks.dmi index 1b28b910c1..1c3b10b9de 100644 Binary files a/icons/obj/drinks.dmi and b/icons/obj/drinks.dmi differ diff --git a/modular_citadel/icons/mob/mam_ears.dmi b/modular_citadel/icons/mob/mam_ears.dmi index a3f09819f2..1ed3d8fbbe 100644 Binary files a/modular_citadel/icons/mob/mam_ears.dmi and b/modular_citadel/icons/mob/mam_ears.dmi differ diff --git a/tgstation.dme b/tgstation.dme index 017bd393e7..2e5bd87e51 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -51,6 +51,7 @@ #include "code\__DEFINES\economy.dm" #include "code\__DEFINES\events.dm" #include "code\__DEFINES\exosuit_fabs.dm" +#include "code\__DEFINES\explosion.dm" #include "code\__DEFINES\exports.dm" #include "code\__DEFINES\fantasy_affixes.dm" #include "code\__DEFINES\food.dm" @@ -320,6 +321,7 @@ #include "code\controllers\subsystem\disease.dm" #include "code\controllers\subsystem\economy.dm" #include "code\controllers\subsystem\events.dm" +#include "code\controllers\subsystem\explosions.dm" #include "code\controllers\subsystem\fail2topic.dm" #include "code\controllers\subsystem\fire_burning.dm" #include "code\controllers\subsystem\fluid.dm" @@ -410,6 +412,7 @@ #include "code\datums\emotes.dm" #include "code\datums\ert.dm" #include "code\datums\explosion.dm" +#include "code\datums\explosion2.dm" #include "code\datums\forced_movement.dm" #include "code\datums\holocall.dm" #include "code\datums\http.dm" @@ -2625,7 +2628,7 @@ #include "code\modules\mob\living\carbon\human\species_types\abductor.dm" #include "code\modules\mob\living\carbon\human\species_types\android.dm" #include "code\modules\mob\living\carbon\human\species_types\angel.dm" -#include "code\modules\mob\living\carbon\human\species_types\anthromorph.dm" +#include "code\modules\mob\living\carbon\human\species_types\anthropomorph.dm" #include "code\modules\mob\living\carbon\human\species_types\arachnid.dm" #include "code\modules\mob\living\carbon\human\species_types\bugmen.dm" #include "code\modules\mob\living\carbon\human\species_types\corporate.dm"