Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Hawk_v3
2019-05-23 22:46:42 +01:00
32 changed files with 1786 additions and 27 deletions

View File

@@ -248,7 +248,7 @@
icon_state = "television"
icon_keyboard = null
icon_screen = "detective_tv"
circuit = null
circuit = /obj/item/weapon/circuitboard/security/tv
light_color = "#3848B3"
light_power_on = 0.5

View File

@@ -553,4 +553,5 @@
icon_state = "laptop"
icon_keyboard = "laptop_key"
icon_screen = "medlaptop"
density = 0
circuit = /obj/item/weapon/circuitboard/med_data/laptop
density = 0

View File

@@ -121,7 +121,7 @@
if(card)
if(checkFace())
if(checkCardCooldown())
makeOffDuty()
makeOnDuty(href_list["switch-to-onduty"])
usr.put_in_hands(card)
card = null
update_icon()

View File

@@ -7,6 +7,7 @@ obj/machinery/recharger
use_power = 1
idle_power_usage = 4
active_power_usage = 40000 //40 kW
var/efficiency = 40000 //will provide the modified power rate when upgraded
var/obj/item/charging = null
var/list/allowed_devices = list(/obj/item/weapon/gun/energy, /obj/item/weapon/melee/baton, /obj/item/modular_computer, /obj/item/weapon/computer_hardware/battery_module, /obj/item/weapon/cell, /obj/item/device/flashlight, /obj/item/device/electronic_assembly, /obj/item/weapon/weldingtool/electric, /obj/item/ammo_magazine/smart, /obj/item/device/flash, /obj/item/ammo_casing/nsfw_batt) //VOREStation Add - NSFW Batteries
var/icon_state_charged = "recharger2"
@@ -68,6 +69,8 @@ obj/machinery/recharger
return
else if(default_deconstruction_crowbar(user, G))
return
else if(default_part_replacement(user, G))
return
/obj/machinery/recharger/attack_hand(mob/user as mob)
if(istype(user,/mob/living/silicon))
@@ -95,7 +98,7 @@ obj/machinery/recharger
var/obj/item/modular_computer/C = charging
if(!C.battery_module.battery.fully_charged())
icon_state = icon_state_charging
C.battery_module.battery.give(active_power_usage*CELLRATE)
C.battery_module.battery.give(CELLRATE*efficiency)
update_use_power(2)
else
icon_state = icon_state_charged
@@ -105,7 +108,7 @@ obj/machinery/recharger
var/obj/item/weapon/computer_hardware/battery_module/BM = charging
if(!BM.battery.fully_charged())
icon_state = icon_state_charging
BM.battery.give(active_power_usage*CELLRATE)
BM.battery.give(CELLRATE*efficiency)
update_use_power(2)
else
icon_state = icon_state_charged
@@ -116,7 +119,7 @@ obj/machinery/recharger
if(istype(C))
if(!C.fully_charged())
icon_state = icon_state_charging
C.give(active_power_usage*CELLRATE)
C.give(CELLRATE*efficiency)
update_use_power(2)
else
icon_state = icon_state_charged
@@ -153,13 +156,20 @@ obj/machinery/recharger
else
icon_state = icon_state_idle
/obj/machinery/recharger/RefreshParts()
var/E = 0
for(var/obj/item/weapon/stock_parts/capacitor/C in component_parts)
E += C.rating
efficiency = active_power_usage * (1+ (E - 1)*0.5)
/obj/machinery/recharger/wallcharger
name = "wall recharger"
icon = 'icons/obj/stationobjs.dmi'
icon_state = "wrecharger0"
plane = TURF_PLANE
layer = ABOVE_TURF_LAYER
active_power_usage = 25000 //25 kW , It's more specialized than the standalone recharger (guns, batons, and flashlights only) so make it more powerful
active_power_usage = 60000 //60 kW , It's more specialized than the standalone recharger (guns, batons, and flashlights only) so make it more powerful
efficiency = 60000
allowed_devices = list(/obj/item/weapon/gun/energy, /obj/item/weapon/gun/magnetic, /obj/item/weapon/melee/baton, /obj/item/device/flashlight, /obj/item/weapon/cell/device)
icon_state_charged = "wrecharger2"
icon_state_charging = "wrecharger1"

View File

@@ -515,7 +515,8 @@
if(M)
S.icon_state = initial(S.icon_state)
S.icon = initial(S.icon)
S.reagents.trans_to_mob(M, S.reagents.total_volume, CHEM_BLOOD)
if(M.can_inject())
S.reagents.trans_to_mob(M, S.reagents.total_volume, CHEM_BLOOD)
M.take_organ_damage(2)
S.visible_message("<span class=\"attack\"> [M] was hit by the syringe!</span>")
break
@@ -661,6 +662,7 @@
occupant_message("<span class=\"alert\">No reagent info gained from [A].</span>")
return 0
occupant_message("Analyzing reagents...")
//VOREStation Block Edit - Start
for(var/datum/reagent/R in A.reagents.reagent_list)
if(R.id in known_reagents)
occupant_message("Reagent \"[R.name]\" already present in database, skipping.")
@@ -669,7 +671,8 @@
send_byjax(chassis.occupant,"msyringegun.browser","reagents_form",get_reagents_form())
else
occupant_message("Reagent \"[R.name]\" unable to be scanned, skipping.")
occupant_message("Analyzis complete.")
//VOREstation Block Edit - End
occupant_message("Analysis complete.")
return 1
/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun/proc/add_known_reagent(r_id,r_name)

View File

@@ -6,7 +6,7 @@
w_class = ITEMSIZE_SMALL
matter = list("glass" = 200)
flags = NOBLUDGEON
var/list/accept_mobs = list(/mob/living/simple_mob/animal/passive/lizard, /mob/living/simple_mob/animal/passive/mouse)
var/list/accept_mobs = list(/mob/living/simple_mob/animal/passive/lizard, /mob/living/simple_mob/animal/passive/mouse, /mob/living/simple_mob/animal/sif/leech, /mob/living/simple_mob/animal/sif/frostfly, /mob/living/simple_mob/animal/sif/glitterfly)
var/contains = 0 // 0 = nothing, 1 = money, 2 = animal, 3 = spiderling
/obj/item/glass_jar/New()
@@ -96,6 +96,12 @@
for(var/mob/M in src)
var/image/victim = image(M.icon, M.icon_state)
victim.pixel_y = 6
victim.color = M.color
if(M.plane == PLANE_LIGHTING_ABOVE) // This will only show up on the ground sprite, due to the HuD being over it, so we need both images.
var/image/victim_glow = image(M.icon, M.icon_state)
victim_glow.pixel_y = 6
victim_glow.color = M.color
underlays += victim_glow
underlays += victim
name = "glass jar with [M]"
desc = "A small jar with [M] inside."

View File

@@ -14,6 +14,10 @@
..()
network = using_map.station_networks
/obj/item/weapon/circuitboard/security/tv
name = T_BOARD("security camera monitor - television")
build_path = /obj/machinery/computer/security/wooden_tv
/obj/item/weapon/circuitboard/security/engineering
name = T_BOARD("engineering camera monitor")
build_path = /obj/machinery/computer/security/engineering

View File

@@ -21,6 +21,10 @@
name = T_BOARD("medical records console")
build_path = /obj/machinery/computer/med_data
/obj/item/weapon/circuitboard/med_data/laptop
name = T_BOARD("medical records laptop")
build_path = /obj/machinery/computer/med_data/laptop
/obj/item/weapon/circuitboard/scan_consolenew
name = T_BOARD("DNA machine")
build_path = /obj/machinery/computer/scan_consolenew

View File

@@ -177,7 +177,8 @@
/obj/item/weapon/gun/projectile/sec,
/obj/item/weapon/gun/projectile/p92x,
/obj/item/taperoll,
/obj/item/weapon/gun/projectile/colt/detective
/obj/item/weapon/gun/projectile/colt/detective,
/obj/item/device/holowarrant
)
/obj/item/weapon/storage/belt/detective
@@ -219,7 +220,8 @@
/obj/item/weapon/flame/lighter,
/obj/item/weapon/reagent_containers/food/snacks/donut/,
/obj/item/ammo_magazine,
/obj/item/weapon/gun/projectile/colt/detective
/obj/item/weapon/gun/projectile/colt/detective,
/obj/item/device/holowarrant
)
/obj/item/weapon/storage/belt/soulstone

View File

@@ -24,7 +24,7 @@
// Step 1, find out what we can see.
/datum/ai_holder/proc/list_targets()
. = hearers(vision_range, holder) - src // Remove ourselves to prevent suicidal decisions.
. = hearers(vision_range, holder) - holder // Remove ourselves to prevent suicidal decisions. ~ SRC is the ai_holder.
var/static/hostile_machines = typecacheof(list(/obj/machinery/porta_turret, /obj/mecha))

View File

@@ -17,7 +17,7 @@
gas_transfer_coefficient = 0.01
permeability_coefficient = 0.02
item_flags = 0
body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|FEET|ARMS
body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|FEET|ARMS|HANDS
allowed = list(/obj/item/weapon/tank/emergency/oxygen, /obj/item/device/flashlight,/obj/item/weapon/gun/energy, /obj/item/weapon/gun/projectile, /obj/item/ammo_magazine, /obj/item/ammo_casing, /obj/item/weapon/melee/baton,/obj/item/weapon/handcuffs)
slowdown = 1.5
armor = list(melee = 65, bullet = 50, laser = 50, energy = 25, bomb = 50, bio = 100, rad = 50)

View File

