Merge branch 'master' into alcohol-intolerance
This commit is contained in:
@@ -12,6 +12,7 @@
|
||||
#define APPRENTICE_BLUESPACE "bluespace"
|
||||
#define APPRENTICE_ROBELESS "robeless"
|
||||
#define APPRENTICE_HEALING "healing"
|
||||
#define APPRENTICE_MARTIAL "martial"
|
||||
|
||||
|
||||
//ERT Types
|
||||
|
||||
@@ -57,9 +57,9 @@
|
||||
#define BALLS_SACK_SIZE_DEF 8
|
||||
#define BALLS_SACK_SIZE_MAX 40
|
||||
|
||||
#define CUM_RATE 0.035
|
||||
#define CUM_RATE 2 // holy shit what a really shitty define name - relates to units per arbitrary measure of time?
|
||||
#define CUM_RATE_MULT 1
|
||||
#define CUM_EFFICIENCY 1//amount of nutrition required per life()
|
||||
#define CUM_EFFICIENCY 1 //amount of nutrition required per life()
|
||||
|
||||
#define EGG_GIRTH_MIN 1//inches
|
||||
#define EGG_GIRTH_DEF 6
|
||||
@@ -109,8 +109,16 @@
|
||||
#define MEDIHOUND_SLEEPER (1<<0)
|
||||
#define EATING_NOISES (1<<1)
|
||||
#define DIGESTION_NOISES (1<<2)
|
||||
#define BREAST_ENLARGEMENT (1<<3)
|
||||
#define PENIS_ENLARGEMENT (1<<4)
|
||||
#define FORCED_FEM (1<<5)
|
||||
#define FORCED_MASC (1<<6)
|
||||
#define HYPNO (1<<7)
|
||||
#define NEVER_HYPNO (1<<8)
|
||||
#define NO_APHRO (1<<9)
|
||||
#define NO_ASS_SLAP (1<<10)
|
||||
|
||||
#define TOGGLES_CITADEL (EATING_NOISES|DIGESTION_NOISES)
|
||||
#define TOGGLES_CITADEL (EATING_NOISES|DIGESTION_NOISES|BREAST_ENLARGEMENT|PENIS_ENLARGEMENT)
|
||||
|
||||
//component stuff
|
||||
#define COMSIG_COMBAT_TOGGLED "combatmode_toggled" //called by combat mode toggle on all equipped items. args: (mob/user, combatmode)
|
||||
|
||||
@@ -54,6 +54,10 @@
|
||||
#define EXAMINE_POSITION_BEFORE 2
|
||||
//End positions
|
||||
#define COMPONENT_EXNAME_CHANGED 1
|
||||
#define COMSIG_ATOM_UPDATE_ICON "atom_update_icon" //from base of atom/update_icon(): ()
|
||||
#define COMSIG_ATOM_NO_UPDATE_ICON_STATE 1
|
||||
#define COMSIG_ATOM_NO_UPDATE_OVERLAYS 2
|
||||
#define COMSIG_ATOM_UPDATE_OVERLAYS "atom_update_overlays" //from base of atom/update_overlays(): (list/new_overlays)
|
||||
#define COMSIG_ATOM_ENTERED "atom_entered" //from base of atom/Entered(): (atom/movable/entering, /atom)
|
||||
#define COMSIG_ATOM_EXIT "atom_exit" //from base of atom/Exit(): (/atom/movable/exiting, /atom/newloc)
|
||||
#define COMPONENT_ATOM_BLOCK_EXIT 1
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
#define CURRENT_LIVING_PLAYERS 1
|
||||
#define CURRENT_LIVING_ANTAGS 2
|
||||
#define CURRENT_DEAD_PLAYERS 3
|
||||
#define CURRENT_OBSERVERS 4
|
||||
|
||||
#define NO_ASSASSIN (1<<0)
|
||||
#define WAROPS_ALWAYS_ALLOWED (1<<1)
|
||||
|
||||
#define ONLY_RULESET (1<<0)
|
||||
#define HIGHLANDER_RULESET (1<<1)
|
||||
#define TRAITOR_RULESET (1<<2)
|
||||
#define MINOR_RULESET (1<<3)
|
||||
|
||||
#define RULESET_STOP_PROCESSING 1
|
||||
@@ -11,6 +11,7 @@
|
||||
#define GROSS (1<<10)
|
||||
#define TOXIC (1<<11)
|
||||
#define PINEAPPLE (1<<12)
|
||||
#define BREAKFAST (1<<13)
|
||||
|
||||
#define DRINK_NICE 1
|
||||
#define DRINK_GOOD 2
|
||||
|
||||
@@ -118,6 +118,8 @@ GLOBAL_LIST_INIT(turfs_without_ground, typecacheof(list(
|
||||
|
||||
#define ismouse(A) (istype(A, /mob/living/simple_animal/mouse))
|
||||
|
||||
#define iscow(A) (istype(A, /mob/living/simple_animal/cow))
|
||||
|
||||
#define isslime(A) (istype(A, /mob/living/simple_animal/slime))
|
||||
|
||||
#define isdrone(A) (istype(A, /mob/living/simple_animal/drone))
|
||||
@@ -222,6 +224,8 @@ GLOBAL_LIST_INIT(heavyfootmob, typecacheof(list(
|
||||
|
||||
#define isorgan(A) (istype(A, /obj/item/organ))
|
||||
|
||||
#define isclothing(A) (istype(A, /obj/item/clothing))
|
||||
|
||||
GLOBAL_LIST_INIT(pointed_types, typecacheof(list(
|
||||
/obj/item/pen,
|
||||
/obj/item/screwdriver,
|
||||
|
||||
@@ -59,11 +59,13 @@
|
||||
#define LIGHT_RANGE_FIRE 3 //How many tiles standard fires glow.
|
||||
|
||||
#define LIGHTING_PLANE_ALPHA_VISIBLE 255
|
||||
#define LIGHTING_PLANE_ALPHA_NV_TRAIT 250
|
||||
#define LIGHTING_PLANE_ALPHA_NV_TRAIT 223
|
||||
#define LIGHTING_PLANE_ALPHA_MOSTLY_VISIBLE 192
|
||||
#define LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE 128 //For lighting alpha, small amounts lead to big changes. even at 128 its hard to figure out what is dark and what is light, at 64 you almost can't even tell.
|
||||
#define LIGHTING_PLANE_ALPHA_INVISIBLE 0
|
||||
|
||||
#define NIGHT_VISION_DARKSIGHT_RANGE 3
|
||||
|
||||
//lighting area defines
|
||||
#define DYNAMIC_LIGHTING_DISABLED 0 //dynamic lighting disabled (area stays at full brightness)
|
||||
#define DYNAMIC_LIGHTING_ENABLED 1 //dynamic lighting enabled
|
||||
@@ -80,4 +82,4 @@
|
||||
|
||||
#define FLASH_LIGHT_DURATION 2
|
||||
#define FLASH_LIGHT_POWER 3
|
||||
#define FLASH_LIGHT_RANGE 3.8
|
||||
#define FLASH_LIGHT_RANGE 3.8
|
||||
|
||||
@@ -38,8 +38,6 @@ require only minor tweaks.
|
||||
#define ZTRAIT_SPACE_RUINS "Space Ruins"
|
||||
#define ZTRAIT_LAVA_RUINS "Lava Ruins"
|
||||
#define ZTRAIT_ISOLATED_RUINS "Isolated Ruins" //Placing ruins on z levels with this trait will use turf reservation instead of usual placement.
|
||||
// prevents certain turfs from being stripped by a singularity
|
||||
#define ZTRAIT_PLANET "Planet"
|
||||
|
||||
// number - bombcap is multiplied by this before being applied to bombs
|
||||
#define ZTRAIT_BOMBCAP_MULTIPLIER "Bombcap Multiplier"
|
||||
@@ -60,11 +58,18 @@ require only minor tweaks.
|
||||
// CROSSLINKED - mixed in with the cross-linked space pool
|
||||
#define CROSSLINKED "Cross"
|
||||
|
||||
// string - type path of the z-level's baseturf (defaults to space)
|
||||
#define ZTRAIT_BASETURF "Baseturf"
|
||||
|
||||
// default trait definitions, used by SSmapping
|
||||
#define ZTRAITS_CENTCOM list(ZTRAIT_CENTCOM = TRUE)
|
||||
#define ZTRAITS_STATION list(ZTRAIT_LINKAGE = CROSSLINKED, ZTRAIT_STATION = TRUE)
|
||||
#define ZTRAITS_SPACE list(ZTRAIT_LINKAGE = CROSSLINKED, ZTRAIT_SPACE_RUINS = TRUE)
|
||||
#define ZTRAITS_LAVALAND list(ZTRAIT_MINING = TRUE, ZTRAIT_LAVA_RUINS = TRUE, ZTRAIT_BOMBCAP_MULTIPLIER = 5)
|
||||
#define ZTRAITS_LAVALAND list(\
|
||||
ZTRAIT_MINING = TRUE, \
|
||||
ZTRAIT_LAVA_RUINS = TRUE, \
|
||||
ZTRAIT_BOMBCAP_MULTIPLIER = 5, \
|
||||
ZTRAIT_BASETURF = /turf/open/lava/smooth/lava_land_surface)
|
||||
#define ZTRAITS_REEBE list(ZTRAIT_REEBE = TRUE, ZTRAIT_BOMBCAP_MULTIPLIER = 0.5)
|
||||
|
||||
#define DL_NAME "name"
|
||||
|
||||
@@ -7,4 +7,5 @@
|
||||
#define MARTIALART_MUSHPUNCH "mushroom punch"
|
||||
#define MARTIALART_KRAVMAGA "krav maga"
|
||||
#define MARTIALART_CQC "CQC"
|
||||
#define MARTIALART_PLASMAFIST "plasma fist"
|
||||
#define MARTIALART_PLASMAFIST "plasma fist"
|
||||
#define MARTIALART_RISINGBASS "rising bass"
|
||||
@@ -427,6 +427,7 @@ GLOBAL_LIST_INIT(pda_reskins, list(PDA_SKIN_CLASSIC = 'icons/obj/pda.dmi', PDA_S
|
||||
|
||||
//Dummy mob reserve slots
|
||||
#define DUMMY_HUMAN_SLOT_PREFERENCES "dummy_preference_preview"
|
||||
#define DUMMY_HUMAN_SLOT_HOLOFORM "dummy_holoform_generation"
|
||||
#define DUMMY_HUMAN_SLOT_ADMIN "admintools"
|
||||
#define DUMMY_HUMAN_SLOT_MANIFEST "dummy_manifest_generation"
|
||||
|
||||
@@ -528,3 +529,11 @@ GLOBAL_LIST_INIT(pda_reskins, list(PDA_SKIN_CLASSIC = 'icons/obj/pda.dmi', PDA_S
|
||||
#define FOURSPACES " "
|
||||
|
||||
#define CRYOMOBS 'icons/obj/cryo_mobs.dmi'
|
||||
|
||||
#define CUSTOM_HOLOFORM_DELAY 10 SECONDS //prevents spamming to make lag. it's pretty expensive to do this.
|
||||
|
||||
#define HOLOFORM_FILTER_AI "FILTER_AI"
|
||||
#define HOLOFORM_FILTER_PAI "FILTER_PAI"
|
||||
#define HOLOFORM_FILTER_STATIC "FILTER_STATIC"
|
||||
|
||||
#define CANT_REENTER_ROUND -1
|
||||
|
||||
@@ -57,6 +57,7 @@
|
||||
|
||||
#define MOVESPEED_ID_PRONE_DRAGGING "PRONE_DRAG"
|
||||
#define MOVESPEED_ID_HUMAN_CARRYING "HUMAN_CARRY"
|
||||
#define MOVESPEED_ID_SHRINK_RAY "SHRUNKEN_SPEED_MODIFIER"
|
||||
|
||||
#define MOVESPEED_ID_TASED_STATUS "TASED"
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
#define VOICEBOX_TOGGLABLE (1<<6) //The voicebox in this clothing can be toggled.
|
||||
#define VOICEBOX_DISABLED (1<<7) //The voicebox is currently turned off.
|
||||
#define IGNORE_HAT_TOSS (1<<8) //Hats with negative effects when worn (i.e the tinfoil hat).
|
||||
#define SCAN_REAGENTS (1<<9) // Allows helmets and glasses to scan reagents.
|
||||
|
||||
// Flags for the organ_flags var on /obj/item/organ
|
||||
|
||||
|
||||
@@ -118,6 +118,7 @@
|
||||
#define TRAIT_PARALYSIS_R_ARM "para-r-arm"
|
||||
#define TRAIT_PARALYSIS_L_LEG "para-l-leg"
|
||||
#define TRAIT_PARALYSIS_R_LEG "para-r-leg"
|
||||
#define TRAIT_DISK_VERIFIER "disk-verifier"
|
||||
#define TRAIT_UNINTELLIGIBLE_SPEECH "unintelligible-speech"
|
||||
#define TRAIT_SOOTHED_THROAT "soothed-throat"
|
||||
#define TRAIT_LAW_ENFORCEMENT_METABOLISM "law-enforcement-metabolism"
|
||||
@@ -133,6 +134,7 @@
|
||||
#define TRAIT_NORUNNING "norunning" // You walk!
|
||||
#define TRAIT_NOMARROW "nomarrow" // You don't make blood, with chemicals or nanites.
|
||||
#define TRAIT_NOPULSE "nopulse" // Your heart doesn't beat.
|
||||
#define TRAIT_EXEMPT_HEALTH_EVENTS "exempt-health-events"
|
||||
|
||||
|
||||
//non-mob traits
|
||||
@@ -159,17 +161,16 @@
|
||||
#define TRAIT_TAGGER "tagger"
|
||||
#define TRAIT_PHOTOGRAPHER "photographer"
|
||||
#define TRAIT_MUSICIAN "musician"
|
||||
#define TRAIT_CROCRIN_IMMUNE "crocin_immune"
|
||||
#define TRAIT_NYMPHO "nymphomania"
|
||||
#define TRAIT_MASO "masochism"
|
||||
#define TRAIT_EXHIBITIONIST "exhibitionist"
|
||||
#define TRAIT_HIGH_BLOOD "high_blood"
|
||||
#define TRAIT_PHARMA "hepatic_pharmacokinesis"
|
||||
#define TRAIT_PARA "paraplegic"
|
||||
#define TRAIT_EMPATH "empath"
|
||||
#define TRAIT_FRIENDLY "friendly"
|
||||
#define TRAIT_ASSBLASTUSA "assblastusa"
|
||||
#define TRAIT_CULT_EYES "cult_eyes"
|
||||
#define TRAIT_AUTO_CATCH_ITEM "auto_catch_item"
|
||||
#define TRAIT_CLOWN_MENTALITY "clown_mentality" // The future is now, clownman.
|
||||
#define TRAIT_FREESPRINT "free_sprinting"
|
||||
#define TRAIT_NO_ALCOHOL "alcohol_intolerance"
|
||||
|
||||
@@ -192,6 +193,7 @@
|
||||
#define ABSTRACT_ITEM_TRAIT "abstract-item"
|
||||
#define STATUS_EFFECT_TRAIT "status-effect"
|
||||
#define ROUNDSTART_TRAIT "roundstart" //cannot be removed without admin intervention
|
||||
#define GHOSTROLE_TRAIT "ghostrole"
|
||||
|
||||
// unique trait sources, still defines
|
||||
#define STATUE_MUTE "statue"
|
||||
@@ -225,5 +227,9 @@
|
||||
#define NINJA_SUIT_TRAIT "ninja-suit"
|
||||
#define ANTI_DROP_IMPLANT_TRAIT "anti-drop-implant"
|
||||
#define SLEEPING_CARP_TRAIT "sleeping_carp"
|
||||
#define RISING_BASS_TRAIT "rising_bass"
|
||||
#define ABDUCTOR_ANTAGONIST "abductor-antagonist"
|
||||
#define NUKEOP_ANTAGONIST "nukeop-antagonist"
|
||||
#define MADE_UNCLONEABLE "made-uncloneable"
|
||||
#define NUKEOP_TRAIT "nuke-op"
|
||||
#define DEATHSQUAD_TRAIT "deathsquad"
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
#define PLURALITY_VOTING 0
|
||||
#define APPROVAL_VOTING 1
|
||||
#define RANKED_CHOICE_VOTING 2
|
||||
#define SCORE_VOTING 3
|
||||
|
||||
GLOBAL_LIST_INIT(vote_score_options,list("Bad","Poor","Acceptable","Good","Great"))
|
||||
@@ -157,6 +157,8 @@
|
||||
WRITE_LOG(GLOB.config_error_log, text)
|
||||
SEND_TEXT(world.log, text)
|
||||
|
||||
/proc/log_mapping(text)
|
||||
WRITE_LOG(GLOB.world_map_error_log, text)
|
||||
|
||||
/* For logging round startup. */
|
||||
/proc/start_log(log)
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
// Generates a holoform appearance
|
||||
// Equipment list is slot = path.
|
||||
/proc/generate_custom_holoform_from_prefs(datum/preferences/prefs, list/equipment_by_slot, list/inhand_equipment, copy_job = FALSE, apply_loadout = FALSE)
|
||||
ASSERT(prefs)
|
||||
var/mob/living/carbon/human/dummy/mannequin = generate_or_wait_for_human_dummy(DUMMY_HUMAN_SLOT_HOLOFORM)
|
||||
prefs.copy_to(mannequin)
|
||||
if(apply_loadout && prefs.parent)
|
||||
SSjob.equip_loadout(prefs.parent.mob, mannequin, bypass_prereqs = TRUE)
|
||||
if(copy_job)
|
||||
var/datum/job/highest = prefs.get_highest_job()
|
||||
if(highest && !istype(highest, /datum/job/ai) && !istype(highest, /datum/job/cyborg))
|
||||
highest.equip(mannequin, TRUE, preference_source = prefs.parent)
|
||||
|
||||
if(length(equipment_by_slot))
|
||||
for(var/slot in equipment_by_slot)
|
||||
var/obj/item/I = new equipment_by_slot[slot]
|
||||
mannequin.equip_to_slot_if_possible(I, slot, TRUE, TRUE, TRUE, TRUE)
|
||||
if(length(inhand_equipment))
|
||||
for(var/path in inhand_equipment)
|
||||
var/obj/item/I = new path
|
||||
mannequin.equip_to_slot_if_possible(I, SLOT_HANDS, TRUE, TRUE, TRUE, TRUE)
|
||||
|
||||
|
||||
var/icon/combined = new
|
||||
for(var/d in GLOB.cardinals)
|
||||
mannequin.setDir(d)
|
||||
COMPILE_OVERLAYS(mannequin)
|
||||
CHECK_TICK
|
||||
var/icon/capture = getFlatIcon(mannequin)
|
||||
CHECK_TICK
|
||||
combined.Insert(capture, dir = d)
|
||||
CHECK_TICK
|
||||
|
||||
unset_busy_human_dummy(DUMMY_HUMAN_SLOT_HOLOFORM)
|
||||
return combined
|
||||
|
||||
/proc/process_holoform_icon_filter(icon/I, filter_type, clone = TRUE)
|
||||
if(clone)
|
||||
I = icon(I) //Clone
|
||||
switch(filter_type)
|
||||
if(HOLOFORM_FILTER_AI)
|
||||
I = getHologramIcon(I)
|
||||
if(HOLOFORM_FILTER_STATIC)
|
||||
I = getStaticIcon(I)
|
||||
if(HOLOFORM_FILTER_PAI)
|
||||
I = getPAIHologramIcon(I)
|
||||
return I
|
||||
|
||||
//Errors go to user.
|
||||
/proc/generate_custom_holoform_from_prefs_safe(datum/preferences/prefs, mob/user)
|
||||
if(user)
|
||||
if(user.client.prefs.last_custom_holoform > world.time - CUSTOM_HOLOFORM_DELAY)
|
||||
to_chat(user, "<span class='boldwarning'>You are attempting to set your custom holoform too fast!</span>")
|
||||
return
|
||||
return generate_custom_holoform_from_prefs(prefs, null, null, TRUE, TRUE)
|
||||
|
||||
//Prompts this client for custom holoform parameters.
|
||||
/proc/user_interface_custom_holoform(client/C)
|
||||
var/datum/preferences/target_prefs = C.prefs
|
||||
ASSERT(target_prefs)
|
||||
//In the future, maybe add custom path allowances a la admin create outfit but for now..
|
||||
return generate_custom_holoform_from_prefs_safe(target_prefs, C.mob)
|
||||
@@ -447,7 +447,7 @@
|
||||
var/list/candidates = list()
|
||||
|
||||
for(var/mob/dead/observer/G in GLOB.player_list)
|
||||
if(G.reenter_round_timeout < world.realtime)
|
||||
if(G.can_reenter_round(TRUE))
|
||||
candidates += G
|
||||
|
||||
return pollCandidates(Question, jobbanType, gametypeCheck, be_special_flag, poll_time, ignore_category, flashwindow, candidates)
|
||||
|
||||
@@ -939,7 +939,7 @@ world
|
||||
I.pixel_y++
|
||||
add_overlay(I)//And finally add the overlay.
|
||||
|
||||
/proc/getHologramIcon(icon/A, safety=1)//If safety is on, a new icon is not created.
|
||||
/proc/getHologramIcon(icon/A, safety = TRUE)//If safety is on, a new icon is not created.
|
||||
var/icon/flat_icon = safety ? A : new(A)//Has to be a new icon to not constantly change the same icon.
|
||||
flat_icon.ColorTone(rgb(125,180,225))//Let's make it bluish.
|
||||
flat_icon.ChangeOpacity(0.5)//Make it half transparent.
|
||||
@@ -947,6 +947,14 @@ world
|
||||
flat_icon.AddAlphaMask(alpha_mask)//Finally, let's mix in a distortion effect.
|
||||
return flat_icon
|
||||
|
||||
/proc/getPAIHologramIcon(icon/A, safety = TRUE)
|
||||
var/icon/flat_icon = safety? A : new(A)
|
||||
flat_icon.SetIntensity(0.75, 1, 0.75)
|
||||
flat_icon.ChangeOpacity(0.7)
|
||||
var/icon/alpha_mask = new('icons/effects/effects.dmi', "scanlineslow")//Scanline effect.
|
||||
flat_icon.AddAlphaMask(alpha_mask)//Finally, let's mix in a distortion effect.
|
||||
return flat_icon
|
||||
|
||||
//What the mob looks like as animated static
|
||||
//By vg's ComicIronic
|
||||
/proc/getStaticIcon(icon/A, safety = TRUE)
|
||||
|
||||
@@ -12,6 +12,3 @@
|
||||
#define is_reserved_level(z) SSmapping.level_trait(z, ZTRAIT_RESERVED)
|
||||
|
||||
#define is_away_level(z) SSmapping.level_trait(z, ZTRAIT_AWAY)
|
||||
|
||||
// If true, the singularity cannot strip away asteroid turf on this Z
|
||||
#define is_planet_level(z) SSmapping.level_trait(z, ZTRAIT_PLANET)
|
||||
|
||||
@@ -20,8 +20,6 @@
|
||||
else
|
||||
return "000"
|
||||
|
||||
#define UNDIE_COLORABLE(U) (U?.has_color)
|
||||
|
||||
/proc/random_underwear(gender)
|
||||
if(!GLOB.underwear_list.len)
|
||||
init_sprite_accessory_subtypes(/datum/sprite_accessory/underwear/bottom, GLOB.underwear_list, GLOB.underwear_m, GLOB.underwear_f)
|
||||
@@ -76,6 +74,8 @@
|
||||
init_sprite_accessory_subtypes(/datum/sprite_accessory/insect_wings, GLOB.insect_wings_list)
|
||||
if(!GLOB.insect_fluffs_list.len)
|
||||
init_sprite_accessory_subtypes(/datum/sprite_accessory/insect_fluff, GLOB.insect_fluffs_list)
|
||||
if(!GLOB.insect_markings_list.len)
|
||||
init_sprite_accessory_subtypes(/datum/sprite_accessory/insect_markings, GLOB.insect_markings_list)
|
||||
|
||||
//CIT CHANGES - genitals and such
|
||||
if(!GLOB.cock_shapes_list.len)
|
||||
@@ -151,6 +151,7 @@
|
||||
"caps" = pick(GLOB.caps_list),
|
||||
"insect_wings" = pick(GLOB.insect_wings_list),
|
||||
"insect_fluff" = "None",
|
||||
"insect_markings" = pick(GLOB.insect_markings_list),
|
||||
"taur" = "None",
|
||||
"mam_body_markings" = pick(snowflake_markings_list),
|
||||
"mam_ears" = pick(snowflake_ears_list),
|
||||
|
||||
@@ -19,6 +19,9 @@
|
||||
var/list/mob_data = list()
|
||||
if(isnewplayer(m))
|
||||
continue
|
||||
if (m.client && m.client.prefs && m.client.prefs.auto_ooc)
|
||||
if (!(m.client.prefs.chat_toggles & CHAT_OOC))
|
||||
m.client.prefs.chat_toggles ^= CHAT_OOC
|
||||
if(m.mind)
|
||||
if(m.stat != DEAD && !isbrain(m) && !iscameramob(m))
|
||||
num_survivors++
|
||||
@@ -320,6 +323,8 @@
|
||||
parts += "[FOURSPACES][FOURSPACES][str]"
|
||||
for(var/entry in mode.threat_tallies)
|
||||
parts += "[FOURSPACES][FOURSPACES][entry] added [mode.threat_tallies[entry]]"
|
||||
SSblackbox.record_feedback("tally","dynamic_threat",mode.threat_level,"Final threat level")
|
||||
SSblackbox.record_feedback("tally","dynamic_threat",mode.threat,"Threat left")
|
||||
return parts.Join("<br>")
|
||||
|
||||
/client/proc/roundend_report_file()
|
||||
|
||||
+475
-475
File diff suppressed because it is too large
Load Diff
@@ -758,16 +758,6 @@ GLOBAL_LIST_INIT(can_embed_types, typecacheof(list(
|
||||
/obj/item/stack/rods,
|
||||
/obj/item/pipe)))
|
||||
|
||||
/proc/can_embed(obj/item/W)
|
||||
if(W.get_sharpness())
|
||||
return 1
|
||||
if(is_pointed(W))
|
||||
return 1
|
||||
|
||||
if(is_type_in_typecache(W, GLOB.can_embed_types))
|
||||
return 1
|
||||
|
||||
|
||||
/*
|
||||
Checks if that loc and dir has an item on the wall
|
||||
*/
|
||||
|
||||
@@ -143,6 +143,7 @@ GLOBAL_LIST_INIT(bitfields, list(
|
||||
"VOICEBOX_TOGGLABLE" = VOICEBOX_TOGGLABLE,
|
||||
"VOICEBOX_DISABLED" = VOICEBOX_DISABLED,
|
||||
"IGNORE_HAT_TOSS" = IGNORE_HAT_TOSS,
|
||||
"SCAN_REAGENTS" = SCAN_REAGENTS
|
||||
),
|
||||
"tesla_flags" = list(
|
||||
"TESLA_MOB_DAMAGE" = TESLA_MOB_DAMAGE,
|
||||
|
||||
@@ -37,6 +37,7 @@ GLOBAL_LIST_EMPTY(deco_wings_list)
|
||||
GLOBAL_LIST_EMPTY(r_wings_list)
|
||||
GLOBAL_LIST_EMPTY(insect_wings_list)
|
||||
GLOBAL_LIST_EMPTY(insect_fluffs_list)
|
||||
GLOBAL_LIST_EMPTY(insect_markings_list)
|
||||
GLOBAL_LIST_EMPTY(caps_list)
|
||||
|
||||
GLOBAL_LIST_INIT(ghost_forms_with_directions_list, list("ghost")) //stores the ghost forms that support directional sprites
|
||||
|
||||
@@ -115,5 +115,6 @@ GLOBAL_LIST_INIT(maintenance_loot, list(
|
||||
/obj/item/clothing/shoes/kindleKicks = 1,
|
||||
/obj/item/autosurgeon/penis = 1,
|
||||
/obj/item/autosurgeon/testicles = 1,
|
||||
/obj/item/storage/box/marshmallow = 2,
|
||||
"" = 3
|
||||
))
|
||||
|
||||
@@ -48,3 +48,5 @@ GLOBAL_LIST_EMPTY(sortedAreas)
|
||||
GLOBAL_LIST_EMPTY_TYPED(areas_by_type, /area)
|
||||
|
||||
GLOBAL_LIST_EMPTY(all_abstract_markers)
|
||||
|
||||
GLOBAL_LIST_EMPTY(stationroom_landmarks) //List of all spawns for stationrooms
|
||||
|
||||
@@ -28,6 +28,8 @@ GLOBAL_VAR(world_job_debug_log)
|
||||
GLOBAL_PROTECT(world_job_debug_log)
|
||||
GLOBAL_VAR(world_virus_log)
|
||||
GLOBAL_PROTECT(world_virus_log)
|
||||
GLOBAL_VAR(world_map_error_log)
|
||||
GLOBAL_PROTECT(world_map_error_log)
|
||||
|
||||
GLOBAL_LIST_EMPTY(bombers)
|
||||
GLOBAL_PROTECT(bombers)
|
||||
|
||||
@@ -195,89 +195,107 @@
|
||||
// Language menu
|
||||
using = new /obj/screen/language_menu
|
||||
using.screen_loc = ui_borg_language_menu
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
|
||||
//AI core
|
||||
using = new /obj/screen/ai/aicore()
|
||||
using.screen_loc = ui_ai_core
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
|
||||
//Camera list
|
||||
using = new /obj/screen/ai/camera_list()
|
||||
using.screen_loc = ui_ai_camera_list
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
|
||||
//Track
|
||||
using = new /obj/screen/ai/camera_track()
|
||||
using.screen_loc = ui_ai_track_with_camera
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
|
||||
//Camera light
|
||||
using = new /obj/screen/ai/camera_light()
|
||||
using.screen_loc = ui_ai_camera_light
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
|
||||
//Crew Monitoring
|
||||
using = new /obj/screen/ai/crew_monitor()
|
||||
using.screen_loc = ui_ai_crew_monitor
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
|
||||
//Crew Manifest
|
||||
using = new /obj/screen/ai/crew_manifest()
|
||||
using.screen_loc = ui_ai_crew_manifest
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
|
||||
//Alerts
|
||||
using = new /obj/screen/ai/alerts()
|
||||
using.screen_loc = ui_ai_alerts
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
|
||||
//Announcement
|
||||
using = new /obj/screen/ai/announcement()
|
||||
using.screen_loc = ui_ai_announcement
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
|
||||
//Shuttle
|
||||
using = new /obj/screen/ai/call_shuttle()
|
||||
using.screen_loc = ui_ai_shuttle
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
|
||||
//Laws
|
||||
using = new /obj/screen/ai/state_laws()
|
||||
using.screen_loc = ui_ai_state_laws
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
|
||||
//PDA message
|
||||
using = new /obj/screen/ai/pda_msg_send()
|
||||
using.screen_loc = ui_ai_pda_send
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
|
||||
//PDA log
|
||||
using = new /obj/screen/ai/pda_msg_show()
|
||||
using.screen_loc = ui_ai_pda_log
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
|
||||
//Take image
|
||||
using = new /obj/screen/ai/image_take()
|
||||
using.screen_loc = ui_ai_take_picture
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
|
||||
//View images
|
||||
using = new /obj/screen/ai/image_view()
|
||||
using.screen_loc = ui_ai_view_images
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
|
||||
//Medical/Security sensors
|
||||
using = new /obj/screen/ai/sensors()
|
||||
using.screen_loc = ui_ai_sensor
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
|
||||
//Multicamera mode
|
||||
using = new /obj/screen/ai/multicam()
|
||||
using.screen_loc = ui_ai_multicam
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
|
||||
//Add multicamera camera
|
||||
using = new /obj/screen/ai/add_multicam()
|
||||
using.screen_loc = ui_ai_add_multicam
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
|
||||
@@ -213,6 +213,16 @@ or something covering your eyes."
|
||||
desc = "Whoa man, you're tripping balls! Careful you don't get addicted... if you aren't already."
|
||||
icon_state = "high"
|
||||
|
||||
/obj/screen/alert/mind_control
|
||||
name = "Mind Control"
|
||||
desc = "Your mind has been hijacked! Click to view the mind control command."
|
||||
icon_state = "mind_control"
|
||||
var/command
|
||||
|
||||
/obj/screen/alert/mind_control/Click()
|
||||
var/mob/living/L = usr
|
||||
to_chat(L, "<span class='mind_control'>[command]</span>")
|
||||
|
||||
/obj/screen/alert/hypnosis
|
||||
name = "Hypnosis"
|
||||
desc = "Something's hypnotizing you, but you're not really sure about what."
|
||||
|
||||
@@ -43,18 +43,20 @@
|
||||
using.icon = ui_style
|
||||
using.icon_state = "swap_1"
|
||||
using.screen_loc = ui_swaphand_position(owner,1)
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
|
||||
using = new /obj/screen/swap_hand()
|
||||
using.icon = ui_style
|
||||
using.icon_state = "swap_2"
|
||||
using.screen_loc = ui_swaphand_position(owner,2)
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
|
||||
using = new /obj/screen/act_intent/alien()
|
||||
using.icon_state = mymob.a_intent
|
||||
static_inventory += using
|
||||
action_intent = using
|
||||
action_intent = new /obj/screen/act_intent/alien()
|
||||
action_intent.icon_state = mymob.a_intent
|
||||
action_intent.hud = src
|
||||
static_inventory += action_intent
|
||||
|
||||
if(isalienhunter(mymob))
|
||||
var/mob/living/carbon/alien/humanoid/hunter/H = mymob
|
||||
@@ -64,43 +66,52 @@
|
||||
|
||||
using = new/obj/screen/language_menu
|
||||
using.screen_loc = ui_alien_language_menu
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
|
||||
using = new /obj/screen/drop()
|
||||
using.icon = ui_style
|
||||
using.screen_loc = ui_drop_throw
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
|
||||
using = new /obj/screen/resist()
|
||||
using.icon = ui_style
|
||||
using.screen_loc = ui_pull_resist
|
||||
using.hud = src
|
||||
hotkeybuttons += using
|
||||
|
||||
throw_icon = new /obj/screen/throw_catch()
|
||||
throw_icon.icon = ui_style
|
||||
throw_icon.screen_loc = ui_drop_throw
|
||||
throw_icon.hud = src
|
||||
hotkeybuttons += throw_icon
|
||||
|
||||
pull_icon = new /obj/screen/pull()
|
||||
pull_icon.icon = ui_style
|
||||
pull_icon.update_icon(mymob)
|
||||
pull_icon.hud = src
|
||||
pull_icon.update_icon()
|
||||
pull_icon.screen_loc = ui_pull_resist
|
||||
static_inventory += pull_icon
|
||||
|
||||
//begin indicators
|
||||
|
||||
healths = new /obj/screen/healths/alien()
|
||||
healths.hud = src
|
||||
infodisplay += healths
|
||||
|
||||
alien_plasma_display = new /obj/screen/alien/plasma_display()
|
||||
alien_plasma_display.hud = src
|
||||
infodisplay += alien_plasma_display
|
||||
|
||||
if(!isalienqueen(mymob))
|
||||
alien_queen_finder = new /obj/screen/alien/alien_queen_finder
|
||||
alien_queen_finder.hud = src
|
||||
infodisplay += alien_queen_finder
|
||||
|
||||
zone_select = new /obj/screen/zone_sel/alien()
|
||||
zone_select.update_icon(mymob)
|
||||
zone_select.hud = src
|
||||
zone_select.update_icon()
|
||||
static_inventory += zone_select
|
||||
|
||||
for(var/obj/screen/inventory/inv in (static_inventory + toggleable_inventory))
|
||||
|
||||
@@ -5,26 +5,32 @@
|
||||
..()
|
||||
var/obj/screen/using
|
||||
|
||||
using = new /obj/screen/act_intent/alien()
|
||||
using.icon_state = mymob.a_intent
|
||||
static_inventory += using
|
||||
action_intent = using
|
||||
action_intent = new /obj/screen/act_intent/alien()
|
||||
action_intent.icon_state = mymob.a_intent
|
||||
action_intent.hud = src
|
||||
static_inventory += action_intent
|
||||
|
||||
healths = new /obj/screen/healths/alien()
|
||||
healths.hud = src
|
||||
infodisplay += healths
|
||||
|
||||
alien_queen_finder = new /obj/screen/alien/alien_queen_finder()
|
||||
alien_queen_finder.hud = src
|
||||
infodisplay += alien_queen_finder
|
||||
|
||||
pull_icon = new /obj/screen/pull()
|
||||
pull_icon.icon = 'icons/mob/screen_alien.dmi'
|
||||
pull_icon.update_icon(mymob)
|
||||
pull_icon.hud = src
|
||||
pull_icon.update_icon()
|
||||
pull_icon.screen_loc = ui_pull_resist
|
||||
hotkeybuttons += pull_icon
|
||||
|
||||
using = new/obj/screen/language_menu
|
||||
using.screen_loc = ui_alien_language_menu
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
|
||||
zone_select = new /obj/screen/zone_sel/alien()
|
||||
zone_select.update_icon(mymob)
|
||||
zone_select.hud = src
|
||||
zone_select.update_icon()
|
||||
static_inventory += zone_select
|
||||
|
||||
@@ -133,17 +133,21 @@
|
||||
blobpwrdisplay.mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
blobpwrdisplay.layer = ABOVE_HUD_LAYER
|
||||
blobpwrdisplay.plane = ABOVE_HUD_PLANE
|
||||
blobpwrdisplay.hud = src
|
||||
infodisplay += blobpwrdisplay
|
||||
|
||||
healths = new /obj/screen/healths/blob()
|
||||
healths.hud = src
|
||||
infodisplay += healths
|
||||
|
||||
using = new /obj/screen/blob/BlobHelp()
|
||||
using.screen_loc = "WEST:6,NORTH:-3"
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
|
||||
using = new /obj/screen/blob/JumpToNode()
|
||||
using.screen_loc = ui_inventory
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
|
||||
using = new /obj/screen/blob/JumpToCore()
|
||||
@@ -153,18 +157,22 @@
|
||||
|
||||
using = new /obj/screen/blob/Blobbernaut()
|
||||
using.screen_loc = ui_belt
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
|
||||
using = new /obj/screen/blob/ResourceBlob()
|
||||
using.screen_loc = ui_back
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
|
||||
using = new /obj/screen/blob/NodeBlob()
|
||||
using.screen_loc = ui_hand_position(2)
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
|
||||
using = new /obj/screen/blob/FactoryBlob()
|
||||
using.screen_loc = ui_hand_position(1)
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
|
||||
using = new /obj/screen/blob/ReadaptChemical()
|
||||
@@ -174,4 +182,5 @@
|
||||
|
||||
using = new /obj/screen/blob/RelocateCore()
|
||||
using.screen_loc = ui_storage2
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
|
||||
@@ -3,7 +3,9 @@
|
||||
..()
|
||||
|
||||
blobpwrdisplay = new /obj/screen/healths/blob/naut/core()
|
||||
blobpwrdisplay.hud = src
|
||||
infodisplay += blobpwrdisplay
|
||||
|
||||
healths = new /obj/screen/healths/blob/naut()
|
||||
healths.hud = src
|
||||
infodisplay += healths
|
||||
|
||||
@@ -5,9 +5,11 @@
|
||||
..()
|
||||
pull_icon = new /obj/screen/pull()
|
||||
pull_icon.icon = ui_style
|
||||
pull_icon.update_icon(mymob)
|
||||
pull_icon.hud = src
|
||||
pull_icon.update_icon()
|
||||
pull_icon.screen_loc = ui_construct_pull
|
||||
static_inventory += pull_icon
|
||||
|
||||
healths = new /obj/screen/healths/construct()
|
||||
healths.hud = src
|
||||
infodisplay += healths
|
||||
|
||||
@@ -9,11 +9,13 @@
|
||||
using = new /obj/screen/drop()
|
||||
using.icon = ui_style
|
||||
using.screen_loc = ui_drone_drop
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
|
||||
pull_icon = new /obj/screen/pull()
|
||||
pull_icon.icon = ui_style
|
||||
pull_icon.update_icon(mymob)
|
||||
pull_icon.hud = src
|
||||
pull_icon.update_icon()
|
||||
pull_icon.screen_loc = ui_drone_pull
|
||||
static_inventory += pull_icon
|
||||
|
||||
@@ -26,6 +28,7 @@
|
||||
using.screen_loc = ui_swaphand_position(owner,1)
|
||||
using.layer = HUD_LAYER
|
||||
using.plane = HUD_PLANE
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
|
||||
using = new /obj/screen/inventory()
|
||||
@@ -35,14 +38,19 @@
|
||||
using.screen_loc = ui_swaphand_position(owner,2)
|
||||
using.layer = HUD_LAYER
|
||||
using.plane = HUD_PLANE
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
|
||||
zone_select = new /obj/screen/zone_sel()
|
||||
zone_select.icon = ui_style
|
||||
zone_select.update_icon(mymob)
|
||||
zone_select.hud = src
|
||||
zone_select.update_icon()
|
||||
|
||||
lingchemdisplay = new /obj/screen/ling/chems()
|
||||
lingchemdisplay.hud = src
|
||||
|
||||
devilsouldisplay = new /obj/screen/devil/soul_counter
|
||||
devilsouldisplay.hud = src
|
||||
infodisplay += devilsouldisplay
|
||||
|
||||
|
||||
|
||||
@@ -6,11 +6,13 @@
|
||||
using = new /obj/screen/drop()
|
||||
using.icon = ui_style
|
||||
using.screen_loc = ui_drone_drop
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
|
||||
pull_icon = new /obj/screen/pull()
|
||||
pull_icon.icon = ui_style
|
||||
pull_icon.update_icon(mymob)
|
||||
pull_icon.hud = src
|
||||
pull_icon.update_icon()
|
||||
pull_icon.screen_loc = ui_drone_pull
|
||||
static_inventory += pull_icon
|
||||
|
||||
@@ -20,12 +22,14 @@
|
||||
using.icon = ui_style
|
||||
using.icon_state = "swap_1_m"
|
||||
using.screen_loc = ui_swaphand_position(owner,1)
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
|
||||
using = new /obj/screen/swap_hand()
|
||||
using.icon = ui_style
|
||||
using.icon_state = "swap_2"
|
||||
using.screen_loc = ui_swaphand_position(owner,2)
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
|
||||
if(mymob.possible_a_intents)
|
||||
@@ -36,20 +40,24 @@
|
||||
action_intent = new /obj/screen/act_intent
|
||||
action_intent.icon = ui_style
|
||||
action_intent.icon_state = mymob.a_intent
|
||||
action_intent.hud = src
|
||||
static_inventory += action_intent
|
||||
|
||||
|
||||
zone_select = new /obj/screen/zone_sel()
|
||||
zone_select.icon = ui_style
|
||||
zone_select.update_icon(mymob)
|
||||
zone_select.hud = src
|
||||
zone_select.update_icon()
|
||||
static_inventory += zone_select
|
||||
|
||||
using = new /obj/screen/craft
|
||||
using.icon = ui_style
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
|
||||
using = new /obj/screen/area_creator
|
||||
using.icon = ui_style
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
|
||||
mymob.client.screen = list()
|
||||
|
||||
@@ -50,26 +50,32 @@
|
||||
|
||||
using = new /obj/screen/ghost/jumptomob()
|
||||
using.screen_loc = ui_ghost_jumptomob
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
|
||||
using = new /obj/screen/ghost/orbit()
|
||||
using.screen_loc = ui_ghost_orbit
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
|
||||
using = new /obj/screen/ghost/reenter_corpse()
|
||||
using.screen_loc = ui_ghost_reenter_corpse
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
|
||||
using = new /obj/screen/ghost/teleport()
|
||||
using.screen_loc = ui_ghost_teleport
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
|
||||
using = new /obj/screen/ghost/pai()
|
||||
using.screen_loc = ui_ghost_pai
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
|
||||
using = new /obj/screen/language_menu
|
||||
using.icon = ui_style
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
|
||||
/datum/hud/ghost/show_hud(version = 0, mob/viewmob)
|
||||
|
||||
@@ -4,26 +4,32 @@
|
||||
var/obj/screen/using
|
||||
|
||||
healths = new /obj/screen/healths/guardian()
|
||||
healths.hud = src
|
||||
infodisplay += healths
|
||||
|
||||
using = new /obj/screen/guardian/Manifest()
|
||||
using.screen_loc = ui_hand_position(2)
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
|
||||
using = new /obj/screen/guardian/Recall()
|
||||
using.screen_loc = ui_hand_position(1)
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
|
||||
using = new owner.toggle_button_type()
|
||||
using.screen_loc = ui_storage1
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
|
||||
using = new /obj/screen/guardian/ToggleLight()
|
||||
using.screen_loc = ui_inventory
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
|
||||
using = new /obj/screen/guardian/Communicate()
|
||||
using.screen_loc = ui_back
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
|
||||
/datum/hud/dextrous/guardian/New(mob/living/simple_animal/hostile/guardian/owner) //for a dextrous guardian
|
||||
|
||||
@@ -61,6 +61,9 @@ GLOBAL_LIST_INIT(available_ui_styles, list(
|
||||
// subtypes can override this to force a specific UI style
|
||||
var/ui_style
|
||||
|
||||
//Citadel stuff
|
||||
var/obj/screen/arousal
|
||||
|
||||
/datum/hud/New(mob/owner)
|
||||
mymob = owner
|
||||
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
/datum/hud
|
||||
var/obj/screen/arousal
|
||||
@@ -95,18 +95,21 @@
|
||||
using.icon = ui_style
|
||||
if(!widescreenlayout) // CIT CHANGE
|
||||
using.screen_loc = ui_boxcraft // CIT CHANGE
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
|
||||
using = new/obj/screen/language_menu
|
||||
using.icon = ui_style
|
||||
if(!widescreenlayout) // CIT CHANGE
|
||||
using.screen_loc = ui_boxlang // CIT CHANGE
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
|
||||
using = new /obj/screen/area_creator
|
||||
using.icon = ui_style
|
||||
if(!widescreenlayout) // CIT CHANGE
|
||||
using.screen_loc = ui_boxarea // CIT CHANGE
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
|
||||
using = new /obj/screen/voretoggle() //We fancy Vore now
|
||||
@@ -114,16 +117,19 @@
|
||||
using.screen_loc = ui_voremode
|
||||
if(!widescreenlayout)
|
||||
using.screen_loc = ui_boxvore
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
|
||||
action_intent = new /obj/screen/act_intent/segmented
|
||||
action_intent.icon_state = mymob.a_intent
|
||||
action_intent.hud = src
|
||||
static_inventory += action_intent
|
||||
|
||||
using = new /obj/screen/mov_intent
|
||||
using.icon = tg_ui_icon_to_cit_ui(ui_style) // CIT CHANGE - overrides mov intent icon
|
||||
using.icon_state = (mymob.m_intent == MOVE_INTENT_RUN ? "running" : "walking")
|
||||
using.screen_loc = ui_movi
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
|
||||
//CITADEL CHANGES - sprint button
|
||||
@@ -131,19 +137,21 @@
|
||||
using.icon = tg_ui_icon_to_cit_ui(ui_style)
|
||||
using.icon_state = (owner.sprinting ? "act_sprint_on" : "act_sprint")
|
||||
using.screen_loc = ui_movi
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
//END OF CITADEL CHANGES
|
||||
|
||||
//same as above but buffer.
|
||||
using = new /obj/screen/sprint_buffer
|
||||
using.screen_loc = ui_sprintbufferloc
|
||||
sprint_buffer = using
|
||||
static_inventory += using
|
||||
sprint_buffer = new /obj/screen/sprint_buffer
|
||||
sprint_buffer.screen_loc = ui_sprintbufferloc
|
||||
sprint_buffer.hud = src
|
||||
static_inventory += sprint_buffer
|
||||
|
||||
|
||||
using = new /obj/screen/drop()
|
||||
using.icon = ui_style
|
||||
using.screen_loc = ui_drop_throw
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
|
||||
inv_box = new /obj/screen/inventory()
|
||||
@@ -168,12 +176,14 @@
|
||||
using.icon = ui_style
|
||||
using.icon_state = "swap_1"
|
||||
using.screen_loc = ui_swaphand_position(owner,1)
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
|
||||
using = new /obj/screen/swap_hand()
|
||||
using.icon = ui_style
|
||||
using.icon_state = "swap_2"
|
||||
using.screen_loc = ui_swaphand_position(owner,2)
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
|
||||
inv_box = new /obj/screen/inventory()
|
||||
@@ -235,28 +245,33 @@
|
||||
using = new /obj/screen/resist()
|
||||
using.icon = ui_style
|
||||
using.screen_loc = ui_overridden_resist // CIT CHANGE - changes this to overridden resist
|
||||
using.hud = src
|
||||
hotkeybuttons += using
|
||||
|
||||
//CIT CHANGES - rest and combat mode buttons
|
||||
using = new /obj/screen/restbutton()
|
||||
using.icon = tg_ui_icon_to_cit_ui(ui_style)
|
||||
using.screen_loc = ui_pull_resist
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
|
||||
using = new /obj/screen/combattoggle()
|
||||
using.icon = tg_ui_icon_to_cit_ui(ui_style)
|
||||
using.screen_loc = ui_combat_toggle
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
//END OF CIT CHANGES
|
||||
|
||||
using = new /obj/screen/human/toggle()
|
||||
using.icon = ui_style
|
||||
using.screen_loc = ui_inventory
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
|
||||
using = new /obj/screen/human/equip()
|
||||
using.icon = ui_style
|
||||
using.screen_loc = ui_equip_position(mymob)
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
|
||||
inv_box = new /obj/screen/inventory()
|
||||
@@ -311,54 +326,71 @@
|
||||
throw_icon = new /obj/screen/throw_catch()
|
||||
throw_icon.icon = ui_style
|
||||
throw_icon.screen_loc = ui_drop_throw
|
||||
throw_icon.hud = src
|
||||
hotkeybuttons += throw_icon
|
||||
|
||||
internals = new /obj/screen/internals()
|
||||
internals.hud = src
|
||||
infodisplay += internals
|
||||
|
||||
healths = new /obj/screen/healths()
|
||||
healths.hud = src
|
||||
infodisplay += healths
|
||||
//CIT CHANGE - adds arousal and stamina to hud
|
||||
arousal = new /obj/screen/arousal()
|
||||
arousal.icon_state = (owner.canbearoused == 1 ? "arousal0" : "")
|
||||
arousal.hud = src
|
||||
infodisplay += arousal
|
||||
|
||||
staminas = new /obj/screen/staminas()
|
||||
staminas.hud = src
|
||||
infodisplay += staminas
|
||||
|
||||
if(!CONFIG_GET(flag/disable_stambuffer))
|
||||
staminabuffer = new /obj/screen/staminabuffer()
|
||||
staminabuffer.hud = src
|
||||
infodisplay += staminabuffer
|
||||
//END OF CIT CHANGES
|
||||
|
||||
healthdoll = new /obj/screen/healthdoll()
|
||||
healthdoll.hud = src
|
||||
infodisplay += healthdoll
|
||||
|
||||
pull_icon = new /obj/screen/pull()
|
||||
pull_icon.icon = ui_style
|
||||
pull_icon.update_icon(mymob)
|
||||
pull_icon.hud = src
|
||||
pull_icon.update_icon()
|
||||
pull_icon.screen_loc = ui_pull_resist
|
||||
static_inventory += pull_icon
|
||||
|
||||
lingchemdisplay = new /obj/screen/ling/chems()
|
||||
lingchemdisplay.hud = src
|
||||
infodisplay += lingchemdisplay
|
||||
|
||||
lingstingdisplay = new /obj/screen/ling/sting()
|
||||
lingstingdisplay.hud = src
|
||||
infodisplay += lingstingdisplay
|
||||
|
||||
devilsouldisplay = new /obj/screen/devil/soul_counter
|
||||
devilsouldisplay.hud = src
|
||||
infodisplay += devilsouldisplay
|
||||
|
||||
blood_display = new /obj/screen/bloodsucker/blood_counter // Blood Volume
|
||||
blood_display.hud = src
|
||||
infodisplay += blood_display
|
||||
|
||||
vamprank_display = new /obj/screen/bloodsucker/rank_counter // Vampire Rank
|
||||
vamprank_display.hud = src
|
||||
infodisplay += vamprank_display
|
||||
|
||||
sunlight_display = new /obj/screen/bloodsucker/sunlight_counter // Sunlight
|
||||
sunlight_display.hud = src
|
||||
infodisplay += sunlight_display
|
||||
|
||||
zone_select = new /obj/screen/zone_sel()
|
||||
zone_select.icon = ui_style
|
||||
zone_select.update_icon(mymob)
|
||||
zone_select.hud = src
|
||||
zone_select.update_icon()
|
||||
static_inventory += zone_select
|
||||
|
||||
for(var/obj/screen/inventory/inv in (static_inventory + toggleable_inventory))
|
||||
|
||||
@@ -6,9 +6,9 @@
|
||||
|
||||
pull_icon = new /obj/screen/pull()
|
||||
pull_icon.icon = ui_style
|
||||
pull_icon.hud = src
|
||||
pull_icon.update_icon()
|
||||
pull_icon.screen_loc = ui_living_pull
|
||||
pull_icon.hud = src
|
||||
static_inventory += pull_icon
|
||||
|
||||
healths = new /obj/screen/healths/lavaland_elite()
|
||||
|
||||
@@ -7,21 +7,25 @@
|
||||
action_intent.icon = ui_style
|
||||
action_intent.icon_state = mymob.a_intent
|
||||
action_intent.screen_loc = ui_acti
|
||||
action_intent.hud = src
|
||||
static_inventory += action_intent
|
||||
|
||||
using = new /obj/screen/mov_intent()
|
||||
using.icon = ui_style
|
||||
using.icon_state = (mymob.m_intent == MOVE_INTENT_RUN ? "running" : "walking")
|
||||
using.screen_loc = ui_movi
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
|
||||
using = new/obj/screen/language_menu
|
||||
using.icon = ui_style
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
|
||||
using = new /obj/screen/drop()
|
||||
using.icon = ui_style
|
||||
using.screen_loc = ui_drop_throw
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
|
||||
build_hand_slots()
|
||||
@@ -30,12 +34,14 @@
|
||||
using.icon = ui_style
|
||||
using.icon_state = "swap_1_m" //extra wide!
|
||||
using.screen_loc = ui_swaphand_position(owner,1)
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
|
||||
using = new /obj/screen/swap_hand()
|
||||
using.icon = ui_style
|
||||
using.icon_state = "swap_2"
|
||||
using.screen_loc = ui_swaphand_position(owner,2)
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
|
||||
inv_box = new /obj/screen/inventory()
|
||||
@@ -76,30 +82,37 @@
|
||||
throw_icon = new /obj/screen/throw_catch()
|
||||
throw_icon.icon = ui_style
|
||||
throw_icon.screen_loc = ui_drop_throw
|
||||
throw_icon.hud = src
|
||||
hotkeybuttons += throw_icon
|
||||
|
||||
internals = new /obj/screen/internals()
|
||||
internals.hud = src
|
||||
infodisplay += internals
|
||||
|
||||
healths = new /obj/screen/healths()
|
||||
healths.hud = src
|
||||
infodisplay += healths
|
||||
|
||||
pull_icon = new /obj/screen/pull()
|
||||
pull_icon.icon = ui_style
|
||||
pull_icon.update_icon(mymob)
|
||||
pull_icon.screen_loc = ui_pull_resist
|
||||
pull_icon.hud = src
|
||||
pull_icon.update_icon()
|
||||
static_inventory += pull_icon
|
||||
|
||||
lingchemdisplay = new /obj/screen/ling/chems()
|
||||
lingchemdisplay.hud = src
|
||||
infodisplay += lingchemdisplay
|
||||
|
||||
lingstingdisplay = new /obj/screen/ling/sting()
|
||||
lingstingdisplay.hud = src
|
||||
infodisplay += lingstingdisplay
|
||||
|
||||
|
||||
zone_select = new /obj/screen/zone_sel()
|
||||
zone_select.icon = ui_style
|
||||
zone_select.update_icon(mymob)
|
||||
zone_select.hud = src
|
||||
zone_select.update_icon()
|
||||
static_inventory += zone_select
|
||||
|
||||
mymob.client.screen = list()
|
||||
@@ -107,6 +120,7 @@
|
||||
using = new /obj/screen/resist()
|
||||
using.icon = ui_style
|
||||
using.screen_loc = ui_pull_resist
|
||||
using.hud = src
|
||||
hotkeybuttons += using
|
||||
|
||||
for(var/obj/screen/inventory/inv in (static_inventory + toggleable_inventory))
|
||||
|
||||
@@ -3,4 +3,5 @@
|
||||
..()
|
||||
|
||||
healths = new /obj/screen/healths/revenant()
|
||||
healths.hud = src
|
||||
infodisplay += healths
|
||||
|
||||
@@ -118,26 +118,31 @@
|
||||
|
||||
using = new/obj/screen/robot/language_menu
|
||||
using.screen_loc = ui_borg_language_menu
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
|
||||
//Radio
|
||||
using = new /obj/screen/robot/radio()
|
||||
using.screen_loc = ui_borg_radio
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
|
||||
//Module select
|
||||
using = new /obj/screen/robot/module1()
|
||||
using.screen_loc = ui_inv1
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
mymobR.inv1 = using
|
||||
|
||||
using = new /obj/screen/robot/module2()
|
||||
using.screen_loc = ui_inv2
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
mymobR.inv2 = using
|
||||
|
||||
using = new /obj/screen/robot/module3()
|
||||
using.screen_loc = ui_inv3
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
mymobR.inv3 = using
|
||||
|
||||
@@ -146,36 +151,43 @@
|
||||
//Photography stuff
|
||||
using = new /obj/screen/ai/image_take()
|
||||
using.screen_loc = ui_borg_camera
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
|
||||
using = new /obj/screen/ai/image_view()
|
||||
using.screen_loc = ui_borg_album
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
|
||||
//Sec/Med HUDs
|
||||
using = new /obj/screen/robot/sensors()
|
||||
using.screen_loc = ui_borg_sensor
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
|
||||
//Headlamp control
|
||||
using = new /obj/screen/robot/lamp()
|
||||
using.screen_loc = ui_borg_lamp
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
mymobR.lamp_button = using
|
||||
|
||||
//Thrusters
|
||||
using = new /obj/screen/robot/thrusters()
|
||||
using.screen_loc = ui_borg_thrusters
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
mymobR.thruster_button = using
|
||||
|
||||
//Intent
|
||||
action_intent = new /obj/screen/act_intent/robot()
|
||||
action_intent.icon_state = mymob.a_intent
|
||||
action_intent.hud = src
|
||||
static_inventory += action_intent
|
||||
|
||||
//Health
|
||||
healths = new /obj/screen/healths/robot()
|
||||
healths.hud = src
|
||||
infodisplay += healths
|
||||
|
||||
//Installed Module
|
||||
@@ -185,17 +197,20 @@
|
||||
|
||||
//Store
|
||||
module_store_icon = new /obj/screen/robot/store()
|
||||
module_store_icon.hud = src
|
||||
module_store_icon.screen_loc = ui_borg_store
|
||||
|
||||
pull_icon = new /obj/screen/pull()
|
||||
pull_icon.icon = 'icons/mob/screen_cyborg.dmi'
|
||||
pull_icon.update_icon(mymob)
|
||||
pull_icon.hud = src
|
||||
pull_icon.update_icon()
|
||||
pull_icon.screen_loc = ui_borg_pull
|
||||
hotkeybuttons += pull_icon
|
||||
|
||||
|
||||
zone_select = new /obj/screen/zone_sel/robot()
|
||||
zone_select.update_icon(mymob)
|
||||
zone_select.hud = src
|
||||
zone_select.update_icon()
|
||||
static_inventory += zone_select
|
||||
|
||||
|
||||
|
||||
@@ -110,21 +110,21 @@
|
||||
// At this point in client Click() code we have passed the 1/10 sec check and little else
|
||||
// We don't even know if it's a middle click
|
||||
if(world.time <= usr.next_move)
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
if(usr.incapacitated())
|
||||
return 1
|
||||
return TRUE
|
||||
if(ismecha(usr.loc)) // stops inventory actions in a mech
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
if(hud && hud.mymob && slot_id)
|
||||
if(hud?.mymob && slot_id)
|
||||
var/obj/item/inv_item = hud.mymob.get_item_by_slot(slot_id)
|
||||
if(inv_item)
|
||||
return inv_item.Click(location, control, params)
|
||||
|
||||
if(usr.attack_ui(slot_id))
|
||||
usr.update_inv_hands()
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
/obj/screen/inventory/MouseEntered()
|
||||
..()
|
||||
@@ -135,35 +135,37 @@
|
||||
cut_overlay(object_overlays)
|
||||
object_overlays.Cut()
|
||||
|
||||
/obj/screen/inventory/update_icon()
|
||||
/obj/screen/inventory/update_icon_state()
|
||||
if(!icon_empty)
|
||||
icon_empty = icon_state
|
||||
|
||||
if(hud && hud.mymob && slot_id && icon_full)
|
||||
if(hud?.mymob && slot_id && icon_full)
|
||||
if(hud.mymob.get_item_by_slot(slot_id))
|
||||
icon_state = icon_full
|
||||
else
|
||||
icon_state = icon_empty
|
||||
|
||||
/obj/screen/inventory/proc/add_overlays()
|
||||
var/mob/user = hud.mymob
|
||||
var/mob/user = hud?.mymob
|
||||
|
||||
if(hud && user && slot_id)
|
||||
var/obj/item/holding = user.get_active_held_item()
|
||||
if(!user || !slot_id)
|
||||
return
|
||||
|
||||
if(!holding || user.get_item_by_slot(slot_id))
|
||||
return
|
||||
var/obj/item/holding = user.get_active_held_item()
|
||||
|
||||
var/image/item_overlay = image(holding)
|
||||
item_overlay.alpha = 92
|
||||
if(!holding || user.get_item_by_slot(slot_id))
|
||||
return
|
||||
|
||||
if(!user.can_equip(holding, slot_id, TRUE))
|
||||
item_overlay.color = "#FF0000"
|
||||
else
|
||||
item_overlay.color = "#00ff00"
|
||||
var/image/item_overlay = image(holding)
|
||||
item_overlay.alpha = 92
|
||||
|
||||
object_overlays += item_overlay
|
||||
add_overlay(object_overlays)
|
||||
if(!user.can_equip(holding, slot_id, TRUE))
|
||||
item_overlay.color = "#FF0000"
|
||||
else
|
||||
item_overlay.color = "#00ff00"
|
||||
|
||||
object_overlays += item_overlay
|
||||
add_overlay(object_overlays)
|
||||
|
||||
/obj/screen/inventory/hand
|
||||
var/mutable_appearance/handcuff_overlay
|
||||
@@ -171,45 +173,50 @@
|
||||
var/held_index = 0
|
||||
|
||||
/obj/screen/inventory/hand/update_icon()
|
||||
..()
|
||||
. = ..()
|
||||
|
||||
if(!handcuff_overlay)
|
||||
var/state = (!(held_index % 2)) ? "markus" : "gabrielle"
|
||||
handcuff_overlay = mutable_appearance('icons/mob/screen_gen.dmi', state)
|
||||
|
||||
cut_overlays()
|
||||
cut_overlay(list(handcuff_overlay, blocked_overlay, "hand_active"))
|
||||
|
||||
if(hud && hud.mymob)
|
||||
if(iscarbon(hud.mymob))
|
||||
var/mob/living/carbon/C = hud.mymob
|
||||
if(C.handcuffed)
|
||||
add_overlay(handcuff_overlay)
|
||||
if(!hud?.mymob)
|
||||
return
|
||||
|
||||
if(held_index)
|
||||
if(!C.has_hand_for_held_index(held_index))
|
||||
add_overlay(blocked_overlay)
|
||||
if(iscarbon(hud.mymob))
|
||||
var/mob/living/carbon/C = hud.mymob
|
||||
if(C.handcuffed)
|
||||
add_overlay(handcuff_overlay)
|
||||
|
||||
if(held_index == hud.mymob.active_hand_index)
|
||||
add_overlay("hand_active")
|
||||
if(held_index)
|
||||
if(!C.has_hand_for_held_index(held_index))
|
||||
add_overlay(blocked_overlay)
|
||||
|
||||
if(held_index == hud.mymob.active_hand_index)
|
||||
add_overlay("hand_active")
|
||||
|
||||
|
||||
/obj/screen/inventory/hand/Click(location, control, params)
|
||||
// At this point in client Click() code we have passed the 1/10 sec check and little else
|
||||
// We don't even know if it's a middle click
|
||||
if(world.time <= usr.next_move)
|
||||
return 1
|
||||
if(usr.incapacitated() || isobserver(usr))
|
||||
return 1
|
||||
if (ismecha(usr.loc)) // stops inventory actions in a mech
|
||||
return 1
|
||||
var/mob/user = hud?.mymob
|
||||
if(usr != user)
|
||||
return TRUE
|
||||
if(world.time <= user.next_move)
|
||||
return TRUE
|
||||
if(user.incapacitated())
|
||||
return TRUE
|
||||
if (ismecha(user.loc)) // stops inventory actions in a mech
|
||||
return TRUE
|
||||
|
||||
if(hud.mymob.active_hand_index == held_index)
|
||||
var/obj/item/I = hud.mymob.get_active_held_item()
|
||||
if(user.active_hand_index == held_index)
|
||||
var/obj/item/I = user.get_active_held_item()
|
||||
if(I)
|
||||
I.Click(location, control, params)
|
||||
else
|
||||
hud.mymob.swap_hand(held_index)
|
||||
return 1
|
||||
user.swap_hand(held_index)
|
||||
return TRUE
|
||||
|
||||
/obj/screen/close
|
||||
name = "close"
|
||||
@@ -343,12 +350,8 @@
|
||||
/obj/screen/mov_intent/Click()
|
||||
toggle(usr)
|
||||
|
||||
/obj/screen/mov_intent/update_icon(mob/user)
|
||||
if(!user && hud)
|
||||
user = hud.mymob
|
||||
if(!user)
|
||||
return
|
||||
switch(user.m_intent)
|
||||
/obj/screen/mov_intent/update_icon_state()
|
||||
switch(hud?.mymob?.m_intent)
|
||||
if(MOVE_INTENT_WALK)
|
||||
icon_state = "walking"
|
||||
if(MOVE_INTENT_RUN)
|
||||
@@ -369,10 +372,8 @@
|
||||
return
|
||||
usr.stop_pulling()
|
||||
|
||||
/obj/screen/pull/update_icon(mob/mymob)
|
||||
if(!mymob)
|
||||
return
|
||||
if(mymob.pulling)
|
||||
/obj/screen/pull/update_icon_state()
|
||||
if(hud?.mymob?.pulling)
|
||||
icon_state = "pull"
|
||||
else
|
||||
icon_state = "pull0"
|
||||
@@ -401,11 +402,11 @@
|
||||
var/mob/living/L = usr
|
||||
L.lay_down()
|
||||
|
||||
/obj/screen/rest/update_icon(mob/mymob)
|
||||
if(!isliving(mymob))
|
||||
/obj/screen/rest/update_icon_state()
|
||||
var/mob/living/user = hud?.mymob
|
||||
if(!istype(user))
|
||||
return
|
||||
var/mob/living/L = mymob
|
||||
if(!L.resting)
|
||||
if(!user.resting)
|
||||
icon_state = "act_rest"
|
||||
else
|
||||
icon_state = "act_rest0"
|
||||
@@ -448,7 +449,7 @@
|
||||
name = "damage zone"
|
||||
icon_state = "zone_sel"
|
||||
screen_loc = ui_zonesel
|
||||
var/selecting = BODY_ZONE_CHEST
|
||||
var/overlay_icon = 'icons/mob/screen_gen.dmi'
|
||||
var/static/list/hover_overlays_cache = list()
|
||||
var/hovering
|
||||
|
||||
@@ -541,26 +542,24 @@
|
||||
return BODY_ZONE_HEAD
|
||||
|
||||
/obj/screen/zone_sel/proc/set_selected_zone(choice, mob/user)
|
||||
if(isobserver(user))
|
||||
if(user != hud?.mymob)
|
||||
return
|
||||
|
||||
if(choice != selecting)
|
||||
selecting = choice
|
||||
update_icon(usr)
|
||||
return 1
|
||||
if(choice != hud.mymob.zone_selected)
|
||||
hud.mymob.zone_selected = choice
|
||||
update_icon()
|
||||
|
||||
/obj/screen/zone_sel/update_icon(mob/user)
|
||||
cut_overlays()
|
||||
add_overlay(mutable_appearance('icons/mob/screen_gen.dmi', "[selecting]"))
|
||||
user.zone_selected = selecting
|
||||
return TRUE
|
||||
|
||||
/obj/screen/zone_sel/update_overlays()
|
||||
. = ..()
|
||||
if(!hud?.mymob)
|
||||
return
|
||||
. += mutable_appearance(overlay_icon, "[hud.mymob.zone_selected]")
|
||||
|
||||
/obj/screen/zone_sel/alien
|
||||
icon = 'icons/mob/screen_alien.dmi'
|
||||
|
||||
/obj/screen/zone_sel/alien/update_icon(mob/user)
|
||||
cut_overlays()
|
||||
add_overlay(mutable_appearance('icons/mob/screen_alien.dmi', "[selecting]"))
|
||||
user.zone_selected = selecting
|
||||
overlay_icon = 'icons/mob/screen_alien.dmi'
|
||||
|
||||
/obj/screen/zone_sel/robot
|
||||
icon = 'icons/mob/screen_cyborg.dmi'
|
||||
|
||||
@@ -69,24 +69,30 @@
|
||||
|
||||
using = new /obj/screen/swarmer/FabricateTrap()
|
||||
using.screen_loc = ui_hand_position(2)
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
|
||||
using = new /obj/screen/swarmer/Barricade()
|
||||
using.screen_loc = ui_hand_position(1)
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
|
||||
using = new /obj/screen/swarmer/Replicate()
|
||||
using.screen_loc = ui_zonesel
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
|
||||
using = new /obj/screen/swarmer/RepairSelf()
|
||||
using.screen_loc = ui_storage1
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
|
||||
using = new /obj/screen/swarmer/ToggleLight()
|
||||
using.screen_loc = ui_back
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
|
||||
using = new /obj/screen/swarmer/ContactSwarmers()
|
||||
using.screen_loc = ui_inventory
|
||||
using.hud = src
|
||||
static_inventory += using
|
||||
|
||||
@@ -98,17 +98,19 @@
|
||||
take_damage(I.force, I.damtype, "melee", 1)
|
||||
|
||||
/mob/living/attacked_by(obj/item/I, mob/living/user)
|
||||
//CIT CHANGES START HERE - combatmode and resting checks
|
||||
var/totitemdamage = I.force
|
||||
if(iscarbon(user))
|
||||
var/mob/living/carbon/tempcarb = user
|
||||
if(!tempcarb.combatmode)
|
||||
totitemdamage *= 0.5
|
||||
if(user.resting)
|
||||
totitemdamage *= 0.5
|
||||
//CIT CHANGES END HERE
|
||||
if(user != src && check_shields(I, totitemdamage, "the [I.name]", MELEE_ATTACK, I.armour_penetration))
|
||||
return FALSE
|
||||
send_item_attack_message(I, user)
|
||||
if(I.force)
|
||||
//CIT CHANGES START HERE - combatmode and resting checks
|
||||
var/totitemdamage = I.force
|
||||
if(iscarbon(user))
|
||||
var/mob/living/carbon/tempcarb = user
|
||||
if(!tempcarb.combatmode)
|
||||
totitemdamage *= 0.5
|
||||
if(user.resting)
|
||||
totitemdamage *= 0.5
|
||||
//CIT CHANGES END HERE
|
||||
apply_damage(totitemdamage, I.damtype) //CIT CHANGE - replaces I.force with totitemdamage
|
||||
if(I.damtype == BRUTE && !HAS_TRAIT(src, TRAIT_NOMARROW))
|
||||
if(prob(33))
|
||||
|
||||
@@ -91,6 +91,8 @@
|
||||
var/obj/item/clothing/gloves/G = gloves
|
||||
if(istype(G) && G.Touch(A,0)) // for magic gloves
|
||||
return
|
||||
if (istype(glasses) && glasses.ranged_attack(src,A,mouseparams))
|
||||
return
|
||||
|
||||
for(var/datum/mutation/human/HM in dna.mutations)
|
||||
HM.on_ranged_attack(src, A, mouseparams)
|
||||
|
||||
@@ -151,6 +151,7 @@
|
||||
var/key_mode
|
||||
var/value_mode
|
||||
var/splitter = " "
|
||||
var/lowercase = TRUE
|
||||
|
||||
/datum/config_entry/keyed_list/New()
|
||||
. = ..()
|
||||
@@ -167,7 +168,9 @@
|
||||
var/key_value = null
|
||||
|
||||
if(key_pos || value_mode == VALUE_MODE_FLAG)
|
||||
key_name = lowertext(copytext(str_val, 1, key_pos))
|
||||
key_name = copytext(str_val, 1, key_pos)
|
||||
if(lowercase)
|
||||
key_name = lowertext(key_name)
|
||||
key_value = copytext(str_val, key_pos + 1)
|
||||
var/new_key
|
||||
var/new_value
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
var/list/modes // allowed modes
|
||||
var/list/gamemode_cache
|
||||
var/list/votable_modes // votable modes
|
||||
var/list/storyteller_cache
|
||||
var/list/mode_names
|
||||
var/list/mode_reports
|
||||
var/list/mode_false_report_weight
|
||||
@@ -37,6 +38,7 @@
|
||||
CRASH("/datum/controller/configuration/Load() called more than once!")
|
||||
InitEntries()
|
||||
LoadModes()
|
||||
storyteller_cache = typecacheof(/datum/dynamic_storyteller, TRUE)
|
||||
if(fexists("[directory]/config.txt") && LoadEntries("config.txt") <= 1)
|
||||
var/list/legacy_configs = list("game_options.txt", "dbconfig.txt", "comms.txt")
|
||||
for(var/I in legacy_configs)
|
||||
@@ -227,6 +229,7 @@
|
||||
for(var/T in gamemode_cache)
|
||||
// I wish I didn't have to instance the game modes in order to look up
|
||||
// their information, but it is the only way (at least that I know of).
|
||||
// for future reference: just use initial() lol
|
||||
var/datum/game_mode/M = new T()
|
||||
|
||||
if(M.config_tag)
|
||||
@@ -317,6 +320,14 @@
|
||||
return new T
|
||||
return new /datum/game_mode/extended()
|
||||
|
||||
/datum/controller/configuration/proc/pick_storyteller(storyteller_name)
|
||||
for(var/T in storyteller_cache)
|
||||
var/datum/dynamic_storyteller/S = T
|
||||
var/name = initial(S.name)
|
||||
if(name && name == storyteller_name)
|
||||
return T
|
||||
return /datum/dynamic_storyteller/classic
|
||||
|
||||
/datum/controller/configuration/proc/get_runnable_modes()
|
||||
var/list/datum/game_mode/runnable_modes = new
|
||||
var/list/probabilities = Get(/datum/config_entry/keyed_list/probability)
|
||||
|
||||
@@ -376,6 +376,21 @@
|
||||
|
||||
/datum/config_entry/flag/disable_stambuffer
|
||||
|
||||
/datum/config_entry/keyed_list/box_random_engine
|
||||
key_mode = KEY_MODE_TEXT
|
||||
value_mode = VALUE_MODE_FLAG
|
||||
lowercase = FALSE
|
||||
splitter = "-"
|
||||
|
||||
/datum/config_entry/number/auto_transfer_delay
|
||||
config_entry_value = 72000
|
||||
min_val = 0
|
||||
|
||||
/datum/config_entry/flag/pai_custom_holoforms
|
||||
|
||||
/datum/config_entry/number/marauder_delay_non_reebe
|
||||
config_entry_value = 1800
|
||||
min_val = 0
|
||||
|
||||
/datum/config_entry/flag/allow_clockwork_marauder_on_station
|
||||
config_entry_value = TRUE
|
||||
|
||||
@@ -315,7 +315,7 @@ SUBSYSTEM_DEF(air)
|
||||
var/starting_ats = active_turfs.len
|
||||
sleep(world.tick_lag)
|
||||
var/timer = world.timeofday
|
||||
warning("There are [starting_ats] active turfs at roundstart, this is a mapping error caused by a difference of the air between the adjacent turfs. You can see its coordinates using \"Mapping -> Show roundstart AT list\" verb (debug verbs required)")
|
||||
log_mapping("There are [starting_ats] active turfs at roundstart caused by a difference of the air between the adjacent turfs. You can see its coordinates using \"Mapping -> Show roundstart AT list\" verb (debug verbs required).")
|
||||
for(var/turf/T in active_turfs)
|
||||
GLOB.active_turfs_startlist += T
|
||||
|
||||
@@ -382,6 +382,9 @@ SUBSYSTEM_DEF(air)
|
||||
CHECK_TICK
|
||||
|
||||
/datum/controller/subsystem/air/proc/setup_template_machinery(list/atmos_machines)
|
||||
if(!initialized)
|
||||
return
|
||||
|
||||
for(var/A in atmos_machines)
|
||||
var/obj/machinery/atmospherics/AM = A
|
||||
AM.atmosinit()
|
||||
|
||||
@@ -658,7 +658,7 @@ SUBSYSTEM_DEF(job)
|
||||
message_admins(msg)
|
||||
CRASH(msg)
|
||||
|
||||
/datum/controller/subsystem/job/proc/equip_loadout(mob/dead/new_player/N, mob/living/M, equipbackpackstuff)
|
||||
/datum/controller/subsystem/job/proc/equip_loadout(mob/dead/new_player/N, mob/living/M, equipbackpackstuff, bypass_prereqs = FALSE)
|
||||
var/mob/the_mob = N
|
||||
if(!the_mob)
|
||||
the_mob = M // cause this doesn't get assigned if player is a latejoiner
|
||||
@@ -671,7 +671,7 @@ SUBSYSTEM_DEF(job)
|
||||
if(!G)
|
||||
continue
|
||||
var/permitted = TRUE
|
||||
if(G.restricted_roles && G.restricted_roles.len && !(M.mind.assigned_role in G.restricted_roles))
|
||||
if(!bypass_prereqs && G.restricted_roles && G.restricted_roles.len && !(M.mind.assigned_role in G.restricted_roles))
|
||||
permitted = FALSE
|
||||
if(G.donoritem && !G.donator_ckey_check(the_mob.client.ckey))
|
||||
permitted = FALSE
|
||||
|
||||
@@ -91,6 +91,7 @@ SUBSYSTEM_DEF(mapping)
|
||||
var/list/space_ruins = levels_by_trait(ZTRAIT_SPACE_RUINS)
|
||||
if (space_ruins.len)
|
||||
seedRuins(space_ruins, CONFIG_GET(number/space_budget), /area/space, space_ruins_templates)
|
||||
SSmapping.seedStation()
|
||||
loading_ruins = FALSE
|
||||
#endif
|
||||
repopulate_sorted_areas()
|
||||
@@ -363,6 +364,8 @@ GLOBAL_LIST_EMPTY(the_station_areas)
|
||||
lava_ruins_templates[R.name] = R
|
||||
else if(istype(R, /datum/map_template/ruin/space))
|
||||
space_ruins_templates[R.name] = R
|
||||
else if(istype(R, /datum/map_template/ruin/station))
|
||||
station_room_templates[R.name] = R
|
||||
|
||||
/datum/controller/subsystem/mapping/proc/preloadShuttleTemplates()
|
||||
var/list/unbuyable = generateMapList("[global.config.directory]/unbuyableshuttles.txt")
|
||||
@@ -524,4 +527,15 @@ GLOBAL_LIST_EMPTY(the_station_areas)
|
||||
if(!isolated_ruins_z)
|
||||
isolated_ruins_z = add_new_zlevel("Isolated Ruins/Reserved", list(ZTRAIT_RESERVED = TRUE, ZTRAIT_ISOLATED_RUINS = TRUE))
|
||||
initialize_reserved_level(isolated_ruins_z.z_value)
|
||||
return isolated_ruins_z.z_value
|
||||
return isolated_ruins_z.z_value
|
||||
|
||||
// Station Ruins
|
||||
/datum/controller/subsystem/mapping
|
||||
var/list/station_room_templates = list()
|
||||
|
||||
/datum/controller/subsystem/mapping/proc/seedStation()
|
||||
for(var/V in GLOB.stationroom_landmarks)
|
||||
var/obj/effect/landmark/stationroom/LM = V
|
||||
LM.load()
|
||||
if(GLOB.stationroom_landmarks.len)
|
||||
seedStation() //I'm sure we can trust everyone not to insert a 1x1 rooms which loads a landmark which loads a landmark which loads a la...
|
||||
|
||||
@@ -12,13 +12,15 @@ SUBSYSTEM_DEF(persistence)
|
||||
var/list/obj/structure/chisel_message/chisel_messages = list()
|
||||
var/list/saved_messages = list()
|
||||
var/list/saved_modes = list(1,2,3)
|
||||
var/list/saved_threat_levels = list(1,1,1)
|
||||
var/list/saved_dynamic_rules = list(list(),list(),list())
|
||||
var/list/saved_storytellers = list("foo","bar","baz","foo again","bar again")
|
||||
var/list/saved_maps
|
||||
var/list/saved_trophies = list()
|
||||
var/list/spawned_objects = list()
|
||||
var/list/antag_rep = list()
|
||||
var/list/antag_rep_change = list()
|
||||
var/list/picture_logging_information = list()
|
||||
var/list/saved_votes = list()
|
||||
var/list/obj/structure/sign/picture_frame/photo_frames
|
||||
var/list/obj/item/storage/photo_album/photo_albums
|
||||
|
||||
@@ -28,9 +30,12 @@ SUBSYSTEM_DEF(persistence)
|
||||
LoadChiselMessages()
|
||||
LoadTrophies()
|
||||
LoadRecentModes()
|
||||
LoadRecentThreats()
|
||||
LoadRecentStorytellers()
|
||||
LoadRecentRulesets()
|
||||
LoadRecentMaps()
|
||||
LoadPhotoPersistence()
|
||||
for(var/client/C in GLOB.clients)
|
||||
LoadSavedVote(C.ckey)
|
||||
if(CONFIG_GET(flag/use_antag_rep))
|
||||
LoadAntagReputation()
|
||||
LoadRandomizedRecipes()
|
||||
@@ -168,14 +173,23 @@ SUBSYSTEM_DEF(persistence)
|
||||
return
|
||||
saved_modes = json["data"]
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/LoadRecentThreats()
|
||||
var/json_file = file("data/RecentThreatLevels.json")
|
||||
/datum/controller/subsystem/persistence/proc/LoadRecentRulesets()
|
||||
var/json_file = file("data/RecentRulesets.json")
|
||||
if(!fexists(json_file))
|
||||
return
|
||||
var/list/json = json_decode(file2text(json_file))
|
||||
if(!json)
|
||||
return
|
||||
saved_threat_levels = json["data"]
|
||||
saved_dynamic_rules = json["data"]
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/LoadRecentStorytellers()
|
||||
var/json_file = file("data/RecentStorytellers.json")
|
||||
if(!fexists(json_file))
|
||||
return
|
||||
var/list/json = json_decode(file2text(json_file))
|
||||
if(!json)
|
||||
return
|
||||
saved_storytellers = json["data"]
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/LoadRecentMaps()
|
||||
var/json_file = file("data/RecentMaps.json")
|
||||
@@ -196,6 +210,15 @@ SUBSYSTEM_DEF(persistence)
|
||||
return
|
||||
antag_rep = json_decode(json)
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/LoadSavedVote(var/ckey)
|
||||
var/json_file = file("data/player_saves/[copytext(ckey,1,2)]/[ckey]/SavedVotes.json")
|
||||
if(!fexists(json_file))
|
||||
return
|
||||
var/list/json = json_decode(file2text(json_file))
|
||||
if(!json)
|
||||
return
|
||||
saved_votes[ckey] = json["data"]
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/SetUpTrophies(list/trophy_items)
|
||||
for(var/A in GLOB.trophy_cases)
|
||||
var/obj/structure/displaycase/trophy/T = A
|
||||
@@ -227,7 +250,10 @@ SUBSYSTEM_DEF(persistence)
|
||||
CollectSecretSatchels()
|
||||
CollectTrophies()
|
||||
CollectRoundtype()
|
||||
CollectThreatLevel()
|
||||
if(istype(SSticker.mode, /datum/game_mode/dynamic))
|
||||
var/datum/game_mode/dynamic/mode = SSticker.mode
|
||||
CollectStoryteller(mode)
|
||||
CollectRulesets(mode)
|
||||
RecordMaps()
|
||||
SavePhotoPersistence() //THIS IS PERSISTENCE, NOT THE LOGGING PORTION.
|
||||
if(CONFIG_GET(flag/use_antag_rep))
|
||||
@@ -384,17 +410,31 @@ SUBSYSTEM_DEF(persistence)
|
||||
fdel(json_file)
|
||||
WRITE_FILE(json_file, json_encode(file_data))
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/CollectThreatLevel()
|
||||
if(istype(SSticker.mode, /datum/game_mode/dynamic))
|
||||
var/datum/game_mode/dynamic/mode = SSticker.mode
|
||||
saved_threat_levels[3] = saved_threat_levels[2]
|
||||
saved_threat_levels[2] = saved_threat_levels [1]
|
||||
saved_threat_levels[1] = mode.threat_level
|
||||
var/json_file = file("data/RecentThreatLevels.json")
|
||||
var/list/file_data = list()
|
||||
file_data["data"] = saved_threat_levels
|
||||
fdel(json_file)
|
||||
WRITE_FILE(json_file, json_encode(file_data))
|
||||
/datum/controller/subsystem/persistence/proc/CollectStoryteller(var/datum/game_mode/dynamic/mode)
|
||||
saved_storytellers.len = 5
|
||||
saved_storytellers[5] = saved_storytellers[4]
|
||||
saved_storytellers[4] = saved_storytellers[3]
|
||||
saved_storytellers[3] = saved_storytellers[2]
|
||||
saved_storytellers[2] = saved_storytellers[1]
|
||||
saved_storytellers[1] = mode.storyteller.name
|
||||
var/json_file = file("data/RecentStorytellers.json")
|
||||
var/list/file_data = list()
|
||||
file_data["data"] = saved_storytellers
|
||||
fdel(json_file)
|
||||
WRITE_FILE(json_file, json_encode(file_data))
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/CollectRulesets(var/datum/game_mode/dynamic/mode)
|
||||
saved_dynamic_rules[3] = saved_dynamic_rules[2]
|
||||
saved_dynamic_rules[2] = saved_dynamic_rules[1]
|
||||
saved_dynamic_rules[1] = list()
|
||||
for(var/r in mode.executed_rules)
|
||||
var/datum/dynamic_ruleset/rule = r
|
||||
saved_dynamic_rules[1] += rule.config_tag
|
||||
var/json_file = file("data/RecentRulesets.json")
|
||||
var/list/file_data = list()
|
||||
file_data["data"] = saved_dynamic_rules
|
||||
fdel(json_file)
|
||||
WRITE_FILE(json_file, json_encode(file_data))
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/RecordMaps()
|
||||
saved_maps = saved_maps?.len ? list("[SSmapping.config.map_name]") | saved_maps : list("[SSmapping.config.map_name]")
|
||||
@@ -459,3 +499,11 @@ SUBSYSTEM_DEF(persistence)
|
||||
|
||||
fdel(json_file)
|
||||
WRITE_FILE(json_file, json_encode(file_data))
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/SaveSavedVotes()
|
||||
for(var/ckey in saved_votes)
|
||||
var/json_file = file("data/player_saves/[copytext(ckey,1,2)]/[ckey]/SavedVotes.json")
|
||||
var/list/file_data = list()
|
||||
file_data["data"] = saved_votes[ckey]
|
||||
fdel(json_file)
|
||||
WRITE_FILE(json_file, json_encode(file_data))
|
||||
|
||||
@@ -6,6 +6,7 @@ PROCESSING_SUBSYSTEM_DEF(nanites)
|
||||
var/list/datum/nanite_cloud_backup/cloud_backups = list()
|
||||
var/list/mob/living/nanite_monitored_mobs = list()
|
||||
var/list/datum/nanite_program/relay/nanite_relays = list()
|
||||
var/neural_network_count = 0
|
||||
|
||||
/datum/controller/subsystem/processing/nanites/proc/check_hardware(datum/nanite_cloud_backup/backup)
|
||||
if(QDELETED(backup.storage) || (backup.storage.stat & (NOPOWER|BROKEN)))
|
||||
|
||||
@@ -35,7 +35,7 @@ PROCESSING_SUBSYSTEM_DEF(quirks)
|
||||
var/list/my_quirks = cli.prefs.all_quirks.Copy()
|
||||
var/list/cut
|
||||
if(job?.blacklisted_quirks)
|
||||
cut = filter_quirks(quirks, job)
|
||||
cut = filter_quirks(my_quirks, job)
|
||||
for(var/V in my_quirks)
|
||||
var/datum/quirk/Q = quirks[V]
|
||||
if(Q)
|
||||
@@ -63,28 +63,28 @@ PROCESSING_SUBSYSTEM_DEF(quirks)
|
||||
for(var/i in quirk_names)
|
||||
. += quirk_points_by_name(i)
|
||||
|
||||
/datum/controller/subsystem/processing/quirks/proc/filter_quirks(list/quirks, datum/job/job)
|
||||
/datum/controller/subsystem/processing/quirks/proc/filter_quirks(list/our_quirks, datum/job/job)
|
||||
var/list/cut = list()
|
||||
var/list/banned_names = list()
|
||||
for(var/i in job.blacklisted_quirks)
|
||||
var/name = quirk_name_by_path(i)
|
||||
if(name)
|
||||
banned_names += name
|
||||
var/list/blacklisted = quirks & banned_names
|
||||
var/list/blacklisted = our_quirks & banned_names
|
||||
if(length(blacklisted))
|
||||
for(var/i in blacklisted)
|
||||
quirks -= i
|
||||
our_quirks -= i
|
||||
cut += i
|
||||
|
||||
/* //Code to automatically reduce positive quirks until balance is even.
|
||||
var/points_used = total_points(quirks)
|
||||
var/points_used = total_points(our_quirks)
|
||||
if(points_used > 0)
|
||||
//they owe us points, let's collect.
|
||||
for(var/i in quirks)
|
||||
for(var/i in our_quirks)
|
||||
var/points = quirk_points_by_name(i)
|
||||
if(points > 0)
|
||||
cut += i
|
||||
quirks -= i
|
||||
our_quirks -= i
|
||||
points_used -= points
|
||||
if(points_used <= 0)
|
||||
break
|
||||
@@ -92,9 +92,9 @@ PROCESSING_SUBSYSTEM_DEF(quirks)
|
||||
|
||||
//Nah, let's null all non-neutrals out.
|
||||
if(cut.len)
|
||||
for(var/i in quirks)
|
||||
for(var/i in our_quirks)
|
||||
if(quirk_points_by_name(i) != 0)
|
||||
//cut += i -- Commented out: Only show the ones that triggered the quirk purge.
|
||||
quirks -= i
|
||||
our_quirks -= i
|
||||
|
||||
return cut
|
||||
|
||||
@@ -37,7 +37,7 @@ SUBSYSTEM_DEF(shuttle)
|
||||
var/points = 5000 //number of trade-points we have
|
||||
var/centcom_message = "" //Remarks from CentCom on how well you checked the last order.
|
||||
var/list/discoveredPlants = list() //Typepaths for unusual plants we've already sent CentCom, associated with their potencies
|
||||
var/passive_supply_points_per_minute = 750
|
||||
var/passive_supply_points_per_minute = 500
|
||||
|
||||
var/list/supply_packs = list()
|
||||
var/list/shoppinglist = list()
|
||||
|
||||
@@ -401,6 +401,9 @@ SUBSYSTEM_DEF(ticker)
|
||||
qdel(player)
|
||||
living.notransform = TRUE
|
||||
if(living.client)
|
||||
if (living.client.prefs && living.client.prefs.auto_ooc)
|
||||
if (living.client.prefs.chat_toggles & CHAT_OOC)
|
||||
living.client.prefs.chat_toggles ^= CHAT_OOC
|
||||
var/obj/screen/splash/S = new(living.client, TRUE)
|
||||
S.Fade(TRUE)
|
||||
livings += living
|
||||
@@ -480,7 +483,10 @@ SUBSYSTEM_DEF(ticker)
|
||||
SSticker.timeLeft = 900
|
||||
SSticker.modevoted = TRUE
|
||||
var/dynamic = CONFIG_GET(flag/dynamic_voting)
|
||||
SSvote.initiate_vote(dynamic ? "dynamic" : "roundtype","server",TRUE)
|
||||
if(dynamic)
|
||||
SSvote.initiate_vote("dynamic","server",hideresults=TRUE,votesystem=SCORE_VOTING,forced=TRUE,vote_time = 2 MINUTES)
|
||||
else
|
||||
SSvote.initiate_vote("roundtype","server",hideresults=TRUE,votesystem=PLURALITY_VOTING,forced=TRUE, vote_time = 2 MINUTES)
|
||||
|
||||
/datum/controller/subsystem/ticker/Recover()
|
||||
current_state = SSticker.current_state
|
||||
|
||||
@@ -93,7 +93,7 @@ SUBSYSTEM_DEF(traumas)
|
||||
/obj/item/clothing/under/rank/head_of_security/grey, /obj/item/clothing/under/rank/head_of_security/alt,
|
||||
/obj/item/clothing/under/rank/research_director/alt, /obj/item/clothing/under/rank/research_director/turtleneck,
|
||||
/obj/item/clothing/under/captainparade, /obj/item/clothing/under/hosparademale, /obj/item/clothing/under/hosparadefem,
|
||||
/obj/item/clothing/head/helmet/abductor, /obj/item/clothing/suit/armor/abductor/vest, /obj/item/abductor_baton,
|
||||
/obj/item/clothing/head/helmet/abductor, /obj/item/clothing/suit/armor/abductor/vest, /obj/item/abductor/baton,
|
||||
/obj/item/storage/belt/military/abductor, /obj/item/gun/energy/alien, /obj/item/abductor/silencer,
|
||||
/obj/item/abductor/gizmo, /obj/item/clothing/under/rank/centcom_officer,
|
||||
/obj/item/clothing/suit/space/hardsuit/ert, /obj/item/clothing/suit/space/hardsuit/ert/sec,
|
||||
@@ -136,7 +136,7 @@ SUBSYSTEM_DEF(traumas)
|
||||
"aliens" = typecacheof(list(/obj/item/clothing/mask/facehugger, /obj/item/organ/body_egg/alien_embryo,
|
||||
/obj/structure/alien, /obj/item/toy/toy_xeno,
|
||||
/obj/item/clothing/suit/armor/abductor, /obj/item/abductor, /obj/item/gun/energy/alien,
|
||||
/obj/item/abductor_baton, /obj/item/radio/headset/abductor, /obj/item/scalpel/alien, /obj/item/hemostat/alien,
|
||||
/obj/item/abductor/baton, /obj/item/radio/headset/abductor, /obj/item/scalpel/alien, /obj/item/hemostat/alien,
|
||||
/obj/item/retractor/alien, /obj/item/circular_saw/alien, /obj/item/surgicaldrill/alien, /obj/item/cautery/alien,
|
||||
/obj/item/clothing/head/helmet/abductor, /obj/structure/bed/abductor, /obj/structure/table_frame/abductor,
|
||||
/obj/structure/table/abductor, /obj/structure/table/optable/abductor, /obj/structure/closet/abductor, /obj/item/organ/heart/gland,
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
#define VOTE_COOLDOWN 10
|
||||
|
||||
SUBSYSTEM_DEF(vote)
|
||||
name = "Vote"
|
||||
wait = 10
|
||||
@@ -8,13 +10,17 @@ SUBSYSTEM_DEF(vote)
|
||||
|
||||
var/initiator = null
|
||||
var/started_time = null
|
||||
var/time_remaining = 0
|
||||
var/end_time = 0
|
||||
var/mode = null
|
||||
var/vote_system = PLURALITY_VOTING
|
||||
var/question = null
|
||||
var/list/choices = list()
|
||||
var/list/choice_descs = list() // optional descriptions
|
||||
var/list/voted = list()
|
||||
var/list/voting = list()
|
||||
var/list/saved = list()
|
||||
var/list/generated_actions = list()
|
||||
var/next_pop = 0
|
||||
|
||||
var/obfuscated = FALSE//CIT CHANGE - adds obfuscated/admin-only votes
|
||||
|
||||
@@ -22,28 +28,30 @@ SUBSYSTEM_DEF(vote)
|
||||
|
||||
/datum/controller/subsystem/vote/fire() //called by master_controller
|
||||
if(mode)
|
||||
time_remaining = round((started_time + CONFIG_GET(number/vote_period) - world.time)/10)
|
||||
|
||||
if(time_remaining < 0)
|
||||
if(end_time < world.time)
|
||||
result()
|
||||
SSpersistence.SaveSavedVotes()
|
||||
for(var/client/C in voting)
|
||||
C << browse(null, "window=vote;can_close=0")
|
||||
reset()
|
||||
else
|
||||
else if(next_pop < world.time)
|
||||
var/datum/browser/client_popup
|
||||
for(var/client/C in voting)
|
||||
client_popup = new(C, "vote", "Voting Panel")
|
||||
client_popup = new(C, "vote", "Voting Panel", nwidth=600,nheight=700)
|
||||
client_popup.set_window_options("can_close=0")
|
||||
client_popup.set_content(interface(C))
|
||||
client_popup.open(0)
|
||||
next_pop = world.time+VOTE_COOLDOWN
|
||||
|
||||
|
||||
|
||||
/datum/controller/subsystem/vote/proc/reset()
|
||||
initiator = null
|
||||
time_remaining = 0
|
||||
end_time = 0
|
||||
mode = null
|
||||
question = null
|
||||
choices.Cut()
|
||||
choice_descs.Cut()
|
||||
voted.Cut()
|
||||
voting.Cut()
|
||||
obfuscated = FALSE //CIT CHANGE - obfuscated votes
|
||||
@@ -84,17 +92,114 @@ SUBSYSTEM_DEF(vote)
|
||||
. += option
|
||||
return .
|
||||
|
||||
/datum/controller/subsystem/vote/proc/calculate_condorcet_votes(var/blackbox_text)
|
||||
// https://en.wikipedia.org/wiki/Schulze_method#Implementation
|
||||
var/list/d[][] = new/list(choices.len,choices.len) // the basic vote matrix, how many times a beats b
|
||||
for(var/ckey in voted)
|
||||
var/list/this_vote = voted[ckey]
|
||||
for(var/a in 1 to choices.len)
|
||||
for(var/b in a+1 to choices.len)
|
||||
var/a_rank = this_vote.Find(a)
|
||||
var/b_rank = this_vote.Find(b)
|
||||
a_rank = a_rank ? a_rank : choices.len+1
|
||||
b_rank = b_rank ? b_rank : choices.len+1
|
||||
if(a_rank<b_rank)
|
||||
d[a][b]++
|
||||
else if(b_rank<a_rank)
|
||||
d[b][a]++
|
||||
//if equal, do nothing
|
||||
var/list/p[][] = new/list(choices.len,choices.len) //matrix of shortest path from a to b
|
||||
for(var/i in 1 to choices.len)
|
||||
for(var/j in 1 to choices.len)
|
||||
if(i != j)
|
||||
var/pref_number = d[i][j]
|
||||
var/opposite_pref = d[j][i]
|
||||
if(pref_number>opposite_pref)
|
||||
p[i][j] = d[i][j]
|
||||
p[j][i] = 0
|
||||
else
|
||||
p[i][j] = 0
|
||||
p[j][i] = d[i][j]
|
||||
for(var/i in 1 to choices.len)
|
||||
for(var/j in 1 to choices.len)
|
||||
if(i != j)
|
||||
for(var/k in 1 to choices.len) // YEAH O(n^3) !!
|
||||
if(i != k && j != k)
|
||||
p[j][k] = max(p[j][k],min(p[j][i], p[i][k]))
|
||||
//one last pass, now that we've done the math
|
||||
for(var/i in 1 to choices.len)
|
||||
for(var/j in 1 to choices.len)
|
||||
if(i != j)
|
||||
SSblackbox.record_feedback("nested tally","voting",p[i][j],list(blackbox_text,"Shortest Paths",choices[i],choices[j]))
|
||||
if(p[i][j] >= p[j][i])
|
||||
choices[choices[i]]++ // higher shortest path = better candidate, so we add to choices here
|
||||
// choices[choices[i]] is the schulze ranking, here, rather than raw vote numbers
|
||||
|
||||
/datum/controller/subsystem/vote/proc/calculate_majority_judgement_vote(var/blackbox_text)
|
||||
// https://en.wikipedia.org/wiki/Majority_judgment
|
||||
var/list/scores_by_choice = list()
|
||||
for(var/choice in choices)
|
||||
scores_by_choice[choice] = list()
|
||||
for(var/ckey in voted)
|
||||
var/list/this_vote = voted[ckey]
|
||||
var/list/pretty_vote = list()
|
||||
for(var/choice in this_vote)
|
||||
sorted_insert(scores_by_choice[choice],this_vote[choice],/proc/cmp_numeric_asc)
|
||||
// START BALLOT GATHERING
|
||||
pretty_vote += choice
|
||||
pretty_vote[choice] = GLOB.vote_score_options[this_vote[choice]]
|
||||
SSblackbox.record_feedback("associative","voting_ballots",1,pretty_vote)
|
||||
// END BALLOT GATHERING
|
||||
for(var/score_name in scores_by_choice)
|
||||
var/list/score = scores_by_choice[score_name]
|
||||
for(var/indiv_score in score)
|
||||
SSblackbox.record_feedback("nested tally","voting",1,list(blackbox_text,"Scores",score_name,GLOB.vote_score_options[indiv_score]))
|
||||
if(score.len == 0)
|
||||
scores_by_choice -= score_name
|
||||
while(scores_by_choice.len > 1)
|
||||
var/highest_median = 0
|
||||
for(var/score_name in scores_by_choice) // first get highest median
|
||||
var/list/score = scores_by_choice[score_name]
|
||||
if(!score.len)
|
||||
scores_by_choice -= score_name
|
||||
continue
|
||||
var/median = score[max(1,round(score.len/2))]
|
||||
if(median >= highest_median)
|
||||
highest_median = median
|
||||
for(var/score_name in scores_by_choice) // then, remove
|
||||
var/list/score = scores_by_choice[score_name]
|
||||
var/median = score[max(1,round(score.len/2))]
|
||||
if(median < highest_median)
|
||||
scores_by_choice -= score_name
|
||||
for(var/score_name in scores_by_choice) // after removals
|
||||
var/list/score = scores_by_choice[score_name]
|
||||
if(score.len == 0)
|
||||
choices[score_name] += 100 // we're in a tie situation--just go with the first one
|
||||
return
|
||||
var/median_pos = max(1,round(score.len/2))
|
||||
score.Cut(median_pos,median_pos+1)
|
||||
choices[score_name]++
|
||||
|
||||
/datum/controller/subsystem/vote/proc/announce_result()
|
||||
var/list/winners = get_result()
|
||||
var/vote_title_text
|
||||
var/text
|
||||
if(question)
|
||||
text += "<b>[question]</b>"
|
||||
vote_title_text = "[question]"
|
||||
else
|
||||
text += "<b>[capitalize(mode)] Vote</b>"
|
||||
vote_title_text = "[capitalize(mode)] Vote"
|
||||
if(vote_system == RANKED_CHOICE_VOTING)
|
||||
calculate_condorcet_votes(vote_title_text)
|
||||
if(vote_system == SCORE_VOTING)
|
||||
calculate_majority_judgement_vote(vote_title_text)
|
||||
var/list/winners = get_result()
|
||||
var/was_roundtype_vote = mode == "roundtype" || mode == "dynamic"
|
||||
if(winners.len > 0)
|
||||
if(question)
|
||||
text += "<b>[question]</b>"
|
||||
else
|
||||
text += "<b>[capitalize(mode)] Vote</b>"
|
||||
if(was_roundtype_vote)
|
||||
stored_gamemode_votes = list()
|
||||
if(!obfuscated && vote_system == RANKED_CHOICE_VOTING)
|
||||
text += "\nIt should be noted that this is not a raw tally of votes (impossible in ranked choice) but the score determined by the schulze method of voting, so the numbers will look weird!"
|
||||
for(var/i=1,i<=choices.len,i++)
|
||||
var/votes = choices[choices[i]]
|
||||
if(!votes)
|
||||
@@ -116,17 +221,25 @@ SUBSYSTEM_DEF(vote)
|
||||
log_vote(text)
|
||||
remove_action_buttons()
|
||||
to_chat(world, "\n<font color='purple'>[text]</font>")
|
||||
switch(vote_system)
|
||||
if(APPROVAL_VOTING,PLURALITY_VOTING)
|
||||
for(var/i=1,i<=choices.len,i++)
|
||||
SSblackbox.record_feedback("nested tally","voting",choices[choices[i]],list(vote_title_text,choices[i]))
|
||||
if(RANKED_CHOICE_VOTING)
|
||||
for(var/i=1,i<=voted.len,i++)
|
||||
var/list/myvote = voted[voted[i]]
|
||||
for(var/j=1,j<=myvote.len,j++)
|
||||
SSblackbox.record_feedback("nested tally","voting",1,list(vote_title_text,"[j]\th",choices[myvote[j]]))
|
||||
if(obfuscated) //CIT CHANGE - adds obfuscated votes. this messages admins with the vote's true results
|
||||
var/admintext = "Obfuscated results"
|
||||
if(vote_system == RANKED_CHOICE_VOTING)
|
||||
admintext += "\nIt should be noted that this is not a raw tally of votes (impossible in ranked choice) but the score determined by the schulze method of voting, so the numbers will look weird!"
|
||||
for(var/i=1,i<=choices.len,i++)
|
||||
var/votes = choices[choices[i]]
|
||||
admintext += "\n<b>[choices[i]]:</b> [votes]"
|
||||
message_admins(admintext)
|
||||
return .
|
||||
|
||||
#define PEACE "calm"
|
||||
#define CHAOS "chaotic"
|
||||
|
||||
/datum/controller/subsystem/vote/proc/result()
|
||||
. = announce_result()
|
||||
var/restart = 0
|
||||
@@ -152,33 +265,15 @@ SUBSYSTEM_DEF(vote)
|
||||
if("dynamic")
|
||||
if(SSticker.current_state > GAME_STATE_PREGAME)//Don't change the mode if the round already started.
|
||||
return message_admins("A vote has tried to change the gamemode, but the game has already started. Aborting.")
|
||||
GLOB.master_mode = "dynamic"
|
||||
if("extended" in choices)
|
||||
if(. == "extended")
|
||||
GLOB.dynamic_forced_extended = TRUE // we still do the rest of the stuff
|
||||
choices[PEACE] += choices["extended"]
|
||||
var/mean = 0
|
||||
var/voters = 0
|
||||
for(var/client/c in GLOB.clients)
|
||||
var/vote = c.prefs.preferred_chaos
|
||||
if(vote)
|
||||
voters += 1
|
||||
switch(vote)
|
||||
if(CHAOS_NONE)
|
||||
mean -= 0.1
|
||||
if(CHAOS_LOW)
|
||||
mean -= 0.05
|
||||
if(CHAOS_HIGH)
|
||||
mean += 0.05
|
||||
if(CHAOS_MAX)
|
||||
mean += 0.1
|
||||
mean/=voters
|
||||
if(voted.len != 0)
|
||||
mean += (choices[PEACE]*-1+choices[CHAOS])/voted.len
|
||||
GLOB.dynamic_curve_centre = mean*20
|
||||
GLOB.dynamic_curve_width = CLAMP(2-abs(mean*5),0.5,4)
|
||||
to_chat(world,"<span class='boldannounce'>Dynamic curve centre set to [GLOB.dynamic_curve_centre] and width set to [GLOB.dynamic_curve_width].</span>")
|
||||
log_admin("Dynamic curve centre set to [GLOB.dynamic_curve_centre] and width set to [GLOB.dynamic_curve_width]")
|
||||
if(. == "Secret")
|
||||
GLOB.master_mode = "secret"
|
||||
SSticker.save_mode(.)
|
||||
message_admins("The gamemode has been voted for, and has been changed to: [GLOB.master_mode]")
|
||||
log_admin("Gamemode has been voted for and switched to: [GLOB.master_mode].")
|
||||
else
|
||||
GLOB.master_mode = "dynamic"
|
||||
var/datum/dynamic_storyteller/S = config.pick_storyteller(.)
|
||||
GLOB.dynamic_storyteller_type = S
|
||||
if("map")
|
||||
var/datum/map_config/VM = config.maplist[.]
|
||||
message_admins("The map has been voted for and will change to: [VM.map_name]")
|
||||
@@ -196,27 +291,58 @@ SUBSYSTEM_DEF(vote)
|
||||
else
|
||||
to_chat(world, "<span style='boldannounce'>Notice:Restart vote will not restart the server automatically because there are active admins on.</span>")
|
||||
message_admins("A restart vote has passed, but there are active admins on with +server, so it has been canceled. If you wish, you may restart the server.")
|
||||
|
||||
|
||||
return .
|
||||
|
||||
/datum/controller/subsystem/vote/proc/submit_vote(vote)
|
||||
/datum/controller/subsystem/vote/proc/submit_vote(vote, score = 0)
|
||||
if(mode)
|
||||
if(CONFIG_GET(flag/no_dead_vote) && usr.stat == DEAD && !usr.client.holder)
|
||||
return 0
|
||||
if(!(usr.ckey in voted))
|
||||
if(vote && 1<=vote && vote<=choices.len)
|
||||
voted += usr.ckey
|
||||
voted[usr.ckey] = vote
|
||||
choices[choices[vote]]++ //check this
|
||||
return vote
|
||||
else if(vote && 1<=vote && vote<=choices.len)
|
||||
choices[choices[voted[usr.ckey]]]--
|
||||
voted[usr.ckey] = vote
|
||||
choices[choices[vote]]++
|
||||
return vote
|
||||
if(vote && ISINRANGE(vote, 1, choices.len))
|
||||
switch(vote_system)
|
||||
if(PLURALITY_VOTING)
|
||||
if(usr.ckey in voted)
|
||||
choices[choices[voted[usr.ckey]]]--
|
||||
voted[usr.ckey] = vote
|
||||
choices[choices[vote]]++
|
||||
return vote
|
||||
else
|
||||
voted += usr.ckey
|
||||
voted[usr.ckey] = vote
|
||||
choices[choices[vote]]++ //check this
|
||||
return vote
|
||||
if(APPROVAL_VOTING)
|
||||
if(usr.ckey in voted)
|
||||
if(vote in voted[usr.ckey])
|
||||
voted[usr.ckey] -= vote
|
||||
choices[choices[vote]]--
|
||||
else
|
||||
voted[usr.ckey] += vote
|
||||
choices[choices[vote]]++
|
||||
else
|
||||
voted += usr.ckey
|
||||
voted[usr.ckey] = list(vote)
|
||||
choices[choices[vote]]++
|
||||
return vote
|
||||
if(RANKED_CHOICE_VOTING)
|
||||
if(usr.ckey in voted)
|
||||
if(vote in voted[usr.ckey])
|
||||
voted[usr.ckey] -= vote
|
||||
else
|
||||
voted += usr.ckey
|
||||
voted[usr.ckey] = list()
|
||||
voted[usr.ckey] += vote
|
||||
saved -= usr.ckey
|
||||
if(SCORE_VOTING)
|
||||
if(!(usr.ckey in voted))
|
||||
voted += usr.ckey
|
||||
voted[usr.ckey] = list()
|
||||
voted[usr.ckey][choices[vote]] = score
|
||||
saved -= usr.ckey
|
||||
return 0
|
||||
|
||||
/datum/controller/subsystem/vote/proc/initiate_vote(vote_type, initiator_key, hideresults)//CIT CHANGE - adds hideresults argument to votes to allow for obfuscated votes
|
||||
/datum/controller/subsystem/vote/proc/initiate_vote(vote_type, initiator_key, hideresults, votesystem = PLURALITY_VOTING, forced = FALSE,vote_time = -1)//CIT CHANGE - adds hideresults argument to votes to allow for obfuscated votes
|
||||
vote_system = votesystem
|
||||
if(!mode)
|
||||
if(started_time)
|
||||
var/next_allowed_time = (started_time + CONFIG_GET(number/vote_delay))
|
||||
@@ -257,11 +383,17 @@ SUBSYSTEM_DEF(vote)
|
||||
if("roundtype") //CIT CHANGE - adds the roundstart secret/extended vote
|
||||
choices.Add("secret", "extended")
|
||||
if("dynamic")
|
||||
var/saved_threats = SSpersistence.saved_threat_levels
|
||||
if((saved_threats[1]+saved_threats[2]+saved_threats[3])>150)
|
||||
choices.Add("extended",PEACE,CHAOS)
|
||||
else
|
||||
choices.Add(PEACE,CHAOS)
|
||||
for(var/T in config.storyteller_cache)
|
||||
var/datum/dynamic_storyteller/S = T
|
||||
var/recent_rounds = 0
|
||||
for(var/i in 1 to SSpersistence.saved_storytellers.len)
|
||||
if(SSpersistence.saved_storytellers[i] == initial(S.name))
|
||||
recent_rounds++
|
||||
if(recent_rounds < initial(S.weight))
|
||||
choices.Add(initial(S.name))
|
||||
choice_descs.Add(initial(S.desc))
|
||||
choices.Add("Secret")
|
||||
choice_descs.Add("Standard secret. Switches mode if it wins.")
|
||||
if("custom")
|
||||
question = stripped_input(usr,"What is the vote for?")
|
||||
if(!question)
|
||||
@@ -280,9 +412,11 @@ SUBSYSTEM_DEF(vote)
|
||||
if(mode == "custom")
|
||||
text += "\n[question]"
|
||||
log_vote(text)
|
||||
var/vp = CONFIG_GET(number/vote_period)
|
||||
var/vp = vote_time
|
||||
if(vp == -1)
|
||||
vp = CONFIG_GET(number/vote_period)
|
||||
to_chat(world, "\n<font color='purple'><b>[text]</b>\nType <b>vote</b> or click <a href='?src=[REF(src)]'>here</a> to place your votes.\nYou have [DisplayTimeText(vp)] to vote.</font>")
|
||||
time_remaining = round(vp/10)
|
||||
end_time = started_time+vp
|
||||
for(var/c in GLOB.clients)
|
||||
SEND_SOUND(c, sound('sound/misc/server-ready.ogg'))
|
||||
var/client/C = c
|
||||
@@ -292,6 +426,11 @@ SUBSYSTEM_DEF(vote)
|
||||
C.player_details.player_actions += V
|
||||
V.Grant(C.mob)
|
||||
generated_actions += V
|
||||
if(forced)
|
||||
var/datum/browser/popup = new(C, "vote", "Voting Panel",nwidth=600,nheight=700)
|
||||
popup.set_window_options("can_close=0")
|
||||
popup.set_content(SSvote.interface(C))
|
||||
popup.open(0)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
@@ -311,14 +450,71 @@ SUBSYSTEM_DEF(vote)
|
||||
. += "<h2>Vote: '[question]'</h2>"
|
||||
else
|
||||
. += "<h2>Vote: [capitalize(mode)]</h2>"
|
||||
. += "Time Left: [time_remaining] s<hr><ul>"
|
||||
for(var/i=1,i<=choices.len,i++)
|
||||
var/votes = choices[choices[i]]
|
||||
var/ivotedforthis = ((C.ckey in voted) && (voted[C.ckey] == i) ? TRUE : FALSE)
|
||||
if(!votes)
|
||||
votes = 0
|
||||
. += "<li>[ivotedforthis ? "<b>" : ""]<a href='?src=[REF(src)];vote=[i]'>[choices[i]]</a> ([obfuscated ? (admin ? "??? ([votes])" : "???") : votes] votes)[ivotedforthis ? "</b>" : ""]</li>" // CIT CHANGE - adds obfuscated votes
|
||||
. += "</ul><hr>"
|
||||
switch(vote_system)
|
||||
if(PLURALITY_VOTING)
|
||||
. += "<h3>Vote one.</h3>"
|
||||
if(APPROVAL_VOTING)
|
||||
. += "<h3>Vote any number of choices.</h3>"
|
||||
if(RANKED_CHOICE_VOTING)
|
||||
. += "<h3>Vote by order of preference. Revoting will demote to the bottom. 1 is your favorite, and higher numbers are worse.</h3>"
|
||||
if(SCORE_VOTING)
|
||||
. += "<h3>Grade the candidates by how much you like them.</h3>"
|
||||
. += "<h3>No-votes have no power--your opinion is only heard if you vote!</h3>"
|
||||
. += "Time Left: [DisplayTimeText(end_time-world.time)]<hr><ul>"
|
||||
switch(vote_system)
|
||||
if(PLURALITY_VOTING, APPROVAL_VOTING)
|
||||
for(var/i=1,i<=choices.len,i++)
|
||||
var/votes = choices[choices[i]]
|
||||
var/ivotedforthis = FALSE
|
||||
switch(vote_system)
|
||||
if(PLURALITY_VOTING)
|
||||
ivotedforthis = ((C.ckey in voted) && (voted[C.ckey] == i))
|
||||
if(APPROVAL_VOTING)
|
||||
ivotedforthis = ((C.ckey in voted) && (i in voted[C.ckey]))
|
||||
if(!votes)
|
||||
votes = 0
|
||||
. += "<li>[ivotedforthis ? "<b>" : ""]<a href='?src=[REF(src)];vote=[i]'>[choices[i]]</a> ([obfuscated ? (admin ? "??? ([votes])" : "???") : votes] votes)[ivotedforthis ? "</b>" : ""]</li>" // CIT CHANGE - adds obfuscated votes
|
||||
if(choice_descs.len >= i)
|
||||
. += "<li>[choice_descs[i]]</li>"
|
||||
. += "</ul><hr>"
|
||||
if(RANKED_CHOICE_VOTING)
|
||||
var/list/myvote = voted[C.ckey]
|
||||
for(var/i=1,i<=choices.len,i++)
|
||||
var/vote = (myvote ? (myvote.Find(i)) : 0)
|
||||
if(vote)
|
||||
. += "<li><b><a href='?src=[REF(src)];vote=[i]'>[choices[i]]</a> ([vote])</b></li>"
|
||||
else
|
||||
. += "<li><a href='?src=[REF(src)];vote=[i]'>[choices[i]]</a></li>"
|
||||
if(choice_descs.len >= i)
|
||||
. += "<li>[choice_descs[i]]</li>"
|
||||
. += "</ul><hr>"
|
||||
if(!(C.ckey in saved))
|
||||
. += "(<a href='?src=[REF(src)];vote=save'>Save vote</a>)"
|
||||
else
|
||||
. += "(Saved!)"
|
||||
. += "(<a href='?src=[REF(src)];vote=load'>Load vote from save</a>)"
|
||||
. += "(<a href='?src=[REF(src)];vote=reset'>Reset votes</a>)"
|
||||
if(SCORE_VOTING)
|
||||
var/list/myvote = voted[C.ckey]
|
||||
for(var/i=1,i<=choices.len,i++)
|
||||
. += "<li><b>[choices[i]]</b>"
|
||||
for(var/r in 1 to GLOB.vote_score_options.len)
|
||||
. += " <a href='?src=[REF(src)];vote=[i];score=[r]'>"
|
||||
if((choices[i] in myvote) && myvote[choices[i]] == r)
|
||||
. +="<b>([GLOB.vote_score_options[r]])</b>"
|
||||
else
|
||||
. +="[GLOB.vote_score_options[r]]"
|
||||
. += "</a>"
|
||||
. += "</li>"
|
||||
if(choice_descs.len >= i)
|
||||
. += "<li>[choice_descs[i]]</li>"
|
||||
. += "</ul><hr>"
|
||||
if(!(C.ckey in saved))
|
||||
. += "(<a href='?src=[REF(src)];vote=save'>Save vote</a>)"
|
||||
else
|
||||
. += "(Saved!)"
|
||||
. += "(<a href='?src=[REF(src)];vote=load'>Load vote from save</a>)"
|
||||
. += "(<a href='?src=[REF(src)];vote=reset'>Reset votes</a>)"
|
||||
if(admin)
|
||||
. += "(<a href='?src=[REF(src)];vote=cancel'>Cancel Vote</a>) "
|
||||
else
|
||||
@@ -376,8 +572,31 @@ SUBSYSTEM_DEF(vote)
|
||||
if("custom")
|
||||
if(usr.client.holder)
|
||||
initiate_vote("custom",usr.key)
|
||||
if("reset")
|
||||
if(usr.ckey in voted)
|
||||
voted -= usr.ckey
|
||||
if("save")
|
||||
if(usr.ckey in voted)
|
||||
if(!(usr.ckey in SSpersistence.saved_votes))
|
||||
SSpersistence.saved_votes[usr.ckey] = list()
|
||||
SSpersistence.saved_votes[usr.ckey][mode] = voted[usr.ckey]
|
||||
saved += usr.ckey
|
||||
if("load")
|
||||
if(!(usr.ckey in SSpersistence.saved_votes))
|
||||
SSpersistence.LoadSavedVote(usr.ckey)
|
||||
if(!(usr.ckey in SSpersistence.saved_votes))
|
||||
SSpersistence.saved_votes[usr.ckey] = list()
|
||||
if(usr.ckey in voted)
|
||||
SSpersistence.saved_votes[usr.ckey][mode] = voted[usr.ckey]
|
||||
else
|
||||
SSpersistence.saved_votes[usr.ckey][mode] = list()
|
||||
voted[usr.ckey] = SSpersistence.saved_votes[usr.ckey][mode]
|
||||
saved += usr.ckey
|
||||
else
|
||||
submit_vote(round(text2num(href_list["vote"])))
|
||||
if(vote_system == SCORE_VOTING)
|
||||
submit_vote(round(text2num(href_list["vote"])),round(text2num(href_list["score"])))
|
||||
else
|
||||
submit_vote(round(text2num(href_list["vote"])))
|
||||
usr.vote()
|
||||
|
||||
/datum/controller/subsystem/vote/proc/remove_action_buttons()
|
||||
@@ -392,7 +611,7 @@ SUBSYSTEM_DEF(vote)
|
||||
set category = "OOC"
|
||||
set name = "Vote"
|
||||
|
||||
var/datum/browser/popup = new(src, "vote", "Voting Panel")
|
||||
var/datum/browser/popup = new(src, "vote", "Voting Panel",nwidth=600,nheight=700)
|
||||
popup.set_window_options("can_close=0")
|
||||
popup.set_content(SSvote.interface(client))
|
||||
popup.open(0)
|
||||
@@ -419,6 +638,3 @@ SUBSYSTEM_DEF(vote)
|
||||
var/datum/player_details/P = GLOB.player_details[owner.ckey]
|
||||
if(P)
|
||||
P.player_actions -= src
|
||||
|
||||
#undef PEACE
|
||||
#undef CHAOS
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
|
||||
if(ishuman(M) && source.force && source.get_sharpness())
|
||||
var/mob/living/carbon/human/H = M
|
||||
if((H.health <= H.crit_threshold || (user.pulling == H && user.grab_state >= GRAB_NECK) || H.IsSleeping()) && user.zone_selected == BODY_ZONE_HEAD) // Only sleeping, neck grabbed, or crit, can be sliced.
|
||||
if((H.health <= H.crit_threshold || (user.pulling == H && user.grab_state >= GRAB_NECK) || H.IsSleeping()) && user.zone_selected == BODY_ZONE_PRECISE_MOUTH) // Only sleeping, neck grabbed, or crit, can be sliced.
|
||||
if(H.has_status_effect(/datum/status_effect/neck_slice))
|
||||
user.show_message("<span class='warning'>[H]'s neck has already been already cut, you can't make the bleeding any worse!</span>", 1, \
|
||||
"<span class='warning'>Their neck has already been already cut, you can't make the bleeding any worse!</span>")
|
||||
@@ -120,4 +120,4 @@
|
||||
if(eater.safety_mode || (eater.stat & (BROKEN|NOPOWER))) //I'm so sorry.
|
||||
return
|
||||
if(L.stat == DEAD && (L.butcher_results || L.guaranteed_butcher_results))
|
||||
Butcher(parent, L)
|
||||
Butcher(parent, L)
|
||||
|
||||
@@ -11,8 +11,9 @@
|
||||
var/list/datum/nanite_program/programs = list()
|
||||
var/max_programs = NANITE_PROGRAM_LIMIT
|
||||
|
||||
var/stealth = FALSE //if TRUE, does not appear on HUDs and health scans, and does not display the program list on nanite scans
|
||||
|
||||
var/stealth = FALSE //if TRUE, does not appear on HUDs and health scans
|
||||
var/diagnostics = TRUE //if TRUE, displays program list when scanned by nanite scanners
|
||||
|
||||
/datum/component/nanites/Initialize(amount = 100, cloud = 0)
|
||||
if(!isliving(parent) && !istype(parent, /datum/nanite_cloud_backup))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
@@ -252,8 +253,8 @@
|
||||
to_chat(user, "<span class='info'>Cloud ID: [cloud_id ? cloud_id : "Disabled"]</span>")
|
||||
to_chat(user, "<span class='info'>================</span>")
|
||||
to_chat(user, "<span class='info'>Program List:</span>")
|
||||
if(stealth)
|
||||
to_chat(user, "<span class='alert'>%#$ENCRYPTED&^@</span>")
|
||||
if(!diagnostics)
|
||||
to_chat(user, "<span class='alert'>Diagnostics Disabled</span>")
|
||||
else
|
||||
for(var/X in programs)
|
||||
var/datum/nanite_program/NP = X
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
/datum/component/shrink
|
||||
var/olddens
|
||||
var/oldopac
|
||||
dupe_mode = COMPONENT_DUPE_HIGHLANDER
|
||||
|
||||
/datum/component/shrink/Initialize(shrink_time)
|
||||
if(!isatom(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
var/atom/parent_atom = parent
|
||||
parent_atom.transform = parent_atom.transform.Scale(0.5,0.5)
|
||||
olddens = parent_atom.density
|
||||
oldopac = parent_atom.opacity
|
||||
parent_atom.density = 0
|
||||
parent_atom.opacity = 0
|
||||
if(isliving(parent_atom))
|
||||
var/mob/living/L = parent_atom
|
||||
L.add_movespeed_modifier(MOVESPEED_ID_SHRINK_RAY, update=TRUE, priority=100, multiplicative_slowdown=4)
|
||||
if(iscarbon(L))
|
||||
var/mob/living/carbon/C = L
|
||||
C.unequip_everything()
|
||||
C.visible_message("<span class='warning'>[C]'s belongings fall off of [C.p_them()] as they shrink down!</span>",
|
||||
"<span class='userdanger'>Your belongings fall away as everything grows bigger!</span>")
|
||||
if(ishuman(C))
|
||||
var/mob/living/carbon/human/H = C
|
||||
H.physiology.damage_resistance -= 100//carbons take double damage while shrunk
|
||||
parent_atom.visible_message("<span class='warning'>[parent_atom] shrinks down to a tiny size!</span>",
|
||||
"<span class='userdanger'>Everything grows bigger!</span>")
|
||||
QDEL_IN(src, shrink_time)
|
||||
|
||||
|
||||
/datum/component/shrink/Destroy()
|
||||
var/atom/parent_atom = parent
|
||||
parent_atom.transform = parent_atom.transform.Scale(2,2)
|
||||
parent_atom.density = olddens
|
||||
parent_atom.opacity = oldopac
|
||||
if(isliving(parent_atom))
|
||||
var/mob/living/L = parent_atom
|
||||
L.remove_movespeed_modifier(MOVESPEED_ID_SHRINK_RAY)
|
||||
if(ishuman(L))
|
||||
var/mob/living/carbon/human/H = L
|
||||
H.physiology.damage_resistance += 100
|
||||
..()
|
||||
@@ -0,0 +1,25 @@
|
||||
/datum/component/sizzle
|
||||
var/mutable_appearance/sizzling
|
||||
var/sizzlealpha = 0
|
||||
dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS
|
||||
|
||||
/datum/component/sizzle/Initialize()
|
||||
if(!isatom(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
setup_sizzle()
|
||||
|
||||
/datum/component/sizzle/InheritComponent(datum/component/C, i_am_original)
|
||||
var/atom/food = parent
|
||||
sizzlealpha += 5
|
||||
sizzling.alpha = sizzlealpha
|
||||
food.cut_overlay(sizzling)
|
||||
food.add_overlay(sizzling)
|
||||
|
||||
/datum/component/sizzle/proc/setup_sizzle()
|
||||
var/atom/food = parent
|
||||
var/icon/grill_marks = icon(initial(food.icon), initial(food.icon_state)) //we only want to apply grill marks to the initial icon_state for each object
|
||||
grill_marks.Blend("#fff", ICON_ADD) //fills the icon_state with white (except where it's transparent)
|
||||
grill_marks.Blend(icon('icons/obj/kitchen.dmi', "grillmarks"), ICON_MULTIPLY) //adds grill marks and the remaining white areas become transparent
|
||||
sizzling = new(grill_marks)
|
||||
sizzling.alpha = sizzlealpha
|
||||
food.add_overlay(sizzling)
|
||||
@@ -66,7 +66,7 @@
|
||||
/datum/component/storage/concrete/_insert_physical_item(obj/item/I, override = FALSE)
|
||||
. = TRUE
|
||||
var/atom/real_location = real_location()
|
||||
if(I.loc != real_location)
|
||||
if(I.loc != real_location && real_location)
|
||||
I.forceMove(real_location)
|
||||
refresh_mob_views()
|
||||
|
||||
|
||||
@@ -136,9 +136,10 @@
|
||||
/datum/emote/sound
|
||||
var/sound //Sound to play when emote is called
|
||||
var/vary = FALSE //used for the honk borg emote
|
||||
var/volume = 50
|
||||
mob_type_allowed_typecache = list(/mob/living/brain, /mob/living/silicon)
|
||||
|
||||
/datum/emote/sound/run_emote(mob/user, params)
|
||||
. = ..()
|
||||
if(.)
|
||||
playsound(user.loc, sound, 50, vary)
|
||||
playsound(user.loc, sound, volume, vary)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
mid_sounds = list('sound/machines/shower/shower_mid1.ogg'=1,'sound/machines/shower/shower_mid2.ogg'=1,'sound/machines/shower/shower_mid3.ogg'=1)
|
||||
mid_length = 10
|
||||
end_sound = 'sound/machines/shower/shower_end.ogg'
|
||||
volume = 20
|
||||
volume = 10
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
mid_sounds = list('sound/machines/fryer/deep_fryer_1.ogg' = 1, 'sound/machines/fryer/deep_fryer_2.ogg' = 1)
|
||||
mid_length = 2
|
||||
end_sound = 'sound/machines/fryer/deep_fryer_emerge.ogg'
|
||||
volume = 15
|
||||
volume = 5
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -43,3 +43,12 @@
|
||||
mid_length = 10
|
||||
end_sound = 'sound/machines/microwave/microwave-end.ogg'
|
||||
volume = 90
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/datum/looping_sound/grill
|
||||
mid_length = 2
|
||||
mid_sounds = list('sound/machines/fryer/deep_fryer_1.ogg' = 1, 'sound/machines/fryer/deep_fryer_2.ogg' = 1)
|
||||
volume = 10
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -8,6 +8,8 @@
|
||||
var/deflection_chance = 0 //Chance to deflect projectiles
|
||||
var/reroute_deflection = FALSE //Delete the bullet, or actually deflect it in some direction?
|
||||
var/block_chance = 0 //Chance to block melee attacks using items while on throw mode.
|
||||
var/dodge_chance = 0
|
||||
var/restraining = 0 //used in cqc's disarm_act to check if the disarmed is being restrained and so whether they should be put in a chokehold or not
|
||||
var/help_verb
|
||||
var/pacifism_check = TRUE //are the martial arts combos/attacks unable to be used by pacifist.
|
||||
var/allow_temp_override = TRUE //if this martial art can be overridden by temporary martial arts
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
help_verb = /mob/living/carbon/human/proc/CQC_help
|
||||
block_chance = 75
|
||||
var/old_grab_state = null
|
||||
var/restraining = FALSE
|
||||
|
||||
/datum/martial_art/cqc/reset_streak(mob/living/carbon/human/new_target)
|
||||
. = ..()
|
||||
|
||||
@@ -0,0 +1,158 @@
|
||||
#define SIDE_KICK_COMBO "DH"
|
||||
#define SHOULDER_FLIP_COMBO "GHDGHH"
|
||||
#define REPULSE_PUNCH_COMBO "GHGH"
|
||||
#define FOOT_SMASH_COMBO "HH"
|
||||
#define DEFT_SWITCH_COMBO "GDD"
|
||||
|
||||
/datum/martial_art/the_rising_bass
|
||||
name = "The Rising Bass"
|
||||
id = MARTIALART_RISINGBASS
|
||||
dodge_chance = 100
|
||||
allow_temp_override = FALSE
|
||||
help_verb = /mob/living/carbon/human/proc/rising_bass_help
|
||||
|
||||
/datum/martial_art/the_rising_bass/proc/check_streak(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
if(findtext(streak,SIDE_KICK_COMBO))
|
||||
streak = ""
|
||||
sideKick(A,D)
|
||||
return 1
|
||||
if(findtext(streak,SHOULDER_FLIP_COMBO))
|
||||
streak = ""
|
||||
shoulderFlip(A,D)
|
||||
return 1
|
||||
if(findtext(streak,REPULSE_PUNCH_COMBO))
|
||||
streak = ""
|
||||
repulsePunch(A,D)
|
||||
return 1
|
||||
if(findtext(streak,FOOT_SMASH_COMBO))
|
||||
streak = ""
|
||||
footSmash(A,D)
|
||||
return 1
|
||||
if(findtext(streak,DEFT_SWITCH_COMBO))
|
||||
streak = ""
|
||||
deftSwitch(A,D)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
||||
/datum/martial_art/the_rising_bass/proc/sideKick(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
if(!D.IsKnockdown() || D.lying == 0)
|
||||
var/turf/H = get_step(D, A.dir & (NORTH | SOUTH) ? pick(EAST, WEST) : pick(NORTH, SOUTH))
|
||||
A.do_attack_animation(D, ATTACK_EFFECT_KICK)
|
||||
D.visible_message("<span class='warning'>[A] kicks [D] in the side, sliding them over!</span>", \
|
||||
"<span class='userdanger'>[A] kicks you in the side, forcing you to step away!</span>")
|
||||
playsound(get_turf(A), 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
|
||||
D.apply_damage(5, BRUTE, BODY_ZONE_CHEST)
|
||||
D.Knockdown(60)
|
||||
var/L = H
|
||||
for(var/obj/i in H.contents)
|
||||
if(!istype(i,/mob) && i.density == 1)
|
||||
L = D.loc
|
||||
D.forceMove(L)
|
||||
log_combat(A, D, "side kicked (Rising Bass)")
|
||||
return 1
|
||||
return basic_hit(A,D)
|
||||
|
||||
/datum/martial_art/the_rising_bass/proc/shoulderFlip(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
if(!D.IsKnockdown() || !D.lying)
|
||||
var/turf/H = get_step(A, get_dir(D,A))
|
||||
var/L = H
|
||||
for(var/obj/i in H.contents)
|
||||
if(!istype(i,/mob) && i.density == 1)//(i.anchored == 1 && i.density == 1) || istype(i,/obj/structure) || istype(i,/turf/closed)
|
||||
L = A.loc
|
||||
A.do_attack_animation(D, ATTACK_EFFECT_PUNCH)
|
||||
D.visible_message("<span class='warning'>[A] flips [D] over their shoulder, slamming them into the ground!</span>", \
|
||||
"<span class='userdanger'>[A] flips you over their shoulder, slamming you into the ground!</span>")
|
||||
playsound(get_turf(A), 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
|
||||
D.emote("scream")
|
||||
D.apply_damage(10, BRUTE, BODY_ZONE_CHEST)
|
||||
D.apply_damage(30, BRUTE, BODY_ZONE_HEAD)
|
||||
D.Sleeping(60)
|
||||
D.Knockdown(300)
|
||||
D.forceMove(L)
|
||||
log_combat(A, D, "shoulder flipped (Rising Bass)")
|
||||
return 1
|
||||
return basic_hit(A,D)
|
||||
|
||||
/datum/martial_art/the_rising_bass/proc/repulsePunch(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
if(!D.IsKnockdown() || !D.lying)
|
||||
A.do_attack_animation(D, ATTACK_EFFECT_PUNCH)
|
||||
D.visible_message("<span class='warning'>[A] smashes [D] in the chest, throwing them away!</span>", \
|
||||
"<span class='userdanger'>[A] smashes you in the chest, repelling you away!</span>")
|
||||
playsound(get_turf(A), 'sound/weapons/punch1.ogg', 50, 1, -1)
|
||||
var/atom/F = get_edge_target_turf(D, get_dir(A, get_step_away(D, A)))
|
||||
D.throw_at(F, 10, 1)
|
||||
D.apply_damage(10, BRUTE, BODY_ZONE_CHEST)
|
||||
D.Knockdown(90)
|
||||
log_combat(A, D, "repulse punched (Rising Bass)")
|
||||
return 1
|
||||
return basic_hit(A,D)
|
||||
|
||||
/datum/martial_art/the_rising_bass/proc/footSmash(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
if(!D.IsKnockdown() || !D.lying)
|
||||
A.do_attack_animation(D, ATTACK_EFFECT_KICK)
|
||||
D.visible_message("<span class='warning'>[A] smashes their foot down on [D]'s foot!</span>", \
|
||||
"<span class='userdanger'>[A] smashes your foot!</span>")
|
||||
playsound(get_turf(A), 'sound/weapons/punch1.ogg', 50, 1, -1)
|
||||
D.apply_damage(5, BRUTE, pick(BODY_ZONE_L_LEG, BODY_ZONE_R_LEG))
|
||||
D.dropItemToGround(D.get_active_held_item())
|
||||
log_combat(A, D, "foot smashed (Rising Bass)")
|
||||
return 1
|
||||
return basic_hit(A,D)
|
||||
|
||||
/datum/martial_art/the_rising_bass/proc/deftSwitch(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
if(!D.IsKnockdown() || !D.lying)
|
||||
if (D.get_active_held_item())
|
||||
var/obj/item/G = D.get_active_held_item()
|
||||
if (G && !(G.item_flags & (ABSTRACT|DROPDEL)) && D.temporarilyRemoveItemFromInventory(G))
|
||||
A.put_in_hands(G)
|
||||
D.visible_message("<span class='warning'>[A] slaps [D]'s hands, taking [G] from them!</span>", \
|
||||
"<span class='userdanger'>[A] slaps you, taking [G] from you!</span>")
|
||||
log_combat(A, D, "deft switched (Rising Bass)")
|
||||
return 1
|
||||
else
|
||||
to_chat(A, "<i>[G] can't be taken out of [D]'s hands!</i>")
|
||||
return 0
|
||||
|
||||
/datum/martial_art/the_rising_bass/disarm_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
add_to_streak("D",D)
|
||||
if(check_streak(A,D))
|
||||
return 1
|
||||
return ..()
|
||||
|
||||
/datum/martial_art/the_rising_bass/harm_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
add_to_streak("H",D)
|
||||
if(check_streak(A,D))
|
||||
return 1
|
||||
return ..()
|
||||
|
||||
/datum/martial_art/the_rising_bass/grab_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
add_to_streak("G",D)
|
||||
if(check_streak(A,D))
|
||||
return 1
|
||||
return ..()
|
||||
|
||||
/mob/living/carbon/human/proc/rising_bass_help()
|
||||
set name = "Recall Teachings"
|
||||
set desc = "Remember the martial techniques of the Rising Bass clan."
|
||||
set category = "Rising Bass"
|
||||
|
||||
to_chat(usr, "<b><i>You retreat inward and recall the teachings of the Rising Bass...</i></b>")
|
||||
|
||||
to_chat(usr, "<span class='notice'>Side Kick</span>: Disarm Harm. Forces opponent to step to the side.")
|
||||
to_chat(usr, "<span class='notice'>Shoulder Flip</span>: Grab Harm Disarm Grab Harm Harm. Flips opponent over your shoulder and stuns.")
|
||||
to_chat(usr, "<span class='notice'>Repulse Punch</span>: Grab Harm Grab Harm. Slams the opponent far away from you.")
|
||||
to_chat(usr, "<span class='notice'>Foot Smash</span>: Harm Harm. Stuns opponent, minor damage.")
|
||||
to_chat(usr, "<span class='notice'>Deft Switch</span>: Grab Disarm Disarm. Switches the opponent's held item for your own. Most useful with nothing in your hand.")
|
||||
|
||||
/datum/martial_art/the_rising_bass/teach(mob/living/carbon/human/H, make_temporary = FALSE)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
ADD_TRAIT(H, TRAIT_NOGUNS, RISING_BASS_TRAIT)
|
||||
ADD_TRAIT(H, TRAIT_AUTO_CATCH_ITEM, RISING_BASS_TRAIT)
|
||||
|
||||
/datum/martial_art/the_rising_bass/on_remove(mob/living/carbon/human/H)
|
||||
. = ..()
|
||||
REMOVE_TRAIT(H, TRAIT_NOGUNS, RISING_BASS_TRAIT)
|
||||
REMOVE_TRAIT(H, TRAIT_AUTO_CATCH_ITEM, RISING_BASS_TRAIT)
|
||||
@@ -185,9 +185,8 @@
|
||||
righthand_file = 'icons/mob/inhands/weapons/staves_righthand.dmi'
|
||||
block_chance = 50
|
||||
|
||||
/obj/item/twohanded/bostaff/update_icon()
|
||||
/obj/item/twohanded/bostaff/update_icon_state()
|
||||
icon_state = "bostaff[wielded]"
|
||||
return
|
||||
|
||||
/obj/item/twohanded/bostaff/attack(mob/target, mob/living/user)
|
||||
add_fingerprint(user)
|
||||
|
||||
@@ -135,6 +135,9 @@
|
||||
if(L.client && L.client.prefs)
|
||||
L.canbearoused = L.client.prefs.arousable //Technically this should make taking over a character mean the body gain the new minds setting...
|
||||
L.update_arousal_hud() //Removes the old icon
|
||||
if (L.client.prefs.auto_ooc)
|
||||
if (L.client.prefs.chat_toggles & CHAT_OOC)
|
||||
L.client.prefs.chat_toggles ^= CHAT_OOC
|
||||
|
||||
SEND_SIGNAL(src, COMSIG_MIND_TRANSFER, new_character, old_character)
|
||||
|
||||
|
||||
@@ -134,6 +134,12 @@
|
||||
mood_change = 3
|
||||
timeout = 3000
|
||||
|
||||
/datum/mood_event/breakfast
|
||||
description = "<span class='nicegreen'>Nothing like a hearty breakfast to start the shift.</span>\n"
|
||||
mood_change = 2
|
||||
timeout = 15 MINUTES
|
||||
|
||||
//Power gamer stuff below
|
||||
/datum/mood_event/drankblood
|
||||
description = "<span class='nicegreen'>I have fed greedly from that which nourishes me.</span>\n"
|
||||
mood_change = 10
|
||||
@@ -143,6 +149,7 @@
|
||||
description = "<span class='nicegreen'>I slept in a coffin during the day. I feel whole again.</span>\n"
|
||||
mood_change = 8
|
||||
timeout = 1200
|
||||
|
||||
//Cursed stuff below.
|
||||
|
||||
/datum/mood_event/orgasm
|
||||
|
||||
@@ -95,6 +95,7 @@
|
||||
message = replacetext(message," ugly "," beautiful ")
|
||||
message = replacetext(message," douchbag "," nice guy ")
|
||||
message = replacetext(message," whore "," lady ")
|
||||
message = replacetext(message," gamer "," intellectual ")
|
||||
message = replacetext(message," nerd "," smarty pants ")
|
||||
message = replacetext(message," moron "," fun person ")
|
||||
message = replacetext(message," IT'S LOOSE "," EVERYTHING IS FINE ")
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
var/turf/master_turf //The center of the wave
|
||||
var/steps=0 //How far we've moved
|
||||
var/intensity //How strong it was originaly
|
||||
var/remaining_contam //How much contaminated material it still has
|
||||
var/range_modifier //Higher than 1 makes it drop off faster, 0.5 makes it drop off half etc
|
||||
var/move_dir //The direction of movement
|
||||
var/list/__dirs //The directions to the side of the wave, stored for easy looping
|
||||
@@ -18,6 +19,7 @@
|
||||
__dirs+=turn(dir, -90)
|
||||
|
||||
intensity = _intensity
|
||||
remaining_contam = intensity
|
||||
range_modifier = _range_modifier
|
||||
can_contaminate = _can_contaminate
|
||||
|
||||
@@ -46,8 +48,9 @@
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
radiate(atoms, FLOOR(strength, 1))
|
||||
|
||||
if(radiate(atoms, FLOOR(min(strength,remaining_contam), 1)))
|
||||
//oof ow ouch
|
||||
remaining_contam = max(0,remaining_contam-((min(strength,remaining_contam)-RAD_MINIMUM_CONTAMINATION) * RAD_CONTAMINATION_STR_COEFFICIENT))
|
||||
check_obstructions(atoms) // reduce our overall strength if there are radiation insulators
|
||||
|
||||
/datum/radiation_wave/proc/get_rad_atoms()
|
||||
@@ -89,7 +92,8 @@
|
||||
intensity *= (1-((1-thing.rad_insulation)/width))
|
||||
|
||||
/datum/radiation_wave/proc/radiate(list/atoms, strength)
|
||||
var/contamination_chance = (strength-RAD_MINIMUM_CONTAMINATION) * RAD_CONTAMINATION_CHANCE_COEFFICIENT * min(1, 1/(steps*range_modifier))
|
||||
var/can_contam = strength >= RAD_MINIMUM_CONTAMINATION
|
||||
var/list/contam_atoms = list()
|
||||
for(var/k in 1 to atoms.len)
|
||||
var/atom/thing = atoms[k]
|
||||
if(!thing)
|
||||
@@ -109,8 +113,14 @@
|
||||
))
|
||||
if(!can_contaminate || blacklisted[thing.type])
|
||||
continue
|
||||
if(prob(contamination_chance)) // Only stronk rads get to have little baby rads
|
||||
if(CHECK_BITFIELD(thing.rad_flags, RAD_NO_CONTAMINATE) || SEND_SIGNAL(thing, COMSIG_ATOM_RAD_CONTAMINATING, strength) & COMPONENT_BLOCK_CONTAMINATION)
|
||||
continue
|
||||
var/rad_strength = (strength-RAD_MINIMUM_CONTAMINATION) * RAD_CONTAMINATION_STR_COEFFICIENT
|
||||
if(CHECK_BITFIELD(thing.rad_flags, RAD_NO_CONTAMINATE) || SEND_SIGNAL(thing, COMSIG_ATOM_RAD_CONTAMINATING, strength) & COMPONENT_BLOCK_CONTAMINATION)
|
||||
continue
|
||||
contam_atoms += thing
|
||||
var/did_contam = 0
|
||||
if(length(can_contam))
|
||||
var/rad_strength = ((strength-RAD_MINIMUM_CONTAMINATION) * RAD_CONTAMINATION_STR_COEFFICIENT)/contam_atoms.len
|
||||
for(var/k in 1 to contam_atoms.len)
|
||||
var/atom/thing = contam_atoms[k]
|
||||
thing.AddComponent(/datum/component/radioactive, rad_strength, source)
|
||||
did_contam = 1
|
||||
return did_contam
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
/datum/map_template/ruin/station
|
||||
prefix = "_maps/RandomRuins/StationRuins/"
|
||||
cost = 0
|
||||
|
||||
// Boxstation
|
||||
// Engine
|
||||
|
||||
/datum/map_template/ruin/station/box/engine
|
||||
id = "engine_sm"
|
||||
suffix = "Box/Engine/engine_sm.dmm"
|
||||
name = "Engine SM"
|
||||
|
||||
/datum/map_template/ruin/station/box/engine/singulo
|
||||
id = "engine_singulo"
|
||||
suffix = "Box/Engine/engine_singulo.dmm"
|
||||
name = "Engine Singulo"
|
||||
|
||||
/datum/map_template/ruin/station/box/engine/tesla
|
||||
id = "engine_tesla"
|
||||
suffix = "Box/Engine/engine_tesla.dmm"
|
||||
name = "Engine Tesla"
|
||||
@@ -292,6 +292,7 @@
|
||||
var/mob/living/carbon/C = owner
|
||||
for(var/X in C.bodyparts)
|
||||
var/obj/item/bodypart/BP = X
|
||||
BP.max_damage *= 10
|
||||
BP.brute_dam *= 10
|
||||
BP.burn_dam *= 10
|
||||
owner.toxloss *= 10
|
||||
@@ -377,6 +378,7 @@
|
||||
var/obj/item/bodypart/BP = X
|
||||
BP.brute_dam *= 0.1
|
||||
BP.burn_dam *= 0.1
|
||||
BP.max_damage /= 10
|
||||
owner.toxloss *= 0.1
|
||||
owner.oxyloss *= 0.1
|
||||
owner.cloneloss *= 0.1
|
||||
|
||||
@@ -208,3 +208,15 @@
|
||||
/datum/quirk/bloodpressure/remove()
|
||||
var/mob/living/M = quirk_holder
|
||||
M.blood_ratio = 1
|
||||
|
||||
/datum/quirk/night_vision
|
||||
name = "Night Vision"
|
||||
desc = "You can see slightly more clearly in full darkness than most people."
|
||||
value = 1
|
||||
mob_trait = TRAIT_NIGHT_VISION
|
||||
gain_text = "<span class='notice'>The shadows seem a little less dark.</span>"
|
||||
lose_text = "<span class='danger'>Everything seems a little darker.</span>"
|
||||
|
||||
/datum/quirk/night_vision/on_spawn()
|
||||
var/mob/living/carbon/human/H = quirk_holder
|
||||
H.update_sight()
|
||||
|
||||
@@ -88,15 +88,6 @@
|
||||
if(quirk_holder)
|
||||
quirk_holder.remove_client_colour(/datum/client_colour/monochrome)
|
||||
|
||||
/datum/quirk/crocrin_immunity
|
||||
name = "Crocin Immunity"
|
||||
desc = "You're one of the few people in the galaxy who are genetically immune to Crocin and Hexacrocin products and their addictive properties! However, you can still get brain damage from Hexacrocin addiction."
|
||||
mob_trait = TRAIT_CROCRIN_IMMUNE
|
||||
value = 0
|
||||
gain_text = "<span class='notice'>You feel more prudish.</span>"
|
||||
lose_text = "<span class='notice'>You don't feel as prudish as before.</span>"
|
||||
medical_record_text = "Patient exhibits a special gene that makes them immune to aphrodisiacs."
|
||||
|
||||
/datum/quirk/libido
|
||||
name = "Nymphomania"
|
||||
desc = "You're always feeling a bit in heat. Also, you get aroused faster than usual."
|
||||
@@ -131,26 +122,6 @@
|
||||
gain_text = "<span class='notice'>You feel like exposing yourself to the world.</span>"
|
||||
lose_text = "<span class='notice'>Indecent exposure doesn't sound as charming to you anymore.</span>"
|
||||
|
||||
/datum/quirk/pharmacokinesis //Prevents unwanted organ additions.
|
||||
name = "Acute hepatic pharmacokinesis"
|
||||
desc = "You've a rare genetic disorder that causes Incubus draft and Sucubus milk to be absorbed by your liver instead."
|
||||
value = 0
|
||||
mob_trait = TRAIT_PHARMA
|
||||
lose_text = "<span class='notice'>Your liver feels different.</span>"
|
||||
medical_record_text = "Non-invasive tests report that the patient's metabolism is indeed incompatible with a certain \"stimulants\"."
|
||||
var/active = FALSE
|
||||
var/power = 0
|
||||
var/cachedmoveCalc = 1
|
||||
|
||||
/datum/quirk/assblastusa
|
||||
name = "Buns of Steel"
|
||||
desc = "You've never skipped ass day. With this trait, you are completely immune to all forms of ass slapping and anyone who tries to slap your rock hard ass usually gets a broken hand."
|
||||
mob_trait = TRAIT_ASSBLASTUSA
|
||||
value = 0
|
||||
medical_record_text = "Patient never skipped ass day."
|
||||
gain_text = "<span class='notice'>Your ass rivals those of golems.</span>"
|
||||
lose_text = "<span class='notice'>Your butt feels more squishy and slappable.</span>"
|
||||
|
||||
/datum/quirk/alcohol_intolerance
|
||||
name = "Alcohol Intolerance"
|
||||
desc = "You take toxin damage from alcohol rather than getting drunk."
|
||||
|
||||
@@ -22,27 +22,17 @@
|
||||
target_trait = ZTRAIT_STATION
|
||||
|
||||
immunity_type = "rad"
|
||||
|
||||
var/radiation_intensity = 100
|
||||
|
||||
/datum/weather/rad_storm/telegraph()
|
||||
..()
|
||||
status_alarm(TRUE)
|
||||
|
||||
|
||||
/datum/weather/rad_storm/weather_act(mob/living/L)
|
||||
var/resist = L.getarmor(null, "rad")
|
||||
if(prob(40))
|
||||
if(ishuman(L))
|
||||
var/mob/living/carbon/human/H = L
|
||||
if(H.dna && !HAS_TRAIT(H, TRAIT_RADIMMUNE))
|
||||
if(prob(max(0,100-resist)))
|
||||
H.randmuti()
|
||||
if(prob(50))
|
||||
if(prob(90))
|
||||
H.randmutb()
|
||||
else
|
||||
H.randmutg()
|
||||
H.domutcheck()
|
||||
L.rad_act(20)
|
||||
var/ratio = 1 - (min(resist, 100) / 100)
|
||||
L.rad_act(radiation_intensity * ratio)
|
||||
|
||||
/datum/weather/rad_storm/end()
|
||||
if(..())
|
||||
|
||||
+11
-3
@@ -326,8 +326,13 @@ GLOBAL_LIST_EMPTY(teleportlocs)
|
||||
F.update_fire_light(fire)
|
||||
for(var/obj/machinery/light/L in src)
|
||||
L.update()
|
||||
|
||||
/area/proc/update_icon()
|
||||
/**
|
||||
* Update the icon state of the area
|
||||
*
|
||||
* Im not sure what the heck this does, somethign to do with weather being able to set icon
|
||||
* states on areas?? where the heck would that even display?
|
||||
*/
|
||||
/area/update_icon_state()
|
||||
var/weather_icon
|
||||
for(var/V in SSweather.processing)
|
||||
var/datum/weather/W = V
|
||||
@@ -337,7 +342,10 @@ GLOBAL_LIST_EMPTY(teleportlocs)
|
||||
if(!weather_icon)
|
||||
icon_state = null
|
||||
|
||||
/area/space/update_icon()
|
||||
/**
|
||||
* Update the icon of the area (overridden to always be null for space
|
||||
*/
|
||||
/area/space/update_icon_state()
|
||||
icon_state = null
|
||||
|
||||
/*
|
||||
|
||||
+30
-2
@@ -24,6 +24,8 @@
|
||||
var/list/add_overlays // a very temporary list of overlays to add
|
||||
|
||||
var/list/managed_vis_overlays //vis overlays managed by SSvis_overlays to automaticaly turn them like other overlays
|
||||
///overlays managed by update_overlays() to prevent removing overlays that weren't added by the same proc
|
||||
var/list/managed_overlays
|
||||
|
||||
var/datum/proximity_monitor/proximity_monitor
|
||||
var/buckle_message_cooldown = 0
|
||||
@@ -45,7 +47,7 @@
|
||||
/atom/New(loc, ...)
|
||||
//atom creation method that preloads variables at creation
|
||||
if(GLOB.use_preloader && (src.type == GLOB._preloader.target_path))//in case the instanciated atom is creating other atoms in New()
|
||||
GLOB._preloader.load(src)
|
||||
world.preloader_load(src)
|
||||
|
||||
if(datum_flags & DF_USE_TAG)
|
||||
GenerateTag()
|
||||
@@ -164,7 +166,7 @@
|
||||
|
||||
return FALSE
|
||||
|
||||
/atom/proc/attack_hulk(mob/living/carbon/human/user, does_attack_animation = 0)
|
||||
/atom/proc/attack_hulk(mob/living/carbon/human/user, does_attack_animation = FALSE)
|
||||
SEND_SIGNAL(src, COMSIG_ATOM_HULK_ATTACK, user)
|
||||
if(does_attack_animation)
|
||||
user.changeNext_move(CLICK_CD_MELEE)
|
||||
@@ -310,6 +312,32 @@
|
||||
|
||||
SEND_SIGNAL(src, COMSIG_PARENT_EXAMINE, user, .)
|
||||
|
||||
/// Updates the icon of the atom
|
||||
/atom/proc/update_icon()
|
||||
// I expect we're going to need more return flags and options in this proc
|
||||
var/signalOut = SEND_SIGNAL(src, COMSIG_ATOM_UPDATE_ICON)
|
||||
|
||||
if(!(signalOut & COMSIG_ATOM_NO_UPDATE_ICON_STATE))
|
||||
update_icon_state()
|
||||
|
||||
if(!(signalOut & COMSIG_ATOM_NO_UPDATE_OVERLAYS))
|
||||
var/list/new_overlays = update_overlays()
|
||||
if(managed_overlays)
|
||||
cut_overlay(managed_overlays)
|
||||
managed_overlays = null
|
||||
if(length(new_overlays))
|
||||
managed_overlays = new_overlays
|
||||
add_overlay(new_overlays)
|
||||
|
||||
/// Updates the icon state of the atom
|
||||
/atom/proc/update_icon_state()
|
||||
|
||||
/// Updates the overlays of the atom
|
||||
/atom/proc/update_overlays()
|
||||
SHOULD_CALL_PARENT(1)
|
||||
. = list()
|
||||
SEND_SIGNAL(src, COMSIG_ATOM_UPDATE_OVERLAYS, .)
|
||||
|
||||
/atom/proc/relaymove(mob/user)
|
||||
if(buckle_message_cooldown <= world.time)
|
||||
buckle_message_cooldown = world.time + 50
|
||||
|
||||
@@ -515,10 +515,10 @@
|
||||
step(src, AM.dir)
|
||||
..()
|
||||
|
||||
/atom/movable/proc/safe_throw_at(atom/target, range, speed, mob/thrower, spin=TRUE, diagonals_first = FALSE, var/datum/callback/callback)
|
||||
return throw_at(target, range, speed, thrower, spin, diagonals_first, callback)
|
||||
/atom/movable/proc/safe_throw_at(atom/target, range, speed, mob/thrower, spin=TRUE, diagonals_first = FALSE, var/datum/callback/callback, messy_throw = TRUE)
|
||||
return throw_at(target, range, speed, thrower, spin, diagonals_first, callback, messy_throw)
|
||||
|
||||
/atom/movable/proc/throw_at(atom/target, range, speed, mob/thrower, spin=TRUE, diagonals_first = FALSE, var/datum/callback/callback) //If this returns FALSE then callback will not be called.
|
||||
/atom/movable/proc/throw_at(atom/target, range, speed, mob/thrower, spin=TRUE, diagonals_first = FALSE, var/datum/callback/callback, messy_throw = TRUE) //If this returns FALSE then callback will not be called.
|
||||
. = FALSE
|
||||
if (!target || speed <= 0)
|
||||
return
|
||||
|
||||
@@ -57,7 +57,6 @@
|
||||
..()
|
||||
if(visualsOnly)
|
||||
return
|
||||
H.dna.add_mutation(CLOWNMUT)
|
||||
H.dna.add_mutation(SMILE)
|
||||
|
||||
/datum/outfit/syndicate/clownop/leader
|
||||
|
||||
@@ -1,14 +1,3 @@
|
||||
#define CURRENT_LIVING_PLAYERS 1
|
||||
#define CURRENT_LIVING_ANTAGS 2
|
||||
#define CURRENT_DEAD_PLAYERS 3
|
||||
#define CURRENT_OBSERVERS 4
|
||||
|
||||
#define ONLY_RULESET 1
|
||||
#define HIGHLANDER_RULESET 2
|
||||
#define TRAITOR_RULESET 4
|
||||
#define MINOR_RULESET 8
|
||||
|
||||
#define RULESET_STOP_PROCESSING 1
|
||||
|
||||
// -- Injection delays
|
||||
GLOBAL_VAR_INIT(dynamic_latejoin_delay_min, (10 MINUTES))
|
||||
@@ -52,6 +41,8 @@ GLOBAL_LIST_EMPTY(dynamic_forced_roundstart_ruleset)
|
||||
// Forced threat level, setting this to zero or higher forces the roundstart threat to the value.
|
||||
GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
|
||||
|
||||
GLOBAL_VAR_INIT(dynamic_storyteller_type, null)
|
||||
|
||||
/datum/game_mode/dynamic
|
||||
name = "dynamic mode"
|
||||
config_tag = "dynamic"
|
||||
@@ -60,7 +51,8 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
|
||||
announce_text = "Dynamic mode!" // This needs to be changed maybe
|
||||
|
||||
reroll_friendly = FALSE;
|
||||
|
||||
// Current storyteller
|
||||
var/datum/dynamic_storyteller/storyteller = null
|
||||
// Threat logging vars
|
||||
/// The "threat cap", threat shouldn't normally go above this and is used in ruleset calculations
|
||||
var/threat_level = 0
|
||||
@@ -164,6 +156,7 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
|
||||
|
||||
dat += "Threat to Spend: <b>[threat]</b> <a href='?src=\ref[src];[HrefToken()];adjustthreat=1'>\[Adjust\]</A> <a href='?src=\ref[src];[HrefToken()];threatlog=1'>\[View Log\]</a><br/>"
|
||||
dat += "<br/>"
|
||||
dat += "Storyteller: <b>[storyteller.name]</b><br/>"
|
||||
dat += "Parameters: centre = [GLOB.dynamic_curve_centre] ; width = [GLOB.dynamic_curve_width].<br/>"
|
||||
dat += "<i>On average, <b>[peaceful_percentage]</b>% of the rounds are more peaceful.</i><br/>"
|
||||
dat += "Forced extended: <a href='?src=\ref[src];[HrefToken()];forced_extended=1'><b>[GLOB.dynamic_forced_extended ? "On" : "Off"]</b></a><br/>"
|
||||
@@ -178,7 +171,7 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
|
||||
dat += "[DR.ruletype] - <b>[DR.name]</b><br>"
|
||||
else
|
||||
dat += "none.<br>"
|
||||
dat += "<br>Injection Timers: (<b>[get_injection_chance(TRUE)]%</b> chance)<BR>"
|
||||
dat += "<br>Injection Timers: (<b>[storyteller.get_injection_chance(TRUE)]%</b> chance)<BR>"
|
||||
dat += "Latejoin: [(latejoin_injection_cooldown-world.time)>60*10 ? "[round((latejoin_injection_cooldown-world.time)/60/10,0.1)] minutes" : "[(latejoin_injection_cooldown-world.time)] seconds"] <a href='?src=\ref[src];[HrefToken()];injectlate=1'>\[Now!\]</a><BR>"
|
||||
dat += "Midround: [(midround_injection_cooldown-world.time)>60*10 ? "[round((midround_injection_cooldown-world.time)/60/10,0.1)] minutes" : "[(midround_injection_cooldown-world.time)] seconds"] <a href='?src=\ref[src];[HrefToken()];injectmid=1'>\[Now!\]</a><BR>"
|
||||
dat += "Event: [(event_injection_cooldown-world.time)>60*10 ? "[round((event_injection_cooldown-world.time)/60/10,0.1)] minutes" : "[(event_injection_cooldown-world.time)] seconds"] <a href='?src=\ref[src];[HrefToken()];forceevent=1'>\[Now!\]</a><BR>"
|
||||
@@ -300,6 +293,7 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
|
||||
|
||||
/datum/game_mode/dynamic/proc/log_threat(var/log_str,var/verbose = FALSE)
|
||||
threat_log_verbose += ("[worldtime2text()]: "+log_str)
|
||||
SSblackbox.record_feedback("tally","dynamic_threat_log",1,log_str)
|
||||
if(!verbose)
|
||||
threat_log += log_str
|
||||
|
||||
@@ -329,8 +323,15 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
|
||||
peaceful_percentage = round(LORENTZ_CUMULATIVE_DISTRIBUTION(relative_threat, GLOB.dynamic_curve_centre, GLOB.dynamic_curve_width), 0.01)*100
|
||||
|
||||
threat = threat_level
|
||||
SSblackbox.record_feedback("tally","dynamic_threat",threat_level,"Initial threat level")
|
||||
SSblackbox.record_feedback("tally","dynamic_threat",GLOB.dynamic_curve_centre,"Curve centre")
|
||||
SSblackbox.record_feedback("tally","dynamic_threat",GLOB.dynamic_curve_width,"Curve width")
|
||||
SSblackbox.record_feedback("tally","dynamic_threat",peaceful_percentage,"Percent of same-vote rounds that are more peaceful")
|
||||
|
||||
/datum/game_mode/dynamic/can_start()
|
||||
storyteller = new GLOB.dynamic_storyteller_type // this is where all the initialization happens
|
||||
storyteller.on_start()
|
||||
SSblackbox.record_feedback("text","dynamic_storyteller",1,storyteller.name)
|
||||
message_admins("Dynamic mode parameters for the round:")
|
||||
message_admins("Centre is [GLOB.dynamic_curve_centre], Width is [GLOB.dynamic_curve_width], Forced extended is [GLOB.dynamic_forced_extended ? "Enabled" : "Disabled"], No stacking is [GLOB.dynamic_no_stacking ? "Enabled" : "Disabled"].")
|
||||
message_admins("Stacking limit is [GLOB.dynamic_stacking_limit], Classic secret is [GLOB.dynamic_classic_secret ? "Enabled" : "Disabled"], High population limit is [GLOB.dynamic_high_pop_limit].")
|
||||
@@ -340,18 +341,12 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
|
||||
if(GLOB.dynamic_forced_threat_level >= 0)
|
||||
threat_level = round(GLOB.dynamic_forced_threat_level, 0.1)
|
||||
threat = threat_level
|
||||
SSblackbox.record_feedback("tally","dynamic_threat",threat_level,"Threat level (forced)")
|
||||
else
|
||||
generate_threat()
|
||||
|
||||
var/latejoin_injection_cooldown_middle = 0.5*(GLOB.dynamic_first_latejoin_delay_max + GLOB.dynamic_first_latejoin_delay_min)
|
||||
latejoin_injection_cooldown = round(CLAMP(EXP_DISTRIBUTION(latejoin_injection_cooldown_middle), GLOB.dynamic_first_latejoin_delay_min, GLOB.dynamic_first_latejoin_delay_max)) + world.time
|
||||
storyteller.start_injection_cooldowns()
|
||||
|
||||
var/midround_injection_cooldown_middle = 0.5*(GLOB.dynamic_first_midround_delay_min + GLOB.dynamic_first_midround_delay_max)
|
||||
midround_injection_cooldown = round(CLAMP(EXP_DISTRIBUTION(midround_injection_cooldown_middle), GLOB.dynamic_first_midround_delay_min, GLOB.dynamic_first_midround_delay_max)) + world.time
|
||||
|
||||
var/event_injection_cooldown_middle = 0.5*(GLOB.dynamic_event_delay_max + GLOB.dynamic_event_delay_min)
|
||||
event_injection_cooldown = (round(CLAMP(EXP_DISTRIBUTION(event_injection_cooldown_middle), GLOB.dynamic_event_delay_min, GLOB.dynamic_event_delay_max)) + world.time)
|
||||
|
||||
log_game("DYNAMIC: Dynamic Mode initialized with a Threat Level of... [threat_level]!")
|
||||
initial_threat_level = threat_level
|
||||
return TRUE
|
||||
@@ -384,7 +379,8 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
|
||||
if (roundstart_rules.len <= 0)
|
||||
log_game("DYNAMIC: [roundstart_rules.len] rules.")
|
||||
return TRUE
|
||||
|
||||
SSblackbox.record_feedback("tally","dynamic",roundstart_rules.len,"Roundstart rules considered")
|
||||
SSblackbox.record_feedback("tally","dynamic",roundstart_pop_ready,"Players readied up")
|
||||
if(GLOB.dynamic_forced_roundstart_ruleset.len > 0)
|
||||
rigged_roundstart()
|
||||
else
|
||||
@@ -422,13 +418,7 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
|
||||
if (GLOB.dynamic_forced_extended)
|
||||
log_game("DYNAMIC: Starting a round of forced extended.")
|
||||
return TRUE
|
||||
var/list/drafted_rules = list()
|
||||
for (var/datum/dynamic_ruleset/roundstart/rule in roundstart_rules)
|
||||
if (rule.acceptable(roundstart_pop_ready, threat_level) && threat >= rule.cost) // If we got the population and threat required
|
||||
rule.candidates = candidates.Copy()
|
||||
rule.trim_candidates()
|
||||
if (rule.ready() && rule.candidates.len > 0)
|
||||
drafted_rules[rule] = rule.weight
|
||||
var/list/drafted_rules = storyteller.roundstart_draft()
|
||||
if(!drafted_rules.len)
|
||||
message_admins("Not enough threat level for roundstart antags!")
|
||||
log_game("DYNAMIC: Not enough threat level for roundstart antags!")
|
||||
@@ -537,6 +527,7 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
|
||||
if(rule.execute())
|
||||
if(rule.persistent)
|
||||
current_rules += rule
|
||||
SSblackbox.record_feedback("associative","dynamic_rulesets",1,rule.get_blackbox_info())
|
||||
return TRUE
|
||||
rule.clean_up() // Refund threat, delete teams and so on.
|
||||
executed_rules -= rule
|
||||
@@ -615,6 +606,7 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
|
||||
else if(new_rule.flags & ONLY_RULESET)
|
||||
only_ruleset_executed = TRUE
|
||||
log_game("DYNAMIC: Making a call to a specific ruleset...[new_rule.name]!")
|
||||
SSblackbox.record_feedback("associative","dynamic_rulesets",1,new_rule.get_blackbox_info())
|
||||
executed_rules += new_rule
|
||||
if (new_rule.persistent)
|
||||
current_rules += new_rule
|
||||
@@ -639,11 +631,11 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
|
||||
message_admins("[key_name(M)] joined the station, and was selected by the [rule.name] ruleset.")
|
||||
log_game("DYNAMIC: [key_name(M)] joined the station, and was selected by the [rule.name] ruleset.")
|
||||
executed_rules += rule
|
||||
SSblackbox.record_feedback("associative","dynamic_rulesets",1,rule.get_blackbox_info())
|
||||
rule.candidates.Cut()
|
||||
if (rule.persistent)
|
||||
current_rules += rule
|
||||
return TRUE
|
||||
rule.clean_up()
|
||||
stack_trace("The [rule.ruletype] rule \"[rule.name]\" failed to execute.")
|
||||
return FALSE
|
||||
|
||||
@@ -655,56 +647,45 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
|
||||
for (var/datum/dynamic_ruleset/rule in current_rules)
|
||||
if(rule.rule_process() == RULESET_STOP_PROCESSING) // If rule_process() returns 1 (RULESET_STOP_PROCESSING), stop processing.
|
||||
current_rules -= rule
|
||||
|
||||
SSblackbox.record_feedback("tally","dynamic",1,"Rulesets finished")
|
||||
SSblackbox.record_feedback("associative","dynamic_rulesets_finished",1,rule.get_blackbox_info())
|
||||
|
||||
storyteller.do_process()
|
||||
|
||||
if (midround_injection_cooldown < world.time)
|
||||
if (GLOB.dynamic_forced_extended)
|
||||
return
|
||||
|
||||
// Somehow it managed to trigger midround multiple times so this was moved here.
|
||||
// There is no way this should be able to trigger an injection twice now.
|
||||
var/midround_injection_cooldown_middle = 0.5*(GLOB.dynamic_midround_delay_max + GLOB.dynamic_midround_delay_min)
|
||||
midround_injection_cooldown = (round(CLAMP(EXP_DISTRIBUTION(midround_injection_cooldown_middle), GLOB.dynamic_midround_delay_min, GLOB.dynamic_midround_delay_max)) + world.time)
|
||||
midround_injection_cooldown = storyteller.get_midround_cooldown() + world.time
|
||||
|
||||
// Time to inject some threat into the round
|
||||
if(EMERGENCY_ESCAPED_OR_ENDGAMED) // Unless the shuttle is gone
|
||||
return
|
||||
if((world.realtime - SSshuttle.realtimeofstart) > SSshuttle.auto_call) // no rules after shuttle is auto-called
|
||||
return
|
||||
message_admins("DYNAMIC: Checking for midround injection.")
|
||||
log_game("DYNAMIC: Checking for midround injection.")
|
||||
|
||||
update_playercounts()
|
||||
if (get_injection_chance())
|
||||
var/cur_threat_frac = threat/threat_level
|
||||
var/list/drafted_rules = list()
|
||||
var/antag_num = current_players[CURRENT_LIVING_ANTAGS].len
|
||||
for (var/datum/dynamic_ruleset/midround/rule in midround_rules)
|
||||
// if there are antags OR the rule is an antag rule, antag_acceptable will be true.
|
||||
if (rule.acceptable(current_players[CURRENT_LIVING_PLAYERS].len, threat_level) && threat >= rule.cost)
|
||||
// Classic secret : only autotraitor/minor roles
|
||||
if (GLOB.dynamic_classic_secret && !((rule.flags & TRAITOR_RULESET) || (rule.flags & MINOR_RULESET)))
|
||||
continue
|
||||
rule.trim_candidates()
|
||||
if (rule.ready())
|
||||
if(!antag_num)
|
||||
drafted_rules[rule] = round(rule.get_weight() + (rule.cost * cur_threat_frac))
|
||||
else
|
||||
drafted_rules[rule] = rule.get_weight()
|
||||
if (prob(storyteller.get_injection_chance()))
|
||||
SSblackbox.record_feedback("tally","dynamic",1,"Attempted midround injections")
|
||||
var/list/drafted_rules = storyteller.midround_draft()
|
||||
if (drafted_rules.len > 0)
|
||||
SSblackbox.record_feedback("tally","dynamic",1,"Successful midround injections")
|
||||
picking_midround_latejoin_rule(drafted_rules)
|
||||
else
|
||||
midround_injection_cooldown = (midround_injection_cooldown + world.time)/2
|
||||
// get_injection_chance can do things on fail
|
||||
|
||||
if(event_injection_cooldown < world.time)
|
||||
var/event_injection_cooldown_middle = 0.5*(GLOB.dynamic_event_delay_max + GLOB.dynamic_event_delay_min)
|
||||
event_injection_cooldown = (round(CLAMP(EXP_DISTRIBUTION(event_injection_cooldown_middle), GLOB.dynamic_event_delay_min, GLOB.dynamic_event_delay_max)) + world.time)
|
||||
SSblackbox.record_feedback("tally","dynamic",1,"Attempted event injections")
|
||||
event_injection_cooldown = storyteller.get_event_cooldown() + world.time
|
||||
message_admins("DYNAMIC: Doing event injection.")
|
||||
log_game("DYNAMIC: Doing event injection.")
|
||||
update_playercounts()
|
||||
var/list/drafted_rules = list()
|
||||
for(var/datum/dynamic_ruleset/event/rule in events)
|
||||
if(rule.acceptable(current_players[CURRENT_LIVING_PLAYERS].len, threat_level) && threat >= rule.cost)
|
||||
if(rule.ready())
|
||||
drafted_rules[rule] = rule.get_weight()
|
||||
var/list/drafted_rules = storyteller.event_draft()
|
||||
if(drafted_rules.len > 0)
|
||||
SSblackbox.record_feedback("tally","dynamic",1,"Successful event injections")
|
||||
picking_midround_latejoin_rule(drafted_rules)
|
||||
|
||||
/// Updates current_players.
|
||||
@@ -721,38 +702,13 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
|
||||
if (M.mind && (M.mind.special_role || M.mind.antag_datums?.len > 0))
|
||||
current_players[CURRENT_LIVING_ANTAGS].Add(M)
|
||||
else
|
||||
if (istype(M,/mob/dead/observer))
|
||||
if (isobserver(M))
|
||||
var/mob/dead/observer/O = M
|
||||
if (O.started_as_observer) // Observers
|
||||
current_players[CURRENT_OBSERVERS].Add(M)
|
||||
continue
|
||||
current_players[CURRENT_DEAD_PLAYERS].Add(M) // Players who actually died (and admins who ghosted, would be nice to avoid counting them somehow)
|
||||
|
||||
/// Gets the chance for latejoin and midround injection, the dry_run argument is only used for forced injection.
|
||||
/datum/game_mode/dynamic/proc/get_injection_chance(dry_run = FALSE)
|
||||
if(forced_injection)
|
||||
forced_injection = !dry_run
|
||||
return 100
|
||||
var/chance = 0
|
||||
// If the high pop override is in effect, we reduce the impact of population on the antag injection chance
|
||||
var/high_pop_factor = (current_players[CURRENT_LIVING_PLAYERS].len >= GLOB.dynamic_high_pop_limit)
|
||||
var/max_pop_per_antag = max(5,15 - round(threat_level/10) - round(current_players[CURRENT_LIVING_PLAYERS].len/(high_pop_factor ? 10 : 5)))
|
||||
if (!current_players[CURRENT_LIVING_ANTAGS].len)
|
||||
chance += 80 // No antags at all? let's boost those odds!
|
||||
else
|
||||
var/current_pop_per_antag = current_players[CURRENT_LIVING_PLAYERS].len / current_players[CURRENT_LIVING_ANTAGS].len
|
||||
if (current_pop_per_antag > max_pop_per_antag)
|
||||
chance += min(50, 25+10*(current_pop_per_antag-max_pop_per_antag))
|
||||
else
|
||||
chance += 25-10*(max_pop_per_antag-current_pop_per_antag)
|
||||
if (current_players[CURRENT_DEAD_PLAYERS].len > current_players[CURRENT_LIVING_PLAYERS].len)
|
||||
chance -= 30 // More than half the crew died? ew, let's calm down on antags
|
||||
if (threat > 70)
|
||||
chance += 15
|
||||
if (threat < 30)
|
||||
chance -= 15
|
||||
return round(max(0,chance))
|
||||
|
||||
/// Removes type from the list
|
||||
/datum/game_mode/dynamic/proc/remove_from_list(list/type_list, type)
|
||||
for(var/I in type_list)
|
||||
@@ -783,7 +739,8 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
|
||||
return
|
||||
if(EMERGENCY_ESCAPED_OR_ENDGAMED) // No more rules after the shuttle has left
|
||||
return
|
||||
|
||||
if((world.realtime - SSshuttle.realtimeofstart) > SSshuttle.auto_call) // no rules after shuttle is auto-called
|
||||
return
|
||||
update_playercounts()
|
||||
|
||||
if (forced_latejoin_rule)
|
||||
@@ -794,30 +751,17 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
|
||||
picking_midround_latejoin_rule(list(forced_latejoin_rule), forced = TRUE)
|
||||
forced_latejoin_rule = null
|
||||
|
||||
else if (latejoin_injection_cooldown < world.time && prob(get_injection_chance()))
|
||||
var/list/drafted_rules = list()
|
||||
for (var/datum/dynamic_ruleset/latejoin/rule in latejoin_rules)
|
||||
if (rule.acceptable(current_players[CURRENT_LIVING_PLAYERS].len, threat_level) && threat >= rule.cost)
|
||||
// Classic secret : only autotraitor/minor roles
|
||||
if (GLOB.dynamic_classic_secret && !((rule.flags & TRAITOR_RULESET) || (rule.flags & MINOR_RULESET)))
|
||||
continue
|
||||
// No stacking : only one round-ender, unless threat level > stacking_limit.
|
||||
if (threat_level > GLOB.dynamic_stacking_limit && GLOB.dynamic_no_stacking)
|
||||
if(rule.flags & HIGHLANDER_RULESET && highlander_executed)
|
||||
continue
|
||||
|
||||
rule.candidates = list(newPlayer)
|
||||
rule.trim_candidates()
|
||||
if (rule.ready())
|
||||
drafted_rules[rule] = rule.get_weight()
|
||||
|
||||
else if (latejoin_injection_cooldown < world.time && prob(storyteller.get_injection_chance()))
|
||||
SSblackbox.record_feedback("tally","dynamic",1,"Attempted latejoin injections")
|
||||
var/list/drafted_rules = storyteller.latejoin_draft(newPlayer)
|
||||
if (drafted_rules.len > 0 && picking_midround_latejoin_rule(drafted_rules))
|
||||
var/latejoin_injection_cooldown_middle = 0.5*(GLOB.dynamic_latejoin_delay_max + GLOB.dynamic_latejoin_delay_min)
|
||||
latejoin_injection_cooldown = round(CLAMP(EXP_DISTRIBUTION(latejoin_injection_cooldown_middle), GLOB.dynamic_latejoin_delay_min, GLOB.dynamic_latejoin_delay_max)) + world.time
|
||||
SSblackbox.record_feedback("tally","dynamic",1,"Successful latejoin injections")
|
||||
latejoin_injection_cooldown = storyteller.get_latejoin_cooldown() + world.time
|
||||
|
||||
/// Refund threat, but no more than threat_level.
|
||||
/datum/game_mode/dynamic/proc/refund_threat(regain)
|
||||
threat = min(threat_level,threat+regain)
|
||||
SSblackbox.record_feedback("tally","dynamic_threat",regain,"Refunded threat")
|
||||
log_threat("[regain] refunded. Threat is now [threat].", verbose = TRUE)
|
||||
|
||||
/// Generate threat and increase the threat_level if it goes beyond, capped at 100
|
||||
@@ -825,11 +769,13 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
|
||||
threat = min(100, threat+gain)
|
||||
if(threat > threat_level)
|
||||
threat_level = threat
|
||||
SSblackbox.record_feedback("tally","dynamic_threat",gain,"Created threat")
|
||||
log_threat("[gain] created. Threat is now [threat] and threat level is now [threat_level].", verbose = TRUE)
|
||||
|
||||
/// Expend threat, can't fall under 0.
|
||||
/datum/game_mode/dynamic/proc/spend_threat(cost)
|
||||
threat = max(threat-cost,0)
|
||||
SSblackbox.record_feedback("tally","dynamic_threat",cost,"Threat spent")
|
||||
log_threat("[cost] spent. Threat is now [threat].", verbose = TRUE)
|
||||
|
||||
/// Turns the value generated by lorentz distribution to threat value between 0 and 100.
|
||||
|
||||
@@ -80,6 +80,13 @@
|
||||
/// Delay for when execute will get called from the time of post_setup (roundstart) or process (midround/latejoin).
|
||||
/// Make sure your ruleset works with execute being called during the game when using this, and that the clean_up proc reverts it properly in case of faliure.
|
||||
var/delay = 0
|
||||
/// List of tags for use in storytellers.
|
||||
var/list/property_weights = list()
|
||||
/// Whether or not recent-round weight values are taken into account for this ruleset.
|
||||
/// Weight reduction uses the same values as secret's recent-round mode weight reduction.
|
||||
var/always_max_weight = FALSE
|
||||
/// Weight reduction by recent-rounds. Saved on new.
|
||||
var/weight_mult = 1
|
||||
|
||||
/datum/dynamic_ruleset/New()
|
||||
..()
|
||||
@@ -91,8 +98,13 @@
|
||||
var/costs = CONFIG_GET(keyed_list/dynamic_cost)
|
||||
var/requirementses = CONFIG_GET(keyed_list/dynamic_requirements) // can't damn well use requirements
|
||||
var/high_population_requirements = CONFIG_GET(keyed_list/dynamic_high_population_requirement)
|
||||
var/list/repeated_mode_adjust = CONFIG_GET(number_list/repeated_mode_adjust)
|
||||
if(config_tag in weights)
|
||||
weight = weights[config_tag]
|
||||
if(!always_max_weight && SSpersistence.saved_dynamic_rules.len == 3 && repeated_mode_adjust.len == 3)
|
||||
var/saved_dynamic_rules = SSpersistence.saved_dynamic_rules
|
||||
for(var/i in 1 to 3)
|
||||
if(config_tag in saved_dynamic_rules[i])
|
||||
weight_mult -= (repeated_mode_adjust[i]/100)
|
||||
if(config_tag in costs)
|
||||
cost = costs[config_tag]
|
||||
if(config_tag in requirementses)
|
||||
@@ -115,12 +127,15 @@
|
||||
/// If your rule has extra checks, such as counting security officers, do that in ready() instead
|
||||
/datum/dynamic_ruleset/proc/acceptable(population = 0, threat_level = 0)
|
||||
if(minimum_players > population)
|
||||
SSblackbox.record_feedback("tally","dynamic",1,"Times rulesets rejected due to low pop")
|
||||
return FALSE
|
||||
if(maximum_players > 0 && population > maximum_players)
|
||||
SSblackbox.record_feedback("tally","dynamic",1,"Times rulesets rejected due to high pop")
|
||||
return FALSE
|
||||
if (population >= GLOB.dynamic_high_pop_limit)
|
||||
indice_pop = 10
|
||||
if(threat_level < high_population_requirement)
|
||||
SSblackbox.record_feedback("tally","dynamic",1,"Times rulesets rejected due to not enough threat level")
|
||||
log_game("DYNAMIC: [name] did not reach threat level threshold: [threat_level]/[high_population_requirement]")
|
||||
return FALSE
|
||||
else
|
||||
@@ -132,6 +147,7 @@
|
||||
log_game("DYNAMIC: requirements and antag_cap lists have different lengths in ruleset [name]. Likely config issue, report this.")
|
||||
indice_pop = min(requirements.len,round(population/pop_per_requirement)+1)
|
||||
if(threat_level < requirements[indice_pop])
|
||||
SSblackbox.record_feedback("tally","dynamic",1,"Times rulesets rejected due to not enough threat level")
|
||||
log_game("DYNAMIC: [name] did not reach threat level threshold: [threat_level]/[requirements[indice_pop]]")
|
||||
return FALSE
|
||||
else
|
||||
@@ -178,6 +194,7 @@
|
||||
/// IMPORTANT: If ready() returns TRUE, that means pre_execute() or execute() should never fail!
|
||||
/datum/dynamic_ruleset/proc/ready(forced = 0)
|
||||
if (required_candidates > candidates.len)
|
||||
SSblackbox.record_feedback("tally","dynamic",1,"Times rulesets rejected due to not enough candidates")
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
@@ -212,6 +229,24 @@
|
||||
/datum/dynamic_ruleset/proc/check_finished()
|
||||
return FALSE
|
||||
|
||||
/// Returns a list to be displayed on statbus.
|
||||
/datum/dynamic_ruleset/proc/get_blackbox_info()
|
||||
var/list/ruleset_data = list()
|
||||
ruleset_data["name"] = name
|
||||
ruleset_data["rule_type"] = ruletype
|
||||
ruleset_data["cost"] = total_cost
|
||||
ruleset_data["weight"] = weight
|
||||
ruleset_data["scaled_times"] = scaled_times
|
||||
ruleset_data["antagonist_type"] = antag_datum
|
||||
ruleset_data["population_tier"] = indice_pop
|
||||
ruleset_data["assigned"] = list()
|
||||
for (var/datum/mind/M in assigned)
|
||||
var/assigned_data = list()
|
||||
assigned_data["key"] = M.key
|
||||
assigned_data["name"] = M.name
|
||||
ruleset_data["assigned"] += list(assigned_data)
|
||||
return ruleset_data
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// //
|
||||
// ROUNDSTART RULESETS //
|
||||
|
||||
@@ -3,6 +3,17 @@
|
||||
var/typepath // typepath of the event
|
||||
var/triggering
|
||||
|
||||
/datum/dynamic_ruleset/event/get_blackbox_info()
|
||||
var/list/ruleset_data = list()
|
||||
ruleset_data["name"] = name
|
||||
ruleset_data["rule_type"] = ruletype
|
||||
ruleset_data["cost"] = total_cost
|
||||
ruleset_data["weight"] = weight
|
||||
ruleset_data["scaled_times"] = scaled_times
|
||||
ruleset_data["event_type"] = typepath
|
||||
ruleset_data["population_tier"] = indice_pop
|
||||
return ruleset_data
|
||||
|
||||
/datum/dynamic_ruleset/event/execute()
|
||||
var/datum/round_event/E = new typepath()
|
||||
E.current_players = get_active_player_count(alive_check = 1, afk_check = 1, human_check = 1)
|
||||
@@ -26,6 +37,7 @@
|
||||
|
||||
var/threat = round(mode.threat_level/10)
|
||||
if (job_check < required_enemies[threat])
|
||||
SSblackbox.record_feedback("tally","dynamic",1,"Times rulesets rejected due to not enough enemy roles")
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
@@ -46,6 +58,7 @@
|
||||
cost = 10
|
||||
blocking_rules = list(/datum/dynamic_ruleset/roundstart/nuclear,/datum/dynamic_ruleset/midround/from_ghosts/nuclear)
|
||||
requirements = list(70,60,50,50,40,40,40,30,20,15)
|
||||
property_weights = list("story_potential" = 1, "trust" = 1, "chaos" = 1)
|
||||
high_population_requirement = 15
|
||||
|
||||
/datum/dynamic_ruleset/event/pirates/ready(forced = FALSE)
|
||||
@@ -69,6 +82,7 @@
|
||||
cost = 10
|
||||
requirements = list(70,60,50,50,40,40,40,30,20,15)
|
||||
high_population_requirement = 15
|
||||
property_weights = list("chaos" = 1, "valid" = 1)
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// //
|
||||
@@ -88,6 +102,7 @@
|
||||
requirements = list(5,5,5,5,5,5,5,5,5,5) // yes, can happen on fake-extended
|
||||
high_population_requirement = 5
|
||||
repeatable = TRUE
|
||||
property_weights = list("chaos" = 1, "extended" = 2)
|
||||
|
||||
/datum/dynamic_ruleset/event/ventclog/ready()
|
||||
if(mode.threat_level > 30 && mode.threat >= 5 && prob(20))
|
||||
@@ -121,10 +136,12 @@
|
||||
required_enemies = list(1,1,0,0,0,0,0,0,0,0)
|
||||
weight = 4
|
||||
// no repeatable weight decrease. too variable to be unfun multiple times in one round
|
||||
cost = 3
|
||||
cost = 1
|
||||
requirements = list(5,5,5,5,5,5,5,5,5,5)
|
||||
high_population_requirement = 5
|
||||
repeatable = TRUE
|
||||
property_weights = list("story_potential" = 1, "extended" = 1)
|
||||
always_max_weight = TRUE
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// //
|
||||
@@ -143,15 +160,19 @@
|
||||
repeatable_weight_decrease = 2
|
||||
requirements = list(60,50,40,30,30,30,30,30,30,30)
|
||||
high_population_requirement = 30
|
||||
property_weights = list("extended" = -2)
|
||||
|
||||
/datum/dynamic_ruleset/event/meteor_wave/ready()
|
||||
if(mode.threat_level > 40 && mode.threat >= 25 && prob(20))
|
||||
name = "Meteor Wave: Threatening"
|
||||
cost = 25
|
||||
typepath = /datum/round_event/meteor_wave/threatening
|
||||
else if(mode.threat_level > 50 && mode.threat >= 40 && prob(30))
|
||||
name = "Meteor Wave: Catastrophic"
|
||||
cost = 40
|
||||
typepath = /datum/round_event/meteor_wave/catastrophic
|
||||
else
|
||||
name = "Meteor Wave: Normal"
|
||||
cost = 15
|
||||
typepath = /datum/round_event/meteor_wave
|
||||
return ..()
|
||||
@@ -174,6 +195,7 @@
|
||||
requirements = list(5,5,5,5,5,5,5,5,5,5)
|
||||
high_population_requirement = 5
|
||||
repeatable = TRUE
|
||||
property_weights = list("extended" = 1)
|
||||
|
||||
/datum/dynamic_ruleset/event/anomaly_flux
|
||||
name = "Anomaly: Hyper-Energetic Flux"
|
||||
@@ -187,6 +209,7 @@
|
||||
requirements = list(5,5,5,5,5,5,5,5,5,5)
|
||||
high_population_requirement = 10
|
||||
repeatable = TRUE
|
||||
property_weights = list("extended" = 1)
|
||||
|
||||
/datum/dynamic_ruleset/event/anomaly_gravitational
|
||||
name = "Anomaly: Gravitational"
|
||||
@@ -198,6 +221,7 @@
|
||||
requirements = list(5,5,5,5,5,5,5,5,5,5)
|
||||
high_population_requirement = 5
|
||||
repeatable = TRUE
|
||||
property_weights = list("extended" = 1)
|
||||
|
||||
/datum/dynamic_ruleset/event/anomaly_pyroclastic
|
||||
name = "Anomaly: Pyroclastic"
|
||||
@@ -211,6 +235,7 @@
|
||||
requirements = list(10,10,10,10,10,10,10,10,10,10)
|
||||
high_population_requirement = 10
|
||||
repeatable = TRUE
|
||||
property_weights = list("extended" = 1)
|
||||
|
||||
/datum/dynamic_ruleset/event/anomaly_vortex
|
||||
name = "Anomaly: Vortex"
|
||||
@@ -224,6 +249,7 @@
|
||||
requirements = list(10,10,10,10,10,10,10,10,10,10)
|
||||
high_population_requirement = 10
|
||||
repeatable = TRUE
|
||||
property_weights = list("extended" = 1)
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// //
|
||||
@@ -243,6 +269,7 @@
|
||||
requirements = list(10,10,10,10,10,10,10,10,10,10)
|
||||
high_population_requirement = 10
|
||||
repeatable = TRUE
|
||||
property_weights = list("extended" = -1, "chaos" = 1)
|
||||
|
||||
/datum/dynamic_ruleset/event/carp_migration
|
||||
name = "Carp Migration"
|
||||
@@ -254,6 +281,7 @@
|
||||
requirements = list(10,10,10,10,10,10,10,10,10,10)
|
||||
high_population_requirement = 10
|
||||
repeatable = TRUE
|
||||
property_weights = list("extended" = 1)
|
||||
|
||||
/datum/dynamic_ruleset/event/communications_blackout
|
||||
name = "Communications Blackout"
|
||||
@@ -267,6 +295,7 @@
|
||||
requirements = list(5,5,5,5,5,5,5,5,5,5)
|
||||
high_population_requirement = 5
|
||||
repeatable = TRUE
|
||||
property_weights = list("extended" = 1, "chaos" = 1)
|
||||
|
||||
/datum/dynamic_ruleset/event/processor_overload
|
||||
name = "Processor Overload"
|
||||
@@ -280,6 +309,8 @@
|
||||
requirements = list(5,5,5,5,5,5,5,5,5,5)
|
||||
high_population_requirement = 5
|
||||
repeatable = TRUE
|
||||
property_weights = list("extended" = 1, "chaos" = 1)
|
||||
always_max_weight = TRUE
|
||||
|
||||
/datum/dynamic_ruleset/event/space_dust
|
||||
name = "Minor Space Dust"
|
||||
@@ -293,6 +324,8 @@
|
||||
requirements = list(5,5,5,5,5,5,5,5,5,5)
|
||||
high_population_requirement = 5
|
||||
repeatable = TRUE
|
||||
property_weights = list("extended" = 1)
|
||||
always_max_weight = TRUE
|
||||
|
||||
/datum/dynamic_ruleset/event/major_dust
|
||||
name = "Major Space Dust"
|
||||
@@ -306,6 +339,7 @@
|
||||
requirements = list(10,10,10,10,10,10,10,10,10,10)
|
||||
high_population_requirement = 10
|
||||
repeatable = TRUE
|
||||
property_weights = list("extended" = 1)
|
||||
|
||||
/datum/dynamic_ruleset/event/electrical_storm
|
||||
name = "Electrical Storm"
|
||||
@@ -319,6 +353,7 @@
|
||||
requirements = list(5,5,5,5,5,5,5,5,5,5)
|
||||
high_population_requirement = 5
|
||||
repeatable = TRUE
|
||||
property_weights = list("extended" = 1)
|
||||
|
||||
/datum/dynamic_ruleset/event/heart_attack
|
||||
name = "Random Heart Attack"
|
||||
@@ -332,6 +367,8 @@
|
||||
requirements = list(101,101,101,5,5,5,5,5,5,5)
|
||||
high_population_requirement = 5
|
||||
repeatable = TRUE
|
||||
property_weights = list("extended" = 1)
|
||||
always_max_weight = TRUE
|
||||
|
||||
/datum/dynamic_ruleset/event/radiation_storm
|
||||
name = "Radiation Storm"
|
||||
@@ -343,3 +380,4 @@
|
||||
required_enemies = list(1,1,1,1,1,1,1,1,1,1)
|
||||
requirements = list(5,5,5,5,5,5,5,5,5,5)
|
||||
high_population_requirement = 5
|
||||
property_weights = list("extended" = 1,"chaos" = 1)
|
||||
|
||||
@@ -36,9 +36,9 @@
|
||||
continue // Dead players cannot count as opponents
|
||||
if (M.mind && M.mind.assigned_role && (M.mind.assigned_role in enemy_roles) && (!(M in candidates) || (M.mind.assigned_role in restricted_roles)))
|
||||
job_check++ // Checking for "enemies" (such as sec officers). To be counters, they must either not be candidates to that rule, or have a job that restricts them from it
|
||||
|
||||
var/threat = round(mode.threat_level/10)
|
||||
if (job_check < required_enemies[threat])
|
||||
SSblackbox.record_feedback("tally","dynamic",1,"Times rulesets rejected due to not enough enemy roles")
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
@@ -69,6 +69,14 @@
|
||||
high_population_requirement = 15
|
||||
repeatable = TRUE
|
||||
flags = TRAITOR_RULESET
|
||||
property_weights = list("story_potential" = 2, "trust" = -1, "extended" = 1)
|
||||
always_max_weight = TRUE
|
||||
|
||||
/datum/dynamic_ruleset/latejoin/infiltrator/execute()
|
||||
. = ..()
|
||||
for(var/datum/mind/M in assigned)
|
||||
log_admin("[M.name] was made into a traitor by dynamic.")
|
||||
message_admins("[M.name] was made into a traitor by dynamic.")
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// //
|
||||
@@ -93,6 +101,7 @@
|
||||
requirements = list(101,101,70,40,40,40,40,40,40,40)
|
||||
high_population_requirement = 40
|
||||
flags = HIGHLANDER_RULESET
|
||||
property_weights = list("trust" = -2, "chaos" = 2, "extended" = -2, "valid" = 2, "conversion" = 1)
|
||||
var/required_heads_of_staff = 3
|
||||
var/finished = FALSE
|
||||
var/datum/team/revolution/revolution
|
||||
@@ -122,6 +131,8 @@
|
||||
revolution.update_objectives()
|
||||
revolution.update_heads()
|
||||
SSshuttle.registerHostileEnvironment(src)
|
||||
log_admin("[M.name] was made into a revolutionary by dynamic.")
|
||||
message_admins("[M.name] was made into a revolutionary by dynamic.")
|
||||
return TRUE
|
||||
else
|
||||
log_game("DYNAMIC: [ruletype] [name] discarded [M.name] from head revolutionary due to ineligibility.")
|
||||
@@ -186,30 +197,31 @@
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// //
|
||||
// VAMPIRE //
|
||||
// BLOODSUCKERS //
|
||||
// //
|
||||
//////////////////////////////////////////////
|
||||
|
||||
/*
|
||||
/datum/dynamic_ruleset/latejoin/vampire
|
||||
name = "vampire"
|
||||
config_tag = "vampire_latejoin"
|
||||
antag_flag = ROLE_VAMPIRE
|
||||
antag_datum = ANTAG_DATUM_VAMPIRE
|
||||
protected_roles = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain")
|
||||
/datum/dynamic_ruleset/latejoin/bloodsucker
|
||||
name = "Bloodsucker Infiltrator"
|
||||
config_tag = "latejoin_bloodsucker"
|
||||
antag_datum = ANTAG_DATUM_BLOODSUCKER
|
||||
antag_flag = ROLE_TRAITOR
|
||||
restricted_roles = list("AI", "Cyborg")
|
||||
protected_roles = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster")
|
||||
required_candidates = 1
|
||||
weight = 5
|
||||
cost = 15
|
||||
requirements = list(80,70,60,50,40,20,20,15,15,15)
|
||||
weight = 3
|
||||
cost = 10
|
||||
property_weights = list("story_potential" = 2, "extended" = 2, "trust" = -2, "valid" = 1)
|
||||
requirements = list(70,65,60,55,50,45,40,35,30,30)
|
||||
high_population_requirement = 30
|
||||
repeatable = TRUE
|
||||
high_population_requirement = 15
|
||||
|
||||
/datum/dynamic_ruleset/latejoin/vampire/pre_execute()
|
||||
/datum/dynamic_ruleset/latejoin/bloodsucker/execute()
|
||||
var/mob/M = pick(candidates)
|
||||
candidates -= M
|
||||
assigned += M.mind
|
||||
M.mind.restricted_roles = restricted_roles
|
||||
M.mind.special_role = ROLE_VAMPIRE
|
||||
M.mind.special_role = antag_flag
|
||||
if(mode.make_bloodsucker(M.mind))
|
||||
mode.bloodsuckers += M
|
||||
log_admin("[M.name] was made into a bloodsucker by dynamic.")
|
||||
message_admins("[M.name] was made into a bloodsucker by dynamic.")
|
||||
return TRUE
|
||||
*/
|
||||
|
||||
@@ -87,6 +87,7 @@
|
||||
|
||||
var/threat = round(mode.threat_level/10)
|
||||
if (job_check < required_enemies[threat])
|
||||
SSblackbox.record_feedback("tally","dynamic",1,"Times rulesets rejected due to not enough enemy roles")
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
@@ -107,8 +108,12 @@
|
||||
|
||||
candidates = pollGhostCandidates("The mode is looking for volunteers to become a [name]", antag_flag, SSticker.mode, antag_flag, poll_time = 300)
|
||||
|
||||
if(!candidates || candidates.len <= required_candidates)
|
||||
if(!candidates || candidates.len < required_candidates)
|
||||
message_admins("The ruleset [name] did not receive enough applications.")
|
||||
if(candidates)
|
||||
message_admins("Only received [candidates.len], needed [required_candidates].")
|
||||
else
|
||||
message_admins("There were no candidates.")
|
||||
log_game("DYNAMIC: The ruleset [name] did not receive enough applications.")
|
||||
return FALSE
|
||||
|
||||
@@ -179,6 +184,8 @@
|
||||
repeatable = TRUE
|
||||
high_population_requirement = 15
|
||||
flags = TRAITOR_RULESET
|
||||
property_weights = list("story_potential" = 2, "trust" = -1, "extended" = 1)
|
||||
always_max_weight = TRUE
|
||||
|
||||
/datum/dynamic_ruleset/midround/autotraitor/acceptable(population = 0, threat = 0)
|
||||
var/player_count = mode.current_players[CURRENT_LIVING_PLAYERS].len
|
||||
@@ -212,6 +219,8 @@
|
||||
living_players -= M
|
||||
var/datum/antagonist/traitor/newTraitor = new
|
||||
M.mind.add_antag_datum(newTraitor)
|
||||
log_admin("[M] was made into a traitor by dynamic.")
|
||||
message_admins("[M] was made into a traitor by dynamic.")
|
||||
return TRUE
|
||||
|
||||
|
||||
@@ -235,6 +244,7 @@
|
||||
requirements = list(101,101,70,50,50,50,40,30,30,30)
|
||||
high_population_requirement = 30
|
||||
required_type = /mob/living/silicon/ai
|
||||
property_weights = list("story_potential" = 2, "trust" = 1, "chaos" = 2)
|
||||
var/ion_announce = 33
|
||||
var/removeDontImproveChance = 10
|
||||
|
||||
@@ -259,6 +269,8 @@
|
||||
var/datum/antagonist/traitor/AI = new
|
||||
M.mind.special_role = antag_flag
|
||||
M.mind.add_antag_datum(AI)
|
||||
log_admin("[M] was made into a malf AI by dynamic.")
|
||||
message_admins("[M] was made into a malf AI by dynamic.")
|
||||
if(prob(ion_announce))
|
||||
priority_announce("Ion storm detected near the station. Please check all AI-controlled equipment for errors.", "Anomaly Alert", "ionstorm")
|
||||
if(prob(removeDontImproveChance))
|
||||
@@ -287,10 +299,12 @@
|
||||
requirements = list(90,90,70,50,50,50,50,40,30,30)
|
||||
high_population_requirement = 30
|
||||
repeatable = TRUE
|
||||
property_weights = list("story_potential" = 2, "trust" = 1, "chaos" = 2, "extended" = -2)
|
||||
var/datum/mind/wizard
|
||||
|
||||
/datum/dynamic_ruleset/midround/from_ghosts/wizard/ready(forced = FALSE)
|
||||
if (required_candidates > (dead_players.len + list_observers.len))
|
||||
SSblackbox.record_feedback("tally","dynamic",1,"Times rulesets rejected due to not enough ghosts")
|
||||
return FALSE
|
||||
if(GLOB.wizardstart.len == 0)
|
||||
log_admin("Cannot accept Wizard ruleset. Couldn't find any wizard spawn points.")
|
||||
@@ -334,6 +348,7 @@
|
||||
cost = 35
|
||||
requirements = list(90,90,90,80,70,60,50,40,40,40)
|
||||
high_population_requirement = 40
|
||||
property_weights = list("story_potential" = 2, "trust" = 2, "chaos" = 2, "extended" = -2, "valid" = 2)
|
||||
var/operative_cap = list(2,2,3,3,4,5,5,5,5,5)
|
||||
var/datum/team/nuclear/nuke_team
|
||||
flags = HIGHLANDER_RULESET
|
||||
@@ -353,6 +368,7 @@
|
||||
|
||||
/datum/dynamic_ruleset/midround/from_ghosts/nuclear/ready(forced = FALSE)
|
||||
if (required_candidates > (dead_players.len + list_observers.len))
|
||||
SSblackbox.record_feedback("tally","dynamic",1,"Times rulesets rejected due to not enough ghosts")
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
@@ -386,9 +402,11 @@
|
||||
requirements = list(101,101,101,80,60,50,50,50,50,50)
|
||||
high_population_requirement = 50
|
||||
repeatable = TRUE
|
||||
property_weights = list("story_potential" = -1, "trust" = 2, "chaos" = 2, "extended" = -2, "valid" = 2)
|
||||
|
||||
/datum/dynamic_ruleset/midround/from_ghosts/blob/ready(forced = FALSE)
|
||||
if (required_candidates > (dead_players.len + list_observers.len))
|
||||
SSblackbox.record_feedback("tally","dynamic",1,"Times rulesets rejected due to not enough ghosts")
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
@@ -416,10 +434,12 @@
|
||||
high_population_requirement = 50
|
||||
repeatable_weight_decrease = 2
|
||||
repeatable = TRUE
|
||||
property_weights = list("story_potential" = -1, "trust" = 1, "chaos" = 2, "extended" = -2, "valid" = 2)
|
||||
var/list/vents = list()
|
||||
|
||||
/datum/dynamic_ruleset/midround/from_ghosts/xenomorph/ready(forced = FALSE)
|
||||
if (required_candidates > (dead_players.len + list_observers.len))
|
||||
SSblackbox.record_feedback("tally","dynamic",1,"Times rulesets rejected due to not enough ghosts")
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
@@ -470,6 +490,7 @@
|
||||
high_population_requirement = 50
|
||||
repeatable_weight_decrease = 2
|
||||
repeatable = TRUE
|
||||
property_weights = list("story_potential" = 1, "trust" = 1, "extended" = 1, "valid" = 2, "integrity" = 2)
|
||||
var/list/spawn_locs = list()
|
||||
|
||||
/datum/dynamic_ruleset/midround/from_ghosts/nightmare/execute()
|
||||
@@ -515,10 +536,12 @@
|
||||
weight = 4
|
||||
cost = 5
|
||||
requirements = list(30,30,20,20,15,10,10,10,10,5) // yes, it can even happen in "extended"!
|
||||
property_weights = list("story_potential" = 1, "extended" = 1, "valid" = -2)
|
||||
high_population_requirement = 5
|
||||
|
||||
/datum/dynamic_ruleset/midround/from_ghosts/sentient_disease/ready(forced = FALSE)
|
||||
if (required_candidates > (dead_players.len + list_observers.len))
|
||||
SSblackbox.record_feedback("tally","dynamic",1,"Times rulesets rejected due to not enough ghosts")
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
@@ -548,15 +571,20 @@
|
||||
cost = 5
|
||||
requirements = list(30,30,30,30,20,15,15,15,15,15)
|
||||
high_population_requirement = 15
|
||||
property_weights = list("story_potential" = -2, "extended" = -1)
|
||||
var/list/spawn_locs = list()
|
||||
|
||||
/datum/dynamic_ruleset/midround/from_ghosts/revenant/ready(forced = FALSE)
|
||||
/datum/dynamic_ruleset/midround/from_ghosts/revenant/acceptable(population = 0,threat = 0)
|
||||
var/deadMobs = 0
|
||||
for(var/mob/M in GLOB.dead_mob_list)
|
||||
deadMobs++
|
||||
if(deadMobs < REVENANT_SPAWN_THRESHOLD)
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/datum/dynamic_ruleset/midround/from_ghosts/revenant/ready(forced = FALSE)
|
||||
if(required_candidates > (dead_players.len + list_observers.len))
|
||||
SSblackbox.record_feedback("tally","dynamic",1,"Times rulesets rejected due to not enough ghosts")
|
||||
return FALSE
|
||||
for(var/mob/living/L in GLOB.dead_mob_list) //look for any dead bodies
|
||||
var/turf/T = get_turf(L)
|
||||
@@ -599,11 +627,13 @@
|
||||
weight = 4
|
||||
cost = 15
|
||||
requirements = list(101,101,101,90,80,70,60,50,40,30)
|
||||
property_weights = list("story_potential" = -2, "extended" = -2, "integrity" = 2, "valid" = 2, "trust" = 2)
|
||||
high_population_requirement = 30
|
||||
var/list/spawn_locs = list()
|
||||
|
||||
/datum/dynamic_ruleset/midround/from_ghosts/slaughter_demon/ready(forced = FALSE)
|
||||
if(required_candidates > (dead_players.len + list_observers.len))
|
||||
SSblackbox.record_feedback("tally","dynamic",1,"Times rulesets rejected due to not enough ghosts")
|
||||
return FALSE
|
||||
for(var/obj/effect/landmark/carpspawn/L in GLOB.landmarks_list)
|
||||
if(isturf(L.loc))
|
||||
@@ -650,11 +680,13 @@
|
||||
blocking_rules = list(/datum/dynamic_ruleset/roundstart/nuclear,/datum/dynamic_ruleset/midround/from_ghosts/nuclear)
|
||||
high_population_requirement = 15
|
||||
var/datum/team/abductor_team/team
|
||||
property_weights = list("story_potential" = 1, "extended" = -2, "valid" = 1, "trust" = -1, "chaos" = 2)
|
||||
repeatable_weight_decrease = 4
|
||||
repeatable = TRUE
|
||||
|
||||
/datum/dynamic_ruleset/midround/from_ghosts/abductors/ready(forced = FALSE)
|
||||
if(required_candidates > (dead_players.len + list_observers.len))
|
||||
SSblackbox.record_feedback("tally","dynamic",1,"Times rulesets rejected due to not enough ghosts")
|
||||
return FALSE
|
||||
team = new /datum/team/abductor_team
|
||||
if(team.team_number > ABDUCTOR_MAX_TEAMS)
|
||||
@@ -689,11 +721,13 @@
|
||||
cost = 15
|
||||
requirements = list(101,101,101,90,80,70,60,50,40,30)
|
||||
high_population_requirement = 30
|
||||
property_weights = list("story_potential" = 1, "extended" = -2, "valid" = 2)
|
||||
var/list/spawn_locs = list()
|
||||
var/spawn_loc
|
||||
|
||||
/datum/dynamic_ruleset/midround/from_ghosts/ninja/ready(forced = FALSE)
|
||||
if(required_candidates > (dead_players.len + list_observers.len))
|
||||
SSblackbox.record_feedback("tally","dynamic",1,"Times rulesets rejected due to not enough ghosts")
|
||||
return FALSE
|
||||
if(!spawn_loc)
|
||||
var/list/spawn_locs = list()
|
||||
@@ -734,31 +768,3 @@
|
||||
|
||||
#undef ABDUCTOR_MAX_TEAMS
|
||||
#undef REVENANT_SPAWN_THRESHOLD
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// //
|
||||
// BLOODSUCKERS //
|
||||
// //
|
||||
//////////////////////////////////////////////
|
||||
|
||||
/datum/dynamic_ruleset/latejoin/bloodsucker
|
||||
name = "Bloodsucker Infiltrator"
|
||||
config_tag = "latejoin_bloodsucker"
|
||||
antag_datum = ANTAG_DATUM_BLOODSUCKER
|
||||
antag_flag = ROLE_TRAITOR
|
||||
restricted_roles = list("AI", "Cyborg")
|
||||
protected_roles = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster")
|
||||
required_candidates = 1
|
||||
weight = 3
|
||||
cost = 10
|
||||
requirements = list(90,80,70,60,55,50,45,40,35,30)
|
||||
high_population_requirement = 30
|
||||
repeatable = TRUE
|
||||
|
||||
/datum/dynamic_ruleset/latejoin/bloodsucker/execute()
|
||||
var/mob/M = pick(candidates)
|
||||
assigned += M.mind
|
||||
M.mind.special_role = antag_flag
|
||||
if(mode.make_bloodsucker(M.mind))
|
||||
mode.bloodsuckers += M
|
||||
return TRUE
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
requirements = list(50,50,50,50,50,50,50,50,50,50)
|
||||
high_population_requirement = 40
|
||||
antag_cap = list(1,1,1,1,2,2,2,2,3,3)
|
||||
property_weights = list("story_potential" = 2, "trust" = -1, "extended" = 1, "valid" = 1)
|
||||
always_max_weight = TRUE
|
||||
var/autotraitor_cooldown = 450 // 15 minutes (ticks once per 2 sec)
|
||||
|
||||
/datum/dynamic_ruleset/roundstart/traitor/pre_execute()
|
||||
@@ -60,6 +62,7 @@
|
||||
requirements = list(101,101,101,101,101,101,101,101,101,101)
|
||||
high_population_requirement = 101
|
||||
antag_cap = list(2,2,2,2,2,2,2,2,2,2) // Can pick 3 per team, but rare enough it doesn't matter.
|
||||
property_weights = list("story_potential" = 1, "trust" = -1, "extended" = 1, "valid" = 1)
|
||||
var/list/datum/team/brother_team/pre_brother_teams = list()
|
||||
var/const/min_team_size = 2
|
||||
|
||||
@@ -107,6 +110,7 @@
|
||||
cost = 15
|
||||
scaling_cost = 15
|
||||
requirements = list(101,101,101,101,101,101,101,101,101,101)
|
||||
property_weights = list("trust" = -2, "valid" = 2)
|
||||
high_population_requirement = 10
|
||||
antag_cap = list(1,1,1,1,1,2,2,2,2,3)
|
||||
var/team_mode_probability = 30
|
||||
@@ -159,6 +163,7 @@
|
||||
cost = 30
|
||||
requirements = list(101,101,101,60,50,50,50,50,50,50)
|
||||
high_population_requirement = 50
|
||||
property_weights = list("story_potential" = 2, "trust" = 1, "chaos" = 2, "extended" = -2, "valid" = 2)
|
||||
var/list/roundstart_wizards = list()
|
||||
|
||||
/datum/dynamic_ruleset/roundstart/wizard/acceptable(population=0, threat=0)
|
||||
@@ -221,6 +226,7 @@
|
||||
weight = 3
|
||||
cost = 30
|
||||
requirements = list(101,101,101,80,70,60,50,50,50,50)
|
||||
property_weights = list("story_potential" = -1, "trust" = -1, "chaos" = 1, "conversion" = 1, "extended" = -2, "valid" = 2)
|
||||
high_population_requirement = 50
|
||||
flags = HIGHLANDER_RULESET
|
||||
antag_cap = list(2,2,2,3,3,4,4,4,4,4)
|
||||
@@ -282,6 +288,7 @@
|
||||
high_population_requirement = 50
|
||||
flags = HIGHLANDER_RULESET
|
||||
antag_cap = list(1,1,2,3,4,5,5,5,5,5)
|
||||
property_weights = list("story_potential" = 2, "trust" = 2, "chaos" = 2, "extended" = -2, "valid" = 2)
|
||||
var/datum/team/nuclear/nuke_team
|
||||
|
||||
/datum/dynamic_ruleset/roundstart/nuclear/ready(forced = FALSE)
|
||||
@@ -372,6 +379,7 @@
|
||||
flags = HIGHLANDER_RULESET
|
||||
// I give up, just there should be enough heads with 35 players...
|
||||
minimum_players = 35
|
||||
property_weights = list("trust" = -2, "chaos" = 2, "extended" = -2, "valid" = 2, "conversion" = 1)
|
||||
var/datum/team/revolution/revolution
|
||||
var/finished = FALSE
|
||||
|
||||
@@ -489,6 +497,7 @@
|
||||
weight = 3
|
||||
cost = 0
|
||||
requirements = list(101,101,101,101,101,101,101,101,101,101)
|
||||
property_weights = list("extended" = 2)
|
||||
high_population_requirement = 101
|
||||
|
||||
/datum/dynamic_ruleset/roundstart/extended/pre_execute()
|
||||
@@ -516,6 +525,7 @@
|
||||
high_population_requirement = 50
|
||||
flags = HIGHLANDER_RULESET
|
||||
antag_cap = list(2,3,3,4,4,4,4,4,4,4)
|
||||
property_weights = list("trust" = 2, "chaos" = 2, "extended" = -2, "conversion" = 1, "valid" = 2)
|
||||
var/ark_time
|
||||
|
||||
/datum/dynamic_ruleset/roundstart/clockcult/pre_execute()
|
||||
@@ -615,6 +625,8 @@
|
||||
antag_leader_datum = /datum/antagonist/nukeop/leader/clownop
|
||||
requirements = list(101,101,101,101,101,101,101,101,101,101)
|
||||
high_population_requirement = 101
|
||||
property_weights = list("trust" = 2, "chaos" = 2, "extended" = -2, "story_potential" = 2, "valid" = 2)
|
||||
|
||||
|
||||
/datum/dynamic_ruleset/roundstart/nuclear/clown_ops/pre_execute()
|
||||
. = ..()
|
||||
@@ -646,6 +658,7 @@
|
||||
requirements = list(101,101,101,101,101,101,101,101,101,101)
|
||||
high_population_requirement = 101
|
||||
antag_cap = list(1,1,1,2,2,2,3,3,3,4)
|
||||
property_weights = list("extended" = 1)
|
||||
|
||||
/datum/dynamic_ruleset/roundstart/devil/pre_execute()
|
||||
var/num_devils = antag_cap[indice_pop]
|
||||
@@ -697,6 +710,7 @@
|
||||
cost = 0
|
||||
requirements = list(101,101,101,101,101,101,101,101,101,101)
|
||||
high_population_requirement = 101
|
||||
property_weights = list("extended" = -2, "chaos" = 2, "conversion" = 1, "valid" = 2)
|
||||
var/players_per_carrier = 30
|
||||
var/monkeys_to_win = 1
|
||||
var/escaped_monkeys = 0
|
||||
@@ -758,6 +772,7 @@
|
||||
cost = 0
|
||||
requirements = list(101,101,101,101,101,101,101,101,101,101)
|
||||
high_population_requirement = 101
|
||||
property_weights = list("extended" = -2, "chaos" = 2, "trust" = 2)
|
||||
var/meteordelay = 2000
|
||||
var/nometeors = 0
|
||||
var/rampupdelta = 5
|
||||
@@ -798,7 +813,8 @@
|
||||
weight = 2
|
||||
cost = 15
|
||||
scaling_cost = 10
|
||||
requirements = list(90,80,70,60,50,50,50,50,50,50)
|
||||
property_weights = list("story_potential" = 1, "extended" = 1, "trust" = -2, "valid" = 1)
|
||||
requirements = list(70,65,60,55,50,50,50,50,50,50)
|
||||
high_population_requirement = 50
|
||||
antag_cap = list(1,1,1,1,1,2,2,2,2,2)
|
||||
|
||||
|
||||
@@ -0,0 +1,235 @@
|
||||
/datum/dynamic_storyteller
|
||||
var/name = "none"
|
||||
var/desc = "A coder's idiocy."
|
||||
var/list/property_weights = list()
|
||||
var/curve_centre = 0
|
||||
var/curve_width = 1.8
|
||||
var/forced_threat_level = -1
|
||||
var/flags = 0
|
||||
var/weight = 3 // how many rounds need to have been recently played for this storyteller to be left out of the vote
|
||||
var/datum/game_mode/dynamic/mode = null
|
||||
|
||||
/**
|
||||
Property weights are:
|
||||
"story_potential" -- essentially how many different ways the antag can be played.
|
||||
"trust" -- How much it makes the crew trust each other. Negative values means they're suspicious. Team antags are like this.
|
||||
"chaos" -- How chaotic it makes the round. Has some overlap with "valid" and somewhat contradicts "extended".
|
||||
"valid" -- How likely the non-antag-enemy crew are to get involved, e.g. nukies encouraging the warden to
|
||||
let everyone into the armory, wizard moving around and being a nuisance, nightmare busting lights.
|
||||
"extended" -- How much the antag is conducive to a long round. Nukies and cults are bad for this; Wizard is less bad; and so on.
|
||||
"conversion" -- Basically a bool. Conversion antags, well, convert. It's its own class for a good reason.
|
||||
*/
|
||||
|
||||
/datum/dynamic_storyteller/New()
|
||||
..()
|
||||
if (istype(SSticker.mode, /datum/game_mode/dynamic))
|
||||
mode = SSticker.mode
|
||||
GLOB.dynamic_curve_centre = curve_centre
|
||||
GLOB.dynamic_curve_width = curve_width
|
||||
GLOB.dynamic_forced_threat_level = forced_threat_level
|
||||
|
||||
/datum/dynamic_storyteller/proc/start_injection_cooldowns()
|
||||
var/latejoin_injection_cooldown_middle = 0.5*(GLOB.dynamic_first_latejoin_delay_max + GLOB.dynamic_first_latejoin_delay_min)
|
||||
mode.latejoin_injection_cooldown = round(CLAMP(EXP_DISTRIBUTION(latejoin_injection_cooldown_middle), GLOB.dynamic_first_latejoin_delay_min, GLOB.dynamic_first_latejoin_delay_max)) + world.time
|
||||
|
||||
var/midround_injection_cooldown_middle = 0.5*(GLOB.dynamic_first_midround_delay_min + GLOB.dynamic_first_midround_delay_max)
|
||||
mode.midround_injection_cooldown = round(CLAMP(EXP_DISTRIBUTION(midround_injection_cooldown_middle), GLOB.dynamic_first_midround_delay_min, GLOB.dynamic_first_midround_delay_max)) + world.time
|
||||
|
||||
var/event_injection_cooldown_middle = 0.5*(GLOB.dynamic_event_delay_max + GLOB.dynamic_event_delay_min)
|
||||
mode.event_injection_cooldown = (round(CLAMP(EXP_DISTRIBUTION(event_injection_cooldown_middle), GLOB.dynamic_event_delay_min, GLOB.dynamic_event_delay_max)) + world.time)
|
||||
|
||||
/datum/dynamic_storyteller/proc/do_process()
|
||||
return
|
||||
|
||||
/datum/dynamic_storyteller/proc/on_start()
|
||||
return
|
||||
|
||||
/datum/dynamic_storyteller/proc/get_midround_cooldown()
|
||||
var/midround_injection_cooldown_middle = 0.5*(GLOB.dynamic_midround_delay_max + GLOB.dynamic_midround_delay_min)
|
||||
return round(CLAMP(EXP_DISTRIBUTION(midround_injection_cooldown_middle), GLOB.dynamic_midround_delay_min, GLOB.dynamic_midround_delay_max))
|
||||
|
||||
/datum/dynamic_storyteller/proc/get_event_cooldown()
|
||||
var/event_injection_cooldown_middle = 0.5*(GLOB.dynamic_event_delay_max + GLOB.dynamic_event_delay_min)
|
||||
return round(CLAMP(EXP_DISTRIBUTION(event_injection_cooldown_middle), GLOB.dynamic_event_delay_min, GLOB.dynamic_event_delay_max))
|
||||
|
||||
/datum/dynamic_storyteller/proc/get_latejoin_cooldown()
|
||||
var/latejoin_injection_cooldown_middle = 0.5*(GLOB.dynamic_latejoin_delay_max + GLOB.dynamic_latejoin_delay_min)
|
||||
return round(CLAMP(EXP_DISTRIBUTION(latejoin_injection_cooldown_middle), GLOB.dynamic_latejoin_delay_min, GLOB.dynamic_latejoin_delay_max))
|
||||
|
||||
/datum/dynamic_storyteller/proc/get_injection_chance(dry_run = FALSE)
|
||||
if(mode.forced_injection)
|
||||
mode.forced_injection = !dry_run
|
||||
return 100
|
||||
var/chance = 0
|
||||
// If the high pop override is in effect, we reduce the impact of population on the antag injection chance
|
||||
var/high_pop_factor = (mode.current_players[CURRENT_LIVING_PLAYERS].len >= GLOB.dynamic_high_pop_limit)
|
||||
var/max_pop_per_antag = max(5,15 - round(mode.threat_level/10) - round(mode.current_players[CURRENT_LIVING_PLAYERS].len/(high_pop_factor ? 10 : 5)))
|
||||
if (!mode.current_players[CURRENT_LIVING_ANTAGS].len)
|
||||
chance += 80 // No antags at all? let's boost those odds!
|
||||
else
|
||||
var/current_pop_per_antag = mode.current_players[CURRENT_LIVING_PLAYERS].len / mode.current_players[CURRENT_LIVING_ANTAGS].len
|
||||
if (current_pop_per_antag > max_pop_per_antag)
|
||||
chance += min(50, 25+10*(current_pop_per_antag-max_pop_per_antag))
|
||||
else
|
||||
chance += 25-10*(max_pop_per_antag-current_pop_per_antag)
|
||||
if (mode.current_players[CURRENT_DEAD_PLAYERS].len > mode.current_players[CURRENT_LIVING_PLAYERS].len)
|
||||
chance -= 30 // More than half the crew died? ew, let's calm down on antags
|
||||
if (mode.threat > 70)
|
||||
chance += 15
|
||||
if (mode.threat < 30)
|
||||
chance -= 15
|
||||
return round(max(0,chance))
|
||||
|
||||
/datum/dynamic_storyteller/proc/roundstart_draft()
|
||||
var/list/drafted_rules = list()
|
||||
for (var/datum/dynamic_ruleset/roundstart/rule in mode.roundstart_rules)
|
||||
if (rule.acceptable(mode.roundstart_pop_ready, mode.threat_level) && mode.threat >= rule.cost) // If we got the population and threat required
|
||||
rule.candidates = mode.candidates.Copy()
|
||||
rule.trim_candidates()
|
||||
if (rule.ready() && rule.candidates.len > 0)
|
||||
var/property_weight = 0
|
||||
for(var/property in property_weights)
|
||||
if(property in rule.property_weights) // just treat it as 0 if it's not in there
|
||||
property_weight += rule.property_weights[property] * property_weights[property]
|
||||
drafted_rules[rule] = (rule.get_weight() + property_weight)*rule.weight_mult
|
||||
return drafted_rules
|
||||
|
||||
/datum/dynamic_storyteller/proc/midround_draft()
|
||||
var/list/drafted_rules = list()
|
||||
for (var/datum/dynamic_ruleset/midround/rule in mode.midround_rules)
|
||||
// if there are antags OR the rule is an antag rule, antag_acceptable will be true.
|
||||
if (rule.acceptable(mode.current_players[CURRENT_LIVING_PLAYERS].len, mode.threat_level) && mode.threat >= rule.cost)
|
||||
// Classic secret : only autotraitor/minor roles
|
||||
if (GLOB.dynamic_classic_secret && !((rule.flags & TRAITOR_RULESET) || (rule.flags & MINOR_RULESET)))
|
||||
continue
|
||||
rule.trim_candidates()
|
||||
if (rule.ready())
|
||||
var/property_weight = 0
|
||||
for(var/property in property_weights)
|
||||
if(property in rule.property_weights)
|
||||
property_weight += rule.property_weights[property] * property_weights[property]
|
||||
drafted_rules[rule] = (rule.get_weight() + property_weight)*rule.weight_mult
|
||||
else if(mode.threat < rule.cost)
|
||||
SSblackbox.record_feedback("tally","dynamic",1,"Times rulesets rejected due to not enough threat to spend")
|
||||
return drafted_rules
|
||||
|
||||
/datum/dynamic_storyteller/proc/latejoin_draft(mob/living/carbon/human/newPlayer)
|
||||
var/list/drafted_rules = list()
|
||||
for (var/datum/dynamic_ruleset/latejoin/rule in mode.latejoin_rules)
|
||||
if (rule.acceptable(mode.current_players[CURRENT_LIVING_PLAYERS].len, mode.threat_level) && mode.threat >= rule.cost)
|
||||
// Classic secret : only autotraitor/minor roles
|
||||
if (GLOB.dynamic_classic_secret && !((rule.flags & TRAITOR_RULESET) || (rule.flags & MINOR_RULESET)))
|
||||
continue
|
||||
// No stacking : only one round-ender, unless threat level > stacking_limit.
|
||||
if (mode.threat_level > GLOB.dynamic_stacking_limit && GLOB.dynamic_no_stacking)
|
||||
if(rule.flags & HIGHLANDER_RULESET && mode.highlander_executed)
|
||||
continue
|
||||
|
||||
rule.candidates = list(newPlayer)
|
||||
rule.trim_candidates()
|
||||
if (rule.ready())
|
||||
var/property_weight = 0
|
||||
for(var/property in property_weights)
|
||||
if(property in rule.property_weights)
|
||||
property_weight += rule.property_weights[property] * property_weights[property]
|
||||
drafted_rules[rule] = (rule.get_weight() + property_weight)*rule.weight_mult
|
||||
else if(mode.threat < rule.cost)
|
||||
SSblackbox.record_feedback("tally","dynamic",1,"Times rulesets rejected due to not enough threat to spend")
|
||||
return drafted_rules
|
||||
|
||||
/datum/dynamic_storyteller/proc/event_draft()
|
||||
var/list/drafted_rules = list()
|
||||
for(var/datum/dynamic_ruleset/event/rule in mode.events)
|
||||
if(rule.acceptable(mode.current_players[CURRENT_LIVING_PLAYERS].len, mode.threat_level) && mode.threat >= rule.cost)
|
||||
if(rule.ready())
|
||||
var/property_weight = 0
|
||||
for(var/property in property_weights)
|
||||
if(property in rule.property_weights)
|
||||
property_weight += rule.property_weights[property] * property_weights[property]
|
||||
drafted_rules[rule] = (rule.get_weight() + property_weight)*rule.weight_mult
|
||||
else if(mode.threat < rule.cost)
|
||||
SSblackbox.record_feedback("tally","dynamic",1,"Times rulesets rejected due to not enough threat to spend")
|
||||
return drafted_rules
|
||||
|
||||
|
||||
/datum/dynamic_storyteller/cowabunga
|
||||
name = "Chaotic"
|
||||
curve_centre = 10
|
||||
desc = "Chaos: high. Variation: high. Likely antags: clock cult, revs, wizard."
|
||||
property_weights = list("extended" = -1, "chaos" = 10)
|
||||
weight = 2
|
||||
flags = WAROPS_ALWAYS_ALLOWED
|
||||
var/refund_cooldown
|
||||
|
||||
/datum/dynamic_storyteller/cowabunga/get_midround_cooldown()
|
||||
return ..() / 4
|
||||
|
||||
/datum/dynamic_storyteller/cowabunga/get_latejoin_cooldown()
|
||||
return ..() / 4
|
||||
|
||||
/datum/dynamic_storyteller/cowabunga/do_process()
|
||||
if(refund_cooldown < world.time)
|
||||
mode.refund_threat(10)
|
||||
mode.log_threat("Cowabunga it is. Refunded 10 threat. Threat is now [mode.threat].")
|
||||
refund_cooldown = world.time + 300 SECONDS
|
||||
|
||||
/datum/dynamic_storyteller/team
|
||||
name = "Teamwork"
|
||||
desc = "Chaos: high. Variation: low. Likely antags: nukies, clockwork cult, wizard, blob, xenomorph."
|
||||
curve_centre = 2
|
||||
curve_width = 1.5
|
||||
weight = 2
|
||||
flags = WAROPS_ALWAYS_ALLOWED
|
||||
property_weights = list("valid" = 3, "trust" = 5)
|
||||
|
||||
/datum/dynamic_storyteller/team/get_injection_chance(dry_run = FALSE)
|
||||
return (mode.current_players[CURRENT_LIVING_ANTAGS].len ? 0 : ..())
|
||||
|
||||
/datum/dynamic_storyteller/conversion
|
||||
name = "Conversion"
|
||||
desc = "Chaos: high. Variation: medium. Likely antags: cults, bloodsuckers, revs."
|
||||
curve_centre = 3
|
||||
curve_width = 1
|
||||
weight = 2
|
||||
flags = WAROPS_ALWAYS_ALLOWED
|
||||
property_weights = list("valid" = 1, "conversion" = 20)
|
||||
|
||||
/datum/dynamic_storyteller/classic
|
||||
name = "Random"
|
||||
desc = "Chaos: varies. Variation: highest. No special weights attached."
|
||||
weight = 6
|
||||
curve_width = 4
|
||||
|
||||
/datum/dynamic_storyteller/memes
|
||||
name = "Story"
|
||||
desc = "Chaos: varies. Variation: high. Likely antags: abductors, nukies, wizard, traitor."
|
||||
curve_width = 4
|
||||
property_weights = list("story_potential" = 10)
|
||||
|
||||
/datum/dynamic_storyteller/suspicion
|
||||
name = "Intrigue"
|
||||
desc = "Chaos: low. Variation: high. Likely antags: traitor, bloodsucker. Rare: revs, blood cult."
|
||||
curve_width = 4
|
||||
property_weights = list("trust" = -5)
|
||||
|
||||
/datum/dynamic_storyteller/liteextended
|
||||
name = "Calm"
|
||||
desc = "Chaos: low. Variation: medium. Likely antags: bloodsuckers, traitors, sentient disease, revenant."
|
||||
curve_centre = -5
|
||||
curve_width = 0.5
|
||||
flags = NO_ASSASSIN
|
||||
weight = 2
|
||||
property_weights = list("extended" = 1, "chaos" = -1, "valid" = -1, "story_potential" = 1, "conversion" = -10)
|
||||
|
||||
/datum/dynamic_storyteller/liteextended/get_injection_chance(dry_run = FALSE)
|
||||
return ..()/2
|
||||
|
||||
/datum/dynamic_storyteller/extended
|
||||
name = "Extended"
|
||||
desc = "Chaos: none. Variation: none. Likely antags: none."
|
||||
curve_centre = -20
|
||||
weight = 2
|
||||
curve_width = 0.5
|
||||
|
||||
/datum/dynamic_storyteller/extended/on_start()
|
||||
GLOB.dynamic_forced_extended = TRUE
|
||||
@@ -0,0 +1,246 @@
|
||||
#define DOM_BLOCKED_SPAM_CAP 6
|
||||
//32 instead of 40 for safety reasons. How many turfs aren't walls around dominator for it to work
|
||||
//Update ppl somehow fuckup at 32, now we are down to 25. I hope to god they don't try harder to wall it.
|
||||
#define DOM_REQUIRED_TURFS 25
|
||||
#define DOM_HULK_HITS_REQUIRED 10
|
||||
|
||||
/obj/machinery/dominator
|
||||
name = "dominator"
|
||||
desc = "A visibly sinister device. Looks like you can break it if you hit it enough."
|
||||
icon = 'icons/obj/machines/dominator.dmi'
|
||||
icon_state = "dominator"
|
||||
density = TRUE
|
||||
anchored = TRUE
|
||||
layer = HIGH_OBJ_LAYER
|
||||
max_integrity = 300
|
||||
integrity_failure = 100
|
||||
armor = list("melee" = 20, "bullet" = 50, "laser" = 50, "energy" = 50, "bomb" = 10, "bio" = 100, "rad" = 100, "fire" = 10, "acid" = 70)
|
||||
var/datum/team/gang/gang
|
||||
var/operating = FALSE //false=standby or broken, true=takeover
|
||||
var/warned = FALSE //if this device has set off the warning at <3 minutes yet
|
||||
var/spam_prevention = DOM_BLOCKED_SPAM_CAP //first message is immediate
|
||||
var/datum/effect_system/spark_spread/spark_system
|
||||
var/obj/effect/countdown/dominator/countdown
|
||||
|
||||
/obj/machinery/dominator/Initialize()
|
||||
. = ..()
|
||||
set_light(l_range = 2, l_power = 0.75)
|
||||
GLOB.poi_list |= src
|
||||
spark_system = new
|
||||
spark_system.set_up(5, TRUE, src)
|
||||
countdown = new(src)
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/dominator/Destroy()
|
||||
if(!(stat & BROKEN))
|
||||
set_broken()
|
||||
GLOB.poi_list.Remove(src)
|
||||
gang = null
|
||||
QDEL_NULL(spark_system)
|
||||
QDEL_NULL(countdown)
|
||||
STOP_PROCESSING(SSmachines, src)
|
||||
return ..()
|
||||
|
||||
/obj/machinery/dominator/emp_act(severity)
|
||||
take_damage(100, BURN, "energy", 0)
|
||||
..()
|
||||
|
||||
/obj/machinery/dominator/hulk_damage()
|
||||
return (max_integrity - integrity_failure) / DOM_HULK_HITS_REQUIRED
|
||||
|
||||
/obj/machinery/dominator/tesla_act()
|
||||
qdel(src)
|
||||
|
||||
/obj/machinery/dominator/update_icon()
|
||||
cut_overlays()
|
||||
if(stat & BROKEN)
|
||||
icon_state = "dominator-broken"
|
||||
return
|
||||
icon_state = "dominator"
|
||||
if(operating)
|
||||
var/mutable_appearance/dominator_overlay = mutable_appearance('icons/obj/machines/dominator.dmi', "dominator-overlay")
|
||||
if(gang)
|
||||
dominator_overlay.color = gang.color
|
||||
add_overlay(dominator_overlay)
|
||||
if(obj_integrity/max_integrity < 0.66)
|
||||
add_overlay("damage")
|
||||
|
||||
/obj/machinery/dominator/examine(mob/user)
|
||||
. = ..()
|
||||
if(stat & BROKEN)
|
||||
return
|
||||
|
||||
if(gang && gang.domination_time != NOT_DOMINATING)
|
||||
if(gang.domination_time > world.time)
|
||||
. += "<span class='notice'>Hostile Takeover in progress. Estimated [gang.domination_time_remaining()] seconds remain.</span>"
|
||||
else
|
||||
. += "<span class='notice'>Hostile Takeover of [station_name()] successful. Have a great day.</span>"
|
||||
else
|
||||
. += "<span class='notice'>System on standby.</span>"
|
||||
. += "<span class='danger'>System Integrity: [round((obj_integrity/max_integrity)*100,1)]%</span>"
|
||||
|
||||
/obj/machinery/dominator/process()
|
||||
..()
|
||||
if(gang && gang.domination_time != NOT_DOMINATING)
|
||||
var/time_remaining = gang.domination_time_remaining()
|
||||
if(time_remaining > 0)
|
||||
if(!is_station_level(z))
|
||||
explosion(src, 5, 10, 20, 30) //you now get a nice explosion if this moves off station.
|
||||
qdel(src) //to make sure it doesn't continue to exist.
|
||||
if(excessive_walls_check())
|
||||
gang.domination_time += 20
|
||||
if(spam_prevention < DOM_BLOCKED_SPAM_CAP)
|
||||
spam_prevention++
|
||||
else
|
||||
playsound(loc, 'sound/machines/buzz-two.ogg', 50, 0) // Play sound buzz-two.ogg, not before cause its annoying.
|
||||
gang.message_gangtools("Warning: There are too many walls around your gang's dominator, its signal is being blocked!")
|
||||
say("Error: Takeover signal is currently blocked! There are too many walls within 3 standard units of this device.")
|
||||
spam_prevention = 0
|
||||
return
|
||||
. = TRUE
|
||||
playsound(loc, 'sound/items/timer.ogg', 10, 0)
|
||||
if(!warned && (time_remaining < 180))
|
||||
warned = TRUE
|
||||
var/area/domloc = get_area(loc)
|
||||
gang.message_gangtools("Less than 3 minutes remains in hostile takeover. Defend your dominator at [domloc.map_name]!")
|
||||
for(var/G in GLOB.gangs)
|
||||
var/datum/team/gang/tempgang = G
|
||||
if(tempgang != gang)
|
||||
tempgang.message_gangtools("WARNING: [gang.name] Gang takeover imminent. Their dominator at [domloc.map_name] must be destroyed!",1,1)
|
||||
else
|
||||
Cinematic(CINEMATIC_MALF,world) //Here is the gang victory trigger on the dominator ending.
|
||||
gang.winner = TRUE
|
||||
SSticker.news_report = GANG_VICTORY
|
||||
SSticker.force_ending = TRUE
|
||||
|
||||
if(!.)
|
||||
STOP_PROCESSING(SSmachines, src)
|
||||
|
||||
/obj/machinery/dominator/play_attack_sound(damage_amount, damage_type = BRUTE, damage_flag = 0)
|
||||
switch(damage_type)
|
||||
if(BRUTE)
|
||||
if(damage_amount)
|
||||
playsound(src, 'sound/effects/bang.ogg', 50, 1)
|
||||
else
|
||||
playsound(loc, 'sound/weapons/tap.ogg', 50, 1)
|
||||
if(BURN)
|
||||
playsound(src.loc, 'sound/items/welder.ogg', 100, 1)
|
||||
|
||||
/obj/machinery/dominator/take_damage(damage_amount, damage_type = BRUTE, damage_flag = 0, sound_effect = 1)
|
||||
. = ..()
|
||||
if(.)
|
||||
if(obj_integrity/max_integrity > 0.66)
|
||||
if(prob(damage_amount*2))
|
||||
spark_system.start()
|
||||
else if(!(stat & BROKEN))
|
||||
spark_system.start()
|
||||
update_icon()
|
||||
|
||||
|
||||
/obj/machinery/dominator/obj_break(damage_flag)
|
||||
if(!(stat & BROKEN) && !(flags_1 & NODECONSTRUCT_1))
|
||||
set_broken()
|
||||
|
||||
/obj/machinery/dominator/deconstruct(disassembled = TRUE)
|
||||
if(!(flags_1 & NODECONSTRUCT_1))
|
||||
if(!(stat & BROKEN))
|
||||
set_broken()
|
||||
new /obj/item/stack/sheet/plasteel(src.loc)
|
||||
qdel(src)
|
||||
|
||||
/obj/machinery/dominator/attacked_by(obj/item/I, mob/living/user)
|
||||
add_fingerprint(user)
|
||||
..()
|
||||
|
||||
/obj/machinery/dominator/attack_hand(mob/user)
|
||||
if(operating || (stat & BROKEN))
|
||||
examine(user)
|
||||
return
|
||||
|
||||
var/datum/team/gang/tempgang
|
||||
|
||||
var/datum/antagonist/gang/GA = user.mind.has_antag_datum(/datum/antagonist/gang)
|
||||
if(GA)
|
||||
tempgang = GA.gang
|
||||
if(!tempgang)
|
||||
examine(user)
|
||||
return
|
||||
|
||||
if(tempgang.domination_time != NOT_DOMINATING)
|
||||
to_chat(user, "<span class='warning'>Error: Hostile Takeover is already in progress.</span>")
|
||||
return
|
||||
|
||||
if(!tempgang.dom_attempts)
|
||||
to_chat(user, "<span class='warning'>Error: Unable to breach station network. Firewall has logged our signature and is blocking all further attempts.</span>")
|
||||
return
|
||||
|
||||
var/time = round(tempgang.determine_domination_time()/60,0.1)
|
||||
if(alert(user,"A takeover will require [time] minutes.\nYour gang will be unable to gain influence while it is active.\nThe entire station will likely be alerted to it once it starts.\nYou have [tempgang.dom_attempts] attempt(s) remaining. Are you ready?","Confirm","Ready","Later") == "Ready")
|
||||
if((tempgang.domination_time != NOT_DOMINATING) || !tempgang.dom_attempts || !in_range(src, user) || !isturf(loc))
|
||||
return 0
|
||||
|
||||
var/area/A = get_area(loc)
|
||||
var/locname = A.map_name
|
||||
|
||||
gang = tempgang
|
||||
gang.dom_attempts --
|
||||
priority_announce("Network breach detected in [locname]. The [gang.name] Gang is attempting to seize control of the station!","Network Alert")
|
||||
gang.domination()
|
||||
SSshuttle.registerHostileEnvironment(src)
|
||||
name = "[gang.name] Gang [name]"
|
||||
operating = TRUE
|
||||
update_icon()
|
||||
|
||||
countdown.start()
|
||||
countdown.color = gang.color
|
||||
|
||||
set_light(l_range = 3, l_power = 0.9)
|
||||
light_color = gang.color
|
||||
START_PROCESSING(SSmachines, src)
|
||||
|
||||
gang.message_gangtools("Hostile takeover in progress: Estimated [time] minutes until victory.[gang.dom_attempts ? "" : " This is your final attempt."]")
|
||||
for(var/G in GLOB.gangs)
|
||||
var/datum/team/gang/vagos = G
|
||||
if(vagos != gang)
|
||||
vagos.message_gangtools("Enemy takeover attempt detected in [locname]: Estimated [time] minutes until our defeat.",1,1)
|
||||
|
||||
/obj/machinery/dominator/proc/excessive_walls_check() // why the fuck was this even a global proc...
|
||||
var/open = 0
|
||||
for(var/turf/T in view(3, src))
|
||||
if(!iswallturf(T)) //Check for /closed/wall, isclosedturf() moves it back to just checking for /closed/ which makes it very finicky.
|
||||
open++
|
||||
//to_chat(world, "THE DOMINATOR SEES [open] OPEN TURFS") uncomment to see what this shitty fucking wallcheck sees
|
||||
if(open < DOM_REQUIRED_TURFS)
|
||||
return TRUE
|
||||
else
|
||||
return FALSE
|
||||
/obj/machinery/dominator/proc/set_broken()
|
||||
if(gang)
|
||||
gang.domination_time = NOT_DOMINATING
|
||||
|
||||
var/takeover_in_progress = FALSE
|
||||
for(var/G in GLOB.gangs)
|
||||
var/datum/team/gang/ballas = G
|
||||
if(ballas.domination_time != NOT_DOMINATING)
|
||||
takeover_in_progress = TRUE
|
||||
break
|
||||
if(!takeover_in_progress)
|
||||
var/was_stranded = SSshuttle.emergency.mode == SHUTTLE_STRANDED
|
||||
if(!was_stranded)
|
||||
priority_announce("All hostile activity within station systems has ceased.","Network Alert")
|
||||
|
||||
if(get_security_level() == "delta")
|
||||
set_security_level("red")
|
||||
|
||||
SSshuttle.clearHostileEnvironment(src)
|
||||
gang.message_gangtools("Hostile takeover cancelled: Dominator is no longer operational.[gang.dom_attempts ? " You have [gang.dom_attempts] attempt remaining." : " The station network will have likely blocked any more attempts by us."]",1,1)
|
||||
|
||||
set_light(0)
|
||||
operating = FALSE
|
||||
stat |= BROKEN
|
||||
update_icon()
|
||||
STOP_PROCESSING(SSmachines, src)
|
||||
|
||||
#undef DOM_BLOCKED_SPAM_CAP
|
||||
#undef DOM_REQUIRED_TURFS
|
||||
#undef DOM_HULK_HITS_REQUIRED
|
||||
@@ -0,0 +1,13 @@
|
||||
/obj/effect/countdown/dominator
|
||||
name = "dominator countdown"
|
||||
text_size = 1
|
||||
color = "#e5e5e5" // Overwritten when the dominator starts
|
||||
|
||||
/obj/effect/countdown/dominator/get_value()
|
||||
var/obj/machinery/dominator/D = attached_to
|
||||
if(!istype(D))
|
||||
return
|
||||
else if(D.gang && D.gang.domination_time != NOT_DOMINATING)
|
||||
return D.gang.domination_time_remaining()
|
||||
else
|
||||
return "OFFLINE"
|
||||
@@ -0,0 +1,477 @@
|
||||
/datum/antagonist/gang
|
||||
name = "Gangster"
|
||||
roundend_category = "gangsters"
|
||||
can_coexist_with_others = FALSE
|
||||
job_rank = ROLE_GANG
|
||||
antagpanel_category = "Gang"
|
||||
var/hud_type = "gangster"
|
||||
var/message_name = "Gangster"
|
||||
var/datum/team/gang/gang
|
||||
|
||||
/datum/antagonist/gang/can_be_owned(datum/mind/new_owner)
|
||||
. = ..()
|
||||
if(.)
|
||||
if(new_owner.unconvertable)
|
||||
return FALSE
|
||||
|
||||
/datum/antagonist/gang/apply_innate_effects(mob/living/mob_override)
|
||||
var/mob/living/M = mob_override || owner.current
|
||||
update_gang_icons_added(M)
|
||||
|
||||
/datum/antagonist/gang/remove_innate_effects(mob/living/mob_override)
|
||||
var/mob/living/M = mob_override || owner.current
|
||||
update_gang_icons_removed(M)
|
||||
|
||||
/datum/antagonist/gang/get_team()
|
||||
return gang
|
||||
|
||||
/datum/antagonist/gang/greet()
|
||||
gang.greet_gangster(owner)
|
||||
|
||||
/datum/antagonist/gang/farewell()
|
||||
if(ishuman(owner.current))
|
||||
owner.current.visible_message("<span class='deconversion_message'>[owner.current] looks like [owner.current.p_theyve()] just remembered [owner.current.p_their()] real allegiance!</span>", null, null, null, owner.current)
|
||||
to_chat(owner, "<span class='userdanger'>You are no longer a gangster!</span>")
|
||||
|
||||
/datum/antagonist/gang/on_gain()
|
||||
if(!gang)
|
||||
create_team()
|
||||
..()
|
||||
var/mob/living/carbon/human/H = owner.current
|
||||
if(istype(H))
|
||||
if(owner.assigned_role == "Clown")
|
||||
to_chat(owner, "Your training has allowed you to overcome your clownish nature, allowing you to wield weapons without harming yourself.")
|
||||
H.dna.remove_mutation(CLOWNMUT)
|
||||
add_to_gang()
|
||||
|
||||
/datum/antagonist/gang/on_removal()
|
||||
remove_from_gang()
|
||||
..()
|
||||
|
||||
/datum/antagonist/gang/create_team(team)
|
||||
if(!gang) // add_antag_datum calls create_team, so we need to avoid generating two gangs in that case
|
||||
if(team)
|
||||
gang = team
|
||||
return
|
||||
var/datum/team/gang/gangteam = pick_n_take(GLOB.possible_gangs)
|
||||
if(gangteam)
|
||||
gang = new gangteam
|
||||
|
||||
/datum/antagonist/gang/proc/equip_gang() // Bosses get equipped with their tools
|
||||
return
|
||||
|
||||
/datum/antagonist/gang/proc/update_gang_icons_added(mob/living/M)
|
||||
var/datum/atom_hud/antag/gang/ganghud = GLOB.huds[gang.hud_entry_num]
|
||||
if(!ganghud)
|
||||
ganghud = new/datum/atom_hud/antag/gang()
|
||||
gang.hud_entry_num = GLOB.huds.len+1 // this is the index the gang hud will be added at
|
||||
GLOB.huds += ganghud
|
||||
ganghud.color = gang.color
|
||||
ganghud.join_hud(M)
|
||||
set_antag_hud(M,hud_type)
|
||||
|
||||
/datum/antagonist/gang/proc/update_gang_icons_removed(mob/living/M)
|
||||
var/datum/atom_hud/antag/gang/ganghud = GLOB.huds[gang.hud_entry_num]
|
||||
if(ganghud)
|
||||
ganghud.leave_hud(M)
|
||||
set_antag_hud(M, null)
|
||||
|
||||
/datum/antagonist/gang/proc/can_be_converted(mob/living/candidate)
|
||||
if(!candidate.mind)
|
||||
return FALSE
|
||||
if(!can_be_owned(candidate.mind))
|
||||
return FALSE
|
||||
var/mob/living/carbon/human/H = candidate
|
||||
if(!istype(H)) //Can't nonhumans
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/antagonist/gang/proc/promote() // Bump up to boss
|
||||
var/datum/team/gang/old_gang = gang
|
||||
var/datum/mind/old_owner = owner
|
||||
owner.remove_antag_datum(/datum/antagonist/gang)
|
||||
var/datum/antagonist/gang/boss/lieutenant/new_boss = new
|
||||
new_boss.silent = TRUE
|
||||
old_owner.add_antag_datum(new_boss,old_gang)
|
||||
new_boss.silent = FALSE
|
||||
log_game("[key_name(old_owner)] has been promoted to Lieutenant in the [old_gang.name] Gang")
|
||||
to_chat(old_owner, "<FONT size=3 color=red><B>You have been promoted to Lieutenant!</B></FONT>")
|
||||
|
||||
|
||||
// Admin commands
|
||||
/datum/antagonist/gang/get_admin_commands()
|
||||
. = ..()
|
||||
.["Promote"] = CALLBACK(src,.proc/admin_promote)
|
||||
.["Set Influence"] = CALLBACK(src, .proc/admin_adjust_influence)
|
||||
if(gang.domination_time != NOT_DOMINATING)
|
||||
.["Set domination time left"] = CALLBACK(src, .proc/set_dom_time_left)
|
||||
|
||||
/datum/antagonist/gang/admin_add(datum/mind/new_owner,mob/admin)
|
||||
var/new_or_existing = input(admin, "Which gang do you want to be assigned to the user?", "Gangs") as null|anything in list("New","Existing")
|
||||
if(isnull(new_or_existing))
|
||||
return
|
||||
else if(new_or_existing == "New")
|
||||
var/newgang = input(admin, "Select a gang, or select random to pick a random one.", "New gang") as null|anything in GLOB.possible_gangs + "Random"
|
||||
if(isnull(newgang))
|
||||
return
|
||||
else if(newgang == "Random")
|
||||
var/datum/team/gang/G = pick_n_take(GLOB.possible_gangs)
|
||||
gang = new G
|
||||
else
|
||||
GLOB.possible_gangs -= newgang
|
||||
gang = new newgang
|
||||
else
|
||||
if(!GLOB.gangs.len) // no gangs exist
|
||||
to_chat(admin, "<span class='danger'>No gangs exist, please create a new one instead.</span>")
|
||||
return
|
||||
var/existinggang = input(admin, "Select a gang, or select random to pick a random one.", "Existing gang") as null|anything in GLOB.gangs + "Random"
|
||||
if(isnull(existinggang))
|
||||
return
|
||||
else if(existinggang == "Random")
|
||||
gang = pick(GLOB.gangs)
|
||||
else
|
||||
gang = existinggang
|
||||
..()
|
||||
return TRUE
|
||||
|
||||
/datum/antagonist/gang/proc/admin_promote(mob/admin)
|
||||
message_admins("[key_name_admin(admin)] has promoted [owner] to gang boss.")
|
||||
log_admin("[key_name(admin)] has promoted [owner] to boss.")
|
||||
promote()
|
||||
|
||||
/datum/antagonist/gang/proc/admin_adjust_influence()
|
||||
var/inf = input("Influence for [gang.name]","Gang influence", gang.influence) as null | num
|
||||
if(!isnull(inf))
|
||||
gang.influence = inf
|
||||
message_admins("[key_name_admin(usr)] changed [gang.name]'s influence to [inf].")
|
||||
log_admin("[key_name(usr)] changed [gang.name]'s influence to [inf].")
|
||||
|
||||
/datum/antagonist/gang/proc/add_to_gang()
|
||||
gang.add_member(owner)
|
||||
owner.current.log_message("<font color='red'>Has been converted to the [gang.name] gang!</font>", INDIVIDUAL_ATTACK_LOG)
|
||||
|
||||
/datum/antagonist/gang/proc/remove_from_gang()
|
||||
gang.remove_member(owner)
|
||||
owner.current.log_message("<font color='red'>Has been deconverted from the [gang.name] gang!</font>", INDIVIDUAL_ATTACK_LOG)
|
||||
|
||||
/datum/antagonist/gang/proc/set_dom_time_left(mob/admin)
|
||||
if(gang.domination_time == NOT_DOMINATING)
|
||||
return // an admin shouldn't need this
|
||||
var/seconds = input(admin, "Set the time left for the gang to win, in seconds", "Domination time left") as null|num
|
||||
if(seconds && seconds > 0)
|
||||
gang.domination_time = world.time + seconds*10
|
||||
gang.message_gangtools("Takeover shortened to [gang.domination_time_remaining()] seconds by your Syndicate benefactors.")
|
||||
|
||||
// Boss type. Those can use gang tools to buy items for their gang, in particular the Dominator, used to win the gamemode, along with more gang tools to promote fellow gangsters to boss status.
|
||||
/datum/antagonist/gang/boss
|
||||
name = "Gang boss"
|
||||
hud_type = "gang_boss"
|
||||
message_name = "Leader"
|
||||
|
||||
/datum/antagonist/gang/boss/on_gain()
|
||||
..()
|
||||
if(gang)
|
||||
gang.leaders += owner
|
||||
|
||||
/datum/antagonist/gang/boss/on_removal()
|
||||
if(gang)
|
||||
gang.leaders -= owner
|
||||
..()
|
||||
|
||||
/datum/antagonist/gang/boss/antag_listing_name()
|
||||
return ..() + "(Boss)"
|
||||
|
||||
/datum/antagonist/gang/boss/equip_gang(gangtool = TRUE, pen = TRUE, spraycan = TRUE, hud = TRUE) // usually has to be called separately
|
||||
var/mob/living/carbon/human/H = owner.current
|
||||
if(!istype(H))
|
||||
return
|
||||
|
||||
var/list/slots = list (
|
||||
"backpack" = SLOT_IN_BACKPACK,
|
||||
"left pocket" = SLOT_L_STORE,
|
||||
"right pocket" = SLOT_R_STORE,
|
||||
"hands" = SLOT_HANDS
|
||||
)
|
||||
|
||||
if(gangtool)//Here is where all of the text occurs when a gang boss first spawns in.
|
||||
var/obj/item/device/gangtool/G = new()
|
||||
var/where = H.equip_in_one_of_slots(G, slots)
|
||||
if (!where)
|
||||
to_chat(H, "Your Syndicate benefactors were unfortunately unable to get you a Gangtool.")
|
||||
else
|
||||
G.register_device(H)
|
||||
to_chat(H, "The <b>Gangtool</b> in your [where] will allow you to purchase weapons and equipment, send messages to your gang, and recall the emergency shuttle from anywhere on the station.")
|
||||
to_chat(H, "As the gang boss, you can also promote your gang members to <b>lieutenant</b>. Unlike regular gangsters, Lieutenants cannot be deconverted and are able to use gangtools too.")
|
||||
|
||||
if(pen)
|
||||
var/obj/item/pen/gang/T = new()
|
||||
var/where2 = H.equip_in_one_of_slots(T, slots)
|
||||
if (!where2)
|
||||
to_chat(H, "Your Syndicate benefactors were unfortunately unable to get you a recruitment pen to start.")
|
||||
else
|
||||
to_chat(H, "The <b>recruitment pen</b> in your [where2] will help you get your gang started. Stab unsuspecting crew members with it to recruit them. All gangsters can use these, distribute them to see your gang grow.")
|
||||
|
||||
if(spraycan)
|
||||
var/obj/item/toy/crayon/spraycan/gang/SC = new(null,gang)
|
||||
var/where3 = H.equip_in_one_of_slots(SC, slots)
|
||||
if (!where3)
|
||||
to_chat(H, "Your Syndicate benefactors were unfortunately unable to get you a territory spraycan to start.")
|
||||
else
|
||||
to_chat(H, "The <b>territory spraycan</b> in your [where3] can be used to claim areas of the station for your gang. The more territory your gang controls, the more influence you get. All gangsters can use these, so distribute them to grow your influence faster.")
|
||||
|
||||
if(hud)
|
||||
var/obj/item/clothing/glasses/hud/security/chameleon/C = new(null,gang)
|
||||
var/where4 = H.equip_in_one_of_slots(C, slots)
|
||||
if (!where4)
|
||||
to_chat(H, "Your Syndicate benefactors were unfortunately unable to get you a chameleon security HUD.")
|
||||
else
|
||||
to_chat(H, "The <b>chameleon security HUD</b> in your [where4] will help you keep track of who is mindshield-implanted, and unable to be recruited.")
|
||||
|
||||
// Admin commands for bosses
|
||||
/datum/antagonist/gang/boss/admin_add(datum/mind/new_owner,mob/admin)
|
||||
if(!new_owner.has_antag_datum(parent_type))
|
||||
..()
|
||||
to_chat(new_owner.current, "<span class='userdanger'>You are a member of the [gang.name] Gang leadership now!</span>")
|
||||
return
|
||||
promote()
|
||||
message_admins("[key_name_admin(admin)] has made [new_owner.current] a boss of the [gang.name] gang.")
|
||||
log_admin("[key_name(admin)] has made [new_owner.current] a boss of the [gang.name] gang.")
|
||||
to_chat(new_owner.current, "<span class='userdanger'>You are a member of the [gang.name] Gang leadership now!</span>")
|
||||
|
||||
/datum/antagonist/gang/boss/get_admin_commands()
|
||||
. = ..()
|
||||
. -= "Promote"
|
||||
.["Take gangtool"] = CALLBACK(src,.proc/admin_take_gangtool)
|
||||
.["Give gangtool"] = CALLBACK(src,.proc/admin_give_gangtool)
|
||||
.["Demote"] = CALLBACK(src,.proc/admin_demote)
|
||||
|
||||
/datum/antagonist/gang/boss/proc/demote()
|
||||
var/old_gang = gang
|
||||
var/datum/mind/old_owner = owner
|
||||
silent = TRUE
|
||||
owner.remove_antag_datum(/datum/antagonist/gang/boss)
|
||||
var/datum/antagonist/gang/new_gangster = new /datum/antagonist/gang()
|
||||
new_gangster.silent = TRUE
|
||||
old_owner.add_antag_datum(new_gangster,old_gang)
|
||||
new_gangster.silent = FALSE
|
||||
log_game("[key_name(old_owner)] has been demoted to Gangster in the [gang.name] Gang")
|
||||
to_chat(old_owner, "<span class='userdanger'>The gang has been disappointed of your leader traits! You are a regular gangster now!</span>")
|
||||
|
||||
/datum/antagonist/gang/boss/proc/admin_take_gangtool(mob/admin)
|
||||
var/list/L = owner.current.get_contents()
|
||||
var/obj/item/device/gangtool/gangtool = locate() in L
|
||||
if (!gangtool)
|
||||
to_chat(admin, "<span class='danger'>Deleting gangtool failed!</span>")
|
||||
return
|
||||
qdel(gangtool)
|
||||
|
||||
/datum/antagonist/gang/boss/proc/admin_give_gangtool(mob/admin)
|
||||
equip_gang(TRUE, FALSE, FALSE, FALSE)
|
||||
|
||||
/datum/antagonist/gang/boss/proc/admin_demote(datum/mind/target,mob/user)
|
||||
message_admins("[key_name_admin(user)] has demoted [owner.current] from gang boss.")
|
||||
log_admin("[key_name(user)] has demoted [owner.current] from gang boss.")
|
||||
admin_take_gangtool(user)
|
||||
demote()
|
||||
|
||||
/datum/antagonist/gang/boss/lieutenant
|
||||
name = "Gang Lieutenant"
|
||||
message_name = "Lieutenant"
|
||||
hud_type = "gang_lt"
|
||||
|
||||
#define MAXIMUM_RECALLS 3
|
||||
#define INFLUENCE_INTERVAL 1200 //This handles the interval between each count of influence.
|
||||
// Gang team datum. This handles the gang itself.
|
||||
/datum/team/gang
|
||||
name = "Gang"
|
||||
member_name = "gangster"
|
||||
var/hud_entry_num // because if you put something other than a number in GLOB.huds, god have mercy on your fucking soul friend
|
||||
var/list/leaders = list() // bosses
|
||||
var/max_leaders = MAX_LEADERS_GANG
|
||||
var/list/territories = list() // territories owned by the gang.
|
||||
var/list/lost_territories = list() // territories lost by the gang.
|
||||
var/list/new_territories = list() // territories captured by the gang.
|
||||
var/list/gangtools = list()
|
||||
var/domination_time = NOT_DOMINATING
|
||||
var/dom_attempts = INITIAL_DOM_ATTEMPTS
|
||||
var/color
|
||||
var/influence = 0 // influence of the gang, based on how many territories they own. Can be used to buy weapons and tools from a gang uplink.
|
||||
var/winner // Once the gang wins with a dominator, this becomes true. For roundend credits purposes.
|
||||
var/list/inner_outfits = list()
|
||||
var/list/outer_outfits = list()
|
||||
var/next_point_time
|
||||
var/recalls = MAXIMUM_RECALLS // Once this reaches 0, this gang cannot force recall the shuttle with their gangtool anymore
|
||||
|
||||
/datum/team/gang/New(starting_members)
|
||||
. = ..()
|
||||
GLOB.gangs += src
|
||||
if(starting_members)
|
||||
if(islist(starting_members))
|
||||
for(var/datum/mind/groveboss in starting_members)
|
||||
leaders += groveboss
|
||||
var/datum/antagonist/gang/boss/gb = new
|
||||
groveboss.add_antag_datum(gb, src)
|
||||
gb.equip_gang()
|
||||
|
||||
else
|
||||
var/datum/mind/CJ = starting_members
|
||||
if(istype(CJ))
|
||||
leaders += CJ
|
||||
var/datum/antagonist/gang/boss/bossdatum = new
|
||||
CJ.add_antag_datum(bossdatum, src)
|
||||
bossdatum.equip_gang()
|
||||
next_point_time = world.time + INFLUENCE_INTERVAL
|
||||
addtimer(CALLBACK(src, .proc/handle_territories), INFLUENCE_INTERVAL)
|
||||
|
||||
/datum/team/gang/Destroy()
|
||||
GLOB.gangs -= src
|
||||
..()
|
||||
|
||||
/datum/team/gang/roundend_report() //roundend report.
|
||||
var/list/report = list()
|
||||
report += "<span class='header'>[name]:</span>"
|
||||
if(winner)
|
||||
report += "<span class='greentext'>The [name] gang successfully activated the mind dominator!</span>"
|
||||
else
|
||||
report += "<span class='redtext'>The [name] gang has failed!</span>"
|
||||
|
||||
report += "The [name] gang bosses were:"
|
||||
report += printplayerlist(leaders)
|
||||
report += "The [name] [member_name]s were:"
|
||||
report += printplayerlist(members-leaders)
|
||||
|
||||
return "<div class='panel redborder'>[report.Join("<br>")]</div>"
|
||||
|
||||
/datum/team/gang/proc/greet_gangster(datum/mind/gangster) //The text a person receives when recruited.
|
||||
var/message = "<FONT size=3 color=red><B>You are now a member of the <font color='[color]'>[name]</font> Gang!</B></FONT>"
|
||||
message += "<font color='red'>Help your bosses take over the station by claiming territory with <b>spraycans</b>. Simply spray on any unclaimed area of the station.</font>"
|
||||
message += "<font color='red'>You can also use recruitment pens to recruit more to your cause, If your boss provides you one.</font>"
|
||||
message += "<font color='red'>Their ultimate objective is to take over the station with a Dominator machine.</font>"
|
||||
message += "<font color='red'>You can identify your mates by their <b>large, <font color='[color]'> \[G\]</font> icon</b>.</font>"
|
||||
to_chat(gangster, message)
|
||||
gangster.store_memory("You are a member of the [name] Gang!")
|
||||
|
||||
/datum/team/gang/proc/handle_territories()
|
||||
next_point_time = world.time + INFLUENCE_INTERVAL
|
||||
if(!leaders.len)
|
||||
return
|
||||
var/added_names = ""
|
||||
var/lost_names = ""
|
||||
|
||||
//Re-add territories that were reclaimed, so if they got tagged over, they can still earn income if they tag it back before the next status report
|
||||
var/list/reclaimed_territories = new_territories & lost_territories
|
||||
territories |= reclaimed_territories
|
||||
new_territories -= reclaimed_territories
|
||||
lost_territories -= reclaimed_territories
|
||||
|
||||
//Process lost territories
|
||||
for(var/area in lost_territories)
|
||||
if(lost_names != "")
|
||||
lost_names += ", "
|
||||
lost_names += "[lost_territories[area]]"
|
||||
territories -= area
|
||||
|
||||
//Calculate and report influence growth
|
||||
|
||||
//Process new territories
|
||||
for(var/area in new_territories)
|
||||
if(added_names != "")
|
||||
added_names += ", "
|
||||
added_names += "[new_territories[area]]"
|
||||
territories += area
|
||||
|
||||
//Report territory changes
|
||||
var/message = "<b>[src] Gang Status Report:</b>.<BR>*---------*<BR>"
|
||||
message += "<b>[new_territories.len] new territories:</b><br><i>[added_names]</i><br>"
|
||||
message += "<b>[lost_territories.len] territories lost:</b><br><i>[lost_names]</i><br>"
|
||||
//Clear the lists
|
||||
new_territories = list()
|
||||
lost_territories = list()
|
||||
var/total_territories = total_claimable_territories()
|
||||
var/control = round((territories.len/total_territories)*100, 1)
|
||||
var/uniformed = check_clothing()
|
||||
message += "Your gang now has <b>[control]% control</b> of the station.<BR>*---------*<BR>"
|
||||
if(domination_time != NOT_DOMINATING)
|
||||
var/new_time = max(world.time, domination_time - (uniformed * 4) - (territories.len * 2))
|
||||
if(new_time < domination_time)
|
||||
message += "Takeover shortened by [(domination_time - new_time)*0.1] seconds for defending [territories.len] territories.<BR>"
|
||||
domination_time = new_time
|
||||
message += "<b>[domination_time_remaining()] seconds remain</b> in hostile takeover.<BR>"
|
||||
else
|
||||
var/new_influence = check_territory_income()
|
||||
if(new_influence != influence)
|
||||
message += "Gang influence has increased by [new_influence - influence] for defending [territories.len] territories and [uniformed] uniformed gangsters.<BR>"
|
||||
influence = new_influence
|
||||
message += "Your gang now has <b>[influence] influence</b>.<BR>"
|
||||
message_gangtools(message)
|
||||
addtimer(CALLBACK(src, .proc/handle_territories), INFLUENCE_INTERVAL)
|
||||
|
||||
/datum/team/gang/proc/total_claimable_territories()
|
||||
var/list/valid_territories = list()
|
||||
for(var/z in SSmapping.levels_by_trait(ZTRAIT_STATION)) //First, collect all area types on the station zlevel
|
||||
for(var/ar in SSmapping.areas_in_z["[z]"])
|
||||
var/area/A = ar
|
||||
if(!(A.type in valid_territories) && A.valid_territory)
|
||||
valid_territories |= A.type
|
||||
return valid_territories.len
|
||||
|
||||
/datum/team/gang/proc/check_territory_income()
|
||||
var/new_influence = min(999,influence + 15 + (check_clothing() * 2) + territories.len)
|
||||
return new_influence
|
||||
|
||||
/datum/team/gang/proc/check_clothing()
|
||||
//Count uniformed gangsters
|
||||
var/uniformed = 0
|
||||
for(var/datum/mind/gangmind in members)
|
||||
if(ishuman(gangmind.current))
|
||||
var/mob/living/carbon/human/gangster = gangmind.current
|
||||
//Gangster must be alive and should return 0 not continue if conditions are met.
|
||||
if(!istype(gangster) || gangster.stat == DEAD)
|
||||
return 0
|
||||
|
||||
var/obj/item/clothing/outfit
|
||||
var/obj/item/clothing/gang_outfit
|
||||
if(gangster.w_uniform)
|
||||
outfit = gangster.w_uniform
|
||||
if(outfit.type in inner_outfits)
|
||||
gang_outfit = outfit
|
||||
if(gangster.wear_suit)
|
||||
outfit = gangster.wear_suit
|
||||
if(outfit.type in outer_outfits)
|
||||
gang_outfit = outfit
|
||||
|
||||
if(gang_outfit)
|
||||
uniformed++
|
||||
return uniformed
|
||||
|
||||
/datum/team/gang/proc/adjust_influence(value)
|
||||
influence = max(0, influence + value)
|
||||
|
||||
/datum/team/gang/proc/message_gangtools(message)
|
||||
if(!gangtools.len || !message)
|
||||
return
|
||||
for(var/i in gangtools)
|
||||
var/obj/item/device/gangtool/tool = i
|
||||
var/mob/living/mob = get(tool.loc, /mob/living)
|
||||
if(mob && mob.mind && mob.stat == CONSCIOUS)
|
||||
var/datum/antagonist/gang/gangster = mob.mind.has_antag_datum(/datum/antagonist/gang)
|
||||
if(gangster.gang == src)
|
||||
to_chat(mob, "<span class='warning'>[icon2html(tool, mob)] [message]</span>")
|
||||
playsound(mob.loc, 'sound/machines/twobeep.ogg', 50, 1)
|
||||
return
|
||||
|
||||
/datum/team/gang/proc/domination()
|
||||
domination_time = world.time + determine_domination_time()*10
|
||||
set_security_level("delta")
|
||||
|
||||
/datum/team/gang/proc/determine_domination_time() // calculates the value in seconds (this is the initial domination time!)
|
||||
var/total_territories = total_claimable_territories()
|
||||
return max(180,480 - (round((territories.len/total_territories)*100, 1) * 9))
|
||||
|
||||
/datum/team/gang/proc/domination_time_remaining() // retrieves the value from world.time based deciseconds to seconds
|
||||
var/diff = domination_time - world.time
|
||||
return round(diff * 0.1)
|
||||
|
||||
|
||||
#undef MAXIMUM_RECALLS
|
||||
#undef INFLUENCE_INTERVAL
|
||||
@@ -0,0 +1,139 @@
|
||||
// Gang datums go here. If you want to create a new gang, you must be sure to edit:
|
||||
// name
|
||||
// color (must be a hex, "blue" isn't acceptable due to how spraycans are handled)
|
||||
// inner_outfits (must be a list() with typepaths of the clothes in it. One is fine, but there is support for multiple: one will be picked at random when bought)
|
||||
// outer_outfits (same as above)
|
||||
// You also need to make a gang graffiti, that will go in crayondecal.dmi inside our icons, with the same name of the gang it's assigned to. Nothing else,just the icon.
|
||||
// Those are all required. If one is missed, stuff could break.
|
||||
|
||||
/datum/team/gang/clandestine
|
||||
name = "Clandestine"
|
||||
color = "#FF0000"
|
||||
inner_outfits = list(/obj/item/clothing/under/syndicate/combat)
|
||||
outer_outfits = list(/obj/item/clothing/suit/jacket)
|
||||
|
||||
/datum/team/gang/prima
|
||||
name = "Prima"
|
||||
color = "#FFFF00"
|
||||
inner_outfits = list(/obj/item/clothing/under/color/yellow)
|
||||
outer_outfits = list(/obj/item/clothing/suit/hastur)
|
||||
|
||||
/datum/team/gang/zerog
|
||||
name = "Zero-G"
|
||||
color = "#C0C0C0"
|
||||
inner_outfits = list(/obj/item/clothing/under/suit_jacket/white)
|
||||
outer_outfits = list(/obj/item/clothing/suit/hooded/wintercoat)
|
||||
|
||||
/datum/team/gang/max
|
||||
name = "Max"
|
||||
color = "#800000"
|
||||
inner_outfits = list(/obj/item/clothing/under/color/maroon)
|
||||
outer_outfits = list(/obj/item/clothing/suit/poncho/red)
|
||||
|
||||
/datum/team/gang/blasto
|
||||
name = "Blasto"
|
||||
color = "#000080"
|
||||
inner_outfits = list(/obj/item/clothing/under/suit_jacket/navy)
|
||||
outer_outfits = list(/obj/item/clothing/suit/jacket/miljacket)
|
||||
|
||||
/datum/team/gang/waffle
|
||||
name = "Waffle"
|
||||
color = "#808000" //shared color with cyber, but they can keep brown cause waffles.
|
||||
inner_outfits = list(/obj/item/clothing/under/suit_jacket/green)
|
||||
outer_outfits = list(/obj/item/clothing/suit/poncho)
|
||||
|
||||
/datum/team/gang/north
|
||||
name = "North"
|
||||
color = "#00FF00"
|
||||
inner_outfits = list(/obj/item/clothing/under/color/green)
|
||||
outer_outfits = list(/obj/item/clothing/suit/poncho/green)
|
||||
|
||||
/datum/team/gang/omni
|
||||
name = "Omni"
|
||||
color = "#008080"
|
||||
inner_outfits = list(/obj/item/clothing/under/color/teal)
|
||||
outer_outfits = list(/obj/item/clothing/suit/chaplain/studentuni)
|
||||
|
||||
/datum/team/gang/newton
|
||||
name = "Newton"
|
||||
color = "#A52A2A"
|
||||
inner_outfits = list(/obj/item/clothing/under/color/brown)
|
||||
outer_outfits = list(/obj/item/clothing/suit/toggle/owlwings)
|
||||
|
||||
/datum/team/gang/cyber
|
||||
name = "Cyber"
|
||||
color = "#00f904" //Cyber and waffle shared colors, I made these guys green and made weed darker green.
|
||||
inner_outfits = list(/obj/item/clothing/under/color/lightbrown)
|
||||
outer_outfits = list(/obj/item/clothing/suit/chaplain/pharaoh)
|
||||
|
||||
/datum/team/gang/donk
|
||||
name = "Donk"
|
||||
color = "#0000FF"
|
||||
inner_outfits = list(/obj/item/clothing/under/color/darkblue)
|
||||
outer_outfits = list(/obj/item/clothing/suit/apron/overalls)
|
||||
|
||||
/datum/team/gang/gene
|
||||
name = "Gene"
|
||||
color = "#00FFFF"
|
||||
inner_outfits = list(/obj/item/clothing/under/color/blue)
|
||||
outer_outfits = list(/obj/item/clothing/suit/apron)
|
||||
|
||||
/datum/team/gang/gib
|
||||
name = "Gib"
|
||||
color = "#636060" //Applying black to grayscale... Zero-G is already grey too. oh well.
|
||||
inner_outfits = list(/obj/item/clothing/under/color/black)
|
||||
outer_outfits = list(/obj/item/clothing/suit/jacket/leather/overcoat)
|
||||
|
||||
/datum/team/gang/tunnel
|
||||
name = "Tunnel"
|
||||
color = "#FF00FF" //Gave the leather jacket to the tunnel gang over diablo.
|
||||
inner_outfits = list(/obj/item/clothing/under/villain)
|
||||
outer_outfits = list(/obj/item/clothing/suit/jacket/leather)
|
||||
|
||||
/datum/team/gang/diablo
|
||||
name = "Diablo"
|
||||
color = "#FF0000" //literal early 90s skinhead regalia.
|
||||
inner_outfits = list(/obj/item/clothing/under/pants/classicjeans)
|
||||
outer_outfits = list(/obj/item/clothing/suit/suspenders)
|
||||
|
||||
/datum/team/gang/psyke
|
||||
name = "Psyke"
|
||||
color = "#808080"
|
||||
inner_outfits = list(/obj/item/clothing/under/color/grey)
|
||||
outer_outfits = list(/obj/item/clothing/suit/toggle/owlwings/griffinwings)
|
||||
|
||||
/datum/team/gang/osiron
|
||||
name = "Osiron"
|
||||
color = "#FFFFFF"
|
||||
inner_outfits = list(/obj/item/clothing/under/color/white)
|
||||
outer_outfits = list(/obj/item/clothing/suit/toggle/labcoat)
|
||||
|
||||
/datum/team/gang/sirius
|
||||
name = "Sirius"
|
||||
color = "#FFC0CB"
|
||||
inner_outfits = list(/obj/item/clothing/under/color/pink)
|
||||
outer_outfits = list(/obj/item/clothing/suit/jacket/puffer/vest)
|
||||
|
||||
/datum/team/gang/sleepingcarp
|
||||
name = "Sleeping Carp"
|
||||
color = "#800080"
|
||||
inner_outfits = list(/obj/item/clothing/under/color/lightpurple)
|
||||
outer_outfits = list(/obj/item/clothing/suit/hooded/carp_costume)
|
||||
|
||||
/datum/team/gang/h
|
||||
name = "H"
|
||||
color = "#993333"
|
||||
inner_outfits = list(/obj/item/clothing/under/jabroni) //Why not?
|
||||
outer_outfits = list(/obj/item/clothing/suit/toggle/owlwings)
|
||||
|
||||
/datum/team/gang/rigatonifamily
|
||||
name = "Rigatoni family"
|
||||
color = "#cc9900" // p a s t a colored
|
||||
inner_outfits = list(/obj/item/clothing/under/rank/chef)
|
||||
outer_outfits = list(/obj/item/clothing/suit/apron/chef)
|
||||
|
||||
/datum/team/gang/weed
|
||||
name = "Weed"
|
||||
color = "#6cd648"
|
||||
inner_outfits = list(/obj/item/clothing/under/color/darkgreen)
|
||||
outer_outfits = list(/obj/item/clothing/suit/vapeshirt)
|
||||
@@ -0,0 +1,38 @@
|
||||
/obj/effect/decal/cleanable/crayon/Initialize(mapload, main, type, e_name, graf_rot, alt_icon = null)
|
||||
. = ..()
|
||||
if(type == "poseur tag")
|
||||
var/datum/team/gang/gang = pick(subtypesof(/datum/team/gang))
|
||||
var/gangname = initial(gang.name)
|
||||
icon = 'icons/effects/crayondecal.dmi'
|
||||
icon_state = "[gangname]"
|
||||
type = null
|
||||
|
||||
/obj/effect/decal/cleanable/crayon/gang
|
||||
icon = 'icons/effects/crayondecal.dmi'
|
||||
layer = ABOVE_NORMAL_TURF_LAYER //Harder to hide
|
||||
plane = GAME_PLANE
|
||||
do_icon_rotate = FALSE //These are designed to always face south, so no rotation please.
|
||||
var/datum/team/gang/gang
|
||||
|
||||
/obj/effect/decal/cleanable/crayon/gang/Initialize(mapload, datum/team/gang/G, e_name = "gang tag", rotation = 0, mob/user)
|
||||
if(!G)
|
||||
return INITIALIZE_HINT_QDEL
|
||||
gang = G
|
||||
var/newcolor = G.color
|
||||
var/area/territory = get_area(src)
|
||||
icon_state = G.name
|
||||
G.new_territories |= list(territory.type = territory.name)
|
||||
//If this isn't tagged by a specific gangster there's no bonus income.
|
||||
.=..(mapload, newcolor, icon_state, e_name, rotation)
|
||||
|
||||
/obj/effect/decal/cleanable/crayon/gang/Destroy()
|
||||
if(gang)
|
||||
var/area/territory = get_area(src)
|
||||
gang.territories -= territory.type
|
||||
gang.new_territories -= territory.type
|
||||
gang.lost_territories |= list(territory.type = territory.name)
|
||||
gang = null
|
||||
return ..()
|
||||
|
||||
/obj/effect/decal/cleanable/crayon/NeverShouldHaveComeHere(turf/T)
|
||||
return isspaceturf(T) || islava(T) || istype(T, /turf/open/water) || ischasm(T)
|
||||
@@ -0,0 +1,34 @@
|
||||
/datum/atom_hud/antag/gang
|
||||
var/color = null
|
||||
|
||||
/datum/atom_hud/antag/gang/add_to_hud(atom/A)
|
||||
if(!A)
|
||||
return
|
||||
var/image/holder = A.hud_list[ANTAG_HUD]
|
||||
if(holder)
|
||||
holder.color = color
|
||||
..()
|
||||
|
||||
/datum/atom_hud/antag/gang/remove_from_hud(atom/A)
|
||||
if(!A)
|
||||
return
|
||||
var/image/holder = A.hud_list[ANTAG_HUD]
|
||||
if(holder)
|
||||
holder.color = null
|
||||
..()
|
||||
|
||||
/datum/atom_hud/antag/gang/join_hud(mob/M)
|
||||
if(!istype(M))
|
||||
CRASH("join_hud(): [M] ([M.type]) is not a mob!")
|
||||
var/image/holder = M.hud_list[ANTAG_HUD]
|
||||
if(holder)
|
||||
holder.color = color
|
||||
..()
|
||||
|
||||
/datum/atom_hud/antag/gang/leave_hud(mob/M)
|
||||
if(!istype(M))
|
||||
CRASH("leave_hud(): [M] ([M.type]) is not a mob!")
|
||||
var/image/holder = M.hud_list[ANTAG_HUD]
|
||||
if(holder)
|
||||
holder.color = null
|
||||
..()
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user