mirror of
https://github.com/PolarisSS13/Polaris.git
synced 2026-01-05 23:12:26 +00:00
Merge branch 'master' of https://github.com/PolarisSS13/Polaris into parachute
# Conflicts: # icons/mob/back.dmi # icons/obj/storage.dmi
This commit is contained in:
@@ -6,11 +6,13 @@ var/list/admin_verbs_default = list(
|
||||
/client/proc/hide_verbs, //hides all our adminverbs,
|
||||
/client/proc/hide_most_verbs, //hides all our hideable adminverbs,
|
||||
/client/proc/debug_variables, //allows us to -see- the variables of any instance in the game. +VAREDIT needed to modify,
|
||||
/client/proc/cmd_check_new_players, //allows us to see every new player
|
||||
// /client/proc/check_antagonists, //shows all antags,
|
||||
// /client/proc/cmd_mod_say,
|
||||
// /client/proc/deadchat //toggles deadchat on/off,
|
||||
// /client/proc/toggle_ahelp_sound,
|
||||
)
|
||||
|
||||
var/list/admin_verbs_admin = list(
|
||||
/client/proc/player_panel_new, //shows an interface for all players, with links to various panels,
|
||||
/datum/admins/proc/set_tcrystals,
|
||||
@@ -99,16 +101,19 @@ var/list/admin_verbs_admin = list(
|
||||
/datum/admins/proc/paralyze_mob,
|
||||
/client/proc/fixatmos,
|
||||
/datum/admins/proc/sendFax
|
||||
)
|
||||
)
|
||||
|
||||
var/list/admin_verbs_ban = list(
|
||||
/client/proc/unban_panel,
|
||||
/client/proc/jobbans
|
||||
)
|
||||
|
||||
var/list/admin_verbs_sounds = list(
|
||||
/client/proc/play_local_sound,
|
||||
/client/proc/play_sound,
|
||||
/client/proc/play_server_sound
|
||||
)
|
||||
|
||||
var/list/admin_verbs_fun = list(
|
||||
/client/proc/object_talk,
|
||||
/datum/admins/proc/cmd_admin_dress,
|
||||
@@ -141,6 +146,7 @@ var/list/admin_verbs_spawn = list(
|
||||
/client/proc/map_template_upload,
|
||||
/client/proc/map_template_load_on_new_z
|
||||
)
|
||||
|
||||
var/list/admin_verbs_server = list(
|
||||
/datum/admins/proc/capture_map,
|
||||
/client/proc/Set_Holiday,
|
||||
@@ -168,6 +174,7 @@ var/list/admin_verbs_server = list(
|
||||
/client/proc/recipe_dump,
|
||||
/client/proc/panicbunker
|
||||
)
|
||||
|
||||
var/list/admin_verbs_debug = list(
|
||||
/client/proc/getruntimelog, //allows us to access runtime logs to somebody,
|
||||
/client/proc/cmd_admin_list_open_jobs,
|
||||
@@ -209,7 +216,8 @@ var/list/admin_verbs_debug = list(
|
||||
/client/proc/show_gm_status,
|
||||
/datum/admins/proc/change_weather,
|
||||
/datum/admins/proc/change_time,
|
||||
/client/proc/admin_give_modifier
|
||||
/client/proc/admin_give_modifier,
|
||||
/client/proc/simple_DPS
|
||||
)
|
||||
|
||||
var/list/admin_verbs_paranoid_debug = list(
|
||||
@@ -290,6 +298,7 @@ var/list/admin_verbs_hideable = list(
|
||||
/client/proc/kill_airgroup,
|
||||
/client/proc/debug_controller,
|
||||
/client/proc/startSinglo,
|
||||
/client/proc/simple_DPS,
|
||||
/client/proc/cmd_debug_mob_lists,
|
||||
/client/proc/cmd_debug_using_map,
|
||||
/client/proc/cmd_debug_del_all,
|
||||
|
||||
@@ -16,6 +16,56 @@
|
||||
|
||||
// callproc moved to code/modules/admin/callproc
|
||||
|
||||
/client/proc/simple_DPS()
|
||||
set name = "Simple DPS"
|
||||
set category = "Debug"
|
||||
set desc = "Gives a really basic idea of how much hurt something in-hand does."
|
||||
|
||||
var/obj/item/I = null
|
||||
var/mob/living/user = null
|
||||
if(isliving(usr))
|
||||
user = usr
|
||||
I = user.get_active_hand()
|
||||
if(!I || !istype(I))
|
||||
to_chat(user, "<span class='warning'>You need to have something in your active hand, to use this verb.</span>")
|
||||
return
|
||||
var/weapon_attack_speed = user.get_attack_speed(I) / 10
|
||||
var/weapon_damage = I.force
|
||||
|
||||
if(istype(I, /obj/item/weapon/gun))
|
||||
var/obj/item/weapon/gun/G = I
|
||||
var/obj/item/projectile/P
|
||||
|
||||
if(istype(I, /obj/item/weapon/gun/energy))
|
||||
var/obj/item/weapon/gun/energy/energy_gun = G
|
||||
P = new energy_gun.projectile_type()
|
||||
|
||||
else if(istype(I, /obj/item/weapon/gun/projectile))
|
||||
var/obj/item/weapon/gun/projectile/projectile_gun = G
|
||||
var/obj/item/ammo_casing/ammo = projectile_gun.chambered
|
||||
P = ammo.BB
|
||||
|
||||
else
|
||||
to_chat(user, "<span class='warning'>DPS calculation by this verb is not supported for \the [G]'s type. Energy or Ballistic only, sorry.</span>")
|
||||
|
||||
weapon_damage = P.damage
|
||||
weapon_attack_speed = G.fire_delay / 10
|
||||
qdel(P)
|
||||
|
||||
var/DPS = weapon_damage / weapon_attack_speed
|
||||
to_chat(user, "<span class='notice'>Damage: [weapon_damage]</span>")
|
||||
to_chat(user, "<span class='notice'>Attack Speed: [weapon_attack_speed]/s</span>")
|
||||
to_chat(user, "<span class='notice'>\The [I] does <b>[DPS]</b> damage per second.</span>")
|
||||
if(DPS > 0)
|
||||
to_chat(user, "<span class='notice'>At your maximum health ([user.getMaxHealth()]), it would take approximately;</span>")
|
||||
to_chat(user, "<span class='notice'>[(user.getMaxHealth() - config.health_threshold_softcrit) / DPS] seconds to softcrit you. ([config.health_threshold_softcrit] health)</span>")
|
||||
to_chat(user, "<span class='notice'>[(user.getMaxHealth() - config.health_threshold_crit) / DPS] seconds to hardcrit you. ([config.health_threshold_crit] health)</span>")
|
||||
to_chat(user, "<span class='notice'>[(user.getMaxHealth() - config.health_threshold_dead) / DPS] seconds to kill you. ([config.health_threshold_dead] health)</span>")
|
||||
|
||||
else
|
||||
to_chat(user, "<span class='warning'>You need to be a living mob, with hands, and for an object to be in your active hand, to use this verb.</span>")
|
||||
return
|
||||
|
||||
/client/proc/Cell()
|
||||
set category = "Debug"
|
||||
set name = "Cell"
|
||||
|
||||
@@ -43,6 +43,40 @@
|
||||
message_admins("<font color='blue'>[key_name_admin(usr)] sent [key_name_admin(M)] to the prison station.</font>", 1)
|
||||
feedback_add_details("admin_verb","PRISON") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
//Allows staff to determine who the newer players are.
|
||||
/client/proc/cmd_check_new_players()
|
||||
set category = "Admin"
|
||||
set name = "Check new Players"
|
||||
if(!holder)
|
||||
src << "Only staff members may use this command."
|
||||
|
||||
var/age = alert(src, "Age check", "Show accounts yonger then _____ days","7", "30" , "All")
|
||||
|
||||
if(age == "All")
|
||||
age = 9999999
|
||||
else
|
||||
age = text2num(age)
|
||||
|
||||
var/missing_ages = 0
|
||||
var/msg = ""
|
||||
|
||||
var/highlight_special_characters = 1
|
||||
|
||||
for(var/client/C in clients)
|
||||
if(C.player_age == "Requires database")
|
||||
missing_ages = 1
|
||||
continue
|
||||
if(C.player_age < age)
|
||||
msg += "[key_name(C, 1, 1, highlight_special_characters)]: account is [C.player_age] days old<br>"
|
||||
|
||||
if(missing_ages)
|
||||
src << "Some accounts did not have proper ages set in their clients. This function requires database to be present."
|
||||
|
||||
if(msg != "")
|
||||
src << browse(msg, "window=Player_age_check")
|
||||
else
|
||||
src << "No matches for that age range found."
|
||||
|
||||
/client/proc/cmd_admin_subtle_message(mob/M as mob in mob_list)
|
||||
set category = "Special Verbs"
|
||||
set name = "Subtle Message"
|
||||
|
||||
@@ -112,6 +112,8 @@
|
||||
|
||||
/obj/effect/blob/proc/pulse(var/forceLeft, var/list/dirs)
|
||||
regen()
|
||||
animate(src, color = "#FF0000", time=1)
|
||||
animate(color = "#FFFFFF", time=4, easing=ELASTIC_EASING)
|
||||
sleep(5)
|
||||
var/pushDir = pick(dirs)
|
||||
var/turf/T = get_step(src, pushDir)
|
||||
|
||||
10
code/modules/blob2/_defines.dm
Normal file
10
code/modules/blob2/_defines.dm
Normal file
@@ -0,0 +1,10 @@
|
||||
#define BLOB_CORE_PULSE_RANGE 6
|
||||
#define BLOB_NODE_PULSE_RANGE 4
|
||||
|
||||
#define BLOB_CORE_EXPAND_RANGE 8
|
||||
#define BLOB_NODE_EXPAND_RANGE 6
|
||||
|
||||
#define BLOB_DIFFICULTY_EASY 0
|
||||
#define BLOB_DIFFICULTY_MEDIUM 1
|
||||
#define BLOB_DIFFICULTY_HARD 2
|
||||
#define BLOB_DIFFICULTY_SUPERHARD 3
|
||||
18
code/modules/blob2/announcement.dm
Normal file
18
code/modules/blob2/announcement.dm
Normal file
@@ -0,0 +1,18 @@
|
||||
/proc/level_seven_blob_announcement(var/obj/structure/blob/core/B)
|
||||
if(!B || !B.overmind)
|
||||
return
|
||||
var/datum/blob_type/blob = B.overmind.blob_type // Shortcut so we don't need to delve into three variables every time.
|
||||
var/list/lines = list()
|
||||
|
||||
lines += "Confirmed outbreak of level [7 + blob.difficulty] biohazard aboard [station_name()]. All personnel must contain the outbreak."
|
||||
|
||||
if(blob.difficulty >= BLOB_DIFFICULTY_MEDIUM) // Tell them what kind of blob it is if it's tough.
|
||||
lines += "The biohazard has been identified as a '[blob.name]'."
|
||||
|
||||
if(blob.difficulty >= BLOB_DIFFICULTY_HARD) // If it's really hard then tell them where it is so the response occurs faster.
|
||||
lines += "It is suspected to have originated from \the [get_area(B)]."
|
||||
|
||||
if(blob.difficulty >= BLOB_DIFFICULTY_SUPERHARD)
|
||||
lines += "Extreme caution is advised."
|
||||
|
||||
command_announcement.Announce(lines.Join("\n"), "Biohazard Alert", new_sound = 'sound/AI/outbreak7.ogg')
|
||||
298
code/modules/blob2/blobs/base_blob.dm
Normal file
298
code/modules/blob2/blobs/base_blob.dm
Normal file
@@ -0,0 +1,298 @@
|
||||
var/list/blobs = list()
|
||||
|
||||
/obj/structure/blob
|
||||
name = "blob"
|
||||
icon = 'icons/mob/blob.dmi'
|
||||
desc = "A thick wall of writhing tendrils."
|
||||
light_range = 2
|
||||
density = FALSE // This is false because blob mob AI's walk_to() proc appears to never attempt to move onto dense objects even if allowed by CanPass().
|
||||
opacity = FALSE
|
||||
anchored = TRUE
|
||||
layer = MOB_LAYER + 0.1
|
||||
var/integrity = 0
|
||||
var/point_return = 0 //How many points the blob gets back when it removes a blob of that type. If less than 0, blob cannot be removed.
|
||||
var/max_integrity = 30
|
||||
var/health_regen = 2 //how much health this blob regens when pulsed
|
||||
var/pulse_timestamp = 0 //we got pulsed when?
|
||||
var/heal_timestamp = 0 //we got healed when?
|
||||
var/mob/observer/blob/overmind = null
|
||||
var/base_name = "blob" // The name that gets appended along with the blob_type's name.
|
||||
|
||||
/obj/structure/blob/New(var/newloc, var/new_overmind)
|
||||
..(newloc)
|
||||
if(new_overmind)
|
||||
overmind = new_overmind
|
||||
update_icon()
|
||||
if(!integrity)
|
||||
integrity = max_integrity
|
||||
set_dir(pick(cardinal))
|
||||
blobs += src
|
||||
consume_tile()
|
||||
|
||||
|
||||
/obj/structure/blob/Destroy()
|
||||
playsound(src.loc, 'sound/effects/splat.ogg', 50, 1) //Expand() is no longer broken, no check necessary.
|
||||
blobs -= src
|
||||
overmind = null
|
||||
return ..()
|
||||
|
||||
/obj/structure/blob/update_icon() //Updates color based on overmind color if we have an overmind.
|
||||
if(overmind)
|
||||
name = "[overmind.blob_type.name] [base_name]" // This is in update_icon() because inert blobs can turn into other blobs with magic if another blob core claims it with pulsing.
|
||||
color = overmind.blob_type.color
|
||||
set_light(3, 3, color)
|
||||
else
|
||||
name = "inert [base_name]"
|
||||
color = null
|
||||
set_light(0)
|
||||
|
||||
/obj/structure/blob/CanPass(atom/movable/mover, turf/target, height=0, air_group=0)
|
||||
if(air_group || (height==0))
|
||||
return TRUE
|
||||
if(istype(mover) && mover.checkpass(PASSBLOB))
|
||||
return TRUE
|
||||
else
|
||||
return FALSE
|
||||
// return ..()
|
||||
|
||||
/obj/structure/blob/examine(mob/user)
|
||||
..()
|
||||
if(!overmind)
|
||||
to_chat(user, "It seems inert.") // Dead blob.
|
||||
else
|
||||
to_chat(user, overmind.blob_type.desc)
|
||||
|
||||
/obj/structure/blob/get_description_info()
|
||||
if(overmind)
|
||||
return overmind.blob_type.effect_desc
|
||||
return ..()
|
||||
|
||||
/obj/structure/blob/emp_act(severity)
|
||||
if(overmind)
|
||||
overmind.blob_type.on_emp(src, severity)
|
||||
|
||||
/obj/structure/blob/proc/pulsed()
|
||||
if(pulse_timestamp <= world.time)
|
||||
consume_tile()
|
||||
if(heal_timestamp <= world.time)
|
||||
adjust_integrity(health_regen)
|
||||
heal_timestamp = world.time + 2 SECONDS
|
||||
update_icon()
|
||||
pulse_timestamp = world.time + 1 SECOND
|
||||
if(overmind)
|
||||
overmind.blob_type.on_pulse(src)
|
||||
return TRUE //we did it, we were pulsed!
|
||||
return FALSE //oh no we failed
|
||||
|
||||
/obj/structure/blob/proc/pulse_area(pulsing_overmind = overmind, claim_range = 10, pulse_range = 3, expand_range = 2)
|
||||
src.pulsed()
|
||||
var/expanded = FALSE
|
||||
if(prob(70) && expand())
|
||||
expanded = TRUE
|
||||
|
||||
var/list/blobs_to_affect = list()
|
||||
for(var/obj/structure/blob/B in urange(claim_range, src, 1))
|
||||
blobs_to_affect += B
|
||||
|
||||
shuffle_inplace(blobs_to_affect)
|
||||
|
||||
for(var/L in blobs_to_affect)
|
||||
var/obj/structure/blob/B = L
|
||||
if(!B.overmind && !istype(B, /obj/structure/blob/core) && prob(30))
|
||||
B.overmind = pulsing_overmind //reclaim unclaimed, non-core blobs.
|
||||
B.update_icon()
|
||||
|
||||
var/distance = get_dist(get_turf(src), get_turf(B))
|
||||
var/expand_probablity = max(50 / (max(distance, 1)), 1)
|
||||
if(overmind)
|
||||
expand_probablity *= overmind.blob_type.spread_modifier
|
||||
if(overmind.blob_type.slow_spread_with_size)
|
||||
expand_probablity /= (blobs.len / 10)
|
||||
|
||||
if(distance <= expand_range)
|
||||
var/can_expand = TRUE
|
||||
if(blobs_to_affect.len >= 120 && B.heal_timestamp > world.time)
|
||||
can_expand = FALSE
|
||||
if(!expanded && can_expand && B.pulse_timestamp <= world.time && prob(expand_probablity))
|
||||
var/obj/structure/blob/newB = B.expand(null, null, !expanded) //expansion falls off with range but is faster near the blob causing the expansion
|
||||
if(newB)
|
||||
if(expanded)
|
||||
qdel(newB)
|
||||
expanded = TRUE
|
||||
|
||||
if(distance <= pulse_range)
|
||||
B.pulsed()
|
||||
|
||||
/obj/structure/blob/proc/expand(turf/T = null, controller = null, expand_reaction = 1)
|
||||
if(!T)
|
||||
var/list/dirs = cardinal.Copy()
|
||||
for(var/i = 1 to 4)
|
||||
var/dirn = pick(dirs)
|
||||
dirs.Remove(dirn)
|
||||
T = get_step(src, dirn)
|
||||
if(!(locate(/obj/structure/blob) in T))
|
||||
break
|
||||
else
|
||||
T = null
|
||||
if(!T)
|
||||
return FALSE
|
||||
|
||||
var/make_blob = TRUE //can we make a blob?
|
||||
|
||||
if(istype(T, /turf/space) && !(locate(/obj/structure/lattice) in T) && prob(80))
|
||||
make_blob = FALSE
|
||||
playsound(src.loc, 'sound/effects/splat.ogg', 50, 1) //Let's give some feedback that we DID try to spawn in space, since players are used to it
|
||||
|
||||
consume_tile() //hit the tile we're in, making sure there are no border objects blocking us
|
||||
|
||||
if(!T.CanPass(src, T)) //is the target turf impassable
|
||||
make_blob = FALSE
|
||||
T.blob_act(src) //hit the turf if it is
|
||||
|
||||
for(var/atom/A in T)
|
||||
if(!A.CanPass(src, T)) //is anything in the turf impassable
|
||||
make_blob = FALSE
|
||||
A.blob_act(src) //also hit everything in the turf
|
||||
|
||||
if(make_blob) //well, can we?
|
||||
var/obj/structure/blob/B = new /obj/structure/blob/normal(src.loc)
|
||||
if(controller)
|
||||
B.overmind = controller
|
||||
else
|
||||
B.overmind = overmind
|
||||
B.density = TRUE
|
||||
if(T.Enter(B,src)) //NOW we can attempt to move into the tile
|
||||
sleep(1) // To have the slide animation work.
|
||||
B.density = initial(B.density)
|
||||
B.forceMove(T)
|
||||
B.update_icon()
|
||||
if(B.overmind && expand_reaction)
|
||||
B.overmind.blob_type.on_expand(src, B, T, B.overmind)
|
||||
return B
|
||||
|
||||
else
|
||||
blob_attack_animation(T, controller)
|
||||
T.blob_act(src) //if we can't move in hit the turf again
|
||||
qdel(B) //we should never get to this point, since we checked before moving in. destroy the blob so we don't have two blobs on one tile
|
||||
return null
|
||||
else
|
||||
blob_attack_animation(T, controller) //if we can't, animate that we attacked
|
||||
return null
|
||||
|
||||
/obj/structure/blob/proc/consume_tile()
|
||||
for(var/atom/A in loc)
|
||||
A.blob_act(src)
|
||||
if(loc && loc.density)
|
||||
loc.blob_act(src) //don't ask how a wall got on top of the core, just eat it
|
||||
|
||||
/obj/structure/blob/proc/blob_glow_animation()
|
||||
flick("[icon_state]_glow", src)
|
||||
|
||||
/obj/structure/blob/proc/blob_attack_animation(atom/A = null, controller) //visually attacks an atom
|
||||
var/obj/effect/temporary_effect/blob_attack/O = new /obj/effect/temporary_effect/blob_attack(src.loc)
|
||||
O.set_dir(dir)
|
||||
if(controller)
|
||||
var/mob/observer/blob/BO = controller
|
||||
O.color = BO.blob_type.color
|
||||
O.alpha = 200
|
||||
else if(overmind)
|
||||
O.color = overmind.blob_type.color
|
||||
if(A)
|
||||
O.do_attack_animation(A) //visually attack the whatever
|
||||
return O //just in case you want to do something to the animation.
|
||||
|
||||
/obj/structure/blob/proc/change_to(type, controller)
|
||||
if(!ispath(type))
|
||||
throw EXCEPTION("change_to(): invalid type for blob")
|
||||
return
|
||||
var/obj/structure/blob/B = new type(src.loc, controller)
|
||||
if(controller)
|
||||
B.overmind = controller
|
||||
B.update_icon()
|
||||
B.set_dir(dir)
|
||||
qdel(src)
|
||||
return B
|
||||
|
||||
/obj/structure/blob/attackby(var/obj/item/weapon/W, var/mob/user)
|
||||
user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
|
||||
playsound(loc, 'sound/effects/attackblob.ogg', 50, 1)
|
||||
visible_message("<span class='danger'>\The [src] has been attacked with \the [W][(user ? " by [user]." : ".")]</span>")
|
||||
var/damage = W.force
|
||||
switch(W.damtype)
|
||||
if(BURN)
|
||||
if(overmind)
|
||||
damage *= overmind.blob_type.burn_multiplier
|
||||
else
|
||||
damage *= 2
|
||||
|
||||
if(damage > 0)
|
||||
playsound(src.loc, 'sound/items/welder.ogg', 100, 1)
|
||||
else
|
||||
playsound(src, 'sound/weapons/tap.ogg', 50, 1)
|
||||
if(BRUTE)
|
||||
if(overmind)
|
||||
damage *= overmind.blob_type.brute_multiplier
|
||||
else
|
||||
damage *= 2
|
||||
|
||||
if(damage > 0)
|
||||
playsound(src.loc, 'sound/effects/attackblob.ogg', 50, 1)
|
||||
else
|
||||
playsound(src, 'sound/weapons/tap.ogg', 50, 1)
|
||||
if(overmind)
|
||||
damage = overmind.blob_type.on_received_damage(src, damage, W.damtype, user)
|
||||
adjust_integrity(-damage)
|
||||
return
|
||||
|
||||
/obj/structure/blob/bullet_act(var/obj/item/projectile/P)
|
||||
if(!P)
|
||||
return
|
||||
|
||||
var/damage = P.damage
|
||||
switch(P.damage_type)
|
||||
if(BRUTE)
|
||||
if(overmind)
|
||||
damage *= overmind.blob_type.brute_multiplier
|
||||
if(BURN)
|
||||
if(overmind)
|
||||
damage *= overmind.blob_type.burn_multiplier
|
||||
|
||||
if(overmind)
|
||||
damage = overmind.blob_type.on_received_damage(src, damage, P.damage_type, P.firer)
|
||||
|
||||
adjust_integrity(-damage)
|
||||
|
||||
return ..()
|
||||
|
||||
/obj/structure/blob/water_act(amount)
|
||||
if(overmind)
|
||||
overmind.blob_type.on_water(src, amount)
|
||||
|
||||
/obj/structure/blob/proc/adjust_integrity(amount)
|
||||
integrity = between(0, integrity + amount, max_integrity)
|
||||
if(integrity == 0)
|
||||
playsound(loc, 'sound/effects/splat.ogg', 50, 1)
|
||||
if(overmind)
|
||||
overmind.blob_type.on_death(src)
|
||||
qdel(src)
|
||||
else
|
||||
update_icon()
|
||||
|
||||
/obj/effect/temporary_effect/blob_attack
|
||||
name = "blob"
|
||||
desc = "The blob lashing out at something."
|
||||
icon = 'icons/effects/effects.dmi'
|
||||
icon_state = "blob_attack"
|
||||
layer = 5.2
|
||||
time_to_die = 6
|
||||
alpha = 140
|
||||
invisibility = 0
|
||||
mouse_opacity = 0
|
||||
new_light_range = 0
|
||||
new_light_power = 0
|
||||
|
||||
/obj/structure/grille/blob_act()
|
||||
qdel(src)
|
||||
|
||||
/turf/simulated/wall/blob_act()
|
||||
take_damage(100)
|
||||
179
code/modules/blob2/blobs/core.dm
Normal file
179
code/modules/blob2/blobs/core.dm
Normal file
@@ -0,0 +1,179 @@
|
||||
var/list/blob_cores = list()
|
||||
|
||||
/obj/structure/blob/core
|
||||
name = "blob core"
|
||||
base_name = "core"
|
||||
icon = 'icons/mob/blob.dmi'
|
||||
icon_state = "blank_blob"
|
||||
desc = "A huge, pulsating yellow mass."
|
||||
max_integrity = 150
|
||||
point_return = -1
|
||||
health_regen = 0 //we regen in Life() instead of when pulsed
|
||||
var/datum/blob_type/desired_blob_type = null // If this is set, the core always creates an overmind possessing this blob type.
|
||||
var/difficulty_threshold = null // Otherwise if this is set, it picks a random blob_type that is equal or lower in difficulty.
|
||||
var/core_regen = 2
|
||||
var/overmind_get_delay = 0 //we don't want to constantly try to find an overmind, this var tracks when we'll try to get an overmind again
|
||||
var/resource_delay = 0
|
||||
var/point_rate = 2
|
||||
var/ai_controlled = TRUE
|
||||
|
||||
// Spawn this if you want a ghost to be able to play as the blob.
|
||||
/obj/structure/blob/core/player
|
||||
ai_controlled = FALSE
|
||||
|
||||
// Spawn these if you want a semi-random blob.
|
||||
/obj/structure/blob/core/random_easy
|
||||
difficulty_threshold = BLOB_DIFFICULTY_EASY
|
||||
|
||||
/obj/structure/blob/core/random_medium
|
||||
difficulty_threshold = BLOB_DIFFICULTY_MEDIUM
|
||||
|
||||
/obj/structure/blob/core/random_hard
|
||||
difficulty_threshold = BLOB_DIFFICULTY_HARD
|
||||
|
||||
// Spawn these if you want a specific blob.
|
||||
/obj/structure/blob/core/blazing_oil
|
||||
desired_blob_type = /datum/blob_type/blazing_oil
|
||||
|
||||
/obj/structure/blob/core/grey_goo
|
||||
desired_blob_type = /datum/blob_type/grey_goo
|
||||
|
||||
/obj/structure/blob/core/electromagnetic_web
|
||||
desired_blob_type = /datum/blob_type/electromagnetic_web
|
||||
|
||||
/obj/structure/blob/core/fungal_bloom
|
||||
desired_blob_type = /datum/blob_type/fungal_bloom
|
||||
|
||||
/obj/structure/blob/core/fulminant_organism
|
||||
desired_blob_type = /datum/blob_type/fulminant_organism
|
||||
|
||||
/obj/structure/blob/core/reactive_spines
|
||||
desired_blob_type = /datum/blob_type/reactive_spines
|
||||
|
||||
/obj/structure/blob/core/synchronous_mesh
|
||||
desired_blob_type = /datum/blob_type/synchronous_mesh
|
||||
|
||||
/obj/structure/blob/core/shifting_fragments
|
||||
desired_blob_type = /datum/blob_type/shifting_fragments
|
||||
|
||||
/obj/structure/blob/core/cryogenic_goo
|
||||
desired_blob_type = /datum/blob_type/cryogenic_goo
|
||||
|
||||
/obj/structure/blob/core/energized_jelly
|
||||
desired_blob_type = /datum/blob_type/energized_jelly
|
||||
|
||||
/obj/structure/blob/core/explosive_lattice
|
||||
desired_blob_type = /datum/blob_type/explosive_lattice
|
||||
|
||||
/obj/structure/blob/core/pressurized_slime
|
||||
desired_blob_type = /datum/blob_type/pressurized_slime
|
||||
|
||||
/obj/structure/blob/core/radioactive_ooze
|
||||
desired_blob_type = /datum/blob_type/radioactive_ooze
|
||||
|
||||
/obj/structure/blob/core/classic
|
||||
desired_blob_type = /datum/blob_type/classic
|
||||
|
||||
/obj/structure/blob/core/New(var/newloc, var/client/new_overmind = null, new_rate = 2, placed = 0)
|
||||
..(newloc)
|
||||
blob_cores += src
|
||||
processing_objects += src
|
||||
update_icon() //so it atleast appears
|
||||
if(!placed && !overmind)
|
||||
create_overmind(new_overmind)
|
||||
if(overmind)
|
||||
update_icon()
|
||||
point_rate = new_rate
|
||||
|
||||
/obj/structure/blob/core/Destroy()
|
||||
blob_cores -= src
|
||||
if(overmind)
|
||||
overmind.blob_core = null
|
||||
qdel(overmind)
|
||||
overmind = null
|
||||
processing_objects -= src
|
||||
return ..()
|
||||
|
||||
/obj/structure/blob/core/update_icon()
|
||||
overlays.Cut()
|
||||
color = null
|
||||
var/mutable_appearance/blob_overlay = mutable_appearance('icons/mob/blob.dmi', "blob")
|
||||
if(overmind)
|
||||
blob_overlay.color = overmind.blob_type.color
|
||||
name = "[overmind.blob_type.name] [base_name]"
|
||||
overlays += blob_overlay
|
||||
overlays += mutable_appearance('icons/mob/blob.dmi', "blob_core_overlay")
|
||||
|
||||
/obj/structure/blob/core/process()
|
||||
set waitfor = FALSE
|
||||
if(QDELETED(src))
|
||||
return
|
||||
if(!overmind)
|
||||
spawn(0)
|
||||
create_overmind()
|
||||
else
|
||||
if(resource_delay <= world.time)
|
||||
resource_delay = world.time + 1 SECOND
|
||||
overmind.add_points(point_rate)
|
||||
integrity = min(max_integrity, integrity + core_regen)
|
||||
// if(overmind)
|
||||
// overmind.update_health_hud()
|
||||
pulse_area(overmind, 15, BLOB_CORE_PULSE_RANGE, BLOB_CORE_EXPAND_RANGE)
|
||||
for(var/obj/structure/blob/normal/B in range(1, src))
|
||||
if(prob(5))
|
||||
B.change_to(/obj/structure/blob/shield/core, overmind)
|
||||
|
||||
/obj/structure/blob/core/proc/create_overmind(client/new_overmind, override_delay)
|
||||
if(overmind_get_delay > world.time && !override_delay)
|
||||
return
|
||||
if(!ai_controlled) // Do we want a bona fide player blob?
|
||||
overmind_get_delay = world.time + 15 SECONDS //if this fails, we'll try again in 15 seconds
|
||||
|
||||
if(overmind)
|
||||
qdel(overmind)
|
||||
|
||||
|
||||
var/client/C = null
|
||||
if(!new_overmind)
|
||||
var/datum/ghost_query/Q = new /datum/ghost_query/blob()
|
||||
var/list/winner = Q.query()
|
||||
if(winner.len)
|
||||
var/mob/observer/dead/D = winner[1]
|
||||
C = D.client
|
||||
|
||||
else
|
||||
C = new_overmind
|
||||
|
||||
if(C)
|
||||
if(!desired_blob_type && !isnull(difficulty_threshold))
|
||||
desired_blob_type = get_random_blob_type()
|
||||
var/mob/observer/blob/B = new(loc, TRUE, 60, desired_blob_type)
|
||||
B.key = C.key
|
||||
B.blob_core = src
|
||||
src.overmind = B
|
||||
update_icon()
|
||||
if(B.mind && !B.mind.special_role)
|
||||
B.mind.special_role = "Blob Overmind"
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
else // An AI opponent.
|
||||
if(!desired_blob_type && !isnull(difficulty_threshold))
|
||||
desired_blob_type = get_random_blob_type()
|
||||
var/mob/observer/blob/B = new(loc, TRUE, 60, desired_blob_type)
|
||||
overmind = B
|
||||
B.blob_core = src
|
||||
B.ai_controlled = TRUE
|
||||
update_icon()
|
||||
return TRUE
|
||||
|
||||
/obj/structure/blob/core/proc/get_random_blob_type()
|
||||
if(!difficulty_threshold)
|
||||
return
|
||||
var/list/valid_types = list()
|
||||
for(var/thing in subtypesof(/datum/blob_type))
|
||||
var/datum/blob_type/BT = thing
|
||||
if(initial(BT.difficulty) > difficulty_threshold)
|
||||
continue
|
||||
valid_types += BT
|
||||
return pick(valid_types)
|
||||
37
code/modules/blob2/blobs/factory.dm
Normal file
37
code/modules/blob2/blobs/factory.dm
Normal file
@@ -0,0 +1,37 @@
|
||||
/obj/structure/blob/factory
|
||||
name = "factory blob"
|
||||
base_name = "factory"
|
||||
icon = 'icons/mob/blob.dmi'
|
||||
icon_state = "blob_factory"
|
||||
desc = "A thick spire of tendrils."
|
||||
description_info = "A section of the blob that creates numerous hostile entities to attack enemies of the blob. \
|
||||
It requires a 'node' blob be nearby, or it will cease functioning."
|
||||
max_integrity = 40
|
||||
health_regen = 1
|
||||
point_return = 25
|
||||
var/list/spores = list()
|
||||
var/max_spores = 3
|
||||
var/spore_delay = 0
|
||||
var/spore_cooldown = 8 SECONDS
|
||||
|
||||
/obj/structure/blob/factory/Destroy()
|
||||
for(var/mob/living/simple_animal/hostile/blob/spore/spore in spores)
|
||||
if(spore.factory == src)
|
||||
spore.factory = null
|
||||
spores = null
|
||||
return ..()
|
||||
|
||||
/obj/structure/blob/factory/pulsed()
|
||||
. = ..()
|
||||
if(spores.len >= max_spores)
|
||||
return
|
||||
if(spore_delay > world.time)
|
||||
return
|
||||
flick("blob_factory_glow", src)
|
||||
spore_delay = world.time + spore_cooldown
|
||||
var/mob/living/simple_animal/hostile/blob/spore/S = null
|
||||
if(overmind)
|
||||
S = new overmind.blob_type.spore_type(src.loc, src)
|
||||
S.overmind = overmind
|
||||
S.update_icons()
|
||||
overmind.blob_mobs.Add(S)
|
||||
36
code/modules/blob2/blobs/node.dm
Normal file
36
code/modules/blob2/blobs/node.dm
Normal file
@@ -0,0 +1,36 @@
|
||||
var/list/blob_nodes = list()
|
||||
|
||||
/obj/structure/blob/node
|
||||
name = "blob node"
|
||||
base_name = "node"
|
||||
icon_state = "blank_blob"
|
||||
desc = "A large, pulsating yellow mass."
|
||||
max_integrity = 50
|
||||
health_regen = 3
|
||||
point_return = 50
|
||||
|
||||
/obj/structure/blob/node/New(var/newloc)
|
||||
..()
|
||||
blob_nodes += src
|
||||
processing_objects += src
|
||||
update_icon()
|
||||
|
||||
/obj/structure/blob/node/Destroy()
|
||||
blob_nodes -= src
|
||||
processing_objects -= src
|
||||
return ..()
|
||||
|
||||
/obj/structure/blob/node/update_icon()
|
||||
overlays.Cut()
|
||||
color = null
|
||||
var/mutable_appearance/blob_overlay = mutable_appearance('icons/mob/blob.dmi', "blob")
|
||||
if(overmind)
|
||||
name = "[overmind.blob_type.name] [base_name]"
|
||||
blob_overlay.color = overmind.blob_type.color
|
||||
overlays += blob_overlay
|
||||
overlays += mutable_appearance('icons/mob/blob.dmi', "blob_node_overlay")
|
||||
|
||||
/obj/structure/blob/node/process()
|
||||
set waitfor = FALSE
|
||||
if(overmind) // This check is so that if the core is killed, the nodes stop.
|
||||
pulse_area(overmind, 10, BLOB_NODE_PULSE_RANGE, BLOB_NODE_EXPAND_RANGE)
|
||||
22
code/modules/blob2/blobs/normal.dm
Normal file
22
code/modules/blob2/blobs/normal.dm
Normal file
@@ -0,0 +1,22 @@
|
||||
/obj/structure/blob/normal
|
||||
name = "normal blob"
|
||||
base_name = "blob"
|
||||
icon_state = "blob"
|
||||
light_range = 0
|
||||
integrity = 21 //doesn't start at full health
|
||||
max_integrity = 25
|
||||
health_regen = 1
|
||||
|
||||
/obj/structure/blob/normal/update_icon()
|
||||
..()
|
||||
if(integrity <= 15)
|
||||
icon_state = "blob_damaged"
|
||||
desc = "A thin lattice of slightly twitching tendrils."
|
||||
else
|
||||
icon_state = "blob"
|
||||
desc = "A thick wall of writhing tendrils."
|
||||
|
||||
if(overmind)
|
||||
name = "[overmind.blob_type.name]"
|
||||
else
|
||||
name = "inert [base_name]"
|
||||
30
code/modules/blob2/blobs/resource.dm
Normal file
30
code/modules/blob2/blobs/resource.dm
Normal file
@@ -0,0 +1,30 @@
|
||||
/obj/structure/blob/resource
|
||||
name = "resource blob"
|
||||
base_name = "resource blob"
|
||||
icon = 'icons/mob/blob.dmi'
|
||||
icon_state = "blob_resource"
|
||||
desc = "A thin spire of slightly swaying tendrils."
|
||||
max_integrity = 40
|
||||
point_return = 15
|
||||
var/resource_delay = 0
|
||||
|
||||
/obj/structure/blob/resource/New(var/newloc, var/new_overmind)
|
||||
..(newloc, new_overmind)
|
||||
if(overmind)
|
||||
overmind.resource_blobs += src
|
||||
|
||||
/obj/structure/blob/resource/Destroy()
|
||||
if(overmind)
|
||||
overmind.resource_blobs -= src
|
||||
return ..()
|
||||
|
||||
/obj/structure/blob/resource/pulsed()
|
||||
. = ..()
|
||||
if(resource_delay > world.time)
|
||||
return
|
||||
flick("blob_resource_glow", src)
|
||||
if(overmind)
|
||||
overmind.add_points(1)
|
||||
resource_delay = world.time + 4 SECONDS + (overmind.resource_blobs.len * 2.5) //4 seconds plus a quarter second for each resource blob the overmind has
|
||||
else
|
||||
resource_delay = world.time + 4 SECONDS
|
||||
25
code/modules/blob2/blobs/shield.dm
Normal file
25
code/modules/blob2/blobs/shield.dm
Normal file
@@ -0,0 +1,25 @@
|
||||
/obj/structure/blob/shield
|
||||
name = "thick blob"
|
||||
base_name = "thick"
|
||||
icon = 'icons/mob/blob.dmi'
|
||||
icon_state = "blob_shield"
|
||||
desc = "A solid wall of slightly twitching tendrils."
|
||||
max_integrity = 100
|
||||
point_return = 4
|
||||
|
||||
/obj/structure/blob/shield/core
|
||||
point_return = 0
|
||||
|
||||
/obj/structure/blob/shield/update_icon()
|
||||
..()
|
||||
if(integrity <= 75)
|
||||
icon_state = "blob_shield_damaged"
|
||||
desc = "A wall of twitching tendrils."
|
||||
else
|
||||
icon_state = initial(icon_state)
|
||||
desc = initial(desc)
|
||||
|
||||
if(overmind)
|
||||
name = "[base_name] [overmind.blob_type.name]"
|
||||
else
|
||||
name = "inert [base_name] blob"
|
||||
57
code/modules/blob2/mobs/blob_mob.dm
Normal file
57
code/modules/blob2/mobs/blob_mob.dm
Normal file
@@ -0,0 +1,57 @@
|
||||
////////////////
|
||||
// BASE TYPE //
|
||||
////////////////
|
||||
|
||||
//Do not spawn
|
||||
/mob/living/simple_animal/hostile/blob
|
||||
icon = 'icons/mob/blob.dmi'
|
||||
pass_flags = PASSBLOB | PASSTABLE
|
||||
faction = "blob"
|
||||
// bubble_icon = "blob"
|
||||
// speak_emote = null //so we use verb_yell/verb_say/etc
|
||||
// atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
|
||||
// minbodytemp = 0
|
||||
// maxbodytemp = 360
|
||||
// unique_name = 1
|
||||
// a_intent = INTENT_HARM
|
||||
cooperative = TRUE
|
||||
heat_damage_per_tick = 0
|
||||
cold_damage_per_tick = 0
|
||||
min_oxy = 0
|
||||
max_tox = 0
|
||||
max_co2 = 0
|
||||
var/mob/observer/blob/overmind = null
|
||||
var/obj/structure/blob/factory/factory = null
|
||||
|
||||
/mob/living/simple_animal/hostile/blob/speech_bubble_appearance()
|
||||
return "slime"
|
||||
|
||||
/mob/living/simple_animal/hostile/blob/update_icons()
|
||||
if(overmind)
|
||||
color = overmind.blob_type.complementary_color
|
||||
else
|
||||
color = null
|
||||
|
||||
/mob/living/simple_animal/hostile/blob/Destroy()
|
||||
if(overmind)
|
||||
overmind.blob_mobs -= src
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/blob/blob_act(obj/structure/blob/B)
|
||||
if(!overmind && B.overmind)
|
||||
overmind = B.overmind
|
||||
update_icon()
|
||||
|
||||
if(stat != DEAD && health < maxHealth)
|
||||
adjustBruteLoss(-maxHealth*0.0125)
|
||||
adjustFireLoss(-maxHealth*0.0125)
|
||||
|
||||
/mob/living/simple_animal/hostile/blob/CanPass(atom/movable/mover, turf/target)
|
||||
if(istype(mover, /obj/structure/blob)) // Don't block blobs from expanding onto a tile occupied by a blob mob.
|
||||
return TRUE
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/blob/Process_Spacemove()
|
||||
for(var/obj/structure/blob/B in range(1, src))
|
||||
return TRUE
|
||||
return ..()
|
||||
110
code/modules/blob2/mobs/spore.dm
Normal file
110
code/modules/blob2/mobs/spore.dm
Normal file
@@ -0,0 +1,110 @@
|
||||
////////////////
|
||||
// BLOB SPORE //
|
||||
////////////////
|
||||
|
||||
/mob/living/simple_animal/hostile/blob/spore
|
||||
name = "blob spore"
|
||||
desc = "A floating, fragile spore."
|
||||
icon_state = "blobpod"
|
||||
icon_living = "blobpod"
|
||||
health = 30
|
||||
maxHealth = 30
|
||||
melee_damage_lower = 2
|
||||
melee_damage_upper = 4
|
||||
layer = MOB_LAYER + 0.2 // Over the blob.
|
||||
attacktext = "slams into"
|
||||
attack_sound = 'sound/effects/slime_squish.ogg'
|
||||
emote_see = list("sways", "inflates briefly")
|
||||
var/mob/living/carbon/human/infested = null // The human this thing is totally not making into a zombie.
|
||||
var/can_infest = FALSE
|
||||
var/is_infesting = FALSE
|
||||
|
||||
/mob/living/simple_animal/hostile/blob/spore/infesting
|
||||
name = "infesting blob spore"
|
||||
can_infest = TRUE
|
||||
|
||||
/mob/living/simple_animal/hostile/blob/spore/weak
|
||||
name = "fragile blob spore"
|
||||
health = 15
|
||||
maxHealth = 15
|
||||
melee_damage_lower = 1
|
||||
melee_damage_upper = 2
|
||||
|
||||
/mob/living/simple_animal/hostile/blob/spore/New(var/newloc, var/obj/structure/blob/factory/my_factory)
|
||||
if(istype(my_factory))
|
||||
factory = my_factory
|
||||
factory.spores += src
|
||||
..(newloc)
|
||||
|
||||
/mob/living/simple_animal/hostile/blob/spore/Destroy()
|
||||
if(factory)
|
||||
factory.spores -= src
|
||||
factory = null
|
||||
if(infested)
|
||||
infested.forceMove(get_turf(src))
|
||||
visible_message("<span class='warning'>\The [infested] falls to the ground as the blob spore bursts.</span>")
|
||||
infested = null
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/blob/spore/death(gibbed, deathmessage = "bursts!")
|
||||
if(overmind)
|
||||
overmind.blob_type.on_spore_death(src)
|
||||
..(gibbed, deathmessage)
|
||||
qdel(src)
|
||||
|
||||
/mob/living/simple_animal/hostile/blob/spore/update_icons()
|
||||
if(overmind)
|
||||
color = overmind.blob_type.complementary_color
|
||||
set_light(3, 5, color)
|
||||
else
|
||||
color = null
|
||||
set_light(0)
|
||||
|
||||
if(is_infesting)
|
||||
overlays.Cut()
|
||||
icon = infested.icon
|
||||
overlays = infested.overlays
|
||||
var/mutable_appearance/blob_head_overlay = mutable_appearance('icons/mob/blob.dmi', "blob_head")
|
||||
if(overmind)
|
||||
blob_head_overlay.color = overmind.blob_type.complementary_color
|
||||
color = initial(color)//looks better.
|
||||
overlays += blob_head_overlay
|
||||
|
||||
/mob/living/simple_animal/hostile/blob/spore/Life()
|
||||
if(can_infest && !is_infesting && isturf(src.loc))
|
||||
for(var/mob/living/carbon/human/H in view(src,1))
|
||||
if(H.stat != DEAD) // We want zombies.
|
||||
continue
|
||||
if(H.isSynthetic()) // Not philosophical zombies.
|
||||
continue
|
||||
infest(H)
|
||||
break
|
||||
if(factory && z != factory.z) // This is to prevent spores getting lost in space and making the factory useless.
|
||||
qdel(src)
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/hostile/blob/spore/proc/infest(mob/living/carbon/human/H)
|
||||
is_infesting = TRUE
|
||||
if(H.wear_suit)
|
||||
var/obj/item/clothing/suit/A = H.wear_suit
|
||||
if(A.armor && A.armor["melee"])
|
||||
maxHealth += A.armor["melee"] //That zombie's got armor, I want armor!
|
||||
|
||||
maxHealth += 40
|
||||
health = maxHealth
|
||||
name = "Infested [H.real_name]" // Not using the Z word.
|
||||
desc = "A parasitic organism attached to a deceased body, controlling it directly as if it were a puppet."
|
||||
melee_damage_lower += 8 // 10 total.
|
||||
melee_damage_upper += 11 // 15 total.
|
||||
emote_see = list("shambles around", "twitches", "stares")
|
||||
attacktext = "claws"
|
||||
|
||||
H.forceMove(src)
|
||||
infested = H
|
||||
|
||||
update_icons()
|
||||
visible_message("<span class='warning'>The corpse of [H.name] suddenly rises!</span>")
|
||||
|
||||
/mob/living/simple_animal/hostile/blob/spore/GetIdCard()
|
||||
if(infested) // If we've infested someone, use their ID.
|
||||
return infested.GetIdCard()
|
||||
97
code/modules/blob2/overmind/overmind.dm
Normal file
97
code/modules/blob2/overmind/overmind.dm
Normal file
@@ -0,0 +1,97 @@
|
||||
var/list/overminds = list()
|
||||
|
||||
/mob/observer/blob
|
||||
name = "Blob Overmind"
|
||||
real_name = "Blob Overmind"
|
||||
desc = "The overmind. It controls the blob."
|
||||
icon = 'icons/mob/blob.dmi'
|
||||
icon_state = "marker"
|
||||
mouse_opacity = 1
|
||||
see_in_dark = 8
|
||||
invisibility = INVISIBILITY_OBSERVER
|
||||
layer = FLY_LAYER + 0.1
|
||||
|
||||
faction = "blob"
|
||||
var/obj/structure/blob/core/blob_core = null // The blob overmind's core
|
||||
var/blob_points = 0
|
||||
var/max_blob_points = 200
|
||||
var/last_attack = 0
|
||||
var/datum/blob_type/blob_type = null
|
||||
var/list/blob_mobs = list()
|
||||
var/list/resource_blobs = list()
|
||||
var/placed = 0
|
||||
var/base_point_rate = 2 //for blob core placement
|
||||
var/ai_controlled = TRUE
|
||||
var/auto_pilot = FALSE // If true, and if a client is attached, the AI routine will continue running.
|
||||
|
||||
/mob/observer/blob/New(var/newloc, pre_placed = 0, starting_points = 60, desired_blob_type = null)
|
||||
blob_points = starting_points
|
||||
if(pre_placed) //we already have a core!
|
||||
placed = 1
|
||||
|
||||
overminds += src
|
||||
var/new_name = "[initial(name)] ([rand(1, 999)])"
|
||||
name = new_name
|
||||
real_name = new_name
|
||||
if(desired_blob_type)
|
||||
blob_type = new desired_blob_type()
|
||||
else
|
||||
var/datum/blob_type/BT = pick(subtypesof(/datum/blob_type))
|
||||
blob_type = new BT()
|
||||
color = blob_type.complementary_color
|
||||
if(blob_core)
|
||||
blob_core.update_icon()
|
||||
level_seven_blob_announcement(blob_core)
|
||||
|
||||
..(newloc)
|
||||
|
||||
/mob/observer/blob/Destroy()
|
||||
for(var/BL in blobs)
|
||||
var/obj/structure/blob/B = BL
|
||||
if(B && B.overmind == src)
|
||||
B.overmind = null
|
||||
B.update_icon() //reset anything that was ours
|
||||
|
||||
for(var/BLO in blob_mobs)
|
||||
var/mob/living/simple_animal/hostile/blob/BM = BLO
|
||||
if(BM)
|
||||
BM.overmind = null
|
||||
BM.update_icons()
|
||||
|
||||
overminds -= src
|
||||
return ..()
|
||||
|
||||
/mob/observer/blob/Stat()
|
||||
..()
|
||||
if(statpanel("Status"))
|
||||
if(blob_core)
|
||||
stat(null, "Core Health: [blob_core.integrity]")
|
||||
stat(null, "Power Stored: [blob_points]/[max_blob_points]")
|
||||
stat(null, "Total Blobs: [blobs.len]")
|
||||
|
||||
/mob/observer/blob/Move(NewLoc, Dir = 0)
|
||||
if(placed)
|
||||
var/obj/structure/blob/B = locate() in range("3x3", NewLoc)
|
||||
if(B)
|
||||
forceMove(NewLoc)
|
||||
return TRUE
|
||||
else
|
||||
return FALSE
|
||||
else
|
||||
var/area/A = get_area(NewLoc)
|
||||
if(istype(NewLoc, /turf/space) || istype(A, /area/shuttle)) //if unplaced, can't go on shuttles or space tiles
|
||||
return FALSE
|
||||
forceMove(NewLoc)
|
||||
return TRUE
|
||||
|
||||
/mob/observer/blob/proc/add_points(points)
|
||||
blob_points = between(0, blob_points + points, max_blob_points)
|
||||
|
||||
/mob/observer/blob/Life()
|
||||
if(ai_controlled && (!client || auto_pilot))
|
||||
if(prob(blob_type.ai_aggressiveness))
|
||||
auto_attack()
|
||||
|
||||
if(blob_points >= 100)
|
||||
if(!auto_factory() && !auto_resource())
|
||||
auto_node()
|
||||
229
code/modules/blob2/overmind/powers.dm
Normal file
229
code/modules/blob2/overmind/powers.dm
Normal file
@@ -0,0 +1,229 @@
|
||||
/mob/observer/blob/proc/can_buy(cost = 15)
|
||||
if(blob_points < cost)
|
||||
to_chat(src, "<span class='warning'>You cannot afford this, you need at least [cost] resources!</span>")
|
||||
return FALSE
|
||||
add_points(-cost)
|
||||
return TRUE
|
||||
|
||||
/mob/observer/blob/verb/transport_core()
|
||||
set category = "Blob"
|
||||
set name = "Jump to Core"
|
||||
set desc = "Move your camera to your core."
|
||||
|
||||
if(blob_core)
|
||||
forceMove(blob_core.loc)
|
||||
|
||||
/mob/observer/blob/proc/createSpecial(price, blobType, nearEquals, needsNode, turf/T)
|
||||
if(!T)
|
||||
T = get_turf(src)
|
||||
var/obj/structure/blob/B = (locate(/obj/structure/blob) in T)
|
||||
|
||||
if(!B)
|
||||
to_chat(src, "<span class='warning'>There is no blob here!</span>")
|
||||
return
|
||||
|
||||
if(!istype(B, /obj/structure/blob/normal))
|
||||
to_chat(src, "<span class='warning'>Unable to use this blob, find a normal one.</span>")
|
||||
return
|
||||
|
||||
if(nearEquals)
|
||||
for(var/obj/structure/blob/L in orange(nearEquals, T))
|
||||
if(L.type == blobType)
|
||||
to_chat(src, "<span class='warning'>There is a similar blob nearby, move more than [nearEquals] tiles away from it!</span>")
|
||||
return
|
||||
|
||||
if(!can_buy(price))
|
||||
return
|
||||
|
||||
var/obj/structure/blob/N = B.change_to(blobType, src)
|
||||
return N
|
||||
|
||||
/mob/observer/blob/verb/create_shield_power()
|
||||
set category = "Blob"
|
||||
set name = "Create Shield Blob (15)"
|
||||
set desc = "Create a shield blob, which is hard to kill."
|
||||
create_shield()
|
||||
|
||||
/mob/observer/blob/proc/create_shield(turf/T)
|
||||
createSpecial(15, /obj/structure/blob/shield, 0, 0, T)
|
||||
|
||||
/mob/observer/blob/verb/create_resource()
|
||||
set category = "Blob"
|
||||
set name = "Create Resource Blob (40)"
|
||||
set desc = "Create a resource tower which will generate resources for you."
|
||||
|
||||
if(!blob_type.can_build_resources)
|
||||
return FALSE
|
||||
|
||||
createSpecial(40, /obj/structure/blob/resource, 4, 1)
|
||||
|
||||
/mob/observer/blob/verb/auto_resource()
|
||||
set category = "Blob"
|
||||
set name = "Auto Resource Blob (40)"
|
||||
set desc = "Automatically places a resource tower near a node or your core, at a sufficent distance."
|
||||
|
||||
if(!blob_type.can_build_resources)
|
||||
return FALSE
|
||||
|
||||
var/obj/structure/blob/B = null
|
||||
var/list/potential_blobs = blobs.Copy()
|
||||
while(potential_blobs.len)
|
||||
var/obj/structure/blob/temp = pick(potential_blobs)
|
||||
if(!(locate(/obj/structure/blob/node) in range(temp, BLOB_NODE_PULSE_RANGE) ) && !(locate(/obj/structure/blob/core) in range(temp, BLOB_CORE_PULSE_RANGE) ))
|
||||
potential_blobs -= temp // Can't be pulsed.
|
||||
else if(locate(/obj/structure/blob/resource) in range(temp, 4) )
|
||||
potential_blobs -= temp // Too close to another resource blob.
|
||||
else if(locate(/obj/structure/blob/core) in range(temp, 1) )
|
||||
potential_blobs -= temp // Don't take up the core's shield spot.
|
||||
else if(!istype(temp, /obj/structure/blob/normal))
|
||||
potential_blobs -= temp // Not a normal blob.
|
||||
else
|
||||
B = temp
|
||||
break
|
||||
|
||||
CHECK_TICK // Iterating over a list containing hundreds of blobs can get taxing.
|
||||
|
||||
if(B)
|
||||
forceMove(B.loc)
|
||||
return createSpecial(40, /obj/structure/blob/resource, 4, 1, B.loc)
|
||||
|
||||
|
||||
/mob/observer/blob/verb/create_factory()
|
||||
set category = "Blob"
|
||||
set name = "Create Factory Blob (60)"
|
||||
set desc = "Create a spore tower that will spawn spores to harass your enemies."
|
||||
|
||||
if(!blob_type.can_build_factories)
|
||||
return FALSE
|
||||
|
||||
createSpecial(60, /obj/structure/blob/factory, 7, 1)
|
||||
|
||||
/mob/observer/blob/verb/auto_factory()
|
||||
set category = "Blob"
|
||||
set name = "Auto Factory Blob (60)"
|
||||
set desc = "Automatically places a resource tower near a node or your core, at a sufficent distance."
|
||||
|
||||
if(!blob_type.can_build_factories)
|
||||
return FALSE
|
||||
|
||||
var/obj/structure/blob/B = null
|
||||
var/list/potential_blobs = blobs.Copy()
|
||||
while(potential_blobs.len)
|
||||
var/obj/structure/blob/temp = pick(potential_blobs)
|
||||
if(!(locate(/obj/structure/blob/node) in range(temp, BLOB_NODE_PULSE_RANGE) ) && !(locate(/obj/structure/blob/core) in range(temp, BLOB_CORE_PULSE_RANGE) ))
|
||||
potential_blobs -= temp // Can't be pulsed.
|
||||
else if(locate(/obj/structure/blob/factory) in range(temp, 7) )
|
||||
potential_blobs -= temp // Too close to another factory blob.
|
||||
else if(locate(/obj/structure/blob/core) in range(temp, 1) )
|
||||
potential_blobs -= temp // Don't take up the core's shield spot.
|
||||
else if(!istype(temp, /obj/structure/blob/normal))
|
||||
potential_blobs -= temp // Not a normal blob.
|
||||
else
|
||||
B = temp
|
||||
break
|
||||
|
||||
CHECK_TICK
|
||||
|
||||
if(B)
|
||||
forceMove(B.loc)
|
||||
return createSpecial(60, /obj/structure/blob/factory, 7, 1, B.loc)
|
||||
|
||||
|
||||
|
||||
/mob/observer/blob/verb/create_node()
|
||||
set category = "Blob"
|
||||
set name = "Create Node Blob (100)"
|
||||
set desc = "Create a node, which will expand blobs around it, and power nearby factory and resource blobs."
|
||||
|
||||
if(!blob_type.can_build_nodes)
|
||||
return FALSE
|
||||
|
||||
createSpecial(100, /obj/structure/blob/node, 5, 0)
|
||||
|
||||
/mob/observer/blob/verb/auto_node()
|
||||
set category = "Blob"
|
||||
set name = "Auto Node Blob (100)"
|
||||
set desc = "Automatically places a node blob at a sufficent distance."
|
||||
|
||||
if(!blob_type.can_build_nodes)
|
||||
return FALSE
|
||||
|
||||
var/obj/structure/blob/B = null
|
||||
var/list/potential_blobs = blobs.Copy()
|
||||
while(potential_blobs.len)
|
||||
var/obj/structure/blob/temp = pick(potential_blobs)
|
||||
if(locate(/obj/structure/blob/node) in range(temp, 5) )
|
||||
potential_blobs -= temp
|
||||
else if(locate(/obj/structure/blob/core) in range(temp, 5) )
|
||||
potential_blobs -= temp
|
||||
else if(!istype(temp, /obj/structure/blob/normal))
|
||||
potential_blobs -= temp
|
||||
else
|
||||
B = temp
|
||||
break
|
||||
|
||||
CHECK_TICK
|
||||
|
||||
if(B)
|
||||
forceMove(B.loc)
|
||||
return createSpecial(100, /obj/structure/blob/node, 5, 0, B.loc)
|
||||
|
||||
|
||||
|
||||
/mob/observer/blob/verb/expand_blob_power()
|
||||
set category = "Blob"
|
||||
set name = "Expand/Attack Blob (4)"
|
||||
set desc = "Attempts to create a new blob in this tile. If the tile isn't clear, instead attacks it, damaging mobs and objects."
|
||||
var/turf/T = get_turf(src)
|
||||
expand_blob(T)
|
||||
|
||||
/mob/observer/blob/proc/expand_blob(turf/T)
|
||||
var/obj/structure/blob/B = null
|
||||
var/turf/other_T = null
|
||||
for(var/direction in cardinal)
|
||||
other_T = get_step(T, direction)
|
||||
if(other_T)
|
||||
B = locate(/obj/structure/blob) in other_T
|
||||
if(B)
|
||||
break
|
||||
|
||||
if(!B)
|
||||
to_chat(src, "<span class='warning'>There is no blob cardinally adjacent to the target tile!</span>")
|
||||
return
|
||||
|
||||
if(!can_buy(4))
|
||||
return
|
||||
|
||||
B.expand(T)
|
||||
|
||||
/mob/observer/blob/verb/auto_attack()
|
||||
set category = "Blob"
|
||||
set name = "Auto Attack (4)"
|
||||
set desc = "Automatically tries to kill whatever's attacking you."
|
||||
|
||||
transport_core() // In-case the overmind wandered off somewhere else.
|
||||
|
||||
var/list/potential_targets = list()
|
||||
for(var/mob/living/L in view(src))
|
||||
if(L.stat == DEAD)
|
||||
continue // Already dying or dead.
|
||||
if(L.faction == "blob")
|
||||
continue // No friendly fire.
|
||||
if(locate(/obj/structure/blob) in L.loc)
|
||||
continue // Already has a blob over them.
|
||||
|
||||
var/obj/structure/blob/B = null
|
||||
for(var/direction in cardinal)
|
||||
var/turf/T = get_step(L, direction)
|
||||
B = locate(/obj/structure/blob) in T
|
||||
if(B)
|
||||
break
|
||||
if(!B)
|
||||
continue
|
||||
|
||||
potential_targets += L
|
||||
|
||||
if(potential_targets.len)
|
||||
var/mob/living/victim = pick(potential_targets)
|
||||
var/turf/T = get_turf(victim)
|
||||
expand_blob(T)
|
||||
545
code/modules/blob2/overmind/types.dm
Normal file
545
code/modules/blob2/overmind/types.dm
Normal file
@@ -0,0 +1,545 @@
|
||||
// There are different kinds of blobs, with different colors, properties, weaknesses, etc. This datum tells the blob objects what kind they are, without a million typepaths.
|
||||
/datum/blob_type
|
||||
var/name = "base blob"
|
||||
var/desc = "This shouldn't exist." // Shown on examine.
|
||||
var/effect_desc = "This does nothing special." // For examine panel.
|
||||
var/ai_desc = "default" // Shown when examining the overmind.
|
||||
var/difficulty = BLOB_DIFFICULTY_EASY // A rough guess on how hard a blob is to kill.
|
||||
// When a harder blob spawns by event, the crew is given more information than usual from the announcement.
|
||||
var/color = "#FFFFFF" // The actual blob's color.
|
||||
var/complementary_color = "#000000" //a color that's complementary to the normal blob color. Blob mobs are colored in this.
|
||||
|
||||
var/attack_message = "The blob attacks you" // Base message the mob gets when blob_act() gets called on them by the blob. An exclaimation point is added to the end.
|
||||
var/attack_message_living = null // Appended to attack_message, if the target fails isSynthetic() check.
|
||||
var/attack_message_synth = null // Ditto, but if they pass isSynthetic().
|
||||
var/attack_verb = "attacks" // Used for the visible_message(), as the above is shown to the mob getting hit directly.
|
||||
// Format is '\The [blob name] [attack_verb] [victim]!' E.g. 'The explosive lattice blasts John Doe!'
|
||||
|
||||
var/damage_type = BRUTE // What kind of damage to do to living mobs via blob_act()
|
||||
var/armor_check = "melee" // What armor to check for when blob_act()-ing living mobs.
|
||||
var/armor_pen = 0 // How much armor to penetrate(ignore) when attacking via blob_act().
|
||||
var/damage_lower = 30 // Lower bound for amount of damage to do for attacks.
|
||||
var/damage_upper = 40 // Upper bound.
|
||||
|
||||
var/brute_multiplier = 0.5 // Adjust to make blobs stonger or weaker against brute damage.
|
||||
var/burn_multiplier = 1.0 // Ditto, for burns.
|
||||
var/spread_modifier = 0.5 // A multipler on how fast the blob should naturally spread from the core and nodes.
|
||||
var/slow_spread_with_size = TRUE // Blobs that get really huge will slow down in expansion.
|
||||
|
||||
var/ai_aggressiveness = 10 // Probability of the blob AI attempting to attack someone next to the blob, independant of the attacks from node/core pulsing.
|
||||
|
||||
var/can_build_factories = FALSE // Forbids this blob type from building factories. Set to true to enable.
|
||||
var/can_build_resources = FALSE // Ditto, for resource blobs.
|
||||
var/can_build_nodes = TRUE // Ditto, for nodes.
|
||||
|
||||
var/spore_type = /mob/living/simple_animal/hostile/blob/spore
|
||||
|
||||
// Called when a blob receives damage. This needs to return the final damage or blobs will be immortal.
|
||||
/datum/blob_type/proc/on_received_damage(var/obj/structure/blob/B, damage, damage_type)
|
||||
return damage
|
||||
|
||||
// Called when a blob dies due to integrity depletion. Not called if deleted by other means.
|
||||
/datum/blob_type/proc/on_death(var/obj/structure/blob/B)
|
||||
return
|
||||
|
||||
// Called when a blob expands onto another tile.
|
||||
/datum/blob_type/proc/on_expand(var/obj/structure/blob/B, var/obj/structure/blob/new_B, var/turf/T, var/mob/observer/blob/O)
|
||||
return
|
||||
|
||||
// Called when blob_act() is called on a living mob.
|
||||
/datum/blob_type/proc/on_attack(var/obj/structure/blob/B, var/mob/living/victim, var/def_zone)
|
||||
return
|
||||
|
||||
// Called when the blob is pulsed by a node or the core.
|
||||
/datum/blob_type/proc/on_pulse(var/obj/structure/blob/B)
|
||||
return
|
||||
|
||||
// Called when hit by EMP.
|
||||
/datum/blob_type/proc/on_emp(obj/structure/blob/B, severity)
|
||||
return
|
||||
|
||||
// Called when hit by water.
|
||||
/datum/blob_type/proc/on_water(obj/structure/blob/B, amount)
|
||||
return
|
||||
|
||||
// Spore things
|
||||
/datum/blob_type/proc/on_spore_death(mob/living/simple_animal/hostile/blob/spore/S)
|
||||
return
|
||||
|
||||
|
||||
// Subtypes
|
||||
|
||||
// Super fast spreading, but weak to EMP.
|
||||
/datum/blob_type/grey_goo
|
||||
name = "grey tide"
|
||||
desc = "A swarm of self replicating nanomachines. Extremely illegal and dangerous, the EIO was meant to prevent this from showing up a second time."
|
||||
effect_desc = "Spreads much faster than average, but is harmed greatly by electromagnetic pulses."
|
||||
ai_desc = "genocidal"
|
||||
difficulty = BLOB_DIFFICULTY_SUPERHARD // Fastest spread of them all and has snowballing capabilities.
|
||||
color = "#888888"
|
||||
complementary_color = "#CCCCCC"
|
||||
spread_modifier = 1.0
|
||||
slow_spread_with_size = FALSE
|
||||
ai_aggressiveness = 80
|
||||
can_build_resources = TRUE
|
||||
attack_message = "The tide tries to shallow you"
|
||||
attack_message_living = ", and you feel your skin dissolve"
|
||||
attack_message_synth = ", and your external plating dissolves"
|
||||
|
||||
/datum/blob_type/grey_goo/on_emp(obj/structure/blob/B, severity)
|
||||
B.adjust_integrity(-(20 / severity))
|
||||
|
||||
|
||||
// A blob meant to be fought like a fire.
|
||||
/datum/blob_type/blazing_oil
|
||||
name = "blazing oil"
|
||||
desc = "A strange, extremely vicious liquid that seems to burn endlessly."
|
||||
ai_desc = "aggressive"
|
||||
effect_desc = "Cannot be harmed by burning weapons, and ignites entities it attacks. It will also gradually heat up the area it is in. Water harms it greatly."
|
||||
difficulty = BLOB_DIFFICULTY_MEDIUM // Emitters don't work but extinguishers are fairly common. Might need fire/atmos suits.
|
||||
color = "#B68D00"
|
||||
complementary_color = "#BE5532"
|
||||
spread_modifier = 0.5
|
||||
ai_aggressiveness = 50
|
||||
damage_type = BURN
|
||||
burn_multiplier = 0 // Fire immunity
|
||||
attack_message = "The blazing oil splashes you with its burning oil"
|
||||
attack_message_living = ", and you feel your skin char and melt"
|
||||
attack_message_synth = ", and your external plating melts"
|
||||
attack_verb = "splashes"
|
||||
|
||||
/datum/blob_type/blazing_oil/on_attack(obj/structure/blob/B, mob/living/victim)
|
||||
victim.fire_act() // Burn them.
|
||||
|
||||
/datum/blob_type/blazing_oil/on_water(obj/structure/blob/B, amount)
|
||||
spawn(1)
|
||||
B.adjust_integrity(-(amount * 5))
|
||||
|
||||
/datum/blob_type/blazing_oil/on_pulse(var/obj/structure/blob/B)
|
||||
var/turf/T = get_turf(B)
|
||||
if(!T)
|
||||
return
|
||||
var/datum/gas_mixture/env = T.return_air()
|
||||
if(env)
|
||||
env.add_thermal_energy(10 * 1000)
|
||||
|
||||
|
||||
// Mostly a classic blob. No nodes, no other blob types.
|
||||
/datum/blob_type/classic
|
||||
name = "lethargic blob"
|
||||
desc = "A mass that seems bound to its core."
|
||||
ai_desc = "unambitious"
|
||||
effect_desc = "Will not create any nodes. Has average strength and resistances."
|
||||
difficulty = BLOB_DIFFICULTY_EASY // Behaves almost like oldblob, and as such is about as easy as oldblob.
|
||||
color = "#AAFF00"
|
||||
complementary_color = "#57787B"
|
||||
can_build_nodes = FALSE
|
||||
spread_modifier = 1.0
|
||||
ai_aggressiveness = 0
|
||||
|
||||
|
||||
// Makes robots cry. Really weak to brute damage.
|
||||
/datum/blob_type/electromagnetic_web
|
||||
name = "electromagnetic web"
|
||||
desc = "A gooy mesh that generates an electromagnetic field. Electronics will likely be ruined if nearby."
|
||||
ai_desc = "balanced"
|
||||
effect_desc = "Causes an EMP on attack, and will EMP upon death. It is also more fragile than average, especially to brute force."
|
||||
difficulty = BLOB_DIFFICULTY_MEDIUM // Rough for robots but otherwise fragile and can be fought at range like most blobs anyways.
|
||||
color = "#83ECEC"
|
||||
complementary_color = "#EC8383"
|
||||
damage_type = BURN
|
||||
damage_lower = 10
|
||||
damage_upper = 20
|
||||
brute_multiplier = 3
|
||||
burn_multiplier = 2
|
||||
ai_aggressiveness = 60
|
||||
attack_message = "The web lashes you"
|
||||
attack_message_living = ", and you hear a faint buzzing"
|
||||
attack_message_synth = ", and your electronics get badly damaged"
|
||||
attack_verb = "lashes"
|
||||
|
||||
/datum/blob_type/electromagnetic_web/on_death(obj/structure/blob/B)
|
||||
empulse(B.loc, 0, 1, 2)
|
||||
|
||||
/datum/blob_type/electromagnetic_web/on_attack(obj/structure/blob/B, mob/living/victim)
|
||||
victim.emp_act(2)
|
||||
|
||||
|
||||
// Makes spores that spread the blob and infest dead people.
|
||||
/datum/blob_type/fungal_bloom
|
||||
name = "fungal bloom"
|
||||
desc = "A massive network of rapidly expanding mycelium. Large spore-like particles can be seen spreading from it."
|
||||
ai_desc = "swarming"
|
||||
effect_desc = "Creates floating spores that attack enemies from specialized blobs, and will spread the blob if killed. The spores can also \
|
||||
infest deceased biological humanoids. It is vulnerable to fire."
|
||||
difficulty = BLOB_DIFFICULTY_MEDIUM // The spores are more of an annoyance but can be difficult to contain.
|
||||
color = "#AAAAAA"
|
||||
complementary_color = "#FFFFFF"
|
||||
damage_type = TOX
|
||||
damage_lower = 15
|
||||
damage_upper = 25
|
||||
spread_modifier = 0.3 // Lower, since spores will do a lot of the spreading.
|
||||
burn_multiplier = 3
|
||||
ai_aggressiveness = 40
|
||||
can_build_factories = TRUE
|
||||
spore_type = /mob/living/simple_animal/hostile/blob/spore/infesting
|
||||
|
||||
/datum/blob_type/fungal_bloom/on_spore_death(mob/living/simple_animal/hostile/blob/spore/S)
|
||||
if(S.is_infesting)
|
||||
return // Don't make blobs if they were on someone's head.
|
||||
var/turf/T = get_turf(S)
|
||||
var/obj/structure/blob/B = locate(/obj/structure/blob) in T
|
||||
if(B) // Is there already a blob here? If so, just heal it.
|
||||
B.adjust_integrity(10)
|
||||
else
|
||||
B = new /obj/structure/blob/normal(T, S.overmind) // Otherwise spread it.
|
||||
B.visible_message("<span class='danger'>\A [B] forms on \the [T] as \the [S] bursts!</span>")
|
||||
|
||||
// Makes tons of weak spores whenever it spreads.
|
||||
/datum/blob_type/fulminant_organism
|
||||
name = "fulminant organism"
|
||||
desc = "A self expanding mass of living biomaterial, that appears to produce entities to defend it, much like a living organism's immune system."
|
||||
ai_desc = "swarming"
|
||||
effect_desc = "Creates weak floating spores that attack enemies from specialized blobs, has a chance to also create a spore when \
|
||||
it spreads onto a new tile, and has a chance to create a spore when a blob tile is destroyed. It is more fragile than average to all types of damage."
|
||||
difficulty = BLOB_DIFFICULTY_HARD // Loads of spores that can overwhelm, and spreads quickly.
|
||||
color = "#FF0000" // Red
|
||||
complementary_color = "#FFCC00" // Orange-ish
|
||||
damage_type = TOX
|
||||
damage_lower = 10
|
||||
damage_upper = 20
|
||||
spread_modifier = 0.7
|
||||
burn_multiplier = 1.5
|
||||
brute_multiplier = 1.5
|
||||
ai_aggressiveness = 30 // The spores do most of the fighting.
|
||||
can_build_factories = TRUE
|
||||
spore_type = /mob/living/simple_animal/hostile/blob/spore/weak
|
||||
|
||||
/datum/blob_type/fulminant_organism/on_expand(var/obj/structure/blob/B, var/obj/structure/blob/new_B, var/turf/T, var/mob/observer/blob/O)
|
||||
if(prob(10)) // 10% chance to make a weak spore when expanding.
|
||||
var/mob/living/simple_animal/hostile/blob/S = new spore_type(T)
|
||||
S.overmind = O
|
||||
S.update_icons()
|
||||
O.blob_mobs.Add(S)
|
||||
|
||||
/datum/blob_type/fulminant_organism/on_death(obj/structure/blob/B)
|
||||
if(prob(33)) // 33% chance to make a spore when dying.
|
||||
var/mob/living/simple_animal/hostile/blob/S = new spore_type(get_turf(B))
|
||||
B.visible_message("<span class='danger'>A spore floats free from the [name]!</span>")
|
||||
S.overmind = B.overmind
|
||||
S.update_icons()
|
||||
B.overmind.blob_mobs.Add(S)
|
||||
|
||||
|
||||
// Auto-retaliates against melee attacks. Weak to projectiles.
|
||||
/datum/blob_type/reactive_spines
|
||||
name = "reactive spines"
|
||||
desc = "An ever-growing lifeform with a large amount of sharp, powerful looking spines. They look like they could pierce most armor."
|
||||
ai_desc = "defensive"
|
||||
effect_desc = "When attacked by a melee weapon, it will automatically retaliate, striking the attacker with an armor piercing attack. \
|
||||
The blob itself is rather weak to all forms of attacks regardless, and lacks automatic realitation from ranged attacks."
|
||||
difficulty = BLOB_DIFFICULTY_EASY // Potentially deadly to people not knowing the mechanics, but otherwise fairly tame, due to its slow spread and weakness.
|
||||
color = "#9ACD32"
|
||||
complementary_color = "#FFA500"
|
||||
damage_type = BRUTE
|
||||
damage_lower = 30
|
||||
damage_upper = 40
|
||||
armor_pen = 50 // Even with riot armor and tactical jumpsuit, you'd have 90 armor, reduced by 50, totaling 40. Getting hit for around 21 damage is still rough.
|
||||
burn_multiplier = 2.0
|
||||
brute_multiplier = 2.0
|
||||
spread_modifier = 0.35 // Ranged projectiles tend to have a higher material cost, so ease up on the spreading.
|
||||
ai_aggressiveness = 40
|
||||
attack_message = "The blob stabs you"
|
||||
attack_message_living = ", and you feel sharp spines pierce your flesh"
|
||||
attack_message_synth = ", and your external plating is pierced by sharp spines"
|
||||
attack_verb = "stabs"
|
||||
|
||||
// Even if the melee attack is enough to one-shot this blob, it gets to retaliate at least once.
|
||||
/datum/blob_type/reactive_spines/on_received_damage(var/obj/structure/blob/B, damage, damage_type, mob/living/attacker)
|
||||
if(damage > 0 && attacker && get_dist(B, attacker) <= 1)
|
||||
B.visible_message("<span class='danger'>The [name] retaliates, lashing out at \the [attacker]!</span>")
|
||||
B.blob_attack_animation(attacker, B.overmind)
|
||||
attacker.blob_act(B)
|
||||
..()
|
||||
|
||||
|
||||
// Spreads damage to nearby blobs, and attacks with the force of all nearby blobs.
|
||||
/datum/blob_type/synchronous_mesh
|
||||
name = "synchronous mesh"
|
||||
desc = "A mesh that seems strongly interconnected to itself. It moves slowly, but with purpose."
|
||||
ai_desc = "defensive"
|
||||
effect_desc = "When damaged, spreads the damage to nearby blobs. When attacking, damage is increased based on how many blobs are near the target. It is resistant to burn damage."
|
||||
difficulty = BLOB_DIFFICULTY_EASY // Mostly a tank and spank.
|
||||
color = "#65ADA2"
|
||||
complementary_color = "#AD6570"
|
||||
damage_type = BRUTE
|
||||
damage_lower = 10
|
||||
damage_upper = 15
|
||||
brute_multiplier = 0.5
|
||||
burn_multiplier = 0.2 // Emitters do so much damage that this will likely not matter too much.
|
||||
spread_modifier = 0.3 // Since the blob spreads damage, it takes awhile to actually kill, so spread is reduced.
|
||||
ai_aggressiveness = 60
|
||||
attack_message = "The mesh synchronously strikes you"
|
||||
attack_verb = "synchronously strikes"
|
||||
var/synchronously_attacking = FALSE
|
||||
|
||||
/datum/blob_type/synchronous_mesh/on_attack(obj/structure/blob/B, mob/living/victim)
|
||||
if(synchronously_attacking)
|
||||
return
|
||||
synchronously_attacking = TRUE // To avoid infinite loops.
|
||||
for(var/obj/structure/blob/C in orange(1, victim))
|
||||
if(victim) // Some things delete themselves when dead...
|
||||
C.blob_attack_animation(victim)
|
||||
victim.blob_act(C)
|
||||
synchronously_attacking = FALSE
|
||||
|
||||
/datum/blob_type/synchronous_mesh/on_received_damage(var/obj/structure/blob/B, damage, damage_type)
|
||||
var/list/blobs_to_hurt = list() // Maximum split is 9, reducing the damage each blob takes to 11.1% but doing that damage to 9 blobs.
|
||||
for(var/obj/structure/blob/C in range(1, B))
|
||||
if(!istype(C, /obj/structure/blob/core) && !istype(C, /obj/structure/blob/node) && C.overmind && (C.overmind == B.overmind) ) //if it doesn't have the same 'ownership' or is a core or node, don't split damage to it
|
||||
blobs_to_hurt += C
|
||||
|
||||
for(var/thing in blobs_to_hurt)
|
||||
var/obj/structure/blob/C = thing
|
||||
if(C == B)
|
||||
continue // We'll damage this later.
|
||||
|
||||
C.adjust_integrity(-(damage / blobs_to_hurt.len))
|
||||
|
||||
return damage / max(blobs_to_hurt.len, 1) // To hurt the blob that got hit.
|
||||
|
||||
|
||||
/datum/blob_type/shifting_fragments
|
||||
name = "shifting fragments"
|
||||
desc = "A collection of fragments that seem to shuffle around constantly."
|
||||
ai_desc = "evasive"
|
||||
effect_desc = "Swaps places with nearby blobs when hit or when expanding."
|
||||
difficulty = BLOB_DIFFICULTY_EASY
|
||||
color = "#C8963C"
|
||||
complementary_color = "#3C6EC8"
|
||||
damage_type = BRUTE
|
||||
damage_lower = 20
|
||||
damage_upper = 30
|
||||
brute_multiplier = 0.5
|
||||
burn_multiplier = 0.5
|
||||
spread_modifier = 0.5
|
||||
ai_aggressiveness = 30
|
||||
attack_message = "A fragment strikes you"
|
||||
attack_verb = "strikes"
|
||||
|
||||
/datum/blob_type/shifting_fragments/on_received_damage(var/obj/structure/blob/B, damage, damage_type)
|
||||
if(damage > 0 && prob(60))
|
||||
var/list/available_blobs = list()
|
||||
for(var/obj/structure/blob/OB in orange(1, B))
|
||||
if((istype(OB, /obj/structure/blob/normal) || (istype(OB, /obj/structure/blob/shield) && prob(25))) && OB.overmind && OB.overmind == B.overmind)
|
||||
available_blobs += OB
|
||||
if(available_blobs.len)
|
||||
var/obj/structure/blob/targeted = pick(available_blobs)
|
||||
var/turf/T = get_turf(targeted)
|
||||
targeted.forceMove(get_turf(B))
|
||||
B.forceMove(T) // Swap places.
|
||||
return ..()
|
||||
|
||||
/datum/blob_type/shifting_fragments/on_expand(var/obj/structure/blob/B, var/obj/structure/blob/new_B, var/turf/T, var/mob/observer/blob/O)
|
||||
if(istype(B, /obj/structure/blob/normal) || (istype(B, /obj/structure/blob/shield) && prob(25)))
|
||||
new_B.forceMove(get_turf(B))
|
||||
B.forceMove(T)
|
||||
|
||||
// A very cool blob, literally.
|
||||
/datum/blob_type/cryogenic_goo
|
||||
name = "cryogenic goo"
|
||||
desc = "A mass of goo that freezes anything it touches."
|
||||
ai_desc = "balanced"
|
||||
effect_desc = "Lowers the temperature of the room passively, and will also greatly lower the temperature of anything it attacks."
|
||||
difficulty = BLOB_DIFFICULTY_MEDIUM
|
||||
color = "#8BA6E9"
|
||||
complementary_color = "#7D6EB4"
|
||||
damage_type = BURN
|
||||
damage_lower = 15
|
||||
damage_upper = 25
|
||||
brute_multiplier = 0.25
|
||||
burn_multiplier = 1.2
|
||||
spread_modifier = 0.5
|
||||
ai_aggressiveness = 50
|
||||
attack_message = "The goo stabs you"
|
||||
attack_message_living = ", and you feel an intense chill from within"
|
||||
attack_message_synth = ", and your system reports lower internal temperatures"
|
||||
attack_verb = "stabs"
|
||||
|
||||
/datum/blob_type/cryogenic_goo/on_attack(obj/structure/blob/B, mob/living/victim)
|
||||
if(ishuman(victim))
|
||||
var/mob/living/carbon/human/H = victim
|
||||
var/protection = H.get_cold_protection(50)
|
||||
if(protection < 1)
|
||||
var/temp_change = 80 // Each hit can reduce temperature by up to 80 kelvin.
|
||||
var/datum/species/baseline = all_species["Human"]
|
||||
var/temp_cap = baseline.cold_level_3 - 5 // Can't go lower than this.
|
||||
|
||||
var/cold_factor = abs(protection - 1)
|
||||
temp_change *= cold_factor // If protection was at 0.5, then they only lose 40 kelvin.
|
||||
|
||||
H.bodytemperature = max(H.bodytemperature - temp_change, temp_cap)
|
||||
else // Just do some extra burn for mobs who don't process bodytemp
|
||||
victim.adjustFireLoss(20)
|
||||
|
||||
/datum/blob_type/cryogenic_goo/on_pulse(var/obj/structure/blob/B)
|
||||
var/turf/simulated/T = get_turf(B)
|
||||
if(!istype(T))
|
||||
return
|
||||
T.freeze_floor()
|
||||
var/datum/gas_mixture/env = T.return_air()
|
||||
if(env)
|
||||
env.add_thermal_energy(-10 * 1000)
|
||||
|
||||
// Electric blob that stuns.
|
||||
/datum/blob_type/energized_jelly
|
||||
name = "energized jelly"
|
||||
desc = "A substance that seems to generate electricity."
|
||||
ai_desc = "suppressive"
|
||||
effect_desc = "When attacking an entity, it will shock them with a strong electric shock. Repeated attacks can stun the target."
|
||||
difficulty = BLOB_DIFFICULTY_MEDIUM
|
||||
color = "#EFD65A"
|
||||
complementary_color = "#00E5B1"
|
||||
damage_type = BURN
|
||||
damage_lower = 5
|
||||
damage_upper = 10
|
||||
brute_multiplier = 0.5
|
||||
burn_multiplier = 0.5
|
||||
spread_modifier = 0.35
|
||||
ai_aggressiveness = 80
|
||||
attack_message = "The jelly prods you"
|
||||
attack_message_living = ", and your flesh burns as electricity arcs into you"
|
||||
attack_message_synth = ", and your internal circuity is overloaded as electricity arcs into you"
|
||||
attack_verb = "prods"
|
||||
|
||||
/datum/blob_type/energized_jelly/on_attack(obj/structure/blob/B, mob/living/victim, def_zone)
|
||||
victim.electrocute_act(10, src, 1, def_zone)
|
||||
victim.stun_effect_act(0, 40, BP_TORSO, src)
|
||||
|
||||
|
||||
// A blob with area of effect attacks.
|
||||
/datum/blob_type/explosive_lattice
|
||||
name = "explosive lattice"
|
||||
desc = "A very unstable lattice that looks quite explosive."
|
||||
ai_desc = "aggressive"
|
||||
effect_desc = "When attacking an entity, it will cause a small explosion, hitting things near the target. It is somewhat resilient, but weaker to brute damage."
|
||||
difficulty = BLOB_DIFFICULTY_MEDIUM
|
||||
color = "#8B2500"
|
||||
complementary_color = "#00668B"
|
||||
damage_type = BURN
|
||||
damage_lower = 25
|
||||
damage_upper = 35
|
||||
armor_check = "bomb"
|
||||
armor_pen = 5 // This is so blob hits still hurt just slightly when wearing a bomb suit (100 bomb resist).
|
||||
brute_multiplier = 0.75
|
||||
burn_multiplier = 0.5
|
||||
spread_modifier = 0.4
|
||||
ai_aggressiveness = 75
|
||||
attack_message = "The lattice blasts you"
|
||||
attack_message_living = ", and your flesh burns from the blast wave"
|
||||
attack_message_synth = ", and your plating burns from the blast wave"
|
||||
attack_verb = "blasts"
|
||||
var/exploding = FALSE
|
||||
|
||||
/datum/blob_type/explosive_lattice/on_attack(obj/structure/blob/B, mob/living/victim, def_zone) // This doesn't use actual bombs since they're too strong and it would hurt the blob.
|
||||
if(exploding) // We're busy, don't infinite loop us.
|
||||
return
|
||||
|
||||
exploding = TRUE
|
||||
for(var/mob/living/L in range(get_turf(victim), 1)) // We don't use orange(), in case there is more than one mob on the target tile.
|
||||
if(L == victim) // Already hit.
|
||||
continue
|
||||
if(L.faction == "blob") // No friendly fire
|
||||
continue
|
||||
L.blob_act()
|
||||
|
||||
// Visual effect.
|
||||
var/datum/effect/system/explosion/E = new/datum/effect/system/explosion/smokeless()
|
||||
var/turf/T = get_turf(victim)
|
||||
E.set_up(T)
|
||||
E.start()
|
||||
|
||||
// Now for sounds.
|
||||
playsound(T, "explosion", 75, 1) // Local sound.
|
||||
|
||||
for(var/mob/M in player_list) // For everyone else.
|
||||
if(M.z == T.z && get_dist(M, T) > world.view && !M.ear_deaf && !istype(M.loc,/turf/space))
|
||||
M << 'sound/effects/explosionfar.ogg'
|
||||
|
||||
exploding = FALSE
|
||||
|
||||
|
||||
// A blob that slips and drowns you.
|
||||
/datum/blob_type/pressurized_slime
|
||||
name = "pressurized slime"
|
||||
desc = "A large mass that seems to leak slippery fluid everywhere."
|
||||
ai_desc = "drowning"
|
||||
effect_desc = "Wets the floor when expanding and when hit. Tries to drown its enemies when attacking. It forces itself past internals. Resistant to burn damage."
|
||||
difficulty = BLOB_DIFFICULTY_HARD
|
||||
color = "#AAAABB"
|
||||
complementary_color = "#BBBBAA"
|
||||
damage_type = OXY
|
||||
damage_lower = 5
|
||||
damage_upper = 15
|
||||
armor_check = null
|
||||
brute_multiplier = 0.6
|
||||
burn_multiplier = 0.2
|
||||
spread_modifier = 0.4
|
||||
ai_aggressiveness = 75
|
||||
attack_message = "The slime splashes into you"
|
||||
attack_message_living = ", and you gasp for breath"
|
||||
attack_message_synth = ", and the fluid wears down on your components"
|
||||
attack_verb = "splashes"
|
||||
|
||||
/datum/blob_type/pressurized_slime/on_attack(obj/structure/blob/B, mob/living/victim, def_zone)
|
||||
victim.water_act(5)
|
||||
var/turf/simulated/T = get_turf(victim)
|
||||
if(T)
|
||||
T.wet_floor()
|
||||
|
||||
/datum/blob_type/pressurized_slime/on_received_damage(var/obj/structure/blob/B, damage, damage_type)
|
||||
wet_surroundings(B, damage)
|
||||
return ..()
|
||||
|
||||
/datum/blob_type/pressurized_slime/on_pulse(var/obj/structure/blob/B)
|
||||
var/turf/simulated/T = get_turf(B)
|
||||
if(!istype(T))
|
||||
return
|
||||
T.wet_floor()
|
||||
|
||||
/datum/blob_type/pressurized_slime/on_death(obj/structure/blob/B)
|
||||
B.visible_message("<span class='danger'>The blob ruptures, spraying the area with liquid!</span>")
|
||||
wet_surroundings(B, 50)
|
||||
|
||||
/datum/blob_type/pressurized_slime/proc/wet_surroundings(var/obj/structure/blob/B, var/probability = 50)
|
||||
for(var/turf/simulated/T in range(1, B))
|
||||
if(prob(probability))
|
||||
T.wet_floor()
|
||||
for(var/atom/movable/AM in T)
|
||||
AM.water_act(2)
|
||||
|
||||
|
||||
// A blob that irradiates everything.
|
||||
/datum/blob_type/radioactive_ooze
|
||||
name = "radioactive ooze"
|
||||
desc = "A goopy mess that glows with an unhealthy aura."
|
||||
ai_desc = "radical"
|
||||
effect_desc = "Irradiates the surrounding area, and inflicts toxic attacks. Weak to brute damage."
|
||||
difficulty = BLOB_DIFFICULTY_MEDIUM
|
||||
color = "#33CC33"
|
||||
complementary_color = "#99FF66"
|
||||
damage_type = TOX
|
||||
damage_lower = 20
|
||||
damage_upper = 30
|
||||
armor_check = "rad"
|
||||
brute_multiplier = 0.75
|
||||
burn_multiplier = 0.2
|
||||
spread_modifier = 0.8
|
||||
ai_aggressiveness = 50
|
||||
attack_message = "The ooze splashes you"
|
||||
attack_message_living = ", and you feel warm"
|
||||
attack_message_synth = ", and your internal systems are bombarded by ionizing radiation"
|
||||
attack_verb = "splashes"
|
||||
|
||||
/datum/blob_type/radioactive_ooze/on_pulse(var/obj/structure/blob/B)
|
||||
radiation_repository.radiate(B, 200)
|
||||
@@ -199,7 +199,7 @@
|
||||
|
||||
|
||||
/datum/gear/accessory/sweater
|
||||
display_name = "Sweater Selection"
|
||||
display_name = "sweater selection"
|
||||
path = /obj/item/clothing/accessory/sweater
|
||||
|
||||
/datum/gear/accessory/sweater/New()
|
||||
@@ -231,4 +231,13 @@
|
||||
|
||||
/datum/gear/accessory/bracelet/friendship
|
||||
display_name = "friendship bracelet"
|
||||
path = /obj/item/clothing/accessory/bracelet/friendship
|
||||
path = /obj/item/clothing/accessory/bracelet/friendship
|
||||
|
||||
/datum/gear/accessory/stethoscope
|
||||
display_name = "stethoscope"
|
||||
path = /obj/item/clothing/accessory/stethoscope
|
||||
allowed_roles = list("Chief Medical Officer","Medical Doctor","Chemist","Psychiatrist","Paramedic")
|
||||
|
||||
/datum/gear/accessory/locket
|
||||
display_name = "locket"
|
||||
path = /obj/item/clothing/accessory/locket
|
||||
@@ -1,16 +1,20 @@
|
||||
/datum/gear/lipstick
|
||||
/datum/gear/cosmetic/lipstick/black
|
||||
display_name = "lipstick, black"
|
||||
path = /obj/item/weapon/lipstick/black
|
||||
sort_category = "Cosmetics"
|
||||
|
||||
/datum/gear/lipstick/jade
|
||||
/datum/gear/cosmetic/lipstick/jade
|
||||
display_name = "lipstick, jade"
|
||||
path = /obj/item/weapon/lipstick/jade
|
||||
|
||||
/datum/gear/lipstick/purple
|
||||
/datum/gear/cosmetic/lipstick/purple
|
||||
display_name = "lipstick, purple"
|
||||
path = /obj/item/weapon/lipstick/purple
|
||||
|
||||
/datum/gear/lipstick/red
|
||||
/datum/gear/cosmetic/lipstick
|
||||
display_name = "lipstick, red"
|
||||
path = /obj/item/weapon/lipstick
|
||||
|
||||
/datum/gear/cosmetic
|
||||
display_name = "purple comb"
|
||||
path = /obj/item/weapon/haircomb
|
||||
sort_category = "Cosmetics"
|
||||
@@ -18,14 +18,18 @@
|
||||
path = /obj/item/clothing/glasses/regular/hipster
|
||||
|
||||
/datum/gear/eyes/glasses/monocle
|
||||
display_name = "Monocle"
|
||||
display_name = "monocle"
|
||||
path = /obj/item/clothing/glasses/monocle
|
||||
|
||||
/datum/gear/eyes/scanning_goggles
|
||||
/datum/gear/eyes/goggles
|
||||
display_name = "plain goggles"
|
||||
path = /obj/item/clothing/glasses/goggles
|
||||
|
||||
/datum/gear/eyes/goggles/scanning
|
||||
display_name = "scanning goggles"
|
||||
path = /obj/item/clothing/glasses/regular/scanners
|
||||
|
||||
/datum/gear/eyes/sciencegoggles
|
||||
/datum/gear/eyes/goggles/science
|
||||
display_name = "Science Goggles"
|
||||
path = /obj/item/clothing/glasses/science
|
||||
|
||||
@@ -73,7 +77,7 @@
|
||||
allowed_roles = list("Station Engineer","Chief Engineer","Atmospheric Technician", "Scientist", "Research Director")
|
||||
|
||||
/datum/gear/eyes/meson/prescription
|
||||
display_name = "Optical Meson Scanners, prescription (Engineering)"
|
||||
display_name = "Optical Meson Scanners, prescription (Engineering, Science)"
|
||||
path = /obj/item/clothing/glasses/meson/prescription
|
||||
|
||||
/datum/gear/eyes/material
|
||||
@@ -86,11 +90,11 @@
|
||||
path = /obj/item/clothing/glasses/material/prescription
|
||||
|
||||
/datum/gear/eyes/meson/aviator
|
||||
display_name = "Optical Meson Aviators, (Engineering)"
|
||||
display_name = "Optical Meson Aviators, (Engineering, Science)"
|
||||
path = /obj/item/clothing/glasses/meson/aviator
|
||||
|
||||
/datum/gear/eyes/meson/aviator/prescription
|
||||
display_name = "Optical Meson Aviators, prescription (Engineering)"
|
||||
display_name = "Optical Meson Aviators, prescription (Engineering, Science)"
|
||||
path = /obj/item/clothing/glasses/meson/aviator/prescription
|
||||
|
||||
/datum/gear/eyes/glasses/fakesun
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
display_name = "cane"
|
||||
path = /obj/item/weapon/cane
|
||||
|
||||
/datum/gear/cane/white
|
||||
display_name = "white cane"
|
||||
path = /obj/item/weapon/cane/whitecane
|
||||
|
||||
/datum/gear/dice
|
||||
display_name = "dice pack"
|
||||
path = /obj/item/weapon/storage/pill_bottle/dice
|
||||
@@ -62,10 +66,6 @@
|
||||
..()
|
||||
gear_tweaks += new/datum/gear_tweak/reagents(lunchables_drink_reagents())
|
||||
|
||||
/datum/gear/comb
|
||||
display_name = "purple comb"
|
||||
path = /obj/item/weapon/haircomb
|
||||
|
||||
/datum/gear/lunchbox
|
||||
display_name = "lunchbox"
|
||||
description = "A little lunchbox."
|
||||
|
||||
@@ -114,9 +114,13 @@
|
||||
path = /obj/item/clothing/head/soft/yellow
|
||||
|
||||
/datum/gear/head/cap/white
|
||||
display_name = "cap, white"
|
||||
display_name = "cap (colorable)"
|
||||
path = /obj/item/clothing/head/soft/mime
|
||||
|
||||
/datum/gear/head/cap/white/New()
|
||||
..()
|
||||
gear_tweaks = list(gear_tweak_free_color_choice)
|
||||
|
||||
/datum/gear/head/cap/mbill
|
||||
display_name = "cap, bill"
|
||||
path = /obj/item/clothing/head/soft/mbill
|
||||
@@ -154,7 +158,7 @@
|
||||
path = /obj/item/clothing/head/fedora/grey
|
||||
|
||||
/datum/gear/head/hairflower
|
||||
display_name = "hair flower pin"
|
||||
display_name = "hair flower pin (colorable)"
|
||||
path = /obj/item/clothing/head/hairflower/white
|
||||
|
||||
/datum/gear/head/hairflower/New()
|
||||
@@ -162,21 +166,17 @@
|
||||
gear_tweaks = list(gear_tweak_free_color_choice)
|
||||
|
||||
/datum/gear/head/hardhat
|
||||
display_name = "hardhat, yellow"
|
||||
display_name = "hardhat selection"
|
||||
path = /obj/item/clothing/head/hardhat
|
||||
cost = 2
|
||||
|
||||
/datum/gear/head/hardhat/blue
|
||||
display_name = "hardhat, blue"
|
||||
path = /obj/item/clothing/head/hardhat/dblue
|
||||
|
||||
/datum/gear/head/hardhat/orange
|
||||
display_name = "hardhat, orange"
|
||||
path = /obj/item/clothing/head/hardhat/orange
|
||||
|
||||
/datum/gear/head/hardhat/red
|
||||
display_name = "hardhat, red"
|
||||
path = /obj/item/clothing/head/hardhat/red
|
||||
/datum/gear/head/hardhat/New()
|
||||
..()
|
||||
var/list/hardhats = list()
|
||||
for(var/hardhat in typesof(/obj/item/clothing/head/hardhat))
|
||||
var/obj/item/clothing/head/hardhat/hardhat_type = hardhat
|
||||
hardhats[initial(hardhat_type.name)] = hardhat_type
|
||||
gear_tweaks += new/datum/gear_tweak/path(sortAssoc(hardhats))
|
||||
|
||||
/datum/gear/head/boater
|
||||
display_name = "hat, boatsman"
|
||||
@@ -194,22 +194,30 @@
|
||||
display_name = "hat, tophat"
|
||||
path = /obj/item/clothing/head/that
|
||||
|
||||
/datum/gear/head/philosopher_wig
|
||||
/datum/gear/head/wig/philosopher
|
||||
display_name = "natural philosopher's wig"
|
||||
path = /obj/item/clothing/head/philosopher_wig
|
||||
|
||||
/datum/gear/head/wig
|
||||
display_name = "powdered wig"
|
||||
path = /obj/item/clothing/head/powdered_wig
|
||||
|
||||
/datum/gear/head/ushanka
|
||||
display_name = "ushanka"
|
||||
path = /obj/item/clothing/head/ushanka
|
||||
|
||||
/datum/gear/head/santahat
|
||||
display_name = "santa hat, red (holiday)"
|
||||
display_name = "santa hat"
|
||||
path = /obj/item/clothing/head/santa
|
||||
cost = 2
|
||||
|
||||
/datum/gear/head/santahat/green
|
||||
display_name = "santa hat, green (holiday)"
|
||||
path = /obj/item/clothing/head/santa/green
|
||||
/datum/gear/head/santahat/New()
|
||||
..()
|
||||
var/list/santahats = list()
|
||||
for(var/santahat in typesof(/obj/item/clothing/head/santa))
|
||||
var/obj/item/clothing/head/santa/santahat_type = santahat
|
||||
santahats[initial(santahat_type.name)] = santahat_type
|
||||
gear_tweaks += new/datum/gear_tweak/path(sortAssoc(santahats))
|
||||
|
||||
/datum/gear/head/hijab
|
||||
display_name = "hijab"
|
||||
@@ -243,11 +251,14 @@
|
||||
..()
|
||||
gear_tweaks = list(gear_tweak_free_color_choice)
|
||||
|
||||
|
||||
/datum/gear/head/kitty
|
||||
display_name = "kitty ears"
|
||||
path = /obj/item/clothing/head/kitty
|
||||
|
||||
/datum/gear/head/rabbit
|
||||
display_name = "rabbit ears"
|
||||
path = /obj/item/clothing/head/rabbitears
|
||||
|
||||
/datum/gear/head/beanie
|
||||
display_name = "beanie"
|
||||
path = /obj/item/clothing/head/beanie
|
||||
|
||||
@@ -1,20 +1,29 @@
|
||||
/datum/gear/smokingpipe
|
||||
display_name = "pipe, smoking"
|
||||
|
||||
/datum/gear/pipe
|
||||
display_name = "pipe"
|
||||
path = /obj/item/clothing/mask/smokable/pipe
|
||||
|
||||
/datum/gear/cornpipe
|
||||
display_name = "pipe, corn"
|
||||
path = /obj/item/clothing/mask/smokable/pipe/cobpipe
|
||||
/datum/gear/pipe/New()
|
||||
..()
|
||||
var/list/pipes = list()
|
||||
for(var/pipe_style in typesof(/obj/item/clothing/mask/smokable/pipe))
|
||||
var/obj/item/clothing/mask/smokable/pipe/pipe = pipe_style
|
||||
pipes[initial(pipe.name)] = pipe
|
||||
gear_tweaks += new/datum/gear_tweak/path(sortAssoc(pipes))
|
||||
|
||||
/datum/gear/matchbook
|
||||
display_name = "matchbook"
|
||||
path = /obj/item/weapon/storage/box/matches
|
||||
|
||||
/datum/gear/zippo
|
||||
display_name = "Zippo Selection"
|
||||
/datum/gear/lighter
|
||||
display_name = "cheap lighter"
|
||||
path = /obj/item/weapon/flame/lighter
|
||||
|
||||
/datum/gear/lighter/zippo
|
||||
display_name = "Zippo selection"
|
||||
path = /obj/item/weapon/flame/lighter/zippo
|
||||
|
||||
/datum/gear/zippo/New()
|
||||
/datum/gear/lighter/zippo/New()
|
||||
..()
|
||||
var/list/zippos = list()
|
||||
for(var/zippo in typesof(/obj/item/weapon/flame/lighter/zippo))
|
||||
@@ -40,4 +49,4 @@
|
||||
for(var/cigarette in (typesof(/obj/item/weapon/storage/fancy/cigarettes) - typesof(/obj/item/weapon/storage/fancy/cigarettes/killthroat)))
|
||||
var/obj/item/weapon/storage/fancy/cigarettes/cigarette_brand = cigarette
|
||||
cigarettes[initial(cigarette_brand.name)] = cigarette_brand
|
||||
gear_tweaks += new/datum/gear_tweak/path(sortAssoc(cigarettes))
|
||||
gear_tweaks += new/datum/gear_tweak/path(sortAssoc(cigarettes))
|
||||
|
||||
@@ -6,6 +6,10 @@
|
||||
sort_category = "Suits and Overwear"
|
||||
cost = 2
|
||||
|
||||
/datum/gear/suit/greatcoat
|
||||
display_name = "greatcoat"
|
||||
path = /obj/item/clothing/suit/greatcoat
|
||||
|
||||
/datum/gear/suit/leather_coat
|
||||
display_name = "leather coat"
|
||||
path = /obj/item/clothing/suit/leathercoat
|
||||
|
||||
@@ -349,7 +349,7 @@
|
||||
|
||||
/datum/gear/uniform/whitewedding
|
||||
display_name= "white wedding dress"
|
||||
path = /obj/item/clothing/under/dress/white
|
||||
path = /obj/item/clothing/under/wedding/bride_white
|
||||
|
||||
/datum/gear/uniform/skirts
|
||||
display_name = "executive skirt"
|
||||
|
||||
@@ -13,6 +13,10 @@
|
||||
path = /obj/item/device/communicator
|
||||
cost = 0
|
||||
|
||||
/datum/gear/utility/camera
|
||||
display_name = "camera"
|
||||
path = /obj/item/device/camera
|
||||
|
||||
/datum/gear/utility/codex
|
||||
display_name = "the traveler's guide to vir"
|
||||
path = /obj/item/weapon/book/codex/lore/vir
|
||||
|
||||
@@ -43,25 +43,33 @@
|
||||
bandtypes[initial(band.name)] = band
|
||||
gear_tweaks += new/datum/gear_tweak/path(sortAssoc(bandtypes))
|
||||
|
||||
/datum/gear/ears/skrell/cloth/male
|
||||
display_name = "male headtail cloth (Skrell)"
|
||||
/datum/gear/ears/skrell/cloth/short
|
||||
display_name = "short headtail cloth (Skrell)"
|
||||
path = /obj/item/clothing/ears/skrell/cloth_male/black
|
||||
sort_category = "Xenowear"
|
||||
whitelisted = "Skrell"
|
||||
|
||||
/datum/gear/ears/skrell/cloth/male/New()
|
||||
/datum/gear/ears/skrell/cloth/short/New()
|
||||
..()
|
||||
gear_tweaks = list(gear_tweak_free_color_choice)
|
||||
var/list/shorttypes = list()
|
||||
for(var/short_style in typesof(/obj/item/clothing/ears/skrell/cloth_male))
|
||||
var/obj/item/clothing/ears/skrell/cloth_male/short = short_style
|
||||
shorttypes[initial(short.name)] = short
|
||||
gear_tweaks += new/datum/gear_tweak/path(sortAssoc(shorttypes))
|
||||
|
||||
/datum/gear/ears/skrell/cloth/female
|
||||
display_name = "female headtail cloth (Skrell)"
|
||||
/datum/gear/ears/skrell/cloth/long
|
||||
display_name = "long headtail cloth (Skrell)"
|
||||
path = /obj/item/clothing/ears/skrell/cloth_female/black
|
||||
sort_category = "Xenowear"
|
||||
whitelisted = "Skrell"
|
||||
|
||||
/datum/gear/ears/skrell/cloth/female/New()
|
||||
/datum/gear/ears/skrell/cloth/long/New()
|
||||
..()
|
||||
gear_tweaks = list(gear_tweak_free_color_choice)
|
||||
var/list/longtypes = list()
|
||||
for(var/long_style in typesof(/obj/item/clothing/ears/skrell/cloth_female))
|
||||
var/obj/item/clothing/ears/skrell/cloth_female/long = long_style
|
||||
longtypes[initial(long.name)] = long
|
||||
gear_tweaks += new/datum/gear_tweak/path(sortAssoc(longtypes))
|
||||
|
||||
/datum/gear/ears/skrell/colored/band
|
||||
display_name = "Colored bands (Skrell)"
|
||||
|
||||
@@ -43,9 +43,9 @@
|
||||
name = "winter boots"
|
||||
desc = "Boots lined with 'synthetic' animal fur."
|
||||
icon_state = "winterboots"
|
||||
cold_protection = FEET|LEGS
|
||||
cold_protection = FEET
|
||||
min_cold_protection_temperature = SHOE_MIN_COLD_PROTECTION_TEMPERATURE
|
||||
heat_protection = FEET|LEGS
|
||||
heat_protection = FEET
|
||||
max_heat_protection_temperature = SHOE_MAX_HEAT_PROTECTION_TEMPERATURE
|
||||
snow_speed = -1
|
||||
step_volume_mod = 0.8
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
siemens_coefficient = 0.9
|
||||
species_restricted = list("exclude","Diona")
|
||||
preserve_item = 1
|
||||
phoronproof = 1
|
||||
|
||||
var/obj/machinery/camera/camera
|
||||
var/list/camera_networks
|
||||
@@ -61,6 +62,7 @@
|
||||
siemens_coefficient = 0.9
|
||||
species_restricted = list("exclude","Diona")
|
||||
preserve_item = 1
|
||||
phoronproof = 1
|
||||
|
||||
var/list/supporting_limbs //If not-null, automatically splints breaks. Checked when removing the suit.
|
||||
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|BLOCKHAIR
|
||||
body_parts_covered = HEAD|FACE|EYES
|
||||
siemens_coefficient = 0.9
|
||||
item_flags = THICKMATERIAL
|
||||
phoronproof = 1
|
||||
|
||||
/obj/item/clothing/suit/bio_suit
|
||||
name = "bio suit"
|
||||
@@ -16,12 +18,14 @@
|
||||
w_class = ITEMSIZE_LARGE//bulky item
|
||||
gas_transfer_coefficient = 0.01
|
||||
permeability_coefficient = 0.01
|
||||
body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|FEET|ARMS|HANDS
|
||||
body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|ARMS|HANDS|FEET
|
||||
slowdown = 1.0
|
||||
allowed = list(/obj/item/weapon/tank/emergency/oxygen,/obj/item/weapon/pen,/obj/item/device/flashlight/pen)
|
||||
armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 100, rad = 20)
|
||||
flags_inv = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT|HIDETAIL|HIDETIE|HIDEHOLSTER
|
||||
siemens_coefficient = 0.9
|
||||
item_flags = THICKMATERIAL
|
||||
phoronproof = 1
|
||||
|
||||
//Standard biosuit, orange stripe
|
||||
/obj/item/clothing/head/bio_hood/general
|
||||
|
||||
@@ -659,9 +659,9 @@ obj/item/clothing/suit/storage/toggle/peacoat
|
||||
desc = "A heavy jacket made from 'synthetic' animal furs."
|
||||
icon_state = "coatwinter"
|
||||
item_state_slots = list(slot_r_hand_str = "coatwinter", slot_l_hand_str = "coatwinter")
|
||||
body_parts_covered = UPPER_TORSO|LOWER_TORSO|ARMS
|
||||
body_parts_covered = UPPER_TORSO|LOWER_TORSO|ARMS|LEGS
|
||||
flags_inv = HIDEHOLSTER
|
||||
cold_protection = UPPER_TORSO|LOWER_TORSO|ARMS
|
||||
cold_protection = UPPER_TORSO|LOWER_TORSO|ARMS|LEGS
|
||||
min_cold_protection_temperature = SPACE_SUIT_MIN_COLD_PROTECTION_TEMPERATURE
|
||||
armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 10, rad = 0)
|
||||
hooded = 1
|
||||
@@ -798,6 +798,9 @@ obj/item/clothing/suit/storage/toggle/peacoat
|
||||
name = "explorer hood"
|
||||
desc = "An armoured hood for exploring harsh environments."
|
||||
icon_state = "explorer"
|
||||
brightness_on = 3
|
||||
light_overlay = "hood_light"
|
||||
action_button_name = "Toggle Head-light"
|
||||
body_parts_covered = HEAD
|
||||
cold_protection = HEAD
|
||||
flags = THICKMATERIAL
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
var/mob/living/carbon/H = hood.loc
|
||||
H.unEquip(hood, 1)
|
||||
H.update_inv_wear_suit()
|
||||
hood.loc = src
|
||||
hood.forceMove(src)
|
||||
|
||||
/obj/item/clothing/suit/storage/hooded/dropped()
|
||||
RemoveHood()
|
||||
|
||||
@@ -95,4 +95,4 @@
|
||||
slowdown = 1.5
|
||||
armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 60, rad = 100)
|
||||
flags_inv = HIDEJUMPSUIT|HIDETAIL|HIDETIE|HIDEHOLSTER
|
||||
item_flags = THICKMATERIAL
|
||||
item_flags = THICKMATERIAL
|
||||
@@ -2,24 +2,20 @@
|
||||
announceWhen = 12
|
||||
endWhen = 120
|
||||
|
||||
var/obj/effect/blob/core/Blob
|
||||
var/obj/structure/blob/core/Blob
|
||||
|
||||
/datum/event/blob/announce()
|
||||
level_seven_announcement()
|
||||
|
||||
/datum/event/blob/start()
|
||||
var/turf/T = pick(blobstart)
|
||||
if(!T)
|
||||
kill()
|
||||
return
|
||||
Blob = new /obj/effect/blob/core(T)
|
||||
for(var/i = 1; i < rand(3, 4), i++)
|
||||
Blob.process()
|
||||
|
||||
Blob = new /obj/structure/blob/core/random_medium(T)
|
||||
|
||||
|
||||
/datum/event/blob/tick()
|
||||
if(!Blob || !Blob.loc)
|
||||
Blob = null
|
||||
kill()
|
||||
return
|
||||
if(IsMultiple(activeFor, 3))
|
||||
Blob.process()
|
||||
|
||||
@@ -238,7 +238,7 @@
|
||||
|
||||
/obj/effect/plant/attackby(var/obj/item/weapon/W, var/mob/user)
|
||||
|
||||
user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
|
||||
user.setClickCooldown(user.get_attack_speed(W))
|
||||
plant_controller.add_plant(src)
|
||||
|
||||
if(istype(W, /obj/item/weapon/wirecutters) || istype(W, /obj/item/weapon/surgical/scalpel))
|
||||
|
||||
@@ -61,7 +61,7 @@
|
||||
"<span class='warning'>You hear shredding and ripping.</span>")
|
||||
unbuckle()
|
||||
else
|
||||
user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
|
||||
user.setClickCooldown(user.get_attack_speed())
|
||||
health -= rand(1,5)
|
||||
var/text = pick("rip","tear","pull", "bite", "tug")
|
||||
user.visible_message(\
|
||||
|
||||
@@ -568,7 +568,7 @@
|
||||
return
|
||||
|
||||
else if(O.force && seed)
|
||||
user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
|
||||
user.setClickCooldown(user.get_attack_speed(O))
|
||||
user.visible_message("<span class='danger'>\The [seed.display_name] has been attacked by [user] with \the [O]!</span>")
|
||||
if(!dead)
|
||||
health -= O.force
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
var/accuracy_dispersion // Positive numbers make gun firing cover a wider tile range, and therefore more inaccurate. Negatives help negate dispersion penalties.
|
||||
var/metabolism_percent // Adjusts the mob's metabolic rate, which affects reagent processing. Won't affect mobs without reagent processing.
|
||||
var/icon_scale_percent // Makes the holder's icon get scaled up or down.
|
||||
var/attack_speed_percent // Makes the holder's 'attack speed' (click delay) shorter or longer.
|
||||
|
||||
/datum/modifier/New(var/new_holder, var/new_origin)
|
||||
holder = new_holder
|
||||
@@ -206,6 +207,9 @@
|
||||
if(!isnull(icon_scale_percent))
|
||||
effects += "Your appearance is [multipler_to_percentage(icon_scale_percent, TRUE)] [icon_scale_percent > 1 ? "larger" : "smaller"]."
|
||||
|
||||
if(!isnull(attack_speed_percent))
|
||||
effects += "The delay between attacking is [multipler_to_percentage(attack_speed_percent, TRUE)] [disable_duration_percent > 1.0 ? "longer" : "shorter"]."
|
||||
|
||||
return jointext(effects, "<br>")
|
||||
|
||||
|
||||
|
||||
@@ -140,7 +140,7 @@ note dizziness decrements automatically in the mob's Life() proc.
|
||||
//reset the pixel offsets to zero
|
||||
is_floating = 0
|
||||
|
||||
/mob/proc/do_attack_animation(mob/M)
|
||||
/atom/movable/proc/do_attack_animation(mob/M)
|
||||
|
||||
var/pixel_x_diff = 0
|
||||
var/pixel_y_diff = 0
|
||||
|
||||
@@ -283,19 +283,19 @@
|
||||
..()
|
||||
|
||||
/mob/living/carbon/human/getToxLoss()
|
||||
if((species.flags & NO_POISON) || isSynthetic())
|
||||
if(species.flags & NO_POISON)
|
||||
toxloss = 0
|
||||
return ..()
|
||||
|
||||
/mob/living/carbon/human/adjustToxLoss(var/amount)
|
||||
if((species.flags & NO_POISON) || isSynthetic())
|
||||
if(species.flags & NO_POISON)
|
||||
toxloss = 0
|
||||
else
|
||||
amount = amount*species.toxins_mod
|
||||
..(amount)
|
||||
|
||||
/mob/living/carbon/human/setToxLoss(var/amount)
|
||||
if((species.flags & NO_POISON) || isSynthetic())
|
||||
if(species.flags & NO_POISON)
|
||||
toxloss = 0
|
||||
else
|
||||
..()
|
||||
|
||||
@@ -165,6 +165,12 @@
|
||||
|
||||
output += "Current Battery Charge: [nutrition]\n"
|
||||
|
||||
var/toxDam = getToxLoss()
|
||||
if(toxDam)
|
||||
output += "System Instability: <span class='warning'>[toxDam > 25 ? "Severe" : "Moderate"]</span>\n"
|
||||
else
|
||||
output += "System Instability: <span style='color:green;'>OK</span>\n"
|
||||
|
||||
for(var/obj/item/organ/external/EO in organs)
|
||||
if(EO.brute_dam || EO.burn_dam)
|
||||
output += "[EO.name] - <span class='warning'>[EO.burn_dam + EO.brute_dam > ROBOLIMB_REPAIR_CAP ? "Heavy Damage" : "Light Damage"]</span>\n"
|
||||
|
||||
@@ -226,7 +226,7 @@
|
||||
if(gene.is_active(src))
|
||||
gene.OnMobLife(src)
|
||||
|
||||
radiation = Clamp(radiation,0,100)
|
||||
radiation = Clamp(radiation,0,250)
|
||||
|
||||
if(!radiation)
|
||||
if(species.appearance_flags & RADIATION_GLOWS)
|
||||
@@ -285,8 +285,12 @@
|
||||
adjustCloneLoss(5 * RADIATION_SPEED_COEFFICIENT)
|
||||
emote("gasp")
|
||||
|
||||
if (radiation > 150)
|
||||
damage = 6
|
||||
radiation -= 4 * RADIATION_SPEED_COEFFICIENT
|
||||
|
||||
if(damage)
|
||||
damage *= isSynthetic() ? 0.5 : species.radiation_mod
|
||||
damage *= species.radiation_mod
|
||||
adjustToxLoss(damage * RADIATION_SPEED_COEFFICIENT)
|
||||
updatehealth()
|
||||
if(!isSynthetic() && organs.len)
|
||||
@@ -816,18 +820,34 @@
|
||||
|
||||
if(!isSynthetic())
|
||||
|
||||
if(touching) touching.metabolize()
|
||||
if(ingested) ingested.metabolize()
|
||||
if(bloodstr) bloodstr.metabolize()
|
||||
if(touching)
|
||||
touching.metabolize()
|
||||
if(ingested)
|
||||
ingested.metabolize()
|
||||
if(bloodstr)
|
||||
bloodstr.metabolize()
|
||||
|
||||
var/total_phoronloss = 0
|
||||
for(var/obj/item/I in src)
|
||||
if(I.contaminated)
|
||||
if(src.species && src.species.get_bodytype() != "Vox")
|
||||
total_phoronloss += vsc.plc.CONTAMINATION_LOSS
|
||||
if(!(status_flags & GODMODE)) adjustToxLoss(total_phoronloss)
|
||||
// This is hacky, I'm so sorry.
|
||||
if(I != l_hand && I != r_hand) //If the item isn't in your hands, you're probably wearing it. Full damage for you.
|
||||
total_phoronloss += vsc.plc.CONTAMINATION_LOSS
|
||||
else if(I == l_hand) //If the item is in your hands, but you're wearing protection, you might be alright.
|
||||
var/l_hand_blocked = 0
|
||||
l_hand_blocked = 1-(100-getarmor(BP_L_HAND, "bio"))/100 //This should get a number between 0 and 1
|
||||
total_phoronloss += vsc.plc.CONTAMINATION_LOSS * l_hand_blocked
|
||||
else if(I == r_hand) //If the item is in your hands, but you're wearing protection, you might be alright.
|
||||
var/r_hand_blocked = 0
|
||||
r_hand_blocked = 1-(100-getarmor(BP_R_HAND, "bio"))/100 //This should get a number between 0 and 1
|
||||
total_phoronloss += vsc.plc.CONTAMINATION_LOSS * r_hand_blocked
|
||||
if(total_phoronloss)
|
||||
if(!(status_flags & GODMODE))
|
||||
adjustToxLoss(total_phoronloss)
|
||||
|
||||
if(status_flags & GODMODE) return 0 //godmode
|
||||
if(status_flags & GODMODE)
|
||||
return 0 //godmode
|
||||
|
||||
var/obj/item/organ/internal/diona/node/light_organ = locate() in internal_organs
|
||||
|
||||
@@ -1375,9 +1395,15 @@
|
||||
|
||||
// Puke if toxloss is too high
|
||||
if(!stat)
|
||||
if (getToxLoss() >= 30 && isSynthetic())
|
||||
if(!confused)
|
||||
if(prob(5))
|
||||
to_chat(src, "<span class='danger'>You lose directional control!</span>")
|
||||
Confuse(10)
|
||||
if (getToxLoss() >= 45)
|
||||
spawn vomit()
|
||||
|
||||
|
||||
//0.1% chance of playing a scary sound to someone who's in complete darkness
|
||||
if(isturf(loc) && rand(1,1000) == 1)
|
||||
var/turf/T = loc
|
||||
|
||||
@@ -58,12 +58,12 @@ default behaviour is:
|
||||
for(var/mob/living/M in range(tmob, 1))
|
||||
if(tmob.pinned.len || ((M.pulling == tmob && ( tmob.restrained() && !( M.restrained() ) && M.stat == 0)) || locate(/obj/item/weapon/grab, tmob.grabbed_by.len)) )
|
||||
if ( !(world.time % 5) )
|
||||
src << "<span class='warning'>[tmob] is restrained, you cannot push past</span>"
|
||||
to_chat(src, "<span class='warning'>[tmob] is restrained, you cannot push past</span>")
|
||||
now_pushing = 0
|
||||
return
|
||||
if( tmob.pulling == M && ( M.restrained() && !( tmob.restrained() ) && tmob.stat == 0) )
|
||||
if ( !(world.time % 5) )
|
||||
src << "<span class='warning'>[tmob] is restraining [M], you cannot push past</span>"
|
||||
to_chat(src, "<span class='warning'>[tmob] is restraining [M], you cannot push past</span>")
|
||||
now_pushing = 0
|
||||
return
|
||||
|
||||
@@ -103,7 +103,7 @@ default behaviour is:
|
||||
return
|
||||
if(istype(tmob, /mob/living/carbon/human) && (FAT in tmob.mutations))
|
||||
if(prob(40) && !(FAT in src.mutations))
|
||||
src << "<span class='danger'>You fail to push [tmob]'s fat ass out of the way.</span>"
|
||||
to_chat(src, "<span class='danger'>You fail to push [tmob]'s fat ass out of the way.</span>")
|
||||
now_pushing = 0
|
||||
return
|
||||
if(tmob.r_hand && istype(tmob.r_hand, /obj/item/weapon/shield/riot))
|
||||
@@ -129,9 +129,13 @@ default behaviour is:
|
||||
playsound(loc, "punch", 25, 1, -1)
|
||||
visible_message("<span class='warning'>[src] [pick("ran", "slammed")] into \the [AM]!</span>")
|
||||
src.apply_damage(5, BRUTE)
|
||||
src << ("<span class='warning'>You just [pick("ran", "slammed")] into \the [AM]!</span>")
|
||||
to_chat(src, "<span class='warning'>You just [pick("ran", "slammed")] into \the [AM]!</span>")
|
||||
return
|
||||
if (!now_pushing)
|
||||
if(isobj(AM))
|
||||
var/obj/I = AM
|
||||
if(!can_pull_size || can_pull_size < I.w_class)
|
||||
return
|
||||
now_pushing = 1
|
||||
|
||||
var/t = get_dir(src, AM)
|
||||
@@ -153,7 +157,7 @@ default behaviour is:
|
||||
if ((src.health < 0 && src.health > (5-src.getMaxHealth()))) // Health below Zero but above 5-away-from-death, as before, but variable
|
||||
src.adjustOxyLoss(src.health + src.getMaxHealth() * 2) // Deal 2x health in OxyLoss damage, as before but variable.
|
||||
src.health = src.getMaxHealth() - src.getOxyLoss() - src.getToxLoss() - src.getFireLoss() - src.getBruteLoss()
|
||||
src << "<font color='blue'>You have given up life and succumbed to death.</font>"
|
||||
to_chat(src, "<font color='blue'>You have given up life and succumbed to death.</font>")
|
||||
|
||||
|
||||
/mob/living/proc/updatehealth()
|
||||
@@ -239,6 +243,7 @@ default behaviour is:
|
||||
amount *= M.incoming_healing_percent
|
||||
|
||||
bruteloss = min(max(bruteloss + amount, 0),(getMaxHealth()*2))
|
||||
updatehealth()
|
||||
|
||||
/mob/living/proc/getOxyLoss()
|
||||
return oxyloss
|
||||
@@ -258,6 +263,7 @@ default behaviour is:
|
||||
amount *= M.incoming_healing_percent
|
||||
|
||||
oxyloss = min(max(oxyloss + amount, 0),(getMaxHealth()*2))
|
||||
updatehealth()
|
||||
|
||||
/mob/living/proc/setOxyLoss(var/amount)
|
||||
if(status_flags & GODMODE) return 0 //godmode
|
||||
@@ -281,6 +287,7 @@ default behaviour is:
|
||||
amount *= M.incoming_healing_percent
|
||||
|
||||
toxloss = min(max(toxloss + amount, 0),(getMaxHealth()*2))
|
||||
updatehealth()
|
||||
|
||||
/mob/living/proc/setToxLoss(var/amount)
|
||||
if(status_flags & GODMODE) return 0 //godmode
|
||||
@@ -309,6 +316,7 @@ default behaviour is:
|
||||
amount *= M.incoming_healing_percent
|
||||
|
||||
fireloss = min(max(fireloss + amount, 0),(getMaxHealth()*2))
|
||||
updatehealth()
|
||||
|
||||
/mob/living/proc/getCloneLoss()
|
||||
return cloneloss
|
||||
@@ -328,6 +336,7 @@ default behaviour is:
|
||||
amount *= M.incoming_healing_percent
|
||||
|
||||
cloneloss = min(max(cloneloss + amount, 0),(getMaxHealth()*2))
|
||||
updatehealth()
|
||||
|
||||
/mob/living/proc/setCloneLoss(var/amount)
|
||||
if(status_flags & GODMODE) return 0 //godmode
|
||||
@@ -362,6 +371,7 @@ default behaviour is:
|
||||
if(!isnull(M.incoming_healing_percent))
|
||||
amount *= M.incoming_healing_percent
|
||||
halloss = min(max(halloss + amount, 0),(getMaxHealth()*2))
|
||||
updatehealth()
|
||||
|
||||
/mob/living/proc/setHalLoss(var/amount)
|
||||
if(status_flags & GODMODE) return 0 //godmode
|
||||
@@ -640,11 +650,11 @@ default behaviour is:
|
||||
|
||||
if(config.allow_Metadata)
|
||||
if(client)
|
||||
usr << "[src]'s Metainfo:<br>[client.prefs.metadata]"
|
||||
to_chat(usr, "[src]'s Metainfo:<br>[client.prefs.metadata]")
|
||||
else
|
||||
usr << "[src] does not have any stored infomation!"
|
||||
to_chat(usr, "[src] does not have any stored infomation!")
|
||||
else
|
||||
usr << "OOC Metadata is not supported by this server!"
|
||||
to_chat(usr, "OOC Metadata is not supported by this server!")
|
||||
|
||||
return
|
||||
|
||||
@@ -791,8 +801,8 @@ default behaviour is:
|
||||
|
||||
if(istype(M))
|
||||
M.drop_from_inventory(H)
|
||||
M << "<span class='warning'>\The [H] wriggles out of your grip!</span>"
|
||||
src << "<span class='warning'>You wriggle out of \the [M]'s grip!</span>"
|
||||
to_chat(M, "<span class='warning'>\The [H] wriggles out of your grip!</span>")
|
||||
to_chat(src, "<span class='warning'>You wriggle out of \the [M]'s grip!</span>")
|
||||
|
||||
// Update whether or not this mob needs to pass emotes to contents.
|
||||
for(var/atom/A in M.contents)
|
||||
@@ -804,10 +814,10 @@ default behaviour is:
|
||||
var/obj/item/clothing/accessory/holster/holster = H.loc
|
||||
if(holster.holstered == H)
|
||||
holster.clear_holster()
|
||||
src << "<span class='warning'>You extricate yourself from \the [holster].</span>"
|
||||
to_chat(src, "<span class='warning'>You extricate yourself from \the [holster].</span>")
|
||||
H.forceMove(get_turf(H))
|
||||
else if(istype(H.loc,/obj/item))
|
||||
src << "<span class='warning'>You struggle free of \the [H.loc].</span>"
|
||||
to_chat(src, "<span class='warning'>You struggle free of \the [H.loc].</span>")
|
||||
H.forceMove(get_turf(H))
|
||||
|
||||
/mob/living/proc/escape_buckle()
|
||||
@@ -827,7 +837,7 @@ default behaviour is:
|
||||
set category = "IC"
|
||||
|
||||
resting = !resting
|
||||
src << "<span class='notice'>You are now [resting ? "resting" : "getting up"]</span>"
|
||||
to_chat(src, "<span class='notice'>You are now [resting ? "resting" : "getting up"]</span>")
|
||||
|
||||
/mob/living/proc/cannot_use_vents()
|
||||
if(mob_size > MOB_SMALL)
|
||||
@@ -863,7 +873,7 @@ default behaviour is:
|
||||
inertia_dir = 1
|
||||
else if(y >= world.maxy -TRANSITIONEDGE)
|
||||
inertia_dir = 2
|
||||
src << "<span class='warning'>Something you are carrying is preventing you from leaving.</span>"
|
||||
to_chat(src, "<span class='warning'>Something you are carrying is preventing you from leaving.</span>")
|
||||
return
|
||||
|
||||
..()
|
||||
@@ -881,54 +891,52 @@ default behaviour is:
|
||||
ear_deaf = deaf
|
||||
|
||||
/mob/living/proc/vomit(var/skip_wait, var/blood_vomit)
|
||||
|
||||
if(isSynthetic())
|
||||
src << "<span class='danger'>A sudden, dizzying wave of internal feedback rushes over you!</span>"
|
||||
src.Weaken(5)
|
||||
return
|
||||
|
||||
if(!check_has_mouth())
|
||||
return
|
||||
|
||||
if(!lastpuke)
|
||||
lastpuke = 1
|
||||
if (nutrition <= 100)
|
||||
src << "<span class='danger'>You gag as you want to throw up, but there's nothing in your stomach!</span>"
|
||||
src.Weaken(10)
|
||||
if(isSynthetic())
|
||||
to_chat(src, "<span class='danger'>A sudden, dizzying wave of internal feedback rushes over you!</span>")
|
||||
src.Weaken(5)
|
||||
else
|
||||
src << "<span class='warning'>You feel nauseous...</span>"
|
||||
|
||||
if(!skip_wait)
|
||||
sleep(150) //15 seconds until second warning
|
||||
src << "<span class='warning'>You feel like you are about to throw up!</span>"
|
||||
sleep(100) //and you have 10 more for mad dash to the bucket
|
||||
|
||||
//Damaged livers cause you to vomit blood.
|
||||
if(!blood_vomit)
|
||||
if(ishuman(src))
|
||||
var/mob/living/carbon/human/H = src
|
||||
if(!H.isSynthetic())
|
||||
var/obj/item/organ/internal/liver/L = H.internal_organs_by_name["liver"]
|
||||
if(L.is_broken())
|
||||
blood_vomit = 1
|
||||
|
||||
Stun(5)
|
||||
src.visible_message("<span class='warning'>[src] throws up!</span>","<span class='warning'>You throw up!</span>")
|
||||
playsound(loc, 'sound/effects/splat.ogg', 50, 1)
|
||||
|
||||
var/turf/simulated/T = get_turf(src) //TODO: Make add_blood_floor remove blood from human mobs
|
||||
if(istype(T))
|
||||
if(blood_vomit)
|
||||
T.add_blood_floor(src)
|
||||
else
|
||||
T.add_vomit_floor(src, 1)
|
||||
|
||||
if(blood_vomit)
|
||||
if(getBruteLoss() < 50)
|
||||
adjustBruteLoss(3)
|
||||
if (nutrition <= 100)
|
||||
to_chat(src, "<span class='danger'>You gag as you want to throw up, but there's nothing in your stomach!</span>")
|
||||
src.Weaken(10)
|
||||
else
|
||||
nutrition -= 40
|
||||
adjustToxLoss(-3)
|
||||
to_chat(src, "<span class='warning'>You feel nauseous...</span>")
|
||||
|
||||
if(!skip_wait)
|
||||
sleep(150) //15 seconds until second warning
|
||||
to_chat(src, "<span class='warning'>You feel like you are about to throw up!</span>")
|
||||
sleep(100) //and you have 10 more for mad dash to the bucket
|
||||
|
||||
//Damaged livers cause you to vomit blood.
|
||||
if(!blood_vomit)
|
||||
if(ishuman(src))
|
||||
var/mob/living/carbon/human/H = src
|
||||
if(!H.isSynthetic())
|
||||
var/obj/item/organ/internal/liver/L = H.internal_organs_by_name["liver"]
|
||||
if(L.is_broken())
|
||||
blood_vomit = 1
|
||||
|
||||
Stun(5)
|
||||
src.visible_message("<span class='warning'>[src] throws up!</span>","<span class='warning'>You throw up!</span>")
|
||||
playsound(loc, 'sound/effects/splat.ogg', 50, 1)
|
||||
|
||||
var/turf/simulated/T = get_turf(src) //TODO: Make add_blood_floor remove blood from human mobs
|
||||
if(istype(T))
|
||||
if(blood_vomit)
|
||||
T.add_blood_floor(src)
|
||||
else
|
||||
T.add_vomit_floor(src, 1)
|
||||
|
||||
if(blood_vomit)
|
||||
if(getBruteLoss() < 50)
|
||||
adjustBruteLoss(3)
|
||||
else
|
||||
nutrition -= 40
|
||||
adjustToxLoss(-3)
|
||||
|
||||
sleep(350)
|
||||
lastpuke = 0
|
||||
|
||||
@@ -162,6 +162,43 @@
|
||||
O.emp_act(severity)
|
||||
..()
|
||||
|
||||
/mob/living/blob_act(var/obj/structure/blob/B)
|
||||
if(stat == DEAD)
|
||||
return
|
||||
|
||||
var/damage = rand(30, 40)
|
||||
var/armor_pen = 0
|
||||
var/armor_check = "melee"
|
||||
var/damage_type = BRUTE
|
||||
var/attack_message = "The blob attacks you!"
|
||||
var/attack_verb = "attacks"
|
||||
var/def_zone = pick(BP_HEAD, BP_TORSO, BP_GROIN, BP_L_ARM, BP_R_ARM, BP_L_LEG, BP_R_LEG)
|
||||
|
||||
if(B && B.overmind)
|
||||
var/datum/blob_type/blob = B.overmind.blob_type
|
||||
|
||||
damage = rand(blob.damage_lower, blob.damage_upper)
|
||||
armor_check = blob.armor_check
|
||||
armor_pen = blob.armor_pen
|
||||
damage_type = blob.damage_type
|
||||
|
||||
attack_message = "[blob.attack_message][isSynthetic() ? "[blob.attack_message_synth]":"[blob.attack_message_living]"]"
|
||||
attack_verb = blob.attack_verb
|
||||
B.overmind.blob_type.on_attack(B, src, def_zone)
|
||||
|
||||
if( (damage_type == TOX || damage_type == OXY) && isSynthetic()) // Borgs and FBPs don't really handle tox/oxy damage the same way other mobs do.
|
||||
damage_type = BRUTE
|
||||
damage *= 0.66 // Take 2/3s as much damage.
|
||||
|
||||
visible_message("<span class='danger'>\The [B] [attack_verb] \the [src]!</span>", "<span class='danger'>[attack_message]!</span>")
|
||||
playsound(loc, 'sound/effects/attackblob.ogg', 50, 1)
|
||||
|
||||
//Armor
|
||||
var/soaked = get_armor_soak(def_zone, armor_check, armor_pen)
|
||||
var/absorb = run_armor_check(def_zone, armor_check, armor_pen)
|
||||
|
||||
apply_damage(damage, damage_type, def_zone, absorb, soaked)
|
||||
|
||||
/mob/living/proc/resolve_item_attack(obj/item/I, mob/living/user, var/target_zone)
|
||||
return target_zone
|
||||
|
||||
|
||||
@@ -486,7 +486,7 @@
|
||||
return
|
||||
var/obj/item/weapon/weldingtool/WT = W
|
||||
if (WT.remove_fuel(0))
|
||||
user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
|
||||
user.setClickCooldown(user.get_attack_speed(WT))
|
||||
adjustBruteLoss(-30)
|
||||
updatehealth()
|
||||
add_fingerprint(user)
|
||||
@@ -502,7 +502,7 @@
|
||||
return
|
||||
var/obj/item/stack/cable_coil/coil = W
|
||||
if (coil.use(1))
|
||||
user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
|
||||
user.setClickCooldown(user.get_attack_speed(W))
|
||||
adjustFireLoss(-30)
|
||||
updatehealth()
|
||||
for(var/mob/O in viewers(user, null))
|
||||
|
||||
@@ -29,8 +29,8 @@
|
||||
|
||||
|
||||
/mob/living/simple_animal/parrot
|
||||
name = "\improper Parrot"
|
||||
desc = "The parrot squaks, \"It's a Parrot! BAWWK!\""
|
||||
name = "parrot"
|
||||
desc = "The parrot squawks, \"It's a parrot! BAWWK!\""
|
||||
icon = 'icons/mob/animal.dmi'
|
||||
icon_state = "parrot_fly"
|
||||
icon_living = "parrot_fly"
|
||||
@@ -47,9 +47,9 @@
|
||||
stop_automated_movement = 1
|
||||
universal_speak = 1
|
||||
|
||||
has_langs = list("Bird")
|
||||
has_langs = list("Bird", "Galactic Common")
|
||||
speak_chance = 2
|
||||
speak = list("Hi","Hello!","Cracker?","BAWWWWK george mellons griffing me")
|
||||
speak = list("Hi","Hello!","Cracker?","Bawk!")
|
||||
speak_emote = list("squawks","says","yells")
|
||||
emote_hear = list("squawks","bawks")
|
||||
emote_see = list("flutters its wings")
|
||||
@@ -164,19 +164,19 @@
|
||||
if(copytext(possible_phrase,1,3) in department_radio_keys)
|
||||
possible_phrase = copytext(possible_phrase,3,length(possible_phrase))
|
||||
else
|
||||
usr << "<font color='red'>There is nothing to remove from its [remove_from].</font>"
|
||||
to_chat(usr, "<font color='red'>There is nothing to remove from its [remove_from].</font>")
|
||||
return
|
||||
|
||||
//Adding things to inventory
|
||||
else if(href_list["add_inv"])
|
||||
var/add_to = href_list["add_inv"]
|
||||
if(!usr.get_active_hand())
|
||||
usr << "<font color='red'>You have nothing in your hand to put on its [add_to].</font>"
|
||||
to_chat(usr, "<font color='red'>You have nothing in your hand to put on its [add_to].</font>")
|
||||
return
|
||||
switch(add_to)
|
||||
if("ears")
|
||||
if(ears)
|
||||
usr << "<font color='red'>It's already wearing something.</font>"
|
||||
to_chat(usr, "<font color='red'>It's already wearing something.</font>")
|
||||
return
|
||||
else
|
||||
var/obj/item/item_to_add = usr.get_active_hand()
|
||||
@@ -184,7 +184,7 @@
|
||||
return
|
||||
|
||||
if( !istype(item_to_add, /obj/item/device/radio/headset) )
|
||||
usr << "<font color='red'>This object won't fit.</font>"
|
||||
to_chat(usr, "<font color='red'>This object won't fit.</font>")
|
||||
return
|
||||
|
||||
var/obj/item/device/radio/headset/headset_to_add = item_to_add
|
||||
@@ -192,7 +192,7 @@
|
||||
usr.drop_item()
|
||||
headset_to_add.forceMove(src)
|
||||
src.ears = headset_to_add
|
||||
usr << "You fit the headset onto [src]."
|
||||
to_chat(usr, "You fit the headset onto [src].")
|
||||
|
||||
clearlist(available_channels)
|
||||
for(var/ch in headset_to_add.channels)
|
||||
@@ -213,7 +213,7 @@
|
||||
available_channels.Add(":q")
|
||||
|
||||
if(headset_to_add.translate_binary)
|
||||
available_channels.Add(":b")
|
||||
available_channels.Add("#b")
|
||||
else
|
||||
..()
|
||||
|
||||
@@ -576,7 +576,7 @@
|
||||
return -1
|
||||
|
||||
if(held_item)
|
||||
src << "<font color='red'>You are already holding the [held_item]</font>"
|
||||
to_chat(src, "<font color='red'>You are already holding the [held_item]</font>")
|
||||
return 1
|
||||
|
||||
for(var/obj/item/I in view(1,src))
|
||||
@@ -592,7 +592,7 @@
|
||||
visible_message("[src] grabs the [held_item]!", "<font color='blue'>You grab the [held_item]!</font>", "You hear the sounds of wings flapping furiously.")
|
||||
return held_item
|
||||
|
||||
src << "<font color='red'>There is nothing of interest to take.</font>"
|
||||
to_chat(src, "<font color='red'>There is nothing of interest to take.</font>")
|
||||
return 0
|
||||
|
||||
/mob/living/simple_animal/parrot/proc/steal_from_mob()
|
||||
@@ -604,7 +604,7 @@
|
||||
return -1
|
||||
|
||||
if(held_item)
|
||||
src << "<font color='red'>You are already holding the [held_item]</font>"
|
||||
to_chat(src, "<font color='red'>You are already holding the [held_item]</font>")
|
||||
return 1
|
||||
|
||||
var/obj/item/stolen_item = null
|
||||
@@ -623,7 +623,7 @@
|
||||
visible_message("[src] grabs the [held_item] out of [C]'s hand!", "<font color='blue'>You snag the [held_item] out of [C]'s hand!</font>", "You hear the sounds of wings flapping furiously.")
|
||||
return held_item
|
||||
|
||||
src << "<font color='red'>There is nothing of interest to take.</font>"
|
||||
to_chat(src, "<font color='red'>There is nothing of interest to take.</font>")
|
||||
return 0
|
||||
|
||||
/mob/living/simple_animal/parrot/verb/drop_held_item_player()
|
||||
@@ -647,7 +647,7 @@
|
||||
return -1
|
||||
|
||||
if(!held_item)
|
||||
usr << "<font color='red'>You have nothing to drop!</font>"
|
||||
to_chat(usr, "<font color='red'>You have nothing to drop!</font>")
|
||||
return 0
|
||||
|
||||
if(!drop_gently)
|
||||
@@ -655,11 +655,11 @@
|
||||
var/obj/item/weapon/grenade/G = held_item
|
||||
G.forceMove(src.loc)
|
||||
G.prime()
|
||||
src << "You let go of the [held_item]!"
|
||||
to_chat(src, "You let go of the [held_item]!")
|
||||
held_item = null
|
||||
return 1
|
||||
|
||||
src << "You drop the [held_item]."
|
||||
to_chat(src, "You drop the [held_item].")
|
||||
|
||||
held_item.forceMove(src.loc)
|
||||
held_item = null
|
||||
@@ -680,7 +680,7 @@
|
||||
src.forceMove(AM.loc)
|
||||
icon_state = "parrot_sit"
|
||||
return
|
||||
src << "<font color='red'>There is no perch nearby to sit on.</font>"
|
||||
to_chat(src, "<font color='red'>There is no perch nearby to sit on.</font>")
|
||||
return
|
||||
|
||||
/*
|
||||
@@ -764,4 +764,4 @@
|
||||
parrot_interest = user
|
||||
parrot_state = PARROT_SWOOP | PARROT_ATTACK //Attack other animals regardless
|
||||
icon_state = "parrot_fly"
|
||||
return success
|
||||
return success
|
||||
|
||||
@@ -213,7 +213,7 @@
|
||||
// Otherwise they're probably fighting the slime.
|
||||
if(prob(25))
|
||||
visible_message("<span class='danger'>\The [user]'s [W] passes right through [src]!</span>")
|
||||
user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
|
||||
user.setClickCooldown(user.get_attack_speed(W))
|
||||
return
|
||||
..()
|
||||
|
||||
|
||||
@@ -4,7 +4,10 @@
|
||||
return
|
||||
|
||||
if(!gibbed && is_adult)
|
||||
var/mob/living/simple_animal/slime/S = make_new_slime()
|
||||
var/death_type = type_on_death
|
||||
if(!death_type)
|
||||
death_type = src.type
|
||||
var/mob/living/simple_animal/slime/S = make_new_slime(death_type)
|
||||
S.rabid = TRUE
|
||||
step_away(S, src)
|
||||
is_adult = FALSE
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/mob/living/simple_animal/slime
|
||||
name = "baby slime"
|
||||
name = "slime"
|
||||
desc = "The most basic of slimes. The grey slime has no remarkable qualities, however it remains one of the most useful colors for scientists."
|
||||
icon = 'icons/mob/slime2.dmi'
|
||||
icon_state = "grey baby slime"
|
||||
@@ -84,6 +84,7 @@
|
||||
/mob/living/simple_animal/slime/blue,
|
||||
/mob/living/simple_animal/slime/purple
|
||||
)
|
||||
var/type_on_death = null // Set this if you want dying slimes to split into a specific type and not their type.
|
||||
|
||||
var/reagent_injected = null // Some slimes inject reagents on attack. This tells the game what reagent to use.
|
||||
var/injection_amount = 5 // This determines how much.
|
||||
@@ -123,7 +124,7 @@
|
||||
/mob/living/simple_animal/slime/proc/update_name()
|
||||
if(docile) // Docile slimes are generally named, so we shouldn't mess with it.
|
||||
return
|
||||
name = "[slime_color] [is_adult ? "adult" : "baby"] slime ([number])"
|
||||
name = "[slime_color] [is_adult ? "adult" : "baby"] [initial(name)] ([number])"
|
||||
real_name = name
|
||||
|
||||
/mob/living/simple_animal/slime/update_icon()
|
||||
@@ -338,8 +339,10 @@
|
||||
to_chat(src, "<span class='notice'>I am not old enough to reproduce yet...</span>")
|
||||
|
||||
// Used for reproducing and dying.
|
||||
/mob/living/simple_animal/slime/proc/make_new_slime()
|
||||
/mob/living/simple_animal/slime/proc/make_new_slime(var/desired_type)
|
||||
var/t = src.type
|
||||
if(desired_type)
|
||||
t = desired_type
|
||||
if(prob(mutation_chance / 10))
|
||||
t = /mob/living/simple_animal/slime/rainbow
|
||||
|
||||
|
||||
@@ -209,6 +209,26 @@
|
||||
/mob/living/simple_animal/slime/dark_blue/get_cold_protection()
|
||||
return 1 // This slime is immune to cold.
|
||||
|
||||
// Surfave variant
|
||||
/mob/living/simple_animal/slime/dark_blue/wild
|
||||
name = "wild slime"
|
||||
desc = "The result of slimes escaping containment from some xenobiology lab. The slime makes other entities near it feel much colder, \
|
||||
and it is more resilient to the cold. These qualities have made this color of slime able to thrive on a harsh, cold world and is able to rival \
|
||||
the ferocity of other apex predators in this region of Sif. As such, it is a very invasive species."
|
||||
description_info = "This slime makes other entities near it feel much colder, and is more resilient to the cold. It also has learned advanced combat tactics from \
|
||||
having to endure the harsh world outside its lab. Note that processing this large slime will give six cores."
|
||||
icon_scale = 2
|
||||
optimal_combat = TRUE // Gotta be sharp to survive out there.
|
||||
rabid = TRUE
|
||||
cores = 6
|
||||
maxHealth = 150 // Base health
|
||||
maxHealth_adult = 250
|
||||
type_on_death = /mob/living/simple_animal/slime/dark_blue // Otherwise infinite slimes might occur.
|
||||
pixel_y = -10 // Since the base sprite isn't centered properly, the pixel auto-adjustment needs some help.
|
||||
|
||||
/mob/living/simple_animal/slime/dark_blue/wild/New()
|
||||
..()
|
||||
make_adult()
|
||||
|
||||
/mob/living/simple_animal/slime/silver
|
||||
desc = "This slime is shiny, and can deflect lasers or other energy weapons directed at it."
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
dead_mob_list += src
|
||||
else
|
||||
living_mob_list += src
|
||||
update_transform() // Some mobs may start bigger or smaller than normal.
|
||||
..()
|
||||
|
||||
/mob/proc/show_message(msg, type, alt, alt_type)//Message, type of message (1 or 2), alternative message, alt message type (1 or 2)
|
||||
|
||||
@@ -104,8 +104,6 @@
|
||||
var/cpr_time = 1.0//Carbon
|
||||
|
||||
var/bodytemperature = 310.055 //98.7 F
|
||||
var/old_x = 0
|
||||
var/old_y = 0
|
||||
var/drowsyness = 0.0//Carbon
|
||||
var/charges = 0.0
|
||||
var/nutrition = 400.0//Carbon
|
||||
|
||||
@@ -62,6 +62,10 @@
|
||||
name = "Short Hair 2"
|
||||
icon_state = "hair_shorthair3"
|
||||
|
||||
short3
|
||||
name = "Short Hair 3"
|
||||
icon_state = "hair_shorthair4"
|
||||
|
||||
twintail
|
||||
name = "Twintail"
|
||||
icon_state = "hair_twintail"
|
||||
|
||||
@@ -411,7 +411,7 @@
|
||||
user << "<span class='warning'>You can't reach your [src.name] while holding [tool] in your [owner.get_bodypart_name(grasp)].</span>"
|
||||
return 0
|
||||
|
||||
user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
|
||||
user.setClickCooldown(user.get_attack_speed(tool))
|
||||
if(!do_mob(user, owner, 10))
|
||||
user << "<span class='warning'>You must stand still to do that.</span>"
|
||||
return 0
|
||||
|
||||
@@ -687,6 +687,12 @@
|
||||
update_icon()
|
||||
return 1
|
||||
|
||||
/obj/machinery/power/apc/blob_act()
|
||||
if(!wires.IsAllCut())
|
||||
wiresexposed = TRUE
|
||||
wires.CutAll()
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/power/apc/attack_hand(mob/user)
|
||||
// if (!can_use(user)) This already gets called in interact() and in topic()
|
||||
// return
|
||||
@@ -699,7 +705,7 @@
|
||||
var/mob/living/carbon/human/H = user
|
||||
|
||||
if(H.species.can_shred(H))
|
||||
user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
|
||||
user.setClickCooldown(user.get_attack_speed())
|
||||
user.visible_message("<span call='warning'>[user.name] slashes at the [src.name]!</span>", "<span class='notice'>You slash at the [src.name]!</span>")
|
||||
playsound(src.loc, 'sound/weapons/slash.ogg', 100, 1)
|
||||
|
||||
|
||||
@@ -329,6 +329,9 @@
|
||||
broken()
|
||||
return 1
|
||||
|
||||
/obj/machinery/light/blob_act()
|
||||
broken()
|
||||
|
||||
// attempt to set the light's on/off status
|
||||
// will not switch on if broken/burned/empty
|
||||
/obj/machinery/light/proc/seton(var/s)
|
||||
@@ -527,7 +530,7 @@
|
||||
if(istype(user,/mob/living/carbon/human))
|
||||
var/mob/living/carbon/human/H = user
|
||||
if(H.species.can_shred(H))
|
||||
user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
|
||||
user.setClickCooldown(user.get_attack_speed())
|
||||
for(var/mob/M in viewers(src))
|
||||
M.show_message("<font color='red'>[user.name] smashed the light!</font>", 3, "You hear a tinkle of breaking glass", 2)
|
||||
broken()
|
||||
|
||||
@@ -250,14 +250,21 @@
|
||||
if(!P || !P.damage || P.get_structure_damage() <= 0 )
|
||||
return
|
||||
|
||||
integrity = integrity - P.damage
|
||||
if(integrity <= 0)
|
||||
adjust_integrity(-P.get_structure_damage())
|
||||
|
||||
/obj/machinery/power/emitter/blob_act()
|
||||
adjust_integrity(-1000) // This kills the emitter.
|
||||
|
||||
/obj/machinery/power/emitter/proc/adjust_integrity(amount)
|
||||
integrity = between(0, integrity + amount, initial(integrity))
|
||||
if(integrity == 0)
|
||||
if(powernet && avail(active_power_usage)) // If it's powered, it goes boom if killed.
|
||||
visible_message(src, "<span class='danger'>\The [src] explodes violently!</span>", "<span class='danger'>You hear an explosion!</span>")
|
||||
explosion(get_turf(src), 1, 2, 4)
|
||||
else
|
||||
src.visible_message("<span class='danger'>\The [src] crumples apart!</span>", "<span class='warning'>You hear metal collapsing.</span>")
|
||||
qdel(src)
|
||||
if(src)
|
||||
qdel(src)
|
||||
|
||||
/obj/machinery/power/emitter/examine(mob/user)
|
||||
..()
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
mrate_static = TRUE
|
||||
affects_dead = 1 //so you can pump blood into someone before defibbing them
|
||||
color = "#C80000"
|
||||
var/volume_mod = 1 // So if you add different subtypes of blood, you can affect how much vessel blood each unit of reagent adds
|
||||
|
||||
glass_name = "tomato juice"
|
||||
glass_desc = "Are you sure this is tomato juice?"
|
||||
@@ -69,9 +70,21 @@
|
||||
M.antibodies |= data["antibodies"]
|
||||
|
||||
/datum/reagent/blood/affect_blood(var/mob/living/carbon/M, var/alien, var/removed)
|
||||
M.inject_blood(src, volume)
|
||||
M.inject_blood(src, volume * volume_mod)
|
||||
remove_self(volume)
|
||||
|
||||
/datum/reagent/blood/synthblood
|
||||
name = "Synthetic blood"
|
||||
id = "synthblood"
|
||||
color = "#999966"
|
||||
volume_mod = 2
|
||||
|
||||
/datum/reagent/blood/synthblood/initialize_data(var/newdata)
|
||||
..()
|
||||
if(data && !data["blood_type"])
|
||||
data["blood_type"] = "O-"
|
||||
return
|
||||
|
||||
// pure concentrated antibodies
|
||||
/datum/reagent/antibodies
|
||||
data = list("antibodies"=list())
|
||||
@@ -124,11 +137,13 @@
|
||||
else if(volume >= 10)
|
||||
T.wet_floor(1)
|
||||
|
||||
/datum/reagent/water/touch_obj(var/obj/O)
|
||||
/datum/reagent/water/touch_obj(var/obj/O, var/amount)
|
||||
if(istype(O, /obj/item/weapon/reagent_containers/food/snacks/monkeycube))
|
||||
var/obj/item/weapon/reagent_containers/food/snacks/monkeycube/cube = O
|
||||
if(!cube.wrapped)
|
||||
cube.Expand()
|
||||
else
|
||||
O.water_act(amount / 5)
|
||||
|
||||
/datum/reagent/water/touch_mob(var/mob/living/L, var/amount)
|
||||
if(istype(L))
|
||||
|
||||
@@ -101,7 +101,7 @@
|
||||
user << "<span class='warning'>\The [blocked] is in the way!</span>"
|
||||
return
|
||||
|
||||
user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) //puts a limit on how fast people can eat/drink things
|
||||
user.setClickCooldown(user.get_attack_speed(src)) //puts a limit on how fast people can eat/drink things
|
||||
self_feed_message(user)
|
||||
reagents.trans_to_mob(user, issmall(user) ? ceil(amount_per_transfer_from_this/2) : amount_per_transfer_from_this, CHEM_INGEST)
|
||||
feed_sound(user)
|
||||
@@ -119,7 +119,7 @@
|
||||
|
||||
other_feed_message_start(user, target)
|
||||
|
||||
user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
|
||||
user.setClickCooldown(user.get_attack_speed(src))
|
||||
if(!do_mob(user, target))
|
||||
return
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
desc = "An advanced nanite and chemical synthesizer and injection system, designed for heavy-duty medical equipment. This type is capable of safely bypassing \
|
||||
thick materials that other hyposprays would struggle with."
|
||||
bypass_protection = TRUE // Because mercs tend to be in spacesuits.
|
||||
reagent_ids = list("healing_nanites", "hyperzine", "tramadol", "oxycodone", "spaceacillin", "peridaxon", "osteodaxon", "myelamine")
|
||||
reagent_ids = list("healing_nanites", "hyperzine", "tramadol", "oxycodone", "spaceacillin", "peridaxon", "osteodaxon", "myelamine", "synthblood")
|
||||
|
||||
/obj/item/weapon/reagent_containers/borghypo/New()
|
||||
..()
|
||||
|
||||
@@ -68,7 +68,7 @@
|
||||
user << "<span class='warning'>\The [blocked] is in the way!</span>"
|
||||
return
|
||||
|
||||
user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) //puts a limit on how fast people can eat/drink things
|
||||
user.setClickCooldown(user.get_attack_speed(src)) //puts a limit on how fast people can eat/drink things
|
||||
if (fullness <= 50)
|
||||
M << "<span class='danger'>You hungrily chew out a piece of [src] and gobble it!</span>"
|
||||
if (fullness > 50 && fullness <= 150)
|
||||
@@ -101,7 +101,7 @@
|
||||
user.visible_message("<span class='danger'>[user] cannot force anymore of [src] down [M]'s throat.</span>")
|
||||
return 0
|
||||
|
||||
user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
|
||||
user.setClickCooldown(user.get_attack_speed(src))
|
||||
if(!do_mob(user, M)) return
|
||||
|
||||
M.attack_log += text("\[[time_stamp()]\] <font color='orange'>Has been fed [src.name] by [user.name] ([user.ckey]) Reagents: [reagentlist(src)]</font>")
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
|
||||
user.visible_message("<span class='warning'>[user] attempts to force [M] to swallow \the [src].</span>")
|
||||
|
||||
user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
|
||||
user.setClickCooldown(user.get_attack_speed(src))
|
||||
if(!do_mob(user, M))
|
||||
return
|
||||
|
||||
|
||||
@@ -198,12 +198,4 @@
|
||||
|
||||
/obj/item/weapon/reagent_containers/spray/plantbgone/New()
|
||||
..()
|
||||
reagents.add_reagent("plantbgone", 100)
|
||||
|
||||
/obj/item/weapon/reagent_containers/spray/plantbgone/afterattack(atom/A as mob|obj, mob/user as mob, proximity)
|
||||
if(!proximity) return
|
||||
|
||||
if(istype(A, /obj/effect/blob)) // blob damage in blob code
|
||||
return
|
||||
|
||||
..()
|
||||
reagents.add_reagent("plantbgone", 100)
|
||||
@@ -59,7 +59,8 @@
|
||||
else
|
||||
return
|
||||
|
||||
|
||||
/obj/structure/reagent_dispensers/blob_act()
|
||||
qdel(src)
|
||||
|
||||
|
||||
|
||||
@@ -160,6 +161,9 @@
|
||||
/obj/structure/reagent_dispensers/fueltank/ex_act()
|
||||
explode()
|
||||
|
||||
/obj/structure/reagent_dispensers/fueltank/blob_act()
|
||||
explode()
|
||||
|
||||
/obj/structure/reagent_dispensers/fueltank/proc/explode()
|
||||
if (reagents.total_volume > 500)
|
||||
explosion(src.loc,1,2,4)
|
||||
|
||||
@@ -751,6 +751,14 @@ other types of metals and chemistry for reagents).
|
||||
build_path = /obj/item/device/paicard
|
||||
sort_string = "VABAI"
|
||||
|
||||
/datum/design/item/communicator
|
||||
name = "Communcator"
|
||||
id = "communicator"
|
||||
req_tech = list(TECH_DATA = 2, TECH_MAGNET = 2)
|
||||
materials = list(DEFAULT_WALL_MATERIAL = 500, "glass" = 500)
|
||||
build_path = /obj/item/device/communicator
|
||||
sort_string = "VABAJ"
|
||||
|
||||
/datum/design/item/intellicard
|
||||
name = "'intelliCore', AI preservation and transportation system"
|
||||
desc = "Allows for the construction of an intelliCore."
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
if(W.force)
|
||||
adjust_strength(-W.force / 20)
|
||||
user.do_attack_animation(src)
|
||||
user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
|
||||
user.setClickCooldown(user.get_attack_speed(W))
|
||||
..()
|
||||
|
||||
/obj/effect/energy_field/attack_hand(var/mob/living/user)
|
||||
|
||||
@@ -54,6 +54,9 @@
|
||||
visible_message("<span class='warning'>\The [src] breaks down!</span>")
|
||||
return break_to_parts() // if we break and form shards, return them to the caller to do !FUN! things with
|
||||
|
||||
/obj/structure/table/blob_act()
|
||||
take_damage(100)
|
||||
|
||||
/obj/structure/table/initialize()
|
||||
..()
|
||||
|
||||
|
||||
@@ -94,7 +94,7 @@
|
||||
if(health < maxhealth)
|
||||
if(open)
|
||||
health = min(maxhealth, health+10)
|
||||
user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
|
||||
user.setClickCooldown(user.get_attack_speed(W))
|
||||
playsound(src, T.usesound, 50, 1)
|
||||
user.visible_message("<font color='red'>[user] repairs [src]!</font>","<font color='blue'> You repair [src]!</font>")
|
||||
else
|
||||
@@ -104,7 +104,7 @@
|
||||
else
|
||||
user << "<span class='notice'>Unable to repair while [src] is off.</span>"
|
||||
else if(hasvar(W,"force") && hasvar(W,"damtype"))
|
||||
user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
|
||||
user.setClickCooldown(user.get_attack_speed(W))
|
||||
switch(W.damtype)
|
||||
if("fire")
|
||||
health -= W.force * fire_dam_coeff
|
||||
|
||||
@@ -899,6 +899,7 @@
|
||||
|
||||
evasion = 2
|
||||
slowdown = -1
|
||||
attack_speed_percent = 0.75
|
||||
|
||||
|
||||
// *********************
|
||||
|
||||
Reference in New Issue
Block a user