@@ -42,6 +42,7 @@
switch(suit_style)
if("Engineer")
name = "\improper Engineer's Guild Shroud"
base_name = "\improper Engineer's Guild Shroud"
desc = "This rugged Shroud was created by the Xozi Engineering Guild."
icon_state = "zaddat_engie"
item_state = "zaddat_engie"
@@ -52,6 +53,7 @@
helmet.item_state = "zaddat_engie"
if("Spacer")
name = "\improper Spacer's Guild Shroud"
base_name = "\improper Spacer's Guild Shroud"
desc = "The blue plastic Shroud worn by members of the Zaddat Spacer's Guild."
icon_state = "zaddat_spacer"
item_state = "zaddat_spacer"
@@ -62,6 +64,7 @@
helmet.item_state = "zaddat_spacer"
if("Knight")
name = "\improper Knight's Shroud"
base_name = "\improper Knight's Shroud"
desc = "This distinctive steel-plated Shroud was popularized by the Noble Guild."
icon_state = "zaddat_knight"
item_state = "zaddat_knight"
@@ -72,6 +75,7 @@
helmet.item_state = "zaddat_knight"
if("Fashion")
name = "\improper Avazi House Shroud"
base_name = "\improper Avazi House Shroud"
desc = "The designers of the Avazi Fashion House are among the most renowned in Zaddat society, and their Shroud designs second to none."
icon_state = "zaddat_fashion"
item_state = "zaddat_fashion"
@@ -82,6 +86,7 @@
helmet.item_state = "zaddat_fashion"
if("Bishop")
name = "\improper Bishop-patterned Shroud"
base_name = "\improper Bishop-patterned Shroud"
desc = "The bold designers of the Dzaz Fashion House chose to make this Bishop-themed Shroud design as a commentary on the symbiotic nature of Vanax and human culture. Allegedly."
icon_state = "zaddat_bishop"
item_state = "zaddat_bishop"
@@ -92,6 +97,7 @@
helmet.item_state = "zaddat_bishop"
if("Rugged")
name = "rugged Shroud"
base_name = "rugged Shroud"
desc = "This Shroud was patterned after from First Contact era human voidsuits."
icon_state = "zaddat_rugged"
item_state = "zaddat_rugged"

View File

@@ -269,6 +269,20 @@ the artifact triggers the rage.
return FALSE
return TRUE
/datum/modifier/poisoned/paralysis
desc = "You have poison inside of you. It will cause harm over a long span of time if not cured, and may cause temporary paralysis."
on_created_text = "<span class='warning'>You feel incredibly weak...</span>"
damage_per_tick = 0.75
/datum/modifier/poisoned/paralysis/tick()
..()
if(prob(5))
holder.Paralyse(3)
/datum/modifier/poisoned/paralysis/on_applied()
..()
holder.Paralyse(4)
// Pulse modifier.
/datum/modifier/false_pulse
name = "false pulse"
@@ -278,4 +292,4 @@ the artifact triggers the rage.
on_expired_text = "<span class='notice'>You feel.. different.</span>"
stacks = MODIFIER_STACK_EXTEND
pulse_set_level = PULSE_NORM
pulse_set_level = PULSE_NORM

View File

@@ -104,6 +104,10 @@ var/list/holder_mob_icon_cache = list()
/obj/item/weapon/holder/borer
origin_tech = list(TECH_BIO = 6)
/obj/item/weapon/holder/leech
color = "#003366"
origin_tech = list(TECH_BIO = 5, TECH_PHORON = 2)
/obj/item/weapon/holder/fish
attack_verb = list("fished", "disrespected", "smacked", "smackereled")
hitsound = 'sound/effects/slime_squish.ogg'

View File

@@ -137,7 +137,7 @@
/mob/living/bot/secbot/attackby(var/obj/item/O, var/mob/user)
var/curhealth = health
. = ..()
if(health < curhealth)
if(health < curhealth && on == 1)
react_to_attack(user)
/mob/living/bot/secbot/bullet_act(var/obj/item/projectile/P)

View File

@@ -27,6 +27,8 @@
if(!temp || !temp.is_usable())
H << "<font color='red'>You can't use your hand.</font>"
return
if(H.lying)
return
M.break_cloak()
..()
@@ -113,7 +115,7 @@
spawn(30)
cpr_time = 1
H.visible_message("<span class='danger'>\The [H] is trying perform CPR on \the [src]!</span>")
H.visible_message("<span class='danger'>\The [H] is trying to perform CPR on \the [src]!</span>")
if(!do_after(H, 30))
return
@@ -143,6 +145,7 @@
var/obj/item/weapon/grab/G = new /obj/item/weapon/grab(M, src)
if(buckled)
M << "<span class='notice'>You cannot grab [src], [TT.he] is buckled in!</span>"
return
if(!G) //the grab will delete itself in New if affecting is anchored
return
M.put_in_active_hand(G)

View File

@@ -47,6 +47,7 @@
var/movement_sound = null // If set, will play this sound when it moves on its own will.
var/turn_sound = null // If set, plays the sound when the mob's dir changes in most cases.
var/movement_shake_radius = 0 // If set, moving will shake the camera of all living mobs within this radius slightly.
var/aquatic_movement = 0 // If set, the mob will move through fluids with no hinderance.
//Mob interaction
var/response_help = "tries to help" // If clicked on help intent
@@ -230,8 +231,11 @@
// Turf related slowdown
var/turf/T = get_turf(src)
if(T && T.movement_cost && !hovering) // Flying mobs ignore turf-based slowdown.
tally += T.movement_cost
if(T && T.movement_cost && !hovering) // Flying mobs ignore turf-based slowdown. Aquatic mobs ignore water slowdown, and can gain bonus speed in it.
if(istype(T,/turf/simulated/floor/water) && aquatic_movement)
tally -= aquatic_movement - 1
else
tally += T.movement_cost
if(purge)//Purged creatures will move more slowly. The more time before their purge stops, the slower they'll move.
if(tally <= 0)

View File

@@ -0,0 +1,58 @@
// Crystal-feather "ducks" are rather weak, but will become aggressive if you have food.
/datum/category_item/catalogue/fauna/crystalduck
name = "Sivian Fauna - Crystal-Feather Duck"
desc = "Classification: S Anatidae vitriae \
<br><br>\
Small, asocial omnivores with glistening, razor-thin feathers valued for their use as a reflective glitter by poachers. \
The Crystal-Feather Duck commonly forms at most a familial group of four, a male, two females, and a single 'chosen' young. Primarily detrivorous browsers, \
supplementing their diet with animals living below thinner shore ice-sheets. \
Family units have been observed to form gangs and scavenge from Sivian domeciles and \
various food transports during stressful months. \
It is advised to seal and hide any form of food near even lone individuals, as they will become \
increasingly aggressive."
value = CATALOGUER_REWARD_EASY
/mob/living/simple_mob/animal/sif/duck
name = "crystal-feather duck"
desc = "A glittering flightless bird."
tt_desc = "S Anatidae vitriae"
catalogue_data = list(/datum/category_item/catalogue/fauna/crystalduck)
faction = "duck"
icon_state = "duck"
icon_living = "duck"
icon_dead = "duck_dead"
icon = 'icons/mob/animal.dmi'
has_eye_glow = TRUE
maxHealth = 50
health = 50
movement_cooldown = 0
melee_damage_lower = 2
melee_damage_upper = 10
base_attack_cooldown = 1 SECOND
attack_edge = 1 // Razor-edged wings, and 'claws' made for digging through ice.
attacktext = list("nipped", "bit", "cut", "clawed")
say_list_type = /datum/say_list/duck
ai_holder_type = /datum/ai_holder/simple_mob/retaliate/cooperative
/datum/say_list/duck
speak = list("Wack!", "Wock?", "Wack.")
emote_see = list("ruffles its wings","looks around", "preens itself")
emote_hear = list("quacks", "giggles")
/mob/living/simple_mob/animal/sif/duck/IIsAlly(mob/living/L)
. = ..()
var/has_food = FALSE
for(var/obj/item/I in L.get_contents()) // Do they have food?
if(istype(I, /obj/item/weapon/reagent_containers/food))
has_food = TRUE
break
if(has_food) // Yes? Gimme the food.
return FALSE

View File

