toast. And DiscoFox™️
99
code/__DEFINES/achievements.dm
Normal file
@@ -0,0 +1,99 @@
|
||||
// Keep the identifiers here below 32 characters, you can put the full display name in the actual achievement datum
|
||||
|
||||
#define ACHIEVEMENT_DEFAULT "default"
|
||||
#define ACHIEVEMENT_SCORE "score"
|
||||
|
||||
//Misc Medal hub IDs
|
||||
#define MEDAL_METEOR "Your Life Before Your Eyes"
|
||||
#define MEDAL_PULSE "Jackpot"
|
||||
#define MEDAL_TIMEWASTE "Overextended The Joke"
|
||||
#define MEDAL_RODSUPLEX "Feat of Strength"
|
||||
#define MEDAL_CLOWNCARKING "Round and Full"
|
||||
#define MEDAL_THANKSALOT "The Best Driver"
|
||||
#define MEDAL_HELBITALJANKEN "Hel-bent on Winning"
|
||||
#define MEDAL_MATERIALCRAFT "Getting an Upgrade"
|
||||
#define MEDAL_DISKPLEASE "Disk, Please!"
|
||||
#define MEDAL_GAMER "I'm Not Important"
|
||||
#define MEDAL_VENDORSQUISH "Teenage Anarchist"
|
||||
#define MEDAL_SWIRLIE "Bowl-d"
|
||||
#define MEDAL_SELFOUCH "Hands???"
|
||||
#define MEDAL_SANDMAN "Mister Sandman"
|
||||
#define MEDAL_CLEANBOSS "Cleanboss"
|
||||
#define MEDAL_RULE8 "Rule 8"
|
||||
#define MEDAL_LONGSHIFT "longshift"
|
||||
#define MEDAL_SNAIL "KKKiiilll mmmeee"
|
||||
#define MEDAL_LOOKOUTSIR "Look Out, Sir!"
|
||||
#define MEDAL_GOTTEM "GOTTEM"
|
||||
#define MEDAL_ASCENSION "Ascension"
|
||||
#define MEDAL_FRENCHING "FrenchingTheBubble"
|
||||
#define MEDAL_ASH_ASCENSION "Ash"
|
||||
#define MEDAL_FLESH_ASCENSION "Flesh"
|
||||
#define MEDAL_RUST_ASCENSION "Rust"
|
||||
#define MEDAL_VOID_ASCENSION "Void"
|
||||
#define MEDAL_TOOLBOX_SOUL "Toolsoul"
|
||||
|
||||
//Skill medal hub IDs
|
||||
#define MEDAL_LEGENDARY_MINER "Legendary Miner"
|
||||
|
||||
//Mafia medal hub IDs (wins)
|
||||
#define MAFIA_MEDAL_ASSISTANT "Assistant"
|
||||
#define MAFIA_MEDAL_DETECTIVE "Detective"
|
||||
#define MAFIA_MEDAL_PSYCHOLOGIST "Psychologist"
|
||||
#define MAFIA_MEDAL_CHAPLAIN "Chaplain"
|
||||
#define MAFIA_MEDAL_MD "Medical Doctor"
|
||||
#define MAFIA_MEDAL_LAWYER "Lawyer"
|
||||
#define MAFIA_MEDAL_HOP "Head of Personnel"
|
||||
#define MAFIA_MEDAL_CHANGELING "CHANGELING"
|
||||
#define MAFIA_MEDAL_THOUGHTFEEDER "Thoughtfeeder"
|
||||
#define MAFIA_MEDAL_TRAITOR "Traitor"
|
||||
#define MAFIA_MEDAL_NIGHTMARE "Nightmare"
|
||||
#define MAFIA_MEDAL_FUGITIVE "Fugitive"
|
||||
#define MAFIA_MEDAL_OBSESSED "Obsessed"
|
||||
#define MAFIA_MEDAL_CLOWN "Clown"
|
||||
|
||||
//Mafia medal hub IDs (misc stuff)
|
||||
#define MAFIA_MEDAL_HATED "Universally Hated"
|
||||
|
||||
//Boss medals
|
||||
|
||||
// Medal hub IDs for boss medals (Pre-fixes)
|
||||
#define BOSS_MEDAL_ANY "Boss Killer"
|
||||
#define BOSS_MEDAL_MINER "Blood-drunk Miner Killer"
|
||||
#define BOSS_MEDAL_FROSTMINER "Demonic-frost Miner Killer"
|
||||
#define BOSS_MEDAL_BUBBLEGUM "Bubblegum Killer"
|
||||
#define BOSS_MEDAL_COLOSSUS "Colossus Killer"
|
||||
#define BOSS_MEDAL_DRAKE "Drake Killer"
|
||||
#define BOSS_MEDAL_HIEROPHANT "Hierophant Killer"
|
||||
#define BOSS_MEDAL_LEGION "Legion Killer"
|
||||
#define BOSS_MEDAL_TENDRIL "Tendril Exterminator"
|
||||
#define BOSS_MEDAL_SWARMERS "Swarmer Beacon Killer"
|
||||
#define BOSS_MEDAL_WENDIGO "Wendigo Killer"
|
||||
#define BOSS_MEDAL_KINGGOAT "King Goat Killer"
|
||||
|
||||
#define BOSS_MEDAL_MINER_CRUSHER "Blood-drunk Miner Crusher"
|
||||
#define BOSS_MEDAL_FROSTMINER_CRUSHER "Demonic-frost Miner Crusher"
|
||||
#define BOSS_MEDAL_BUBBLEGUM_CRUSHER "Bubblegum Crusher"
|
||||
#define BOSS_MEDAL_COLOSSUS_CRUSHER "Colossus Crusher"
|
||||
#define BOSS_MEDAL_DRAKE_CRUSHER "Drake Crusher"
|
||||
#define BOSS_MEDAL_HIEROPHANT_CRUSHER "Hierophant Crusher"
|
||||
#define BOSS_MEDAL_LEGION_CRUSHER "Legion Crusher"
|
||||
#define BOSS_MEDAL_SWARMERS_CRUSHER "Swarmer Beacon Crusher"
|
||||
#define BOSS_MEDAL_WENDIGO_CRUSHER "Wendigo Crusher"
|
||||
#define BOSS_MEDAL_KINGGOAT_CRUSHER "King Goat Crusher"
|
||||
|
||||
// Medal hub IDs for boss-kill scores
|
||||
#define BOSS_SCORE "Bosses Killed"
|
||||
#define MINER_SCORE "BDMs Killed"
|
||||
#define FROST_MINER_SCORE "DFMs Killed"
|
||||
#define BUBBLEGUM_SCORE "Bubblegum Killed"
|
||||
#define COLOSSUS_SCORE "Colossus Killed"
|
||||
#define DRAKE_SCORE "Drakes Killed"
|
||||
#define HIEROPHANT_SCORE "Hierophants Killed"
|
||||
#define LEGION_SCORE "Legion Killed"
|
||||
#define SWARMER_BEACON_SCORE "Swarmer Beacs Killed"
|
||||
#define WENDIGO_SCORE "Wendigos Killed"
|
||||
#define KINGGOAT_SCORE "King Goat Killed"
|
||||
#define TENDRIL_CLEAR_SCORE "Tendrils Killed"
|
||||
|
||||
// DB IDs for hardcore random mode
|
||||
#define HARDCORE_RANDOM_SCORE "Hardcore Random Score"
|
||||
@@ -52,3 +52,9 @@
|
||||
#define COLOR_ASSEMBLY_BLUE "#38559E"
|
||||
#define COLOR_ASSEMBLY_PURPLE "#6F6192"
|
||||
#define COLOR_ASSEMBLY_PINK "#ff4adc"
|
||||
|
||||
#define COLOR_WHITE "#FFFFFF"
|
||||
#define COLOR_VERY_LIGHT_GRAY "#EEEEEE"
|
||||
#define COLOR_SILVER "#C0C0C0"
|
||||
#define COLOR_GRAY "#808080"
|
||||
#define COLOR_HALF_TRANSPARENT_BLACK "#0000007A"
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
// Medal names
|
||||
#define BOSS_KILL_MEDAL "Killer"
|
||||
#define ALL_KILL_MEDAL "Exterminator" //Killing all of x type
|
||||
#define BOSS_KILL_MEDAL_CRUSHER "Crusher"
|
||||
|
||||
//Defines for boss medals
|
||||
#define BOSS_MEDAL_MINER "Blood-drunk Miner"
|
||||
#define BOSS_MEDAL_BUBBLEGUM "Bubblegum"
|
||||
#define BOSS_MEDAL_COLOSSUS "Colossus"
|
||||
#define BOSS_MEDAL_DRAKE "Drake"
|
||||
#define BOSS_MEDAL_HIEROPHANT "Hierophant"
|
||||
#define BOSS_MEDAL_LEGION "Legion"
|
||||
#define BOSS_MEDAL_TENDRIL "Tendril"
|
||||
#define BOSS_MEDAL_SWARMERS "Swarmer Beacon"
|
||||
|
||||
// Score names
|
||||
#define HIEROPHANT_SCORE "Hierophants Killed"
|
||||
#define BOSS_SCORE "Bosses Killed"
|
||||
#define BUBBLEGUM_SCORE "Bubblegum Killed"
|
||||
#define COLOSSUS_SCORE "Colossus Killed"
|
||||
#define DRAKE_SCORE "Drakes Killed"
|
||||
#define LEGION_SCORE "Legion Killed"
|
||||
#define SWARMER_BEACON_SCORE "Swarmer Beacons Killed"
|
||||
#define TENDRIL_CLEAR_SCORE "Tendrils Killed"
|
||||
|
||||
//Misc medals
|
||||
#define MEDAL_METEOR "Your Life Before Your Eyes"
|
||||
#define MEDAL_PULSE "Jackpot"
|
||||
#define MEDAL_TIMEWASTE "Overextended The Joke"
|
||||
@@ -435,8 +435,13 @@ GLOBAL_LIST_INIT(pda_reskins, list(PDA_SKIN_CLASSIC = 'icons/obj/pda.dmi', PDA_S
|
||||
//text files
|
||||
#define BRAIN_DAMAGE_FILE "traumas.json"
|
||||
#define ION_FILE "ion_laws.json"
|
||||
#define REDPILL_FILE "redpill.json"
|
||||
#define PIRATE_NAMES_FILE "pirates.json"
|
||||
#define REDPILL_FILE "redpill.json"
|
||||
#define ARCADE_FILE "arcade.json"
|
||||
// #define BOOMER_FILE "boomer.json"
|
||||
// #define LOCATIONS_FILE "locations.json"
|
||||
// #define WANTED_FILE "wanted_message.json"
|
||||
// #define VISTA_FILE "steve.json"
|
||||
#define FLESH_SCAR_FILE "wounds/flesh_scar_desc.json"
|
||||
#define BONE_SCAR_FILE "wounds/bone_scar_desc.json"
|
||||
#define SCAR_LOC_FILE "wounds/scar_loc.json"
|
||||
|
||||
@@ -108,7 +108,7 @@
|
||||
#define INIT_ORDER_SOUNDS 83
|
||||
#define INIT_ORDER_INSTRUMENTS 82
|
||||
#define INIT_ORDER_VIS 80
|
||||
// #define INIT_ORDER_ACHIEVEMENTS 77
|
||||
#define INIT_ORDER_ACHIEVEMENTS 77
|
||||
#define INIT_ORDER_RESEARCH 75
|
||||
#define INIT_ORDER_EVENTS 70
|
||||
#define INIT_ORDER_JOBS 65
|
||||
|
||||
@@ -90,6 +90,9 @@
|
||||
#define VV_HK_TRIGGER_EMP "empulse"
|
||||
#define VV_HK_TRIGGER_EXPLOSION "explode"
|
||||
#define VV_HK_AUTO_RENAME "auto_rename"
|
||||
// #define VV_HK_RADIATE "radiate"
|
||||
#define VV_HK_EDIT_FILTERS "edit_filters"
|
||||
// #define VV_HK_ADD_AI "add_ai"
|
||||
|
||||
// /obj
|
||||
#define VV_HK_OSAY "osay"
|
||||
|
||||
319
code/__HELPERS/filters.dm
Normal file
@@ -0,0 +1,319 @@
|
||||
#define ICON_NOT_SET "Not Set"
|
||||
|
||||
//This is stored as a nested list instead of datums or whatever because it json encodes nicely for usage in tgui
|
||||
GLOBAL_LIST_INIT(master_filter_info, list(
|
||||
"alpha" = list(
|
||||
"defaults" = list(
|
||||
"x" = 0,
|
||||
"y" = 0,
|
||||
"icon" = ICON_NOT_SET,
|
||||
"render_source" = "",
|
||||
"flags" = 0
|
||||
),
|
||||
"flags" = list(
|
||||
"MASK_INVERSE" = MASK_INVERSE,
|
||||
"MASK_SWAP" = MASK_SWAP
|
||||
)
|
||||
),
|
||||
"angular_blur" = list(
|
||||
"defaults" = list(
|
||||
"x" = 0,
|
||||
"y" = 0,
|
||||
"size" = 1
|
||||
)
|
||||
),
|
||||
/* Not supported because making a proper matrix editor on the frontend would be a huge dick pain.
|
||||
Uncomment if you ever implement it
|
||||
"color" = list(
|
||||
"defaults" = list(
|
||||
"color" = matrix(),
|
||||
"space" = FILTER_COLOR_RGB
|
||||
)
|
||||
),
|
||||
*/
|
||||
"displace" = list(
|
||||
"defaults" = list(
|
||||
"x" = 0,
|
||||
"y" = 0,
|
||||
"size" = null,
|
||||
"icon" = ICON_NOT_SET,
|
||||
"render_source" = ""
|
||||
)
|
||||
),
|
||||
"drop_shadow" = list(
|
||||
"defaults" = list(
|
||||
"x" = 1,
|
||||
"y" = -1,
|
||||
"size" = 1,
|
||||
"offset" = 0,
|
||||
"color" = COLOR_HALF_TRANSPARENT_BLACK
|
||||
)
|
||||
),
|
||||
"blur" = list(
|
||||
"defaults" = list(
|
||||
"size" = 1
|
||||
)
|
||||
),
|
||||
"layer" = list(
|
||||
"defaults" = list(
|
||||
"x" = 0,
|
||||
"y" = 0,
|
||||
"icon" = ICON_NOT_SET,
|
||||
"render_source" = "",
|
||||
"flags" = FILTER_OVERLAY,
|
||||
"color" = "",
|
||||
"transform" = null,
|
||||
"blend_mode" = BLEND_DEFAULT
|
||||
)
|
||||
),
|
||||
"motion_blur" = list(
|
||||
"defaults" = list(
|
||||
"x" = 0,
|
||||
"y" = 0
|
||||
)
|
||||
),
|
||||
"outline" = list(
|
||||
"defaults" = list(
|
||||
"size" = 0,
|
||||
"color" = COLOR_BLACK,
|
||||
"flags" = NONE
|
||||
),
|
||||
"flags" = list(
|
||||
"OUTLINE_SHARP" = OUTLINE_SHARP,
|
||||
"OUTLINE_SQUARE" = OUTLINE_SQUARE
|
||||
)
|
||||
),
|
||||
"radial_blur" = list(
|
||||
"defaults" = list(
|
||||
"x" = 0,
|
||||
"y" = 0,
|
||||
"size" = 0.01
|
||||
)
|
||||
),
|
||||
"rays" = list(
|
||||
"defaults" = list(
|
||||
"x" = 0,
|
||||
"y" = 0,
|
||||
"size" = 16,
|
||||
"color" = COLOR_WHITE,
|
||||
"offset" = 0,
|
||||
"density" = 10,
|
||||
"threshold" = 0.5,
|
||||
"factor" = 0,
|
||||
"flags" = FILTER_OVERLAY | FILTER_UNDERLAY
|
||||
),
|
||||
"flags" = list(
|
||||
"FILTER_OVERLAY" = FILTER_OVERLAY,
|
||||
"FILTER_UNDERLAY" = FILTER_UNDERLAY
|
||||
)
|
||||
),
|
||||
"ripple" = list(
|
||||
"defaults" = list(
|
||||
"x" = 0,
|
||||
"y" = 0,
|
||||
"size" = 1,
|
||||
"repeat" = 2,
|
||||
"radius" = 0,
|
||||
"falloff" = 1,
|
||||
"flags" = NONE
|
||||
),
|
||||
"flags" = list(
|
||||
"WAVE_BOUNDED" = WAVE_BOUNDED
|
||||
)
|
||||
),
|
||||
"wave" = list(
|
||||
"defaults" = list(
|
||||
"x" = 0,
|
||||
"y" = 0,
|
||||
"size" = 1,
|
||||
"offset" = 0,
|
||||
"flags" = NONE
|
||||
),
|
||||
"flags" = list(
|
||||
"WAVE_SIDEWAYS" = WAVE_SIDEWAYS,
|
||||
"WAVE_BOUNDED" = WAVE_BOUNDED
|
||||
)
|
||||
)
|
||||
))
|
||||
|
||||
#undef ICON_NOT_SET
|
||||
|
||||
//Helpers to generate lists for filter helpers
|
||||
//This is the only practical way of writing these that actually produces sane lists
|
||||
/proc/alpha_mask_filter(x, y, icon/icon, render_source, flags)
|
||||
. = list("type" = "alpha")
|
||||
if(!isnull(x))
|
||||
.["x"] = x
|
||||
if(!isnull(y))
|
||||
.["y"] = y
|
||||
if(!isnull(icon))
|
||||
.["icon"] = icon
|
||||
if(!isnull(render_source))
|
||||
.["render_source"] = render_source
|
||||
if(!isnull(flags))
|
||||
.["flags"] = flags
|
||||
|
||||
/proc/angular_blur_filter(x, y, size)
|
||||
. = list("type" = "angular_blur")
|
||||
if(!isnull(x))
|
||||
.["x"] = x
|
||||
if(!isnull(y))
|
||||
.["y"] = y
|
||||
if(!isnull(size))
|
||||
.["size"] = size
|
||||
|
||||
/proc/color_matrix_filter(matrix/in_matrix, space)
|
||||
. = list("type" = "color")
|
||||
.["color"] = in_matrix
|
||||
if(!isnull(space))
|
||||
.["space"] = space
|
||||
|
||||
/proc/displacement_map_filter(icon, render_source, x, y, size = 32)
|
||||
. = list("type" = "displace")
|
||||
if(!isnull(icon))
|
||||
.["icon"] = icon
|
||||
if(!isnull(render_source))
|
||||
.["render_source"] = render_source
|
||||
if(!isnull(x))
|
||||
.["x"] = x
|
||||
if(!isnull(y))
|
||||
.["y"] = y
|
||||
if(!isnull(size))
|
||||
.["size"] = size
|
||||
|
||||
/proc/drop_shadow_filter(x, y, size, offset, color)
|
||||
. = list("type" = "drop_shadow")
|
||||
if(!isnull(x))
|
||||
.["x"] = x
|
||||
if(!isnull(y))
|
||||
.["y"] = y
|
||||
if(!isnull(size))
|
||||
.["size"] = size
|
||||
if(!isnull(offset))
|
||||
.["offset"] = offset
|
||||
if(!isnull(color))
|
||||
.["color"] = color
|
||||
|
||||
/proc/gauss_blur_filter(size)
|
||||
. = list("type" = "blur")
|
||||
if(!isnull(size))
|
||||
.["size"] = size
|
||||
|
||||
/proc/layering_filter(icon, render_source, x, y, flags, color, transform, blend_mode)
|
||||
. = list("type" = "layer")
|
||||
if(!isnull(icon))
|
||||
.["icon"] = icon
|
||||
if(!isnull(render_source))
|
||||
.["render_source"] = render_source
|
||||
if(!isnull(x))
|
||||
.["x"] = x
|
||||
if(!isnull(y))
|
||||
.["y"] = y
|
||||
if(!isnull(color))
|
||||
.["color"] = color
|
||||
if(!isnull(flags))
|
||||
.["flags"] = flags
|
||||
if(!isnull(transform))
|
||||
.["transform"] = transform
|
||||
if(!isnull(blend_mode))
|
||||
.["blend_mode"] = blend_mode
|
||||
|
||||
/proc/motion_blur_filter(x, y)
|
||||
. = list("type" = "motion_blur")
|
||||
if(!isnull(x))
|
||||
.["x"] = x
|
||||
if(!isnull(y))
|
||||
.["y"] = y
|
||||
|
||||
/proc/outline_filter(size, color, flags)
|
||||
. = list("type" = "outline")
|
||||
if(!isnull(size))
|
||||
.["size"] = size
|
||||
if(!isnull(color))
|
||||
.["color"] = color
|
||||
if(!isnull(flags))
|
||||
.["flags"] = flags
|
||||
|
||||
/proc/radial_blur_filter(size, x, y)
|
||||
. = list("type" = "radial_blur")
|
||||
if(!isnull(size))
|
||||
.["size"] = size
|
||||
if(!isnull(x))
|
||||
.["x"] = x
|
||||
if(!isnull(y))
|
||||
.["y"] = y
|
||||
|
||||
/proc/rays_filter(size, color, offset, density, threshold, factor, x, y, flags)
|
||||
. = list("type" = "rays")
|
||||
if(!isnull(size))
|
||||
.["size"] = size
|
||||
if(!isnull(color))
|
||||
.["color"] = color
|
||||
if(!isnull(offset))
|
||||
.["offset"] = offset
|
||||
if(!isnull(density))
|
||||
.["density"] = density
|
||||
if(!isnull(threshold))
|
||||
.["threshold"] = threshold
|
||||
if(!isnull(factor))
|
||||
.["factor"] = factor
|
||||
if(!isnull(x))
|
||||
.["x"] = x
|
||||
if(!isnull(y))
|
||||
.["y"] = y
|
||||
if(!isnull(flags))
|
||||
.["flags"] = flags
|
||||
|
||||
/proc/ripple_filter(radius, size, falloff, repeat, x, y, flags)
|
||||
. = list("type" = "ripple")
|
||||
if(!isnull(radius))
|
||||
.["radius"] = radius
|
||||
if(!isnull(size))
|
||||
.["size"] = size
|
||||
if(!isnull(falloff))
|
||||
.["falloff"] = falloff
|
||||
if(!isnull(repeat))
|
||||
.["repeat"] = repeat
|
||||
if(!isnull(flags))
|
||||
.["flags"] = flags
|
||||
if(!isnull(x))
|
||||
.["x"] = x
|
||||
if(!isnull(y))
|
||||
.["y"] = y
|
||||
|
||||
/proc/wave_filter(x, y, size, offset, flags)
|
||||
. = list("type" = "wave")
|
||||
if(!isnull(size))
|
||||
.["size"] = size
|
||||
if(!isnull(x))
|
||||
.["x"] = x
|
||||
if(!isnull(y))
|
||||
.["y"] = y
|
||||
if(!isnull(offset))
|
||||
.["offset"] = offset
|
||||
if(!isnull(flags))
|
||||
.["flags"] = flags
|
||||
|
||||
/proc/apply_wibbly_filters(atom/in_atom, length)
|
||||
for(var/i in 1 to 7)
|
||||
//This is a very baffling and strange way of doing this but I am just preserving old functionality
|
||||
var/X
|
||||
var/Y
|
||||
var/rsq
|
||||
do
|
||||
X = 60*rand() - 30
|
||||
Y = 60*rand() - 30
|
||||
rsq = X*X + Y*Y
|
||||
while(rsq<100 || rsq>900) // Yeah let's just loop infinitely due to bad luck what's the worst that could happen?
|
||||
var/random_roll = rand()
|
||||
in_atom.add_filter("wibbly-[i]", 5, wave_filter(x = X, y = Y, size = rand() * 2.5 + 0.5, offset = random_roll))
|
||||
var/filter = in_atom.get_filter("wibbly-[i]")
|
||||
animate(filter, offset = random_roll, time = 0, loop = -1, flags = ANIMATION_PARALLEL)
|
||||
animate(offset = random_roll - 1, time = rand() * 20 + 10)
|
||||
|
||||
/proc/remove_wibbly_filters(atom/in_atom)
|
||||
var/filter
|
||||
for(var/i in 1 to 7)
|
||||
filter = in_atom.get_filter("wibbly-[i]")
|
||||
animate(filter)
|
||||
in_atom.remove_filter("wibbly-[i]")
|
||||
@@ -169,6 +169,28 @@
|
||||
file_data["wanted"] = list("author" = "[GLOB.news_network.wanted_issue.scannedUser]", "criminal" = "[GLOB.news_network.wanted_issue.criminal]", "description" = "[GLOB.news_network.wanted_issue.body]", "photo file" = "[GLOB.news_network.wanted_issue.photo_file]")
|
||||
WRITE_FILE(json_file, json_encode(file_data))
|
||||
|
||||
///Handles random hardcore point rewarding if it applies.
|
||||
/datum/controller/subsystem/ticker/proc/HandleRandomHardcoreScore(client/player_client)
|
||||
if(!ishuman(player_client.mob))
|
||||
return FALSE
|
||||
var/mob/living/carbon/human/human_mob = player_client.mob
|
||||
if(!human_mob.hardcore_survival_score) ///no score no glory
|
||||
return FALSE
|
||||
|
||||
if(human_mob.mind && (human_mob.mind.special_role || length(human_mob.mind.antag_datums) > 0))
|
||||
var/didthegamerwin = TRUE
|
||||
for(var/a in human_mob.mind.antag_datums)
|
||||
var/datum/antagonist/antag_datum = a
|
||||
for(var/i in antag_datum.objectives)
|
||||
var/datum/objective/objective_datum = i
|
||||
if(!objective_datum.check_completion())
|
||||
didthegamerwin = FALSE
|
||||
if(!didthegamerwin)
|
||||
return FALSE
|
||||
player_client.give_award(/datum/award/score/hardcore_random, human_mob, round(human_mob.hardcore_survival_score))
|
||||
else if(human_mob.onCentCom())
|
||||
player_client.give_award(/datum/award/score/hardcore_random, human_mob, round(human_mob.hardcore_survival_score))
|
||||
|
||||
/datum/controller/subsystem/ticker/proc/declare_completion()
|
||||
set waitfor = FALSE
|
||||
|
||||
@@ -186,6 +208,19 @@
|
||||
C.RollCredits()
|
||||
C.playtitlemusic(40)
|
||||
CONFIG_SET(flag/suicide_allowed,TRUE) // EORG suicides allowed
|
||||
|
||||
var/speed_round = FALSE
|
||||
if(world.time - SSticker.round_start_time <= 300 SECONDS)
|
||||
speed_round = TRUE
|
||||
|
||||
for(var/client/C in GLOB.clients)
|
||||
if(!C.credits)
|
||||
C.RollCredits()
|
||||
C.playtitlemusic(40)
|
||||
if(speed_round)
|
||||
C.give_award(/datum/award/achievement/misc/speed_round, C.mob)
|
||||
HandleRandomHardcoreScore(C)
|
||||
|
||||
var/popcount = gather_roundend_feedback()
|
||||
display_report(popcount)
|
||||
|
||||
|
||||
0
code/_globalvars/lists/medals.dm → code/_globalvars/lists/achievements.dm
Executable file → Normal file
@@ -97,6 +97,9 @@
|
||||
M.lastattacker = user.real_name
|
||||
M.lastattackerckey = user.ckey
|
||||
|
||||
if(force && M == user && user.client)
|
||||
user.client.give_award(/datum/award/achievement/misc/selfouch, user)
|
||||
|
||||
user.do_attack_animation(M)
|
||||
M.attacked_by(src, user, attackchain_flags, damage_multiplier)
|
||||
|
||||
|
||||
74
code/controllers/subsystem/achievements.dm
Normal file
@@ -0,0 +1,74 @@
|
||||
SUBSYSTEM_DEF(achievements)
|
||||
name = "Achievements"
|
||||
flags = SS_NO_FIRE
|
||||
init_order = INIT_ORDER_ACHIEVEMENTS
|
||||
var/achievements_enabled = FALSE
|
||||
|
||||
///List of achievements
|
||||
var/list/datum/award/achievement/achievements = list()
|
||||
///List of scores
|
||||
var/list/datum/award/score/scores = list()
|
||||
///List of all awards
|
||||
var/list/datum/award/awards = list()
|
||||
|
||||
/datum/controller/subsystem/achievements/Initialize(timeofday)
|
||||
if(!SSdbcore.Connect())
|
||||
return ..()
|
||||
achievements_enabled = TRUE
|
||||
|
||||
for(var/T in subtypesof(/datum/award/achievement))
|
||||
var/instance = new T
|
||||
achievements[T] = instance
|
||||
awards[T] = instance
|
||||
|
||||
for(var/T in subtypesof(/datum/award/score))
|
||||
var/instance = new T
|
||||
scores[T] = instance
|
||||
awards[T] = instance
|
||||
|
||||
update_metadata()
|
||||
|
||||
for(var/i in GLOB.clients)
|
||||
var/client/C = i
|
||||
if(!C.player_details.achievements.initialized)
|
||||
C.player_details.achievements.InitializeData()
|
||||
|
||||
return ..()
|
||||
|
||||
/datum/controller/subsystem/achievements/Shutdown()
|
||||
save_achievements_to_db()
|
||||
|
||||
/datum/controller/subsystem/achievements/proc/save_achievements_to_db()
|
||||
var/list/cheevos_to_save = list()
|
||||
for(var/ckey in GLOB.player_details)
|
||||
var/datum/player_details/PD = GLOB.player_details[ckey]
|
||||
if(!PD || !PD.achievements)
|
||||
continue
|
||||
cheevos_to_save += PD.achievements.get_changed_data()
|
||||
if(!length(cheevos_to_save))
|
||||
return
|
||||
SSdbcore.MassInsert(format_table_name("achievements"),cheevos_to_save,duplicate_key = TRUE)
|
||||
|
||||
//Update the metadata if any are behind
|
||||
/datum/controller/subsystem/achievements/proc/update_metadata()
|
||||
var/list/current_metadata = list()
|
||||
//select metadata here
|
||||
var/datum/DBQuery/Q = SSdbcore.NewQuery("SELECT achievement_key,achievement_version FROM [format_table_name("achievement_metadata")]")
|
||||
if(!Q.Execute(async = TRUE))
|
||||
qdel(Q)
|
||||
return
|
||||
else
|
||||
while(Q.NextRow())
|
||||
current_metadata[Q.item[1]] = text2num(Q.item[2])
|
||||
qdel(Q)
|
||||
|
||||
var/list/to_update = list()
|
||||
for(var/T in awards)
|
||||
var/datum/award/A = awards[T]
|
||||
if(!A.database_id)
|
||||
continue
|
||||
if(!current_metadata[A.database_id] || current_metadata[A.database_id] < A.achievement_version)
|
||||
to_update += list(A.get_metadata_row())
|
||||
|
||||
if(to_update.len)
|
||||
SSdbcore.MassInsert(format_table_name("achievement_metadata"),to_update,duplicate_key = TRUE)
|
||||
@@ -1,87 +0,0 @@
|
||||
SUBSYSTEM_DEF(medals)
|
||||
name = "Medals"
|
||||
flags = SS_NO_FIRE
|
||||
var/hub_enabled = FALSE
|
||||
|
||||
/datum/controller/subsystem/medals/Initialize(timeofday)
|
||||
if(CONFIG_GET(string/medal_hub_address) && CONFIG_GET(string/medal_hub_password))
|
||||
hub_enabled = TRUE
|
||||
return ..()
|
||||
|
||||
/datum/controller/subsystem/medals/proc/UnlockMedal(medal, client/player)
|
||||
set waitfor = FALSE
|
||||
if(!medal || !hub_enabled)
|
||||
return
|
||||
if(isnull(world.SetMedal(medal, player, CONFIG_GET(string/medal_hub_address), CONFIG_GET(string/medal_hub_password))))
|
||||
hub_enabled = FALSE
|
||||
log_game("MEDAL ERROR: Could not contact hub to award medal:[medal] player:[player.key]")
|
||||
message_admins("Error! Failed to contact hub to award [medal] medal to [player.key]!")
|
||||
return
|
||||
to_chat(player, "<span class='greenannounce'><B>Achievement unlocked: [medal]!</B></span>")
|
||||
|
||||
|
||||
/datum/controller/subsystem/medals/proc/SetScore(score, client/player, increment, force)
|
||||
set waitfor = FALSE
|
||||
if(!score || !hub_enabled)
|
||||
return
|
||||
|
||||
var/list/oldscore = GetScore(score, player, TRUE)
|
||||
if(increment)
|
||||
if(!oldscore[score])
|
||||
oldscore[score] = 1
|
||||
else
|
||||
oldscore[score] = (text2num(oldscore[score]) + 1)
|
||||
else
|
||||
oldscore[score] = force
|
||||
|
||||
var/newscoreparam = list2params(oldscore)
|
||||
|
||||
if(isnull(world.SetScores(player.ckey, newscoreparam, CONFIG_GET(string/medal_hub_address), CONFIG_GET(string/medal_hub_password))))
|
||||
hub_enabled = FALSE
|
||||
log_game("SCORE ERROR: Could not contact hub to set score. Score:[score] player:[player.key]")
|
||||
message_admins("Error! Failed to contact hub to set [score] score for [player.key]!")
|
||||
|
||||
/datum/controller/subsystem/medals/proc/GetScore(score, client/player, returnlist)
|
||||
if(!score || !hub_enabled)
|
||||
return
|
||||
|
||||
var/scoreget = world.GetScores(player.ckey, score, CONFIG_GET(string/medal_hub_address), CONFIG_GET(string/medal_hub_password))
|
||||
if(isnull(scoreget))
|
||||
hub_enabled = FALSE
|
||||
log_game("SCORE ERROR: Could not contact hub to get score. Score:[score] player:[player.key]")
|
||||
message_admins("Error! Failed to contact hub to get score: [score] for [player.key]!")
|
||||
return
|
||||
. = params2list(scoreget)
|
||||
if(!returnlist)
|
||||
return .[score]
|
||||
|
||||
/datum/controller/subsystem/medals/proc/CheckMedal(medal, client/player)
|
||||
if(!medal || !hub_enabled)
|
||||
return
|
||||
|
||||
if(isnull(world.GetMedal(medal, player, CONFIG_GET(string/medal_hub_address), CONFIG_GET(string/medal_hub_password))))
|
||||
hub_enabled = FALSE
|
||||
log_game("MEDAL ERROR: Could not contact hub to get medal:[medal] player: [player.key]")
|
||||
message_admins("Error! Failed to contact hub to get [medal] medal for [player.key]!")
|
||||
return
|
||||
to_chat(player, "[medal] is unlocked")
|
||||
|
||||
/datum/controller/subsystem/medals/proc/LockMedal(medal, client/player)
|
||||
if(!player || !medal || !hub_enabled)
|
||||
return
|
||||
var/result = world.ClearMedal(medal, player, CONFIG_GET(string/medal_hub_address), CONFIG_GET(string/medal_hub_password))
|
||||
switch(result)
|
||||
if(null)
|
||||
hub_enabled = FALSE
|
||||
log_game("MEDAL ERROR: Could not contact hub to clear medal:[medal] player:[player.key]")
|
||||
message_admins("Error! Failed to contact hub to clear [medal] medal for [player.key]!")
|
||||
if(TRUE)
|
||||
message_admins("Medal: [medal] removed for [player.key]")
|
||||
if(FALSE)
|
||||
message_admins("Medal: [medal] was not found for [player.key]. Unable to clear.")
|
||||
|
||||
|
||||
/datum/controller/subsystem/medals/proc/ClearScore(client/player)
|
||||
if(isnull(world.SetScores(player.ckey, "", CONFIG_GET(string/medal_hub_address), CONFIG_GET(string/medal_hub_password))))
|
||||
log_game("MEDAL ERROR: Could not contact hub to clear scores for [player.key]!")
|
||||
message_admins("Error! Failed to contact hub to clear scores for [player.key]!")
|
||||
@@ -65,6 +65,8 @@ SUBSYSTEM_DEF(shuttle)
|
||||
|
||||
var/datum/turf_reservation/preview_reservation
|
||||
|
||||
var/shuttle_loading
|
||||
|
||||
/datum/controller/subsystem/shuttle/Initialize(timeofday)
|
||||
ordernum = rand(1, 9000)
|
||||
|
||||
@@ -664,7 +666,7 @@ SUBSYSTEM_DEF(shuttle)
|
||||
emergencyNoRecall = TRUE
|
||||
endvote_passed = TRUE
|
||||
|
||||
/datum/controller/subsystem/shuttle/proc/action_load(datum/map_template/shuttle/loading_template, obj/docking_port/stationary/destination_port)
|
||||
/datum/controller/subsystem/shuttle/proc/action_load(datum/map_template/shuttle/loading_template, obj/docking_port/stationary/destination_port, replace = FALSE)
|
||||
// Check for an existing preview
|
||||
if(preview_shuttle && (loading_template != preview_template))
|
||||
preview_shuttle.jumpToNullSpace()
|
||||
@@ -673,8 +675,8 @@ SUBSYSTEM_DEF(shuttle)
|
||||
QDEL_NULL(preview_reservation)
|
||||
|
||||
if(!preview_shuttle)
|
||||
if(load_template(loading_template))
|
||||
preview_shuttle.linkup(loading_template, destination_port)
|
||||
load_template(loading_template)
|
||||
preview_shuttle.linkup(loading_template, destination_port)
|
||||
preview_template = loading_template
|
||||
|
||||
// get the existing shuttle information, if any
|
||||
@@ -684,7 +686,7 @@ SUBSYSTEM_DEF(shuttle)
|
||||
|
||||
if(istype(destination_port))
|
||||
D = destination_port
|
||||
else if(existing_shuttle)
|
||||
else if(existing_shuttle && replace)
|
||||
timer = existing_shuttle.timer
|
||||
mode = existing_shuttle.mode
|
||||
D = existing_shuttle.get_docked()
|
||||
@@ -703,11 +705,12 @@ SUBSYSTEM_DEF(shuttle)
|
||||
WARNING("Template shuttle [preview_shuttle] cannot dock at [D] ([result]).")
|
||||
return
|
||||
|
||||
if(existing_shuttle)
|
||||
if(existing_shuttle && replace)
|
||||
existing_shuttle.jumpToNullSpace()
|
||||
|
||||
var/list/force_memory = preview_shuttle.movement_force
|
||||
preview_shuttle.movement_force = list("KNOCKDOWN" = 0, "THROW" = 0)
|
||||
preview_shuttle.mode = SHUTTLE_PREARRIVAL//No idle shuttle moving. Transit dock get removed if shuttle moves too long.
|
||||
preview_shuttle.initiate_docking(D)
|
||||
preview_shuttle.movement_force = force_memory
|
||||
|
||||
@@ -718,7 +721,7 @@ SUBSYSTEM_DEF(shuttle)
|
||||
preview_shuttle.timer = timer
|
||||
preview_shuttle.mode = mode
|
||||
|
||||
preview_shuttle.register()
|
||||
preview_shuttle.register(replace)
|
||||
|
||||
// TODO indicate to the user that success happened, rather than just
|
||||
// blanking the modification tab
|
||||
@@ -848,7 +851,8 @@ SUBSYSTEM_DEF(shuttle)
|
||||
return data
|
||||
|
||||
/datum/controller/subsystem/shuttle/ui_act(action, params)
|
||||
if(..())
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
|
||||
var/mob/user = usr
|
||||
@@ -891,22 +895,10 @@ SUBSYSTEM_DEF(shuttle)
|
||||
SSblackbox.record_feedback("text", "shuttle_manipulator", 1, "[M.name]")
|
||||
break
|
||||
|
||||
if("preview")
|
||||
if(S)
|
||||
. = TRUE
|
||||
unload_preview()
|
||||
load_template(S)
|
||||
if(preview_shuttle)
|
||||
preview_template = S
|
||||
user.forceMove(get_turf(preview_shuttle))
|
||||
if("load")
|
||||
if(existing_shuttle == backup_shuttle)
|
||||
// TODO make the load button disabled
|
||||
WARNING("The shuttle that the selected shuttle will replace \
|
||||
is the backup shuttle. Backup shuttle is required to be \
|
||||
intact for round sanity.")
|
||||
else if(S)
|
||||
if(S && !shuttle_loading)
|
||||
. = TRUE
|
||||
shuttle_loading = TRUE
|
||||
// If successful, returns the mobile docking port
|
||||
var/obj/docking_port/mobile/mdp = action_load(S)
|
||||
if(mdp)
|
||||
@@ -914,3 +906,38 @@ SUBSYSTEM_DEF(shuttle)
|
||||
message_admins("[key_name_admin(usr)] loaded [mdp] with the shuttle manipulator.")
|
||||
log_admin("[key_name(usr)] loaded [mdp] with the shuttle manipulator.</span>")
|
||||
SSblackbox.record_feedback("text", "shuttle_manipulator", 1, "[mdp.name]")
|
||||
shuttle_loading = FALSE
|
||||
|
||||
if("preview")
|
||||
//if(preview_shuttle && (loading_template != preview_template))
|
||||
if(S && !shuttle_loading)
|
||||
. = TRUE
|
||||
shuttle_loading = TRUE
|
||||
unload_preview()
|
||||
load_template(S)
|
||||
if(preview_shuttle)
|
||||
preview_template = S
|
||||
user.forceMove(get_turf(preview_shuttle))
|
||||
shuttle_loading = FALSE
|
||||
|
||||
if("replace")
|
||||
if(existing_shuttle == backup_shuttle)
|
||||
// TODO make the load button disabled
|
||||
WARNING("The shuttle that the selected shuttle will replace \
|
||||
is the backup shuttle. Backup shuttle is required to be \
|
||||
intact for round sanity.")
|
||||
else if(S && !shuttle_loading)
|
||||
. = TRUE
|
||||
shuttle_loading = TRUE
|
||||
// If successful, returns the mobile docking port
|
||||
var/obj/docking_port/mobile/mdp = action_load(S, replace = TRUE)
|
||||
if(mdp)
|
||||
user.forceMove(get_turf(mdp))
|
||||
message_admins("[key_name_admin(usr)] load/replaced [mdp] with the shuttle manipulator.")
|
||||
log_admin("[key_name(usr)] load/replaced [mdp] with the shuttle manipulator.</span>")
|
||||
SSblackbox.record_feedback("text", "shuttle_manipulator", 1, "[mdp.name]")
|
||||
shuttle_loading = FALSE
|
||||
if(emergency == mdp) //you just changed the emergency shuttle, there are events in game + captains that can change your snowflake choice.
|
||||
var/set_purchase = alert(usr, "Do you want to also disable shuttle purchases/random events that would change the shuttle?", "Butthurt Admin Prevention", "Yes, disable purchases/events", "No, I want to possibly get owned")
|
||||
if(set_purchase == "Yes, disable purchases/events")
|
||||
SSshuttle.shuttle_purchased = SHUTTLEPURCHASE_FORCED
|
||||
|
||||
148
code/datums/achievements/_achievement_data.dm
Normal file
@@ -0,0 +1,148 @@
|
||||
///Datum that handles
|
||||
/datum/achievement_data
|
||||
///Ckey of this achievement data's owner
|
||||
var/owner_ckey
|
||||
///Up to date list of all achievements and their info.
|
||||
var/data = list()
|
||||
///Original status of achievement.
|
||||
var/original_cached_data = list()
|
||||
///Have we done our set-up yet?
|
||||
var/initialized = FALSE
|
||||
|
||||
/datum/achievement_data/New(ckey)
|
||||
owner_ckey = ckey
|
||||
if(SSachievements.initialized && !initialized)
|
||||
InitializeData()
|
||||
|
||||
/datum/achievement_data/proc/InitializeData()
|
||||
initialized = TRUE
|
||||
load_all_achievements() //So we know which achievements we have unlocked so far.
|
||||
|
||||
///Gets list of changed rows in MassInsert format
|
||||
/datum/achievement_data/proc/get_changed_data()
|
||||
. = list()
|
||||
for(var/T in data)
|
||||
var/datum/award/A = SSachievements.awards[T]
|
||||
if(data[T] != original_cached_data[T])//If our data from before is not the same as now, save it to db.
|
||||
var/deets = A.get_changed_rows(owner_ckey,data[T])
|
||||
if(deets)
|
||||
. += list(deets)
|
||||
|
||||
/datum/achievement_data/proc/load_all_achievements()
|
||||
set waitfor = FALSE
|
||||
|
||||
var/list/kv = list()
|
||||
var/datum/DBQuery/Query = SSdbcore.NewQuery(
|
||||
"SELECT achievement_key,value FROM [format_table_name("achievements")] WHERE ckey = [owner_ckey]",
|
||||
)
|
||||
if(!Query.Execute())
|
||||
qdel(Query)
|
||||
return
|
||||
while(Query.NextRow())
|
||||
var/key = Query.item[1]
|
||||
var/value = text2num(Query.item[2])
|
||||
kv[key] = value
|
||||
qdel(Query)
|
||||
|
||||
for(var/T in subtypesof(/datum/award))
|
||||
var/datum/award/A = SSachievements.awards[T]
|
||||
if(!A || !A.name) //Skip abstract achievements types
|
||||
continue
|
||||
if(!data[T])
|
||||
data[T] = A.parse_value(kv[A.database_id])
|
||||
original_cached_data[T] = data[T]
|
||||
|
||||
///Updates local cache with db data for the given achievement type if it wasn't loaded yet.
|
||||
/datum/achievement_data/proc/get_data(achievement_type)
|
||||
var/datum/award/A = SSachievements.awards[achievement_type]
|
||||
if(!A.name)
|
||||
return FALSE
|
||||
if(!data[achievement_type])
|
||||
data[achievement_type] = A.load(owner_ckey)
|
||||
original_cached_data[achievement_type] = data[achievement_type]
|
||||
|
||||
///Unlocks an achievement of a specific type. achievement type is a typepath to the award, user is the mob getting the award, and value is an optional value to be used for defining a score to add to the leaderboard
|
||||
/datum/achievement_data/proc/unlock(achievement_type, mob/user, value = 1)
|
||||
set waitfor = FALSE
|
||||
|
||||
if(!SSachievements.achievements_enabled)
|
||||
return
|
||||
var/datum/award/A = SSachievements.awards[achievement_type]
|
||||
get_data(achievement_type) //Get the current status first if necessary
|
||||
if(istype(A, /datum/award/achievement))
|
||||
if(data[achievement_type]) //You already unlocked it so don't bother running the unlock proc
|
||||
return
|
||||
data[achievement_type] = TRUE
|
||||
A.on_unlock(user) //Only on default achievement, as scores keep going up.
|
||||
else if(istype(A, /datum/award/score))
|
||||
data[achievement_type] += value
|
||||
|
||||
///Getter for the status/score of an achievement
|
||||
/datum/achievement_data/proc/get_achievement_status(achievement_type)
|
||||
return data[achievement_type]
|
||||
|
||||
///Resets an achievement to default values.
|
||||
/datum/achievement_data/proc/reset(achievement_type)
|
||||
if(!SSachievements.achievements_enabled)
|
||||
return
|
||||
var/datum/award/A = SSachievements.awards[achievement_type]
|
||||
get_data(achievement_type)
|
||||
if(istype(A, /datum/award/achievement))
|
||||
data[achievement_type] = FALSE
|
||||
else if(istype(A, /datum/award/score))
|
||||
data[achievement_type] = 0
|
||||
|
||||
/datum/achievement_data/ui_assets(mob/user)
|
||||
return list(
|
||||
get_asset_datum(/datum/asset/spritesheet/simple/achievements),
|
||||
)
|
||||
|
||||
/datum/achievement_data/ui_state(mob/user)
|
||||
return GLOB.always_state
|
||||
|
||||
/datum/achievement_data/ui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, "Achievements")
|
||||
ui.open()
|
||||
|
||||
/datum/achievement_data/ui_data(mob/user)
|
||||
var/ret_data = list() // screw standards (qustinnus you must rename src.data ok)
|
||||
ret_data["categories"] = list("Bosses", "Misc", "Mafia", "Scores")
|
||||
ret_data["achievements"] = list()
|
||||
ret_data["user_key"] = user.ckey
|
||||
|
||||
var/datum/asset/spritesheet/simple/assets = get_asset_datum(/datum/asset/spritesheet/simple/achievements)
|
||||
//This should be split into static data later
|
||||
for(var/achievement_type in SSachievements.awards)
|
||||
if(!SSachievements.awards[achievement_type].name) //No name? we a subtype.
|
||||
continue
|
||||
if(isnull(data[achievement_type])) //We're still loading
|
||||
continue
|
||||
var/list/this = list(
|
||||
"name" = SSachievements.awards[achievement_type].name,
|
||||
"desc" = SSachievements.awards[achievement_type].desc,
|
||||
"category" = SSachievements.awards[achievement_type].category,
|
||||
"icon_class" = assets.icon_class_name(SSachievements.awards[achievement_type].icon),
|
||||
"value" = data[achievement_type],
|
||||
"score" = ispath(achievement_type,/datum/award/score)
|
||||
)
|
||||
ret_data["achievements"] += list(this)
|
||||
|
||||
return ret_data
|
||||
|
||||
/datum/achievement_data/ui_static_data(mob/user)
|
||||
. = ..()
|
||||
.["highscore"] = list()
|
||||
for(var/score in SSachievements.scores)
|
||||
var/datum/award/score/S = SSachievements.scores[score]
|
||||
if(!S.name || !S.track_high_scores || !S.high_scores.len)
|
||||
continue
|
||||
.["highscore"] += list(list("name" = S.name,"scores" = S.high_scores))
|
||||
|
||||
/client/verb/checkachievements()
|
||||
set category = "OOC"
|
||||
set name = "Check achievements"
|
||||
set desc = "See all of your achievements!"
|
||||
|
||||
player_details.achievements.ui_interact(usr)
|
||||
115
code/datums/achievements/_awards.dm
Normal file
@@ -0,0 +1,115 @@
|
||||
/datum/award
|
||||
///Name of the achievement, If null it won't show up in the achievement browser. (Handy for inheritance trees)
|
||||
var/name
|
||||
var/desc = "You did it."
|
||||
///Found in UI_Icons/Achievements
|
||||
var/icon = "default"
|
||||
var/category = "Normal"
|
||||
|
||||
///What ID do we use in db, limited to 32 characters
|
||||
var/database_id
|
||||
//Bump this up if you're changing outdated table identifier and/or achievement type
|
||||
var/achievement_version = 2
|
||||
|
||||
//Value returned on db connection failure, in case we want to differ 0 and nonexistent later on
|
||||
var/default_value = FALSE
|
||||
|
||||
///This proc loads the achievement data from the hub.
|
||||
/datum/award/proc/load(key)
|
||||
if(!SSdbcore.Connect())
|
||||
return default_value
|
||||
if(!key || !database_id || !name)
|
||||
return default_value
|
||||
var/raw_value = get_raw_value(key)
|
||||
return parse_value(raw_value)
|
||||
|
||||
///This saves the changed data to the hub.
|
||||
/datum/award/proc/get_changed_rows(key, value)
|
||||
if(!database_id || !key || !name)
|
||||
return
|
||||
return list(
|
||||
"ckey" = key,
|
||||
"achievement_key" = database_id,
|
||||
"value" = value,
|
||||
)
|
||||
|
||||
/datum/award/proc/get_metadata_row()
|
||||
return list(
|
||||
"achievement_key" = database_id,
|
||||
"achievement_version" = achievement_version,
|
||||
"achievement_type" = "award",
|
||||
"achievement_name" = name,
|
||||
"achievement_description" = desc,
|
||||
)
|
||||
|
||||
///Get raw numerical achievement value from the database
|
||||
/datum/award/proc/get_raw_value(key)
|
||||
var/datum/DBQuery/Q = SSdbcore.NewQuery(
|
||||
"SELECT value FROM [format_table_name("achievements")] WHERE ckey = [key] AND achievement_key = [database_id]"
|
||||
)
|
||||
if(!Q.Execute(async = TRUE))
|
||||
qdel(Q)
|
||||
return 0
|
||||
var/result = 0
|
||||
if(Q.NextRow())
|
||||
result = text2num(Q.item[1])
|
||||
qdel(Q)
|
||||
return result
|
||||
|
||||
//Should return sanitized value for achievement cache
|
||||
/datum/award/proc/parse_value(raw_value)
|
||||
return default_value
|
||||
|
||||
///Can be overriden for achievement specific events
|
||||
/datum/award/proc/on_unlock(mob/user)
|
||||
return
|
||||
|
||||
///Achievements are one-off awards for usually doing cool things.
|
||||
/datum/award/achievement
|
||||
desc = "Achievement for epic people"
|
||||
|
||||
/datum/award/achievement/get_metadata_row()
|
||||
. = ..()
|
||||
.["achievement_type"] = "achievement"
|
||||
|
||||
/datum/award/achievement/parse_value(raw_value)
|
||||
return raw_value > 0
|
||||
|
||||
/datum/award/achievement/on_unlock(mob/user)
|
||||
. = ..()
|
||||
to_chat(user, "<span class='greenannounce'><B>Achievement unlocked: [name]!</B></span>")
|
||||
|
||||
///Scores are for leaderboarded things, such as killcount of a specific boss
|
||||
/datum/award/score
|
||||
desc = "you did it sooo many times."
|
||||
category = "Scores"
|
||||
default_value = 0
|
||||
|
||||
var/track_high_scores = TRUE
|
||||
var/list/high_scores = list()
|
||||
|
||||
/datum/award/score/New()
|
||||
. = ..()
|
||||
if(track_high_scores)
|
||||
LoadHighScores()
|
||||
|
||||
/datum/award/score/get_metadata_row()
|
||||
. = ..()
|
||||
.["achievement_type"] = "score"
|
||||
|
||||
/datum/award/score/proc/LoadHighScores()
|
||||
var/datum/DBQuery/Q = SSdbcore.NewQuery(
|
||||
"SELECT ckey,value FROM [format_table_name("achievements")] WHERE achievement_key = [database_id] ORDER BY value DESC LIMIT 50"
|
||||
)
|
||||
if(!Q.Execute(async = TRUE))
|
||||
qdel(Q)
|
||||
return
|
||||
else
|
||||
while(Q.NextRow())
|
||||
var/key = Q.item[1]
|
||||
var/score = text2num(Q.item[2])
|
||||
high_scores[key] = score
|
||||
qdel(Q)
|
||||
|
||||
/datum/award/score/parse_value(raw_value)
|
||||
return isnum(raw_value) ? raw_value : 0
|
||||
130
code/datums/achievements/boss_achievements.dm
Normal file
@@ -0,0 +1,130 @@
|
||||
/datum/award/achievement/boss
|
||||
category = "Bosses"
|
||||
icon = "baseboss"
|
||||
|
||||
/datum/award/achievement/boss/tendril_exterminator
|
||||
name = "Tendril Exterminator"
|
||||
desc = "Watch your step"
|
||||
database_id = BOSS_MEDAL_TENDRIL
|
||||
icon = "tendril"
|
||||
|
||||
/datum/award/achievement/boss/boss_killer
|
||||
name = "Boss Killer"
|
||||
desc = "You've come a long ways from asking how to switch hands."
|
||||
database_id = "Boss Killer"
|
||||
icon = "firstboss"
|
||||
|
||||
/datum/award/achievement/boss/blood_miner_kill
|
||||
name = "Blood-Drunk Miner Killer"
|
||||
desc = "I guess he couldn't handle his drink that well."
|
||||
database_id = BOSS_MEDAL_MINER
|
||||
icon = "miner"
|
||||
|
||||
/datum/award/achievement/boss/demonic_miner_kill
|
||||
name = "Demonic-Frost Miner Killer"
|
||||
desc = "Definitely harder than the Blood-Drunk Miner."
|
||||
database_id = BOSS_MEDAL_FROSTMINER
|
||||
|
||||
/datum/award/achievement/boss/bubblegum_kill
|
||||
name = "Bubblegum Killer"
|
||||
desc = "I guess he wasn't made of candy after all"
|
||||
database_id = BOSS_MEDAL_BUBBLEGUM
|
||||
icon = "bbgum"
|
||||
|
||||
/datum/award/achievement/boss/colossus_kill
|
||||
name = "Colossus Killer"
|
||||
desc = "The bigger they are... the better the loot"
|
||||
database_id = BOSS_MEDAL_COLOSSUS
|
||||
icon = "colossus"
|
||||
|
||||
/datum/award/achievement/boss/drake_kill
|
||||
name = "Drake Killer"
|
||||
desc = "Now I can wear Rune Platebodies!"
|
||||
database_id = BOSS_MEDAL_DRAKE
|
||||
icon = "drake"
|
||||
|
||||
/datum/award/achievement/boss/hierophant_kill
|
||||
name = "Hierophant Killer"
|
||||
desc = "Hierophant, but not triumphant."
|
||||
database_id = BOSS_MEDAL_HIEROPHANT
|
||||
icon = "hierophant"
|
||||
|
||||
/datum/award/achievement/boss/legion_kill
|
||||
name = "Legion Killer"
|
||||
desc = "We were many..now we are none."
|
||||
database_id = BOSS_MEDAL_LEGION
|
||||
icon = "legion"
|
||||
|
||||
/datum/award/achievement/boss/swarmer_beacon_kill
|
||||
name = "Swarm Beacon Killer"
|
||||
desc = "GET THEM OFF OF ME!"
|
||||
database_id = BOSS_MEDAL_SWARMERS
|
||||
icon = "swarmer"
|
||||
|
||||
/datum/award/achievement/boss/wendigo_kill
|
||||
name = "Wendigo Killer"
|
||||
desc = "You've now ruined years of mythical storytelling."
|
||||
database_id = BOSS_MEDAL_WENDIGO
|
||||
|
||||
/datum/award/achievement/boss/blood_miner_crusher
|
||||
name = "Blood-Drunk Miner Crusher"
|
||||
desc = "I guess he couldn't handle his drink that well."
|
||||
database_id = BOSS_MEDAL_MINER_CRUSHER
|
||||
icon = "miner"
|
||||
|
||||
/datum/award/achievement/boss/demonic_miner_crusher
|
||||
name = "Demonic-Frost Miner Crusher"
|
||||
desc = "Definitely harder than the Blood-Drunk Miner."
|
||||
database_id = BOSS_MEDAL_FROSTMINER_CRUSHER
|
||||
|
||||
/datum/award/achievement/boss/bubblegum_crusher
|
||||
name = "Bubblegum Crusher"
|
||||
desc = "I guess he wasn't made of candy after all"
|
||||
database_id = BOSS_MEDAL_BUBBLEGUM_CRUSHER
|
||||
icon = "bbgum"
|
||||
|
||||
/datum/award/achievement/boss/colossus_crusher
|
||||
name = "Colossus Crusher"
|
||||
desc = "The bigger they are... the better the loot"
|
||||
database_id = BOSS_MEDAL_COLOSSUS_CRUSHER
|
||||
icon = "colossus"
|
||||
|
||||
/datum/award/achievement/boss/drake_crusher
|
||||
name = "Drake Crusher"
|
||||
desc = "Now I can wear Rune Platebodies!"
|
||||
database_id = BOSS_MEDAL_DRAKE_CRUSHER
|
||||
icon = "drake"
|
||||
|
||||
/datum/award/achievement/boss/hierophant_crusher
|
||||
name = "Hierophant Crusher"
|
||||
desc = "Hierophant, but not triumphant."
|
||||
database_id = BOSS_MEDAL_HIEROPHANT_CRUSHER
|
||||
icon = "hierophant"
|
||||
|
||||
/datum/award/achievement/boss/legion_crusher
|
||||
name = "Legion Crusher"
|
||||
desc = "We were many... now we are none."
|
||||
database_id = BOSS_MEDAL_LEGION_CRUSHER
|
||||
|
||||
/datum/award/achievement/boss/swarmer_beacon_crusher
|
||||
name = "Swarm Beacon Crusher"
|
||||
desc = "GET THEM OFF OF ME!"
|
||||
database_id = BOSS_MEDAL_SWARMERS_CRUSHER
|
||||
|
||||
/datum/award/achievement/boss/wendigo_crusher
|
||||
name = "Wendigo Crusher"
|
||||
desc = "You've now ruined years of mythical storytelling."
|
||||
database_id = BOSS_MEDAL_WENDIGO_CRUSHER
|
||||
|
||||
//should be removed soon
|
||||
/datum/award/achievement/boss/king_goat_kill
|
||||
name = "King Goat Killer"
|
||||
desc = "The king is dead, long live the king!"
|
||||
database_id = BOSS_MEDAL_KINGGOAT
|
||||
icon = "goatboss"
|
||||
|
||||
/datum/award/achievement/boss/king_goat_crusher
|
||||
name = "King Goat Crusher"
|
||||
desc = "The king is dead, long live the king!"
|
||||
database_id = BOSS_MEDAL_KINGGOAT_CRUSHER
|
||||
icon = "goatboss"
|
||||
54
code/datums/achievements/boss_scores.dm
Normal file
@@ -0,0 +1,54 @@
|
||||
/datum/award/score/tendril_score
|
||||
name = "Tendril Score"
|
||||
desc = "Watch your step"
|
||||
database_id = TENDRIL_CLEAR_SCORE
|
||||
|
||||
/datum/award/score/boss_score
|
||||
name = "Bosses Killed"
|
||||
desc = "You've killed HOW many?"
|
||||
database_id = BOSS_SCORE
|
||||
|
||||
/datum/award/score/blood_miner_score
|
||||
name = "Blood-Drunk Miners Killed"
|
||||
desc = "You've killed HOW many?"
|
||||
database_id = MINER_SCORE
|
||||
|
||||
/datum/award/score/demonic_miner_score
|
||||
name = "Demonic-Frost Miners Killed"
|
||||
desc = "You've killed HOW many?"
|
||||
database_id = FROST_MINER_SCORE
|
||||
|
||||
/datum/award/score/bubblegum_score
|
||||
name = "Bubblegums Killed"
|
||||
desc = "You've killed HOW many?"
|
||||
database_id = BUBBLEGUM_SCORE
|
||||
|
||||
/datum/award/score/colussus_score
|
||||
name = "Colossus Killed"
|
||||
desc = "You've killed HOW many?"
|
||||
database_id = COLOSSUS_SCORE
|
||||
|
||||
/datum/award/score/drake_score
|
||||
name = "Drakes Killed"
|
||||
desc = "You've killed HOW many?"
|
||||
database_id = DRAKE_SCORE
|
||||
|
||||
/datum/award/score/hierophant_score
|
||||
name = "Hierophants Killed"
|
||||
desc = "You've killed HOW many?"
|
||||
database_id = HIEROPHANT_SCORE
|
||||
|
||||
/datum/award/score/legion_score
|
||||
name = "Legions Killed"
|
||||
desc = "You've killed HOW many?"
|
||||
database_id = LEGION_SCORE
|
||||
|
||||
/datum/award/score/swarmer_beacon_score
|
||||
name = "Swarmer Beacons Killed"
|
||||
desc = "You've killed HOW many?"
|
||||
database_id = SWARMER_BEACON_SCORE
|
||||
|
||||
/datum/award/score/wendigo_score
|
||||
name = "Wendigos Killed"
|
||||
desc = "You've killed HOW many?"
|
||||
database_id = WENDIGO_SCORE
|
||||
4
code/datums/achievements/hardcore_random.dm
Normal file
@@ -0,0 +1,4 @@
|
||||
/datum/award/score/hardcore_random
|
||||
name = "Hardcore random points"
|
||||
desc = "Well, I might be a blind, deaf, crippled guy, but hey, at least I'm alive."
|
||||
database_id = HARDCORE_RANDOM_SCORE
|
||||
97
code/datums/achievements/mafia_achievements.dm
Normal file
@@ -0,0 +1,97 @@
|
||||
/datum/award/achievement/mafia
|
||||
category = "Mafia"
|
||||
icon = "basemafia"
|
||||
|
||||
///ALL THE ACHIEVEMENTS FOR WINNING A ROUND AS A ROLE///
|
||||
|
||||
/datum/award/achievement/mafia/assistant
|
||||
name = "Assistant Victory"
|
||||
desc = "If you got killed instead of someone more important, you just flexed the true strength of your \"\"\"\"role\"\"\"\"."
|
||||
database_id = MAFIA_MEDAL_ASSISTANT
|
||||
icon = "assistant"
|
||||
|
||||
/datum/award/achievement/mafia/detective
|
||||
name = "Detective Victory"
|
||||
desc = "If you did this with a Medical Doctor in the game, i'm not really that impressed."
|
||||
database_id = MAFIA_MEDAL_DETECTIVE
|
||||
icon = "detective"
|
||||
|
||||
/datum/award/achievement/mafia/psychologist
|
||||
name = "Psychologist Victory"
|
||||
desc = "You learned how to not reveal someone random night one! Or... maybe you're just a lucky bastard."
|
||||
database_id = MAFIA_MEDAL_PSYCHOLOGIST
|
||||
icon = "psychologist"
|
||||
|
||||
/datum/award/achievement/mafia/chaplain
|
||||
name = "Chaplain Victory"
|
||||
desc = "Useless... until the one night the thoughtfeeder confidently claims themselves as detective. Mafia's true bullshit detector."
|
||||
database_id = MAFIA_MEDAL_CHAPLAIN
|
||||
icon = "chaplain"
|
||||
|
||||
/datum/award/achievement/mafia/md
|
||||
name = "Medical Doctor Victory"
|
||||
desc = "Congratulations on learning how to not talk!"
|
||||
database_id = MAFIA_MEDAL_MD
|
||||
icon = "md"
|
||||
|
||||
/datum/award/achievement/mafia/lawyer
|
||||
name = "Lawyer Victory"
|
||||
desc = "Oh don't mind me, i'm just the worst rol- Oops, I just instantly ended the game."
|
||||
database_id = MAFIA_MEDAL_LAWYER
|
||||
icon = "lawyer"
|
||||
|
||||
/datum/award/achievement/mafia/hop
|
||||
name = "Head of Personnel Victory"
|
||||
desc = "King of Assistants, waster of a single mafia's night, thrower of games."
|
||||
database_id = MAFIA_MEDAL_HOP
|
||||
icon = "hop"
|
||||
|
||||
/datum/award/achievement/mafia/changeling
|
||||
name = "Changeling Victory"
|
||||
desc = "I think the changelings are metacomming."
|
||||
database_id = MAFIA_MEDAL_CHANGELING
|
||||
icon = "changeling"
|
||||
|
||||
/datum/award/achievement/mafia/thoughtfeeder
|
||||
name = "Thoughtfeeder Victory"
|
||||
desc = "Clown's best friend. And Obsessed. And fugitive? Whose side are you on?!"
|
||||
database_id = MAFIA_MEDAL_THOUGHTFEEDER
|
||||
icon = "thoughtfeeder"
|
||||
|
||||
/datum/award/achievement/mafia/traitor
|
||||
name = "Traitor Victory"
|
||||
desc = "Guys, we still have two more changelings to ki-!! TRAITOR VICTORY !!"
|
||||
database_id = MAFIA_MEDAL_TRAITOR
|
||||
icon = "traitor"
|
||||
|
||||
/datum/award/achievement/mafia/nightmare
|
||||
name = "Nightmare Victory"
|
||||
desc = "DID YOUR LIGHT FLICKER?!"
|
||||
database_id = MAFIA_MEDAL_NIGHTMARE
|
||||
icon = "nightmare"
|
||||
|
||||
/datum/award/achievement/mafia/fugitive
|
||||
name = "Fugitive Victory"
|
||||
desc = "I'm just the description on an achievement, but if you end up having to choose between town and changelings, go changelings."
|
||||
database_id = MAFIA_MEDAL_FUGITIVE
|
||||
icon = "fugitive"
|
||||
|
||||
/datum/award/achievement/mafia/obsessed
|
||||
name = "Obsessed Victory"
|
||||
desc = "You got your target lynched, so instead of being spiteful and annoying, you're just smug and annoying."
|
||||
database_id = MAFIA_MEDAL_OBSESSED
|
||||
icon = "obsessed"
|
||||
|
||||
/datum/award/achievement/mafia/clown
|
||||
name = "Clown Victory"
|
||||
desc = "Did you know this works on traitors, despite their immunity? If you hit the jackpot and manage to kill one, they'll salt into the next dimension. Clown tips!"
|
||||
database_id = MAFIA_MEDAL_CLOWN
|
||||
icon = "clown"
|
||||
|
||||
///ALL THE ACHIEVEMENTS FOR MISC MAFIA ODDITIES///
|
||||
|
||||
/datum/award/achievement/mafia/universally_hated
|
||||
name = "Universally Hated"
|
||||
desc = "Managed to get more than 12 votes when put up on trial, jesus christ."
|
||||
database_id = MAFIA_MEDAL_HATED
|
||||
icon = "hated"
|
||||
155
code/datums/achievements/misc_achievements.dm
Normal file
@@ -0,0 +1,155 @@
|
||||
/datum/award/achievement/misc
|
||||
category = "Misc"
|
||||
icon = "basemisc"
|
||||
|
||||
/datum/award/achievement/misc/meteor_examine
|
||||
name = "Your Life Before Your Eyes"
|
||||
desc = "Take a close look at hurtling space debris"
|
||||
database_id = MEDAL_METEOR
|
||||
icon = "meteors"
|
||||
|
||||
/datum/award/achievement/misc/pulse
|
||||
name = "Jackpot"
|
||||
desc = "Win a pulse rifle from an arcade machine"
|
||||
database_id = MEDAL_PULSE
|
||||
icon = "jackpot"
|
||||
|
||||
/datum/award/achievement/misc/time_waste
|
||||
name = "Time waster"
|
||||
desc = "Speak no evil, hear no evil, see just errors"
|
||||
database_id = MEDAL_TIMEWASTE
|
||||
icon = "timewaste"
|
||||
|
||||
/datum/award/achievement/misc/feat_of_strength
|
||||
name = "Feat of Strength"
|
||||
desc = "If the rod is immovable, is it passing you or are you passing it?"
|
||||
database_id = MEDAL_RODSUPLEX
|
||||
icon = "featofstrength"
|
||||
|
||||
/datum/award/achievement/misc/round_and_full
|
||||
name = "Round and Full"
|
||||
desc = "Well at least you aren't down the river, I hear they eat people there."
|
||||
database_id = MEDAL_CLOWNCARKING
|
||||
icon = "clownking"
|
||||
|
||||
/datum/award/achievement/misc/the_best_driver
|
||||
name = "The Best Driver"
|
||||
desc = "100 honks later"
|
||||
database_id = MEDAL_THANKSALOT
|
||||
icon = "clownthanks"
|
||||
|
||||
/datum/award/achievement/misc/helbitaljanken
|
||||
name = "Helbitaljanken"
|
||||
desc = "You janked hard"
|
||||
database_id = MEDAL_HELBITALJANKEN
|
||||
icon = "helbital"
|
||||
|
||||
/datum/award/achievement/misc/getting_an_upgrade
|
||||
name = "Getting an upgrade"
|
||||
desc = "Make your first unique material item!"
|
||||
database_id = MEDAL_MATERIALCRAFT
|
||||
|
||||
/datum/award/achievement/misc/rocket_holdup
|
||||
name = "Disk, Please!"
|
||||
desc = "Is the man currently pointing a loaded rocket launcher at your head point blank really dumb enough to pull the trigger? Do you really want to find out?"
|
||||
database_id = MEDAL_DISKPLEASE
|
||||
|
||||
/datum/award/achievement/misc/gamer
|
||||
name = "My Watchlist Status is Not Important"
|
||||
desc = "You may be under the impression that violent video games are a harmless pastime, but the security and medical personnel swarming your location with batons and knockout gas look like they disagree."
|
||||
database_id = MEDAL_GAMER
|
||||
|
||||
/datum/award/achievement/misc/vendor_squish
|
||||
name = "I Was a Teenage Anarchist"
|
||||
desc = "You were doing a great job sticking it to the system until that vending machine decided to fight back."
|
||||
database_id = MEDAL_VENDORSQUISH
|
||||
|
||||
/datum/award/achievement/misc/swirlie
|
||||
name = "A Bowl-d New World"
|
||||
desc = "There's a lot of grisly ways to kick it on the Spinward Periphery, but drowning to death in a toilet probably wasn't what you had in mind. Probably."
|
||||
database_id = MEDAL_SWIRLIE
|
||||
|
||||
/datum/award/achievement/misc/selfouch
|
||||
name = "How Do I Switch Hands???"
|
||||
desc = "If you saw someone casually club themselves upside the head with a toolbox anywhere in the galaxy but here, you'd probably be pretty concerned for them."
|
||||
database_id = MEDAL_SELFOUCH
|
||||
|
||||
/datum/award/achievement/misc/sandman
|
||||
name = "Mister Sandman"
|
||||
desc = "Mechanically speaking, there's no real benefit to being unconscious during surgery. Weird how insistent this doctor is about using the N2O anyway though, huh?"
|
||||
database_id = MEDAL_SANDMAN
|
||||
|
||||
/datum/award/achievement/misc/cleanboss
|
||||
name = "One Lean, Mean, Cleaning Machine"
|
||||
desc = "How does it feel to know that your workplace values a mop bucket on wheels more than you?" // i can do better than this give me time
|
||||
database_id = MEDAL_CLEANBOSS
|
||||
|
||||
/datum/award/achievement/misc/rule8
|
||||
name = "Rule 8"
|
||||
desc = "Call an admin this is ILLEGAL!!"
|
||||
database_id = MEDAL_RULE8
|
||||
icon = "rule8"
|
||||
|
||||
/datum/award/achievement/misc/speed_round
|
||||
name = "Long shift"
|
||||
desc = "Well, that didn't take long."
|
||||
database_id = MEDAL_LONGSHIFT
|
||||
icon = "longshift"
|
||||
|
||||
/datum/award/achievement/misc/snail
|
||||
name = "KKKiiilll mmmeee"
|
||||
desc = "You were a little too ambitious, but hey, I guess you're still alive?"
|
||||
database_id = MEDAL_SNAIL
|
||||
icon = "snail"
|
||||
|
||||
/datum/award/achievement/misc/lookoutsir
|
||||
name = "Look Out, Sir!"
|
||||
desc = "Either awarded for making the ultimate sacrifice for your comrades, or a really dumb attempt at grenade jumping."
|
||||
database_id = MEDAL_LOOKOUTSIR
|
||||
|
||||
/datum/award/achievement/misc/gottem
|
||||
name = "HA, GOTTEM"
|
||||
desc = "Made you look!"
|
||||
database_id = MEDAL_GOTTEM
|
||||
|
||||
/datum/award/achievement/misc/ascension
|
||||
name = "Ascension"
|
||||
desc = "Caedite eos. Novit enim Dominus qui sunt eius."
|
||||
database_id = MEDAL_ASCENSION
|
||||
icon = "ascension"
|
||||
|
||||
/datum/award/achievement/misc/frenching
|
||||
name = "Frenching"
|
||||
desc = "Just a taste, for science!"
|
||||
database_id = MEDAL_FRENCHING
|
||||
icon = "frenching"
|
||||
|
||||
/datum/award/achievement/misc/ash_ascension
|
||||
name = "Nightwatcher's Eyes"
|
||||
desc = "You've risen above the flames, became one with the ashes. You've been reborn as one with the Nightwatcher."
|
||||
database_id = MEDAL_ASH_ASCENSION
|
||||
icon = "ashascend"
|
||||
|
||||
/datum/award/achievement/misc/flesh_ascension
|
||||
name = "Vortex of Arms"
|
||||
desc = "You've became something more, something greater. A piece of the emperor resides within you, and you within him."
|
||||
database_id = MEDAL_FLESH_ASCENSION
|
||||
icon = "fleshascend"
|
||||
|
||||
/datum/award/achievement/misc/rust_ascension
|
||||
name = "Hills of Rust"
|
||||
desc = "You've summoned a piece of the Hill of rust, and so the Hills welcome you."
|
||||
database_id = MEDAL_RUST_ASCENSION
|
||||
icon = "rustascend"
|
||||
|
||||
/datum/award/achievement/misc/void_ascension
|
||||
name = "All that perish"
|
||||
desc = "Place of a diffrent being, diffrent time. Everything ends there... but maybe it is just the beginning?"
|
||||
database_id = MEDAL_VOID_ASCENSION
|
||||
icon = "voidascend"
|
||||
|
||||
/datum/award/achievement/misc/toolbox_soul
|
||||
name = "SOUL'd Out"
|
||||
desc = "My eternal soul was destroyed to make a toolbox look funny and all I got was this achievement..."
|
||||
database_id = MEDAL_TOOLBOX_SOUL
|
||||
icon = "toolbox_soul"
|
||||
10
code/datums/achievements/skill_achievements.dm
Normal file
@@ -0,0 +1,10 @@
|
||||
/datum/award/achievement/skill
|
||||
category = "Skills"
|
||||
icon = "baseskill"
|
||||
|
||||
/datum/award/achievement/skill/legendary_miner
|
||||
name = "Legendary miner"
|
||||
desc = "No mere rock can stop me!"
|
||||
database_id = MEDAL_LEGENDARY_MINER
|
||||
icon = "mining"
|
||||
|
||||
@@ -275,6 +275,11 @@
|
||||
else
|
||||
target.visible_message("<span class='danger'>[target] is hit by a [proj_name][hit_part ? " in the [hit_part.name]" : ""]!</span>", null, null, COMBAT_MESSAGE_RANGE, target)
|
||||
to_chat(target, "<span class='userdanger'>You're hit by a [proj_name][hit_part ? " in the [hit_part.name]" : ""]!</span>")
|
||||
|
||||
for(var/M in purple_hearts)
|
||||
var/mob/living/martyr = M
|
||||
if(martyr.stat == DEAD && martyr.client)
|
||||
martyr.client.give_award(/datum/award/achievement/misc/lookoutsir, martyr)
|
||||
UnregisterSignal(parent, COMSIG_PARENT_PREQDELETED)
|
||||
if(queued_delete)
|
||||
qdel(parent)
|
||||
|
||||
@@ -882,6 +882,9 @@
|
||||
VV_DROPDOWN_OPTION(VV_HK_ADD_REAGENT, "Add Reagent")
|
||||
VV_DROPDOWN_OPTION(VV_HK_TRIGGER_EMP, "EMP Pulse")
|
||||
VV_DROPDOWN_OPTION(VV_HK_TRIGGER_EXPLOSION, "Explosion")
|
||||
// VV_DROPDOWN_OPTION(VV_HK_RADIATE, "Radiate")
|
||||
VV_DROPDOWN_OPTION(VV_HK_EDIT_FILTERS, "Edit Filters")
|
||||
// VV_DROPDOWN_OPTION(VV_HK_ADD_AI, "Add AI controller")
|
||||
|
||||
/atom/vv_do_topic(list/href_list)
|
||||
. = ..()
|
||||
@@ -925,6 +928,9 @@
|
||||
var/newname = input(usr, "What do you want to rename this to?", "Automatic Rename") as null|text
|
||||
if(newname)
|
||||
vv_auto_rename(newname)
|
||||
if(href_list[VV_HK_EDIT_FILTERS] && check_rights(R_VAREDIT))
|
||||
var/client/C = usr.client
|
||||
C?.open_filter_editor(src)
|
||||
|
||||
/atom/vv_get_header()
|
||||
. = ..()
|
||||
@@ -1145,7 +1151,6 @@
|
||||
|
||||
victim.log_message(message, LOG_ATTACK, color="blue")
|
||||
|
||||
// Filter stuff
|
||||
/atom/proc/add_filter(name,priority,list/params)
|
||||
LAZYINITLIST(filter_data)
|
||||
var/list/p = params.Copy()
|
||||
@@ -1161,16 +1166,50 @@
|
||||
var/list/arguments = data.Copy()
|
||||
arguments -= "priority"
|
||||
filters += filter(arglist(arguments))
|
||||
UNSETEMPTY(filter_data)
|
||||
|
||||
/atom/proc/transition_filter(name, time, list/new_params, easing, loop)
|
||||
var/filter = get_filter(name)
|
||||
if(!filter)
|
||||
return
|
||||
|
||||
var/list/old_filter_data = filter_data[name]
|
||||
|
||||
var/list/params = old_filter_data.Copy()
|
||||
for(var/thing in new_params)
|
||||
params[thing] = new_params[thing]
|
||||
|
||||
animate(filter, new_params, time = time, easing = easing, loop = loop)
|
||||
for(var/param in params)
|
||||
filter_data[name][param] = params[param]
|
||||
|
||||
/atom/proc/change_filter_priority(name, new_priority)
|
||||
if(!filter_data || !filter_data[name])
|
||||
return
|
||||
|
||||
filter_data[name]["priority"] = new_priority
|
||||
update_filters()
|
||||
|
||||
/obj/item/update_filters()
|
||||
. = ..()
|
||||
for(var/X in actions)
|
||||
var/datum/action/A = X
|
||||
A.UpdateButtonIcon()
|
||||
|
||||
/atom/proc/get_filter(name)
|
||||
if(filter_data && filter_data[name])
|
||||
return filters[filter_data.Find(name)]
|
||||
|
||||
/atom/proc/remove_filter(name)
|
||||
if(filter_data && filter_data[name])
|
||||
filter_data -= name
|
||||
update_filters()
|
||||
return TRUE
|
||||
/atom/proc/remove_filter(name_or_names)
|
||||
if(!filter_data)
|
||||
return
|
||||
|
||||
var/list/names = islist(name_or_names) ? name_or_names : list(name_or_names)
|
||||
|
||||
for(var/name in names)
|
||||
if(filter_data[name])
|
||||
filter_data -= name
|
||||
update_filters()
|
||||
|
||||
/atom/proc/intercept_zImpact(atom/movable/AM, levels = 1)
|
||||
. |= SEND_SIGNAL(src, COMSIG_ATOM_INTERCEPT_Z_FALL, AM, levels)
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
#define DEFAULT_METEOR_LIFETIME 1800
|
||||
#define MAP_EDGE_PAD 5
|
||||
|
||||
GLOBAL_VAR_INIT(meteor_wave_delay, 625) //minimum wait between waves in tenths of seconds
|
||||
//set to at least 100 unless you want evarr ruining every round
|
||||
|
||||
@@ -30,7 +32,7 @@ GLOBAL_LIST_INIT(meteorsC, list(/obj/effect/meteor/dust)) //for space dust event
|
||||
var/turf/pickedgoal
|
||||
var/max_i = 10//number of tries to spawn meteor.
|
||||
while(!isspaceturf(pickedstart))
|
||||
var/startSide = dir || pick(GLOB.cardinals)
|
||||
var/startSide = (dir ? dir : pick(GLOB.cardinals))
|
||||
var/startZ = pick(SSmapping.levels_by_trait(ZTRAIT_STATION))
|
||||
pickedstart = spaceDebrisStartLoc(startSide, startZ)
|
||||
pickedgoal = spaceDebrisFinishLoc(startSide, startZ)
|
||||
@@ -46,17 +48,17 @@ GLOBAL_LIST_INIT(meteorsC, list(/obj/effect/meteor/dust)) //for space dust event
|
||||
var/startx
|
||||
switch(startSide)
|
||||
if(NORTH)
|
||||
starty = world.maxy-(TRANSITIONEDGE+2)
|
||||
startx = rand((TRANSITIONEDGE+2), world.maxx-(TRANSITIONEDGE+2))
|
||||
starty = world.maxy-(TRANSITIONEDGE + MAP_EDGE_PAD)
|
||||
startx = rand((TRANSITIONEDGE + MAP_EDGE_PAD), world.maxx-(TRANSITIONEDGE + MAP_EDGE_PAD))
|
||||
if(EAST)
|
||||
starty = rand((TRANSITIONEDGE+2),world.maxy-(TRANSITIONEDGE+2))
|
||||
startx = world.maxx-(TRANSITIONEDGE+2)
|
||||
starty = rand((TRANSITIONEDGE + MAP_EDGE_PAD),world.maxy-(TRANSITIONEDGE + MAP_EDGE_PAD))
|
||||
startx = world.maxx-(TRANSITIONEDGE + MAP_EDGE_PAD)
|
||||
if(SOUTH)
|
||||
starty = (TRANSITIONEDGE+2)
|
||||
startx = rand((TRANSITIONEDGE+2), world.maxx-(TRANSITIONEDGE+2))
|
||||
starty = (TRANSITIONEDGE + MAP_EDGE_PAD)
|
||||
startx = rand((TRANSITIONEDGE + MAP_EDGE_PAD), world.maxx-(TRANSITIONEDGE + MAP_EDGE_PAD))
|
||||
if(WEST)
|
||||
starty = rand((TRANSITIONEDGE+2), world.maxy-(TRANSITIONEDGE+2))
|
||||
startx = (TRANSITIONEDGE+2)
|
||||
starty = rand((TRANSITIONEDGE + MAP_EDGE_PAD), world.maxy-(TRANSITIONEDGE + MAP_EDGE_PAD))
|
||||
startx = (TRANSITIONEDGE + MAP_EDGE_PAD)
|
||||
. = locate(startx, starty, Z)
|
||||
|
||||
/proc/spaceDebrisFinishLoc(startSide, Z)
|
||||
@@ -64,17 +66,17 @@ GLOBAL_LIST_INIT(meteorsC, list(/obj/effect/meteor/dust)) //for space dust event
|
||||
var/endx
|
||||
switch(startSide)
|
||||
if(NORTH)
|
||||
endy = (TRANSITIONEDGE+1)
|
||||
endx = rand((TRANSITIONEDGE+1), world.maxx-(TRANSITIONEDGE+1))
|
||||
endy = (TRANSITIONEDGE + MAP_EDGE_PAD)
|
||||
endx = rand((TRANSITIONEDGE + MAP_EDGE_PAD), world.maxx-(TRANSITIONEDGE + MAP_EDGE_PAD))
|
||||
if(EAST)
|
||||
endy = rand((TRANSITIONEDGE+1), world.maxy-(TRANSITIONEDGE+1))
|
||||
endx = (TRANSITIONEDGE+1)
|
||||
endy = rand((TRANSITIONEDGE + MAP_EDGE_PAD), world.maxy-(TRANSITIONEDGE + MAP_EDGE_PAD))
|
||||
endx = (TRANSITIONEDGE + MAP_EDGE_PAD)
|
||||
if(SOUTH)
|
||||
endy = world.maxy-(TRANSITIONEDGE+1)
|
||||
endx = rand((TRANSITIONEDGE+1), world.maxx-(TRANSITIONEDGE+1))
|
||||
endy = world.maxy-(TRANSITIONEDGE + MAP_EDGE_PAD)
|
||||
endx = rand((TRANSITIONEDGE + MAP_EDGE_PAD), world.maxx-(TRANSITIONEDGE + MAP_EDGE_PAD))
|
||||
if(WEST)
|
||||
endy = rand((TRANSITIONEDGE+1),world.maxy-(TRANSITIONEDGE+1))
|
||||
endx = world.maxx-(TRANSITIONEDGE+1)
|
||||
endy = rand((TRANSITIONEDGE + MAP_EDGE_PAD),world.maxy-(TRANSITIONEDGE + MAP_EDGE_PAD))
|
||||
endx = world.maxx-(TRANSITIONEDGE + MAP_EDGE_PAD)
|
||||
. = locate(endx, endy, Z)
|
||||
|
||||
///////////////////////
|
||||
@@ -82,7 +84,7 @@ GLOBAL_LIST_INIT(meteorsC, list(/obj/effect/meteor/dust)) //for space dust event
|
||||
//////////////////////
|
||||
|
||||
/obj/effect/meteor
|
||||
name = "the concept of meteor"
|
||||
name = "\proper the concept of meteor"
|
||||
desc = "You should probably run instead of gawking at this."
|
||||
icon = 'icons/obj/meteor.dmi'
|
||||
icon_state = "small"
|
||||
@@ -92,7 +94,7 @@ GLOBAL_LIST_INIT(meteorsC, list(/obj/effect/meteor/dust)) //for space dust event
|
||||
var/hitpwr = 2 //Level of ex_act to be called on hit.
|
||||
var/dest
|
||||
pass_flags = PASSTABLE
|
||||
var/heavy = 0
|
||||
var/heavy = FALSE
|
||||
var/meteorsound = 'sound/effects/meteorimpact.ogg'
|
||||
var/z_original
|
||||
var/threat = 0 // used for determining which meteors are most interesting
|
||||
@@ -108,12 +110,12 @@ GLOBAL_LIST_INIT(meteorsC, list(/obj/effect/meteor/dust)) //for space dust event
|
||||
|
||||
. = ..() //process movement...
|
||||
|
||||
var/turf/T = get_turf(loc)
|
||||
if(.)//.. if did move, ram the turf we get in
|
||||
var/turf/T = get_turf(loc)
|
||||
ram_turf(T)
|
||||
|
||||
if(prob(10) && !isspaceturf(T) && !istype(T, /turf/closed/mineral) && !istype(T, /turf/open/floor/plating/asteroid))//randomly takes a 'hit' from ramming
|
||||
get_hit()
|
||||
if(prob(10) && !isspaceturf(T) && !istype(T, /turf/closed/mineral) && !istype(T, /turf/open/floor/plating/asteroid))//randomly takes a 'hit' from ramming, and ignore spare ruin aseroids
|
||||
get_hit()
|
||||
|
||||
/obj/effect/meteor/Destroy()
|
||||
if (timerid)
|
||||
@@ -135,24 +137,25 @@ GLOBAL_LIST_INIT(meteorsC, list(/obj/effect/meteor/dust)) //for space dust event
|
||||
/obj/effect/meteor/Bump(atom/A)
|
||||
if(A)
|
||||
ram_turf(get_turf(A))
|
||||
playsound(src.loc, meteorsound, 40, 1)
|
||||
if(!istype(A, /turf/closed/mineral) && !istype(A, /turf/open/floor/plating/asteroid))
|
||||
playsound(src.loc, meteorsound, 40, TRUE)
|
||||
if(!istype(A, /turf/closed/mineral) && !istype(A, /turf/open/floor/plating/asteroid)) // ignore localstation ruins
|
||||
get_hit()
|
||||
|
||||
/obj/effect/meteor/proc/ram_turf(turf/T)
|
||||
//first bust whatever is in the turf
|
||||
for(var/atom/A in T)
|
||||
if(A != src)
|
||||
if(isliving(A))
|
||||
A.visible_message("<span class='warning'>[src] slams into [A].</span>", "<span class='userdanger'>[src] slams into you!.</span>")
|
||||
A.ex_act(hitpwr)
|
||||
for(var/thing in T)
|
||||
if(thing == src)
|
||||
continue
|
||||
if(isliving(thing))
|
||||
var/mob/living/living_thing = thing
|
||||
living_thing.visible_message("<span class='warning'>[src] slams into [living_thing].</span>", "<span class='userdanger'>[src] slams into you!.</span>")
|
||||
A.ex_act(hitpwr)
|
||||
|
||||
//then, ram the turf if it still exists
|
||||
if(T)
|
||||
T.ex_act(hitpwr)
|
||||
|
||||
|
||||
|
||||
//process getting 'hit' by colliding with a dense object
|
||||
//or randomly when ramming turfs
|
||||
/obj/effect/meteor/proc/get_hit()
|
||||
@@ -162,13 +165,10 @@ GLOBAL_LIST_INIT(meteorsC, list(/obj/effect/meteor/dust)) //for space dust event
|
||||
meteor_effect()
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/meteor/ex_act()
|
||||
return
|
||||
|
||||
/obj/effect/meteor/examine(mob/user)
|
||||
. = ..()
|
||||
if(!(flags_1 & ADMIN_SPAWNED_1) && isliving(user))
|
||||
SSmedals.UnlockMedal(MEDAL_METEOR, user.client)
|
||||
return ..()
|
||||
user.client.give_award(/datum/award/achievement/misc/meteor_examine, user)
|
||||
|
||||
/obj/effect/meteor/attackby(obj/item/I, mob/user, params)
|
||||
if(I.tool_behaviour == TOOL_MINING)
|
||||
@@ -232,7 +232,7 @@ GLOBAL_LIST_INIT(meteorsC, list(/obj/effect/meteor/dust)) //for space dust event
|
||||
name = "big meteor"
|
||||
icon_state = "large"
|
||||
hits = 6
|
||||
heavy = 1
|
||||
heavy = TRUE
|
||||
dropamt = 4
|
||||
threat = 10
|
||||
|
||||
@@ -245,7 +245,7 @@ GLOBAL_LIST_INIT(meteorsC, list(/obj/effect/meteor/dust)) //for space dust event
|
||||
name = "flaming meteor"
|
||||
icon_state = "flaming"
|
||||
hits = 5
|
||||
heavy = 1
|
||||
heavy = TRUE
|
||||
meteorsound = 'sound/effects/bamf.ogg'
|
||||
meteordrop = list(/obj/item/stack/ore/plasma)
|
||||
threat = 20
|
||||
@@ -258,7 +258,7 @@ GLOBAL_LIST_INIT(meteorsC, list(/obj/effect/meteor/dust)) //for space dust event
|
||||
/obj/effect/meteor/irradiated
|
||||
name = "glowing meteor"
|
||||
icon_state = "glowing"
|
||||
heavy = 1
|
||||
heavy = TRUE
|
||||
meteordrop = list(/obj/item/stack/ore/uranium)
|
||||
threat = 15
|
||||
|
||||
@@ -275,7 +275,7 @@ GLOBAL_LIST_INIT(meteorsC, list(/obj/effect/meteor/dust)) //for space dust event
|
||||
icon_state = "meateor"
|
||||
desc = "Just... don't think too hard about where this thing came from."
|
||||
hits = 2
|
||||
heavy = 1
|
||||
heavy = TRUE
|
||||
meteorsound = 'sound/effects/blobattack.ogg'
|
||||
meteordrop = list(/obj/item/reagent_containers/food/snacks/meat/slab/human, /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant, /obj/item/organ/heart, /obj/item/organ/lungs, /obj/item/organ/tongue, /obj/item/organ/appendix/)
|
||||
var/meteorgibs = /obj/effect/gibspawner/generic
|
||||
@@ -327,7 +327,7 @@ GLOBAL_LIST_INIT(meteorsC, list(/obj/effect/meteor/dust)) //for space dust event
|
||||
desc = "Your life briefly passes before your eyes the moment you lay them on this monstrosity."
|
||||
hits = 30
|
||||
hitpwr = 1
|
||||
heavy = 1
|
||||
heavy = TRUE
|
||||
meteorsound = 'sound/effects/bamf.ogg'
|
||||
meteordrop = list(/obj/item/stack/ore/plasma)
|
||||
threat = 50
|
||||
@@ -358,7 +358,7 @@ GLOBAL_LIST_INIT(meteorsSPOOKY, list(/obj/effect/meteor/pumpkin))
|
||||
icon = 'icons/obj/meteor_spooky.dmi'
|
||||
icon_state = "pumpkin"
|
||||
hits = 10
|
||||
heavy = 1
|
||||
heavy = TRUE
|
||||
dropamt = 1
|
||||
meteordrop = list(/obj/item/clothing/head/hardhat/pumpkinhead, /obj/item/reagent_containers/food/snacks/grown/pumpkin)
|
||||
threat = 100
|
||||
@@ -368,3 +368,4 @@ GLOBAL_LIST_INIT(meteorsSPOOKY, list(/obj/effect/meteor/pumpkin))
|
||||
meteorsound = pick('sound/hallucinations/im_here1.ogg','sound/hallucinations/im_here2.ogg')
|
||||
//////////////////////////
|
||||
#undef DEFAULT_METEOR_LIFETIME
|
||||
#undef MAP_EDGE_PAD
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#define AUTOLATHE_MAIN_MENU 1
|
||||
#define AUTOLATHE_CATEGORY_MENU 2
|
||||
#define AUTOLATHE_SEARCH_MENU 3
|
||||
#define AUTOLATHE_MAIN_MENU 1
|
||||
#define AUTOLATHE_CATEGORY_MENU 2
|
||||
#define AUTOLATHE_SEARCH_MENU 3
|
||||
|
||||
/obj/machinery/autolathe
|
||||
name = "autolathe"
|
||||
@@ -17,7 +17,7 @@
|
||||
var/list/L = list()
|
||||
var/list/LL = list()
|
||||
var/hacked = FALSE
|
||||
var/disabled = 0
|
||||
var/disabled = FALSE
|
||||
var/shocked = FALSE
|
||||
var/hack_wire
|
||||
var/disable_wire
|
||||
@@ -27,13 +27,13 @@
|
||||
var/prod_coeff = 1
|
||||
|
||||
var/datum/design/being_built
|
||||
var/datum/techweb/stored_research
|
||||
var/list/datum/design/matching_designs
|
||||
var/selected_category
|
||||
var/screen = 1
|
||||
var/base_price = 25
|
||||
var/hacked_price = 50
|
||||
|
||||
var/datum/techweb/specialized/autounlocking/stored_research = /datum/techweb/specialized/autounlocking/autolathe
|
||||
var/list/categories = list(
|
||||
"Tools",
|
||||
"Electronics",
|
||||
@@ -46,19 +46,13 @@
|
||||
"Dinnerware",
|
||||
"Imported"
|
||||
)
|
||||
var/list/allowed_materials
|
||||
|
||||
/// Base print speed
|
||||
var/base_print_speed = 10
|
||||
|
||||
/obj/machinery/autolathe/Initialize()
|
||||
var/list/mats = allowed_materials
|
||||
if(!mats)
|
||||
mats = SSmaterials.materialtypes_by_category[MAT_CATEGORY_RIGID]
|
||||
AddComponent(/datum/component/material_container, mats, _show_on_examine=TRUE, _after_insert=CALLBACK(src, .proc/AfterMaterialInsert))
|
||||
AddComponent(/datum/component/material_container, SSmaterials.materialtypes_by_category[MAT_CATEGORY_RIGID], 0, TRUE, null, null, CALLBACK(src, .proc/AfterMaterialInsert))
|
||||
. = ..()
|
||||
|
||||
wires = new /datum/wires/autolathe(src)
|
||||
stored_research = new stored_research
|
||||
stored_research = new /datum/techweb/specialized/autounlocking/autolathe
|
||||
matching_designs = list()
|
||||
|
||||
/obj/machinery/autolathe/Destroy()
|
||||
@@ -83,7 +77,7 @@
|
||||
if(AUTOLATHE_SEARCH_MENU)
|
||||
dat = search_win(user)
|
||||
|
||||
var/datum/browser/popup = new(user, name, name, 400, 500)
|
||||
var/datum/browser/popup = new(user, "autolathe", name, 400, 500)
|
||||
popup.set_content(dat)
|
||||
popup.open()
|
||||
|
||||
@@ -114,9 +108,9 @@
|
||||
return TRUE
|
||||
|
||||
if(istype(O, /obj/item/disk/design_disk))
|
||||
user.visible_message("[user] begins to load \the [O] in \the [src]...",
|
||||
"You begin to load a design from \the [O]...",
|
||||
"You hear the chatter of a floppy drive.")
|
||||
user.visible_message("<span class='notice'>[user] begins to load \the [O] in \the [src]...</span>",
|
||||
"<span class='notice'>You begin to load a design from \the [O]...</span>",
|
||||
"<span class='hear'>You hear the chatter of a floppy drive.</span>")
|
||||
busy = TRUE
|
||||
var/obj/item/disk/design_disk/D = O
|
||||
if(do_after(user, 14.4, target = src))
|
||||
@@ -128,14 +122,16 @@
|
||||
|
||||
return ..()
|
||||
|
||||
/obj/machinery/autolathe/proc/AfterMaterialInsert(obj/item/item_inserted, id_inserted, amount_inserted)
|
||||
|
||||
/obj/machinery/autolathe/proc/AfterMaterialInsert(item_inserted, id_inserted, amount_inserted)
|
||||
if(istype(item_inserted, /obj/item/stack/ore/bluespace_crystal))
|
||||
use_power(MINERAL_MATERIAL_AMOUNT / 10)
|
||||
else if(item_inserted.custom_materials?.len && item_inserted.custom_materials[SSmaterials.GetMaterialRef(/datum/material/glass)])
|
||||
else if(custom_materials && custom_materials.len && custom_materials[SSmaterials.GetMaterialRef(/datum/material/glass)])
|
||||
flick("autolathe_r",src)//plays glass insertion animation by default otherwise
|
||||
else
|
||||
flick("autolathe_o",src)//plays metal insertion animation
|
||||
|
||||
|
||||
use_power(min(1000, amount_inserted / 100))
|
||||
updateUsrDialog()
|
||||
|
||||
@@ -187,7 +183,7 @@
|
||||
if(materials.materials[i] > 0)
|
||||
list_to_show += i
|
||||
|
||||
used_material = input("Choose [used_material]", "Custom Material") as null|anything in list_to_show
|
||||
used_material = input("Choose [used_material]", "Custom Material") as null|anything in sortList(list_to_show, /proc/cmp_typepaths_asc)
|
||||
if(!used_material)
|
||||
return //Didn't pick any material, so you can't build shit either.
|
||||
custom_materials[used_material] += amount_needed
|
||||
@@ -198,8 +194,8 @@
|
||||
busy = TRUE
|
||||
use_power(power)
|
||||
icon_state = "autolathe_n"
|
||||
var/time = is_stack ? 10 : base_print_speed * coeff * multiplier
|
||||
addtimer(CALLBACK(src, .proc/make_item, power, materials_used, custom_materials, multiplier, coeff, is_stack), time)
|
||||
var/time = is_stack ? 32 : (32 * coeff * multiplier) ** 0.8
|
||||
addtimer(CALLBACK(src, .proc/make_item, power, materials_used, custom_materials, multiplier, coeff, is_stack, usr), time)
|
||||
else
|
||||
to_chat(usr, "<span class=\"alert\">Not enough materials for this operation.</span>")
|
||||
|
||||
@@ -218,10 +214,11 @@
|
||||
|
||||
return
|
||||
|
||||
/obj/machinery/autolathe/proc/make_item(power, var/list/materials_used, var/list/picked_materials, multiplier, coeff, is_stack)
|
||||
/obj/machinery/autolathe/proc/make_item(power, list/materials_used, list/picked_materials, multiplier, coeff, is_stack, mob/user)
|
||||
var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
|
||||
var/atom/A = drop_location()
|
||||
use_power(power)
|
||||
|
||||
materials.use_materials(materials_used)
|
||||
|
||||
if(is_stack)
|
||||
@@ -235,6 +232,11 @@
|
||||
|
||||
if(length(picked_materials))
|
||||
new_item.set_custom_materials(picked_materials, 1 / multiplier) //Ensure we get the non multiplied amount
|
||||
for(var/x in picked_materials)
|
||||
var/datum/material/M = x
|
||||
if(!istype(M, /datum/material/glass) && !istype(M, /datum/material/iron))
|
||||
user.client.give_award(/datum/award/achievement/misc/getting_an_upgrade, user)
|
||||
|
||||
|
||||
icon_state = "autolathe"
|
||||
busy = FALSE
|
||||
@@ -246,12 +248,10 @@
|
||||
T += MB.rating*75000
|
||||
var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
|
||||
materials.max_amount = T
|
||||
var/manips = 0
|
||||
var/total_manip_rating = 0
|
||||
T=1.2
|
||||
for(var/obj/item/stock_parts/manipulator/M in component_parts)
|
||||
total_manip_rating += M.rating
|
||||
manips++
|
||||
prod_coeff = STANDARD_PART_LEVEL_LATHE_COEFFICIENT(total_manip_rating / (manips? manips : 1))
|
||||
T -= M.rating*0.2
|
||||
prod_coeff = min(1,max(0,T)) // Coeff going 1 -> 0,8 -> 0,6 -> 0,4
|
||||
|
||||
/obj/machinery/autolathe/examine(mob/user)
|
||||
. += ..()
|
||||
@@ -376,6 +376,7 @@
|
||||
|
||||
return materials.has_materials(required_materials)
|
||||
|
||||
|
||||
/obj/machinery/autolathe/proc/get_design_cost(datum/design/D)
|
||||
var/coeff = (ispath(D.build_path, /obj/item/stack) ? 1 : prod_coeff)
|
||||
var/dat
|
||||
@@ -416,9 +417,7 @@
|
||||
hacked = state
|
||||
for(var/id in SSresearch.techweb_designs)
|
||||
var/datum/design/D = SSresearch.techweb_design_by_id(id)
|
||||
if(D.build_type & stored_research.design_autounlock_skip_types)
|
||||
continue
|
||||
if((D.build_type & stored_research.design_autounlock_buildtypes) && ("hacked" in D.category))
|
||||
if((D.build_type & AUTOLATHE) && ("hacked" in D.category))
|
||||
if(hacked)
|
||||
stored_research.add_design(D)
|
||||
else
|
||||
@@ -428,19 +427,24 @@
|
||||
. = ..()
|
||||
adjust_hacked(TRUE)
|
||||
|
||||
//Called when the object is constructed by an autolathe
|
||||
//Has a reference to the autolathe so you can do !!FUN!! things with hacked lathes
|
||||
/obj/item/proc/autolathe_crafted(obj/machinery/autolathe/A)
|
||||
return
|
||||
|
||||
/obj/machinery/autolathe/secure
|
||||
name = "secured autolathe"
|
||||
desc = "It produces items using metal and glass. This model was reprogrammed without some of the more hazardous designs."
|
||||
circuit = /obj/item/circuitboard/machine/autolathe/secure
|
||||
stored_research = /datum/techweb/specialized/autounlocking/autolathe/public
|
||||
base_print_speed = 20
|
||||
|
||||
/obj/machinery/autolathe/secure/Initialize()
|
||||
. = ..()
|
||||
stored_research = new /datum/techweb/specialized/autounlocking/autolathe/public
|
||||
|
||||
/obj/machinery/autolathe/toy
|
||||
name = "autoylathe"
|
||||
desc = "It produces toys using plastic, metal and glass."
|
||||
circuit = /obj/item/circuitboard/machine/autolathe/toy
|
||||
|
||||
stored_research = /datum/techweb/specialized/autounlocking/autolathe/toy
|
||||
categories = list(
|
||||
"Toys",
|
||||
"Figurines",
|
||||
@@ -453,12 +457,8 @@
|
||||
"Misc",
|
||||
"Imported"
|
||||
)
|
||||
allowed_materials = list(
|
||||
/datum/material/iron,
|
||||
/datum/material/glass,
|
||||
/datum/material/plastic
|
||||
)
|
||||
|
||||
/obj/machinery/autolathe/toy/hacked/Initialize()
|
||||
. = ..()
|
||||
adjust_hacked(TRUE)
|
||||
stored_research = new /datum/techweb/specialized/autounlocking/autolathe/toy
|
||||
|
||||
@@ -3,14 +3,7 @@
|
||||
#define ARCADE_WEIGHT_RARE 1
|
||||
#define ARCADE_RATIO_PLUSH 0.20 // average 1 out of 6 wins is a plush.
|
||||
|
||||
/obj/machinery/computer/arcade
|
||||
name = "random arcade"
|
||||
desc = "random arcade machine"
|
||||
icon_state = "arcade"
|
||||
icon_keyboard = null
|
||||
icon_screen = "invaders"
|
||||
clockwork = TRUE //it'd look weird
|
||||
var/list/prizes = list(
|
||||
GLOBAL_LIST_INIT(arcade_prize_pool, list(
|
||||
/obj/item/toy/balloon = ARCADE_WEIGHT_USELESS,
|
||||
/obj/item/toy/beach_ball = ARCADE_WEIGHT_USELESS,
|
||||
/obj/item/toy/cattoy = ARCADE_WEIGHT_USELESS,
|
||||
@@ -70,9 +63,16 @@
|
||||
/obj/item/clothing/mask/fakemoustache/italian = ARCADE_WEIGHT_RARE,
|
||||
/obj/item/clothing/suit/hooded/wintercoat/ratvar/fake = ARCADE_WEIGHT_TRICK,
|
||||
/obj/item/clothing/suit/hooded/wintercoat/narsie/fake = ARCADE_WEIGHT_TRICK
|
||||
)
|
||||
))
|
||||
|
||||
/obj/machinery/computer/arcade
|
||||
name = "random arcade"
|
||||
desc = "random arcade machine"
|
||||
icon_state = "arcade"
|
||||
icon_keyboard = "no_keyboard"
|
||||
icon_screen = "invaders"
|
||||
light_color = LIGHT_COLOR_GREEN
|
||||
var/list/prize_override
|
||||
|
||||
/obj/machinery/computer/arcade/proc/Reset()
|
||||
return
|
||||
@@ -96,39 +96,51 @@
|
||||
prizes[/obj/item/toy/plush/random] = counterlist_sum(prizes) * ARCADE_RATIO_PLUSH
|
||||
Reset()
|
||||
|
||||
/obj/machinery/computer/arcade/proc/prizevend(mob/user, list/rarity_classes)
|
||||
SEND_SIGNAL(user, COMSIG_ADD_MOOD_EVENT, "arcade", /datum/mood_event/arcade)
|
||||
/obj/machinery/computer/arcade/proc/prizevend(mob/user, prizes = 1)
|
||||
// if(user.mind?.get_skill_level(/datum/skill/gaming) >= SKILL_LEVEL_LEGENDARY && HAS_TRAIT(user, TRAIT_GAMERGOD))
|
||||
// visible_message("<span class='notice'>[user] inputs an intense cheat code!",\
|
||||
// "<span class='notice'>You hear a flurry of buttons being pressed.</span>")
|
||||
// say("CODE ACTIVATED: EXTRA PRIZES.")
|
||||
// prizes *= 2
|
||||
for(var/i = 0, i < prizes, i++)
|
||||
SEND_SIGNAL(user, COMSIG_ADD_MOOD_EVENT, "arcade", /datum/mood_event/arcade)
|
||||
if(prob(0.0001)) //1 in a million
|
||||
new /obj/item/gun/energy/pulse/prize(src)
|
||||
visible_message("<span class='notice'>[src] dispenses.. woah, a gun! Way past cool.</span>", "<span class='notice'>You hear a chime and a shot.</span>")
|
||||
user.client.give_award(/datum/award/achievement/misc/pulse, user)
|
||||
return
|
||||
|
||||
if(prob(1) && prob(1) && prob(1)) //Proper 1 in a million
|
||||
new /obj/item/gun/energy/pulse/prize(src)
|
||||
SSmedals.UnlockMedal(MEDAL_PULSE, usr.client)
|
||||
var/prizeselect
|
||||
if(prize_override)
|
||||
prizeselect = pickweight(prize_override)
|
||||
else
|
||||
prizeselect = pickweight(GLOB.arcade_prize_pool)
|
||||
var/atom/movable/the_prize = new prizeselect(get_turf(src))
|
||||
playsound(src, 'sound/machines/machine_vend.ogg', 50, TRUE, extrarange = -3)
|
||||
visible_message("<span class='notice'>[src] dispenses [the_prize]!</span>", "<span class='notice'>You hear a chime and a clunk.</span>")
|
||||
|
||||
if(!contents.len)
|
||||
var/list/toy_raffle
|
||||
if(rarity_classes)
|
||||
for(var/A in prizes)
|
||||
if(prizes[A] in rarity_classes)
|
||||
LAZYSET(toy_raffle, A, prizes[A])
|
||||
if(!toy_raffle)
|
||||
toy_raffle = prizes
|
||||
var/prizeselect = pickweight(toy_raffle)
|
||||
new prizeselect(src)
|
||||
|
||||
var/atom/movable/prize = pick(contents)
|
||||
visible_message("<span class='notice'>[src] dispenses [prize]!</span>", "<span class='notice'>You hear a chime and a clunk.</span>")
|
||||
|
||||
prize.forceMove(get_turf(src))
|
||||
|
||||
/obj/machinery/computer/arcade/emp_act(severity)
|
||||
. = ..()
|
||||
var/override = FALSE
|
||||
if(prize_override)
|
||||
override = TRUE
|
||||
|
||||
if(stat & (NOPOWER|BROKEN) || . & EMP_PROTECT_SELF)
|
||||
return
|
||||
|
||||
var/empprize = null
|
||||
var/num_of_prizes = rand(round(severity/50),round(severity/100))
|
||||
var/num_of_prizes = 0
|
||||
switch(severity)
|
||||
if(1)
|
||||
num_of_prizes = rand(1,4)
|
||||
if(2)
|
||||
num_of_prizes = rand(0,2)
|
||||
for(var/i = num_of_prizes; i > 0; i--)
|
||||
empprize = pickweight(prizes)
|
||||
if(override)
|
||||
empprize = pickweight(prize_override)
|
||||
else
|
||||
empprize = pickweight(GLOB.arcade_prize_pool)
|
||||
new empprize(loc)
|
||||
explosion(loc, -1, 0, 1+num_of_prizes, flame_range = 1+num_of_prizes)
|
||||
|
||||
|
||||
@@ -1,130 +1,399 @@
|
||||
// ** BATTLE ** //
|
||||
|
||||
|
||||
/obj/machinery/computer/arcade/battle
|
||||
name = "arcade machine"
|
||||
desc = "Does not support Pinball."
|
||||
icon_state = "arcade"
|
||||
circuit = /obj/item/circuitboard/computer/arcade/battle
|
||||
var/enemy_name = "Space Villain"
|
||||
var/temp = "Winners don't use space drugs" //Temporary message, for attack messages, etc
|
||||
var/player_hp = 30 //Player health/attack points
|
||||
var/player_mp = 10
|
||||
var/enemy_hp = 45 //Enemy health/attack points
|
||||
var/enemy_mp = 20
|
||||
var/gameover = FALSE
|
||||
var/blocked = FALSE //Player cannot attack/heal while set
|
||||
var/turtle = 0
|
||||
|
||||
var/turn_speed = 5 //Measured in deciseconds.
|
||||
var/enemy_name = "Space Villain"
|
||||
///Enemy health/attack points
|
||||
var/enemy_hp = 100
|
||||
var/enemy_mp = 40
|
||||
///Temporary message, for attack messages, etc
|
||||
var/temp = "<br><center><h3>Winners don't use space drugs<center><h3>"
|
||||
///the list of passive skill the enemy currently has. the actual passives are added in the enemy_setup() proc
|
||||
var/list/enemy_passive
|
||||
///if all the enemy's weakpoints have been triggered becomes TRUE
|
||||
var/finishing_move = FALSE
|
||||
///linked to passives, when it's equal or above the max_passive finishing move will become TRUE
|
||||
var/pissed_off = 0
|
||||
///the number of passives the enemy will start with
|
||||
var/max_passive = 3
|
||||
///weapon wielded by the enemy, the shotgun doesn't count.
|
||||
var/chosen_weapon
|
||||
|
||||
///Player health
|
||||
var/player_hp = 85
|
||||
///player magic points
|
||||
var/player_mp = 20
|
||||
///used to remember the last three move of the player before this turn.
|
||||
var/list/last_three_move
|
||||
///if the enemy or player died. restart the game when TRUE
|
||||
var/gameover = FALSE
|
||||
///the player cannot make any move while this is set to TRUE. should only TRUE during enemy turns.
|
||||
var/blocked = FALSE
|
||||
///used to clear the enemy_action proc timer when the game is restarted
|
||||
var/timer_id
|
||||
///weapon used by the enemy, pure fluff.for certain actions
|
||||
var/list/weapons
|
||||
///unique to the emag mode, acts as a time limit where the player dies when it reaches 0.
|
||||
var/bomb_cooldown = 19
|
||||
|
||||
///creates the enemy base stats for a new round along with the enemy passives
|
||||
/obj/machinery/computer/arcade/battle/proc/enemy_setup(player_skill)
|
||||
player_hp = 85
|
||||
player_mp = 20
|
||||
enemy_hp = 100
|
||||
enemy_mp = 40
|
||||
gameover = FALSE
|
||||
blocked = FALSE
|
||||
finishing_move = FALSE
|
||||
pissed_off = 0
|
||||
last_three_move = null
|
||||
|
||||
enemy_passive = list("short_temper" = TRUE, "poisonous" = TRUE, "smart" = TRUE, "shotgun" = TRUE, "magical" = TRUE, "chonker" = TRUE)
|
||||
for(var/i = LAZYLEN(enemy_passive); i > max_passive; i--) //we'll remove passives from the list until we have the number of passive we want
|
||||
var/picked_passive = pick(enemy_passive)
|
||||
LAZYREMOVE(enemy_passive, picked_passive)
|
||||
|
||||
if(LAZYACCESS(enemy_passive, "chonker"))
|
||||
enemy_hp += 20
|
||||
|
||||
if(LAZYACCESS(enemy_passive, "shotgun"))
|
||||
chosen_weapon = "shotgun"
|
||||
else if(weapons)
|
||||
chosen_weapon = pick(weapons)
|
||||
else
|
||||
chosen_weapon = "null gun" //if the weapons list is somehow empty, shouldn't happen but runtimes are sneaky bastards.
|
||||
|
||||
if(player_skill)
|
||||
player_hp += player_skill * 2
|
||||
|
||||
/obj/machinery/computer/arcade/battle/Reset()
|
||||
max_passive = 3
|
||||
var/name_action
|
||||
var/name_part1
|
||||
var/name_part2
|
||||
|
||||
name_action = pick("Defeat ", "Annihilate ", "Save ", "Strike ", "Stop ", "Destroy ", "Robust ", "Romance ", "Pwn ", "Own ", "Ban ")
|
||||
if(SSevents.holidays && SSevents.holidays[HALLOWEEN])
|
||||
name_action = pick_list(ARCADE_FILE, "rpg_action_halloween")
|
||||
name_part1 = pick_list(ARCADE_FILE, "rpg_adjective_halloween")
|
||||
name_part2 = pick_list(ARCADE_FILE, "rpg_enemy_halloween")
|
||||
weapons = strings(ARCADE_FILE, "rpg_weapon_halloween")
|
||||
else if(SSevents.holidays && SSevents.holidays[CHRISTMAS])
|
||||
name_action = pick_list(ARCADE_FILE, "rpg_action_xmas")
|
||||
name_part1 = pick_list(ARCADE_FILE, "rpg_adjective_xmas")
|
||||
name_part2 = pick_list(ARCADE_FILE, "rpg_enemy_xmas")
|
||||
weapons = strings(ARCADE_FILE, "rpg_weapon_xmas")
|
||||
else if(SSevents.holidays && SSevents.holidays[VALENTINES])
|
||||
name_action = pick_list(ARCADE_FILE, "rpg_action_valentines")
|
||||
name_part1 = pick_list(ARCADE_FILE, "rpg_adjective_valentines")
|
||||
name_part2 = pick_list(ARCADE_FILE, "rpg_enemy_valentines")
|
||||
weapons = strings(ARCADE_FILE, "rpg_weapon_valentines")
|
||||
else
|
||||
name_action = pick_list(ARCADE_FILE, "rpg_action")
|
||||
name_part1 = pick_list(ARCADE_FILE, "rpg_adjective")
|
||||
name_part2 = pick_list(ARCADE_FILE, "rpg_enemy")
|
||||
weapons = strings(ARCADE_FILE, "rpg_weapon")
|
||||
|
||||
name_part1 = pick("the Automatic ", "Farmer ", "Lord ", "Professor ", "the Cuban ", "the Evil ", "the Dread King ", "the Space ", "Lord ", "the Great ", "Duke ", "General ")
|
||||
name_part2 = pick("Melonoid", "Murdertron", "Sorcerer", "Ruin", "Jeff", "Ectoplasm", "Crushulon", "Uhangoid", "Vhakoid", "Peteoid", "slime", "Griefer", "ERPer", "Lizard Man", "Unicorn", "Bloopers")
|
||||
enemy_name = ("The " + name_part1 + " " + name_part2)
|
||||
name = (name_action + " " + enemy_name)
|
||||
|
||||
enemy_name = replacetext((name_part1 + name_part2), "the ", "")
|
||||
name = (name_action + name_part1 + name_part2)
|
||||
enemy_setup(0) //in the case it's reset we assume the player skill is 0 because the VOID isn't a gamer
|
||||
|
||||
/obj/machinery/computer/arcade/battle/ui_interact(mob/user)
|
||||
. = ..()
|
||||
screen_setup(user)
|
||||
|
||||
///sets up the main screen for the user
|
||||
/obj/machinery/computer/arcade/battle/proc/screen_setup(mob/user)
|
||||
var/dat = "<a href='byond://?src=[REF(src)];close=1'>Close</a>"
|
||||
dat += "<center><h4>[enemy_name]</h4></center>"
|
||||
|
||||
dat += "<br><center><h3>[temp]</h3></center>"
|
||||
dat += "[temp]"
|
||||
dat += "<br><center>Health: [player_hp] | Magic: [player_mp] | Enemy Health: [enemy_hp]</center>"
|
||||
|
||||
if (gameover)
|
||||
dat += "<center><b><a href='byond://?src=[REF(src)];newgame=1'>New Game</a>"
|
||||
else
|
||||
dat += "<center><b><a href='byond://?src=[REF(src)];attack=1'>Attack</a> | "
|
||||
dat += "<a href='byond://?src=[REF(src)];heal=1'>Heal</a> | "
|
||||
dat += "<a href='byond://?src=[REF(src)];charge=1'>Recharge Power</a>"
|
||||
dat += "<center><b><a href='byond://?src=[REF(src)];attack=1'>Light attack</a>"
|
||||
dat += "<center><b><a href='byond://?src=[REF(src)];defend=1'>Defend</a>"
|
||||
dat += "<center><b><a href='byond://?src=[REF(src)];counter_attack=1'>Counter attack</a>"
|
||||
dat += "<center><b><a href='byond://?src=[REF(src)];power_attack=1'>Power attack</a>"
|
||||
|
||||
dat += "</b></center>"
|
||||
var/datum/browser/popup = new(user, "arcade", "Space Villain 2000")
|
||||
popup.set_content(dat)
|
||||
popup.open()
|
||||
if(user.client) //mainly here to avoid a runtime when the player gets gibbed when losing the emag mode.
|
||||
var/datum/browser/popup = new(user, "arcade", "Space Villain 2000")
|
||||
popup.set_content(dat)
|
||||
popup.open()
|
||||
|
||||
/obj/machinery/computer/arcade/battle/Topic(href, href_list)
|
||||
if(..())
|
||||
return
|
||||
var/gamerSkill = 0
|
||||
// if(usr?.mind)
|
||||
// gamerSkill = usr.mind.get_skill_level(/datum/skill/gaming)
|
||||
|
||||
if (!blocked && !gameover)
|
||||
var/attackamt = rand(5,7) + rand(0, gamerSkill)
|
||||
|
||||
if(finishing_move) //time to bonk that fucker,cuban pete will sometime survive a finishing move.
|
||||
attackamt *= 100
|
||||
|
||||
//light attack suck absolute ass but it doesn't cost any MP so it's pretty good to finish an enemy off
|
||||
if (href_list["attack"])
|
||||
blocked = TRUE
|
||||
var/attackamt = rand(2,6)
|
||||
temp = "You attack for [attackamt] damage!"
|
||||
playsound(loc, 'sound/arcade/hit.ogg', 50, TRUE, extrarange = -3)
|
||||
updateUsrDialog()
|
||||
if(turtle > 0)
|
||||
turtle--
|
||||
|
||||
sleep(turn_speed)
|
||||
temp = "<br><center><h3>you do quick jab for [attackamt] of damage!</h3></center>"
|
||||
enemy_hp -= attackamt
|
||||
arcade_action(usr)
|
||||
arcade_action(usr,"attack",attackamt)
|
||||
|
||||
else if (href_list["heal"])
|
||||
blocked = TRUE
|
||||
var/pointamt = rand(1,3)
|
||||
var/healamt = rand(6,8)
|
||||
temp = "You use [pointamt] magic to heal for [healamt] damage!"
|
||||
playsound(loc, 'sound/arcade/heal.ogg', 50, TRUE, extrarange = -3)
|
||||
updateUsrDialog()
|
||||
turtle++
|
||||
//defend lets you gain back MP and take less damage from non magical attack.
|
||||
else if(href_list["defend"])
|
||||
temp = "<br><center><h3>you take a defensive stance and gain back 10 mp!</h3></center>"
|
||||
player_mp += 10
|
||||
arcade_action(usr,"defend",attackamt)
|
||||
playsound(src, 'sound/arcade/mana.ogg', 50, TRUE, extrarange = -3)
|
||||
|
||||
sleep(turn_speed)
|
||||
player_mp -= pointamt
|
||||
player_hp += healamt
|
||||
blocked = TRUE
|
||||
updateUsrDialog()
|
||||
arcade_action(usr)
|
||||
//mainly used to counter short temper and their absurd damage, will deal twice the damage the player took of a non magical attack.
|
||||
else if(href_list["counter_attack"] && player_mp >= 10)
|
||||
temp = "<br><center><h3>you prepare yourself to counter the next attack!</h3></center>"
|
||||
player_mp -= 10
|
||||
arcade_action(usr,"counter_attack",attackamt)
|
||||
playsound(src, 'sound/arcade/mana.ogg', 50, TRUE, extrarange = -3)
|
||||
|
||||
else if (href_list["charge"])
|
||||
blocked = TRUE
|
||||
var/chargeamt = rand(4,7)
|
||||
temp = "You regain [chargeamt] points"
|
||||
playsound(loc, 'sound/arcade/mana.ogg', 50, TRUE, extrarange = -3)
|
||||
player_mp += chargeamt
|
||||
if(turtle > 0)
|
||||
turtle--
|
||||
else if(href_list["counter_attack"] && player_mp < 10)
|
||||
temp = "<br><center><h3>you don't have the mp necessary to counter attack and defend yourself instead</h3></center>"
|
||||
player_mp += 10
|
||||
arcade_action(usr,"defend",attackamt)
|
||||
playsound(src, 'sound/arcade/mana.ogg', 50, TRUE, extrarange = -3)
|
||||
|
||||
updateUsrDialog()
|
||||
sleep(turn_speed)
|
||||
arcade_action(usr)
|
||||
//power attack deals twice the amount of damage but is really expensive MP wise, mainly used with combos to get weakpoints.
|
||||
else if (href_list["power_attack"] && player_mp >= 20)
|
||||
temp = "<br><center><h3>You attack [enemy_name] with all your might for [attackamt * 2] damage!</h3></center>"
|
||||
enemy_hp -= attackamt * 2
|
||||
player_mp -= 20
|
||||
arcade_action(usr,"power_attack",attackamt)
|
||||
|
||||
else if(href_list["power_attack"] && player_mp < 20)
|
||||
temp = "<br><center><h3>You don't have the mp necessary for a power attack and settle for a light attack!</h3></center>"
|
||||
enemy_hp -= attackamt
|
||||
arcade_action(usr,"attack",attackamt)
|
||||
|
||||
if (href_list["close"])
|
||||
usr.unset_machine()
|
||||
usr << browse(null, "window=arcade")
|
||||
|
||||
else if (href_list["newgame"]) //Reset everything
|
||||
temp = "New Round"
|
||||
player_hp = initial(player_hp)
|
||||
player_mp = initial(player_mp)
|
||||
enemy_hp = initial(enemy_hp)
|
||||
enemy_mp = initial(enemy_mp)
|
||||
gameover = FALSE
|
||||
turtle = 0
|
||||
temp = "<br><center><h3>New Round<center><h3>"
|
||||
|
||||
if(obj_flags & EMAGGED)
|
||||
Reset()
|
||||
obj_flags &= ~EMAGGED
|
||||
|
||||
enemy_setup(gamerSkill)
|
||||
screen_setup(usr)
|
||||
|
||||
|
||||
add_fingerprint(usr)
|
||||
updateUsrDialog()
|
||||
return
|
||||
|
||||
/obj/machinery/computer/arcade/battle/proc/arcade_action(mob/user)
|
||||
if ((enemy_mp <= 0) || (enemy_hp <= 0))
|
||||
///happens after a player action and before the enemy turn. the enemy turn will be cancelled if there's a gameover.
|
||||
/obj/machinery/computer/arcade/battle/proc/arcade_action(mob/user,player_stance,attackamt)
|
||||
screen_setup(user)
|
||||
blocked = TRUE
|
||||
if(player_stance == "attack" || player_stance == "power_attack")
|
||||
if(attackamt > 40)
|
||||
playsound(src, 'sound/arcade/boom.ogg', 50, TRUE, extrarange = -3)
|
||||
else
|
||||
playsound(src, 'sound/arcade/hit.ogg', 50, TRUE, extrarange = -3)
|
||||
|
||||
timer_id = addtimer(CALLBACK(src, .proc/enemy_action,player_stance,user),1 SECONDS,TIMER_STOPPABLE)
|
||||
gameover_check(user)
|
||||
|
||||
///the enemy turn, the enemy's action entirely depend on their current passive and a teensy tiny bit of randomness
|
||||
/obj/machinery/computer/arcade/battle/proc/enemy_action(player_stance,mob/user)
|
||||
var/list/list_temp = list()
|
||||
|
||||
switch(LAZYLEN(last_three_move)) //we keep the last three action of the player in a list here
|
||||
if(0 to 2)
|
||||
LAZYADD(last_three_move, player_stance)
|
||||
if(3)
|
||||
for(var/i in 1 to 2)
|
||||
last_three_move[i] = last_three_move[i + 1]
|
||||
last_three_move[3] = player_stance
|
||||
|
||||
if(4 to INFINITY)
|
||||
last_three_move = null //this shouldn't even happen but we empty the list if it somehow goes above 3
|
||||
|
||||
var/enemy_stance
|
||||
var/attack_amount = rand(8,10) //making the attack amount not vary too much so that it's easier to see if the enemy has a shotgun
|
||||
|
||||
if(player_stance == "defend")
|
||||
attack_amount -= 5
|
||||
|
||||
//if emagged, cuban pete will set up a bomb acting up as a timer. when it reaches 0 the player fucking dies
|
||||
if(obj_flags & EMAGGED)
|
||||
switch(bomb_cooldown--)
|
||||
if(18)
|
||||
list_temp += "<br><center><h3>[enemy_name] takes two valve tank and links them together, what's he planning?<center><h3>"
|
||||
if(15)
|
||||
list_temp += "<br><center><h3>[enemy_name] adds a remote control to the tan- ho god is that a bomb?<center><h3>"
|
||||
if(12)
|
||||
list_temp += "<br><center><h3>[enemy_name] throws the bomb next to you, you'r too scared to pick it up. <center><h3>"
|
||||
if(6)
|
||||
list_temp += "<br><center><h3>[enemy_name]'s hand brushes the remote linked to the bomb, your heart skipped a beat. <center><h3>"
|
||||
if(2)
|
||||
list_temp += "<br><center><h3>[enemy_name] is going to press the button! It's now or never! <center><h3>"
|
||||
if(0)
|
||||
player_hp -= attack_amount * 1000 //hey it's a maxcap we might as well go all in
|
||||
|
||||
//yeah I used the shotgun as a passive, you know why? because the shotgun gives +5 attack which is pretty good
|
||||
if(LAZYACCESS(enemy_passive, "shotgun"))
|
||||
if(weakpoint_check("shotgun","defend","defend","power_attack"))
|
||||
list_temp += "<br><center><h3>You manage to disarm [enemy_name] with a surprise power attack and shoot him with his shotgun until it runs out of ammo! <center><h3> "
|
||||
enemy_hp -= 10
|
||||
chosen_weapon = "empty shotgun"
|
||||
else
|
||||
attack_amount += 5
|
||||
|
||||
//heccing chonker passive, only gives more HP at the start of a new game but has one of the hardest weakpoint to trigger.
|
||||
if(LAZYACCESS(enemy_passive, "chonker"))
|
||||
if(weakpoint_check("chonker","power_attack","power_attack","power_attack"))
|
||||
list_temp += "<br><center><h3>After a lot of power attacks you manage to tip over [enemy_name] as they fall over their enormous weight<center><h3> "
|
||||
enemy_hp -= 30
|
||||
|
||||
//smart passive trait, mainly works in tandem with other traits, makes the enemy unable to be counter_attacked
|
||||
if(LAZYACCESS(enemy_passive, "smart"))
|
||||
if(weakpoint_check("smart","defend","defend","attack"))
|
||||
list_temp += "<br><center><h3>[enemy_name] is confused by your illogical strategy!<center><h3> "
|
||||
attack_amount -= 5
|
||||
|
||||
else if(attack_amount >= player_hp)
|
||||
player_hp -= attack_amount
|
||||
list_temp += "<br><center><h3>[enemy_name] figures out you are really close to death and finishes you off with their [chosen_weapon]!<center><h3>"
|
||||
enemy_stance = "attack"
|
||||
|
||||
else if(player_stance == "counter_attack")
|
||||
list_temp += "<br><center><h3>[enemy_name] is not taking your bait. <center><h3> "
|
||||
if(LAZYACCESS(enemy_passive, "short_temper"))
|
||||
list_temp += "However controlling their hatred of you still takes a toll on their mental and physical health!"
|
||||
enemy_hp -= 5
|
||||
enemy_mp -= 5
|
||||
enemy_stance = "defensive"
|
||||
|
||||
//short temper passive trait, gets easily baited into being counter attacked but will bypass your counter when low on HP
|
||||
if(LAZYACCESS(enemy_passive, "short_temper"))
|
||||
if(weakpoint_check("short_temper","counter_attack","counter_attack","counter_attack"))
|
||||
list_temp += "<br><center><h3>[enemy_name] is getting frustrated at all your counter attacks and throws a tantrum!<center><h3>"
|
||||
enemy_hp -= attack_amount
|
||||
|
||||
else if(player_stance == "counter_attack")
|
||||
if(!(LAZYACCESS(enemy_passive, "smart")) && enemy_hp > 30)
|
||||
list_temp += "<br><center><h3>[enemy_name] took the bait and allowed you to counter attack for [attack_amount * 2] damage!<center><h3>"
|
||||
player_hp -= attack_amount
|
||||
enemy_hp -= attack_amount * 2
|
||||
enemy_stance = "attack"
|
||||
|
||||
else if(enemy_hp <= 30) //will break through the counter when low enough on HP even when smart.
|
||||
list_temp += "<br><center><h3>[enemy_name] is getting tired of your tricks and breaks through your counter with their [chosen_weapon]!<center><h3>"
|
||||
player_hp -= attack_amount
|
||||
enemy_stance = "attack"
|
||||
|
||||
else if(!enemy_stance)
|
||||
var/added_temp
|
||||
|
||||
if(rand())
|
||||
added_temp = "you for [attack_amount + 5] damage!"
|
||||
player_hp -= attack_amount + 5
|
||||
enemy_stance = "attack"
|
||||
else
|
||||
added_temp = "the wall, breaking their skull in the process and losing [attack_amount] hp!" //[enemy_name] you have a literal dent in your skull
|
||||
enemy_hp -= attack_amount
|
||||
enemy_stance = "attack"
|
||||
|
||||
list_temp += "<br><center><h3>[enemy_name] grits their teeth and charge right into [added_temp]<center><h3>"
|
||||
|
||||
//in the case none of the previous passive triggered, Mainly here to set an enemy stance for passives that needs it like the magical passive.
|
||||
if(!enemy_stance)
|
||||
enemy_stance = pick("attack","defensive")
|
||||
if(enemy_stance == "attack")
|
||||
player_hp -= attack_amount
|
||||
list_temp += "<br><center><h3>[enemy_name] attacks you for [attack_amount] points of damage with their [chosen_weapon]<center><h3>"
|
||||
if(player_stance == "counter_attack")
|
||||
enemy_hp -= attack_amount * 2
|
||||
list_temp += "<br><center><h3>You counter [enemy_name]'s attack and deal [attack_amount * 2] points of damage!<center><h3>"
|
||||
|
||||
if(enemy_stance == "defensive" && enemy_mp < 15)
|
||||
list_temp += "<br><center><h3>[enemy_name] take some time to get some mp back!<center><h3> "
|
||||
enemy_mp += attack_amount
|
||||
|
||||
else if (enemy_stance == "defensive" && enemy_mp >= 15 && !(LAZYACCESS(enemy_passive, "magical")))
|
||||
list_temp += "<br><center><h3>[enemy_name] quickly heal themselves for 5 hp!<center><h3> "
|
||||
enemy_mp -= 15
|
||||
enemy_hp += 5
|
||||
|
||||
//magical passive trait, recharges MP nearly every turn it's not blasting you with magic.
|
||||
if(LAZYACCESS(enemy_passive, "magical"))
|
||||
if(player_mp >= 50)
|
||||
list_temp += "<br><center><h3>the huge amount of magical energy you have acumulated throws [enemy_name] off balance!<center><h3>"
|
||||
enemy_mp = 0
|
||||
LAZYREMOVE(enemy_passive, "magical")
|
||||
pissed_off++
|
||||
|
||||
else if(LAZYACCESS(enemy_passive, "smart") && player_stance == "counter_attack" && enemy_mp >= 20)
|
||||
list_temp += "<br><center><h3>[enemy_name] blasts you with magic from afar for 10 points of damage before you can counter!<center><h3>"
|
||||
player_hp -= 10
|
||||
enemy_mp -= 20
|
||||
|
||||
else if(enemy_hp >= 20 && enemy_mp >= 40 && enemy_stance == "defensive")
|
||||
list_temp += "<br><center><h3>[enemy_name] Blasts you with magic from afar!<center><h3>"
|
||||
enemy_mp -= 40
|
||||
player_hp -= 30
|
||||
enemy_stance = "attack"
|
||||
|
||||
else if(enemy_hp < 20 && enemy_mp >= 20 && enemy_stance == "defensive") //it's a pretty expensive spell so they can't spam it that much
|
||||
list_temp += "<br><center><h3>[enemy_name] heal themselves with magic and gain back 20 hp!<center><h3>"
|
||||
enemy_hp += 20
|
||||
enemy_mp -= 30
|
||||
else
|
||||
list_temp += "<br><center><h3>[enemy_name]'s magical nature lets them get some mp back!<center><h3>"
|
||||
enemy_mp += attack_amount
|
||||
|
||||
//poisonous passive trait, while it's less damage added than the shotgun it acts up even when the enemy doesn't attack at all.
|
||||
if(LAZYACCESS(enemy_passive, "poisonous"))
|
||||
if(weakpoint_check("poisonous","attack","attack","attack"))
|
||||
list_temp += "<br><center><h3>your flurry of attack throws back the poisonnous gas at [enemy_name] and makes them choke on it!<center><h3> "
|
||||
enemy_hp -= 5
|
||||
else
|
||||
list_temp += "<br><center><h3>the stinky breath of [enemy_name] hurts you for 3 hp!<center><h3> "
|
||||
player_hp -= 3
|
||||
|
||||
//if all passive's weakpoint have been triggered, set finishing_move to TRUE
|
||||
if(pissed_off >= max_passive && !finishing_move)
|
||||
list_temp += "<br><center><h3>You have weakened [enemy_name] enough for them to show their weak point, you will do 10 times as much damage with your next attack!<center><h3> "
|
||||
finishing_move = TRUE
|
||||
|
||||
playsound(src, 'sound/arcade/heal.ogg', 50, TRUE, extrarange = -3)
|
||||
|
||||
temp = list_temp.Join()
|
||||
gameover_check(user)
|
||||
screen_setup(user)
|
||||
blocked = FALSE
|
||||
|
||||
|
||||
/obj/machinery/computer/arcade/battle/proc/gameover_check(mob/user)
|
||||
var/xp_gained = 0
|
||||
if(enemy_hp <= 0)
|
||||
if(!gameover)
|
||||
if(timer_id)
|
||||
deltimer(timer_id)
|
||||
timer_id = null
|
||||
if(player_hp <= 0)
|
||||
player_hp = 1 //let's just pretend the enemy didn't kill you so not both the player and enemy look dead.
|
||||
gameover = TRUE
|
||||
temp = "[enemy_name] has fallen! Rejoice!"
|
||||
playsound(loc, 'sound/arcade/win.ogg', 50, TRUE, extrarange = -3)
|
||||
blocked = FALSE
|
||||
temp = "<br><center><h3>[enemy_name] has fallen! Rejoice!<center><h3>"
|
||||
playsound(loc, 'sound/arcade/win.ogg', 50, TRUE)
|
||||
|
||||
if(obj_flags & EMAGGED)
|
||||
new /obj/effect/spawner/newbomb/timer/syndicate(loc)
|
||||
@@ -133,78 +402,76 @@
|
||||
log_game("[key_name(usr)] has outbombed Cuban Pete and been awarded a bomb.")
|
||||
Reset()
|
||||
obj_flags &= ~EMAGGED
|
||||
xp_gained += 100
|
||||
else
|
||||
prizevend(user)
|
||||
xp_gained += 50
|
||||
SSblackbox.record_feedback("nested tally", "arcade_results", 1, list("win", (obj_flags & EMAGGED ? "emagged":"normal")))
|
||||
|
||||
|
||||
else if ((obj_flags & EMAGGED) && (turtle >= 4))
|
||||
var/boomamt = rand(5,10)
|
||||
temp = "[enemy_name] throws a bomb, exploding you for [boomamt] damage!"
|
||||
playsound(loc, 'sound/arcade/boom.ogg', 50, TRUE, extrarange = -3)
|
||||
player_hp -= boomamt
|
||||
|
||||
else if ((enemy_mp <= 5) && (prob(70)))
|
||||
var/stealamt = rand(2,3)
|
||||
temp = "[enemy_name] steals [stealamt] of your power!"
|
||||
playsound(loc, 'sound/arcade/steal.ogg', 50, TRUE, extrarange = -3)
|
||||
player_mp -= stealamt
|
||||
updateUsrDialog()
|
||||
|
||||
if (player_mp <= 0)
|
||||
gameover = TRUE
|
||||
sleep(turn_speed)
|
||||
temp = "You have been drained! GAME OVER"
|
||||
playsound(loc, 'sound/arcade/lose.ogg', 50, TRUE, extrarange = -3)
|
||||
if(obj_flags & EMAGGED)
|
||||
usr.gib()
|
||||
SSblackbox.record_feedback("nested tally", "arcade_results", 1, list("loss", "mana", (obj_flags & EMAGGED ? "emagged":"normal")))
|
||||
|
||||
else if ((enemy_hp <= 10) && (enemy_mp > 4))
|
||||
temp = "[enemy_name] heals for 4 health!"
|
||||
playsound(loc, 'sound/arcade/heal.ogg', 50, TRUE, extrarange = -3)
|
||||
enemy_hp += 4
|
||||
enemy_mp -= 4
|
||||
|
||||
else
|
||||
var/attackamt = rand(3,6)
|
||||
temp = "[enemy_name] attacks for [attackamt] damage!"
|
||||
playsound(loc, 'sound/arcade/hit.ogg', 50, TRUE, extrarange = -3)
|
||||
player_hp -= attackamt
|
||||
|
||||
if ((player_mp <= 0) || (player_hp <= 0))
|
||||
else if(player_hp <= 0)
|
||||
if(timer_id)
|
||||
deltimer(timer_id)
|
||||
timer_id = null
|
||||
gameover = TRUE
|
||||
temp = "You have been crushed! GAME OVER"
|
||||
playsound(loc, 'sound/arcade/lose.ogg', 50, TRUE, extrarange = -3)
|
||||
temp = "<br><center><h3>You have been crushed! GAME OVER<center><h3>"
|
||||
playsound(loc, 'sound/arcade/lose.ogg', 50, TRUE)
|
||||
xp_gained += 10//pity points
|
||||
if(obj_flags & EMAGGED)
|
||||
usr.gib()
|
||||
var/mob/living/living_user = user
|
||||
if (istype(living_user))
|
||||
living_user.gib()
|
||||
SSblackbox.record_feedback("nested tally", "arcade_results", 1, list("loss", "hp", (obj_flags & EMAGGED ? "emagged":"normal")))
|
||||
|
||||
blocked = FALSE
|
||||
return
|
||||
// if(gameover)
|
||||
// user?.mind?.adjust_experience(/datum/skill/gaming, xp_gained+1)//always gain at least 1 point of XP
|
||||
|
||||
|
||||
///used to check if the last three move of the player are the one we want in the right order and if the passive's weakpoint has been triggered yet
|
||||
/obj/machinery/computer/arcade/battle/proc/weakpoint_check(passive,first_move,second_move,third_move)
|
||||
if(LAZYLEN(last_three_move) < 3)
|
||||
return FALSE
|
||||
|
||||
if(last_three_move[1] == first_move && last_three_move[2] == second_move && last_three_move[3] == third_move && LAZYACCESS(enemy_passive, passive))
|
||||
LAZYREMOVE(enemy_passive, passive)
|
||||
pissed_off++
|
||||
return TRUE
|
||||
else
|
||||
return FALSE
|
||||
|
||||
|
||||
/obj/machinery/computer/arcade/battle/Destroy()
|
||||
enemy_passive = null
|
||||
weapons = null
|
||||
last_three_move = null
|
||||
return ..() //well boys we did it, lists are no more
|
||||
|
||||
/obj/machinery/computer/arcade/battle/examine_more(mob/user)
|
||||
to_chat(user, "<span class='notice'>Scribbled on the side of the Arcade Machine you notice some writing...\
|
||||
\nmagical -> >=50 power\
|
||||
\nsmart -> defend, defend, light attack\
|
||||
\nshotgun -> defend, defend, power attack\
|
||||
\nshort temper -> counter, counter, counter\
|
||||
\npoisonous -> light attack, light attack, light attack\
|
||||
\nchonker -> power attack, power attack, power attack</span>")
|
||||
return ..()
|
||||
var/list/msg = list("<span class='notice'><i>You notice some writing scribbled on the side of [src]...</i></span>")
|
||||
msg += "\t<span class='info'>smart -> defend, defend, light attack</span>"
|
||||
msg += "\t<span class='info'>shotgun -> defend, defend, power attack</span>"
|
||||
msg += "\t<span class='info'>short temper -> counter, counter, counter</span>"
|
||||
msg += "\t<span class='info'>poisonous -> light attack, light attack, light attack</span>"
|
||||
msg += "\t<span class='info'>chonker -> power attack, power attack, power attack</span>"
|
||||
return msg
|
||||
|
||||
/obj/machinery/computer/arcade/battle/emag_act(mob/user)
|
||||
. = ..()
|
||||
if(obj_flags & EMAGGED)
|
||||
return
|
||||
|
||||
to_chat(user, "<span class='warning'>A mesmerizing Rhumba beat starts playing from the arcade machine's speakers!</span>")
|
||||
temp = "If you die in the game, you die for real!"
|
||||
player_hp = 30
|
||||
player_mp = 10
|
||||
enemy_hp = 45
|
||||
enemy_mp = 20
|
||||
temp = "<br><center><h2>If you die in the game, you die for real!<center><h2>"
|
||||
max_passive = 6
|
||||
bomb_cooldown = 18
|
||||
var/gamerSkill = 0
|
||||
// if(usr?.mind)
|
||||
// gamerSkill = usr.mind.get_skill_level(/datum/skill/gaming)
|
||||
enemy_setup(gamerSkill)
|
||||
enemy_hp += 100 //extra HP just to make cuban pete even more bullshit
|
||||
player_hp += 30 //the player will also get a few extra HP in order to have a fucking chance
|
||||
|
||||
screen_setup(user)
|
||||
gameover = FALSE
|
||||
blocked = FALSE
|
||||
|
||||
obj_flags |= EMAGGED
|
||||
|
||||
|
||||
@@ -268,7 +268,7 @@
|
||||
visible_message("<span class='notice'>[src] dispenses [itemname]!</span>", "<span class='notice'>You hear a chime and a clunk.</span>")
|
||||
DISABLE_BITFIELD(obj_flags, EMAGGED)
|
||||
else
|
||||
var/dope_prizes = (area >= 480) ? list(ARCADE_WEIGHT_RARE) : (area >= 256) ? list(ARCADE_WEIGHT_RARE, ARCADE_WEIGHT_TRICK) : null
|
||||
var/dope_prizes = (area >= 480) ? 6 : (area >= 256) ? 4 : 2
|
||||
prizevend(user, dope_prizes)
|
||||
|
||||
if(game_status == MINESWEEPER_GAME_WON)
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
icon_state = "arcade"
|
||||
circuit = /obj/item/circuitboard/computer/arcade/amputation
|
||||
|
||||
/obj/machinery/computer/arcade/amputation/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
|
||||
/obj/machinery/computer/arcade/amputation/on_attack_hand(mob/user)
|
||||
if(!iscarbon(user))
|
||||
return
|
||||
var/mob/living/carbon/c_user = user
|
||||
@@ -24,8 +24,13 @@
|
||||
var/obj/item/bodypart/chopchop = c_user.get_bodypart(which_hand)
|
||||
chopchop.dismember()
|
||||
qdel(chopchop)
|
||||
playsound(loc, 'sound/arcade/win.ogg', 50, TRUE, extrarange = -3)
|
||||
for(var/i=1; i<=rand(3,5); i++)
|
||||
prizevend(user)
|
||||
// user.mind?.adjust_experience(/datum/skill/gaming, 100)
|
||||
playsound(loc, 'sound/arcade/win.ogg', 50, TRUE)
|
||||
prizevend(user, rand(3,5))
|
||||
else
|
||||
to_chat(c_user, "<span class='notice'>You (wisely) decide against putting your hand in the machine.</span>")
|
||||
|
||||
/obj/machinery/computer/arcade/amputation/festive //dispenses wrapped gifts instead of arcade prizes, also known as the ancap christmas tree
|
||||
name = "Mediborg's Festive Amputation Adventure"
|
||||
desc = "A picture of a blood-soaked medical cyborg wearing a Santa hat flashes on the screen. The mediborg has a speech bubble that says, \"Put your hand in the machine if you aren't a <b>coward!</b>\""
|
||||
prize_override = list(/obj/item/a_gift/anything = 1)
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
|
||||
|
||||
// *** THE ORION TRAIL ** //
|
||||
|
||||
#define ORION_TRAIL_WINTURN 9
|
||||
@@ -15,6 +13,8 @@
|
||||
#define ORION_TRAIL_COLLISION "Collision"
|
||||
#define ORION_TRAIL_SPACEPORT "Spaceport"
|
||||
#define ORION_TRAIL_BLACKHOLE "BlackHole"
|
||||
#define ORION_TRAIL_OLDSHIP "Old Ship"
|
||||
#define ORION_TRAIL_SEARCH "Old Ship Search"
|
||||
|
||||
#define ORION_STATUS_START 1
|
||||
#define ORION_STATUS_NORMAL 2
|
||||
@@ -44,7 +44,8 @@
|
||||
ORION_TRAIL_LING = 3,
|
||||
ORION_TRAIL_MALFUNCTION = 2,
|
||||
ORION_TRAIL_COLLISION = 1,
|
||||
ORION_TRAIL_SPACEPORT = 2
|
||||
ORION_TRAIL_SPACEPORT = 2,
|
||||
ORION_TRAIL_OLDSHIP = 2
|
||||
)
|
||||
var/list/stops = list()
|
||||
var/list/stopblurbs = list()
|
||||
@@ -55,13 +56,27 @@
|
||||
var/gameStatus = ORION_STATUS_START
|
||||
var/canContinueEvent = 0
|
||||
|
||||
var/obj/item/radio/Radio
|
||||
var/list/gamers = list()
|
||||
var/killed_crew = 0
|
||||
|
||||
|
||||
/obj/machinery/computer/arcade/orion_trail/Initialize()
|
||||
. = ..()
|
||||
Radio = new /obj/item/radio(src)
|
||||
Radio.listening = 0
|
||||
|
||||
/obj/machinery/computer/arcade/orion_trail/Destroy()
|
||||
QDEL_NULL(Radio)
|
||||
return ..()
|
||||
|
||||
/obj/machinery/computer/arcade/orion_trail/kobayashi
|
||||
name = "Kobayashi Maru control computer"
|
||||
desc = "A test for cadets"
|
||||
icon = 'icons/obj/machines/particle_accelerator.dmi'
|
||||
icon_state = "control_boxp"
|
||||
events = list("Raiders" = 3, "Interstellar Flux" = 1, "Illness" = 3, "Breakdown" = 2, "Malfunction" = 2, "Collision" = 1, "Spaceport" = 2)
|
||||
prizes = list(/obj/item/paper/fluff/holodeck/trek_diploma = 1)
|
||||
prize_override = list(/obj/item/paper/fluff/holodeck/trek_diploma = 1)
|
||||
settlers = list("Kirk","Worf","Gene")
|
||||
|
||||
/obj/machinery/computer/arcade/orion_trail/Reset()
|
||||
@@ -96,14 +111,52 @@
|
||||
event = null
|
||||
gameStatus = ORION_STATUS_NORMAL
|
||||
lings_aboard = 0
|
||||
killed_crew = 0
|
||||
|
||||
//spaceport junk
|
||||
spaceport_raided = 0
|
||||
spaceport_freebie = 0
|
||||
last_spaceport_action = ""
|
||||
|
||||
/obj/machinery/computer/arcade/orion_trail/ui_interact(mob/user)
|
||||
/obj/machinery/computer/arcade/orion_trail/proc/report_player(mob/gamer)
|
||||
if(gamers[gamer] == -2)
|
||||
return // enough harassing them
|
||||
|
||||
if(gamers[gamer] == -1)
|
||||
say("WARNING: Continued antisocial behavior detected: Dispensing self-help literature.")
|
||||
new /obj/item/paper/pamphlet/violent_video_games(drop_location())
|
||||
gamers[gamer]--
|
||||
return
|
||||
|
||||
if(!(gamer in gamers))
|
||||
gamers[gamer] = 0
|
||||
|
||||
gamers[gamer]++ // How many times the player has 'prestiged' (massacred their crew)
|
||||
|
||||
if(gamers[gamer] > 2 && prob(20 * gamers[gamer]))
|
||||
|
||||
Radio.set_frequency(FREQ_SECURITY)
|
||||
Radio.talk_into(src, "SECURITY ALERT: Crewmember [gamer] recorded displaying antisocial tendencies in [get_area(src)]. Please watch for violent behavior.", FREQ_SECURITY)
|
||||
|
||||
Radio.set_frequency(FREQ_MEDICAL)
|
||||
Radio.talk_into(src, "PSYCH ALERT: Crewmember [gamer] recorded displaying antisocial tendencies in [get_area(src)]. Please schedule psych evaluation.", FREQ_MEDICAL)
|
||||
|
||||
gamers[gamer] = -1
|
||||
|
||||
gamer.client.give_award(/datum/award/achievement/misc/gamer, gamer) // PSYCH REPORT NOTE: patient kept rambling about how they did it for an "achievement", recommend continued holding for observation
|
||||
// gamer.mind?.adjust_experience(/datum/skill/gaming, 50) // cheevos make u better
|
||||
|
||||
if(!isnull(GLOB.data_core.general))
|
||||
for(var/datum/data/record/R in GLOB.data_core.general)
|
||||
if(R.fields["name"] == gamer.name)
|
||||
R.fields["m_stat"] = "*Unstable*"
|
||||
return
|
||||
|
||||
/obj/machinery/computer/arcade/orion_trail/ui_interact(mob/_user)
|
||||
. = ..()
|
||||
if (!isliving(_user))
|
||||
return
|
||||
var/mob/living/user = _user
|
||||
if(fuel <= 0 || food <=0 || settlers.len == 0)
|
||||
gameStatus = ORION_STATUS_GAMEOVER
|
||||
event = null
|
||||
@@ -136,6 +189,8 @@
|
||||
desc = "Learn how our ancestors got to Orion, and have fun in the process!"
|
||||
|
||||
dat += "<P ALIGN=Right><a href='byond://?src=[REF(src)];menu=1'>May They Rest In Peace</a></P>"
|
||||
// user?.mind?.adjust_experience(/datum/skill/gaming, 10)//learning from your mistakes is the first rule of roguelikes
|
||||
|
||||
else if(event)
|
||||
dat = eventdat
|
||||
else if(gameStatus == ORION_STATUS_NORMAL)
|
||||
@@ -174,20 +229,32 @@
|
||||
return
|
||||
busy = TRUE
|
||||
|
||||
var/gamerSkillLevel = 0
|
||||
var/gamerSkill = 0
|
||||
var/gamerSkillRands = 0
|
||||
|
||||
// if(usr?.mind)
|
||||
// gamerSkillLevel = usr.mind.get_skill_level(/datum/skill/gaming)
|
||||
// gamerSkill = usr.mind.get_skill_modifier(/datum/skill/gaming, SKILL_PROBS_MODIFIER)
|
||||
// gamerSkillRands = usr.mind.get_skill_modifier(/datum/skill/gaming, SKILL_RANDS_MODIFIER)
|
||||
|
||||
|
||||
var/xp_gained = 0
|
||||
if (href_list["continue"]) //Continue your travels
|
||||
if(gameStatus == ORION_STATUS_NORMAL && !event && turns != 7)
|
||||
if(turns >= ORION_TRAIL_WINTURN)
|
||||
win(usr)
|
||||
xp_gained += 34
|
||||
else
|
||||
food -= (alive+lings_aboard)*2
|
||||
fuel -= 5
|
||||
if(turns == 2 && prob(30))
|
||||
if(turns == 2 && prob(30-gamerSkill))
|
||||
event = ORION_TRAIL_COLLISION
|
||||
event()
|
||||
else if(prob(75))
|
||||
else if(prob(75-gamerSkill))
|
||||
event = pickweight(events)
|
||||
if(lings_aboard)
|
||||
if(event == ORION_TRAIL_LING || prob(55))
|
||||
if(event == ORION_TRAIL_LING || prob(55-gamerSkill))
|
||||
event = ORION_TRAIL_LING_ATTACK
|
||||
event()
|
||||
turns += 1
|
||||
@@ -195,15 +262,18 @@
|
||||
var/mob/living/carbon/M = usr //for some vars
|
||||
switch(event)
|
||||
if(ORION_TRAIL_RAIDERS)
|
||||
if(prob(50))
|
||||
if(prob(50-gamerSkill))
|
||||
to_chat(usr, "<span class='userdanger'>You hear battle shouts. The tramping of boots on cold metal. Screams of agony. The rush of venting air. Are you going insane?</span>")
|
||||
M.hallucination += 30
|
||||
else
|
||||
to_chat(usr, "<span class='userdanger'>Something strikes you from behind! It hurts like hell and feel like a blunt weapon, but nothing is there...</span>")
|
||||
M.take_bodypart_damage(30)
|
||||
playsound(loc, 'sound/weapons/genhit2.ogg', 100, 1)
|
||||
playsound(loc, 'sound/weapons/genhit2.ogg', 100, TRUE)
|
||||
if(ORION_TRAIL_ILLNESS)
|
||||
var/severity = rand(1,3) //pray to RNGesus. PRAY, PIGS
|
||||
var/maxSeverity = 3
|
||||
// if(gamerSkillLevel >= SKILL_LEVEL_EXPERT)
|
||||
// maxSeverity = 2 //part of gitting gud is rng mitigation
|
||||
var/severity = rand(1,maxSeverity) //pray to RNGesus. PRAY, PIGS
|
||||
if(severity == 1)
|
||||
to_chat(M, "<span class='userdanger'>You suddenly feel slightly nauseated.</span>" )
|
||||
if(severity == 2)
|
||||
@@ -215,16 +285,16 @@
|
||||
sleep(30)
|
||||
M.vomit(10, distance = 5)
|
||||
if(ORION_TRAIL_FLUX)
|
||||
if(prob(75))
|
||||
if(prob(75-gamerSkill))
|
||||
M.DefaultCombatKnockdown(60)
|
||||
say("A sudden gust of powerful wind slams [M] into the floor!")
|
||||
M.take_bodypart_damage(25)
|
||||
playsound(loc, 'sound/weapons/genhit.ogg', 100, 1)
|
||||
playsound(loc, 'sound/weapons/genhit.ogg', 100, TRUE)
|
||||
else
|
||||
to_chat(M, "<span class='userdanger'>A violent gale blows past you, and you barely manage to stay standing!</span>")
|
||||
if(ORION_TRAIL_COLLISION) //by far the most damaging event
|
||||
if(prob(90))
|
||||
playsound(loc, 'sound/effects/bang.ogg', 100, 1)
|
||||
if(prob(90-gamerSkill))
|
||||
playsound(loc, 'sound/effects/bang.ogg', 100, TRUE)
|
||||
var/turf/open/floor/F
|
||||
for(F in orange(1, src))
|
||||
F.ScrapeAway()
|
||||
@@ -232,15 +302,15 @@
|
||||
if(hull)
|
||||
sleep(10)
|
||||
say("A new floor suddenly appears around [src]. What the hell?")
|
||||
playsound(loc, 'sound/weapons/genhit.ogg', 100, 1)
|
||||
playsound(loc, 'sound/weapons/genhit.ogg', 100, TRUE)
|
||||
var/turf/open/space/T
|
||||
for(T in orange(1, src))
|
||||
T.PlaceOnTop(/turf/open/floor/plating)
|
||||
else
|
||||
say("Something slams into the floor around [src] - luckily, it didn't get through!")
|
||||
playsound(loc, 'sound/effects/bang.ogg', 50, 1)
|
||||
playsound(loc, 'sound/effects/bang.ogg', 50, TRUE)
|
||||
if(ORION_TRAIL_MALFUNCTION)
|
||||
playsound(loc, 'sound/effects/empulse.ogg', 50, 1)
|
||||
playsound(loc, 'sound/effects/empulse.ogg', 50, TRUE)
|
||||
visible_message("<span class='danger'>[src] malfunctions, randomizing in-game stats!</span>")
|
||||
var/oldfood = food
|
||||
var/oldfuel = fuel
|
||||
@@ -254,7 +324,7 @@
|
||||
audible_message("<span class='danger'>[src] lets out a somehow ominous chime.</span>")
|
||||
food = oldfood
|
||||
fuel = oldfuel
|
||||
playsound(loc, 'sound/machines/chime.ogg', 50, 1)
|
||||
playsound(loc, 'sound/machines/chime.ogg', 50, TRUE)
|
||||
|
||||
else if(href_list["newgame"]) //Reset everything
|
||||
if(gameStatus == ORION_STATUS_START)
|
||||
@@ -266,6 +336,10 @@
|
||||
food = 80
|
||||
fuel = 60
|
||||
settlers = list("Harry","Larry","Bob")
|
||||
else if(href_list["search"]) //search old ship
|
||||
if(event == ORION_TRAIL_OLDSHIP)
|
||||
event = ORION_TRAIL_SEARCH
|
||||
event()
|
||||
else if(href_list["slow"]) //slow down
|
||||
if(event == ORION_TRAIL_FLUX)
|
||||
food -= (alive+lings_aboard)*2
|
||||
@@ -302,11 +376,11 @@
|
||||
event = null
|
||||
else if(href_list["blackhole"]) //keep speed past a black hole
|
||||
if(turns == 7)
|
||||
if(prob(75))
|
||||
if(prob(75-gamerSkill))
|
||||
event = ORION_TRAIL_BLACKHOLE
|
||||
event()
|
||||
if(obj_flags & EMAGGED)
|
||||
playsound(loc, 'sound/effects/supermatter.ogg', 100, 1)
|
||||
playsound(loc, 'sound/effects/supermatter.ogg', 100, TRUE)
|
||||
say("A miniature black hole suddenly appears in front of [src], devouring [usr] alive!")
|
||||
if(isliving(usr))
|
||||
var/mob/living/L = usr
|
||||
@@ -328,22 +402,29 @@
|
||||
else if(href_list["killcrew"]) //shoot a crewmember
|
||||
if(gameStatus == ORION_STATUS_NORMAL || event == ORION_TRAIL_LING)
|
||||
var/sheriff = remove_crewmember() //I shot the sheriff
|
||||
playsound(loc,'sound/weapons/gunshot.ogg', 100, 1)
|
||||
playsound(loc,'sound/weapons/gun/pistol/shot.ogg', 100, TRUE)
|
||||
killed_crew++
|
||||
|
||||
var/mob/living/user = usr
|
||||
|
||||
if(settlers.len == 0 || alive == 0)
|
||||
say("The last crewmember [sheriff], shot themselves, GAME OVER!")
|
||||
if(obj_flags & EMAGGED)
|
||||
usr.death(0)
|
||||
obj_flags &= EMAGGED
|
||||
user.death(FALSE)
|
||||
gameStatus = ORION_STATUS_GAMEOVER
|
||||
event = null
|
||||
|
||||
if(killed_crew >= 4)
|
||||
xp_gained -= 15//no cheating by spamming game overs
|
||||
report_player(usr)
|
||||
else if(obj_flags & EMAGGED)
|
||||
if(usr.name == sheriff)
|
||||
say("The crew of the ship chose to kill [usr.name]!")
|
||||
usr.death(0)
|
||||
user.death(FALSE)
|
||||
|
||||
if(event == ORION_TRAIL_LING) //only ends the ORION_TRAIL_LING event, since you can do this action in multiple places
|
||||
event = null
|
||||
killed_crew-- // the kill was valid
|
||||
|
||||
//Spaceport specific interactions
|
||||
//they get a header because most of them don't reset event (because it's a shop, you leave when you want to)
|
||||
@@ -356,6 +437,7 @@
|
||||
fuel -= 10
|
||||
food -= 10
|
||||
event()
|
||||
killed_crew-- // I mean not really but you know
|
||||
|
||||
else if(href_list["sellcrew"]) //sell a crewmember
|
||||
if(gameStatus == ORION_STATUS_MARKET)
|
||||
@@ -377,15 +459,16 @@
|
||||
else if(href_list["raid_spaceport"])
|
||||
if(gameStatus == ORION_STATUS_MARKET)
|
||||
if(!spaceport_raided)
|
||||
var/success = min(15 * alive,100) //default crew (4) have a 60% chance
|
||||
var/success = min(15 * alive + gamerSkill,100) //default crew (4) have a 60% chance
|
||||
spaceport_raided = 1
|
||||
|
||||
var/FU = 0
|
||||
var/FO = 0
|
||||
if(prob(success))
|
||||
FU = rand(5,15)
|
||||
FO = rand(5,15)
|
||||
FU = rand(5 + gamerSkillRands,15 + gamerSkillRands)
|
||||
FO = rand(5 + gamerSkillRands,15 + gamerSkillRands)
|
||||
last_spaceport_action = "You successfully raided the spaceport! You gained [FU] Fuel and [FO] Food! (+[FU]FU,+[FO]FO)"
|
||||
xp_gained += 10
|
||||
else
|
||||
FU = rand(-5,-15)
|
||||
FO = rand(-5,-15)
|
||||
@@ -444,7 +527,7 @@
|
||||
add_fingerprint(usr)
|
||||
updateUsrDialog()
|
||||
busy = FALSE
|
||||
return
|
||||
// usr?.mind?.adjust_experience(/datum/skill/gaming, xp_gained+1)
|
||||
|
||||
|
||||
/obj/machinery/computer/arcade/orion_trail/proc/event()
|
||||
@@ -686,8 +769,279 @@
|
||||
eventdat += "<P ALIGN=Right><a href='byond://?src=[REF(src)];leave_spaceport=1'>Depart Spaceport</a></P>"
|
||||
|
||||
|
||||
/obj/machinery/computer/arcade/orion_trail/proc/event()
|
||||
eventdat = "<center><h1>[event]</h1></center>"
|
||||
canContinueEvent = 0
|
||||
switch(event)
|
||||
if(ORION_TRAIL_RAIDERS)
|
||||
eventdat += "Raiders have come aboard your ship!"
|
||||
if(prob(50))
|
||||
var/sfood = rand(1,10)
|
||||
var/sfuel = rand(1,10)
|
||||
food -= sfood
|
||||
fuel -= sfuel
|
||||
eventdat += "<br>They have stolen [sfood] <b>Food</b> and [sfuel] <b>Fuel</b>."
|
||||
else if(prob(10))
|
||||
var/deadname = remove_crewmember()
|
||||
eventdat += "<br>[deadname] tried to fight back, but was killed."
|
||||
else
|
||||
eventdat += "<br>Fortunately, you fended them off without any trouble."
|
||||
eventdat += "<P ALIGN=Right><a href='byond://?src=[REF(src)];eventclose=1'>Continue</a></P>"
|
||||
eventdat += "<P ALIGN=Right><a href='byond://?src=[REF(src)];close=1'>Close</a></P>"
|
||||
canContinueEvent = 1
|
||||
|
||||
if(ORION_TRAIL_FLUX)
|
||||
eventdat += "This region of space is highly turbulent. <br>If we go slowly we may avoid more damage, but if we keep our speed we won't waste supplies."
|
||||
eventdat += "<br>What will you do?"
|
||||
eventdat += "<P ALIGN=Right><a href='byond://?src=[REF(src)];slow=1'>Slow Down</a> <a href='byond://?src=[REF(src)];keepspeed=1'>Continue</a></P>"
|
||||
eventdat += "<P ALIGN=Right><a href='byond://?src=[REF(src)];close=1'>Close</a></P>"
|
||||
|
||||
if(ORION_TRAIL_OLDSHIP)
|
||||
eventdat += "<br>Your crew spots an old ship floating through space. It might have some supplies, but then again it looks rather unsafe."
|
||||
eventdat += "<P ALIGN=Right><a href='byond://?src=[REF(src)];search=1'>Search it</a><a href='byond://?src=[REF(src)];eventclose=1'>Leave it</a></P><P ALIGN=Right><a href='byond://?src=[REF(src)];close=1'>Close</a></P>"
|
||||
canContinueEvent = 1
|
||||
|
||||
if(ORION_TRAIL_SEARCH)
|
||||
switch(rand(100))
|
||||
if(0 to 15)
|
||||
var/rescued = add_crewmember()
|
||||
var/oldfood = rand(1,7)
|
||||
var/oldfuel = rand(4,10)
|
||||
food += oldfood
|
||||
fuel += oldfuel
|
||||
eventdat += "<br>As you look through it you find some supplies and a living person!"
|
||||
eventdat += "<br>[rescued] was rescued from the abandoned ship!"
|
||||
eventdat += "<br>You found [oldfood] <b>Food</b> and [oldfuel] <b>Fuel</b>."
|
||||
if(15 to 35)
|
||||
var/lfuel = rand(4,7)
|
||||
var/deadname = remove_crewmember()
|
||||
fuel -= lfuel
|
||||
eventdat += "<br>[deadname] was lost deep in the wreckage, and your own vessel lost [lfuel] <b>Fuel</b> maneuvering to the the abandoned ship."
|
||||
if(35 to 65)
|
||||
var/oldfood = rand(5,11)
|
||||
food += oldfood
|
||||
engine++
|
||||
eventdat += "<br>You found [oldfood] <b>Food</b> and some parts amongst the wreck."
|
||||
else
|
||||
eventdat += "<br>As you look through the wreck you cannot find much of use."
|
||||
eventdat += "<P ALIGN=Right><a href='byond://?src=[REF(src)];eventclose=1'>Continue</a></P>"
|
||||
eventdat += "<P ALIGN=Right><a href='byond://?src=[REF(src)];close=1'>Close</a></P>"
|
||||
canContinueEvent = 1
|
||||
|
||||
if(ORION_TRAIL_ILLNESS)
|
||||
eventdat += "A deadly illness has been contracted!"
|
||||
var/deadname = remove_crewmember()
|
||||
eventdat += "<br>[deadname] was killed by the disease."
|
||||
eventdat += "<P ALIGN=Right><a href='byond://?src=[REF(src)];eventclose=1'>Continue</a></P>"
|
||||
eventdat += "<P ALIGN=Right><a href='byond://?src=[REF(src)];close=1'>Close</a></P>"
|
||||
canContinueEvent = 1
|
||||
|
||||
if(ORION_TRAIL_BREAKDOWN)
|
||||
eventdat += "Oh no! The engine has broken down!"
|
||||
eventdat += "<br>You can repair it with an engine part, or you can make repairs for 3 days."
|
||||
if(engine >= 1)
|
||||
eventdat += "<P ALIGN=Right><a href='byond://?src=[REF(src)];useengine=1'>Use Part</a><a href='byond://?src=[REF(src)];wait=1'>Wait</a></P>"
|
||||
else
|
||||
eventdat += "<P ALIGN=Right><a href='byond://?src=[REF(src)];wait=1'>Wait</a></P>"
|
||||
eventdat += "<P ALIGN=Right><a href='byond://?src=[REF(src)];close=1'>Close</a></P>"
|
||||
|
||||
if(ORION_TRAIL_MALFUNCTION)
|
||||
eventdat += "The ship's systems are malfunctioning!"
|
||||
eventdat += "<br>You can replace the broken electronics with spares, or you can spend 3 days troubleshooting the AI."
|
||||
if(electronics >= 1)
|
||||
eventdat += "<P ALIGN=Right><a href='byond://?src=[REF(src)];useelec=1'>Use Part</a><a href='byond://?src=[REF(src)];wait=1'>Wait</a></P>"
|
||||
else
|
||||
eventdat += "<P ALIGN=Right><a href='byond://?src=[REF(src)];wait=1'>Wait</a></P>"
|
||||
eventdat += "<P ALIGN=Right><a href='byond://?src=[REF(src)];close=1'>Close</a></P>"
|
||||
|
||||
if(ORION_TRAIL_COLLISION)
|
||||
eventdat += "Something hit us! Looks like there's some hull damage."
|
||||
if(prob(25))
|
||||
var/sfood = rand(5,15)
|
||||
var/sfuel = rand(5,15)
|
||||
food -= sfood
|
||||
fuel -= sfuel
|
||||
eventdat += "<br>[sfood] <b>Food</b> and [sfuel] <b>Fuel</b> was vented out into space."
|
||||
if(prob(10))
|
||||
var/deadname = remove_crewmember()
|
||||
eventdat += "<br>[deadname] was killed by rapid depressurization."
|
||||
eventdat += "<br>You can repair the damage with hull plates, or you can spend the next 3 days welding scrap together."
|
||||
if(hull >= 1)
|
||||
eventdat += "<P ALIGN=Right><a href='byond://?src=[REF(src)];usehull=1'>Use Part</a><a href='byond://?src=[REF(src)];wait=1'>Wait</a></P>"
|
||||
else
|
||||
eventdat += "<P ALIGN=Right><a href='byond://?src=[REF(src)];wait=1'>Wait</a></P>"
|
||||
eventdat += "<P ALIGN=Right><a href='byond://?src=[REF(src)];close=1'>Close</a></P>"
|
||||
|
||||
if(ORION_TRAIL_BLACKHOLE)
|
||||
eventdat += "You were swept away into the black hole."
|
||||
eventdat += "<P ALIGN=Right><a href='byond://?src=[REF(src)];holedeath=1'>Oh...</a></P>"
|
||||
eventdat += "<P ALIGN=Right><a href='byond://?src=[REF(src)];close=1'>Close</a></P>"
|
||||
settlers = list()
|
||||
|
||||
if(ORION_TRAIL_LING)
|
||||
eventdat += "Strange reports warn of changelings infiltrating crews on trips to Orion..."
|
||||
if(settlers.len <= 2)
|
||||
eventdat += "<br>Your crew's chance of reaching Orion is so slim the changelings likely avoided your ship..."
|
||||
eventdat += "<P ALIGN=Right><a href='byond://?src=[REF(src)];eventclose=1'>Continue</a></P>"
|
||||
eventdat += "<P ALIGN=Right><a href='byond://?src=[REF(src)];close=1'>Close</a></P>"
|
||||
if(prob(10)) // "likely", I didn't say it was guaranteed!
|
||||
lings_aboard = min(++lings_aboard,2)
|
||||
else
|
||||
if(lings_aboard) //less likely to stack lings
|
||||
if(prob(20))
|
||||
lings_aboard = min(++lings_aboard,2)
|
||||
else if(prob(70))
|
||||
lings_aboard = min(++lings_aboard,2)
|
||||
|
||||
eventdat += "<P ALIGN=Right><a href='byond://?src=[REF(src)];killcrew=1'>Kill a Crewmember</a></P>"
|
||||
eventdat += "<P ALIGN=Right><a href='byond://?src=[REF(src)];eventclose=1'>Risk it</a></P>"
|
||||
eventdat += "<P ALIGN=Right><a href='byond://?src=[REF(src)];close=1'>Close</a></P>"
|
||||
canContinueEvent = 1
|
||||
|
||||
if(ORION_TRAIL_LING_ATTACK)
|
||||
if(lings_aboard <= 0) //shouldn't trigger, but hey.
|
||||
eventdat += "Haha, fooled you, there are no changelings on board!"
|
||||
eventdat += "<br>(You should report this to a coder :S)"
|
||||
else
|
||||
var/ling1 = remove_crewmember()
|
||||
var/ling2 = ""
|
||||
if(lings_aboard >= 2)
|
||||
ling2 = remove_crewmember()
|
||||
|
||||
eventdat += "Changelings among your crew suddenly burst from hiding and attack!"
|
||||
if(ling2)
|
||||
eventdat += "<br>[ling1] and [ling2]'s arms twist and contort into grotesque blades!"
|
||||
else
|
||||
eventdat += "<br>[ling1]'s arm twists and contorts into a grotesque blade!"
|
||||
|
||||
var/chance2attack = alive*20
|
||||
if(prob(chance2attack))
|
||||
var/chancetokill = 30*lings_aboard-(5*alive) //eg: 30*2-(10) = 50%, 2 lings, 2 crew is 50% chance
|
||||
if(prob(chancetokill))
|
||||
var/deadguy = remove_crewmember()
|
||||
var/murder_text = pick("The changeling[ling2 ? "s" : ""] bring[ling2 ? "" : "s"] down [deadguy] and disembowel[ling2 ? "" : "s"] them in a spray of gore!", \
|
||||
"[ling2 ? pick(ling1, ling2) : ling1] corners [deadguy] and impales them through the stomach!", \
|
||||
"[ling2 ? pick(ling1, ling2) : ling1] decapitates [deadguy] in a single cleaving arc!")
|
||||
eventdat += "<br>[murder_text]"
|
||||
else
|
||||
eventdat += "<br><br><b>You valiantly fight off the changeling[ling2 ? "s":""]!</b>"
|
||||
if(ling2)
|
||||
food += 30
|
||||
lings_aboard = max(0,lings_aboard-2)
|
||||
else
|
||||
food += 15
|
||||
lings_aboard = max(0,--lings_aboard)
|
||||
eventdat += "<br><i>Well, it's perfectly good food...</i>\
|
||||
<br>You cut the changeling[ling2 ? "s" : ""] into meat, gaining <b>[ling2 ? "30" : "15"]</b> Food!"
|
||||
else
|
||||
eventdat += "<br><br>[pick("Sensing unfavorable odds", "After a failed attack", "Suddenly breaking nerve")], \
|
||||
the changeling[ling2 ? "s":""] vanish[ling2 ? "" : "es"] into space through the airlocks! You're safe... for now."
|
||||
if(ling2)
|
||||
lings_aboard = max(0,lings_aboard-2)
|
||||
else
|
||||
lings_aboard = max(0,--lings_aboard)
|
||||
|
||||
eventdat += "<P ALIGN=Right><a href='byond://?src=[REF(src)];eventclose=1'>Continue</a></P>"
|
||||
eventdat += "<P ALIGN=Right><a href='byond://?src=[REF(src)];close=1'>Close</a></P>"
|
||||
canContinueEvent = 1
|
||||
|
||||
|
||||
if(ORION_TRAIL_SPACEPORT)
|
||||
gameStatus = ORION_STATUS_MARKET
|
||||
if(spaceport_raided)
|
||||
eventdat += "The spaceport is on high alert! You've been barred from docking by the local authorities after your failed raid."
|
||||
if(last_spaceport_action)
|
||||
eventdat += "<br><b>Last Spaceport Action:</b> [last_spaceport_action]"
|
||||
eventdat += "<P ALIGN=Right><a href='byond://?src=[REF(src)];leave_spaceport=1'>Depart Spaceport</a></P>"
|
||||
eventdat += "<P ALIGN=Right><a href='byond://?src=[REF(src)];close=1'>Close</a></P>"
|
||||
else
|
||||
eventdat += "Your jump into the sector yields a spaceport - a lucky find!"
|
||||
eventdat += "<br>This spaceport is home to travellers who failed to reach Orion, but managed to find a different home..."
|
||||
eventdat += "<br>Trading terms: FU = Fuel, FO = Food"
|
||||
if(last_spaceport_action)
|
||||
eventdat += "<br><b>Last action:</b> [last_spaceport_action]"
|
||||
eventdat += "<h3><b>Crew:</b></h3>"
|
||||
eventdat += english_list(settlers)
|
||||
eventdat += "<br><b>Food: </b>[food] | <b>Fuel: </b>[fuel]"
|
||||
eventdat += "<br><b>Engine Parts: </b>[engine] | <b>Hull Panels: </b>[hull] | <b>Electronics: </b>[electronics]"
|
||||
|
||||
|
||||
//If your crew is pathetic you can get freebies (provided you haven't already gotten one from this port)
|
||||
if(!spaceport_freebie && (fuel < 20 || food < 20))
|
||||
spaceport_freebie++
|
||||
var/FU = 10
|
||||
var/FO = 10
|
||||
var/freecrew = 0
|
||||
if(prob(30))
|
||||
FU = 25
|
||||
FO = 25
|
||||
|
||||
if(prob(10))
|
||||
add_crewmember()
|
||||
freecrew++
|
||||
|
||||
eventdat += "<br>The traders of the spaceport take pity on you, and generously give you some free supplies! (+[FU]FU, +[FO]FO)"
|
||||
if(freecrew)
|
||||
eventdat += "<br>You also gain a new crewmember!"
|
||||
|
||||
fuel += FU
|
||||
food += FO
|
||||
|
||||
//CREW INTERACTIONS
|
||||
eventdat += "<P ALIGN=Right>Crew Management:</P>"
|
||||
|
||||
//Buy crew
|
||||
if(food >= 10 && fuel >= 10)
|
||||
eventdat += "<P ALIGN=Right><a href='byond://?src=[REF(src)];buycrew=1'>Hire a New Crewmember (-10FU, -10FO)</a></P>"
|
||||
else
|
||||
eventdat += "<P ALIGN=Right>You cannot afford a new crewmember.</P>"
|
||||
|
||||
//Sell crew
|
||||
if(settlers.len > 1)
|
||||
eventdat += "<P ALIGN=Right><a href='byond://?src=[REF(src)];sellcrew=1'>Sell Crew for Fuel and Food (+7FU, +7FO)</a></P>"
|
||||
else
|
||||
eventdat += "<P ALIGN=Right>You have no other crew to sell.</P>"
|
||||
|
||||
//BUY/SELL STUFF
|
||||
eventdat += "<P ALIGN=Right>Spare Parts:</P>"
|
||||
|
||||
//Engine parts
|
||||
if(fuel > 5)
|
||||
eventdat += "<P ALIGN=Right><a href='byond://?src=[REF(src)];buyparts=1'>Buy Engine Parts (-5FU)</a></P>"
|
||||
else
|
||||
eventdat += "<P ALIGN=Right>You cannot afford engine parts.</a>"
|
||||
|
||||
//Hull plates
|
||||
if(fuel > 5)
|
||||
eventdat += "<P ALIGN=Right><a href='byond://?src=[REF(src)];buyparts=2'>Buy Hull Plates (-5FU)</a></P>"
|
||||
else
|
||||
eventdat += "<P ALIGN=Right>You cannot afford hull plates.</a>"
|
||||
|
||||
//Electronics
|
||||
if(fuel > 5)
|
||||
eventdat += "<P ALIGN=Right><a href='byond://?src=[REF(src)];buyparts=3'>Buy Spare Electronics (-5FU)</a></P>"
|
||||
else
|
||||
eventdat += "<P ALIGN=Right>You cannot afford spare electronics.</a>"
|
||||
|
||||
//Trade
|
||||
if(fuel > 5)
|
||||
eventdat += "<P ALIGN=Right><a href='byond://?src=[REF(src)];trade=1'>Trade Fuel for Food (-5FU,+5FO)</a></P>"
|
||||
else
|
||||
eventdat += "<P ALIGN=Right>You don't have 5FU to trade.</P"
|
||||
|
||||
if(food > 5)
|
||||
eventdat += "<P ALIGN=Right><a href='byond://?src=[REF(src)];trade=2'>Trade Food for Fuel (+5FU,-5FO)</a></P>"
|
||||
else
|
||||
eventdat += "<P ALIGN=Right>You don't have 5FO to trade.</P"
|
||||
|
||||
//Raid the spaceport
|
||||
eventdat += "<P ALIGN=Right><a href='byond://?src=[REF(src)];raid_spaceport=1'>!! Raid Spaceport !!</a></P>"
|
||||
|
||||
eventdat += "<P ALIGN=Right><a href='byond://?src=[REF(src)];leave_spaceport=1'>Depart Spaceport</a></P>"
|
||||
|
||||
|
||||
//Add Random/Specific crewmember
|
||||
/obj/machinery/computer/arcade/orion_trail/proc/add_crewmember(var/specific = "")
|
||||
/obj/machinery/computer/arcade/orion_trail/proc/add_crewmember(specific = "")
|
||||
var/newcrew = ""
|
||||
if(specific)
|
||||
newcrew = specific
|
||||
@@ -703,7 +1057,7 @@
|
||||
|
||||
|
||||
//Remove Random/Specific crewmember
|
||||
/obj/machinery/computer/arcade/orion_trail/proc/remove_crewmember(var/specific = "", var/dont_remove = "")
|
||||
/obj/machinery/computer/arcade/orion_trail/proc/remove_crewmember(specific = "", dont_remove = "")
|
||||
var/list/safe2remove = settlers
|
||||
var/removed = ""
|
||||
if(dont_remove)
|
||||
@@ -779,14 +1133,14 @@
|
||||
to_chat(user, "<span class='warning'>You flip the switch on the underside of [src].</span>")
|
||||
active = 1
|
||||
visible_message("<span class='notice'>[src] softly beeps and whirs to life!</span>")
|
||||
playsound(loc, 'sound/machines/defib_SaftyOn.ogg', 25, 1)
|
||||
playsound(loc, 'sound/machines/defib_SaftyOn.ogg', 25, TRUE)
|
||||
say("This is ship ID #[rand(1,1000)] to Orion Port Authority. We're coming in for landing, over.")
|
||||
sleep(20)
|
||||
visible_message("<span class='warning'>[src] begins to vibrate...</span>")
|
||||
say("Uh, Port? Having some issues with our reactor, could you check it out? Over.")
|
||||
sleep(30)
|
||||
say("Oh, God! Code Eight! CODE EIGHT! IT'S GONNA BL-")
|
||||
playsound(loc, 'sound/machines/buzz-sigh.ogg', 25, 1)
|
||||
playsound(loc, 'sound/machines/buzz-sigh.ogg', 25, TRUE)
|
||||
sleep(3.6)
|
||||
visible_message("<span class='userdanger'>[src] explodes!</span>")
|
||||
explosion(loc, 2,4,8, flame_range = 16)
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
lefthand_file = 'icons/mob/inhands/equipment/toolbox_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/equipment/toolbox_righthand.dmi'
|
||||
icon = 'icons/obj/items_and_weapons.dmi'
|
||||
w_class = WEIGHT_CLASS_BULKY
|
||||
w_class = WEIGHT_CLASS_GIGANTIC
|
||||
force = 12
|
||||
total_mass = TOTAL_MASS_NORMAL_ITEM // average toolbox
|
||||
attack_verb = list("robusted")
|
||||
@@ -70,19 +70,19 @@
|
||||
else
|
||||
. += "<span class='his_grace'>[src] is latched closed.</span>"
|
||||
|
||||
/obj/item/his_grace/relaymove(mob/living/user) //Allows changelings, etc. to climb out of Him after they revive, provided He isn't active
|
||||
/obj/item/his_grace/relaymove(mob/living/user, direction) //Allows changelings, etc. to climb out of Him after they revive, provided He isn't active
|
||||
if(!awakened)
|
||||
user.forceMove(get_turf(src))
|
||||
user.visible_message("<span class='warning'>[user] scrambles out of [src]!</span>", "<span class='notice'>You climb out of [src]!</span>")
|
||||
|
||||
/obj/item/his_grace/process()
|
||||
/obj/item/his_grace/process(delta_time)
|
||||
if(!bloodthirst)
|
||||
drowse()
|
||||
return
|
||||
if(bloodthirst < HIS_GRACE_CONSUME_OWNER && !ascended)
|
||||
adjust_bloodthirst(1 + FLOOR(LAZYLEN(contents) * 0.5, 1)) //Maybe adjust this?
|
||||
adjust_bloodthirst((1 + FLOOR(LAZYLEN(contents) * 0.5, 1)) * delta_time) //Maybe adjust this?
|
||||
else
|
||||
adjust_bloodthirst(1) //don't cool off rapidly once we're at the point where His Grace consumes all.
|
||||
adjust_bloodthirst(1 * delta_time) //don't cool off rapidly once we're at the point where His Grace consumes all.
|
||||
var/mob/living/master = get_atom_on_turf(src, /mob/living)
|
||||
if(istype(master) && (src in master.held_items))
|
||||
switch(bloodthirst)
|
||||
@@ -94,7 +94,7 @@
|
||||
REMOVE_TRAIT(src, TRAIT_NODROP, HIS_GRACE_TRAIT)
|
||||
master.DefaultCombatKnockdown(60)
|
||||
master.adjustBruteLoss(master.maxHealth)
|
||||
playsound(master, 'sound/effects/splat.ogg', 100, 0)
|
||||
playsound(master, 'sound/effects/splat.ogg', 100, FALSE)
|
||||
else
|
||||
master.apply_status_effect(STATUS_EFFECT_HISGRACE)
|
||||
return
|
||||
@@ -115,8 +115,8 @@
|
||||
if(!L.stat)
|
||||
L.visible_message("<span class='warning'>[src] lunges at [L]!</span>", "<span class='his_grace big bold'>[src] lunges at you!</span>")
|
||||
do_attack_animation(L, null, src)
|
||||
playsound(L, 'sound/weapons/smash.ogg', 50, 1)
|
||||
playsound(L, 'sound/misc/desceration-01.ogg', 50, 1)
|
||||
playsound(L, 'sound/weapons/smash.ogg', 50, TRUE)
|
||||
playsound(L, 'sound/misc/desceration-01.ogg', 50, TRUE)
|
||||
L.adjustBruteLoss(force)
|
||||
adjust_bloodthirst(-5) //Don't stop attacking they're right there!
|
||||
else
|
||||
@@ -137,6 +137,8 @@
|
||||
move_gracefully()
|
||||
|
||||
/obj/item/his_grace/proc/move_gracefully()
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(!awakened)
|
||||
return
|
||||
var/static/list/transforms
|
||||
@@ -161,7 +163,7 @@
|
||||
return
|
||||
var/turf/T = get_turf(src)
|
||||
T.visible_message("<span class='boldwarning'>[src] slowly stops rattling and falls still, His latch snapping shut.</span>")
|
||||
playsound(loc, 'sound/weapons/batonextend.ogg', 100, 1)
|
||||
playsound(loc, 'sound/weapons/batonextend.ogg', 100, TRUE)
|
||||
name = initial(name)
|
||||
desc = initial(desc)
|
||||
icon_state = initial(icon_state)
|
||||
@@ -178,8 +180,8 @@
|
||||
var/victims = 0
|
||||
meal.visible_message("<span class='warning'>[src] swings open and devours [meal]!</span>", "<span class='his_grace big bold'>[src] consumes you!</span>")
|
||||
meal.adjustBruteLoss(200)
|
||||
playsound(meal, 'sound/misc/desceration-02.ogg', 75, 1)
|
||||
playsound(src, 'sound/items/eatfood.ogg', 100, 1)
|
||||
playsound(meal, 'sound/misc/desceration-02.ogg', 75, TRUE)
|
||||
playsound(src, 'sound/items/eatfood.ogg', 100, TRUE)
|
||||
meal.forceMove(src)
|
||||
force_bonus += HIS_GRACE_FORCE_BONUS
|
||||
prev_bloodthirst = bloodthirst
|
||||
@@ -253,3 +255,4 @@
|
||||
if(istype(master))
|
||||
master.visible_message("<span class='his_grace big bold'>Gods will be watching.</span>")
|
||||
name = "[master]'s mythical toolbox of three powers"
|
||||
master.client?.give_award(/datum/award/achievement/misc/ascension, master)
|
||||
|
||||
@@ -24,9 +24,9 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
|
||||
*/
|
||||
/obj/item/banhammer/attack(mob/M, mob/user)
|
||||
if(user.zone_selected == BODY_ZONE_HEAD)
|
||||
M.visible_message("<span class='danger'>[user] are stroking the head of [M] with a bangammer</span>", "<span class='userdanger'>[user] are stroking the head with a bangammer</span>", "you hear a bangammer stroking a head");
|
||||
M.visible_message("<span class='danger'>[user] are stroking the head of [M] with a bangammer.</span>", "<span class='userdanger'>[user] are stroking your head with a bangammer.</span>", "<span class='hear'>You hear a bangammer stroking a head.</span>") // see above comment
|
||||
else
|
||||
M.visible_message("<span class='danger'>[M] has been banned FOR NO REISIN by [user]</span>", "<span class='userdanger'>You have been banned FOR NO REISIN by [user]</span>", "you hear a banhammer banning someone")
|
||||
M.visible_message("<span class='danger'>[M] has been banned FOR NO REISIN by [user]!</span>", "<span class='userdanger'>You have been banned FOR NO REISIN by [user]!</span>", "<span class='hear'>You hear a banhammer banning someone.</span>")
|
||||
playsound(loc, 'sound/effects/adminhelp.ogg', 15) //keep it at 15% volume so people don't jump out of their skin too much
|
||||
if(user.a_intent != INTENT_HELP)
|
||||
return ..(M, user)
|
||||
@@ -89,7 +89,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
|
||||
/obj/item/claymore/highlander //ALL COMMENTS MADE REGARDING THIS SWORD MUST BE MADE IN ALL CAPS
|
||||
desc = "<b><i>THERE CAN BE ONLY ONE, AND IT WILL BE YOU!!!</i></b>\nActivate it in your hand to point to the nearest victim."
|
||||
flags_1 = CONDUCT_1
|
||||
item_flags = DROPDEL
|
||||
item_flags = DROPDEL //WOW BRO YOU LOST AN ARM, GUESS WHAT YOU DONT GET YOUR SWORD ANYMORE //I CANT BELIEVE SPOOKYDONUT WOULD BREAK THE REQUIREMENTS
|
||||
slot_flags = null
|
||||
block_chance = 0 //RNG WON'T HELP YOU NOW, PANSY
|
||||
light_range = 3
|
||||
@@ -130,8 +130,6 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
|
||||
/obj/item/claymore/highlander/dropped(mob/living/user)
|
||||
. = ..()
|
||||
user.unignore_slowdown(HIGHLANDER)
|
||||
if(!QDELETED(src))
|
||||
qdel(src) //If this ever happens, it's because you lost an arm
|
||||
|
||||
/obj/item/claymore/highlander/examine(mob/user)
|
||||
. = ..()
|
||||
@@ -141,8 +139,8 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
|
||||
|
||||
/obj/item/claymore/highlander/attack(mob/living/target, mob/living/user)
|
||||
. = ..()
|
||||
if(!QDELETED(target) && iscarbon(target) && target.stat == DEAD && target.mind && target.mind.special_role == "highlander")
|
||||
user.fully_heal() //STEAL THE LIFE OF OUR FALLEN FOES
|
||||
if(!QDELETED(target) && target.stat == DEAD && target.mind && target.mind.special_role == "highlander")
|
||||
user.fully_heal(admin_revive = FALSE) //STEAL THE LIFE OF OUR FALLEN FOES
|
||||
add_notch(user)
|
||||
target.visible_message("<span class='warning'>[target] crumbles to dust beneath [user]'s blows!</span>", "<span class='userdanger'>As you fall, your body crumbles to dust!</span>")
|
||||
target.dust()
|
||||
@@ -150,9 +148,13 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
|
||||
/obj/item/claymore/highlander/attack_self(mob/living/user)
|
||||
var/closest_victim
|
||||
var/closest_distance = 255
|
||||
for(var/mob/living/carbon/human/H in GLOB.player_list - user)
|
||||
if(H.client && H.mind.special_role == "highlander" && (!closest_victim || get_dist(user, closest_victim) < closest_distance))
|
||||
closest_victim = H
|
||||
for(var/mob/living/carbon/human/scot in GLOB.player_list - user)
|
||||
if(scot.mind.special_role == "highlander" && (!closest_victim || get_dist(user, closest_victim) < closest_distance))
|
||||
closest_victim = scot
|
||||
for(var/mob/living/silicon/robot/siliscot in GLOB.player_list - user)
|
||||
if(siliscot.mind.special_role == "highlander" && (!closest_victim || get_dist(user, closest_victim) < closest_distance))
|
||||
closest_victim = siliscot
|
||||
|
||||
if(!closest_victim)
|
||||
to_chat(user, "<span class='warning'>[src] thrums for a moment and falls dark. Perhaps there's nobody nearby.</span>")
|
||||
return
|
||||
@@ -161,7 +163,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
|
||||
/obj/item/claymore/highlander/run_block(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
|
||||
if((attack_type & ATTACK_TYPE_PROJECTILE) && is_energy_reflectable_projectile(object))
|
||||
return BLOCK_SUCCESS | BLOCK_SHOULD_REDIRECT | BLOCK_PHYSICAL_EXTERNAL | BLOCK_REDIRECTED
|
||||
return ..()
|
||||
return ..() //YOU THINK YOUR PUNY LASERS CAN STOP ME?
|
||||
|
||||
/obj/item/claymore/highlander/proc/add_notch(mob/living/user) //DYNAMIC CLAYMORE PROGRESSION SYSTEM - THIS IS THE FUTURE
|
||||
notches++
|
||||
@@ -214,7 +216,22 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
|
||||
remove_atom_colour(ADMIN_COLOUR_PRIORITY)
|
||||
|
||||
name = new_name
|
||||
playsound(user, 'sound/items/screwdriver2.ogg', 50, 1)
|
||||
playsound(user, 'sound/items/screwdriver2.ogg', 50, TRUE)
|
||||
|
||||
/obj/item/claymore/highlander/robot //BLOODTHIRSTY BORGS NOW COME IN PLAID
|
||||
icon = 'icons/obj/items_cyborg.dmi'
|
||||
icon_state = "claymore_cyborg"
|
||||
var/mob/living/silicon/robot/robot
|
||||
|
||||
/obj/item/claymore/highlander/robot/Initialize()
|
||||
var/obj/item/robot_module/kiltkit = loc
|
||||
robot = kiltkit.loc
|
||||
if(!istype(robot))
|
||||
qdel(src)
|
||||
return ..()
|
||||
|
||||
/obj/item/claymore/highlander/robot/process()
|
||||
loc.layer = LARGE_MOB_LAYER
|
||||
|
||||
/obj/item/katana
|
||||
name = "katana"
|
||||
@@ -227,7 +244,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
|
||||
slot_flags = ITEM_SLOT_BELT | ITEM_SLOT_BACK
|
||||
force = 40
|
||||
throwforce = 10
|
||||
w_class = WEIGHT_CLASS_BULKY
|
||||
w_class = WEIGHT_CLASS_HUGE
|
||||
hitsound = 'sound/weapons/bladeslice.ogg'
|
||||
attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut")
|
||||
block_chance = 50
|
||||
@@ -417,7 +434,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
|
||||
desc = "A misnomer of sorts, this is effectively a blunt katana made from steelwood, a dense organic wood derived from steelcaps. Why steelwood? Druids can use it. Duh."
|
||||
icon_state = "bokken_steel"
|
||||
item_state = "bokken_steel"
|
||||
force = 12
|
||||
force = 12
|
||||
stamina_damage_increment = 3
|
||||
|
||||
/obj/item/melee/bokken/waki
|
||||
@@ -427,7 +444,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
|
||||
item_state = "wakibokken"
|
||||
slot_flags = ITEM_SLOT_BELT
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
force = 6
|
||||
force = 6
|
||||
stamina_damage_increment = 4
|
||||
block_parry_data = /datum/block_parry_data/bokken/waki
|
||||
default_parry_data = /datum/block_parry_data/bokken/waki
|
||||
@@ -442,7 +459,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
|
||||
parry_time_perfect_leeway = 1
|
||||
parry_imperfect_falloff_percent = 7.5
|
||||
parry_efficiency_to_counterattack = 120
|
||||
parry_efficiency_considered_successful = 65
|
||||
parry_efficiency_considered_successful = 65
|
||||
parry_efficiency_perfect = 120
|
||||
parry_efficiency_perfect_override = list(
|
||||
TEXT_ATTACK_TYPE_PROJECTILE = 30,
|
||||
@@ -455,10 +472,10 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
|
||||
/datum/block_parry_data/bokken/waki/quick_parry //For the parry spammer in you
|
||||
parry_stamina_cost = 2 // Slam that parry button
|
||||
parry_time_active = 2.5
|
||||
parry_time_perfect = 1
|
||||
parry_time_perfect = 1
|
||||
parry_time_perfect_leeway = 1
|
||||
parry_failed_stagger_duration = 1 SECONDS
|
||||
parry_failed_clickcd_duration = 1 SECONDS
|
||||
parry_failed_clickcd_duration = 1 SECONDS
|
||||
|
||||
/datum/block_parry_data/bokken/waki/quick_parry/proj
|
||||
parry_efficiency_perfect_override = list()
|
||||
@@ -468,7 +485,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
|
||||
desc = "A misnomer of sorts, this is effectively a blunt wakizashi made from steelwood, a dense organic wood derived from steelcaps. Why steelwood? Druids can use it. Duh."
|
||||
icon_state = "wakibokken_steel"
|
||||
item_state = "wakibokken_steel"
|
||||
force = 8
|
||||
force = 8
|
||||
stamina_damage_increment = 2
|
||||
|
||||
/obj/item/melee/bokken/debug
|
||||
@@ -575,7 +592,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
|
||||
user.put_in_hands(S)
|
||||
to_chat(user, "<span class='notice'>You fasten the glass shard to the top of the rod with the cable.</span>")
|
||||
|
||||
else if(istype(I, /obj/item/assembly/igniter) && !HAS_TRAIT(I, TRAIT_NODROP))
|
||||
else if(istype(I, /obj/item/assembly/igniter) && !(HAS_TRAIT(I, TRAIT_NODROP)))
|
||||
var/obj/item/melee/baton/cattleprod/P = new /obj/item/melee/baton/cattleprod
|
||||
|
||||
remove_item_from_storage(user)
|
||||
@@ -598,13 +615,13 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
|
||||
lefthand_file = 'icons/mob/inhands/equipment/shields_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/equipment/shields_righthand.dmi'
|
||||
force = 2
|
||||
throwforce = 10 //This is never used on mobs since this has a 100% embed chance.
|
||||
throwforce = 10 //10 + 2 (WEIGHT_CLASS_SMALL) * 4 (EMBEDDED_IMPACT_PAIN_MULTIPLIER) = 18 damage on hit due to guaranteed embedding
|
||||
throw_speed = 4
|
||||
embedding = list("pain_mult" = 4, "embed_chance" = 100, "fall_chance" = 0, "embed_chance_turf_mod" = 15)
|
||||
armour_penetration = 40
|
||||
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
sharpness = SHARP_EDGED
|
||||
sharpness = SHARP_POINTY
|
||||
custom_materials = list(/datum/material/iron=500, /datum/material/glass=500)
|
||||
resistance_flags = FIRE_PROOF
|
||||
|
||||
@@ -639,27 +656,23 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
|
||||
attack_verb = list("stubbed", "poked")
|
||||
resistance_flags = FIRE_PROOF
|
||||
var/extended = 0
|
||||
var/extended_force = 20
|
||||
var/extended_throwforce = 23
|
||||
var/extended_icon_state = "switchblade_ext"
|
||||
var/retracted_icon_state = "switchblade"
|
||||
|
||||
/obj/item/switchblade/attack_self(mob/user)
|
||||
extended = !extended
|
||||
playsound(src.loc, 'sound/weapons/batonextend.ogg', 50, 1)
|
||||
playsound(src.loc, 'sound/weapons/batonextend.ogg', 50, TRUE)
|
||||
if(extended)
|
||||
force = extended_force
|
||||
force = 20
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
throwforce = extended_throwforce
|
||||
icon_state = extended_icon_state
|
||||
throwforce = 23
|
||||
icon_state = "switchblade_ext"
|
||||
attack_verb = list("slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut")
|
||||
hitsound = 'sound/weapons/bladeslice.ogg'
|
||||
sharpness = SHARP_EDGED
|
||||
else
|
||||
force = initial(force)
|
||||
force = 3
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
throwforce = initial(throwforce)
|
||||
icon_state = retracted_icon_state
|
||||
throwforce = 5
|
||||
icon_state = "switchblade"
|
||||
attack_verb = list("stubbed", "poked")
|
||||
hitsound = 'sound/weapons/genhit.ogg'
|
||||
sharpness = SHARP_NONE
|
||||
@@ -750,6 +763,10 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
|
||||
user.visible_message("<span class='suicide'>[user] is inhaling [src]! It looks like [user.p_theyre()] trying to visit the astral plane!</span>")
|
||||
return (OXYLOSS)
|
||||
|
||||
// /obj/item/ectoplasm/angelic
|
||||
// icon = 'icons/obj/wizard.dmi'
|
||||
// icon_state = "angelplasm"
|
||||
|
||||
/obj/item/mounted_chainsaw
|
||||
name = "mounted chainsaw"
|
||||
desc = "A chainsaw that has replaced your arm."
|
||||
@@ -758,7 +775,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
|
||||
lefthand_file = 'icons/mob/inhands/weapons/chainsaw_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/weapons/chainsaw_righthand.dmi'
|
||||
item_flags = ABSTRACT | DROPDEL
|
||||
w_class = WEIGHT_CLASS_BULKY
|
||||
w_class = WEIGHT_CLASS_HUGE
|
||||
force = 24
|
||||
throwforce = 0
|
||||
throw_range = 0
|
||||
@@ -801,7 +818,13 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
|
||||
/obj/item/statuebust/Initialize()
|
||||
. = ..()
|
||||
AddElement(/datum/element/art, impressiveness)
|
||||
addtimer(CALLBACK(src, /datum.proc/_AddElement, list(/datum/element/beauty, 1000)), 0)
|
||||
// AddComponent(/datum/component/beauty, 1000)
|
||||
|
||||
// /obj/item/statuebust/hippocratic
|
||||
// name = "hippocrates bust"
|
||||
// desc = "A bust of the famous Greek physician Hippocrates of Kos, often referred to as the father of western medicine."
|
||||
// icon_state = "hippocratic"
|
||||
// impressiveness = 50
|
||||
|
||||
/obj/item/tailclub
|
||||
name = "tail club"
|
||||
@@ -825,8 +848,8 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
|
||||
icon_state = "catwhip"
|
||||
|
||||
/obj/item/melee/skateboard
|
||||
name = "improvised skateboard"
|
||||
desc = "A skateboard. It can be placed on its wheels and ridden, or used as a strong weapon."
|
||||
name = "skateboard"
|
||||
desc = "A skateboard. It can be placed on its wheels and ridden, or used as a radical weapon."
|
||||
icon_state = "skateboard"
|
||||
item_state = "skateboard"
|
||||
force = 12
|
||||
@@ -839,17 +862,22 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
|
||||
/obj/item/melee/skateboard/attack_self(mob/user)
|
||||
if(!user.canUseTopic(src, TRUE, FALSE, TRUE))
|
||||
return
|
||||
var/obj/vehicle/ridden/scooter/skateboard/S = new board_item_type(get_turf(user))
|
||||
var/obj/vehicle/ridden/scooter/skateboard/S = new board_item_type(get_turf(user))//this probably has fucky interactions with telekinesis but for the record it wasn't my fault
|
||||
S.buckle_mob(user)
|
||||
qdel(src)
|
||||
|
||||
/obj/item/melee/skateboard/improvised
|
||||
name = "improvised skateboard"
|
||||
desc = "A jury-rigged skateboard. It can be placed on its wheels and ridden, or used as a radical weapon."
|
||||
// board_item_type = /obj/vehicle/ridden/scooter/skateboard/improvised
|
||||
|
||||
/obj/item/melee/skateboard/pro
|
||||
name = "skateboard"
|
||||
desc = "A RaDSTORMz brand professional skateboard. It looks sturdy and well made."
|
||||
desc = "An EightO brand professional skateboard. It looks sturdy and well made."
|
||||
icon_state = "skateboard2"
|
||||
item_state = "skateboard2"
|
||||
board_item_type = /obj/vehicle/ridden/scooter/skateboard/pro
|
||||
custom_premium_price = 500
|
||||
custom_premium_price = PAYCHECK_HARD * 5
|
||||
|
||||
/obj/item/melee/skateboard/hoverboard
|
||||
name = "hoverboard"
|
||||
@@ -857,10 +885,10 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
|
||||
icon_state = "hoverboard_red"
|
||||
item_state = "hoverboard_red"
|
||||
board_item_type = /obj/vehicle/ridden/scooter/skateboard/hoverboard
|
||||
custom_premium_price = 2015
|
||||
custom_premium_price = PAYCHECK_COMMAND * 5.4 //If I can't make it a meme I'll make it RAD
|
||||
|
||||
/obj/item/melee/skateboard/hoverboard/admin
|
||||
name = "\improper Board Of Directors"
|
||||
name = "Board Of Directors"
|
||||
desc = "The engineering complexity of a spaceship concentrated inside of a board. Just as expensive, too."
|
||||
icon_state = "hoverboard_nt"
|
||||
item_state = "hoverboard_nt"
|
||||
@@ -879,11 +907,19 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
|
||||
throwforce = 12
|
||||
attack_verb = list("beat", "smacked")
|
||||
custom_materials = list(/datum/material/wood = MINERAL_MATERIAL_AMOUNT * 3.5)
|
||||
w_class = WEIGHT_CLASS_BULKY
|
||||
w_class = WEIGHT_CLASS_HUGE
|
||||
var/homerun_ready = 0
|
||||
var/homerun_able = 0
|
||||
total_mass = 2.7 //a regular wooden major league baseball bat weighs somewhere between 2 to 3.4 pounds, according to google
|
||||
|
||||
/obj/item/melee/baseball_bat/Initialize()
|
||||
. = ..()
|
||||
if(prob(1))
|
||||
name = "cricket bat"
|
||||
desc = "You've got red on you."
|
||||
icon_state = "baseball_bat_brit"
|
||||
item_state = "baseball_bat_brit"
|
||||
|
||||
/obj/item/melee/baseball_bat/chaplain
|
||||
name = "blessed baseball bat"
|
||||
desc = "There ain't a cult in the league that can withstand a swatter."
|
||||
@@ -908,11 +944,11 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
|
||||
..()
|
||||
return
|
||||
if(homerun_ready)
|
||||
to_chat(user, "<span class='notice'>You're already ready to do a home run!</span>")
|
||||
to_chat(user, "<span class='warning'>You're already ready to do a home run!</span>")
|
||||
..()
|
||||
return
|
||||
to_chat(user, "<span class='warning'>You begin gathering strength...</span>")
|
||||
playsound(get_turf(src), 'sound/magic/lightning_chargeup.ogg', 65, 1)
|
||||
playsound(get_turf(src), 'sound/magic/lightning_chargeup.ogg', 65, TRUE)
|
||||
if(do_after(user, 90, target = src))
|
||||
to_chat(user, "<span class='userdanger'>You gather power! Time for a home run!</span>")
|
||||
homerun_ready = 1
|
||||
@@ -920,12 +956,14 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
|
||||
|
||||
/obj/item/melee/baseball_bat/attack(mob/living/target, mob/living/user)
|
||||
. = ..()
|
||||
if(HAS_TRAIT(user, TRAIT_PACIFISM))
|
||||
return
|
||||
var/atom/throw_target = get_edge_target_turf(target, user.dir)
|
||||
if(homerun_ready)
|
||||
user.visible_message("<span class='userdanger'>It's a home run!</span>")
|
||||
target.throw_at(throw_target, rand(8,10), 14, user)
|
||||
target.ex_act(EXPLODE_HEAVY)
|
||||
playsound(get_turf(src), 'sound/weapons/homerun.ogg', 100, 1)
|
||||
playsound(get_turf(src), 'sound/weapons/homerun.ogg', 100, TRUE)
|
||||
homerun_ready = 0
|
||||
return
|
||||
else if(!target.anchored)
|
||||
@@ -956,7 +994,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
|
||||
|
||||
/obj/item/melee/flyswatter
|
||||
name = "flyswatter"
|
||||
desc = "Useful for killing insects of all sizes."
|
||||
desc = "Useful for killing pests of all sizes."
|
||||
icon = 'icons/obj/items_and_weapons.dmi'
|
||||
icon_state = "flyswatter"
|
||||
item_state = "flyswatter"
|
||||
@@ -969,7 +1007,6 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
//Things in this list will be instantly splatted. Flyman weakness is handled in the flyman species weakness proc.
|
||||
var/list/strong_against
|
||||
var/list/spider_panic
|
||||
|
||||
/obj/item/melee/flyswatter/Initialize()
|
||||
. = ..()
|
||||
@@ -977,13 +1014,11 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
|
||||
/mob/living/simple_animal/hostile/poison/bees/,
|
||||
/mob/living/simple_animal/butterfly,
|
||||
/mob/living/simple_animal/cockroach,
|
||||
/obj/item/queen_bee
|
||||
))
|
||||
spider_panic = typecacheof(list(
|
||||
/mob/living/simple_animal/banana_spider,
|
||||
/mob/living/simple_animal/hostile/poison/giant_spider,
|
||||
/obj/item/queen_bee,
|
||||
/obj/structure/spider/spiderling
|
||||
))
|
||||
|
||||
|
||||
/obj/item/melee/flyswatter/afterattack(atom/target, mob/user, proximity_flag)
|
||||
. = ..()
|
||||
if(proximity_flag)
|
||||
@@ -993,11 +1028,6 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
|
||||
if(istype(target, /mob/living/))
|
||||
var/mob/living/bug = target
|
||||
bug.death(1)
|
||||
if(is_type_in_typecache(target, spider_panic))
|
||||
to_chat(user, "<span class='warning'>You easily land a critical blow on the [target].</span>")
|
||||
if(istype(target, /mob/living/))
|
||||
var/mob/living/bug = target
|
||||
bug.adjustBruteLoss(35) //What kinda mad man would go into melee with a spider?!
|
||||
else
|
||||
qdel(target)
|
||||
|
||||
@@ -1007,7 +1037,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
|
||||
icon_state = "madeyoulook"
|
||||
force = 0
|
||||
throwforce = 0
|
||||
item_flags = DROPDEL | ABSTRACT
|
||||
item_flags = DROPDEL | ABSTRACT // | HAND_ITEM
|
||||
attack_verb = list("bopped")
|
||||
|
||||
/obj/item/circlegame/Initialize()
|
||||
@@ -1030,6 +1060,8 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
|
||||
|
||||
/// Stage 1: The mistake is made
|
||||
/obj/item/circlegame/proc/ownerExamined(mob/living/owner, mob/living/sucker)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(!istype(sucker) || !in_range(owner, sucker))
|
||||
return
|
||||
addtimer(CALLBACK(src, .proc/waitASecond, owner, sucker), 4)
|
||||
@@ -1076,6 +1108,10 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
|
||||
to_chat(owner, "<span class='warning'>[sucker] looks down at your [src.name] before trying to avert [sucker.p_their()] eyes, but it's too late!</span>")
|
||||
to_chat(sucker, "<span class='danger'><b>[owner] sees the fear in your eyes as you try to look away from [owner.p_their()] [src.name]!</b></span>")
|
||||
|
||||
owner.face_atom(sucker)
|
||||
if(owner.client)
|
||||
owner.client.give_award(/datum/award/achievement/misc/gottem, owner) // then everybody clapped
|
||||
|
||||
playsound(get_turf(owner), 'sound/effects/hit_punch.ogg', 50, TRUE, -1)
|
||||
owner.do_attack_animation(sucker)
|
||||
|
||||
@@ -1103,7 +1139,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
|
||||
item_state = "nothing"
|
||||
force = 0
|
||||
throwforce = 0
|
||||
item_flags = DROPDEL | ABSTRACT
|
||||
item_flags = DROPDEL | ABSTRACT // | HAND_ITEM
|
||||
attack_verb = list("slapped")
|
||||
hitsound = 'sound/effects/snap.ogg'
|
||||
|
||||
@@ -1112,16 +1148,12 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
|
||||
var/mob/living/carbon/human/L = M
|
||||
if(L && L.dna && L.dna.species)
|
||||
L.dna.species.stop_wagging_tail(M)
|
||||
if(user.a_intent != INTENT_HARM && ((user.zone_selected == BODY_ZONE_PRECISE_MOUTH) || (user.zone_selected == BODY_ZONE_PRECISE_EYES) || (user.zone_selected == BODY_ZONE_HEAD)))
|
||||
user.do_attack_animation(M)
|
||||
playsound(M, 'sound/weapons/slap.ogg', 50, 1, -1)
|
||||
user.visible_message("<span class='danger'>[user] slaps [M]!</span>",
|
||||
"<span class='notice'>You slap [M]!</span>",\
|
||||
"You hear a slap.")
|
||||
return
|
||||
else
|
||||
..()
|
||||
|
||||
user.do_attack_animation(M)
|
||||
playsound(M, 'sound/weapons/slap.ogg', 50, TRUE, -1)
|
||||
user.visible_message("<span class='danger'>[user] slaps [M]!</span>",
|
||||
"<span class='notice'>You slap [M]!</span>",\
|
||||
"<span class='hear'>You hear a slap.</span>")
|
||||
return
|
||||
/obj/item/proc/can_trigger_gun(mob/living/user)
|
||||
if(!user.can_use_guns(src))
|
||||
return FALSE
|
||||
@@ -1138,6 +1170,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
|
||||
force = 0
|
||||
throwforce = 5
|
||||
reach = 2
|
||||
var/min_reach = 2
|
||||
|
||||
/obj/item/extendohand/acme
|
||||
name = "\improper ACME Extendo-Hand"
|
||||
@@ -1145,13 +1178,26 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
|
||||
|
||||
/obj/item/extendohand/attack(atom/M, mob/living/carbon/human/user)
|
||||
var/dist = get_dist(M, user)
|
||||
if(dist < reach)
|
||||
if(dist < min_reach)
|
||||
to_chat(user, "<span class='warning'>[M] is too close to use [src] on.</span>")
|
||||
return
|
||||
M.attack_hand(user)
|
||||
|
||||
//HF blade
|
||||
// /obj/item/gohei
|
||||
// name = "gohei"
|
||||
// desc = "A wooden stick with white streamers at the end. Originally used by shrine maidens to purify things. Now used by the station's valued weeaboos."
|
||||
// force = 5
|
||||
// throwforce = 5
|
||||
// hitsound = "swing_hit"
|
||||
// attack_verb_continuous = list("whacks", "thwacks", "wallops", "socks")
|
||||
// attack_verb_simple = list("whack", "thwack", "wallop", "sock")
|
||||
// icon = 'icons/obj/items_and_weapons.dmi'
|
||||
// icon_state = "gohei"
|
||||
// inhand_icon_state = "gohei"
|
||||
// lefthand_file = 'icons/mob/inhands/weapons/staves_lefthand.dmi'
|
||||
// righthand_file = 'icons/mob/inhands/weapons/staves_righthand.dmi'
|
||||
|
||||
//HF blade
|
||||
/obj/item/vibro_weapon
|
||||
icon_state = "hfrequency0"
|
||||
lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi'
|
||||
@@ -1160,6 +1206,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
|
||||
desc = "A potent weapon capable of cutting through nearly anything. Wielding it in two hands will allow you to deflect gunfire."
|
||||
armour_penetration = 100
|
||||
block_chance = 40
|
||||
force = 20
|
||||
throwforce = 20
|
||||
throw_speed = 4
|
||||
sharpness = SHARP_EDGED
|
||||
@@ -1182,10 +1229,14 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
|
||||
|
||||
/// triggered on wield of two handed item
|
||||
/obj/item/vibro_weapon/proc/on_wield(obj/item/source, mob/user)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
wielded = TRUE
|
||||
|
||||
/// triggered on unwield of two handed item
|
||||
/obj/item/vibro_weapon/proc/on_unwield(obj/item/source, mob/user)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
wielded = FALSE
|
||||
|
||||
/obj/item/vibro_weapon/update_icon_state()
|
||||
|
||||
@@ -52,12 +52,12 @@ GLOBAL_LIST_INIT(tendrils, list())
|
||||
last_tendril = FALSE
|
||||
|
||||
if(last_tendril && !(flags_1 & ADMIN_SPAWNED_1))
|
||||
if(SSmedals.hub_enabled)
|
||||
if(SSachievements.achievements_enabled)
|
||||
for(var/mob/living/L in view(7,src))
|
||||
if(L.stat || !L.client)
|
||||
continue
|
||||
SSmedals.UnlockMedal("[BOSS_MEDAL_TENDRIL] [ALL_KILL_MEDAL]", L.client)
|
||||
SSmedals.SetScore(TENDRIL_CLEAR_SCORE, L.client, 1)
|
||||
L.client.give_award(/datum/award/achievement/boss/tendril_exterminator, L)
|
||||
L.client.give_award(/datum/award/score/tendril_score, L) //Progresses score by one
|
||||
GLOB.tendrils -= src
|
||||
QDEL_NULL(emitted_light)
|
||||
QDEL_NULL(gps)
|
||||
|
||||
@@ -47,14 +47,19 @@
|
||||
if(open)
|
||||
GM.visible_message("<span class='danger'>[user] starts to give [GM] a swirlie!</span>", "<span class='userdanger'>[user] starts to give you a swirlie...</span>")
|
||||
swirlie = GM
|
||||
if(do_after(user, 30, 0, target = src))
|
||||
GM.visible_message("<span class='danger'>[user] gives [GM] a swirlie!</span>", "<span class='userdanger'>[user] gives you a swirlie!</span>", "<span class='italics'>You hear a toilet flushing.</span>")
|
||||
var/was_alive = (swirlie.stat != DEAD)
|
||||
if(do_after(user, 3 SECONDS, target = src, timed_action_flags = IGNORE_HELD_ITEM))
|
||||
GM.visible_message("<span class='danger'>[user] gives [GM] a swirlie!</span>", "<span class='userdanger'>[user] gives you a swirlie!</span>", "<span class='hear'>You hear a toilet flushing.</span>")
|
||||
if(iscarbon(GM))
|
||||
var/mob/living/carbon/C = GM
|
||||
if(!C.internal)
|
||||
log_combat(user, C, "swirlied (oxy)")
|
||||
C.adjustOxyLoss(5)
|
||||
else
|
||||
log_combat(user, GM, "swirlied (oxy)")
|
||||
GM.adjustOxyLoss(5)
|
||||
if(was_alive && swirlie.stat == DEAD && swirlie.client)
|
||||
swirlie.client.give_award(/datum/award/achievement/misc/swirlie, swirlie) // just like space high school all over again!
|
||||
swirlie = null
|
||||
else
|
||||
playsound(src.loc, 'sound/effects/bang.ogg', 25, 1)
|
||||
|
||||
@@ -872,20 +872,18 @@
|
||||
/turf/closed/mineral/strong/gets_drilled(mob/user)
|
||||
if(!ishuman(user))
|
||||
return // see attackby
|
||||
/*
|
||||
var/mob/living/carbon/human/H = user
|
||||
if(!(H.mind.get_skill_level(/datum/skill/mining) >= SKILL_LEVEL_MASTER))
|
||||
return
|
||||
*/
|
||||
// if(!(H.mind?.get_skill_level(/datum/skill/mining) >= SKILL_LEVEL_MASTER))
|
||||
// return
|
||||
drop_ores()
|
||||
// H.client.give_award(/datum/award/achievement/skill/legendary_miner, H)
|
||||
H.client.give_award(/datum/award/achievement/skill/legendary_miner, H)
|
||||
var/flags = NONE
|
||||
if(defer_change) // TODO: make the defer change var a var for any changeturf flag
|
||||
flags = CHANGETURF_DEFER_CHANGE
|
||||
ScrapeAway(flags=flags)
|
||||
addtimer(CALLBACK(src, .proc/AfterChange), 1, TIMER_UNIQUE)
|
||||
playsound(src, 'sound/effects/break_stone.ogg', 50, TRUE) //beautiful destruction
|
||||
// H.mind.adjust_experience(/datum/skill/mining, 100) //yay!
|
||||
// H.mind?.adjust_experience(/datum/skill/mining, 100) //yay!
|
||||
|
||||
/turf/closed/mineral/strong/proc/drop_ores()
|
||||
if(prob(10))
|
||||
|
||||
@@ -6,13 +6,21 @@ GLOBAL_PROTECT(admin_verbs_default)
|
||||
return list(
|
||||
/client/proc/deadmin, /*destroys our own admin datum so we can play as a regular player*/
|
||||
/client/proc/cmd_admin_say, /*admin-only ooc chat*/
|
||||
/client/proc/dsay, /*talk in deadchat using our ckey/fakekey*/
|
||||
/client/proc/deadchat,
|
||||
/client/proc/investigate_show, /*various admintools for investigation. Such as a singulo grief-log*/
|
||||
/client/proc/hide_verbs, /*hides all our adminverbs*/
|
||||
/client/proc/hide_most_verbs, /*hides all our hideable adminverbs*/
|
||||
/client/proc/debug_variables, /*allows us to -see- the variables of any instance in the game. +VAREDIT needed to modify*/
|
||||
/client/proc/toggleprayers,
|
||||
/client/proc/toggleadminhelpsound,
|
||||
/client/proc/debugstatpanel,
|
||||
/client/proc/dsay, /*talk in deadchat using our ckey/fakekey*/
|
||||
/client/proc/investigate_show, /*various admintools for investigation. Such as a singulo grief-log*/
|
||||
/client/proc/secrets,
|
||||
/client/proc/toggle_hear_radio, /*allows admins to hide all radio output*/
|
||||
/client/proc/reload_admins,
|
||||
/client/proc/reestablish_db_connection, /*reattempt a connection to the database*/
|
||||
/client/proc/cmd_admin_pm_context, /*right-click adminPM interface*/
|
||||
/client/proc/cmd_admin_pm_panel, /*admin-pm list*/
|
||||
/client/proc/stop_sounds,
|
||||
/client/proc/mark_datum_mapview,
|
||||
/client/proc/debugstatpanel
|
||||
// /client/proc/fix_air /*resets air in designated radius to its default atmos composition*/
|
||||
)
|
||||
GLOBAL_LIST_INIT(admin_verbs_admin, world.AVerbsAdmin())
|
||||
GLOBAL_PROTECT(admin_verbs_admin)
|
||||
@@ -24,6 +32,7 @@ GLOBAL_PROTECT(admin_verbs_admin)
|
||||
/datum/verbs/menu/Admin/verb/playerpanel,
|
||||
/client/proc/game_panel, /*game panel, allows to change game-mode etc*/
|
||||
/client/proc/check_ai_laws, /*shows AI and borg laws*/
|
||||
// /client/proc/ghost_pool_protection, /*opens a menu for toggling ghost roles*/
|
||||
/datum/admins/proc/toggleooc, /*toggles ooc on/off for everyone*/
|
||||
/datum/admins/proc/toggleooclocal, /*toggles looc on/off for everyone*/
|
||||
/datum/admins/proc/toggleoocdead, /*toggles ooc on/off for everyone who is dead*/
|
||||
@@ -35,15 +44,15 @@ GLOBAL_PROTECT(admin_verbs_admin)
|
||||
/client/proc/admin_ghost, /*allows us to ghost/reenter body at will*/
|
||||
/client/proc/toggle_view_range, /*changes how far we can see*/
|
||||
/client/proc/getserverlogs, /*for accessing server logs*/
|
||||
/client/proc/cmd_admin_subtle_message, /*send an message to somebody as a 'voice in their head'*/
|
||||
/client/proc/cmd_admin_headset_message, /*send an message to somebody through their headset as CentCom*/
|
||||
/client/proc/getcurrentlogs, /*for accessing server logs for the current round*/
|
||||
/client/proc/cmd_admin_subtle_message, /*send a message to somebody as a 'voice in their head'*/
|
||||
/client/proc/cmd_admin_headset_message, /*send a message to somebody through their headset as CentCom*/
|
||||
/client/proc/cmd_admin_delete, /*delete an instance/object/mob/etc*/
|
||||
/client/proc/cmd_admin_check_contents, /*displays the contents of an instance*/
|
||||
/client/proc/centcom_podlauncher,/*Open a window to launch a Supplypod and configure it or it's contents*/
|
||||
/client/proc/check_antagonists, /*shows all antags*/
|
||||
/datum/admins/proc/access_news_network, /*allows access of newscasters*/
|
||||
/client/proc/jumptocoord, /*we ghost and jump to a coordinate*/
|
||||
/client/proc/getcurrentlogs, /*for accessing server logs for the current round*/
|
||||
/client/proc/Getmob, /*teleports a mob to our location*/
|
||||
/client/proc/Getkey, /*teleports a mob with a certain ckey to our location*/
|
||||
// /client/proc/sendmob, /*sends a mob somewhere*/ -Removed due to it needing two sorting procs to work, which were executed every time an admin right-clicked. ~Errorage
|
||||
@@ -53,6 +62,8 @@ GLOBAL_PROTECT(admin_verbs_admin)
|
||||
/client/proc/jumptoturf, /*allows us to jump to a specific turf*/
|
||||
/client/proc/admin_call_shuttle, /*allows us to call the emergency shuttle*/
|
||||
/client/proc/admin_cancel_shuttle, /*allows us to cancel the emergency shuttle, sending it back to centcom*/
|
||||
// /client/proc/admin_disable_shuttle, /*allows us to disable the emergency shuttle admin-wise so that it cannot be called*/
|
||||
// /client/proc/admin_enable_shuttle, /*undoes the above*/
|
||||
/client/proc/cmd_admin_direct_narrate, /*send text directly to a player with no padding. Useful for narratives and fluff-text*/
|
||||
/client/proc/cmd_admin_world_narrate, /*sends text to all players with no padding*/
|
||||
/client/proc/cmd_admin_local_narrate, /*sends text to all mobs within view of atom*/
|
||||
@@ -64,26 +75,18 @@ GLOBAL_PROTECT(admin_verbs_admin)
|
||||
/client/proc/toggle_combo_hud, // toggle display of the combination pizza antag and taco sci/med/eng hud
|
||||
/client/proc/toggle_AI_interact, /*toggle admin ability to interact with machines as an AI*/
|
||||
/datum/admins/proc/open_shuttlepanel, /* Opens shuttle manipulator UI */
|
||||
/client/proc/deadchat,
|
||||
/client/proc/toggleprayers,
|
||||
// /client/proc/toggle_prayer_sound,
|
||||
// /client/proc/colorasay,
|
||||
// /client/proc/resetasaycolor,
|
||||
/client/proc/toggleadminhelpsound,
|
||||
/client/proc/respawn_character,
|
||||
/client/proc/secrets,
|
||||
/client/proc/toggle_hear_radio, /*allows admins to hide all radio output*/
|
||||
/client/proc/reload_admins,
|
||||
/client/proc/reestablish_db_connection, /*reattempt a connection to the database*/
|
||||
/client/proc/cmd_admin_pm_context, /*right-click adminPM interface*/
|
||||
/client/proc/cmd_admin_pm_panel, /*admin-pm list*/
|
||||
/client/proc/panicbunker,
|
||||
/client/proc/addbunkerbypass,
|
||||
/client/proc/revokebunkerbypass,
|
||||
/client/proc/stop_sounds,
|
||||
/client/proc/mark_datum_mapview,
|
||||
/client/proc/hide_verbs, /*hides all our adminverbs*/
|
||||
/client/proc/hide_most_verbs, /*hides all our hideable adminverbs*/
|
||||
/datum/admins/proc/open_borgopanel,
|
||||
/client/proc/admin_cmd_respawn_return_to_lobby,
|
||||
/client/proc/admin_cmd_remove_ghost_respawn_timer
|
||||
/client/proc/admin_cmd_respawn_return_to_lobby, //CIT
|
||||
/client/proc/admin_cmd_remove_ghost_respawn_timer, //CIT
|
||||
/datum/admins/proc/open_borgopanel
|
||||
)
|
||||
|
||||
GLOBAL_LIST_INIT(admin_verbs_ban, list(/client/proc/unban_panel, /client/proc/DB_ban_panel, /client/proc/stickybanpanel))
|
||||
GLOBAL_LIST_INIT(admin_verbs_ban, list(/client/proc/DB_ban_panel, /client/proc/stickybanpanel))
|
||||
GLOBAL_PROTECT(admin_verbs_ban)
|
||||
GLOBAL_LIST_INIT(admin_verbs_sounds, list(/client/proc/play_local_sound, /client/proc/play_sound, /client/proc/manual_play_web_sound, /client/proc/set_round_end_sound))
|
||||
GLOBAL_PROTECT(admin_verbs_sounds)
|
||||
@@ -110,13 +113,14 @@ GLOBAL_LIST_INIT(admin_verbs_fun, list(
|
||||
/client/proc/show_tip,
|
||||
/client/proc/smite,
|
||||
/client/proc/admin_away,
|
||||
/client/proc/cmd_admin_toggle_fov,
|
||||
/client/proc/cmd_admin_toggle_fov, //CIT CHANGE - FOV
|
||||
/client/proc/roll_dices //CIT CHANGE - Adds dice verb
|
||||
))
|
||||
GLOBAL_PROTECT(admin_verbs_fun)
|
||||
GLOBAL_LIST_INIT(admin_verbs_spawn, list(/datum/admins/proc/spawn_atom, /datum/admins/proc/podspawn_atom, /datum/admins/proc/spawn_cargo, /datum/admins/proc/spawn_objasmob, /client/proc/respawn_character))
|
||||
GLOBAL_PROTECT(admin_verbs_spawn)
|
||||
GLOBAL_LIST_INIT(admin_verbs_server, world.AVerbsServer())
|
||||
GLOBAL_PROTECT(admin_verbs_server)
|
||||
/world/proc/AVerbsServer()
|
||||
return list(
|
||||
/datum/admins/proc/startnow,
|
||||
@@ -126,17 +130,22 @@ GLOBAL_LIST_INIT(admin_verbs_server, world.AVerbsServer())
|
||||
/datum/admins/proc/toggleaban,
|
||||
/client/proc/everyone_random,
|
||||
/datum/admins/proc/toggleAI,
|
||||
/datum/admins/proc/toggleMulticam,
|
||||
/datum/admins/proc/toggledynamicvote,
|
||||
/datum/admins/proc/toggleMulticam, //CIT
|
||||
/datum/admins/proc/toggledynamicvote, //CIT
|
||||
/client/proc/cmd_admin_delete, /*delete an instance/object/mob/etc*/
|
||||
/client/proc/cmd_debug_del_all,
|
||||
/client/proc/toggle_random_events,
|
||||
/client/proc/forcerandomrotate,
|
||||
/client/proc/adminchangemap,
|
||||
/client/proc/toggle_hub
|
||||
/client/proc/panicbunker,
|
||||
/client/proc/addbunkerbypass, //CIT
|
||||
/client/proc/revokebunkerbypass, //CIT
|
||||
// /client/proc/toggle_interviews,
|
||||
/client/proc/toggle_hub,
|
||||
/client/proc/toggle_cdn
|
||||
)
|
||||
GLOBAL_PROTECT(admin_verbs_server)
|
||||
GLOBAL_LIST_INIT(admin_verbs_debug, world.AVerbsDebug())
|
||||
GLOBAL_PROTECT(admin_verbs_debug)
|
||||
/world/proc/AVerbsDebug()
|
||||
return list(
|
||||
/client/proc/restart_controller,
|
||||
@@ -174,27 +183,37 @@ GLOBAL_LIST_INIT(admin_verbs_debug, world.AVerbsDebug())
|
||||
/client/proc/cmd_display_init_log,
|
||||
/client/proc/cmd_display_overlay_log,
|
||||
/client/proc/reload_configuration,
|
||||
// /client/proc/atmos_control,
|
||||
// /client/proc/reload_cards,
|
||||
// /client/proc/validate_cards,
|
||||
// /client/proc/test_cardpack_distribution,
|
||||
// /client/proc/print_cards,
|
||||
#ifdef TESTING
|
||||
/client/proc/check_missing_sprites,
|
||||
#endif
|
||||
/datum/admins/proc/create_or_modify_area,
|
||||
#ifdef REFERENCE_TRACKING
|
||||
/datum/admins/proc/view_refs,
|
||||
/datum/admins/proc/view_del_failures,
|
||||
#endif
|
||||
/client/proc/generate_wikichem_list, //DO NOT PRESS UNLESS YOU WANT SUPERLAG
|
||||
// /client/proc/check_timer_sources,
|
||||
/client/proc/toggle_cdn,
|
||||
/client/proc/generate_wikichem_list //DO NOT PRESS UNLESS YOU WANT SUPERLAG
|
||||
)
|
||||
GLOBAL_PROTECT(admin_verbs_debug)
|
||||
GLOBAL_LIST_INIT(admin_verbs_possess, list(/proc/possess, /proc/release))
|
||||
GLOBAL_PROTECT(admin_verbs_possess)
|
||||
GLOBAL_LIST_INIT(admin_verbs_permissions, list(/client/proc/edit_admin_permissions))
|
||||
GLOBAL_PROTECT(admin_verbs_permissions)
|
||||
GLOBAL_LIST_INIT(admin_verbs_poll, list(/client/proc/create_poll))
|
||||
GLOBAL_PROTECT(admin_verbs_poll)
|
||||
|
||||
//verbs which can be hidden - needs work
|
||||
GLOBAL_PROTECT(admin_verbs_poll)
|
||||
GLOBAL_LIST_INIT(admin_verbs_hideable, list(
|
||||
/client/proc/set_ooc,
|
||||
/client/proc/reset_ooc,
|
||||
/client/proc/deadmin,
|
||||
/datum/admins/proc/show_traitor_panel,
|
||||
// /datum/admins/proc/show_skill_panel,
|
||||
/datum/admins/proc/toggleenter,
|
||||
/datum/admins/proc/toggleguests,
|
||||
/datum/admins/proc/announce,
|
||||
@@ -239,7 +258,7 @@ GLOBAL_LIST_INIT(admin_verbs_hideable, list(
|
||||
/client/proc/Debug2,
|
||||
/client/proc/reload_admins,
|
||||
/client/proc/cmd_debug_make_powernets,
|
||||
/client/proc/startSinglo,
|
||||
/client/proc/startSinglo, // tg removed this
|
||||
/client/proc/cmd_debug_mob_lists,
|
||||
/client/proc/cmd_debug_del_all,
|
||||
/client/proc/enable_debug_verbs,
|
||||
@@ -247,8 +266,9 @@ GLOBAL_LIST_INIT(admin_verbs_hideable, list(
|
||||
/proc/release,
|
||||
/client/proc/reload_admins,
|
||||
/client/proc/panicbunker,
|
||||
/client/proc/addbunkerbypass,
|
||||
/client/proc/revokebunkerbypass,
|
||||
/client/proc/addbunkerbypass, //CIT
|
||||
/client/proc/revokebunkerbypass, //CIT
|
||||
// /client/proc/toggle_interviews,
|
||||
/client/proc/admin_change_sec_level,
|
||||
/client/proc/toggle_nuke,
|
||||
/client/proc/cmd_display_del_log,
|
||||
@@ -322,7 +342,7 @@ GLOBAL_PROTECT(admin_verbs_hideable)
|
||||
remove_verb(src, /client/proc/hide_most_verbs)
|
||||
add_verb(src, /client/proc/show_verbs)
|
||||
|
||||
to_chat(src, "<span class='interface'>Most of your adminverbs have been hidden.</span>")
|
||||
to_chat(src, "<span class='interface'>Most of your adminverbs have been hidden.</span>", confidential = TRUE)
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Hide Most Adminverbs") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
return
|
||||
|
||||
@@ -333,7 +353,7 @@ GLOBAL_PROTECT(admin_verbs_hideable)
|
||||
remove_admin_verbs()
|
||||
add_verb(src, /client/proc/show_verbs)
|
||||
|
||||
to_chat(src, "<span class='interface'>Almost all of your adminverbs have been hidden.</span>")
|
||||
to_chat(src, "<span class='interface'>Almost all of your adminverbs have been hidden.</span>", confidential = TRUE)
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Hide All Adminverbs") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
return
|
||||
|
||||
@@ -344,7 +364,7 @@ GLOBAL_PROTECT(admin_verbs_hideable)
|
||||
remove_verb(src, /client/proc/show_verbs)
|
||||
add_admin_verbs()
|
||||
|
||||
to_chat(src, "<span class='interface'>All of your adminverbs are now visible.</span>")
|
||||
to_chat(src, "<span class='interface'>All of your adminverbs are now visible.</span>", confidential = TRUE)
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Show Adminverbs") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
|
||||
@@ -354,7 +374,8 @@ GLOBAL_PROTECT(admin_verbs_hideable)
|
||||
set category = "Admin.Game"
|
||||
set name = "Aghost"
|
||||
if(!holder)
|
||||
return FALSE
|
||||
return
|
||||
. = TRUE
|
||||
if(isobserver(mob))
|
||||
//re-enter
|
||||
var/mob/dead/observer/ghost = mob
|
||||
@@ -367,7 +388,7 @@ GLOBAL_PROTECT(admin_verbs_hideable)
|
||||
ghost.reenter_corpse()
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Admin Reenter") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
else if(isnewplayer(mob))
|
||||
to_chat(src, "<font color='red'>Error: Aghost: Can't admin-ghost whilst in the lobby. Join or Observe first.</font>")
|
||||
to_chat(src, "<font color='red'>Error: Aghost: Can't admin-ghost whilst in the lobby. Join or Observe first.</font>", confidential = TRUE)
|
||||
return FALSE
|
||||
else
|
||||
//ghostize
|
||||
@@ -375,10 +396,10 @@ GLOBAL_PROTECT(admin_verbs_hideable)
|
||||
message_admins("[key_name_admin(usr)] admin ghosted.")
|
||||
var/mob/body = mob
|
||||
body.ghostize(1, voluntary = TRUE)
|
||||
init_verbs()
|
||||
if(body && !body.key)
|
||||
body.key = "@[key]" //Haaaaaaaack. But the people have spoken. If it breaks; blame adminbus
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Admin Ghost") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
return TRUE
|
||||
|
||||
/client/proc/invisimin()
|
||||
set name = "Invisimin"
|
||||
@@ -387,10 +408,10 @@ GLOBAL_PROTECT(admin_verbs_hideable)
|
||||
if(holder && mob)
|
||||
if(mob.invisibility == INVISIBILITY_OBSERVER)
|
||||
mob.invisibility = initial(mob.invisibility)
|
||||
to_chat(mob, "<span class='boldannounce'>Invisimin off. Invisibility reset.</span>")
|
||||
to_chat(mob, "<span class='boldannounce'>Invisimin off. Invisibility reset.</span>", confidential = TRUE)
|
||||
else
|
||||
mob.invisibility = INVISIBILITY_OBSERVER
|
||||
to_chat(mob, "<span class='adminnotice'><b>Invisimin on. You are now as invisible as a ghost.</b></span>")
|
||||
to_chat(mob, "<span class='adminnotice'><b>Invisimin on. You are now as invisible as a ghost.</b></span>", confidential = TRUE)
|
||||
|
||||
/client/proc/check_antagonists()
|
||||
set name = "Check Antagonists"
|
||||
@@ -402,15 +423,21 @@ GLOBAL_PROTECT(admin_verbs_hideable)
|
||||
message_admins("[key_name_admin(usr)] checked antagonists.")
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Check Antagonists") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/client/proc/unban_panel()
|
||||
set name = "Unban Panel"
|
||||
set category = "Admin"
|
||||
if(holder)
|
||||
if(CONFIG_GET(flag/ban_legacy_system))
|
||||
holder.unbanpanel()
|
||||
else
|
||||
holder.DB_ban_panel()
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Unban Panel") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
// /client/proc/ban_panel()
|
||||
// set name = "Banning Panel"
|
||||
// set category = "Admin"
|
||||
// if(!check_rights(R_BAN))
|
||||
// return
|
||||
// holder.ban_panel()
|
||||
// SSblackbox.record_feedback("tally", "admin_verb", 1, "Banning Panel") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
// /client/proc/unban_panel()
|
||||
// set name = "Unbanning Panel"
|
||||
// set category = "Admin"
|
||||
// if(!check_rights(R_BAN))
|
||||
// return
|
||||
// holder.unban_panel()
|
||||
// SSblackbox.record_feedback("tally", "admin_verb", 1, "Unbanning Panel") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/client/proc/game_panel()
|
||||
set name = "Game Panel"
|
||||
@@ -419,13 +446,13 @@ GLOBAL_PROTECT(admin_verbs_hideable)
|
||||
holder.Game()
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Game Panel") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/client/proc/secrets()
|
||||
set name = "Secrets"
|
||||
set category = "Admin.Game"
|
||||
if (holder)
|
||||
holder.Secrets()
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Secrets Panel") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
// /client/proc/poll_panel()
|
||||
// set name = "Server Poll Management"
|
||||
// set category = "Admin"
|
||||
// if(!check_rights(R_POLL))
|
||||
// return
|
||||
// holder.poll_list_panel()
|
||||
// SSblackbox.record_feedback("tally", "admin_verb", 1, "Server Poll Management") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/client/proc/findStealthKey(txt)
|
||||
if(txt)
|
||||
@@ -457,7 +484,10 @@ GLOBAL_PROTECT(admin_verbs_hideable)
|
||||
if(isobserver(mob))
|
||||
mob.invisibility = initial(mob.invisibility)
|
||||
mob.alpha = initial(mob.alpha)
|
||||
mob.name = initial(mob.name)
|
||||
if(mob.mind)
|
||||
mob.name = mob.mind.name
|
||||
else
|
||||
mob.name = mob.real_name
|
||||
mob.mouse_opacity = initial(mob.mouse_opacity)
|
||||
else
|
||||
var/new_key = ckeyEx(stripped_input(usr, "Enter your desired display name.", "Fake Key", key, 26))
|
||||
@@ -485,7 +515,7 @@ GLOBAL_PROTECT(admin_verbs_hideable)
|
||||
|
||||
switch(choice)
|
||||
if(null)
|
||||
return 0
|
||||
return
|
||||
if("Small Bomb (1, 2, 3, 3)")
|
||||
explosion(epicenter, 1, 2, 3, 3, TRUE, TRUE)
|
||||
if("Medium Bomb (2, 3, 4, 4)")
|
||||
@@ -538,7 +568,7 @@ GLOBAL_PROTECT(admin_verbs_hideable)
|
||||
if (isnull(ex_power))
|
||||
return
|
||||
var/range = round((2 * ex_power)**GLOB.DYN_EX_SCALE)
|
||||
to_chat(usr, "Estimated Explosive Range: (Devastation: [round(range*0.25)], Heavy: [round(range*0.5)], Light: [round(range)])")
|
||||
to_chat(usr, "Estimated Explosive Range: (Devastation: [round(range*0.25)], Heavy: [round(range*0.5)], Light: [round(range)])", confidential = TRUE)
|
||||
|
||||
/client/proc/get_dynex_power()
|
||||
set category = "Debug"
|
||||
@@ -549,7 +579,7 @@ GLOBAL_PROTECT(admin_verbs_hideable)
|
||||
if (isnull(ex_range))
|
||||
return
|
||||
var/power = (0.5 * ex_range)**(1/GLOB.DYN_EX_SCALE)
|
||||
to_chat(usr, "Estimated Explosive Power: [power]")
|
||||
to_chat(usr, "Estimated Explosive Power: [power]", confidential = TRUE)
|
||||
|
||||
/client/proc/set_dynex_scale()
|
||||
set category = "Debug"
|
||||
@@ -563,6 +593,55 @@ GLOBAL_PROTECT(admin_verbs_hideable)
|
||||
log_admin("[key_name(usr)] has modified Dynamic Explosion Scale: [ex_scale]")
|
||||
message_admins("[key_name_admin(usr)] has modified Dynamic Explosion Scale: [ex_scale]")
|
||||
|
||||
// /client/proc/atmos_control()
|
||||
// set name = "Atmos Control Panel"
|
||||
// set category = "Debug"
|
||||
// if(!check_rights(R_DEBUG))
|
||||
// return
|
||||
// SSair.ui_interact(mob)
|
||||
|
||||
// /client/proc/reload_cards()
|
||||
// set name = "Reload Cards"
|
||||
// set category = "Debug"
|
||||
// if(!check_rights(R_DEBUG))
|
||||
// return
|
||||
// if(!SStrading_card_game.loaded)
|
||||
// message_admins("The card subsystem is not currently loaded")
|
||||
// return
|
||||
// reloadAllCardFiles(SStrading_card_game.card_files, SStrading_card_game.card_directory)
|
||||
|
||||
// /client/proc/validate_cards()
|
||||
// set name = "Validate Cards"
|
||||
// set category = "Debug"
|
||||
// if(!check_rights(R_DEBUG))
|
||||
// return
|
||||
// if(!SStrading_card_game.loaded)
|
||||
// message_admins("The card subsystem is not currently loaded")
|
||||
// return
|
||||
// var/message = checkCardpacks(SStrading_card_game.card_packs)
|
||||
// message += checkCardDatums()
|
||||
// if(message)
|
||||
// message_admins(message)
|
||||
|
||||
// /client/proc/test_cardpack_distribution()
|
||||
// set name = "Test Cardpack Distribution"
|
||||
// set category = "Debug"
|
||||
// if(!check_rights(R_DEBUG))
|
||||
// return
|
||||
// if(!SStrading_card_game.loaded)
|
||||
// message_admins("The card subsystem is not currently loaded")
|
||||
// return
|
||||
// var/pack = input("Which pack should we test?", "You fucked it didn't you") as null|anything in sortList(SStrading_card_game.card_packs)
|
||||
// var/batchCount = input("How many times should we open it?", "Don't worry, I understand") as null|num
|
||||
// var/batchSize = input("How many cards per batch?", "I hope you remember to check the validation") as null|num
|
||||
// var/guar = input("Should we use the pack's guaranteed rarity? If so, how many?", "We've all been there. Man you should have seen the old system") as null|num
|
||||
// checkCardDistribution(pack, batchSize, batchCount, guar)
|
||||
|
||||
// /client/proc/print_cards()
|
||||
// set name = "Print Cards"
|
||||
// set category = "Debug"
|
||||
// printAllCards()
|
||||
|
||||
/client/proc/give_spell(mob/T in GLOB.mob_list)
|
||||
set category = "Admin.Fun"
|
||||
set name = "Give Spell"
|
||||
@@ -572,13 +651,13 @@ GLOBAL_PROTECT(admin_verbs_hideable)
|
||||
var/type_length = length_char("/obj/effect/proc_holder/spell") + 2
|
||||
for(var/A in GLOB.spells)
|
||||
spell_list[copytext_char("[A]", type_length)] = A
|
||||
var/obj/effect/proc_holder/spell/S = input("Choose the spell to give to that guy", "ABRAKADABRA") as null|anything in spell_list
|
||||
var/obj/effect/proc_holder/spell/S = input("Choose the spell to give to that guy", "ABRAKADABRA") as null|anything in sortList(spell_list)
|
||||
if(!S)
|
||||
return
|
||||
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Give Spell") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
log_admin("[key_name(usr)] gave [key_name(T)] the spell [S].")
|
||||
message_admins("<span class='adminnotice'>[key_name_admin(usr)] gave [key_name(T)] the spell [S].</span>")
|
||||
message_admins("<span class='adminnotice'>[key_name_admin(usr)] gave [key_name_admin(T)] the spell [S].</span>")
|
||||
|
||||
S = spell_list[S]
|
||||
if(T.mind)
|
||||
@@ -592,12 +671,12 @@ GLOBAL_PROTECT(admin_verbs_hideable)
|
||||
set name = "Remove Spell"
|
||||
set desc = "Remove a spell from the selected mob."
|
||||
|
||||
if(T && T.mind)
|
||||
var/obj/effect/proc_holder/spell/S = input("Choose the spell to remove", "NO ABRAKADABRA") as null|anything in T.mind.spell_list
|
||||
if(T?.mind)
|
||||
var/obj/effect/proc_holder/spell/S = input("Choose the spell to remove", "NO ABRAKADABRA") as null|anything in sortList(T.mind.spell_list)
|
||||
if(S)
|
||||
T.mind.RemoveSpell(S)
|
||||
log_admin("[key_name(usr)] removed the spell [S] from [key_name(T)].")
|
||||
message_admins("<span class='adminnotice'>[key_name_admin(usr)] removed the spell [S] from [key_name(T)].</span>")
|
||||
message_admins("<span class='adminnotice'>[key_name_admin(usr)] removed the spell [S] from [key_name_admin(T)].</span>")
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Remove Spell") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/client/proc/give_disease(mob/living/T in GLOB.mob_living_list)
|
||||
@@ -605,15 +684,15 @@ GLOBAL_PROTECT(admin_verbs_hideable)
|
||||
set name = "Give Disease"
|
||||
set desc = "Gives a Disease to a mob."
|
||||
if(!istype(T))
|
||||
to_chat(src, "<span class='notice'>You can only give a disease to a mob of type /mob/living.</span>")
|
||||
to_chat(src, "<span class='notice'>You can only give a disease to a mob of type /mob/living.</span>", confidential = TRUE)
|
||||
return
|
||||
var/datum/disease/D = input("Choose the disease to give to that guy", "ACHOO") as null|anything in SSdisease.diseases
|
||||
var/datum/disease/D = input("Choose the disease to give to that guy", "ACHOO") as null|anything in sortList(SSdisease.diseases, /proc/cmp_typepaths_asc)
|
||||
if(!D)
|
||||
return
|
||||
T.ForceContractDisease(new D, FALSE, TRUE)
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Give Disease") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
log_admin("[key_name(usr)] gave [key_name(T)] the disease [D].")
|
||||
message_admins("<span class='adminnotice'>[key_name_admin(usr)] gave [key_name(T)] the disease [D].</span>")
|
||||
message_admins("<span class='adminnotice'>[key_name_admin(usr)] gave [key_name_admin(T)] the disease [D].</span>")
|
||||
|
||||
/client/proc/object_say(obj/O in world)
|
||||
set category = "Admin.Events"
|
||||
@@ -655,8 +734,8 @@ GLOBAL_PROTECT(admin_verbs_hideable)
|
||||
holder.deactivate()
|
||||
|
||||
to_chat(src, "<span class='interface'>You are now a normal player.</span>")
|
||||
log_admin("[src] deadmined themself.")
|
||||
message_admins("[src] deadmined themself.")
|
||||
log_admin("[src] deadminned themselves.")
|
||||
message_admins("[src] deadminned themselves.")
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Deadmin")
|
||||
|
||||
/client/proc/readmin()
|
||||
@@ -679,7 +758,7 @@ GLOBAL_PROTECT(admin_verbs_hideable)
|
||||
if (!holder)
|
||||
return //This can happen if an admin attempts to vv themself into somebody elses's deadmin datum by getting ref via brute force
|
||||
|
||||
to_chat(src, "<span class='interface'>You are now an admin.</span>")
|
||||
to_chat(src, "<span class='interface'>You are now an admin.</span>", confidential = TRUE)
|
||||
message_admins("[src] re-adminned themselves.")
|
||||
log_admin("[src] re-adminned themselves.")
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Readmin")
|
||||
|
||||
@@ -28,6 +28,8 @@ GLOBAL_PROTECT(href_token)
|
||||
|
||||
var/deadmined
|
||||
|
||||
var/datum/filter_editor/filteriffic
|
||||
|
||||
/datum/admins/CanProcCall(procname)
|
||||
. = ..()
|
||||
if(!check_rights(R_SENSITIVE))
|
||||
|
||||
@@ -2500,9 +2500,6 @@
|
||||
break
|
||||
return
|
||||
|
||||
else if(href_list["secrets"])
|
||||
Secrets_topic(href_list["secrets"],href_list)
|
||||
|
||||
else if(href_list["ac_view_wanted"]) //Admin newscaster Topic() stuff be here
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
|
||||
@@ -790,11 +790,12 @@
|
||||
if(!check_rights(R_DEBUG))
|
||||
return
|
||||
|
||||
SSmedals.hub_enabled = !SSmedals.hub_enabled
|
||||
SSachievements.achievements_enabled = !SSachievements.achievements_enabled
|
||||
|
||||
message_admins("<span class='adminnotice'>[key_name_admin(src)] [SSmedals.hub_enabled ? "disabled" : "enabled"] the medal hub lockout.</span>")
|
||||
message_admins("<span class='adminnotice'>[key_name_admin(src)] [SSachievements.achievements_enabled ? "disabled" : "enabled"] the medal hub lockout.</span>")
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Toggle Medal Disable") // If...
|
||||
log_admin("[key_name(src)] [SSmedals.hub_enabled ? "disabled" : "enabled"] the medal hub lockout.")
|
||||
log_admin("[key_name(src)] [SSachievements.achievements_enabled ? "disabled" : "enabled"] the medal hub lockout.")
|
||||
|
||||
|
||||
/client/proc/view_runtimes()
|
||||
set category = "Debug"
|
||||
|
||||
@@ -63,3 +63,31 @@
|
||||
load_admins()
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Reload All Admins") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
message_admins("[key_name_admin(usr)] manually reloaded admins")
|
||||
|
||||
/client/proc/toggle_cdn()
|
||||
set name = "Toggle CDN"
|
||||
set category = "Server"
|
||||
var/static/admin_disabled_cdn_transport = null
|
||||
if (alert(usr, "Are you sure you want to toggle the CDN asset transport?", "Confirm", "Yes", "No") != "Yes")
|
||||
return
|
||||
var/current_transport = CONFIG_GET(string/asset_transport)
|
||||
if (!current_transport || current_transport == "simple")
|
||||
if (admin_disabled_cdn_transport)
|
||||
CONFIG_SET(string/asset_transport, admin_disabled_cdn_transport)
|
||||
admin_disabled_cdn_transport = null
|
||||
SSassets.OnConfigLoad()
|
||||
message_admins("[key_name_admin(usr)] re-enabled the CDN asset transport")
|
||||
log_admin("[key_name(usr)] re-enabled the CDN asset transport")
|
||||
else
|
||||
to_chat(usr, "<span class='adminnotice'>The CDN is not enabled!</span>")
|
||||
if (alert(usr, "The CDN asset transport is not enabled! If you having issues with assets you can also try disabling filename mutations.", "The CDN asset transport is not enabled!", "Try disabling filename mutations", "Nevermind") == "Try disabling filename mutations")
|
||||
SSassets.transport.dont_mutate_filenames = !SSassets.transport.dont_mutate_filenames
|
||||
message_admins("[key_name_admin(usr)] [(SSassets.transport.dont_mutate_filenames ? "disabled" : "re-enabled")] asset filename transforms")
|
||||
log_admin("[key_name(usr)] [(SSassets.transport.dont_mutate_filenames ? "disabled" : "re-enabled")] asset filename transforms")
|
||||
else
|
||||
admin_disabled_cdn_transport = current_transport
|
||||
CONFIG_SET(string/asset_transport, "simple")
|
||||
SSassets.OnConfigLoad()
|
||||
SSassets.transport.dont_mutate_filenames = TRUE
|
||||
message_admins("[key_name_admin(usr)] disabled the CDN asset transport")
|
||||
log_admin("[key_name(usr)] disabled the CDN asset transport")
|
||||
|
||||
99
code/modules/admin/view_variables/filterrific.dm
Normal file
@@ -0,0 +1,99 @@
|
||||
/datum/filter_editor
|
||||
var/atom/target
|
||||
|
||||
/datum/filter_editor/New(atom/target)
|
||||
src.target = target
|
||||
|
||||
/datum/filter_editor/ui_state(mob/user)
|
||||
return GLOB.admin_state
|
||||
|
||||
/datum/filter_editor/ui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, "Filteriffic")
|
||||
ui.open()
|
||||
|
||||
/datum/filter_editor/ui_static_data(mob/user)
|
||||
var/list/data = list()
|
||||
data["filter_info"] = GLOB.master_filter_info
|
||||
return data
|
||||
|
||||
/datum/filter_editor/ui_data()
|
||||
var/list/data = list()
|
||||
data["target_name"] = target.name
|
||||
data["target_filter_data"] = target.filter_data
|
||||
return data
|
||||
|
||||
/datum/filter_editor/ui_act(action, list/params)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
|
||||
switch(action)
|
||||
if("add_filter")
|
||||
var/target_name = params["name"]
|
||||
while(target.filter_data && target.filter_data[target_name])
|
||||
target_name = "[target_name]-dupe"
|
||||
target.add_filter(target_name, params["priority"], list("type" = params["type"]))
|
||||
. = TRUE
|
||||
if("remove_filter")
|
||||
target.remove_filter(params["name"])
|
||||
. = TRUE
|
||||
if("rename_filter")
|
||||
var/list/filter_data = target.filter_data[params["name"]]
|
||||
target.remove_filter(params["name"])
|
||||
target.add_filter(params["new_name"], filter_data["priority"], filter_data)
|
||||
. = TRUE
|
||||
if("edit_filter")
|
||||
target.remove_filter(params["name"])
|
||||
target.add_filter(params["name"], params["priority"], params["new_filter"])
|
||||
. = TRUE
|
||||
if("change_priority")
|
||||
var/new_priority = params["new_priority"]
|
||||
target.change_filter_priority(params["name"], new_priority)
|
||||
. = TRUE
|
||||
if("transition_filter_value")
|
||||
target.transition_filter(params["name"], 4, params["new_data"])
|
||||
. = TRUE
|
||||
if("modify_filter_value")
|
||||
var/list/old_filter_data = target.filter_data[params["name"]]
|
||||
var/list/new_filter_data = old_filter_data.Copy()
|
||||
for(var/entry in params["new_data"])
|
||||
new_filter_data[entry] = params["new_data"][entry]
|
||||
for(var/entry in new_filter_data)
|
||||
if(entry == GLOB.master_filter_info[old_filter_data["type"]]["defaults"][entry])
|
||||
new_filter_data.Remove(entry)
|
||||
target.remove_filter(params["name"])
|
||||
target.add_filter(params["name"], old_filter_data["priority"], new_filter_data)
|
||||
. = TRUE
|
||||
if("modify_color_value")
|
||||
var/new_color = input(usr, "Pick new filter color", "Filteriffic Colors!") as color|null
|
||||
if(new_color)
|
||||
target.transition_filter(params["name"], 4, list("color" = new_color))
|
||||
. = TRUE
|
||||
if("modify_icon_value")
|
||||
var/icon/new_icon = input("Pick icon:", "Icon") as null|icon
|
||||
if(new_icon)
|
||||
target.filter_data[params["name"]]["icon"] = new_icon
|
||||
target.update_filters()
|
||||
. = TRUE
|
||||
if("mass_apply")
|
||||
if(!check_rights_for(usr.client, R_FUN))
|
||||
to_chat(usr, "<span class='userdanger>Stay in your lane, jannie.</span>'")
|
||||
return
|
||||
var/target_path = text2path(params["path"])
|
||||
if(!target_path)
|
||||
return
|
||||
var/filters_to_copy = target.filters
|
||||
var/filter_data_to_copy = target.filter_data
|
||||
var/count = 0
|
||||
for(var/thing in world.contents)
|
||||
if(istype(thing, target_path))
|
||||
var/atom/thing_at = thing
|
||||
thing_at.filters = filters_to_copy
|
||||
thing_at.filter_data = filter_data_to_copy
|
||||
count += 1
|
||||
message_admins("LOCAL CLOWN [usr.ckey] JUST MASS FILTER EDITED [count] WITH PATH OF [params["path"]]!")
|
||||
log_admin("LOCAL CLOWN [usr.ckey] JUST MASS FILTER EDITED [count] WITH PATH OF [params["path"]]!")
|
||||
|
||||
|
||||
@@ -5,10 +5,13 @@
|
||||
|
||||
var/method = 0 //0 means strict type detection while 1 means this type and all subtypes (IE: /obj/item with this set to 1 will set it to ALL items)
|
||||
|
||||
// if(tgui_alert(src, "Are you sure you'd like to mass-modify every instance of the [var_name] variable? This can break everything if you do not know what you are doing.", "Slow down, chief!", list("Yes", "No")) != "Yes")
|
||||
// return
|
||||
|
||||
if(!check_rights(R_VAREDIT))
|
||||
return
|
||||
|
||||
if(A && A.type)
|
||||
if(A?.type)
|
||||
method = vv_subtype_prompt(A.type)
|
||||
|
||||
src.massmodify_variables(A, var_name, method)
|
||||
@@ -114,7 +117,7 @@
|
||||
var/list/varsvars = vv_parse_text(O, new_value)
|
||||
var/pre_processing = new_value
|
||||
var/unique
|
||||
if (varsvars && varsvars.len)
|
||||
if (varsvars?.len)
|
||||
unique = alert(usr, "Process vars unique to each instance, or same for all?", "Variable Association", "Unique", "Same")
|
||||
if(unique == "Unique")
|
||||
unique = TRUE
|
||||
|
||||
@@ -23,7 +23,7 @@ GLOBAL_PROTECT(VVpixelmovement)
|
||||
var/list/subtypes = subtypesof(type)
|
||||
if (!subtypes || !subtypes.len)
|
||||
return FALSE
|
||||
if (subtypes && subtypes.len)
|
||||
if (subtypes?.len)
|
||||
switch(alert("Strict object type detection?", "Type detection", "Strictly this type","This type and subtypes", "Cancel"))
|
||||
if("Strictly this type")
|
||||
return FALSE
|
||||
|
||||
@@ -29,6 +29,12 @@
|
||||
return
|
||||
|
||||
var/new_name = stripped_input(usr,"What would you like to name this mob?","Input a name",M.real_name,MAX_NAME_LEN)
|
||||
|
||||
// If the new name is something that would be restricted by IC chat filters,
|
||||
// give the admin a warning but allow them to do it anyway if they want.
|
||||
// if(CHAT_FILTER_CHECK(new_name) && alert(usr, "Your selected name contains words restricted by IC chat filters. Confirm this new name?", "IC Chat Filter Conflict", "Confirm", "Cancel") == "Cancel")
|
||||
// return
|
||||
|
||||
if( !new_name || !M )
|
||||
return
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
usr.client.debug_variables(src)
|
||||
return
|
||||
|
||||
#ifdef REFERENCE_TRACKING //people with debug can only access this putnam!
|
||||
#ifdef REFERENCE_TRACKING
|
||||
if(href_list[VV_HK_VIEW_REFERENCES])
|
||||
var/datum/D = locate(href_list[VV_HK_TARGET])
|
||||
if(!D)
|
||||
|
||||
@@ -193,7 +193,7 @@
|
||||
var/list/trait_list = list(TRAIT_NOBREATH,TRAIT_RESISTCOLD,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE)
|
||||
|
||||
/datum/eldritch_knowledge/final/ash_final/on_finished_recipe(mob/living/user, list/atoms, loc)
|
||||
priority_announce("$^@&#*$^@(#&$(@&#^$&#^@# Fear the blaze, for Ashbringer [user.real_name] has come! $^@&#*$^@(#&$(@&#^$&#^@#","#$^@&#*$^@(#&$(@&#^$&#^@#", 'sound/announcer/classic/spanomalies.ogg')
|
||||
priority_announce("$^@&#*$^@(#&$(@&#^$&#^@# Fear the blaze, for the Ashlord, [user.real_name] has ascended! The flames shall consume all! $^@&#*$^@(#&$(@&#^$&#^@#","#$^@&#*$^@(#&$(@&#^$&#^@#", 'sound/announcer/classic/spanomalies.ogg')
|
||||
user.mind.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/fire_cascade/big)
|
||||
user.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/fire_sworn)
|
||||
var/mob/living/carbon/human/H = user
|
||||
@@ -201,6 +201,7 @@
|
||||
H.physiology.burn_mod *= 0.5
|
||||
var/datum/antagonist/heretic/ascension = H.mind.has_antag_datum(/datum/antagonist/heretic)
|
||||
ascension.ascended = TRUE
|
||||
H.client?.give_award(/datum/award/achievement/misc/ash_ascension, H)
|
||||
for(var/X in trait_list)
|
||||
ADD_TRAIT(user,X,MAGIC_TRAIT)
|
||||
return ..()
|
||||
|
||||
@@ -232,7 +232,7 @@
|
||||
log_game("[key_name_admin(ghost_candidate)] has taken control of ([key_name_admin(summoned)]).")
|
||||
summoned.ghostize(FALSE)
|
||||
summoned.key = ghost_candidate.key
|
||||
summoned.mind.add_antag_datum(/datum/antagonist/heretic_monster)
|
||||
summoned.mind.add_antag_datum(/datum/antagonist/heretic_monster) //no you will NOT get the achivement you ghost.
|
||||
var/datum/antagonist/heretic_monster/monster = summoned.mind.has_antag_datum(/datum/antagonist/heretic_monster)
|
||||
var/datum/antagonist/heretic/master = user.mind.has_antag_datum(/datum/antagonist/heretic)
|
||||
monster.set_owner(master)
|
||||
@@ -243,7 +243,10 @@
|
||||
user.SetImmobilized(0)
|
||||
priority_announce("$^@&#*$^@(#&$(@&#^$&#^@# Fear the dark, for king of arms has ascended! Lord of the night has come! $^@&#*$^@(#&$(@&#^$&#^@#","#$^@&#*$^@(#&$(@&#^$&#^@#", 'sound/announcer/classic/spanomalies.ogg')
|
||||
log_game("[user.real_name] ascended as [summoned.real_name]")
|
||||
var/mob/living/carbon/carbon_user = user
|
||||
if(!ishuman(user))
|
||||
return
|
||||
var/mob/living/carbon/human/H = user
|
||||
H.client?.give_award(/datum/award/achievement/misc/flesh_ascension, H)
|
||||
var/datum/antagonist/heretic/ascension = carbon_user.mind.has_antag_datum(/datum/antagonist/heretic)
|
||||
ascension.ascended = TRUE
|
||||
carbon_user.mind.transfer_to(summoned, TRUE)
|
||||
|
||||
@@ -169,7 +169,8 @@
|
||||
var/mob/living/carbon/human/H = user
|
||||
H.physiology.brute_mod *= 0.5
|
||||
H.physiology.burn_mod *= 0.5
|
||||
priority_announce("$^@&#*$^@(#&$(@&#^$&#^@# Fear the decay, for Rustbringer [user.real_name] has come! $^@&#*$^@(#&$(@&#^$&#^@#","#$^@&#*$^@(#&$(@&#^$&#^@#", 'sound/announcer/classic/spanomalies.ogg')
|
||||
H.client?.give_award(/datum/award/achievement/misc/rust_ascension, H)
|
||||
priority_announce("$^@&#*$^@(#&$(@&#^$&#^@# Fear the decay, for the Rustbringer, [user.real_name] has ascended! None shall escape the corrosion! $^@&#*$^@(#&$(@&#^$&#^@#","#$^@&#*$^@(#&$(@&#^$&#^@#", 'sound/announcer/classic/spanomalies.ogg')
|
||||
new /datum/rust_spread(loc)
|
||||
var/datum/antagonist/heretic/ascension = H.mind.has_antag_datum(/datum/antagonist/heretic)
|
||||
ascension.ascended = TRUE
|
||||
|
||||
@@ -80,7 +80,7 @@
|
||||
if(1000)
|
||||
SpeakPeace(list("The ends exists somewhere beyond meaningful milestones.", "There will be no more messages until then.", "You disgust me."))
|
||||
if(5643)
|
||||
SSmedals.UnlockMedal(MEDAL_TIMEWASTE, user.client)
|
||||
user.client.give_award(/datum/award/achievement/misc/time_waste, user)
|
||||
var/obj/item/reagent_containers/food/drinks/trophy/gold_cup/never_ends = new(get_turf(user))
|
||||
never_ends.name = "Overextending The Joke: First Place"
|
||||
never_ends.desc = "And so we are left alone with our regrets."
|
||||
|
||||
@@ -1009,6 +1009,25 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
|
||||
/client/proc/can_have_part(part_name)
|
||||
return prefs.pref_species.mutant_bodyparts[part_name] || (part_name in GLOB.unlocked_mutant_parts)
|
||||
|
||||
///Redirect proc that makes it easier to call the unlock achievement proc. Achievement type is the typepath to the award, user is the mob getting the award, and value is an optional variable used for leaderboard value increments
|
||||
/client/proc/give_award(achievement_type, mob/user, value = 1)
|
||||
return player_details.achievements.unlock(achievement_type, user, value)
|
||||
|
||||
///Redirect proc that makes it easier to get the status of an achievement. Achievement type is the typepath to the award.
|
||||
/client/proc/get_award_status(achievement_type, mob/user, value = 1)
|
||||
return player_details.achievements.get_achievement_status(achievement_type)
|
||||
|
||||
///Redirect proc that makes it easier to get the status of an achievement. Achievement type is the typepath to the award.
|
||||
/client/proc/award_heart(heart_reason)
|
||||
to_chat(src, "<span class='nicegreen'>Someone awarded you a heart![heart_reason ? " They said: [heart_reason]!" : ""]</span>")
|
||||
if(!src)
|
||||
return
|
||||
prefs.hearted_until = world.realtime + (24 HOURS)
|
||||
prefs.hearted = TRUE
|
||||
if(!src)
|
||||
return
|
||||
prefs.save_preferences()
|
||||
|
||||
/// compiles a full list of verbs and sends it to the browser
|
||||
/client/proc/init_verbs()
|
||||
if(IsAdminAdvancedProcCall())
|
||||
@@ -1048,3 +1067,7 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/client/proc/open_filter_editor(atom/in_atom)
|
||||
if(holder)
|
||||
holder.filteriffic = new /datum/filter_editor(in_atom)
|
||||
holder.filteriffic.ui_interact(mob)
|
||||
|
||||
@@ -3,4 +3,21 @@
|
||||
var/list/logging = list()
|
||||
var/list/post_login_callbacks = list()
|
||||
var/list/post_logout_callbacks = list()
|
||||
var/list/played_names = list() //List of names this key played under this round
|
||||
var/byond_version = "Unknown"
|
||||
var/datum/achievement_data/achievements
|
||||
|
||||
/datum/player_details/New(key)
|
||||
achievements = new(key)
|
||||
|
||||
/proc/log_played_names(ckey, ...)
|
||||
if(!ckey)
|
||||
return
|
||||
if(args.len < 2)
|
||||
return
|
||||
var/list/names = args.Copy(2)
|
||||
var/datum/player_details/P = GLOB.player_details[ckey]
|
||||
if(P)
|
||||
for(var/name in names)
|
||||
if(name)
|
||||
P.played_names |= name
|
||||
|
||||
@@ -160,6 +160,7 @@ In my current plan for it, 'solid' will be defined as anything with density == 1
|
||||
wizard.apply_damage(25, BRUTE)
|
||||
qdel(src)
|
||||
else
|
||||
U.client.give_award(/datum/award/achievement/misc/feat_of_strength, U) //rod-form wizards would probably make this a lot easier to get so keep it to regular rods only
|
||||
U.visible_message("<span class='boldwarning'>[U] suplexes [src] into the ground!</span>", "<span class='warning'>You suplex [src] into the ground!</span>")
|
||||
new /obj/structure/festivus/anchored(drop_location())
|
||||
new /obj/effect/anomaly/flux(drop_location())
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
|
||||
|
||||
/**
|
||||
* The mafia controller handles the mafia minigame in progress.
|
||||
* It is first created when the first ghost signs up to play.
|
||||
*/
|
||||
* The mafia controller handles the mafia minigame in progress.
|
||||
* It is first created when the first ghost signs up to play.
|
||||
*/
|
||||
/datum/mafia_controller
|
||||
///list of observers that should get game updates.
|
||||
var/list/spectators = list()
|
||||
///all roles in the game, dead or alive. check their game status if you only want living or dead.
|
||||
var/list/all_roles = list()
|
||||
///exists to speed up role retrieval, it's a dict. player_role_lookup[player ckey] will give you the role they play
|
||||
///exists to speed up role retrieval, it's a dict. `player_role_lookup[player ckey]` will give you the role they play
|
||||
var/list/player_role_lookup = list()
|
||||
///what part of the game you're playing in. day phases, night phases, judgement phases, etc.
|
||||
var/phase = MAFIA_PHASE_SETUP
|
||||
///how long the game has gone on for, changes with every sunrise. day one, night one, day two, etc.
|
||||
var/turn = 0
|
||||
///for debugging and testing a full game, or adminbuse. If this is not null, it will use this as a setup. clears when game is over
|
||||
///for debugging and testing a full game, or adminbuse. If this is not empty, it will use this as a setup. clears when game is over
|
||||
var/list/custom_setup = list()
|
||||
///first day has no voting, and thus is shorter
|
||||
var/first_day_phase_period = 20 SECONDS
|
||||
@@ -82,20 +82,20 @@
|
||||
qdel(map_deleter)
|
||||
|
||||
/**
|
||||
* Triggers at beginning of the game when there is a confirmed list of valid, ready players.
|
||||
* Creates a 100% ready game that has NOT started (no players in bodies)
|
||||
* Followed by start game
|
||||
*
|
||||
* Does the following:
|
||||
* * Picks map, and loads it
|
||||
* * Grabs landmarks if it is the first time it's loading
|
||||
* * Sets up the role list
|
||||
* * Puts players in each role randomly
|
||||
* Arguments:
|
||||
* * setup_list: list of all the datum setups (fancy list of roles) that would work for the game
|
||||
* * ready_players: list of filtered, sane players (so not playing or disconnected) for the game to put into roles
|
||||
*/
|
||||
/datum/mafia_controller/proc/prepare_game(setup_list, ready_players)
|
||||
* Triggers at beginning of the game when there is a confirmed list of valid, ready players.
|
||||
* Creates a 100% ready game that has NOT started (no players in bodies)
|
||||
* Followed by start game
|
||||
*
|
||||
* Does the following:
|
||||
* * Picks map, and loads it
|
||||
* * Grabs landmarks if it is the first time it's loading
|
||||
* * Sets up the role list
|
||||
* * Puts players in each role randomly
|
||||
* Arguments:
|
||||
* * setup_list: list of all the datum setups (fancy list of roles) that would work for the game
|
||||
* * ready_players: list of filtered, sane players (so not playing or disconnected) for the game to put into roles
|
||||
*/
|
||||
/datum/mafia_controller/proc/prepare_game(setup_list,ready_players)
|
||||
|
||||
var/list/possible_maps = subtypesof(/datum/map_template/mafia)
|
||||
var/turf/spawn_area = get_turf(locate(/obj/effect/landmark/mafia_game_area) in GLOB.landmarks_list)
|
||||
@@ -166,23 +166,23 @@
|
||||
to_chat(M, "[link] MAFIA: [msg] [team_suffix]")
|
||||
|
||||
/**
|
||||
* The game by this point is now all set up, and so we can put people in their bodies and start the first phase.
|
||||
*
|
||||
* Does the following:
|
||||
* * Creates bodies for all of the roles with the first proc
|
||||
* * Starts the first day manually (so no timer) with the second proc
|
||||
*/
|
||||
* The game by this point is now all set up, and so we can put people in their bodies and start the first phase.
|
||||
*
|
||||
* Does the following:
|
||||
* * Creates bodies for all of the roles with the first proc
|
||||
* * Starts the first day manually (so no timer) with the second proc
|
||||
*/
|
||||
/datum/mafia_controller/proc/start_game()
|
||||
create_bodies()
|
||||
start_day()
|
||||
|
||||
/**
|
||||
* How every day starts.
|
||||
*
|
||||
* What players do in this phase:
|
||||
* * If day one, just a small starting period to see who is in the game and check role, leading to the night phase.
|
||||
* * Otherwise, it's a longer period used to discuss events that happened during the night, leading to the voting phase.
|
||||
*/
|
||||
* How every day starts.
|
||||
*
|
||||
* What players do in this phase:
|
||||
* * If day one, just a small starting period to see who is in the game and check role, leading to the night phase.
|
||||
* * Otherwise, it's a longer period used to discuss events that happened during the night, leading to the voting phase.
|
||||
*/
|
||||
/datum/mafia_controller/proc/start_day()
|
||||
turn += 1
|
||||
phase = MAFIA_PHASE_DAY
|
||||
@@ -198,12 +198,12 @@
|
||||
SStgui.update_uis(src)
|
||||
|
||||
/**
|
||||
* Players have finished the discussion period, and now must put up someone to the chopping block.
|
||||
*
|
||||
* What players do in this phase:
|
||||
* * Vote on which player to put up for lynching, leading to the judgement phase.
|
||||
* * If no votes are case, the judgement phase is skipped, leading to the night phase.
|
||||
*/
|
||||
* Players have finished the discussion period, and now must put up someone to the chopping block.
|
||||
*
|
||||
* What players do in this phase:
|
||||
* * Vote on which player to put up for lynching, leading to the judgement phase.
|
||||
* * If no votes are case, the judgement phase is skipped, leading to the night phase.
|
||||
*/
|
||||
/datum/mafia_controller/proc/start_voting_phase()
|
||||
phase = MAFIA_PHASE_VOTING
|
||||
next_phase_timer = addtimer(CALLBACK(src, .proc/check_trial, TRUE),voting_phase_period,TIMER_STOPPABLE) //be verbose!
|
||||
@@ -211,21 +211,21 @@
|
||||
SStgui.update_uis(src)
|
||||
|
||||
/**
|
||||
* Players have voted someone up, and now the person must defend themselves while the town votes innocent or guilty.
|
||||
*
|
||||
* What players do in this phase:
|
||||
* * Vote innocent or guilty, if they are not on trial.
|
||||
* * Defend themselves and wait for judgement, if they are.
|
||||
* * Leads to the lynch phase.
|
||||
* Arguments:
|
||||
* * verbose: boolean, announces whether there were votes or not. after judgement it goes back here with no voting period to end the day.
|
||||
*/
|
||||
* Players have voted someone up, and now the person must defend themselves while the town votes innocent or guilty.
|
||||
*
|
||||
* What players do in this phase:
|
||||
* * Vote innocent or guilty, if they are not on trial.
|
||||
* * Defend themselves and wait for judgement, if they are.
|
||||
* * Leads to the lynch phase.
|
||||
* Arguments:
|
||||
* * verbose: boolean, announces whether there were votes or not. after judgement it goes back here with no voting period to end the day.
|
||||
*/
|
||||
/datum/mafia_controller/proc/check_trial(verbose = TRUE)
|
||||
var/datum/mafia_role/loser = get_vote_winner("Day")//, majority_of_town = TRUE)
|
||||
// var/loser_votes = get_vote_count(loser,"Day")
|
||||
var/loser_votes = get_vote_count(loser,"Day")
|
||||
if(loser)
|
||||
// if(loser_votes > 12)
|
||||
// loser.body.client?.give_award(/datum/award/achievement/mafia/universally_hated, loser.body)
|
||||
if(loser_votes > 12)
|
||||
award_role(/datum/award/achievement/mafia/universally_hated, loser)
|
||||
send_message("<b>[loser.body.real_name] wins the day vote, Listen to their defense and vote \"INNOCENT\" or \"GUILTY\"!</b>")
|
||||
//refresh the lists
|
||||
judgement_abstain_votes = list()
|
||||
@@ -248,12 +248,12 @@
|
||||
SStgui.update_uis(src)
|
||||
|
||||
/**
|
||||
* Players have voted innocent or guilty on the person on trial, and that person is now killed or returned home.
|
||||
*
|
||||
* What players do in this phase:
|
||||
* * r/watchpeopledie
|
||||
* * If the accused is killed, their true role is revealed to the rest of the players.
|
||||
*/
|
||||
* Players have voted innocent or guilty on the person on trial, and that person is now killed or returned home.
|
||||
*
|
||||
* What players do in this phase:
|
||||
* * r/watchpeopledie
|
||||
* * If the accused is killed, their true role is revealed to the rest of the players.
|
||||
*/
|
||||
/datum/mafia_controller/proc/lynch()
|
||||
for(var/i in judgement_innocent_votes)
|
||||
var/datum/mafia_role/role = i
|
||||
@@ -276,25 +276,25 @@
|
||||
next_phase_timer = addtimer(CALLBACK(src, .proc/check_trial, FALSE),judgement_lynch_period,TIMER_STOPPABLE)// small pause to see the guy dead, no verbosity since we already did this
|
||||
|
||||
/**
|
||||
* Teenie helper proc to move players back to their home.
|
||||
* Used in the above, but also used in the debug button "send all players home"
|
||||
* Arguments:
|
||||
* * role: mafia role that is getting sent back to the game.
|
||||
*/
|
||||
* Teenie helper proc to move players back to their home.
|
||||
* Used in the above, but also used in the debug button "send all players home"
|
||||
* Arguments:
|
||||
* * role: mafia role that is getting sent back to the game.
|
||||
*/
|
||||
/datum/mafia_controller/proc/send_home(datum/mafia_role/role)
|
||||
role.body.forceMove(get_turf(role.assigned_landmark))
|
||||
|
||||
/**
|
||||
* Checks to see if a faction (or solo antagonist) has won.
|
||||
*
|
||||
* Calculates in this order:
|
||||
* * counts up town, mafia, and solo
|
||||
* * solos can count as town members for the purposes of mafia winning
|
||||
* * sends the amount of living people to the solo antagonists, and see if they won OR block the victory of the teams
|
||||
* * checks if solos won from above, then if town, then if mafia
|
||||
* * starts the end of the game if a faction won
|
||||
* * returns TRUE if someone won the game, halting other procs from continuing in the case of a victory
|
||||
*/
|
||||
* Checks to see if a faction (or solo antagonist) has won.
|
||||
*
|
||||
* Calculates in this order:
|
||||
* * counts up town, mafia, and solo
|
||||
* * solos can count as town members for the purposes of mafia winning
|
||||
* * sends the amount of living people to the solo antagonists, and see if they won OR block the victory of the teams
|
||||
* * checks if solos won from above, then if town, then if mafia
|
||||
* * starts the end of the game if a faction won
|
||||
* * returns TRUE if someone won the game, halting other procs from continuing in the case of a victory
|
||||
*/
|
||||
/datum/mafia_controller/proc/check_victory()
|
||||
//needed for achievements
|
||||
var/list/total_town = list()
|
||||
@@ -336,8 +336,7 @@
|
||||
var/solo_end = FALSE
|
||||
for(var/datum/mafia_role/winner in total_victors)
|
||||
send_message("<span class='big comradio'>!! [uppertext(winner.name)] VICTORY !!</span>")
|
||||
// var/client/winner_client = GLOB.directory[winner.player_key]
|
||||
// winner_client?.give_award(winner.winner_award, winner.body)
|
||||
award_role(winner.winner_award, winner)
|
||||
solo_end = TRUE
|
||||
if(solo_end)
|
||||
start_the_end()
|
||||
@@ -345,28 +344,39 @@
|
||||
if(blocked_victory)
|
||||
return FALSE
|
||||
if(alive_mafia == 0)
|
||||
// for(var/datum/mafia_role/townie in total_town)
|
||||
// var/client/townie_client = GLOB.directory[townie.player_key]
|
||||
// townie_client?.give_award(townie.winner_award, townie.body)
|
||||
for(var/datum/mafia_role/townie in total_town)
|
||||
award_role(townie.winner_award, townie)
|
||||
start_the_end("<span class='big green'>!! TOWN VICTORY !!</span>")
|
||||
return TRUE
|
||||
else if(alive_mafia >= alive_town) //guess could change if town nightkill is added
|
||||
start_the_end("<span class='big red'>!! MAFIA VICTORY !!</span>")
|
||||
// for(var/datum/mafia_role/changeling in total_mafia)
|
||||
// var/client/changeling_client = GLOB.directory[changeling.player_key]
|
||||
// changeling_client?.give_award(changeling.winner_award, changeling.body)
|
||||
for(var/datum/mafia_role/changeling in total_mafia)
|
||||
award_role(changeling.winner_award, changeling)
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* The end of the game is in two procs, because we want a bit of time for players to see eachothers roles.
|
||||
* Because of how check_victory works, the game is halted in other places by this point.
|
||||
*
|
||||
* What players do in this phase:
|
||||
* * See everyone's role postgame
|
||||
* * See who won the game
|
||||
* Arguments:
|
||||
* * message: string, if non-null it sends it to all players. used to announce team victories while solos are handled in check victory
|
||||
*/
|
||||
* Lets the game award roles with all their checks and sanity, prevents achievements given out for debug games
|
||||
*
|
||||
* Arguments:
|
||||
* * award: path of the award
|
||||
* * role: mafia_role datum to reward.
|
||||
*/
|
||||
/datum/mafia_controller/proc/award_role(award, datum/mafia_role/rewarded)
|
||||
if(custom_setup.len)
|
||||
return
|
||||
var/client/role_client = GLOB.directory[rewarded.player_key]
|
||||
role_client?.give_award(award, rewarded.body)
|
||||
|
||||
/**
|
||||
* The end of the game is in two procs, because we want a bit of time for players to see eachothers roles.
|
||||
* Because of how check_victory works, the game is halted in other places by this point.
|
||||
*
|
||||
* What players do in this phase:
|
||||
* * See everyone's role postgame
|
||||
* * See who won the game
|
||||
* Arguments:
|
||||
* * message: string, if non-null it sends it to all players. used to announce team victories while solos are handled in check victory
|
||||
*/
|
||||
/datum/mafia_controller/proc/start_the_end(message)
|
||||
SEND_SIGNAL(src,COMSIG_MAFIA_GAME_END)
|
||||
if(message)
|
||||
@@ -377,8 +387,8 @@
|
||||
next_phase_timer = addtimer(CALLBACK(src,.proc/end_game),victory_lap_period,TIMER_STOPPABLE)
|
||||
|
||||
/**
|
||||
* Cleans up the game, resetting variables back to the beginning and removing the map with the generator.
|
||||
*/
|
||||
* Cleans up the game, resetting variables back to the beginning and removing the map with the generator.
|
||||
*/
|
||||
/datum/mafia_controller/proc/end_game()
|
||||
map_deleter.generate() //remove the map, it will be loaded at the start of the next one
|
||||
QDEL_LIST(all_roles)
|
||||
@@ -392,17 +402,17 @@
|
||||
phase = MAFIA_PHASE_SETUP
|
||||
|
||||
/**
|
||||
* After the voting and judgement phases, the game goes to night shutting the windows and beginning night with a proc.
|
||||
*/
|
||||
* After the voting and judgement phases, the game goes to night shutting the windows and beginning night with a proc.
|
||||
*/
|
||||
/datum/mafia_controller/proc/lockdown()
|
||||
toggle_night_curtains(close=TRUE)
|
||||
start_night()
|
||||
|
||||
/**
|
||||
* Shuts poddoors attached to mafia.
|
||||
* Arguments:
|
||||
* * close: boolean, the state you want the curtains in.
|
||||
*/
|
||||
* Shuts poddoors attached to mafia.
|
||||
* Arguments:
|
||||
* * close: boolean, the state you want the curtains in.
|
||||
*/
|
||||
/datum/mafia_controller/proc/toggle_night_curtains(close)
|
||||
for(var/obj/machinery/door/poddoor/D in GLOB.machines) //I really dislike pathing of these
|
||||
if(D.id != "mafia") //so as to not trigger shutters on station, lol
|
||||
@@ -413,12 +423,12 @@
|
||||
INVOKE_ASYNC(D, /obj/machinery/door/poddoor.proc/open)
|
||||
|
||||
/**
|
||||
* The actual start of night for players. Mostly info is given at the start of the night as the end of the night is when votes and actions are submitted and tried.
|
||||
*
|
||||
* What players do in this phase:
|
||||
* * Mafia are told to begin voting on who to kill
|
||||
* * Powers that are picked during the day announce themselves right now
|
||||
*/
|
||||
* The actual start of night for players. Mostly info is given at the start of the night as the end of the night is when votes and actions are submitted and tried.
|
||||
*
|
||||
* What players do in this phase:
|
||||
* * Mafia are told to begin voting on who to kill
|
||||
* * Powers that are picked during the day announce themselves right now
|
||||
*/
|
||||
/datum/mafia_controller/proc/start_night()
|
||||
phase = MAFIA_PHASE_NIGHT
|
||||
send_message("<b>Night [turn] started! Lockdown will end in 45 seconds.</b>")
|
||||
@@ -427,16 +437,16 @@
|
||||
SStgui.update_uis(src)
|
||||
|
||||
/**
|
||||
* The end of the night, and a series of signals for the order of events on a night.
|
||||
*
|
||||
* Order of events, and what they mean:
|
||||
* * Start of resolve (NIGHT_START) is for activating night abilities that MUST go first
|
||||
* * Action phase (NIGHT_ACTION_PHASE) is for non-lethal day abilities
|
||||
* * Mafia then tallies votes and kills the highest voted person (note: one random voter visits that person for the purposes of roleblocking)
|
||||
* * Killing phase (NIGHT_KILL_PHASE) is for lethal night abilities
|
||||
* * End of resolve (NIGHT_END) is for cleaning up abilities that went off and i guess doing some that must go last
|
||||
* * Finally opens the curtains and calls the start of day phase, completing the cycle until check victory returns TRUE
|
||||
*/
|
||||
* The end of the night, and a series of signals for the order of events on a night.
|
||||
*
|
||||
* Order of events, and what they mean:
|
||||
* * Start of resolve (NIGHT_START) is for activating night abilities that MUST go first
|
||||
* * Action phase (NIGHT_ACTION_PHASE) is for non-lethal day abilities
|
||||
* * Mafia then tallies votes and kills the highest voted person (note: one random voter visits that person for the purposes of roleblocking)
|
||||
* * Killing phase (NIGHT_KILL_PHASE) is for lethal night abilities
|
||||
* * End of resolve (NIGHT_END) is for cleaning up abilities that went off and i guess doing some that must go last
|
||||
* * Finally opens the curtains and calls the start of day phase, completing the cycle until check victory returns TRUE
|
||||
*/
|
||||
/datum/mafia_controller/proc/resolve_night()
|
||||
SEND_SIGNAL(src,COMSIG_MAFIA_NIGHT_START)
|
||||
SEND_SIGNAL(src,COMSIG_MAFIA_NIGHT_ACTION_PHASE)
|
||||
@@ -457,15 +467,15 @@
|
||||
SStgui.update_uis(src)
|
||||
|
||||
/**
|
||||
* Proc that goes off when players vote for something with their mafia panel.
|
||||
*
|
||||
* If teams, it hides the tally overlay and only sends the vote messages to the team that is voting
|
||||
* Arguments:
|
||||
* * voter: the mafia role that is trying to vote for...
|
||||
* * target: the mafia role that is getting voted for
|
||||
* * vote_type: type of vote submitted (is this the day vote? is this the mafia night vote?)
|
||||
* * teams: see mafia team defines for what to put in, makes the messages only send to a specific team (so mafia night votes only sending messages to mafia at night)
|
||||
*/
|
||||
* Proc that goes off when players vote for something with their mafia panel.
|
||||
*
|
||||
* If teams, it hides the tally overlay and only sends the vote messages to the team that is voting
|
||||
* Arguments:
|
||||
* * voter: the mafia role that is trying to vote for...
|
||||
* * target: the mafia role that is getting voted for
|
||||
* * vote_type: type of vote submitted (is this the day vote? is this the mafia night vote?)
|
||||
* * teams: see mafia team defines for what to put in, makes the messages only send to a specific team (so mafia night votes only sending messages to mafia at night)
|
||||
*/
|
||||
/datum/mafia_controller/proc/vote_for(datum/mafia_role/voter,datum/mafia_role/target,vote_type, teams)
|
||||
if(!votes[vote_type])
|
||||
votes[vote_type] = list()
|
||||
@@ -485,8 +495,8 @@
|
||||
old.body.update_icon()
|
||||
|
||||
/**
|
||||
* Clears out the votes of a certain type (day votes, mafia kill votes) while leaving others untouched
|
||||
*/
|
||||
* Clears out the votes of a certain type (day votes, mafia kill votes) while leaving others untouched
|
||||
*/
|
||||
/datum/mafia_controller/proc/reset_votes(vote_type)
|
||||
var/list/bodies_to_update = list()
|
||||
for(var/vote in votes[vote_type])
|
||||
@@ -497,11 +507,11 @@
|
||||
M.update_icon()
|
||||
|
||||
/**
|
||||
* Returns how many people voted for the role, in whatever vote (day vote, night kill vote)
|
||||
* Arguments:
|
||||
* * role: the mafia role the proc tries to get the amount of votes for
|
||||
* * vote_type: the vote type (getting how many day votes were for the role, or mafia night votes for the role)
|
||||
*/
|
||||
* Returns how many people voted for the role, in whatever vote (day vote, night kill vote)
|
||||
* Arguments:
|
||||
* * role: the mafia role the proc tries to get the amount of votes for
|
||||
* * vote_type: the vote type (getting how many day votes were for the role, or mafia night votes for the role)
|
||||
*/
|
||||
/datum/mafia_controller/proc/get_vote_count(role,vote_type)
|
||||
. = 0
|
||||
for(var/v in votes[vote_type])
|
||||
@@ -510,11 +520,11 @@
|
||||
. += votee.vote_power
|
||||
|
||||
/**
|
||||
* Returns whichever role got the most votes, in whatever vote (day vote, night kill vote)
|
||||
* returns null if no votes
|
||||
* Arguments:
|
||||
* * vote_type: the vote type (getting the role that got the most day votes, or the role that got the most mafia votes)
|
||||
*/
|
||||
* Returns whichever role got the most votes, in whatever vote (day vote, night kill vote)
|
||||
* returns null if no votes
|
||||
* Arguments:
|
||||
* * vote_type: the vote type (getting the role that got the most day votes, or the role that got the most mafia votes)
|
||||
*/
|
||||
/datum/mafia_controller/proc/get_vote_winner(vote_type)
|
||||
var/list/tally = list()
|
||||
for(var/votee in votes[vote_type])
|
||||
@@ -526,21 +536,23 @@
|
||||
return length(tally) ? tally[1] : null
|
||||
|
||||
/**
|
||||
* Returns a random person who voted for whatever vote (day vote, night kill vote)
|
||||
* Arguments:
|
||||
* * vote_type: vote type (getting a random day voter, or mafia night voter)
|
||||
*/
|
||||
* Returns a random person who voted for whatever vote (day vote, night kill vote)
|
||||
* Arguments:
|
||||
* * vote_type: vote type (getting a random day voter, or mafia night voter)
|
||||
*/
|
||||
/datum/mafia_controller/proc/get_random_voter(vote_type)
|
||||
if(length(votes[vote_type]))
|
||||
return pick(votes[vote_type])
|
||||
|
||||
/**
|
||||
* Adds mutable appearances to people who get publicly voted on (so not night votes) showing how many people are picking them
|
||||
* Arguments:
|
||||
* * source: the body of the role getting the overlays
|
||||
* * overlay_list: signal var passing the overlay list of the mob
|
||||
*/
|
||||
* Adds mutable appearances to people who get publicly voted on (so not night votes) showing how many people are picking them
|
||||
* Arguments:
|
||||
* * source: the body of the role getting the overlays
|
||||
* * overlay_list: signal var passing the overlay list of the mob
|
||||
*/
|
||||
/datum/mafia_controller/proc/display_votes(atom/source, list/overlay_list)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(phase != MAFIA_PHASE_VOTING)
|
||||
return
|
||||
var/v = get_vote_count(player_role_lookup[source],"Day")
|
||||
@@ -548,14 +560,14 @@
|
||||
overlay_list += MA
|
||||
|
||||
/**
|
||||
* Called when the game is setting up, AFTER map is loaded but BEFORE the phase timers start. Creates and places each role's body and gives the correct player key
|
||||
*
|
||||
* Notably:
|
||||
* * Toggles godmode so the mafia players cannot kill themselves
|
||||
* * Adds signals for voting overlays, see display_votes proc
|
||||
* * gives mafia panel
|
||||
* * sends the greeting text (goals, role name, etc)
|
||||
*/
|
||||
* Called when the game is setting up, AFTER map is loaded but BEFORE the phase timers start. Creates and places each role's body and gives the correct player key
|
||||
*
|
||||
* Notably:
|
||||
* * Toggles godmode so the mafia players cannot kill themselves
|
||||
* * Adds signals for voting overlays, see display_votes proc
|
||||
* * gives mafia panel
|
||||
* * sends the greeting text (goals, role name, etc)
|
||||
*/
|
||||
/datum/mafia_controller/proc/create_bodies()
|
||||
for(var/datum/mafia_role/role in all_roles)
|
||||
var/mob/living/carbon/human/H = new(get_turf(role.assigned_landmark))
|
||||
@@ -716,13 +728,14 @@
|
||||
if(GLOB.mafia_signup[C.ckey])
|
||||
GLOB.mafia_signup -= C.ckey
|
||||
to_chat(usr, "<span class='notice'>You unregister from Mafia.</span>")
|
||||
return
|
||||
return TRUE
|
||||
else
|
||||
GLOB.mafia_signup[C.ckey] = C
|
||||
to_chat(usr, "<span class='notice'>You sign up for Mafia.</span>")
|
||||
if(phase == MAFIA_PHASE_SETUP)
|
||||
check_signups()
|
||||
try_autostart()
|
||||
return TRUE
|
||||
if("mf_spectate")
|
||||
if(C.ckey in spectators)
|
||||
to_chat(usr, "<span class='notice'>You will no longer get messages from the game.</span>")
|
||||
@@ -730,6 +743,7 @@
|
||||
else
|
||||
to_chat(usr, "<span class='notice'>You will now get messages from the game.</span>")
|
||||
spectators += C.ckey
|
||||
return TRUE
|
||||
if(user_role.game_status == MAFIA_DEAD)
|
||||
return
|
||||
//User actions (just living)
|
||||
@@ -800,13 +814,13 @@
|
||||
. += L[key]
|
||||
|
||||
/**
|
||||
* Returns a semirandom setup, with...
|
||||
* Town, Two invest roles, one protect role, sometimes a misc role, and the rest assistants for town.
|
||||
* Mafia, 2 normal mafia and one special.
|
||||
* Neutral, two disruption roles, sometimes one is a killing.
|
||||
*
|
||||
* See _defines.dm in the mafia folder for a rundown on what these groups of roles include.
|
||||
*/
|
||||
* Returns a semirandom setup, with...
|
||||
* Town, Two invest roles, one protect role, sometimes a misc role, and the rest assistants for town.
|
||||
* Mafia, 2 normal mafia and one special.
|
||||
* Neutral, two disruption roles, sometimes one is a killing.
|
||||
*
|
||||
* See _defines.dm in the mafia folder for a rundown on what these groups of roles include.
|
||||
*/
|
||||
/datum/mafia_controller/proc/generate_random_setup()
|
||||
var/invests_left = 2
|
||||
var/protects_left = 1
|
||||
@@ -845,8 +859,8 @@
|
||||
return random_setup
|
||||
|
||||
/**
|
||||
* Helper proc that adds a random role of a type to a setup. if it doesn't exist in the setup, it adds the path to the list and otherwise bumps the path in the list up one
|
||||
*/
|
||||
* Helper proc that adds a random role of a type to a setup. if it doesn't exist in the setup, it adds the path to the list and otherwise bumps the path in the list up one
|
||||
*/
|
||||
/datum/mafia_controller/proc/add_setup_role(setup_list, wanted_role_type)
|
||||
var/list/role_type_paths = list()
|
||||
for(var/path in typesof(/datum/mafia_role))
|
||||
@@ -868,17 +882,17 @@
|
||||
setup_list[mafia_path] = 1
|
||||
|
||||
/**
|
||||
* Called when enough players have signed up to fill a setup. DOESN'T NECESSARILY MEAN THE GAME WILL START.
|
||||
*
|
||||
* Checks for a custom setup, if so gets the required players from that and if not it sets the player requirement to required_player(max_player) and generates one IF basic setup starts a game.
|
||||
* Checks if everyone signed up is an observer, and is still connected. If people aren't, they're removed from the list.
|
||||
* If there aren't enough players post sanity, it aborts. otherwise, it selects enough people for the game and starts preparing the game for real.
|
||||
*/
|
||||
* Called when enough players have signed up to fill a setup. DOESN'T NECESSARILY MEAN THE GAME WILL START.
|
||||
*
|
||||
* Checks for a custom setup, if so gets the required players from that and if not it sets the player requirement to MAFIA_MAX_PLAYER_COUNT and generates one IF basic setup starts a game.
|
||||
* Checks if everyone signed up is an observer, and is still connected. If people aren't, they're removed from the list.
|
||||
* If there aren't enough players post sanity, it aborts. otherwise, it selects enough people for the game and starts preparing the game for real.
|
||||
*/
|
||||
/datum/mafia_controller/proc/basic_setup()
|
||||
var/req_players
|
||||
var/list/setup = custom_setup
|
||||
if(!setup.len)
|
||||
req_players = required_player //max_player
|
||||
req_players = max_player //MAFIA_MAX_PLAYER_COUNT
|
||||
else
|
||||
req_players = assoc_value_sum(setup)
|
||||
|
||||
@@ -918,10 +932,10 @@
|
||||
start_game()
|
||||
|
||||
/**
|
||||
* Called when someone signs up, and sees if there are enough people in the signup list to begin.
|
||||
*
|
||||
* Only checks if everyone is actually valid to start (still connected and an observer) if there are enough players (basic_setup)
|
||||
*/
|
||||
* Called when someone signs up, and sees if there are enough people in the signup list to begin.
|
||||
*
|
||||
* Only checks if everyone is actually valid to start (still connected and an observer) if there are enough players (basic_setup)
|
||||
*/
|
||||
/datum/mafia_controller/proc/try_autostart()
|
||||
if(phase != MAFIA_PHASE_SETUP) // || !(GLOB.ghost_role_flags & GHOSTROLE_MINIGAME))
|
||||
return
|
||||
@@ -929,10 +943,10 @@
|
||||
basic_setup()
|
||||
|
||||
/**
|
||||
* Filters inactive player into a different list until they reconnect, and removes players who are no longer ghosts.
|
||||
*
|
||||
* If a disconnected player gets a non-ghost mob and reconnects, they will be first put back into mafia_signup then filtered by that.
|
||||
*/
|
||||
* Filters inactive player into a different list until they reconnect, and removes players who are no longer ghosts.
|
||||
*
|
||||
* If a disconnected player gets a non-ghost mob and reconnects, they will be first put back into mafia_signup then filtered by that.
|
||||
*/
|
||||
/datum/mafia_controller/proc/check_signups()
|
||||
for(var/bad_key in GLOB.mafia_bad_signup)
|
||||
if(GLOB.directory[bad_key])//they have reconnected if we can search their key and get a client
|
||||
@@ -962,8 +976,8 @@
|
||||
parent.ui_interact(owner)
|
||||
|
||||
/**
|
||||
* Creates the global datum for playing mafia games, destroys the last if that's required and returns the new.
|
||||
*/
|
||||
* Creates the global datum for playing mafia games, destroys the last if that's required and returns the new.
|
||||
*/
|
||||
/proc/create_mafia_game()
|
||||
if(GLOB.mafia_game)
|
||||
QDEL_NULL(GLOB.mafia_game)
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
var/list/actions = list()
|
||||
var/list/targeted_actions = list()
|
||||
//what the role gets when it wins a game
|
||||
// var/winner_award = /datum/award/achievement/mafia/assistant
|
||||
var/winner_award = /datum/award/achievement/mafia/assistant
|
||||
|
||||
//so mafia have to also kill them to have a majority
|
||||
var/solo_counts_as_town = FALSE //(don't set this for town)
|
||||
@@ -124,7 +124,7 @@
|
||||
desc = "You can investigate a single person each night to learn their team."
|
||||
revealed_outfit = /datum/outfit/mafia/detective
|
||||
role_type = TOWN_INVEST
|
||||
// winner_award = /datum/award/achievement/mafia/detective
|
||||
winner_award = /datum/award/achievement/mafia/detective
|
||||
|
||||
hud_icon = "huddetective"
|
||||
revealed_icon = "detective"
|
||||
@@ -151,6 +151,8 @@
|
||||
current_investigation = target
|
||||
|
||||
/datum/mafia_role/detective/proc/investigate(datum/mafia_controller/game)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
var/datum/mafia_role/target = current_investigation
|
||||
if(target)
|
||||
if(target.detect_immune)
|
||||
@@ -178,7 +180,7 @@
|
||||
desc = "You can visit someone ONCE PER GAME to reveal their true role in the morning!"
|
||||
revealed_outfit = /datum/outfit/mafia/psychologist
|
||||
role_type = TOWN_INVEST
|
||||
// winner_award = /datum/award/achievement/mafia/psychologist
|
||||
winner_award = /datum/award/achievement/mafia/psychologist
|
||||
|
||||
hud_icon = "hudpsychologist"
|
||||
revealed_icon = "psychologist"
|
||||
@@ -202,6 +204,8 @@
|
||||
current_target = target
|
||||
|
||||
/datum/mafia_role/psychologist/proc/therapy_reveal(datum/mafia_controller/game)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(SEND_SIGNAL(src,COMSIG_MAFIA_CAN_PERFORM_ACTION,game,"reveal",current_target) & MAFIA_PREVENT_ACTION || game_status != MAFIA_ALIVE) //Got lynched or roleblocked by a lawyer.
|
||||
current_target = null
|
||||
if(current_target)
|
||||
@@ -218,7 +222,7 @@
|
||||
role_type = TOWN_INVEST
|
||||
hud_icon = "hudchaplain"
|
||||
revealed_icon = "chaplain"
|
||||
// winner_award = /datum/award/achievement/mafia/chaplain
|
||||
winner_award = /datum/award/achievement/mafia/chaplain
|
||||
|
||||
targeted_actions = list("Pray")
|
||||
var/current_target
|
||||
@@ -238,6 +242,8 @@
|
||||
current_target = target
|
||||
|
||||
/datum/mafia_role/chaplain/proc/commune(datum/mafia_controller/game)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
var/datum/mafia_role/target = current_target
|
||||
if(target)
|
||||
to_chat(body,"<span class='warning'>You invoke spirit of [target.body.real_name] and learn their role was <b>[target.name]<b>.</span>")
|
||||
@@ -251,7 +257,7 @@
|
||||
role_type = TOWN_PROTECT
|
||||
hud_icon = "hudmedicaldoctor"
|
||||
revealed_icon = "medicaldoctor"
|
||||
// winner_award = /datum/award/achievement/mafia/md
|
||||
winner_award = /datum/award/achievement/mafia/md
|
||||
|
||||
targeted_actions = list("Protect")
|
||||
var/datum/mafia_role/current_protected
|
||||
@@ -277,16 +283,22 @@
|
||||
current_protected = target
|
||||
|
||||
/datum/mafia_role/md/proc/protect(datum/mafia_controller/game)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(current_protected)
|
||||
RegisterSignal(current_protected,COMSIG_MAFIA_ON_KILL,.proc/prevent_kill)
|
||||
add_note("N[game.turn] - Protected [current_protected.body.real_name]")
|
||||
|
||||
/datum/mafia_role/md/proc/prevent_kill(datum/source)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
to_chat(body,"<span class='warning'>The person you protected tonight was attacked!</span>")
|
||||
to_chat(current_protected.body,"<span class='userdanger'>You were attacked last night, but someone nursed you back to life!</span>")
|
||||
return MAFIA_PREVENT_KILL
|
||||
|
||||
/datum/mafia_role/md/proc/end_protection(datum/mafia_controller/game)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(current_protected)
|
||||
UnregisterSignal(current_protected,COMSIG_MAFIA_ON_KILL)
|
||||
current_protected = null
|
||||
@@ -298,7 +310,7 @@
|
||||
role_type = TOWN_PROTECT
|
||||
hud_icon = "hudlawyer"
|
||||
revealed_icon = "lawyer"
|
||||
// winner_award = /datum/award/achievement/mafia/lawyer
|
||||
winner_award = /datum/award/achievement/mafia/lawyer
|
||||
|
||||
targeted_actions = list("Advise")
|
||||
var/datum/mafia_role/current_target
|
||||
@@ -310,6 +322,8 @@
|
||||
RegisterSignal(game,COMSIG_MAFIA_NIGHT_END,.proc/release)
|
||||
|
||||
/datum/mafia_role/lawyer/proc/roleblock_text(datum/mafia_controller/game)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(SEND_SIGNAL(src,COMSIG_MAFIA_CAN_PERFORM_ACTION,game,"roleblock",current_target) & MAFIA_PREVENT_ACTION || game_status != MAFIA_ALIVE) //Got lynched or roleblocked by another lawyer.
|
||||
current_target = null
|
||||
if(current_target)
|
||||
@@ -335,16 +349,22 @@
|
||||
to_chat(body,"<span class='warning'>You will block [target.body.real_name] tonight.</span>")
|
||||
|
||||
/datum/mafia_role/lawyer/proc/try_to_roleblock(datum/mafia_controller/game)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(current_target)
|
||||
RegisterSignal(current_target,COMSIG_MAFIA_CAN_PERFORM_ACTION, .proc/prevent_action)
|
||||
|
||||
/datum/mafia_role/lawyer/proc/release(datum/mafia_controller/game)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
. = ..()
|
||||
if(current_target)
|
||||
UnregisterSignal(current_target, COMSIG_MAFIA_CAN_PERFORM_ACTION)
|
||||
current_target = null
|
||||
|
||||
/datum/mafia_role/lawyer/proc/prevent_action(datum/source)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(game_status == MAFIA_ALIVE) //in case we got killed while imprisoning sk - bad luck edge
|
||||
return MAFIA_PREVENT_ACTION
|
||||
|
||||
@@ -355,7 +375,7 @@
|
||||
role_type = TOWN_MISC
|
||||
hud_icon = "hudheadofpersonnel"
|
||||
revealed_icon = "headofpersonnel"
|
||||
// winner_award = /datum/award/achievement/mafia/hop
|
||||
winner_award = /datum/award/achievement/mafia/hop
|
||||
|
||||
targeted_actions = list("Reveal")
|
||||
|
||||
@@ -378,7 +398,7 @@
|
||||
role_type = MAFIA_REGULAR
|
||||
hud_icon = "hudchangeling"
|
||||
revealed_icon = "changeling"
|
||||
// winner_award = /datum/award/achievement/mafia/changeling
|
||||
winner_award = /datum/award/achievement/mafia/changeling
|
||||
|
||||
revealed_outfit = /datum/outfit/mafia/changeling
|
||||
special_theme = "syndicate"
|
||||
@@ -389,6 +409,8 @@
|
||||
RegisterSignal(game,COMSIG_MAFIA_SUNDOWN,.proc/mafia_text)
|
||||
|
||||
/datum/mafia_role/mafia/proc/mafia_text(datum/mafia_controller/source)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
to_chat(body,"<b>Vote for who to kill tonight. The killer will be chosen randomly from voters.</b>")
|
||||
|
||||
//better detective for mafia
|
||||
@@ -398,7 +420,7 @@
|
||||
role_type = MAFIA_SPECIAL
|
||||
hud_icon = "hudthoughtfeeder"
|
||||
revealed_icon = "thoughtfeeder"
|
||||
// winner_award = /datum/award/achievement/mafia/thoughtfeeder
|
||||
winner_award = /datum/award/achievement/mafia/thoughtfeeder
|
||||
|
||||
targeted_actions = list("Learn Role")
|
||||
var/datum/mafia_role/current_investigation
|
||||
@@ -418,6 +440,8 @@
|
||||
current_investigation = target
|
||||
|
||||
/datum/mafia_role/mafia/thoughtfeeder/proc/investigate(datum/mafia_controller/game)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
var/datum/mafia_role/target = current_investigation
|
||||
current_investigation = null
|
||||
if(SEND_SIGNAL(src,COMSIG_MAFIA_CAN_PERFORM_ACTION,game,"thoughtfeed",target) & MAFIA_PREVENT_ACTION)
|
||||
@@ -441,7 +465,7 @@
|
||||
win_condition = "kill everyone."
|
||||
team = MAFIA_TEAM_SOLO
|
||||
role_type = NEUTRAL_KILL
|
||||
// winner_award = /datum/award/achievement/mafia/traitor
|
||||
winner_award = /datum/award/achievement/mafia/traitor
|
||||
|
||||
targeted_actions = list("Night Kill")
|
||||
revealed_outfit = /datum/outfit/mafia/traitor
|
||||
@@ -464,6 +488,8 @@
|
||||
return TRUE //while alive, town AND mafia cannot win (though since mafia know who is who it's pretty easy to win from that point)
|
||||
|
||||
/datum/mafia_role/traitor/proc/nightkill_immunity(datum/source,datum/mafia_controller/game,lynch)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(game.phase == MAFIA_PHASE_NIGHT && !lynch)
|
||||
to_chat(body,"<span class='userdanger'>You were attacked, but they'll have to try harder than that to put you down.</span>")
|
||||
return MAFIA_PREVENT_KILL
|
||||
@@ -481,6 +507,8 @@
|
||||
to_chat(body,"<span class='warning'>You will attempt to kill [target.body.real_name] tonight.</span>")
|
||||
|
||||
/datum/mafia_role/traitor/proc/try_to_kill(datum/mafia_controller/source)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
var/datum/mafia_role/target = current_victim
|
||||
current_victim = null
|
||||
if(SEND_SIGNAL(src,COMSIG_MAFIA_CAN_PERFORM_ACTION,source,"traitor kill",target) & MAFIA_PREVENT_ACTION)
|
||||
@@ -500,7 +528,7 @@
|
||||
special_theme = "neutral"
|
||||
hud_icon = "hudnightmare"
|
||||
revealed_icon = "nightmare"
|
||||
// winner_award = /datum/award/achievement/mafia/nightmare
|
||||
winner_award = /datum/award/achievement/mafia/nightmare
|
||||
|
||||
targeted_actions = list("Flicker", "Hunt")
|
||||
var/list/flickering = list()
|
||||
@@ -543,6 +571,8 @@
|
||||
to_chat(body,"<span class='danger'>You will hunt everyone in a flickering room down tonight.</span>")
|
||||
|
||||
/datum/mafia_role/nightmare/proc/flicker_or_hunt(datum/mafia_controller/source)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(game_status != MAFIA_ALIVE || !flicker_target)
|
||||
return
|
||||
if(SEND_SIGNAL(src,COMSIG_MAFIA_CAN_PERFORM_ACTION,source,"nightmare actions",flicker_target) & MAFIA_PREVENT_ACTION)
|
||||
@@ -576,7 +606,7 @@
|
||||
special_theme = "neutral"
|
||||
hud_icon = "hudfugitive"
|
||||
revealed_icon = "fugitive"
|
||||
// winner_award = /datum/award/achievement/mafia/fugitive
|
||||
winner_award = /datum/award/achievement/mafia/fugitive
|
||||
|
||||
actions = list("Self Preservation")
|
||||
var/charges = 2
|
||||
@@ -604,11 +634,15 @@
|
||||
protection_status = !protection_status
|
||||
|
||||
/datum/mafia_role/fugitive/proc/night_start(datum/mafia_controller/game)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(protection_status == FUGITIVE_WILL_PRESERVE)
|
||||
to_chat(body,"<span class='danger'>Your preparations are complete. Nothing could kill you tonight!</span>")
|
||||
RegisterSignal(src,COMSIG_MAFIA_ON_KILL,.proc/prevent_death)
|
||||
|
||||
/datum/mafia_role/fugitive/proc/night_end(datum/mafia_controller/game)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(protection_status == FUGITIVE_WILL_PRESERVE)
|
||||
charges--
|
||||
UnregisterSignal(src,COMSIG_MAFIA_ON_KILL)
|
||||
@@ -616,13 +650,16 @@
|
||||
protection_status = FUGITIVE_NOT_PRESERVING
|
||||
|
||||
/datum/mafia_role/fugitive/proc/prevent_death(datum/mafia_controller/game)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
to_chat(body,"<span class='userdanger'>You were attacked! Luckily, you were ready for this!</span>")
|
||||
return MAFIA_PREVENT_KILL
|
||||
|
||||
/datum/mafia_role/fugitive/proc/survived(datum/mafia_controller/game)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(game_status == MAFIA_ALIVE)
|
||||
// var/client/winner_client = GLOB.directory[player_key]
|
||||
// winner_client?.give_award(winner_award, body)
|
||||
game.award_role(winner_award, src)
|
||||
game.send_message("<span class='big comradio'>!! FUGITIVE VICTORY !!</span>")
|
||||
|
||||
#undef FUGITIVE_NOT_PRESERVING
|
||||
@@ -640,7 +677,7 @@
|
||||
hud_icon = "hudobsessed"
|
||||
revealed_icon = "obsessed"
|
||||
|
||||
// winner_award = /datum/award/achievement/mafia/obsessed
|
||||
winner_award = /datum/award/achievement/mafia/obsessed
|
||||
|
||||
revealed_outfit = /datum/outfit/mafia/obsessed // /mafia <- outfit must be readded (just make a new mafia outfits file for all of these)
|
||||
solo_counts_as_town = TRUE //after winning or whatever, can side with whoever. they've already done their objective!
|
||||
@@ -652,6 +689,8 @@
|
||||
RegisterSignal(game,COMSIG_MAFIA_SUNDOWN,.proc/find_obsession)
|
||||
|
||||
/datum/mafia_role/obsessed/proc/find_obsession(datum/mafia_controller/game)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
var/list/all_roles_shuffle = shuffle(game.all_roles)
|
||||
for(var/role in all_roles_shuffle)
|
||||
var/datum/mafia_role/possible = role
|
||||
@@ -667,13 +706,14 @@
|
||||
UnregisterSignal(game,COMSIG_MAFIA_SUNDOWN)
|
||||
|
||||
/datum/mafia_role/obsessed/proc/check_victory(datum/source,datum/mafia_controller/game,lynch)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
UnregisterSignal(source,COMSIG_MAFIA_ON_KILL)
|
||||
if(game_status == MAFIA_DEAD)
|
||||
return
|
||||
if(lynch)
|
||||
game.send_message("<span class='big comradio'>!! OBSESSED VICTORY !!</span>")
|
||||
// var/client/winner_client = GLOB.directory[player_key]
|
||||
// winner_client?.give_award(winner_award, body)
|
||||
game.award_role(winner_award, src)
|
||||
reveal_role(game, FALSE)
|
||||
else
|
||||
to_chat(body, "<span class='userdanger'>You have failed your objective to lynch [obsession.body]!</span>")
|
||||
@@ -689,17 +729,18 @@
|
||||
special_theme = "neutral"
|
||||
hud_icon = "hudclown"
|
||||
revealed_icon = "clown"
|
||||
// winner_award = /datum/award/achievement/mafia/clown
|
||||
winner_award = /datum/award/achievement/mafia/clown
|
||||
|
||||
/datum/mafia_role/clown/New(datum/mafia_controller/game)
|
||||
. = ..()
|
||||
RegisterSignal(src,COMSIG_MAFIA_ON_KILL,.proc/prank)
|
||||
|
||||
/datum/mafia_role/clown/proc/prank(datum/source,datum/mafia_controller/game,lynch)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(lynch)
|
||||
var/datum/mafia_role/victim = pick(game.judgement_guilty_votes + game.judgement_abstain_votes)
|
||||
game.send_message("<span class='big clown'>[body.real_name] WAS A CLOWN! HONK! They take down [victim.body.real_name] with their last prank.</span>")
|
||||
game.send_message("<span class='big clown'>!! CLOWN VICTORY !!</span>")
|
||||
// var/client/winner_client = GLOB.directory[player_key]
|
||||
// winner_client?.give_award(winner_award, body)
|
||||
game.award_role(winner_award, src)
|
||||
victim.kill(game,FALSE)
|
||||
|
||||
@@ -75,6 +75,7 @@
|
||||
var/lastpuke = 0
|
||||
var/account_id
|
||||
var/last_fire_update
|
||||
var/hardcore_survival_score = 0
|
||||
|
||||
/// Unarmed parry data for human
|
||||
/datum/block_parry_data/unarmed/human
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
model = "Cleanbot"
|
||||
bot_core_type = /obj/machinery/bot_core/cleanbot
|
||||
window_id = "autoclean"
|
||||
window_name = "Automatic Station Cleaner v1.3"
|
||||
pass_flags = PASSMOB
|
||||
window_name = "Automatic Station Cleaner v1.4"
|
||||
pass_flags = PASSMOB // | PASSFLAPS
|
||||
path_image_color = "#993299"
|
||||
weather_immunities = list("lava","ash")
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
var/blood = 1
|
||||
var/trash = 0
|
||||
var/pests = 0
|
||||
var/drawn = 0
|
||||
|
||||
var/list/target_types
|
||||
var/obj/effect/decal/cleanable/target
|
||||
@@ -53,6 +54,9 @@
|
||||
var/list/prefixes
|
||||
var/list/suffixes
|
||||
|
||||
var/ascended = FALSE // if we have all the top titles, grant achievements to living mobs that gaze upon our cleanbot god
|
||||
|
||||
|
||||
/mob/living/simple_animal/bot/cleanbot/proc/deputize(obj/item/W, mob/user)
|
||||
if(in_range(src, user))
|
||||
to_chat(user, "<span class='notice'>You attach \the [W] to \the [src].</span>")
|
||||
@@ -66,6 +70,8 @@
|
||||
/mob/living/simple_animal/bot/cleanbot/proc/update_titles()
|
||||
var/working_title = ""
|
||||
|
||||
ascended = TRUE
|
||||
|
||||
for(var/pref in prefixes)
|
||||
for(var/title in pref)
|
||||
if(title in stolen_valor)
|
||||
@@ -73,6 +79,8 @@
|
||||
if(title in officers)
|
||||
commissioned = TRUE
|
||||
break
|
||||
else
|
||||
ascended = FALSE // we didn't have the first entry in the list if we got here, so we're not achievement worthy yet
|
||||
|
||||
working_title += chosen_name
|
||||
|
||||
@@ -81,6 +89,8 @@
|
||||
if(title in stolen_valor)
|
||||
working_title += " " + suf[title]
|
||||
break
|
||||
else
|
||||
ascended = FALSE
|
||||
|
||||
name = working_title
|
||||
|
||||
@@ -89,8 +99,12 @@
|
||||
if(weapon)
|
||||
. += " <span class='warning'>Is that \a [weapon] taped to it...?</span>"
|
||||
|
||||
if(ascended && user.stat == CONSCIOUS && user.client)
|
||||
user.client.give_award(/datum/award/achievement/misc/cleanboss, user)
|
||||
|
||||
/mob/living/simple_animal/bot/cleanbot/Initialize()
|
||||
. = ..()
|
||||
|
||||
chosen_name = name
|
||||
get_targets()
|
||||
icon_state = "cleanbot[on]"
|
||||
@@ -98,7 +112,6 @@
|
||||
var/datum/job/janitor/J = new/datum/job/janitor
|
||||
access_card.access += J.get_access()
|
||||
prev_access = access_card.access
|
||||
|
||||
stolen_valor = list()
|
||||
|
||||
prefixes = list(command, security, engineering)
|
||||
@@ -123,7 +136,7 @@
|
||||
|
||||
/mob/living/simple_animal/bot/cleanbot/bot_reset()
|
||||
..()
|
||||
if(weapon && (emagged == 2))
|
||||
if(weapon && emagged == 2)
|
||||
weapon.force = weapon_orig_force
|
||||
ignore_list = list() //Allows the bot to clean targets it previously ignored due to being unreachable.
|
||||
target = null
|
||||
@@ -151,7 +164,7 @@
|
||||
C.Knockdown(20)
|
||||
|
||||
/mob/living/simple_animal/bot/cleanbot/attackby(obj/item/W, mob/user, params)
|
||||
if(istype(W, /obj/item/card/id)||istype(W, /obj/item/pda))
|
||||
if(W.GetID())
|
||||
if(bot_core.allowed(user) && !open && !emagged)
|
||||
locked = !locked
|
||||
to_chat(user, "<span class='notice'>You [ locked ? "lock" : "unlock"] \the [src] behaviour controls.</span>")
|
||||
@@ -161,7 +174,7 @@
|
||||
if(open)
|
||||
to_chat(user, "<span class='warning'>Please close the access panel before locking it.</span>")
|
||||
else
|
||||
to_chat(user, "<span class='notice'>The [src] doesn't seem to respect your authority.</span>")
|
||||
to_chat(user, "<span class='notice'>\The [src] doesn't seem to respect your authority.</span>")
|
||||
|
||||
else if(istype(W, /obj/item/kitchen/knife) && user.a_intent != INTENT_HARM)
|
||||
to_chat(user, "<span class='notice'>You start attaching \the [W] to \the [src]...</span>")
|
||||
@@ -203,7 +216,8 @@
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/bot/cleanbot/emag_act(mob/user)
|
||||
. = ..()
|
||||
..()
|
||||
|
||||
if(emagged == 2)
|
||||
if(weapon)
|
||||
weapon.force = weapon_orig_force
|
||||
@@ -259,6 +273,9 @@
|
||||
if(!target && trash) //Then for trash.
|
||||
target = scan(/obj/item/trash)
|
||||
|
||||
// if(!target && trash) //Search for dead mices.
|
||||
// target = scan(/obj/item/food/deadmouse)
|
||||
|
||||
if(!target && auto_patrol) //Search for cleanables it can see.
|
||||
if(mode == BOT_IDLE || mode == BOT_START_PATROL)
|
||||
start_patrol()
|
||||
@@ -335,13 +352,18 @@
|
||||
target_types += /mob/living/simple_animal/cockroach
|
||||
target_types += /mob/living/simple_animal/mouse
|
||||
|
||||
if(drawn)
|
||||
target_types += /obj/effect/decal/cleanable/crayon
|
||||
|
||||
if(trash)
|
||||
target_types += /obj/item/trash
|
||||
target_types += /obj/item/reagent_containers/food/snacks/meat/slab/human
|
||||
|
||||
target_types = typecacheof(target_types)
|
||||
|
||||
/mob/living/simple_animal/bot/cleanbot/UnarmedAttack(atom/A, proximity, intent = a_intent, flags = NONE)
|
||||
/mob/living/simple_animal/bot/cleanbot/UnarmedAttack(atom/A)
|
||||
if(HAS_TRAIT(src, TRAIT_HANDS_BLOCKED))
|
||||
return
|
||||
if(istype(A, /obj/effect/decal/cleanable))
|
||||
anchored = TRUE
|
||||
icon_state = "cleanbot-c"
|
||||
@@ -361,8 +383,9 @@
|
||||
icon_state = "cleanbot[on]"
|
||||
else if(istype(A, /obj/item) || istype(A, /obj/effect/decal/remains))
|
||||
visible_message("<span class='danger'>[src] sprays hydrofluoric acid at [A]!</span>")
|
||||
playsound(src, 'sound/effects/spray2.ogg', 50, 1, -6)
|
||||
playsound(src, 'sound/effects/spray2.ogg', 50, TRUE, -6)
|
||||
A.acid_act(75, 10)
|
||||
target = null
|
||||
else if(istype(A, /mob/living/simple_animal/cockroach) || istype(A, /mob/living/simple_animal/mouse))
|
||||
var/mob/living/simple_animal/M = target
|
||||
if(!M.stat)
|
||||
@@ -383,7 +406,7 @@
|
||||
"FREED AT LEST FROM FILTHY PROGRAMMING.")
|
||||
say(phrase)
|
||||
victim.emote("scream")
|
||||
playsound(src.loc, 'sound/effects/spray2.ogg', 50, 1, -6)
|
||||
playsound(src.loc, 'sound/effects/spray2.ogg', 50, TRUE, -6)
|
||||
victim.acid_act(5, 100)
|
||||
else if(A == src) // Wets floors and spawns foam randomly
|
||||
if(prob(75))
|
||||
@@ -412,10 +435,14 @@
|
||||
do_sparks(3, TRUE, src)
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/bot/cleanbot/medbay
|
||||
name = "Scrubs, MD"
|
||||
bot_core_type = /obj/machinery/bot_core/cleanbot/medbay
|
||||
on = FALSE
|
||||
|
||||
/obj/machinery/bot_core/cleanbot
|
||||
req_one_access = list(ACCESS_JANITOR, ACCESS_ROBOTICS)
|
||||
|
||||
|
||||
/mob/living/simple_animal/bot/cleanbot/get_controls(mob/user)
|
||||
var/dat
|
||||
dat += hack(user)
|
||||
@@ -424,9 +451,10 @@
|
||||
Status: <A href='?src=[REF(src)];power=1'>[on ? "On" : "Off"]</A><BR>
|
||||
Behaviour controls are [locked ? "locked" : "unlocked"]<BR>
|
||||
Maintenance panel panel is [open ? "opened" : "closed"]"})
|
||||
if(!locked || hasSiliconAccessInArea(user)|| IsAdminGhost(user))
|
||||
if(!locked || issilicon(user)|| IsAdminGhost(user))
|
||||
dat += "<BR>Clean Blood: <A href='?src=[REF(src)];operation=blood'>[blood ? "Yes" : "No"]</A>"
|
||||
dat += "<BR>Clean Trash: <A href='?src=[REF(src)];operation=trash'>[trash ? "Yes" : "No"]</A>"
|
||||
dat += "<BR>Clean Graffiti: <A href='?src=[REF(src)];operation=drawn'>[drawn ? "Yes" : "No"]</A>"
|
||||
dat += "<BR>Exterminate Pests: <A href='?src=[REF(src)];operation=pests'>[pests ? "Yes" : "No"]</A>"
|
||||
dat += "<BR><BR>Patrol Station: <A href='?src=[REF(src)];operation=patrol'>[auto_patrol ? "Yes" : "No"]</A>"
|
||||
return dat
|
||||
@@ -442,5 +470,10 @@ Maintenance panel panel is [open ? "opened" : "closed"]"})
|
||||
pests = !pests
|
||||
if("trash")
|
||||
trash = !trash
|
||||
if("drawn")
|
||||
drawn = !drawn
|
||||
get_targets()
|
||||
update_controls()
|
||||
|
||||
/obj/machinery/bot_core/cleanbot/medbay
|
||||
req_one_access = list(ACCESS_JANITOR, ACCESS_ROBOTICS, ACCESS_MEDICAL)
|
||||
|
||||
@@ -44,6 +44,9 @@ Difficulty: Medium
|
||||
wander = FALSE
|
||||
del_on_death = TRUE
|
||||
blood_volume = BLOOD_VOLUME_NORMAL
|
||||
achievement_type = /datum/award/achievement/boss/blood_miner_kill
|
||||
crusher_achievement_type = /datum/award/achievement/boss/blood_miner_crusher
|
||||
score_achievement_type = /datum/award/score/blood_miner_score
|
||||
medal_type = BOSS_MEDAL_MINER
|
||||
var/obj/item/melee/transforming/cleaving_saw/miner/miner_saw
|
||||
var/time_until_next_transform = 0
|
||||
|
||||
@@ -51,8 +51,11 @@ Difficulty: Hard
|
||||
crusher_loot = list(/obj/structure/closet/crate/necropolis/bubblegum/crusher)
|
||||
loot = list(/obj/structure/closet/crate/necropolis/bubblegum)
|
||||
var/charging = 0
|
||||
medal_type = BOSS_MEDAL_BUBBLEGUM
|
||||
score_type = BUBBLEGUM_SCORE
|
||||
|
||||
achievement_type = /datum/award/achievement/boss/bubblegum_kill
|
||||
crusher_achievement_type = /datum/award/achievement/boss/bubblegum_crusher
|
||||
score_achievement_type = /datum/award/score/bubblegum_score
|
||||
|
||||
deathmessage = "sinks into a pool of blood, fleeing the battle. You've won, for now... "
|
||||
death_sound = 'sound/magic/enter_blood.ogg'
|
||||
|
||||
@@ -153,6 +156,20 @@ Difficulty: Hard
|
||||
charging = 0
|
||||
Goto(target, move_to_delay, minimum_distance)
|
||||
|
||||
/**
|
||||
* Attack by override for bubblegum
|
||||
*
|
||||
* This is used to award the frenching achievement for hitting bubblegum with a tongue
|
||||
*
|
||||
* Arguments:
|
||||
* * obj/item/W the item hitting bubblegum
|
||||
* * mob/user The user of the item
|
||||
* * params, extra parameters
|
||||
*/
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/attackby(obj/item/W, mob/user, params)
|
||||
. = ..()
|
||||
if(istype(W, /obj/item/organ/tongue))
|
||||
user.client?.give_award(/datum/award/achievement/misc/frenching, user)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/Bump(atom/A)
|
||||
if(charging)
|
||||
|
||||
@@ -43,9 +43,10 @@ Difficulty: Very Hard
|
||||
move_to_delay = 10
|
||||
ranged = 1
|
||||
pixel_x = -32
|
||||
del_on_death = 1
|
||||
medal_type = BOSS_MEDAL_COLOSSUS
|
||||
score_type = COLOSSUS_SCORE
|
||||
del_on_death = TRUE
|
||||
achievement_type = /datum/award/achievement/boss/colossus_kill
|
||||
crusher_achievement_type = /datum/award/achievement/boss/colossus_crusher
|
||||
score_achievement_type = /datum/award/score/colussus_score
|
||||
crusher_loot = list(/obj/structure/closet/crate/necropolis/colossus/crusher)
|
||||
loot = list(/obj/structure/closet/crate/necropolis/colossus)
|
||||
butcher_results = list(/obj/item/stack/ore/diamond = 5, /obj/item/stack/sheet/sinew = 5, /obj/item/stack/sheet/animalhide/ashdrake = 10, /obj/item/stack/sheet/bone = 30)
|
||||
|
||||
@@ -31,6 +31,9 @@ Difficulty: Extremely Hard
|
||||
wander = FALSE
|
||||
del_on_death = TRUE
|
||||
blood_volume = BLOOD_VOLUME_NORMAL
|
||||
achievement_type = /datum/award/achievement/boss/demonic_miner_kill
|
||||
crusher_achievement_type = /datum/award/achievement/boss/demonic_miner_crusher
|
||||
score_achievement_type = /datum/award/score/demonic_miner_score
|
||||
deathmessage = "falls to the ground, decaying into plasma particles."
|
||||
deathsound = "bodyfall"
|
||||
attack_action_types = list(/datum/action/innate/megafauna_attack/frost_orbs,
|
||||
|
||||
@@ -64,8 +64,9 @@ Difficulty: Medium
|
||||
guaranteed_butcher_results = list(/obj/item/stack/sheet/animalhide/ashdrake = 10)
|
||||
var/swooping = NONE
|
||||
var/swoop_cooldown = 0
|
||||
medal_type = BOSS_MEDAL_DRAKE
|
||||
score_type = DRAKE_SCORE
|
||||
achievement_type = /datum/award/achievement/boss/drake_kill
|
||||
crusher_achievement_type = /datum/award/achievement/boss/drake_crusher
|
||||
score_achievement_type = /datum/award/score/drake_score
|
||||
deathmessage = "collapses into a pile of bones, its flesh sloughing away."
|
||||
death_sound = 'sound/magic/demon_dies.ogg'
|
||||
var/datum/action/small_sprite/smallsprite = new/datum/action/small_sprite/drake()
|
||||
|
||||
@@ -61,8 +61,9 @@ Difficulty: Normal
|
||||
loot = list(/obj/item/hierophant_club)
|
||||
crusher_loot = list(/obj/item/hierophant_club)
|
||||
wander = FALSE
|
||||
medal_type = BOSS_MEDAL_HIEROPHANT
|
||||
score_type = HIEROPHANT_SCORE
|
||||
achievement_type = /datum/award/achievement/boss/hierophant_kill
|
||||
crusher_achievement_type = /datum/award/achievement/boss/hierophant_crusher
|
||||
score_achievement_type = /datum/award/score/hierophant_score
|
||||
del_on_death = TRUE
|
||||
death_sound = 'sound/magic/repulse.ogg'
|
||||
|
||||
|
||||
@@ -42,8 +42,9 @@ SHITCODE AHEAD. BE ADVISED. Also comment extravaganza
|
||||
retreat_distance = 5
|
||||
minimum_distance = 5
|
||||
ranged_cooldown_time = 10
|
||||
medal_type = BOSS_MEDAL_LEGION
|
||||
score_type = LEGION_SCORE
|
||||
achievement_type = /datum/award/achievement/boss/legion_kill
|
||||
crusher_achievement_type = /datum/award/achievement/boss/legion_crusher
|
||||
score_achievement_type = /datum/award/score/legion_score
|
||||
pixel_y = -16
|
||||
pixel_x = -32
|
||||
loot = list(/obj/item/stack/sheet/bone = 3)
|
||||
|
||||
@@ -28,24 +28,31 @@
|
||||
layer = LARGE_MOB_LAYER //Looks weird with them slipping under mineral walls and cameras and shit otherwise
|
||||
flags_1 = PREVENT_CONTENTS_EXPLOSION_1 | HEAR_1
|
||||
has_field_of_vision = FALSE //You are a frikkin boss
|
||||
/// Crusher loot dropped when fauna killed with a crusher
|
||||
/// Crusher loot dropped when the megafauna is killed with a crusher
|
||||
var/list/crusher_loot
|
||||
var/medal_type
|
||||
/// Score given to players when the fauna is killed
|
||||
var/score_type = BOSS_SCORE
|
||||
/// If the megafauna is actually killed (vs entering another phase)
|
||||
/// Achievement given to surrounding players when the megafauna is killed
|
||||
var/achievement_type
|
||||
/// Crusher achievement given to players when megafauna is killed
|
||||
var/crusher_achievement_type
|
||||
/// Score given to players when megafauna is killed
|
||||
var/score_achievement_type
|
||||
/// If the megafauna was actually killed (not just dying, then transforming into another type)
|
||||
var/elimination = 0
|
||||
/// Modifies attacks when at lower health
|
||||
var/anger_modifier = 0
|
||||
/// Internal tracking GPS inside fauna
|
||||
var/obj/item/gps/internal
|
||||
/// Next time fauna can use a melee attack
|
||||
/// Next time the megafauna can use a melee attack
|
||||
var/recovery_time = 0
|
||||
|
||||
var/true_spawn = TRUE // if this is a megafauna that should grant achievements, or have a gps signal
|
||||
/// If this is a megafauna that is real (has achievements, gps signal)
|
||||
var/true_spawn = TRUE
|
||||
/// Range the megafauna can move from their nest (if they have one
|
||||
var/nest_range = 10
|
||||
var/chosen_attack = 1 // chosen attack num
|
||||
/// The chosen attack by the megafauna
|
||||
var/chosen_attack = 1
|
||||
/// Attack actions, sets chosen_attack to the number in the action
|
||||
var/list/attack_action_types = list()
|
||||
/// If there is a small sprite icon for players controlling the megafauna to use
|
||||
var/small_sprite_type
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/Initialize(mapload)
|
||||
@@ -73,23 +80,22 @@
|
||||
return
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/death(gibbed)
|
||||
/mob/living/simple_animal/hostile/megafauna/death(gibbed, list/force_grant)
|
||||
if(health > 0)
|
||||
return
|
||||
else
|
||||
var/datum/status_effect/crusher_damage/C = has_status_effect(STATUS_EFFECT_CRUSHERDAMAGETRACKING)
|
||||
var/crusher_kill = FALSE
|
||||
if(C && crusher_loot && C.total_damage >= maxHealth * 0.6)
|
||||
spawn_crusher_loot()
|
||||
crusher_kill = TRUE
|
||||
if(!(flags_1 & ADMIN_SPAWNED_1))
|
||||
var/tab = "megafauna_kills"
|
||||
if(crusher_kill)
|
||||
tab = "megafauna_kills_crusher"
|
||||
var/datum/status_effect/crusher_damage/crusher_dmg = has_status_effect(STATUS_EFFECT_CRUSHERDAMAGETRACKING)
|
||||
var/crusher_kill = FALSE
|
||||
if(crusher_dmg && crusher_loot && crusher_dmg.total_damage >= maxHealth * 0.6)
|
||||
spawn_crusher_loot()
|
||||
crusher_kill = TRUE
|
||||
if(true_spawn && !(flags_1 & ADMIN_SPAWNED_1))
|
||||
var/tab = "megafauna_kills"
|
||||
if(crusher_kill)
|
||||
tab = "megafauna_kills_crusher"
|
||||
if(!elimination) //used so the achievment only occurs for the last legion to die.
|
||||
grant_achievement(achievement_type, score_achievement_type, crusher_kill, force_grant)
|
||||
SSblackbox.record_feedback("tally", tab, 1, "[initial(name)]")
|
||||
if(!elimination) //used so the achievment only occurs for the last legion to die.
|
||||
grant_achievement(medal_type, score_type, crusher_kill)
|
||||
..()
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/proc/spawn_crusher_loot()
|
||||
loot = crusher_loot
|
||||
@@ -143,26 +149,29 @@
|
||||
if(EXPLODE_LIGHT)
|
||||
adjustBruteLoss(50)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/proc/SetRecoveryTime(buffer_time)
|
||||
/// 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
|
||||
ranged_cooldown = max(ranged_cooldown, world.time + buffer_time) // CITADEL BANDAID FIX FOR MEGAFAUNA NOT RESPECTING RECOVERY TIME.
|
||||
ranged_cooldown = world.time + buffer_time
|
||||
if(ranged_buffer_time)
|
||||
ranged_cooldown = world.time + ranged_buffer_time
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/proc/grant_achievement(medaltype, scoretype, crusher_kill)
|
||||
if(!medal_type || (flags_1 & ADMIN_SPAWNED_1)) //Don't award medals if the medal type isn't set
|
||||
/// Grants medals and achievements to surrounding players
|
||||
/mob/living/simple_animal/hostile/megafauna/proc/grant_achievement(medaltype, scoretype, crusher_kill, list/grant_achievement = list())
|
||||
if(!achievement_type || (flags_1 & ADMIN_SPAWNED_1) || !SSachievements.achievements_enabled) //Don't award medals if the medal type isn't set
|
||||
return FALSE
|
||||
if(!SSmedals.hub_enabled) // This allows subtypes to carry on other special rewards not tied with medals. (such as bubblegum's arena shuttle)
|
||||
return TRUE
|
||||
|
||||
for(var/mob/living/L in view(7,src))
|
||||
if(!grant_achievement.len)
|
||||
for(var/mob/living/L in view(7,src))
|
||||
grant_achievement += L
|
||||
for(var/mob/living/L in grant_achievement)
|
||||
if(L.stat || !L.client)
|
||||
continue
|
||||
var/client/C = L.client
|
||||
SSmedals.UnlockMedal("Boss [BOSS_KILL_MEDAL]", C)
|
||||
SSmedals.UnlockMedal("[medaltype] [BOSS_KILL_MEDAL]", C)
|
||||
L.client.give_award(/datum/award/achievement/boss/boss_killer, L)
|
||||
L.client.give_award(achievement_type, L)
|
||||
if(crusher_kill && istype(L.get_active_held_item(), /obj/item/kinetic_crusher))
|
||||
SSmedals.UnlockMedal("[medaltype] [BOSS_KILL_MEDAL_CRUSHER]", C)
|
||||
SSmedals.SetScore(BOSS_SCORE, C, 1)
|
||||
SSmedals.SetScore(score_type, C, 1)
|
||||
L.client.give_award(crusher_achievement_type, L)
|
||||
L.client.give_award(/datum/award/score/boss_score, L) //Score progression for bosses killed in general
|
||||
L.client.give_award(score_achievement_type, L) //Score progression for specific boss killed
|
||||
return TRUE
|
||||
|
||||
/datum/action/innate/megafauna_attack
|
||||
|
||||
@@ -48,8 +48,9 @@ GLOBAL_LIST_INIT(AISwarmerCapsByType, list(/mob/living/simple_animal/hostile/swa
|
||||
health = 750
|
||||
maxHealth = 750 //""""low-ish"""" HP because it's a passive boss, and the swarm itself is the real foe
|
||||
mob_biotypes = MOB_ROBOTIC
|
||||
medal_type = BOSS_MEDAL_SWARMERS
|
||||
score_type = SWARMER_BEACON_SCORE
|
||||
achievement_type = /datum/award/achievement/boss/swarmer_beacon_kill
|
||||
crusher_achievement_type = /datum/award/achievement/boss/swarmer_beacon_crusher
|
||||
score_achievement_type = /datum/award/score/swarmer_beacon_score
|
||||
faction = list("mining", "boss", "swarmer")
|
||||
weather_immunities = list("lava","ash")
|
||||
stop_automated_movement = TRUE
|
||||
|
||||
@@ -81,13 +81,14 @@
|
||||
surgery.status++
|
||||
if(surgery.status > surgery.steps.len)
|
||||
surgery.complete()
|
||||
surgery.step_in_progress = FALSE
|
||||
return advance
|
||||
else
|
||||
surgery.step_in_progress = FALSE
|
||||
if(repeatable)
|
||||
return FALSE //This is how the repeatable surgery detects it shouldn't cycle
|
||||
return TRUE //Stop the attack chain! - Except on repeatable steps, because otherwise we land in an infinite loop.
|
||||
|
||||
if(target.stat == DEAD && was_sleeping && user.client)
|
||||
user.client.give_award(/datum/award/achievement/misc/sandman, user)
|
||||
|
||||
surgery.step_in_progress = FALSE
|
||||
if(repeatable)
|
||||
return FALSE //This is how the repeatable surgery detects it shouldn't cycle
|
||||
return advance //Stop the attack chain! - Except on repeatable steps, because otherwise we land in an infinite loop.
|
||||
|
||||
|
||||
/datum/surgery_step/proc/preop(mob/user, mob/living/target, target_zone, obj/item/tool, datum/surgery/surgery)
|
||||
|
||||
@@ -559,6 +559,9 @@ GLOBAL_LIST_EMPTY(vending_products)
|
||||
if(crit_case)
|
||||
L.apply_damage(squish_damage, forced=TRUE)
|
||||
|
||||
if(was_alive && L.stat == DEAD && L.client)
|
||||
L.client.give_award(/datum/award/achievement/misc/vendor_squish, L) // good job losing a fight with an inanimate object idiot
|
||||
|
||||
L.Paralyze(60)
|
||||
L.emote("scream")
|
||||
playsound(L, 'sound/effects/blobattack.ogg', 40, TRUE)
|
||||
|
||||
BIN
icons/UI_Icons/Achievements/Boss/bbgum.png
Normal file
|
After Width: | Height: | Size: 4.8 KiB |
BIN
icons/UI_Icons/Achievements/Boss/colossus.png
Normal file
|
After Width: | Height: | Size: 5.9 KiB |
BIN
icons/UI_Icons/Achievements/Boss/drake.png
Normal file
|
After Width: | Height: | Size: 7.7 KiB |
BIN
icons/UI_Icons/Achievements/Boss/hierophant.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
icons/UI_Icons/Achievements/Boss/legion.png
Normal file
|
After Width: | Height: | Size: 7.8 KiB |
BIN
icons/UI_Icons/Achievements/Boss/miner.png
Normal file
|
After Width: | Height: | Size: 3.4 KiB |
BIN
icons/UI_Icons/Achievements/Boss/swarmer.png
Normal file
|
After Width: | Height: | Size: 3.9 KiB |
BIN
icons/UI_Icons/Achievements/Boss/tendril.png
Normal file
|
After Width: | Height: | Size: 6.4 KiB |
BIN
icons/UI_Icons/Achievements/Mafia/assistant.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
icons/UI_Icons/Achievements/Mafia/changeling.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
icons/UI_Icons/Achievements/Mafia/chaplain.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
icons/UI_Icons/Achievements/Mafia/clown.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
icons/UI_Icons/Achievements/Mafia/detective.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
icons/UI_Icons/Achievements/Mafia/fugitive.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
icons/UI_Icons/Achievements/Mafia/hated.png
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
BIN
icons/UI_Icons/Achievements/Mafia/hop.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
icons/UI_Icons/Achievements/Mafia/lawyer.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
icons/UI_Icons/Achievements/Mafia/md.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
icons/UI_Icons/Achievements/Mafia/nightmare.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
icons/UI_Icons/Achievements/Mafia/obsessed.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
icons/UI_Icons/Achievements/Mafia/psychologist.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
icons/UI_Icons/Achievements/Mafia/thoughtfeeder.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
icons/UI_Icons/Achievements/Mafia/traitor.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
icons/UI_Icons/Achievements/Misc/ascension.png
Normal file
|
After Width: | Height: | Size: 3.0 KiB |
BIN
icons/UI_Icons/Achievements/Misc/ashascend.png
Normal file
|
After Width: | Height: | Size: 9.4 KiB |
BIN
icons/UI_Icons/Achievements/Misc/clownking.png
Normal file
|
After Width: | Height: | Size: 5.0 KiB |
BIN
icons/UI_Icons/Achievements/Misc/clownthanks.png
Normal file
|
After Width: | Height: | Size: 3.4 KiB |
BIN
icons/UI_Icons/Achievements/Misc/featofstrength.png
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
BIN
icons/UI_Icons/Achievements/Misc/fleshascend.png
Normal file
|
After Width: | Height: | Size: 7.9 KiB |
BIN
icons/UI_Icons/Achievements/Misc/frenchingthebubble.png
Normal file
|
After Width: | Height: | Size: 4.8 KiB |
BIN
icons/UI_Icons/Achievements/Misc/helbital.png
Normal file
|
After Width: | Height: | Size: 3.3 KiB |
BIN
icons/UI_Icons/Achievements/Misc/jackpot.png
Normal file
|
After Width: | Height: | Size: 3.0 KiB |