Merge remote-tracking branch 'citadel/master' into combat_rework
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
#define VV_HTML_ENCODE(thing) ( sanitize ? html_encode(thing) : thing )
|
||||
/// Get displayed variable in VV variable list
|
||||
/proc/debug_variable(name, value, level, datum/D, sanitize = TRUE) //if D is a list, name will be index, and value will be assoc value.
|
||||
var/header
|
||||
if(D)
|
||||
@@ -35,6 +36,19 @@
|
||||
else if (isfile(value))
|
||||
item = "[VV_HTML_ENCODE(name)] = <span class='value'>'[value]'</span>"
|
||||
|
||||
else if(istype(value, /matrix)) // Needs to be before datum
|
||||
var/matrix/M = value
|
||||
item = {"[VV_HTML_ENCODE(name)] = <span class='value'>
|
||||
<table class='matrixbrak'><tbody><tr>
|
||||
<td class='lbrak'> </td>
|
||||
<td><table class='matrix'><tbody>
|
||||
<tr><td>[M.a]</td><td>[M.d]</td><td>0</td></tr>
|
||||
<tr><td>[M.b]</td><td>[M.e]</td><td>0</td></tr>
|
||||
<tr><td>[M.c]</td><td>[M.f]</td><td>1</td></tr>
|
||||
</tbody></table></td>
|
||||
<td class='rbrak'> </td>
|
||||
</tr></tbody></table></span>"} //TODO link to modify_transform wrapper for all matrices
|
||||
|
||||
else if (istype(value, /datum))
|
||||
var/datum/DV = value
|
||||
if ("[DV]" != "[DV.type]") //if the thing as a name var, lets use it.
|
||||
|
||||
@@ -96,16 +96,7 @@
|
||||
<head>
|
||||
<meta http-equiv='Content-Type' content='text/html; charset=UTF-8'>
|
||||
<title>[title]</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: Verdana, sans-serif;
|
||||
font-size: 9pt;
|
||||
}
|
||||
.value {
|
||||
font-family: "Courier New", monospace;
|
||||
font-size: 8pt;
|
||||
}
|
||||
</style>
|
||||
<link rel="stylesheet" type="text/css" href="view_variables.css">
|
||||
</head>
|
||||
<body onload='selectTextField()' onkeydown='return handle_keydown()' onkeyup='handle_keyup()'>
|
||||
<script type="text/javascript">
|
||||
|
||||
@@ -135,6 +135,29 @@
|
||||
|
||||
return TRUE
|
||||
|
||||
//For the Volt Void scripture, fires a ray of energy at a target location
|
||||
/obj/effect/proc_holder/slab/volt
|
||||
ranged_mousepointer = 'icons/effects/volt_target.dmi'
|
||||
|
||||
/obj/effect/proc_holder/slab/volt/InterceptClickOn(mob/living/caller, params, atom/target)
|
||||
if(target == slab || ..()) //we can't cancel
|
||||
return TRUE
|
||||
|
||||
var/turf/T = ranged_ability_user.loc
|
||||
if(!isturf(T))
|
||||
return TRUE
|
||||
|
||||
if(target in view(7, get_turf(ranged_ability_user)))
|
||||
successful = TRUE
|
||||
ranged_ability_user.visible_message("<span class='warning'>[ranged_ability_user] fires a ray of energy at [target]!</span>", "<span class='nzcrentr'>You fire a volt ray at [target].</span>")
|
||||
playsound(ranged_ability_user, 'sound/effects/light_flicker.ogg', 50, 1)
|
||||
T = get_turf(target)
|
||||
new/obj/effect/temp_visual/ratvar/volt_hit(T, ranged_ability_user)
|
||||
log_combat(ranged_ability_user, T, "fired a volt ray")
|
||||
remove_ranged_ability()
|
||||
|
||||
return TRUE
|
||||
|
||||
//For the Kindle scripture; stuns and mutes a target non-servant.
|
||||
/obj/effect/proc_holder/slab/kindle
|
||||
ranged_mousepointer = 'icons/effects/volt_target.dmi'
|
||||
|
||||
@@ -263,3 +263,160 @@
|
||||
duration = max(duration, 100)
|
||||
return slab.procure_gateway(invoker, duration, portal_uses)
|
||||
|
||||
|
||||
//Mending Mantra: Channeled for up to ten times over twenty seconds to repair structures and heal allies
|
||||
/datum/clockwork_scripture/channeled/mending_mantra
|
||||
descname = "Channeled, Area Healing and Repair"
|
||||
name = "Mending Mantra"
|
||||
desc = "Repairs nearby structures and constructs. Servants wearing clockwork armor will also be healed. Channeled every two seconds for a maximum of twenty seconds."
|
||||
chant_invocations = list("Mend our dents!", "Heal our scratches!", "Repair our gears!")
|
||||
chant_amount = 10
|
||||
chant_interval = 20
|
||||
power_cost = 400
|
||||
usage_tip = "This is a very effective way to rapidly reinforce a base after an attack."
|
||||
tier = SCRIPTURE_SCRIPT
|
||||
primary_component = VANGUARD_COGWHEEL
|
||||
sort_priority = 7
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Repairs nearby structures and constructs. Servants wearing clockwork armor will also be healed.<br><b>Maximum 10 chants.</b>"
|
||||
var/heal_attempts = 4
|
||||
var/heal_amount = 2.5
|
||||
var/static/list/damage_heal_order = list(BRUTE, BURN, OXY)
|
||||
var/static/list/heal_finish_messages = list("There, all mended!", "Try not to get too damaged.", "No more dents and scratches for you!", "Champions never die.", "All patched up.", \
|
||||
"Ah, child, it's okay now.", "Pain is temporary.", "What you do for the Justiciar is eternal.", "Bear this for me.", "Be strong, child.", "Please, be careful!", \
|
||||
"If you die, you will be remembered.")
|
||||
var/static/list/heal_target_typecache = typecacheof(list(
|
||||
/obj/structure/destructible/clockwork,
|
||||
/obj/machinery/door/airlock/clockwork,
|
||||
/obj/machinery/door/window/clockwork,
|
||||
/obj/structure/window/reinforced/clockwork,
|
||||
/obj/structure/table/reinforced/brass))
|
||||
var/static/list/ratvarian_armor_typecache = typecacheof(list(
|
||||
/obj/item/clothing/suit/armor/clockwork,
|
||||
/obj/item/clothing/head/helmet/clockwork,
|
||||
/obj/item/clothing/gloves/clockwork,
|
||||
/obj/item/clothing/shoes/clockwork))
|
||||
|
||||
/datum/clockwork_scripture/channeled/mending_mantra/chant_effects(chant_number)
|
||||
var/turf/T
|
||||
for(var/atom/movable/M in range(7, invoker))
|
||||
if(isliving(M))
|
||||
if(isclockmob(M) || istype(M, /mob/living/simple_animal/drone/cogscarab))
|
||||
var/mob/living/simple_animal/S = M
|
||||
if(S.health == S.maxHealth || S.stat == DEAD)
|
||||
continue
|
||||
T = get_turf(M)
|
||||
for(var/i in 1 to heal_attempts)
|
||||
if(S.health < S.maxHealth)
|
||||
S.adjustHealth(-heal_amount)
|
||||
new /obj/effect/temp_visual/heal(T, "#1E8CE1")
|
||||
if(i == heal_attempts && S.health >= S.maxHealth) //we finished healing on the last tick, give them the message
|
||||
to_chat(S, "<span class='inathneq'>\"[text2ratvar(pick(heal_finish_messages))]\"</span>")
|
||||
break
|
||||
else
|
||||
to_chat(S, "<span class='inathneq'>\"[text2ratvar(pick(heal_finish_messages))]\"</span>")
|
||||
break
|
||||
else if(issilicon(M))
|
||||
var/mob/living/silicon/S = M
|
||||
if(S.health == S.maxHealth || S.stat == DEAD || !is_servant_of_ratvar(S))
|
||||
continue
|
||||
T = get_turf(M)
|
||||
for(var/i in 1 to heal_attempts)
|
||||
if(S.health < S.maxHealth)
|
||||
S.heal_ordered_damage(heal_amount, damage_heal_order)
|
||||
new /obj/effect/temp_visual/heal(T, "#1E8CE1")
|
||||
if(i == heal_attempts && S.health >= S.maxHealth)
|
||||
to_chat(S, "<span class='inathneq'>\"[text2ratvar(pick(heal_finish_messages))]\"</span>")
|
||||
break
|
||||
else
|
||||
to_chat(S, "<span class='inathneq'>\"[text2ratvar(pick(heal_finish_messages))]\"</span>")
|
||||
break
|
||||
else if(ishuman(M))
|
||||
var/mob/living/carbon/human/H = M
|
||||
if(H.health == H.maxHealth || H.stat == DEAD || !is_servant_of_ratvar(H))
|
||||
continue
|
||||
T = get_turf(M)
|
||||
var/heal_ticks = 0 //one heal tick for each piece of ratvarian armor worn
|
||||
var/obj/item/I = H.get_item_by_slot(SLOT_WEAR_SUIT)
|
||||
if(is_type_in_typecache(I, ratvarian_armor_typecache))
|
||||
heal_ticks++
|
||||
I = H.get_item_by_slot(SLOT_HEAD)
|
||||
if(is_type_in_typecache(I, ratvarian_armor_typecache))
|
||||
heal_ticks++
|
||||
I = H.get_item_by_slot(SLOT_GLOVES)
|
||||
if(is_type_in_typecache(I, ratvarian_armor_typecache))
|
||||
heal_ticks++
|
||||
I = H.get_item_by_slot(SLOT_SHOES)
|
||||
if(is_type_in_typecache(I, ratvarian_armor_typecache))
|
||||
heal_ticks++
|
||||
if(heal_ticks)
|
||||
for(var/i in 1 to heal_ticks)
|
||||
if(H.health < H.maxHealth)
|
||||
H.heal_ordered_damage(heal_amount, damage_heal_order)
|
||||
new /obj/effect/temp_visual/heal(T, "#1E8CE1")
|
||||
if(i == heal_ticks && H.health >= H.maxHealth)
|
||||
to_chat(H, "<span class='inathneq'>\"[text2ratvar(pick(heal_finish_messages))]\"</span>")
|
||||
break
|
||||
else
|
||||
to_chat(H, "<span class='inathneq'>\"[text2ratvar(pick(heal_finish_messages))]\"</span>")
|
||||
break
|
||||
else if(is_type_in_typecache(M, heal_target_typecache))
|
||||
var/obj/structure/destructible/clockwork/C = M
|
||||
if(C.obj_integrity == C.max_integrity || (istype(C) && !C.can_be_repaired))
|
||||
continue
|
||||
T = get_turf(M)
|
||||
for(var/i in 1 to heal_attempts)
|
||||
if(C.obj_integrity < C.max_integrity)
|
||||
C.obj_integrity = min(C.obj_integrity + 5, C.max_integrity)
|
||||
C.update_icon()
|
||||
new /obj/effect/temp_visual/heal(T, "#1E8CE1")
|
||||
else
|
||||
break
|
||||
new /obj/effect/temp_visual/ratvar/mending_mantra(get_turf(invoker))
|
||||
return TRUE
|
||||
|
||||
//Volt Blaster: Channeled for up to five times over ten seconds to fire up to five rays of energy at target locations.
|
||||
/datum/clockwork_scripture/channeled/volt_blaster
|
||||
descname = "Channeled, Targeted Energy Blasts"
|
||||
name = "Volt Blaster"
|
||||
desc = "Allows you to fire five energy rays at target locations. Channeled every fourth of a second for a maximum of ten seconds."
|
||||
channel_time = 30
|
||||
invocations = list("Amperage...", "...grant me your power!")
|
||||
chant_invocations = list("Use charge to kill!", "Slay with power!", "Hunt with energy!")
|
||||
chant_amount = 5
|
||||
chant_interval = 4
|
||||
power_cost = 500
|
||||
usage_tip = "Though it requires you to stand still, this scripture can do massive damage."
|
||||
tier = SCRIPTURE_SCRIPT
|
||||
primary_component = HIEROPHANT_ANSIBLE
|
||||
sort_priority = 10
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Allows you to fire energy rays at target locations.<br><b>Maximum 5 chants.</b>"
|
||||
var/static/list/nzcrentr_insults = list("You're not very good at aiming.", "You hunt badly.", "What a waste of energy.", "Almost funny to watch.",
|
||||
"Boss says </span><span class='heavy_brass'>\"Click something, you idiot!\"</span><span class='nzcrentr'>.", "Stop wasting power if you can't aim.")
|
||||
|
||||
/datum/clockwork_scripture/channeled/volt_blaster/chant_effects(chant_number)
|
||||
slab.busy = null
|
||||
var/datum/clockwork_scripture/ranged_ability/volt_ray/ray = new
|
||||
ray.slab = slab
|
||||
ray.invoker = invoker
|
||||
var/turf/T = get_turf(invoker)
|
||||
if(!ray.run_scripture() && slab && invoker)
|
||||
if(can_recite() && T == get_turf(invoker))
|
||||
to_chat(invoker, "<span class='nzcrentr'>\"[text2ratvar(pick(nzcrentr_insults))]\"</span>")
|
||||
else
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/obj/effect/ebeam/volt_ray
|
||||
name = "volt_ray"
|
||||
layer = LYING_MOB_LAYER
|
||||
|
||||
/datum/clockwork_scripture/ranged_ability/volt_ray
|
||||
name = "Volt Ray"
|
||||
slab_overlay = "volt"
|
||||
allow_mobility = FALSE
|
||||
ranged_type = /obj/effect/proc_holder/slab/volt
|
||||
ranged_message = "<span class='nzcrentr_small'><i>You charge the clockwork slab with shocking might.</i>\n\
|
||||
<b>Left-click a target to fire, quickly!</b></span>"
|
||||
timeout_time = 20
|
||||
|
||||
@@ -343,7 +343,7 @@
|
||||
icon = 'icons/obj/items_and_weapons.dmi'
|
||||
icon_state = "disintegrate"
|
||||
item_state = null
|
||||
item_flags = NEEDS_PERMIT | ABSTRACT | DROPDEL | NO_ATTACK_CHAIN_SOFT_STAMCRIT
|
||||
item_flags = NEEDS_PERMIT | ABSTRACT | DROPDEL
|
||||
|
||||
w_class = WEIGHT_CLASS_HUGE
|
||||
throwforce = 0
|
||||
|
||||
@@ -116,24 +116,11 @@
|
||||
/mob/living/carbon/true_devil/get_ear_protection()
|
||||
return 2
|
||||
|
||||
|
||||
/mob/living/carbon/true_devil/attacked_by(obj/item/I, mob/living/user, def_zone, attackchain_flags = NONE, damage_multiplier = 1)
|
||||
var/weakness = check_weakness(I, user)
|
||||
apply_damage(I.force * weakness * damage_multiplier, I.damtype, def_zone)
|
||||
var/message_verb = ""
|
||||
if(I.attack_verb && I.attack_verb.len)
|
||||
message_verb = "[pick(I.attack_verb)]"
|
||||
else if(I.force)
|
||||
message_verb = "attacked"
|
||||
|
||||
var/attack_message = "[src] has been [message_verb] with [I]."
|
||||
if(user)
|
||||
user.do_attack_animation(src)
|
||||
if(user in viewers(src, null))
|
||||
attack_message = "[user] has [message_verb] [src] with [I]!"
|
||||
if(message_verb)
|
||||
visible_message("<span class='danger'>[attack_message]</span>",
|
||||
"<span class='userdanger'>[attack_message]</span>", null, COMBAT_MESSAGE_RANGE)
|
||||
var/totitemdamage = pre_attacked_by(I, user)
|
||||
totitemdamage *= check_weakness(I, user)
|
||||
apply_damage(totitemdamage, I.damtype, def_zone)
|
||||
send_item_attack_message(I, user, null, totitemdamage)
|
||||
return TRUE
|
||||
|
||||
/mob/living/carbon/true_devil/singularity_act()
|
||||
|
||||
@@ -66,6 +66,16 @@
|
||||
crate_name = "shaft miner starter kit"
|
||||
crate_type = /obj/structure/closet/crate/secure
|
||||
|
||||
/datum/supply_pack/service/snowmobile
|
||||
name = "Snowmobile kit"
|
||||
desc = "trapped on a frigid wasteland? need to get around fast? purchase a refurbished snowmobile, with a FREE 10 microsecond warranty!"
|
||||
cost = 1500 // 1000 points cheaper than ATV
|
||||
contains = list(/obj/vehicle/ridden/atv/snowmobile = 1,
|
||||
/obj/item/key = 1,
|
||||
/obj/item/clothing/mask/gas/explorer = 1)
|
||||
crate_name = "Snowmobile kit"
|
||||
crate_type = /obj/structure/closet/crate/large
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////// Chef, Botanist, Bartender ////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -743,4 +743,9 @@ GLOBAL_LIST_EMPTY(asset_datums)
|
||||
"dna_discovered.gif" = 'html/dna_discovered.gif',
|
||||
"dna_undiscovered.gif" = 'html/dna_undiscovered.gif',
|
||||
"dna_extra.gif" = 'html/dna_extra.gif'
|
||||
)
|
||||
)
|
||||
|
||||
/datum/asset/simple/vv
|
||||
assets = list(
|
||||
"view_variables.css" = 'html/admin/view_variables.css'
|
||||
)
|
||||
|
||||
@@ -2572,8 +2572,8 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
current_tab = text2num(href_list["tab"])
|
||||
if(href_list["preference"] == "gear")
|
||||
if(href_list["clear_loadout"])
|
||||
LAZYCLEARLIST(chosen_gear)
|
||||
gear_points = initial(gear_points)
|
||||
chosen_gear = list()
|
||||
gear_points = CONFIG_GET(number/initial_gear_points)
|
||||
save_preferences()
|
||||
if(href_list["select_category"])
|
||||
for(var/i in GLOB.loadout_items)
|
||||
@@ -2585,7 +2585,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
return
|
||||
var/toggle = text2num(href_list["toggle_gear"])
|
||||
if(!toggle && (G.type in chosen_gear))//toggling off and the item effectively is in chosen gear)
|
||||
LAZYREMOVE(chosen_gear, G.type)
|
||||
chosen_gear -= G.type
|
||||
gear_points += initial(G.cost)
|
||||
else if(toggle && (!(is_type_in_ref_list(G, chosen_gear))))
|
||||
if(!is_loadout_slot_available(G.category))
|
||||
@@ -2595,7 +2595,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
to_chat(user, "<span class='danger'>This is an item intended for donator use only. You are not authorized to use this item.</span>")
|
||||
return
|
||||
if(gear_points >= initial(G.cost))
|
||||
LAZYADD(chosen_gear, G.type)
|
||||
chosen_gear += G.type
|
||||
gear_points -= initial(G.cost)
|
||||
|
||||
ShowChoices(user)
|
||||
|
||||
@@ -434,3 +434,4 @@
|
||||
desc = "A symbol of discipline, honor, and lots and lots of removal of some type of skewered food."
|
||||
icon_state = "russobluecamohat"
|
||||
item_state = "russobluecamohat"
|
||||
dynamic_hair_suffix = ""
|
||||
|
||||
@@ -40,9 +40,6 @@
|
||||
return ..()
|
||||
return ..()
|
||||
|
||||
/obj/item/holo/esword/attack(target as mob, mob/user as mob)
|
||||
..()
|
||||
|
||||
/obj/item/holo/esword/Initialize()
|
||||
. = ..()
|
||||
saber_color = pick("red","blue","green","purple")
|
||||
|
||||
@@ -205,6 +205,11 @@
|
||||
popup.set_content(dat)
|
||||
popup.open()
|
||||
|
||||
/obj/machinery/biogenerator/AltClick(mob/living/user)
|
||||
. = ..()
|
||||
if(istype(user) && user.canUseTopic(src, BE_CLOSE, FALSE, NO_TK))
|
||||
detach(user)
|
||||
|
||||
/obj/machinery/biogenerator/proc/activate()
|
||||
if (usr.stat != CONSCIOUS)
|
||||
return
|
||||
@@ -293,9 +298,9 @@
|
||||
update_icon()
|
||||
return .
|
||||
|
||||
/obj/machinery/biogenerator/proc/detach()
|
||||
/obj/machinery/biogenerator/proc/detach(mob/living/user)
|
||||
if(beaker)
|
||||
beaker.forceMove(drop_location())
|
||||
user.put_in_hands(beaker)
|
||||
beaker = null
|
||||
update_icon()
|
||||
|
||||
@@ -310,7 +315,7 @@
|
||||
updateUsrDialog()
|
||||
|
||||
else if(href_list["detach"])
|
||||
detach()
|
||||
detach(usr)
|
||||
updateUsrDialog()
|
||||
|
||||
else if(href_list["create"])
|
||||
|
||||
@@ -189,6 +189,26 @@
|
||||
name = "Coffee House"
|
||||
icon_state = "hair_coffeehouse"
|
||||
|
||||
/datum/sprite_accessory/hair/cornrows1
|
||||
name = "Cornrows"
|
||||
icon_state = "hair_cornrows"
|
||||
|
||||
/datum/sprite_accessory/hair/cornrows2
|
||||
name = "Cornrows 2"
|
||||
icon_state = "hair_cornrows2"
|
||||
|
||||
/datum/sprite_accessory/hair/cornrowbun
|
||||
name = "Cornrow Bun"
|
||||
icon_state = "hair_cornrowbun"
|
||||
|
||||
/datum/sprite_accessory/hair/cornrowbraid
|
||||
name = "Cornrow Braid"
|
||||
icon_state = "hair_cornrowbraid"
|
||||
|
||||
/datum/sprite_accessory/hair/cornrowdualtail
|
||||
name = "Cornrow Tail"
|
||||
icon_state = "hair_cornrowtail"
|
||||
|
||||
/datum/sprite_accessory/hair/country
|
||||
name = "Country"
|
||||
icon_state = "hair_country"
|
||||
|
||||
@@ -280,25 +280,15 @@
|
||||
. = ..()
|
||||
C.faction |= "plants"
|
||||
C.faction |= "vines"
|
||||
C.AddElement(/datum/element/photosynthesis)
|
||||
|
||||
/datum/species/golem/wood/on_species_loss(mob/living/carbon/C)
|
||||
. = ..()
|
||||
C.faction -= "plants"
|
||||
C.faction -= "vines"
|
||||
C.RemoveElement(/datum/element/photosynthesis)
|
||||
|
||||
/datum/species/golem/wood/spec_life(mob/living/carbon/human/H)
|
||||
if(H.stat == DEAD)
|
||||
return
|
||||
var/light_amount = 0 //how much light there is in the place, affects receiving nutrition and healing
|
||||
if(isturf(H.loc)) //else, there's considered to be no light
|
||||
var/turf/T = H.loc
|
||||
light_amount = min(1,T.get_lumcount()) - 0.5
|
||||
H.adjust_nutrition(light_amount * 4, NUTRITION_LEVEL_FULL)
|
||||
if(light_amount > 0.2) //if there's enough light, heal
|
||||
H.heal_overall_damage(1,1)
|
||||
H.adjustToxLoss(-1)
|
||||
H.adjustOxyLoss(-1)
|
||||
|
||||
if(H.nutrition < NUTRITION_LEVEL_STARVING + 50)
|
||||
H.take_overall_damage(2,0)
|
||||
|
||||
|
||||
@@ -14,34 +14,24 @@
|
||||
liked_food = VEGETABLES | FRUIT | GRAIN
|
||||
species_language_holder = /datum/language_holder/sylvan
|
||||
var/light_nutrition_gain_factor = 4
|
||||
var/light_toxheal = 1
|
||||
var/light_oxyheal = 1
|
||||
var/light_burnheal = 1
|
||||
var/light_bruteheal = 1
|
||||
var/light_toxheal = -1
|
||||
var/light_oxyheal = -1
|
||||
var/light_burnheal = -1
|
||||
var/light_bruteheal = -1
|
||||
|
||||
/datum/species/pod/on_species_gain(mob/living/carbon/C, datum/species/old_species)
|
||||
. = ..()
|
||||
C.faction |= "plants"
|
||||
C.faction |= "vines"
|
||||
C.AddElement(/datum/element/photosynthesis, light_bruteheal, light_burnheal, light_toxheal, light_oxyheal, light_nutrition_gain_factor)
|
||||
|
||||
/datum/species/pod/on_species_loss(mob/living/carbon/C)
|
||||
. = ..()
|
||||
C.faction -= "plants"
|
||||
C.faction -= "vines"
|
||||
C.RemoveElement(/datum/element/photosynthesis, light_bruteheal, light_burnheal, light_toxheal, light_oxyheal, light_nutrition_gain_factor)
|
||||
|
||||
/datum/species/pod/spec_life(mob/living/carbon/human/H)
|
||||
if(H.stat == DEAD)
|
||||
return
|
||||
var/light_amount = 0 //how much light there is in the place, affects receiving nutrition and healing
|
||||
if(isturf(H.loc)) //else, there's considered to be no light
|
||||
var/turf/T = H.loc
|
||||
light_amount = min(1,T.get_lumcount()) - 0.5
|
||||
H.adjust_nutrition(light_amount * light_nutrition_gain_factor, NUTRITION_LEVEL_FULL)
|
||||
if(light_amount > 0.2) //if there's enough light, heal
|
||||
H.heal_overall_damage(light_bruteheal, light_burnheal)
|
||||
H.adjustToxLoss(-light_toxheal)
|
||||
H.adjustOxyLoss(-light_oxyheal)
|
||||
|
||||
if(H.nutrition < NUTRITION_LEVEL_STARVING + 50)
|
||||
H.take_overall_damage(2,0)
|
||||
|
||||
@@ -77,9 +67,9 @@
|
||||
mutant_bodyparts = list("mcolor" = "FFF","mcolor2" = "FFF","mcolor3" = "FFF", "mam_snouts" = "Husky", "mam_tail" = "Husky", "mam_ears" = "Husky", "mam_body_markings" = "Husky", "taur" = "None", "legs" = "Normal Legs")
|
||||
limbs_id = "pod"
|
||||
light_nutrition_gain_factor = 3
|
||||
light_bruteheal = 0.2
|
||||
light_burnheal = 0.2
|
||||
light_toxheal = 0.7
|
||||
light_bruteheal = -0.2
|
||||
light_burnheal = -0.2
|
||||
light_toxheal = -0.7
|
||||
|
||||
/datum/species/pod/pseudo_weak/spec_death(gibbed, mob/living/carbon/human/H)
|
||||
if(H)
|
||||
|
||||
@@ -15,16 +15,13 @@
|
||||
dangerous_existence = 1
|
||||
mutanteyes = /obj/item/organ/eyes/night_vision
|
||||
|
||||
/datum/species/shadow/on_species_gain(mob/living/carbon/C, datum/species/old_species)
|
||||
. = ..()
|
||||
C.AddElement(/datum/element/photosynthesis, 1, 1, 0, 0, 0, 0, SHADOW_SPECIES_LIGHT_THRESHOLD, SHADOW_SPECIES_LIGHT_THRESHOLD)
|
||||
|
||||
/datum/species/shadow/spec_life(mob/living/carbon/human/H)
|
||||
var/turf/T = H.loc
|
||||
if(istype(T))
|
||||
var/light_amount = T.get_lumcount()
|
||||
|
||||
if(light_amount > SHADOW_SPECIES_LIGHT_THRESHOLD) //if there's enough light, start dying
|
||||
H.take_overall_damage(1,1)
|
||||
else if (light_amount < SHADOW_SPECIES_LIGHT_THRESHOLD) //heal in the dark
|
||||
H.heal_overall_damage(1,1)
|
||||
/datum/species/shadow/on_species_loss(mob/living/carbon/C)
|
||||
. = ..()
|
||||
C.RemoveElement(/datum/element/photosynthesis, 1, 1, 0, 0, 0, 0, SHADOW_SPECIES_LIGHT_THRESHOLD, SHADOW_SPECIES_LIGHT_THRESHOLD)
|
||||
|
||||
/datum/species/shadow/check_roundstart_eligible()
|
||||
if(SSevents.holidays && SSevents.holidays[HALLOWEEN])
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
|
||||
typing_indicator_enabled = TRUE
|
||||
|
||||
var/last_click_move = 0 // Stores the previous next_move value.
|
||||
|
||||
var/resize = 1 //Badminnery resize
|
||||
var/lastattacker = null
|
||||
var/lastattackerckey = null
|
||||
|
||||
@@ -2,15 +2,16 @@
|
||||
name = "A Perfectly Generic Boss Placeholder"
|
||||
desc = ""
|
||||
threat = 10
|
||||
robust_searching = 1
|
||||
robust_searching = TRUE
|
||||
stat_attack = UNCONSCIOUS
|
||||
status_flags = 0
|
||||
status_flags = NONE
|
||||
a_intent = INTENT_HARM
|
||||
gender = NEUTER
|
||||
has_field_of_vision = FALSE //You are a frikkin boss
|
||||
var/list/boss_abilities = list() //list of /datum/action/boss
|
||||
var/datum/boss_active_timed_battle/atb
|
||||
var/point_regen_delay = 1
|
||||
var/point_regen_delay = 20
|
||||
var/point_regen_amount = 1
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/boss/Initialize()
|
||||
@@ -18,6 +19,7 @@
|
||||
|
||||
atb = new()
|
||||
atb.point_regen_delay = point_regen_delay
|
||||
atb.point_regen_amount = point_regen_amount
|
||||
atb.boss = src
|
||||
|
||||
for(var/ab in boss_abilities)
|
||||
@@ -40,6 +42,7 @@
|
||||
required_mobility_flags = NONE
|
||||
var/boss_cost = 100 //Cost of usage for the boss' AI 1-100
|
||||
var/usage_probability = 100
|
||||
var/list/req_statuses //If set, will only trigger if the mob AI status is present in this list.
|
||||
var/mob/living/simple_animal/hostile/boss/boss
|
||||
var/boss_type = /mob/living/simple_animal/hostile/boss
|
||||
var/needs_target = TRUE //Does the boss need to have a target? (Only matters for the AI)
|
||||
@@ -57,7 +60,7 @@
|
||||
. = ..()
|
||||
boss = null
|
||||
|
||||
/datum/action/boss/Trigger()
|
||||
/datum/action/boss/IsAvailable(silent = FALSE)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
@@ -69,6 +72,11 @@
|
||||
return FALSE
|
||||
if(!boss.client && needs_target && !boss.target)
|
||||
return FALSE
|
||||
|
||||
/datum/action/boss/Trigger()
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
if(!boss.atb.spend(boss_cost))
|
||||
return FALSE
|
||||
if(say_when_triggered)
|
||||
@@ -85,7 +93,8 @@
|
||||
//Designed for boss mobs only
|
||||
/datum/boss_active_timed_battle
|
||||
var/list/abilities //a list of /datum/action/boss owned by a boss mob
|
||||
var/point_regen_delay = 5
|
||||
var/point_regen_delay = 20
|
||||
var/point_regen_amount = 1
|
||||
var/max_points = 100
|
||||
var/points = 50 //start with 50 so we can use some abilities but not insta-buttfug somebody
|
||||
var/next_point_time = 0
|
||||
@@ -93,48 +102,45 @@
|
||||
var/highest_cost = 0
|
||||
var/mob/living/simple_animal/hostile/boss/boss
|
||||
|
||||
|
||||
/datum/boss_active_timed_battle/New()
|
||||
..()
|
||||
START_PROCESSING(SSobj, src)
|
||||
|
||||
|
||||
/datum/boss_active_timed_battle/proc/assign_abilities(list/L)
|
||||
if(!L)
|
||||
return 0
|
||||
return FALSE
|
||||
abilities = L
|
||||
for(var/ab in abilities)
|
||||
var/datum/action/boss/AB = ab
|
||||
if(AB.boss_cost > highest_cost)
|
||||
highest_cost = AB.boss_cost
|
||||
|
||||
|
||||
/datum/boss_active_timed_battle/proc/spend(cost)
|
||||
if(cost <= points)
|
||||
points = max(0,points-cost)
|
||||
points -= cost
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
|
||||
/datum/boss_active_timed_battle/proc/refund(cost)
|
||||
points = min(points+cost, max_points)
|
||||
|
||||
|
||||
/datum/boss_active_timed_battle/process()
|
||||
if(world.time >= next_point_time && points < max_points)
|
||||
next_point_time = world.time + point_regen_delay
|
||||
points = min(max_points, ++points) //has to be out of 100
|
||||
points = min(max_points, points + point_regen_amount)
|
||||
|
||||
if(abilities)
|
||||
chance_to_hold_onto_points = highest_cost*0.5
|
||||
if(points != max_points && prob(chance_to_hold_onto_points))
|
||||
return //Let's save our points for a better ability (unless we're at max points, in which case we can't save anymore!)
|
||||
if(!boss.client)
|
||||
abilities = shuffle(abilities)
|
||||
for(var/ab in abilities)
|
||||
var/datum/action/boss/AB = ab
|
||||
if(prob(AB.usage_probability) && AB.Trigger())
|
||||
break
|
||||
if(!abilities)
|
||||
return
|
||||
chance_to_hold_onto_points = highest_cost*0.5
|
||||
if(points != max_points && prob(chance_to_hold_onto_points))
|
||||
return //Let's save our points for a better ability (unless we're at max points, in which case we can't save anymore!)
|
||||
if(!boss.client)
|
||||
abilities = shuffle(abilities)
|
||||
for(var/ab in abilities)
|
||||
var/datum/action/boss/AB = ab
|
||||
if(!boss.client && (!AB.req_statuses || (boss.AIStatus in AB.req_statuses)) && prob(AB.usage_probability) && AB.Trigger())
|
||||
break
|
||||
AB.UpdateButtonIcon(TRUE)
|
||||
|
||||
|
||||
/datum/boss_active_timed_battle/Destroy()
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
boss_cost = 30
|
||||
boss_type = /mob/living/simple_animal/hostile/boss/paper_wizard
|
||||
needs_target = FALSE
|
||||
req_statuses = list(AI_ON)
|
||||
say_when_triggered = "Rise, my creations! Jump off your pages and into this realm!"
|
||||
var/list/summoned_minions = list()
|
||||
var/maximum_stickmen = 6
|
||||
@@ -85,6 +86,7 @@
|
||||
usage_probability = 30
|
||||
boss_cost = 40
|
||||
boss_type = /mob/living/simple_animal/hostile/boss/paper_wizard
|
||||
req_statuses = list(AI_ON)
|
||||
say_when_triggered = ""
|
||||
|
||||
/datum/action/boss/wizard_mimic/Trigger()
|
||||
|
||||
@@ -105,6 +105,7 @@ IGNORE_PROC_IF_NOT_TARGET(attack_slime)
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/curseblob/attacked_by(obj/item/I, mob/living/L, attackchain_flags = NONE, damage_multiplier = 1)
|
||||
if(L != set_target)
|
||||
L.changeNext_move(I.click_delay) //pre_attacked_by not called
|
||||
return
|
||||
return ..()
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
throw_speed = 3
|
||||
throw_range = 5
|
||||
force = 5
|
||||
item_flags = NEEDS_PERMIT | NO_ATTACK_CHAIN_SOFT_STAMCRIT
|
||||
item_flags = NEEDS_PERMIT
|
||||
attack_verb = list("struck", "hit", "bashed")
|
||||
|
||||
var/fire_sound = "gunshot"
|
||||
@@ -140,12 +140,13 @@
|
||||
to_chat(user, "<span class='danger'>*click*</span>")
|
||||
playsound(src, "gun_dry_fire", 30, 1)
|
||||
|
||||
/obj/item/gun/proc/shoot_live_shot(mob/living/user as mob|obj, pointblank = 0, mob/pbtarget = null, message = 1)
|
||||
/obj/item/gun/proc/shoot_live_shot(mob/living/user, pointblank = FALSE, mob/pbtarget, message = 1, stam_cost = 0)
|
||||
if(recoil)
|
||||
shake_camera(user, recoil + 1, recoil)
|
||||
|
||||
if(isliving(user)) //CIT CHANGE - makes gun recoil cause staminaloss
|
||||
user.adjustStaminaLossBuffered(getstamcost(user)*(firing && burst_size >= 2 ? 1/burst_size : 1)) //CIT CHANGE - ditto
|
||||
if(stam_cost) //CIT CHANGE - makes gun recoil cause staminaloss
|
||||
var/safe_cost = clamp(stam_cost, 0, STAMINA_NEAR_CRIT - user.getStaminaLoss())*(firing && burst_size >= 2 ? 1/burst_size : 1)
|
||||
user.adjustStaminaLossBuffered(safe_cost) //CIT CHANGE - ditto
|
||||
|
||||
if(suppressed)
|
||||
playsound(user, fire_sound, 10, 1)
|
||||
@@ -172,9 +173,10 @@
|
||||
return
|
||||
if(firing)
|
||||
return
|
||||
if(IS_STAMCRIT(user)) //respect stamina softcrit
|
||||
to_chat(user, "<span class='warning'>You are too exhausted to fire [src]!</span>")
|
||||
return
|
||||
var/stamloss = user.getStaminaLoss()
|
||||
if(stamloss >= STAMINA_NEAR_SOFTCRIT) //The more tired you are, the less damage you do.
|
||||
var/penalty = (stamloss - STAMINA_NEAR_SOFTCRIT)/(STAMINA_NEAR_CRIT - STAMINA_NEAR_SOFTCRIT)*STAM_CRIT_GUN_DELAY
|
||||
user.changeNext_move(CLICK_CD_RANGE+(CLICK_CD_RANGE*penalty))
|
||||
if(flag) //It's adjacent, is the user, or is on the user's person
|
||||
if(target in user.contents) //can't shoot stuff inside us.
|
||||
return
|
||||
@@ -216,7 +218,7 @@
|
||||
var/loop_counter = 0
|
||||
|
||||
if(user)
|
||||
bonus_spread += getinaccuracy(user) //CIT CHANGE - adds bonus spread while not aiming
|
||||
bonus_spread = getinaccuracy(user, bonus_spread, stamloss) //CIT CHANGE - adds bonus spread while not aiming
|
||||
if(ishuman(user) && user.a_intent == INTENT_HARM && weapon_weight <= WEAPON_LIGHT)
|
||||
var/mob/living/carbon/human/H = user
|
||||
for(var/obj/item/gun/G in H.held_items)
|
||||
@@ -225,9 +227,11 @@
|
||||
else if(G.can_trigger_gun(user))
|
||||
bonus_spread += 24 * G.weapon_weight * G.dualwield_spread_mult
|
||||
loop_counter++
|
||||
addtimer(CALLBACK(G, /obj/item/gun.proc/process_fire, target, user, TRUE, params, null, bonus_spread), loop_counter)
|
||||
var/stam_cost = G.getstamcost(user)
|
||||
addtimer(CALLBACK(G, /obj/item/gun.proc/process_fire, target, user, TRUE, params, null, bonus_spread, stam_cost), loop_counter)
|
||||
|
||||
process_fire(target, user, TRUE, params, null, bonus_spread)
|
||||
var/stam_cost = getstamcost(user)
|
||||
process_fire(target, user, TRUE, params, null, bonus_spread, stam_cost)
|
||||
|
||||
/obj/item/gun/can_trigger_gun(mob/living/user)
|
||||
. = ..()
|
||||
@@ -258,21 +262,21 @@
|
||||
/obj/item/gun/proc/on_cooldown()
|
||||
return busy_action || firing || ((last_fire + fire_delay) > world.time)
|
||||
|
||||
/obj/item/gun/proc/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0)
|
||||
/obj/item/gun/proc/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0, stam_cost = 0)
|
||||
add_fingerprint(user)
|
||||
|
||||
if(on_cooldown())
|
||||
return
|
||||
firing = TRUE
|
||||
. = do_fire(target, user, message, params, zone_override, bonus_spread)
|
||||
. = do_fire(target, user, message, params, zone_override, bonus_spread, stam_cost)
|
||||
firing = FALSE
|
||||
last_fire = world.time
|
||||
|
||||
if(user)
|
||||
user.update_inv_hands()
|
||||
SEND_SIGNAL(user, COMSIG_LIVING_GUN_PROCESS_FIRE, target, params, zone_override)
|
||||
SEND_SIGNAL(user, COMSIG_LIVING_GUN_PROCESS_FIRE, target, params, zone_override, bonus_spread, stam_cost)
|
||||
|
||||
/obj/item/gun/proc/do_fire(atom/target, mob/living/user, message = TRUE, params, zone_override = "", bonus_spread = 0)
|
||||
/obj/item/gun/proc/do_fire(atom/target, mob/living/user, message = TRUE, params, zone_override = "", bonus_spread = 0, stam_cost = 0)
|
||||
var/sprd = 0
|
||||
var/randomized_gun_spread = 0
|
||||
var/rand_spr = rand()
|
||||
@@ -290,7 +294,7 @@
|
||||
sleep(burst_shot_delay)
|
||||
if(QDELETED(src))
|
||||
break
|
||||
do_burst_shot(user, target, message, params, zone_override, sprd, randomized_gun_spread, randomized_bonus_spread, rand_spr, i)
|
||||
do_burst_shot(user, target, message, params, zone_override, sprd, randomized_gun_spread, randomized_bonus_spread, rand_spr, i, stam_cost)
|
||||
else
|
||||
if(chambered)
|
||||
sprd = round((rand() - 0.5) * DUALWIELD_PENALTY_EXTRA_MULTIPLIER * (randomized_gun_spread + randomized_bonus_spread))
|
||||
@@ -300,9 +304,9 @@
|
||||
return
|
||||
else
|
||||
if(get_dist(user, target) <= 1) //Making sure whether the target is in vicinity for the pointblank shot
|
||||
shoot_live_shot(user, 1, target, message)
|
||||
shoot_live_shot(user, 1, target, message, stam_cost)
|
||||
else
|
||||
shoot_live_shot(user, 0, target, message)
|
||||
shoot_live_shot(user, 0, target, message, stam_cost)
|
||||
else
|
||||
shoot_with_empty_chamber(user)
|
||||
return
|
||||
@@ -312,7 +316,7 @@
|
||||
SSblackbox.record_feedback("tally", "gun_fired", 1, type)
|
||||
return TRUE
|
||||
|
||||
/obj/item/gun/proc/do_burst_shot(mob/living/user, atom/target, message = TRUE, params=null, zone_override = "", sprd = 0, randomized_gun_spread = 0, randomized_bonus_spread = 0, rand_spr = 0, iteration = 0)
|
||||
/obj/item/gun/proc/do_burst_shot(mob/living/user, atom/target, message = TRUE, params=null, zone_override = "", sprd = 0, randomized_gun_spread = 0, randomized_bonus_spread = 0, rand_spr = 0, iteration = 0, stam_cost = 0)
|
||||
if(!user || !firing)
|
||||
firing = FALSE
|
||||
return FALSE
|
||||
@@ -336,9 +340,9 @@
|
||||
return FALSE
|
||||
else
|
||||
if(get_dist(user, target) <= 1) //Making sure whether the target is in vicinity for the pointblank shot
|
||||
shoot_live_shot(user, 1, target, message)
|
||||
shoot_live_shot(user, 1, target, message, stam_cost)
|
||||
else
|
||||
shoot_live_shot(user, 0, target, message)
|
||||
shoot_live_shot(user, 0, target, message, stam_cost)
|
||||
if (iteration >= burst_size)
|
||||
firing = FALSE
|
||||
else
|
||||
@@ -349,20 +353,21 @@
|
||||
update_icon()
|
||||
return TRUE
|
||||
|
||||
/obj/item/gun/attack(mob/M as mob, mob/user)
|
||||
/obj/item/gun/attack(mob/living/M, mob/user)
|
||||
if(user.a_intent == INTENT_HARM) //Flogging
|
||||
if(bayonet)
|
||||
M.attackby(bayonet, user)
|
||||
attack_delay_done = TRUE
|
||||
return
|
||||
else
|
||||
return ..()
|
||||
return
|
||||
attack_delay_done = TRUE //we are firing the gun, not bashing people with its butt.
|
||||
|
||||
/obj/item/gun/attack_obj(obj/O, mob/user)
|
||||
if(user.a_intent == INTENT_HARM)
|
||||
if(bayonet)
|
||||
O.attackby(bayonet, user)
|
||||
return
|
||||
return TRUE
|
||||
return ..()
|
||||
|
||||
/obj/item/gun/attackby(obj/item/I, mob/user, params)
|
||||
@@ -498,7 +503,7 @@
|
||||
if(chambered && chambered.BB)
|
||||
chambered.BB.damage *= 5
|
||||
|
||||
process_fire(target, user, TRUE, params)
|
||||
process_fire(target, user, TRUE, params, stam_cost = getstamcost(user))
|
||||
|
||||
/obj/item/gun/proc/unlock() //used in summon guns and as a convience for admins
|
||||
if(pin)
|
||||
@@ -566,7 +571,25 @@
|
||||
chambered = null
|
||||
update_icon()
|
||||
|
||||
/obj/item/gun/proc/getinaccuracy(mob/user)
|
||||
if(SEND_SIGNAL(user, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_INACTIVE))
|
||||
return ((weapon_weight * 25) * inaccuracy_modifier)
|
||||
return 0
|
||||
/obj/item/gun/proc/getinaccuracy(mob/living/user, bonus_spread, stamloss)
|
||||
if(inaccuracy_modifier == 0)
|
||||
return bonus_spread
|
||||
var/base_inaccuracy = weapon_weight * 25 * inaccuracy_modifier
|
||||
var/aiming_delay = 0 //Otherwise aiming would be meaningless for slower guns such as sniper rifles and launchers.
|
||||
if(fire_delay)
|
||||
var/penalty = (last_fire + GUN_AIMING_TIME + fire_delay) - world.time
|
||||
if(penalty > 0) //Yet we only penalize users firing it multiple times in a haste. fire_delay isn't necessarily cumbersomeness.
|
||||
aiming_delay = penalty
|
||||
if(SEND_SIGNAL(user, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_ACTIVE)) //To be removed in favor of something less tactless later.
|
||||
base_inaccuracy /= 1.5
|
||||
if(stamloss > STAMINA_NEAR_SOFTCRIT) //This can null out the above bonus.
|
||||
base_inaccuracy *= 1 + (stamloss - STAMINA_NEAR_SOFTCRIT)/(STAMINA_NEAR_CRIT - STAMINA_NEAR_SOFTCRIT)*0.5
|
||||
var/mult = max((GUN_AIMING_TIME + aiming_delay + user.last_click_move - world.time)/GUN_AIMING_TIME, -0.5) //Yes, there is a bonus for taking time aiming.
|
||||
if(mult < 0) //accurate weapons should provide a proper bonus with negative inaccuracy. the opposite is true too.
|
||||
mult *= 1/inaccuracy_modifier
|
||||
return max(bonus_spread + (base_inaccuracy * mult), 0) //no negative spread.
|
||||
|
||||
/obj/item/gun/proc/getstamcost(mob/living/carbon/user)
|
||||
. = recoil
|
||||
if(user && !user.has_gravity())
|
||||
. = recoil*5
|
||||
|
||||
@@ -365,7 +365,7 @@
|
||||
can_unsuppress = TRUE
|
||||
can_suppress = TRUE
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
inaccuracy_modifier = 0
|
||||
inaccuracy_modifier = 0.5
|
||||
zoomable = TRUE
|
||||
zoom_amt = 10 //Long range, enough to see in front of you, but no tiles behind you.
|
||||
zoom_out_amt = 13
|
||||
|
||||
@@ -132,7 +132,7 @@
|
||||
else
|
||||
qdel(src)
|
||||
|
||||
/obj/item/gun/ballistic/minigun/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0)
|
||||
/obj/item/gun/ballistic/minigun/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0, stam_cost = 0)
|
||||
if(ammo_pack)
|
||||
if(ammo_pack.overheat < ammo_pack.overheat_max)
|
||||
ammo_pack.overheat += burst_size
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
name = "grenade launcher"
|
||||
icon_state = "dshotgun-sawn"
|
||||
item_state = "gun"
|
||||
inaccuracy_modifier = 0
|
||||
inaccuracy_modifier = 0.5
|
||||
mag_type = /obj/item/ammo_box/magazine/internal/grenadelauncher
|
||||
fire_sound = 'sound/weapons/grenadelaunch.ogg'
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
@@ -87,7 +87,7 @@
|
||||
pin = /obj/item/firing_pin/implant/pindicate
|
||||
burst_size = 1
|
||||
fire_delay = 0
|
||||
inaccuracy_modifier = 0
|
||||
inaccuracy_modifier = 0.25
|
||||
casing_ejector = FALSE
|
||||
weapon_weight = WEAPON_HEAVY
|
||||
magazine_wording = "rocket"
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
spread = 0
|
||||
recoil = 0.1
|
||||
casing_ejector = FALSE
|
||||
inaccuracy_modifier = 0
|
||||
inaccuracy_modifier = 0.15
|
||||
dualwield_spread_mult = 1.4
|
||||
weapon_weight = WEAPON_MEDIUM
|
||||
w_class = WEIGHT_CLASS_BULKY
|
||||
@@ -46,7 +46,7 @@
|
||||
return 0
|
||||
. = ..()
|
||||
|
||||
/obj/item/gun/ballistic/automatic/magrifle/shoot_live_shot()
|
||||
/obj/item/gun/ballistic/automatic/magrifle/shoot_live_shot(mob/living/user, pointblank = FALSE, mob/pbtarget, message = 1, stam_cost = 0)
|
||||
var/obj/item/ammo_casing/caseless/magnetic/shot = chambered
|
||||
cell.use(shot.energy_cost)
|
||||
. = ..()
|
||||
|
||||
@@ -102,7 +102,7 @@
|
||||
. = ..()
|
||||
safe_calibers = magazine.caliber
|
||||
|
||||
/obj/item/gun/ballistic/revolver/detective/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0)
|
||||
/obj/item/gun/ballistic/revolver/detective/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0, stam_cost = 0)
|
||||
if(chambered && !(chambered.caliber in safe_calibers))
|
||||
if(prob(70 - (magazine.ammo_count() * 10))) //minimum probability of 10, maximum of 60
|
||||
playsound(user, fire_sound, 50, 1)
|
||||
@@ -242,7 +242,7 @@
|
||||
user.visible_message("<span class='danger'>*click*</span>")
|
||||
playsound(src, "gun_dry_fire", 30, 1)
|
||||
|
||||
/obj/item/gun/ballistic/revolver/russian/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0)
|
||||
/obj/item/gun/ballistic/revolver/russian/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0, stam_cost = 0)
|
||||
add_fingerprint(user)
|
||||
playsound(src, "gun_dry_fire", 30, TRUE)
|
||||
user.visible_message("<span class='danger'>[user.name] tries to fire \the [src] at the same time, but only succeeds at looking like an idiot.</span>", "<span class='danger'>\The [src]'s anti-combat mechanism prevents you from firing it at the same time!</span>")
|
||||
|
||||
@@ -116,7 +116,7 @@
|
||||
icon_state = "moistnugget"
|
||||
item_state = "moistnugget"
|
||||
slot_flags = 0 //no ITEM_SLOT_BACK sprite, alas
|
||||
inaccuracy_modifier = 0
|
||||
inaccuracy_modifier = 0.5
|
||||
mag_type = /obj/item/ammo_box/magazine/internal/boltaction
|
||||
var/bolt_open = FALSE
|
||||
can_bayonet = TRUE
|
||||
@@ -191,7 +191,7 @@
|
||||
/obj/item/gun/ballistic/shotgun/boltaction/enchanted/attack_self()
|
||||
return
|
||||
|
||||
/obj/item/gun/ballistic/shotgun/boltaction/enchanted/shoot_live_shot(mob/living/user as mob|obj, pointblank = 0, mob/pbtarget = null, message = 1)
|
||||
/obj/item/gun/ballistic/shotgun/boltaction/enchanted/shoot_live_shot(mob/living/user, pointblank = FALSE, mob/pbtarget, message = 1, stam_cost = 0)
|
||||
..()
|
||||
if(guns_left)
|
||||
var/obj/item/gun/ballistic/shotgun/boltaction/enchanted/GUN = new gun_type
|
||||
@@ -205,7 +205,7 @@
|
||||
|
||||
// Automatic Shotguns//
|
||||
|
||||
/obj/item/gun/ballistic/shotgun/automatic/shoot_live_shot(mob/living/user as mob|obj)
|
||||
/obj/item/gun/ballistic/shotgun/automatic/shoot_live_shot(mob/living/user, pointblank = FALSE, mob/pbtarget, message = 1, stam_cost = 0)
|
||||
..()
|
||||
src.pump(user)
|
||||
|
||||
|
||||
@@ -127,12 +127,12 @@
|
||||
chambered = null //either way, released the prepared shot
|
||||
recharge_newshot() //try to charge a new shot
|
||||
|
||||
/obj/item/gun/energy/do_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0)
|
||||
/obj/item/gun/energy/do_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0, stam_cost = 0)
|
||||
if(!chambered && can_shoot())
|
||||
process_chamber() // If the gun was drained and then recharged, load a new shot.
|
||||
return ..()
|
||||
|
||||
/obj/item/gun/energy/do_burst_shot(mob/living/user, atom/target, message = TRUE, params = null, zone_override="", sprd = 0, randomized_gun_spread = 0, randomized_bonus_spread = 0, rand_spr = 0, iteration = 0)
|
||||
/obj/item/gun/energy/do_burst_shot(mob/living/user, atom/target, message = TRUE, params = null, zone_override="", sprd = 0, randomized_gun_spread = 0, randomized_bonus_spread = 0, rand_spr = 0, iteration = 0, stam_cost = 0)
|
||||
if(!chambered && can_shoot())
|
||||
process_chamber() // Ditto.
|
||||
return ..()
|
||||
|
||||
@@ -237,7 +237,7 @@
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/obj/item/gun/energy/dueling/process_fire(atom/target, mob/living/user, message, params, zone_override, bonus_spread)
|
||||
/obj/item/gun/energy/dueling/process_fire(atom/target, mob/living/user, message, params, zone_override, bonus_spread = 0, stam_cost = 0)
|
||||
if(duel.state == DUEL_READY)
|
||||
duel.confirmations[src] = TRUE
|
||||
to_chat(user,"<span class='notice'>You confirm your readiness.</span>")
|
||||
|
||||
@@ -110,7 +110,7 @@
|
||||
fail_tick--
|
||||
..()
|
||||
|
||||
/obj/item/gun/energy/e_gun/nuclear/shoot_live_shot()
|
||||
/obj/item/gun/energy/e_gun/nuclear/shoot_live_shot(mob/living/user, pointblank = FALSE, mob/pbtarget, message = 1, stam_cost = 0)
|
||||
failcheck()
|
||||
update_icon()
|
||||
..()
|
||||
|
||||
@@ -60,6 +60,12 @@
|
||||
else
|
||||
cut_overlays()
|
||||
|
||||
/obj/item/gun/energy/kinetic_accelerator/getinaccuracy(mob/living/user, bonus_spread, stamloss)
|
||||
var/old_fire_delay = fire_delay //It's pretty irrelevant tbh but whatever.
|
||||
fire_delay = overheat_time
|
||||
. = ..()
|
||||
fire_delay = old_fire_delay
|
||||
|
||||
/obj/item/gun/energy/kinetic_accelerator/examine(mob/user)
|
||||
. = ..()
|
||||
if(max_mod_capacity)
|
||||
@@ -128,7 +134,7 @@
|
||||
if(!holds_charge)
|
||||
empty()
|
||||
|
||||
/obj/item/gun/energy/kinetic_accelerator/shoot_live_shot()
|
||||
/obj/item/gun/energy/kinetic_accelerator/shoot_live_shot(mob/living/user, pointblank = FALSE, mob/pbtarget, message = 1, stam_cost = 0)
|
||||
. = ..()
|
||||
attempt_reload()
|
||||
|
||||
@@ -207,6 +213,12 @@
|
||||
var/obj/item/gun/energy/kinetic_accelerator/KA = loc
|
||||
KA.modify_projectile(BB)
|
||||
|
||||
/obj/item/gun/energy/kinetic_accelerator/getstamcost(mob/living/carbon/user)
|
||||
if(user && !lavaland_equipment_pressure_check(get_turf(user)))
|
||||
return 0
|
||||
else
|
||||
return ..()
|
||||
|
||||
//Projectiles
|
||||
/obj/item/projectile/kinetic
|
||||
name = "kinetic force"
|
||||
|
||||
@@ -62,7 +62,7 @@
|
||||
slot_flags = ITEM_SLOT_BACK
|
||||
w_class = WEIGHT_CLASS_BULKY
|
||||
weapon_weight = WEAPON_MEDIUM
|
||||
inaccuracy_modifier = 0.5
|
||||
inaccuracy_modifier = 0.7
|
||||
force = 10
|
||||
throwforce = 10
|
||||
cell_type = /obj/item/stock_parts/cell/lascarbine
|
||||
|
||||
@@ -89,7 +89,7 @@
|
||||
suppressed = TRUE
|
||||
ammo_type = list(/obj/item/ammo_casing/energy/bolt)
|
||||
weapon_weight = WEAPON_LIGHT
|
||||
inaccuracy_modifier = 0
|
||||
inaccuracy_modifier = 0.25
|
||||
obj_flags = 0
|
||||
overheat_time = 20
|
||||
holds_charge = TRUE
|
||||
@@ -126,7 +126,7 @@
|
||||
attack_verb = list("attacked", "slashed", "cut", "sliced")
|
||||
force = 12
|
||||
sharpness = IS_SHARP
|
||||
inaccuracy_modifier = 0
|
||||
inaccuracy_modifier = 0.25
|
||||
can_charge = 0
|
||||
|
||||
heat = 3800
|
||||
@@ -182,7 +182,7 @@
|
||||
item_state = null
|
||||
icon_state = "wormhole_projector"
|
||||
pin = null
|
||||
inaccuracy_modifier = 0
|
||||
inaccuracy_modifier = 0.25
|
||||
var/obj/effect/portal/p_blue
|
||||
var/obj/effect/portal/p_orange
|
||||
var/atmos_link = FALSE
|
||||
@@ -318,7 +318,7 @@
|
||||
icon_state = "emitter_carbine"
|
||||
force = 12
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
inaccuracy_modifier = 0
|
||||
inaccuracy_modifier = 0.25
|
||||
cell_type = /obj/item/stock_parts/cell/super
|
||||
ammo_type = list(/obj/item/ammo_casing/energy/emitter)
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
/obj/item/projectile/magic/death, /obj/item/projectile/magic/teleport, /obj/item/projectile/magic/door, /obj/item/projectile/magic/aoe/fireball,
|
||||
/obj/item/projectile/magic/spellblade, /obj/item/projectile/magic/arcane_barrage, /obj/item/projectile/magic/locker)
|
||||
|
||||
/obj/item/gun/magic/staff/chaos/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0)
|
||||
/obj/item/gun/magic/staff/chaos/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0, stam_cost = 0)
|
||||
chambered.projectile_type = pick(allowed_projectile_types)
|
||||
. = ..()
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
throw_speed = 3
|
||||
throw_range = 7
|
||||
force = 4
|
||||
inaccuracy_modifier = 0
|
||||
inaccuracy_modifier = 0.25
|
||||
custom_materials = list(/datum/material/iron=2000)
|
||||
clumsy_check = FALSE
|
||||
fire_sound = 'sound/items/syringeproj.ogg'
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
/obj/item/gun/grenadelauncher/can_shoot()
|
||||
return grenades.len
|
||||
|
||||
/obj/item/gun/grenadelauncher/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0)
|
||||
/obj/item/gun/grenadelauncher/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0, stam_cost = 0)
|
||||
user.visible_message("<span class='danger'>[user] fired a grenade!</span>", \
|
||||
"<span class='danger'>You fire the grenade launcher!</span>")
|
||||
var/obj/item/grenade/F = grenades[1] //Now with less copypasta!
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
on_beam_release(current_target)
|
||||
current_target = null
|
||||
|
||||
/obj/item/gun/medbeam/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0)
|
||||
/obj/item/gun/medbeam/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0, stam_cost = 0)
|
||||
if(isliving(user))
|
||||
add_fingerprint(user)
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
throw_speed = 3
|
||||
throw_range = 7
|
||||
force = 4
|
||||
inaccuracy_modifier = 0
|
||||
inaccuracy_modifier = 0.25
|
||||
custom_materials = list(/datum/material/iron=2000)
|
||||
clumsy_check = 0
|
||||
fire_sound = 'sound/items/syringeproj.ogg'
|
||||
@@ -160,7 +160,7 @@
|
||||
item_state = "blowgun"
|
||||
fire_sound = 'sound/items/syringeproj.ogg'
|
||||
|
||||
/obj/item/gun/syringe/blowgun/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0)
|
||||
/obj/item/gun/syringe/blowgun/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0, stam_cost = 0)
|
||||
visible_message("<span class='danger'>[user] starts aiming with a blowgun!</span>")
|
||||
if(do_after(user, 25, target = src))
|
||||
user.adjustStaminaLoss(20)
|
||||
|
||||
@@ -272,7 +272,7 @@
|
||||
return TRUE
|
||||
|
||||
var/distance = get_dist(T, starting) // Get the distance between the turf shot from and the mob we hit and use that for the calculations.
|
||||
if(check_zone(def_zone) != BODY_ZONE_CHEST)
|
||||
if(def_zone && check_zone(def_zone) != BODY_ZONE_CHEST)
|
||||
def_zone = ran_zone(def_zone, max(100-(7*distance), 5) * zone_accuracy_factor) //Lower accurancy/longer range tradeoff. 7 is a balanced number to use.
|
||||
|
||||
if(isturf(A) && hitsound_wall)
|
||||
@@ -548,7 +548,7 @@
|
||||
var/safety = CEILING(pixel_increment_amount / world.icon_size, 1) * 2 + 1
|
||||
while(T != loc)
|
||||
if(!--safety)
|
||||
CRASH("Projectile took more than pixel incrememnt speed times 2 to get to its location, this is probably something seriously scuffed going on.")
|
||||
CRASH("[type] took too long (allowed: [CEILING(pixel_increment_amount/world.icon_size,1)*2] moves) to get to its location.")
|
||||
step_towards(src, T)
|
||||
if(QDELETED(src))
|
||||
return
|
||||
|
||||
@@ -213,6 +213,11 @@
|
||||
for(var/datum/reagent/R in beaker.reagents.reagent_list)
|
||||
. += "<span class='notice'>- [R.volume] units of [R.name].</span>"
|
||||
|
||||
/obj/machinery/reagentgrinder/AltClick(mob/user)
|
||||
. = ..()
|
||||
if(istype(user) && user.canUseTopic(src, BE_CLOSE, FALSE, NO_TK))
|
||||
replace_beaker(user)
|
||||
|
||||
/obj/machinery/reagentgrinder/proc/eject(mob/user)
|
||||
for(var/i in holdingitems)
|
||||
var/obj/item/O = i
|
||||
|
||||
@@ -25,14 +25,8 @@
|
||||
/obj/item/reagent_containers/pill/attack_self(mob/user)
|
||||
return
|
||||
|
||||
/obj/item/reagent_containers/pill/get_w_volume()
|
||||
switch(reagents.total_volume)
|
||||
if(0 to 9.5)
|
||||
return 1
|
||||
if(9.5 to 25)
|
||||
return DEFAULT_VOLUME_TINY
|
||||
else
|
||||
return DEFAULT_VOLUME_SMALL
|
||||
/obj/item/reagent_containers/pill/get_w_volume() // DEFAULT_VOLUME_TINY at 25u, DEFAULT_VOLUME_SMALL at 50u
|
||||
return DEFAULT_VOLUME_TINY/2 + reagents.total_volume / reagents.maximum_volume * DEFAULT_VOLUME_TINY
|
||||
|
||||
/obj/item/reagent_containers/pill/attack(mob/M, mob/user, def_zone)
|
||||
if(!canconsume(M, user))
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
/obj/machinery/computer/shuttle/snow_taxi
|
||||
name = "snow taxi console"
|
||||
desc = "Used to direct the snow taxi."
|
||||
circuit = /obj/item/circuitboard/computer/snow_taxi
|
||||
shuttleId = "snow_taxi"
|
||||
possible_destinations = "snaxi_nw;snaxi_ne;snaxi_s"
|
||||
no_destination_swap = TRUE
|
||||
@@ -285,7 +285,7 @@
|
||||
if(status == BODYPART_ORGANIC)
|
||||
icon = base_bp_icon || DEFAULT_BODYPART_ICON_ORGANIC
|
||||
else if(status == BODYPART_ROBOTIC)
|
||||
icon = base_bp_icon || DEFAULT_BODYPART_ICON_ROBOTIC
|
||||
icon = DEFAULT_BODYPART_ICON_ROBOTIC
|
||||
|
||||
if(owner)
|
||||
owner.updatehealth()
|
||||
|
||||
@@ -60,3 +60,23 @@
|
||||
turret.pixel_x = 12
|
||||
turret.pixel_y = 4
|
||||
turret.layer = OBJ_LAYER
|
||||
|
||||
/obj/vehicle/ridden/atv/snowmobile
|
||||
name = "snowmobile"
|
||||
desc = "a tracked vehicle designed for use in the snow, it looks like it would have difficulty moving elsewhere, however."
|
||||
icon_state = "snowmobile"
|
||||
|
||||
/obj/vehicle/ridden/atv/snowmobile/Moved()
|
||||
. = ..()
|
||||
var/static/list/snow_typecache = typecacheof(list(/turf/open/floor/plating/asteroid/snow/icemoon, /turf/open/floor/plating/snowed/smoothed/icemoon))
|
||||
var/datum/component/riding/E = LoadComponent(/datum/component/riding)
|
||||
if(snow_typecache[loc.type])
|
||||
E.vehicle_move_delay = 1
|
||||
else
|
||||
E.vehicle_move_delay = 2
|
||||
|
||||
/obj/vehicle/ridden/atv/snowmobile/snowcurity
|
||||
name = "security snowmobile"
|
||||
desc = "for when you want to look like even more of a tool than riding a secway."
|
||||
icon_state = "snowcurity"
|
||||
key_type = /obj/item/key/security
|
||||
|
||||
@@ -51,10 +51,10 @@
|
||||
|
||||
/obj/vehicle/sealed/car/attacked_by(obj/item/I, mob/living/user, attackchain_flags = NONE, damage_multiplier = 1)
|
||||
if(!I.force)
|
||||
return
|
||||
return FALSE
|
||||
if(occupants[user])
|
||||
to_chat(user, "<span class='notice'>Your attack bounces off of the car's padded interior.</span>")
|
||||
return
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/obj/vehicle/sealed/car/attack_hand(mob/living/user)
|
||||
|
||||
@@ -465,7 +465,7 @@
|
||||
log_attack("[key_name(owner)] digested [key_name(M)].")
|
||||
|
||||
// If digested prey is also a pred... anyone inside their bellies gets moved up.
|
||||
if(is_vore_predator(M))
|
||||
if(has_vore_belly(M))
|
||||
M.release_vore_contents(include_absorbed = TRUE, silent = TRUE)
|
||||
|
||||
//Drop all items into the belly
|
||||
|
||||
@@ -73,15 +73,9 @@
|
||||
to_chat(user, "<span class='notice'>They aren't able to be fed.</span>")
|
||||
to_chat(pred, "<span class='notice'>[user] tried to feed you themselves, but you aren't voracious enough to be fed.</span>")
|
||||
return
|
||||
if(!is_vore_predator(pred))
|
||||
to_chat(user, "<span class='notice'>They aren't voracious enough.</span>")
|
||||
return
|
||||
feed_self_to_grabbed(user, pred)
|
||||
|
||||
else if(pred == user) //you click yourself
|
||||
if(!is_vore_predator(src))
|
||||
to_chat(user, "<span class='notice'>You aren't voracious enough.</span>")
|
||||
return
|
||||
feed_grabbed_to_self(user, prey)
|
||||
|
||||
else // click someone other than you/prey
|
||||
@@ -93,9 +87,6 @@
|
||||
to_chat(user, "<span class='notice'>They aren't able to be fed to someone.</span>")
|
||||
to_chat(prey, "<span class='notice'>[user] tried to feed you to [pred], but you aren't able to be fed to them.</span>")
|
||||
return
|
||||
if(!is_vore_predator(pred))
|
||||
to_chat(user, "<span class='notice'>They aren't voracious enough.</span>")
|
||||
return
|
||||
feed_grabbed_to_other(user, prey, pred)
|
||||
//
|
||||
// Eating procs depending on who clicked what
|
||||
@@ -395,7 +386,7 @@
|
||||
return taste_message
|
||||
// Check if an object is capable of eating things, based on vore_organs
|
||||
//
|
||||
/proc/is_vore_predator(var/mob/living/O)
|
||||
/proc/has_vore_belly(var/mob/living/O)
|
||||
if(istype(O))
|
||||
if(O.vore_organs.len > 0)
|
||||
return TRUE
|
||||
|
||||
Reference in New Issue
Block a user