@@ -0,0 +1,169 @@
// Frostflies are large, flightless insects with glittering wings, used as a means of deploying their gaseous self-defense mechanism.
/datum/category_item/catalogue/fauna/frostfly
name = "Sivian Fauna - Frostfly"
desc = "Classification: S Carabidae glacios \
<br><br>\
A large, flightless insectoid with bioluminescent wings. \
Frostflies utilize their vestigial wings as a method of dispersing a chemical that produces a rapid \
endothermic reaction on contact with the air, resulting in the flash-freezing of nearby materials. \
<br>\
Carnivorous in nature, they use their cryogenic compounds to trap smaller prey, or frighten predators. \
Individuals are known to slalom when facing other creatures, dispersing clouds of gas, and spitting \
condensed globs of the compound. These masses of mucous and ice seem to be intended to impede movement. \
<br>\
Travelers are advised to avoid frostfly swarms whenever possible, as they will become aggressive \
to anything other than Diyaabs, which they seem to have formed a tangential symbiosis with."
value = CATALOGUER_REWARD_MEDIUM
/mob/living/simple_mob/animal/sif/frostfly
name = "frostfly"
desc = "A large insect with glittering wings."
tt_desc = "S Carabidae glacios"
catalogue_data = list(/datum/category_item/catalogue/fauna/frostfly)
faction = "diyaab"
icon_state = "firefly"
icon_living = "firefly"
icon_dead = "firefly_dead"
icon_rest = "firefly_dead"
icon = 'icons/mob/animal.dmi'
has_eye_glow = TRUE
maxHealth = 65
health = 65
pass_flags = PASSTABLE
var/energy = 100
var/max_energy = 100
movement_cooldown = 0.5
melee_damage_lower = 5
melee_damage_upper = 10
base_attack_cooldown = 1.5 SECONDS
attacktext = list("nipped", "bit", "pinched")
projectiletype = /obj/item/projectile/energy/blob/freezing
special_attack_cooldown = 5 SECONDS
special_attack_min_range = 0
special_attack_max_range = 4
armor = list(
"melee" = 20,
"bullet" = 10,
"laser" = 5,
"energy" = 0,
"bomb" = 10,
"bio" = 100,
"rad" = 100
)
// The frostfly's body is incredibly cold at all times, natural resistance to things trying to burn it.
armor_soak = list(
"melee" = 0,
"bullet" = 0,
"laser" = 15,
"energy" = 0,
"bomb" = 0,
"bio" = 0,
"rad" = 0
)
var/datum/effect/effect/system/smoke_spread/frost/smoke_special
say_list_type = /datum/say_list/frostfly
ai_holder_type = /datum/ai_holder/simple_mob/ranged/kiting/threatening/frostfly
/mob/living/simple_mob/animal/sif/frostfly/get_cold_protection()
return 1 // It literally produces a cryogenic mist inside itself. Cold doesn't bother it.
/mob/living/simple_mob/animal/sif/frostfly/Initialize()
..()
smoke_special = new
verbs += /mob/living/proc/ventcrawl
verbs += /mob/living/proc/hide
/datum/say_list/frostfly
speak = list("Zzzz.", "Kss.", "Zzt?")
emote_see = list("flutters its wings","looks around", "rubs its mandibles")
emote_hear = list("chitters", "clicks", "chirps")
say_understood = list("Ssst.")
say_cannot = list("Zzrt.")
say_maybe_target = list("Ki?")
say_got_target = list("Ksst!")
say_threaten = list("Kszsz.","Kszzt...","Kzzi!")
say_stand_down = list("Sss.","Zt.","! clicks.")
say_escalate = list("Rszt!")
threaten_sound = 'sound/effects/refill.ogg'
stand_down_sound = 'sound/effects/sparks5.ogg'
/mob/living/simple_mob/animal/sif/frostfly/handle_special()
..()
if(energy < max_energy)
energy++
/mob/living/simple_mob/animal/sif/frostfly/Stat()
..()
if(client.statpanel == "Status")
statpanel("Status")
if(emergency_shuttle)
var/eta_status = emergency_shuttle.get_status_panel_eta()
if(eta_status)
stat(null, eta_status)
stat("Energy", energy)
/mob/living/simple_mob/animal/sif/frostfly/should_special_attack(atom/A)
if(energy >= 20)
return TRUE
return FALSE
/mob/living/simple_mob/animal/sif/frostfly/do_special_attack(atom/A)
. = TRUE
switch(a_intent)
if(I_DISARM)
if(energy < 20)
return FALSE
energy -= 20
if(smoke_special)
smoke_special.set_up(7,0,src)
smoke_special.start()
return TRUE
return FALSE
/datum/ai_holder/simple_mob/ranged/kiting/threatening/frostfly
can_flee = TRUE
dying_threshold = 0.5
flee_when_outmatched = TRUE
run_if_this_close = 3
/datum/ai_holder/simple_mob/ranged/kiting/threatening/frostfly/special_flee_check()
var/mob/living/simple_mob/animal/sif/frostfly/F = holder
if(F.energy < F.max_energy * 0.2)
return TRUE
return FALSE
/datum/ai_holder/simple_mob/ranged/kiting/threatening/frostfly/pre_special_attack(atom/A)
if(isliving(A))
holder.a_intent = I_DISARM
else
holder.a_intent = I_HURT
/datum/ai_holder/simple_mob/ranged/kiting/threatening/frostfly/post_ranged_attack(atom/A)
var/mob/living/simple_mob/animal/sif/frostfly/F = holder
if(istype(A,/mob/living))
var/new_dir = turn(F.dir, -90)
if(prob(50))
new_dir = turn(F.dir, 90)
holder.IMove(get_step(holder, new_dir))
holder.face_atom(A)
F.energy = max(0, F.energy - 1) // The AI will eventually flee.

View File

@@ -0,0 +1,102 @@
// Glitterflies! Little butterfly-like creatures that float around and be cute.
/datum/category_item/catalogue/fauna/glitterfly
name = "Sivian Fauna - Glitterfly"
desc = "Classification: S Lepidoptera adamas \
<br><br>\
An herbivorous insectoid beloved for its glittering wings. \
<br>\
The creature has four wings mirrored laterally, which reflect \
the ambient light to provide a measure of camouflage."
value = CATALOGUER_REWARD_TRIVIAL
/datum/category_item/catalogue/fauna/glitterfly_rare
name = "Sivian Fauna - Adela's Glitterfly"
desc = "Classification: S Lepidoptera adamas \
<br><br>\
This mutation of the glitterfly is incredibly rare, one of the few and first known individuals\
known to exist with it is owned by little-known Sivian ecologist Adela Svingelm, and kept within its own \
climate-controlled habitat."
value = CATALOGUER_REWARD_HARD
/mob/living/simple_mob/animal/sif/glitterfly
name = "glitterfly"
desc = "A shiny butterfly!"
tt_desc = "S Lepidoptera adamas"
catalogue_data = list(/datum/category_item/catalogue/fauna/glitterfly)
faction = "neutral"
icon_state = "butterfly"
icon_living = "butterfly"
icon_dead = "butterfly_dead"
icon = 'icons/mob/animal.dmi'
maxHealth = 10
health = 10
movement_cooldown = -1
hovering = TRUE
melee_damage_lower = 1
melee_damage_upper = 2
attack_armor_pen = 80
attack_sharp = TRUE
density = FALSE // Non-dense, so things can walk through their groups unhindered.
pass_flags = PASSTABLE
attacktext = list("bit", "buffeted", "slashed")
say_list_type = /datum/say_list/glitterfly
ai_holder_type = /datum/ai_holder/simple_mob/melee/evasive/glitterfly
/mob/living/simple_mob/animal/sif/glitterfly/Initialize()
..()
var/colorlist = list(rgb(rand(100,255), rand(100,255), rand(100,255)) = 10, rgb(rand(5,100), rand(5,100), rand(5,100)) = 2, "#222222" = 1)
color = pickweight(colorlist)
default_pixel_y = rand(5,12)
pixel_y = default_pixel_y
/mob/living/simple_mob/animal/sif/glitterfly/rare
name = "sparkling glitterfly"
desc = "An incredibly shiny butterfly!"
catalogue_data = list(/datum/category_item/catalogue/fauna/glitterfly, /datum/category_item/catalogue/fauna/glitterfly_rare)
maxHealth = 30
health = 30
movement_cooldown = -2
melee_damage_upper = 5
plane = PLANE_LIGHTING_ABOVE
/mob/living/simple_mob/animal/sif/glitterfly/rare/Initialize()
..()
/datum/say_list/glitterfly
speak = list("Pi..","Po...", "Pa...")
emote_see = list("vibrates","flutters", "twirls")
emote_hear = list("pips", "clicks", "chirps")
/datum/ai_holder/simple_mob/melee/evasive/glitterfly
hostile = FALSE
can_flee = TRUE
flee_when_outmatched = TRUE
outmatched_threshold = 100
max_home_distance = 5
/datum/ai_holder/simple_mob/melee/evasive/glitterfly/handle_special_strategical()
if(prob(1))
var/friendly_animal_corpse = FALSE
for(var/mob/living/simple_mob/animal/A in view(vision_range,holder))
if(holder.IIsAlly(A) && A.stat == DEAD)
friendly_animal_corpse = TRUE
break
if(friendly_animal_corpse)
hostile = TRUE
return
hostile = initial(hostile)

View File

