This commit is contained in:
Ghommie
2020-05-24 04:00:51 +02:00
423 changed files with 6450 additions and 3566 deletions
-59
View File
@@ -69,11 +69,6 @@
<A href='?src=[REF(src)];[HrefToken()];secrets=floorlava'>The floor is lava! (DANGEROUS: extremely lame)</A><BR>
<A href='?src=[REF(src)];[HrefToken()];secrets=customportal'>Spawn a custom portal storm</A><BR>
<BR>
<A href='?src=[REF(src)];[HrefToken()];secrets=flipmovement'>Flip client movement directions</A><BR>
<A href='?src=[REF(src)];[HrefToken()];secrets=randommovement'>Randomize client movement directions</A><BR>
<A href='?src=[REF(src)];[HrefToken()];secrets=custommovement'>Set each movement direction manually</A><BR>
<A href='?src=[REF(src)];[HrefToken()];secrets=resetmovement'>Reset movement directions to default</A><BR>
<BR>
<A href='?src=[REF(src)];[HrefToken()];secrets=changebombcap'>Change bomb cap</A><BR>
<A href='?src=[REF(src)];[HrefToken()];secrets=masspurrbation'>Mass Purrbation</A><BR>
<A href='?src=[REF(src)];[HrefToken()];secrets=massremovepurrbation'>Mass Remove Purrbation</A><BR>
@@ -603,60 +598,6 @@
purrbation.")
log_admin("[key_name(usr)] has removed everyone from purrbation.")
if("flipmovement")
if(!check_rights(R_FUN))
return
if(alert("Flip all movement controls?","Confirm","Yes","Cancel") == "Cancel")
return
var/list/movement_keys = SSinput.movement_keys
for(var/i in 1 to movement_keys.len)
var/key = movement_keys[i]
movement_keys[key] = turn(movement_keys[key], 180)
message_admins("[key_name_admin(usr)] has flipped all movement directions.")
log_admin("[key_name(usr)] has flipped all movement directions.")
if("randommovement")
if(!check_rights(R_FUN))
return
if(alert("Randomize all movement controls?","Confirm","Yes","Cancel") == "Cancel")
return
var/list/movement_keys = SSinput.movement_keys
for(var/i in 1 to movement_keys.len)
var/key = movement_keys[i]
movement_keys[key] = turn(movement_keys[key], 45 * rand(1, 8))
message_admins("[key_name_admin(usr)] has randomized all movement directions.")
log_admin("[key_name(usr)] has randomized all movement directions.")
if("custommovement")
if(!check_rights(R_FUN))
return
if(alert("Are you sure you want to change every movement key?","Confirm","Yes","Cancel") == "Cancel")
return
var/list/movement_keys = SSinput.movement_keys
var/list/new_movement = list()
for(var/i in 1 to movement_keys.len)
var/key = movement_keys[i]
var/msg = "Please input the new movement direction when the user presses [key]. Ex. northeast"
var/title = "New direction for [key]"
var/new_direction = text2dir(input(usr, msg, title) as text|null)
if(!new_direction)
new_direction = movement_keys[key]
new_movement[key] = new_direction
SSinput.movement_keys = new_movement
message_admins("[key_name_admin(usr)] has configured all movement directions.")
log_admin("[key_name(usr)] has configured all movement directions.")
if("resetmovement")
if(!check_rights(R_FUN))
return
if(alert("Are you sure you want to reset movement keys to default?","Confirm","Yes","Cancel") == "Cancel")
return
SSinput.setup_default_movement_keys()
message_admins("[key_name_admin(usr)] has reset all movement keys.")
log_admin("[key_name(usr)] has reset all movement keys.")
if("customportal")
if(!check_rights(R_FUN))
return
@@ -24,6 +24,8 @@ GLOBAL_LIST_EMPTY(antagonists)
var/list/blacklisted_quirks = list(/datum/quirk/nonviolent,/datum/quirk/mute) // Quirks that will be removed upon gaining this antag. Pacifist and mute are default.
var/threat = 0 // Amount of threat this antag poses, for dynamic mode
var/list/skill_modifiers
/datum/antagonist/New()
GLOB.antagonists += src
typecache_datum_blacklist = typecacheof(typecache_datum_blacklist)
@@ -68,15 +70,19 @@ GLOBAL_LIST_EMPTY(antagonists)
//Proc called when the datum is given to a mind.
/datum/antagonist/proc/on_gain()
if(owner && owner.current)
if(!silent)
greet()
apply_innate_effects()
give_antag_moodies()
remove_blacklisted_quirks()
if(is_banned(owner.current) && replace_banned)
replace_banned_player()
SEND_SIGNAL(owner.current, COMSIG_MOB_ANTAG_ON_GAIN, src)
if(!(owner?.current))
return
if(!silent)
greet()
apply_innate_effects()
give_antag_moodies()
remove_blacklisted_quirks()
if(is_banned(owner.current) && replace_banned)
replace_banned_player()
if(skill_modifiers)
for(var/A in skill_modifiers)
ADD_SINGLETON_SKILL_MODIFIER(owner, A, type)
SEND_SIGNAL(owner.current, COMSIG_MOB_ANTAG_ON_GAIN, src)
/datum/antagonist/proc/is_banned(mob/M)
if(!M)
@@ -99,6 +105,8 @@ GLOBAL_LIST_EMPTY(antagonists)
clear_antag_moodies()
if(owner)
LAZYREMOVE(owner.antag_datums, src)
for(var/A in skill_modifiers)
owner.remove_skill_modifier(GET_SKILL_MOD_ID(A, type))
if(!silent && owner.current)
farewell()
var/datum/team/team = get_team()
@@ -21,6 +21,7 @@
landmark_type = /obj/effect/landmark/abductor/agent
greet_text = "Use your stealth technology and equipment to incapacitate humans for your scientist to retrieve."
show_in_antagpanel = TRUE
skill_modifiers = list(/datum/skill_modifier/job/level/wiring)
/datum/antagonist/abductor/scientist
name = "Abductor Scientist"
@@ -29,6 +30,7 @@
landmark_type = /obj/effect/landmark/abductor/scientist
greet_text = "Use your experimental console and surgical equipment to monitor your agent and experiment upon abducted humans."
show_in_antagpanel = TRUE
skill_modifiers = list(/datum/skill_modifier/job/affinity/surgery)
/datum/antagonist/abductor/create_team(datum/team/abductor_team/new_team)
if(!new_team)
@@ -23,5 +23,5 @@
addtimer(CALLBACK(src, .proc/zap), rand(30, 100))
/obj/item/organ/heart/gland/electric/proc/zap()
tesla_zap(owner, 4, 8000, TESLA_MOB_DAMAGE | TESLA_OBJ_DAMAGE | TESLA_MOB_STUN)
tesla_zap(owner, 4, 8000, ZAP_MOB_DAMAGE | ZAP_OBJ_DAMAGE | ZAP_MOB_STUN)
playsound(get_turf(owner), 'sound/magic/lightningshock.ogg', 50, TRUE)
@@ -86,7 +86,8 @@
melee_damage_upper = 4
obj_damage = 20
environment_smash = ENVIRONMENT_SMASH_STRUCTURES
attacktext = "hits"
attack_verb_continuous = "hits"
attack_verb_simple = "hit"
attack_sound = 'sound/weapons/genhit1.ogg'
movement_type = FLYING
del_on_death = 1
@@ -205,7 +206,8 @@
melee_damage_lower = 20
melee_damage_upper = 20
obj_damage = 60
attacktext = "slams"
attack_verb_continuous = "slams"
attack_verb_simple = "slam"
attack_sound = 'sound/effects/blobattack.ogg'
verb_say = "gurgles"
verb_ask = "demands"
@@ -284,11 +286,11 @@
if(overmind) //if we have an overmind, we're doing chemical reactions instead of pure damage
melee_damage_lower = 4
melee_damage_upper = 4
attacktext = overmind.blobstrain.blobbernaut_message
attack_verb_continuous = overmind.blobstrain.blobbernaut_message
else
melee_damage_lower = initial(melee_damage_lower)
melee_damage_upper = initial(melee_damage_upper)
attacktext = initial(attacktext)
attack_verb_continuous = initial(attack_verb_continuous)
/mob/living/simple_animal/hostile/blob/blobbernaut/death(gibbed)
..(gibbed)
@@ -207,8 +207,8 @@
if(prob(100 - severity * 30))
new /obj/effect/temp_visual/emp(get_turf(src))
/obj/structure/blob/tesla_act(power)
..()
/obj/structure/blob/zap_act(power)
. = ..()
if(overmind)
if(overmind.blobstrain.tesla_reaction(src, power))
take_damage(power/400, BURN, "energy")
@@ -492,7 +492,7 @@
/obj/structure/bloodsucker/candelabrum/process()
if(!lit)
return
for(var/mob/living/carbon/human/H in get_actual_viewers(7, src))
for(var/mob/living/carbon/human/H in fov_viewers(7, src))
var/datum/antagonist/vassal/T = H.mind.has_antag_datum(ANTAG_DATUM_VASSAL)
if(AmBloodsucker(H) || T) //We dont want vassals or vampires affected by this
return
@@ -19,7 +19,7 @@
if(!.)
return
// must have nobody around to see the cloak
for(var/mob/living/M in get_actual_viewers(9, owner) - owner)
for(var/mob/living/M in fov_viewers(9, owner) - owner)
to_chat(owner, "<span class='warning'>You may only vanish into the shadows unseen.</span>")
return FALSE
return TRUE
@@ -169,7 +169,7 @@
vision_distance = notice_range, ignored_mobs = target) // Only people who AREN'T the target will notice this action.
// Warn Feeder about Witnesses...
var/was_unnoticed = TRUE
for(var/mob/living/M in get_actual_viewers(notice_range, owner) - owner - target)
for(var/mob/living/M in fov_viewers(notice_range, owner) - owner - target)
if(M.client && !M.silicon_privileges && !M.eye_blind && !M.mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER))
was_unnoticed = FALSE
break
@@ -64,7 +64,7 @@
var/turf/T = get_turf(user)
if(T && T.lighting_object && T.get_lumcount()>= 0.1)
// B) Check for Viewers
for(var/mob/living/M in get_actual_viewers(world.view, get_turf(owner)) - owner)
for(var/mob/living/M in fov_viewers(world.view, get_turf(owner)) - owner)
if(M.client && !M.silicon_privileges && !M.eye_blind)
am_seen = TRUE
if (!M.mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER))
@@ -64,7 +64,7 @@
to_chat(owner, "<span class='warning'>Your victim's eyes are glazed over. They cannot perceive you.</span>")
return FALSE
// Check: Target See Me? (behind wall)
if(!(owner in target.visible_atoms()))
if(!(owner in target.fov_view()))
// Sub-Check: GET CLOSER
//if (!(owner in range(target_range, get_turf(target)))
// if (display_error)
@@ -117,8 +117,6 @@
RegisterSignal(target, COMSIG_MOVABLE_MOVED, .proc/ContinueTarget)
// 5 second windup
addtimer(CALLBACK(src, .proc/apply_effects, L, target, power_time), 6 SECONDS)
ADD_TRAIT(target, TRAIT_COMBAT_MODE_LOCKED, src)
ADD_TRAIT(L, TRAIT_COMBAT_MODE_LOCKED, src)
/datum/action/bloodsucker/targeted/mesmerize/proc/apply_effects(aggressor, victim, power_time)
var/mob/living/carbon/target = victim
@@ -127,7 +125,6 @@
return
PowerActivatedSuccessfully() // blood & cooldown only altered if power activated successfully - less "fuck you"-y
target.apply_status_effect(STATUS_EFFECT_MESMERIZE, power_time)
REMOVE_TRAIT(L, TRAIT_COMBAT_MODE_LOCKED, src)
target.face_atom(L)
target.Stun(power_time)
to_chat(L, "<span class='notice'>[target] is fixed in place by your hypnotic gaze.</span>")
@@ -136,8 +133,7 @@
spawn(power_time)
if(istype(target) && success)
target.notransform = FALSE
REMOVE_TRAIT(target, TRAIT_COMBAT_MODE_LOCKED, src)
if(istype(L) && target.stat == CONSCIOUS && (target in L.visible_atoms(10))) // They Woke Up! (Notice if within view)
if(istype(L) && target.stat == CONSCIOUS && (target in L.fov_view(10))) // They Woke Up! (Notice if within view)
to_chat(L, "<span class='warning'>[target] has snapped out of their trance.</span>")
@@ -5,6 +5,7 @@
clockwork_desc = "A sigil of some purpose."
icon_state = "sigil"
layer = LOW_OBJ_LAYER
plane = ABOVE_WALL_PLANE
alpha = 50
resistance_flags = NONE
var/affects_servants = FALSE
@@ -0,0 +1,82 @@
//Subtype of (riot) shield because of already implemented shieldbash stuff aswell as integrity and simillar things
//ratvarian shield: A shield that absorbs energy from attacks and uses it to empower its bashes with remendous force. It is also quite resistant to damage, though less so against lasers and energy weaponry.
/obj/item/shield/riot/ratvarian
name = "ratvarian shield"
icon_state = "ratvarian_shield" //Its icons are in the same place the normal shields are in
item_state = "ratvarian_shield"
desc = "A resilient shield made out of brass.. It feels warm to the touch."
var/clockwork_desc = "A powerful shield of ratvarian making. It absorbs blocked attacks to charge devastating bashes."
armor = list("melee" = 80, "bullet" = 70, "laser" = -10, "energy" = -20, "bomb" = 60, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 100)
shield_flags = SHIELD_FLAGS_DEFAULT
max_integrity = 300 //High integrity, extremely strong against melee / bullets, but still quite easy to destroy with lasers and energy
repair_material = /obj/item/stack/tile/brass
var/dam_absorbed = 0
var/bash_mult_steps = 30
var/max_bash_mult = 4
/obj/item/shield/riot/ratvarian/examine(mob/user)
if((is_servant_of_ratvar(user) || isobserver(user)))
desc = clockwork_desc
desc +="\n <span class='inathneq_small'>The shield has absorbed [dam_absorbed] damage, multiplying the effectiveness of its bashes by [calc_bash_mult()]</span>"
. = ..()
desc = initial(desc)
obj/item/shield/riot/ratvarian/proc/calc_bash_mult()
var/bash_mult = 0
if(!dam_absorbed)
return 1
else
bash_mult += round(clamp(1 + (dam_absorbed / bash_mult_steps), 1, max_bash_mult), 0.1) //Multiplies the effect of bashes by up to [max_bash_mult], though never less than one
return bash_mult
/obj/item/shield/riot/ratvarian/proc/calc_bash_absorb_use()
var/absorb_use = 0
absorb_use = max(0, round(dam_absorbed * (calc_bash_mult() / round(1 + (dam_absorbed / bash_mult_steps), 0.1)), 1)) //Calculates how much of the absorbed damage the bash would actually use, so its not wasted
return absorb_use
/obj/item/shield/riot/ratvarian/on_shield_block(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
if(!damage)
return ..()
if(!is_servant_of_ratvar(owner))
owner.visible_message("<span class='warning'>As [owner] blocks the attack with [src], [owner.p_they()] suddenly drops it, whincing in pain! </span>", "<span class='warning'>As you block the attack with [src], it heats up tremendously, forcing you to drop it from the pain alone! </span>")
owner.emote("scream")
playsound(src, 'sound/machines/fryer/deep_fryer_emerge.ogg', 50)
if(iscarbon(owner)) //Type safety for if a drone somehow got a shield (ratvar protect us)
var/mob/living/carbon/C = owner
var/obj/item/bodypart/part = C.get_holding_bodypart_of_item(src)
C.apply_damage((iscultist(C) ? damage * 2 : damage), BURN, (istype(part, /obj/item/bodypart/l_arm) ? BODY_ZONE_L_ARM : BODY_ZONE_R_ARM)) //Deals the damage to the holder instead of absorbing it instead + forcedrops. Doubled if a cultist of Nar'Sie.
else
owner.adjustFireLoss(iscultist(owner) ? damage * 2 : damage)
addtimer(CALLBACK(owner, /mob/living.proc/dropItemToGround, src, TRUE), 1)
else if(!is_servant_of_ratvar(attacker)) //No exploiting my snowflake mechanics
dam_absorbed += damage
playsound(owner, 'sound/machines/clockcult/steam_whoosh.ogg', 30)
if(damage <= 10) //The shield itself is hard to break, this DOES NOT modify the actual blocking-mechanic
damage = 0
else
damage -= 5
return ..()
/obj/item/shield/riot/ratvarian/shatter(mob/living/carbon/human/owner)
playsound(owner, 'sound/magic/clockwork/anima_fragment_death.ogg', 50)
new /obj/item/clockwork/alloy_shards/large(get_turf(src))
/obj/item/shield/riot/ratvarian/user_shieldbash(mob/living/user, atom/target, harmful)
if(!harmful || !is_servant_of_ratvar(user)) // No fun for non-clockies, but you can keep the normal bashes. Until you try to block with it.
shieldbash_knockback = initial(shieldbash_knockback)
shieldbash_brutedamage = initial(shieldbash_brutedamage) //Prevention for funky stuff that might happen otherwise
shieldbash_stamdmg = initial(shieldbash_stamdmg)
return ..()
var/actual_bash_mult = calc_bash_mult()
shieldbash_knockback = round(initial(shieldbash_knockback) * actual_bash_mult, 1) //Modifying the strength of the bash, done with initial() to prevent magic-number issues if the original shieldbash values are changed
shieldbash_brutedamage = round(initial(shieldbash_brutedamage) * actual_bash_mult, 1) //Where I think of it, better round this stuff because we don't need even more things that deal like 3.25 damage
shieldbash_stamdmg = round(initial(shieldbash_stamdmg) * actual_bash_mult, 1) //Like 20 brute and 60 stam + a fuckton of knockback at the moment (at maximum charge), seems mostly fine? I think?
. = ..()
if(.) //If this bash actually hit someone
if(actual_bash_mult > 1)
playsound(user, 'sound/magic/fireball.ogg', 50, TRUE, frequency = 1.25)
dam_absorbed -= calc_bash_absorb_use()
return
@@ -17,7 +17,8 @@
obj_damage = 40
melee_damage_lower = 12
melee_damage_upper = 12
attacktext = "slashes"
attack_verb_continuous = "slashes"
attack_verb_simple = "slash"
attack_sound = 'sound/weapons/bladeslice.ogg'
weather_immunities = list("lava")
movement_type = FLYING
@@ -68,14 +69,16 @@
maxHealth = 300
melee_damage_upper = 25
melee_damage_lower = 25
attacktext = "devastates"
attack_verb_continuous = "devastates"
attack_verb_simple = "devastate"
speed = -1
obj_damage = 100
max_shield_health = INFINITY
else if(GLOB.ratvar_approaches) //Hefty health bonus and slight attack damage increase
melee_damage_upper = 15
melee_damage_lower = 15
attacktext = "carves"
attack_verb_continuous = "carves"
attack_verb_simple = "carve"
obj_damage = 50
max_shield_health = 4
@@ -100,6 +100,24 @@
quickbind = TRUE
quickbind_desc = "Creates a Judicial Visor, which can smite an area, applying Belligerent and briefly stunning."
//Nezbere's shield: Creates a ratvarian shield which absorbs attacks, see ratvarian_shield.dm for details.
/datum/clockwork_scripture/create_object/nezberes_shield
descname = "Shield with empowerable bashes"
name = "Nezbere's shield"
desc = "Creates a shield which generates charge from blocking damage, using it to empower its bashes tremendously. It is repaired with brass, and while very durable, extremely weak to lasers and, even more so, to energy weaponry."
invocations = list("Shield me...", "... from the coming dark!")
channel_time = 20
power_cost = 600 //Shouldn't be too spammable but not too hard to get either
whispered = TRUE
creator_message = "You form a ratvarian shield, which is capable of absorbing blocked attacks to empower its bashes."
object_path = /obj/item/shield/riot/ratvarian
usage_tip = "Bashes will only use charge when performed with intent to harm."
tier = SCRIPTURE_SCRIPT
space_allowed = TRUE
primary_component = VANGUARD_COGWHEEL
sort_priority = 5
quickbind = TRUE
quickbind_desc = "Creates a Ratvarian shield, which can absorb energy from attacks for use in powerful bashes."
//Clockwork Armaments: Grants the invoker the ability to call forth a Ratvarian spear and clockwork armor.
/datum/clockwork_scripture/clockwork_armaments
@@ -113,7 +131,7 @@
usage_tip = "Throwing the spear at a mob will do massive damage and knock them down, but break the spear. You will need to wait for 30 seconds before resummoning it."
tier = SCRIPTURE_SCRIPT
primary_component = VANGUARD_COGWHEEL
sort_priority = 5
sort_priority = 6
important = TRUE
quickbind = TRUE
quickbind_desc = "Permanently binds clockwork armor and a Ratvarian spear to you."
@@ -213,7 +231,7 @@
usage_tip = "This gateway is strictly one-way and will only allow things through the invoker's portal."
tier = SCRIPTURE_SCRIPT
primary_component = GEIS_CAPACITOR
sort_priority = 6
sort_priority = 7
quickbind = TRUE
quickbind_desc = "Allows you to create a one-way Spatial Gateway to a living Servant or Clockwork Obelisk."
@@ -5,6 +5,7 @@
antagpanel_category = "Clockcult"
job_rank = ROLE_SERVANT_OF_RATVAR
antag_moodlet = /datum/mood_event/cult
skill_modifiers = list(/datum/skill_modifier/job/level/wiring)
var/datum/action/innate/hierophant/hierophant_network = new
threat = 3
var/datum/team/clockcult/clock_team
+8 -4
View File
@@ -7,9 +7,12 @@
desc = "A large, menacing creature covered in armored black scales."
speak_emote = list("cackles")
emote_hear = list("cackles","screeches")
response_help = "thinks better of touching"
response_disarm = "flails at"
response_harm = "punches"
response_help_continuous = "thinks better of touching"
response_help_simple = "think better of touching"
response_disarm_continuous = "flails at"
response_disarm_simple = "flail at"
response_harm_continuous = "punches"
response_harm_simple = "punch"
icon = 'icons/mob/mob.dmi'
icon_state = "imp"
icon_living = "imp"
@@ -23,7 +26,8 @@
minbodytemp = 250 //Weak to cold
maxbodytemp = INFINITY
faction = list("hell")
attacktext = "wildly tears into"
attack_verb_continuous = "wildly tears into"
attack_verb_simple = "wildly tear into"
maxHealth = 200
health = 200
healable = 0
+2
View File
@@ -51,6 +51,7 @@
/datum/antagonist/ert/engineer
role = "Engineer"
outfit = /datum/outfit/ert/engineer
skill_modifiers = list(/datum/skill_modifier/job/level/wiring)
/datum/antagonist/ert/engineer/amber
outfit = /datum/outfit/ert/engineer/alert
@@ -61,6 +62,7 @@
/datum/antagonist/ert/medic
role = "Medical Officer"
outfit = /datum/outfit/ert/medic
skill_modifiers = list(/datum/skill_modifier/job/affinity/surgery)
/datum/antagonist/ert/medic/amber
outfit = /datum/outfit/ert/medic/alert
+2 -1
View File
@@ -28,7 +28,8 @@
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
vision_range = 1 // Only attack when target is close
wander = FALSE
attacktext = "glomps"
attack_verb_continuous = "glomps"
attack_verb_simple = "glomp"
attack_sound = 'sound/effects/blobattack.ogg'
butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab = 2)
@@ -451,9 +451,9 @@
return
qdel(src)
/obj/machinery/nuclearbomb/tesla_act(power, tesla_flags)
/obj/machinery/nuclearbomb/zap_act(power, zap_flags)
..()
if(tesla_flags & TESLA_MACHINE_EXPLOSIVE)
if(zap_flags & ZAP_MACHINE_EXPLOSIVE)
qdel(src)//like the singulo, tesla deletes it. stops it from exploding over and over
#define NUKERANGE 127
@@ -5,6 +5,7 @@
job_rank = ROLE_OPERATIVE
antag_moodlet = /datum/mood_event/focused
threat = 10
skill_modifiers = list(/datum/skill_modifier/job/level/wiring)
var/datum/team/nuclear/nuke_team
var/always_new_team = FALSE //If not assigned a team by default ops will try to join existing ones, set this to TRUE to always create new team.
var/send_to_spawnpoint = TRUE //Should the user be moved to default spawnpoint.
@@ -31,16 +31,20 @@
see_in_dark = 8
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
response_help = "passes through"
response_disarm = "swings through"
response_harm = "punches through"
response_help_continuous = "passes through"
response_help_simple = "pass through"
response_disarm_continuous = "swings through"
response_disarm_simple = "swing through"
response_harm_continuous = "punches through"
response_harm_simple = "punch through"
unsuitable_atmos_damage = 0
damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 0, CLONE = 0, STAMINA = 0, OXY = 0) //I don't know how you'd apply those, but revenants no-sell them anyway.
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
minbodytemp = 0
maxbodytemp = INFINITY
harm_intent_damage = 0
friendly = "touches"
friendly_verb_continuous = "touches"
friendly_verb_simple = "touch"
status_flags = 0
wander = FALSE
density = FALSE
@@ -6,9 +6,12 @@
desc = "A large, menacing creature covered in armored black scales."
speak_emote = list("gurgles")
emote_hear = list("wails","screeches")
response_help = "thinks better of touching"
response_disarm = "flails at"
response_harm = "punches"
response_help_continuous = "thinks better of touching"
response_help_simple = "think better of touching"
response_disarm_continuous = "flails at"
response_disarm_simple = "flail at"
response_harm_continuous = "punches"
response_harm_simple = "punch"
icon = 'icons/mob/mob.dmi'
icon_state = "daemon"
icon_living = "daemon"
@@ -24,7 +27,8 @@
minbodytemp = 0
maxbodytemp = INFINITY
faction = list("slaughter")
attacktext = "wildly tears into"
attack_verb_continuous = "wildly tears into"
attack_verb_simple = "wildly tear into"
maxHealth = 200
health = 200
healable = 0
@@ -116,8 +120,10 @@
desc = "A large, adorable creature covered in armor with pink bows."
speak_emote = list("giggles","titters","chuckles")
emote_hear = list("guffaws","laughs")
response_help = "hugs"
attacktext = "wildly tickles"
response_help_continuous = "hugs"
response_help_simple = "hug"
attack_verb_continuous = "wildly tickles"
attack_verb_simple = "wildly tickle"
attack_sound = 'sound/items/bikehorn.ogg'
feast_sound = 'sound/spookoween/scary_horn2.ogg'
+4 -2
View File
@@ -84,9 +84,11 @@
hud_possible = list(ANTAG_HUD, DIAG_STAT_HUD, DIAG_HUD)
obj_damage = 0
environment_smash = ENVIRONMENT_SMASH_NONE
attacktext = "shocks"
attack_verb_continuous = "shocks"
attack_verb_simple = "shock"
attack_sound = 'sound/effects/empulse.ogg'
friendly = "pinches"
friendly_verb_continuous = "pinches"
friendly_verb_simple = "pinch"
speed = 0
faction = list("swarmer")
AIStatus = AI_OFF
@@ -4,6 +4,7 @@
antagpanel_category = "Traitor"
job_rank = ROLE_TRAITOR
antag_moodlet = /datum/mood_event/focused
skill_modifiers = list(/datum/skill_modifier/job/level/wiring/basic)
var/special_role = ROLE_TRAITOR
var/employer = "The Syndicate"
var/give_objectives = TRUE
@@ -226,7 +226,11 @@
/datum/spellbook_entry/lightningbolt/Buy(mob/living/carbon/human/user,obj/item/spellbook/book) //return 1 on success
. = ..()
user.flags_1 |= TESLA_IGNORE_1
ADD_TRAIT(user, TRAIT_TESLA_SHOCKIMMUNE, "lightning_bolt_spell")
/datum/spellbook_entry/lightningbolt/Refund(mob/living/carbon/human/user, obj/item/spellbook/book)
. = ..()
REMOVE_TRAIT(user, TRAIT_TESLA_SHOCKIMMUNE, "lightning_bolt_spell")
/datum/spellbook_entry/infinite_guns
name = "Lesser Summon Guns"
@@ -17,6 +17,7 @@
active_power_usage = 0
power_channel = ENVIRON
layer = GAS_PIPE_HIDDEN_LAYER //under wires
plane = ABOVE_WALL_PLANE
resistance_flags = FIRE_PROOF
max_integrity = 200
obj_flags = CAN_BE_HIT | ON_BLUEPRINTS
@@ -7,6 +7,7 @@
name = "circulator/heat exchanger"
desc = "A gas circulator pump and heat exchanger."
icon_state = "circ-off-0"
plane = GAME_PLANE
var/active = FALSE
@@ -32,7 +32,7 @@
var/turf/T = loc
if(level == 2 || (istype(T) && !T.intact))
showpipe = TRUE
plane = GAME_PLANE
plane = ABOVE_WALL_PLANE
else
showpipe = FALSE
plane = FLOOR_PLANE
@@ -6,6 +6,7 @@
max_integrity = 350
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 100, "bomb" = 0, "bio" = 100, "rad" = 100, "fire" = 30, "acid" = 30)
layer = ABOVE_WINDOW_LAYER
plane = GAME_PLANE
state_open = FALSE
circuit = /obj/item/circuitboard/machine/cryo_tube
pipe_flags = PIPING_ONE_PER_TURF | PIPING_DEFAULT_LAYER_ONLY
@@ -15,8 +16,8 @@
var/volume = 100
var/efficiency = 1
var/sleep_factor = 0.00125
var/unconscious_factor = 0.001
var/base_knockout = 30 SECONDS
var/knockout_factor = 1
var/heat_capacity = 20000
var/conduction_coefficient = 0.3
@@ -53,10 +54,9 @@
var/C
for(var/obj/item/stock_parts/matter_bin/M in component_parts)
C += M.rating
// 2 bins total, so C ranges from 2 to 8.
efficiency = initial(efficiency) * C
sleep_factor = initial(sleep_factor) * C
unconscious_factor = initial(unconscious_factor) * C
knockout_factor = initial(knockout_factor) / max(1, (C * 0.33))
heat_capacity = initial(heat_capacity) / C
conduction_coefficient = initial(conduction_coefficient) * C
@@ -188,8 +188,10 @@
if(air1.gases.len)
if(mob_occupant.bodytemperature < T0C) // Sleepytime. Why? More cryo magic.
mob_occupant.Sleeping((mob_occupant.bodytemperature * sleep_factor) * 2000)
mob_occupant.Unconscious((mob_occupant.bodytemperature * unconscious_factor) * 2000)
// temperature factor goes from 1 to about 2.5
var/amount = max(1, (4 * log(T0C - mob_occupant.bodytemperature)) - 20) * knockout_factor * base_knockout
mob_occupant.Sleeping(amount)
mob_occupant.Unconscious(amount)
if(beaker)
if(reagent_transfer == 0) // Magically transfer reagents. Because cryo magic.
beaker.reagents.trans_to(occupant, 1, efficiency * 0.25) // Transfer reagents.
@@ -7,6 +7,7 @@
max_integrity = 800
density = TRUE
layer = ABOVE_WINDOW_LAYER
plane = GAME_PLANE
pipe_flags = PIPING_ONE_PER_TURF
var/volume = 10000 //in liters
var/gas_type = 0
@@ -9,6 +9,7 @@
max_integrity = 300
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 100, "bomb" = 0, "bio" = 100, "rad" = 100, "fire" = 80, "acid" = 30)
layer = OBJ_LAYER
plane = GAME_PLANE
circuit = /obj/item/circuitboard/machine/thermomachine
ui_x = 300
ui_y = 230
+7 -4
View File
@@ -119,6 +119,7 @@
var/list/data = list()
data["requestonly"] = requestonly
data["supplies"] = list()
data["emagged"] = obj_flags & EMAGGED
for(var/pack in SSshuttle.supply_packs)
var/datum/supply_pack/P = SSshuttle.supply_packs[pack]
if(!data["supplies"][P.group])
@@ -133,7 +134,8 @@
"cost" = P.cost,
"id" = pack,
"desc" = P.desc || P.name, // If there is a description, use it. Otherwise use the pack's name.
"access" = P.access
"access" = P.access,
"can_private_buy" = P.can_private_buy
))
return data
@@ -195,9 +197,10 @@
rank = "Silicon"
var/datum/bank_account/account
if(self_paid && ishuman(usr))
var/mob/living/carbon/human/H = usr
var/obj/item/card/id/id_card = H.get_idcard(TRUE)
if(self_paid)
if(!pack.can_private_buy && !(obj_flags & EMAGGED))
return
var/obj/item/card/id/id_card = usr.get_idcard(TRUE)
if(!istype(id_card))
say("No ID card detected.")
return
+3 -3
View File
@@ -110,7 +110,7 @@
include_subtypes = FALSE
/datum/export/glasswork_lens
cost = 1800
cost = 1600
unit_name = "small glass lens"
export_types = list(/obj/item/glasswork/glass_base/lens)
@@ -133,13 +133,13 @@
include_subtypes = FALSE
/datum/export/glasswork_teaplate
cost = 1200
cost = 1000
unit_name = "tea gear"
export_types = list(/obj/item/tea_plate)
include_subtypes = FALSE
/datum/export/glasswork_teacup
cost = 1800
cost = 1600
unit_name = "tea gear"
export_types = list(/obj/item/tea_cup)
include_subtypes = FALSE
-6
View File
@@ -120,12 +120,6 @@
message = "of cloth"
export_types = list(/obj/item/stack/sheet/cloth)
/datum/export/stack/silk
cost = 200 //The new plasma
unit_name = "sheets"
message = "of silk"
export_types = list(/obj/item/stack/sheet/silk)
/datum/export/stack/duracloth
cost = 40
unit_name = "sheets"
+6 -3
View File
@@ -2,9 +2,12 @@
name = "gondola"
real_name = "gondola"
desc = "The silent walker. This one seems to be part of a delivery agency."
response_help = "pets"
response_disarm = "bops"
response_harm = "kicks"
response_help_continuous = "pets"
response_help_simple = "pet"
response_disarm_continuous = "bops"
response_disarm_simple = "bop"
response_harm_continuous = "kicks"
response_harm_simple = "kick"
faction = list("gondola")
turns_per_move = 10
icon = 'icons/mob/gondolapod.dmi'
+1
View File
@@ -15,6 +15,7 @@
var/special_enabled = FALSE
var/DropPodOnly = FALSE //only usable by the Bluespace Drop Pod via the express cargo console
var/admin_spawned = FALSE //Can only an admin spawn this crate?
var/can_private_buy = TRUE //Can it be purchased privately by each crewmember?
/datum/supply_pack/proc/generate(atom/A, datum/bank_account/paying_account)
var/obj/structure/closet/crate/C
+1
View File
@@ -10,6 +10,7 @@
group = "Armory"
access = ACCESS_ARMORY
crate_type = /obj/structure/closet/crate/secure/weapon
can_private_buy = FALSE
/datum/supply_pack/security/armory/bulletarmor
name = "Bulletproof Armor Crate"
+1 -1
View File
@@ -148,7 +148,7 @@
crate_name = "supermatter shard crate"
crate_type = /obj/structure/closet/crate/secure/engineering
dangerous = TRUE
/datum/supply_pack/engine/tesla_coils
name = "Tesla Coil Crate"
desc = "Whether it's high-voltage executions, creating research points, or just plain old power generation: This pack of four Tesla coils can do it all!"
-26
View File
@@ -81,32 +81,6 @@
contains = list(/obj/item/stack/sheet/mineral/wood/fifty)
crate_name = "wood planks crate"
/datum/supply_pack/materials/rawcotton
name = "Raw Cotton Crate"
desc = "Plushies have been on the down in the market, and now due to a flood of raw cotton the price of it is so cheap, its a steal! Contains 40 raw cotton sheets."
cost = 800 // 100 net cost, 20 x 20 = 400. 300 profit if turned into cloth sheets or more if turned to silk then 10 x 200 = 2000
contains = list(/obj/item/stack/sheet/cotton/thirty,
/obj/item/stack/sheet/cotton/ten
)
crate_name = "cotton crate"
crate_type = /obj/structure/closet/crate/hydroponics
/datum/supply_pack/materials/rawcottonbulk
name = "Raw Cotton Crate (Bulk)"
desc = "We have so much of this stuff we need to get rid of it in -bulk- now. This crate contains 240 raw cotton sheets."
cost = 1300 // 600 net cost 20 x 120 = 2400 profit if turned into cloth sheets or if turned into silk 200 x 60 = 12000
contains = list(/obj/item/stack/sheet/cotton/thirty,
/obj/item/stack/sheet/cotton/thirty,
/obj/item/stack/sheet/cotton/thirty,
/obj/item/stack/sheet/cotton/thirty,
/obj/item/stack/sheet/cotton/thirty,
/obj/item/stack/sheet/cotton/thirty,
/obj/item/stack/sheet/cotton/thirty,
/obj/item/stack/sheet/cotton/thirty,
)
crate_name = "bulk cotton crate"
crate_type = /obj/structure/closet/crate/hydroponics
/datum/supply_pack/materials/rcdammo
name = "Spare RCD ammo"
desc = "This crate contains sixteen RCD compressed matter packs, to help with any holes or projects people might be working on."
+2 -1
View File
@@ -252,6 +252,7 @@
crate_name = "virus crate"
crate_type = /obj/structure/closet/crate/secure/plasma
dangerous = TRUE
can_private_buy = FALSE
/datum/supply_pack/medical/anitvirus
name = "Virus Containment Crate"
@@ -271,4 +272,4 @@
/obj/item/storage/box/syringes,
/obj/item/storage/box/beakers)
crate_name = "virus containment unit crate"
crate_type = /obj/structure/closet/crate/secure/plasma
crate_type = /obj/structure/closet/crate/secure/plasma
-16
View File
@@ -370,22 +370,6 @@
/////////////////////////////////// Misc /////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
/datum/supply_pack/organic/hunting
name = "Hunting Gear"
desc = "Even in space, we can find prey to hunt, this crate contains everthing a fine hunter needs to have a sporting time. This crate needs armory access to open. A true huntter only needs a fine bottle of cognac, a nice coat, some good o' cigars, and of cource a hunting shotgun. "
cost = 3500
contraband = TRUE
contains = list(/obj/item/clothing/head/flatcap,
/obj/item/clothing/suit/hooded/wintercoat/captain,
/obj/item/reagent_containers/food/drinks/bottle/cognac,
/obj/item/storage/fancy/cigarettes/cigars/havana,
/obj/item/clothing/gloves/color/white,
/obj/item/clothing/under/rank/civilian/curator,
/obj/item/gun/ballistic/shotgun/lethal)
access = ACCESS_ARMORY
crate_name = "sporting crate"
crate_type = /obj/structure/closet/crate/secure // Would have liked a wooden crate but access >:(
/datum/supply_pack/organic/party
name = "Party Equipment"
desc = "Celebrate both life and death on the station with Nanotrasen's Party Essentials(tm)! Contains seven colored glowsticks, four beers, two ales, a drinking shaker, and a bottle of patron & goldschlager!"
+1
View File
@@ -17,6 +17,7 @@
cost = 2500
contains = list (/obj/item/reagent_containers/food/snacks/cube/ape)
crate_name = "ape cube crate"
can_private_buy = FALSE
/datum/supply_pack/science/beakers
name = "Chemistry Beakers Crate"
+21
View File
@@ -10,6 +10,7 @@
group = "Security"
access = ACCESS_SECURITY
crate_type = /obj/structure/closet/crate/secure/gear
can_private_buy = FALSE
/datum/supply_pack/security/ammo
name = "Ammo Crate - General Purpose"
@@ -57,6 +58,7 @@
/obj/item/toy/crayon/white,
/obj/item/clothing/head/fedora/det_hat)
crate_name = "forensics crate"
can_private_buy = TRUE
/datum/supply_pack/security/helmets
name = "Helmets Crate"
@@ -134,6 +136,7 @@
/obj/item/grenade/barrier)
cost = 2000
crate_name = "security barriers crate"
can_private_buy = TRUE
/datum/supply_pack/security/securityclothes
name = "Security Clothing Crate"
@@ -152,6 +155,7 @@
/obj/item/clothing/suit/armor/hos/navyblue,
/obj/item/clothing/head/beret/sec/navyhos)
crate_name = "security clothing crate"
can_private_buy = TRUE
/datum/supply_pack/security/supplies
name = "Security Supplies Crate"
@@ -179,6 +183,7 @@
contains = list(/obj/item/clothing/head/helmet/justice,
/obj/item/clothing/mask/gas/sechailer)
crate_name = "security clothing crate"
can_private_buy = TRUE
/datum/supply_pack/security/baton
name = "Stun Batons Crate"
@@ -207,3 +212,19 @@
/obj/item/storage/box/wall_flash,
/obj/item/storage/box/wall_flash)
crate_name = "wall-mounted flash crate"
/datum/supply_pack/security/hunting
name = "Hunting Gear"
desc = "Even in space, we can find prey to hunt, this crate contains everthing a fine hunter needs to have a sporting time. This crate needs armory access to open. A true huntter only needs a fine bottle of cognac, a nice coat, some good o' cigars, and of cource a hunting shotgun. "
cost = 3500
contraband = TRUE
contains = list(/obj/item/clothing/head/flatcap,
/obj/item/clothing/suit/hooded/wintercoat/captain,
/obj/item/reagent_containers/food/drinks/bottle/cognac,
/obj/item/storage/fancy/cigarettes/cigars/havana,
/obj/item/clothing/gloves/color/white,
/obj/item/clothing/under/rank/civilian/curator,
/obj/item/gun/ballistic/shotgun/lethal)
access = ACCESS_ARMORY
crate_name = "sporting crate"
crate_type = /obj/structure/closet/crate/secure // Would have liked a wooden crate but access >:(
+1
View File
@@ -99,6 +99,7 @@
contains = list(/obj/machinery/vending/security)
crate_name = "SecTech supply crate"
crate_type = /obj/structure/closet/crate/secure/gear
can_private_buy = FALSE
/datum/supply_pack/vending/snack
name = "Snack Supply Crate"
+14
View File
@@ -80,10 +80,24 @@
var/list/char_render_holders //Should only be a key-value list of north/south/east/west = obj/screen.
/// Keys currently held
var/list/keys_held = list()
/// These next two vars are to apply movement for keypresses and releases made while move delayed.
/// Because discarding that input makes the game less responsive.
/// On next move, add this dir to the move that would otherwise be done
var/next_move_dir_add
/// On next move, subtract this dir from the move that would otherwise be done
var/next_move_dir_sub
/// Amount of keydowns in the last keysend checking interval
var/client_keysend_amount = 0
/// World tick time where client_keysend_amount will reset
var/next_keysend_reset = 0
/// World tick time where keysend_tripped will reset back to false
var/next_keysend_trip_reset = 0
/// When set to true, user will be autokicked if they trip the keysends in a second limit again
var/keysend_tripped = FALSE
/// custom movement keys for this client
var/list/movement_keys = list()
/// Messages currently seen by this client
var/list/seen_messages
+27 -4
View File
@@ -265,6 +265,9 @@ GLOBAL_LIST_EMPTY(external_rsc_urls)
else
prefs = new /datum/preferences(src)
GLOB.preferences_datums[ckey] = prefs
if(SSinput.initialized)
set_macros()
update_movement_keys(prefs)
prefs.last_ip = address //these are gonna be used for banning
prefs.last_id = computer_id //these are gonna be used for banning
@@ -328,9 +331,6 @@ GLOBAL_LIST_EMPTY(external_rsc_urls)
qdel(src)
return
if(SSinput.initialized)
set_macros()
chatOutput.start() // Starts the chat
if(alert_mob_dupe_login)
@@ -789,7 +789,9 @@ GLOBAL_LIST_EMPTY(external_rsc_urls)
log_game("[key_name(src)] is using the middle click aimbot exploit")
message_admins("[ADMIN_LOOKUPFLW(src)] [ADMIN_KICK(usr)] is using the middle click aimbot exploit</span>")
add_system_note("aimbot", "Is using the middle click aimbot exploit")
log_click(object, location, control, params, src, "lockout (spam - minute ab c [ab] s [middragtime])")
else
log_click(object, location, control, params, src, "lockout (spam - minute)")
log_game("[key_name(src)] Has hit the per-minute click limit of [mcl] clicks in a given game minute")
message_admins("[ADMIN_LOOKUPFLW(src)] [ADMIN_KICK(usr)] Has hit the per-minute click limit of [mcl] clicks in a given game minute")
to_chat(src, "<span class='danger'>[msg]</span>")
@@ -809,8 +811,12 @@ GLOBAL_LIST_EMPTY(external_rsc_urls)
return
if(ab) //Citadel edit, things with stuff.
log_click(object, location, control, params, src, "dropped (ab c [ab] s [middragtime])")
return
if(prefs.log_clicks)
log_click(object, location, control, params, src)
if (prefs.hotkeys)
// If hotkey mode is enabled, then clicking the map will automatically
// unfocus the text bar. This removes the red color from the text bar
@@ -892,6 +898,23 @@ GLOBAL_LIST_EMPTY(external_rsc_urls)
y = clamp(y+change, min,max)
change_view("[x]x[y]")
/client/proc/update_movement_keys(datum/preferences/direct_prefs)
var/datum/preferences/D = prefs || direct_prefs
if(!D?.key_bindings)
return
movement_keys = list()
for(var/key in D.key_bindings)
for(var/kb_name in D.key_bindings[key])
switch(kb_name)
if("North")
movement_keys[key] = NORTH
if("East")
movement_keys[key] = EAST
if("West")
movement_keys[key] = WEST
if("South")
movement_keys[key] = SOUTH
/client/proc/change_view(new_size)
if (isnull(new_size))
CRASH("change_view called without argument.")
+210 -28
View File
@@ -1,11 +1,6 @@
/* CAUTION! CAUTION! CAUTION! CAUTION! CAUTION! *\
| THIS FILE CONTAINS HOOKS FOR FOR |
| CHANGES SPECIFIC TO CITADEL. IF |
| YOU'RE FIXING A MERGE CONFLICT |
| HERE, PLEASE ASK FOR REVIEW FROM |
| ANOTHER MAINTAINER TO ENSURE YOU |
| DON'T INTRODUCE REGRESSIONS. |
\* */
#define DEFAULT_SLOT_AMT 2
#define HANDS_SLOT_AMT 2
#define BACKPACK_SLOT_AMT 4
GLOBAL_LIST_EMPTY(preferences_datums)
@@ -20,6 +15,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
var/muted = 0
var/last_ip
var/last_id
var/log_clicks = FALSE
var/icon/custom_holoform_icon
var/list/cached_holoform_icons
@@ -51,6 +47,11 @@ GLOBAL_LIST_EMPTY(preferences_datums)
var/chat_on_map = TRUE
var/max_chat_length = CHAT_MESSAGE_MAX_LENGTH
var/see_chat_non_mob = TRUE
/// Custom Keybindings
var/list/key_bindings = list()
var/tgui_fancy = TRUE
var/tgui_lock = TRUE
var/windowflashing = TRUE
@@ -189,9 +190,6 @@ GLOBAL_LIST_EMPTY(preferences_datums)
var/uplink_spawn_loc = UPLINK_PDA
var/sprint_spacebar = FALSE
var/sprint_toggle = FALSE
var/hud_toggle_flash = TRUE
var/hud_toggle_color = "#ffffff"
@@ -204,6 +202,10 @@ GLOBAL_LIST_EMPTY(preferences_datums)
var/vore_flags = 0
var/list/belly_prefs = list()
var/vore_taste = "nothing in particular"
var/toggleeatingnoise = TRUE
var/toggledigestionnoise = TRUE
var/hound_sleeper = TRUE
var/cit_toggles = TOGGLES_CITADEL
//backgrounds
var/mutable_appearance/character_background
@@ -214,6 +216,19 @@ GLOBAL_LIST_EMPTY(preferences_datums)
var/no_tetris_storage = FALSE
///loadout stuff
var/gear_points = 10
var/list/gear_categories
var/list/chosen_gear = list()
var/gear_tab
var/screenshake = 100
var/damagescreenshake = 2
var/arousable = TRUE
var/widescreenpref = TRUE
var/autostand = TRUE
var/auto_ooc = FALSE
/datum/preferences/New(client/C)
parent = C
@@ -233,6 +248,8 @@ GLOBAL_LIST_EMPTY(preferences_datums)
return
//we couldn't load character data so just randomize the character appearance + name
random_character() //let's create a random character then - rather than a fat, bald and naked man.
key_bindings = deepCopyList(GLOB.hotkey_keybinding_list_by_key) // give them default keybinds and update their movement keys
C?.update_movement_keys(src)
real_name = pref_species.random_name(gender,1)
if(!loaded_preferences_successfully)
save_preferences()
@@ -254,6 +271,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
dat += "<a href='?_src_=prefs;preference=tab;tab=3' [current_tab == 3 ? "class='linkOn'" : ""]>Loadout</a>"
dat += "<a href='?_src_=prefs;preference=tab;tab=1' [current_tab == 1 ? "class='linkOn'" : ""]>Game Preferences</a>"
dat += "<a href='?_src_=prefs;preference=tab;tab=4' [current_tab == 4 ? "class='linkOn'" : ""]>Content Preferences</a>"
dat += "<a href='?_src_=prefs;preference=tab;tab=5' [current_tab == 5 ? "class='linkOn'" : ""]>Keybindings</a>"
if(!path)
dat += "<div class='notice'>Please create an account to save your preferences</div>"
@@ -395,7 +413,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
mutant_colors = TRUE
if (CONFIG_GET(number/body_size_min) != CONFIG_GET(number/body_size_max))
dat += "<b>Sprite Size:</b> <a href='?_src_=prefs;preference=body_size;task=input'>[features["body_size"]]%</a><br>"
dat += "<b>Sprite Size:</b> <a href='?_src_=prefs;preference=body_size;task=input'>[features["body_size"]*100]%</a><br>"
if((EYECOLOR in pref_species.species_traits) && !(NOEYES in pref_species.species_traits))
@@ -843,7 +861,6 @@ GLOBAL_LIST_EMPTY(preferences_datums)
dat += "<b>See Runechat for non-mobs:</b> <a href='?_src_=prefs;preference=see_chat_non_mob'>[see_chat_non_mob ? "Enabled" : "Disabled"]</a><br>"
dat += "<br>"
dat += "<b>Action Buttons:</b> <a href='?_src_=prefs;preference=action_buttons'>[(buttons_locked) ? "Locked In Place" : "Unlocked"]</a><br>"
dat += "<b>Keybindings:</b> <a href='?_src_=prefs;preference=hotkeys'>[(hotkeys) ? "Hotkeys" : "Default"]</a><br>"
dat += "<br>"
dat += "<b>PDA Color:</b> <span style='border:1px solid #161616; background-color: [pda_color];'>&nbsp;&nbsp;&nbsp;</span> <a href='?_src_=prefs;preference=pda_color;task=input'>Change</a><BR>"
dat += "<b>PDA Style:</b> <a href='?_src_=prefs;task=input;preference=pda_style'>[pda_style]</a><br>"
@@ -939,8 +956,6 @@ GLOBAL_LIST_EMPTY(preferences_datums)
dat += "</a><br>"
dat += "<b>Ambient Occlusion:</b> <a href='?_src_=prefs;preference=ambientocclusion'>[ambientocclusion ? "Enabled" : "Disabled"]</a><br>"
dat += "<b>Fit Viewport:</b> <a href='?_src_=prefs;preference=auto_fit_viewport'>[auto_fit_viewport ? "Auto" : "Manual"]</a><br>"
dat += "<b>Sprint Key:</b> <a href='?_src_=prefs;preference=sprint_key'>[sprint_spacebar ? "Space" : "Shift"]</a><br>"
dat += "<b>Toggle Sprint:</b> <a href='?_src_=prefs;preference=sprint_toggle'>[sprint_toggle ? "Enabled" : "Disabled"]</a><br>"
dat += "<b>HUD Button Flashes:</b> <a href='?_src_=prefs;preference=hud_toggle_flash'>[hud_toggle_flash ? "Enabled" : "Disabled"]</a><br>"
dat += "<b>HUD Button Flash Color:</b> <span style='border: 1px solid #161616; background-color: [hud_toggle_color];'>&nbsp;&nbsp;&nbsp;</span> <a href='?_src_=prefs;preference=hud_toggle_color;task=input'>Change</a><br>"
@@ -1063,6 +1078,56 @@ GLOBAL_LIST_EMPTY(preferences_datums)
dat += "<b>Ass Slapping:</b> <a href='?_src_=prefs;preference=ass_slap'>[(cit_toggles & NO_ASS_SLAP) ? "Disallowed" : "Allowed"]</a><br>"
dat += "</tr></table>"
dat += "<br>"
if(5) // Custom keybindings
dat += "<b>Keybindings:</b> <a href='?_src_=prefs;preference=hotkeys'>[(hotkeys) ? "Hotkeys" : "Input"]</a><br>"
dat += "Keybindings mode controls how the game behaves with tab and map/input focus.<br>If it is on <b>Hotkeys</b>, the game will always attempt to force you to map focus, meaning keypresses are sent \
directly to the map instead of the input. You will still be able to use the command bar, but you need to tab to do it every time you click on the game map.<br>\
If it is on <b>Input</b>, the game will not force focus away from the input bar, and you can switch focus using TAB between these two modes: If the input bar is pink, that means that you are in non-hotkey mode, sending all keypresses of the normal \
alphanumeric characters, punctuation, spacebar, backspace, enter, etc, typing keys into the input bar. If the input bar is white, you are in hotkey mode, meaning all keypresses go into the game's keybind handling system unless you \
manually click on the input bar to shift focus there.<br>\
Input mode is the closest thing to the old input system.<br>\
<b>IMPORTANT:</b> While in input mode's non hotkey setting (tab toggled), Ctrl + KEY will send KEY to the keybind system as the key itself, not as Ctrl + KEY. This means Ctrl + T/W/A/S/D/all your familiar stuff still works, but you \
won't be able to access any regular Ctrl binds.<br>"
// Create an inverted list of keybindings -> key
var/list/user_binds = list()
for (var/key in key_bindings)
for(var/kb_name in key_bindings[key])
user_binds[kb_name] += list(key)
var/list/kb_categories = list()
// Group keybinds by category
for (var/name in GLOB.keybindings_by_name)
var/datum/keybinding/kb = GLOB.keybindings_by_name[name]
kb_categories[kb.category] += list(kb)
dat += "<style>label { display: inline-block; width: 200px; }</style><body>"
for (var/category in kb_categories)
dat += "<h3>[category]</h3>"
for (var/i in kb_categories[category])
var/datum/keybinding/kb = i
if(!length(user_binds[kb.name]))
dat += "<label>[kb.full_name]</label> <a href ='?_src_=prefs;preference=keybindings_capture;keybinding=[kb.name];old_key=["Unbound"]'>Unbound</a>"
var/list/default_keys = hotkeys ? kb.hotkey_keys : kb.classic_keys
if(LAZYLEN(default_keys))
dat += "| Default: [default_keys.Join(", ")]"
dat += "<br>"
else
var/bound_key = user_binds[kb.name][1]
dat += "<label>[kb.full_name]</label> <a href ='?_src_=prefs;preference=keybindings_capture;keybinding=[kb.name];old_key=[bound_key]'>[bound_key]</a>"
for(var/bound_key_index in 2 to length(user_binds[kb.name]))
bound_key = user_binds[kb.name][bound_key_index]
dat += " | <a href ='?_src_=prefs;preference=keybindings_capture;keybinding=[kb.name];old_key=[bound_key]'>[bound_key]</a>"
if(length(user_binds[kb.name]) < MAX_KEYS_PER_KEYBIND)
dat += "| <a href ='?_src_=prefs;preference=keybindings_capture;keybinding=[kb.name]'>Add Secondary</a>"
var/list/default_keys = hotkeys ? kb.classic_keys : kb.hotkey_keys
if(LAZYLEN(default_keys))
dat += "| Default: [default_keys.Join(", ")]"
dat += "<br>"
dat += "<br><br>"
dat += "<a href ='?_src_=prefs;preference=keybindings_reset'>\[Reset to default\]</a>"
dat += "</body>"
dat += "<hr><center>"
@@ -1083,6 +1148,31 @@ GLOBAL_LIST_EMPTY(preferences_datums)
#undef APPEARANCE_CATEGORY_COLUMN
#undef MAX_MUTANT_ROWS
/datum/preferences/proc/CaptureKeybinding(mob/user, datum/keybinding/kb, var/old_key)
var/HTML = {"
<div id='focus' style="outline: 0;" tabindex=0>Keybinding: [kb.full_name]<br>[kb.description]<br><br><b>Press any key to change<br>Press ESC to clear</b></div>
<script>
var deedDone = false;
document.onkeyup = function(e) {
if(deedDone){ return; }
var alt = e.altKey ? 1 : 0;
var ctrl = e.ctrlKey ? 1 : 0;
var shift = e.shiftKey ? 1 : 0;
var numpad = (95 < e.keyCode && e.keyCode < 112) ? 1 : 0;
var escPressed = e.keyCode == 27 ? 1 : 0;
var url = 'byond://?_src_=prefs;preference=keybindings_set;keybinding=[kb.name];old_key=[old_key];clear_key='+escPressed+';key='+e.key+';alt='+alt+';ctrl='+ctrl+';shift='+shift+';numpad='+numpad+';key_code='+e.keyCode;
window.location=url;
deedDone = true;
}
document.getElementById('focus').focus();
</script>
"}
winshow(user, "capturekeypress", TRUE)
var/datum/browser/popup = new(user, "capturekeypress", "<div align='center'>Keybindings</div>", 350, 300)
popup.set_content(HTML)
popup.open(FALSE)
onclose(user, "capturekeypress", src)
/datum/preferences/proc/SetChoices(mob/user, limit = 17, list/splitJobs = list("Chief Engineer"), widthPerColumn = 295, height = 620)
if(!SSjob)
return
@@ -2263,10 +2353,73 @@ GLOBAL_LIST_EMPTY(preferences_datums)
if("hotkeys")
hotkeys = !hotkeys
if(hotkeys)
winset(user, null, "input.focus=true input.background-color=[COLOR_INPUT_ENABLED] mainwindow.macro=default")
else
winset(user, null, "input.focus=true input.background-color=[COLOR_INPUT_ENABLED] mainwindow.macro=old_default")
user.client.set_macros()
if("keybindings_capture")
var/datum/keybinding/kb = GLOB.keybindings_by_name[href_list["keybinding"]]
var/old_key = href_list["old_key"]
CaptureKeybinding(user, kb, old_key)
return
if("keybindings_set")
var/kb_name = href_list["keybinding"]
if(!kb_name)
user << browse(null, "window=capturekeypress")
ShowChoices(user)
return
var/clear_key = text2num(href_list["clear_key"])
var/old_key = href_list["old_key"]
if(clear_key)
if(key_bindings[old_key])
key_bindings[old_key] -= kb_name
if(!length(key_bindings[old_key]))
key_bindings -= old_key
user << browse(null, "window=capturekeypress")
save_preferences()
ShowChoices(user)
return
var/new_key = uppertext(href_list["key"])
var/AltMod = text2num(href_list["alt"]) ? "Alt" : ""
var/CtrlMod = text2num(href_list["ctrl"]) ? "Ctrl" : ""
var/ShiftMod = text2num(href_list["shift"]) ? "Shift" : ""
var/numpad = text2num(href_list["numpad"]) ? "Numpad" : ""
// var/key_code = text2num(href_list["key_code"])
if(GLOB._kbMap[new_key])
new_key = GLOB._kbMap[new_key]
var/full_key
switch(new_key)
if("Alt")
full_key = "[new_key][CtrlMod][ShiftMod]"
if("Ctrl")
full_key = "[AltMod][new_key][ShiftMod]"
if("Shift")
full_key = "[AltMod][CtrlMod][new_key]"
else
full_key = "[AltMod][CtrlMod][ShiftMod][numpad][new_key]"
if(key_bindings[old_key])
key_bindings[old_key] -= kb_name
if(!length(key_bindings[old_key]))
key_bindings -= old_key
key_bindings[full_key] += list(kb_name)
key_bindings[full_key] = sortList(key_bindings[full_key])
user << browse(null, "window=capturekeypress")
user.client.update_movement_keys()
save_preferences()
if("keybindings_reset")
var/choice = tgalert(user, "Would you prefer 'hotkey' or 'classic' defaults?", "Setup keybindings", "Hotkey", "Classic", "Cancel")
if(choice == "Cancel")
ShowChoices(user)
return
hotkeys = (choice == "Hotkey")
key_bindings = (hotkeys) ? deepCopyList(GLOB.hotkey_keybinding_list_by_key) : deepCopyList(GLOB.classic_keybinding_list_by_key)
user.client.update_movement_keys()
if("chat_on_map")
chat_on_map = !chat_on_map
if("see_chat_non_mob")
@@ -2385,9 +2538,11 @@ GLOBAL_LIST_EMPTY(preferences_datums)
if("ambientocclusion")
ambientocclusion = !ambientocclusion
if(parent && parent.screen && parent.screen.len)
var/obj/screen/plane_master/game_world/PM = parent.mob.hud_used.plane_masters["[GAME_PLANE]"]
var/obj/screen/plane_master/game_world/G = parent.mob.hud_used.plane_masters["[GAME_PLANE]"]
var/obj/screen/plane_master/above_wall/A = parent.mob.hud_used.plane_masters["[ABOVE_WALL_PLANE]"]
var/obj/screen/plane_master/wall/W = parent.mob.hud_used.plane_masters["[WALL_PLANE]"]
PM.backdrop(parent.mob)
G.backdrop(parent.mob)
A.backdrop(parent.mob)
W.backdrop(parent.mob)
if("auto_fit_viewport")
@@ -2395,13 +2550,6 @@ GLOBAL_LIST_EMPTY(preferences_datums)
if(auto_fit_viewport && parent)
parent.fit_viewport()
if("sprint_key")
sprint_spacebar = !sprint_spacebar
if("sprint_toggle")
sprint_toggle = !sprint_toggle
if("hud_toggle_flash")
hud_toggle_flash = !hud_toggle_flash
@@ -2580,3 +2728,37 @@ GLOBAL_LIST_EMPTY(preferences_datums)
if(!cached_holoform_icons[filter_type])
cached_holoform_icons[filter_type] = process_holoform_icon_filter(custom_holoform_icon, filter_type)
return cached_holoform_icons[filter_type]
//Used in savefile update 32, can be removed once that is no longer relevant.
/datum/preferences/proc/force_reset_keybindings()
var/choice = tgalert(parent.mob, "Your basic keybindings need to be reset, emotes will remain as before. Would you prefer 'hotkey' or 'classic' mode?", "Reset keybindings", "Hotkey", "Classic")
hotkeys = (choice != "Classic")
var/list/oldkeys = key_bindings
key_bindings = (hotkeys) ? deepCopyList(GLOB.hotkey_keybinding_list_by_key) : deepCopyList(GLOB.classic_keybinding_list_by_key)
for(var/key in oldkeys)
if(!key_bindings[key])
key_bindings[key] = oldkeys[key]
parent.update_movement_keys()
/datum/preferences/proc/is_loadout_slot_available(slot)
var/list/L
LAZYINITLIST(L)
for(var/i in chosen_gear)
var/datum/gear/G = i
var/occupied_slots = L[slot_to_string(initial(G.category))] ? L[slot_to_string(initial(G.category))] + 1 : 1
LAZYSET(L, slot_to_string(initial(G.category)), occupied_slots)
switch(slot)
if(SLOT_IN_BACKPACK)
if(L[slot_to_string(SLOT_IN_BACKPACK)] < BACKPACK_SLOT_AMT)
return TRUE
if(SLOT_HANDS)
if(L[slot_to_string(SLOT_HANDS)] < HANDS_SLOT_AMT)
return TRUE
else
if(L[slot_to_string(slot)] < DEFAULT_SLOT_AMT)
return TRUE
#undef DEFAULT_SLOT_AMT
#undef HANDS_SLOT_AMT
#undef BACKPACK_SLOT_AMT
+50 -10
View File
@@ -5,7 +5,7 @@
// You do not need to raise this if you are adding new values that have sane defaults.
// Only raise this value when changing the meaning/format/name/layout of an existing value
// where you would want the updater procs below to run
#define SAVEFILE_VERSION_MAX 31
#define SAVEFILE_VERSION_MAX 32
/*
SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Carn
@@ -42,7 +42,8 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
//if your savefile is 3 months out of date, then 'tough shit'.
/datum/preferences/proc/update_preferences(current_version, savefile/S)
return
if(current_version < 32) //If you remove this, remove force_reset_keybindings() too.
addtimer(CALLBACK(src, .proc/force_reset_keybindings), 30) //No mob available when this is run, timer allows user choice.
/datum/preferences/proc/update_character(current_version, savefile/S)
if(current_version < 19)
@@ -250,8 +251,6 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
S["parallax"] >> parallax
S["ambientocclusion"] >> ambientocclusion
S["auto_fit_viewport"] >> auto_fit_viewport
S["sprint_spacebar"] >> sprint_spacebar
S["sprint_toggle"] >> sprint_toggle
S["hud_toggle_flash"] >> hud_toggle_flash
S["hud_toggle_color"] >> hud_toggle_color
S["menuoptions"] >> menuoptions
@@ -261,6 +260,9 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
S["pda_color"] >> pda_color
S["pda_skin"] >> pda_skin
// Custom hotkeys
S["key_bindings"] >> key_bindings
//citadel code
S["arousable"] >> arousable
S["screenshake"] >> screenshake
@@ -295,8 +297,6 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
parallax = sanitize_integer(parallax, PARALLAX_INSANE, PARALLAX_DISABLE, null)
ambientocclusion = sanitize_integer(ambientocclusion, 0, 1, initial(ambientocclusion))
auto_fit_viewport = sanitize_integer(auto_fit_viewport, 0, 1, initial(auto_fit_viewport))
sprint_spacebar = sanitize_integer(sprint_spacebar, 0, 1, initial(sprint_spacebar))
sprint_toggle = sanitize_integer(sprint_toggle, 0, 1, initial(sprint_toggle))
hud_toggle_flash = sanitize_integer(hud_toggle_flash, 0, 1, initial(hud_toggle_flash))
hud_toggle_color = sanitize_hexcolor(hud_toggle_color, 6, 1, initial(hud_toggle_color))
ghost_form = sanitize_inlist(ghost_form, GLOB.ghost_forms, initial(ghost_form))
@@ -315,9 +315,25 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
cit_toggles = sanitize_integer(cit_toggles, 0, 16777215, initial(cit_toggles))
auto_ooc = sanitize_integer(auto_ooc, 0, 1, initial(auto_ooc))
no_tetris_storage = sanitize_integer(no_tetris_storage, 0, 1, initial(no_tetris_storage))
key_bindings = sanitize_islist(key_bindings, list())
verify_keybindings_valid() // one of these days this will runtime and you'll be glad that i put it in a different proc so no one gets their saves wiped
return 1
/datum/preferences/proc/verify_keybindings_valid()
// Sanitize the actual keybinds to make sure they exist.
for(var/key in key_bindings)
if(!islist(key_bindings[key]))
key_bindings -= key
var/list/binds = key_bindings[key]
for(var/bind in binds)
if(!GLOB.keybindings_by_name[bind])
binds -= bind
if(!length(binds))
key_bindings -= key
// End
/datum/preferences/proc/save_preferences()
if(!path)
return 0
@@ -362,8 +378,6 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
WRITE_FILE(S["parallax"], parallax)
WRITE_FILE(S["ambientocclusion"], ambientocclusion)
WRITE_FILE(S["auto_fit_viewport"], auto_fit_viewport)
WRITE_FILE(S["sprint_spacebar"], sprint_spacebar)
WRITE_FILE(S["sprint_toggle"], sprint_toggle)
WRITE_FILE(S["hud_toggle_flash"], hud_toggle_flash)
WRITE_FILE(S["hud_toggle_color"], hud_toggle_color)
WRITE_FILE(S["menuoptions"], menuoptions)
@@ -372,6 +386,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
WRITE_FILE(S["pda_style"], pda_style)
WRITE_FILE(S["pda_color"], pda_color)
WRITE_FILE(S["pda_skin"], pda_skin)
WRITE_FILE(S["key_bindings"], key_bindings)
//citadel code
WRITE_FILE(S["screenshake"], screenshake)
@@ -465,6 +480,9 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
S["feature_insect_wings"] >> features["insect_wings"]
S["feature_insect_fluff"] >> features["insect_fluff"]
S["feature_insect_markings"] >> features["insect_markings"]
S["feature_horns_color"] >> features["horns_color"]
S["feature_wings_color"] >> features["wings_color"]
//Custom names
for(var/custom_name_id in GLOB.preferences_custom_names)
@@ -541,6 +559,21 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
S["vore_taste"] >> vore_taste
S["belly_prefs"] >> belly_prefs
//gear loadout
var/text_to_load
S["loadout"] >> text_to_load
var/list/saved_loadout_paths = splittext(text_to_load, "|")
chosen_gear = list()
gear_points = CONFIG_GET(number/initial_gear_points)
for(var/i in saved_loadout_paths)
var/datum/gear/path = text2path(i)
if(path)
var/init_cost = initial(path.cost)
if(init_cost > gear_points)
continue
chosen_gear += path
gear_points -= init_cost
//try to fix any outdated data if necessary
if(needs_update >= 0)
update_character(needs_update, S) //needs_update == savefile_version if we need an update (positive integer)
@@ -701,8 +734,6 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
WRITE_FILE(S["shirt_color"] , shirt_color)
WRITE_FILE(S["socks"] , socks)
WRITE_FILE(S["socks_color"] , socks_color)
WRITE_FILE(S["horns_color"] , features["horns_color"])
WRITE_FILE(S["wings_color"] , features["wings_color"])
WRITE_FILE(S["backbag"] , backbag)
WRITE_FILE(S["jumpsuit_style"] , jumpsuit_style)
WRITE_FILE(S["uplink_loc"] , uplink_spawn_loc)
@@ -718,6 +749,8 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
WRITE_FILE(S["feature_lizard_body_markings"] , features["body_markings"])
WRITE_FILE(S["feature_lizard_legs"] , features["legs"])
WRITE_FILE(S["feature_deco_wings"] , features["deco_wings"])
WRITE_FILE(S["feature_horns_color"] , features["horns_color"])
WRITE_FILE(S["feature_wings_color"] , features["wings_color"])
WRITE_FILE(S["feature_insect_wings"] , features["insect_wings"])
WRITE_FILE(S["feature_insect_fluff"] , features["insect_fluff"])
WRITE_FILE(S["feature_insect_markings"] , features["insect_markings"])
@@ -771,6 +804,13 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
WRITE_FILE(S["vore_taste"] , vore_taste)
WRITE_FILE(S["belly_prefs"] , belly_prefs)
//gear loadout
if(chosen_gear.len)
var/text_to_save = chosen_gear.Join("|")
S["loadout"] << text_to_save
else
S["loadout"] << "" //empty string to reset the value
cit_character_pref_save(S)
return 1
+3 -3
View File
@@ -649,7 +649,6 @@
max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT
clothing_flags = STOPSPRESSUREDAMAGE | THICKMATERIAL | IMMUTABLE_SLOW
resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF
flags_1 = TESLA_IGNORE_1
/obj/item/clothing/head/helmet/space/hardsuit/ancient/mason
name = "M.A.S.O.N RIG helmet"
@@ -665,7 +664,6 @@
max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT
clothing_flags = STOPSPRESSUREDAMAGE | THICKMATERIAL | BLOCK_GAS_SMOKE_EFFECT | ALLOWINTERNALS | SCAN_REAGENTS
resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF
flags_1 = TESLA_IGNORE_1
/obj/item/clothing/head/helmet/space/hardsuit/ancient/mason/Initialize()
. = ..()
@@ -676,12 +674,14 @@
if (slot == SLOT_HEAD)
var/datum/atom_hud/DHUD = GLOB.huds[DATA_HUD_DIAGNOSTIC_BASIC]
DHUD.add_hud_to(user)
ADD_TRAIT(user, TRAIT_TESLA_SHOCKIMMUNE, "mason_hardsuit")
/obj/item/clothing/head/helmet/space/hardsuit/ancient/mason/dropped(mob/living/carbon/human/user)
..()
if (user.head == src)
if (HAS_TRAIT_FROM(user, TRAIT_TESLA_SHOCKIMMUNE, "mason_hardsuit"))
var/datum/atom_hud/DHUD = GLOB.huds[DATA_HUD_DIAGNOSTIC_BASIC]
DHUD.remove_hud_from(user)
REMOVE_TRAIT(user, TRAIT_TESLA_SHOCKIMMUNE, "mason_hardsuit")
/obj/item/clothing/suit/space/hardsuit/ancient/proc/on_mob_move()
var/mob/living/carbon/human/H = loc
@@ -395,10 +395,18 @@ Contains:
actions_types = list()
resistance_flags = FIRE_PROOF
mutantrace_variation = NONE
var/charges = INFINITY
/obj/item/clothing/suit/space/hardsuit/ert/paranormal/Initialize()
/obj/item/clothing/head/helmet/space/hardsuit/ert/paranormal/Initialize()
. = ..()
AddComponent(/datum/component/anti_magic, FALSE, FALSE, TRUE, ITEM_SLOT_HEAD)
AddComponent(/datum/component/anti_magic, FALSE, FALSE, TRUE, ITEM_SLOT_HEAD, charges, TRUE, null, CALLBACK(src, .proc/anti_magic_gone))
/obj/item/clothing/head/helmet/space/hardsuit/ert/paranormal/proc/anti_magic_gone()
var/mob/M = loc
if(!istype(M))
return
do_sparks(2, TRUE, M)
M.show_message("<span class='warning'>\The [src] sparks and fizzles as its psychic wards wane away at last...</span>", MSG_VISUAL)
/obj/item/clothing/suit/space/hardsuit/ert/paranormal
name = "paranormal response team suit"
@@ -408,10 +416,18 @@ Contains:
helmettype = /obj/item/clothing/head/helmet/space/hardsuit/ert/paranormal
max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT
resistance_flags = FIRE_PROOF
var/charges = INFINITY
/obj/item/clothing/suit/space/hardsuit/ert/paranormal/Initialize()
. = ..()
AddComponent(/datum/component/anti_magic, TRUE, TRUE, FALSE, ITEM_SLOT_OCLOTHING)
AddComponent(/datum/component/anti_magic, TRUE, TRUE, FALSE, ITEM_SLOT_OCLOTHING, charges, TRUE, null, CALLBACK(src, .proc/anti_magic_gone))
/obj/item/clothing/suit/space/hardsuit/ert/paranormal/proc/anti_magic_gone()
var/mob/M = loc
if(!istype(M))
return
do_sparks(2, TRUE, M)
M.show_message("<span class='warning'>\The [src] sparks and fizzles as its anti magic wards wane away at last...</span>", MSG_VISUAL)
/obj/item/clothing/suit/space/hardsuit/ert/paranormal/inquisitor
name = "inquisitor's hardsuit"
@@ -424,6 +440,19 @@ Contains:
icon_state = "hardsuit0-inq"
item_state = "hardsuit0-inq"
/obj/item/clothing/suit/space/hardsuit/ert/paranormal/inquisitor/old
desc = "Powerful wards are built into this hardsuit, protecting the user from all manner of paranormal threats. Alas, this one looks pretty worn out and rusted."
armor = list("melee" = 55, "bullet" = 40, "laser" = 40, "energy" = 40, "bomb" = 40, "bio" = 80, "rad" = 80, "fire" = 60, "acid" = 60)
slowdown = 0.8
obj_flags = IMMUTABLE_SLOW //rest in peace rusty joints.
helmettype = /obj/item/clothing/head/helmet/space/hardsuit/ert/paranormal/inquisitor/old
charges = 12
/obj/item/clothing/head/helmet/space/hardsuit/ert/paranormal/inquisitor/old
desc = "A helmet worn by those who deal with paranormal threats for a living. Alas, this one looks pretty worn out and rusted."
armor = list("melee" = 55, "bullet" = 40, "laser" = 40, "energy" = 40, "bomb" = 40, "bio" = 80, "rad" = 80, "fire" = 60, "acid" = 60)
charges = 12
/obj/item/clothing/suit/space/hardsuit/ert/paranormal/beserker
name = "champion's hardsuit"
desc = "Voices echo from the hardsuit, driving the user insane."
@@ -437,6 +466,19 @@ Contains:
icon_state = "hardsuit0-beserker"
item_state = "hardsuit0-beserker"
/obj/item/clothing/suit/space/hardsuit/ert/paranormal/beserker/old
desc = "Voices echo from the hardsuit, driving the user insane. This one is pretty battle-worn, but still fearsome."
armor = list("melee" = 55, "bullet" = 40, "laser" = 40, "energy" = 40, "bomb" = 40, "bio" = 80, "rad" = 80, "fire" = 60, "acid" = 60)
slowdown = 0.8
obj_flags = IMMUTABLE_SLOW //rest in peace rusty joints.
helmettype = /obj/item/clothing/head/helmet/space/hardsuit/ert/paranormal/inquisitor/old
charges = 6
/obj/item/clothing/head/helmet/space/hardsuit/ert/paranormal/beserker/old
desc = "Peering into the eyes of the helmet is enough to seal damnation. This one is pretty battle-worn, but still fearsome."
armor = list("melee" = 55, "bullet" = 40, "laser" = 40, "energy" = 40, "bomb" = 40, "bio" = 80, "rad" = 80, "fire" = 60, "acid" = 60)
charges = 6
/obj/item/clothing/head/helmet/space/fragile
name = "emergency space helmet"
desc = "A bulky, air-tight helmet meant to protect the user during emergency situations. It doesn't look very durable."
@@ -477,4 +519,4 @@ Contains:
name = "paramedic EVA helmet"
desc = "A deep blue space helmet with a large red cross on the faceplate to designate the wearer as trained emergency medical personnel."
icon_state = "paramedic-eva-helmet"
item_state = "paramedic-eva-helmet"
item_state = "paramedic-eva-helmet"
+2 -2
View File
@@ -76,7 +76,7 @@
icon_state = "dragon"
desc = "A suit of armour fashioned from the remains of an ash drake."
allowed = list(/obj/item/flashlight, /obj/item/tank/internals, /obj/item/resonator, /obj/item/mining_scanner, /obj/item/t_scanner/adv_mining_scanner, /obj/item/gun/energy/kinetic_accelerator, /obj/item/pickaxe, /obj/item/spear)
armor = list("melee" = 60, "bullet" = 20, "laser" = 30, "energy" = 25, "bomb" = 25, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 100)
armor = list("melee" = 70, "bullet" = 20, "laser" = 35, "energy" = 25, "bomb" = 25, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 100)
hoodtype = /obj/item/clothing/head/hooded/cloakhood/drake
heat_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
body_parts_covered = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
@@ -87,7 +87,7 @@
name = "drake helm"
icon_state = "dragon"
desc = "The skull of a dragon."
armor = list("melee" = 60, "bullet" = 20, "laser" = 30, "energy" = 25, "bomb" = 25, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 100)
armor = list("melee" = 70, "bullet" = 20, "laser" = 35, "energy" = 25, "bomb" = 25, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 100)
heat_protection = HEAD
max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT
resistance_flags = FIRE_PROOF | ACID_PROOF | GOLIATH_RESISTANCE
@@ -647,6 +647,19 @@
desc = "A white winter coat hood with green markings."
icon_state = "winterhood_viro"
/obj/item/clothing/suit/hooded/wintercoat/paramedic
name = "paramedic winter coat"
desc = "A winter coat with blue markings. Warm, but probably won't protect from biological agents. For the cozy doctor on the go."
icon_state = "coatparamed"
item_state = "coatparamed"
allowed = list(/obj/item/analyzer, /obj/item/stack/medical, /obj/item/dnainjector, /obj/item/reagent_containers/dropper, /obj/item/reagent_containers/syringe, /obj/item/reagent_containers/hypospray, /obj/item/healthanalyzer, /obj/item/flashlight/pen, /obj/item/reagent_containers/glass/bottle, /obj/item/reagent_containers/glass/beaker, /obj/item/reagent_containers/pill, /obj/item/storage/pill_bottle, /obj/item/paper, /obj/item/melee/classic_baton/telescopic, /obj/item/toy, /obj/item/storage/fancy/cigarettes, /obj/item/lighter, /obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/plasmaman)
armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 50, "rad" = 0, "fire" = 0, "acid" = 45)
hoodtype = /obj/item/clothing/head/hooded/winterhood/paramedic
/obj/item/clothing/head/hooded/winterhood/paramedic
desc = "A white winter coat hood with blue markings."
icon_state = "winterhood_paramed"
/obj/item/clothing/suit/hooded/wintercoat/science
name = "science winter coat"
desc = "A white winter coat with an outdated atomic model instead of a plastic zipper tab."
@@ -164,21 +164,21 @@
desc = "An experimental suit of armor with sensitive detectors hooked up to a huge capacitor grid, with emitters strutting out of it. Zap."
siemens_coefficient = -1
reactivearmor_cooldown_duration = 20
var/tesla_power = 25000
var/tesla_range = 20
var/tesla_flags = TESLA_MOB_DAMAGE | TESLA_OBJ_DAMAGE
var/zap_power = 25000
var/zap_range = 20
var/zap_flags = ZAP_MOB_DAMAGE | ZAP_OBJ_DAMAGE
var/legacy = FALSE
var/legacy_dmg = 30
/obj/item/clothing/suit/armor/reactive/tesla/dropped(mob/user)
..()
if(istype(user))
user.flags_1 &= ~TESLA_IGNORE_1
REMOVE_TRAIT(user, TRAIT_TESLA_SHOCKIMMUNE, "reactive_tesla_armor")
/obj/item/clothing/suit/armor/reactive/tesla/equipped(mob/user, slot)
..()
if(slot_flags & slotdefine2slotbit(slot)) //Was equipped to a valid slot for this item?
user.flags_1 |= TESLA_IGNORE_1
ADD_TRAIT(user, TRAIT_TESLA_SHOCKIMMUNE, "reactive_tesla_armor")
/obj/item/clothing/suit/armor/reactive/tesla/block_action(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
if(prob(hit_reaction_chance))
@@ -190,7 +190,7 @@
return
owner.visible_message("<span class='danger'>[src] blocks [attack_text], sending out arcs of lightning!</span>")
if(!legacy)
tesla_zap(owner, tesla_range, tesla_power, tesla_flags)
tesla_zap(owner, zap_range, zap_power, zap_flags)
else
for(var/mob/living/M in view(7, owner))
if(M == owner)
+2 -2
View File
@@ -329,14 +329,14 @@
name = "bone talisman"
desc = "A hunter's talisman, some say the old gods smile on those who wear it."
icon_state = "talisman"
armor = list("melee" = 5, "bullet" = 5, "laser" = 5, "energy" = 5, "bomb" = 20, "bio" = 20, "rad" = 5, "fire" = 0, "acid" = 25)
armor = list("melee" = 5, "bullet" = 5, "laser" = 0, "energy" = 0, "bomb" = 10, "bio" = 20, "rad" = 5, "fire" = 0, "acid" = 25)
/obj/item/clothing/accessory/skullcodpiece
name = "skull codpiece"
desc = "A skull shaped ornament, intended to protect the important things in life."
icon_state = "skull"
above_suit = TRUE
armor = list("melee" = 5, "bullet" = 5, "laser" = 5, "energy" = 5, "bomb" = 20, "bio" = 20, "rad" = 5, "fire" = 0, "acid" = 25)
armor = list("melee" = 5, "bullet" = 5, "laser" = 0, "energy" = 0, "bomb" = 10, "bio" = 20, "rad" = 5, "fire" = 0, "acid" = 25)
/obj/item/clothing/accessory/skullcodpiece/fake
name = "false codpiece"
+2 -2
View File
@@ -1258,7 +1258,7 @@ GLOBAL_LIST_INIT(hallucination_list, list(
..()
if(!target.halbody)
var/list/possible_points = list()
for(var/turf/open/floor/F in target.visible_atoms(world.view))
for(var/turf/open/floor/F in target.fov_view(world.view))
possible_points += F
if(possible_points.len)
var/turf/open/floor/husk_point = pick(possible_points)
@@ -1289,7 +1289,7 @@ GLOBAL_LIST_INIT(hallucination_list, list(
set waitfor = FALSE
..()
var/list/turf/startlocs = list()
for(var/turf/open/T in target.visible_atoms(world.view+1)-view(world.view,target))
for(var/turf/open/T in target.fov_view(world.view+1)-view(world.view,target))
startlocs += T
if(!startlocs.len)
qdel(src)
@@ -29,7 +29,7 @@
<span class="ms" id="pingMs">--ms</span>
</div>
<div id="darkmodething">
<a href="#" class="subCell toggle" id="changeColorPreset" title="Change color preset"><i class="fas fa-eye-open"></i></a>
<a href="#" class="subCell toggle" id="changeColorPreset" title="Change color preset"><i class="fas fa-eye"></i></a>
</div>
<div id="audio">
<a href="#" class="subCell toggle" id="toggleAudio" title="Audio"><i class="fas fa-volume-up"></i></a>
+4 -2
View File
@@ -38,8 +38,10 @@
health = 25
density = FALSE
speech_span = "spooky"
friendly = "pets"
response_help = "chats with"
friendly_verb_continuous = "pets"
friendly_verb_simple = "pet"
response_help_continuous = "chats with"
response_help_simple = "chat with"
light_range = 3
light_color = "#ff9842"
var/last_poof
+6 -3
View File
@@ -15,6 +15,9 @@
speak_chance = 1
turns_per_move = 2
butcher_results = list()
response_help = "pets"
response_disarm = "pushes aside"
response_harm = "kicks"
response_help_continuous = "pets"
response_help_simple = "pet"
response_disarm_continuous = "pushes aside"
response_disarm_simple = "push aside"
response_harm_continuous = "kicks"
response_harm_simple = "kick"
@@ -89,7 +89,7 @@
desc = "Produces electricity from chemicals."
icon_state = "chemical_cell"
extended_desc = "This is effectively an internal beaker. It will consume and produce power from plasma, slime jelly, welding fuel, carbon,\
ethanol, nutriment, and blood in order of decreasing efficiency. It will consume fuel only if the battery can take more energy."
ethanol, nutriment, and blood in order of decreasing efficiency. It will consume fuel only if the battery can take more energy. But no fuel can be compared with blood of living human."
complexity = 4
inputs = list()
outputs = list("volume used" = IC_PINTYPE_NUMBER, "self reference" = IC_PINTYPE_SELFREF)
@@ -102,10 +102,8 @@
var/lfwb =TRUE
/obj/item/integrated_circuit/passive/power/chemical_cell/Initialize()
..()
. = ..()
create_reagents(volume, OPENCONTAINER)
extended_desc +="But no fuel can be compared with blood of living human."
/obj/item/integrated_circuit/passive/power/chemical_cell/interact(mob/user)
set_pin_data(IC_OUTPUT, 2, WEAKREF(src))
@@ -426,7 +426,7 @@
activators = list("compute abs coordinates" = IC_PINTYPE_PULSE_IN, "on convert" = IC_PINTYPE_PULSE_OUT)
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
/obj/item/integrated_circuit/converter/abs_to_rel_coords/do_work()
/obj/item/integrated_circuit/converter/rel_to_abs_coords/do_work()
var/x1 = get_pin_data(IC_INPUT, 1)
var/y1 = get_pin_data(IC_INPUT, 2)
@@ -456,7 +456,7 @@
activators = list("compute abs coordinates" = IC_PINTYPE_PULSE_IN, "on convert" = IC_PINTYPE_PULSE_OUT)
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
/obj/item/integrated_circuit/converter/abs_to_rel_coords/do_work()
/obj/item/integrated_circuit/converter/adv_rel_to_abs_coords/do_work()
var/turf/T = get_turf(src)
if(!T)
@@ -296,6 +296,7 @@
var/x_abs = clamp(T.x + target_x_rel, 0, world.maxx)
var/y_abs = clamp(T.y + target_y_rel, 0, world.maxy)
var/range = round(clamp(sqrt(target_x_rel*target_x_rel+target_y_rel*target_y_rel),0,8),1)
playsound(src, 'sound/weapons/sonic_jackhammer.ogg', 50, 1)
assembly.visible_message("<span class='danger'>\The [assembly] has thrown [A]!</span>")
log_attack("[assembly] [REF(assembly)] has thrown [A] with lethal force.")
A.forceMove(drop_location())
@@ -1,24 +0,0 @@
/datum/admins/key_down(_key, client/user)
switch(_key)
if("F3")
user.get_admin_say()
return
if("F5")
user.admin_ghost()
return
if("F6")
player_panel_new()
return
if("F7")
user.togglebuildmodeself()
return
if("F8")
if(user.keys_held["Ctrl"])
user.stealth()
else
user.invisimin()
return
if("F10")
user.get_dead_say()
return
..()
+1 -1
View File
@@ -5,7 +5,7 @@
if(!user.keys_held["Ctrl"])
var/movement_dir = NONE
for(var/_key in user.keys_held)
movement_dir = movement_dir | SSinput.movement_keys[_key]
movement_dir = movement_dir | user.movement_keys[_key]
if(user.next_move_dir_add)
movement_dir |= user.next_move_dir_add
if(user.next_move_dir_sub)
@@ -1,9 +0,0 @@
/mob/living/carbon/key_down(_key, client/user)
switch(_key)
if("R", "Southwest") // Southwest is End
toggle_throw_mode()
return
if("C")
user_toggle_intentional_combat_mode()
return
return ..()
+42 -28
View File
@@ -33,55 +33,69 @@
to_chat(src, "<span class='userdanger'>Invalid KeyDown detected! You have been disconnected from the server automatically.</span>")
log_admin("Client [ckey] just attempted to send an invalid keypress. Keymessage was over [MAX_KEYPRESS_COMMANDLENGTH] characters, autokicking due to likely abuse.")
message_admins("Client [ckey] just attempted to send an invalid keypress. Keymessage was over [MAX_KEYPRESS_COMMANDLENGTH] characters, autokicking due to likely abuse.")
QDEL_IN(src, 1)
qdel(src)
return
if(_key == "Tab")
ForceAllKeysUp() //groan, more hacky kevcode
return
if(length(keys_held) > MAX_HELD_KEYS)
keys_held.Cut(1,2)
keys_held[_key] = TRUE
var/movement = SSinput.movement_keys[_key]
var/movement = movement_keys[_key]
if(!(next_move_dir_sub & movement) && !keys_held["Ctrl"])
next_move_dir_add |= movement
// Client-level keybindings are ones anyone should be able to do at any time
// Things like taking screenshots, hitting tab, and adminhelps.
var/AltMod = keys_held["Alt"] ? "Alt" : ""
var/CtrlMod = keys_held["Ctrl"] ? "Ctrl" : ""
var/ShiftMod = keys_held["Shift"] ? "Shift" : ""
var/full_key
switch(_key)
if("F1")
if(keys_held["Ctrl"] && keys_held["Shift"]) // Is this command ever used?
winset(src, null, "command=.options")
else
get_adminhelp()
return
if("F2") // Screenshot. Hold shift to choose a name and location to save in
winset(src, null, "command=.screenshot [!keys_held["shift"] ? "auto" : ""]")
return
if("F12") // Toggles minimal HUD
mob.button_pressed_F12()
return
if("Alt", "Ctrl", "Shift")
full_key = "[AltMod][CtrlMod][ShiftMod]"
else
full_key = "[AltMod][CtrlMod][ShiftMod][_key]"
var/keycount = 0
for(var/kb_name in prefs.key_bindings[full_key])
keycount++
var/datum/keybinding/kb = GLOB.keybindings_by_name[kb_name]
if(kb.can_use(src) && kb.down(src) && keycount >= MAX_COMMANDS_PER_KEY)
break
if(holder)
holder.key_down(_key, src)
if(mob.focus)
mob.focus.key_down(_key, src)
holder?.key_down(_key, src)
mob.focus?.key_down(_key, src)
/// Keyup's all keys held down.
/client/proc/ForceAllKeysUp()
// simulate a user releasing all keys except for the mod keys. groan. i hate this. thanks, byond. why aren't keyups able to be forced to fire on macro change aoaoaoao.
// groan
for(var/key in keys_held) // all of these won't be the 3 mod keys.
if((key == "Ctrl") || (key == "Alt") || (key == "Shift"))
continue
keyUp("[key]")
/client/verb/keyUp(_key as text)
set instant = TRUE
set hidden = TRUE
keys_held -= _key
var/movement = SSinput.movement_keys[_key]
var/movement = movement_keys[_key]
if(!(next_move_dir_add & movement))
next_move_dir_sub |= movement
if(holder)
holder.key_up(_key, src)
if(mob.focus)
mob.focus.key_up(_key, src)
// We don't do full key for release, because for mod keys you
// can hold different keys and releasing any should be handled by the key binding specifically
for (var/kb_name in prefs.key_bindings[_key])
var/datum/keybinding/kb = GLOB.keybindings_by_name[kb_name]
if(kb.can_use(src) && kb.up(src))
break
holder?.key_up(_key, src)
mob.focus?.key_up(_key, src)
// Called every game tick
/client/keyLoop()
if(holder)
holder.keyLoop(src)
if(mob.focus)
mob.focus.keyLoop(src)
holder?.keyLoop(src)
mob.focus?.keyLoop(src)
@@ -1,80 +0,0 @@
/mob/living/carbon/human/key_down(_key, client/user)
if(client.keys_held["Shift"])
switch(_key)
if("E") // Put held thing in belt or take out most recent thing from belt
var/obj/item/thing = get_active_held_item()
var/obj/item/storage/equipped_belt = get_item_by_slot(SLOT_BELT)
if(!equipped_belt) // We also let you equip a belt like this
if(!thing)
to_chat(user, "<span class='notice'>You have no belt to take something out of.</span>")
return
equip_to_slot_if_possible(thing, SLOT_BELT)
return
if(!istype(equipped_belt)) // not a storage item
if(!thing)
to_chat(user, "<span class='notice'>You have no belt to take something out of.</span>")
else
to_chat(user, "<span class='notice'>You can't fit anything in.</span>")
return
if(thing) // put thing in belt
if(!SEND_SIGNAL(equipped_belt, COMSIG_TRY_STORAGE_INSERT, thing, user.mob))
to_chat(user, "<span class='notice'>You can't fit anything in.</span>")
return
if(!equipped_belt.contents.len) // nothing to take out
to_chat(user, "<span class='notice'>There's nothing in your belt to take out.</span>")
return
var/obj/item/stored = equipped_belt.contents[equipped_belt.contents.len]
if(!stored || stored.on_found(src))
return
stored.attack_hand(src) // take out thing from belt
return
if("B") // Put held thing in backpack or take out most recent thing from backpack
var/obj/item/thing = get_active_held_item()
var/obj/item/storage/equipped_backpack = get_item_by_slot(SLOT_BACK)
if(!equipped_backpack) // We also let you equip a backpack like this
if(!thing)
to_chat(user, "<span class='notice'>You have no backpack to take something out of.</span>")
return
equip_to_slot_if_possible(thing, SLOT_BACK)
return
if(!istype(equipped_backpack)) // not a storage item
if(!thing)
to_chat(user, "<span class='notice'>You have no backpack to take something out of.</span>")
else
to_chat(user, "<span class='notice'>You can't fit anything in.</span>")
return
if(thing) // put thing in backpack
if(!SEND_SIGNAL(equipped_backpack, COMSIG_TRY_STORAGE_INSERT, thing, user.mob))
to_chat(user, "<span class='notice'>You can't fit anything in.</span>")
return
if(!equipped_backpack.contents.len) // nothing to take out
to_chat(user, "<span class='notice'>There's nothing in your backpack to take out.</span>")
return
var/obj/item/stored = equipped_backpack.contents[equipped_backpack.contents.len]
if(!stored || stored.on_found(src))
return
stored.attack_hand(src) // take out thing from backpack
return
switch(_key)
if("Shift")
if(!user.prefs.sprint_spacebar)
user.prefs.sprint_toggle ? default_toggle_sprint() : sprint_hotkey(TRUE) //Yes, this looks hacky. Yes, this works.
return
if("Space")
if(user.prefs.sprint_spacebar)
user.prefs.sprint_toggle ? default_toggle_sprint() : sprint_hotkey(TRUE)
return
return ..()
/mob/living/carbon/human/key_up(_key, client/user)
switch(_key)
if("Shift")
if(!user.prefs.sprint_spacebar && !user.prefs.sprint_toggle)
sprint_hotkey(FALSE)
return
if("Space")
if(user.prefs.sprint_spacebar && !user.prefs.sprint_toggle)
sprint_hotkey(FALSE)
return
return ..()
@@ -1,26 +0,0 @@
/mob/living/key_down(_key, client/user)
switch(_key)
if("B")
resist()
return
if("1")
if(possible_a_intents)
a_intent_change(INTENT_HELP)
return
if("2")
if(possible_a_intents)
a_intent_change(INTENT_DISARM)
return
if("3")
if(possible_a_intents)
a_intent_change(INTENT_GRAB)
return
if("4")
if(possible_a_intents)
a_intent_change(INTENT_HARM)
return
if ("V")
lay_down()
return
return ..()
-94
View File
@@ -1,94 +0,0 @@
// Technically the client argument is unncessary here since that SHOULD be src.client but let's not assume things
// All it takes is one badmin setting their focus to someone else's client to mess things up
// Or we can have NPC's send actual keypresses and detect that by seeing no client
/mob/key_down(_key, client/user)
switch(_key)
if("Delete", "H")
if(!pulling)
to_chat(src, "<span class='notice'>You are not pulling anything.</span>")
else
stop_pulling()
return
if("Insert", "G")
a_intent_change(INTENT_HOTKEY_RIGHT)
return
if("F")
a_intent_change(INTENT_HOTKEY_LEFT)
return
if("X", "Northeast") // Northeast is Page-up
swap_hand()
return
if("Y", "Z", "Southeast") // Southeast is Page-down
mode() // attack_self(). No idea who came up with "mode()"
return
if("Q", "Northwest") // Northwest is Home
var/obj/item/I = get_active_held_item()
if(!I)
to_chat(src, "<span class='warning'>You have nothing to drop in your hand!</span>")
else
dropItemToGround(I)
return
if("E")
quick_equip()
return
if("Alt")
toggle_move_intent()
return
//Bodypart selections
if("Numpad8")
user.body_toggle_head()
return
if("Numpad4")
user.body_r_arm()
return
if("Numpad5")
user.body_chest()
return
if("Numpad6")
user.body_l_arm()
return
if("Numpad1")
user.body_r_leg()
return
if("Numpad2")
user.body_groin()
return
if("Numpad3")
user.body_l_leg()
return
if(client.keys_held["Ctrl"])
switch(SSinput.movement_keys[_key])
if(NORTH)
if(client.keys_held["Shift"])
northshift()
else
northface()
return
if(SOUTH)
if(client.keys_held["Shift"])
southshift()
else
southface()
return
if(WEST)
if(client.keys_held["Shift"])
westshift()
else
westface()
return
if(EAST)
if(client.keys_held["Shift"])
eastshift()
else
eastface()
return
return ..()
/mob/key_up(_key, client/user)
switch(_key)
if("Alt")
toggle_move_intent()
return
return ..()
@@ -1,22 +0,0 @@
/mob/living/silicon/robot/key_down(_key, client/user)
switch(_key)
if("1", "2", "3")
toggle_module(text2num(_key))
return
if("4")
a_intent_change(INTENT_HOTKEY_LEFT)
return
if("Q")
uneq_active()
return
if("Shift")
sprint_hotkey(TRUE)
return
return ..()
/mob/living/silicon/robot/key_up(_key, client/user)
switch(_key)
if("Shift")
sprint_hotkey(FALSE)
return
return ..()
-3
View File
@@ -1,6 +1,3 @@
/mob
var/datum/focus //What receives our keyboard inputs. src by default
/mob/proc/set_focus(datum/new_focus)
if(focus == new_focus)
return
@@ -0,0 +1,20 @@
#define CATEGORY_CLIENT "CLIENT"
#define CATEGORY_EMOTE "EMOTE"
#define CATEGORY_ADMIN "ADMIN"
#define CATEGORY_XENO "XENO"
#define CATEGORY_CARBON "CARBON"
#define CATEGORY_HUMAN "HUMAN"
#define CATEGORY_ROBOT "ROBOT"
#define CATEGORY_MISC "MISC"
#define CATEGORY_MOVEMENT "MOVEMENT"
#define CATEGORY_TARGETING "TARGETING"
#define WEIGHT_HIGHEST 0
#define WEIGHT_ADMIN 10
#define WEIGHT_CLIENT 20
#define WEIGHT_ROBOT 30
#define WEIGHT_MOB 40
#define WEIGHT_LIVING 50
#define WEIGHT_DEAD 60
#define WEIGHT_EMOTE 70
#define WEIGHT_LOWEST 999
@@ -0,0 +1,24 @@
/datum/keybinding
var/list/hotkey_keys
var/list/classic_keys
var/name
var/full_name
var/description = ""
var/category = CATEGORY_MISC
var/weight = WEIGHT_LOWEST
var/keybind_signal
/datum/keybinding/New()
// Default keys to the master "hotkey_keys"
if(LAZYLEN(hotkey_keys) && !LAZYLEN(classic_keys))
classic_keys = hotkey_keys.Copy()
/datum/keybinding/proc/down(client/user)
return FALSE
/datum/keybinding/proc/up(client/user)
return FALSE
/datum/keybinding/proc/can_use(client/user)
return TRUE
+96
View File
@@ -0,0 +1,96 @@
/datum/keybinding/admin
category = CATEGORY_ADMIN
weight = WEIGHT_ADMIN
/datum/keybinding/admin/can_use(client/user)
return user.holder ? TRUE : FALSE
/datum/keybinding/admin/admin_say
hotkey_keys = list("F3")
name = "admin_say"
full_name = "Admin say"
description = "Talk with other admins."
/datum/keybinding/admin/admin_say/down(client/user)
user.get_admin_say()
return TRUE
/datum/keybinding/admin/admin_ghost
hotkey_keys = list("F5")
name = "admin_ghost"
full_name = "Aghost"
description = "Go ghost"
/datum/keybinding/admin/admin_ghost/down(client/user)
user.admin_ghost()
return TRUE
/datum/keybinding/admin/player_panel_new
hotkey_keys = list("F6")
name = "player_panel_new"
full_name = "Player Panel New"
description = "Opens up the new player panel"
/datum/keybinding/admin/player_panel_new/down(client/user)
user.holder.player_panel_new()
return TRUE
/datum/keybinding/admin/toggle_buildmode_self
hotkey_keys = list("F7")
name = "toggle_buildmode_self"
full_name = "Toggle Buildmode Self"
description = "Toggles buildmode"
/datum/keybinding/admin/toggle_buildmode_self/down(client/user)
user.togglebuildmodeself()
return TRUE
/datum/keybinding/admin/stealthmode
hotkey_keys = list("CtrlF8")
name = "stealth_mode"
full_name = "Stealth mode"
description = "Enters stealth mode"
/datum/keybinding/admin/stealthmode/down(client/user)
user.stealth()
return TRUE
/datum/keybinding/admin/invisimin
hotkey_keys = list("F8")
name = "invisimin"
full_name = "Admin invisibility"
description = "Toggles ghost-like invisibility (Don't abuse this)"
/datum/keybinding/admin/invisimin/down(client/user)
user.invisimin()
return TRUE
/datum/keybinding/admin/deadsay
hotkey_keys = list("F10")
name = "dsay"
full_name = "deadsay"
description = "Allows you to send a message to dead chat"
/datum/keybinding/admin/deadsay/down(client/user)
user.get_dead_say()
return TRUE
/datum/keybinding/admin/deadmin
hotkey_keys = list("Unbound")
name = "deadmin"
full_name = "Deadmin"
description = "Shed your admin powers"
/datum/keybinding/admin/deadmin/down(client/user)
user.deadmin()
return TRUE
/datum/keybinding/admin/readmin
hotkey_keys = list("Unbound")
name = "readmin"
full_name = "Readmin"
description = "Regain your admin powers"
/datum/keybinding/admin/readmin/down(client/user)
user.readmin()
return TRUE
@@ -0,0 +1,62 @@
/datum/keybinding/carbon
category = CATEGORY_CARBON
weight = WEIGHT_MOB
/datum/keybinding/carbon/can_use(client/user)
return iscarbon(user.mob)
/datum/keybinding/carbon/toggle_throw_mode
hotkey_keys = list("R", "Southwest") // END
name = "toggle_throw_mode"
full_name = "Toggle throw mode"
description = "Toggle throwing the current item or not."
category = CATEGORY_CARBON
/datum/keybinding/carbon/toggle_throw_mode/down(client/user)
var/mob/living/carbon/C = user.mob
C.toggle_throw_mode()
return TRUE
/datum/keybinding/carbon/select_help_intent
hotkey_keys = list("1")
name = "select_help_intent"
full_name = "Select help intent"
description = ""
category = CATEGORY_CARBON
/datum/keybinding/carbon/select_help_intent/down(client/user)
user.mob?.a_intent_change(INTENT_HELP)
return TRUE
/datum/keybinding/carbon/select_disarm_intent
hotkey_keys = list("2")
name = "select_disarm_intent"
full_name = "Select disarm intent"
description = ""
category = CATEGORY_CARBON
/datum/keybinding/carbon/select_disarm_intent/down(client/user)
user.mob?.a_intent_change(INTENT_DISARM)
return TRUE
/datum/keybinding/carbon/select_grab_intent
hotkey_keys = list("3")
name = "select_grab_intent"
full_name = "Select grab intent"
description = ""
category = CATEGORY_CARBON
/datum/keybinding/carbon/select_grab_intent/down(client/user)
user.mob?.a_intent_change(INTENT_GRAB)
return TRUE
/datum/keybinding/carbon/select_harm_intent
hotkey_keys = list("4")
name = "select_harm_intent"
full_name = "Select harm intent"
description = ""
category = CATEGORY_CARBON
/datum/keybinding/carbon/select_harm_intent/down(client/user)
user.mob?.a_intent_change(INTENT_HARM)
return TRUE
@@ -0,0 +1,33 @@
/datum/keybinding/client
category = CATEGORY_CLIENT
weight = WEIGHT_HIGHEST
/datum/keybinding/client/admin_help
hotkey_keys = list("F1")
name = "admin_help"
full_name = "Admin Help"
description = "Ask an admin for help."
/datum/keybinding/client/admin_help/down(client/user)
user.get_adminhelp()
return TRUE
/datum/keybinding/client/screenshot
hotkey_keys = list("F2")
name = "screenshot"
full_name = "Screenshot"
description = "Take a screenshot."
/datum/keybinding/client/screenshot/down(client/user)
winset(user, null, "command=.screenshot [!user.keys_held["shift"] ? "auto" : ""]")
return TRUE
/datum/keybinding/client/minimal_hud
hotkey_keys = list("F12")
name = "minimal_hud"
full_name = "Minimal HUD"
description = "Hide most HUD features"
/datum/keybinding/client/minimal_hud/down(client/user)
user.mob.button_pressed_F12()
return TRUE
+15
View File
@@ -0,0 +1,15 @@
/datum/keybinding/emote
category = CATEGORY_EMOTE
weight = WEIGHT_EMOTE
var/emote_key
/datum/keybinding/emote/proc/link_to_emote(datum/emote/faketype)
hotkey_keys = list("Unbound")
emote_key = initial(faketype.key)
name = initial(faketype.key)
full_name = capitalize(initial(faketype.key))
description = "Do the emote '*[emote_key]'"
/datum/keybinding/emote/down(client/user)
. = ..()
return user.mob.emote(emote_key, intentional=TRUE)
+39
View File
@@ -0,0 +1,39 @@
/datum/keybinding/human
category = CATEGORY_HUMAN
weight = WEIGHT_MOB
/datum/keybinding/human/can_use(client/user)
return ishuman(user.mob)
/datum/keybinding/human/quick_equip
hotkey_keys = list("E")
name = "quick_equip"
full_name = "Quick Equip"
description = "Quickly puts an item in the best slot available"
/datum/keybinding/human/quick_equip/down(client/user)
var/mob/living/carbon/human/H = user.mob
H.quick_equip()
return TRUE
/datum/keybinding/human/quick_equipbelt
hotkey_keys = list("ShiftE")
name = "quick_equipbelt"
full_name = "Quick equip belt"
description = "Put held thing in belt or take out most recent thing from belt"
/datum/keybinding/human/quick_equipbelt/down(client/user)
var/mob/living/carbon/human/H = user.mob
H.smart_equipbelt()
return TRUE
/datum/keybinding/human/bag_equip
hotkey_keys = list("ShiftB")
name = "bag_equip"
full_name = "Bag equip"
description = "Put held thing in backpack or take out most recent thing from backpack"
/datum/keybinding/human/bag_equip/down(client/user)
var/mob/living/carbon/human/H = user.mob
H.smart_equipbag()
return TRUE
@@ -0,0 +1,41 @@
/datum/keybinding/living
category = CATEGORY_HUMAN
weight = WEIGHT_MOB
/datum/keybinding/living/can_use(client/user)
return isliving(user.mob)
/datum/keybinding/living/resist
hotkey_keys = list("B")
name = "resist"
full_name = "Resist"
description = "Break free of your current state. Handcuffed? on fire? Resist!"
/datum/keybinding/living/resist/down(client/user)
var/mob/living/L = user.mob
L.resist()
return TRUE
/datum/keybinding/living/toggle_combat_mode
hotkey_keys = list("C")
name = "toggle_combat_mode"
full_name = "Toggle combat mode"
description = "Toggles whether or not you're in combat mode."
/datum/keybinding/living/toggle_combat_mode/can_use(client/user)
return iscarbon(user.mob) // for now, only carbons should be using combat mode, although all livings have combat mode implemented.
/datum/keybinding/living/toggle_combat_mode/down(client/user)
var/mob/living/carbon/C = user.mob
C.user_toggle_intentional_combat_mode()
return TRUE
/datum/keybinding/living/toggle_resting
hotkey_keys = list("V")
name = "toggle_resting"
full_name = "Toggle Resting"
description = "Toggles whether or not you are intentionally laying down."
/datum/keybinding/living/toggle_resting/down(client/user)
var/mob/living/L = user.mob
L.lay_down()
+123
View File
@@ -0,0 +1,123 @@
/datum/keybinding/mob
category = CATEGORY_HUMAN
weight = WEIGHT_MOB
/datum/keybinding/mob/stop_pulling
hotkey_keys = list("H", "Delete")
name = "stop_pulling"
full_name = "Stop pulling"
description = ""
/datum/keybinding/mob/stop_pulling/down(client/user)
var/mob/M = user.mob
if(!M.pulling)
to_chat(user, "<span class='notice'>You are not pulling anything.</span>")
else
M.stop_pulling()
return TRUE
/datum/keybinding/mob/cycle_intent_right
hotkey_keys = list("Northwest", "F") // HOME
name = "cycle_intent_right"
full_name = "Cycle Action Intent Right"
description = ""
/datum/keybinding/mob/cycle_intent_right/down(client/user)
var/mob/M = user.mob
M.a_intent_change(INTENT_HOTKEY_RIGHT)
return TRUE
/datum/keybinding/mob/cycle_intent_left
hotkey_keys = list("Insert", "G")
name = "cycle_intent_left"
full_name = "Cycle Action Intent Left"
description = ""
/datum/keybinding/mob/cycle_intent_left/down(client/user)
var/mob/M = user.mob
M.a_intent_change(INTENT_HOTKEY_LEFT)
return TRUE
/datum/keybinding/mob/swap_hands
hotkey_keys = list("X", "Northeast") // PAGEUP
name = "swap_hands"
full_name = "Swap hands"
description = ""
/datum/keybinding/mob/swap_hands/down(client/user)
var/mob/M = user.mob
M.swap_hand()
return TRUE
/datum/keybinding/mob/activate_inhand
hotkey_keys = list("Z", "Southeast") // PAGEDOWN
name = "activate_inhand"
full_name = "Activate in-hand"
description = "Uses whatever item you have inhand"
/datum/keybinding/mob/activate_inhand/down(client/user)
var/mob/M = user.mob
M.mode()
return TRUE
/datum/keybinding/mob/drop_item
hotkey_keys = list("Q")
name = "drop_item"
full_name = "Drop Item"
description = ""
/datum/keybinding/mob/drop_item/down(client/user)
if(iscyborg(user.mob)) //cyborgs can't drop items
return FALSE
var/mob/M = user.mob
var/obj/item/I = M.get_active_held_item()
if(!I)
to_chat(user, "<span class='warning'>You have nothing to drop in your hand!</span>")
else
user.mob.dropItemToGround(I)
return TRUE
/datum/keybinding/mob/say_with_indicator
hotkey_keys = list("CtrlT")
classic_keys = list()
name = "say_with_indicator"
full_name = "Say with Typing Indicator"
/datum/keybinding/mob/say_with_indicator/down(client/user)
var/mob/M = user.mob
M.say_typing_indicator()
return TRUE
/datum/keybinding/mob/me_with_indicator
hotkey_keys = list("CtrlM")
classic_keys = list()
name = "me_with_indicator"
full_name = "Me (emote) with Typing Indicator"
/datum/keybinding/mob/me_with_indicator/down(client/user)
var/mob/M = user.mob
M.me_typing_indicator()
return TRUE
/datum/keybinding/living/subtle
hotkey_keys = list("5")
classic_keys = list()
name = "subtle_emote"
full_name = "Subtle Emote"
/datum/keybinding/living/subtle/down(client/user)
var/mob/living/L = user.mob
L.subtle_keybind()
return TRUE
/datum/keybinding/mob/whisper
hotkey_keys = list("Y")
classic_keys = list()
name = "whisper"
full_name = "Whisper"
/datum/keybinding/mob/whisper/down(client/user)
var/mob/M = user.mob
M.whisper_keybind()
return TRUE
@@ -0,0 +1,187 @@
/datum/keybinding/movement
category = CATEGORY_MOVEMENT
weight = WEIGHT_HIGHEST
/datum/keybinding/movement/north
hotkey_keys = list("W", "North")
name = "North"
full_name = "Move North"
description = "Moves your character north"
/datum/keybinding/movement/south
hotkey_keys = list("S", "South")
name = "South"
full_name = "Move South"
description = "Moves your character south"
/datum/keybinding/movement/west
hotkey_keys = list("A", "West")
name = "West"
full_name = "Move West"
description = "Moves your character left"
/datum/keybinding/movement/east
hotkey_keys = list("D", "East")
name = "East"
full_name = "Move East"
description = "Moves your character east"
/datum/keybinding/mob/face_north
hotkey_keys = list("CtrlW", "CtrlNorth")
name = "face_north"
full_name = "Face North"
description = ""
category = CATEGORY_MOVEMENT
/datum/keybinding/mob/face_north/down(client/user)
var/mob/M = user.mob
M.northface()
return TRUE
/datum/keybinding/mob/face_east
hotkey_keys = list("CtrlD", "CtrlEast")
name = "face_east"
full_name = "Face East"
description = ""
category = CATEGORY_MOVEMENT
/datum/keybinding/mob/face_east/down(client/user)
var/mob/M = user.mob
M.eastface()
return TRUE
/datum/keybinding/mob/face_south
hotkey_keys = list("CtrlS", "CtrlSouth")
name = "face_south"
full_name = "Face South"
description = ""
category = CATEGORY_MOVEMENT
/datum/keybinding/mob/face_south/down(client/user)
var/mob/M = user.mob
M.southface()
return TRUE
/datum/keybinding/mob/face_west
hotkey_keys = list("CtrlA", "CtrlWest")
name = "face_west"
full_name = "Face West"
description = ""
category = CATEGORY_MOVEMENT
/datum/keybinding/mob/face_west/down(client/user)
var/mob/M = user.mob
M.westface()
return TRUE
/datum/keybinding/mob/shift_north
hotkey_keys = list("CtrlShiftW", "CtrlShiftNorth")
name = "pixel_shift_north"
full_name = "Pixel Shift North"
description = ""
category = CATEGORY_MOVEMENT
/datum/keybinding/mob/shift_north/down(client/user)
var/mob/M = user.mob
M.northshift()
return TRUE
/datum/keybinding/mob/shift_east
hotkey_keys = list("CtrlShiftD", "CtrlShiftEast")
name = "pixel_shift_east"
full_name = "Pixel Shift East"
description = ""
category = CATEGORY_MOVEMENT
/datum/keybinding/mob/shift_east/down(client/user)
var/mob/M = user.mob
M.eastshift()
return TRUE
/datum/keybinding/mob/shift_south
hotkey_keys = list("CtrlShiftS", "CtrlShiftSouth")
name = "pixel_shift_south"
full_name = "Pixel Shift South"
description = ""
category = CATEGORY_MOVEMENT
/datum/keybinding/mob/shift_south/down(client/user)
var/mob/M = user.mob
M.southshift()
return TRUE
/datum/keybinding/mob/shift_west
hotkey_keys = list("CtrlShiftA", "CtrlShiftWest")
name = "pixel_shift_west"
full_name = "Pixel Shift West"
description = ""
category = CATEGORY_MOVEMENT
/datum/keybinding/mob/shift_west/down(client/user)
var/mob/M = user.mob
M.westshift()
return TRUE
/datum/keybinding/living/hold_sprint
hotkey_keys = list("Shift")
name = "hold_sprint"
full_name = "Sprint (hold down)"
description = "Hold down to sprint"
category = CATEGORY_MOVEMENT
/datum/keybinding/living/hold_sprint/can_use(client/user)
return ishuman(user.mob) || iscyborg(user.mob)
/datum/keybinding/living/hold_sprint/down(client/user)
var/mob/living/L = user.mob
L.sprint_hotkey(TRUE)
return TRUE
/datum/keybinding/living/hold_sprint/up(client/user)
var/mob/living/L = user.mob
L.sprint_hotkey(FALSE)
return TRUE
/datum/keybinding/living/toggle_sprint
hotkey_keys = list()
name = "toggle_sprint"
full_name = "Sprint (toggle)"
description = "Press to toggle sprint"
category = CATEGORY_MOVEMENT
/datum/keybinding/living/toggle_sprint/can_use(client/user)
return ishuman(user.mob) || iscyborg(user.mob)
/datum/keybinding/living/toggle_sprint/down(client/user)
var/mob/living/L = user.mob
L.default_toggle_sprint(TRUE)
return TRUE
/datum/keybinding/mob/toggle_move_intent
hotkey_keys = list("Alt")
name = "toggle_move_intent"
full_name = "Hold to toggle move intent"
description = "Held down to cycle to the other move intent, release to cycle back"
category = CATEGORY_MOVEMENT
/datum/keybinding/mob/toggle_move_intent/down(client/user)
var/mob/M = user.mob
M.toggle_move_intent()
return TRUE
/datum/keybinding/mob/toggle_move_intent/up(client/user)
var/mob/M = user.mob
M.toggle_move_intent()
return TRUE
/datum/keybinding/mob/toggle_move_intent_alternative
hotkey_keys = list("Unbound")
name = "toggle_move_intent_alt"
full_name = "press to cycle move intent"
description = "Pressing this cycle to the opposite move intent, does not cycle back"
category = CATEGORY_MOVEMENT
/datum/keybinding/mob/toggle_move_intent_alternative/down(client/user)
var/mob/M = user.mob
M.toggle_move_intent()
return TRUE
+61
View File
@@ -0,0 +1,61 @@
/datum/keybinding/robot
category = CATEGORY_ROBOT
weight = WEIGHT_ROBOT
/datum/keybinding/robot/can_use(client/user)
return iscyborg(user.mob)
/datum/keybinding/robot/moduleone
hotkey_keys = list("1")
name = "module_one"
full_name = "Toggle module 1"
description = "Equips or unequips the first module"
/datum/keybinding/robot/moduleone/down(client/user)
var/mob/living/silicon/robot/R = user.mob
R.toggle_module(1)
return TRUE
/datum/keybinding/robot/moduletwo
hotkey_keys = list("2")
name = "module_two"
full_name = "Toggle module 2"
description = "Equips or unequips the second module"
/datum/keybinding/robot/moduletwo/down(client/user)
var/mob/living/silicon/robot/R = user.mob
R.toggle_module(2)
return TRUE
/datum/keybinding/robot/modulethree
hotkey_keys = list("3")
name = "module_three"
full_name = "Toggle module 3"
description = "Equips or unequips the third module"
/datum/keybinding/robot/modulethree/down(client/user)
var/mob/living/silicon/robot/R = user.mob
R.toggle_module(3)
return TRUE
/datum/keybinding/robot/intent_cycle
hotkey_keys = list("4")
name = "cycle_intent"
full_name = "Cycle intent left"
description = "Cycles the intent left"
/datum/keybinding/robot/intent_cycle/down(client/user)
var/mob/living/silicon/robot/R = user.mob
R.a_intent_change(INTENT_HOTKEY_LEFT)
return TRUE
/datum/keybinding/robot/unequip_module
hotkey_keys = list("Q")
name = "unequip_module"
full_name = "Unequip module"
description = "Unequips the active module"
/datum/keybinding/robot/unequip_module/down(client/user)
var/mob/living/silicon/robot/R = user.mob
R.uneq_active()
return TRUE
@@ -0,0 +1,76 @@
/datum/keybinding/mob/target_head_cycle
hotkey_keys = list("Numpad8")
name = "target_head_cycle"
full_name = "Target: Cycle head"
description = ""
category = CATEGORY_TARGETING
/datum/keybinding/mob/target_head_cycle/down(client/user)
user.body_toggle_head()
return TRUE
/datum/keybinding/mob/target_r_arm
hotkey_keys = list("Numpad4")
name = "target_r_arm"
full_name = "Target: right arm"
description = ""
category = CATEGORY_TARGETING
/datum/keybinding/mob/target_r_arm/down(client/user)
user.body_r_arm()
return TRUE
/datum/keybinding/mob/target_body_chest
hotkey_keys = list("Numpad5")
name = "target_body_chest"
full_name = "Target: Body"
description = ""
category = CATEGORY_TARGETING
/datum/keybinding/mob/target_body_chest/down(client/user)
user.body_chest()
return TRUE
/datum/keybinding/mob/target_left_arm
hotkey_keys = list("Numpad6")
name = "target_left_arm"
full_name = "Target: left arm"
description = ""
category = CATEGORY_TARGETING
/datum/keybinding/mob/target_left_arm/down(client/user)
user.body_l_arm()
return TRUE
/datum/keybinding/mob/target_right_leg
hotkey_keys = list("Numpad1")
name = "target_right_leg"
full_name = "Target: Right leg"
description = ""
category = CATEGORY_TARGETING
/datum/keybinding/mob/target_right_leg/down(client/user)
user.body_r_leg()
return TRUE
/datum/keybinding/mob/target_body_groin
hotkey_keys = list("Numpad2")
name = "target_body_groin"
full_name = "Target: Groin"
description = ""
category = CATEGORY_TARGETING
/datum/keybinding/mob/target_body_groin/down(client/user)
user.body_groin()
return TRUE
/datum/keybinding/mob/target_left_leg
hotkey_keys = list("Numpad3")
name = "target_left_leg"
full_name = "Target: left leg"
description = ""
category = CATEGORY_TARGETING
/datum/keybinding/mob/target_left_leg/down(client/user)
user.body_l_leg()
return TRUE
+26 -34
View File
@@ -1,55 +1,47 @@
/client
/// Keys currently held
var/list/keys_held = list()
/// These next two vars are to apply movement for keypresses and releases made while move delayed.
/// Because discarding that input makes the game less responsive.
/// On next move, add this dir to the move that would otherwise be done
var/next_move_dir_add
/// On next move, subtract this dir from the move that would otherwise be done
var/next_move_dir_sub
// Set a client's focus to an object and override these procs on that object to let it handle keypresses
/datum/proc/key_down(key, client/user) // Called when a key is pressed down initially
return
/datum/proc/key_up(key, client/user) // Called when a key is released
return
/datum/proc/keyLoop(client/user) // Called once every frame
set waitfor = FALSE
return
// removes all the existing macros
/client/proc/erase_all_macros()
var/list/macro_sets = params2list(winget(src, null, "macros"))
var/erase_output = ""
for(var/i in 1 to macro_sets.len)
var/setname = macro_sets[i]
var/list/macro_set = params2list(winget(src, "[setname].*", "command")) // The third arg doesnt matter here as we're just removing them all
for(var/k in 1 to macro_set.len)
var/list/split_name = splittext(macro_set[k], ".")
var/macro_name = "[split_name[1]].[split_name[2]]" // [3] is "command"
erase_output = "[erase_output];[macro_name].parent=null"
var/list/macro_set = params2list(winget(src, "default.*", "command")) // The third arg doesnt matter here as we're just removing them all
for(var/k in 1 to length(macro_set))
var/list/split_name = splittext(macro_set[k], ".")
var/macro_name = "[split_name[1]].[split_name[2]]" // [3] is "command"
erase_output = "[erase_output];[macro_name].parent=null"
winset(src, null, erase_output)
/client/proc/set_macros()
/client/proc/apply_macro_set(name, list/macroset)
ASSERT(name)
ASSERT(islist(macroset))
winclone(src, "default", name)
for(var/i in 1 to length(macroset))
var/key = macroset[i]
var/command = macroset[key]
winset(src, "[name]-[REF(key)]", "parent=[name];name=[key];command=[command]")
/client/proc/set_macros(datum/preferences/prefs_override = prefs)
set waitfor = FALSE
keys_held.Cut()
erase_all_macros()
var/list/macro_sets = SSinput.macro_sets
for(var/i in 1 to macro_sets.len)
var/setname = macro_sets[i]
if(setname != "default")
winclone(src, "default", setname)
var/list/macro_set = macro_sets[setname]
for(var/k in 1 to macro_set.len)
var/key = macro_set[k]
var/command = macro_set[key]
winset(src, "[setname]-[REF(key)]", "parent=[setname];name=[key];command=[command]")
apply_macro_set(SKIN_MACROSET_HOTKEYS, SSinput.macroset_hotkey)
apply_macro_set(SKIN_MACROSET_CLASSIC_HOTKEYS, SSinput.macroset_classic_hotkey)
apply_macro_set(SKIN_MACROSET_CLASSIC_INPUT, SSinput.macroset_classic_input)
if(prefs.hotkeys)
winset(src, null, "input.focus=true input.background-color=[COLOR_INPUT_ENABLED] mainwindow.macro=default")
set_hotkeys_preference()
/client/proc/set_hotkeys_preference(datum/preferences/prefs_override = prefs)
if(prefs_override.hotkeys)
winset(src, null, "map.focus=true input.background-color=[COLOR_INPUT_DISABLED] mainwindow.macro=[SKIN_MACROSET_HOTKEYS]")
else
winset(src, null, "input.focus=true input.background-color=[COLOR_INPUT_ENABLED] mainwindow.macro=old_default")
winset(src, null, "input.focus=true input.background-color=[COLOR_INPUT_ENABLED] mainwindow.macro=[SKIN_MACROSET_CLASSIC_INPUT]")
+34 -51
View File
@@ -2,11 +2,11 @@
// And corners get shared between multiple turfs (unless you're on the corners of the map, then 1 corner doesn't).
// For the record: these should never ever ever be deleted, even if the turf doesn't have dynamic lighting.
// This list is what the code that assigns corners listens to, the order in this list is the order in which corners are added to the /turf/corners list.
GLOBAL_LIST_INIT(LIGHTING_CORNER_DIAGONAL, list(NORTHEAST, SOUTHEAST, SOUTHWEST, NORTHWEST))
/datum/lighting_corner
var/list/turf/masters
var/turf/northeast
var/turf/northwest
var/turf/southeast
var/turf/southwest
var/list/datum/light_source/affecting // Light sources affecting us.
var/active = FALSE // TRUE if one of our masters has dynamic lighting.
@@ -25,10 +25,18 @@ GLOBAL_LIST_INIT(LIGHTING_CORNER_DIAGONAL, list(NORTHEAST, SOUTHEAST, SOUTHWEST,
var/cache_b = LIGHTING_SOFT_THRESHOLD
var/cache_mx = 0
/datum/lighting_corner/New(var/turf/new_turf, var/diagonal)
// Diagonal is our direction FROM them, not to.
/datum/lighting_corner/New(turf/new_turf, diagonal)
. = ..()
masters = list()
masters[new_turf] = turn(diagonal, 180)
#define SET_DIAGONAL(turf, diagonal) \
switch(diagonal){ \
if(SOUTHWEST) { northeast = turf; turf.lc_bottomleft = src; } \
if(SOUTHEAST) { northwest = turf; turf.lc_bottomright = src; } \
if(NORTHEAST) { southwest = turf; turf.lc_topright = src; } \
if(NORTHWEST) { southeast = turf; turf.lc_topleft = src; } \
}
SET_DIAGONAL(new_turf, diagonal)
z = new_turf.z
var/vertical = diagonal & ~(diagonal - 1) // The horizontal directions (4 and 8) are bigger than the vertical ones (1 and 2), so we can reliably say the lsb is the horizontal direction.
@@ -37,52 +45,28 @@ GLOBAL_LIST_INIT(LIGHTING_CORNER_DIAGONAL, list(NORTHEAST, SOUTHEAST, SOUTHWEST,
x = new_turf.x + (horizontal == EAST ? 0.5 : -0.5)
y = new_turf.y + (vertical == NORTH ? 0.5 : -0.5)
// My initial plan was to make this loop through a list of all the dirs (horizontal, vertical, diagonal).
// Issue being that the only way I could think of doing it was very messy, slow and honestly overengineered.
// So we'll have this hardcode instead.
var/turf/T
var/i
// Diagonal one is easy.
// Build diagonal one
T = get_step(new_turf, diagonal)
if (T) // In case we're on the map's border.
if (!T.corners)
T.corners = list(null, null, null, null)
masters[T] = diagonal
i = GLOB.LIGHTING_CORNER_DIAGONAL.Find(turn(diagonal, 180))
T.corners[i] = src
// Now the horizontal one.
if(T)
SET_DIAGONAL(T, turn(diagonal, 180))
// Build horizontal
T = get_step(new_turf, horizontal)
if (T) // Ditto.
if (!T.corners)
T.corners = list(null, null, null, null)
masters[T] = ((T.x > x) ? EAST : WEST) | ((T.y > y) ? NORTH : SOUTH) // Get the dir based on coordinates.
i = GLOB.LIGHTING_CORNER_DIAGONAL.Find(turn(masters[T], 180))
T.corners[i] = src
// And finally the vertical one.
if(T)
SET_DIAGONAL(T, turn(((T.x > x) ? EAST : WEST) | ((T.y > y) ? NORTH : SOUTH), 180))
// Build vertical
T = get_step(new_turf, vertical)
if (T)
if (!T.corners)
T.corners = list(null, null, null, null)
masters[T] = ((T.x > x) ? EAST : WEST) | ((T.y > y) ? NORTH : SOUTH) // Get the dir based on coordinates.
i = GLOB.LIGHTING_CORNER_DIAGONAL.Find(turn(masters[T], 180))
T.corners[i] = src
if(T)
SET_DIAGONAL(T, turn(((T.x > x) ? EAST : WEST) | ((T.y > y) ? NORTH : SOUTH), 180))
update_active()
#undef SET_DIAGONAL
/datum/lighting_corner/proc/update_active()
active = FALSE
var/turf/T
var/thing
for (thing in masters)
T = thing
if (T.lighting_object)
active = TRUE
if(northeast?.lighting_object || northwest?.lighting_object || southeast?.lighting_object || southwest?.lighting_object)
active = TRUE
// God that was a mess, now to do the rest of the corner code! Hooray!
/datum/lighting_corner/proc/update_lumcount(var/delta_r, var/delta_g, var/delta_b)
@@ -122,13 +106,12 @@ GLOBAL_LIST_INIT(LIGHTING_CORNER_DIAGONAL, list(NORTHEAST, SOUTHEAST, SOUTHWEST,
#endif
cache_mx = round(mx, LIGHTING_ROUND_VALUE)
for (var/TT in masters)
var/turf/T = TT
if (T.lighting_object)
if (!T.lighting_object.needs_update)
T.lighting_object.needs_update = TRUE
GLOB.lighting_update_objects += T.lighting_object
#define QUEUE(turf) if(turf?.lighting_object && !turf.lighting_object.needs_update) { turf.lighting_object.needs_update = TRUE; GLOB.lighting_update_objects += turf.lighting_object }
QUEUE(northeast)
QUEUE(northwest)
QUEUE(southeast)
QUEUE(southwest)
#undef QUEUE
/datum/lighting_corner/dummy/New()
return
+5 -11
View File
@@ -55,7 +55,7 @@
if (loc)
var/turf/oldturf = get_turf(myturf)
var/turf/newturf = get_turf(loc)
warning("A lighting object realised it's loc had changed in update() ([myturf]\[[myturf ? myturf.type : "null"]]([COORD(oldturf)]) -> [loc]\[[ loc ? loc.type : "null"]]([COORD(newturf)]))!")
stack_trace("A lighting object realised it's loc had changed in update() ([myturf]\[[myturf ? myturf.type : "null"]]([COORD(oldturf)]) -> [loc]\[[ loc ? loc.type : "null"]]([COORD(newturf)]))!")
qdel(src, TRUE)
return
@@ -71,16 +71,10 @@
// See LIGHTING_CORNER_DIAGONAL in lighting_corner.dm for why these values are what they are.
var/static/datum/lighting_corner/dummy/dummy_lighting_corner = new
var/list/corners = myturf.corners
var/datum/lighting_corner/cr = dummy_lighting_corner
var/datum/lighting_corner/cg = dummy_lighting_corner
var/datum/lighting_corner/cb = dummy_lighting_corner
var/datum/lighting_corner/ca = dummy_lighting_corner
if (corners) //done this way for speed
cr = corners[3] || dummy_lighting_corner
cg = corners[2] || dummy_lighting_corner
cb = corners[4] || dummy_lighting_corner
ca = corners[1] || dummy_lighting_corner
var/datum/lighting_corner/cr = myturf.lc_bottomleft || dummy_lighting_corner
var/datum/lighting_corner/cg = myturf.lc_bottomright || dummy_lighting_corner
var/datum/lighting_corner/cb = myturf.lc_topleft || dummy_lighting_corner
var/datum/lighting_corner/ca = myturf.lc_topright || dummy_lighting_corner
var/max = max(cr.cache_mx, cg.cache_mx, cb.cache_mx, ca.cache_mx)
+11 -4
View File
@@ -237,18 +237,25 @@
return //nothing's changed
var/list/datum/lighting_corner/corners = list()
var/datum/lighting_corner/C
var/list/turf/turfs = list()
var/thing
var/datum/lighting_corner/C
var/turf/T
if (source_turf)
var/oldlum = source_turf.luminosity
source_turf.luminosity = CEILING(light_range, 1)
for(T in view(CEILING(light_range, 1), source_turf))
for (thing in T.get_corners(source_turf))
C = thing
corners[C] = 0
turfs += T
if(!IS_DYNAMIC_LIGHTING(T) && !T.light_sources)
continue
if(!T.lighting_corners_initialised)
T.generate_missing_corners()
if(T.has_opaque_atom)
continue
corners[T.lc_topright] = 0
corners[T.lc_bottomright] = 0
corners[T.lc_bottomleft] = 0
corners[T.lc_topleft] = 0
source_turf.luminosity = oldlum
LAZYINITLIST(affecting_turfs)
+37 -47
View File
@@ -6,9 +6,15 @@
var/tmp/list/datum/light_source/affecting_lights // List of light sources affecting this turf.
var/tmp/atom/movable/lighting_object/lighting_object // Our lighting object.
var/tmp/list/datum/lighting_corner/corners
var/tmp/datum/lighting_corner/lc_topleft
var/tmp/datum/lighting_corner/lc_topright
var/tmp/datum/lighting_corner/lc_bottomleft
var/tmp/datum/lighting_corner/lc_bottomright
var/tmp/has_opaque_atom = FALSE // Not to be confused with opacity, this will be TRUE if there's any opaque atom on the tile.
// counterclockwisse 0 to 360
#define PROC_ON_CORNERS(operation) lc_topright?.##operation;lc_bottomright?.##operation;lc_bottomleft?.##operation;lc_topleft?.##operation
// Causes any affecting light sources to be queued for a visibility update, for example a door got opened.
/turf/proc/reconsider_lights()
var/datum/light_source/L
@@ -21,13 +27,7 @@
if (lighting_object)
qdel(lighting_object, TRUE)
var/datum/lighting_corner/C
var/thing
for (thing in corners)
if(!thing)
continue
C = thing
C.update_active()
PROC_ON_CORNERS(update_active())
// Builds a lighting object for us, but only if our area is dynamic.
/turf/proc/lighting_build_overlay()
@@ -43,32 +43,31 @@
new/atom/movable/lighting_object(src)
var/thing
var/datum/lighting_corner/C
var/datum/light_source/S
for (thing in corners)
if(!thing)
continue
C = thing
if (!C.active) // We would activate the corner, calculate the lighting for it.
for (thing in C.affecting)
S = thing
S.recalc_corner(C)
C.active = TRUE
var/i
#define OPERATE(corner) \
if(corner && !corner.active) { \
for(i in corner.affecting) { \
S = i ; \
S.recalc_corner(corner) \
} \
corner.active = TRUE \
}
OPERATE(lc_topright)
OPERATE(lc_bottomright)
OPERATE(lc_bottomleft)
OPERATE(lc_topleft)
#undef OPERATE
// Used to get a scaled lumcount.
/turf/proc/get_lumcount(var/minlum = 0, var/maxlum = 1)
if (!lighting_object)
if(!lighting_object)
return 1
var/totallums = 0
var/thing
var/datum/lighting_corner/L
for (thing in corners)
if(!thing)
continue
L = thing
totallums += L.lum_r + L.lum_b + L.lum_g
var/totallums = (lc_topright? (lc_topright.lum_r + lc_topright.lum_g + lc_topright.lum_b) : 0) \
+ (lc_bottomright? (lc_bottomright.lum_r + lc_bottomright.lum_g + lc_bottomright.lum_b) : 0) \
+ (lc_bottomleft? (lc_bottomleft.lum_r + lc_bottomleft.lum_g + lc_bottomleft.lum_b) : 0) \
+ (lc_topleft? (lc_topleft.lum_r + lc_topleft.lum_g + lc_topleft.lum_b) : 0)
totallums /= 12 // 4 corners, each with 3 channels, get the average.
@@ -110,27 +109,18 @@
else
lighting_clear_overlay()
/turf/proc/get_corners()
if (!IS_DYNAMIC_LIGHTING(src) && !light_sources)
return null
if (!lighting_corners_initialised)
generate_missing_corners()
if (has_opaque_atom)
return null // Since this proc gets used in a for loop, null won't be looped though.
return corners
/turf/proc/generate_missing_corners()
if (!IS_DYNAMIC_LIGHTING(src) && !light_sources)
return
lighting_corners_initialised = TRUE
if (!corners)
corners = list(null, null, null, null)
for (var/i = 1 to 4)
if (corners[i]) // Already have a corner on this direction.
continue
corners[i] = new/datum/lighting_corner(src, GLOB.LIGHTING_CORNER_DIAGONAL[i])
// counterclockwise from 0 to 360.
if(!lc_topright)
new /datum/lighting_corner(src, NORTHEAST)
if(!lc_bottomright)
new /datum/lighting_corner(src, SOUTHEAST)
if(!lc_bottomleft)
new /datum/lighting_corner(src, SOUTHWEST)
if(!lc_topleft)
new /datum/lighting_corner(src, NORTHWEST)
#undef PROC_ON_CORNERS
@@ -16,7 +16,6 @@
resistance_flags = FIRE_PROOF
mutantrace_variation = STYLE_DIGITIGRADE|STYLE_SNEK_TAURIC|STYLE_PAW_TAURIC
/obj/item/clothing/head/hooded/explorer
name = "explorer hood"
desc = "An armoured hood for exploring harsh environments."
@@ -51,7 +50,7 @@
visor_flags_inv = HIDEFACIALHAIR
visor_flags_cover = MASKCOVERSMOUTH
actions_types = list(/datum/action/item_action/adjust)
armor = list("melee" = 10, "bullet" = 5, "laser" = 5, "energy" = 5, "bomb" = 0, "bio" = 50, "rad" = 0, "fire" = 20, "acid" = 40)
armor = list("melee" = 10, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 5, "bio" = 50, "rad" = 0, "fire" = 20, "acid" = 40)
resistance_flags = FIRE_PROOF
/obj/item/clothing/mask/gas/explorer/attack_self(mob/user)
@@ -140,7 +139,7 @@
max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT
heat_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
hoodtype = /obj/item/clothing/head/hooded/explorer/seva
armor = list("melee" = 15, "bullet" = 10, "laser" = 10, "energy" = 10, "bomb" = 25, "bio" = 50, "rad" = 25, "fire" = 100, "acid" = 25)
armor = list("melee" = 15, "bullet" = 10, "laser" = 10, "energy" = 10, "bomb" = 35, "bio" = 50, "rad" = 25, "fire" = 100, "acid" = 25)
resistance_flags = FIRE_PROOF | GOLIATH_WEAKNESS
/obj/item/clothing/head/hooded/explorer/seva
@@ -149,7 +148,7 @@
icon_state = "seva"
item_state = "seva"
max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT
armor = list("melee" = 10, "bullet" = 10, "laser" = 10, "energy" = 10, "bomb" = 25, "bio" = 50, "rad" = 25, "fire" = 100, "acid" = 25)
armor = list("melee" = 10, "bullet" = 10, "laser" = 10, "energy" = 10, "bomb" = 35, "bio" = 50, "rad" = 25, "fire" = 100, "acid" = 25)
resistance_flags = FIRE_PROOF | GOLIATH_WEAKNESS
/obj/item/clothing/mask/gas/seva
@@ -39,7 +39,7 @@
if(11)
new /obj/item/ship_in_a_bottle(src)
if(12)
new /obj/item/clothing/suit/space/hardsuit/ert/paranormal/beserker(src)
new /obj/item/clothing/suit/space/hardsuit/ert/paranormal/beserker/old(src)
if(13)
new /obj/item/jacobs_ladder(src)
if(14)
@@ -67,7 +67,7 @@
new /obj/item/grenade/clusterbuster/inferno(src)
if(24)
new /obj/item/reagent_containers/food/drinks/bottle/holywater/hell(src)
new /obj/item/clothing/suit/space/hardsuit/ert/paranormal/inquisitor(src)
new /obj/item/clothing/suit/space/hardsuit/ert/paranormal/inquisitor/old(src)
if(25)
new /obj/item/book/granter/spell/summonitem(src)
if(26)
+2 -1
View File
@@ -24,7 +24,8 @@
environment_smash = ENVIRONMENT_SMASH_NONE
check_friendly_fire = TRUE
stop_automated_movement_when_pulled = TRUE
attacktext = "drills"
attack_verb_continuous = "drills"
attack_verb_simple = "drill"
attack_sound = 'sound/weapons/circsawhit.ogg'
sentience_type = SENTIENCE_MINEBOT
speak_emote = list("states")
+18 -1
View File
@@ -102,7 +102,22 @@ GLOBAL_LIST_INIT(sand_recipes, list(\
/obj/item/stack/ore/glass/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
if(..() || !ishuman(hit_atom))
return
var/mob/living/carbon/human/C = hit_atom
var/mob/living/carbon/human/poorsod = hit_atom
eyesand(poorsod)
/obj/item/stack/ore/glass/attack(mob/living/M, mob/living/user)
if(!ishuman(M))
return ..()
if(user.zone_selected != BODY_ZONE_PRECISE_EYES && user.zone_selected != BODY_ZONE_HEAD)
return ..()
var/mob/living/carbon/human/poorsod = M
visible_message("<span class='danger'>[user] throws the sand at [poorsod]'s face!</span>")
if(ishuman(user))
var/mob/living/carbon/human/sayer = user
sayer.forcesay("POCKET SAAND!!")
eyesand(poorsod)
/obj/item/stack/ore/glass/proc/eyesand(mob/living/carbon/human/C)
if(C.head && C.head.flags_cover & HEADCOVERSEYES)
visible_message("<span class='danger'>[C]'s headgear blocks the sand!</span>")
return
@@ -116,8 +131,10 @@ GLOBAL_LIST_INIT(sand_recipes, list(\
C.adjustStaminaLoss(15)//the pain from your eyes burning does stamina damage
C.confused += 5
to_chat(C, "<span class='userdanger'>\The [src] gets into your eyes! The pain, it burns!</span>")
C.forcesay("*scream")
qdel(src)
/obj/item/stack/ore/glass/ex_act(severity, target)
if (severity == EXPLODE_NONE)
return
@@ -450,6 +450,18 @@
color_src = MATRIXED
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
/datum/sprite_accessory/tails/human/tamamo_kitsune
name = "Tamamo Kitsune Tails" //Tamamo-no-Tiro, let it be known!
icon_state = "9sune"
color_src = MATRIXED
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
/datum/sprite_accessory/tails_animated/human/tamamo_kitsune
name = "Tamamo Kitsune Tails"
icon_state = "9sune"
color_src = MATRIXED
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
/datum/sprite_accessory/tails/human/tentacle
name = "Tentacle"
icon_state = "tentacle"
@@ -816,6 +828,14 @@ datum/sprite_accessory/mam_tails/insect
name = "Squirrel"
icon_state = "squirrel"
/datum/sprite_accessory/mam_tails/tamamo_kitsune
name = "Tamamo Kitsune Tails"
icon_state = "9sune"
/datum/sprite_accessory/mam_tails_animated/tamamo_kitsune
name = "Tamamo Kitsune Tails"
icon_state = "9sune"
/datum/sprite_accessory/mam_tails/tentacle
name = "Tentacle"
icon_state = "tentacle"
+1 -1
View File
@@ -707,7 +707,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
//this is a mob verb instead of atom for performance reasons
//see /mob/verb/examinate() in mob.dm for more info
//overridden here and in /mob/living for different point span classes and sanity checks
/mob/dead/observer/pointed(atom/A as mob|obj|turf in visible_atoms())
/mob/dead/observer/pointed(atom/A as mob|obj|turf in fov_view())
if(!..())
return 0
usr.visible_message("<span class='deadsay'><b>[src]</b> points to [A].</span>")
+19 -26
View File
@@ -51,6 +51,12 @@
var/datum/brain_trauma/BT = X
BT.owner = owner
BT.on_gain()
if(damage > BRAIN_DAMAGE_MILD)
var/datum/skill_modifier/S
ADD_SKILL_MODIFIER_BODY(/datum/skill_modifier/brain_damage, null, C, S)
if(damage > BRAIN_DAMAGE_SEVERE)
var/datum/skill_modifier/S
ADD_SKILL_MODIFIER_BODY(/datum/skill_modifier/heavy_brain_damage, null, C, S)
//Update the body's icon so it doesnt appear debrained anymore
C.update_hair()
@@ -66,6 +72,8 @@
if((!QDELETED(src) || C) && !no_id_transfer)
transfer_identity(C)
if(C)
REMOVE_SKILL_MODIFIER_BODY(/datum/skill_modifier/brain_damage, null, C)
REMOVE_SKILL_MODIFIER_BODY(/datum/skill_modifier/heavy_brain_damage, null, C)
C.update_hair()
/obj/item/organ/brain/prepare_eat()
@@ -219,31 +227,6 @@
Insert(C)
else
..()
/* TO BE REMOVED, KEPT IN CASE OF BUGS
/obj/item/organ/brain/proc/get_brain_damage()
var/brain_damage_threshold = max_integrity * BRAIN_DAMAGE_INTEGRITY_MULTIPLIER
var/offset_integrity = obj_integrity - (max_integrity - brain_damage_threshold)
. = round((1 - (offset_integrity / brain_damage_threshold)) * BRAIN_DAMAGE_DEATH, DAMAGE_PRECISION)
/obj/item/organ/brain/proc/adjust_brain_damage(amount, maximum)
var/adjusted_amount
if(amount >= 0 && maximum)
var/brainloss = get_brain_damage()
var/new_brainloss = clamp(brainloss + amount, 0, maximum)
if(brainloss > new_brainloss) //brainloss is over the cap already
return 0
adjusted_amount = new_brainloss - brainloss
else
adjusted_amount = amount
adjusted_amount = round(adjusted_amount * BRAIN_DAMAGE_INTEGRITY_MULTIPLIER, DAMAGE_PRECISION)
if(adjusted_amount)
if(adjusted_amount >= DAMAGE_PRECISION)
take_damage(adjusted_amount)
else if(adjusted_amount <= -DAMAGE_PRECISION)
obj_integrity = min(max_integrity, obj_integrity-adjusted_amount)
. = adjusted_amount
*/
/obj/item/organ/brain/applyOrganDamage(var/d, var/maximum = maxHealth)
. = ..()
@@ -261,18 +244,28 @@
. = ..()
//if we're not more injured than before, return without gambling for a trauma
if(damage <= prev_damage)
if(damage < prev_damage && owner)
if(prev_damage > BRAIN_DAMAGE_MILD && damage <= BRAIN_DAMAGE_MILD)
REMOVE_SKILL_MODIFIER_BODY(/datum/skill_modifier/brain_damage, null, owner)
if(prev_damage > BRAIN_DAMAGE_SEVERE && damage <= BRAIN_DAMAGE_SEVERE)
REMOVE_SKILL_MODIFIER_BODY(/datum/skill_modifier/heavy_brain_damage, null, owner)
return
damage_delta = damage - prev_damage
if(damage > BRAIN_DAMAGE_MILD)
if(prob(damage_delta * (1 + max(0, (damage - BRAIN_DAMAGE_MILD)/100)))) //Base chance is the hit damage; for every point of damage past the threshold the chance is increased by 1% //learn how to do your bloody math properly goddamnit
gain_trauma_type(BRAIN_TRAUMA_MILD)
if(prev_damage <= BRAIN_DAMAGE_MILD && owner)
var/datum/skill_modifier/S
ADD_SKILL_MODIFIER_BODY(/datum/skill_modifier/brain_damage, null, owner, S)
if(damage > BRAIN_DAMAGE_SEVERE)
if(prob(damage_delta * (1 + max(0, (damage - BRAIN_DAMAGE_SEVERE)/100)))) //Base chance is the hit damage; for every point of damage past the threshold the chance is increased by 1%
if(prob(20))
gain_trauma_type(BRAIN_TRAUMA_SPECIAL)
else
gain_trauma_type(BRAIN_TRAUMA_SEVERE)
if(prev_damage <= BRAIN_DAMAGE_SEVERE && owner)
var/datum/skill_modifier/S
ADD_SKILL_MODIFIER_BODY(/datum/skill_modifier/heavy_brain_damage, null, owner, S)
if (owner)
if(owner.stat < UNCONSCIOUS) //conscious or soft-crit
var/brain_message
@@ -140,7 +140,8 @@ Des: Removes all infected images from the alien.
/mob/living/carbon/alien/proc/alien_evolve(mob/living/carbon/alien/new_xeno)
to_chat(src, "<span class='noticealien'>You begin to evolve!</span>")
visible_message("<span class='alertalien'>[src] begins to twist and contort!</span>")
visible_message("<span class='alertalien'>[src] begins to twist and contort!</span>",
"<span class='alertalien'>You begin to twist and contort!</span>")
new_xeno.setDir(dir)
if(!alien_name_regex.Find(name))
new_xeno.name = name
@@ -27,13 +27,16 @@ In all, this is a lot like the monkey code. /N
AdjustUnconscious(-60, FALSE)
AdjustSleeping(-100, FALSE)
update_mobility()
visible_message("<span class='notice'>[M.name] nuzzles [src] trying to wake [p_them()] up!</span>")
visible_message("<span class='notice'>[M.name] nuzzles [src] trying to wake [p_them()] up!</span>",
"<span class='notice'>[M.name] nuzzles you trying to wake you up!</span>", target = M,
target_message = "<span class='notice'>You nuzzle [src] trying to wake [p_them()] up!</span>")
if(INTENT_DISARM, INTENT_HARM)
if(health > 0)
M.do_attack_animation(src, ATTACK_EFFECT_BITE)
playsound(loc, 'sound/weapons/bite.ogg', 50, 1, -1)
visible_message("<span class='danger'>[M.name] bites [src]!</span>", \
"<span class='userdanger'>[M.name] bites [src]!</span>", null, COMBAT_MESSAGE_RANGE)
"<span class='userdanger'>[M.name] bites [src]!</span>", null, COMBAT_MESSAGE_RANGE, null, M,
"<span class='danger'>You bite [src]!</span>")
adjustBruteLoss(1)
log_combat(M, src, "attacked")
updatehealth()
@@ -25,6 +25,7 @@
/mob/living/carbon/alien/humanoid/Initialize()
AddAbility(new/obj/effect/proc_holder/alien/regurgitate(null))
. = ..()
AddComponent(/datum/component/footstep, FOOTSTEP_MOB_CLAW, 0.5, -3)
/mob/living/carbon/alien/humanoid/restrained(ignore_grab)
return handcuffed
+4 -5
View File
@@ -22,9 +22,6 @@
QDEL_NULL(dna)
GLOB.carbon_list -= src
/mob/living/carbon/initialize_footstep()
AddComponent(/datum/component/footstep, 0.6, 2)
/mob/living/carbon/relaymove(mob/user, direction)
if(user in src.stomach_contents)
if(prob(40))
@@ -253,7 +250,8 @@
var/obj/item/ITEM = get_item_by_slot(slot)
if(ITEM && istype(ITEM, /obj/item/tank) && wear_mask && (wear_mask.clothing_flags & ALLOWINTERNALS))
visible_message("<span class='danger'>[usr] tries to [internal ? "close" : "open"] the valve on [src]'s [ITEM.name].</span>", \
"<span class='userdanger'>[usr] tries to [internal ? "close" : "open"] the valve on [src]'s [ITEM.name].</span>")
"<span class='userdanger'>[usr] tries to [internal ? "close" : "open"] the valve on your [ITEM.name].</span>", \
target = usr, target_message = "<span class='danger'>You try to [internal ? "close" : "open"] the valve on [src]'s [ITEM.name].</span>")
if(do_mob(usr, src, POCKET_STRIP_DELAY))
if(internal)
internal = null
@@ -264,7 +262,8 @@
update_internals_hud_icon(1)
visible_message("<span class='danger'>[usr] [internal ? "opens" : "closes"] the valve on [src]'s [ITEM.name].</span>", \
"<span class='userdanger'>[usr] [internal ? "opens" : "closes"] the valve on [src]'s [ITEM.name].</span>")
"<span class='userdanger'>[usr] [internal ? "opens" : "closes"] the valve on your [ITEM.name].</span>", \
target = usr, target_message = "<span class='danger'>You [internal ? "opens" : "closes"] the valve on [src]'s [ITEM.name].</span>")
/mob/living/carbon/fall(forced)
@@ -185,7 +185,8 @@
M.powerlevel = 0
visible_message("<span class='danger'>The [M.name] has shocked [src]!</span>", \
"<span class='userdanger'>The [M.name] has shocked [src]!</span>")
"<span class='userdanger'>The [M.name] has shocked you!</span>", target = M,
target_message = "<span class='danger'>You have shocked [src]!</span>")
do_sparks(5, TRUE, src)
var/power = M.powerlevel + rand(0,3)
@@ -234,38 +235,44 @@
var/obj/item/organ/O = X
O.emp_act(severity)
///Adds to the parent by also adding functionality to propagate shocks through pulling and doing some fluff effects.
/mob/living/carbon/electrocute_act(shock_damage, source, siemens_coeff = 1, flags = NONE)
if((flags & SHOCK_TESLA) && (flags_1 & TESLA_IGNORE_1))
return FALSE
if(HAS_TRAIT(src, TRAIT_SHOCKIMMUNE))
return FALSE
shock_damage *= siemens_coeff
if(dna && dna.species)
shock_damage *= dna.species.siemens_coeff
if(shock_damage < 1)
return 0
if(reagents.has_reagent(/datum/reagent/teslium))
shock_damage *= 1.5 //If the mob has teslium in their body, shocks are 50% more damaging!
if((flags & SHOCK_ILLUSION))
adjustStaminaLoss(shock_damage)
else
take_overall_damage(0,shock_damage)
visible_message(
"<span class='danger'>[src] was shocked by \the [source]!</span>", \
"<span class='userdanger'>You feel a powerful shock coursing through your body!</span>", \
"<span class='italics'>You hear a heavy electrical crack.</span>" \
)
jitteriness += 1000 //High numbers for violent convulsions
. = ..()
if(!.)
return
//Propagation through pulling, fireman carry
if(!(flags & SHOCK_ILLUSION))
var/list/shocking_queue = list()
if(iscarbon(pulling) && source != pulling)
shocking_queue += pulling
if(iscarbon(pulledby) && source != pulledby)
shocking_queue += pulledby
if(iscarbon(buckled) && source != buckled)
shocking_queue += buckled
for(var/mob/living/carbon/carried in buckled_mobs)
if(source != carried)
shocking_queue += carried
//Found our victims, now lets shock them all
for(var/victim in shocking_queue)
var/mob/living/carbon/C = victim
C.electrocute_act(shock_damage*0.75, src, 1, flags)
//Stun
var/should_stun = (!(flags & SHOCK_TESLA) || siemens_coeff > 0.5) && !(flags & SHOCK_NOSTUN)
if(should_stun)
Stun(40)
//Jitter and other fluff.
jitteriness += 1000
do_jitter_animation(jitteriness)
stuttering += 2
if((!(flags & SHOCK_TESLA) || siemens_coeff > 0.5) && !(flags & SHOCK_NOSTUN))
Stun(40)
spawn(20)
jitteriness = max(jitteriness - 990, 10) //Still jittery, but vastly less
if((!(flags & SHOCK_TESLA) || siemens_coeff > 0.5) && !(flags & SHOCK_NOSTUN))
DefaultCombatKnockdown(60)
addtimer(CALLBACK(src, .proc/secondary_shock, should_stun), 20)
return shock_damage
///Called slightly after electrocute act to reduce jittering and apply a secondary stun.
/mob/living/carbon/proc/secondary_shock(should_stun)
jitteriness = max(jitteriness - 990, 10)
if(should_stun)
DefaultCombatKnockdown(60)
/mob/living/carbon/proc/help_shake_act(mob/living/carbon/M)
if(on_fire)
to_chat(M, "<span class='warning'>You can't put [p_them()] out with just your bare hands!</span>")
@@ -280,12 +287,14 @@
to_chat(M, "<span class='warning'>You need to unbuckle [src] first to do that!")
return
M.visible_message("<span class='notice'>[M] shakes [src] trying to get [p_them()] up!</span>", \
"<span class='notice'>You shake [src] trying to get [p_them()] up!</span>")
"<span class='notice'>You shake [src] trying to get [p_them()] up!</span>", target = src,
target_message = "<span class='notice'>[M] shakes you trying to get you up!</span>")
else if(M.zone_selected == BODY_ZONE_PRECISE_MOUTH) // I ADDED BOOP-EH-DEH-NOSEH - Jon
M.visible_message( \
"<span class='notice'>[M] boops [src]'s nose.</span>", \
"<span class='notice'>You boop [src] on the nose.</span>", )
"<span class='notice'>You boop [src] on the nose.</span>", target = src,
target_message = "<span class='notice'>[M] boops your nose.</span>")
playsound(src, 'sound/items/Nose_boop.ogg', 50, 0)
else if(check_zone(M.zone_selected) == BODY_ZONE_HEAD)
@@ -294,7 +303,8 @@
S = dna.species
M.visible_message("<span class='notice'>[M] gives [src] a pat on the head to make [p_them()] feel better!</span>", \
"<span class='notice'>You give [src] a pat on the head to make [p_them()] feel better!</span>")
"<span class='notice'>You give [src] a pat on the head to make [p_them()] feel better!</span>", target = src,
target_message = "<span class='notice'>[M] gives you a pat on the head to make you feel better!</span>")
SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "headpat", /datum/mood_event/headpat)
friendly_check = TRUE
if(S?.can_wag_tail(src) && !dna.species.is_wagging_tail())
@@ -307,11 +317,13 @@
else if(check_zone(M.zone_selected) == BODY_ZONE_R_ARM || check_zone(M.zone_selected) == BODY_ZONE_L_ARM)
M.visible_message( \
"<span class='notice'>[M] shakes [src]'s hand.</span>", \
"<span class='notice'>You shake [src]'s hand.</span>", )
"<span class='notice'>You shake [src]'s hand.</span>", target = src,
target_message = "<span class='notice'>[M] shakes your hand.</span>")
else
M.visible_message("<span class='notice'>[M] hugs [src] to make [p_them()] feel better!</span>", \
"<span class='notice'>You hug [src] to make [p_them()] feel better!</span>")
"<span class='notice'>You hug [src] to make [p_them()] feel better!</span>", target = src,\
target_message = "<span class='notice'>[M] hugs you to make you feel better!</span>")
SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "hug", /datum/mood_event/hug)
friendly_check = TRUE

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