Conflict fixes

This commit is contained in:
Artur
2020-04-14 09:27:54 +03:00
720 changed files with 148595 additions and 8360 deletions
+1
View File
@@ -25,6 +25,7 @@
#define GENITAL_CAN_AROUSE (1<<8)
#define GENITAL_UNDIES_HIDDEN (1<<9)
#define UPDATE_OWNER_APPEARANCE (1<<10)
#define GENITAL_CAN_TAUR (1<<11)
#define DEF_VAGINA_SHAPE "Human"
+60 -6
View File
@@ -114,12 +114,17 @@
//slowdown when in softcrit
#define SOFTCRIT_ADD_SLOWDOWN 6
//Attack types for checking shields/hit reactions
#define MELEE_ATTACK 1
#define UNARMED_ATTACK 2
#define PROJECTILE_ATTACK 3
#define THROWN_PROJECTILE_ATTACK 4
#define LEAP_ATTACK 5
/// Attack types for check_block()/run_block(). Flags, combinable.
/// Attack was melee, whether or not armed.
#define ATTACK_TYPE_MELEE (1<<0)
/// Attack was with a gun or something that should count as a gun (but not if a gun shouldn't count for a gun, crazy right?)
#define ATTACK_TYPE_PROJECTILE (1<<1)
/// Attack was unarmed.. this usually means hand to hand combat.
#define ATTACK_TYPE_UNARMED (1<<2)
/// Attack was a thrown atom hitting the victim.
#define ATTACK_TYPE_THROWN (1<<3)
/// Attack was a bodyslam/leap/tackle. See: Xenomorph leap tackles.
#define ATTACK_TYPE_TACKLE (1<<4)
//attack visual effects
#define ATTACK_EFFECT_PUNCH "punch"
@@ -252,4 +257,53 @@ GLOBAL_LIST_INIT(shove_disarming_types, typecacheof(list(
#define BULLET_ACT_FORCE_PIERCE "PIERCE" //It pierces through the object regardless of the bullet being piercing by default.
#define BULLET_ACT_TURF "TURF" //It hit us but it should hit something on the same turf too. Usually used for turfs.
/// Bitflags for check_block() and handle_block(). Meant to be combined. You can be hit and still reflect, for example, if you do not use BLOCK_SUCCESS.
/// Attack was not blocked
#define BLOCK_NONE NONE
/// Attack was blocked, do not do damage. THIS FLAG MUST BE THERE FOR DAMAGE/EFFECT PREVENTION!
#define BLOCK_SUCCESS (1<<1)
/// The below are for "metadata" on "how" the attack was blocked.
/// Attack was and should be redirected according to list argument REDIRECT_METHOD (NOTE: the SHOULD here is important, as it says "the thing blocking isn't handling the reflecting for you so do it yourself"!)
#define BLOCK_SHOULD_REDIRECT (1<<2)
/// Attack was redirected (whether by us or by SHOULD_REDIRECT flagging for automatic handling)
#define BLOCK_REDIRECTED (1<<3)
/// Attack was blocked by something like a shield.
#define BLOCK_PHYSICAL_EXTERNAL (1<<4)
/// Attack was blocked by something worn on you.
#define BLOCK_PHYSICAL_INTERNAL (1<<5)
/// Attack outright missed because the target dodged. Should usually be combined with redirection passthrough or something (see martial arts)
#define BLOCK_TARGET_DODGED (1<<7)
/// Meta-flag for run_block/do_run_block : By default, BLOCK_SUCCESS tells do_run_block() to assume the attack is completely blocked and not continue the block chain. If this is present, it will continue to check other items in the chain rather than stopping.
#define BLOCK_CONTINUE_CHAIN (1<<8)
/// For keys in associative list/block_return as we don't want to saturate our (somewhat) limited flags.
#define BLOCK_RETURN_REDIRECT_METHOD "REDIRECT_METHOD"
/// Pass through victim
#define REDIRECT_METHOD_PASSTHROUGH "passthrough"
/// Deflect at randomish angle
#define REDIRECT_METHOD_DEFLECT "deflect"
/// reverse 180 angle, basically (as opposed to "realistic" wall reflections)
#define REDIRECT_METHOD_REFLECT "reflect"
/// "do not taser the bad man with the desword" - actually aims at the firer/attacker rather than just reversing
#define REDIRECT_METHOD_RETURN_TO_SENDER "no_you"
/// These keys are generally only applied to the list if real_attack is FALSE. Used incase we want to make "smarter" mob AI in the future or something.
/// Tells the caller how likely from 0 (none) to 100 (always) we are to reflect energy projectiles
#define BLOCK_RETURN_REFLECT_PROJECTILE_CHANCE "reflect_projectile_chance"
/// Tells the caller how likely we are to block attacks from 0 to 100 in general
#define BLOCK_RETURN_NORMAL_BLOCK_CHANCE "normal_block_chance"
/// Tells the caller about how many hits we can soak on average before our blocking fails.
#define BLOCK_RETURN_BLOCK_CAPACITY "block_capacity"
/// Default if the above isn't set in the list.
#define DEFAULT_REDIRECT_METHOD_PROJECTILE REDIRECT_METHOD_DEFLECT
/// Block priorities
#define BLOCK_PRIORITY_HELD_ITEM 100
#define BLOCK_PRIORITY_CLOTHING 50
#define BLOCK_PRIORITY_WEAR_SUIT 75
#define BLOCK_PRIORITY_UNIFORM 25
#define BLOCK_PRIORITY_DEFAULT BLOCK_PRIORITY_HELD_ITEM
+14
View File
@@ -39,3 +39,17 @@
//Ouch my toes!
#define CALTROP_BYPASS_SHOES 1
#define CALTROP_IGNORE_WALKERS 2
#define SPELL_SKIP_ALL_REQS (1<<0)
#define SPELL_SKIP_CENTCOM (1<<1)
#define SPELL_SKIP_STAT (1<<2)
#define SPELL_SKIP_CLOTHES (1<<3)
#define SPELL_SKIP_ANTIMAGIC (1<<4)
#define SPELL_SKIP_VOCAL (1<<5)
#define SPELL_SKIP_MOBTYPE (1<<6)
#define SPELL_WIZARD_HAT (1<<7)
#define SPELL_WIZARD_ROBE (1<<8)
#define SPELL_CULT_HELMET (1<<9)
#define SPELL_CULT_ARMOR (1<<10)
#define SPELL_WIZARD_GARB (SPELL_WIZARD_HAT|SPELL_WIZARD_ROBE)
#define SPELL_CULT_GARB (SPELL_CULT_HELMET|SPELL_CULT_ARMOR)
+12 -1
View File
@@ -149,7 +149,9 @@
#define COMSIG_MOB_DEATH "mob_death" //from base of mob/death(): (gibbed)
#define COMPONENT_BLOCK_DEATH_BROADCAST 1 //stops the death from being broadcasted in deadchat.
#define COMSIG_MOB_GHOSTIZE "mob_ghostize" //from base of mob/Ghostize(): (can_reenter_corpse, special, penalize)
#define COMPONENT_BLOCK_GHOSTING 1
#define COMPONENT_BLOCK_GHOSTING (1<<0)
#define COMPONENT_DO_NOT_PENALIZE_GHOSTING (1<<1)
#define COMPONENT_FREE_GHOSTING (1<<2)
#define COMSIG_MOB_ALLOWED "mob_allowed" //from base of obj/allowed(mob/M): (/obj) returns bool, if TRUE the mob has id access to the obj
#define COMSIG_MOB_RECEIVE_MAGIC "mob_receive_magic" //from base of mob/anti_magic_check(): (mob/user, magic, holy, tinfoil, chargecost, self, protection_sources)
#define COMPONENT_BLOCK_MAGIC 1
@@ -177,6 +179,8 @@
// #define SPEECH_FORCED 7
#define COMSIG_MOB_ANTAG_ON_GAIN "mob_antag_on_gain" //from base of /datum/antagonist/on_gain(): (antag_datum)
#define COMSIG_MOB_SPELL_CAN_CAST "mob_spell_can_cast" //called from base of /obj/effect/proc_holder/spell/can_cast(): (spell)
// /mob/living signals
#define COMSIG_LIVING_REGENERATE_LIMBS "living_regenerate_limbs" //from base of /mob/living/regenerate_limbs(): (noheal, excluded_limbs)
#define COMSIG_LIVING_RESIST "living_resist" //from base of mob/living/resist() (/mob/living)
@@ -188,6 +192,8 @@
#define COMSIG_MOB_CLIENT_LOGIN "comsig_mob_client_login" //sent when a mob/login() finishes: (client)
#define COMSIG_MOB_CLIENT_MOVE "comsig_mob_client_move" //sent when client/Move() finishes with no early returns: (client, direction, n, oldloc)
#define COMSIG_LIVING_GUN_PROCESS_FIRE "living_gun_process_fire" //from base of /obj/item/gun/proc/process_fire(): (atom/target, params, zone_override)
// This returns flags as defined for block in __DEFINES/combat.dm!
#define COMSIG_LIVING_RUN_BLOCK "living_do_run_block" //from base of mob/living/do_run_block(): (real_attack, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone)
#define COMSIG_LIVING_COMBAT_ENABLED "combatmode_enabled" //from base of mob/living/enable_combat_mode() (was_forced)
#define COMSIG_LIVING_COMBAT_DISABLED "combatmode_disabled" //from base of mob/living/disable_combat_mode() (was_forced)
@@ -236,9 +242,14 @@
#define COMSIG_ITEM_IMBUE_SOUL "item_imbue_soul" //return a truthy value to prevent ensouling, checked in /obj/effect/proc_holder/spell/targeted/lichdom/cast(): (mob/user)
#define COMSIG_ITEM_HIT_REACT "item_hit_react" //from base of obj/item/hit_reaction(): (list/args)
#define COMSIG_ITEM_WEARERCROSSED "wearer_crossed" //called on item when crossed by something (): (/atom/movable)
#define COMSIG_ITEM_WORN_OVERLAYS "item_worn_overlays" //from base of obj/item/worn_overlays(): (isinhands, icon_file, used_state, style_flags, list/overlays)
// THE FOLLOWING TWO BLOCKS SHOULD RETURN BLOCK FLAGS AS DEFINED IN __DEFINES/combat.dm!
#define COMSIG_ITEM_CHECK_BLOCK "check_block" //from base of obj/item/check_block(): (mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
#define COMSIG_ITEM_RUN_BLOCK "run_block" //from base of obj/item/run_block(): (mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
// /obj/item/clothing signals
#define COMSIG_SHOES_STEP_ACTION "shoes_step_action" //from base of obj/item/clothing/shoes/proc/step_action(): ()
#define COMSIG_SUIT_MADE_HELMET "suit_made_helmet" //from base of obj/item/clothing/suit/MakeHelmet(): (helmet)
// /obj/item/implant signals
#define COMSIG_IMPLANT_ACTIVATED "implant_activated" //from base of /obj/item/implant/proc/activate(): ()
+28
View File
@@ -0,0 +1,28 @@
#define DYE_REGISTRY_UNDER "under"
#define DYE_REGISTRY_JUMPSKIRT "jumpskirt"
#define DYE_REGISTRY_GLOVES "gloves"
#define DYE_REGISTRY_SNEAKERS "sneakers"
#define DYE_REGISTRY_FANNYPACK "fannypack"
#define DYE_REGISTRY_BEDSHEET "bedsheet"
#define DYE_RED "red"
#define DYE_ORANGE "orange"
#define DYE_YELLOW "yellow"
#define DYE_GREEN "green"
#define DYE_BLUE "blue"
#define DYE_PURPLE "purple"
#define DYE_BLACK "black"
#define DYE_WHITE "white"
#define DYE_RAINBOW "rainbow"
#define DYE_MIME "mime"
#define DYE_COSMIC "cosmic"
#define DYE_QM "qm"
#define DYE_LAW "law"
#define DYE_CAPTAIN "captain"
#define DYE_HOP "hop"
#define DYE_HOS "hos"
#define DYE_CE "ce"
#define DYE_RD "rd"
#define DYE_CMO "cmo"
#define DYE_REDCOAT "redcoat"
#define DYE_CLOWN "clown"
+1
View File
@@ -7,6 +7,7 @@
#define WAROPS_ALWAYS_ALLOWED (1<<1)
#define USE_PREF_WEIGHTS (1<<2)
#define FORCE_IF_WON (1<<3)
#define USE_PREV_ROUND_WEIGHTS (1<<4)
#define ONLY_RULESET (1<<0)
#define HIGHLANDER_RULESET (1<<1)
+29
View File
@@ -0,0 +1,29 @@
#define INSTRUMENT_MIN_OCTAVE 1
#define INSTRUMENT_MAX_OCTAVE 9
#define INSTRUMENT_MIN_KEY 0
#define INSTRUMENT_MAX_KEY 127
/// Max number of playing notes per instrument.
#define CHANNELS_PER_INSTRUMENT 128
/// Distance multiplier that makes us not be impacted by 3d sound as much. This is a multiplier so lower it is the closer we will pretend to be to people.
#define INSTRUMENT_DISTANCE_FALLOFF_BUFF 0.2
/// How many tiles instruments have no falloff for
#define INSTRUMENT_DISTANCE_NO_FALLOFF 3
/// Maximum length a note should ever go for
#define INSTRUMENT_MAX_TOTAL_SUSTAIN (5 SECONDS)
/// These are per decisecond.
#define INSTRUMENT_EXP_FALLOFF_MIN 1.025 //100/(1.025^50) calculated for [INSTRUMENT_MIN_SUSTAIN_DROPOFF] to be 30.
#define INSTRUMENT_EXP_FALLOFF_MAX 10
/// Minimum volume for when the sound is considered dead.
#define INSTRUMENT_MIN_SUSTAIN_DROPOFF 0
#define SUSTAIN_LINEAR 1
#define SUSTAIN_EXPONENTIAL 2
// /datum/instrument instrument_flags
#define INSTRUMENT_LEGACY (1<<0) //Legacy instrument. Implies INSTRUMENT_DO_NOT_AUTOSAMPLE
#define INSTRUMENT_DO_NOT_AUTOSAMPLE (1<<1) //Do not automatically sample
+1 -1
View File
@@ -465,7 +465,7 @@ GLOBAL_LIST_INIT(pda_reskins, list(PDA_SKIN_CLASSIC = 'icons/obj/pda.dmi', PDA_S
#define EGG_LAYING_MESSAGES list("lays an egg.","squats down and croons.","begins making a huge racket.","begins clucking raucously.")
// list of all null rod weapons
#define HOLY_WEAPONS /obj/item/nullrod, /obj/item/twohanded/dualsaber/hypereutactic/chaplain, /obj/item/gun/energy/laser/redtag/hitscan/chaplain, /obj/item/multitool/chaplain, /obj/item/melee/baseball_bat/chaplain
#define HOLY_WEAPONS /obj/item/nullrod, /obj/item/twohanded/dualsaber/hypereutactic/chaplain, /obj/item/gun/energy/laser/redtag/hitscan/chaplain, /obj/item/multitool/chaplain, /obj/item/clothing/gloves/fingerless/pugilist/chaplain, /obj/item/melee/baseball_bat/chaplain
// Used by PDA and cartridge code to reduce repetitiveness of spritesheets
#define PDAIMG(what) {"<span class="pda16x16 [#what]"></span>"}
+3 -1
View File
@@ -78,4 +78,6 @@
#define MOVESPEED_ID_COLD "COLD"
#define MOVESPEED_ID_HUNGRY "HUNGRY"
#define MOVESPEED_ID_DAMAGE_SLOWDOWN "DAMAGE"
#define MOVESPEED_ID_DAMAGE_SLOWDOWN_FLYING "FLYING"
#define MOVESPEED_ID_DAMAGE_SLOWDOWN_FLYING "FLYING"
#define MOVESPEED_ID_CIRRHOSIS "CIRRHOSIS"
+3 -3
View File
@@ -45,9 +45,9 @@ Ask ninjanomnom if they're around
// WARNING: The deines below could have disastrous consequences if tweaked incorrectly. See: The great SM purge of Oct.6.2017
// contamination_chance = (strength-RAD_MINIMUM_CONTAMINATION) * RAD_CONTAMINATION_CHANCE_COEFFICIENT * min(1/(steps*RAD_DISTANCE_COEFFICIENT), 1))
// contamination_strength = (strength-RAD_MINIMUM_CONTAMINATION) * RAD_CONTAMINATION_STR_COEFFICIENT
#define RAD_MINIMUM_CONTAMINATION 350 // How strong does a radiation wave have to be to contaminate objects
#define RAD_MINIMUM_CONTAMINATION 300 // How strong does a radiation wave have to be to contaminate objects
#define RAD_CONTAMINATION_CHANCE_COEFFICIENT 0.005 // Higher means higher strength scaling contamination chance
#define RAD_CONTAMINATION_STR_COEFFICIENT 0.3 // Higher means higher strength scaling contamination strength
#define RAD_CONTAMINATION_STR_COEFFICIENT 0.99 // Higher means higher strength scaling contamination strength
#define RAD_DISTANCE_COEFFICIENT 1 // Lower means further rad spread
#define RAD_HALF_LIFE 90 // The half-life of contaminated objects
#define RAD_HALF_LIFE 90 // The half-life of contaminated objects
+1
View File
@@ -20,6 +20,7 @@
#define CHANNEL_HIGHEST_AVAILABLE 1008 //CIT CHANGE - COMPENSATES FOR VORESOUND CHANNELS
#define MAX_INSTRUMENT_CHANNELS (128 * 6)
#define SOUND_MINIMUM_PRESSURE 10
#define FALLOFF_SOUNDS 1
+1 -1
View File
@@ -99,7 +99,7 @@
#define STATUS_EFFECT_PENIS_ENLARGEMENT /datum/status_effect/chem/penis_enlarger //More applied slowdown, just like the above.
#define STATUS_EFFECT_NO_COMBAT_MODE /datum/status_effect/no_combat_mode //Wont allow combat mode and will disable it
#define STATUS_EFFECT_MESMERIZE /datum/status_effect/no_combat_mode/mesmerize //Just reskinned no_combat_mode
#define STATUS_EFFECT_MESMERIZE /datum/status_effect/mesmerize //Just reskinned no_combat_mode
#define STATUS_EFFECT_ELECTROSTAFF /datum/status_effect/electrostaff //slows down victim
+8 -5
View File
@@ -50,17 +50,19 @@
#define INIT_ORDER_PROFILER 100
#define INIT_ORDER_FAIL2TOPIC 99
#define INIT_ORDER_TITLE 98
#define INIT_ORDER_GARBAGE 97
#define INIT_ORDER_DBCORE 95
#define INIT_ORDER_BLACKBOX 94
#define INIT_ORDER_SERVER_MAINT 93
#define INIT_ORDER_INPUT 85
#define INIT_ORDER_GARBAGE 95
#define INIT_ORDER_DBCORE 93
#define INIT_ORDER_BLACKBOX 92
#define INIT_ORDER_SERVER_MAINT 91
#define INIT_ORDER_INPUT 90
#define INIT_ORDER_SOUNDS 85
#define INIT_ORDER_VIS 80
#define INIT_ORDER_RESEARCH 75
#define INIT_ORDER_EVENTS 70
#define INIT_ORDER_JOBS 65
#define INIT_ORDER_QUIRKS 60
#define INIT_ORDER_TICKER 55
#define INIT_ORDER_INSTRUMENTS 53
#define INIT_ORDER_MAPPING 50
#define INIT_ORDER_NETWORKS 45
#define INIT_ORDER_ATOMS 30
@@ -100,6 +102,7 @@
#define FIRE_PRIORITY_PROCESS 25
#define FIRE_PRIORITY_THROWING 25
#define FIRE_PRIORITY_SPACEDRIFT 30
#define FIRE_PRIORITY_INSTRUMENTS 30
#define FIRE_PRIORITY_FIELDS 30
#define FIRE_PRIOTITY_SMOOTHING 35
#define FIRE_PRIORITY_NETWORKS 40
+8 -1
View File
@@ -147,6 +147,9 @@
#define TRAIT_NOPULSE "nopulse" // Your heart doesn't beat.
#define TRAIT_EXEMPT_HEALTH_EVENTS "exempt-health-events"
#define TRAIT_NO_MIDROUND_ANTAG "no-midround-antag" //can't be turned into an antag by random events
#define TRAIT_PUGILIST "pugilist" //This guy punches people for a living
#define TRAIT_KI_VAMPIRE "ki-vampire" //when someone with this trait rolls maximum damage on a punch and stuns the target, they regain some stamina and do clone damage
#define TRAIT_PASSTABLE "passtable"
// mobility flag traits
// IN THE FUTURE, IT WOULD BE NICE TO DO SOMETHING SIMILAR TO https://github.com/tgstation/tgstation/pull/48923/files (ofcourse not nearly the same because I have my.. thoughts on it)
@@ -173,6 +176,9 @@
//non-mob traits
#define TRAIT_PARALYSIS "paralysis" //Used for limb-based paralysis, where replacing the limb will fix it
#define VEHICLE_TRAIT "vehicle" // inherited from riding vehicles
#define INNATE_TRAIT "innate"
// item traits
#define TRAIT_NODROP "nodrop"
@@ -236,8 +242,8 @@
#define GHOSTROLE_TRAIT "ghostrole"
#define APHRO_TRAIT "aphro"
#define BLOODSUCKER_TRAIT "bloodsucker"
#define CLOTHING_TRAIT "clothing" //used for quirky carrygloves
#define SHOES_TRAIT "shoes" //inherited from your sweet kicks
#define GLOVE_TRAIT "glove" //inherited by your cool gloves
// unique trait sources, still defines
#define STATUE_MUTE "statue"
@@ -271,6 +277,7 @@
#define LOCKED_HELMET_TRAIT "locked-helmet"
#define NINJA_SUIT_TRAIT "ninja-suit"
#define ANTI_DROP_IMPLANT_TRAIT "anti-drop-implant"
#define MARTIAL_ARTIST_TRAIT "martial_artist"
#define SLEEPING_CARP_TRAIT "sleeping_carp"
#define RISING_BASS_TRAIT "rising_bass"
#define ABDUCTOR_ANTAGONIST "abductor-antagonist"
+102
View File
@@ -19,3 +19,105 @@
#define VV_RESTORE_DEFAULT "Restore to Default"
#define VV_MARKED_DATUM "Marked Datum"
#define VV_BITFIELD "Bitfield"
#define VV_TEXT_LOCATE "Custom Reference Locate"
#define VV_PROCCALL_RETVAL "Return Value of Proccall"
#define VV_MSG_MARKED "<br><font size='1' color='red'><b>Marked Object</b></font>"
#define VV_MSG_EDITED "<br><font size='1' color='red'><b>Var Edited</b></font>"
#define VV_MSG_DELETED "<br><font size='1' color='red'><b>Deleted</b></font>"
#define VV_NORMAL_LIST_NO_EXPAND_THRESHOLD 50
#define VV_SPECIAL_LIST_NO_EXPAND_THRESHOLD 150
//#define IS_VALID_ASSOC_KEY(V) (istext(V) || ispath(V) || isdatum(V) || islist(V))
#define IS_VALID_ASSOC_KEY(V) (!isnum(V)) //hhmmm..
//General helpers
#define VV_HREF_TARGET_INTERNAL(target, href_key) "?_src_=vars;[HrefToken()];[href_key]=TRUE;[VV_HK_TARGET]=[REF(target)]"
#define VV_HREF_TARGETREF_INTERNAL(targetref, href_key) "?_src_=vars;[HrefToken()];[href_key]=TRUE;[VV_HK_TARGET]=[targetref]"
#define VV_HREF_TARGET(target, href_key, text) "<a href='[VV_HREF_TARGET_INTERNAL(target, href_key)]'>[text]</a>"
#define VV_HREF_TARGETREF(targetref, href_key, text) "<a href='[VV_HREF_TARGETREF_INTERNAL(targetref, href_key)]'>[text]</a>"
#define VV_HREF_TARGET_1V(target, href_key, text, varname) "<a href='[VV_HREF_TARGET_INTERNAL(target, href_key)];[VV_HK_VARNAME]=[varname]'>[text]</a>" //for stuff like basic varedits, one variable
#define VV_HREF_TARGETREF_1V(targetref, href_key, text, varname) "<a href='[VV_HREF_TARGETREF_INTERNAL(targetref, href_key)];[VV_HK_VARNAME]=[varname]'>[text]</a>"
#define GET_VV_TARGET locate(href_list[VV_HK_TARGET])
#define GET_VV_VAR_TARGET href_list[VV_HK_VARNAME]
//Helper for getting something to vv_do_topic in general
#define VV_TOPIC_LINK(datum, href_key, text) "<a href='?_src_=vars;[HrefToken()];[href_key]=TRUE;target=[REF(datum)]'>text</a>"
//Helpers for vv_get_dropdown()
#define VV_DROPDOWN_OPTION(href_key, name) . += "<option value='?_src_=vars;[HrefToken()];[href_key]=TRUE;target=[REF(src)]'>[name]</option>"
// VV HREF KEYS
#define VV_HK_TARGET "target"
#define VV_HK_VARNAME "targetvar" //name or index of var for 1 variable targetting hrefs.
// vv_do_list() keys
#define VV_HK_LIST_ADD "listadd"
#define VV_HK_LIST_EDIT "listedit"
#define VV_HK_LIST_CHANGE "listchange"
#define VV_HK_LIST_REMOVE "listremove"
#define VV_HK_LIST_ERASE_NULLS "listnulls"
#define VV_HK_LIST_ERASE_DUPES "listdupes"
#define VV_HK_LIST_SHUFFLE "listshuffle"
#define VV_HK_LIST_SET_LENGTH "listlen"
// vv_do_basic() keys
#define VV_HK_BASIC_EDIT "datumedit"
#define VV_HK_BASIC_CHANGE "datumchange"
#define VV_HK_BASIC_MASSEDIT "massedit"
// /datum
#define VV_HK_DELETE "delete"
#define VV_HK_EXPOSE "expose"
#define VV_HK_CALLPROC "proc_call"
#define VV_HK_MARK "mark"
#define VV_HK_MODIFY_TRAITS "modtraits"
// /atom
#define VV_HK_MODIFY_TRANSFORM "atom_transform"
#define VV_HK_ADD_REAGENT "addreagent"
#define VV_HK_TRIGGER_EMP "empulse"
#define VV_HK_TRIGGER_EXPLOSION "explode"
#define VV_HK_AUTO_RENAME "auto_rename"
// /obj
#define VV_HK_OSAY "osay"
#define VV_HK_MASS_DEL_TYPE "mass_delete_type"
#define VV_HK_ARMOR_MOD "mod_obj_armor"
// /mob
#define VV_HK_GIB "gib"
#define VV_HK_GIVE_SPELL "give_spell"
#define VV_HK_REMOVE_SPELL "remove_spell"
#define VV_HK_GIVE_DISEASE "give_disease"
#define VV_HK_GODMODE "godmode"
#define VV_HK_DROP_ALL "dropall"
#define VV_HK_REGEN_ICONS "regen_icons"
#define VV_HK_PLAYER_PANEL "player_panel"
#define VV_HK_BUILDMODE "buildmode"
#define VV_HK_DIRECT_CONTROL "direct_control"
#define VV_HK_OFFER_GHOSTS "offer_ghosts"
// /mob/living/carbon
#define VV_HK_MAKE_AI "aiify"
#define VV_HK_MODIFY_BODYPART "mod_bodypart"
#define VV_HK_MODIFY_ORGANS "organs_modify"
#define VV_HK_HALLUCINATION "force_hallucinate"
#define VV_HK_MARTIAL_ART "give_martial_art"
#define VV_HK_GIVE_TRAUMA "give_trauma"
#define VV_HK_CURE_TRAUMA "cure_trauma"
// /mob/living/carbon/human
#define VV_HK_COPY_OUTFIT "copy_outfit"
#define VV_HK_MOD_QUIRKS "quirkmod"
#define VV_HK_MAKE_MONKEY "human_monkify"
#define VV_HK_MAKE_CYBORG "human_cyborgify"
#define VV_HK_MAKE_SLIME "human_slimeify"
#define VV_HK_MAKE_ALIEN "human_alienify"
#define VV_HK_SET_SPECIES "setspecies"
#define VV_HK_PURRBATION "purrbation"
// misc
#define VV_HK_SPACEVINE_PURGE "spacevine_purge"
+1 -1
View File
@@ -112,7 +112,7 @@ GLOBAL_VAR_INIT(miscreants_allowed, FALSE)
set desc = "Toggles seeing LocalOutOfCharacter chat"
prefs.chat_toggles ^= CHAT_LOOC
prefs.save_preferences()
src << "You will [(prefs.chat_toggles & CHAT_LOOC) ? "now" : "no longer"] see messages on the LOOC channel."
to_chat(src, "You will [(prefs.chat_toggles & CHAT_LOOC) ? "now" : "no longer"] see messages on the LOOC channel.")
SSblackbox.record_feedback("tally", "admin_verb", 1, "TLOOC") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/mob/living/carbon/proc/has_penis()
+21
View File
@@ -550,6 +550,27 @@
for(var/thing in flat_list)
.[thing] = TRUE
/proc/deep_list2params(list/deep_list)
var/list/L = list()
for(var/i in deep_list)
var/key = i
if(isnum(key))
L += "[key]"
continue
if(islist(key))
key = deep_list2params(key)
else if(!istext(key))
key = "[REF(key)]"
L += "[key]"
var/value = deep_list[key]
if(!isnull(value))
if(islist(value))
value = deep_list2params(value)
else if(!(istext(key) || isnum(key)))
value = "[REF(value)]"
L["[key]"] = "[value]"
return list2params(L)
//Picks from the list, with some safeties, and returns the "default" arg if it fails
#define DEFAULTPICK(L, default) ((islist(L) && length(L)) ? pick(L) : default)
+4 -1
View File
@@ -116,4 +116,7 @@ GLOBAL_VAR_INIT(cmp_field, "name")
if(a_sign != b_sign)
return a_sign - b_sign
else
return sorttext(b_name, a_name)
return sorttext(b_name, a_name)
/proc/cmp_item_block_priority_asc(obj/item/A, obj/item/B)
return A.block_priority - B.block_priority
+2 -3
View File
@@ -425,8 +425,7 @@
candidates -= M
/proc/pollGhostCandidates(Question, jobbanType, datum/game_mode/gametypeCheck, be_special_flag = 0, poll_time = 300, ignore_category = null, flashwindow = TRUE)
var/datum/element/ghost_role_eligibility/eligibility = SSdcs.GetElement(list(/datum/element/ghost_role_eligibility))
var/list/candidates = eligibility.get_all_ghost_role_eligible()
var/list/candidates = get_all_ghost_role_eligible()
return pollCandidates(Question, jobbanType, gametypeCheck, be_special_flag, poll_time, ignore_category, flashwindow, candidates)
/proc/pollCandidates(Question, jobbanType, datum/game_mode/gametypeCheck, be_special_flag = 0, poll_time = 300, ignore_category = null, flashwindow = TRUE, list/group = null)
@@ -581,4 +580,4 @@
var/area/A = C.area
if(GLOB.typecache_powerfailure_safe_areas[A.type])
continue
C.energy_fail(rand(duration_min,duration_max))
C.energy_fail(rand(duration_min,duration_max))
+8
View File
@@ -89,6 +89,14 @@
INVOKE_ASYNC(GLOBAL_PROC, /proc/init_ref_coin_values) //so the current procedure doesn't sleep because of UNTIL()
for(var/path in subtypesof(/area/holodeck))
var/area/holodeck/A = path
var/list/compatibles = initial(A.compatible_holodeck_comps)
if(!compatibles || initial(A.abstract_type) == path)
continue
for(var/comp in compatibles)
LAZYADD(GLOB.holodeck_areas_prototypes[comp], A)
//creates every subtype of prototype (excluding prototype) and adds it to list L.
//if no list/L is provided, one is created.
/proc/init_subtypes(prototype, list/L)
+14
View File
@@ -184,6 +184,7 @@
"cock_length" = COCK_SIZE_DEF,
"cock_diameter_ratio" = COCK_DIAMETER_RATIO_DEF,
"cock_color" = pick("FFFFFF","7F7F7F", "7FFF7F", "7F7FFF", "FF7F7F", "7FFFFF", "FF7FFF", "FFFF7F"),
"cock_taur" = FALSE,
"has_balls" = FALSE,
"balls_color" = pick("FFFFFF","7F7F7F", "7FFF7F", "7F7FFF", "FF7F7F", "7FFFFF", "FF7FFF", "FFFF7F"),
"balls_size" = BALLS_SIZE_DEF,
@@ -579,3 +580,16 @@ GLOBAL_LIST_EMPTY(species_list)
chosen = pick(mob_spawn_meancritters)
var/mob/living/simple_animal/C = new chosen(spawn_location)
return C
/proc/passtable_on(target, source)
var/mob/living/L = target
if(!HAS_TRAIT(L, TRAIT_PASSTABLE) && L.pass_flags & PASSTABLE)
ADD_TRAIT(L, TRAIT_PASSTABLE, INNATE_TRAIT)
ADD_TRAIT(L, TRAIT_PASSTABLE, source)
L.pass_flags |= PASSTABLE
/proc/passtable_off(target, source)
var/mob/living/L = target
REMOVE_TRAIT(L, TRAIT_PASSTABLE, source)
if(!HAS_TRAIT(L, TRAIT_PASSTABLE))
L.pass_flags &= ~PASSTABLE
+18 -8
View File
@@ -25,8 +25,22 @@
/proc/radiation_pulse(atom/source, intensity, range_modifier, log=FALSE, can_contaminate=TRUE)
if(!SSradiation.can_fire)
return
for(var/dir in GLOB.cardinals)
new /datum/radiation_wave(source, dir, intensity, range_modifier, can_contaminate)
var/area/A = get_area(source)
var/atom/nested_loc = source.loc
var/spawn_waves = TRUE
while(nested_loc != A)
if(nested_loc.rad_flags & RAD_PROTECT_CONTENTS)
spawn_waves = FALSE
break
nested_loc = nested_loc.loc
if(spawn_waves)
for(var/dir in GLOB.cardinals)
new /datum/radiation_wave(source, dir, intensity, range_modifier, can_contaminate)
var/static/last_huge_pulse = 0
if(intensity > 3000 && world.time > last_huge_pulse + 200)
last_huge_pulse = world.time
log = TRUE
var/list/things = get_rad_contents(source) //copypasta because I don't want to put special code in waves to handle their origin
for(var/k in 1 to things.len)
@@ -35,11 +49,7 @@
continue
thing.rad_act(intensity)
var/static/last_huge_pulse = 0
if(intensity > 3000 && world.time > last_huge_pulse + 200)
last_huge_pulse = world.time
log = TRUE
if(log)
var/turf/_source_T = isturf(source) ? source : get_turf(source)
log_game("Radiation pulse with intensity: [intensity] and range modifier: [range_modifier] in [loc_name(_source_T)] ")
var/turf/_source_T = get_turf(source)
log_game("Radiation pulse with intensity: [intensity] and range modifier: [range_modifier] in [loc_name(_source_T)][spawn_waves ? "" : " (contained by [nested_loc.name])"]")
return TRUE
+3 -1
View File
@@ -320,8 +320,10 @@
parts += "[FOURSPACES]<i>Nobody died this shift!</i>"
if(istype(SSticker.mode, /datum/game_mode/dynamic))
var/datum/game_mode/dynamic/mode = SSticker.mode
mode.update_playercounts()
parts += "[FOURSPACES]Final threat level: [mode.threat_level]"
parts += "[FOURSPACES]Final threat: [mode.threat]"
parts += "[FOURSPACES]Average threat: [mode.threat_average]"
parts += "[FOURSPACES]Executed rules:"
for(var/datum/dynamic_ruleset/rule in mode.executed_rules)
parts += "[FOURSPACES][FOURSPACES][rule.ruletype] - <b>[rule.name]</b>: -[rule.cost + rule.scaled_times * rule.scaling_cost] threat"
@@ -511,7 +513,7 @@
if(owner && GLOB.common_report && SSticker.current_state == GAME_STATE_FINISHED)
SSticker.show_roundend_report(owner.client, FALSE)
/datum/action/report/IsAvailable()
/datum/action/report/IsAvailable(silent = FALSE)
return 1
/datum/action/report/Topic(href,href_list)
+2 -1
View File
@@ -25,7 +25,8 @@ GLOBAL_VAR_INIT(midnight_rollovers, 0)
GLOBAL_VAR_INIT(rollovercheck_last_timeofday, 0)
/proc/update_midnight_rollover()
if (world.timeofday < GLOB.rollovercheck_last_timeofday) //TIME IS GOING BACKWARDS!
return GLOB.midnight_rollovers++
GLOB.midnight_rollovers++
GLOB.rollovercheck_last_timeofday = world.timeofday
return GLOB.midnight_rollovers
/proc/weekdayofthemonth()
+60
View File
@@ -0,0 +1,60 @@
/proc/make_types_fancy(var/list/types)
if (ispath(types))
types = list(types)
. = list()
for(var/type in types)
var/typename = "[type]"
var/static/list/TYPES_SHORTCUTS = list(
/obj/effect/decal/cleanable = "CLEANABLE",
/obj/item/radio/headset = "HEADSET",
/obj/item/clothing/head/helmet/space = "SPESSHELMET",
/obj/item/book/manual = "MANUAL",
/obj/item/reagent_containers/food/drinks = "DRINK", //longest paths comes first
/obj/item/reagent_containers/food = "FOOD",
/obj/item/reagent_containers = "REAGENT_CONTAINERS",
/obj/machinery/atmospherics = "ATMOS_MECH",
/obj/machinery/portable_atmospherics = "PORT_ATMOS",
/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack = "MECHA_MISSILE_RACK",
/obj/item/mecha_parts/mecha_equipment = "MECHA_EQUIP",
/obj/item/organ = "ORGAN",
/obj/item = "ITEM",
/obj/machinery = "MACHINERY",
/obj/effect = "EFFECT",
/obj = "O",
/datum = "D",
/turf/open = "OPEN",
/turf/closed = "CLOSED",
/turf = "T",
/mob/living/carbon = "CARBON",
/mob/living/simple_animal = "SIMPLE",
/mob/living = "LIVING",
/mob = "M"
)
for (var/tn in TYPES_SHORTCUTS)
if (copytext(typename,1, length("[tn]/")+1)=="[tn]/" /*findtextEx(typename,"[tn]/",1,2)*/ )
typename = TYPES_SHORTCUTS[tn]+copytext(typename,length("[tn]/"))
break
.[typename] = type
/proc/get_fancy_list_of_atom_types()
var/static/list/pre_generated_list
if (!pre_generated_list) //init
pre_generated_list = make_types_fancy(typesof(/atom))
return pre_generated_list
/proc/get_fancy_list_of_datum_types()
var/static/list/pre_generated_list
if (!pre_generated_list) //init
pre_generated_list = make_types_fancy(sortList(typesof(/datum) - typesof(/atom)))
return pre_generated_list
/proc/filter_fancy_list(list/L, filter as text)
var/list/matches = new
for(var/key in L)
var/value = L[key]
if(findtext("[key]", filter) || findtext("[value]", filter))
matches[key] = value
return matches
-2
View File
@@ -8,10 +8,8 @@
/proc/invertHTML(HTMLstring)
if(!istext(HTMLstring))
CRASH("Given non-text argument!")
return
else if(length(HTMLstring) != 7)
CRASH("Given non-HTML argument!")
return
else if(length_char(HTMLstring) != 7)
CRASH("Given non-hex symbols in argument!")
var/textr = copytext(HTMLstring, 2, 4)
+2
View File
@@ -50,3 +50,5 @@ 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
GLOBAL_LIST_EMPTY(holodeck_areas_prototypes) //List of holodeck area prototypes per holodeck computer type
+1 -1
View File
@@ -14,7 +14,7 @@ GLOBAL_VAR_INIT(fileaccess_timer, 0)
GLOBAL_DATUM_INIT(data_core, /datum/datacore, new)
GLOBAL_VAR_INIT(CELLRATE, 0.002) // conversion ratio between a watt-tick and kilojoule
GLOBAL_VAR_INIT(CELLRATE, 0.002) // conversion ratio between a watt-tick and kilojoule, dimensionless, kilojoules/watt-tick
GLOBAL_VAR_INIT(CHARGELEVEL, 0.001) // Cap for how fast cells charge, as a percentage-per-tick (.001 means cellcharge is capped to 1% per second)
GLOBAL_LIST_EMPTY(powernets)
+1
View File
@@ -49,6 +49,7 @@
message_admins("[ADMIN_LOOKUPFLW(src)] might be running a modified client! (failed can_see on AI click of [A] (Turf Loc: [ADMIN_VERBOSEJMP(pixel_turf)]))")
var/message = "[key_name(src)] might be running a modified client! (failed can_see on AI click of [A] (Turf Loc: [AREACOORD(pixel_turf)]))"
log_admin(message)
to_chat(src, "<span class='warning'>You're experiencing a bug. Reconnect immediately to fix it. Admins have been notified.</span>")
if(REALTIMEOFDAY >= chnotify + 9000)
chnotify = REALTIMEOFDAY
send2irc_adminless_only("NOCHEAT", message)
+1 -1
View File
@@ -334,7 +334,7 @@ or shoot a gun to move around via Newton's 3rd Law of Motion."
return
var/datum/antagonist/cult/antag = mob_viewer.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
if(!antag)
if(!antag?.cult_team)
return
var/datum/objective/sacrifice/sac_objective = locate() in antag.cult_team.objectives
+1 -1
View File
@@ -125,7 +125,7 @@
if(!CHECK_MOBILITY(user, MOBILITY_STAND))
totitemdamage *= 0.5
//CIT CHANGES END HERE
if(user != src && check_shields(I, totitemdamage, "the [I.name]", MELEE_ATTACK, I.armour_penetration))
if((user != src) && run_block(I, totitemdamage, "the [I.name]", ATTACK_TYPE_MELEE, I.armour_penetration, user) & BLOCK_SUCCESS)
return FALSE
send_item_attack_message(I, user)
I.do_stagger_action(src, user)
-2
View File
@@ -27,13 +27,11 @@
var/hook_path = text2path("/hook/[hook]")
if(!hook_path)
CRASH("Invalid hook '/hook/[hook]' called.")
return 0
var/caller = new hook_path
var/status = 1
for(var/P in typesof("[hook_path]/proc"))
if(!call(caller, P)(arglist(args)))
CRASH("Hook '[P]' failed or runtimed.")
status = 0
return status
+8 -2
View File
@@ -38,11 +38,17 @@ PROCESSING_SUBSYSTEM_DEF(dcs)
if(istext(key))
value = arguments[key]
if(!(istext(key) || isnum(key)))
key = REF(key)
if(islist(key)) // CITADEL EDIT
key = deep_list2params(key)
else
key = REF(key)
key = "[key]" // Key is stringified so numbers dont break things
if(!isnull(value))
if(!(istext(value) || isnum(value)))
value = REF(value)
if(islist(value)) // CITADEL EDIT
value = deep_list2params(value)
else
value = REF(value)
named_arguments["[key]"] = value
else
fullid += "[key]"
+8 -5
View File
@@ -21,9 +21,6 @@ SUBSYSTEM_DEF(fail2topic)
DropFirewallRule() // Clear the old bans if any still remain
if (world.system_type == UNIX && enabled)
enabled = FALSE
subsystem_log("DISABLED - UNIX systems are not supported.")
if(!enabled)
flags |= SS_NO_FIRE
can_fire = FALSE
@@ -90,7 +87,10 @@ SUBSYSTEM_DEF(fail2topic)
fail_counts -= ip
rate_limiting -= ip
. = shell("netsh advfirewall firewall add rule name=\"[rule_name]\" dir=in interface=any action=block remoteip=[ip]")
if (world.system_type == UNIX)
. = shell("iptables -A [rule_name] -s [ip] -j DROP")
else
. = shell("netsh advfirewall firewall add rule name=\"[rule_name]\" dir=in interface=any action=block remoteip=[ip]")
if (.)
subsystem_log("Failed to ban [ip]. Exit code: [.].")
@@ -105,7 +105,10 @@ SUBSYSTEM_DEF(fail2topic)
active_bans = list()
. = shell("netsh advfirewall firewall delete rule name=\"[rule_name]\"")
if (world.system_type == UNIX)
. = shell("iptables -F [rule_name]") //Let's just assume that folks running linux are smart enough to have a dedicated chain configured for this.
else
. = shell("netsh advfirewall firewall delete rule name=\"[rule_name]\"")
if (.)
subsystem_log("Failed to drop firewall rule. Exit code: [.].")
+5 -1
View File
@@ -14,6 +14,7 @@ SUBSYSTEM_DEF(persistence)
var/list/saved_modes = list(1,2,3)
var/list/saved_dynamic_rules = list(list(),list(),list())
var/list/saved_storytellers = list("foo","bar","baz")
var/list/average_dynamic_threat = 50
var/list/saved_maps
var/list/saved_trophies = list()
var/list/spawned_objects = list()
@@ -191,6 +192,8 @@ SUBSYSTEM_DEF(persistence)
if(!json)
return
saved_storytellers = json["data"]
if(saved_storytellers.len > 3)
average_dynamic_threat = saved_storytellers[4]
saved_storytellers.len = 3
/datum/controller/subsystem/persistence/proc/LoadRecentMaps()
@@ -434,9 +437,10 @@ SUBSYSTEM_DEF(persistence)
saved_storytellers[3] = saved_storytellers[2]
saved_storytellers[2] = saved_storytellers[1]
saved_storytellers[1] = mode.storyteller.name
average_dynamic_threat = (mode.threat_average + average_dynamic_threat) / 2
var/json_file = file("data/RecentStorytellers.json")
var/list/file_data = list()
file_data["data"] = saved_storytellers
file_data["data"] = saved_storytellers + average_dynamic_threat
fdel(json_file)
WRITE_FILE(json_file, json_encode(file_data))
@@ -1,5 +1,4 @@
PROCESSING_SUBSYSTEM_DEF(chemistry)
wait = 5
flags = SS_KEEP_TIMING
name = "Chemistry"
@@ -0,0 +1,43 @@
PROCESSING_SUBSYSTEM_DEF(instruments)
name = "Instruments"
wait = 0.5
init_order = INIT_ORDER_INSTRUMENTS
flags = SS_KEEP_TIMING
priority = FIRE_PRIORITY_INSTRUMENTS
var/static/list/datum/instrument/instrument_data = list() //id = datum
var/static/list/datum/song/songs = list()
var/static/musician_maxlines = 600
var/static/musician_maxlinechars = 300
var/static/musician_hearcheck_mindelay = 5
var/static/max_instrument_channels = MAX_INSTRUMENT_CHANNELS
var/static/current_instrument_channels = 0
/datum/controller/subsystem/processing/instruments/Initialize()
initialize_instrument_data()
return ..()
/datum/controller/subsystem/processing/instruments/proc/on_song_new(datum/song/S)
songs += S
/datum/controller/subsystem/processing/instruments/proc/on_song_del(datum/song/S)
songs -= S
/datum/controller/subsystem/processing/instruments/proc/initialize_instrument_data()
for(var/path in subtypesof(/datum/instrument))
var/datum/instrument/I = path
if(initial(I.abstract_type) == path)
continue
I = new path
I.Initialize()
instrument_data[I.id || "[I.type]"] = I
CHECK_TICK
/datum/controller/subsystem/processing/instruments/proc/get_instrument(id_or_path)
return instrument_data["[id_or_path]"]
/datum/controller/subsystem/processing/instruments/proc/reserve_instrument_channel(datum/instrument/I)
if(current_instrument_channels > max_instrument_channels)
return
. = SSsounds.reserve_sound_channel(I)
if(!isnull(.))
current_instrument_channels++
@@ -1,3 +1,4 @@
PROCESSING_SUBSYSTEM_DEF(status_effects)
wait = 1
flags = SS_TICKER
name = "Status Effects"
@@ -47,7 +47,6 @@ PROCESSING_SUBSYSTEM_DEF(weather)
break
if (!ispath(weather_datum_type, /datum/weather))
CRASH("run_weather called with invalid weather_datum_type: [weather_datum_type || "null"]")
return
if (isnull(z_levels))
z_levels = SSmapping.levels_by_trait(initial(weather_datum_type.target_trait))
@@ -55,7 +54,6 @@ PROCESSING_SUBSYSTEM_DEF(weather)
z_levels = list(z_levels)
else if (!islist(z_levels))
CRASH("run_weather called with invalid z_levels: [z_levels || "null"]")
return
var/datum/weather/W = new weather_datum_type(z_levels)
W.telegraph()
+91
View File
@@ -0,0 +1,91 @@
#define DATUMLESS "NO_DATUM"
SUBSYSTEM_DEF(sounds)
name = "Sounds"
flags = SS_NO_FIRE
init_order = INIT_ORDER_SOUNDS
var/static/using_channels_max = CHANNEL_HIGHEST_AVAILABLE //BYOND max channels
// Hey uh these two needs to be initialized fast because the whole "things get deleted before init" thing.
/// Assoc list, "[channel]" = either the datum using it or TRUE for an unsafe-reserved (datumless reservation) channel
var/list/using_channels = list()
/// Assoc list datum = list(channel1, channel2, ...) for what channels something reserved.
var/list/using_channels_by_datum = list()
/// List of all available channels with associations set to TRUE for fast lookups/allocation.
var/list/available_channels
/datum/controller/subsystem/sounds/Initialize()
setup_available_channels()
return ..()
/datum/controller/subsystem/sounds/proc/setup_available_channels()
available_channels = list()
for(var/i in 1 to using_channels_max)
available_channels[num2text(i)] = TRUE
/// Removes a channel from using list.
/datum/controller/subsystem/sounds/proc/free_sound_channel(channel)
channel = num2text(channel)
var/using = using_channels[channel]
using_channels -= channel
if(using)
using_channels_by_datum[using] -= channel
if(!length(using_channels_by_datum[using]))
using_channels_by_datum -= using
available_channels[channel] = TRUE
/// Frees all the channels a datum is using.
/datum/controller/subsystem/sounds/proc/free_datum_channels(datum/D)
var/list/L = using_channels_by_datum[D]
if(!L)
return
for(var/channel in L)
using_channels -= channel
available_channels[channel] = TRUE
using_channels_by_datum -= D
/// Frees all datumless channels
/datum/controller/subsystem/sounds/proc/free_datumless_channels()
free_datum_channels(DATUMLESS)
/// NO AUTOMATIC CLEANUP - If you use this, you better manually free it later! Returns an integer for channel.
/datum/controller/subsystem/sounds/proc/reserve_sound_channel_datumless()
var/channel = random_available_channel_text()
if(!channel) //oh no..
return FALSE
available_channels -= channel
using_channels[channel] = DATUMLESS
LAZYINITLIST(using_channels_by_datum[DATUMLESS])
using_channels_by_datum[DATUMLESS] += channel
return text2num(channel)
/// Reserves a channel for a datum. Automatic cleanup only when the datum is deleted. Returns an integer for channel.
/datum/controller/subsystem/sounds/proc/reserve_sound_channel(datum/D)
if(!D) //i don't like typechecks but someone will fuck it up
CRASH("Attempted to reserve sound channel without datum using the managed proc.")
var/channel = random_available_channel_text()
if(!channel)
return FALSE
available_channels -= channel
using_channels[channel] = D
LAZYINITLIST(using_channels_by_datum[D])
using_channels_by_datum[D] += channel
return text2num(channel)
/// Random available channel, returns text.
/datum/controller/subsystem/sounds/proc/random_available_channel_text()
return pick(available_channels)
/// Random available channel, returns number
/datum/controller/subsystem/sounds/proc/random_available_channel()
return text2num(pick(available_channels))
/// If a channel is available
/datum/controller/subsystem/sounds/proc/is_channel_available(channel)
return available_channels[num2text(channel)]
/// How many channels we have left.
/datum/controller/subsystem/sounds/proc/available_channels_left()
return length(available_channels)
#undef DATUMLESS
+1 -1
View File
@@ -172,7 +172,7 @@ SUBSYSTEM_DEF(traumas)
/obj/item/ammo_box/magazine/pistolm9mm, /obj/item/ammo_box/a357, /obj/item/ammo_box/magazine/m12g, /obj/item/ammo_box/magazine/mm195x129, /obj/item/antag_spawner/nuke_ops, /obj/mecha/combat/gygax/dark, /obj/mecha/combat/marauder/mauler, /obj/item/soap/syndie, /obj/item/gun/syringe/syndicate, /obj/item/cartridge/virus/syndicate,
/obj/item/cartridge/virus/frame, /obj/item/chameleon, /obj/item/storage/box/syndie_kit/cutouts, /obj/item/clothing/suit/space/hardsuit/syndi, /obj/item/card/emag, /obj/item/storage/toolbox/syndicate, /obj/item/storage/book/bible/syndicate, /obj/item/encryptionkey/binary, /obj/item/encryptionkey/syndicate, /obj/item/aiModule/syndicate,
/obj/item/clothing/shoes/magboots/syndie, /obj/item/powersink, /obj/item/sbeacondrop, /obj/item/sbeacondrop/bomb, /obj/item/syndicatedetonator, /obj/item/shield/energy, /obj/item/assault_pod, /obj/item/slimepotion/slime/sentience/nuclear, /obj/item/stack/telecrystal, /obj/item/jammer, /obj/item/codespeak_manual/unlimited,
/obj/item/toy/cards/deck/syndicate, /obj/item/storage/secure/briefcase/syndie, /obj/item/storage/fancy/cigarettes/cigpack_syndicate, /obj/item/toy/syndicateballoon, /obj/item/clothing/gloves/rapid, /obj/item/paper/fluff/ruins/thederelict/syndie_mission, /obj/item/organ/cyberimp/eyes/hud/security/syndicate, /obj/item/clothing/head/HoS/syndicate,
/obj/item/toy/cards/deck/syndicate, /obj/item/storage/secure/briefcase/syndie, /obj/item/storage/fancy/cigarettes/cigpack_syndicate, /obj/item/toy/syndicateballoon, /obj/item/clothing/gloves/fingerless/pugilist/rapid, /obj/item/paper/fluff/ruins/thederelict/syndie_mission, /obj/item/organ/cyberimp/eyes/hud/security/syndicate, /obj/item/clothing/head/HoS/syndicate,
/obj/machinery/computer/pod/old/syndicate, /obj/machinery/vending/medical/syndicate_access, /obj/item/mmi/syndie, /obj/item/target/syndicate, /obj/machinery/vending/cigarette/syndicate, /obj/item/robot_module/syndicate, /obj/item/clothing/mask/gas/syndicate, /obj/machinery/power/singularity_beacon/syndicate, /obj/item/clothing/head/syndicatefake,
/obj/item/radio/headset/syndicate, /obj/item/gun/ballistic/automatic/pistol/antitank/syndicate, /obj/item/pda/syndicate, /obj/item/clothing/suit/armor/vest/capcarapace/syndicate, /obj/item/gun/ballistic/automatic/flechette, /obj/item/ammo_box/magazine/flechette, /obj/item/clothing/suit/toggle/lawyer/black/syndie, /obj/item/melee/transforming/energy/sword/cx/traitor,
/obj/structure/sign/poster/contraband/syndicate_pistol, /obj/structure/sign/poster/contraband/syndicate_recruitment, /obj/item/bedsheet/syndie, /obj/item/borg/upgrade/syndicate, /obj/item/tank/jetpack/oxygen/harness, /obj/item/firing_pin/implant/pindicate, /obj/item/reagent_containers/glass/bottle/traitor, /obj/item/storage/belt/military,
+1 -1
View File
@@ -763,7 +763,7 @@ SUBSYSTEM_DEF(vote)
remove_from_client()
Remove(owner)
/datum/action/vote/IsAvailable()
/datum/action/vote/IsAvailable(silent = FALSE)
return 1
/datum/action/vote/proc/remove_from_client()
+51 -62
View File
@@ -6,13 +6,15 @@
/datum/action
var/name = "Generic Action"
var/desc = null
var/obj/target = null
var/atom/target = null
var/check_flags = 0
var/required_mobility_flags = MOBILITY_USE
var/processing = FALSE
var/obj/screen/movable/action_button/button = null
var/buttontooltipstyle = ""
var/transparent_when_unavailable = TRUE
var/use_target_appearance = FALSE
var/list/target_appearance_matrix //if set, will be used to transform the target button appearance as an arglist.
var/button_icon = 'icons/mob/actions/backgrounds.dmi' //This is the file for the BACKGROUND icon
var/background_icon_state = ACTION_BUTTON_DEFAULT_BACKGROUND //And this is the state for the background icon
@@ -88,14 +90,14 @@
/datum/action/proc/Trigger()
if(!IsAvailable())
return FALSE
if(SEND_SIGNAL(src, COMSIG_ACTION_TRIGGER, src) & COMPONENT_ACTION_BLOCK_TRIGGER)
if(SEND_SIGNAL(src, COMSIG_ACTION_TRIGGER, target) & COMPONENT_ACTION_BLOCK_TRIGGER)
return FALSE
return TRUE
/datum/action/proc/Process()
return
/datum/action/proc/IsAvailable()
/datum/action/proc/IsAvailable(silent = FALSE)
if(!owner)
return FALSE
var/mob/living/L = owner
@@ -116,29 +118,42 @@
return TRUE
/datum/action/proc/UpdateButtonIcon(status_only = FALSE, force = FALSE)
if(button)
if(!status_only)
button.name = name
button.desc = desc
if(owner && owner.hud_used && background_icon_state == ACTION_BUTTON_DEFAULT_BACKGROUND)
var/list/settings = owner.hud_used.get_action_buttons_icons()
if(button.icon != settings["bg_icon"])
button.icon = settings["bg_icon"]
if(button.icon_state != settings["bg_state"])
button.icon_state = settings["bg_state"]
else
if(button.icon != button_icon)
button.icon = button_icon
if(button.icon_state != background_icon_state)
button.icon_state = background_icon_state
if(!button)
return
if(!status_only)
button.name = name
button.desc = desc
if(owner && owner.hud_used && background_icon_state == ACTION_BUTTON_DEFAULT_BACKGROUND)
var/list/settings = owner.hud_used.get_action_buttons_icons()
if(button.icon != settings["bg_icon"])
button.icon = settings["bg_icon"]
if(button.icon_state != settings["bg_state"])
button.icon_state = settings["bg_state"]
else
if(button.icon != button_icon)
button.icon = button_icon
if(button.icon_state != background_icon_state)
button.icon_state = background_icon_state
if(!use_target_appearance)
ApplyIcon(button, force)
if(!IsAvailable())
button.color = transparent_when_unavailable ? rgb(128,0,0,128) : rgb(128,0,0)
else
button.color = rgb(255,255,255,255)
return 1
else if(target && button.appearance_cache != target.appearance) //replace with /ref comparison if this is not valid.
var/mutable_appearance/M = new(target)
M.layer = FLOAT_LAYER
M.plane = FLOAT_PLANE
if(target_appearance_matrix)
var/list/L = target_appearance_matrix
M.transform = matrix(L[1], L[2], L[3], L[4], L[5], L[6])
button.cut_overlays()
button.add_overlay(M)
button.appearance_cache = target.appearance
if(!IsAvailable(TRUE))
button.color = transparent_when_unavailable ? rgb(128,0,0,128) : rgb(128,0,0)
else
button.color = rgb(255,255,255,255)
return 1
/datum/action/proc/ApplyIcon(obj/screen/movable/action_button/current_button, force = FALSE)
if(icon_icon && button_icon_state && ((current_button.button_icon_state != button_icon_state) || force))
@@ -165,6 +180,7 @@
/datum/action/item_action
check_flags = AB_CHECK_RESTRAINED|AB_CHECK_STUN|AB_CHECK_LYING|AB_CHECK_CONSCIOUS
button_icon_state = null
use_target_appearance = TRUE
// If you want to override the normal icon being the item
// then change this to an icon state
@@ -188,23 +204,6 @@
I.ui_action_click(owner, src)
return 1
/datum/action/item_action/ApplyIcon(obj/screen/movable/action_button/current_button, force)
if(button_icon && button_icon_state)
// If set, use the custom icon that we set instead
// of the item appearence
..()
else if(target && current_button.appearance_cache != target.appearance) //replace with /ref comparison if this is not valid.
var/obj/item/I = target
var/old_layer = I.layer
var/old_plane = I.plane
I.layer = FLOAT_LAYER //AAAH
I.plane = FLOAT_PLANE //^ what that guy said
current_button.cut_overlays()
current_button.add_overlay(I)
I.layer = old_layer
I.plane = old_plane
current_button.appearance_cache = I.appearance
/datum/action/item_action/toggle_light
name = "Toggle Light"
@@ -302,23 +301,13 @@
name = "Toggle Friendly Fire \[ON\]"
..()
/datum/action/item_action/synthswitch
name = "Change Synthesizer Instrument"
desc = "Change the type of instrument your synthesizer is playing as."
/datum/action/item_action/synthswitch/Trigger()
if(istype(target, /obj/item/instrument/piano_synth))
var/obj/item/instrument/piano_synth/synth = target
return synth.selectInstrument()
return ..()
/datum/action/item_action/vortex_recall
name = "Vortex Recall"
desc = "Recall yourself, and anyone nearby, to an attuned hierophant beacon at any time.<br>If the beacon is still attached, will detach it."
icon_icon = 'icons/mob/actions/actions_items.dmi'
button_icon_state = "vortex_recall"
/datum/action/item_action/vortex_recall/IsAvailable()
/datum/action/item_action/vortex_recall/IsAvailable(silent = FALSE)
if(istype(target, /obj/item/hierophant_club))
var/obj/item/hierophant_club/H = target
if(H.teleporting)
@@ -330,7 +319,7 @@
background_icon_state = "bg_clock"
buttontooltipstyle = "clockcult"
/datum/action/item_action/clock/IsAvailable()
/datum/action/item_action/clock/IsAvailable(silent = FALSE)
if(!is_servant_of_ratvar(owner))
return 0
return ..()
@@ -339,7 +328,7 @@
name = "Create Judicial Marker"
desc = "Allows you to create a stunning Judicial Marker at any location in view. Click again to disable."
/datum/action/item_action/clock/toggle_visor/IsAvailable()
/datum/action/item_action/clock/toggle_visor/IsAvailable(silent = FALSE)
if(!is_servant_of_ratvar(owner))
return 0
if(istype(target, /obj/item/clothing/glasses/judicial_visor))
@@ -418,7 +407,7 @@
/datum/action/item_action/jetpack_stabilization
name = "Toggle Jetpack Stabilization"
/datum/action/item_action/jetpack_stabilization/IsAvailable()
/datum/action/item_action/jetpack_stabilization/IsAvailable(silent = FALSE)
var/obj/item/tank/jetpack/J = target
if(!istype(J) || !J.on)
return 0
@@ -475,7 +464,7 @@
/datum/action/item_action/organ_action
check_flags = AB_CHECK_CONSCIOUS
/datum/action/item_action/organ_action/IsAvailable()
/datum/action/item_action/organ_action/IsAvailable(silent = FALSE)
var/obj/item/organ/I = target
if(!I.owner)
return 0
@@ -644,32 +633,32 @@
return FALSE
if(target)
var/obj/effect/proc_holder/S = target
S.Click()
S.Trigger(usr)
return TRUE
/datum/action/spell_action/IsAvailable()
/datum/action/spell_action/IsAvailable(silent = FALSE)
if(!target)
return FALSE
return TRUE
/datum/action/spell_action/spell
/datum/action/spell_action/spell/IsAvailable()
/datum/action/spell_action/spell/IsAvailable(silent = FALSE)
if(!target)
return FALSE
var/obj/effect/proc_holder/spell/S = target
if(owner)
return S.can_cast(owner)
return S.can_cast(owner, FALSE, silent)
return FALSE
/datum/action/spell_action/alien
/datum/action/spell_action/alien/IsAvailable()
/datum/action/spell_action/alien/IsAvailable(silent = FALSE)
if(!target)
return FALSE
var/obj/effect/proc_holder/alien/ab = target
if(owner)
return ab.cost_check(ab.check_turf,owner,1)
return ab.cost_check(ab.check_turf,owner,silent)
return FALSE
@@ -711,7 +700,7 @@
button.maptext_width = 24
button.maptext_height = 12
/datum/action/cooldown/IsAvailable()
/datum/action/cooldown/IsAvailable(silent = FALSE)
return next_use_time <= world.time
/datum/action/cooldown/proc/StartCooldown()
+1 -1
View File
@@ -39,7 +39,7 @@
//title_image = ntitle_image
/datum/browser/proc/add_stylesheet(name, file)
if (istype(name, /datum/asset/spritesheet))
if(istype(name, /datum/asset/spritesheet))
var/datum/asset/spritesheet/sheet = name
stylesheets["spritesheet_[sheet.name].css"] = "data/spritesheets/[sheet.name]"
else
@@ -14,26 +14,32 @@
name = "Glass working tools"
desc = "A lovely belt of most the tools you will need to shape, mold, and refine glass into more advanced shapes."
icon_state = "glass_tools"
tool_behaviour = TOOL_GLASS_CUT
tool_behaviour = TOOL_GLASS_CUT //Cutting takes 20 ticks
/obj/item/glasswork/blowing_rod
name = "Glass working blow rod"
desc = "A hollow metal stick made for glass blowing."
icon_state = "blowing_rods_unused"
tool_behaviour = TOOL_BLOW
tool_behaviour = TOOL_BLOW //Rods take 5 ticks
/obj/item/glasswork/glass_base
/obj/item/glasswork/glass_base //Welding takes 30 ticks
name = "Glass fodder sheet"
desc = "A sheet of glass set aside for glass working"
icon_state = "glass_base"
var/next_step = null
var/rod = /obj/item/glasswork/blowing_rod
/obj/item/lens
name = "Optical lens"
desc = "Good for selling or crafting, by itself its useless"
icon = 'icons/obj/chemical.dmi'
icon_state = "glass_optics"
/obj/item/tea_plate
name = "Tea Plate"
desc = "A polished plate for a tea cup. How fancy!"
icon = 'icons/obj/glass_ware.dmi'
icon_state = "tea_plate"
/obj/item/tea_cup
name = "Tea Cup"
desc = "A glass cup made for fake tea!"
icon = 'icons/obj/glass_ware.dmi'
icon_state = "tea_plate"
//////////////////////Chem Disk/////////////////////
//Two Steps //
@@ -49,8 +55,9 @@
/obj/item/glasswork/glass_base/dish/attackby(obj/item/I, mob/user, params)
..()
if(I.tool_behaviour == TOOL_GLASS_CUT)
new next_step(user.loc, 1)
qdel(src)
if(do_after(user,20, target = src))
new next_step(user.loc, 1)
qdel(src)
/obj/item/glasswork/glass_base/dish_part1
name = "Half chem dish sheet"
@@ -61,8 +68,9 @@
/obj/item/glasswork/glass_base/dish_part1/attackby(obj/item/I, mob/user, params)
..()
if(I.tool_behaviour == TOOL_GLASS_CUT)
new next_step(user.loc, 1)
qdel(src)
if(do_after(user,20, target = src))
new next_step(user.loc, 1)
qdel(src)
//////////////////////Lens//////////////////////////
//Six Steps //
@@ -78,8 +86,9 @@
/obj/item/glasswork/glass_base/glass_lens/attackby(obj/item/I, mob/user, params)
..()
if(I.tool_behaviour == TOOL_GLASS_CUT)
new next_step(user.loc, 1)
qdel(src)
if(do_after(user,20, target = src))
new next_step(user.loc, 1)
qdel(src)
/obj/item/glasswork/glass_base/glass_lens_part1
name = "Glass fodder sheet"
@@ -90,8 +99,9 @@
/obj/item/glasswork/glass_base/glass_lens_part1/attackby(obj/item/I, mob/user, params)
..()
if(I.tool_behaviour == TOOL_WELDER)
new next_step(user.loc, 1)
qdel(src)
if(do_after(user,30, target = src))
new next_step(user.loc, 1)
qdel(src)
/obj/item/glasswork/glass_base/glass_lens_part2
name = "Glass fodder sheet"
@@ -102,8 +112,9 @@
/obj/item/glasswork/glass_base/glass_lens_part2/attackby(obj/item/I, mob/user, params)
..()
if(I.tool_behaviour == TOOL_WELDER)
new next_step(user.loc, 1)
qdel(src)
if(do_after(user,30, target = src))
new next_step(user.loc, 1)
qdel(src)
/obj/item/glasswork/glass_base/glass_lens_part3
name = "Glass fodder sheet"
@@ -114,9 +125,10 @@
/obj/item/glasswork/glass_base/glass_lens_part3/attackby(obj/item/I, mob/user, params)
..()
if(I.tool_behaviour == TOOL_BLOW)
new next_step(user.loc, 1)
qdel(src)
qdel(I)
if(do_after(user,5, target = src))
new next_step(user.loc, 1)
qdel(src)
qdel(I)
/obj/item/glasswork/glass_base/glass_lens_part4
name = "Glass fodder sheet"
@@ -127,29 +139,31 @@
/obj/item/glasswork/glass_base/glass_lens_part4/attackby(obj/item/I, mob/user, params)
..()
if(I.tool_behaviour == TOOL_GLASS_CUT)
new next_step(user.loc, 1)
new rod(user.loc, 1)
qdel(src)
if(do_after(user,20, target = src))
new next_step(user.loc, 1)
new rod(user.loc, 1)
qdel(src)
/obj/item/glasswork/glass_base/glass_lens_part5
name = "Unpolished glass lens"
desc = "A small unpolished glass lens. Could be polished with some cloth."
icon = 'icons/obj/chemical.dmi'
desc = "A small unpolished glass lens. Could be polished with some silk."
icon = 'icons/obj/glass_ware.dmi'
icon_state = "glass_optics"
next_step = /obj/item/glasswork/glass_base/glass_lens_part6
/obj/item/glasswork/glass_base/glass_lens_part5/attackby(obj/item/I, mob/user, params)
..()
if(istype(I, /obj/item/stack/sheet/cloth))
new next_step(user.loc, 1)
qdel(src)
if(istype(I, /obj/item/stack/sheet/silk))
if(do_after(user,10, target = src))
new next_step(user.loc, 1)
qdel(src)
/obj/item/glasswork/glass_base/glass_lens_part6
name = "Unrefined glass lens"
desc = "A small polished glass lens. Just needs to be refined with some sandstone."
icon = 'icons/obj/chemical.dmi'
icon = 'icons/obj/glass_ware.dmi'
icon_state = "glass_optics"
next_step = /obj/item/lens
next_step = /obj/item/glasswork/glass_base/lens
/obj/item/glasswork/glass_base/glass_lens_part6/attackby(obj/item/I, mob/user, params)
..()
@@ -171,8 +185,9 @@
/obj/item/glasswork/glass_base/spouty/attackby(obj/item/I, mob/user, params)
..()
if(I.tool_behaviour == TOOL_GLASS_CUT)
new next_step(user.loc, 1)
qdel(src)
if(do_after(user,20, target = src))
new next_step(user.loc, 1)
qdel(src)
/obj/item/glasswork/glass_base/spouty_part2
name = "Glass fodder sheet"
@@ -183,8 +198,9 @@
/obj/item/glasswork/glass_base/spouty_part2/attackby(obj/item/I, mob/user, params)
..()
if(I.tool_behaviour == TOOL_WELDER)
new next_step(user.loc, 1)
qdel(src)
if(do_after(user,30, target = src))
new next_step(user.loc, 1)
qdel(src)
/obj/item/glasswork/glass_base/spouty_part3
name = "Glass fodder sheet"
@@ -195,9 +211,10 @@
/obj/item/glasswork/glass_base/spouty_part3/attackby(obj/item/I, mob/user, params)
..()
if(I.tool_behaviour == TOOL_BLOW)
new next_step(user.loc, 1)
qdel(src)
qdel(I)
if(do_after(user,5, target = src))
new next_step(user.loc, 1)
qdel(src)
qdel(I)
/obj/item/glasswork/glass_base/spouty_part4
name = "Glass fodder sheet"
@@ -208,9 +225,10 @@
/obj/item/glasswork/glass_base/spouty_part4/attackby(obj/item/I, mob/user, params)
..()
if(I.tool_behaviour == TOOL_GLASS_CUT)
new next_step(user.loc, 1)
new rod(user.loc, 1)
qdel(src)
if(do_after(user,20, target = src))
new next_step(user.loc, 1)
new rod(user.loc, 1)
qdel(src)
//////////////////////Small Bulb Flask//////////////
//Two Steps //
@@ -226,8 +244,9 @@
/obj/item/glasswork/glass_base/flask_small/attackby(obj/item/I, mob/user, params)
..()
if(I.tool_behaviour == TOOL_WELDER)
new next_step(user.loc, 1)
qdel(src)
if(do_after(user,30, target = src))
new next_step(user.loc, 1)
qdel(src)
/obj/item/glasswork/glass_base/flask_small_part1
name = "Metled glass"
@@ -238,9 +257,10 @@
/obj/item/glasswork/glass_base/flask_small_part1/attackby(obj/item/I, mob/user, params)
..()
if(I.tool_behaviour == TOOL_BLOW)
new next_step(user.loc, 1)
qdel(src)
qdel(I)
if(do_after(user,5, target = src))
new next_step(user.loc, 1)
qdel(src)
qdel(I)
/obj/item/glasswork/glass_base/flask_small_part2
name = "Metled glass"
@@ -251,9 +271,10 @@
/obj/item/glasswork/glass_base/flask_small_part2/attackby(obj/item/I, mob/user, params)
..()
if(I.tool_behaviour == TOOL_GLASS_CUT)
new next_step(user.loc, 1)
new rod(user.loc, 1)
qdel(src)
if(do_after(user,20, target = src))
new next_step(user.loc, 1)
new rod(user.loc, 1)
qdel(src)
//////////////////////Large Bulb Flask//////////////
//Two Steps //
@@ -269,8 +290,9 @@
/obj/item/glasswork/glass_base/flask_large/attackby(obj/item/I, mob/user, params)
..()
if(I.tool_behaviour == TOOL_WELDER)
new next_step(user.loc, 1)
qdel(src)
if(do_after(user,30, target = src))
new next_step(user.loc, 1)
qdel(src)
/obj/item/glasswork/glass_base/flask_large_part1
name = "Metled glass"
@@ -281,9 +303,10 @@
/obj/item/glasswork/glass_base/flask_large_part1/attackby(obj/item/I, mob/user, params)
..()
if(I.tool_behaviour == TOOL_BLOW)
new next_step(user.loc, 1)
qdel(src)
qdel(I)
if(do_after(user,5, target = src))
new next_step(user.loc, 1)
qdel(src)
qdel(I)
/obj/item/glasswork/glass_base/flask_large_part2
name = "Metled glass"
@@ -294,6 +317,138 @@
/obj/item/glasswork/glass_base/flask_large_part2/attackby(obj/item/I, mob/user, params)
..()
if(I.tool_behaviour == TOOL_GLASS_CUT)
new next_step(user.loc, 1)
new rod(user.loc, 1)
qdel(src)
if(do_after(user,20, target = src))
new next_step(user.loc, 1)
new rod(user.loc, 1)
qdel(src)
//////////////////////Tea Plates////////////////////
//Three Steps //
//Sells for 1200 cr, takes 5 glass shets //
//Usefull for selling and chemical things //
////////////////////////////////////////////////////
/obj/item/glasswork/glass_base/tea_plate
name = "Glass fodder sheet"
desc = "A set of glass sheets set aside for glass working, this one is ideal for a tea plate, how fancy! Needs to be heated with some tools."
next_step = /obj/item/glasswork/glass_base/tea_plate1
/obj/item/glasswork/glass_base/tea_plate/attackby(obj/item/I, mob/user, params)
..()
if(I.tool_behaviour == TOOL_WELDER)
if(do_after(user,30, target = src))
new next_step(user.loc, 1)
qdel(src)
/obj/item/glasswork/glass_base/tea_plate1
name = "Metled glass"
desc = "A blob of metled glass, this one is ideal for a tea plate. Needs to be blown with some tools."
icon_state = "glass_base_molding"
next_step = /obj/item/glasswork/glass_base/tea_plate2
/obj/item/glasswork/glass_base/tea_plate1/attackby(obj/item/I, mob/user, params)
..()
if(I.tool_behaviour == TOOL_BLOW)
if(do_after(user,5, target = src))
new next_step(user.loc, 1)
qdel(src)
qdel(I)
/obj/item/glasswork/glass_base/tea_plate2
name = "Metled glass"
desc = "A blob of metled glass on the end of a blowing rod. Needs to be cut off with some tools."
icon_state = "blowing_rods_inuse"
next_step = /obj/item/glasswork/glass_base/tea_plate3
/obj/item/glasswork/glass_base/tea_plate2/attackby(obj/item/I, mob/user, params)
..()
if(I.tool_behaviour == TOOL_GLASS_CUT)
if(do_after(user,20, target = src))
new next_step(user.loc, 1)
new rod(user.loc, 1)
qdel(src)
/obj/item/glasswork/glass_base/tea_plate3
name = "Disk of glass"
desc = "A disk of glass that can be cant be used for much. Needs to be polished with some silk."
icon_state = "glass_base_half"
next_step = /obj/item/tea_plate
/obj/item/glasswork/glass_base/tea_plate3/attackby(obj/item/I, mob/user, params)
..()
if(istype(I, /obj/item/stack/sheet/silk))
if(do_after(user,10, target = src))
new next_step(user.loc, 1)
qdel(src)
//////////////////////Tea Cup///////////////////////
//Four Steps //
//Sells for 1800 cr, takes 6 glass shets //
//Usefull for selling and chemical things //
////////////////////////////////////////////////////
/obj/item/glasswork/glass_base/tea_cup
name = "Glass fodder sheet"
desc = "A set of glass sheets set aside for glass working, this one is ideal for a tea cup, how fancy! Needs to be heated with some tools."
next_step = /obj/item/glasswork/glass_base/tea_cup1
/obj/item/glasswork/glass_base/tea_cup/attackby(obj/item/I, mob/user, params)
..()
if(I.tool_behaviour == TOOL_WELDER)
if(do_after(user,30, target = src))
new next_step(user.loc, 1)
qdel(src)
/obj/item/glasswork/glass_base/tea_cup1
name = "Metled glass"
desc = "A blob of metled glass, this one is ideal for a tea cup. Needs to be blown with some tools."
icon_state = "glass_base_molding"
next_step = /obj/item/glasswork/glass_base/tea_cup2
/obj/item/glasswork/glass_base/tea_cup1/attackby(obj/item/I, mob/user, params)
..()
if(I.tool_behaviour == TOOL_BLOW)
if(do_after(user,5, target = src))
new next_step(user.loc, 1)
qdel(src)
qdel(I)
/obj/item/glasswork/glass_base/tea_cupe2
name = "Metled glass"
desc = "A blob of metled glass on the end of a blowing rod. Needs to be cut off with some tools."
icon_state = "blowing_rods_inuse"
next_step = /obj/item/glasswork/glass_base/tea_cup3
/obj/item/glasswork/glass_base/tea_cup2/attackby(obj/item/I, mob/user, params)
..()
if(I.tool_behaviour == TOOL_GLASS_CUT)
if(do_after(user,20, target = src))
new next_step(user.loc, 1)
new rod(user.loc, 1)
qdel(src)
/obj/item/glasswork/glass_base/tea_cup3
name = "Disk of glass"
desc = "A bowl of glass that can be cant be used for much. Needs to be polished with some silk."
icon_state = "glass_base_half"
next_step = /obj/item/glasswork/glass_base/tea_cup4
/obj/item/glasswork/glass_base/cup3/attackby(obj/item/I, mob/user, params)
..()
if(istype(I, /obj/item/stack/sheet/silk))
if(do_after(user,10, target = src))
new next_step(user.loc, 1)
qdel(src)
/obj/item/glasswork/glass_base/tea_cup4
name = "Disk of glass"
desc = "A bowl of polished glass that can be cant be used for much. Needs some more glass to make a handle."
icon_state = "glass_base_half"
next_step = /obj/item/tea_cup
/obj/item/glasswork/glass_base/cup4/attackby(obj/item/I, mob/user, params)
..()
if(istype(I, /obj/item/stack/sheet/glass))
if(do_after(user,10, target = src))
new next_step(user.loc, 1)
qdel(src)
@@ -0,0 +1,98 @@
//This file is for crafting using a lens!
/obj/item/glasswork/glass_base/lens
name = "Optical lens"
desc = "Good for selling or crafting, by itself its useless"
icon = 'icons/obj/glass_ware.dmi'
icon_state = "glass_optics"
//Laser pointers - 2600
/obj/item/glasswork/glass_base/laserpointer_shell
name = "Laser pointer assembly"
desc = "Good for selling or crafting, by itself its useless. Needs a power capactor."
icon_state = "laser_case"
icon = 'icons/obj/glass_ware.dmi'
next_step = /obj/item/glasswork/glass_base/laserpointer_shell_1
/obj/item/glasswork/glass_base/laserpointer_shell/attackby(obj/item/I, mob/user, params)
..()
if(istype(I, /obj/item/stock_parts/capacitor))
new next_step(user.loc, 1)
qdel(src)
/obj/item/glasswork/glass_base/laserpointer_shell_1
name = "Laser pointer assembly"
desc = "Good for selling or crafting, by itself its useless. Needs a glass lens."
icon_state = "laser_wire"
icon_state = "laser_case"
next_step = /obj/item/glasswork/glass_base/laserpointer_shell_2
/obj/item/glasswork/glass_base/laserpointer_shell_1/attackby(obj/item/I, mob/user, params)
..()
if(istype(I, /obj/item/glasswork/glass_base/lens))
new next_step(user.loc, 1)
qdel(src)
/obj/item/glasswork/glass_base/laserpointer_shell_2
name = "Laser pointer assembly"
desc = "Good for selling or crafting, by itself its useless. Needs to be screwed together."
icon_state = "laser_wire"
icon_state = "laser_case"
next_step = /obj/item/laser_pointer/blue/handmade
/obj/item/glasswork/glass_base/laserpointer_shell_2/attackby(obj/item/I, mob/user, params)
..()
if(I.tool_behaviour == TOOL_SCREWDRIVER)
if(do_after(user,260, target = src))
new next_step(user.loc, 1)
qdel(src)
//NERD SHIT - 5000
/obj/item/glasswork/glass_base/glasses_frame
name = "Glasses Frame"
desc = "Good for crafting a pare of glasses, by itself its useless. Just add a pare of lens."
icon = 'icons/obj/glass_ware.dmi'
icon_state = "frames"
next_step = /obj/item/glasswork/glass_base/glasses_frame_1
/obj/item/glasswork/glass_base/glasses_frame/attackby(obj/item/I, mob/user, params)
..()
if(istype(I, /obj/item/glasswork/glass_base/lens))
if(do_after(user,60, target = src))
new next_step(user.loc, 1)
qdel(src)
/obj/item/glasswork/glass_base/glasses_frame_1
name = "Glasses Frame"
desc = "Good for crafting a pare of glasses, by itself its useless. Just add a the other lens."
icon = 'icons/obj/glass_ware.dmi'
icon_state = "frames_1"
next_step = /obj/item/glasswork/glass_base/glasses_frame_2
/obj/item/glasswork/glass_base/glasses_frame_1/attackby(obj/item/I, mob/user, params)
..()
if(istype(I, /obj/item/glasswork/glass_base/lens))
if(do_after(user,60, target = src))
new next_step(user.loc, 1)
qdel(src)
/obj/item/glasswork/glass_base/glasses_frame_2
name = "Glasses Frame"
desc = "Good for crafting a pare of glasses, by itself its useless. Just adjust the pices into the frame with a screwdriver."
icon = 'icons/obj/glass_ware.dmi'
icon_state = "frames_2"
next_step = /obj/item/glasswork/glasses
/obj/item/glasswork/glass_base/glasses_frame_2/attackby(obj/item/I, mob/user, params)
..()
if(I.tool_behaviour == TOOL_SCREWDRIVER)
if(do_after(user,180, target = src))
new next_step(user.loc, 1)
qdel(src)
/obj/item/glasswork/glasses
name = "Hand Made Glasses"
desc = "Hande made glasses that have not been polished at all making them useless. Selling them could still be worth a bit of credits."
icon = 'icons/obj/glass_ware.dmi'
icon_state = "frames_2"
@@ -33,6 +33,13 @@
/obj/item/organ/ears/cat = 1)
category = CAT_CLOTHING
/datum/crafting_recipe/papermask
name = "Paper Mask"
result = /obj/item/clothing/mask/paper
time = 10
reqs = list(/obj/item/paper = 20)
category = CAT_CLOTHING
////////
//Huds//
////////
+1 -2
View File
@@ -25,7 +25,6 @@
RegisterSignal(parent, COMSIG_ITEM_ATTACK_OBJ, .proc/rad_attack)
else
CRASH("Something that wasn't an atom was given /datum/component/radioactive")
return
if(strength > RAD_MINIMUM_CONTAMINATION)
SSradiation.warn(src)
@@ -84,4 +83,4 @@
#undef RAD_AMOUNT_LOW
#undef RAD_AMOUNT_MEDIUM
#undef RAD_AMOUNT_HIGH
#undef RAD_AMOUNT_EXTREME
#undef RAD_AMOUNT_EXTREME
+1 -1
View File
@@ -790,7 +790,7 @@
user.visible_message("<span class='warning'>[user] draws [I] from [parent]!</span>", "<span class='notice'>You draw [I] from [parent].</span>")
return TRUE
/datum/component/storage/proc/action_trigger(datum/signal_source, datum/action/source)
/datum/component/storage/proc/action_trigger(datum/action/source, obj/target)
gather_mode_switch(source.owner)
return COMPONENT_ACTION_BLOCK_TRIGGER
+17 -2
View File
@@ -27,6 +27,8 @@ GLOBAL_LIST_EMPTY(uplinks)
var/datum/ui_state/checkstate
var/compact_mode = FALSE
var/debug = FALSE
var/saved_player_population = 0
var/list/filters = list()
/datum/component/uplink/Initialize(_owner, _lockable = TRUE, _enabled = FALSE, datum/game_mode/_gamemode, starting_tc = 20, datum/ui_state/_checkstate, datum/traitor_class/traitor_class)
if(!isitem(parent))
@@ -47,7 +49,6 @@ GLOBAL_LIST_EMPTY(uplinks)
RegisterSignal(parent, COMSIG_PEN_ROTATED, .proc/pen_rotation)
GLOB.uplinks += src
var/list/filters = list()
if(istype(traitor_class))
filters = traitor_class.uplink_filters
starting_tc = traitor_class.TC
@@ -68,6 +69,7 @@ GLOBAL_LIST_EMPTY(uplinks)
if(!lockable)
active = TRUE
locked = FALSE
saved_player_population = GLOB.joined_player_list.len
/datum/component/uplink/InheritComponent(datum/component/uplink/U)
lockable |= U.lockable
@@ -117,7 +119,18 @@ GLOBAL_LIST_EMPTY(uplinks)
return
active = TRUE
if(user)
//update the saved population
var/previous_player_population = saved_player_population
saved_player_population = GLOB.joined_player_list.len
//if population has changed, update uplink items
if(saved_player_population != previous_player_population)
//make sure discounts are not rerolled
var/old_discounts = uplink_items["Discounted Gear"]
uplink_items = get_uplink_items(gamemode, FALSE, allow_restricted, filters)
if(old_discounts)
uplink_items["Discounted Gear"] = old_discounts
ui_interact(user)
// an unlocked uplink blocks also opening the PDA or headset menu
return COMPONENT_NO_INTERACT
@@ -190,7 +203,9 @@ GLOBAL_LIST_EMPTY(uplinks)
if(item in buyable_items)
var/datum/uplink_item/I = buyable_items[item]
MakePurchase(usr, I)
//check to make sure people cannot buy items when the player pop is below the requirement
if(GLOB.joined_player_list.len >= I.player_minimum)
MakePurchase(usr, I)
. = TRUE
if("lock")
active = FALSE
+1 -1
View File
@@ -176,7 +176,7 @@
/**
*The following procs simply acts as hooks for quit(), since components do not use callbacks anymore
*/
/datum/component/virtual_reality/proc/action_trigger(datum/signal_source, datum/action/source)
/datum/component/virtual_reality/proc/action_trigger(datum/action/source, obj/target)
quit()
return COMPONENT_ACTION_BLOCK_TRIGGER
+1 -1
View File
@@ -19,4 +19,4 @@
UnregisterSignal(equipper, signals)
/datum/component/wearertargeting/proc/on_drop(datum/source, mob/user)
UnregisterSignal(user, signals)
UnregisterSignal(user, signals)
-1
View File
@@ -19,7 +19,6 @@
var/datum/component/wet_floor/WF = newcomp //Lets make an assumption
if(WF.gc()) //See if it's even valid, still. Also does LAZYLEN and stuff for us.
CRASH("Wet floor component tried to inherit another, but the other was able to garbage collect while being inherited! What a waste of time!")
return
for(var/i in WF.time_left_list)
add_wet(text2num(i), WF.time_left_list[i])
+1 -1
View File
@@ -19,7 +19,7 @@
dashing_item = dasher
holder = user
/datum/action/innate/dash/IsAvailable()
/datum/action/innate/dash/IsAvailable(silent = FALSE)
if(current_charges > 0)
return TRUE
else
+2 -2
View File
@@ -109,6 +109,8 @@
UnregisterSignal(target, signal_procs[target])
//END: ECS SHIT
SSsounds.free_datum_channels(src)
return QDEL_HINT_QUEUE
#ifdef DATUMVAR_DEBUGGING_MODE
@@ -173,11 +175,9 @@
if(!islist(jsonlist))
if(!istext(jsonlist))
CRASH("Invalid JSON")
return
jsonlist = json_decode(jsonlist)
if(!islist(jsonlist))
CRASH("Invalid JSON")
return
if(!jsonlist["DATUM_TYPE"])
return
if(!ispath(jsonlist["DATUM_TYPE"]))
+23 -1379
View File
File diff suppressed because it is too large Load Diff
+33 -37
View File
@@ -1,58 +1,54 @@
/datum/element/ghost_role_eligibility
element_flags = ELEMENT_DETACH
var/list/timeouts = list()
var/list/mob/eligible_mobs = list()
GLOBAL_LIST_EMPTY(ghost_eligible_mobs)
/datum/element/ghost_role_eligibility/Attach(datum/target,penalize = FALSE)
GLOBAL_LIST_EMPTY(client_ghost_timeouts)
/datum/element/ghost_role_eligibility
element_flags = ELEMENT_DETACH | ELEMENT_BESPOKE
id_arg_index = 2
var/penalizing = FALSE
var/free_ghost = FALSE
/datum/element/ghost_role_eligibility/Attach(datum/target,free_ghosting = FALSE, penalize_on_ghost = FALSE)
. = ..()
if(!ismob(target))
return ELEMENT_INCOMPATIBLE
penalizing = penalize_on_ghost
free_ghost = free_ghosting
var/mob/M = target
if(!(M in eligible_mobs))
eligible_mobs += M
if(penalize) //penalizing them from making a ghost role / midround antag comeback right away.
var/penalty = CONFIG_GET(number/suicide_reenter_round_timer) MINUTES
var/roundstart_quit_limit = CONFIG_GET(number/roundstart_suicide_time_limit) MINUTES
if(world.time < roundstart_quit_limit) //add up the time difference to their antag rolling penalty if they quit before half a (ingame) hour even passed.
penalty += roundstart_quit_limit - world.time
if(penalty)
penalty += world.realtime
if(SSautotransfer.can_fire && SSautotransfer.maxvotes)
var/maximumRoundEnd = SSautotransfer.starttime + SSautotransfer.voteinterval * SSautotransfer.maxvotes
if(penalty - SSshuttle.realtimeofstart > maximumRoundEnd + SSshuttle.emergencyCallTime + SSshuttle.emergencyDockTime + SSshuttle.emergencyEscapeTime)
penalty = CANT_REENTER_ROUND
if(!(M.ckey in timeouts))
timeouts += M.ckey
timeouts[M.ckey] = 0
else if(timeouts[M.ckey] == CANT_REENTER_ROUND)
return
timeouts[M.ckey] = max(timeouts[M.ckey],penalty)
if(!(M in GLOB.ghost_eligible_mobs))
GLOB.ghost_eligible_mobs += M
RegisterSignal(M, COMSIG_MOB_GHOSTIZE, .proc/get_ghost_flags)
/datum/element/ghost_role_eligibility/Detach(mob/M)
. = ..()
if(M in eligible_mobs)
eligible_mobs -= M
if(M in GLOB.ghost_eligible_mobs)
GLOB.ghost_eligible_mobs -= M
UnregisterSignal(M, COMSIG_MOB_GHOSTIZE)
/datum/element/ghost_role_eligibility/proc/get_all_ghost_role_eligible(silent = FALSE)
/proc/get_all_ghost_role_eligible(silent = FALSE)
var/list/candidates = list()
for(var/m in eligible_mobs)
for(var/m in GLOB.ghost_eligible_mobs)
var/mob/M = m
if(M.can_reenter_round(TRUE))
candidates += M
return candidates
/mob/proc/can_reenter_round(silent = FALSE)
var/datum/element/ghost_role_eligibility/eli = SSdcs.GetElement(list(/datum/element/ghost_role_eligibility))
return eli.can_reenter_round(src,silent)
/datum/element/ghost_role_eligibility/proc/can_reenter_round(var/mob/M,silent = FALSE)
if(!(M in eligible_mobs))
if(!(src in GLOB.ghost_eligible_mobs))
return FALSE
if(!(M.ckey in timeouts))
if(!(ckey in GLOB.client_ghost_timeouts))
return TRUE
var/timeout = timeouts[M.ckey]
var/timeout = GLOB.client_ghost_timeouts[ckey]
if(timeout != CANT_REENTER_ROUND && timeout <= world.realtime)
return TRUE
if(!silent && M.client)
to_chat(M, "<span class='warning'>You are unable to reenter the round[timeout != CANT_REENTER_ROUND ? " yet. Your ghost role blacklist will expire in [DisplayTimeText(timeout - world.realtime)]" : ""].</span>")
if(!silent && client)
to_chat(src, "<span class='warning'>You are unable to reenter the round[timeout != CANT_REENTER_ROUND ? " yet. Your ghost role blacklist will expire in [DisplayTimeText(timeout - world.realtime)]" : ""].</span>")
return FALSE
/datum/element/ghost_role_eligibility/proc/get_ghost_flags()
. = 0
if(!penalizing)
. |= COMPONENT_DO_NOT_PENALIZE_GHOSTING
if(free_ghost)
. |= COMPONENT_FREE_GHOSTING
return .
+8 -2
View File
@@ -71,11 +71,12 @@
name = "bugged mob"
desc = "Yell at coderbrush."
icon = null
alternate_worn_icon = 'icons/mob/animals_held.dmi'
mob_overlay_icon = 'icons/mob/animals_held.dmi'
righthand_file = 'icons/mob/animals_held_rh.dmi'
lefthand_file = 'icons/mob/animals_held_lh.dmi'
icon_state = ""
w_class = WEIGHT_CLASS_BULKY
dynamic_hair_suffix = ""
var/mob/living/held_mob
/obj/item/clothing/head/mob_holder/Initialize(mapload, mob/living/target, worn_state, alt_worn, right_hand, left_hand, slots = NONE)
@@ -85,7 +86,7 @@
assimilate(target)
if(alt_worn)
alternate_worn_icon = alt_worn
mob_overlay_icon = alt_worn
if(worn_state)
item_state = worn_state
icon_state = worn_state
@@ -162,6 +163,11 @@
L.visible_message("<span class='warning'>[held_mob] escapes from [L]!</span>", "<span class='warning'>[held_mob] escapes your grip!</span>")
release()
/obj/item/clothing/head/mob_holder/mob_can_equip(mob/living/M, mob/living/equipper, slot, disable_warning = FALSE, bypass_equip_delay_self = FALSE)
if(!ishuman(M)) //monkeys holding monkeys holding monkeys...
return FALSE
return ..()
/obj/item/clothing/head/mob_holder/assume_air(datum/gas_mixture/env)
var/atom/location = loc
if(!loc)
+187
View File
@@ -0,0 +1,187 @@
#define POLYCHROMIC_ALTCLICK (1<<0)
#define POLYCHROMIC_ACTION (1<<1)
#define POLYCHROMIC_NO_HELD (1<<2)
#define POLYCHROMIC_NO_WORN (1<<3)
/datum/element/polychromic
element_flags = ELEMENT_BESPOKE|ELEMENT_DETACH
id_arg_index = 3
var/overlays_states //A list or a number of states. In the latter case, the atom icon_state/item_state will be used followed by a number.
var/list/colors_by_atom = list() //list of color strings or mutable appearances, depending on the above variable.
var/icon_file
var/worn_file //used in place of items' held or mob overlay icons if present.
var/list/overlays_names //wrap numbers into text strings please.
var/list/actions_by_atom = list()
var/poly_flags
var/static/list/suits_with_helmet_typecache = typecacheof(list(/obj/item/clothing/suit/hooded, /obj/item/clothing/suit/space/hardsuit))
var/list/helmet_by_suit = list() //because poly winter coats exist.
var/list/suit_by_helmet = list() //Idem.
/datum/element/polychromic/Attach(datum/target, list/colors, states, _flags = POLYCHROMIC_ACTION|POLYCHROMIC_NO_HELD, _icon, _worn, list/names = list("Primary", "Secondary", "Tertiary", "Quaternary", "Quinary", "Senary"))
. = ..()
var/make_appearances = islist(states)
var/states_len = make_appearances ? length(states) : states
var/names_len = length(names)
if(!states_len || !names_len || colors_by_atom[target] || !isatom(target))
return ELEMENT_INCOMPATIBLE
var/atom/A = target
overlays_states = states
icon_file = _icon
worn_file = _worn
poly_flags = _flags
var/mut_icon = icon_file || A.icon
var/list/L = list()
for(var/I in 1 to states_len)
var/col = LAZYACCESS(colors, I) || "#FFFFFF"
L += make_appearances ? mutable_appearance(mut_icon, overlays_states[I], color = col) : col
colors_by_atom[A] = L
RegisterSignal(A, COMSIG_ATOM_UPDATE_OVERLAYS, .proc/apply_overlays)
if(_flags & POLYCHROMIC_ALTCLICK)
RegisterSignal(A, COMSIG_PARENT_EXAMINE, .proc/on_examine)
RegisterSignal(A, COMSIG_CLICK_ALT, .proc/set_color)
if(!overlays_names && names) //generate
overlays_names = names
var/diff = states_len - names_len
if(diff > 0)
for(var/i in 1 to diff)
overlays_names += "[names_len + i]°"
else if(diff < 0)
overlays_names.len += diff
if(isitem(A))
if(_flags & POLYCHROMIC_ACTION)
RegisterSignal(A, COMSIG_ITEM_EQUIPPED, .proc/grant_user_action)
RegisterSignal(A, COMSIG_ITEM_DROPPED, .proc/remove_user_action)
if(!(_flags & POLYCHROMIC_NO_WORN) || !(_flags & POLYCHROMIC_NO_HELD))
A.AddElement(/datum/element/update_icon_updates_onmob)
RegisterSignal(A, COMSIG_ITEM_WORN_OVERLAYS, .proc/apply_worn_overlays)
if(suits_with_helmet_typecache[A.type])
RegisterSignal(A, COMSIG_SUIT_MADE_HELMET, .proc/register_helmet)
else if(_flags & POLYCHROMIC_ACTION && ismob(A)) //in the event mob update icon procs are ever standarized.
var/datum/action/polychromic/P = new(A)
RegisterSignal(P, COMSIG_ACTION_TRIGGER, .proc/activate_action)
actions_by_atom[A] = P
P.Grant(A)
A.update_icon() //apply the overlays.
/datum/element/polychromic/Detach(atom/A)
. = ..()
colors_by_atom -= A
var/datum/action/polychromic/P = actions_by_atom[A]
if(P)
actions_by_atom -= A
qdel(P)
UnregisterSignal(A, list(COMSIG_PARENT_EXAMINE, COMSIG_CLICK_ALT, COMSIG_ATOM_UPDATE_OVERLAYS, COMSIG_ITEM_EQUIPPED, COMSIG_ITEM_DROPPED, COMSIG_ITEM_WORN_OVERLAYS, COMSIG_SUIT_MADE_HELMET))
if(isitem(A))
var/obj/item/clothing/head/H = helmet_by_suit[A]
if(H)
UnregisterSignal(H, list(COMSIG_ATOM_UPDATE_OVERLAYS, COMSIG_ITEM_WORN_OVERLAYS, COMSIG_PARENT_QDELETING))
helmet_by_suit -= A
suit_by_helmet -= H
colors_by_atom -= H
if(!QDELETED(H))
H.update_icon() //removing the overlays
if(!(poly_flags & POLYCHROMIC_NO_WORN) || !(poly_flags & POLYCHROMIC_NO_HELD))
A.RemoveElement(/datum/element/update_icon_updates_onmob)
if(!QDELETED(A) && ismob(A.loc))
var/mob/M = A.loc
if(!(poly_flags & POLYCHROMIC_NO_HELD) && M.is_holding(A))
M.update_inv_hands()
else if(!(poly_flags & POLYCHROMIC_NO_WORN))
M.regenerate_icons()
if(!QDELETED(A))
A.update_icon() //removing the overlays
/datum/element/polychromic/proc/apply_overlays(atom/source, list/overlays)
var/list/L = colors_by_atom[source]
var/f_icon = icon_file || source.icon
if(isnum(overlays_states))
for(var/i in 1 to overlays_states)
overlays += mutable_appearance(f_icon, "[source.icon_state]-[i]", color = L[i])
else
overlays += colors_by_atom[source]
/datum/element/polychromic/proc/apply_worn_overlays(obj/item/source, isinhands, icon, used_state, style_flags, list/overlays)
if(poly_flags & (isinhands ? POLYCHROMIC_NO_HELD : POLYCHROMIC_NO_WORN))
return
var/f_icon = worn_file || icon
var/list/L = colors_by_atom[source]
if(isnum(overlays_states))
for(var/i in 1 to overlays_states)
overlays += mutable_appearance(f_icon, "[used_state]-[i]", color = L[i])
else
for(var/i in 1 to length(overlays_states))
var/mutable_appearance/M = L[i]
overlays += mutable_appearance(f_icon, overlays_states[i], color = M.color)
/datum/element/polychromic/proc/set_color(atom/source, mob/user)
var/choice = input(user,"Polychromic options", "Recolor [source]") as null|anything in overlays_names
if(!choice || QDELETED(source) || !user.canUseTopic(source, BE_CLOSE, NO_DEXTERY))
return
var/index = overlays_names.Find(choice)
var/list/L = colors_by_atom[source]
if(!L) // Ummmmmh.
return
var/mutable_appearance/M = L[index]
var/old_color = istype(M) ? M.color : M
var/ncolor = input(user, "Polychromic options", "Choose [choice] Color", old_color) as color|null
if(!ncolor || QDELETED(source) || !colors_by_atom[source] || !user.canUseTopic(source, BE_CLOSE, NO_DEXTERY))
return
ncolor = sanitize_hexcolor(ncolor, 6, TRUE, old_color)
if(istype(M))
M.color = ncolor
else
L[index] = ncolor
source.update_icon()
return TRUE
/datum/element/polychromic/proc/grant_user_action(atom/source, mob/user, slot)
if(slot == SLOT_IN_BACKPACK || slot == SLOT_LEGCUFFED || slot == SLOT_HANDCUFFED || slot == SLOT_GENERC_DEXTROUS_STORAGE)
return
var/datum/action/polychromic/P = actions_by_atom[source]
if(!P)
P = new (source)
P.name = "Modify [source]'\s Colors"
actions_by_atom[source] = P
P.check_flags = AB_CHECK_RESTRAINED|AB_CHECK_STUN|AB_CHECK_CONSCIOUS
RegisterSignal(P, COMSIG_ACTION_TRIGGER, .proc/activate_action)
P.Grant(user)
/datum/element/polychromic/proc/remove_user_action(atom/source, mob/user)
var/datum/action/polychromic/P = actions_by_atom[source]
P?.Remove(user)
/datum/element/polychromic/proc/activate_action(datum/action/source, atom/target)
set_color(target, source.owner)
/datum/element/polychromic/proc/on_examine(atom/source, mob/user, list/examine_list)
examine_list += "<span class='notice'>Alt-click to recolor it.</span>"
/datum/element/polychromic/proc/register_helmet(atom/source, obj/item/clothing/head/H)
suit_by_helmet[H] = source
helmet_by_suit[source] = H
colors_by_atom[H] = colors_by_atom[source]
RegisterSignal(H, COMSIG_ATOM_UPDATE_OVERLAYS, .proc/apply_overlays)
RegisterSignal(H, COMSIG_ITEM_WORN_OVERLAYS, .proc/apply_worn_overlays)
RegisterSignal(H, COMSIG_PARENT_QDELETING, .proc/unregister_helmet)
/datum/element/polychromic/proc/unregister_helmet(atom/source)
var/obj/item/clothing/suit/S = suit_by_helmet[source]
suit_by_helmet -= source
helmet_by_suit -= S
colors_by_atom -= source
/datum/action/polychromic
name = "Modify Polychromic Colors"
background_icon_state = "bg_polychromic"
use_target_appearance = TRUE
button_icon_state = null
target_appearance_matrix = list(0.8,0,0,0,0.8,0)
+54
View File
@@ -0,0 +1,54 @@
/datum/element/spellcasting //allows to cast certain spells or skip requirements.
element_flags = ELEMENT_BESPOKE|ELEMENT_DETACH
id_arg_index = 2
var/cast_flags
var/cast_slots
var/list/users_by_item = list()
var/list/stacked_spellcasting_by_user = list()
/datum/element/spellcasting/Attach(datum/target, _flags, _slots)
. = ..()
if(isitem(target))
RegisterSignal(target, COMSIG_ITEM_EQUIPPED, .proc/on_equip)
RegisterSignal(target, COMSIG_ITEM_DROPPED, .proc/on_drop)
else if(ismob(target))
RegisterSignal(target, COMSIG_MOB_SPELL_CAN_CAST, .proc/on_cast)
stacked_spellcasting_by_user[target]++
else
return ELEMENT_INCOMPATIBLE
cast_flags = _flags
cast_slots = _slots
/datum/element/spellcasting/Detach(datum/target)
. = ..()
UnregisterSignal(target, list(COMSIG_ITEM_EQUIPPED, COMSIG_ITEM_DROPPED, COMSIG_MOB_SPELL_CAN_CAST))
if(users_by_item[target])
var/mob/user = users_by_item[target]
stacked_spellcasting_by_user[user]--
if(!stacked_spellcasting_by_user[user])
stacked_spellcasting_by_user -= user
UnregisterSignal(user, COMSIG_MOB_SPELL_CAN_CAST)
else if(ismob(target))
stacked_spellcasting_by_user[target]--
if(!stacked_spellcasting_by_user[target])
stacked_spellcasting_by_user -= target
/datum/element/spellcasting/proc/on_equip(datum/source, mob/equipper, slot)
if(!(cast_slots & slotdefine2slotbit(slot)))
return
users_by_item[source] = equipper
if(!stacked_spellcasting_by_user[equipper])
RegisterSignal(equipper, COMSIG_MOB_SPELL_CAN_CAST, .proc/on_cast)
stacked_spellcasting_by_user[equipper]++
/datum/element/spellcasting/proc/on_drop(datum/source, mob/user)
if(!users_by_item[source])
return
users_by_item -= source
stacked_spellcasting_by_user[user]--
if(!stacked_spellcasting_by_user[user])
stacked_spellcasting_by_user -= user
UnregisterSignal(user, COMSIG_MOB_SPELL_CAN_CAST)
/datum/element/spellcasting/proc/on_cast(mob/caster, obj/effect/proc_holder/spell)
return cast_flags
@@ -5,7 +5,7 @@
. = ..()
if(!istype(target, /obj/item))
return ELEMENT_INCOMPATIBLE
RegisterSignal(target, COMSIG_ATOM_UPDATED_ICON, .proc/update_onmob)
RegisterSignal(target, COMSIG_ATOM_UPDATED_ICON, .proc/update_onmob, override = TRUE)
/datum/element/update_icon_updates_onmob/proc/update_onmob(obj/item/target)
if(ismob(target.loc))
+1 -1
View File
@@ -128,7 +128,7 @@
// Can most things breathe?
if(trace_gases)
continue
if(A_gases[/datum/gas/oxygen] >= 16)
if(A_gases[/datum/gas/oxygen] <= 16)
continue
if(A_gases[/datum/gas/plasma])
continue
+1 -1
View File
@@ -73,7 +73,7 @@
var/list/atoms_cache = output_atoms
var/sound/S = sound(soundfile)
if(direct)
S.channel = open_sound_channel()
S.channel = SSsounds.random_available_channel()
S.volume = volume
for(var/i in 1 to atoms_cache.len)
var/atom/thing = atoms_cache[i]
+14 -1
View File
@@ -35,6 +35,17 @@
current_target = new_target
streak = ""
/datum/martial_art/proc/damage_roll(mob/living/carbon/human/A, mob/living/carbon/human/D)
//Here we roll for our damage to be added into the damage var in the various attack procs. This is changed depending on whether we are in combat mode, lying down, or if our target is in combat mode.
var/damage = rand(A.dna.species.punchdamagelow, A.dna.species.punchdamagehigh)
if(!(D.combat_flags & COMBAT_FLAG_COMBAT_ACTIVE))
damage *= 1.5
if(!CHECK_MOBILITY(A, MOBILITY_STAND))
damage *= 0.5
if(!(A.combat_flags & COMBAT_FLAG_COMBAT_ACTIVE))
damage *= 0.25
return damage
/datum/martial_art/proc/teach(mob/living/carbon/human/H, make_temporary = FALSE)
if(!istype(H) || !H.mind)
return FALSE
@@ -50,6 +61,7 @@
if(help_verb)
H.verbs += help_verb
H.mind.martial_art = src
ADD_TRAIT(H, TRAIT_PUGILIST, MARTIAL_ARTIST_TRAIT)
return TRUE
/datum/martial_art/proc/store(datum/martial_art/M,mob/living/carbon/human/H)
@@ -68,7 +80,8 @@
else
var/datum/martial_art/X = H.mind.default_martial_art
X.teach(H)
REMOVE_TRAIT(H, TRAIT_PUGILIST, MARTIAL_ARTIST_TRAIT)
/datum/martial_art/proc/on_remove(mob/living/carbon/human/H)
if(help_verb)
H.verbs -= help_verb
+2 -5
View File
@@ -16,16 +16,13 @@
A.do_attack_animation(D, ATTACK_EFFECT_PUNCH)
var/atk_verb = pick("left hook","right hook","straight punch")
var/damage = rand(10, 13)
var/extra_damage = rand(A.dna.species.punchdamagelow, A.dna.species.punchdamagehigh)
var/extra_damage = damage_roll(A,D)
if(extra_damage == A.dna.species.punchdamagelow)
playsound(D.loc, A.dna.species.miss_sound, 25, 1, -1)
D.visible_message("<span class='warning'>[A] has attempted to [atk_verb] [D]!</span>", \
"<span class='userdanger'>[A] has attempted to [atk_verb] [D]!</span>", null, COMBAT_MESSAGE_RANGE)
log_combat(A, D, "attempted to hit", atk_verb)
return TRUE
damage += extra_damage
var/obj/item/bodypart/affecting = D.get_bodypart(ran_zone(A.zone_selected))
var/armor_block = D.run_armor_check(affecting, "melee")
@@ -35,7 +32,7 @@
D.visible_message("<span class='danger'>[A] has [atk_verb]ed [D]!</span>", \
"<span class='userdanger'>[A] has [atk_verb]ed [D]!</span>", null, COMBAT_MESSAGE_RANGE)
D.apply_damage(damage, STAMINA, affecting, armor_block)
D.apply_damage(rand(10,13) + extra_damage, STAMINA, affecting, armor_block)
log_combat(A, D, "punched (boxing) ")
if(D.getStaminaLoss() > 100 && istype(D.mind?.martial_art, /datum/martial_art/boxing))
var/knockout_prob = (D.getStaminaLoss() + rand(-15,15))*0.75
+25 -17
View File
@@ -42,11 +42,12 @@
/datum/martial_art/cqc/proc/Slam(mob/living/carbon/human/A, mob/living/carbon/human/D)
if(!can_use(A))
return FALSE
var/damage = (damage_roll(A,D) + 5)
if(CHECK_MOBILITY(D, MOBILITY_STAND))
D.visible_message("<span class='warning'>[A] slams [D] into the ground!</span>", \
"<span class='userdanger'>[A] slams you into the ground!</span>")
playsound(get_turf(A), 'sound/weapons/slam.ogg', 50, 1, -1)
D.apply_damage(10, BRUTE)
D.apply_damage(damage, BRUTE)
D.DefaultCombatKnockdown(120)
log_combat(A, D, "slammed (CQC)")
return TRUE
@@ -54,29 +55,33 @@
/datum/martial_art/cqc/proc/Kick(mob/living/carbon/human/A, mob/living/carbon/human/D)
if(!can_use(A))
return FALSE
if(CHECK_MOBILITY(D, MOBILITY_STAND))
D.visible_message("<span class='warning'>[A] kicks [D] back!</span>", \
"<span class='userdanger'>[A] kicks you back!</span>")
playsound(get_turf(A), 'sound/weapons/cqchit1.ogg', 50, 1, -1)
var/atom/throw_target = get_edge_target_turf(D, A.dir)
D.throw_at(throw_target, 1, 14, A)
D.apply_damage(10, BRUTE)
log_combat(A, D, "kicked (CQC)")
var/damage = damage_roll(A,D)
if(!CHECK_MOBILITY(D, MOBILITY_STAND) && CHECK_MOBILITY(D, MOBILITY_USE))
log_combat(A, D, "knocked out (Head kick)(CQC)")
D.visible_message("<span class='warning'>[A] kicks [D]'s head, knocking [D.p_them()] out!</span>", \
"<span class='userdanger'>[A] kicks your head, knocking you out!</span>")
playsound(get_turf(A), 'sound/weapons/genhit1.ogg', 50, 1, -1)
D.SetSleeping(300)
D.adjustOrganLoss(ORGAN_SLOT_BRAIN, 15, 150)
D.apply_damage(damage + 5, BRUTE)
var/atom/throw_target = get_edge_target_turf(D, A.dir)
D.throw_at(throw_target, 1, 14, A)
D.adjustOrganLoss(ORGAN_SLOT_BRAIN, damage + 10, 150)
else
D.visible_message("<span class='warning'>[A] kicks [D]!</span>", \
"<span class='userdanger'>[A] kicks you!</span>")
playsound(get_turf(A), 'sound/weapons/cqchit1.ogg', 50, 1, -1)
D.Dizzy(damage)
D.apply_damage(damage + 15, BRUTE)
log_combat(A, D, "kicked (CQC)")
return TRUE
/datum/martial_art/cqc/proc/Pressure(mob/living/carbon/human/A, mob/living/carbon/human/D)
if(!can_use(A))
return FALSE
var/damage = (damage_roll(A,D) + 55)
log_combat(A, D, "pressured (CQC)")
D.visible_message("<span class='warning'>[A] punches [D]'s neck!</span>")
D.adjustStaminaLoss(60)
D.apply_damage(damage, STAMINA)
playsound(get_turf(A), 'sound/weapons/cqchit1.ogg', 50, 1, -1)
return TRUE
@@ -85,11 +90,12 @@
return
if(!can_use(A))
return FALSE
var/damage = (damage_roll(A,D) + 15)
if(!D.stat)
log_combat(A, D, "restrained (CQC)")
D.visible_message("<span class='warning'>[A] locks [D] into a restraining position!</span>", \
"<span class='userdanger'>[A] locks you into a restraining position!</span>")
D.adjustStaminaLoss(20)
D.apply_damage(damage, STAMINA)
D.Stun(100)
restraining = TRUE
addtimer(VARSET_CALLBACK(src, restraining, FALSE), 50, TIMER_UNIQUE)
@@ -98,6 +104,7 @@
/datum/martial_art/cqc/proc/Consecutive(mob/living/carbon/human/A, mob/living/carbon/human/D)
if(!can_use(A))
return FALSE
var/damage = damage_roll(A,D)
if(!D.stat)
log_combat(A, D, "consecutive CQC'd (CQC)")
D.visible_message("<span class='warning'>[A] strikes [D]'s abdomen, neck and back consecutively</span>", \
@@ -106,8 +113,8 @@
var/obj/item/I = D.get_active_held_item()
if(I && D.temporarilyRemoveItemFromInventory(I))
A.put_in_hands(I)
D.adjustStaminaLoss(50)
D.apply_damage(25, BRUTE)
D.apply_damage(damage + 45, STAMINA)
D.apply_damage(damage + 20, BRUTE)
return TRUE
/datum/martial_art/cqc/grab_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
@@ -135,7 +142,7 @@
log_combat(A, D, "attacked (CQC)")
A.do_attack_animation(D)
var/picked_hit_type = pick("CQC'd", "Big Bossed")
var/bonus_damage = 13
var/bonus_damage = (damage_roll(A,D) + 7)
if(!CHECK_MOBILITY(D, MOBILITY_STAND))
bonus_damage += 5
picked_hit_type = "stomps on"
@@ -151,7 +158,7 @@
D.visible_message("<span class='warning'>[A] leg sweeps [D]!", \
"<span class='userdanger'>[A] leg sweeps you!</span>")
playsound(get_turf(A), 'sound/effects/hit_kick.ogg', 50, 1, -1)
D.apply_damage(10, BRUTE)
D.apply_damage(bonus_damage, BRUTE)
D.DefaultCombatKnockdown(60)
log_combat(A, D, "sweeped (CQC)")
return TRUE
@@ -161,6 +168,7 @@
return FALSE
add_to_streak("D",D)
var/obj/item/I = null
var/damage = (damage_roll(A,D)*0.5)
if(check_streak(A,D))
return TRUE
if(prob(65))
@@ -172,7 +180,7 @@
if(I && D.temporarilyRemoveItemFromInventory(I))
A.put_in_hands(I)
D.Jitter(2)
D.apply_damage(5, BRUTE)
D.apply_damage(damage, BRUTE)
else
D.visible_message("<span class='danger'>[A] attempted to disarm [D]!</span>", \
"<span class='userdanger'>[A] attempted to disarm [D]!</span>")
+51 -34
View File
@@ -84,64 +84,71 @@
if("neck_chop")
streak = ""
neck_chop(A,D)
return 1
return TRUE
if("leg_sweep")
streak = ""
leg_sweep(A,D)
return 1
return TRUE
if("quick_choke")//is actually lung punch
streak = ""
quick_choke(A,D)
return 1
return 0
return TRUE
return FALSE
/datum/martial_art/krav_maga/proc/leg_sweep(mob/living/carbon/human/A, mob/living/carbon/human/D)
var/obj/item/bodypart/affecting = D.get_bodypart(BODY_ZONE_CHEST)
var/armor_block = D.run_armor_check(affecting, "melee")
var/damage = damage_roll(A,D)
if(!CHECK_MOBILITY(D, MOBILITY_STAND))
return 0
return FALSE
D.visible_message("<span class='warning'>[A] leg sweeps [D]!</span>", \
"<span class='userdanger'>[A] leg sweeps you!</span>")
playsound(get_turf(A), 'sound/effects/hit_kick.ogg', 50, 1, -1)
D.apply_damage(5, BRUTE)
D.DefaultCombatKnockdown(40, override_hardstun = 0.01, override_stamdmg = 25)
D.apply_damage(damage + 25, STAMINA, affecting, armor_block)
D.DefaultCombatKnockdown(80, override_hardstun = 1, override_stamdmg = 0)
log_combat(A, D, "leg sweeped")
return 1
return TRUE
/datum/martial_art/krav_maga/proc/quick_choke(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)//is actually lung punch
var/damage = damage_roll(A,D)
D.visible_message("<span class='warning'>[A] pounds [D] on the chest!</span>", \
"<span class='userdanger'>[A] slams your chest! You can't breathe!</span>")
playsound(get_turf(A), 'sound/effects/hit_punch.ogg', 50, 1, -1)
if(D.losebreath <= 10)
D.losebreath = CLAMP(D.losebreath + 5, 0, 10)
D.adjustOxyLoss(10)
D.adjustOxyLoss(damage + 5)
log_combat(A, D, "quickchoked")
return 1
return TRUE
/datum/martial_art/krav_maga/proc/neck_chop(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
var/damage = (damage_roll(A,D)*0.5)
D.visible_message("<span class='warning'>[A] karate chops [D]'s neck!</span>", \
"<span class='userdanger'>[A] karate chops your neck, rendering you unable to speak!</span>")
playsound(get_turf(A), 'sound/effects/hit_punch.ogg', 50, 1, -1)
D.apply_damage(5, BRUTE)
D.apply_damage(damage, BRUTE)
if(D.silent <= 10)
D.silent = CLAMP(D.silent + 10, 0, 10)
log_combat(A, D, "neck chopped")
return 1
return TRUE
/datum/martial_art/krav_maga/grab_act(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
if(check_streak(A,D))
return 1
return TRUE
log_combat(A, D, "grabbed (Krav Maga)")
..()
/datum/martial_art/krav_maga/harm_act(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
var/obj/item/bodypart/affecting = D.get_bodypart(ran_zone(A.zone_selected))
var/armor_block = D.run_armor_check(affecting, "melee")
if(check_streak(A,D))
return 1
return TRUE
log_combat(A, D, "punched")
var/picked_hit_type = pick("punches", "kicks")
var/bonus_damage = 10
if(CHECK_MOBILITY(D, MOBILITY_STAND))
bonus_damage += 5
var/bonus_damage = damage_roll(A,D)
if(!CHECK_MOBILITY(D, MOBILITY_STAND))
bonus_damage += 10
picked_hit_type = "stomps on"
D.apply_damage(bonus_damage, BRUTE)
D.apply_damage(bonus_damage, BRUTE, affecting, armor_block)
if(picked_hit_type == "kicks" || picked_hit_type == "stomps on")
A.do_attack_animation(D, ATTACK_EFFECT_KICK)
playsound(get_turf(D), 'sound/effects/hit_kick.ogg', 50, 1, -1)
@@ -151,24 +158,34 @@
D.visible_message("<span class='danger'>[A] [picked_hit_type] [D]!</span>", \
"<span class='userdanger'>[A] [picked_hit_type] you!</span>")
log_combat(A, D, "[picked_hit_type] with [name]")
return 1
return TRUE
/datum/martial_art/krav_maga/disarm_act(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
var/obj/item/I = null
if(prob(60))
I = D.get_active_held_item()
if(I)
if(D.temporarilyRemoveItemFromInventory(I))
A.put_in_hands(I)
D.visible_message("<span class='danger'>[A] has disarmed [D]!</span>", \
"<span class='userdanger'>[A] has disarmed [D]!</span>")
playsound(D, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
/datum/martial_art/krav_maga/disarm_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
if(check_streak(A,D))
return TRUE
var/obj/item/bodypart/affecting = D.get_bodypart(ran_zone(A.zone_selected))
var/armor_block = D.run_armor_check(affecting, "melee")
var/damage = (damage_roll(A,D)*2)
if(D.mobility_flags & MOBILITY_STAND)
D.visible_message("<span class='danger'>[A] reprimands [D]!</span>", \
"<span class='userdanger'>You're slapped by [A]!</span>", "<span class='hear'>You hear a sickening sound of flesh hitting flesh!</span>", COMBAT_MESSAGE_RANGE, A)
to_chat(A, "<span class='danger'>You jab [D]!</span>")
A.do_attack_animation(D, ATTACK_EFFECT_PUNCH)
playsound(D, 'sound/effects/hit_punch.ogg', 50, TRUE, -1)
D.apply_damage(damage + 5, STAMINA, affecting, armor_block)
log_combat(A, D, "punched nonlethally")
else
D.visible_message("<span class='danger'>[A] attempted to disarm [D]!</span>", \
"<span class='userdanger'>[A] attempted to disarm [D]!</span>")
playsound(D, 'sound/weapons/punchmiss.ogg', 25, 1, -1)
log_combat(A, D, "disarmed (Krav Maga)", "[I ? " removing \the [I]" : ""]")
return 1
D.visible_message("<span class='danger'>[A] reprimands [D]!</span>", \
"<span class='userdanger'>You're manhandled by [A]!</span>", "<span class='hear'>You hear a sickening sound of flesh hitting flesh!</span>", COMBAT_MESSAGE_RANGE, A)
to_chat(A, "<span class='danger'>You stomp [D]!</span>")
A.do_attack_animation(D, ATTACK_EFFECT_KICK)
playsound(D, 'sound/effects/hit_punch.ogg', 50, TRUE, -1)
D.apply_damage(damage + 10, STAMINA, affecting, armor_block)
log_combat(A, D, "stomped nonlethally")
if(prob(D.getStaminaLoss()))
D.visible_message("<span class='warning'>[D] sputters and recoils in pain!</span>", "<span class='userdanger'>You recoil in pain as you are jabbed in a nerve!</span>")
D.drop_all_held_items()
return TRUE
//Krav Maga Gloves
+2 -1
View File
@@ -4,6 +4,7 @@
/datum/martial_art/mushpunch/harm_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
var/atk_verb
var/damage = (damage_roll(A,D)*3)
to_chat(A, "<span class='spider'>You begin to wind up an attack...</span>")
if(!do_after(A, 25, target = D))
to_chat(A, "<span class='spider'><b>Your attack was interrupted!</b></span>")
@@ -12,7 +13,7 @@
atk_verb = pick("punches", "smashes", "ruptures", "cracks")
D.visible_message("<span class='danger'>[A] [atk_verb] [D] with inhuman strength, sending [D.p_them()] flying backwards!</span>", \
"<span class='userdanger'>[A] [atk_verb] you with inhuman strength, sending you flying backwards!</span>")
D.apply_damage(rand(15,30), BRUTE)
D.apply_damage(damage, BRUTE) //KAPOW
playsound(D, 'sound/effects/meteorimpact.ogg', 25, 1, -1)
var/throwtarget = get_edge_target_turf(A, get_dir(A, get_step_away(D, A)))
D.throw_at(throwtarget, 4, 2, A)//So stuff gets tossed around at the same time.
+2
View File
@@ -44,11 +44,13 @@
return
/datum/martial_art/plasma_fist/proc/Throwback(mob/living/carbon/human/A, mob/living/carbon/human/D)
var/damage = (damage_roll(A,D)*3)
D.visible_message("<span class='danger'>[A] has hit [D] with Plasma Punch!</span>", \
"<span class='userdanger'>[A] has hit [D] with Plasma Punch!</span>")
playsound(D.loc, 'sound/weapons/punch1.ogg', 50, 1, -1)
var/atom/throw_target = get_edge_target_turf(D, get_dir(D, get_step_away(D, A)))
D.throw_at(throw_target, 200, 4,A)
D.apply_damage(damage, BRUTE)
A.say("HYAH!", forced="plasma fist")
log_combat(A, D, "threw back (Plasma Fist)")
return
+5 -4
View File
@@ -14,6 +14,7 @@
/datum/martial_art/psychotic_brawling/proc/psycho_attack(mob/living/carbon/human/A, mob/living/carbon/human/D)
var/atk_verb
var/damage = damage_roll(A,D)
switch(rand(1,8))
if(1)
D.help_shake_act(A)
@@ -44,10 +45,10 @@
D.visible_message("<span class='danger'>[A] [atk_verb] [D]!</span>", \
"<span class='userdanger'>[A] [atk_verb] you!</span>")
playsound(get_turf(D), 'sound/weapons/punch1.ogg', 40, 1, -1)
D.apply_damage(rand(5,10), BRUTE, BODY_ZONE_HEAD)
A.apply_damage(rand(5,10), BRUTE, BODY_ZONE_HEAD)
D.apply_damage(damage*1.5, BRUTE, BODY_ZONE_HEAD)
A.apply_damage(damage, BRUTE, BODY_ZONE_HEAD)
if(!istype(D.head,/obj/item/clothing/head/helmet/) && !istype(D.head,/obj/item/clothing/head/hardhat))
D.adjustOrganLoss(ORGAN_SLOT_BRAIN, 5)
D.adjustOrganLoss(ORGAN_SLOT_BRAIN, damage)
A.Stun(rand(10,45))
D.DefaultCombatKnockdown(rand(5,30))//CIT CHANGE - makes stuns from martial arts always use Knockdown instead of Stun for the sake of consistency
if(5,6)
@@ -55,7 +56,7 @@
atk_verb = pick("punches", "kicks", "hits", "slams into")
D.visible_message("<span class='danger'>[A] [atk_verb] [D] with inhuman strength, sending [D.p_them()] flying backwards!</span>", \
"<span class='userdanger'>[A] [atk_verb] you with inhuman strength, sending you flying backwards!</span>")
D.apply_damage(rand(15,30), BRUTE)
D.apply_damage(damage*2, BRUTE)
playsound(get_turf(D), 'sound/effects/meteorimpact.ogg', 25, 1, -1)
var/throwtarget = get_edge_target_turf(A, get_dir(A, get_step_away(D, A)))
D.throw_at(throwtarget, 4, 2, A)//So stuff gets tossed around at the same time.
+10 -6
View File
@@ -78,6 +78,7 @@
return TRUE
/datum/martial_art/the_rising_bass/proc/sideKick(mob/living/carbon/human/A, mob/living/carbon/human/D)
var/damage = (damage_roll(A,D)*0.5)
if(CHECK_MOBILITY(D, MOBILITY_STAND))
var/dir = A.dir & (NORTH | SOUTH) ? pick(EAST, WEST) : pick(NORTH, SOUTH)
var/oppdir = dir == NORTH ? SOUTH : dir == SOUTH ? NORTH : dir == EAST ? WEST : EAST
@@ -87,7 +88,7 @@
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.apply_damage(damage, BRUTE, BODY_ZONE_CHEST)
D.DefaultCombatKnockdown(60)
var/L = !checkfordensity(H,D) ? (!checkfordensity(K,D) ? D.loc : K) : H
D.forceMove(L)
@@ -96,6 +97,7 @@
return TRUE
/datum/martial_art/the_rising_bass/proc/shoulderFlip(mob/living/carbon/human/A, mob/living/carbon/human/D)
var/damage = (damage_roll(A,D) + 25)
if(CHECK_MOBILITY(D, MOBILITY_STAND))
var/turf/H = get_step(A, get_dir(D,A))
var/L = checkfordensity(H,D) ? H : A.loc
@@ -104,8 +106,8 @@
"<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.apply_damage(damage, BRUTE, BODY_ZONE_CHEST)
D.apply_damage(damage, BRUTE, BODY_ZONE_HEAD)
D.Sleeping(60)
D.DefaultCombatKnockdown(300)
D.forceMove(L)
@@ -114,6 +116,7 @@
return FALSE
/datum/martial_art/the_rising_bass/proc/repulsePunch(mob/living/carbon/human/A, mob/living/carbon/human/D)
var/damage = damage_roll(A,D)
if(CHECK_MOBILITY(D, MOBILITY_STAND) && repulsecool < world.time)
A.do_attack_animation(D, ATTACK_EFFECT_PUNCH)
D.visible_message("<span class='warning'>[A] smashes [D] in the chest, throwing them away!</span>", \
@@ -121,7 +124,7 @@
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.apply_damage(damage, BRUTE, BODY_ZONE_CHEST)
D.DefaultCombatKnockdown(90)
log_combat(A, D, "repulse punched (Rising Bass)")
repulsecool = world.time + 3 SECONDS
@@ -129,12 +132,13 @@
return FALSE
/datum/martial_art/the_rising_bass/proc/footSmash(mob/living/carbon/human/A, mob/living/carbon/human/D)
var/damage = (damage_roll(A,D)*0.5)
if(CHECK_MOBILITY(D, MOBILITY_STAND))
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.apply_damage(damage, 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 TRUE
@@ -181,7 +185,7 @@
. = ..()
if(A.incapacitated(FALSE, TRUE)) //NO STUN
return BULLET_ACT_HIT
if(!(A.mobility_flags & MOBILITY_USE)) //NO UNABLE TO USE
if(!CHECK_ALL_MOBILITY(A, MOBILITY_USE|MOBILITY_STAND)) //NO UNABLE TO USE, NO DODGING ON THE FLOOR
return BULLET_ACT_HIT
if(A.dna && A.dna.check_mutation(HULK)) //NO HULK
return BULLET_ACT_HIT
+21 -18
View File
@@ -31,45 +31,48 @@
var/atk_verb = pick("precisely kick", "brutally chop", "cleanly hit", "viciously slam")
///this is the critical hit damage added to the attack if it rolls, it starts at 0 because it'll be changed when rolled
var/crit_damage = 0
var/damage = damage_roll(A,D)
D.visible_message("<span class='danger'>[A] [atk_verb]s [D]!</span>", \
"<span class='userdanger'>[A] [atk_verb]s you!</span>", null, null, A)
to_chat(A, "<span class='danger'>You [atk_verb] [D]!</span>")
if(prob(10))
crit_damage += 20
crit_damage += (damage*2 + 15)
playsound(get_turf(D), 'sound/weapons/bite.ogg', 50, TRUE, -1)
D.visible_message("<span class='warning'>[D] sputters blood as the blow strikes them with inhuman force!</span>", "<span class='userdanger'>You are struck with incredible precision by [A]!</span>")
D.visible_message("<span class='warning'>[D] staggers as the blow strikes them with inhuman force!</span>", "<span class='userdanger'>You are struck with incredible precision by [A]!</span>")
log_combat(A, D, "critcal strong punched (Sleeping Carp)")//log it here because a critical can swing for 40 force and it's important for the sake of how hard they hit
else
playsound(get_turf(D), 'sound/weapons/punch1.ogg', 25, TRUE, -1)
log_combat(A, D, "strong punched (Sleeping Carp)")//so as to not double up on logging
D.apply_damage(20 + crit_damage, BRUTE, affecting)
D.apply_damage((damage + 15) + crit_damage, BRUTE, affecting)
return
///Crashing Wave Kick: Harm Disarm combo, throws people seven tiles backwards
/datum/martial_art/the_sleeping_carp/proc/launchKick(mob/living/carbon/human/A, mob/living/carbon/human/D)
var/damage = (damage_roll(A,D) + 15)
A.do_attack_animation(D, ATTACK_EFFECT_KICK)
D.visible_message("<span class='warning'>[A] kicks [D] square in the chest, sending them flying!</span>", \
"<span class='userdanger'>You are kicked square in the chest by [A], sending you flying!</span>", "<span class='hear'>You hear a sickening sound of flesh hitting flesh!</span>", COMBAT_MESSAGE_RANGE, A)
playsound(get_turf(A), 'sound/effects/hit_kick.ogg', 50, TRUE, -1)
var/atom/throw_target = get_edge_target_turf(D, A.dir)
D.throw_at(throw_target, 7, 14, A)
D.apply_damage(15, BRUTE, BODY_ZONE_CHEST)
D.apply_damage(damage, BRUTE, BODY_ZONE_CHEST)
log_combat(A, D, "launchkicked (Sleeping Carp)")
return
///Keelhaul: Harm Grab combo, knocks people down, deals stamina damage while they're on the floor
/datum/martial_art/the_sleeping_carp/proc/dropKick(mob/living/carbon/human/A, mob/living/carbon/human/D)
var/damage = damage_roll(A,D)
A.do_attack_animation(D, ATTACK_EFFECT_KICK)
playsound(get_turf(A), 'sound/effects/hit_kick.ogg', 50, TRUE, -1)
if((D.mobility_flags & MOBILITY_STAND))
D.apply_damage(10, BRUTE, BODY_ZONE_HEAD)
D.DefaultCombatKnockdown(50)
D.adjustStaminaLoss(40) //A cit specific change form the tg port to really punish anyone who tries to stand up
D.apply_damage(damage, BRUTE, BODY_ZONE_HEAD)
D.DefaultCombatKnockdown(50, override_hardstun = 0.01, override_stamdmg = 0)
D.apply_damage(damage + 35, STAMINA, BODY_ZONE_HEAD) //A cit specific change form the tg port to really punish anyone who tries to stand up
D.visible_message("<span class='warning'>[A] kicks [D] in the head, sending them face first into the floor!</span>", \
"<span class='userdanger'>You are kicked in the head by [A], sending you crashing to the floor!</span>", "<span class='hear'>You hear a sickening sound of flesh hitting flesh!</span>", COMBAT_MESSAGE_RANGE, A)
if(!(D.mobility_flags & MOBILITY_STAND))
D.apply_damage(5, BRUTE, BODY_ZONE_HEAD)
D.adjustStaminaLoss(40)
else
D.apply_damage(damage*0.5, BRUTE, BODY_ZONE_HEAD)
D.apply_damage(damage + 35, STAMINA, BODY_ZONE_HEAD)
D.drop_all_held_items()
D.visible_message("<span class='warning'>[A] kicks [D] in the head!</span>", \
"<span class='userdanger'>You are kicked in the head by [A]!</span>", "<span class='hear'>You hear a sickening sound of flesh hitting flesh!</span>", COMBAT_MESSAGE_RANGE, A)
@@ -85,6 +88,7 @@
/datum/martial_art/the_sleeping_carp/harm_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
add_to_streak("H",D)
var/damage = (damage_roll(A,D) + 5)
if(check_streak(A,D))
return TRUE
var/obj/item/bodypart/affecting = D.get_bodypart(ran_zone(A.zone_selected))
@@ -93,7 +97,7 @@
D.visible_message("<span class='danger'>[A] [atk_verb]s [D]!</span>", \
"<span class='userdanger'>[A] [atk_verb]s you!</span>", null, null, A)
to_chat(A, "<span class='danger'>You [atk_verb] [D]!</span>")
D.apply_damage(rand(10,15), BRUTE, affecting)
D.apply_damage(damage, BRUTE, affecting)
playsound(get_turf(D), 'sound/weapons/punch1.ogg', 25, TRUE, -1)
log_combat(A, D, "punched (Sleeping Carp)")
return TRUE
@@ -110,7 +114,7 @@
. = ..()
if(A.incapacitated(FALSE, TRUE)) //NO STUN
return BULLET_ACT_HIT
if(!(A.mobility_flags & MOBILITY_USE)) //NO UNABLE TO USE
if(!CHECK_ALL_MOBILITY(A, MOBILITY_USE|MOBILITY_STAND)) //NO UNABLE TO USE, NO DEFLECTION ON THE FLOOR
return BULLET_ACT_HIT
if(A.dna && A.dna.check_mutation(HULK)) //NO HULK
return BULLET_ACT_HIT
@@ -121,6 +125,7 @@
playsound(get_turf(A), pick('sound/weapons/bulletflyby.ogg', 'sound/weapons/bulletflyby2.ogg', 'sound/weapons/bulletflyby3.ogg'), 75, TRUE)
P.firer = A
P.setAngle(rand(0, 360))//SHING
A.adjustStaminaLossBuffered (3) //Citadel change to stop infinite bullet sponging as you run away, but it is buffered!
return BULLET_ACT_FORCE_PIERCE
return BULLET_ACT_HIT
@@ -133,7 +138,6 @@
ADD_TRAIT(H, TRAIT_NODISMEMBER, SLEEPING_CARP_TRAIT)
H.physiology.brute_mod *= 0.4 //brute is really not gonna cut it
H.physiology.burn_mod *= 0.7 //burn is distinctly more useful against them than brute but they're still resistant
H.physiology.stamina_mod *= 0.5 //stun batons prove to be one of the few ways to fight them. They have stun resistance already, so I think doubling down too hard on this resistance is a bit much.
H.physiology.stun_mod *= 0.3 //for those rare stuns
H.physiology.pressure_mod *= 0.3 //go hang out with carp
H.physiology.cold_mod *= 0.3 //cold mods are different to burn mods, they do stack however
@@ -148,7 +152,6 @@
REMOVE_TRAIT(H, TRAIT_NODISMEMBER, SLEEPING_CARP_TRAIT)
H.physiology.brute_mod = initial(H.physiology.brute_mod)
H.physiology.burn_mod = initial(H.physiology.burn_mod)
H.physiology.stamina_mod = initial(H.physiology.stamina_mod)
H.physiology.stun_mod = initial(H.physiology.stun_mod)
H.physiology.pressure_mod = initial(H.physiology.pressure_mod) //no more carpies
H.physiology.cold_mod = initial(H.physiology.cold_mod)
@@ -237,7 +240,7 @@
else
return ..()
/obj/item/twohanded/bostaff/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
if(wielded)
return ..()
return FALSE
/obj/item/twohanded/bostaff/run_block(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
if(!wielded)
return BLOCK_NONE
return ..()
+58 -32
View File
@@ -18,28 +18,30 @@
var/datum/action/drop/drop = new/datum/action/drop()
/datum/martial_art/wrestling/proc/check_streak(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
if(!can_use(A, D))
return FALSE
switch(streak)
if("drop")
streak = ""
drop(A,D)
return 1
return TRUE
if("strike")
streak = ""
strike(A,D)
return 1
return TRUE
if("kick")
streak = ""
kick(A,D)
return 1
return TRUE
if("throw")
streak = ""
throw_wrassle(A,D)
return 1
return TRUE
if("slam")
streak = ""
slam(A,D)
return 1
return 0
return TRUE
return FALSE
/datum/action/slam
name = "Slam (Cinch) - Slam a grappled opponent into the floor."
@@ -136,7 +138,7 @@
/datum/martial_art/wrestling/harm_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
if(check_streak(A,D))
return 1
return TRUE
log_combat(A, D, "punched with wrestling")
..()
@@ -171,11 +173,11 @@
if (get_dist(A, D) > 1)
to_chat(A, "[D] is too far away!")
return 0
return FALSE
if (!isturf(A.loc) || !isturf(D.loc))
to_chat(A, "You can't throw [D] from here!")
return 0
return FALSE
A.setDir(turn(A.dir, 90))
var/turf/T = get_step(A, A.dir)
@@ -184,7 +186,7 @@
D.forceMove(T)
D.setDir(get_dir(D, A))
else
return 0
return FALSE
sleep(delay)
@@ -193,11 +195,11 @@
if (get_dist(A, D) > 1)
to_chat(A, "[D] is too far away!")
return 0
return FALSE
if (!isturf(A.loc) || !isturf(D.loc))
to_chat(A, "You can't throw [D] from here!")
return 0
return FALSE
D.forceMove(A.loc) // Maybe this will help with the wallthrowing bug.
@@ -209,7 +211,7 @@
D.emote("scream")
D.throw_at(T, 10, 4, A, TRUE, TRUE, callback = CALLBACK(D, /mob/living/carbon/human.proc/DefaultCombatKnockdown, 20))
log_combat(A, D, "has thrown with wrestling")
return 0
return FALSE
/datum/martial_art/wrestling/proc/FlipAnimation(mob/living/carbon/human/D)
set waitfor = FALSE
@@ -225,6 +227,7 @@
if(!A.pulling || A.pulling != D)
to_chat(A, "You need to have [D] in a cinch!")
return
var/damage = damage_roll(A,D)
D.forceMove(A.loc)
A.setDir(get_dir(A, D))
D.setDir(get_dir(D, A))
@@ -256,7 +259,7 @@
A.pixel_y = 0
D.pixel_x = 0
D.pixel_y = 0
return 0
return FALSE
if (!isturf(A.loc) || !isturf(D.loc))
to_chat(A, "You can't slam [D] here!")
@@ -264,7 +267,7 @@
A.pixel_y = 0
D.pixel_x = 0
D.pixel_y = 0
return 0
return FALSE
else
if (A)
A.pixel_x = 0
@@ -272,7 +275,7 @@
if (D)
D.pixel_x = 0
D.pixel_y = 0
return 0
return FALSE
sleep(1)
@@ -284,11 +287,11 @@
if (get_dist(A, D) > 1)
to_chat(A, "[D] is too far away!")
return 0
return FALSE
if (!isturf(A.loc) || !isturf(D.loc))
to_chat(A, "You can't slam [D] here!")
return 0
return FALSE
D.forceMove(A.loc)
@@ -307,11 +310,11 @@
switch(rand(1,3))
if (2)
D.adjustBruteLoss(rand(20,30))
D.apply_damage(damage + 25, BRUTE)
if (3)
D.ex_act(EXPLODE_LIGHT)
else
D.adjustBruteLoss(rand(10,20))
D.apply_damage(damage + 15, BRUTE)
else
D.ex_act(EXPLODE_LIGHT)
@@ -325,7 +328,7 @@
log_combat(A, D, "body-slammed")
return 0
return FALSE
/datum/martial_art/wrestling/proc/CheckStrikeTurf(mob/living/carbon/human/A, turf/T)
if (A && (T && isturf(T) && get_dist(A, T) <= 1))
@@ -335,6 +338,7 @@
if(!D)
return
var/turf/T = get_turf(A)
var/damage = damage_roll(A,D)
if (T && isturf(T) && D && isturf(D.loc))
for (var/i = 0, i < 4, i++)
A.setDir(turn(A.dir, 90))
@@ -343,7 +347,7 @@
addtimer(CALLBACK(src, .proc/CheckStrikeTurf, A, T), 4)
A.visible_message("<span class = 'danger'><b>[A] headbutts [D]!</b></span>")
D.adjustBruteLoss(rand(10,20))
D.apply_damage(damage + 15, BRUTE)
playsound(A.loc, "swing_hit", 50, 1)
D.Unconscious(20)
log_combat(A, D, "headbutted")
@@ -351,13 +355,14 @@
/datum/martial_art/wrestling/proc/kick(mob/living/carbon/human/A, mob/living/carbon/human/D)
if(!D)
return
var/damage = damage_roll(A,D)
A.emote("scream")
A.emote("flip")
A.setDir(turn(A.dir, 90))
A.visible_message("<span class = 'danger'><B>[A] roundhouse-kicks [D]!</B></span>")
playsound(A.loc, "swing_hit", 50, 1)
D.adjustBruteLoss(rand(10,20))
D.apply_damage(damage + 15, STAMINA)
var/turf/T = get_edge_target_turf(A, get_dir(A, get_step_away(D, A)))
if (T && isturf(T))
@@ -371,7 +376,8 @@
var/obj/surface = null
var/turf/ST = null
var/falling = 0
var/damage = damage_roll(A,D)
for (var/obj/O in oview(1, A))
if (O.density == 1)
if (O == A)
@@ -399,15 +405,15 @@
A.pixel_y = 0
if (falling == 1)
A.visible_message("<span class = 'danger'><B>...and dives head-first into the ground, ouch!</b></span>")
A.adjustBruteLoss(rand(10,20))
A.apply_damage(damage + 15, BRUTE)
A.DefaultCombatKnockdown(60)
to_chat(A, "[D] is too far away!")
return 0
return FALSE
if (!isturf(A.loc) || !isturf(D.loc))
A.pixel_y = 0
to_chat(A, "You can't drop onto [D] from here!")
return 0
return FALSE
if(A)
animate(A, transform = matrix(90, MATRIX_ROTATE), time = 1, loop = 0)
@@ -425,9 +431,9 @@
if (prob(33) || D.stat)
D.ex_act(EXPLODE_LIGHT)
else
D.adjustBruteLoss(rand(20,30))
D.apply_damage(damage + 25, BRUTE)
else
D.adjustBruteLoss(rand(20,30))
D.apply_damage(damage + 25, BRUTE)
D.DefaultCombatKnockdown(40)
@@ -440,14 +446,18 @@
return
/datum/martial_art/wrestling/disarm_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
damage_roll(A,D)
if(check_streak(A,D))
return 1
return TRUE
log_combat(A, D, "wrestling-disarmed")
..()
/datum/martial_art/wrestling/grab_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
damage_roll(A,D)
if(check_streak(A,D))
return 1
return TRUE
if(!can_use(A,D))
return ..()
if(A.pulling == D || A == D) // don't stun grab yoursel
return FALSE
A.start_pulling(D)
@@ -455,7 +465,7 @@
"<span class='userdanger'>[A] gets [D] in a cinch!</span>")
D.Stun(rand(60,100))
log_combat(A, D, "cinched")
return 1
return TRUE
/obj/item/storage/belt/champion/wrestling
name = "Wrestling Belt"
@@ -476,3 +486,19 @@
if(H.get_item_by_slot(SLOT_BELT) == src)
style.remove(H)
return
//Subtype of wrestling, reserved for the wrestling belts found in the holodeck
/datum/martial_art/wrestling/holodeck
name = "Holodeck Wrestling"
/obj/item/storage/belt/champion/wrestling/holodeck
name = "Holodeck Wrestling Belt"
style = new /datum/martial_art/wrestling/holodeck
//Make sure that moves can only be used on people wearing the holodeck belt
/datum/martial_art/wrestling/holodeck/can_use(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
if(!(istype(D.mind?.martial_art, /datum/martial_art/wrestling/holodeck)))
return FALSE
else
return ..()
-1
View File
@@ -470,7 +470,6 @@
/datum/objective/steal,
/datum/objective/download,
/datum/objective/nuclear,
/datum/objective/capture,
/datum/objective/absorb,
/datum/objective/custom
)
+9
View File
@@ -31,6 +31,7 @@
//MUT_EXTRA - A mutation that is in the mutations tab, and can be given and taken away through though the DNA console. Has a 0 before it's name in the mutation section of the dna console
//MUT_OTHER Cannot be interacted with by players through normal means. I.E. wizards mutate
var/list/conflicts //any mutations that might conflict. put mutation typepath defines in here. make sure to enter it both ways (so that A conflicts with B, and B with A)
var/can_chromosome = CHROMOSOME_NONE //can we take chromosomes? 0: CHROMOSOME_NEVER never, 1:CHROMOSOME_NONE yeah, 2: CHROMOSOME_USED no, already have one
var/chromosome_name //purely cosmetic
var/modified = FALSE //ugly but we really don't want chromosomes and on_acquiring to overlap and apply double the powers
@@ -60,6 +61,14 @@
return TRUE
if(limb_req && !H.get_bodypart(limb_req))
return TRUE
for(var/M in H.dna.mutations)//check for conflicting powers
var/datum/mutation/human/mewtayshun = M
if(LAZYLEN(mewtayshun.conflicts))
for(var/cons in mewtayshun.conflicts)
var/datum/mutation/human/conflicter = cons
if(conflicter == type)
to_chat(H, "<span class='warning'>You feel your genes resisting something.</span>")
return TRUE
owner = H
dna = H.dna
dna.mutations += src
+7 -10
View File
@@ -41,7 +41,7 @@
desc = "You can breathe fire at a target."
school = "evocation"
charge_max = 600
clothes_req = FALSE
clothes_req = NONE
range = 20
base_icon_state = "fireball"
action_icon_state = "fireball0"
@@ -121,7 +121,7 @@
name = "Convoke Void" //magic the gathering joke here
desc = "A rare genome that attracts odd forces not usually observed. May sometimes pull you in randomly."
school = "evocation"
clothes_req = FALSE
clothes_req = NONE
charge_max = 600
invocation = "DOOOOOOOOOOOOOOOOOOOOM!!!"
invocation_type = "shout"
@@ -155,7 +155,7 @@
dropmessage = "You let the electricity from your hand dissipate."
hand_path = /obj/item/melee/touch_attack/shock
charge_max = 400
clothes_req = FALSE
clothes_req = NONE
action_icon_state = "zap"
/obj/item/melee/touch_attack/shock
@@ -211,7 +211,7 @@
name = "Remember the Scent"
desc = "Get a scent off of the item you're currently holding to track it. With an empty hand, you'll track the scent you've remembered."
charge_max = 100
clothes_req = FALSE
clothes_req = NONE
range = -1
include_user = TRUE
action_icon_state = "nose"
@@ -289,8 +289,7 @@
/obj/effect/proc_holder/spell/self/self_amputation
name = "Drop a limb"
desc = "Concentrate to make a random limb pop right off your body."
clothes_req = FALSE
human_req = FALSE
clothes_req = NONE
charge_max = 100
action_icon_state = "autotomy"
@@ -327,8 +326,7 @@
/obj/effect/proc_holder/spell/self/lay_genetic_web
name = "Lay Web"
desc = "Drops a web. Only you will be able to traverse your web easily, making it pretty good for keeping you safe."
clothes_req = FALSE
human_req = FALSE
clothes_req = NONE
charge_max = 4 SECONDS //the same time to lay a web
action_icon = 'icons/mob/actions/actions_genetic.dmi'
action_icon_state = "lay_web"
@@ -369,8 +367,7 @@
/obj/effect/proc_holder/spell/self/tongue_spike
name = "Launch spike"
desc = "Shoot your tongue out in the direction you're facing, embedding it and dealing damage until they remove it."
clothes_req = FALSE
human_req = TRUE
clothes_req = NONE
charge_max = 100
action_icon = 'icons/mob/actions/actions_genetic.dmi'
action_icon_state = "spike"
+4 -2
View File
@@ -75,20 +75,21 @@
quality = POSITIVE
difficulty = 16
instability = 5
conflicts = list(GIGANTISM)
locked = TRUE // Default intert species for now, so locked from regular pool.
/datum/mutation/human/dwarfism/on_acquiring(mob/living/carbon/human/owner)
if(..())
return
owner.transform = owner.transform.Scale(1, 0.8)
owner.pass_flags |= PASSTABLE
passtable_on(owner, GENETIC_MUTATION)
owner.visible_message("<span class='danger'>[owner] suddenly shrinks!</span>", "<span class='notice'>Everything around you seems to grow..</span>")
/datum/mutation/human/dwarfism/on_losing(mob/living/carbon/human/owner)
if(..())
return
owner.transform = owner.transform.Scale(1, 1.25)
owner.pass_flags &= ~PASSTABLE
passtable_off(owner, GENETIC_MUTATION)
owner.visible_message("<span class='danger'>[owner] suddenly grows!</span>", "<span class='notice'>Everything around you seems to shrink..</span>")
@@ -333,6 +334,7 @@
desc = "The cells within the subject spread out to cover more area, making the subject appear larger."
quality = MINOR_NEGATIVE
difficulty = 12
conflicts = list(DWARFISM)
/datum/mutation/human/gigantism/on_acquiring(mob/living/carbon/human/owner)
if(..())
+4
View File
@@ -26,3 +26,7 @@
/datum/generecipe/tonguechem
required = "/datum/mutation/human/tongue_spike; /datum/mutation/human/stimmed"
result = TONGUESPIKECHEM
/datum/generecipe/hulk
required = "/datum/mutation/human/strong; /datum/mutation/human/radioactive"
result = HULK
+1 -1
View File
@@ -117,7 +117,7 @@
continue
contam_atoms += thing
var/did_contam = 0
if(length(can_contam))
if(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]
+8 -3
View File
@@ -113,20 +113,25 @@
duration = set_duration
. = ..()
/datum/status_effect/no_combat_mode/mesmerize
/datum/status_effect/mesmerize
id = "Mesmerize"
alert_type = /obj/screen/alert/status_effect/mesmerized
/datum/status_effect/no_combat_mode/mesmerize/on_creation(mob/living/new_owner, set_duration)
/datum/status_effect/mesmerize/on_creation(mob/living/new_owner, set_duration)
. = ..()
ADD_TRAIT(owner, TRAIT_MUTE, "mesmerize")
owner.add_movespeed_modifier("[STATUS_EFFECT_MESMERIZE]_[id]", TRUE, priority = 64, override = TRUE, multiplicative_slowdown = 5, blacklisted_movetypes = FALSE? NONE : CRAWLING)
/datum/status_effect/no_combat_mode/mesmerize/on_remove()
/datum/status_effect/mesmerize/on_remove()
. = ..()
REMOVE_TRAIT(owner, TRAIT_MUTE, "mesmerize")
owner.remove_movespeed_modifier("[STATUS_EFFECT_MESMERIZE]_[id]")
/datum/status_effect/mesmerize/on_creation(mob/living/new_owner, set_duration)
if(isnum(set_duration))
duration = set_duration
. = ..()
/obj/screen/alert/status_effect/mesmerized
name = "Mesmerized"
desc = "You cant tear your sight from who is in front of you... their gaze is simply too enthralling.."
-1
View File
@@ -38,7 +38,6 @@
..()
if(!istype(holder, holder_type))
CRASH("Wire holder is not of the expected type!")
return
src.holder = holder
if(randomize)
+201 -1
View File
@@ -324,6 +324,11 @@ NOTE: there are two lists of areas in the end of this file: centcom and station
name = "Service Hallway"
icon_state = "hall_service"
/area/hallway/secondary/civilian
name = "Civilian Wing"
icon_state = "hallFS"
//Command
/area/bridge
@@ -1046,7 +1051,6 @@ NOTE: there are two lists of areas in the end of this file: centcom and station
name = "Monastery Garden"
icon_state = "hydro"
//Science
/area/science
@@ -1393,3 +1397,199 @@ NOTE: there are two lists of areas in the end of this file: centcom and station
/area/crew_quarters/fitness/pool
name = "Pool Area"
icon_state = "pool"
/area/crew_quarters/dorms/blue
name = "Blue Dorms"
icon_state = "Sleep"
nightshift_public_area = NIGHTSHIFT_AREA_NONE
/area/crew_quarters/dorms/purple
name = "Purple Dorms"
icon_state = "Sleep"
nightshift_public_area = NIGHTSHIFT_AREA_NONE
/area/crew_quarters/lounge/jazz
name = "Jazz Lounge"
icon_state = "yellow"
ambientsounds = list('sound/ambience/ambidet1.ogg','sound/ambience/ambidet2.ogg')
nightshift_public_area = NIGHTSHIFT_AREA_RECREATION
/area/crew_quarters/fitness/recreation
name = "Recreation Area"
icon_state = "fitness"
nightshift_public_area = NIGHTSHIFT_AREA_RECREATION
/area/crew_quarters/fitness/cogpool
name = "Pool"
icon_state = "fitness"
clockwork_warp_fail = "Pool's closed."
nightshift_public_area = NIGHTSHIFT_AREA_RECREATION
/area/crew_quarters/barbershop
name = "Barbershop"
icon_state = "blue"
nightshift_public_area = NIGHTSHIFT_AREA_RECREATION
/area/crew_quarters/observatory
name = "Observatory"
icon_state = "Sleep"
//Engineering
/area/engine/teg_hot
name = "Hot Loop"
icon_state = "red"
/area/engine/teg_cold
name = "Cold Loop"
icon_state = "blue"
/area/engine/workshop
name = "Engineering Workshop"
icon_state = "engine"
/area/security/courtroom/jury
name = "Jury Room"
icon_state = "courtroom"
/area/quartermaster/miningdock/airless
name = "Mining Dock"
icon_state = "mining"
has_gravity = STANDARD_GRAVITY
valid_territory = FALSE
outdoors = TRUE
ambientsounds = SPACE
blob_allowed = FALSE //While part of the station, what good will it do you?
/area/quartermaster/miningdock/airless/no_grav
name = "Mining Dock"
icon_state = "mining"
dynamic_lighting = DYNAMIC_LIGHTING_IFSTARLIGHT
power_light = FALSE
power_equip = FALSE
power_environ = FALSE
valid_territory = FALSE
outdoors = TRUE
ambientsounds = SPACE
blob_allowed = FALSE //While part of the station, what good will it do you?
/area/janitor/aux
name = "Auxiliary Custodial Closet"
icon_state = "janitor"
flags_1 = NONE
/area/hydroponics/lobby
name = "Hydroponics Lobby"
icon_state = "hydro"
//Storage
/area/storage/emergency/generic
name = "Emergency Storage"
icon_state = "emergencystorage"
//Construction
/area/construction
name = "Construction Area"
icon_state = "yellow"
ambientsounds = ENGINEERING
/area/construction/secondary
name = "Secondary Construction Area"
icon_state = "yellow"
/area/construction/minisat_exterior
name = "Minisat Exterior"
icon_state = "yellow"
/area/construction/mining/aux_base
name = "Auxiliary Base Construction"
icon_state = "yellow"
/area/construction/mining/aux_base/closet
name = "Auxiliary Closet Construction"
icon_state = "yellow"
/area/construction/supplyshuttle
name = "Supply Shuttle"
icon_state = "yellow"
/area/construction/quarters
name = "Engineers' Quarters"
icon_state = "yellow"
/area/construction/qmaint
name = "Maintenance"
icon_state = "yellow"
/area/construction/hallway
name = "Hallway"
icon_state = "yellow"
/area/construction/solars
name = "Solar Panels"
icon_state = "yellow"
/area/construction/solarscontrol
name = "Solar Panel Control"
icon_state = "yellow"
/area/construction/storage
name = "Construction Site Storage"
icon_state = "yellow"
/area/construction/storage/wing
name = "Storage Wing"
icon_state = "storage_wing"
//Routers
/area/router
name = "Router"
icon_state = "yellow"
ambientsounds = ENGINEERING
/area/router/service
name = "Service Router"
icon_state = "green"
/area/router/public
name = "Public Router"
icon_state = "yellow"
/area/router/sec
name = "Security Router"
icon_state = "blue"
/area/router/medsci
name = "MedSci Router"
icon_state = "yellow"
/area/router/eva
name = "EVA Router"
icon_state = "yellow"
/area/router/air
name = "Airbridge Router"
icon_state = "red"
/area/router/eng
name = "Engineering Router"
icon_state = "yellow"
/area/router/aux
name = "Routing System"
icon_state = "yellow"
requires_power = FALSE
has_gravity = STANDARD_GRAVITY
always_unpowered = TRUE
dynamic_lighting = DYNAMIC_LIGHTING_IFSTARLIGHT
power_light = FALSE
power_equip = FALSE
power_environ = FALSE
valid_territory = FALSE
outdoors = TRUE
ambientsounds = SPACE
blob_allowed = FALSE //While part of the station, what good will it do you?
+1
View File
@@ -63,6 +63,7 @@
var/xenobiology_compatible = FALSE //Can the Xenobio management console transverse this area by default?
var/list/canSmoothWithAreas //typecache to limit the areas that atoms in this area can smooth with
/// Color on minimaps, if it's null (which is default) it makes one at random.
var/minimap_color
+7
View File
@@ -6,6 +6,8 @@
hidden = TRUE
var/obj/machinery/computer/holodeck/linked
var/list/compatible_holodeck_comps
var/abstract_type = /area/holodeck
var/restricted = 0 // if true, program goes on emag list
/*
@@ -53,6 +55,8 @@
*/
/area/holodeck/rec_center
name = "\improper Recreational Holodeck"
compatible_holodeck_comps = list(/obj/machinery/computer/holodeck)
abstract_type = /area/holodeck/rec_center
/area/holodeck/rec_center/offline
name = "Holodeck - Offline"
@@ -99,6 +103,9 @@
/area/holodeck/rec_center/winterwonderland
name = "Holodeck - Winter Wonderland"
/area/holodeck/rec_center/wrestlingarena
name = "Holodeck - Wrestling Arena"
// Bad programs
/area/holodeck/rec_center/burn
+61 -8
View File
@@ -694,14 +694,64 @@
/atom/vv_get_dropdown()
. = ..()
. += "---"
var/turf/curturf = get_turf(src)
if (curturf)
.["Jump to"] = "?_src_=holder;[HrefToken()];adminplayerobservecoodjump=1;X=[curturf.x];Y=[curturf.y];Z=[curturf.z]"
.["Modify Transform"] = "?_src_=vars;[HrefToken()];modtransform=[REF(src)]"
.["Add reagent"] = "?_src_=vars;[HrefToken()];addreagent=[REF(src)]"
.["Trigger EM pulse"] = "?_src_=vars;[HrefToken()];emp=[REF(src)]"
.["Trigger explosion"] = "?_src_=vars;[HrefToken()];explode=[REF(src)]"
VV_DROPDOWN_OPTION("", "---------")
if(!ismovableatom(src))
var/turf/curturf = get_turf(src)
if(curturf)
. += "<option value='?_src_=holder;[HrefToken()];adminplayerobservecoodjump=1;X=[curturf.x];Y=[curturf.y];Z=[curturf.z]'>Jump To</option>"
VV_DROPDOWN_OPTION(VV_HK_MODIFY_TRANSFORM, "Modify Transform")
VV_DROPDOWN_OPTION(VV_HK_ADD_REAGENT, "Add Reagent")
VV_DROPDOWN_OPTION(VV_HK_TRIGGER_EMP, "EMP Pulse")
VV_DROPDOWN_OPTION(VV_HK_TRIGGER_EXPLOSION, "Explosion")
/atom/vv_do_topic(list/href_list)
. = ..()
if(href_list[VV_HK_ADD_REAGENT] && check_rights(R_VAREDIT))
if(!reagents)
var/amount = input(usr, "Specify the reagent size of [src]", "Set Reagent Size", 50) as num
if(amount)
create_reagents(amount)
if(reagents)
var/chosen_id = choose_reagent_id(usr)
if(chosen_id)
var/amount = input(usr, "Choose the amount to add.", "Choose the amount.", reagents.maximum_volume) as num
if(amount)
reagents.add_reagent(chosen_id, amount)
log_admin("[key_name(usr)] has added [amount] units of [chosen_id] to [src]")
message_admins("<span class='notice'>[key_name(usr)] has added [amount] units of [chosen_id] to [src]</span>")
if(href_list[VV_HK_TRIGGER_EXPLOSION] && check_rights(R_FUN))
usr.client.cmd_admin_explosion(src)
if(href_list[VV_HK_TRIGGER_EMP] && check_rights(R_FUN))
usr.client.cmd_admin_emp(src)
if(href_list[VV_HK_MODIFY_TRANSFORM] && check_rights(R_VAREDIT))
var/result = input(usr, "Choose the transformation to apply","Transform Mod") as null|anything in list("Scale","Translate","Rotate")
var/matrix/M = transform
switch(result)
if("Scale")
var/x = input(usr, "Choose x mod","Transform Mod") as null|num
var/y = input(usr, "Choose y mod","Transform Mod") as null|num
if(!isnull(x) && !isnull(y))
transform = M.Scale(x,y)
if("Translate")
var/x = input(usr, "Choose x mod","Transform Mod") as null|num
var/y = input(usr, "Choose y mod","Transform Mod") as null|num
if(!isnull(x) && !isnull(y))
transform = M.Translate(x,y)
if("Rotate")
var/angle = input(usr, "Choose angle to rotate","Transform Mod") as null|num
if(!isnull(angle))
transform = M.Turn(angle)
if(href_list[VV_HK_AUTO_RENAME] && check_rights(R_VAREDIT))
var/newname = input(usr, "What do you want to rename this to?", "Automatic Rename") as null|text
if(newname)
vv_auto_rename(newname)
/atom/vv_get_header()
. = ..()
var/refid = REF(src)
. += "[VV_HREF_TARGETREF(refid, VV_HK_AUTO_RENAME, "<b id='name'>[src]</b>")]"
. += "<br><font size='1'><a href='?_src_=vars;[HrefToken()];rotatedatum=[refid];rotatedir=left'><<</a> <a href='?_src_=vars;[HrefToken()];datumedit=[refid];varnameedit=dir' id='dir'>[dir2text(dir) || dir]</a> <a href='?_src_=vars;[HrefToken()];rotatedatum=[refid];rotatedir=right'>>></a></font>"
/atom/proc/drop_location()
var/atom/L = loc
@@ -709,6 +759,9 @@
return null
return L.AllowDrop() ? L : L.drop_location()
/atom/proc/vv_auto_rename(newname)
name = newname
/atom/Entered(atom/movable/AM, atom/oldLoc)
SEND_SIGNAL(src, COMSIG_ATOM_ENTERED, AM, oldLoc)
+2 -3
View File
@@ -468,9 +468,8 @@
/atom/movable/vv_get_dropdown()
. = ..()
. -= "Jump to"
.["Follow"] = "?_src_=holder;[HrefToken()];adminplayerobservefollow=[REF(src)]"
.["Get"] = "?_src_=holder;[HrefToken()];admingetmovable=[REF(src)]"
. += "<option value='?_src_=holder;[HrefToken()];adminplayerobservefollow=[REF(src)]'>Follow</option>"
. += "<option value='?_src_=holder;[HrefToken()];admingetmovable=[REF(src)]'>Get</option>"
/atom/movable/proc/ex_check(ex_id)
if(!ex_id)
-2
View File
@@ -147,7 +147,6 @@
return "health-85"
else
return "health-100"
return "0"
//HOOKS
@@ -323,7 +322,6 @@
return "crit"
else
return "dead"
return "dead"
//Sillycone hooks
/mob/living/silicon/proc/diag_hud_set_health()
@@ -119,7 +119,6 @@ GLOBAL_VAR(changeling_team_objective_type) //If this is not null, we hand our th
C.appearance = chosen_prof.appearance_list[slot]
C.name = chosen_prof.name_list[slot]
C.flags_cover = chosen_prof.flags_cover_list[slot]
C.item_color = chosen_prof.item_color_list[slot]
C.item_state = chosen_prof.item_state_list[slot]
if(equip)
user.equip_to_slot_or_del(C, GLOB.slot2slot[slot])
+8 -6
View File
@@ -45,8 +45,11 @@ Credit where due:
// PROCS //
///////////
/proc/is_servant_of_ratvar(mob/M)
return istype(M) && !isobserver(M) && M.mind && M.mind.has_antag_datum(/datum/antagonist/clockcult)
/proc/is_servant_of_ratvar(mob/M, require_full_power = FALSE, holy_water_check = FALSE)
if(!istype(M) || isobserver(M))
return FALSE
var/datum/antagonist/clockcult/D = M?.mind?.has_antag_datum(/datum/antagonist/clockcult)
return D && (!require_full_power || !D.neutered) && (!holy_water_check || !D.ignore_holy_water)
/proc/is_eligible_servant(mob/M)
if(!istype(M))
@@ -70,12 +73,14 @@ Credit where due:
return TRUE
return FALSE
/proc/add_servant_of_ratvar(mob/L, silent = FALSE, create_team = TRUE)
/proc/add_servant_of_ratvar(mob/L, silent = FALSE, create_team = TRUE, override_type)
if(!L || !L.mind)
return
var/update_type = /datum/antagonist/clockcult
if(silent)
update_type = /datum/antagonist/clockcult/silent
if(override_type) //prioritizes
update_type = override_type
var/datum/antagonist/clockcult/C = new update_type(L.mind)
C.make_team = create_team
C.show_in_roundend = create_team //tutorial scarabs begone
@@ -105,9 +110,6 @@ Credit where due:
L.playsound_local(get_turf(L), 'sound/ambience/antag/clockcultalr.ogg', 40, TRUE, frequency = 100000, pressure_affected = FALSE)
flash_color(L, flash_color = list("#BE8700", "#BE8700", "#BE8700", rgb(0,0,0)), flash_time = 5)
/proc/remove_servant_of_ratvar(mob/L, silent = FALSE)
if(!L || !L.mind)
return
@@ -63,7 +63,7 @@
attack_verb_on = list("slipped")
clumsy_check = FALSE
sharpness = IS_BLUNT
item_color = "yellow"
sword_color = "yellow"
heat = 0
light_color = "#ffff00"
var/next_trombone_allowed = 0
+6 -3
View File
@@ -3,8 +3,11 @@
/datum/game_mode
var/list/datum/mind/cult = list()
/proc/iscultist(mob/living/M)
return istype(M) && M.mind && M.mind.has_antag_datum(/datum/antagonist/cult)
/proc/iscultist(mob/living/M, require_full_power = FALSE, holy_water_check = FALSE)
if(!istype(M))
return FALSE
var/datum/antagonist/cult/D = M?.mind?.has_antag_datum(/datum/antagonist/cult)
return D && (!require_full_power || !D.neutered) && (!holy_water_check || !D.ignore_holy_water)
/datum/team/cult/proc/is_sacrifice_target(datum/mind/mind)
for(var/datum/objective/sacrifice/sac_objective in objectives)
@@ -93,7 +96,7 @@
add_cultist(cult_mind, 0, equip=TRUE)
if(!main_cult)
var/datum/antagonist/cult/C = cult_mind.has_antag_datum(/datum/antagonist/cult,TRUE)
if(C && C.cult_team)
if(C?.cult_team)
main_cult = C.cult_team
..()
+23 -5
View File
@@ -54,12 +54,18 @@ GLOBAL_VAR_INIT(dynamic_storyteller_type, /datum/dynamic_storyteller/classic)
// Current storyteller
var/datum/dynamic_storyteller/storyteller = null
// Threat logging vars
/// Starting threat level, for things that increase it but can bring it back down.
var/initial_threat_level = 0
/// Target threat level right now. Events and antags will try to keep the round at this level.
var/threat_level = 0
/// The current antag threat. Recalculated every time a ruletype starts or ends.
var/threat = 0
/// Starting threat level, for things that increase it but can bring it back down.
var/initial_threat_level = 0
/// Threat average over the course of the round, for endgame logs.
var/threat_average = 0
/// Number of times threat average has been calculated, for calculating above.
var/threat_average_weight = 0
/// Last time a threat average sample was taken. Used for weighting the rolling average.
var/last_threat_sample_time = 0
/// Things that cause a rolling threat adjustment to be displayed at roundend.
var/list/threat_tallies = list()
/// Running information about the threat. Can store text or datum entries.
@@ -199,7 +205,7 @@ GLOBAL_VAR_INIT(dynamic_storyteller_type, /datum/dynamic_storyteller/classic)
if(threatadd > 0)
create_threat(threatadd)
else
spend_threat(-threatadd)
remove_threat(threatadd)
else if (href_list["injectlate"])
latejoin_injection_cooldown = 0
forced_injection = TRUE
@@ -241,6 +247,7 @@ GLOBAL_VAR_INIT(dynamic_storyteller_type, /datum/dynamic_storyteller/classic)
. += "<b>Peaceful Waypoint</b></center><BR>"
. += "Your station orbits deep within controlled, core-sector systems and serves as a waypoint for routine traffic through Nanotrasen's trade empire. Due to the combination of high security, interstellar traffic, and low strategic value, it makes any direct threat of violence unlikely. Your primary enemies will be incompetence and bored crewmen: try to organize team-building events to keep staffers interested and productive. However, even deep in our territory there may be subversive elements, especially for such a high-value target as your station. Keep an eye out, but don't expect much trouble."
set_security_level(SEC_LEVEL_GREEN)
station_goals.len = 0
for(var/T in subtypesof(/datum/station_goal))
var/datum/station_goal/G = new T
if(!(G in station_goals))
@@ -251,6 +258,7 @@ GLOBAL_VAR_INIT(dynamic_storyteller_type, /datum/dynamic_storyteller/classic)
. += "<b>Core Territory</b></center><BR>"
. += "Your station orbits within reliably mundane, secure space. Although Nanotrasen has a firm grip on security in your region, the valuable resources and strategic position aboard your station make it a potential target for infiltrations. Monitor crew for non-loyal behavior, but expect a relatively tame shift free of large-scale destruction. We expect great things from your station."
set_security_level(SEC_LEVEL_GREEN)
station_goals.len = 0
for(var/T in subtypesof(/datum/station_goal))
var/datum/station_goal/G = new T
if(!(G in station_goals))
@@ -490,7 +498,7 @@ GLOBAL_VAR_INIT(dynamic_storyteller_type, /datum/dynamic_storyteller/classic)
starting_rule = pickweight(drafted_rules)
// Check if the ruleset is highlander and if a highlander ruleset has been executed
else if(starting_rule.flags & HIGHLANDER_RULESET) // Should already be filtered out, but making sure. Check filtering at end of proc if reported.
if(threat_level > GLOB.dynamic_stacking_limit && GLOB.dynamic_no_stacking)
if(threat_level <= GLOB.dynamic_stacking_limit && GLOB.dynamic_no_stacking)
if(highlander_executed)
drafted_rules -= starting_rule
if(drafted_rules.len <= 0)
@@ -511,7 +519,7 @@ GLOBAL_VAR_INIT(dynamic_storyteller_type, /datum/dynamic_storyteller/classic)
drafted_rules -= starting_rule
starting_rule.trim_candidates()
starting_rule.scale_up(extra_rulesets_amount, threat)
starting_rule.scale_up(extra_rulesets_amount, threat_level)
if (starting_rule.pre_execute())
log_threat("[starting_rule.ruletype] - <b>[starting_rule.name]</b> [starting_rule.cost + starting_rule.scaled_times * starting_rule.scaling_cost] threat", verbose = TRUE)
if(starting_rule.flags & HIGHLANDER_RULESET)
@@ -715,6 +723,16 @@ GLOBAL_VAR_INIT(dynamic_storyteller_type, /datum/dynamic_storyteller/classic)
continue
current_players[CURRENT_DEAD_PLAYERS].Add(M) // Players who actually died (and admins who ghosted, would be nice to avoid counting them somehow)
threat = storyteller.calculate_threat() + added_threat
if(threat_average_weight)
var/cur_sample_weight = world.time - last_threat_sample_time
threat_average = ((threat_average * threat_average_weight) + (threat * cur_sample_weight)) / (threat_average_weight + cur_sample_weight)
threat_average_weight += cur_sample_weight
last_threat_sample_time = world.time
else
threat_average = threat
threat_average_weight++
last_threat_sample_time = world.time
/// Removes type from the list
/datum/game_mode/dynamic/proc/remove_from_list(list/type_list, type)
for(var/I in type_list)
@@ -222,6 +222,26 @@
message_admins("[M.name] was made into a bloodsucker by dynamic.")
return TRUE
//////////////////////////////////////////////
// //
// CHANGELINGS //
// //
//////////////////////////////////////////////
/datum/dynamic_ruleset/latejoin/changeling
name = "Changeling Infiltrator"
config_tag = "latejoin_changeling"
antag_flag = ROLE_CHANGELING
antag_datum = /datum/antagonist/changeling
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 = 15
requirements = list(101,101,101,101,101,101,101,101,101,101)
property_weights = list("trust" = -2, "valid" = 2)
high_population_requirement = 101
//////////////////////////////////////////////
// //
// COLLECTOR //
@@ -241,5 +261,5 @@
requirements = list(10,10,10,10,10,10,10,10,10,10)
high_population_requirement = 10
repeatable = TRUE
flags = TRAITOR_RULESET
flags = TRAITOR_RULESET | MINOR_RULESET
property_weights = list("story_potential" = 2, "trust" = -1, "extended" = 2)
@@ -34,8 +34,7 @@
living_players = trim_list(mode.current_players[CURRENT_LIVING_PLAYERS])
living_antags = trim_list(mode.current_players[CURRENT_LIVING_ANTAGS])
list_observers = trim_list(mode.current_players[CURRENT_OBSERVERS])
var/datum/element/ghost_role_eligibility/eligibility = SSdcs.GetElement(list(/datum/element/ghost_role_eligibility))
ghost_eligible = trim_list(eligibility.get_all_ghost_role_eligible())
ghost_eligible = trim_list(get_all_ghost_role_eligible())
/datum/dynamic_ruleset/midround/proc/trim_list(list/L = list())
var/list/trimmed_list = L.Copy()
@@ -11,6 +11,7 @@
WAROPS_ALWAYS_ALLOWED: Can always do warops, regardless of threat level.
USE_PREF_WEIGHTS: Will use peoples' preferences to change the threat centre.
FORCE_IF_WON: If this mode won the vote, forces it
USE_PREV_ROUND_WEIGHTS: Changes its threat centre based on the average chaos of previous rounds.
*/
var/flags = 0
var/dead_player_weight = 1 // How much dead players matter for threat calculation
@@ -53,6 +54,8 @@ Property weights are:
var/turf/T = get_turf(H)
if(H.stat != DEAD && is_station_level(T.z) && !("Station" in H.faction))
threat += H.threat()
for(var/obj/item/phylactery/P in GLOB.poi_list)
threat += 25 // can't be giving them too much of a break
for (var/mob/M in mode.current_players[CURRENT_LIVING_PLAYERS])
if (M?.mind?.assigned_role && M.stat != DEAD)
var/datum/job/J = SSjob.GetJob(M.mind.assigned_role)
@@ -90,6 +93,8 @@ Property weights are:
mean += 5
if(voters)
GLOB.dynamic_curve_centre += (mean/voters)
if(flags & USE_PREV_ROUND_WEIGHTS)
GLOB.dynamic_curve_centre += (50 - SSpersistence.average_dynamic_threat) / 10
GLOB.dynamic_forced_threat_level = forced_threat_level
/datum/dynamic_storyteller/proc/get_midround_cooldown()
@@ -135,17 +140,19 @@ Property weights are:
if (GLOB.dynamic_classic_secret && !((rule.flags & TRAITOR_RULESET) || (rule.flags & MINOR_RULESET)))
continue
rule.trim_candidates()
var/cost_difference = abs(rule.cost-(mode.threat_level-mode.threat))
/* Basically, the closer the cost is to the current threat-level-away-from-threat, the more likely it is to
pick this particular ruleset.
Let's use a toy example: there's 60 threat level and 10 threat spent.
We want to pick a ruleset that's close to that, so we run the below equation, on two rulesets.
Ruleset 1 has 30 cost, ruleset 2 has 5 cost.
When we do the math, ruleset 1's threat_weight is 0.538, and ruleset 2's is 0.238, meaning ruleset 1
is 2.26 times as likely to be picked, all other things considered.
Of course, we don't want it to GUARANTEE the closest, that's no fun, so it's just a weight.
*/
var/threat_weight = 1-abs(1-LOGISTIC_FUNCTION(2,0.05,cost_difference,0))
var/threat_weight = 1
if(!(rule.flags & MINOR_RULESET)) // makes the traitor rulesets always possible anyway
var/cost_difference = abs(rule.cost-(mode.threat_level-mode.threat))
/* Basically, the closer the cost is to the current threat-level-away-from-threat, the more likely it is to
pick this particular ruleset.
Let's use a toy example: there's 60 threat level and 10 threat spent.
We want to pick a ruleset that's close to that, so we run the below equation, on two rulesets.
Ruleset 1 has 30 cost, ruleset 2 has 5 cost.
When we do the math, ruleset 1's threat_weight is 0.538, and ruleset 2's is 0.238, meaning ruleset 1
is 2.26 times as likely to be picked, all other things considered.
Of course, we don't want it to GUARANTEE the closest, that's no fun, so it's just a weight.
*/
threat_weight = 1-abs(1-LOGISTIC_FUNCTION(2,0.05,cost_difference,0))
if (rule.ready())
var/property_weight = 0
for(var/property in property_weights)
@@ -168,8 +175,10 @@ Property weights are:
rule.candidates = list(newPlayer)
rule.trim_candidates()
var/cost_difference = abs(rule.cost-(mode.threat_level-mode.threat))
var/threat_weight = 1-abs(1-(LOGISTIC_FUNCTION(2,0.05,cost_difference,0)))
var/threat_weight = 1
if(!(rule.flags & MINOR_RULESET))
var/cost_difference = abs(rule.cost-(mode.threat_level-mode.threat))
threat_weight = 1-abs(1-(LOGISTIC_FUNCTION(2,0.05,cost_difference,0)))
if (rule.ready())
var/property_weight = 0
for(var/property in property_weights)
@@ -200,7 +209,7 @@ Property weights are:
weight = 1
event_frequency_lower = 2 MINUTES
event_frequency_upper = 10 MINUTES
flags = WAROPS_ALWAYS_ALLOWED | FORCE_IF_WON
flags = WAROPS_ALWAYS_ALLOWED
min_players = 40
var/refund_cooldown = 0
@@ -224,7 +233,7 @@ Property weights are:
curve_width = 1.5
weight = 2
min_players = 30
flags = WAROPS_ALWAYS_ALLOWED
flags = WAROPS_ALWAYS_ALLOWED | USE_PREV_ROUND_WEIGHTS
property_weights = list("valid" = 3, "trust" = 5)
/datum/dynamic_storyteller/team/get_injection_chance(dry_run = FALSE)
@@ -245,7 +254,10 @@ Property weights are:
config_tag = "random"
weight = 1
desc = "No weighting at all; every ruleset has the same chance of happening. Cooldowns vary wildly. As random as it gets."
forced_threat_level = 100
/datum/dynamic_storyteller/random/on_start()
..()
GLOB.dynamic_forced_threat_level = rand(0,100)
/datum/dynamic_storyteller/random/get_midround_cooldown()
return rand(GLOB.dynamic_midround_delay_min/2, GLOB.dynamic_midround_delay_max*2)
@@ -259,9 +271,6 @@ Property weights are:
/datum/dynamic_storyteller/random/get_injection_chance()
return 50 // i would do rand(0,100) but it's actually the same thing when you do the math
/datum/dynamic_storyteller/random/calculate_threat()
return 0 // what IS threat
/datum/dynamic_storyteller/random/roundstart_draft()
var/list/drafted_rules = list()
for (var/datum/dynamic_ruleset/roundstart/rule in mode.roundstart_rules)
@@ -315,18 +324,20 @@ Property weights are:
desc = "Antags with options for loadouts and gimmicks. Traitor, wizard, nukies. Has a buildup-climax-falling action threat curve."
weight = 2
curve_width = 2
flags = USE_PREV_ROUND_WEIGHTS
property_weights = list("story_potential" = 2)
/datum/dynamic_storyteller/story/do_process()
/datum/dynamic_storyteller/story/calculate_threat()
var/current_time = (world.time / SSautotransfer.targettime)*180
mode.threat_level = round(mode.initial_threat_level*(sin(current_time)+0.5),0.1)
mode.threat_level = round(mode.initial_threat_level*(sin(current_time)+0.25),0.1)
..()
/datum/dynamic_storyteller/classic
name = "Classic"
config_tag = "classic"
desc = "No special antagonist weights. Good variety, but not like random. Uses your chaos preference to weight."
flags = USE_PREF_WEIGHTS
flags = USE_PREF_WEIGHTS | USE_PREV_ROUND_WEIGHTS
/datum/dynamic_storyteller/suspicion
name = "Intrigue"
@@ -335,6 +346,7 @@ Property weights are:
weight = 2
curve_width = 2
dead_player_weight = 2
flags = USE_PREV_ROUND_WEIGHTS
property_weights = list("trust" = -3)
/datum/dynamic_storyteller/liteextended
+2 -2
View File
@@ -663,7 +663,7 @@ GLOBAL_LIST_EMPTY(possible_items_special)
if(count)
target_amount = count
update_explanation_text()
/*
/datum/objective/capture
name = "capture"
var/captured_amount = 0
@@ -709,7 +709,7 @@ GLOBAL_LIST_EMPTY(possible_items_special)
if(count)
target_amount = count
update_explanation_text()
*/
//Changeling Objectives
/datum/objective/absorb
+5 -2
View File
@@ -77,14 +77,14 @@
/datum/sabotage_objective/processing/supermatter/can_run()
return (locate(/obj/machinery/power/supermatter_crystal) in GLOB.machines)
/*
/datum/sabotage_objective/station_integrity
name = "Make sure the station is at less than 80% integrity by the end. Smash walls, windows etc. to reach this goal."
sabotage_type = "integrity"
/datum/sabotage_objective/station_integrity/check_conditions()
return 5-(max(SSticker.station_integrity*4,320)/80)
*/
/datum/sabotage_objective/cloner
name = "Destroy all Nanotrasen cloning machines."
sabotage_type = "cloner"
@@ -98,6 +98,9 @@
special_equipment = list(/obj/item/aiModule/syndicate)
excludefromjob = list("Chief Engineer","Research Director","Head of Personnel","Captain","Chief Medical Officer","Head Of Security")
/datum/sabotage_objective/ai_law/can_run()
return length(active_ais())
/datum/sabotage_objective/ai_law/check_conditions()
for (var/i in GLOB.ai_list)
var/mob/living/silicon/ai/aiPlayer = i
+33 -23
View File
@@ -207,11 +207,14 @@
/obj/machinery/sleeper/ui_data()
var/list/data = list()
var/chemical_list = list()
var/blood_percent = 0
data["occupied"] = occupant ? 1 : 0
data["open"] = state_open
data["efficiency"] = efficiency
data["current_vol"] = reagents.total_volume
data["tot_capacity"] = reagents.maximum_volume
data["blood_levels"] = blood_percent
data["blood_status"] = "Patient either has no blood, or does not require it to function."
data["chemical_list"] = chemical_list
data["chems"] = list()
for(var/chem in available_chems)
@@ -247,10 +250,13 @@
data["occupant"]["fireLoss"] = mob_occupant.getFireLoss()
data["occupant"]["cloneLoss"] = mob_occupant.getCloneLoss()
data["occupant"]["brainLoss"] = mob_occupant.getOrganLoss(ORGAN_SLOT_BRAIN)
data["occupant"]["reagents"] = list()
if(mob_occupant.reagents && mob_occupant.reagents.reagent_list.len)
if(mob_occupant.reagents.reagent_list.len)
for(var/datum/reagent/R in mob_occupant.reagents.reagent_list)
data["occupant"]["reagents"] += list(list("name" = R.name, "volume" = R.volume))
chemical_list += list(list("name" = R.name, "volume" = R.volume))
else
chemical_list = "Patient has no reagents."
data["occupant"]["failing_organs"] = list()
var/mob/living/carbon/C = mob_occupant
if(C)
@@ -259,21 +265,25 @@
continue
data["occupant"]["failing_organs"] += list(list("name" = Or.name))
if(mob_occupant.has_dna()) // Blood-stuff is mostly a copy-paste from the healthscanner.
var/blood_id = C.get_blood_id()
if(blood_id)
data["occupant"]["blood"] = list() // We can start populating this list.
var/blood_type = C.dna.blood_type
if(!(blood_id in GLOB.blood_reagent_types)) // special blood substance
var/datum/reagent/R = GLOB.chemical_reagents_list[blood_id]
if(R)
blood_type = R.name
else
blood_type = blood_id
data["occupant"]["blood"]["maxBloodVolume"] = (BLOOD_VOLUME_NORMAL*C.blood_ratio)
data["occupant"]["blood"]["currentBloodVolume"] = C.blood_volume
data["occupant"]["blood"]["dangerBloodVolume"] = BLOOD_VOLUME_SAFE
data["occupant"]["blood"]["bloodType"] = blood_type
if(istype(C)) //Non-carbons shouldn't be able to enter sleepers, but this is to prevent runtimes if something ever breaks
if(mob_occupant.has_dna()) // Blood-stuff is mostly a copy-paste from the healthscanner.
blood_percent = round((C.blood_volume / BLOOD_VOLUME_NORMAL)*100)
var/blood_id = C.get_blood_id()
var/blood_warning = ""
if(blood_percent < 80)
blood_warning = "Patient has low blood levels."
if(blood_percent < 60)
blood_warning = "Patient has DANGEROUSLY low blood levels."
if(blood_id)
var/blood_type = C.dna.blood_type
if(!(blood_id in GLOB.blood_reagent_types)) // special blood substance
var/datum/reagent/R = GLOB.chemical_reagents_list[blood_id]
if(R)
blood_type = R.name
else
blood_type = blood_id
data["blood_status"] = "Patient has [blood_type] type blood. [blood_warning]"
data["blood_levels"] = blood_percent
return data
/obj/machinery/sleeper/ui_act(action, params)
@@ -309,14 +319,14 @@
if(allowed(usr))
if(!is_operational())
return
reagents.remove_reagent(chem, 10)
reagents.remove_reagent(chem, 1000)
return
if(chem in available_chems)
if(!is_operational())
return
/*var/datum/reagent/R = reagents.has_reagent(chem) //For when purity effects are in
if(R.purity < 0.8)*/
reagents.remove_reagent(chem, 10)
reagents.remove_reagent(chem, 1000)
else
visible_message("<span class='warning'>Access Denied.</span>")
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
-2
View File
@@ -381,14 +381,12 @@
for(var/obj/machinery/camera/C in oview(4, M))
if(C.can_use()) // check if camera disabled
return C
break
return null
/proc/near_range_camera(var/mob/M)
for(var/obj/machinery/camera/C in range(4, M))
if(C.can_use()) // check if camera disabled
return C
break
return null
+1 -1
View File
@@ -55,7 +55,7 @@
/obj/item/stack/tile/fakespace/loaded = ARCADE_WEIGHT_TRICK,
/obj/item/stack/tile/fakepit/loaded = ARCADE_WEIGHT_TRICK,
/obj/item/restraints/handcuffs/fake = ARCADE_WEIGHT_TRICK,
/obj/item/clothing/gloves/rapid/hug = ARCADE_WEIGHT_TRICK,
/obj/item/clothing/gloves/fingerless/pugilist/rapid/hug = ARCADE_WEIGHT_TRICK,
/obj/item/grenade/chem_grenade/glitter/pink = ARCADE_WEIGHT_TRICK,
/obj/item/grenade/chem_grenade/glitter/blue = ARCADE_WEIGHT_TRICK,

Some files were not shown because too many files have changed in this diff Show More