@@ -0,0 +1,404 @@
// Kururaks, large pack-hunting felinids that reside in coastal regions. Less slowdown in water, speed on rocky turf.
/datum/category_item/catalogue/fauna/kururak
name = "Sivian Fauna - Kururak"
desc = "Classification: S Felidae fluctursora \
<br><br>\
An uncommon sight to many Sivian residents, these creatures are hypercarnivores, with\
their diets almost exclusively consisting of other fauna. This is achieved in the frozen \
environments of Sif via the means of fishing, even going to the lengths of evolving a \
third, dense lung only inflated for long dives. \
<br>\
One of the most distinguishing features of these animals are their four tails, capped in \
reflective 'mirrors'. These mirrors are used for tricking fish and other prey into ambushes,\
or distract would-be rivals. \
<br>\
Kururak packs are incredibly dangerous if faced alone, and should only be approached if prepared \
for a fight."
value = CATALOGUER_REWARD_HARD
/mob/living/simple_mob/animal/sif/kururak
name = "kururak"
desc = "A large animal with sleek fur."
tt_desc = "S Felidae fluctursora"
catalogue_data = list(/datum/category_item/catalogue/fauna/kururak)
faction = "kururak"
icon_state = "bigcat"
icon_living = "bigcat"
icon_dead = "bigcat_dead"
icon_rest = "bigcat_rest"
icon = 'icons/mob/64x64.dmi'
default_pixel_x = -16
pixel_x = -16
maxHealth = 200
health = 200
universal_understand = 1
movement_cooldown = 1
melee_damage_lower = 15
melee_damage_upper = 25
attack_armor_pen = 40
base_attack_cooldown = 2 SECONDS
attacktext = list("gouged", "bit", "cut", "clawed", "whipped")
armor = list(
"melee" = 30,
"bullet" = 15,
"laser" = 5,
"energy" = 0,
"bomb" = 10,
"bio" = 100,
"rad" = 100
)
armor_soak = list(
"melee" = 5,
"bullet" = 5,
"laser" = 5,
"energy" = 0,
"bomb" = 0,
"bio" = 0,
"rad" = 0
)
say_list_type = /datum/say_list/kururak
ai_holder_type = /datum/ai_holder/simple_mob/intentional/kururak
special_attack_min_range = 0
special_attack_max_range = 4
special_attack_cooldown = 30 SECONDS
// Players have 2 seperate cooldowns for these, while the AI must choose one. Both respect special_attack_cooldown
var/last_strike_time = 0
var/last_flash_time = 0
var/instinct // The points used by Kururaks to decide Who Is The Boss
var/obey_pack_rule = TRUE // Decides if the Kururak will automatically assign itself to follow the one with the highest instinct.
/datum/say_list/kururak
speak = list("Kurr?","|R|rrh..", "Ksss...")
emote_see = list("scratches its ear","flutters its tails", "flicks an ear", "shakes out its hair")
emote_hear = list("chirps", "clicks", "grumbles", "chitters")
/mob/living/simple_mob/animal/sif/kururak/leader // Going to be the starting leader. Has some base buffs to make it more likely to stay the leader.
maxHealth = 250
health = 250
instinct = 50
/mob/living/simple_mob/animal/sif/kururak/Initialize()
..()
if(!instinct)
if(prob(20))
instinct = rand(6, 10)
return
instinct = rand(0, 5)
/mob/living/simple_mob/animal/sif/kururak/IIsAlly(mob/living/L)
. = ..()
if(!.)
if(issilicon(L)) // Metal things are usually reflective, or in general aggrivating.
return FALSE
if(ishuman(L)) // Might be metal, but they're humanoid shaped.
var/mob/living/carbon/human/H = L
if(H.get_active_hand())
var/obj/item/I = H.get_active_hand()
if(I.force >= 1.20 * melee_damage_upper)
return TRUE
else if(istype(L, /mob/living/simple_mob))
var/mob/living/simple_mob/S = L
if(S.melee_damage_upper > 1.20 * melee_damage_upper)
return TRUE
/mob/living/simple_mob/animal/sif/kururak/handle_special()
..()
if(client)
pack_gauge()
/mob/living/simple_mob/animal/sif/kururak/apply_melee_effects(atom/A) // Only gains instinct.
instinct += rand(1, 2)
return
/mob/living/simple_mob/animal/sif/kururak/should_special_attack(atom/A)
return has_modifier_of_type(/datum/modifier/ace)
/mob/living/simple_mob/animal/sif/kururak/do_special_attack(atom/A)
. = TRUE
switch(a_intent)
if(I_DISARM) // Ranged mob flash, will also confuse borgs rather than stun.
tail_flash(A)
if(I_GRAB) // Armor-ignoring hit, causes agonizing wounds.
set_AI_busy(TRUE)
rending_strike(A)
set_AI_busy(FALSE)
/mob/living/simple_mob/animal/sif/kururak/verb/do_flash()
set category = "Abilities"
set name = "Tail Blind"
set desc = "Disorient a creature within range."
if(world.time < last_flash_time + special_attack_cooldown)
to_chat(src, span("warning", "You do not have the focus to do this so soon.."))
return
last_flash_time = world.time
tail_flash()
/mob/living/simple_mob/animal/sif/kururak/proc/tail_flash(atom/A)
set waitfor = FALSE
if(stat)
to_chat(src, span("warning","You cannot move your tails in this state.."))
return
if(!A && src.client)
var/list/choices = list()
for(var/mob/living/carbon/C in view(1,src))
if(src.Adjacent(C))
choices += C
for(var/obj/mecha/M in view(1,src))
if(src.Adjacent(M))
choices += M
if(!choices.len)
choices["radial"] = get_turf(src)
A = input(src,"What do we wish to flash?") in null|choices
visible_message(span("alien","\The [src] flares its tails!"))
if(isliving(A))
var/mob/living/L = A
if(iscarbon(L))
var/mob/living/carbon/C = L
if(C.stat != DEAD)
var/safety = C.eyecheck()
if(safety <= 0)
var/flash_strength = 5
if(ishuman(C))
var/mob/living/carbon/human/H = C
flash_strength *= H.species.flash_mod
if(flash_strength > 0)
to_chat(H, span("alien","You are disoriented by \the [src]!"))
H.Confuse(flash_strength + 5)
H.Blind(flash_strength)
H.eye_blurry = max(H.eye_blurry, flash_strength + 5)
H.flash_eyes()
H.adjustHalLoss(flash_strength / 5)
H.apply_damage(flash_strength * H.species.flash_burn/5, BURN, BP_HEAD, 0, 0, "Photon burns")
else if(issilicon(L))
if(isrobot(L))
var/flashfail = FALSE
var/mob/living/silicon/robot/R = L
if(R.has_active_type(/obj/item/borg/combat/shield))
var/obj/item/borg/combat/shield/shield = locate() in R
if(shield)
if(shield.active)
shield.adjust_flash_count(R, 1)
flashfail = TRUE
if(!flashfail)
to_chat(R, span("alien","Your optics are scrambled by \the [src]!"))
R.Confuse(10)
R.flash_eyes()
else
L.Confuse(10)
L.flash_eyes()
else
for(var/mob/living/carbon/C in oviewers(special_attack_max_range, null))
var/safety = C.eyecheck()
if(!safety)
if(!C.blinded)
C.flash_eyes()
for(var/mob/living/silicon/robot/R in oviewers(special_attack_max_range, null))
if(R.has_active_type(/obj/item/borg/combat/shield))
var/obj/item/borg/combat/shield/shield = locate() in R
if(shield)
if(shield.active)
continue
R.flash_eyes()
/mob/living/simple_mob/animal/sif/kururak/verb/do_strike()
set category = "Abilities"
set name = "Rending Strike"
set desc = "Strike viciously at an entity within range."
if(world.time < last_strike_time + special_attack_cooldown)
to_chat(src, span("warning", "Your claws cannot take that much stress in so short a time.."))
return
last_strike_time = world.time
rending_strike()
/mob/living/simple_mob/animal/sif/kururak/proc/rending_strike(atom/A)
if(stat)
to_chat(src, span("warning","You cannot strike in this state.."))
return
if(!A && src.client)
var/list/choices = list()
for(var/mob/living/carbon/C in view(1,src))
if(src.Adjacent(C))
choices += C
for(var/obj/mecha/M in view(1,src))
if(src.Adjacent(M))
choices += M
if(!choices.len)
to_chat(src, span("warning","There are no viable targets within range..."))
return
A = input(src,"What do we wish to strike?") in null|choices
if(!A || !src) return
if(!(src.Adjacent(A))) return
var/damage_to_apply = rand(melee_damage_lower, melee_damage_upper) + 10
if(isliving(A))
visible_message(span("danger","\The [src] rakes its claws across [A]."))
var/mob/living/L = A
if(ishuman(L))
var/mob/living/carbon/human/H = L
H.apply_damage(damage_to_apply, BRUTE, BP_TORSO, 0, 0, "Animal claws")
else
L.adjustBruteLoss(damage_to_apply)
L.add_modifier(/datum/modifier/grievous_wounds, 60 SECONDS)
else if(istype(A, /obj/mecha))
visible_message(span("danger","\The [src] rakes its claws against \the [A]."))
var/obj/mecha/M = A
M.take_damage(damage_to_apply)
if(prob(3) && do_after(src, 5))
visible_message(span("critical","\The [src]'s strike ripped \the [M]'s access hatch open, allowing it to drag [M.occupant] out!"))
M.go_out()
else
A.attack_generic(src, damage_to_apply, "rakes its claws against") // Well it's not a mob, and it's not a mech.
/mob/living/simple_mob/animal/sif/kururak/verb/rally_pack() // Mostly for telling other players to follow you. AI Kururaks will auto-follow, if set to.
set name = "Rally Pack"
set desc = "Tries to command your fellow pack members to follow you."
set category = "Abilities"
if(has_modifier_of_type(/datum/modifier/ace))
for(var/mob/living/simple_mob/animal/sif/kururak/K in hearers(7, src))
if(K == src)
continue
if(!K.ai_holder)
continue
if(K.faction != src.faction)
continue
var/datum/ai_holder/AI = K.ai_holder
to_chat(K, span("notice","The pack leader wishes for you to follow them."))
AI.set_follow(src)
/mob/living/simple_mob/animal/sif/kururak/proc/detect_instinct() // Will return the Kururak within 10 tiles that has the highest instinct.
var/mob/living/simple_mob/animal/sif/kururak/A
var/pack_count = 0
for(var/mob/living/simple_mob/animal/sif/kururak/K in hearers(10, src))
if(K == src)
continue
if(K.stat != DEAD)
pack_count++
if(K.instinct > src.instinct)
A = K
if(!A && pack_count)
A = src
return A
/mob/living/simple_mob/animal/sif/kururak/proc/pack_gauge() // Check incase we have a client.
var/mob/living/simple_mob/animal/sif/kururak/highest_instinct = detect_instinct()
if(highest_instinct == src)
add_modifier(/datum/modifier/ace, 60 SECONDS)
else
remove_modifiers_of_type(/datum/modifier/ace)
/datum/ai_holder/simple_mob/intentional/kururak
hostile = FALSE
retaliate = TRUE
cooperative = TRUE
can_flee = TRUE
flee_when_dying = TRUE
/datum/ai_holder/simple_mob/intentional/kururak/handle_special_strategical()
follow_distance = rand(initial(follow_distance), initial(follow_distance) + 2)
var/mob/living/simple_mob/animal/sif/kururak/K = holder
if(istype(K))
var/mob/living/simple_mob/animal/sif/kururak/highest_instinct = K.detect_instinct()
if(highest_instinct == K)
K.add_modifier(/datum/modifier/ace, 60 SECONDS)
else
K.remove_modifiers_of_type(/datum/modifier/ace)
if(holder.has_modifier_of_type(/datum/modifier/ace))
if(leader && istype(leader, /mob/living/simple_mob/animal/sif/kururak)) // Kururaks will not follow another kururak if they're the pack leader.
lose_follow()
else if(highest_instinct)
set_follow(highest_instinct)
if(holder.has_modifier_of_type(/datum/modifier/ace))
hostile = TRUE
else
hostile = initial(hostile)
/datum/ai_holder/simple_mob/intentional/kururak/pre_special_attack(atom/A)
holder.a_intent = I_HURT
if(isliving(A))
var/mob/living/L = A
if(holder.Adjacent(L))
holder.a_intent = I_GRAB
if(iscarbon(L))
var/mob/living/carbon/C = L
if(!C.eyecheck())
if(holder.a_intent != I_GRAB)
holder.a_intent = I_DISARM
if(issilicon(L) && holder.a_intent != I_GRAB)
holder.a_intent = I_DISARM
else if(istype(A, /obj/mecha))
holder.a_intent = I_GRAB
/datum/ai_holder/simple_mob/intentional/kururak/post_melee_attack()
if(holder.has_modifier_of_type(/datum/modifier/ace))
request_help()
// Kururak Ace modifier, given to the one with the highest Instinct.
/datum/modifier/ace
name = "Ace"
desc = "You are universally superior, in terms of physical prowess."
on_created_text = "You feel superior."
on_expired_text = "You feel your superiority lessen..."
stacks = MODIFIER_STACK_EXTEND
mob_overlay_state = "ace"
max_health_flat = 25
max_health_percent = 1.2
disable_duration_percent = 0.8
incoming_damage_percent = 0.7
incoming_healing_percent = 1.5
outgoing_melee_damage_percent = 1.5
evasion = 20
bleeding_rate_percent = 0.7
attack_speed_percent = 0.8

