Merge branch 'master' of https://github.com/Citadel-Station-13/Citadel-Station-13 into Ghommie-cit765
This commit is contained in:
@@ -8,11 +8,11 @@
|
||||
icon_icon = 'icons/mob/actions/actions_spells.dmi'
|
||||
|
||||
/datum/action/item_action/ninjaboost
|
||||
check_flags = NONE
|
||||
name = "Adrenaline Boost"
|
||||
desc = "Inject a secret chemical that will counteract all movement-impairing effect."
|
||||
button_icon_state = "repulse"
|
||||
icon_icon = 'icons/mob/actions/actions_spells.dmi'
|
||||
required_mobility_flags = NONE
|
||||
|
||||
/datum/action/item_action/ninjapulse
|
||||
name = "EM Burst (25E)"
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
return
|
||||
if(world.time > next_check && world.time > next_scare)
|
||||
next_check = world.time + 50
|
||||
var/list/seen_atoms = owner.visible_atoms(7)
|
||||
var/list/seen_atoms = owner.fov_view(7)
|
||||
|
||||
if(LAZYLEN(trigger_objs))
|
||||
for(var/obj/O in seen_atoms)
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
|
||||
#define BAD_ART 12.5
|
||||
#define GOOD_ART 25
|
||||
#define GREAT_ART 50
|
||||
|
||||
/datum/component/art
|
||||
var/impressiveness = 0
|
||||
|
||||
/datum/component/art/Initialize(impress)
|
||||
impressiveness = impress
|
||||
if(isobj(parent))
|
||||
RegisterSignal(parent, COMSIG_PARENT_EXAMINE, .proc/on_obj_examine)
|
||||
else
|
||||
RegisterSignal(parent, COMSIG_PARENT_EXAMINE, .proc/on_other_examine)
|
||||
if(isstructure(parent))
|
||||
RegisterSignal(parent, COMSIG_ATOM_ATTACK_HAND, .proc/on_attack_hand)
|
||||
if(isitem(parent))
|
||||
RegisterSignal(parent, COMSIG_ITEM_ATTACK_SELF, .proc/apply_moodlet)
|
||||
|
||||
/datum/component/art/proc/apply_moodlet(mob/M, impress)
|
||||
M.visible_message("<span class='notice'>[M] stops and looks intently at [parent].</span>", \
|
||||
"<span class='notice'>You stop to take in [parent].</span>")
|
||||
switch(impress)
|
||||
if (0 to BAD_ART)
|
||||
SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "artbad", /datum/mood_event/artbad)
|
||||
if (BAD_ART to GOOD_ART)
|
||||
SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "artok", /datum/mood_event/artok)
|
||||
if (GOOD_ART to GREAT_ART)
|
||||
SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "artgood", /datum/mood_event/artgood)
|
||||
if(GREAT_ART to INFINITY)
|
||||
SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "artgreat", /datum/mood_event/artgreat)
|
||||
|
||||
|
||||
/datum/component/art/proc/on_other_examine(datum/source, mob/M)
|
||||
apply_moodlet(M, impressiveness)
|
||||
|
||||
/datum/component/art/proc/on_obj_examine(datum/source, mob/M)
|
||||
var/obj/O = parent
|
||||
apply_moodlet(M, impressiveness *(O.obj_integrity/O.max_integrity))
|
||||
|
||||
/datum/component/art/proc/on_attack_hand(datum/source, mob/M)
|
||||
to_chat(M, "<span class='notice'>You start examining [parent]...</span>")
|
||||
if(!do_after(M, 20, target = parent))
|
||||
return
|
||||
on_obj_examine(source, M)
|
||||
|
||||
/datum/component/art/rev
|
||||
|
||||
/datum/component/art/rev/apply_moodlet(mob/M, impress)
|
||||
M.visible_message("<span class='notice'>[M] stops to inspect [parent].</span>", \
|
||||
"<span class='notice'>You take in [parent], inspecting the fine craftsmanship of the proletariat.</span>")
|
||||
|
||||
if(M.mind && M.mind.has_antag_datum(/datum/antagonist/rev))
|
||||
SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "artgreat", /datum/mood_event/artgreat)
|
||||
else
|
||||
SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "artbad", /datum/mood_event/artbad)
|
||||
@@ -74,7 +74,7 @@
|
||||
|
||||
//////////////////////Lens//////////////////////////
|
||||
//Six Steps //
|
||||
//Sells for 1800 cr, takes 15 glass shets //
|
||||
//Sells for 1600 cr, takes 15 glass shets //
|
||||
//Usefull for selling and later crafting //
|
||||
////////////////////////////////////////////////////
|
||||
|
||||
@@ -146,14 +146,14 @@
|
||||
|
||||
/obj/item/glasswork/glass_base/glass_lens_part5
|
||||
name = "Unpolished glass lens"
|
||||
desc = "A small unpolished glass lens. Could be polished with some silk."
|
||||
desc = "A small unpolished glass lens. Could be polished with some cloth."
|
||||
icon = 'icons/obj/glass_ware.dmi'
|
||||
icon_state = "glass_optics"
|
||||
next_step = /obj/item/glasswork/glass_base/glass_lens_part6
|
||||
|
||||
/obj/item/glasswork/glass_base/glass_lens_part5/attackby(obj/item/I, mob/user, params)
|
||||
..()
|
||||
if(istype(I, /obj/item/stack/sheet/silk))
|
||||
if(istype(I, /obj/item/stack/sheet/cloth))
|
||||
if(do_after(user,10, target = src))
|
||||
new next_step(user.loc, 1)
|
||||
qdel(src)
|
||||
@@ -324,7 +324,7 @@
|
||||
|
||||
//////////////////////Tea Plates////////////////////
|
||||
//Three Steps //
|
||||
//Sells for 1200 cr, takes 5 glass shets //
|
||||
//Sells for 1000 cr, takes 5 glass shets //
|
||||
//Usefull for selling and chemical things //
|
||||
////////////////////////////////////////////////////
|
||||
|
||||
@@ -370,20 +370,20 @@
|
||||
|
||||
/obj/item/glasswork/glass_base/tea_plate3
|
||||
name = "Disk of glass"
|
||||
desc = "A disk of glass that can be cant be used for much. Needs to be polished with some silk."
|
||||
desc = "A disk of glass that can be cant be used for much. Needs to be polished with some cloth."
|
||||
icon_state = "glass_base_half"
|
||||
next_step = /obj/item/tea_plate
|
||||
|
||||
/obj/item/glasswork/glass_base/tea_plate3/attackby(obj/item/I, mob/user, params)
|
||||
..()
|
||||
if(istype(I, /obj/item/stack/sheet/silk))
|
||||
if(istype(I, /obj/item/stack/sheet/cloth))
|
||||
if(do_after(user,10, target = src))
|
||||
new next_step(user.loc, 1)
|
||||
qdel(src)
|
||||
|
||||
//////////////////////Tea Cup///////////////////////
|
||||
//Four Steps //
|
||||
//Sells for 1800 cr, takes 6 glass shets //
|
||||
//Sells for 1600 cr, takes 6 glass shets //
|
||||
//Usefull for selling and chemical things //
|
||||
////////////////////////////////////////////////////
|
||||
|
||||
@@ -429,13 +429,13 @@
|
||||
|
||||
/obj/item/glasswork/glass_base/tea_cup3
|
||||
name = "Disk of glass"
|
||||
desc = "A bowl of glass that can be cant be used for much. Needs to be polished with some silk."
|
||||
desc = "A bowl of glass that can be cant be used for much. Needs to be polished with some cloth."
|
||||
icon_state = "glass_base_half"
|
||||
next_step = /obj/item/glasswork/glass_base/tea_cup4
|
||||
|
||||
/obj/item/glasswork/glass_base/cup3/attackby(obj/item/I, mob/user, params)
|
||||
..()
|
||||
if(istype(I, /obj/item/stack/sheet/silk))
|
||||
if(istype(I, /obj/item/stack/sheet/cloth))
|
||||
if(do_after(user,10, target = src))
|
||||
new next_step(user.loc, 1)
|
||||
qdel(src)
|
||||
|
||||
@@ -1,21 +1,20 @@
|
||||
//Gun crafting parts til they can be moved elsewhere
|
||||
|
||||
// PARTS //
|
||||
/obj/item/weaponcrafting
|
||||
icon = 'icons/obj/improvised.dmi'
|
||||
|
||||
/obj/item/weaponcrafting/receiver
|
||||
name = "modular receiver"
|
||||
desc = "A prototype modular receiver and trigger assembly for a firearm."
|
||||
icon = 'icons/obj/improvised.dmi'
|
||||
icon_state = "receiver"
|
||||
|
||||
/obj/item/weaponcrafting/stock
|
||||
name = "rifle stock"
|
||||
desc = "A classic rifle stock that doubles as a grip, roughly carved out of wood."
|
||||
icon = 'icons/obj/improvised.dmi'
|
||||
icon_state = "riflestock"
|
||||
|
||||
/obj/item/weaponcrafting/silkstring
|
||||
name = "silkstring"
|
||||
desc = "A long piece of silk with some resemblance to cable coil."
|
||||
icon = 'icons/obj/improvised.dmi'
|
||||
icon_state = "silkstring"
|
||||
/obj/item/weaponcrafting/durathread_string
|
||||
name = "durathread string"
|
||||
desc = "A long piece of durathread with some resemblance to cable coil."
|
||||
icon_state = "durastring"
|
||||
|
||||
@@ -39,14 +39,14 @@
|
||||
time = 10
|
||||
reqs = list(/obj/item/paper = 20)
|
||||
category = CAT_CLOTHING
|
||||
|
||||
|
||||
/datum/crafting_recipe/armwraps
|
||||
name = "Armwraps"
|
||||
result = /obj/item/clothing/gloves/fingerless/pugilist
|
||||
time = 60
|
||||
tools = list(TOOL_WIRECUTTER)
|
||||
reqs = list(/obj/item/stack/sheet/cloth = 4,
|
||||
/obj/item/stack/sheet/silk = 2,
|
||||
/obj/item/stack/sheet/durathread = 2,
|
||||
/obj/item/stack/sheet/leather = 2)
|
||||
category = CAT_CLOTHING
|
||||
|
||||
|
||||
@@ -192,7 +192,7 @@
|
||||
result = /obj/item/gun/ballistic/bow/pipe
|
||||
reqs = list(/obj/item/pipe = 5,
|
||||
/obj/item/stack/sheet/plastic = 15,
|
||||
/obj/item/weaponcrafting/silkstring = 5)
|
||||
/obj/item/weaponcrafting/durathread_string = 5)
|
||||
time = 450
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_WEAPON
|
||||
@@ -281,7 +281,7 @@
|
||||
result = /obj/item/ammo_casing/caseless/arrow/wood
|
||||
time = 30
|
||||
reqs = list(/obj/item/stack/sheet/mineral/wood = 1,
|
||||
/obj/item/stack/sheet/silk = 1,
|
||||
/obj/item/stack/sheet/durathread = 1,
|
||||
/obj/item/stack/rods = 1) // 1 metal sheet = 2 rods = 2 arrows
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_AMMO
|
||||
|
||||
@@ -86,10 +86,10 @@
|
||||
RegisterSignal(M, COMSIG_MOB_CLIENT_LOGOUT, .proc/on_mob_logout)
|
||||
RegisterSignal(M, COMSIG_MOB_GET_VISIBLE_MESSAGE, .proc/on_visible_message)
|
||||
RegisterSignal(M, COMSIG_MOB_EXAMINATE, .proc/on_examinate)
|
||||
RegisterSignal(M, COMSIG_MOB_VISIBLE_ATOMS, .proc/on_visible_atoms)
|
||||
RegisterSignal(M, COMSIG_MOB_FOV_VIEW, .proc/on_fov_view)
|
||||
RegisterSignal(M, COMSIG_MOB_CLIENT_CHANGE_VIEW, .proc/on_change_view)
|
||||
RegisterSignal(M, COMSIG_MOB_RESET_PERSPECTIVE, .proc/on_reset_perspective)
|
||||
RegisterSignal(M, COMSIG_MOB_IS_VIEWER, .proc/is_viewer)
|
||||
RegisterSignal(M, COMSIG_MOB_FOV_VIEWER, .proc/is_viewer)
|
||||
|
||||
/datum/component/field_of_vision/UnregisterFromParent()
|
||||
. = ..()
|
||||
@@ -109,8 +109,8 @@
|
||||
UNREGISTER_NESTED_LOCS(nested_locs, COMSIG_MOVABLE_MOVED, 1)
|
||||
UnregisterSignal(M, list(COMSIG_MOB_CLIENT_LOGIN, COMSIG_MOB_CLIENT_LOGOUT,
|
||||
COMSIG_MOB_GET_VISIBLE_MESSAGE, COMSIG_MOB_EXAMINATE,
|
||||
COMSIG_MOB_VISIBLE_ATOMS, COMSIG_MOB_RESET_PERSPECTIVE,
|
||||
COMSIG_MOB_CLIENT_CHANGE_VIEW, COMSIG_MOB_IS_VIEWER))
|
||||
COMSIG_MOB_FOV_VIEW, COMSIG_MOB_RESET_PERSPECTIVE,
|
||||
COMSIG_MOB_CLIENT_CHANGE_VIEW, COMSIG_MOB_FOV_VIEWER))
|
||||
|
||||
/**
|
||||
* Generates the holder and images (if not generated yet) and adds them to client.images.
|
||||
@@ -296,7 +296,7 @@
|
||||
if(fov.alpha)
|
||||
FOV_ANGLE_CHECK(source, target, return, return COMPONENT_NO_VISIBLE_MESSAGE)
|
||||
|
||||
/datum/component/field_of_vision/proc/on_visible_atoms(mob/source, list/atoms)
|
||||
/datum/component/field_of_vision/proc/on_fov_view(mob/source, list/atoms)
|
||||
if(!fov.alpha)
|
||||
return
|
||||
for(var/k in atoms)
|
||||
|
||||
@@ -1,26 +1,52 @@
|
||||
///Footstep component. Plays footsteps at parents location when it is appropriate.
|
||||
/datum/component/footstep
|
||||
///How many steps the parent has taken since the last time a footstep was played
|
||||
var/steps = 0
|
||||
///volume determines the extra volume of the footstep. This is multiplied by the base volume, should there be one.
|
||||
var/volume
|
||||
///e_range stands for extra range - aka how far the sound can be heard. This is added to the base value and ignored if there isn't a base value.
|
||||
var/e_range
|
||||
///footstep_type is a define which determines what kind of sounds should get chosen.
|
||||
var/footstep_type
|
||||
///This can be a list OR a soundfile OR null. Determines whatever sound gets played.
|
||||
var/footstep_sounds
|
||||
|
||||
/datum/component/footstep/Initialize(volume_ = 0.5, e_range_ = -1)
|
||||
/datum/component/footstep/Initialize(footstep_type_ = FOOTSTEP_MOB_BAREFOOT, volume_ = 0.5, e_range_ = -1)
|
||||
if(!isliving(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
volume = volume_
|
||||
e_range = e_range_
|
||||
RegisterSignal(parent, list(COMSIG_MOVABLE_MOVED), .proc/play_footstep)
|
||||
footstep_type = footstep_type_
|
||||
switch(footstep_type)
|
||||
if(FOOTSTEP_MOB_HUMAN)
|
||||
if(!ishuman(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
RegisterSignal(parent, COMSIG_MOVABLE_MOVED, .proc/play_humanstep)
|
||||
return
|
||||
if(FOOTSTEP_MOB_CLAW)
|
||||
footstep_sounds = GLOB.clawfootstep
|
||||
if(FOOTSTEP_MOB_BAREFOOT)
|
||||
footstep_sounds = GLOB.barefootstep
|
||||
if(FOOTSTEP_MOB_HEAVY)
|
||||
footstep_sounds = GLOB.heavyfootstep
|
||||
if(FOOTSTEP_MOB_SHOE)
|
||||
footstep_sounds = GLOB.footstep
|
||||
if(FOOTSTEP_MOB_SLIME)
|
||||
footstep_sounds = 'sound/effects/footstep/slime1.ogg'
|
||||
if(FOOTSTEP_MOB_CRAWL)
|
||||
footstep_sounds = 'sound/effects/footstep/crawl1.ogg'
|
||||
RegisterSignal(parent, COMSIG_MOVABLE_MOVED, .proc/play_simplestep) //Note that this doesn't get called for humans.
|
||||
|
||||
/datum/component/footstep/proc/play_footstep()
|
||||
///Prepares a footstep. Determines if it should get played. Returns the turf it should get played on. Note that it is always a /turf/open
|
||||
/datum/component/footstep/proc/prepare_step()
|
||||
var/turf/open/T = get_turf(parent)
|
||||
if(!istype(T))
|
||||
return
|
||||
|
||||
var/mob/living/LM = parent
|
||||
var/v = volume
|
||||
var/e = e_range
|
||||
if(!T.footstep || LM.buckled || !CHECK_MOBILITY(LM, MOBILITY_STAND) || LM.buckled || LM.throwing || (LM.movement_type & (VENTCRAWLING | FLYING)))
|
||||
if (LM.lying && !LM.buckled && !(!T.footstep || LM.movement_type & (VENTCRAWLING | FLYING))) //play crawling sound if we're lying
|
||||
playsound(T, 'sound/effects/footstep/crawl1.ogg', 15 * v)
|
||||
playsound(T, 'sound/effects/footstep/crawl1.ogg', 15 * volume)
|
||||
return
|
||||
|
||||
if(HAS_TRAIT(LM, TRAIT_SILENT_STEP))
|
||||
@@ -30,79 +56,83 @@
|
||||
var/mob/living/carbon/C = LM
|
||||
if(!C.get_bodypart(BODY_ZONE_L_LEG) && !C.get_bodypart(BODY_ZONE_R_LEG))
|
||||
return
|
||||
if(ishuman(C) && C.m_intent == MOVE_INTENT_WALK)
|
||||
v /= 2
|
||||
e -= 5
|
||||
if(C.m_intent == MOVE_INTENT_WALK)
|
||||
return
|
||||
steps++
|
||||
|
||||
if(steps >= 3)
|
||||
if(steps >= 6)
|
||||
steps = 0
|
||||
|
||||
else
|
||||
if(steps % 2)
|
||||
return
|
||||
|
||||
if(prob(80) && !LM.has_gravity(T)) // don't need to step as often when you hop around
|
||||
if(steps != 0 && !LM.has_gravity(T)) // don't need to step as often when you hop around
|
||||
return
|
||||
return T
|
||||
|
||||
//begin playsound shenanigans//
|
||||
|
||||
//for barefooted non-clawed mobs like monkeys
|
||||
if(isbarefoot(LM))
|
||||
playsound(T, pick(GLOB.barefootstep[T.barefootstep][1]),
|
||||
GLOB.barefootstep[T.barefootstep][2] * v,
|
||||
TRUE,
|
||||
GLOB.barefootstep[T.barefootstep][3] + e)
|
||||
/datum/component/footstep/proc/play_simplestep()
|
||||
var/turf/open/T = prepare_step()
|
||||
if(!T)
|
||||
return
|
||||
|
||||
//for xenomorphs, dogs, and other clawed mobs
|
||||
if(isclawfoot(LM))
|
||||
if(isalienadult(LM)) //xenos are stealthy and get quieter footsteps
|
||||
v /= 3
|
||||
e -= 5
|
||||
|
||||
playsound(T, pick(GLOB.clawfootstep[T.clawfootstep][1]),
|
||||
GLOB.clawfootstep[T.clawfootstep][2] * v,
|
||||
TRUE,
|
||||
GLOB.clawfootstep[T.clawfootstep][3] + e)
|
||||
if(isfile(footstep_sounds) || istext(footstep_sounds))
|
||||
playsound(T, footstep_sounds, volume)
|
||||
return
|
||||
|
||||
//for megafauna and other large and imtimidating mobs such as the bloodminer
|
||||
if(isheavyfoot(LM))
|
||||
playsound(T, pick(GLOB.heavyfootstep[T.heavyfootstep][1]),
|
||||
GLOB.heavyfootstep[T.heavyfootstep][2] * v,
|
||||
TRUE,
|
||||
GLOB.heavyfootstep[T.heavyfootstep][3] + e)
|
||||
var/turf_footstep
|
||||
switch(footstep_type)
|
||||
if(FOOTSTEP_MOB_CLAW)
|
||||
turf_footstep = T.clawfootstep
|
||||
if(FOOTSTEP_MOB_BAREFOOT)
|
||||
turf_footstep = T.barefootstep
|
||||
if(FOOTSTEP_MOB_HEAVY)
|
||||
turf_footstep = T.heavyfootstep
|
||||
if(FOOTSTEP_MOB_SHOE)
|
||||
turf_footstep = T.footstep
|
||||
if(!turf_footstep)
|
||||
return
|
||||
playsound(T, pick(footstep_sounds[turf_footstep][1]), footstep_sounds[turf_footstep][2] * volume, TRUE, footstep_sounds[turf_footstep][3] + e_range)
|
||||
|
||||
//for slimes
|
||||
if(isslime(LM))
|
||||
playsound(T, 'sound/effects/footstep/slime1.ogg', 15 * v)
|
||||
/datum/component/footstep/proc/play_humanstep()
|
||||
var/turf/open/T = prepare_step()
|
||||
if(!T)
|
||||
return
|
||||
|
||||
//for (simple) humanoid mobs (clowns, russians, pirates, etc.)
|
||||
if(isshoefoot(LM))
|
||||
if(!ishuman(LM))
|
||||
playsound(T, pick(GLOB.footstep[T.footstep][1]),
|
||||
GLOB.footstep[T.footstep][2] * v,
|
||||
TRUE,
|
||||
GLOB.footstep[T.footstep][3] + e)
|
||||
return
|
||||
if(ishuman(LM)) //for proper humans, they're special
|
||||
var/mob/living/carbon/human/H = LM
|
||||
var/feetCover = (H.wear_suit && (H.wear_suit.body_parts_covered & FEET)) || (H.w_uniform && (H.w_uniform.body_parts_covered & FEET) || (H.shoes && (H.shoes.body_parts_covered & FEET)))
|
||||
|
||||
if (H.dna.features["taur"] == "Naga" || H.dna.features["taur"] == "Tentacle") //are we a naga or tentacle taur creature
|
||||
playsound(T, 'sound/effects/footstep/crawl1.ogg', 15 * v)
|
||||
var/mob/living/carbon/human/H = parent
|
||||
var/list/L = GLOB.barefootstep
|
||||
var/turf_footstep = T.barefootstep
|
||||
var/special = FALSE
|
||||
if(H.physiology.footstep_type)
|
||||
switch(H.physiology.footstep_type)
|
||||
if(FOOTSTEP_MOB_CLAW)
|
||||
turf_footstep = T.clawfootstep
|
||||
L = GLOB.clawfootstep
|
||||
if(FOOTSTEP_MOB_BAREFOOT)
|
||||
turf_footstep = T.barefootstep
|
||||
L = GLOB.barefootstep
|
||||
if(FOOTSTEP_MOB_HEAVY)
|
||||
turf_footstep = T.heavyfootstep
|
||||
L = GLOB.heavyfootstep
|
||||
if(FOOTSTEP_MOB_SHOE)
|
||||
turf_footstep = T.footstep
|
||||
L = GLOB.footstep
|
||||
if(FOOTSTEP_MOB_SLIME)
|
||||
playsound(T, 'sound/effects/footstep/slime1.ogg', 50 * volume)
|
||||
return
|
||||
if(FOOTSTEP_MOB_CRAWL)
|
||||
playsound(T, 'sound/effects/footstep/crawl1.ogg', 50 * volume)
|
||||
return
|
||||
special = TRUE
|
||||
else
|
||||
var/feetCover = (H.wear_suit && (H.wear_suit.body_parts_covered & FEET)) || (H.w_uniform && (H.w_uniform.body_parts_covered & FEET) || (H.shoes && (H.shoes.body_parts_covered & FEET)))
|
||||
if(feetCover) //are we wearing shoes
|
||||
playsound(T, pick(GLOB.footstep[T.footstep][1]),
|
||||
GLOB.footstep[T.footstep][2] * volume,
|
||||
TRUE,
|
||||
GLOB.footstep[T.footstep][3] + e_range)
|
||||
return
|
||||
|
||||
if(feetCover) //are we wearing shoes
|
||||
playsound(T, pick(GLOB.footstep[T.footstep][1]),
|
||||
GLOB.footstep[T.footstep][2] * v,
|
||||
TRUE,
|
||||
GLOB.footstep[T.footstep][3] + e)
|
||||
|
||||
if(!feetCover) //are we NOT wearing shoes
|
||||
playsound(T, pick(GLOB.barefootstep[T.barefootstep][1]),
|
||||
GLOB.barefootstep[T.barefootstep][2] * v,
|
||||
TRUE,
|
||||
GLOB.barefootstep[T.barefootstep][3] + e)
|
||||
if(!special && H.dna.species.special_step_sounds)
|
||||
playsound(T, pick(H.dna.species.special_step_sounds), 50, TRUE)
|
||||
else
|
||||
playsound(T, pick(L[turf_footstep][1]),
|
||||
L[turf_footstep][2] * volume,
|
||||
TRUE,
|
||||
L[turf_footstep][3] + e_range)
|
||||
|
||||
@@ -73,7 +73,7 @@
|
||||
if(!material_amount)
|
||||
to_chat(user, "<span class='warning'>[I] does not contain sufficient materials to be accepted by [parent].</span>")
|
||||
return
|
||||
if(!has_space(material_amount))
|
||||
if((!precise_insertion || !GLOB.typecache_stack[I]) && !has_space(material_amount))
|
||||
to_chat(user, "<span class='warning'>[parent] has not enough space. Please remove materials from [parent] in order to insert more.</span>")
|
||||
return
|
||||
user_insert(I, user)
|
||||
|
||||
@@ -23,18 +23,12 @@
|
||||
|
||||
if(can_user_rotate)
|
||||
src.can_user_rotate = can_user_rotate
|
||||
else
|
||||
src.can_user_rotate = CALLBACK(src,.proc/default_can_user_rotate)
|
||||
|
||||
if(can_be_rotated)
|
||||
src.can_be_rotated = can_be_rotated
|
||||
else
|
||||
src.can_be_rotated = CALLBACK(src,.proc/default_can_be_rotated)
|
||||
|
||||
if(after_rotation)
|
||||
src.after_rotation = after_rotation
|
||||
else
|
||||
src.after_rotation = CALLBACK(src,.proc/default_after_rotation)
|
||||
|
||||
//Try Clockwise,counter,flip in order
|
||||
if(src.rotation_flags & ROTATION_FLIP)
|
||||
@@ -103,14 +97,34 @@
|
||||
examine_list += "<span class='notice'>Alt-click to rotate it clockwise.</span>"
|
||||
|
||||
/datum/component/simple_rotation/proc/HandRot(datum/source, mob/user, rotation = default_rotation_direction)
|
||||
if(!can_be_rotated.Invoke(user, rotation) || !can_user_rotate.Invoke(user, rotation))
|
||||
return
|
||||
if(can_be_rotated)
|
||||
if(!can_be_rotated.Invoke(user, default_rotation_direction))
|
||||
return
|
||||
else
|
||||
if(!default_can_be_rotated(user, default_rotation_direction))
|
||||
return
|
||||
if(can_user_rotate)
|
||||
if(!can_user_rotate.Invoke(user, default_rotation_direction))
|
||||
return
|
||||
else
|
||||
if(!default_can_user_rotate(user, default_rotation_direction))
|
||||
return
|
||||
BaseRot(user, rotation)
|
||||
return TRUE
|
||||
|
||||
/datum/component/simple_rotation/proc/WrenchRot(datum/source, obj/item/I, mob/living/user)
|
||||
if(!can_be_rotated.Invoke(user,default_rotation_direction) || !can_user_rotate.Invoke(user,default_rotation_direction))
|
||||
return
|
||||
if(can_be_rotated)
|
||||
if(!can_be_rotated.Invoke(user, default_rotation_direction))
|
||||
return
|
||||
else
|
||||
if(!default_can_be_rotated(user, default_rotation_direction))
|
||||
return
|
||||
if(can_user_rotate)
|
||||
if(!can_user_rotate.Invoke(user, default_rotation_direction))
|
||||
return
|
||||
else
|
||||
if(!default_can_user_rotate(user, default_rotation_direction))
|
||||
return
|
||||
if(istype(I,/obj/item/wrench))
|
||||
BaseRot(user,default_rotation_direction)
|
||||
return COMPONENT_NO_AFTERATTACK
|
||||
@@ -126,7 +140,10 @@
|
||||
if(ROTATION_FLIP)
|
||||
rot_degree = 180
|
||||
AM.setDir(turn(AM.dir,rot_degree))
|
||||
after_rotation.Invoke(user,rotation_type)
|
||||
if(after_rotation)
|
||||
after_rotation.Invoke(user, rotation_type)
|
||||
else
|
||||
default_after_rotation(user, rotation_type)
|
||||
|
||||
/datum/component/simple_rotation/proc/default_can_user_rotate(mob/living/user, rotation_type)
|
||||
if(!istype(user) || !user.canUseTopic(parent, BE_CLOSE, NO_DEXTERY))
|
||||
|
||||
@@ -136,9 +136,7 @@
|
||||
var/mob/M = parent.loc
|
||||
I.dropped(M)
|
||||
if(new_location)
|
||||
//Reset the items values
|
||||
_removal_reset(AM)
|
||||
AM.forceMove(new_location)
|
||||
AM.forceMove(new_location) // exited comsig will handle removal reset.
|
||||
//We don't want to call this if the item is being destroyed
|
||||
AM.on_exit_storage(src)
|
||||
else
|
||||
|
||||
@@ -351,7 +351,6 @@
|
||||
return master._removal_reset(thing)
|
||||
|
||||
/datum/component/storage/proc/_remove_and_refresh(datum/source, atom/movable/thing)
|
||||
_removal_reset(thing)
|
||||
if(LAZYACCESS(ui_item_blocks, thing))
|
||||
var/obj/screen/storage/volumetric_box/center/C = ui_item_blocks[thing]
|
||||
for(var/i in can_see_contents()) //runtimes result if mobs can access post deletion.
|
||||
@@ -359,6 +358,7 @@
|
||||
M.client?.screen -= C.on_screen_objects()
|
||||
ui_item_blocks -= thing
|
||||
qdel(C)
|
||||
_removal_reset(thing) // THIS NEEDS TO HAPPEN AFTER SO LAYERING DOESN'T BREAK!
|
||||
refresh_mob_views()
|
||||
|
||||
//Call this proc to handle the removal of an item from the storage item. The item will be moved to the new_location target, if that is null it's being deleted
|
||||
@@ -572,7 +572,7 @@
|
||||
if(rustle_sound)
|
||||
playsound(parent, "rustle", 50, 1, -5)
|
||||
to_chat(user, "<span class='notice'>You put [I] [insert_preposition]to [parent].</span>")
|
||||
for(var/mob/viewing in get_actual_viewers(world.view, user)-M)
|
||||
for(var/mob/viewing in fov_viewers(world.view, user)-M)
|
||||
if(in_range(M, viewing)) //If someone is standing close enough, they can tell what it is...
|
||||
viewing.show_message("<span class='notice'>[M] puts [I] [insert_preposition]to [parent].</span>", MSG_VISUAL)
|
||||
else if(I && I.w_class >= 3) //Otherwise they can only see large or normal items from a distance...
|
||||
|
||||
@@ -145,4 +145,10 @@
|
||||
return !is_mouth_covered()
|
||||
|
||||
/mob/living/carbon/CanSpreadAirborneDisease()
|
||||
return !((head && (head.flags_cover & HEADCOVERSMOUTH) && (head.armor.getRating("bio") >= 25)) || (wear_mask && (wear_mask.flags_cover & MASKCOVERSMOUTH) && (wear_mask.armor.getRating("bio") >= 25)))
|
||||
return !((head && (head.flags_cover & HEADCOVERSMOUTH) && (head.armor.getRating("bio") >= 25)) || (wear_mask && (wear_mask.flags_cover & MASKCOVERSMOUTH) && (wear_mask.armor.getRating("bio") >= 25)))
|
||||
|
||||
/mob/living/proc/set_shocked()
|
||||
flags_1 |= SHOCKED_1
|
||||
|
||||
/mob/living/proc/reset_shocked()
|
||||
flags_1 &= ~ SHOCKED_1
|
||||
+12
-1
@@ -47,8 +47,8 @@
|
||||
destination.dna.uni_identity = uni_identity
|
||||
destination.dna.blood_type = blood_type
|
||||
destination.dna.skin_tone_override = skin_tone_override
|
||||
destination.set_species(species.type, icon_update=0)
|
||||
destination.dna.features = features.Copy()
|
||||
destination.set_species(species.type, icon_update=0)
|
||||
destination.dna.real_name = real_name
|
||||
destination.dna.nameless = nameless
|
||||
destination.dna.custom_species = custom_species
|
||||
@@ -246,6 +246,17 @@
|
||||
construct_block(GLOB.mam_body_markings_list.Find(features["mam_body_markings"]), GLOB.mam_body_markings_list.len)
|
||||
if(DNA_TAUR_BLOCK)
|
||||
construct_block(GLOB.taur_list.Find(features["taur"]), GLOB.taur_list.len)
|
||||
if(species.mutant_bodyparts["taur"] && ishuman(holder))
|
||||
var/datum/sprite_accessory/taur/T = GLOB.taur_list[features["taur"]]
|
||||
switch(T?.taur_mode)
|
||||
if(STYLE_HOOF_TAURIC)
|
||||
H.physiology.footstep_type = FOOTSTEP_MOB_SHOE
|
||||
if(STYLE_PAW_TAURIC)
|
||||
H.physiology.footstep_type = FOOTSTEP_MOB_CLAW
|
||||
if(STYLE_SNEK_TAURIC)
|
||||
H.physiology.footstep_type = FOOTSTEP_MOB_CRAWL
|
||||
else
|
||||
H.physiology.footstep_type = null
|
||||
|
||||
//Please use add_mutation or activate_mutation instead
|
||||
/datum/dna/proc/force_give(datum/mutation/human/HM)
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
#define SHORT 4/5
|
||||
#define TALL 5/4
|
||||
|
||||
///Very similar to squish, but for dwarves and shorties
|
||||
/datum/element/dwarfism
|
||||
element_flags = ELEMENT_DETACH|ELEMENT_BESPOKE
|
||||
id_arg_index = 2
|
||||
var/comsig
|
||||
var/list/attached_targets = list()
|
||||
|
||||
/datum/element/dwarfism/Attach(datum/target, comsig, comsig_target)
|
||||
. = ..()
|
||||
if(!isliving(target))
|
||||
return ELEMENT_INCOMPATIBLE
|
||||
|
||||
src.comsig = comsig
|
||||
|
||||
var/mob/living/L = target
|
||||
if(L.lying != 0)
|
||||
L.transform = L.transform.Scale(SHORT, 1)
|
||||
else
|
||||
L.transform = L.transform.Scale(1, SHORT)
|
||||
attached_targets[target] = comsig_target
|
||||
RegisterSignal(target, comsig, .proc/check_loss) //Second arg of the signal will be checked against the comsig_target.
|
||||
|
||||
/datum/element/dwarfism/proc/check_loss(mob/living/L, comsig_target)
|
||||
if(attached_targets[L] == comsig_target)
|
||||
Detach(L)
|
||||
|
||||
/datum/element/dwarfism/Detach(mob/living/L)
|
||||
. = ..()
|
||||
if(QDELETED(L))
|
||||
return
|
||||
if(L.lying != 0)
|
||||
L.transform = L.transform.Scale(TALL, 1)
|
||||
else
|
||||
L.transform = L.transform.Scale(1, TALL)
|
||||
UnregisterSignal(L, comsig)
|
||||
attached_targets -= L
|
||||
|
||||
#undef SHORT
|
||||
#undef TALL
|
||||
@@ -41,7 +41,7 @@
|
||||
return
|
||||
//we want to delay the effect to be displayed after the mob is petted, not before.
|
||||
switch(user.a_intent)
|
||||
if(INTENT_HARM, INTENT_DISARM)
|
||||
if(INTENT_HARM)
|
||||
addtimer(CALLBACK(src, .proc/kick_the_dog, source, user), 1)
|
||||
if(INTENT_HELP)
|
||||
addtimer(CALLBACK(src, .proc/pet_the_dog, source, user), 1)
|
||||
|
||||
@@ -5,16 +5,18 @@
|
||||
var/list/testmerge = list()
|
||||
|
||||
/datum/getrev/New()
|
||||
commit = rustg_git_revparse("HEAD")
|
||||
if(commit)
|
||||
date = rustg_git_commit_date(commit)
|
||||
originmastercommit = rustg_git_revparse("origin/master")
|
||||
|
||||
/datum/getrev/proc/load_tgs_info()
|
||||
testmerge = world.TgsTestMerges()
|
||||
var/datum/tgs_revision_information/revinfo = world.TgsRevision()
|
||||
if(revinfo)
|
||||
commit = revinfo.commit
|
||||
originmastercommit = revinfo.origin_commit
|
||||
else
|
||||
commit = rustg_git_revparse("HEAD")
|
||||
if(commit)
|
||||
date = rustg_git_commit_date(commit)
|
||||
originmastercommit = rustg_git_revparse("origin/master")
|
||||
date = rustg_git_commit_date(commit)
|
||||
|
||||
// goes to DD log and config_error.txt
|
||||
log_world(get_log_message())
|
||||
@@ -77,7 +79,9 @@
|
||||
msg += "No commit information"
|
||||
if(world.TgsAvailable())
|
||||
var/datum/tgs_version/version = world.TgsVersion()
|
||||
msg += "Server tools version: [version.raw_parameter]"
|
||||
msg += "TGS version: [version.raw_parameter]"
|
||||
var/datum/tgs_version/api_version = world.TgsApiVersion()
|
||||
msg += "DMAPI version: [api_version.raw_parameter]"
|
||||
|
||||
// Game mode odds
|
||||
msg += "<br><b>Current Informational Settings:</b>"
|
||||
@@ -121,4 +125,4 @@
|
||||
if(probabilities[ctag] > 0)
|
||||
var/percentage = round(probabilities[ctag] / sum * 100, 0.1)
|
||||
msg += "[ctag] [percentage]%"
|
||||
to_chat(src, msg.Join("<br>"))
|
||||
to_chat(src, msg.Join("<br>"))
|
||||
|
||||
@@ -248,7 +248,7 @@
|
||||
description = "<span class='boldwarning'>Something I recently ate was horrifyingly disgusting.</span>\n"
|
||||
mood_change = -5
|
||||
timeout = 5 MINUTES
|
||||
|
||||
|
||||
/datum/mood_event/nanite_sadness
|
||||
description = "<span class='warning robot'>+++++++HAPPINESS SUPPRESSION+++++++</span>\n"
|
||||
mood_change = -7
|
||||
@@ -256,3 +256,7 @@
|
||||
/datum/mood_event/nanite_sadness/add_effects(message)
|
||||
description = "<span class='warning robot'>+++++++[message]+++++++</span>\n"
|
||||
|
||||
/datum/mood_event/artbad
|
||||
description = "<span class='warning'>I've produced better art than that from my ass.</span>\n"
|
||||
mood_change = -2
|
||||
timeout = 1200
|
||||
|
||||
@@ -182,3 +182,17 @@
|
||||
description = "<span class='nicegreen'>What a peculiar emblem. It makes me feel hopeful for my future.</span>\n"
|
||||
mood_change = 5
|
||||
|
||||
/datum/mood_event/artok
|
||||
description = "<span class='nicegreen'>It's nice to see people are making art around here.</span>\n"
|
||||
mood_change = 2
|
||||
timeout = 2 MINUTES
|
||||
|
||||
/datum/mood_event/artgood
|
||||
description = "<span class='nicegreen'>What a thought-provoking piece of art. I'll remember that for a while.</span>\n"
|
||||
mood_change = 3
|
||||
timeout = 3 MINUTES
|
||||
|
||||
/datum/mood_event/artgreat
|
||||
description = "<span class='nicegreen'>That work of art was so great it made me believe in the goodness of humanity. Says a lot in a place like this.</span>\n"
|
||||
mood_change = 4
|
||||
timeout = 4 MINUTES
|
||||
|
||||
@@ -116,7 +116,8 @@
|
||||
owner.apply_overlay(layer_used)
|
||||
if(power)
|
||||
owner.RemoveSpell(power)
|
||||
qdel(src)
|
||||
qdel(power)
|
||||
SEND_SIGNAL(owner, COMSIG_HUMAN_MUTATION_LOSS, src)
|
||||
return 0
|
||||
return 1
|
||||
|
||||
|
||||
@@ -82,7 +82,7 @@
|
||||
if(..())
|
||||
return
|
||||
ADD_TRAIT(owner, TRAIT_DWARF, GENETIC_MUTATION)
|
||||
owner.transform = owner.transform.Scale(1, 0.8)
|
||||
owner.AddElement(/datum/element/dwarfism, COMSIG_HUMAN_MUTATION_LOSS, src)
|
||||
passtable_on(owner, GENETIC_MUTATION)
|
||||
owner.visible_message("<span class='danger'>[owner] suddenly shrinks!</span>", "<span class='notice'>Everything around you seems to grow..</span>")
|
||||
|
||||
@@ -90,7 +90,6 @@
|
||||
if(..())
|
||||
return
|
||||
REMOVE_TRAIT(owner, TRAIT_DWARF, GENETIC_MUTATION)
|
||||
owner.transform = owner.transform.Scale(1, 1.25)
|
||||
passtable_off(owner, GENETIC_MUTATION)
|
||||
owner.visible_message("<span class='danger'>[owner] suddenly grows!</span>", "<span class='notice'>Everything around you seems to shrink..</span>")
|
||||
|
||||
|
||||
@@ -20,18 +20,20 @@ GLOBAL_LIST_INIT_TYPED(skill_datums, /datum/skill, init_skill_datums())
|
||||
var/desc
|
||||
/// Color of the name as shown in the html readout
|
||||
var/name_color = "#F0F0F0" // White on dark surface.
|
||||
/// Our progression type
|
||||
/// Our progression type. These are mostly used to skip typechecks overhead, don't go around messing with these.
|
||||
var/progression_type
|
||||
/// Abstract type
|
||||
var/abstract_type = /datum/skill
|
||||
/// List of max levels. Only used in level skills, but present here for helper macros.
|
||||
var/max_levels = INFINITY
|
||||
/// skill threshold used in generic skill competency calculations.
|
||||
var/list/competency_thresholds = list(0, 0, 0)
|
||||
/// Multiplier of the difference of the holder skill value and the selected threshold.
|
||||
var/list/competency_mults = list(0, 0, 0)
|
||||
/// In which way this skil can affect or be affected through actions and skill modifiers.
|
||||
var/skill_flags = SKILL_USE_MOOD|SKILL_TRAIN_MOOD
|
||||
/// skill threshold used in generic skill competency operations.
|
||||
var/list/competency_thresholds
|
||||
/// Base multiplier used in skill competency operations.
|
||||
var/base_multiplier = 1
|
||||
/// Value added to the base multiplier depending on overall competency compared to maximum value/level.
|
||||
var/competency_multiplier = 1
|
||||
/// A list of ways this skill can affect or be affected through actions and skill modifiers.
|
||||
var/list/skill_traits = list(SKILL_SANITY, SKILL_INTELLIGENCE)
|
||||
|
||||
/**
|
||||
* Ensures what someone's setting as a value for this skill is valid.
|
||||
@@ -66,8 +68,7 @@ GLOBAL_LIST_INIT_TYPED(skill_datums, /datum/skill, init_skill_datums())
|
||||
/datum/skill/binary
|
||||
abstract_type = /datum/skill/binary
|
||||
progression_type = SKILL_PROGRESSION_BINARY
|
||||
competency_thresholds = list(FALSE, TRUE, TRUE)
|
||||
competency_mults = list(0.5, 0.5, 0.5)
|
||||
competency_thresholds = list(THRESHOLD_COMPETENT = FALSE, THRESHOLD_EXPERT = TRUE, THRESHOLD_MASTER = TRUE)
|
||||
|
||||
/datum/skill/binary/sanitize_value(new_value)
|
||||
return new_value? TRUE : FALSE
|
||||
@@ -78,6 +79,7 @@ GLOBAL_LIST_INIT_TYPED(skill_datums, /datum/skill, init_skill_datums())
|
||||
/datum/skill/numerical
|
||||
abstract_type = /datum/skill/numerical
|
||||
progression_type = SKILL_PROGRESSION_NUMERICAL
|
||||
competency_thresholds = list(THRESHOLD_COMPETENT = 25, THRESHOLD_EXPERT = 50, THRESHOLD_MASTER = 75)
|
||||
/// Max value of this skill
|
||||
var/max_value = 100
|
||||
/// Min value of this skill
|
||||
@@ -180,8 +182,7 @@ GLOBAL_LIST_INIT_TYPED(skill_datums, /datum/skill, init_skill_datums())
|
||||
/datum/skill/level/job
|
||||
abstract_type = /datum/skill/level/job
|
||||
levels = list("Basic", "Trained", "Experienced", "Master")
|
||||
competency_thresholds = list(JOB_SKILL_TRAINED, JOB_SKILL_EXPERT, JOB_SKILL_MASTER)
|
||||
competency_mults = list(0.15, 0.1, 0.1)
|
||||
competency_thresholds = list(THRESHOLD_COMPETENT = JOB_SKILL_TRAINED, THRESHOLD_EXPERT = JOB_SKILL_EXPERT, THRESHOLD_MASTER = JOB_SKILL_MASTER)
|
||||
associative = TRUE
|
||||
|
||||
//quite the reference, no?
|
||||
@@ -195,7 +196,6 @@ GLOBAL_LIST_INIT_TYPED(skill_datums, /datum/skill, init_skill_datums())
|
||||
"Proficient", "Talented", "Adept", "Expert",
|
||||
"Professional", "Accomplished", "Great", "Master",
|
||||
"High Master", "Grand Master", "Legendary")
|
||||
competency_thresholds = list(DORF_SKILL_COMPETENT, DORF_SKILL_EXPERT, DORF_SKILL_MASTER)
|
||||
competency_mults = list(0.15, 0.1, 0.08)
|
||||
competency_thresholds = list(THRESHOLD_COMPETENT = DORF_SKILL_COMPETENT, THRESHOLD_EXPERT = DORF_SKILL_EXPERT, THRESHOLD_MASTER = DORF_SKILL_MASTER)
|
||||
associative = TRUE
|
||||
unskilled_tier = "Dabbling"
|
||||
|
||||
@@ -122,16 +122,22 @@
|
||||
* * modifier_is_multiplier : wheter the modifier is a multiplier or a divisor.
|
||||
*/
|
||||
/datum/mind/proc/action_skill_mod(skill, value, threshold, modifier_is_multiplier = TRUE)
|
||||
var/mod
|
||||
var/datum/skill/S = GLOB.skill_datums[skill]
|
||||
if(!S)
|
||||
return
|
||||
return value
|
||||
var/mod = S.base_multiplier
|
||||
switch(S.progression_type)
|
||||
if(SKILL_PROGRESSION_LEVEL)
|
||||
mod = get_skill_level(S.type)
|
||||
var/datum/skill/level/L = S
|
||||
var/skill_lvl = get_skill_level(L.type)
|
||||
mod += skill_lvl/(L.max_levels+max(L.competency_thresholds[threshold]-skill_lvl, 0))*L.competency_multiplier
|
||||
if(SKILL_PROGRESSION_NUMERICAL)
|
||||
var/datum/skill/numerical/N = S
|
||||
var/skill_val = get_skill_value(N.type)
|
||||
mod += skill_val/(N.max_value+max(N.competency_thresholds[threshold]-skill_val, 0))*N.competency_multiplier
|
||||
else
|
||||
mod = get_skill_value(S.type)
|
||||
mod = (1+(mod-S.competency_thresholds[threshold])*S.competency_mults[threshold])
|
||||
var/comp_threshold = S.competency_thresholds[threshold]
|
||||
mod += (comp_threshold ? (get_skill_value(S.type) / comp_threshold) : get_skill_value(S.type))*S.competency_multiplier
|
||||
. = modifier_is_multiplier ? value*mod : value/mod
|
||||
|
||||
/**
|
||||
@@ -139,29 +145,42 @@
|
||||
* Args:
|
||||
* * item/I : the item used in this action. its used_skills list variable contains the skills exercised with it.
|
||||
* * value : the value to modify, may be a delay, damage, probability.
|
||||
* * flags : the required flags that each skill (either in I.used_skills or the skill datum skill_flags) must have to influence
|
||||
* * traits : the required traits each skill (either in I.used_skills or the skill datum skill_traits) must have to influence
|
||||
* * the value.
|
||||
* * bad_flags : the opposite of the above, skills that must not be present to impact the value.
|
||||
* * bad_traits : the opposite of the above.
|
||||
* * modifier_is_multiplier : wheter the modifier is a multiplier or a divisor.
|
||||
*/
|
||||
/datum/mind/proc/item_action_skills_mod(obj/item/I, value, flags = NONE, bad_flags = NONE, modifier_is_multiplier = TRUE)
|
||||
/datum/mind/proc/item_action_skills_mod(obj/item/I, value, traits, bad_traits, modifier_is_multiplier = TRUE)
|
||||
. = value
|
||||
var/sum = 0
|
||||
var/divisor = 0
|
||||
var/one_trait = istext(traits)
|
||||
var/one_bad_trait = istext(bad_traits)
|
||||
for(var/k in I.used_skills)
|
||||
var/datum/skill/S = GLOB.skill_datums[k]
|
||||
if(!S)
|
||||
continue
|
||||
var/our_flags = (I.used_skills[k]|S.skill_flags)
|
||||
if((flags && !(our_flags & flags)) || (bad_flags && our_flags & bad_flags))
|
||||
var/our_traits = S.skill_traits
|
||||
our_traits |= I.used_skills[k]
|
||||
if(traits && !(one_trait ? (traits in our_traits) : length(our_traits & traits)))
|
||||
continue
|
||||
var/mod
|
||||
if(bad_traits && (one_bad_trait ? (bad_traits in our_traits) : length(our_traits & bad_traits)))
|
||||
continue
|
||||
var/mod = S.base_multiplier
|
||||
switch(S.progression_type)
|
||||
if(SKILL_PROGRESSION_LEVEL)
|
||||
mod = get_skill_level(S.type)
|
||||
var/datum/skill/level/L = S
|
||||
var/skill_lvl = get_skill_level(L.type)
|
||||
mod += skill_lvl/(L.max_levels+max(L.competency_thresholds[I.skill_difficulty]-skill_lvl, 0))*L.competency_multiplier
|
||||
if(SKILL_PROGRESSION_NUMERICAL)
|
||||
var/datum/skill/numerical/N = S
|
||||
var/skill_val = get_skill_value(N.type)
|
||||
mod += skill_val/(N.max_value+max(N.competency_thresholds[I.skill_difficulty]-skill_val, 0))*N.competency_multiplier
|
||||
else
|
||||
mod = get_skill_value(S.type)
|
||||
sum += 1+(mod - S.competency_thresholds[I.skill_difficulty])*S.competency_mults[I.skill_difficulty]
|
||||
var/comp_threshold = S.competency_thresholds[I.skill_difficulty]
|
||||
mod += (comp_threshold ? (get_skill_value(S.type) / comp_threshold) : get_skill_value(S.type))*S.competency_multiplier
|
||||
sum += mod
|
||||
divisor++
|
||||
if(divisor)
|
||||
. = modifier_is_multiplier ? value*(sum/divisor) : value/(sum/divisor)
|
||||
|
||||
|
||||
@@ -9,11 +9,13 @@ GLOBAL_LIST_EMPTY(potential_mods_per_skill)
|
||||
/datum/skill_modifier
|
||||
/// flags for this skill modifier.
|
||||
var/modifier_flags = NONE
|
||||
/// target skills, can be a specific skill typepath or a set of skill flags.
|
||||
var/target_skills = NONE
|
||||
/// target skills, can be a specific skill typepath or a list of skill traits.
|
||||
var/target_skills = /datum/skill
|
||||
/// the GLOB.potential_skills_per_mod key generated on runtime. You shouldn't be var-editing it.
|
||||
var/target_skills_key
|
||||
/// The identifier key this skill modifier is associated with.
|
||||
var/identifier
|
||||
/// skill affinity modifier, can be a multiplier or addendum, depending on the modifier_flags flags.
|
||||
/// skill affinity modifier, can be a multiplier or addendum, depending on the modifier_flags.
|
||||
var/affinity_mod = 1
|
||||
/// skill value modifier, see above.
|
||||
var/value_mod = 1
|
||||
@@ -38,21 +40,25 @@ GLOBAL_LIST_EMPTY(potential_mods_per_skill)
|
||||
CRASH("Skill modifier identifier \"[identifier]\" already taken.")
|
||||
GLOB.skill_modifiers[identifier] = src
|
||||
if(ispath(target_skills))
|
||||
target_skills_key = target_skills
|
||||
var/list/mod_L = GLOB.potential_mods_per_skill[target_skills]
|
||||
if(!mod_L)
|
||||
mod_L = GLOB.potential_mods_per_skill[target_skills] = list()
|
||||
else
|
||||
BINARY_INSERT(identifier, mod_L, datum/skill_modifier, src, priority, COMPARE_VALUE)
|
||||
mod_L[identifier] = src
|
||||
GLOB.potential_skills_per_mod["[target_skills]"] = list(target_skills)
|
||||
else //Should be a bitfield.
|
||||
var/list/L = GLOB.potential_skills_per_mod["[target_skills]"]
|
||||
GLOB.potential_skills_per_mod[target_skills_key] = list(target_skills)
|
||||
else //Should be a list.
|
||||
var/list/T = target_skills
|
||||
T = sortTim(target_skills, /proc/cmp_text_asc) //Sort the list contents alphabetically.
|
||||
target_skills_key = T.Join("-")
|
||||
var/list/L = GLOB.potential_skills_per_mod[target_skills_key]
|
||||
if(!L)
|
||||
L = list()
|
||||
for(var/path in GLOB.skill_datums)
|
||||
if(GLOB.skill_datums[path].skill_flags & target_skills)
|
||||
if(GLOB.skill_datums[path].skill_traits & target_skills)
|
||||
L += path
|
||||
GLOB.potential_skills_per_mod["[target_skills]"] = L
|
||||
GLOB.potential_skills_per_mod[target_skills_key] = L
|
||||
for(var/path in L)
|
||||
var/list/mod_L = GLOB.potential_mods_per_skill[path]
|
||||
if(!mod_L)
|
||||
@@ -62,7 +68,7 @@ GLOBAL_LIST_EMPTY(potential_mods_per_skill)
|
||||
mod_L[identifier] = src
|
||||
|
||||
/datum/skill_modifier/Destroy()
|
||||
for(var/path in GLOB.potential_skills_per_mod["[target_skills]"])
|
||||
for(var/path in GLOB.potential_skills_per_mod[target_skills_key])
|
||||
var/mod_L = GLOB.potential_mods_per_skill[path]
|
||||
mod_L -= identifier
|
||||
if(!length(mod_L))
|
||||
@@ -96,7 +102,7 @@ GLOBAL_LIST_EMPTY(potential_mods_per_skill)
|
||||
LAZYINITLIST(skill_holder.skill_affinity_mods)
|
||||
if(M.modifier_flags & MODIFIER_SKILL_LEVEL)
|
||||
LAZYINITLIST(skill_holder.skill_level_mods)
|
||||
for(var/path in GLOB.potential_skills_per_mod["[M.target_skills]"])
|
||||
for(var/path in GLOB.potential_skills_per_mod[M.target_skills_key])
|
||||
if(M.modifier_flags & MODIFIER_SKILL_VALUE)
|
||||
ADD_MOD_STEP(skill_holder.skill_value_mods, path, skill_holder.original_values, get_skill_value(path, FALSE))
|
||||
if(M.modifier_flags & MODIFIER_SKILL_AFFINITY)
|
||||
@@ -127,7 +133,7 @@ GLOBAL_LIST_EMPTY(potential_mods_per_skill)
|
||||
|
||||
if(!skill_holder.skill_value_mods && !skill_holder.skill_affinity_mods && !skill_holder.skill_level_mods)
|
||||
return
|
||||
for(var/path in GLOB.potential_skills_per_mod["[M.target_skills]"])
|
||||
for(var/path in GLOB.potential_skills_per_mod[M.target_skills_key])
|
||||
if(M.modifier_flags & MODIFIER_SKILL_VALUE && skill_holder.skill_value_mods)
|
||||
REMOVE_MOD_STEP(skill_holder.skill_value_mods, path, skill_holder.original_values)
|
||||
if(M.modifier_flags & MODIFIER_SKILL_AFFINITY && skill_holder.skill_affinity_mods)
|
||||
@@ -155,6 +161,18 @@ GLOBAL_LIST_EMPTY(potential_mods_per_skill)
|
||||
if(MODIFIER_TARGET_AFFINITY)
|
||||
mod = affinity_mod
|
||||
|
||||
if(modifier_flags & MODIFIER_USE_THRESHOLDS && istext(mod))
|
||||
var/datum/skill/S = GLOB.skill_datums[skillpath]
|
||||
if(method == MODIFIER_TARGET_VALUE && S.progression_type == SKILL_PROGRESSION_LEVEL)
|
||||
var/datum/skill/level/L = S
|
||||
switch(L.level_up_method)
|
||||
if(STANDARD_LEVEL_UP)
|
||||
mod = XP_LEVEL(L.standard_xp_lvl_up, L.xp_lvl_multiplier, S.competency_thresholds[mod])
|
||||
if(DWARFY_LEVEL_UP)
|
||||
mod = DORF_XP_LEVEL(L.standard_xp_lvl_up, L.xp_lvl_multiplier, S.competency_thresholds[mod])
|
||||
else
|
||||
mod = S.competency_thresholds[mod]
|
||||
|
||||
var/diff = 0
|
||||
if(modifier_flags & (MODIFIER_SKILL_VIRTUE|MODIFIER_SKILL_HANDICAP))
|
||||
if(modifier_flags & MODIFIER_SKILL_VIRTUE)
|
||||
|
||||
@@ -2,5 +2,4 @@
|
||||
name = "Wiring"
|
||||
desc = "How proficient and knowledged you are at wiring beyond laying cables on the floor."
|
||||
name_color = COLOR_PALE_ORANGE
|
||||
competency_thresholds = list(JOB_SKILL_BASIC, JOB_SKILL_EXPERT, JOB_SKILL_MASTER)
|
||||
skill_flags = SKILL_USE_MOOD|SKILL_TRAIN_MOOD|SKILL_USE_TOOL|SKILL_TRAINING_TOOL
|
||||
skill_traits = list(SKILL_SANITY, SKILL_INTELLIGENCE, SKILL_USE_TOOL, SKILL_TRAINING_TOOL)
|
||||
|
||||
@@ -2,4 +2,4 @@
|
||||
name = "Surgery"
|
||||
desc = "How proficient you are at doing surgery."
|
||||
name_color = COLOR_PALE_BLUE_GRAY
|
||||
competency_mults = list(0.025, 0.025, 0.025) // 60% surgery speed up at max value of 100.
|
||||
competency_multiplier = 1.5 // 60% surgery speed up at max value of 100, considering the base multiplier.
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/datum/skill_modifier/bad_mood
|
||||
modifier_flags = MODIFIER_SKILL_VALUE|MODIFIER_SKILL_LEVEL|MODIFIER_SKILL_MULT|MODIFIER_SKILL_BODYBOUND
|
||||
target_skills = SKILL_USE_MOOD
|
||||
target_skills = list(SKILL_SANITY)
|
||||
|
||||
/datum/skill_modifier/great_mood
|
||||
modifier_flags = MODIFIER_SKILL_AFFINITY|MODIFIER_SKILL_MULT|MODIFIER_SKILL_BODYBOUND
|
||||
target_skills = SKILL_TRAIN_MOOD
|
||||
target_skills = list(SKILL_SANITY)
|
||||
affinity_mod = 1.2
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
/datum/skill_modifier/brain_damage
|
||||
target_skills = list(SKILL_INTELLIGENCE)
|
||||
modifier_flags = MODIFIER_SKILL_VALUE|MODIFIER_SKILL_AFFINITY|MODIFIER_SKILL_LEVEL|MODIFIER_SKILL_MULT|MODIFIER_SKILL_BODYBOUND
|
||||
value_mod = 0.85
|
||||
level_mod = 0.85
|
||||
affinity_mod = 0.85
|
||||
|
||||
/datum/skill_modifier/heavy_brain_damage
|
||||
target_skills = list(SKILL_INTELLIGENCE)
|
||||
modifier_flags = MODIFIER_SKILL_VALUE|MODIFIER_SKILL_AFFINITY|MODIFIER_SKILL_LEVEL|MODIFIER_SKILL_BODYBOUND|MODIFIER_SKILL_HANDICAP|MODIFIER_USE_THRESHOLDS
|
||||
priority = MODIFIER_SKILL_PRIORITY_LOW
|
||||
value_mod = THRESHOLD_COMPETENT
|
||||
level_mod = THRESHOLD_COMPETENT
|
||||
@@ -120,11 +120,13 @@
|
||||
/datum/status_effect/mesmerize/on_creation(mob/living/new_owner, set_duration)
|
||||
. = ..()
|
||||
ADD_TRAIT(owner, TRAIT_MUTE, "mesmerize")
|
||||
ADD_TRAIT(owner, TRAIT_COMBAT_MODE_LOCKED, "mesmerize")
|
||||
owner.add_movespeed_modifier(/datum/movespeed_modifier/status_effect/mesmerize)
|
||||
|
||||
/datum/status_effect/mesmerize/on_remove()
|
||||
. = ..()
|
||||
REMOVE_TRAIT(owner, TRAIT_MUTE, "mesmerize")
|
||||
REMOVE_TRAIT(owner, TRAIT_COMBAT_MODE_LOCKED, "mesmerize")
|
||||
owner.remove_movespeed_modifier(/datum/movespeed_modifier/status_effect/mesmerize)
|
||||
|
||||
/datum/status_effect/mesmerize/on_creation(mob/living/new_owner, set_duration)
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
/datum/tgs_event_handler/impl/HandleEvent(event_code, ...)
|
||||
switch(event_code)
|
||||
if(TGS_EVENT_REBOOT_MODE_CHANGE)
|
||||
var/list/reboot_mode_lookup = list ("[TGS_REBOOT_MODE_NORMAL]" = "be normal", "[TGS_REBOOT_MODE_SHUTDOWN]" = "shutdown the server", "[TGS_REBOOT_MODE_RESTART]" = "hard restart the server")
|
||||
var old_reboot_mode = args[2]
|
||||
var new_reboot_mode = args[3]
|
||||
message_admins("TGS: Reboot will no longer [reboot_mode_lookup["[old_reboot_mode]"]], it will instead [reboot_mode_lookup["[new_reboot_mode]"]]")
|
||||
if(TGS_EVENT_PORT_SWAP)
|
||||
message_admins("TGS: Changing port from [world.port] to [args[2]]")
|
||||
if(TGS_EVENT_INSTANCE_RENAMED)
|
||||
message_admins("TGS: Instance renamed to from [world.TgsInstanceName()] to [args[2]]")
|
||||
if(TGS_EVENT_COMPILE_START)
|
||||
message_admins("TGS: Deployment started, new game version incoming...")
|
||||
if(TGS_EVENT_COMPILE_CANCELLED)
|
||||
message_admins("TGS: Deployment cancelled!")
|
||||
if(TGS_EVENT_COMPILE_FAILURE)
|
||||
message_admins("TGS: Deployment failed!")
|
||||
if(TGS_EVENT_DEPLOYMENT_COMPLETE)
|
||||
message_admins("TGS: Deployment complete!")
|
||||
to_chat(world, "<span class='boldannounce'>Server updated, changes will be applied on the next round...</span>")
|
||||
Reference in New Issue
Block a user