View File

@@ -0,0 +1,503 @@
// Small creatures that will embed themselves in unsuspecting victim's bodies, drink their blood, and/or eat their organs. Steals some things from borers.
/datum/category_item/catalogue/fauna/iceleech
name = "Sivian Fauna - River Leech"
desc = "Classification: S Hirudinea phorus \
<br><br>\
An incredibly dangerous species of worm phorogenically mutated from a Sivian river leech, \
believed to have resulted from corporate mining in the Ullran Expanse; these accusations are \
unfounded, however speculation remains.\
<br>\
The creatures' heads hold four long prehensile tendrils surrounding a central beak, which are \
used as locomotive and grappling appendages. Each is capped in a hollow tooth, capable of pumping \
chemicals into an unsuspecting host. \
<br>\
The rear half of the creature is entirely musculature, capped with a sharp, arrowhead-shaped fin."
value = CATALOGUER_REWARD_MEDIUM
/mob/living/simple_mob/animal/sif/leech
name = "river leech"
desc = "What appears to be an oversized leech."
tt_desc = "S Hirudinea phorus"
catalogue_data = list(/datum/category_item/catalogue/fauna/iceleech)
faction = "leech"
icon_state = "leech"
item_state = "brainslug"
icon_living = "leech"
icon_dead = "leech_dead"
icon = 'icons/mob/animal.dmi'
density = FALSE // Non-dense, so things can pass over them.
status_flags = CANPUSH
pass_flags = PASSTABLE
maxHealth = 100
health = 100
universal_understand = 1
special_attack_min_range = 0
special_attack_max_range = 1
var/obj/item/organ/external/host_bodypart // Where in the body we are infesting.
var/docile = FALSE
var/chemicals = 0
var/max_chemicals = 400
var/list/bodypart_targets = list(BP_L_LEG,BP_R_LEG,BP_L_ARM,BP_R_ARM,BP_TORSO,BP_GROIN,BP_HEAD)
var/infest_target = BP_TORSO // The currently chosen bodypart to infest.
var/mob/living/carbon/host // Our humble host.
var/list/produceable_chemicals = list("inaprovaline","anti_toxin","alkysine","bicaridine","tramadol","kelotane","leporazine","iron","phoron","condensedcapsaicin_v","frostoil")
var/randomized_reagent = "iron" // The reagent chosen at random to be produced, if there's no one piloting the worm.
var/passive_reagent = "paracetamol" // Reagent passively produced by the leech. Should usually be a painkiller.
var/feeding_delay = 30 SECONDS // How long do we have to wait to bite our host's organs?
var/last_feeding = 0
intent = I_HELP
holder_type = /obj/item/weapon/holder/leech
movement_cooldown = 0
aquatic_movement = -2
melee_damage_lower = 1
melee_damage_upper = 5
attack_armor_pen = 15
attack_sharp = TRUE
attacktext = list("nipped", "bit", "pinched")
armor = list(
"melee" = 10,
"bullet" = 15,
"laser" = -10,
"energy" = 0,
"bomb" = 10,
"bio" = 100,
"rad" = 100
)
armor_soak = list(
"melee" = 5,
"bullet" = 5,
"laser" = 0,
"energy" = 0,
"bomb" = 0,
"bio" = 0,
"rad" = 0
)
say_list_type = /datum/say_list/leech
ai_holder_type = /datum/ai_holder/simple_mob/intentional/leech
/mob/living/simple_mob/animal/sif/leech/IIsAlly(mob/living/L)
. = ..()
var/mob/living/carbon/human/H = L
if(!istype(H))
return .
if(istype(L.buckled, /obj/vehicle) || L.hovering) // Ignore people hovering or on boats.
return TRUE
if(!.)
var/has_organ = FALSE
var/obj/item/organ/internal/O = H.get_active_hand()
if(istype(O) && O.robotic < ORGAN_ROBOT && !(O.status & ORGAN_DEAD))
has_organ = TRUE
return has_organ
/datum/say_list/leech
speak = list("...", "Sss..", ". . .","Gss..")
emote_see = list("vibrates","looks around", "stares", "extends a proboscis")
emote_hear = list("chitters", "clicks", "gurgles")
/mob/living/simple_mob/animal/sif/leech/Initialize()
..()
verbs += /mob/living/proc/ventcrawl
verbs += /mob/living/proc/hide
/mob/living/simple_mob/animal/sif/leech/Stat()
..()
if(client.statpanel == "Status")
statpanel("Status")
if(emergency_shuttle)
var/eta_status = emergency_shuttle.get_status_panel_eta()
if(eta_status)
stat(null, eta_status)
stat("Chemicals", chemicals)
/mob/living/simple_mob/animal/sif/leech/do_special_attack(atom/A)
. = TRUE
if(istype(A, /mob/living/carbon))
switch(a_intent)
if(I_DISARM) // Poison
set_AI_busy(TRUE)
poison_inject(src, A)
set_AI_busy(FALSE)
if(I_GRAB) // Infesting!
set_AI_busy(TRUE)
do_infest(src, A)
set_AI_busy(FALSE)
/mob/living/simple_mob/animal/sif/leech/handle_special()
if(prob(5))
randomized_reagent = pick(produceable_chemicals)
var/turf/T = get_turf(src)
if(istype(T, /turf/simulated/floor/water) && src.loc == T && !stat) // Are we sitting in water, and alive?
alpha = max(5, alpha - 10)
if(chemicals + 1 < max_chemicals / 3)
chemicals++
else
alpha = min(255, alpha + 20)
if(!client && !host)
infest_target = pick(bodypart_targets)
if(host && !stat && !host.stat)
if(ai_holder)
ai_holder.hostile = FALSE
ai_holder.lose_target()
alpha = 5
if(host.reagents.has_reagent("cordradaxon") && !docile) // Overwhelms the leech with food.
var/message = "We feel the rush of cardiac pluripotent cells in your host's blood, lulling us into docility."
to_chat(src, span("warning", message))
docile = TRUE
if(chemicals + 5 <= max_chemicals)
chemicals += 5
else if(docile)
var/message = "We shake off our lethargy as the pluripotent cell count declines in our host's blood."
to_chat(src, span("notice", message))
docile = FALSE
if(!host.reagents.has_reagent(passive_reagent))
host.reagents.add_reagent(passive_reagent, 5)
chemicals -= 3
if(!docile && ishuman(host) && chemicals < max_chemicals)
var/mob/living/carbon/human/H = host
H.vessel.remove_reagent("blood", 1)
if(!H.reagents.has_reagent("inaprovaline"))
H.reagents.add_reagent("inaprovaline", 1)
chemicals += 2
if(!client && !docile) // Automatic 'AI' to manage damage levels.
if(host.getBruteLoss() >= 30 && chemicals > 50)
host.reagents.add_reagent("bicaridine", 5)
chemicals -= 30
if(host.getToxLoss() >= 30 && chemicals > 50)
var/randomchem = pickweight("tramadol" = 7, "anti_toxin" = 15, "frostoil" = 3)
host.reagents.add_reagent(randomchem, 5)
chemicals -= 50
if(host.getFireLoss() >= 30 && chemicals > 50)
host.reagents.add_reagent("kelotane", 5)
host.reagents.add_reagent("leporazine", 2)
chemicals -= 50
if(host.getOxyLoss() >= 30 && chemicals > 50)
host.reagents.add_reagent("iron", 10)
chemicals -= 40
if(host.getBrainLoss() >= 10 && chemicals > 100)
host.reagents.add_reagent("alkysine", 5)
host.reagents.add_reagent("tramadol", 3)
chemicals -= 100
if(prob(30) && chemicals > 50)
inject_meds(randomized_reagent)
var/heartless_mod = 0
if(ishuman(host)) // Species without hearts mean the worm gets hungry faster, if AI controlled.
var/mob/living/carbon/human/H = host
if(!H.species.has_organ[O_HEART])
heartless_mod = 1
if(prob(15 + (20 * heartless_mod)))
feed_on_organ()
else
if(ai_holder)
ai_holder.hostile = initial(ai_holder.hostile)
if(host && host.stat == DEAD && istype(get_turf(host), /turf/simulated/floor/water))
leave_host()
/mob/living/simple_mob/animal/sif/leech/verb/infest()
set category = "Abilities"
set name = "Infest"
set desc = "Infest a suitable humanoid host."
if(docile)
to_chat(src, span("alium","We are too tired to do this..."))
return
do_infest(usr)
/mob/living/simple_mob/animal/sif/leech/proc/do_infest(var/mob/living/user, var/mob/living/target = null)
if(host)
to_chat(user, span("alien", "We are already within a host."))
return
if(stat)
to_chat(user, span("warning","We cannot infest a target in your current state."))
return
var/mob/living/carbon/M = target
if(!M && src.client)
var/list/choices = list()
for(var/mob/living/carbon/C in view(1,src))
if(src.Adjacent(C))
choices += C
if(!choices.len)
to_chat(user, span("warning","There are no viable hosts within range..."))
return
M = input(src,"Who do we wish to infest?") in null|choices
if(!M || !src) return
if(!(src.Adjacent(M))) return
if(!istype(M) || M.isSynthetic())
to_chat(user, "\The [M] cannot be infested.")
return
if(istype(M,/mob/living/carbon/human))
var/mob/living/carbon/human/H = M
var/obj/item/organ/external/E = H.organs_by_name[infest_target]
if(!E || E.is_stump() || E.robotic >= ORGAN_ROBOT)
to_chat(src,"\The [H] does not have an infestable [infest_target]!")
var/list/covering_clothing = E.get_covering_clothing()
for(var/obj/item/clothing/C in covering_clothing)
if(C.armor["melee"] >= 20 + attack_armor_pen)
to_chat(user, span("notice","We cannot get through that host's protective gear."))
return
if(!do_after(src,2))
to_chat(user, span("notice", "As [M] moves away, we are dislodged and fall to the ground."))
return
if(!M || !src)
return
if(src.stat)
to_chat(user, span("warning","We cannot infest a target in your current state."))
return
if(M in view(1, src))
to_chat(user,span("alien", "We burrow into [M]'s flesh."))
if(!M.stat)
to_chat(M, span("critical", "You feel a sharp pain as something digs into your flesh!"))
src.host = M
src.forceMove(M)
if(ai_holder)
ai_holder.hostile = FALSE
ai_holder.lose_target()
if(istype(M,/mob/living/carbon/human))
var/mob/living/carbon/human/H = M
host_bodypart = H.get_organ(infest_target)
host_bodypart.implants |= src
return
else
to_chat(user, span("notice","They are no longer in range."))
return
/mob/living/simple_mob/animal/sif/leech/verb/uninfest()
set category = "Abilities"
set name = "Uninfest"
set desc = "Leave your current host."
if(docile)
to_chat(src, span("alium","We are too tired to do this..."))
return
leave_host()
/mob/living/simple_mob/animal/sif/leech/proc/leave_host()
if(!host)
return
if(ai_holder)
ai_holder.hostile = initial(ai_holder.hostile)
ai_holder.lose_target()
host_bodypart.implants -= src
host_bodypart = null
forceMove(get_turf(host))
reset_view(null)
host = null
/mob/living/simple_mob/animal/sif/leech/verb/inject_victim()
set category = "Abilities"
set name = "Incapacitate Potential Host"
set desc = "Inject an organic host with an incredibly painful mixture of chemicals."
if(docile)
to_chat(src, span("alium","We are too tired to do this..."))
return
var/mob/living/carbon/M
if(src.client)
var/list/choices = list()
for(var/mob/living/carbon/C in view(1,src))
if(src.Adjacent(C))
choices += C
if(!choices.len)
to_chat(src, span("warning","There are no viable hosts within range..."))
return
M = input(src,"Who do we wish to inject?") in null|choices
if(!M || stat)
return
poison_inject(usr, M)
/mob/living/simple_mob/animal/sif/leech/proc/poison_inject(var/mob/living/user, var/mob/living/carbon/L)
if(!L || !Adjacent(L) || stat)
return
var/mob/living/carbon/human/H = L
if(!istype(H) || H.isSynthetic())
to_chat(user, span("warning","You cannot inject this target..."))
var/obj/item/organ/external/E = H.organs_by_name[infest_target]
if(!E || E.is_stump() || E.robotic >= ORGAN_ROBOT)
to_chat(src,"\The [H] does not have an infestable [infest_target]!")
var/list/covering_clothing = E.get_covering_clothing()
for(var/obj/item/clothing/C in covering_clothing)
if(C.armor["melee"] >= 40 + attack_armor_pen)
to_chat(user, span("notice","You cannot get through that host's protective gear."))
return
H.add_modifier(/datum/modifier/poisoned/paralysis, 15 SECONDS)
/mob/living/simple_mob/animal/sif/leech/verb/medicate_host()
set category = "Abilities"
set name = "Produce Chemicals (50)"
set desc = "Inject your host with possibly beneficial chemicals, to keep the blood flowing."
if(docile)
to_chat(src, span("alium","We are too tired to do this..."))
return
if(!host || chemicals <= 50)
to_chat(usr, span("alien","We cannot produce any chemicals right now."))
return
if(host)
var/chem = input("Select a chemical to produce.", "Chemicals") as null|anything in produceable_chemicals
inject_meds(chem)
/mob/living/simple_mob/animal/sif/leech/proc/inject_meds(var/chem)
if(host)
chemicals = max(1, chemicals - 50)
host.reagents.add_reagent(chem, 5)
to_chat(src, span("alien","We injected \the [host] with five units of [chem]."))
/mob/living/simple_mob/animal/sif/leech/verb/feed_on_organ()
set category = "Abilities"
set name = "Feed on Organ"
set desc = "Extend probosci to feed on a piece of your host's organs."
if(docile)
to_chat(src, span("alium","We are too tired to do this..."))
return
if(host && world.time >= last_feeding + feeding_delay)
var/list/host_internal_organs = host.internal_organs
for(var/obj/item/organ/internal/O in host_internal_organs) // Remove organs with maximum damage.
if(O.damage >= O.max_damage)
host_internal_organs -= O
var/target
if(client)
target = input("Select an organ to feed on.", "Organs") as null|anything in host_internal_organs
if(!target)
to_chat(src, span("alien","We decide not to feed."))
return
if(!target)
target = pick(host_internal_organs)
if(target)
bite_organ(target)
else
to_chat(src, span("warning","We cannot feed now."))
/mob/living/simple_mob/animal/sif/leech/proc/bite_organ(var/obj/item/organ/internal/O)
last_feeding = world.time
if(O)
to_chat(src, span("alien","We feed on [O]."))
O.take_damage(2,silent=prob(10))
chemicals = min(max_chemicals, chemicals + 60)
host.add_modifier(/datum/modifier/grievous_wounds, 60 SECONDS)
adjustBruteLoss(rand(-10,-60))
adjustFireLoss(rand(-10,-60))
/datum/ai_holder/simple_mob/intentional/leech
hostile = TRUE
retaliate = TRUE
vision_range = 3
mauling = TRUE
returns_home = TRUE
can_flee = TRUE
home_low_priority = TRUE // If we've got a target, we're going for them.
max_home_distance = 1 // Low to ensure the creature doesn't leave the water unless it has a host.
/datum/ai_holder/simple_mob/intentional/leech/handle_special_strategical()
var/mob/living/simple_mob/animal/sif/leech/SL = holder
if(!SL.host && !istype(get_turf(SL), /turf/simulated/floor/water))
var/list/nearby_water = list()
for(var/turf/simulated/floor/water/W in view(holder, 10))
nearby_water |= W
if(nearby_water && nearby_water.len)
var/turf/T = pick(nearby_water)
if(T && can_attack(T))
home_turf = T
/datum/ai_holder/simple_mob/intentional/leech/special_flee_check()
var/mob/living/simple_mob/animal/sif/leech/SL = holder
if(!SL.host && !istype(get_turf(SL), /turf/simulated/floor/water))
return TRUE
/datum/ai_holder/simple_mob/intentional/leech/pre_special_attack(atom/A)
if(isliving(A))
var/mob/living/L = A
if(ishuman(L) && !L.isSynthetic())
if(L.incapacitated() || (L.stat && L.stat != DEAD) || L.resting || L.paralysis)
holder.a_intent = I_GRAB // Infesting time.
else
holder.a_intent = I_DISARM // They're standing up! Try to drop or stun them.
else
holder.a_intent = I_HURT // Otherwise, bite.
else if(istype(A, /obj/item))
var/obj/item/I = A
if(istype(I, /obj/item/weapon/reagent_containers/food/snacks))
holder.a_intent = I_HURT
else
holder.a_intent = I_HURT

View File

@@ -0,0 +1,355 @@
// Sakimm are small scavengers with an adoration for shiny things. They won't attack you for them, but you will be their friend holding something like a coin.
/datum/category_item/catalogue/fauna/sakimm
name = "Sivian Fauna - Sakimm"
desc = "Classification: S Procyon cogitae \
<br><br>\
Small, social omnivores known to collect objects within their dens. \
The Sakimm form colonies that have been known to grow up to a hundred individuals. Primarily carnivorous hunters, \
they often supplement their diets with nuts, roots, and other fruits. \
Individuals are known to steal food and reflective objects from unsuspecting Sivian residents. \
It is advised to keep any valuable items within dull wraps when venturing near the den of a Sakimm."
value = CATALOGUER_REWARD_EASY
/mob/living/simple_mob/animal/sif/sakimm
name = "sakimm"
desc = "What appears to be an oversized rodent with hands."
tt_desc = "S Procyon cogitae"
catalogue_data = list(/datum/category_item/catalogue/fauna/sakimm)
faction = "sakimm"
icon_state = "raccoon"
icon_living = "raccoon"
icon_dead = "raccoon_dead"
icon_rest = "raccoon_dead"
icon = 'icons/mob/animal.dmi'
maxHealth = 50
health = 50
has_hands = TRUE
humanoid_hands = TRUE
pass_flags = PASSTABLE
universal_understand = 1
movement_cooldown = 0
melee_damage_lower = 5
melee_damage_upper = 15
base_attack_cooldown = 1 SECOND
attacktext = list("nipped", "bit", "cut", "clawed")
armor = list(
"melee" = 15,
"bullet" = 5,
"laser" = 5,
"energy" = 0,
"bomb" = 10,
"bio" = 100,
"rad" = 100
)
armor_soak = list(
"melee" = 2,
"bullet" = 2,
"laser" = 0,
"energy" = 0,
"bomb" = 0,
"bio" = 0,
"rad" = 0
)
say_list_type = /datum/say_list/sakimm
ai_holder_type = /datum/ai_holder/simple_mob/retaliate/cooperative/sakimm
var/obj/item/clothing/head/hat = null // The hat the Sakimm may be wearing.
var/list/friend_loot_list = list(/obj/item/weapon/coin) // What will make this animal non-hostile if held?
var/randomize_size = TRUE
/mob/living/simple_mob/animal/sif/sakimm/verb/remove_hat()
set name = "Remove Hat"
set desc = "Remove the animal's hat. You monster."
set category = "Abilities"
set src in view(1)
drop_hat(usr)
/mob/living/simple_mob/animal/sif/sakimm/proc/drop_hat(var/mob/user)
if(hat)
hat.forceMove(get_turf(user))
hat = null
update_icon()
if(user == src)
to_chat(user, "<span class='notice'>You removed your hat.</span>")
return
to_chat(user, "<span class='warning'>You removed \the [src]'s hat. You monster.</span>")
else
if(user == src)
to_chat(user, "<span class='notice'>You are not wearing a hat!</span>")
return
to_chat(user, "<span class='notice'>\The [src] is not wearing a hat!</span>")
/mob/living/simple_mob/animal/sif/sakimm/verb/give_hat()
set name = "Give Hat"
set desc = "Give the animal a hat. You hero."
set category = "Abilities"
set src in view(1)
take_hat(usr)
/mob/living/simple_mob/animal/sif/sakimm/proc/take_hat(var/mob/user)
if(hat)
if(user == src)
to_chat(user, "<span class='notice'>You already have a hat!</span>")
return
to_chat(user, "<span class='notice'>\The [src] already has a hat!</span>")
else
if(user == src)
if(istype(get_active_hand(), /obj/item/clothing/head))
hat = get_active_hand()
drop_from_inventory(hat, src)
hat.forceMove(src)
to_chat(user, "<span class='notice'>You put on the hat.</span>")
update_icon()
return
else if(ishuman(user))
var/mob/living/carbon/human/H = user
if(istype(H.get_active_hand(), /obj/item/clothing/head) && !get_active_hand())
var/obj/item/clothing/head/newhat = H.get_active_hand()
H.drop_from_inventory(newhat, get_turf(src))
if(!stat)
intent = I_HELP
newhat.attack_hand(src)
else if(src.get_active_hand())
to_chat(user, "<span class='notice'>\The [src] seems busy with \the [get_active_hand()] already!</span>")
else
to_chat(user, "<span class='warning'>You aren't holding a hat...</span>")
/datum/say_list/sakimm
speak = list("Shurr.", "|R|rr?", "Hss.")
emote_see = list("sniffs","looks around", "rubs its hands")
emote_hear = list("chitters", "clicks")
/mob/living/simple_mob/animal/sif/sakimm/Destroy()
if(hat)
drop_hat(src)
..()
/mob/living/simple_mob/animal/sif/sakimm/update_icon()
overlays.Cut()
..()
if(hat)
var/hat_state = hat.item_state ? hat.item_state : hat.icon_state
var/image/I = image('icons/mob/head.dmi', src, hat_state)
I.pixel_y = -15 // Sakimm are tiny!
I.appearance_flags = RESET_COLOR
add_overlay(I)
/mob/living/simple_mob/animal/sif/sakimm/Initialize()
. = ..()
verbs += /mob/living/proc/ventcrawl
verbs += /mob/living/proc/hide
if(randomize_size)
adjust_scale(rand(8, 11) / 10)
/mob/living/simple_mob/animal/sif/sakimm/IIsAlly(mob/living/L)
. = ..()
var/mob/living/carbon/human/H = L
if(!istype(H))
return .
if(!.)
var/has_loot = FALSE
var/obj/item/I = H.get_active_hand()
if(I)
for(var/item_type in friend_loot_list)
if(istype(I, item_type))
has_loot = TRUE
break
return has_loot
/datum/ai_holder/simple_mob/retaliate/cooperative/sakimm/handle_special_strategical() // Just needs to take hats.
var/mob/living/simple_mob/animal/sif/sakimm/S = holder
if(holder.get_active_hand() && istype(holder.get_active_hand(), /obj/item/clothing/head) && !S.hat)
var/obj/item/I = holder.get_active_hand()
S.take_hat(S)
holder.visible_message("<span class='notice'>\The [holder] wears \the [I]</span>")
/mob/living/simple_mob/animal/sif/sakimm/intelligent
desc = "What appears to be an oversized rodent with hands. This one has a curious look in its eyes."
ai_holder_type = /datum/ai_holder/simple_mob/intentional/sakimm
randomize_size = FALSE // Most likely to have a hat.
/datum/ai_holder/simple_mob/intentional/sakimm
hostile = FALSE
retaliate = TRUE
vision_range = 10
can_flee = TRUE
flee_when_dying = TRUE
var/greed = 0 // The probability we will try to steal something. Increases over time if we are not holding something, or wearing a hat.
var/list/steal_loot_list = list(/obj/item/weapon/coin, /obj/item/weapon/gun, /obj/item/weapon/fossil, /obj/item/stack/material, /obj/item/weapon/material, /obj/item/weapon/reagent_containers/food/snacks, /obj/item/clothing/head, /obj/item/weapon/reagent_containers/glass, /obj/item/device/flashlight, /obj/item/stack/medical, /obj/item/seeds, /obj/item/weapon/spacecash)
var/hoard_items = TRUE
var/hoard_distance = 1 // How far an item can be from the Sakimm's home turf to be counted inside its 'hoard'.
var/original_home_distance = null
var/search_delay = 2 SECONDS // How often can we look for item targets?
var/last_search = 0
/datum/ai_holder/simple_mob/intentional/sakimm/New()
..()
original_home_distance = max_home_distance
/datum/ai_holder/simple_mob/intentional/sakimm/post_melee_attack(atom/A)
if(istype(A, /obj/item) && !holder.get_active_hand() && holder.Adjacent(A))
var/obj/item/I = A
I.attack_hand(holder)
lose_target()
if(istype(A,/mob/living) && holder.Adjacent(A)) // Not the dumbest tool in the shed. If we're fighting, we're gonna dance around them.
holder.IMove(get_step(holder, pick(alldirs)))
holder.face_atom(A)
request_help() // And we're going to call friends, too.
/datum/ai_holder/simple_mob/intentional/sakimm/list_targets()
. = hearers(vision_range, holder) - holder
var/static/hostile_machines = typecacheof(list(/obj/machinery/porta_turret, /obj/mecha))
for(var/HM in typecache_filter_list(range(vision_range, holder), hostile_machines))
if(can_see(holder, HM, vision_range))
. += HM
if(holder.get_active_hand()) // We don't want item targets if we have an item!
return .
if(world.time <= last_search + search_delay) // Don't spam searching for item targets, since they can be in areas with a -lot- of items.
return .
for(var/obj/item/I in view(holder, vision_range))
last_search = world.time
if(!hoard_items || get_dist(I, home_turf) <= 1)
continue
for(var/itemtype in steal_loot_list)
if(istype(I, itemtype))
if(!I.anchored)
. += I
break
. -= holder.contents
/datum/ai_holder/simple_mob/intentional/sakimm/find_target(var/list/possible_targets, var/has_targets_list = FALSE)
var/can_pick_mobs = TRUE
if(!hostile)
can_pick_mobs = FALSE
. = list()
if(!has_targets_list)
possible_targets = list_targets()
for(var/possible_target in possible_targets)
var/atom/A = possible_target
if(found(A))
. = list(A)
break
if(istype(A, /mob/living) && !can_pick_mobs)
continue
if(can_attack(A)) // Can we attack it?
. += A
continue
for(var/obj/item/I in .)
last_search = world.time
if(!hoard_items || get_dist(I, home_turf) <= 1)
. -= I
var/new_target = pick_target(.)
give_target(new_target)
return new_target
/datum/ai_holder/simple_mob/intentional/sakimm/pre_melee_attack(atom/A)
if(isliving(A))
var/mob/living/L = A
if(holder.get_active_hand()) // Are we holding something? If so, drop it, we have a new target to kill, and we shouldn't use their weapons.
holder.drop_from_inventory(holder.get_active_hand(), get_turf(holder))
if(ishuman(L))
if(L.incapacitated(INCAPACITATION_DISABLED)) // Is our target on the ground? If so, let's scratch!
if(prob(30)) // Unless we decide to cut and run, and take their stuff while we're at it.
var/turf/T = get_turf(L)
var/obj/item/IT = locate() in T.contents
if(IT)
lose_target()
give_target(IT)
return
holder.a_intent = I_HURT
else
holder.a_intent = I_DISARM // Otherwise, try to disarm them!
else
holder.a_intent = I_HURT // We can't disarm you, so we're going to hurt you.
else if(istype(A, /obj/item))
var/obj/item/I = A
if(istype(I, /obj/item/weapon/reagent_containers/food/snacks)) // If we can't pick it up, or it's edible, go to harm.
holder.a_intent = I_HURT
else
holder.a_intent = I_HELP
else
holder.a_intent = I_HURT
/datum/ai_holder/simple_mob/intentional/sakimm/should_go_home()
if((!returns_home && !holder.get_active_hand()) || !home_turf) // If we have an item, we want to go home.
return FALSE
if(get_dist(holder, home_turf) > max_home_distance)
if(!home_low_priority)
return TRUE
else if(!leader && !target)
return TRUE
return FALSE
/datum/ai_holder/simple_mob/intentional/sakimm/handle_special_tactic()
var/mob/living/simple_mob/animal/sif/sakimm/S = holder
if(S.hat)
hoard_items = FALSE
else
hoard_items = TRUE
/datum/ai_holder/simple_mob/intentional/sakimm/handle_special_strategical()
var/mob/living/simple_mob/animal/sif/sakimm/S = holder
var/carrying_item = FALSE
if(holder.get_active_hand()) // Do we have loot?
if(istype(holder) && istype(holder.get_active_hand(), /obj/item/clothing/head) && !S.hat)
var/obj/item/I = holder.get_active_hand()
S.take_hat(S)
holder.visible_message("<span class='notice'>\The [holder] wears \the [I]</span>")
carrying_item = TRUE
if(istype(holder) && S.hat) // Do we have a hat? Hats are loot.
carrying_item = TRUE
if(!carrying_item) // Not carrying or wearing anything? We want to carry something more.
greed++
greed = min(95, greed)
else
greed = 0
if(!target && prob(5 + greed) && !holder.get_active_hand())
find_target()
if(holder.get_active_hand() && hoard_items)
lose_target()
max_home_distance = 1
if(get_dist(holder, home_turf) <= max_home_distance)
holder.drop_from_inventory(holder.get_active_hand(), get_turf(holder))
if(!holder.get_active_hand())
max_home_distance = original_home_distance
/datum/ai_holder/simple_mob/intentional/sakimm/special_flee_check()
return holder.get_active_hand()

View File

@@ -16,7 +16,10 @@
w_class = ITEMSIZE_NORMAL
var/icon_state_closed = "laptop-closed"
/obj/item/modular_computer/laptop/AltClick()
/obj/item/modular_computer/laptop/AltClick(mob/living/carbon/user)
// We need to be close to it to open it
if((!in_range(src, user)) || user.stat || user.restrained())
return
// Prevents carrying of open laptops inhand.
// While they work inhand, i feel it'd make tablets lose some of their high-mobility advantage they have over laptops now.
if(!istype(loc, /turf/))
@@ -41,7 +44,9 @@
..()
else
overlays.Cut()
set_light(0) // No glow from closed laptops
icon_state = icon_state_closed
/obj/item/modular_computer/laptop/preset
anchored = FALSE
screen_on = FALSE

View File

@@ -952,6 +952,13 @@ Note that amputating the affected organ does in fact remove the infection from t
qdel(src)
if(victim.l_hand)
if(istype(victim.l_hand,/obj/item/weapon/material/twohanded)) //if they're holding a two-handed weapon, drop it now they've lost a hand
victim.l_hand.update_held_icon()
if(victim.r_hand)
if(istype(victim.r_hand,/obj/item/weapon/material/twohanded))
victim.r_hand.update_held_icon()
/****************************************************
HELPERS
****************************************************/

View File

@@ -26,13 +26,14 @@
..()
/obj/item/projectile/energy/blob/on_impact(var/atom/A)
var/turf/location = get_turf(src)
var/datum/effect/effect/system/smoke_spread/chem/S = new /datum/effect/effect/system/smoke_spread/chem
S.attach(location)
S.set_up(reagents, splatter_volume, 0, location)
playsound(location, 'sound/effects/slime_squish.ogg', 30, 1, -3)
spawn(0)
S.start()
if(splatter)
var/turf/location = get_turf(src)
var/datum/effect/effect/system/smoke_spread/chem/S = new /datum/effect/effect/system/smoke_spread/chem
S.attach(location)
S.set_up(reagents, splatter_volume, 0, location)
playsound(location, 'sound/effects/slime_squish.ogg', 30, 1, -3)
spawn(0)
S.start()
..()
/obj/item/projectile/energy/blob/proc/ready_chemicals()
@@ -61,3 +62,11 @@
splatter = TRUE
flammability = 0.25
my_chems = list("fuel", "mold")
/obj/item/projectile/energy/blob/freezing
my_chems = list("frostoil")
modifier_type_to_apply = /datum/modifier/chilled
modifier_duration = 1 MINUTE
/obj/item/projectile/energy/blob/freezing/splattering
splatter = TRUE

View File

@@ -0,0 +1,38 @@
################################
# Example Changelog File
#
# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb.
#
# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.)
# When it is, any changes listed below will disappear.
#
# Valid Prefixes:
# bugfix
# wip (For works in progress)
# tweak
# soundadd
# sounddel
# rscadd (general adding of nice things)
# rscdel (general deleting of nice things)
# imageadd
# imagedel
# maptweak
# spellcheck (typo fixes)
# experiment
#################################
# Your name.
author: Mechoid
# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again.
delete-after: True
# Any changes you've made. See valid prefix list above.
# INDENT WITH TWO SPACES. NOT TABS. SPACES.
# SCREW THIS UP AND IT WON'T WORK.
# Also, all entries are changed into a single [] after a master changelog generation. Just remove the brackets when you add new entries.
# Please surround your changes in double quotes ("), as certain characters otherwise screws up compiling. The quotes will not show up in the changelog.
changes:
- rscadd: "The Shimm, Frostfly, Glitterfly, River Leech, Crystal-Feathered Duck, and Kururak are now able to be used on the map and PoIs."
- tweak: "Glass jars can now hold glitterflies, river leeches, and frostflies."
- tweak: "Glass jars now respect mobs that exist over the lighting plane, adding a special overlay visible when on the ground."

View File

@@ -0,0 +1,42 @@
################################
# Example Changelog File
#
# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb.
#
# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.)
# When it is, any changes listed below will disappear.
#
# Valid Prefixes:
# bugfix
# wip (For works in progress)
# tweak
# soundadd
# sounddel
# rscadd (general adding of nice things)
# rscdel (general deleting of nice things)
# imageadd
# imagedel
# maptweak
# spellcheck (typo fixes)
# experiment
#################################
# Your name.
author: mistyLuminescence
# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again.
delete-after: True
# Any changes you've made. See valid prefix list above.
# INDENT WITH TWO SPACES. NOT TABS. SPACES.
# SCREW THIS UP AND IT WON'T WORK.
# Also, all entries are changed into a single [] after a master changelog generation. Just remove the brackets when you add new entries.
# Please surround your changes in double quotes ("), as certain characters otherwise screws up compiling. The quotes will not show up in the changelog.
changes:
- bugfix: Prone people can no longer interact with an empty hand.
- bugfix: Two-handed items are now correctly unwielded when the user's offhand is severed.
- bugfix: Mecha syringe guns now respect pierceproof clothing.
- bugfix: Securitrons now correctly ignore attacks when disabled.
- bugfix: Rechargers now correctly benefit from upgraded capacitors.
- bugfix: Medical record laptops and detective TV camera consoles no longer turn into regular consoles when de- and re-constructed.
- bugfix: Zaddat Shrouds now retain their base name when damaged, if the shroud has been customized.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 248 KiB

After

Width:  |  Height:  |  Size: 228 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 25 KiB

View File

@@ -2393,7 +2393,13 @@
#include "code\modules\mob\living\simple_mob\subtypes\animal\pets\parrot.dm"
#include "code\modules\mob\living\simple_mob\subtypes\animal\sif\diyaab.dm"
#include "code\modules\mob\living\simple_mob\subtypes\animal\sif\fluffy_vr.dm"
#include "code\modules\mob\living\simple_mob\subtypes\animal\sif\duck.dm"
#include "code\modules\mob\living\simple_mob\subtypes\animal\sif\frostfly.dm"
#include "code\modules\mob\living\simple_mob\subtypes\animal\sif\glitterfly.dm"
#include "code\modules\mob\living\simple_mob\subtypes\animal\sif\hooligan_crab.dm"
#include "code\modules\mob\living\simple_mob\subtypes\animal\sif\kururak.dm"
#include "code\modules\mob\living\simple_mob\subtypes\animal\sif\leech.dm"
#include "code\modules\mob\living\simple_mob\subtypes\animal\sif\racoon.dm"
#include "code\modules\mob\living\simple_mob\subtypes\animal\sif\savik.dm"
#include "code\modules\mob\living\simple_mob\subtypes\animal\sif\shantak.dm"
#include "code\modules\mob\living\simple_mob\subtypes\animal\sif\sif.dm"