Merge remote-tracking branch 'remotes/upstream/master' into events

# Conflicts:
#	code/modules/events/immovable_rod.dm
This commit is contained in:
uraniummeltdown
2017-02-05 14:04:45 +04:00
337 changed files with 8959 additions and 2460 deletions
+2 -1
View File
@@ -807,7 +807,8 @@ var/global/nologevent = 0
var/turf/T = get_turf(usr.loc)
T.ChangeTurf(chosen)
else
new chosen(usr.loc)
var/atom/A = new chosen(usr.loc)
A.admin_spawned = TRUE
log_admin("[key_name(usr)] spawned [chosen] at ([usr.x],[usr.y],[usr.z])")
feedback_add_details("admin_verb","SA") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
+3 -1
View File
@@ -164,7 +164,9 @@ var/list/admin_verbs_debug = list(
/client/proc/map_template_upload,
/client/proc/view_runtimes,
/client/proc/admin_serialize,
/client/proc/admin_deserialize
/client/proc/admin_deserialize,
/client/proc/jump_to_ruin,
/client/proc/toggle_medal_disable
)
var/list/admin_verbs_possess = list(
/proc/possess,
+5 -2
View File
@@ -393,8 +393,11 @@
logout_status = " <i>(snpc)</i>"
else
logout_status = M.client ? "" : " <i>(logged out)</i>"
var/dname = M.real_name
if(!dname)
dname = M
return {"<tr><td><a href='?src=[UID()];adminplayeropts=\ref[M]'>[M.real_name]</a><b>[caption]</b>[logout_status][M.stat == 2 ? " <b><font color=red>(DEAD)</font></b>" : ""]</td>
return {"<tr><td><a href='?src=[UID()];adminplayeropts=\ref[M]'>[dname]</a><b>[caption]</b>[logout_status][M.stat == 2 ? " <b><font color=red>(DEAD)</font></b>" : ""]</td>
<td><A href='?src=[usr.UID()];priv_msg=\ref[M]'>PM</A></td>[close ? "</tr>" : ""]"}
/datum/admins/proc/check_antagonists()
@@ -424,7 +427,7 @@
else
dat += "<tr><td><i>Nuclear Operative not found!</i></td></tr>"
dat += "</table><br><table><tr><td><B>Nuclear Disk(s)</B></td></tr>"
for(var/obj/item/weapon/disk/nuclear/N in world)
for(var/obj/item/weapon/disk/nuclear/N in poi_list)
dat += "<tr><td>[N.name], "
var/atom/disk_loc = N.loc
while(!istype(disk_loc, /turf))
+1
View File
@@ -2173,6 +2173,7 @@
else
var/atom/O = new path(target)
if(O)
O.admin_spawned = TRUE
O.dir = obj_dir
if(obj_name)
O.name = obj_name
+1
View File
@@ -119,6 +119,7 @@ var/list/adminhelp_ignored_words = list("unknown","the","a","an","of","monkey","
for(var/client/X in modholders + adminholders)
if(X.prefs.sound & SOUND_ADMINHELP)
X << 'sound/effects/adminhelp.ogg'
window_flash(X)
to_chat(X, msg)
//show it to the person adminhelping too
+1
View File
@@ -133,6 +133,7 @@
if(holder && !C.holder)
recieve_message = "<span class='[recieve_span]' size='3'>-- Click the [recieve_pm_type]'s name to reply --</span>\n"
if(C.adminhelped)
window_flash(C)
to_chat(C, recieve_message)
C.adminhelped = 0
+54
View File
@@ -1474,3 +1474,57 @@ But you can call procs that are of type /mob/living/carbon/human/proc/ for that
return
error_cache.showTo(usr)
/client/proc/jump_to_ruin()
set category = "Debug"
set name = "Jump to Ruin"
set desc = "Displays a list of all placed ruins to teleport to."
if(!check_rights(R_DEBUG))
return
var/list/names = list()
for(var/i in ruin_landmarks)
var/obj/effect/landmark/ruin/ruin_landmark = i
var/datum/map_template/ruin/template = ruin_landmark.ruin_template
var/count = 1
var/name = template.name
var/original_name = name
while(name in names)
count++
name = "[original_name] ([count])"
names[name] = ruin_landmark
var/ruinname = input("Select ruin", "Jump to Ruin") as null|anything in names
var/obj/effect/landmark/ruin/landmark = names[ruinname]
if(istype(landmark))
var/datum/map_template/ruin/template = landmark.ruin_template
admin_forcemove(usr, get_turf(landmark))
to_chat(usr, "<span class='name'>[template.name]</span>")
to_chat(usr, "<span class='italics'>[template.description]</span>")
log_admin("[key_name(usr)] jumped to ruin [ruinname]")
if(!isobserver(usr))
message_admins("[key_name_admin(usr)] jumped to ruin [ruinname]", 1)
feedback_add_details("admin_verb","JT") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/client/proc/toggle_medal_disable()
set category = "Debug"
set name = "Toggle Medal Disable"
set desc = "Toggles the safety lock on trying to contact the medal hub."
if(!check_rights(R_DEBUG))
return
global.medals_enabled = !global.medals_enabled
message_admins("<span class='adminnotice'>[key_name_admin(src)] [global.medals_enabled ? "disabled" : "enabled"] the medal hub lockout.</span>")
feedback_add_details("admin_verb","TMH") // If...
log_admin("[key_name(src)] [global.medals_enabled ? "disabled" : "enabled"] the medal hub lockout.")
+6
View File
@@ -30,6 +30,12 @@ var/intercom_range_display_status = 0
src.pixel_x = -224
src.pixel_y = -224
/obj/effect/debugging/mapfix_marker
name = "map fix marker"
icon = 'icons/mob/screen_gen.dmi'
icon_state = "mapfixmarker"
desc = "I am a mappers mistake."
/obj/effect/debugging/marker
icon = 'icons/turf/areas.dmi'
icon_state = "yellow"
+6
View File
@@ -137,32 +137,38 @@
for(var/mob/M in mob_list)
if( istype(M , O.type) )
M.vars[variable] = O.vars[variable]
M.on_varedit(variable)
else if(istype(O, /obj))
for(var/obj/A in world)
if( istype(A , O.type) )
A.vars[variable] = O.vars[variable]
A.on_varedit(variable)
else if(istype(O, /turf))
for(var/turf/A in world)
if( istype(A , O.type) )
A.vars[variable] = O.vars[variable]
A.on_varedit(variable)
else
if(istype(O, /mob))
for(var/mob/M in mob_list)
if(M.type == O.type)
M.vars[variable] = O.vars[variable]
M.on_varedit(variable)
else if(istype(O, /obj))
for(var/obj/A in world)
if(A.type == O.type)
A.vars[variable] = O.vars[variable]
A.on_varedit(variable)
else if(istype(O, /turf))
for(var/turf/A in world)
if(A.type == O.type)
A.vars[variable] = O.vars[variable]
A.on_varedit(variable)
if("edit referenced object")
return .(O.vars[variable])
+2 -1
View File
@@ -131,7 +131,7 @@ var/list/forbidden_varedit_object_types = list(
L[var_value] = mod_list_add_ass() //haha
if("No")
L += var_value
/client/proc/mod_list(var/list/L)
if(!check_rights(R_VAREDIT)) return
@@ -440,6 +440,7 @@ var/list/forbidden_varedit_object_types = list(
if(var_as_text == null)
var_as_text = "[O.vars[variable]]"
O.on_varedit(variable)
log_to_dd("### VarEdit by [src]: [O.type] [variable]=[html_encode("[var_as_text]")]")
log_admin("[key_name(src)] modified [original_name]'s [variable] to [var_as_text]")
message_admins("[key_name_admin(src)] modified [original_name]'s [variable] to [var_as_text]", 1)
+36 -36
View File
@@ -26,6 +26,8 @@
var/corpseidicon = null //For setting it to be a gold, silver, centcomm etc ID
var/timeofdeath = null
var/coffin = 0
var/brute_damage = 0
var/oxy_damage = 0
/obj/effect/landmark/corpse/initialize()
if(istype(src,/obj/effect/landmark/corpse/clown))
@@ -37,34 +39,36 @@
var/mob/living/carbon/human/human/M = new /mob/living/carbon/human/human (src.loc)
M.real_name = src.name
M.death(1) //Kills the new mob
M.adjustOxyLoss(oxy_damage)
M.adjustBruteLoss(brute_damage)
M.timeofdeath = timeofdeath
if(src.mob_species)
M.set_species(src.mob_species)
if(src.corpseuniform)
M.equip_to_slot_or_del(new src.corpseuniform(M), slot_w_uniform)
if(src.corpsesuit)
M.equip_to_slot_or_del(new src.corpsesuit(M), slot_wear_suit)
if(src.corpseshoes)
M.equip_to_slot_or_del(new src.corpseshoes(M), slot_shoes)
if(src.corpsegloves)
M.equip_to_slot_or_del(new src.corpsegloves(M), slot_gloves)
if(src.corpseradio)
M.equip_to_slot_or_del(new src.corpseradio(M), slot_l_ear)
if(src.corpseglasses)
M.equip_to_slot_or_del(new src.corpseglasses(M), slot_glasses)
if(src.corpsemask)
M.equip_to_slot_or_del(new src.corpsemask(M), slot_wear_mask)
if(src.corpsehelmet)
M.equip_to_slot_or_del(new src.corpsehelmet(M), slot_head)
if(src.corpsebelt)
M.equip_to_slot_or_del(new src.corpsebelt(M), slot_belt)
if(src.corpsepocket1)
M.equip_to_slot_or_del(new src.corpsepocket1(M), slot_r_store)
if(src.corpsepocket2)
M.equip_to_slot_or_del(new src.corpsepocket2(M), slot_l_store)
if(src.corpseback)
M.equip_to_slot_or_del(new src.corpseback(M), slot_back)
if(src.corpseid == 1)
if(mob_species)
M.set_species(mob_species)
if(corpseuniform)
M.equip_to_slot_or_del(new corpseuniform(M), slot_w_uniform)
if(corpsesuit)
M.equip_to_slot_or_del(new corpsesuit(M), slot_wear_suit)
if(corpseshoes)
M.equip_to_slot_or_del(new corpseshoes(M), slot_shoes)
if(corpsegloves)
M.equip_to_slot_or_del(new corpsegloves(M), slot_gloves)
if(corpseradio)
M.equip_to_slot_or_del(new corpseradio(M), slot_l_ear)
if(corpseglasses)
M.equip_to_slot_or_del(new corpseglasses(M), slot_glasses)
if(corpsemask)
M.equip_to_slot_or_del(new corpsemask(M), slot_wear_mask)
if(corpsehelmet)
M.equip_to_slot_or_del(new corpsehelmet(M), slot_head)
if(corpsebelt)
M.equip_to_slot_or_del(new corpsebelt(M), slot_belt)
if(corpsepocket1)
M.equip_to_slot_or_del(new corpsepocket1(M), slot_r_store)
if(corpsepocket2)
M.equip_to_slot_or_del(new corpsepocket2(M), slot_l_store)
if(corpseback)
M.equip_to_slot_or_del(new corpseback(M), slot_back)
if(corpseid == 1)
var/obj/item/weapon/card/id/W = new(M)
W.name = "[M.real_name]'s ID Card"
var/datum/job/jobdatum
@@ -73,9 +77,9 @@
if(J.title == corpseidaccess)
jobdatum = J
break
if(src.corpseidicon)
if(corpseidicon)
W.icon_state = corpseidicon
if(src.corpseidaccess)
if(corpseidaccess)
if(jobdatum)
W.access = jobdatum.get_access()
else
@@ -84,18 +88,14 @@
W.assignment = corpseidjob
W.registered_name = M.real_name
M.equip_to_slot_or_del(W, slot_wear_id)
if(src.coffin == 1)
if(coffin == 1)
var/obj/structure/closet/coffin/sarcophagus/sarc = locate(/obj/structure/closet/coffin/sarcophagus) in loc
if(sarc) M.loc = sarc
qdel(src)
// I'll work on making a list of corpses people request for maps, or that I think will be commonly used. Syndicate operatives for example.
/obj/effect/landmark/corpse/damaged
brute_damage = 1000
/obj/effect/landmark/corpse/syndicatesoldier
name = "Syndicate Operative"
+10
View File
@@ -205,7 +205,17 @@ var/global/list/potentialRandomZlevels = generateMapList(filename = "config/away
template = safepick(possible_ruins)
if(!template)
return 0
var/turf/central_turf = get_turf(src)
for(var/i in template.get_affected_turfs(central_turf, 1))
var/turf/T = i
for(var/mob/living/simple_animal/monster in T)
qdel(monster)
for(var/obj/structure/flora/ash/plant in T)
qdel(plant)
template.load(get_turf(src),centered = 1)
template.loaded++
var/datum/map_template/ruin = template
if(istype(ruin))
new /obj/effect/landmark/ruin(central_turf, ruin)
qdel(src)
return 1
@@ -93,6 +93,7 @@ var/global/list/special_role_times = list( //minimum age (in days) for accounts
var/show_ghostitem_attack = TRUE
var/UI_style_color = "#ffffff"
var/UI_style_alpha = 255
var/windowflashing = TRUE
//character preferences
@@ -418,6 +419,7 @@ var/global/list/special_role_times = list( //minimum age (in days) for accounts
dat += "<h2>General Settings</h2>"
dat += "<b>Fancy NanoUI:</b> <a href='?_src_=prefs;preference=nanoui'>[(nanoui_fancy) ? "Yes" : "No"]</a><br>"
dat += "<b>Ghost-Item Attack Animation:</b> <a href='?_src_=prefs;preference=ghost_att_anim'>[(show_ghostitem_attack) ? "Yes" : "No"]</a><br>"
dat += "<b>Window Flashing:</b> <a href='?_src_=prefs;preference=winflash'>[(windowflashing) ? "Yes" : "No"]</a><br>"
dat += "<b>Custom UI settings:</b><br>"
dat += " - <b>UI Style:</b> <a href='?_src_=prefs;preference=ui'><b>[UI_style]</b></a><br>"
dat += " - <b>Color:</b> <a href='?_src_=prefs;preference=UIcolor'><b>[UI_style_color]</b></a> <table style='display:inline;' bgcolor='[UI_style_color]'<tr><td>__</td></tr></table><br>"
@@ -1935,6 +1937,9 @@ var/global/list/special_role_times = list( //minimum age (in days) for accounts
if("ghost_att_anim")
show_ghostitem_attack = !show_ghostitem_attack
if("winflash")
windowflashing = !windowflashing
if("UIcolor")
var/UI_style_color_new = input(user, "Choose your UI color, dark colors are not recommended!", UI_style_color) as color|null
if(!UI_style_color_new) return
@@ -14,7 +14,8 @@
nanoui_fancy,
show_ghostitem_attack,
lastchangelog,
exp
exp,
windowflashing
FROM [format_table_name("player")]
WHERE ckey='[C.ckey]'"}
)
@@ -42,6 +43,7 @@
show_ghostitem_attack = text2num(query.item[12])
lastchangelog = query.item[13]
exp = query.item[14]
windowflashing = text2num(query.item[15])
//Sanitize
ooccolor = sanitize_hexcolor(ooccolor, initial(ooccolor))
@@ -57,6 +59,7 @@
show_ghostitem_attack = sanitize_integer(show_ghostitem_attack, 0, 1, initial(show_ghostitem_attack))
lastchangelog = sanitize_text(lastchangelog, initial(lastchangelog))
exp = sanitize_text(exp, initial(exp))
windowflashing = sanitize_integer(windowflashing, 0, 1, initial(windowflashing))
return 1
/datum/preferences/proc/save_preferences(client/C)
+3 -2
View File
@@ -193,8 +193,9 @@ BLIND // can't see anything
"Drask" = 'icons/mob/species/drask/gloves.dmi'
)
/obj/item/clothing/gloves/proc/Touch()
return
// Called just before an attack_hand(), in mob/UnarmedAttack()
/obj/item/clothing/gloves/proc/Touch(atom/A, proximity)
return 0 // return 1 to cancel attack_hand()
/obj/item/clothing/gloves/attackby(obj/item/weapon/W, mob/user, params)
if(istype(W, /obj/item/weapon/wirecutters))
@@ -56,3 +56,74 @@
icon_state = "latex"
item_state = "lgloves"
flags = NODROP
/obj/item/clothing/gloves/color/yellow/stun
name = "stun gloves"
desc = "Horrendous and awful. It smells like cancer. The fact it has wires attached to it is incidental."
var/obj/item/weapon/stock_parts/cell/cell = null
var/stun_strength = 5
var/stun_cost = 3750
/obj/item/clothing/gloves/color/yellow/stun/New()
..()
update_icon()
/obj/item/clothing/gloves/color/yellow/stun/Destroy()
if(cell)
qdel(cell)
cell = null
return ..()
/obj/item/clothing/gloves/color/yellow/stun/Touch(atom/A, proximity)
if(!ishuman(loc))
return FALSE //Only works while worn
if(!iscarbon(A))
return FALSE
if(!proximity)
return FALSE
if(cell)
var/mob/living/carbon/human/H = loc
if(H.a_intent == I_HARM)
var/mob/living/carbon/C = A
if(cell.use(stun_cost))
var/datum/effect/system/spark_spread/s = new /datum/effect/system/spark_spread
s.set_up(5, 0, loc)
s.start()
playsound(loc, 'sound/weapons/Egloves.ogg', 50, 1, -1)
H.do_attack_animation(C)
visible_message("<span class='danger'>[C] has been touched with [src] by [H]!</span>")
C.Stun(stun_strength)
C.Weaken(stun_strength)
C.apply_effect(STUTTER, stun_strength)
else
to_chat(H, "<span class='notice'>Not enough charge!</span>")
return TRUE
return FALSE
/obj/item/clothing/gloves/color/yellow/stun/update_icon()
..()
overlays.Cut()
overlays += "gloves_wire"
if(cell)
overlays += "gloves_cell"
/obj/item/clothing/gloves/color/yellow/stun/attackby(obj/item/weapon/W, mob/living/user, params)
if(istype(W, /obj/item/weapon/stock_parts/cell))
if(!cell)
if(!user.drop_item())
to_chat(user, "<span class='warning'>[W] is stuck to you!</span>")
return
W.forceMove(src)
cell = W
to_chat(user, "<span class='notice'>You attach [W] to [src].</span>")
update_icon()
else
to_chat(user, "<span class='notice'>[src] already has a cell.</span>")
else if(iswirecutter(W))
if(cell)
to_chat(user, "<span class='notice'>You cut [cell] away from [src].</span>")
cell.forceMove(get_turf(loc))
cell = null
update_icon()
+1 -1
View File
@@ -340,7 +340,7 @@
icon_override = 'icons/goonstation/mob/clothing/mask.dmi'
lefthand_file = 'icons/goonstation/mob/inhands/clothing_lefthand.dmi'
righthand_file = 'icons/goonstation/mob/inhands/clothing_righthand.dmi'
flags = NODROP
flags = NODROP | AIRTIGHT | MASKCOVERSMOUTH
/obj/item/clothing/mask/cursedclown/equipped(mob/user, slot)
..()
+2 -2
View File
@@ -92,7 +92,7 @@ var/global/list/breach_burn_descriptors = list(
if(!breaches)
breaches = list()
if(damage > 25) return //We don't need to keep tracking it when it's at 250% pressure loss, really.
if(damage >= 25) return //We don't need to keep tracking it when it's at 250% pressure loss, really.
if(!loc) return
var/turf/T = get_turf(src)
@@ -125,7 +125,7 @@ var/global/list/breach_burn_descriptors = list(
var/datum/breach/B = new()
breaches += B
B.class = min(amount,5)
B.class = min(amount,(5 - max(damage - 20,0))) //We cap the check at 25, this line could overshoot without the calculation if it gets enough dammage in one shot.
B.damtype = damtype
B.update_descriptor()
@@ -119,7 +119,7 @@
gun.attack_self(holder.wearer)
return 1
gun.process_fire(target,holder.wearer)
gun.afterattack(target,holder.wearer)
return 1
/obj/item/rig_module/mounted/egun
@@ -0,0 +1,50 @@
/obj/item/rig_module/handheld
name = "mounted device"
desc = "Some kind of hardsuit extension."
usable = 0
selectable = 0
toggleable = 1
disruptive = 0
activate_string = "Deploy"
deactivate_string = "Retract"
var/device_type
var/obj/item/device
/obj/item/rig_module/handheld/activate()
if(!..())
return
if(!holder.wearer.put_in_hands(device))
to_chat(holder.wearer, "<span class='notice'>You need a free hand to hold \the [device].</span>")
active = 0
return
to_chat(holder.wearer, "<span class='notice'>You deploy \the [device].</span>")
/obj/item/rig_module/handheld/deactivate()
if(!..())
return
if(ismob(device.loc)) //Better check for the holder, instead of assuming the rigwearer has it.
var/mob/M = device.loc //Helps in case the code fails to keep the module in one place, this should still return it.
M.unEquip(device, 1)
device.loc = src
to_chat(holder.wearer, "<span class='notice'>You retract \the [device].</span>")
/obj/item/rig_module/handheld/New()
..()
if(device_type)
device = new device_type(src)
device.flags |= NODROP //We don't want to drop it while it's active/inhand.
activate_string += " [device]"
deactivate_string += " [device]"
/obj/item/rig_module/handheld/horn
name = "mounted bikehorn"
desc = "For tactical honking"
interface_name = "mounted bikehorn"
interface_desc = "Honks"
device_type = /obj/item/weapon/bikehorn
@@ -94,7 +94,9 @@
*/
/obj/item/rig_module/device/New()
..()
if(device_type) device = new device_type(src)
if(device_type)
device = new device_type(src)
device.flags |= ABSTRACT //Abstract in the sense that it's not an item that stands alone, but rather is just there to let the module act like it.
/obj/item/rig_module/device/engage(atom/target)
if(!..() || !device)
@@ -417,13 +419,15 @@
interface_desc = "Leave your mark."
engage_string = "Toggle stamp type"
usable = 1
var/iastamp
var/deniedstamp
var/obj/iastamp //Theese were just vars, but any device would need to be an object
var/obj/deniedstamp //Stops assigning non-objects to theese vars, which probably would break quite a bit.
/obj/item/rig_module/device/stamp/New()
..()
iastamp = new /obj/item/weapon/stamp/law(src)
deniedstamp = new /obj/item/weapon/stamp/denied(src)
iastamp.flags |= ABSTRACT
deniedstamp.flags |= ABSTRACT
device = iastamp
/obj/item/rig_module/device/stamp/engage(atom/target)
@@ -488,4 +492,4 @@
W.update_icon()
/obj/item/rig_module/welding_tank/proc/get_fuel()
return reagents.get_reagent_amount("fuel")
return reagents.get_reagent_amount("fuel")
+63 -13
View File
@@ -42,7 +42,7 @@
//Component/device holders.
var/obj/item/weapon/tank/air_supply // Air tank, if any.
var/obj/item/clothing/shoes/boots = null // Deployable boots, if any.
var/obj/item/clothing/shoes/magboots/boots = null // Deployable boots, if any.
var/obj/item/clothing/suit/space/new_rig/chest // Deployable chestpiece, if any.
var/obj/item/clothing/head/helmet/space/new_rig/helmet = null // Deployable helmet, if any.
var/obj/item/clothing/gloves/rig/gloves = null // Deployable gauntlets, if any.
@@ -76,6 +76,7 @@
var/airtight = 1 //If set, will adjust AIRTIGHT and STOPSPRESSUREDMAGE flags on components. Otherwise it should leave them untouched.
var/emp_protection = 0
var/has_emergency_release = 1 //Allows suit to be removed from outside.
// Wiring! How exciting.
var/datum/wires/rig/wires
@@ -126,14 +127,17 @@
if(helm_type)
helmet = new helm_type(src)
verbs |= /obj/item/weapon/rig/proc/toggle_helmet
helmet.item_color="[initial(icon_state)]_sealed" //For the lightswitching to know the correct string to manipulate
if(boot_type)
boots = new boot_type(src)
verbs |= /obj/item/weapon/rig/proc/toggle_boots
boots.magboot_state="[initial(icon_state)]_sealed" //For the magboot (de)activation to know the correct string to manipulate
if(chest_type)
chest = new chest_type(src)
if(allowed)
chest.allowed = allowed
chest.slowdown = offline_slowdown
chest.holder = src
verbs |= /obj/item/weapon/rig/proc/toggle_chest
for(var/obj/item/piece in list(gloves,helmet,boots,chest))
@@ -183,6 +187,10 @@
/obj/item/weapon/rig/proc/reset()
offline = 2
flags &= ~NODROP
if(helmet && helmet.on)
helmet.toggle_light(wearer)
if(boots && boots.magpulse)
boots.attack_self(wearer)
for(var/obj/item/piece in list(helmet,boots,gloves,chest))
if(!piece) continue
piece.icon_state = "[initial(icon_state)]"
@@ -254,6 +262,7 @@
switch(msg_type)
if("boots")
to_chat(wearer, "<font color='blue'>\The [correct_piece] seal around your feet.</font>")
correct_piece.icon_state = "[initial(icon_state)]_sealed0" //Solution to not need a sprite for off, on, and unused magboots.
if(user != wearer)
to_chat(user, "<span class='notice'>\The [correct_piece] has been sealed.</span>")
wearer.update_inv_shoes()
@@ -269,6 +278,7 @@
wearer.update_inv_wear_suit()
if("helmet")
to_chat(wearer, "<font color='blue'>\The [correct_piece] hisses closed.</font>")
correct_piece.icon_state = "[initial(icon_state)]_sealed0" //Solution to not need a sprite for off, on, and unused helmet light.
if(user != wearer)
to_chat(user, "<span class='notice'>\The [correct_piece] has been sealed.</span>")
wearer.update_inv_head()
@@ -383,10 +393,14 @@
sealing = FALSE
if(failed_to_seal)
for(var/obj/item/piece in list(helmet, boots, gloves, chest))
for(var/obj/item/piece in list(gloves, chest))
if(!piece)
continue
piece.icon_state = "[initial(icon_state)]_sealed"
if(helmet)
helmet.icon_state = "[initial(icon_state)]_sealed[helmet.on]"
if(boots)
boots.icon_state = "[initial(icon_state)]_sealed[boots.magpulse]"
if(airtight)
update_component_sealed()
update_icon(1)
@@ -406,6 +420,10 @@
update_icon(1)
/obj/item/weapon/rig/proc/update_component_sealed()
if(istype(boots) && !(flags & NODROP) && boots.magpulse) //If we have (active) boots and unsealed the suit, we deactivate the magboots.
boots.attack_self(wearer)
if(istype(helmet) && !(flags & NODROP) && helmet.on) //If we have an (active) headlamp and unsealed the suit, we deactivate the headlamp.
helmet.toggle_light(wearer)
for(var/obj/item/piece in list(helmet,boots,gloves,chest))
if(!(flags & NODROP))
piece.flags &= ~STOPSPRESSUREDMAGE
@@ -695,6 +713,8 @@
M.visible_message("<font color='blue'><b>[M] struggles into \the [src].</b></font>", "<font color='blue'><b>You struggle into \the [src].</b></font>")
wearer = M
wearer.wearing_rig = src
if(has_emergency_release)
M.verbs |= /obj/item/weapon/rig/proc/emergency_release
update_icon()
/obj/item/weapon/rig/proc/toggle_piece(var/piece, var/mob/living/user, var/deploy_mode, var/force)
@@ -705,15 +725,15 @@
if(isliving(uneq_piece.loc))
var/mob/living/L = uneq_piece.loc
L.unEquip(uneq_piece, 1)
uneq_piece.flags &= ~NODROP
uneq_piece.forceMove(src)
return 0
if(sealing || !cell || !cell.charge)
return 0
if(user == wearer && user.incapacitated()) // If the user isn't wearing the suit it's probably an AI.
return 0
if(!(deploy_mode == ONLY_RETRACT && force)) //This should be the case while stripping, stripping does trigger the if statement below.
if(user == wearer && user.incapacitated()) // If the user isn't wearing the suit it's probably an AI.
return 0
var/obj/item/check_slot
var/equip_to
@@ -752,7 +772,6 @@
if(to_strip)
to_strip.unEquip(use_obj, 1)
use_obj.flags &= ~NODROP
use_obj.forceMove(src)
if(wearer)
to_chat(wearer, "<span class='notice'>Your [use_obj] [use_obj.gender == PLURAL ? "retract" : "retracts"] swiftly.")
@@ -762,13 +781,11 @@
to_chat(wearer, "<span class='danger'>You are unable to deploy \the [piece] as \the [check_slot] [check_slot.gender == PLURAL ? "are" : "is"] in the way.</span>")
return
use_obj.forceMove(wearer)
use_obj.flags &= ~NODROP
if(!wearer.equip_to_slot_if_possible(use_obj, equip_to, 0, 1))
use_obj.forceMove(src)
else
if(wearer)
to_chat(wearer, "<span class='notice'>Your [use_obj.name] [use_obj.gender == PLURAL ? "deploy" : "deploys"] swiftly.</span>")
use_obj.flags |= NODROP
if(piece == "helmet" && helmet)
helmet.update_light(wearer)
@@ -777,17 +794,17 @@
if(!wearer || !user)
return 0
if(flags & NODROP)
if(wearer.head && wearer.head != helmet)
if(flags & NODROP) //We need to check if we have the part, the person is wearing something in the parts slot, and if yes, are they the same.
if(helmet && wearer.head && wearer.head != helmet)
to_chat(user, "<span class='danger'>\The [wearer.head] is blocking \the [src] from deploying!</span>")
return 0
if(wearer.gloves && wearer.gloves != gloves)
if(gloves && wearer.gloves && wearer.gloves != gloves)
to_chat(user, "<span class='danger'>\The [wearer.gloves] is preventing \the [src] from deploying!</span>")
return 0
if(wearer.shoes && wearer.shoes != boots)
if(boots && wearer.shoes && wearer.shoes != boots)
to_chat(user, "<span class='danger'>\The [wearer.shoes] is preventing \the [src] from deploying!</span>")
return 0
if(wearer.wear_suit && wearer.wear_suit != chest)
if(chest && wearer.wear_suit && wearer.wear_suit != chest)
to_chat(user, "<span class='danger'>\The [wearer.wear_suit] is preventing \the [src] from deploying!</span>")
return 0
@@ -797,6 +814,7 @@
/obj/item/weapon/rig/dropped(var/mob/user)
..()
user.verbs -= /obj/item/weapon/rig/proc/emergency_release
for(var/piece in list("helmet","gauntlets","chest","boots"))
toggle_piece(piece, user, ONLY_RETRACT, 1)
if(wearer)
@@ -996,6 +1014,38 @@
else
return null
/obj/item/weapon/rig/proc/emergency_release()
set name = "Suit Emergency Release"
set desc = "Activate the suits emergency release system."
set category = "Object"
set src in oview(1)
var/obj/item/weapon/rig/T = get_rig()
return T.do_emergency_release(usr)
/obj/item/weapon/rig/proc/do_emergency_release(var/mob/living/user)
if(!can_touch(user, wearer) || !has_emergency_release)
return can_touch(user,wearer)
usr.visible_message("<span class='warning'>[user] starts activating \the [src] emergency seals release!</span>")
if(!do_after(user,240, target = wearer))
to_chat(user, "<span class='notice'>You need to focus on activating the emergency release.</span>")
return 0
usr.visible_message("<span class='warning'>[user] activated \the [src] emergency seals release!</span>")
malfunctioning += 1
malfunction_delay = 30
unseal(user)
return 1
/obj/item/weapon/rig/proc/can_touch(var/mob/user, var/mob/wearer)
if(!user)
return 0
if(!wearer.Adjacent(user))
return 0
if(user.restrained())
to_chat(user, "<span class='notice'>You need your hands free for this.</span>")
return 0
if(user.stat || user.paralysis || user.sleeping || user.lying || user.weakened)
return 0
return 1
#undef ONLY_DEPLOY
#undef ONLY_RETRACT
#undef SEAL_DELAY
@@ -0,0 +1,21 @@
/obj/item/clothing/suit/space/new_rig/calc_breach_damage()
..()
holder.update_armor() //New dammage, new armormultiplikator.
return damage
/obj/item/weapon/rig/proc/update_armor()
var/multi = 1 //Multiplicative modification to the armor, maybe add an additive later on
if(chest)
multi *= (100 - chest.damage) / 100 //If we have some breaches, lower the armor value.
//TODO check for other armor mods, likely modules, which need to be coded.
for(var/obj/item/piece in list(gloves, helmet, boots, chest))
if(!istype(piece)) //Do we have the piece
continue
if(islist(armor)) //Did we even give them some armor, if this is the case, the list should be initialized from New()
var/list/L = armor
for(var/armortype in L)
piece.armor[armortype] = L[armortype]*multi
//Perfect place to also add something like shield modules, or any other hit_reaction modules check.
@@ -141,7 +141,7 @@
if(user.r_hand && user.l_hand)
cell.forceMove(get_turf(user))
else
cell.forceMove(user.put_in_hands(cell))
user.put_in_hands(cell)
cell = null
else
to_chat(user, "There is nothing loaded in that mount.")
@@ -4,7 +4,7 @@
/obj/item/clothing/head/helmet/space/new_rig
name = "helmet"
flags = HEADCOVERSEYES | BLOCKHAIR | HEADCOVERSMOUTH | THICKMATERIAL
flags = HEADCOVERSEYES | BLOCKHAIR | HEADCOVERSMOUTH | THICKMATERIAL | NODROP
flags_inv = HIDEEARS|HIDEEYES|HIDEFACE|HIDEMASK
body_parts_covered = HEAD
heat_protection = HEAD
@@ -12,11 +12,12 @@
var/brightness_on = 4
var/on = 0
sprite_sheets = list(
"Tajara" = 'icons/mob/species/tajaran/helmet.dmi',
"Tajaran" = 'icons/mob/species/tajaran/helmet.dmi',
"Skrell" = 'icons/mob/species/skrell/helmet.dmi',
"Unathi" = 'icons/mob/species/unathi/helmet.dmi'
)
species_restricted = null
actions_types = list(/datum/action/item_action/toggle_helmet_light)
flash_protect = 2
@@ -28,13 +29,17 @@
toggle_light(user)
/obj/item/clothing/head/helmet/space/new_rig/proc/toggle_light(mob/user)
on = !on
icon_state = "rig[on]-[item_color]"
if(flags & AIRTIGHT) //Could also check for STOPSPRESSUREDMAGE, but one is enough, both get toggled when the seal gets toggled.
if(on)
set_light(brightness_on)
on = !on
icon_state = "[item_color][on]"
if(on)
set_light(brightness_on)
else
set_light(0)
else
set_light(0)
to_chat(user, "<span class='warning'>You cannot turn the light on while the suit isn't sealed.</span>")
if(istype(user,/mob/living/carbon/human))
var/mob/living/carbon/human/H = user
@@ -42,7 +47,7 @@
/obj/item/clothing/gloves/rig
name = "gauntlets"
flags = THICKMATERIAL
flags = THICKMATERIAL | NODROP
body_parts_covered = HANDS
heat_protection = HANDS
cold_protection = HANDS
@@ -51,12 +56,19 @@
/obj/item/clothing/shoes/magboots/rig
name = "boots"
flags = NODROP
body_parts_covered = FEET
cold_protection = FEET
heat_protection = FEET
species_restricted = null
gender = PLURAL
/obj/item/clothing/shoes/magboots/rig/attack_self(mob/user)
if(flags & AIRTIGHT) //Could also check for STOPSPRESSUREDMAGE, but one is enough, both get toggled when the seal gets toggled.
..(user)
else
to_chat(user, "<span class='warning'>You cannot activate mag-pulse traction system while the suit is not sealed.</span>")
/obj/item/clothing/suit/space/new_rig
name = "chestpiece"
allowed = list(/obj/item/device/flashlight,/obj/item/weapon/tank)
@@ -64,14 +76,14 @@
heat_protection = UPPER_TORSO|LOWER_TORSO|LEGS|ARMS
cold_protection = UPPER_TORSO|LOWER_TORSO|LEGS|ARMS
flags_inv = HIDEJUMPSUIT|HIDETAIL
flags = STOPSPRESSUREDMAGE | THICKMATERIAL | AIRTIGHT
flags = STOPSPRESSUREDMAGE | THICKMATERIAL | AIRTIGHT | NODROP
slowdown = 0
//will reach 10 breach damage after 25 laser carbine blasts, 3 revolver hits, or ~1 PTR hit. Completely immune to smg or sts hits.
breach_threshold = 38
breach_threshold = 20
resilience = 0.2
can_breach = 1
var/obj/item/weapon/rig/holder
sprite_sheets = list(
"Tajara" = 'icons/mob/species/tajaran/suit.dmi',
"Tajaran" = 'icons/mob/species/tajaran/suit.dmi',
"Unathi" = 'icons/mob/species/unathi/suit.dmi'
)
@@ -112,7 +112,7 @@
name = "stealth suit control module"
suit_type = "stealth"
desc = "A highly advanced and expensive suit designed for covert operations."
icon_state = "stealth_rig"
icon_state = "ninja_rig" //supposed to be "stealth_rig", but as it currently only has a semi-copied ninja rig sprite, we can just use them directly.
req_access = list(access_syndicate)
+2
View File
@@ -29,6 +29,8 @@
respawnable_list -= C.client
var/mob/living/carbon/alien/larva/new_xeno = new(vent.loc)
new_xeno.key = C.key
if(ticker && ticker.mode)
ticker.mode.xenos += new_xeno.mind
spawncount--
successSpawn = 1
+14 -7
View File
@@ -11,7 +11,7 @@ In my current plan for it, 'solid' will be defined as anything with density == 1
announceWhen = 5
/datum/event/immovable_rod/announce()
event_announcement.Announce("Immovable object inbound. Brace for impact.", "Collision Alert")
event_announcement.Announce("Unidentified object inbound. Brace for impact.", "Collision Alert")
/datum/event/immovable_rod/start()
var/startside = pick(cardinal)
@@ -34,17 +34,24 @@ In my current plan for it, 'solid' will be defined as anything with density == 1
loc = start
z_original = z
destination = end
notify_ghosts("\A [src] is inbound!", source = src)
notify_ghosts("\A [src] is inbound!",
enter_link="<a href=?src=[UID()];orbit=1>(Click to follow)</a>",
source=src, action=NOTIFY_FOLLOW)
poi_list |= src
if(end && end.z==z_original)
walk_towards(src, destination, 1)
/obj/effect/immovablerod/Destroy()
poi_list.Remove(src)
return ..()
/obj/effect/immovablerod/Move()
if(z != z_original || loc == destination)
qdel(src)
return ..()
/obj/effect/immovablerod/ex_act(test)
return FALSE
return 0
/obj/effect/immovablerod/Bump(atom/clong)
if(prob(10))
@@ -55,15 +62,15 @@ In my current plan for it, 'solid' will be defined as anything with density == 1
x = clong.x
y = clong.y
if(isturf(clong) || isobj(clong))
if(istype(clong, /turf) || istype(clong, /obj))
if(clong.density)
clong.ex_act(2)
else if(ismob(clong))
if(ishuman(clong))
else if(istype(clong, /mob))
if(istype(clong, /mob/living/carbon/human))
var/mob/living/carbon/human/H = clong
H.visible_message("<span class='danger'>[H.name] is penetrated by an immovable rod!</span>" , "<span class='userdanger'>The rod penetrates you!</span>" , "<span class ='danger'>You hear a CLANG!</span>")
H.adjustBruteLoss(160)
if(clong.density || prob(10))
clong.ex_act(2)
return
return
@@ -331,4 +331,11 @@
name = "cup"
desc = "A cup with the british flag emblazoned on it."
icon_state = "britcup"
volume = 30
volume = 30
/obj/item/weapon/reagent_containers/food/drinks/mushroom_bowl
name = "mushroom bowl"
desc = "A bowl made out of mushrooms. Not food, though it might have contained some at some point."
icon = 'icons/obj/lavaland/ash_flora.dmi'
icon_state = "mushroom_bowl"
w_class = 2
@@ -8,7 +8,7 @@
use_power = 1
idle_power_usage = 5
active_power_usage = 100
flags = OPENCONTAINER | NOREACT
flags = OPENCONTAINER
var/operating = 0 // Is it on?
var/dirty = 0 // = {0..100} Does it need cleaning?
var/broken = 0 // ={0,1,2} How broken is it???
@@ -33,6 +33,7 @@
/obj/machinery/kitchen_machine/New()
create_reagents(100)
reagents.set_reacting(FALSE)
if(!available_recipes)
available_recipes = new
acceptable_items = new
@@ -10,7 +10,6 @@
use_power = 1
idle_power_usage = 5
active_power_usage = 100
flags = NOREACT
var/max_n_of_items = 1500
var/icon_on = "smartfridge"
var/icon_off = "smartfridge-off"
@@ -25,6 +24,8 @@
/obj/machinery/smartfridge/New()
..()
create_reagents()
reagents.set_reacting(FALSE)
component_parts = list()
var/obj/item/weapon/circuitboard/smartfridge/board = new(null)
board.set_type(type)
@@ -192,14 +193,15 @@
* Item Adding
********************/
/obj/machinery/smartfridge/attackby(obj/item/O, mob/user)
if(istype(O, /obj/item/weapon/screwdriver) && anchored)
playsound(loc, 'sound/items/Screwdriver.ogg', 50, 1)
panel_open = !panel_open
to_chat(user, "You [panel_open ? "open" : "close"] the maintenance panel.")
overlays.Cut()
if(panel_open)
overlays += image(icon, "[initial(icon_state)]-panel")
/obj/machinery/smartfridge/default_deconstruction_screwdriver(mob/user, obj/item/weapon/screwdriver/S)
. = ..(user, icon_state, icon_state, S)
overlays.Cut()
if(panel_open)
overlays += image(icon, "[initial(icon_state)]-panel")
/obj/machinery/smartfridge/attackby(obj/item/O, var/mob/user)
if(default_deconstruction_screwdriver(user, O))
return
if(exchange_parts(user, O))
@@ -305,7 +307,7 @@
to_chat(user, "<span class='notice'>Some items are refused.</span>")
nanomanager.update_uis(src)
/obj/machinery/smartfridge/secure/emag_act(user)
/obj/machinery/smartfridge/secure/emag_act(mob/user)
emagged = 1
locked = -1
to_chat(user, "You short out the product lock on [src].")
@@ -413,4 +415,4 @@
to_chat(usr, "<span class='warning'>Access denied.</span>")
nanomanager.update_uis(src)
return 0
return ..()
return ..()
+4 -7
View File
@@ -1,7 +1,7 @@
/*
===============================================================================
How Garbage Collection Works
How Garbage Collection Works
===============================================================================
In BYOND, there are exactly two ways anything gets deleted:
@@ -31,8 +31,8 @@ that can't be. There are two main procs involved in this process:
/proc/qdel(datumToDelete)
This is, effectively, a replacement for del that tells an object to prepare itself to be soft deleted by calling its
Destroy() proc. Depending on the qdel hint returned by Destroy(), qdel will queue the object in the garbage collector
(to be hard deleted if it isn't soft deleted), directly delete the object, pool the object, or ignore the object and
assume it will handle deleting itself. An object passed into qdel will have its gcDestroyed var set, so
(to be hard deleted if it isn't soft deleted), directly delete the object, or ignore the object and
assume it will handle deleting itself. An object passed into qdel will have its gcDestroyed var set, so
isnull(gcDestroyed) will be true if an object is not being destroyed, and false if it is (which means you should get
rid of the reference you have to it).
@@ -50,7 +50,7 @@ that can't be. There are two main procs involved in this process:
should use a Del proc for any necessary cleanup, as a Destroy proc on them will not automatically get called.
When called by qdel, Destroy is expected to return a qdel hint, which determines whether the object should be directly
deleted, queued for deletion, pooled, or ignored entirely; which of these are appropriate will vary, though objects
deleted, queued for deletion, or ignored entirely; which of these are appropriate will vary, though objects
should be pooled or queued whenever possible. The full list of qdel hints are in the code for the qdel proc.
As mentioned above, gcDestroyed can be used to tell whether an object is being destroyed. This is important, because if
@@ -62,7 +62,4 @@ reference immediately.
The inner workings of the GC itself and the stuff related to testing it probably don't need a detailed description - if
you intend to work with them, it would be best to read the code to understand what they do.
Pooling is related to GC, in that it's meant to reduce deletion overhead, but it does so by re-using objects instead of
deleting them at all. Explaining pooling is outside the scope of this file.
*/
@@ -149,8 +149,6 @@ var/global/datum/controller/process/garbage_collector/garbageCollector
del(D)
if(garbageCollector)
garbageCollector.dels_count++
if(QDEL_HINT_PUTINPOOL) //qdel will put this object in the pool.
PlaceInPool(D,0)
if(QDEL_HINT_FINDREFERENCE)//qdel will, if TESTING is enabled, display all references to this object, then queue the object for deletion.
#ifdef TESTING
D.find_references(remove_from_queue = FALSE)
@@ -11,6 +11,20 @@
return
else if(istype(O,/obj/item/weapon/crowbar))
return
else if(istype(O, /obj/item/weapon/shovel))
if(seed)
to_chat(user, "You dig up and dispose of \the [seed.display_name].")
seed = null
dead = 0
sampled = 0
age = 0
lastproduce = 0
yield_mod = 0
mutation_mod = 0
check_health()
else
to_chat(user, "You clear up [src]!")
qdel(src)
else
..()
@@ -3,7 +3,6 @@
mouse_opacity = 0
simulated = 0
anchored = 1
flags = NOREACT
icon = LIGHTING_ICON
layer = LIGHTING_LAYER
invisibility = INVISIBILITY_LIGHTING
+3 -3
View File
@@ -727,7 +727,7 @@
ranged = 1
sentience_type = SENTIENCE_MINEBOT
ranged_message = "shoots"
ranged_cooldown_cap = 3
ranged_cooldown_time = 30
projectiletype = /obj/item/projectile/kinetic
projectilesound = 'sound/weapons/Gunshot4.ogg'
speak_emote = list("states")
@@ -978,10 +978,10 @@
name = "minebot cooldown upgrade"
/obj/item/device/mine_bot_ugprade/cooldown/upgrade_bot(mob/living/simple_animal/hostile/mining_drone/M, mob/user)
if(M.ranged_cooldown_cap != initial(M.ranged_cooldown_cap))
if(M.ranged_cooldown_time != initial(M.ranged_cooldown_time))
to_chat(user, "[M] already has a decreased weapon cooldown!")
return
M.ranged_cooldown_cap = 1
M.ranged_cooldown_time = 10
to_chat(user, "You upgrade [M]'s ranged weaponry, reducing its cooldown.")
qdel(src)
+205
View File
@@ -0,0 +1,205 @@
/obj/structure/flora/ash
gender = PLURAL
icon = 'icons/obj/lavaland/ash_flora.dmi'
icon_state = "l_mushroom"
name = "large mushrooms"
desc = "A number of large mushrooms, covered in a faint layer of ash and what can only be spores."
var/harvested_name = "shortened mushrooms"
var/harvested_desc = "Some quickly regrowing mushrooms, formerly known to be quite large."
var/needs_sharp_harvest = TRUE
var/harvest = /obj/item/weapon/reagent_containers/food/snacks/ash_flora/shavings
var/harvest_amount_low = 1
var/harvest_amount_high = 3
var/harvest_time = 60
var/harvest_message_low = "You pick a mushroom, but fail to collect many shavings from its cap."
var/harvest_message_med = "You pick a mushroom, carefully collecting the shavings from its cap."
var/harvest_message_high = "You harvest and collect shavings from several mushroom caps."
var/harvested = FALSE
var/base_icon
var/regrowth_time_low = 4800
var/regrowth_time_high = 8400
/obj/structure/flora/ash/New()
..()
base_icon = "[icon_state][rand(1, 4)]"
icon_state = base_icon
if(prob(15))
harvest(null, TRUE)
/obj/structure/flora/ash/proc/harvest(user, no_drop)
if(harvested)
return 0
if(!no_drop)
var/rand_harvested = rand(harvest_amount_low, harvest_amount_high)
if(rand_harvested)
if(user)
var/msg = harvest_message_med
if(rand_harvested == harvest_amount_low)
msg = harvest_message_low
else if(rand_harvested == harvest_amount_high)
msg = harvest_message_high
to_chat(user, "<span class='notice'>[msg]</span>")
for(var/i in 1 to rand_harvested)
new harvest(get_turf(src))
icon_state = "[base_icon]p"
name = harvested_name
desc = harvested_desc
harvested = TRUE
addtimer(src, "regrow", rand(regrowth_time_low, regrowth_time_high))
return 1
/obj/structure/flora/ash/proc/regrow()
icon_state = base_icon
name = initial(name)
desc = initial(desc)
harvested = FALSE
/obj/structure/flora/ash/attackby(obj/item/weapon/W, mob/user, params)
if(!harvested && needs_sharp_harvest && W.sharp)
user.visible_message("<span class='notice'>[user] starts to harvest from [src] with [W].</span>","<span class='notice'>You begin to harvest from [src] with [W].</span>")
if(do_after(user, harvest_time, target = src))
harvest(user)
else
return ..()
/obj/structure/flora/ash/attack_hand(mob/user)
if(!harvested && !needs_sharp_harvest)
user.visible_message("<span class='notice'>[user] starts to harvest from [src].</span>","<span class='notice'>You begin to harvest from [src].</span>")
if(do_after(user, harvest_time, target = src))
harvest(user)
else
..()
/obj/structure/flora/ash/tall_shroom //exists only so that the spawning check doesn't allow these spawning near other things
regrowth_time_low = 4200
/obj/structure/flora/ash/leaf_shroom
icon_state = "s_mushroom"
name = "leafy mushrooms"
desc = "A number of mushrooms, each of which surrounds a greenish sporangium with a number of leaf-like structures."
harvested_name = "leafless mushrooms"
harvested_desc = "A bunch of formerly-leafed mushrooms, with their sporangiums exposed. Scandalous?"
harvest = /obj/item/weapon/reagent_containers/food/snacks/ash_flora/mushroom_leaf
needs_sharp_harvest = FALSE
harvest_amount_high = 4
harvest_time = 20
harvest_message_low = "You pluck a single, suitable leaf."
harvest_message_med = "You pluck a number of leaves, leaving a few unsuitable ones."
harvest_message_high = "You pluck quite a lot of suitable leaves."
regrowth_time_low = 2400
regrowth_time_high = 6000
/obj/structure/flora/ash/cap_shroom
icon_state = "r_mushroom"
name = "tall mushrooms"
desc = "Several mushrooms, the larger of which have a ring of conks at the midpoint of their stems."
harvested_name = "small mushrooms"
harvested_desc = "Several small mushrooms near the stumps of what likely were larger mushrooms."
harvest = /obj/item/weapon/reagent_containers/food/snacks/ash_flora/mushroom_cap
harvest_amount_high = 4
harvest_time = 50
harvest_message_low = "You slice the cap off of a mushroom."
harvest_message_med = "You slice off a few conks from the larger mushrooms."
harvest_message_high = "You slice off a number of caps and conks from these mushrooms."
regrowth_time_low = 3000
regrowth_time_high = 5400
/obj/structure/flora/ash/stem_shroom
icon_state = "t_mushroom"
name = "numerous mushrooms"
desc = "A large number of mushrooms, some of which have long, fleshy stems. They're radiating light!"
luminosity = 1
harvested_name = "tiny mushrooms"
harvested_desc = "A few tiny mushrooms around larger stumps. You can already see them growing back."
harvest = /obj/item/weapon/reagent_containers/food/snacks/ash_flora/mushroom_stem
harvest_amount_high = 4
harvest_time = 40
harvest_message_low = "You pick and slice the cap off of a mushroom, leaving the stem."
harvest_message_med = "You pick and decapitate several mushrooms for their stems."
harvest_message_high = "You acquire a number of stems from these mushrooms."
regrowth_time_low = 3000
regrowth_time_high = 6000
/obj/structure/flora/ash/cacti
icon_state = "cactus"
name = "fruiting cacti"
desc = "Several prickly cacti, brimming with ripe fruit and covered in a thin layer of ash."
harvested_name = "cacti"
harvested_desc = "A bunch of prickly cacti. You can see fruits slowly growing beneath the covering of ash."
harvest = /obj/item/weapon/reagent_containers/food/snacks/ash_flora/cactus_fruit
needs_sharp_harvest = FALSE
harvest_amount_high = 2
harvest_time = 10
harvest_message_low = "You pick a cactus fruit."
harvest_message_med = "You pick several cactus fruit." //shouldn't show up, because you can't get more than two
harvest_message_high = "You pick a pair of cactus fruit."
regrowth_time_low = 4800
regrowth_time_high = 7200
/obj/structure/flora/ash/cacti/Crossed(mob/AM)
if(ishuman(AM) && has_gravity(loc) && prob(70))
var/mob/living/carbon/human/H = AM
if(!H.shoes && !H.lying) //ouch, my feet.
var/picked_def_zone = pick("l_leg", "r_leg")
var/obj/item/organ/external/affected = H.get_organ(picked_def_zone)
if(!istype(affected))
return
H.apply_damage(rand(3, 6), BRUTE, picked_def_zone)
H.Weaken(2)
H.visible_message("<span class='danger'>[H] steps on a cactus!</span>", \
"<span class='userdanger'>You step on a cactus!</span>")
/obj/item/weapon/reagent_containers/food/snacks/ash_flora
name = "mushroom shavings"
desc = "Some shavings from a tall mushroom. With enough, might serve as a bowl."
icon = 'icons/obj/lavaland/ash_flora.dmi'
icon_state = "mushroom_shavings"
list_reagents = list("sugar" = 3, "ethanol" = 2, "stabilizing_agent" = 3, "minttoxin" = 2)
w_class = 1
/obj/item/weapon/reagent_containers/food/snacks/ash_flora/New()
..()
pixel_x = rand(-4, 4)
pixel_y = rand(-4, 4)
/obj/item/weapon/reagent_containers/food/snacks/ash_flora/shavings //for actual crafting
/obj/item/weapon/reagent_containers/food/snacks/ash_flora/mushroom_leaf
name = "mushroom leaf"
desc = "A leaf, from a mushroom."
list_reagents = list("nutriment" = 3, "vitfro" = 2, "nicotine" = 2)
icon_state = "mushroom_leaf"
/obj/item/weapon/reagent_containers/food/snacks/ash_flora/mushroom_cap
name = "mushroom cap"
desc = "The cap of a large mushroom."
list_reagents = list("lsd" = 2, "entpoly" = 4, "psilocybin" = 2)
icon_state = "mushroom_cap"
/obj/item/weapon/reagent_containers/food/snacks/ash_flora/mushroom_stem
name = "mushroom stem"
desc = "A long mushroom stem. It's slightly glowing."
list_reagents = list("tinlux" = 2, "vitamin" = 1, "space_drugs" = 1)
icon_state = "mushroom_stem"
luminosity = 1
/obj/item/weapon/reagent_containers/food/snacks/ash_flora/cactus_fruit
name = "cactus fruit"
list_reagents = list("vitamin" = 2, "nutriment" = 2, "vitfro" = 4)
desc = "A cactus fruit covered in a thick, reddish skin. And some ash."
icon_state = "cactus_fruit"
/obj/item/mushroom_bowl
name = "mushroom bowl"
desc = "A bowl made out of mushrooms. Not food, though it might have contained some at some point."
icon = 'icons/obj/lavaland/ash_flora.dmi'
icon_state = "mushroom_bowl"
w_class = 2
//what you can craft with these things
/datum/crafting_recipe/mushroom_bowl
name = "Mushroom Bowl"
result = /obj/item/weapon/reagent_containers/food/drinks/mushroom_bowl
reqs = list(/obj/item/weapon/reagent_containers/food/snacks/ash_flora/shavings = 5)
time = 30
category = CAT_PRIMAL
@@ -0,0 +1,493 @@
//Black Box
/obj/machinery/smartfridge/black_box
name = "black box"
desc = "A completely indestructible chunk of crystal, rumoured to predate the start of this universe. It looks like you could store things inside it."
icon = 'icons/obj/lavaland/artefacts.dmi'
icon_state = "blackbox"
icon_on = "blackbox"
icon_off = "blackbox"
luminosity = 8
max_n_of_items = INFINITY
unacidable = 1
pixel_y = -4
use_power = 0
var/memory_saved = FALSE
var/list/stored_items = list()
var/static/list/blacklist = typecacheof(list(/obj/item/weapon/spellbook))
/obj/machinery/smartfridge/black_box/update_icon()
return
/obj/machinery/smartfridge/black_box/accept_check(obj/item/O)
if(!istype(O))
return FALSE
if(is_type_in_typecache(O, blacklist))
return FALSE
return TRUE
/obj/machinery/smartfridge/black_box/New()
var/static/obj/machinery/smartfridge/black_box/current
if(current && current != src)
qdel(src, force=TRUE)
return
current = src
ReadMemory()
. = ..()
/obj/machinery/smartfridge/black_box/process()
..()
if(!memory_saved && ticker.current_state == GAME_STATE_FINISHED)
WriteMemory()
/obj/machinery/smartfridge/black_box/proc/WriteMemory()
var/savefile/S = new /savefile("data/npc_saves/Blackbox.sav")
stored_items = list()
for(var/obj/O in (contents-component_parts))
stored_items += O.type
S["stored_items"] << stored_items
memory_saved = TRUE
/obj/machinery/smartfridge/black_box/proc/ReadMemory()
var/savefile/S = new /savefile("data/npc_saves/Blackbox.sav")
S["stored_items"] >> stored_items
if(isnull(stored_items))
stored_items = list()
for(var/item in stored_items)
create_item(item)
//in it's own proc to avoid issues with items that nolonger exist in the code base.
//try catch doesn't always prevent byond runtimes from halting a proc,
/obj/machinery/smartfridge/black_box/proc/create_item(item_type)
new item_type(src)
/obj/machinery/smartfridge/black_box/Destroy(force = FALSE)
if(force)
for(var/thing in src)
qdel(thing)
return ..()
else
return QDEL_HINT_LETMELIVE
//No taking it apart
/obj/machinery/smartfridge/black_box/default_deconstruction_screwdriver()
return
/obj/machinery/smartfridge/black_box/exchange_parts()
return
/obj/machinery/smartfridge/black_box/default_unfasten_wrench()
return
/obj/machinery/smartfridge/black_box/default_deconstruction_crowbar()
return
///Anomolous Crystal///
/obj/machinery/anomalous_crystal
name = "anomalous crystal"
desc = "A strange chunk of crystal, being in the presence of it fills you with equal parts excitement and dread."
icon = 'icons/obj/lavaland/artefacts.dmi'
icon_state = "anomaly_crystal"
luminosity = 8
use_power = 0
density = 1
unacidable = 1
var/activation_method = "touch"
var/activation_damage_type = null
var/last_use_timer = 0
var/cooldown_add = 30
var/list/affected_targets = list()
var/activation_sound = 'sound/effects/break_stone.ogg'
/obj/machinery/anomalous_crystal/New()
activation_method = pick("touch","laser","bullet","energy","bomb","mob_bump","weapon","speech") // "heat" removed due to lack of is_hot()
..()
/obj/machinery/anomalous_crystal/hear_talk(mob/speaker, message)
..()
if(isliving(speaker) && message)
ActivationReaction(speaker, "speech")
/obj/machinery/anomalous_crystal/attack_hand(mob/user)
..()
ActivationReaction(user,"touch")
/obj/machinery/anomalous_crystal/attackby(obj/item/I, mob/user, params)
ActivationReaction(user,"weapon")
..()
/obj/machinery/anomalous_crystal/bullet_act(obj/item/projectile/P, def_zone)
..()
if(istype(P, /obj/item/projectile/magic))
ActivationReaction(P.firer, "magic", P.damage_type)
return
ActivationReaction(P.firer, P.flag, P.damage_type)
/obj/machinery/anomalous_crystal/proc/ActivationReaction(mob/user, method, damtype)
if(world.time < last_use_timer)
return 0
if(activation_damage_type && activation_damage_type != damtype)
return 0
if(method != activation_method)
return 0
last_use_timer = (world.time + cooldown_add)
playsound(user, activation_sound, 100, 1)
return 1
/obj/machinery/anomalous_crystal/Bumped(atom/AM as mob|obj)
..()
if(ismob(AM))
ActivationReaction(AM,"mob_bump")
/obj/machinery/anomalous_crystal/ex_act()
ActivationReaction(null,"bomb")
/obj/machinery/anomalous_crystal/random/New()//Just a random crysal spawner for loot
var/random_crystal = pick(typesof(/obj/machinery/anomalous_crystal) - /obj/machinery/anomalous_crystal/random - /obj/machinery/anomalous_crystal)
new random_crystal(loc)
qdel(src)
/obj/machinery/anomalous_crystal/honk //Strips and equips you as a clown. I apologize for nothing
activation_method = "mob_bump"
activation_sound = 'sound/items/bikehorn.ogg'
/obj/machinery/anomalous_crystal/honk/ActivationReaction(mob/user)
if(..() && ishuman(user) && !(user in affected_targets))
var/mob/living/carbon/human/H = user
for(var/obj/item/W in H)
H.unEquip(W)
var/datum/job/clown/C = job_master.GetJob("Clown")
C.equip(H)
affected_targets.Add(H)
/obj/machinery/anomalous_crystal/honk/New()
..()
activation_method = pick("mob_bump","speech")
/obj/machinery/anomalous_crystal/theme_warp //Warps the area you're in to look like a new one
activation_method = "touch"
cooldown_add = 200
var/terrain_theme = "winter"
var/NewTerrainFloors
var/NewTerrainWalls
var/NewTerrainChairs
var/NewTerrainTables
var/list/NewFlora = list()
var/florachance = 8
/obj/machinery/anomalous_crystal/theme_warp/New()
..()
terrain_theme = pick("lavaland","winter","jungle","alien")
switch(terrain_theme)
if("lavaland")//Depressurizes the place... and free cult metal, I guess.
NewTerrainFloors = /turf/simulated/floor/basalt // Needs to be updated after turf update
NewTerrainWalls = /turf/simulated/wall/cult
NewFlora = list(/mob/living/simple_animal/hostile/asteroid/goldgrub)
florachance = 1
if("winter") //Snow terrain is slow to move in and cold! Get the assistants to shovel your driveway.
NewTerrainFloors = /turf/simulated/floor/snow // Needs to be updated after turf update
NewTerrainWalls = /turf/simulated/wall/mineral/wood
NewTerrainChairs = /obj/structure/stool/bed/chair/wood/normal
NewTerrainTables = /obj/structure/table/glass
NewFlora = list(/obj/structure/flora/grass/green, /obj/structure/flora/grass/brown, /obj/structure/flora/grass/both)
if("jungle") //Beneficial due to actually having breathable air. Plus, monkeys and bows and arrows.
NewTerrainFloors = /turf/simulated/floor/grass
NewTerrainWalls = /turf/simulated/wall/mineral/sandstone
NewTerrainChairs = /obj/structure/stool/bed/chair/wood/normal
NewTerrainTables = /obj/structure/table/woodentable
NewFlora = list(/obj/structure/flora/ausbushes/sparsegrass, /obj/structure/flora/ausbushes/fernybush, /obj/structure/flora/ausbushes/leafybush,
/obj/structure/flora/ausbushes/grassybush, /obj/structure/flora/ausbushes/sunnybush, /obj/structure/flora/tree/palm, /mob/living/carbon/human/monkey,
/obj/item/weapon/gun/projectile/bow, /obj/item/weapon/storage/backpack/quiver/full)
florachance = 20
if("alien") //Beneficial, turns stuff into alien alloy which is useful to cargo and research. Also repairs atmos.
NewTerrainFloors = /turf/simulated/floor/mineral/abductor
NewTerrainWalls = /turf/simulated/wall/mineral/abductor
NewTerrainChairs = /obj/structure/stool/bed/abductor //ayys apparently don't have chairs. An entire species of people who only recline.
NewTerrainTables = /obj/structure/table/abductor
/obj/machinery/anomalous_crystal/theme_warp/ActivationReaction(mob/user, method)
if(..())
var/area/A = get_area(src)
if(!A.outdoors && !(A in affected_targets))
for(var/atom/Stuff in A)
if(isturf(Stuff))
var/turf/T = Stuff
if((isspaceturf(T) || isfloorturf(T)) && NewTerrainFloors)
var/turf/simulated/O = T.ChangeTurf(NewTerrainFloors)
if(O.air)
var/datum/gas_mixture/G = O.air
G.copy_from(O.air)
if(prob(florachance) && NewFlora.len && !is_blocked_turf(O))
var/atom/Picked = pick(NewFlora)
new Picked(O)
continue
if(iswallturf(T) && NewTerrainWalls)
T.ChangeTurf(NewTerrainWalls)
continue
if(istype(Stuff, /obj/structure/stool/bed/chair) && NewTerrainChairs)
var/obj/structure/stool/bed/chair/Original = Stuff
var/obj/structure/stool/bed/chair/C = new NewTerrainChairs(Original.loc)
C.dir = Original.dir
qdel(Stuff)
continue
if(istype(Stuff, /obj/structure/table) && NewTerrainTables)
var/obj/structure/table/Original = Stuff
var/obj/structure/table/T = new NewTerrainTables(Original.loc)
T.dir = Original.dir
qdel(Stuff)
continue
affected_targets += A
/obj/machinery/anomalous_crystal/emitter //Generates a projectile when interacted with
activation_method = "touch"
cooldown_add = 50
var/generated_projectile = /obj/item/projectile/beam/emitter
/obj/machinery/anomalous_crystal/emitter/New()
..()
generated_projectile = pick(/obj/item/projectile/magic/fireball/infernal,/obj/item/projectile/magic/spellblade,
/obj/item/projectile/bullet/meteorshot, /obj/item/projectile/beam/xray, /obj/item/projectile/colossus)
/obj/machinery/anomalous_crystal/emitter/ActivationReaction(mob/user, method)
if(..())
var/obj/item/projectile/P = new generated_projectile(get_turf(src))
P.dir = dir
switch(dir)
if(NORTH)
P.yo = 20
P.xo = 0
if(EAST)
P.yo = 0
P.xo = 20
if(WEST)
P.yo = 0
P.xo = -20
else
P.yo = -20
P.xo = 0
P.fire()
/obj/machinery/anomalous_crystal/dark_reprise //Revives anyone nearby, but turns them into shadowpeople and renders them uncloneable, so the crystal is your only hope of getting up again if you go down.
activation_method = "touch"
activation_sound = 'sound/hallucinations/growl1.ogg'
/obj/machinery/anomalous_crystal/dark_reprise/ActivationReaction(mob/user, method)
if(..())
for(var/i in range(1, src))
if(isturf(i))
new /obj/effect/overlay/temp/cult/sparks(i)
continue
if(ishuman(i))
var/mob/living/carbon/human/H = i
if(H.stat == DEAD)
H.set_species("Shadow")
H.revive()
H.disabilities |= NOCLONE //Free revives, but significantly limits your options for reviving except via the crystal
H.grab_ghost(force = TRUE)
/obj/machinery/anomalous_crystal/helpers //Lets ghost spawn as helpful creatures that can only heal people slightly. Incredibly fragile and they can't converse with humans
activation_method = "touch"
var/ready_to_deploy = 0
/obj/machinery/anomalous_crystal/helpers/ActivationReaction(mob/user, method)
if(..() && !ready_to_deploy)
ready_to_deploy = 1
notify_ghosts("An anomalous crystal has been activated in [get_area(src)]! This crystal can always be used by ghosts hereafter.", enter_link = "<a href=?src=\ref[src];ghostjoin=1>(Click to enter)</a>", source = src, action = NOTIFY_ATTACK)
/obj/machinery/anomalous_crystal/helpers/attack_ghost(mob/dead/observer/user)
..()
if(ready_to_deploy)
var/be_helper = alert("Become a Lightgeist? (Warning, You can no longer be cloned!)",,"Yes","No")
if(be_helper == "No")
return
var/mob/living/simple_animal/hostile/lightgeist/W = new /mob/living/simple_animal/hostile/lightgeist(get_turf(loc))
W.key = user.key
/obj/machinery/anomalous_crystal/helpers/Topic(href, href_list)
if(href_list["ghostjoin"])
var/mob/dead/observer/ghost = usr
if(istype(ghost))
attack_ghost(ghost)
/mob/living/simple_animal/hostile/lightgeist
name = "lightgeist"
desc = "This small floating creature is a completely unknown form of life... being near it fills you with a sense of tranquility."
icon_state = "lightgeist"
icon_living = "lightgeist"
icon_dead = "butterfly_dead"
turns_per_move = 1
response_help = "waves away"
response_disarm = "brushes aside"
response_harm = "disrupts"
speak_emote = list("oscillates")
maxHealth = 2
health = 2
harm_intent_damage = 1
friendly = "mends"
density = 0
flying = 1
pass_flags = PASSTABLE | PASSGRILLE | PASSMOB
ventcrawler = 2
mob_size = MOB_SIZE_TINY
gold_core_spawnable = 0
speak_emote = list("warps")
damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 0, CLONE = 0, STAMINA = 0, OXY = 0)
luminosity = 4
faction = list("neutral")
universal_understand = 1
del_on_death = 1
unsuitable_atmos_damage = 0
flying = 1
minbodytemp = 0
maxbodytemp = 1500
environment_smash = 0
AIStatus = AI_OFF
stop_automated_movement = 1
var/heal_power = 5
/mob/living/simple_animal/hostile/lightgeist/New()
..()
verbs -= /mob/living/verb/pulled
verbs -= /mob/verb/me_verb
var/datum/atom_hud/medsensor = huds[DATA_HUD_MEDICAL_ADVANCED]
medsensor.add_hud_to(src)
/mob/living/simple_animal/hostile/lightgeist/AttackingTarget()
..()
if(isliving(target) && target != src)
var/mob/living/L = target
if(L.stat < DEAD)
L.heal_overall_damage(heal_power, heal_power)
new /obj/effect/overlay/temp/heal(get_turf(target), "#80F5FF")
/mob/living/simple_animal/hostile/lightgeist/ghostize()
if(..())
death()
/obj/machinery/anomalous_crystal/refresher //Deletes and recreates a copy of the item, "refreshing" it.
activation_method = "touch"
cooldown_add = 50
activation_sound = 'sound/magic/TIMEPARADOX2.ogg'
var/list/banned_items_typecache = list(/obj/item/weapon/storage, /obj/item/weapon/implant, /obj/item/weapon/implanter, /obj/item/weapon/disk/nuclear, /obj/item/projectile, /obj/item/weapon/spellbook)
/obj/machinery/anomalous_crystal/refresher/New()
..()
banned_items_typecache = typecacheof(banned_items_typecache)
/obj/machinery/anomalous_crystal/refresher/ActivationReaction(mob/user, method)
if(..())
var/list/L = list()
var/turf/T = get_step(src, dir)
new /obj/effect/overlay/temp/emp/pulse(T)
for(var/i in T)
if(istype(i, /obj/item) && !is_type_in_typecache(i, banned_items_typecache))
var/obj/item/W = i
if(!W.admin_spawned)
L += W
if(L.len)
var/obj/item/CHOSEN = pick(L)
new CHOSEN.type(T)
qdel(CHOSEN)
/obj/machinery/anomalous_crystal/possessor //Allows you to bodyjack small animals, then exit them at your leisure, but you can only do this once per activation. Because they blow up. Also, if the bodyjacked animal dies, SO DO YOU.
activation_method = "touch"
/obj/machinery/anomalous_crystal/possessor/ActivationReaction(mob/user, method)
if(..())
if(ishuman(user))
var/mobcheck = 0
for(var/mob/living/simple_animal/A in range(1, src))
if(A.melee_damage_upper > 5 || A.mob_size >= MOB_SIZE_LARGE || A.ckey || A.stat)
break
var/obj/structure/closet/stasis/S = new /obj/structure/closet/stasis(A)
user.forceMove(S)
mobcheck = 1
break
if(!mobcheck)
new /mob/living/simple_animal/cockroach(get_step(src,dir)) //Just in case there aren't any animals on the station, this will leave you with a terrible option to possess if you feel like it
/obj/structure/closet/stasis
name = "quantum entanglement stasis warp field"
desc = "You can hardly comprehend this thing... which is why you can't see it."
icon_state = null //This shouldn't even be visible, so if it DOES show up, at least nobody will notice
density = 1
anchored = 1
var/mob/living/simple_animal/holder_animal
/obj/structure/closet/stasis/process()
if(holder_animal)
if(holder_animal.stat == DEAD && !qdeleted(holder_animal))
dump_contents()
holder_animal.gib()
return
/obj/structure/closet/stasis/New()
..()
if(isanimal(loc))
holder_animal = loc
processing_objects.Add(src)
/obj/structure/closet/stasis/Entered(atom/A)
if(isliving(A) && holder_animal)
var/mob/living/L = A
L.notransform = 1
L.disabilities |= MUTE
L.status_flags |= GODMODE
L.mind.transfer_to(holder_animal)
var/obj/effect/proc_holder/spell/targeted/exit_possession/P = new /obj/effect/proc_holder/spell/targeted/exit_possession
holder_animal.mind.AddSpell(P)
holder_animal.verbs -= /mob/living/verb/pulled
/obj/structure/closet/stasis/dump_contents(var/kill = 1)
processing_objects.Remove(src)
for(var/mob/living/L in src)
L.disabilities &= ~MUTE
L.status_flags &= ~GODMODE
L.notransform = 0
if(holder_animal && !qdeleted(holder_animal))
holder_animal.mind.transfer_to(L)
L.mind.RemoveSpell(/obj/effect/proc_holder/spell/targeted/exit_possession)
if(kill || !isanimal(loc))
L.death(0)
..()
/obj/structure/closet/stasis/emp_act()
return
/obj/structure/closet/stasis/ex_act()
return
/obj/effect/proc_holder/spell/targeted/exit_possession
name = "Exit Possession"
desc = "Exits the body you are possessing"
charge_max = 60
clothes_req = 0
invocation_type = "none"
max_targets = 1
range = -1
include_user = 1
selection_type = "view"
action_icon_state = "exit_possession"
sound = null
/obj/effect/proc_holder/spell/targeted/exit_possession/cast(list/targets, mob/user = usr)
if(!isfloorturf(user.loc))
return
var/datum/mind/target_mind = user.mind
var/mob/living/current = user // Saving the current mob here to gib as usr seems to get confused after the mind's been transferred, due to delay in transfer_to
for(var/i in user)
if(istype(i, /obj/structure/closet/stasis))
var/obj/structure/closet/stasis/S = i
S.dump_contents(0)
qdel(S)
break
current.gib()
target_mind.RemoveSpell(/obj/effect/proc_holder/spell/targeted/exit_possession)
@@ -0,0 +1,618 @@
//The chests dropped by mob spawner tendrils. Also contains associated loot.
/obj/structure/closet/crate/necropolis
name = "necropolis chest"
desc = "It's watching you closely."
icon_state = "necrocrate"
icon_opened = "necrocrateopen"
icon_closed = "necrocrate"
/obj/structure/closet/crate/necropolis/tendril
desc = "It's watching you suspiciously."
/obj/structure/closet/crate/necropolis/tendril/New()
..()
// uncomment me once these items are being implemented
/*var/loot = rand(1,25)
switch(loot)
if(1)
new /obj/item/device/shared_storage/red(src)
if(2)
new /obj/item/clothing/suit/space/hardsuit/cult(src)
if(3)
new /obj/item/device/soulstone/anybody(src)
if(4)
new /obj/item/weapon/katana/cursed(src)
if(5)
new /obj/item/clothing/glasses/godeye(src)
if(6)
new /obj/item/weapon/reagent_containers/glass/bottle/potion/flight(src)
if(7)
new /obj/item/weapon/pickaxe/diamond(src)
if(8)
new /obj/item/clothing/head/culthood(src)
new /obj/item/clothing/suit/cultrobes(src)
new /obj/item/weapon/bedsheet/cult(src)
if(9)
new /obj/item/organ/brain/alien(src)
if(10)
new /obj/item/organ/heart/cursed(src)
if(11)
new /obj/item/ship_in_a_bottle(src)
if(12)
new /obj/item/clothing/suit/space/hardsuit/ert/paranormal/beserker(src)
if(13)
new /obj/item/weapon/sord(src)
if(14)
new /obj/item/weapon/nullrod/scythe/talking(src)
if(15)
new /obj/item/weapon/nullrod/armblade(src)
if(16)
new /obj/item/weapon/guardiancreator(src)
if(17)
new /obj/item/borg/upgrade/modkit/aoe/turfs/andmobs(src)
if(18)
new /obj/item/device/warp_cube/red(src)
if(19)
new /obj/item/device/wisp_lantern(src)
if(20)
new /obj/item/device/immortality_talisman(src)
if(21)
new /obj/item/weapon/gun/magic/hook(src)
if(22)
new /obj/item/voodoo(src)
if(23)
new /obj/item/weapon/grenade/clusterbuster/inferno(src)
if(24)
new /obj/item/weapon/reagent_containers/food/drinks/bottle/holywater/hell(src)
new /obj/item/clothing/suit/space/hardsuit/ert/paranormal/inquisitor(src)
if(25)
new /obj/item/weapon/spellbook/oneuse/summonitem(src)*/
///Bosses
//Dragon
/obj/structure/closet/crate/necropolis/dragon
name = "dragon chest"
/obj/structure/closet/crate/necropolis/dragon/New()
..()
var/loot = rand(1,4)
switch(loot)
if(1)
new /obj/item/weapon/melee/ghost_sword(src)
if(2)
new /obj/item/weapon/lava_staff(src)
if(3)
new /obj/item/weapon/spellbook/oneuse/sacredflame(src)
new /obj/item/weapon/gun/magic/wand/fireball(src)
if(4)
new /obj/item/weapon/dragons_blood(src)
/obj/item/weapon/melee/ghost_sword
name = "spectral blade"
desc = "A rusted and dulled blade. It doesn't look like it'd do much damage. It glows weakly."
icon_state = "spectral"
item_state = "spectral"
flags = CONDUCT
sharp = 1
edge = 1
w_class = 4
force = 1
throwforce = 1
hitsound = 'sound/effects/ghost2.ogg'
attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "rended")
var/summon_cooldown = 0
var/list/mob/dead/observer/spirits
/obj/item/weapon/melee/ghost_sword/New()
..()
spirits = list()
processing_objects.Add(src)
poi_list |= src
/obj/item/weapon/melee/ghost_sword/Destroy()
for(var/mob/dead/observer/G in spirits)
G.invisibility = initial(G.invisibility)
spirits.Cut()
processing_objects.Remove(src)
poi_list -= src
. = ..()
/obj/item/weapon/melee/ghost_sword/attack_self(mob/user)
if(summon_cooldown > world.time)
to_chat(user, "You just recently called out for aid. You don't want to annoy the spirits.")
return
to_chat(user, "You call out for aid, attempting to summon spirits to your side.")
notify_ghosts("[user] is raising their [src], calling for your help!", enter_link="<a href=?src=[UID()];follow=1>(Click to help)</a>", source = user, action = NOTIFY_FOLLOW)
summon_cooldown = world.time + 600
/obj/item/weapon/melee/ghost_sword/Topic(href, href_list)
if(href_list["follow"])
var/mob/dead/observer/ghost = usr
if(istype(ghost))
ghost.ManualFollow(src)
/obj/item/weapon/melee/ghost_sword/process()
ghost_check()
/obj/item/weapon/melee/ghost_sword/proc/ghost_check()
var/ghost_counter = 0
var/turf/T = get_turf(src)
var/list/contents = T.GetAllContents()
var/mob/dead/observer/current_spirits = list()
for(var/mob/dead/observer/O in player_list)
if(is_type_in_list(O.following, contents))
ghost_counter++
O.invisibility = 0
current_spirits |= O
for(var/mob/dead/observer/G in spirits - current_spirits)
G.invisibility = initial(G.invisibility)
spirits = current_spirits
return ghost_counter
/obj/item/weapon/melee/ghost_sword/attack(mob/living/target, mob/living/carbon/human/user)
force = 0
var/ghost_counter = ghost_check()
force = Clamp((ghost_counter * 4), 0, 75)
user.visible_message("<span class='danger'>[user] strikes with the force of [ghost_counter] vengeful spirits!</span>")
..()
/obj/item/weapon/melee/ghost_sword/hit_reaction(mob/living/carbon/human/owner, attack_text, final_block_chance, damage, attack_type)
var/ghost_counter = ghost_check()
final_block_chance += Clamp((ghost_counter * 5), 0, 75)
owner.visible_message("<span class='danger'>[owner] is protected by a ring of [ghost_counter] ghosts!</span>")
return ..()
// Blood
/obj/item/weapon/dragons_blood
name = "bottle of dragons blood"
desc = "You're not actually going to drink this, are you?"
icon = 'icons/obj/wizard.dmi'
icon_state = "vial"
/obj/item/weapon/dragons_blood/attack_self(mob/living/carbon/human/user)
if(!istype(user))
return
var/mob/living/carbon/human/H = user
var/random = rand(1,3)
switch(random)
if(1)
to_chat(user, "<span class='danger'>Your flesh begins to melt! Miraculously, you seem fine otherwise.</span>")
H.set_species("Skeleton")
if(2)
to_chat(user, "<span class='danger'>Power courses through you! You can now shift your form at will.")
if(user.mind)
var/obj/effect/proc_holder/spell/targeted/shapeshift/dragon/D = new
user.mind.AddSpell(D)
if(3)
to_chat(user, "<span class='danger'>You feel like you could walk straight through lava now.</span>")
H.weather_immunities |= "lava"
playsound(user.loc,'sound/items/drink.ogg', rand(10,50), 1)
qdel(src)
/datum/disease/transformation/dragon
name = "dragon transformation"
cure_text = "nothing"
cures = list("adminordrazine")
agent = "dragon's blood"
desc = "What do dragons have to do with Space Station 13?"
stage_prob = 20
severity = BIOHAZARD
visibility_flags = 0
stage1 = list("Your bones ache.")
stage2 = list("Your skin feels scaley.")
stage3 = list("<span class='danger'>You have an overwhelming urge to terrorize some peasants.</span>", "<span class='danger'>Your teeth feel sharper.</span>")
stage4 = list("<span class='danger'>Your blood burns.</span>")
stage5 = list("<span class='danger'>You're a fucking dragon. However, any previous allegiances you held still apply. It'd be incredibly rude to eat your still human friends for no reason.</span>")
new_form = /mob/living/simple_animal/hostile/megafauna/dragon/lesser
//Lava Staff
/obj/item/weapon/lava_staff
name = "staff of lava"
desc = "The ability to fill the emergency shuttle with lava. What more could you want out of life?"
icon_state = "staffofstorms"
item_state = "staffofstorms"
icon = 'icons/obj/guns/magic.dmi'
slot_flags = SLOT_BACK
item_state = "staffofstorms"
w_class = 4
force = 25
damtype = BURN
hitsound = 'sound/weapons/sear.ogg'
var/turf_type = /turf/unsimulated/floor/lava // /turf/simulated/floor/plating/lava/smooth once Lavaland turfs are added
var/transform_string = "lava"
var/reset_turf_type = /turf/simulated/floor/plating/airless/asteroid // /turf/simulated/floor/plating/asteroid/basalt once Lavaland turfs are added
var/reset_string = "basalt"
var/create_cooldown = 100
var/create_delay = 30
var/reset_cooldown = 50
var/timer = 0
var/banned_turfs
/obj/item/weapon/lava_staff/New()
. = ..()
banned_turfs = typecacheof(list(/turf/space/transit, /turf/unsimulated))
/obj/item/weapon/lava_staff/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
..()
if(timer > world.time)
return
if(is_type_in_typecache(target, banned_turfs))
return
if(target in view(user.client.view, get_turf(user)))
var/turf/simulated/T = get_turf(target)
if(!istype(T))
return
if(!istype(T, turf_type))
var/obj/effect/overlay/temp/lavastaff/L = new /obj/effect/overlay/temp/lavastaff(T)
L.alpha = 0
animate(L, alpha = 255, time = create_delay)
user.visible_message("<span class='danger'>[user] points [src] at [T]!</span>")
timer = world.time + create_delay + 1
if(do_after(user, create_delay, target = T))
user.visible_message("<span class='danger'>[user] turns \the [T] into [transform_string]!</span>")
message_admins("[key_name_admin(user)] fired the lava staff at [get_area(target)] (<A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[T.x];Y=[T.y];Z=[T.z]'>JMP</a>).")
log_game("[key_name(user)] fired the lava staff at [get_area(target)] ([T.x], [T.y], [T.z]).")
T.ChangeTurf(turf_type)
timer = world.time + create_cooldown
qdel(L)
else
timer = world.time
qdel(L)
return
else
user.visible_message("<span class='danger'>[user] turns \the [T] into [reset_string]!</span>")
T.ChangeTurf(reset_turf_type)
timer = world.time + reset_cooldown
playsound(T,'sound/magic/Fireball.ogg', 200, 1)
/obj/effect/overlay/temp/lavastaff
icon_state = "lavastaff_warn"
duration = 50
// Bubblegum
/obj/structure/closet/crate/necropolis/bubblegum
name = "bubblegum chest"
/obj/structure/closet/crate/necropolis/bubblegum/New()
..()
var/loot = rand(1,3)
switch(loot)
if(1)
new /obj/item/mayhem(src)
if(2)
new /obj/item/blood_contract(src)
if(3)
new /obj/item/weapon/gun/magic/staff/spellblade(src)
// Mayhem
/obj/item/mayhem
name = "mayhem in a bottle"
desc = "A magically infused bottle of blood, the scent of which will drive anyone nearby into a murderous frenzy."
icon = 'icons/obj/wizard.dmi'
icon_state = "vial"
/obj/item/mayhem/attack_self(mob/user)
for(var/mob/living/carbon/human/H in range(7,user))
spawn()
var/obj/effect/mine/pickup/bloodbath/B = new(H)
B.mineEffect(H)
to_chat(user, "<span class='notice'>You shatter the bottle!</span>")
playsound(user.loc, 'sound/effects/Glassbr1.ogg', 100, 1)
qdel(src)
// Blood Contract
/obj/item/blood_contract
name = "blood contract"
icon = 'icons/obj/wizard.dmi'
icon_state = "scroll2"
color = "#FF0000"
desc = "Mark your target for death."
var/used = FALSE
/obj/item/blood_contract/attack_self(mob/user)
if(used)
return
used = TRUE
var/choice = input(user,"Who do you want dead?","Choose Your Victim") as null|anything in player_list
if(!choice)
used = FALSE
return
else if(!isliving(choice))
to_chat(user, "[choice] is already dead!")
used = FALSE
return
else
var/mob/living/L = choice
message_admins("[key_name_admin(L)] has been marked for death by [key_name_admin(user)].")
log_admin("[key_name(L)] has been marked for death by [key_name(user)].")
var/datum/objective/survive/survive = new
survive.owner = L.mind
L.mind.objectives += survive
to_chat(L, "<span class='userdanger'>You've been marked for death! Don't let the demons get you!</span>")
L.color = "#FF0000"
spawn()
var/obj/effect/mine/pickup/bloodbath/B = new(L)
B.mineEffect(L)
for(var/mob/living/carbon/human/H in player_list)
if(H == L)
continue
to_chat(H, "<span class='userdanger'>You have an overwhelming desire to kill [L]. They have been marked red! Go kill them!</span>")
H.put_in_hands(new /obj/item/weapon/kitchen/knife/butcher(H))
qdel(src)
// Legion
// Staff of Storms
/obj/item/weapon/staff/storm
name = "staff of storms"
desc = "An ancient staff retrieved from the remains of Legion. The wind stirs as you move it."
icon_state = "staffofstorms"
item_state = "staffofstorms"
icon = 'icons/obj/guns/magic.dmi'
slot_flags = SLOT_BACK
item_state = "staffofstorms"
w_class = 4
force = 25
damtype = BURN
hitsound = 'sound/weapons/sear.ogg'
var/storm_type = /datum/weather/ash_storm
var/storm_cooldown = 0
/obj/item/weapon/staff/storm/attack_self(mob/user)
if(storm_cooldown > world.time)
to_chat(user, "<span class='warning'>The staff is still recharging!</span>")
return
var/area/user_area = get_area(user)
var/datum/weather/A
var/z_level_name = space_manager.levels_by_name[user.z]
for(var/V in weather_master.existing_weather)
var/datum/weather/W = V
if(W.target_z == z_level_name && W.area_type == user_area.type)
A = W
break
if(A)
if(A.stage != END_STAGE)
if(A.stage == WIND_DOWN_STAGE)
to_chat(user, "<span class='warning'>The storm is already ending! It would be a waste to use the staff now.</span>")
return
user.visible_message("<span class='warning'>[user] holds [src] skywards as an orange beam travels into the sky!</span>", \
"<span class='notice'>You hold [src] skyward, dispelling the storm!</span>")
playsound(user, 'sound/magic/Staff_Change.ogg', 200, 0)
A.wind_down()
return
else
A = new storm_type
A.name = "staff storm"
A.area_type = user_area.type
A.target_z = z_level_name
A.telegraph_duration = 100
A.end_duration = 100
user.visible_message("<span class='warning'>[user] holds [src] skywards as red lightning crackles into the sky!</span>", \
"<span class='notice'>You hold [src] skyward, calling down a terrible storm!</span>")
playsound(user, 'sound/magic/Staff_Change.ogg', 200, 0)
A.telegraph()
storm_cooldown = world.time + 200
// Hierophant
//Hierophant
/obj/item/weapon/hierophant_staff
name = "Hierophant's staff"
desc = "A large club with intense magic power infused into it."
icon_state = "hierophant_staff"
item_state = "hierophant_staff"
icon = 'icons/obj/guns/magic.dmi'
slot_flags = SLOT_BACK
w_class = 4
force = 20
hitsound = "swing_hit"
//hitsound = 'sound/weapons/sonic_jackhammer.ogg'
actions_types = list(/datum/action/item_action/vortex_recall, /datum/action/item_action/toggle_unfriendly_fire)
var/cooldown_time = 20 //how long the cooldown between non-melee ranged attacks is
var/chaser_cooldown = 101 //how long the cooldown between firing chasers at mobs is
var/chaser_timer = 0 //what our current chaser cooldown is
var/timer = 0 //what our current cooldown is
var/blast_range = 3 //how long the cardinal blast's walls are
var/obj/effect/hierophant/rune //the associated rune we teleport to
var/teleporting = FALSE //if we ARE teleporting
var/friendly_fire_check = FALSE //if the blasts we make will consider our faction against the faction of hit targets
/obj/item/weapon/hierophant_staff/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
..()
var/turf/T = get_turf(target)
if(!T || timer > world.time)
return
timer = world.time + CLICK_CD_MELEE //by default, melee attacks only cause melee blasts, and have an accordingly short cooldown
if(proximity_flag)
spawn(0)
aoe_burst(T, user)
add_logs(user, target, "fired 3x3 blast at", src)
else
if(ismineralturf(target) && get_dist(user, target) < 6) //target is minerals, we can hit it(even if we can't see it)
spawn(0)
cardinal_blasts(T, user)
timer = world.time + cooldown_time
else if(target in view(5, get_turf(user))) //if the target is in view, hit it
timer = world.time + cooldown_time
if(isliving(target) && chaser_timer <= world.time) //living and chasers off cooldown? fire one!
chaser_timer = world.time + chaser_cooldown
new /obj/effect/overlay/temp/hierophant/chaser(get_turf(user), user, target, 1.5, friendly_fire_check)
add_logs(user, target, "fired a chaser at", src)
else
spawn(0)
cardinal_blasts(T, user) //otherwise, just do cardinal blast
add_logs(user, target, "fired cardinal blast at", src)
else
to_chat(user, "<span class='warning'>That target is out of range!</span>") //too far away
/obj/item/weapon/hierophant_staff/ui_action_click(mob/user, actiontype)
if(actiontype == /datum/action/item_action/toggle_unfriendly_fire) //toggle friendly fire...
friendly_fire_check = !friendly_fire_check
to_chat(user, "<span class='warning'>You toggle friendly fire [friendly_fire_check ? "off":"on"]!</span>")
return
if(user.get_active_hand() != src && user.get_inactive_hand() != src) //you need to hold the staff to teleport
to_chat(user, "<span class='warning'>You need to hold the staff in your hands to [rune ? "teleport with it" : "create a rune"]!</span>")
return
if(!rune)
if(isturf(user.loc))
user.visible_message("<span class='hierophant_warning'>[user] holds [src] carefully in front of them, moving it in a strange pattern...</span>", \
"<span class='notice'>You start creating a hierophant rune to teleport to...</span>")
timer = world.time + 51
if(do_after(user, 50, target = user))
var/turf/T = get_turf(user)
playsound(T,'sound/magic/Blind.ogg', 200, 1, -4)
new /obj/effect/overlay/temp/hierophant/telegraph/teleport(T, user)
var/obj/effect/hierophant/H = new/obj/effect/hierophant(T)
rune = H
user.update_action_buttons_icon()
user.visible_message("<span class='hierophant_warning'>[user] creates a strange rune beneath them!</span>", \
"<span class='hierophant'>You create a hierophant rune, which you can teleport yourself and any allies to at any time!</span>\n\
<span class='notice'>You can remove the rune to place a new one by striking it with the staff.</span>")
else
timer = world.time
else
to_chat(user, "<span class='warning'>You need to be on solid ground to produce a rune!</span>")
return
if(get_dist(user, rune) <= 2) //rune too close abort
to_chat(user, "<span class='warning'>You are too close to the rune to teleport to it!</span>")
return
if(is_blocked_turf(get_turf(rune)))
to_chat(user, "<span class='warning'>The rune is blocked by something, preventing teleportation!</span>")
return
teleporting = TRUE //start channel
user.update_action_buttons_icon()
user.visible_message("<span class='hierophant_warning'>[user] starts to glow faintly...</span>")
timer = world.time + 50
if(do_after(user, 40, target = user) && rune)
var/turf/T = get_turf(rune)
var/turf/source = get_turf(user)
if(is_blocked_turf(T))
teleporting = FALSE
to_chat(user, "<span class='warning'>The rune is blocked by something, preventing teleportation!</span>")
user.update_action_buttons_icon()
return
new /obj/effect/overlay/temp/hierophant/telegraph(T, user)
new /obj/effect/overlay/temp/hierophant/telegraph(source, user)
playsound(T,'sound/magic/blink.ogg', 200, 1)
//playsound(T,'sound/magic/Wand_Teleport.ogg', 200, 1)
playsound(source,'sound/magic/blink.ogg', 200, 1)
//playsound(source,'sound/machines/AirlockOpen.ogg', 200, 1)
if(!do_after(user, 3, target = user) || !rune) //no walking away shitlord
teleporting = FALSE
if(user)
user.update_action_buttons_icon()
return
if(is_blocked_turf(T))
teleporting = FALSE
to_chat(user, "<span class='warning'>The rune is blocked by something, preventing teleportation!</span>")
user.update_action_buttons_icon()
return
add_logs(user, rune, "teleported self from ([source.x],[source.y],[source.z]) to")
new /obj/effect/overlay/temp/hierophant/telegraph/teleport(T, user)
new /obj/effect/overlay/temp/hierophant/telegraph/teleport(source, user)
for(var/t in RANGE_TURFS(1, T))
var/obj/effect/overlay/temp/hierophant/blast/B = new /obj/effect/overlay/temp/hierophant/blast(t, user, TRUE) //blasts produced will not hurt allies
B.damage = 30
for(var/t in RANGE_TURFS(1, source))
var/obj/effect/overlay/temp/hierophant/blast/B = new /obj/effect/overlay/temp/hierophant/blast(t, user, TRUE) //but absolutely will hurt enemies
B.damage = 30
for(var/mob/living/L in range(1, source))
spawn(0)
teleport_mob(source, L, T, user) //regardless, take all mobs near us along
sleep(6) //at this point the blasts detonate
else
timer = world.time
teleporting = FALSE
if(user)
user.update_action_buttons_icon()
/obj/item/weapon/hierophant_staff/proc/teleport_mob(turf/source, mob/M, turf/target, mob/user)
var/turf/turf_to_teleport_to = get_step(target, get_dir(source, M)) //get position relative to caster
if(!turf_to_teleport_to || is_blocked_turf(turf_to_teleport_to))
return
animate(M, alpha = 0, time = 2, easing = EASE_OUT) //fade out
sleep(1)
if(!M)
return
M.visible_message("<span class='hierophant_warning'>[M] fades out!</span>")
sleep(2)
if(!M)
return
M.forceMove(turf_to_teleport_to)
sleep(1)
if(!M)
return
animate(M, alpha = 255, time = 2, easing = EASE_IN) //fade IN
sleep(1)
if(!M)
return
M.visible_message("<span class='hierophant_warning'>[M] fades in!</span>")
if(user != M)
add_logs(user, M, "teleported", null, "from ([source.x],[source.y],[source.z])")
/obj/item/weapon/hierophant_staff/proc/cardinal_blasts(turf/T, mob/living/user) //fire cardinal cross blasts with a delay
if(!T)
return
new /obj/effect/overlay/temp/hierophant/telegraph/cardinal(T, user)
playsound(T,'sound/magic/blink.ogg', 200, 1)
//playsound(T,'sound/effects/bin_close.ogg', 200, 1)
sleep(2)
new /obj/effect/overlay/temp/hierophant/blast(T, user, friendly_fire_check)
for(var/d in cardinal)
spawn(0)
blast_wall(T, d, user)
/obj/item/weapon/hierophant_staff/proc/blast_wall(turf/T, dir, mob/living/user) //make a wall of blasts blast_range tiles long
if(!T)
return
var/range = blast_range
var/turf/previousturf = T
var/turf/J = get_step(previousturf, dir)
for(var/i in 1 to range)
if(!J)
return
new /obj/effect/overlay/temp/hierophant/blast(J, user, friendly_fire_check)
previousturf = J
J = get_step(previousturf, dir)
/obj/item/weapon/hierophant_staff/proc/aoe_burst(turf/T, mob/living/user) //make a 3x3 blast around a target
if(!T)
return
new /obj/effect/overlay/temp/hierophant/telegraph(T, user)
playsound(T,'sound/magic/blink.ogg', 200, 1)
//playsound(T,'sound/effects/bin_close.ogg', 200, 1)
sleep(2)
for(var/t in RANGE_TURFS(1, T))
new /obj/effect/overlay/temp/hierophant/blast(t, user, friendly_fire_check)
+2
View File
@@ -13,6 +13,7 @@
power_environ = 0
power_equip = 0
power_light = 0
outdoors = 1
ambientsounds = list('sound/ambience/ambimine.ogg')
/area/mine/dangerous/unexplored
@@ -25,6 +26,7 @@
power_environ = 0
power_equip = 0
power_light = 0
outdoors = 1
ambientsounds = list('sound/ambience/ambimine.ogg')
/area/mine/lobby
+4 -2
View File
@@ -2,10 +2,12 @@
//this item is intended to give the effect of entering the mine, so that light gradually fades
/obj/effect/light_emitter
name = "Light-emtter"
name = "Light emtter"
anchored = 1
invisibility = 101
unacidable = 1
light_range = 8
light_power = 0
/**********************Miner Lockers**************************/
@@ -89,7 +91,7 @@
var/excavation_amount = 100
/obj/item/weapon/pickaxe/proc/playDigSound()
playsound(src, pick(digsound),20,1)
playsound(src, pick(digsound),20,1)
/obj/item/weapon/pickaxe/silver
name = "silver-plated pickaxe"
+4
View File
@@ -62,6 +62,10 @@
points = 1
refined_type = /obj/item/stack/sheet/glass
materials = list(MAT_GLASS=MINERAL_MATERIAL_AMOUNT)
/obj/item/weapon/ore/glass/basalt
name = "volcanic ash"
icon_state = "volcanic_sand"
/obj/item/weapon/ore/glass/attack_self(mob/living/user as mob)
to_chat(user, "<span class='notice'>You use the sand to make sandstone.</span>")
+1 -1
View File
@@ -25,7 +25,7 @@ var/global/list/boo_phrases=list(
invocation_type = "none"
range = 1 // Or maybe 3?
/obj/effect/proc_holder/spell/aoe_turf/boo/cast(list/targets)
/obj/effect/proc_holder/spell/aoe_turf/boo/cast(list/targets, mob/user = usr)
for(var/turf/T in targets)
for(var/atom/A in T.contents)
@@ -10,6 +10,7 @@
/mob/living/carbon/brain/New()
create_reagents(330)
add_language("Galactic Common")
..()
/mob/living/carbon/brain/Destroy()
@@ -36,4 +36,4 @@
for(var/datum/disease/D in user.viruses)
if(D.IsSpreadByTouch())
ContractDisease(D)
return 0
return 0
+50 -40
View File
@@ -83,12 +83,12 @@
message = "<B>[src]</B> pings at [param]."
else
message = "<B>[src]</B> pings."
playsound(src.loc, 'sound/machines/ping.ogg', 50, 0)
playsound(loc, 'sound/machines/ping.ogg', 50, 0)
m_type = 2
if("buzz2")
message = "<B>[src]</B> emits an irritated buzzing sound."
playsound(src.loc, 'sound/machines/buzz-two.ogg', 50, 0)
playsound(loc, 'sound/machines/buzz-two.ogg', 50, 0)
m_type = 2
if("buzz", "buzzes")
@@ -105,7 +105,7 @@
message = "<B>[src]</B> buzzes at [param]."
else
message = "<B>[src]</B> buzzes."
playsound(src.loc, 'sound/machines/buzz-sigh.ogg', 50, 0)
playsound(loc, 'sound/machines/buzz-sigh.ogg', 50, 0)
m_type = 2
if("beep", "beeps")
@@ -122,7 +122,7 @@
message = "<B>[src]</B> beeps at [param]."
else
message = "<B>[src]</B> beeps."
playsound(src.loc, 'sound/machines/twobeep.ogg', 50, 0)
playsound(loc, 'sound/machines/twobeep.ogg', 50, 0)
m_type = 2
if("drone", "drones", "hum", "hums", "rumble", "rumbles")
@@ -139,7 +139,7 @@
message = "<B>[src]</B> drones at [param]."
else
message = "<B>[src]</B> rumbles."
playsound(src.loc, 'sound/voice/DraskTalk.ogg', 50, 0)
playsound(loc, 'sound/voice/DraskTalk.ogg', 50, 0)
m_type = 2
if("squish", "squishes")
@@ -156,7 +156,7 @@
message = "<B>[src]</B> squishes at [param]."
else
message = "<B>[src]</B> squishes."
playsound(src.loc, 'sound/effects/slime_squish.ogg', 50, 0) //Credit to DrMinky (freesound.org) for the sound.
playsound(loc, 'sound/effects/slime_squish.ogg', 50, 0) //Credit to DrMinky (freesound.org) for the sound.
m_type = 2
if("yes")
@@ -173,7 +173,7 @@
message = "<B>[src]</B> emits an affirmative blip at [param]."
else
message = "<B>[src]</B> emits an affirmative blip."
playsound(src.loc, 'sound/machines/synth_yes.ogg', 50, 0)
playsound(loc, 'sound/machines/synth_yes.ogg', 50, 0)
m_type = 2
if("no")
@@ -190,7 +190,7 @@
message = "<B>[src]</B> emits a negative blip at [param]."
else
message = "<B>[src]</B> emits a negative blip."
playsound(src.loc, 'sound/machines/synth_no.ogg', 50, 0)
playsound(loc, 'sound/machines/synth_no.ogg', 50, 0)
m_type = 2
if("wag", "wags")
@@ -202,7 +202,7 @@
else if(species.bodyflags & TAIL_WAGGING)
if(!wear_suit || !(wear_suit.flags_inv & HIDETAIL) && !istype(wear_suit, /obj/item/clothing/suit/space))
message = "<B>[src]</B> starts wagging \his tail."
src.start_tail_wagging(1)
start_tail_wagging(1)
else
return
else
@@ -212,15 +212,25 @@
if("swag", "swags")
if(species.bodyflags & TAIL_WAGGING || body_accessory)
message = "<B>[src]</B> stops wagging \his tail."
src.stop_tail_wagging(1)
stop_tail_wagging(1)
else
return
m_type = 1
if("airguitar")
if(!src.restrained())
if(!restrained())
message = "<B>[src]</B> is strumming the air and headbanging like a safari chimp."
m_type = 1
if("dance")
if(!restrained())
message = "<B>[src]</B> dances around happily."
m_type = 1
if("jump")
if(!restrained())
message = "<B>[src]</B> jumps!"
m_type = 1
if("blink", "blinks")
message = "<B>[src]</B> blinks."
@@ -231,7 +241,7 @@
m_type = 1
if("bow", "bows")
if(!src.buckled)
if(!buckled)
var/M = null
if(param)
for(var/mob/A in view(null, null))
@@ -248,7 +258,7 @@
m_type = 1
if("salute", "salutes")
if(!src.buckled)
if(!buckled)
var/M = null
if(param)
for(var/mob/A in view(null, null))
@@ -288,13 +298,13 @@
message = "<B>[src]</B> makes a peculiar noise."
m_type = 2
if("clap", "claps")
if(!src.restrained())
if(!restrained())
message = "<B>[src]</B> claps."
m_type = 2
if(miming)
m_type = 1
if("flap", "flaps")
if(!src.restrained())
if(!restrained())
message = "<B>[src]</B> flaps \his wings."
m_type = 2
if(miming)
@@ -302,7 +312,7 @@
if("flip", "flips")
m_type = 1
if(!src.restrained())
if(!restrained())
var/M = null
if(param)
for(var/mob/A in view(1, null))
@@ -340,7 +350,7 @@
SpinAnimation(5,1)
if("aflap", "aflaps")
if(!src.restrained())
if(!restrained())
message = "<B>[src]</B> flaps \his wings ANGRILY!"
m_type = 2
if(miming)
@@ -376,7 +386,7 @@
if("faint", "faints")
message = "<B>[src]</B> faints."
if(src.sleeping)
if(sleeping)
return //Can't faint while asleep
AdjustSleeping(2)
m_type = 1
@@ -578,11 +588,11 @@
message = "<B>[src]</B> takes a drag from a cigarette and blows \"[M]\" out in smoke."
m_type = 1
else
message = "<B>[src]</B> says, \"[M], please. They had a family.\" [src.name] takes a drag from a cigarette and blows their name out in smoke."
message = "<B>[src]</B> says, \"[M], please. They had a family.\" [name] takes a drag from a cigarette and blows their name out in smoke."
m_type = 2
if("point", "points")
if(!src.restrained())
if(!restrained())
var/atom/M = null
if(param)
for(var/atom/A as mob|obj|turf in view())
@@ -597,7 +607,7 @@
m_type = 1
if("raise", "raises")
if(!src.restrained())
if(!restrained())
message = "<B>[src]</B> raises a hand."
m_type = 1
@@ -610,12 +620,12 @@
m_type = 1
if("signal", "signals")
if(!src.restrained())
if(!restrained())
var/t1 = round(text2num(param))
if(isnum(t1))
if(t1 <= 5 && (!src.r_hand || !src.l_hand))
if(t1 <= 5 && (!r_hand || !l_hand))
message = "<B>[src]</B> raises [t1] finger\s."
else if(t1 <= 10 && (!src.r_hand && !src.l_hand))
else if(t1 <= 10 && (!r_hand && !l_hand))
message = "<B>[src]</B> raises [t1] finger\s."
m_type = 1
@@ -699,7 +709,7 @@
if("hug", "hugs")
m_type = 1
if(!src.restrained())
if(!restrained())
var/M = null
if(param)
for(var/mob/A in view(1, null))
@@ -716,7 +726,7 @@
if("handshake")
m_type = 1
if(!src.restrained() && !src.r_hand)
if(!restrained() && !r_hand)
var/mob/M = null
if(param)
for(var/mob/A in view(1, null))
@@ -734,7 +744,7 @@
if("dap", "daps")
m_type = 1
if(!src.restrained())
if(!restrained())
var/M = null
if(param)
for(var/mob/A in view(1, null))
@@ -748,7 +758,7 @@
if("slap", "slaps")
m_type = 1
if(!src.restrained())
if(!restrained())
var/M = null
if(param)
for(var/mob/A in view(1, null))
@@ -757,11 +767,11 @@
break
if(M)
message = "<span class='danger'>[src] slaps [M] across the face. Ouch!</span>"
playsound(src.loc, 'sound/effects/snap.ogg', 50, 1)
playsound(loc, 'sound/effects/snap.ogg', 50, 1)
else
message = "<span class='danger'>[src] slaps \himself!</span>"
playsound(src.loc, 'sound/effects/snap.ogg', 50, 1)
src.adjustFireLoss(4)
playsound(loc, 'sound/effects/snap.ogg', 50, 1)
adjustFireLoss(4)
if("scream", "screams")
if(miming)
@@ -772,9 +782,9 @@
message = "<B>[src]</B> [species.scream_verb]!"
m_type = 2
if(gender == FEMALE)
playsound(src.loc, "[species.female_scream_sound]", 80, 1, 0, pitch = get_age_pitch())
playsound(loc, "[species.female_scream_sound]", 80, 1, 0, pitch = get_age_pitch())
else
playsound(src.loc, "[species.male_scream_sound]", 80, 1, 0, pitch = get_age_pitch()) //default to male screams if no gender is present.
playsound(loc, "[species.male_scream_sound]", 80, 1, 0, pitch = get_age_pitch()) //default to male screams if no gender is present.
else
message = "<B>[src]</B> makes a very loud noise."
@@ -799,24 +809,24 @@
return
message = "<b>[src]</b> snaps \his fingers."
playsound(src.loc, 'sound/effects/fingersnap.ogg', 50, 1, -3)
playsound(loc, 'sound/effects/fingersnap.ogg', 50, 1, -3)
else
message = "<span class='danger'><b>[src]</b> snaps \his fingers right off!</span>"
playsound(src.loc, 'sound/effects/snap.ogg', 50, 1)
playsound(loc, 'sound/effects/snap.ogg', 50, 1)
// Needed for M_TOXIC_FART
if("fart", "farts")
if(reagents.has_reagent("simethicone"))
return
// playsound(src.loc, 'sound/effects/fart.ogg', 50, 1, -3) //Admins still vote no to fun
// playsound(loc, 'sound/effects/fart.ogg', 50, 1, -3) //Admins still vote no to fun
if(locate(/obj/item/weapon/storage/bible) in get_turf(src))
to_chat(viewers(src), "<span class='warning'><b>[src] farts on the Bible!</b></span>")
to_chat(viewers(src), "<span class='notice'><b>A mysterious force smites [src]!</b></span>")
var/datum/effect/system/spark_spread/s = new /datum/effect/system/spark_spread
s.set_up(3, 1, src)
s.start()
src.gib()
gib()
else if(TOXIC_FARTS in mutations)
message = "<b>[src]</b> unleashes a [pick("horrible","terrible","foul","disgusting","awful")] fart."
else if(SUPER_FART in mutations)
@@ -841,9 +851,9 @@
M.reagents.add_reagent("jenkem", 1)
if("help")
var/emotelist = "aflap(s), airguitar, blink(s), blink(s)_r, blush(es), bow(s)-(none)/mob, burp(s), choke(s), chuckle(s), clap(s), collapse(s), cough(s),cry, cries, custom, dap(s)(none)/mob," \
+ " deathgasp(s), drool(s), eyebrow,fart(s), faint(s), flap(s), flip(s), frown(s), gasp(s), giggle(s), glare(s)-(none)/mob, grin(s), groan(s), grumble(s), handshake-mob, hug(s)-(none)/mob," \
+ " glare(s)-(none)/mob, grin(s), johnny, laugh(s), look(s)-(none)/mob, moan(s), mumble(s), nod(s), pale(s), point(s)-atom, quiver(s), raise(s), salute(s)-(none)/mob, scream(s), shake(s)," \
var/emotelist = "aflap(s), airguitar, blink(s), blink(s)_r, blush(es), bow(s)-(none)/mob, burp(s), choke(s), chuckle(s), clap(s), collapse(s), cough(s),cry, cries, custom, dance, dap(s)(none)/mob," \
+ " deathgasp(s), drool(s), eyebrow, fart(s), faint(s), flap(s), flip(s), frown(s), gasp(s), giggle(s), glare(s)-(none)/mob, grin(s), groan(s), grumble(s), grin(s)," \
+ " handshake-mob, hug(s)-(none)/mob, johnny, jump, laugh(s), look(s)-(none)/mob, moan(s), mumble(s), nod(s), pale(s), point(s)-atom, quiver(s), raise(s), salute(s)-(none)/mob, scream(s), shake(s)," \
+ " shiver(s), shrug(s), sigh(s), signal(s)-#1-10,slap(s)-(none)/mob, smile(s),snap(s), sneeze(s), sniff(s), snore(s), stare(s)-(none)/mob, swag(s), tremble(s), twitch(es), twitch(es)_s," \
+ " wag(s), wave(s), whimper(s), wink(s), yawn(s)"
if(species.name == "Machine")
@@ -38,6 +38,7 @@ emp_act
var/obj/item/organ/external/organ = get_organ(check_zone(def_zone))
if(isnull(organ))
. = bullet_act(P, "chest") //act on chest instead
return
//Shrapnel
@@ -56,6 +57,18 @@ emp_act
organ.add_autopsy_data(P.name, P.damage) // Add the bullet's name to the autopsy data
return (..(P , def_zone))
/mob/living/carbon/human/check_projectile_dismemberment(obj/item/projectile/P, def_zone)
var/obj/item/organ/external/affecting = get_organ(check_zone(def_zone))
if(affecting && !affecting.cannot_amputate && affecting.get_damage() >= (affecting.max_damage - P.dismemberment))
var/damtype = DROPLIMB_EDGE
switch(P.damage_type)
if(BRUTE)
damtype = DROPLIMB_BLUNT
if(BURN)
damtype = DROPLIMB_BURN
affecting.droplimb(FALSE, damtype)
/mob/living/carbon/human/getarmor(var/def_zone, var/type)
var/armorval = 0
+2 -2
View File
@@ -1,10 +1,10 @@
/mob/living/carbon/human/say(var/message)
/mob/living/carbon/human/say(var/message, var/sanitize = TRUE, var/ignore_speech_problems = FALSE, var/ignore_atmospherics = FALSE)
var/alt_name = ""
if(name != GetVoice())
alt_name = " (as [get_id_name("Unknown")])"
..(message, alt_name = alt_name) //ohgod we should really be passing a datum here.
..(message, alt_name = alt_name, sanitize = sanitize, ignore_speech_problems = ignore_speech_problems, ignore_atmospherics = ignore_atmospherics) //ohgod we should really be passing a datum here.
/mob/living/carbon/human/proc/forcesay(list/append)
if(stat == CONSCIOUS)
@@ -7,7 +7,10 @@
default_language = "Galactic Common"
unarmed_type = /datum/unarmed_attack/claws
darksight = 8
ignored_by = list(/mob/living/simple_animal/hostile/faithless)
blood_color = "#CCCCCC"
flesh_color = "#AAAAAA"
@@ -20,6 +23,7 @@
oxy_mod = 0
virus_immune = 1
dietflags = DIET_OMNI //the mutation process allowed you to now digest all foods regardless of initial race
reagent_tag = PROCESS_ORG
suicide_messages = list(
@@ -27,14 +31,46 @@
"is jamming their claws into their eye sockets!",
"is twisting their own neck!",
"is staring into the closest light source!")
var/grant_vision_toggle = 1
var/datum/action/innate/shadow/darkvision/vision_toggle
/datum/action/innate/shadow/darkvision //Darkvision toggle so shadowpeople can actually see where darkness is
name = "Toggle Darkvision"
check_flags = AB_CHECK_CONSCIOUS
background_icon_state = "bg_default"
button_icon_state = "blind"
/datum/action/innate/shadow/darkvision/Activate()
var/mob/living/carbon/human/H = owner
if(!H.vision_type)
H.vision_type = new /datum/vision_override/nightvision
to_chat(H, "<span class='notice'>You adjust your vision to pierce the darkness.</span>")
else
H.vision_type = null
to_chat(H, "<span class='notice'>You adjust your vision to recognize the shadows.</span>")
/datum/species/shadow/grant_abilities(var/mob/living/carbon/human/H)
. = ..()
if(grant_vision_toggle)
vision_toggle = new
vision_toggle.Grant(H)
/datum/species/shadow/remove_abilities(var/mob/living/carbon/human/H)
. = ..()
if(grant_vision_toggle && vision_toggle)
H.vision_type = null
vision_toggle.Remove(H)
/datum/species/shadow/handle_life(var/mob/living/carbon/human/H)
var/light_amount = 0
if(isturf(H.loc))
var/turf/T = H.loc
light_amount = T.get_lumcount()*10
light_amount = T.get_lumcount() * 10
if(light_amount > 2) //if there's enough light, start dying
H.take_overall_damage(1,1)
H.throw_alert("lightexposure", /obj/screen/alert/lightexposure)
else if(light_amount < 2) //heal in the dark
H.heal_overall_damage(1,1)
H.heal_overall_damage(1,1)
H.clear_alert("lightexposure")
@@ -50,6 +50,7 @@
var/invis_sight = SEE_INVISIBLE_LIVING
var/darksight = 2
var/hazard_high_pressure = HAZARD_HIGH_PRESSURE // Dangerously high pressure.
var/warning_high_pressure = WARNING_HIGH_PRESSURE // High pressure warning.
var/warning_low_pressure = WARNING_LOW_PRESSURE // Low pressure warning.
@@ -84,6 +85,8 @@
var/ventcrawler = 0 //Determines if the mob can go through the vents.
var/has_fine_manipulation = 1 // Can use small items.
var/mob/living/list/ignored_by = list() // list of mobs that will ignore this species
var/list/allowed_consumed_mobs = list() //If a species can consume mobs, put the type of mobs it can consume here.
@@ -162,7 +165,6 @@
"l_foot" = list("path" = /obj/item/organ/external/foot),
"r_foot" = list("path" = /obj/item/organ/external/foot/right)
)
var/cyborg_type = "Cyborg"
var/list/proc/species_abilities = list()
/datum/species/New()
@@ -808,8 +808,8 @@
return ..()
/datum/species/diona/handle_life(var/mob/living/carbon/human/H)
var/rads = H.radiation/25
H.radiation = Clamp(H.radiation - rads, 0, 100)
var/rads = H.radiation / 25
H.apply_effect(-rads,IRRADIATE,0)
H.nutrition += rads
H.adjustBruteLoss(-(rads))
H.adjustOxyLoss(-(rads))
@@ -818,18 +818,23 @@
var/light_amount = 0 //how much light there is in the place, affects receiving nutrition and healing
if(isturf(H.loc)) //else, there's considered to be no light
var/turf/T = H.loc
light_amount = min(T.get_lumcount()*10, 5) //hardcapped so it's not abused by having a ton of flashlights
light_amount = min(T.get_lumcount() * 10, 5) //hardcapped so it's not abused by having a ton of flashlights
H.nutrition += light_amount
H.traumatic_shock -= light_amount
if(H.nutrition > NUTRITION_LEVEL_WELL_FED)
H.nutrition = NUTRITION_LEVEL_WELL_FED
if(light_amount > 0)
H.clear_alert("nolight")
else
H.throw_alert("nolight", /obj/screen/alert/nolight)
if((light_amount >= 5) && !H.suiciding) //if there's enough light, heal
H.adjustBruteLoss(-(light_amount/2))
H.adjustFireLoss(-(light_amount/4))
H.adjustOxyLoss(-(light_amount))
if(H.nutrition < 200)
H.take_overall_damage(10,0)
H.traumatic_shock++
+28 -28
View File
@@ -147,69 +147,69 @@
action_icon_state = "spell_greytide"
var/recruiting = 0
/obj/effect/proc_holder/spell/targeted/recruit/cast(list/targets)
/obj/effect/proc_holder/spell/targeted/recruit/cast(list/targets,mob/living/user = usr)
for(var/mob/living/carbon/human/target in targets)
var/obj/item/organ/external/head/head_organ = target.get_organ("head")
if(ticker.mode.greyshirts.len >= 3)
to_chat(usr, "<span class='warning'>You have already recruited the maximum number of henchmen.</span>")
if(!in_range(usr, target))
to_chat(usr, "<span class='warning'>You need to be closer to enthrall [target].</span>")
to_chat(user, "<span class='warning'>You have already recruited the maximum number of henchmen.</span>")
if(!in_range(user, target))
to_chat(user, "<span class='warning'>You need to be closer to enthrall [target].</span>")
charge_counter = charge_max
return
if(!target.ckey)
to_chat(usr, "<span class='warning'>The target has no mind.</span>")
to_chat(user, "<span class='warning'>The target has no mind.</span>")
charge_counter = charge_max
return
if(target.stat)
to_chat(usr, "<span class='warning'>The target must be conscious.</span>")
to_chat(user, "<span class='warning'>The target must be conscious.</span>")
charge_counter = charge_max
return
if(!ishuman(target))
to_chat(usr, "<span class='warning'>You can only recruit humans.</span>")
to_chat(user, "<span class='warning'>You can only recruit humans.</span>")
charge_counter = charge_max
return
if(target.mind.assigned_role != "Civilian")
to_chat(usr, "<span class='warning'>You can only recruit Civilians.</span>")
to_chat(user, "<span class='warning'>You can only recruit Civilians.</span>")
if(recruiting)
to_chat(usr, "<span class='danger'>You are already recruiting!</span>")
to_chat(user, "<span class='danger'>You are already recruiting!</span>")
charge_counter = charge_max
return
recruiting = 1
to_chat(usr, "<span class='danger'>This target is valid. You begin the recruiting process.</span>")
to_chat(target, "<span class='userdanger'>[usr] focuses in concentration. Your head begins to ache.</span>")
to_chat(user, "<span class='danger'>This target is valid. You begin the recruiting process.</span>")
to_chat(target, "<span class='userdanger'>[user] focuses in concentration. Your head begins to ache.</span>")
for(var/progress = 0, progress <= 3, progress++)
switch(progress)
if(1)
to_chat(usr, "<span class='notice'>You begin by introducing yourself and explaining what you're about.</span>")
usr.visible_message("<span class='danger'>[usr]'s introduces himself and explains his plans.</span>")
to_chat(user, "<span class='notice'>You begin by introducing yourself and explaining what you're about.</span>")
user.visible_message("<span class='danger'>[user]'s introduces himself and explains his plans.</span>")
if(2)
to_chat(usr, "<span class='notice'>You begin the recruitment of [target].</span>")
usr.visible_message("<span class='danger'>[usr] leans over towards [target], whispering excitedly as he gives a speech.</span>")
to_chat(target, "<span class='danger'>You feel yourself agreeing with [usr], and a surge of loyalty begins building.</span>")
to_chat(user, "<span class='notice'>You begin the recruitment of [target].</span>")
user.visible_message("<span class='danger'>[user] leans over towards [target], whispering excitedly as he gives a speech.</span>")
to_chat(target, "<span class='danger'>You feel yourself agreeing with [user], and a surge of loyalty begins building.</span>")
target.Weaken(12)
sleep(20)
if(isloyal(target))
to_chat(usr, "<span class='notice'>They are enslaved by Nanotrasen. You feel their interest in your cause wane and disappear.</span>")
usr.visible_message("<span class='danger'>[usr] stops talking for a moment, then moves back away from [target].</span>")
to_chat(user, "<span class='notice'>They are enslaved by Nanotrasen. You feel their interest in your cause wane and disappear.</span>")
user.visible_message("<span class='danger'>[user] stops talking for a moment, then moves back away from [target].</span>")
to_chat(target, "<span class='danger'>Your mindshield implant activates, protecting you from conversion.</span>")
return
if(3)
to_chat(usr, "<span class='notice'>You begin filling out the application form with [target].</span>")
usr.visible_message("<span class='danger'>[usr] pulls out a pen and paper and begins filling an application form with [target].</span>")
to_chat(target, "<span class='danger'>You are being convinced by [usr] to fill out an application form to become a henchman.</span>")//Ow the edge
to_chat(user, "<span class='notice'>You begin filling out the application form with [target].</span>")
user.visible_message("<span class='danger'>[user] pulls out a pen and paper and begins filling an application form with [target].</span>")
to_chat(target, "<span class='danger'>You are being convinced by [user] to fill out an application form to become a henchman.</span>")//Ow the edge
if(!do_mob(usr, target, 100)) //around 30 seconds total for enthralling, 45 for someone with a mindshield implant
to_chat(usr, "<span class='danger'>The enrollment process has been interrupted - you have lost the attention of [target].</span>")
to_chat(target, "<span class='warning'>You move away and are no longer under the charm of [usr]. The application form is null and void.</span>")
if(!do_mob(user, target, 100)) //around 30 seconds total for enthralling, 45 for someone with a mindshield implant
to_chat(user, "<span class='danger'>The enrollment process has been interrupted - you have lost the attention of [target].</span>")
to_chat(target, "<span class='warning'>You move away and are no longer under the charm of [user]. The application form is null and void.</span>")
recruiting = 0
return
recruiting = 0
to_chat(usr, "<span class='notice'>You have recruited <b>[target]</b> as your henchman!</span>")
to_chat(target, "<span class='deadsay'><b>You have decided to enroll as a henchman for [usr]. You are now part of the feared 'Greyshirts'.</b></span>")
to_chat(target, "<span class='deadsay'><b>You must follow the orders of [usr], and help him succeed in his dastardly schemes.</span>")
to_chat(target, "<span class='deadsay'>You may not harm other Greyshirt or [usr]. However, you do not need to obey other Greyshirts.</span>")
to_chat(user, "<span class='notice'>You have recruited <b>[target]</b> as your henchman!</span>")
to_chat(target, "<span class='deadsay'><b>You have decided to enroll as a henchman for [user]. You are now part of the feared 'Greyshirts'.</b></span>")
to_chat(target, "<span class='deadsay'><b>You must follow the orders of [user], and help him succeed in his dastardly schemes.</span>")
to_chat(target, "<span class='deadsay'>You may not harm other Greyshirt or [user]. However, you do not need to obey other Greyshirts.</span>")
ticker.mode.greyshirts += target.mind
target.set_species("Human")
head_organ.h_style = "Bald"
+8
View File
@@ -1,7 +1,15 @@
/mob/living/Destroy()
if(ranged_ability)
ranged_ability.remove_ranged_ability(src)
..()
return QDEL_HINT_HARDDEL_NOW
/mob/living/ghostize(can_reenter_corpse = 1)
var/prev_client = client
if(..())
if(ranged_ability && prev_client)
ranged_ability.remove_mousepointer(prev_client)
/mob/living/proc/OpenCraftingMenu()
return
@@ -49,7 +49,12 @@
if(!P.nodamage)
apply_damage(P.damage, P.damage_type, def_zone, armor)
if(P.dismemberment)
check_projectile_dismemberment(P, def_zone)
return P.on_hit(src, armor, def_zone)
/mob/living/proc/check_projectile_dismemberment(obj/item/projectile/P, def_zone)
return 0
/mob/living/proc/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = 0, tesla_shock = 0)
return 0 //only carbon liveforms have this proc
@@ -52,3 +52,5 @@
var/list/surgeries = list() //a list of surgery datums. generally empty, they're added when the player wants them.
var/gene_stability = DEFAULT_GENE_STABILITY
var/obj/effect/proc_holder/ranged_ability //Any ranged ability the mob has, as a click override
+4
View File
@@ -9,6 +9,10 @@
//Vents
if(ventcrawler)
to_chat(src, "<span class='notice'>You can ventcrawl! Use alt+click on vents to quickly travel about the station.</span>")
if(ranged_ability)
ranged_ability.add_ranged_ability(src, "<span class='notice'>You currently have <b>[ranged_ability]</b> active!</span>")
//Should update regardless of if we can ventcrawl, since we can end up in pipes in other ways.
update_pipe_vision()
+2
View File
@@ -1,4 +1,6 @@
/mob/living/Logout()
if(ranged_ability && client)
ranged_ability.remove_mousepointer(client)
..()
if(mind)
if(!key) //key and mind have become seperated. I believe this is for when a staff member aghosts.
+22 -9
View File
@@ -14,6 +14,7 @@ var/list/department_radio_keys = list(
":u" = "Supply", "#u" = "Supply", ".u" = "Supply",
":z" = "Service", "#z" = "Service", ".z" = "Service",
":p" = "AI Private", "#p" = "AI Private", ".p" = "AI Private",
":x" = "cords", "#x" = "cords", ".x" = "cords",
":R" = "right ear", "#R" = "right ear", ".R" = "right ear",
":L" = "left ear", "#L" = "left ear", ".L" = "left ear",
@@ -30,7 +31,8 @@ var/list/department_radio_keys = list(
":Z" = "Service", "#Z" = "Service", ".Z" = "Service",
":P" = "AI Private", "#P" = "AI Private", ".P" = "AI Private",
":-" = "Special Ops", "#-" = "Special Ops", ".-" = "Special Ops",
":_" = "SyndTeam", "#_" = "SyndTeam", "._" = "SyndTeam"
":_" = "SyndTeam", "#_" = "SyndTeam", "._" = "SyndTeam",
":X" = "cords", "#X" = "cords", ".X" = "cords"
)
@@ -106,13 +108,14 @@ proc/get_radio_key_from_channel(var/channel)
return returns
/mob/living/say(var/message, var/datum/language/speaking = null, var/verb = "says", var/alt_name="")
/mob/living/say(var/message, var/datum/language/speaking = null, var/verb = "says", var/alt_name = "", var/sanitize = TRUE, var/ignore_speech_problems = FALSE, var/ignore_atmospherics = FALSE)
if(client)
if(client.prefs.muted & MUTE_IC)
to_chat(src, "<span class='danger'>You cannot speak in IC (Muted).</span>")
return
message = trim_strip_html_properly(message)
if(sanitize)
message = trim_strip_html_properly(message)
if(stat)
if(stat == DEAD)
@@ -146,6 +149,15 @@ proc/get_radio_key_from_channel(var/channel)
if(speaking && (speaking.flags & HIVEMIND))
speaking.broadcast(src,trim(message))
return 1
if(message_mode == "cords")
if(iscarbon(src))
var/mob/living/carbon/C = src
var/obj/item/organ/internal/vocal_cords/V = C.get_int_organ(/obj/item/organ/internal/vocal_cords)
if(V && V.can_speak_with())
C.say(V.handle_speech(message), sanitize = FALSE, ignore_speech_problems = TRUE, ignore_atmospherics = TRUE)
V.speak_with(message) //words come before actions
return 1
verb = say_quote(message, speaking)
@@ -162,7 +174,7 @@ proc/get_radio_key_from_channel(var/channel)
message = handle_autohiss(message, speaking)
if(speaking && !(speaking.flags & NO_STUTTER))
if(!ignore_speech_problems && (speaking && !(speaking.flags & NO_STUTTER)))
var/list/handle_s = handle_speech_problems(message, verb)
message = handle_s[1]
verb = handle_s[2]
@@ -217,12 +229,13 @@ proc/get_radio_key_from_channel(var/channel)
//make sure the air can transmit speech - speaker's side
var/datum/gas_mixture/environment = T.return_air()
var/pressure = environment ? environment.return_pressure() : 0
if(pressure < SOUND_MINIMUM_PRESSURE)
message_range = 1
if(!ignore_atmospherics)
if(pressure < SOUND_MINIMUM_PRESSURE)
message_range = 1
if(pressure < ONE_ATMOSPHERE * 0.4) //sound distortion pressure, to help clue people in that the air is thin, even if it isn't a vacuum yet
italics = 1
sound_vol *= 0.5 //muffle the sound a bit, so it's like we're actually talking through contact
if(pressure < ONE_ATMOSPHERE * 0.4) //sound distortion pressure, to help clue people in that the air is thin, even if it isn't a vacuum yet
italics = 1
sound_vol *= 0.5 //muffle the sound a bit, so it's like we're actually talking through contact
var/list/hear = hear(message_range, T)
var/list/hearturfs = list()
@@ -204,7 +204,7 @@
modules += new /obj/item/weapon/gripper(src)
modules += new /obj/item/weapon/matter_decompiler(src)
modules += new /obj/item/device/floor_painter(src)
modules += new /obj/item/areaeditor/blueprints/cyborg(src)
emag = new /obj/item/borg/stun(src)
for(var/G in stacktypes) //Attempt to unify Engi-Borg material stacks into fewer lines. See Line 492 for example. Variables changed out of paranoia.
@@ -788,6 +788,7 @@ Pass a positive integer as an argument to override a bot's default speed.
frustration = 0
/mob/living/simple_animal/bot/show_inv()
return
/mob/living/simple_animal/bot/proc/show_controls(mob/M)
users |= M
@@ -0,0 +1,51 @@
/mob/living/simple_animal/cockroach
name = "cockroach"
desc = "This station is just crawling with bugs."
icon_state = "cockroach"
icon_dead = "cockroach"
health = 1
maxHealth = 1
turns_per_move = 5
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 = 270
maxbodytemp = INFINITY
pass_flags = PASSTABLE | PASSGRILLE | PASSMOB
mob_size = MOB_SIZE_TINY
response_help = "pokes"
response_disarm = "shoos"
response_harm = "splats"
density = 0
ventcrawler = 2
gold_core_spawnable = 2
var/squish_chance = 50
loot = list(/obj/effect/decal/cleanable/deadcockroach)
del_on_death = 1
/mob/living/simple_animal/cockroach/death(gibbed)
if(ticker.cinematic) //If the nuke is going off, then cockroaches are invincible. Keeps the nuke from killing them, cause cockroaches are immune to nukes.
return
..()
/mob/living/simple_animal/cockroach/Crossed(var/atom/movable/AM)
if(isliving(AM))
var/mob/living/A = AM
if(A.mob_size > MOB_SIZE_SMALL)
if(prob(squish_chance))
A.visible_message("<span class='notice'>\The [A] squashed \the [name].</span>", "<span class='notice'>You squashed \the [name].</span>")
death()
else
visible_message("<span class='notice'>\The [name] avoids getting crushed.</span>")
else if(istype(AM, /obj/structure))
visible_message("<span class='notice'>As \the [AM] moved over \the [name], it was crushed.</span>")
death()
/mob/living/simple_animal/cockroach/ex_act() //Explosions are a terrible way to handle a cockroach.
return
/obj/effect/decal/cleanable/deadcockroach
name = "cockroach guts"
desc = "One bug squashed. Four more will rise in its place."
icon = 'icons/effects/blood.dmi'
icon_state = "xfloor1"
random_icon_states = list("xfloor1", "xfloor2", "xfloor3", "xfloor4", "xfloor5", "xfloor6", "xfloor7")
anchored = 1
@@ -58,7 +58,7 @@
dat += "<tr><td><B>Back:</B></td><td><A href='?src=[UID()];[inventory_back?"remove_inv":"add_inv"]=back'>[(inventory_back && !(inventory_back.flags&ABSTRACT)) ? inventory_back : "<font color=grey>Empty</font>"]</A></td></tr>"
if(can_collar)
dat += "<tr><td>&nbsp;</td></tr>"
dat += "<tr><td><B>Collar:</B></td><td><A href='?src=[UID()];[collar?"remove_inv":"add_inv"]=collar'>[(collar && !(collar.flags&ABSTRACT)) ? collar : "<font color=grey>Empty</font>"]</A></td></tr>"
dat += "<tr><td><B>Collar:</B></td><td><A href='?src=[UID()];item=[slot_collar]'>[(collar && !(collar.flags&ABSTRACT)) ? collar : "<font color=grey>Empty</font>"]</A></td></tr>"
dat += {"</table>
<A href='?src=[user.UID()];mach_close=mob\ref[src]'>Close</A>
@@ -1,6 +1,5 @@
/mob/living/simple_animal/hostile
faction = list("hostile")
mouse_opacity = 2 //This makes it easier to hit hostile mobs, you only need to click on their tile, and is set back to 1 when they die
stop_automated_movement_when_pulled = 0
environment_smash = 1 //Set to 1 to break closets,tables,racks, etc; 2 for walls; 3 for rwalls
var/atom/target
@@ -13,7 +12,8 @@
var/list/friends = list()
var/ranged_message = "fires" //Fluff text for ranged mobs
var/ranged_cooldown = 0 //What the starting cooldown is on ranged attacks
var/ranged_cooldown_cap = 3 //What ranged attacks, after being used are set to, to go back on cooldown, defaults to 3 life() ticks
var/ranged_cooldown_time = 30 //How long, in deciseconds, the cooldown of ranged attacks is
var/ranged_ignores_vision = FALSE //if it'll fire ranged attacks even if it lacks vision on its target, only works with environment smash
var/check_friendly_fire = 0 // Should the ranged mob check for friendlies when shooting
var/retreat_distance = null //If our mob runs from players when they're too close, set in tile distance. By default, mobs do not retreat.
var/minimum_distance = 1 //Minimum approach distance, so ranged mobs chase targets down, but still keep their distance set in tiles to the target, set higher to make mobs keep distance
@@ -30,11 +30,33 @@
var/attack_same = 0 //Set us to 1 to allow us to attack our own faction, or 2, to only ever attack our own faction
var/AIStatus = AI_ON //The Status of our AI, can be set to AI_ON (On, usual processing), AI_IDLE (Will not process, but will return to AI_ON if an enemy comes near), AI_OFF (Off, Not processing ever)
//typecache of things this mob will attack in DestroySurroundings() if it has environment_smash
var/list/environment_target_typecache = list(
/obj/machinery/door/window,
/obj/structure/window,
/obj/structure/closet,
/obj/structure/table,
/obj/structure/grille,
/obj/structure/girder,
/obj/structure/rack,
/obj/structure/barricade) //turned into a typecache in New()
var/atom/targets_from = null //all range/attack/etc. calculations should be done from this atom, defaults to the mob itself, useful for Vehicles and such
var/list/emote_taunt = list()
var/taunt_chance = 0
/mob/living/simple_animal/hostile/New()
..()
if(!targets_from)
targets_from = src
environment_target_typecache = typecacheof(environment_target_typecache)
/mob/living/simple_animal/hostile/Destroy()
targets_from = null
return ..()
/mob/living/simple_animal/hostile/Life()
. = ..()
if(ranged)
ranged_cooldown--
if(!.)
walk(src, 0)
return 0
@@ -58,76 +80,89 @@
if(AIShouldSleep(possible_targets)) // we try to acquire a new one
AIStatus = AI_IDLE // otherwise we go idle
return 1
/mob/living/simple_animal/hostile/attacked_by(obj/item/I, mob/living/user)
if(stat == CONSCIOUS && !target && AIStatus != AI_OFF && !client && user)
FindTarget(list(user), 1)
return ..()
/mob/living/simple_animal/hostile/bullet_act(obj/item/projectile/P)
if(stat == CONSCIOUS && !target && AIStatus != AI_OFF && !client)
if(P.firer && get_dist(src, P.firer) <= aggro_vision_range)
FindTarget(list(P.firer), 1)
Goto(P.starting, move_to_delay, 3)
return ..()
//////////////HOSTILE MOB TARGETTING AND AGGRESSION////////////
/mob/living/simple_animal/hostile/proc/ListTargets()//Step 1, find out what we can see
var/list/L = list()
. = list()
if(!search_objects)
var/list/Mobs = hearers(vision_range, src) - src //Remove self, so we don't suicide
L += Mobs
for(var/obj/mecha/M in mechas_list)
if(get_dist(M, src) <= vision_range && can_see(src, M, vision_range))
L += M
for(var/obj/spacepod/S in spacepods_list)
if(get_dist(S, src) <= vision_range && can_see(src, S, vision_range))
L += S
var/list/Mobs = hearers(vision_range, targets_from) - src //Remove self, so we don't suicide
. += Mobs
var/static/hostile_machines = typecacheof(list(/obj/machinery/porta_turret, /obj/mecha, /obj/spacepod))
for(var/HM in typecache_filter_list(range(vision_range, targets_from), hostile_machines))
if(can_see(targets_from, HM, vision_range))
. += HM
else
var/list/Objects = oview(vision_range, src)
L += Objects
return L
var/list/Objects = oview(vision_range, targets_from)
. += Objects
/mob/living/simple_animal/hostile/proc/FindTarget(var/list/possible_targets, var/HasTargetsList = 0)//Step 2, filter down possible targets to things we actually care about
var/list/Targets = list()
. = list()
if(!HasTargetsList)
possible_targets = ListTargets()
for(var/atom/A in possible_targets)
for(var/pos_targ in possible_targets)
var/atom/A = pos_targ
if(Found(A))//Just in case people want to override targetting
Targets = list(A)
. = list(A)
break
if(CanAttack(A))//Can we attack it?
Targets += A
. += A
continue
var/Target = PickTarget(Targets)
var/Target = PickTarget(.)
GiveTarget(Target)
return Target //We now have a target
/mob/living/simple_animal/hostile/proc/PossibleThreats()
. = list()
for(var/pos_targ in ListTargets())
var/atom/A = pos_targ
if(Found(A))
. = list(A)
break
if(CanAttack(A))
. += A
continue
/mob/living/simple_animal/hostile/proc/Found(var/atom/A)//This is here as a potential override to pick a specific target if available
return
/mob/living/simple_animal/hostile/proc/PickTarget(var/list/Targets)//Step 3, pick amongst the possible, attackable targets
if(!Targets.len)//We didnt find nothin!
return
/mob/living/simple_animal/hostile/proc/PickTarget(list/Targets)//Step 3, pick amongst the possible, attackable targets
if(target != null)//If we already have a target, but are told to pick again, calculate the lowest distance between all possible, and pick from the lowest distance targets
for(var/atom/A in Targets)
var/target_dist = get_dist(src, target)
var/possible_target_distance = get_dist(src, A)
for(var/pos_targ in Targets)
var/atom/A = pos_targ
var/target_dist = get_dist(targets_from, target)
var/possible_target_distance = get_dist(targets_from, A)
if(target_dist < possible_target_distance)
Targets -= A
var/chosen_target = safepick(Targets)//Pick the remaining targets (if any) at random
if(!Targets.len)//We didnt find nothin!
return
var/chosen_target = pick(Targets)//Pick the remaining targets (if any) at random
return chosen_target
/mob/living/simple_animal/hostile/CanAttack(var/atom/the_target)//Can we actually attack a possible target?
if(!the_target)
return 0
if(see_invisible < the_target.invisibility)//Target's invisible to us, forget it
return 0
if(search_objects < 2)
if(istype(the_target, /obj/mecha))
var/obj/mecha/M = the_target
if(M.occupant)//Just so we don't attack empty mechs
if(CanAttack(M.occupant))
return 1
if(istype(the_target, /obj/spacepod))
var/obj/spacepod/S = the_target
if(S.pilot) //Just so we don't attack empty pods
if(CanAttack(S.pilot))
return 1
if(isliving(the_target))
var/mob/living/L = the_target
var/faction_check = 0
for(var/F in faction)
if(F in L.faction)
faction_check = 1
break
var/faction_check = faction_check(L)
if(robust_searching)
if(L.stat > stat_attack || L.stat != stat_attack && stat_exclusive == 1)
return 0
@@ -141,14 +176,42 @@
if(faction_check && !attack_same)
return 0
return 1
if(ishuman(the_target))
var/mob/living/carbon/human/H = the_target
if(is_type_in_list(src, H.species.ignored_by))
return 0
if(istype(the_target, /obj/mecha))
var/obj/mecha/M = the_target
if(M.occupant)//Just so we don't attack empty mechs
if(CanAttack(M.occupant))
return 1
if(istype(the_target, /obj/spacepod))
var/obj/spacepod/S = the_target
if(S.pilot) //Just so we don't attack empty pods
if(CanAttack(S.pilot))
return 1
if(istype(the_target, /obj/machinery/porta_turret))
var/obj/machinery/porta_turret/P = the_target
if(P.faction in faction)
return 0
if(!P.raised) //Don't attack invincible turrets
return 0
if(P.stat & BROKEN) //Or turrets that are already broken
return 0
return 1
if(isobj(the_target))
if(is_type_in_list(the_target, wanted_objects))
return 1
return 0
/mob/living/simple_animal/hostile/proc/GiveTarget(var/new_target)//Step 4, give us our selected target
/mob/living/simple_animal/hostile/proc/GiveTarget(new_target)//Step 4, give us our selected target
target = new_target
if(target != null)
Aggro()
return 1
/mob/living/simple_animal/hostile/proc/MoveToTarget(var/list/possible_targets)//Step 5, handle movement between us and our target
@@ -157,38 +220,45 @@
LoseTarget()
return 0
if(target in possible_targets)
var/target_distance = get_dist(src,target)
if(ranged)//We ranged? Shoot at em
if(target_distance >= 2 && ranged_cooldown <= 0)//But make sure they're a tile away at least, and our range attack is off cooldown
if(target.z != z)
LoseTarget()
return 0
var/target_distance = get_dist(targets_from,target)
if(ranged) //We ranged? Shoot at em
if(!target.Adjacent(targets_from) && ranged_cooldown <= world.time) //But make sure they're not in range for a melee attack and our range attack is off cooldown
OpenFire(target)
if(retreat_distance != null)//If we have a retreat distance, check if we need to run from our target
if(target_distance <= retreat_distance)//If target's closer than our retreat distance, run
if(retreat_distance != null) //If we have a retreat distance, check if we need to run from our target
if(target_distance <= retreat_distance) //If target's closer than our retreat distance, run
walk_away(src,target,retreat_distance,move_to_delay)
else
Goto(target,move_to_delay,minimum_distance)//Otherwise, get to our minimum distance so we chase them
Goto(target,move_to_delay,minimum_distance) //Otherwise, get to our minimum distance so we chase them
else
Goto(target,move_to_delay,minimum_distance)
if(isturf(loc) && target.Adjacent(src)) //If they're next to us, attack
AttackingTarget()
return 1
if(target)
if(targets_from && isturf(targets_from.loc) && target.Adjacent(targets_from)) //If they're next to us, attack
AttackingTarget()
return 1
return 0
if(environment_smash)
if(target.loc != null && get_dist(src, target.loc) <= vision_range)//We can't see our target, but he's in our vision range still
if(environment_smash >= 2)//If we're capable of smashing through walls, forget about vision completely after finding our target
if(target.loc != null && get_dist(targets_from, target.loc) <= vision_range) //We can't see our target, but he's in our vision range still
if(ranged_ignores_vision && ranged_cooldown <= world.time) //we can't see our target... but we can fire at them!
OpenFire(target)
if(environment_smash >= 2) //If we're capable of smashing through walls, forget about vision completely after finding our target
Goto(target,move_to_delay,minimum_distance)
FindHidden()
return 1
else
if(FindHidden())
return 1
LostTarget()
LoseTarget()
return 0
/mob/living/simple_animal/hostile/proc/Goto(var/target, var/delay, var/minimum_distance)
/mob/living/simple_animal/hostile/proc/Goto(target, delay, minimum_distance)
walk_to(src, target, minimum_distance, delay)
/mob/living/simple_animal/hostile/adjustHealth(damage)
..(damage)
if(!stat && search_objects < 3)//Not unconscious, and we don't ignore mobs
. = ..()
if(!ckey && !stat && search_objects < 3 && damage > 0)//Not unconscious, and we don't ignore mobs
if(search_objects)//Turn off item searching and ignore whatever item we were looking at, we're more concerned with fight or flight
search_objects = 0
target = null
@@ -203,101 +273,102 @@
/mob/living/simple_animal/hostile/proc/Aggro()
vision_range = aggro_vision_range
if(target && emote_taunt.len && prob(taunt_chance))
emote("me", 1, "[pick(emote_taunt)] at [target].")
taunt_chance = max(taunt_chance-7,2)
/mob/living/simple_animal/hostile/proc/LoseAggro()
stop_automated_movement = 0
vision_range = idle_vision_range
taunt_chance = initial(taunt_chance)
/mob/living/simple_animal/hostile/proc/LoseTarget()
target = null
walk(src, 0)
LoseAggro()
/mob/living/simple_animal/hostile/proc/LostTarget()
walk(src, 0)
LoseAggro()
//////////////END HOSTILE MOB TARGETTING AND AGGRESSION////////////
/mob/living/simple_animal/hostile/death(gibbed)
LoseAggro()
mouse_opacity = 1
..()
walk(src, 0)
LoseTarget()
..(gibbed)
/mob/living/simple_animal/hostile/proc/summon_backup(distance)
do_alert_animation(src)
playsound(loc, 'sound/machines/chime.ogg', 50, 1, -1)
for(var/mob/living/simple_animal/hostile/M in oview(distance, targets_from))
var/list/L = M.faction&faction
if(L.len)
if(M.AIStatus == AI_OFF)
return
else
M.Goto(src,M.move_to_delay,M.minimum_distance)
/mob/living/simple_animal/hostile/proc/OpenFire(var/the_target)
var/target = the_target
/mob/living/simple_animal/hostile/proc/OpenFire(atom/A)
if(check_friendly_fire)
for(var/turf/T in getline(src, target)) // Not 100% reliable but this is faster than simulating actual trajectory
for(var/turf/T in getline(src,A)) // Not 100% reliable but this is faster than simulating actual trajectory
for(var/mob/living/L in T)
if(L == src || L == target)
if(L == src || L == A)
continue
if(faction_check(L) && !attack_same)
return
visible_message("<span class='danger'><b>[src]</b> [ranged_message] at [target]!</span>")
visible_message("<span class='danger'><b>[src]</b> [ranged_message] at [A]!</span>")
if(rapid)
spawn(1)
Shoot(target, src.loc, src)
if(casingtype)
new casingtype(get_turf(src))
Shoot(A)
spawn(4)
Shoot(target, src.loc, src)
if(casingtype)
new casingtype(get_turf(src))
Shoot(A)
spawn(6)
Shoot(target, src.loc, src)
if(casingtype)
new casingtype(get_turf(src))
Shoot(A)
else
Shoot(target, src.loc, src)
if(casingtype)
new casingtype
ranged_cooldown = ranged_cooldown_cap
return
Shoot(A)
ranged_cooldown = world.time + ranged_cooldown_time
/mob/living/simple_animal/hostile/proc/Shoot(var/target, var/start, var/user, var/bullet = 0)
if(target == start)
/mob/living/simple_animal/hostile/proc/Shoot(atom/targeted_atom)
if(targeted_atom == targets_from.loc || targeted_atom == targets_from)
return
var/turf/startloc = get_turf(targets_from)
if(casingtype)
var/obj/item/ammo_casing/casing = new casingtype
var/obj/item/ammo_casing/casing = new casingtype(startloc)
playsound(src, projectilesound, 100, 1)
casing.fire(target, src, zone_override = ran_zone())
casing.loc = loc
else
var/obj/item/projectile/A = new projectiletype(loc)
playsound(user, projectilesound, 100, 1)
A.current = target
A.firer = src
A.yo = target:y - start:y
A.xo = target:x - start:x
if(AIStatus == AI_OFF)//Don't want mindless mobs to have their movement screwed up firing in space
newtonian_move(get_dir(target, user))
A.original = target
A.fire()
return A
casing.fire(targeted_atom, src, zone_override = ran_zone())
else if(projectiletype)
var/obj/item/projectile/P = new projectiletype(startloc)
playsound(src, projectilesound, 100, 1)
P.current = startloc
P.starting = startloc
P.firer = src
P.yo = targeted_atom.y - startloc.y
P.xo = targeted_atom.x - startloc.x
if(AIStatus != AI_ON)//Don't want mindless mobs to have their movement screwed up firing in space
newtonian_move(get_dir(targeted_atom, targets_from))
P.original = targeted_atom
P.fire()
return P
/mob/living/simple_animal/hostile/proc/DestroySurroundings()
if(environment_smash)
EscapeConfinement()
for(var/dir in cardinal)
var/turf/T = get_step(src, dir)
if(istype(T, /turf/simulated/wall) || istype(T, /turf/simulated/mineral))
if(T.Adjacent(src))
var/turf/T = get_step(targets_from, dir)
if(iswallturf(T) || ismineralturf(T))
if(T.Adjacent(targets_from))
T.attack_animal(src)
for(var/atom/A in T)
if(!A.Adjacent(src))
for(var/a in T)
var/atom/A = a
if(!A.Adjacent(targets_from))
continue
if(istype(A, /obj/structure/window) || istype(A, /obj/structure/closet) || istype(A, /obj/structure/table) || istype(A, /obj/structure/grille) || istype(A, /obj/structure/rack))
if(is_type_in_typecache(A, environment_target_typecache))
A.attack_animal(src)
return
/mob/living/simple_animal/hostile/proc/EscapeConfinement()
if(buckled)
buckled.attack_animal(src)
if(!isturf(src.loc) && src.loc != null)//Did someone put us in something?
var/atom/A = src.loc
if(!isturf(targets_from.loc) && targets_from.loc != null)//Did someone put us in something?
var/atom/A = get_turf(targets_from)
A.attack_animal(src)//Bang on it till we get out
return
@@ -305,12 +376,12 @@
if(istype(target.loc, /obj/structure/closet) || istype(target.loc, /obj/machinery/disposal) || istype(target.loc, /obj/machinery/sleeper) || istype(target.loc, /obj/machinery/bodyscanner) || istype(target.loc, /obj/machinery/recharge_station))
var/atom/A = target.loc
Goto(A,move_to_delay,minimum_distance)
if(A.Adjacent(src))
if(A.Adjacent(targets_from))
A.attack_animal(src)
return 1
/mob/living/simple_animal/hostile/RangedAttack(var/atom/A, var/params) //Player firing
if(ranged && ranged_cooldown <= 0)
/mob/living/simple_animal/hostile/RangedAttack(atom/A, params) //Player firing
if(ranged && ranged_cooldown <= world.time)
target = A
OpenFire(A)
..()
@@ -0,0 +1,393 @@
#define MEDAL_PREFIX "Bubblegum"
/*
BUBBLEGUM
Bubblegum spawns randomly wherever a lavaland creature is able to spawn. It is the most powerful slaughter demon in existence.
Bubblegum's footsteps are heralded by shaking booms, proving its tremendous size.
It acts as a melee creature, chasing down and attacking its target while also using different attacks to augment its power that increase as it takes damage.
It tries to strike at its target through any bloodpools under them; if it fails to do that, it will spray blood and then attempt to warp to a bloodpool near the target.
If it fails to warp to a target, it may summon up to 6 slaughterlings from the blood around it.
If it does not summon all 6 slaughterlings, it will instead charge at its target, dealing massive damage to anything it hits and spraying a stream of blood.
At half health, it will either charge three times or warp, then charge, instead of doing a single charge.
When Bubblegum dies, it leaves behind a chest that can contain three things:
1. A bottle that, when activated, drives everyone nearby into a frenzy
2. A contract that marks for death the chosen target
3. A spellblade that can slice off limbs at range
Difficulty: Hard
*/
/mob/living/simple_animal/hostile/megafauna/bubblegum
name = "bubblegum"
desc = "In what passes for a heirarchy among slaughter demons, this one is king."
health = 2500
maxHealth = 2500
attacktext = "rends"
attack_sound = 'sound/misc/demon_attack1.ogg'
icon_state = "bubblegum"
icon_living = "bubblegum"
icon_dead = ""
friendly = "stares down"
icon = 'icons/mob/lavaland/96x96megafauna.dmi'
speak_emote = list("gurgles")
armour_penetration = 40
melee_damage_lower = 40
melee_damage_upper = 40
speed = 1
move_to_delay = 10
ranged = 1
pixel_x = -32
del_on_death = 1
loot = list(/obj/structure/closet/crate/necropolis/bubblegum)
var/charging = 0
medal_type = MEDAL_PREFIX
score_type = BUBBLEGUM_SCORE
deathmessage = "sinks into a pool of blood, fleeing the battle. You've won, for now... "
death_sound = 'sound/misc/enter_blood.ogg'
/obj/item/device/gps/internal/bubblegum
icon_state = null
gpstag = "Bloody Signal"
desc = "You're not quite sure how a signal can be bloody."
invisibility = 100
/mob/living/simple_animal/hostile/megafauna/bubblegum/adjustBruteLoss(amount)
if(amount > 0 && prob(25))
var/obj/effect/decal/cleanable/blood/gibs/bubblegum/B = new /obj/effect/decal/cleanable/blood/gibs/bubblegum(loc)
if(prob(40))
step(B, pick(cardinal))
else
B.dir = pick(cardinal)
. = ..()
/obj/effect/decal/cleanable/blood/gibs/bubblegum
name = "thick blood"
desc = "Thick, splattered blood."
random_icon_states = list("gib3", "gib5", "gib6")
amount = 20
/obj/effect/decal/cleanable/blood/gibs/bubblegum/can_bloodcrawl_in()
return TRUE
/mob/living/simple_animal/hostile/megafauna/bubblegum/Life()
..()
move_to_delay = Clamp((health/maxHealth) * 10, 5, 10)
/mob/living/simple_animal/hostile/megafauna/bubblegum/OpenFire()
anger_modifier = Clamp(((maxHealth - health)/60),0,20)
if(charging)
return
ranged_cooldown = world.time + ranged_cooldown_time
var/warped = FALSE
if(!try_bloodattack())
spawn(0)
blood_spray()
warped = blood_warp()
if(warped && prob(100 - anger_modifier))
return
if(prob(90 - anger_modifier) || slaughterlings())
if(health > maxHealth * 0.5)
spawn(0)
charge()
else
if(prob(70) || warped)
spawn(0)
triple_charge()
else
spawn(0)
warp_charge()
/mob/living/simple_animal/hostile/megafauna/bubblegum/New()
..()
for(var/mob/living/simple_animal/hostile/megafauna/bubblegum/B in mob_list)
if(B != src)
qdel(src) //There can be only one
break
var/obj/effect/proc_holder/spell/bloodcrawl/bloodspell = new
AddSpell(bloodspell)
if(istype(loc, /obj/effect/dummy/slaughter))
bloodspell.phased = 1
internal_gps = new/obj/item/device/gps/internal/bubblegum(src)
/mob/living/simple_animal/hostile/megafauna/bubblegum/do_attack_animation(atom/A, visual_effect_icon)
if(!charging)
..()
/mob/living/simple_animal/hostile/megafauna/bubblegum/AttackingTarget()
if(!charging)
..()
/mob/living/simple_animal/hostile/megafauna/bubblegum/Goto(target, delay, minimum_distance)
if(!charging)
..()
/mob/living/simple_animal/hostile/megafauna/bubblegum/Move()
if(charging)
new /obj/effect/overlay/temp/decoy/fading(loc, src)
DestroySurroundings()
. = ..()
if(!stat && .)
playsound(src, 'sound/effects/meteorimpact.ogg', 200, 1, 2, 1)
if(charging)
DestroySurroundings()
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/warp_charge()
blood_warp()
charge()
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/triple_charge()
charge()
charge()
charge()
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/charge()
var/turf/T = get_turf(target)
if(!T || T == loc)
return
new /obj/effect/overlay/temp/dragon_swoop(T)
charging = 1
DestroySurroundings()
walk(src, 0)
dir = get_dir(src, T)
var/obj/effect/overlay/temp/decoy/D = new /obj/effect/overlay/temp/decoy(loc, src)
animate(D, alpha = 0, color = "#FF0000", transform = matrix()*2, time = 5)
sleep(5)
throw_at(T, get_dist(src, T), 1, src, 0)
charging = 0
try_bloodattack()
if(target)
Goto(target, move_to_delay, minimum_distance)
/mob/living/simple_animal/hostile/megafauna/bubblegum/Bump(atom/A)
if(charging)
if(isturf(A) || isobj(A) && A.density)
A.ex_act(2)
DestroySurroundings()
..()
/mob/living/simple_animal/hostile/megafauna/bubblegum/throw_impact(atom/A)
if(!charging)
return ..()
else if(isliving(A))
var/mob/living/L = A
L.visible_message("<span class='danger'>[src] slams into [L]!</span>", "<span class='userdanger'>[src] slams into you!</span>")
L.apply_damage(40, BRUTE)
playsound(get_turf(L), 'sound/effects/meteorimpact.ogg', 100, 1)
shake_camera(L, 4, 3)
shake_camera(src, 2, 3)
var/throwtarget = get_edge_target_turf(src, get_dir(src, get_step_away(L, src)))
L.throw_at_fast(throwtarget, 3)
charging = 0
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/get_mobs_on_blood()
var/list/targets = ListTargets()
. = list()
for(var/mob/living/L in targets)
var/list/bloodpool = get_pools(get_turf(L), 0)
if(bloodpool.len && (!faction_check(L) || L.stat == DEAD))
. += L
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/try_bloodattack()
var/list/targets = get_mobs_on_blood()
if(targets.len)
spawn(0)
bloodattack(targets, prob(50))
return TRUE
return FALSE
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/bloodattack(list/targets, handedness)
var/mob/living/target_one = pick_n_take(targets)
var/turf/target_one_turf = get_turf(target_one)
var/mob/living/target_two
if(targets.len)
target_two = pick_n_take(targets)
var/turf/target_two_turf = get_turf(target_two)
if(target_two.stat != CONSCIOUS || prob(10))
bloodgrab(target_two_turf, handedness)
else
bloodsmack(target_two_turf, handedness)
if(target_one)
var/list/pools = get_pools(get_turf(target_one), 0)
if(pools.len)
target_one_turf = get_turf(target_one)
if(target_one_turf)
if(target_one.stat != CONSCIOUS || prob(10))
bloodgrab(target_one_turf, !handedness)
else
bloodsmack(target_one_turf, !handedness)
if(!target_two && target_one)
var/list/poolstwo = get_pools(get_turf(target_one), 0)
if(poolstwo.len)
target_one_turf = get_turf(target_one)
if(target_one_turf)
if(target_one.stat != CONSCIOUS || prob(10))
bloodgrab(target_one_turf, handedness)
else
bloodsmack(target_one_turf, handedness)
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/bloodsmack(turf/T, handedness)
if(handedness)
new /obj/effect/overlay/temp/bubblegum_hands/rightsmack(T)
else
new /obj/effect/overlay/temp/bubblegum_hands/leftsmack(T)
sleep(2.5)
for(var/mob/living/L in T)
if(!faction_check(L))
to_chat(L, "<span class='userdanger'>[src] rends you!</span>")
playsound(T, attack_sound, 100, 1, -1)
var/limb_to_hit = pick("head", "chest", "r_arm", "l_arm", "r_leg", "l_leg")
L.apply_damage(25, BRUTE, limb_to_hit, L.run_armor_check(limb_to_hit, "melee", null, null, armour_penetration))
sleep(3)
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/bloodgrab(turf/T, handedness)
if(handedness)
new /obj/effect/overlay/temp/bubblegum_hands/rightpaw(T)
new /obj/effect/overlay/temp/bubblegum_hands/rightthumb(T)
else
new /obj/effect/overlay/temp/bubblegum_hands/leftpaw(T)
new /obj/effect/overlay/temp/bubblegum_hands/leftthumb(T)
sleep(6)
for(var/mob/living/L in T)
if(!faction_check(L))
to_chat(L, "<span class='userdanger'>[src] drags you through the blood!</span>")
playsound(T, 'sound/misc/enter_blood.ogg', 100, 1, -1)
var/turf/targetturf = get_step(src, dir)
L.forceMove(targetturf)
playsound(targetturf, 'sound/misc/exit_blood.ogg', 100, 1, -1)
if(L.stat != CONSCIOUS)
spawn(2)
devour(L)
sleep(1)
/obj/effect/overlay/temp/bubblegum_hands
icon = 'icons/effects/bubblegum.dmi'
duration = 9
/obj/effect/overlay/temp/bubblegum_hands/rightthumb
icon_state = "rightthumbgrab"
/obj/effect/overlay/temp/bubblegum_hands/leftthumb
icon_state = "leftthumbgrab"
/obj/effect/overlay/temp/bubblegum_hands/rightpaw
icon_state = "rightpawgrab"
layer = MOB_LAYER - 0.1
/obj/effect/overlay/temp/bubblegum_hands/leftpaw
icon_state = "leftpawgrab"
layer = MOB_LAYER - 0.1
/obj/effect/overlay/temp/bubblegum_hands/rightsmack
icon_state = "rightsmack"
/obj/effect/overlay/temp/bubblegum_hands/leftsmack
icon_state = "leftsmack"
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/blood_warp()
if(Adjacent(target))
return FALSE
var/list/can_jaunt = get_pools(get_turf(src), 1)
if(!can_jaunt.len)
return FALSE
var/list/pools = get_pools(get_turf(target), 2)
var/list/pools_to_remove = get_pools(get_turf(target), 1)
pools -= pools_to_remove
if(!pools.len)
return FALSE
var/obj/effect/overlay/temp/decoy/DA = new /obj/effect/overlay/temp/decoy(loc, src)
DA.color = "#FF0000"
var/oldtransform = DA.transform
DA.transform = matrix()*2
animate(DA, alpha = 255, color = initial(DA.color), transform = oldtransform, time = 5)
sleep(5)
qdel(DA)
var/obj/effect/decal/cleanable/blood/found_bloodpool
pools = get_pools(get_turf(target), 2)
pools_to_remove = get_pools(get_turf(target), 1)
pools -= pools_to_remove
if(pools.len)
shuffle(pools)
found_bloodpool = pick(pools)
if(found_bloodpool)
visible_message("<span class='danger'>[src] sinks into the blood...</span>")
playsound(get_turf(src), 'sound/misc/enter_blood.ogg', 100, 1, -1)
forceMove(get_turf(found_bloodpool))
playsound(get_turf(src), 'sound/misc/exit_blood.ogg', 100, 1, -1)
visible_message("<span class='danger'>And springs back out!</span>")
return TRUE
return FALSE
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/get_pools(turf/T, range)
. = list()
for(var/obj/effect/decal/cleanable/nearby in view(T, range))
if(nearby.can_bloodcrawl_in())
. += nearby
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/blood_spray()
visible_message("<span class='danger'>[src] sprays a stream of gore!</span>")
var/range = 6 + round(anger_modifier * 0.4)
var/turf/previousturf = get_turf(src)
var/turf/J = previousturf
var/targetdir = get_dir(src, target)
if(target.loc == loc)
targetdir = dir
face_atom(target)
new /obj/effect/decal/cleanable/blood/bubblegum(J)
for(var/i in 1 to range)
J = get_step(previousturf, targetdir)
new /obj/effect/overlay/temp/dir_setting/bloodsplatter(previousturf, get_dir(previousturf, J))
playsound(previousturf,'sound/effects/splat.ogg', 100, 1, -1)
if(!J || !previousturf.CanAtmosPass(J))
break
new /obj/effect/decal/cleanable/blood/bubblegum(J)
previousturf = J
sleep(1)
/obj/effect/decal/cleanable/blood/bubblegum
amount = 0
/obj/effect/decal/cleanable/blood/bubblegum/can_bloodcrawl_in()
return TRUE
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/slaughterlings()
visible_message("<span class='danger'>[src] summons a shoal of slaughterlings!</span>")
var/max_amount = 6
for(var/H in get_pools(get_turf(src), 1))
if(!max_amount)
break
max_amount--
var/obj/effect/decal/cleanable/blood/B = H
new /mob/living/simple_animal/hostile/asteroid/hivelordbrood/blood/slaughter(B.loc)
return max_amount
/mob/living/simple_animal/hostile/asteroid/hivelordbrood/blood/slaughter
name = "slaughterling"
desc = "Though not yet strong enough to create a true physical form, it's nonetheless determined to murder you."
density = 0
faction = list("mining", "boss")
weather_immunities = list("lava","ash")
/mob/living/simple_animal/hostile/asteroid/hivelordbrood/blood/slaughter/CanPass(atom/movable/mover, turf/target, height = 0)
if(istype(mover, /mob/living/simple_animal/hostile/megafauna/bubblegum))
return 1
return 0
#undef MEDAL_PREFIX
@@ -0,0 +1,266 @@
#define MEDAL_PREFIX "Colossus"
/*
COLOSSUS
The colossus spawns randomly wherever a lavaland creature is able to spawn. It is powerful, ancient, and extremely deadly.
The colossus has a degree of sentience, proving this in speech during its attacks.
It acts as a melee creature, chasing down and attacking its target while also using different attacks to augment its power that increase as it takes damage.
The colossus' true danger lies in its ranged capabilities. It fires immensely damaging death bolts that penetrate all armor in a variety of ways:
1. The colossus fires death bolts in alternating patterns: the cardinal directions and the diagonal directions.
2. The colossus fires death bolts in a shotgun-like pattern, instantly downing anything unfortunate enough to be hit by all of them.
3. The colossus fires a spiral of death bolts.
At 33% health, the colossus gains an additional attack:
4. The colossus fires two spirals of death bolts, spinning in opposite directions.
When a colossus dies, it leaves behind a chunk of glowing crystal known as a black box. Anything placed inside will carry over into future rounds.
For instance, you could place a bag of holding into the black box, and then kill another colossus next round and retrieve the bag of holding from inside.
Difficulty: Very Hard
*/
/mob/living/simple_animal/hostile/megafauna/colossus
name = "colossus"
desc = "A monstrous creature protected by heavy shielding."
health = 2500
maxHealth = 2500
attacktext = "judges"
attack_sound = 'sound/magic/ratvar_attack.ogg'
icon_state = "eva"
icon_living = "eva"
icon_dead = "dragon_dead"
friendly = "stares down"
icon = 'icons/mob/lavaland/96x96megafauna.dmi'
speak_emote = list("roars")
armour_penetration = 40
melee_damage_lower = 40
melee_damage_upper = 40
speed = 1
move_to_delay = 10
ranged = 1
pixel_x = -32
del_on_death = 1
medal_type = MEDAL_PREFIX
score_type = COLOSSUS_SCORE
loot = list(/obj/machinery/anomalous_crystal/random, /obj/item/organ/internal/vocal_cords/colossus)
butcher_results = list(/obj/item/weapon/ore/diamond = 5, /obj/item/stack/sheet/sinew = 5, /obj/item/stack/sheet/animalhide/ashdrake = 10, /obj/item/stack/sheet/bone = 30)
deathmessage = "disintegrates, leaving a glowing core in its wake."
death_sound = 'sound/misc/demon_dies.ogg'
/mob/living/simple_animal/hostile/megafauna/colossus/devour(mob/living/L)
visible_message("<span class='colossus'>[src] disintegrates [L]!</span>")
L.dust()
/mob/living/simple_animal/hostile/megafauna/colossus/OpenFire()
anger_modifier = Clamp(((maxHealth - health)/50),0,20)
ranged_cooldown = world.time + 120
if(enrage(target))
if(move_to_delay == initial(move_to_delay))
visible_message("<span class='colossus'>\"<b>You can't dodge.</b>\"</span>")
ranged_cooldown = world.time + 30
telegraph()
dir_shots(alldirs)
move_to_delay = 3
return
else
move_to_delay = initial(move_to_delay)
if(prob(20+anger_modifier)) //Major attack
telegraph()
if(health < maxHealth/3)
double_spiral()
else
visible_message("<span class='colossus'>\"<b>Judgement.</b>\"</span>")
spawn(0)
spiral_shoot(rand(0, 1))
else if(prob(20))
ranged_cooldown = world.time + 30
random_shots()
else
if(prob(70))
ranged_cooldown = world.time + 20
blast()
else
ranged_cooldown = world.time + 40
spawn(0)
alternating_dir_shots()
/mob/living/simple_animal/hostile/megafauna/colossus/New()
..()
internal_gps = new/obj/item/device/gps/internal/colossus(src)
/obj/effect/overlay/temp/at_shield
name = "anti-toolbox field"
desc = "A shimmering forcefield protecting the colossus."
icon = 'icons/effects/effects.dmi'
icon_state = "at_shield2"
layer = FLY_LAYER
luminosity = 2
duration = 8
var/target
/obj/effect/overlay/temp/at_shield/New(new_loc, new_target)
..()
target = new_target
spawn(0)
orbit(target, 0, FALSE, 0, 0, FALSE, TRUE)
/mob/living/simple_animal/hostile/megafauna/colossus/bullet_act(obj/item/projectile/P)
if(!stat)
var/obj/effect/overlay/temp/at_shield/AT = new /obj/effect/overlay/temp/at_shield(loc, src)
var/random_x = rand(-32, 32)
AT.pixel_x += random_x
var/random_y = rand(0, 72)
AT.pixel_y += random_y
..()
/mob/living/simple_animal/hostile/megafauna/colossus/proc/enrage(mob/living/L)
if(ishuman(L))
var/mob/living/carbon/human/H = L
if(H.martial_art && prob(H.martial_art.deflection_chance))
. = TRUE
/mob/living/simple_animal/hostile/megafauna/colossus/proc/alternating_dir_shots()
dir_shots(diagonals)
sleep(10)
dir_shots(cardinal)
sleep(10)
dir_shots(diagonals)
sleep(10)
dir_shots(cardinal)
/mob/living/simple_animal/hostile/megafauna/colossus/proc/double_spiral()
visible_message("<span class='colossus'>\"<b>Die.</b>\"</span>")
sleep(10)
spawn(0)
spiral_shoot()
spawn(0)
spiral_shoot(1)
/mob/living/simple_animal/hostile/megafauna/colossus/proc/spiral_shoot(negative = 0, counter_start = 1)
var/counter = counter_start
var/turf/marker
for(var/i in 1 to 80)
switch(counter)
if(1)
marker = locate(x, y - 2, z)
if(2)
marker = locate(x - 1, y - 2, z)
if(3)
marker = locate(x - 2, y - 2, z)
if(4)
marker = locate(x - 2, y - 1, z)
if(5)
marker = locate(x - 2, y, z)
if(6)
marker = locate(x - 2, y + 1, z)
if(7)
marker = locate(x - 2, y + 2, z)
if(8)
marker = locate(x - 1, y + 2, z)
if(9)
marker = locate(x, y + 2, z)
if(10)
marker = locate(x + 1, y + 2, z)
if(11)
marker = locate(x + 2, y + 2, z)
if(12)
marker = locate(x + 2, y + 1, z)
if(13)
marker = locate(x + 2, y, z)
if(14)
marker = locate(x + 2, y - 1, z)
if(15)
marker = locate(x + 2, y - 2, z)
if(16)
marker = locate(x + 1, y - 2, z)
if(negative)
counter--
else
counter++
if(counter > 16)
counter = 1
if(counter < 1)
counter = 16
shoot_projectile(marker)
playsound(get_turf(src), 'sound/magic/invoke_general.ogg', 20, 1)
sleep(1)
/mob/living/simple_animal/hostile/megafauna/colossus/proc/shoot_projectile(turf/marker)
if(!marker || marker == loc)
return
var/turf/startloc = get_turf(src)
var/obj/item/projectile/P = new /obj/item/projectile/colossus(startloc)
P.current = startloc
P.starting = startloc
P.firer = src
P.yo = marker.y - startloc.y
P.xo = marker.x - startloc.x
if(target)
P.original = target
else
P.original = marker
P.fire()
/mob/living/simple_animal/hostile/megafauna/colossus/proc/random_shots()
var/turf/U = get_turf(src)
playsound(U, 'sound/magic/invoke_general.ogg', 300, 1, 5)
for(var/T in RANGE_TURFS(12, U) - U)
if(prob(5))
shoot_projectile(T)
/mob/living/simple_animal/hostile/megafauna/colossus/proc/blast()
playsound(get_turf(src), 'sound/magic/invoke_general.ogg', 200, 1, 2)
var/turf/T = get_turf(target)
newtonian_move(get_dir(T, targets_from))
for(var/turf/turf in range(1, T))
shoot_projectile(turf)
/mob/living/simple_animal/hostile/megafauna/colossus/proc/dir_shots(list/dirs)
if(!islist(dirs))
dirs = alldirs.Copy()
playsound(get_turf(src), 'sound/magic/invoke_general.ogg', 200, 1, 2)
for(var/d in dirs)
var/turf/E = get_step(src, d)
shoot_projectile(E)
/mob/living/simple_animal/hostile/megafauna/colossus/proc/telegraph()
for(var/mob/M in range(10,src))
if(M.client)
flash_color(M.client, rgb(200, 0, 0), 1)
shake_camera(M, 4, 3)
playsound(get_turf(src),'sound/magic/narsie_attack.ogg', 200, 1)
/obj/item/projectile/colossus
name ="death bolt"
icon_state= "chronobolt"
damage = 25
armour_penetration = 100
speed = 2
eyeblur = 0
damage_type = BRUTE
pass_flags = PASSTABLE
/obj/item/projectile/colossus/on_hit(atom/target, blocked = 0)
. = ..()
if(isturf(target) || isobj(target))
target.ex_act(2)
/obj/item/device/gps/internal/colossus
icon_state = null
gpstag = "Angelic Signal"
desc = "Get in the fucking robot."
invisibility = 100
#undef MEDAL_PREFIX
@@ -0,0 +1,278 @@
#define MEDAL_PREFIX "Drake"
/*
ASH DRAKE
Ash drakes spawn randomly wherever a lavaland creature is able to spawn. They are the draconic guardians of the Necropolis.
It acts as a melee creature, chasing down and attacking its target while also using different attacks to augment its power that increase as it takes damage.
Whenever possible, the drake will breathe fire in the four cardinal directions, igniting and heavily damaging anything caught in the blast.
It also often causes fire to rain from the sky - many nearby turfs will flash red as a fireball crashes into them, dealing damage to anything on the turfs.
The drake also utilizes its wings to fly into the sky and crash down onto a specified point. Anything on this point takes tremendous damage.
- Sometimes it will chain these swooping attacks over and over, making swiftness a necessity.
When an ash drake dies, it leaves behind a chest that can contain four things:
1. A spectral blade that allows its wielder to call ghosts to it, enhancing its power
2. A lava staff that allows its wielder to create lava
3. A spellbook and wand of fireballs
4. A bottle of dragon's blood with several effects, including turning its imbiber into a drake themselves.
When butchered, they leave behind diamonds, sinew, bone, and ash drake hide. Ash drake hide can be used to create a hooded cloak that protects its wearer from ash storms.
Difficulty: Medium
*/
/mob/living/simple_animal/hostile/megafauna/dragon
name = "ash drake"
desc = "Guardians of the necropolis."
health = 2500
maxHealth = 2500
attacktext = "chomps"
attack_sound = 'sound/misc/demon_attack1.ogg'
icon_state = "dragon"
icon_living = "dragon"
icon_dead = "dragon_dead"
friendly = "stares down"
icon = 'icons/mob/lavaland/dragon.dmi'
speak_emote = list("roars")
armour_penetration = 40
melee_damage_lower = 40
melee_damage_upper = 40
speed = 1
move_to_delay = 10
ranged = 1
pixel_x = -16
loot = list(/obj/structure/closet/crate/necropolis/dragon)
butcher_results = list(/obj/item/weapon/ore/diamond = 5, /obj/item/stack/sheet/sinew = 5, /obj/item/stack/sheet/animalhide/ashdrake = 10, /obj/item/stack/sheet/bone = 30)
var/swooping = 0
var/swoop_cooldown = 0
medal_type = MEDAL_PREFIX
score_type = DRAKE_SCORE
deathmessage = "collapses into a pile of bones, its flesh sloughing away."
death_sound = 'sound/misc/demon_dies.ogg'
/mob/living/simple_animal/hostile/megafauna/dragon/New()
..()
internal_gps = new/obj/item/device/gps/internal/dragon(src)
/mob/living/simple_animal/hostile/megafauna/dragon/ex_act(severity, target)
if(severity == 3)
return
..()
/mob/living/simple_animal/hostile/megafauna/dragon/adjustHealth(amount)
if(swooping)
return 0
return ..()
/mob/living/simple_animal/hostile/megafauna/dragon/AttackingTarget()
if(!swooping)
..()
/mob/living/simple_animal/hostile/megafauna/dragon/DestroySurroundings()
if(!swooping)
..()
/mob/living/simple_animal/hostile/megafauna/dragon/Move()
if(!swooping)
..()
/mob/living/simple_animal/hostile/megafauna/dragon/Goto(target, delay, minimum_distance)
if(!swooping)
..()
/mob/living/simple_animal/hostile/megafauna/dragon/Process_Spacemove(movement_dir = 0)
return 1
/obj/effect/overlay/temp/fireball
icon = 'icons/obj/wizard.dmi'
icon_state = "fireball"
name = "fireball"
desc = "Get out of the way!"
layer = 6
randomdir = 0
duration = 12
pixel_z = 500
/obj/effect/overlay/temp/fireball/New(loc)
..()
animate(src, pixel_z = 0, time = 12)
/obj/effect/overlay/temp/target
icon = 'icons/mob/actions.dmi'
icon_state = "sniper_zoom"
layer = MOB_LAYER - 0.1
luminosity = 2
duration = 12
/obj/effect/overlay/temp/dragon_swoop
name = "certain death"
desc = "Don't just stand there, move!"
icon = 'icons/effects/96x96.dmi'
icon_state = "landing"
layer = MOB_LAYER - 0.1
pixel_x = -32
pixel_y = -32
color = "#FF0000"
duration = 10
/obj/effect/overlay/temp/target/ex_act()
return
/obj/effect/overlay/temp/target/New(loc)
..()
spawn(0)
fall()
/obj/effect/overlay/temp/target/proc/fall()
var/turf/T = get_turf(src)
playsound(T,'sound/magic/Fireball.ogg', 200, 1)
new /obj/effect/overlay/temp/fireball(T)
sleep(12)
explosion(T, 0, 0, 1, 0, 0, 0, 1)
/mob/living/simple_animal/hostile/megafauna/dragon/OpenFire()
anger_modifier = Clamp(((maxHealth - health)/50),0,20)
ranged_cooldown = world.time + ranged_cooldown_time
if(swooping)
fire_rain()
return
if(prob(15 + anger_modifier) && !client)
if(health < maxHealth/2)
spawn(0)
swoop_attack(1)
else
fire_rain()
else if(prob(10+anger_modifier) && !client)
if(health > maxHealth/2)
spawn(0)
swoop_attack(0)
else
spawn(0)
triple_swoop(0)
else
fire_walls()
/mob/living/simple_animal/hostile/megafauna/dragon/proc/fire_rain()
visible_message("<span class='boldwarning'>Fire rains from the sky!</span>")
for(var/turf/turf in range(12,get_turf(src)))
if(prob(10))
new /obj/effect/overlay/temp/target(turf)
/mob/living/simple_animal/hostile/megafauna/dragon/proc/fire_walls()
playsound(get_turf(src),'sound/magic/Fireball.ogg', 200, 1)
for(var/d in cardinal)
spawn(0)
fire_wall(d)
/mob/living/simple_animal/hostile/megafauna/dragon/proc/fire_wall(dir)
var/list/hit_things = list(src)
var/turf/E = get_edge_target_turf(src, dir)
var/range = 10
var/turf/previousturf = get_turf(src)
for(var/turf/J in getline(src,E))
if(!range || !previousturf.CanAtmosPass(J))
break
range--
new /obj/effect/hotspot(J)
J.hotspot_expose(700,50,1)
for(var/mob/living/L in J.contents - hit_things)
L.adjustFireLoss(20)
to_chat(L, "<span class='userdanger'>You're hit by the drake's fire breath!</span>")
hit_things += L
previousturf = J
sleep(1)
/mob/living/simple_animal/hostile/megafauna/dragon/proc/triple_swoop()
swoop_attack()
swoop_attack()
swoop_attack()
/mob/living/simple_animal/hostile/megafauna/dragon/proc/swoop_attack(fire_rain = 0, atom/movable/manual_target)
if(stat || swooping)
return
swoop_cooldown = world.time + 200
var/atom/swoop_target
if(manual_target)
swoop_target = manual_target
else
swoop_target = target
stop_automated_movement = TRUE
swooping = 1
density = 0
icon_state = "swoop"
visible_message("<span class='boldwarning'>[src] swoops up high!</span>")
if(prob(50))
animate(src, pixel_x = 500, pixel_z = 500, time = 10)
else
animate(src, pixel_x = -500, pixel_z = 500, time = 10)
sleep(30)
var/turf/tturf
if(fire_rain)
fire_rain()
icon_state = "dragon"
if(swoop_target && !qdeleted(swoop_target) && swoop_target.z == src.z)
tturf = get_turf(swoop_target)
else
tturf = get_turf(src)
forceMove(tturf)
new /obj/effect/overlay/temp/dragon_swoop(tturf)
animate(src, pixel_x = initial(pixel_x), pixel_z = 0, time = 10)
sleep(10)
playsound(src.loc, 'sound/effects/meteorimpact.ogg', 200, 1)
for(var/mob/living/L in orange(1, src))
if(L.stat)
visible_message("<span class='warning'>[src] slams down on [L], crushing them!</span>")
L.gib()
else
L.adjustBruteLoss(75)
if(L && !qdeleted(L)) // Some mobs are deleted on death
var/throw_dir = get_dir(src, L)
if(L.loc == loc)
throw_dir = pick(alldirs)
var/throwtarget = get_edge_target_turf(src, throw_dir)
L.throw_at_fast(throwtarget, 3)
visible_message("<span class='warning'>[L] is thrown clear of [src]!</span>")
for(var/mob/M in range(7, src))
shake_camera(M, 15, 1)
stop_automated_movement = FALSE
swooping = 0
density = 1
/mob/living/simple_animal/hostile/megafauna/dragon/AltClickOn(atom/movable/A)
if(!istype(A))
return
if(swoop_cooldown >= world.time)
to_chat(src, "<span class='warning'>You need to wait 20 seconds between swoop attacks!</span>")
return
swoop_attack(1, A)
/obj/item/device/gps/internal/dragon
icon_state = null
gpstag = "Fiery Signal"
desc = "Here there be dragons."
invisibility = 100
/mob/living/simple_animal/hostile/megafauna/dragon/lesser
name = "lesser ash drake"
maxHealth = 200
health = 200
faction = list("neutral")
melee_damage_upper = 30
melee_damage_lower = 30
damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 1, CLONE = 1, STAMINA = 0, OXY = 1)
loot = list()
/mob/living/simple_animal/hostile/megafauna/dragon/lesser/grant_achievement(medaltype,scoretype)
return
#undef MEDAL_PREFIX
@@ -0,0 +1,611 @@
#define MEDAL_PREFIX "Hierophant"
/*
The Hierophant
The Hierophant spawns in its arena, an area designed to make it harder to fight than it would otherwise be.
The text this boss speaks is ROT4, use ROT22 to decode
The Hierophant's attacks are as follows, and INTENSIFY at a random chance based on Hierophant's health;
- Creates a cardinal or diagonal blast(Cross Blast) under its target, exploding after a short time.
INTENSITY EFFECT: Creates one of the cross blast types under itself instead of under the target.
INTENSITY EFFECT: The created Cross Blast fires in all directions if below half health.
- If no chasers exist, creates a chaser that will seek its target, leaving a trail of blasts.
INTENSITY EFFECT: Creates a second, slower chaser.
- Creates an expanding AoE burst.
- INTENSE ATTACKS:
If target is at least 2 tiles away; Blinks to the target after a very brief delay, damaging everything near the start and end points.
As above, but does so multiple times if below half health.
Rapidly creates Cross Blasts under a target.
If chasers are off cooldown, creates four high-speed chasers.
- IF TARGET WAS STRUCK IN MELEE: Creates a 3x3 square of blasts under the target.
Cross Blasts and the AoE burst gain additional range as the Hierophant loses health, while Chasers gain additional speed.
When The Hierophant dies, it leaves behind its staff, which, while much weaker than when wielded by The Hierophant itself, is still quite effective.
- The staff can place a teleport rune, allowing the user to teleport themself and their allies to the rune.
Difficulty: Hard
*/
/mob/living/simple_animal/hostile/megafauna/hierophant
name = "Hierophant"
desc = "An ancient, powerful priest-like being wielding a mighty staff."
health = 2500
maxHealth = 2500
attacktext = "clubs"
//attack_sound = 'sound/weapons/sonic_jackhammer.ogg'
attack_sound = "swing_hit"
icon_state = "hierophant"
icon_living = "hierophant"
friendly = "stares down"
icon = 'icons/mob/lavaland/hierophant.dmi'
faction = list("boss") //asteroid mobs? get that shit out of my beautiful square house
speak_emote = list("preaches")
armour_penetration = 50
melee_damage_lower = 10
melee_damage_upper = 10
speed = 1
move_to_delay = 10
ranged = 1
pixel_x = -16
ranged_cooldown_time = 40
aggro_vision_range = 23
loot = list(/obj/item/weapon/hierophant_staff)
wander = FALSE
var/burst_range = 3 //range on burst aoe
var/beam_range = 5 //range on cross blast beams
var/chaser_speed = 3 //how fast chasers are currently
var/chaser_cooldown = 101 //base cooldown/cooldown var between spawning chasers
var/major_attack_cooldown = 60 //base cooldown for major attacks
var/blinking = FALSE //if we're doing something that requires us to stand still and not attack
var/obj/effect/hierophant/spawned_rune //the rune we teleport back to
var/timeout_time = 15 //after this many Life() ticks with no target, we return to our rune
var/did_reset = TRUE //if we timed out, returned to our rune, and healed some
//var/list/kill_phrases = list("Wsyvgi sj irivkc xettih. Vitemvmrk...", "Irivkc wsyvgi jsyrh. Vitemvmrk...", "Jyip jsyrh. Egxmzexmrk vitemv gcgpiw...")
//var/list/target_phrases = list("Xevkix psgexih.", "Iriqc jsyrh.", "Eguymvih xevkix.")
medal_type = MEDAL_PREFIX
score_type = BIRD_SCORE
del_on_death = TRUE
death_sound = 'sound/magic/Repulse.ogg'
/mob/living/simple_animal/hostile/megafauna/hierophant/New()
..()
internal_gps = new/obj/item/device/gps/internal/hierophant(src)
spawned_rune = new(loc)
/mob/living/simple_animal/hostile/megafauna/hierophant/Life()
. = ..()
if(. && spawned_rune && !client)
if(target || loc == spawned_rune.loc)
timeout_time = initial(timeout_time)
else
timeout_time--
if(timeout_time <= 0 && !did_reset)
did_reset = TRUE
//visible_message("<span class='hierophant'>\"Vixyvrmrk xs fewi...\"</span>")
blink(spawned_rune)
adjustHealth(min((health - maxHealth) * 0.5, -50)) //heal for 50% of our missing health
wander = FALSE
/*if(health > maxHealth * 0.9)
visible_message("<span class='hierophant'>\"Vitemvw gsqtpixi. Stivexmrk ex qebmqyq ijjmgmirgc.\"</span>")
else
visible_message("<span class='hierophant'>\"Vitemvw gsqtpixi. Stivexmsrep ijjmgmirgc gsqtvsqmwih.\"</span>")*/
/mob/living/simple_animal/hostile/megafauna/hierophant/death()
if(health > 0 || stat == DEAD)
return
else
stat = DEAD
blinking = TRUE //we do a fancy animation, release a huge burst(), and leave our staff.
animate(src, alpha = 0, color = "660099", time = 20, easing = EASE_OUT)
burst_range = 10
//visible_message("<span class='hierophant'>\"Mrmxmexmrk wipj-hiwxvygx wiuyirgi...\"</span>")
visible_message("<span class='hierophant_warning'>[src] disappears in a massive burst of magic, leaving only its staff.</span>")
burst(get_turf(src))
..()
/mob/living/simple_animal/hostile/megafauna/hierophant/Destroy()
qdel(spawned_rune)
. = ..()
/mob/living/simple_animal/hostile/megafauna/hierophant/devour(mob/living/L)
for(var/obj/item/W in L)
if(!L.unEquip(W))
qdel(W)
/*visible_message(
"<span class='hierophant'>\"[pick(kill_phrases)]\"</span>\n<span class='hierophant_warning'>[src] annihilates [L]!</span>",
"<span class='userdanger'>You annihilate [L], restoring your health!</span>")*/
visible_message(
"<span class='hierophant'>\"Caw.\"</span>\n<span class='hierophant_warning'>[src] annihilates [L]!</span>",
"<span class='userdanger'>You annihilate [L], restoring your health!</span>")
adjustHealth(-L.maxHealth*0.5)
L.dust()
/*/mob/living/simple_animal/hostile/megafauna/hierophant/GiveTarget(new_target)
var/targets_the_same = (new_target == target)
. = ..()
if(. && target && !targets_the_same)
visible_message("<span class='hierophant'>\"[pick(target_phrases)]\"</span>")*/
/mob/living/simple_animal/hostile/megafauna/hierophant/adjustHealth(amount)
. = ..()
if(src && amount > 0 && !blinking)
wander = TRUE
did_reset = FALSE
/mob/living/simple_animal/hostile/megafauna/hierophant/AttackingTarget()
if(!blinking)
if(target && isliving(target))
spawn(0)
melee_blast(get_turf(target)) //melee attacks on living mobs produce a 3x3 blast
..()
/mob/living/simple_animal/hostile/megafauna/hierophant/DestroySurroundings()
if(!blinking)
..()
/mob/living/simple_animal/hostile/megafauna/hierophant/Move()
if(!blinking)
/*if(!stat)
playsound(loc, 'sound/mecha/mechmove04.ogg', 150, 1, -4)*/
..()
/mob/living/simple_animal/hostile/megafauna/hierophant/Goto(target, delay, minimum_distance)
wander = TRUE
if(!blinking)
..()
/mob/living/simple_animal/hostile/megafauna/hierophant/proc/calculate_rage() //how angry we are overall
did_reset = FALSE //oh hey we're doing SOMETHING, clearly we might need to heal if we recall
anger_modifier = Clamp(((maxHealth - health) / 42),0,50)
burst_range = initial(burst_range) + round(anger_modifier * 0.08)
beam_range = initial(beam_range) + round(anger_modifier * 0.12)
/mob/living/simple_animal/hostile/megafauna/hierophant/OpenFire()
calculate_rage()
var/target_is_slow = FALSE
if(isliving(target))
var/mob/living/L = target
if(!blinking && L.stat == DEAD && get_dist(src, L) > 2)
blink(L)
return
if(L.movement_delay() > 1.5)
target_is_slow = TRUE
chaser_speed = max(1, (3 - anger_modifier * 0.04) + target_is_slow * 0.5)
if(blinking)
return
ranged_cooldown = world.time + max(5, ranged_cooldown_time - anger_modifier * 0.75) //scale cooldown lower with high anger.
if(prob(anger_modifier * 0.75)) //major ranged attack
var/list/possibilities = list()
var/cross_counter = 1 + round(anger_modifier * 0.12)
if(cross_counter > 1)
possibilities += "cross_blast_spam"
if(get_dist(src, target) > 2)
possibilities += "blink_spam"
if(chaser_cooldown < world.time)
if(prob(anger_modifier * 2))
possibilities = list("chaser_swarm")
else
possibilities += "chaser_swarm"
if(possibilities.len)
ranged_cooldown = world.time + max(5, major_attack_cooldown - anger_modifier * 0.75) //we didn't cancel out of an attack, use the higher cooldown
var/blink_counter = 1 + round(anger_modifier * 0.08)
switch(pick(possibilities))
if("blink_spam") //blink either once or multiple times.
if(health < maxHealth * 0.5 && !target_is_slow && blink_counter > 1)
//visible_message("<span class='hierophant'>\"Mx ampp rsx iwgeti.\"</span>")
animate(src, color = "#660099", time = 6)
while(health && target && blink_counter)
if(loc == target.loc || loc == target) //we're on the same tile as them after about a second we can stop now
break
blink_counter--
blinking = FALSE
blink(target)
blinking = TRUE
sleep(5)
animate(src, color = initial(color), time = 8)
sleep(8)
blinking = FALSE
else
blink(target)
if("cross_blast_spam") //fire a lot of cross blasts at a target.
//visible_message("<span class='hierophant'>\"Piezi mx rsalivi xs vyr.\"</span>")
blinking = TRUE
animate(src, color = "#660099", time = 6)
while(health && target && cross_counter)
cross_counter--
var/delay = 6
if(prob(60))
spawn(0)
cardinal_blasts(target)
else
spawn(0)
diagonal_blasts(target)
delay = 5 //this one isn't so mean, so do the next one faster(if there is one)
sleep(delay)
animate(src, color = initial(color), time = 8)
sleep(8)
blinking = FALSE
if("chaser_swarm") //fire four fucking chasers at a target and their friends.
//visible_message("<span class='hierophant'>\"Mx gerrsx lmhi.\"</span>")
blinking = TRUE
animate(src, color = "#660099", time = 10)
var/list/targets = ListTargets()
var/list/cardinal_copy = cardinal.Copy()
while(health && targets.len && cardinal_copy.len)
var/mob/living/pickedtarget = pick(targets)
if(targets.len > 4)
pickedtarget = pick_n_take(targets)
if(pickedtarget.stat == DEAD)
pickedtarget = target
var/obj/effect/overlay/temp/hierophant/chaser/C = new /obj/effect/overlay/temp/hierophant/chaser(loc, src, pickedtarget, chaser_speed, FALSE)
C.moving = 3
C.moving_dir = pick_n_take(cardinal_copy)
sleep(10)
chaser_cooldown = world.time + initial(chaser_cooldown)
animate(src, color = initial(color), time = 8)
sleep(8)
blinking = FALSE
return
if(prob(10 + (anger_modifier * 0.5)) && get_dist(src, target) > 2)
blink(target)
else if(prob(70 - anger_modifier)) //a cross blast of some type
if(prob(anger_modifier)) //at us?
if(prob(anger_modifier * 2) && health < maxHealth * 0.5) //we're super angry do it at all dirs
spawn(0)
alldir_blasts(src)
else if(prob(60))
spawn(0)
cardinal_blasts(src)
else
spawn(0)
diagonal_blasts(src)
else //at them?
if(prob(anger_modifier * 2) && health < maxHealth * 0.5 && !target_is_slow) //we're super angry do it at all dirs
spawn(0)
alldir_blasts(target)
else if(prob(60))
spawn(0)
cardinal_blasts(target)
else
spawn(0)
diagonal_blasts(target)
else if(chaser_cooldown < world.time) //if chasers are off cooldown, fire some!
var/obj/effect/overlay/temp/hierophant/chaser/C = new /obj/effect/overlay/temp/hierophant/chaser(loc, src, target, chaser_speed, FALSE)
chaser_cooldown = world.time + initial(chaser_cooldown)
if((prob(anger_modifier) || target.Adjacent(src)) && target != src)
var/obj/effect/overlay/temp/hierophant/chaser/OC = new /obj/effect/overlay/temp/hierophant/chaser(loc, src, target, max(1.5, 5 - anger_modifier * 0.07), FALSE)
OC.moving = 4
OC.moving_dir = pick(cardinal - C.moving_dir)
else //just release a burst of power
spawn(0)
burst(get_turf(src))
/mob/living/simple_animal/hostile/megafauna/hierophant/proc/diagonal_blasts(mob/victim) //fire diagonal cross blasts with a delay
var/turf/T = get_turf(victim)
if(!T)
return
new /obj/effect/overlay/temp/hierophant/telegraph/diagonal(T, src)
playsound(T,'sound/magic/blink.ogg', 200, 1)
//playsound(T,'sound/effects/bin_close.ogg', 200, 1)
sleep(2)
new /obj/effect/overlay/temp/hierophant/blast(T, src, FALSE)
for(var/d in diagonals)
spawn(0)
blast_wall(T, d)
/mob/living/simple_animal/hostile/megafauna/hierophant/proc/cardinal_blasts(mob/victim) //fire cardinal cross blasts with a delay
var/turf/T = get_turf(victim)
if(!T)
return
new /obj/effect/overlay/temp/hierophant/telegraph/cardinal(T, src)
playsound(T,'sound/magic/blink.ogg', 200, 1)
//playsound(T,'sound/effects/bin_close.ogg', 200, 1)
sleep(2)
new /obj/effect/overlay/temp/hierophant/blast(T, src, FALSE)
for(var/d in cardinal)
spawn(0)
blast_wall(T, d)
/mob/living/simple_animal/hostile/megafauna/hierophant/proc/alldir_blasts(mob/victim) //fire alldir cross blasts with a delay
var/turf/T = get_turf(victim)
if(!T)
return
new /obj/effect/overlay/temp/hierophant/telegraph(T, src)
playsound(T,'sound/magic/blink.ogg', 200, 1)
//playsound(T,'sound/effects/bin_close.ogg', 200, 1)
sleep(2)
new /obj/effect/overlay/temp/hierophant/blast(T, src, FALSE)
for(var/d in alldirs)
spawn(0)
blast_wall(T, d)
/mob/living/simple_animal/hostile/megafauna/hierophant/proc/blast_wall(turf/T, dir) //make a wall of blasts beam_range tiles long
var/range = beam_range
var/turf/previousturf = T
var/turf/J = get_step(previousturf, dir)
for(var/i in 1 to range)
new /obj/effect/overlay/temp/hierophant/blast(J, src, FALSE)
previousturf = J
J = get_step(previousturf, dir)
/mob/living/simple_animal/hostile/megafauna/hierophant/proc/blink(mob/victim) //blink to a target
if(blinking || !victim)
return
var/turf/T = get_turf(victim)
var/turf/source = get_turf(src)
new /obj/effect/overlay/temp/hierophant/telegraph(T, src)
new /obj/effect/overlay/temp/hierophant/telegraph(source, src)
playsound(T,'sound/magic/blink.ogg', 200, 1)
//playsound(T,'sound/magic/Wand_Teleport.ogg', 200, 1)
playsound(source,'sound/magic/blink.ogg', 200, 1)
//playsound(source,'sound/machines/AirlockOpen.ogg', 200, 1)
blinking = TRUE
sleep(2) //short delay before we start...
new /obj/effect/overlay/temp/hierophant/telegraph/teleport(T, src)
new /obj/effect/overlay/temp/hierophant/telegraph/teleport(source, src)
for(var/t in RANGE_TURFS(1, T))
var/obj/effect/overlay/temp/hierophant/blast/B = new /obj/effect/overlay/temp/hierophant/blast(t, src, FALSE)
B.damage = 30
for(var/t in RANGE_TURFS(1, source))
var/obj/effect/overlay/temp/hierophant/blast/B = new /obj/effect/overlay/temp/hierophant/blast(t, src, FALSE)
B.damage = 30
animate(src, alpha = 0, time = 2, easing = EASE_OUT) //fade out
sleep(1)
visible_message("<span class='hierophant_warning'>[src] fades out!</span>")
density = FALSE
sleep(2)
forceMove(T)
sleep(1)
animate(src, alpha = 255, time = 2, easing = EASE_IN) //fade IN
sleep(1)
density = TRUE
visible_message("<span class='hierophant_warning'>[src] fades in!</span>")
sleep(1) //at this point the blasts we made detonate
blinking = FALSE
/mob/living/simple_animal/hostile/megafauna/hierophant/proc/melee_blast(mob/victim) //make a 3x3 blast around a target
if(!victim)
return
var/turf/T = get_turf(victim)
if(!T)
return
new /obj/effect/overlay/temp/hierophant/telegraph(T, src)
playsound(T,'sound/magic/blink.ogg', 200, 1)
//playsound(T,'sound/effects/bin_close.ogg', 200, 1)
sleep(2)
for(var/t in RANGE_TURFS(1, T))
new /obj/effect/overlay/temp/hierophant/blast(t, src, FALSE)
/mob/living/simple_animal/hostile/megafauna/hierophant/proc/burst(turf/original) //release a wave of blasts
playsound(original,'sound/magic/blink.ogg', 200, 1)
//playsound(original,'sound/machines/AirlockOpen.ogg', 200, 1)
var/last_dist = 0
for(var/t in spiral_range_turfs(burst_range, original))
var/turf/T = t
if(!T)
continue
var/dist = get_dist(original, T)
if(dist > last_dist)
last_dist = dist
sleep(1 + (burst_range - last_dist) * 0.5) //gets faster as it gets further out
new /obj/effect/overlay/temp/hierophant/blast(T, src, FALSE)
/mob/living/simple_animal/hostile/megafauna/hierophant/AltClickOn(atom/A) //player control handler(don't give this to a player holy fuck)
if(!istype(A) || get_dist(A, src) <= 2)
return
blink(A)
//Hierophant overlays
/obj/effect/overlay/temp/hierophant
layer = MOB_LAYER - 0.1
var/mob/living/caster //who made this, anyway
/obj/effect/overlay/temp/hierophant/New(loc, new_caster)
..()
if(new_caster)
caster = new_caster
/obj/effect/overlay/temp/hierophant/chaser //a hierophant's chaser. follows target around, moving and producing a blast every speed deciseconds.
duration = 98
var/mob/living/target //what it's following
var/turf/targetturf //what turf the target is actually on
var/moving_dir //what dir it's moving in
var/previous_moving_dir //what dir it was moving in before that
var/more_previouser_moving_dir //what dir it was moving in before THAT
var/moving = 0 //how many steps to move before recalculating
var/standard_moving_before_recalc = 4 //how many times we step before recalculating normally
var/tiles_per_step = 1 //how many tiles we move each step
var/speed = 3 //how many deciseconds between each step
var/currently_seeking = FALSE
var/friendly_fire_check = FALSE //if blasts produced apply friendly fire
/obj/effect/overlay/temp/hierophant/chaser/New(loc, new_caster, new_target, new_speed, is_friendly_fire)
..()
target = new_target
friendly_fire_check = is_friendly_fire
if(new_speed)
speed = new_speed
spawn(0)
seek_target()
/obj/effect/overlay/temp/hierophant/chaser/proc/get_target_dir()
. = get_cardinal_dir(src, targetturf)
if((. != previous_moving_dir && . == more_previouser_moving_dir) || . == 0) //we're alternating, recalculate
var/list/cardinal_copy = cardinal.Copy()
cardinal_copy -= more_previouser_moving_dir
. = pick(cardinal_copy)
/obj/effect/overlay/temp/hierophant/chaser/proc/seek_target()
if(!currently_seeking)
currently_seeking = TRUE
targetturf = get_turf(target)
while(target && src && !qdeleted(src) && currently_seeking && x && y && targetturf) //can this target actually be sook out
if(!moving) //we're out of tiles to move, find more and where the target is!
more_previouser_moving_dir = previous_moving_dir
previous_moving_dir = moving_dir
moving_dir = get_target_dir()
var/standard_target_dir = get_cardinal_dir(src, targetturf)
if((standard_target_dir != previous_moving_dir && standard_target_dir == more_previouser_moving_dir) || standard_target_dir == 0)
moving = 1 //we would be repeating, only move a tile before checking
else
moving = standard_moving_before_recalc
if(moving) //move in the dir we're moving in right now
var/turf/T = get_turf(src)
for(var/i in 1 to tiles_per_step)
var/maybe_new_turf = get_step(T, moving_dir)
if(maybe_new_turf)
T = maybe_new_turf
else
break
forceMove(T)
make_blast() //make a blast, too
moving--
sleep(speed)
targetturf = get_turf(target)
/obj/effect/overlay/temp/hierophant/chaser/proc/make_blast()
new /obj/effect/overlay/temp/hierophant/blast(loc, caster, friendly_fire_check)
/obj/effect/overlay/temp/hierophant/telegraph
icon = 'icons/effects/96x96.dmi'
icon_state = "hierophant_telegraph"
pixel_x = -32
pixel_y = -32
duration = 3
/obj/effect/overlay/temp/hierophant/telegraph/diagonal
icon_state = "hierophant_telegraph_diagonal"
/obj/effect/overlay/temp/hierophant/telegraph/cardinal
icon_state = "hierophant_telegraph_cardinal"
/obj/effect/overlay/temp/hierophant/telegraph/teleport
icon_state = "hierophant_telegraph_teleport"
duration = 9
/obj/effect/overlay/temp/hierophant/blast
icon = 'icons/effects/effects.dmi'
icon_state = "hierophant_blast"
name = "vortex blast"
luminosity = 1
desc = "Get out of the way!"
duration = 9
var/damage = 10 //how much damage do we do?
var/list/hit_things = list() //we hit these already, ignore them
var/friendly_fire_check = FALSE
var/bursting = FALSE //if we're bursting and need to hit anyone crossing us
/obj/effect/overlay/temp/hierophant/blast/New(loc, new_caster, friendly_fire)
..()
friendly_fire_check = friendly_fire
if(new_caster)
hit_things += new_caster
if(ismineralturf(loc)) //drill mineral turfs
var/turf/simulated/mineral/M = loc
M.gets_drilled(caster)
spawn(0)
blast()
/obj/effect/overlay/temp/hierophant/blast/proc/blast()
var/turf/T = get_turf(src)
if(!T)
return
playsound(T,'sound/magic/Blind.ogg', 125, 1, -5) //make a sound
sleep(6) //wait a little
bursting = TRUE
do_damage(T) //do damage and mark us as bursting
sleep(1.3) //slightly forgiving; the burst animation is 1.5 deciseconds
bursting = FALSE //we no longer damage crossers
/obj/effect/overlay/temp/hierophant/blast/Crossed(atom/movable/AM)
..()
if(bursting)
do_damage(get_turf(src))
/obj/effect/overlay/temp/hierophant/blast/proc/do_damage(turf/T)
for(var/mob/living/L in T.contents - hit_things) //find and damage mobs...
hit_things += L
if((friendly_fire_check && caster && caster.faction_check(L)) || L.stat == DEAD)
continue
if(L.client)
flash_color(L.client, "#660099", 1)
playsound(L,'sound/weapons/sear.ogg', 50, 1, -4)
to_chat(L, "<span class='userdanger'>You're struck by a [name]!</span>")
var/limb_to_hit = pick("head", "chest", "r_arm", "l_arm", "r_leg", "l_leg")
var/armor = L.run_armor_check(limb_to_hit, "melee", "Your armor absorbs [src]!", "Your armor blocks part of [src]!", 50, "Your armor was penetrated by [src]!")
L.apply_damage(damage, BURN, limb_to_hit, armor)
if(ismegafauna(L) || istype(L, /mob/living/simple_animal/hostile/asteroid))
L.adjustBruteLoss(damage)
add_logs(caster, L, "struck with a [name]")
for(var/obj/mecha/M in T.contents - hit_things) //and mechs.
hit_things += M
if(M.occupant)
if(friendly_fire_check && caster && caster.faction_check(M.occupant))
continue
to_chat(M.occupant, "<span class='userdanger'>Your [M.name] is struck by a [name]!</span>")
playsound(M,'sound/weapons/sear.ogg', 50, 1, -4)
M.take_damage(damage, BURN, 0, 0)
/obj/effect/hierophant
name = "hierophant rune"
desc = "A powerful magic mark allowing whomever attunes themself to it to return to it at will."
icon = 'icons/obj/rune.dmi'
icon_state = "hierophant"
layer = 2.5
anchored = TRUE
color = "#CC00FF"
/obj/effect/hierophant/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/weapon/hierophant_staff))
var/obj/item/weapon/hierophant_staff/H = I
if(H.rune == src)
to_chat(user, "<span class='notice'>You start removing your hierophant rune...</span>")
H.timer = world.time + 51
if(do_after(user, 50, target = src))
playsound(src,'sound/magic/Blind.ogg', 200, 1, -4)
new /obj/effect/overlay/temp/hierophant/telegraph/teleport(get_turf(src), user)
to_chat(user, "<span class='hierophant_warning'>You touch the rune with the staff, dispelling it!</span>")
H.rune = null
user.update_action_buttons_icon()
qdel(src)
else
H.timer = world.time
else
to_chat(user, "<span class='hierophant_warning'>You touch the rune with the staff, but nothing happens.</span>")
else
..()
/obj/item/device/gps/internal/hierophant
icon_state = null
gpstag = "Zealous Signal"
desc = "Heed its words."
invisibility = 100
/turf/simulated/indestructible/hierophant
icon_state = "hierophant1"
oxygen = 14
nitrogen = 23
temperature = 300
desc = "A floor with a square pattern. It's faintly cool to the touch."
/turf/simulated/indestructible/hierophant/New()
..()
if(prob(50))
icon_state = "hierophant2"
/turf/simulated/indestructible/riveted/hierophant
name = "wall"
desc = "A wall made out of smooth, cold stone."
icon = 'icons/turf/walls/hierophant_wall.dmi'
icon_state = "hierophant"
smooth = SMOOTH_TRUE
#undef MEDAL_PREFIX
@@ -0,0 +1,142 @@
#define MEDAL_PREFIX "Legion"
/*
LEGION
Legion spawns from the necropolis gate in the far north of lavaland. It is the guardian of the Necropolis and emerges from within whenever an intruder tries to enter through its gate.
Whenever Legion emerges, everything in lavaland will receive a notice via color, audio, and text. This is because Legion is powerful enough to slaughter the entirety of lavaland with little effort.
It has two attack modes that it constantly rotates between.
In ranged mode, it will behave like a normal legion - retreating when possible and firing legion skulls at the target.
In charge mode, it will spin and rush its target, attacking with melee whenever possible.
When Legion dies, it drops a staff of storms, which allows its wielder to call and disperse ash storms at will and functions as a powerful melee weapon.
Difficulty: Medium
*/
/mob/living/simple_animal/hostile/megafauna/legion
name = "Legion"
health = 800
maxHealth = 800
icon_state = "legion"
icon_living = "legion"
desc = "One of many."
icon = 'icons/mob/lavaland/legion.dmi'
attacktext = "chomps"
attack_sound = 'sound/misc/demon_attack1.ogg'
speak_emote = list("echoes")
armour_penetration = 50
melee_damage_lower = 25
melee_damage_upper = 25
speed = 2
ranged = 1
del_on_death = 1
retreat_distance = 5
minimum_distance = 5
ranged_cooldown_time = 20
var/size = 5
var/charging = 0
medal_type = MEDAL_PREFIX
score_type = LEGION_SCORE
pixel_y = -90
pixel_x = -75
loot = list(/obj/item/stack/sheet/bone = 3)
vision_range = 13
elimination = 1
idle_vision_range = 13
appearance_flags = 0
mouse_opacity = 1
stat_attack = 1 // Overriden from /tg/ - otherwise Legion starts chasing its minions
/mob/living/simple_animal/hostile/megafauna/legion/New()
..()
internal_gps = new/obj/item/device/gps/internal/legion(src)
/mob/living/simple_animal/hostile/megafauna/legion/AttackingTarget()
..()
if(ishuman(target))
var/mob/living/L = target
if(L.stat == UNCONSCIOUS)
var/mob/living/simple_animal/hostile/asteroid/hivelordbrood/legion/A = new(loc)
A.infest(L)
/mob/living/simple_animal/hostile/megafauna/legion/OpenFire(the_target)
if(world.time >= ranged_cooldown && !charging)
if(prob(75))
var/mob/living/simple_animal/hostile/asteroid/hivelordbrood/legion/A = new(loc)
A.GiveTarget(target)
A.friends = friends
A.faction = faction
ranged_cooldown = world.time + ranged_cooldown_time
else
visible_message("<span class='warning'><b>[src] charges!</b></span>")
SpinAnimation(speed = 20, loops = 5)
ranged = 0
retreat_distance = 0
minimum_distance = 0
speed = 0
charging = 1
spawn(50)
reset_charge()
/mob/living/simple_animal/hostile/megafauna/legion/proc/reset_charge()
ranged = 1
retreat_distance = 5
minimum_distance = 5
speed = 2
charging = 0
/mob/living/simple_animal/hostile/megafauna/legion/death()
if(health > 0)
return
if(size > 1)
adjustHealth(-maxHealth) //heal ourself to full in prep for splitting
var/mob/living/simple_animal/hostile/megafauna/legion/L = new(loc)
L.maxHealth = maxHealth * 0.6
maxHealth = L.maxHealth
L.health = L.maxHealth
health = maxHealth
size--
L.size = size
L.resize = L.size * 0.2
transform = initial(transform)
resize = size * 0.2
L.update_transform()
update_transform()
L.faction = faction.Copy()
L.GiveTarget(target)
visible_message("<span class='boldannounce'>[src] splits in twain!</span>")
else
var/last_legion = TRUE
for(var/mob/living/simple_animal/hostile/megafauna/legion/other in mob_list)
if(other != src)
last_legion = FALSE
break
if(last_legion)
loot = list(/obj/item/weapon/staff/storm)
elimination = 0
else if(prob(5))
loot = list(/obj/structure/closet/crate/necropolis/tendril)
..()
/mob/living/simple_animal/hostile/megafauna/legion/Process_Spacemove(movement_dir = 0)
return 1
/obj/item/device/gps/internal/legion
icon_state = null
gpstag = "Echoing Signal"
desc = "The message repeats."
invisibility = 100
#undef MEDAL_PREFIX
@@ -0,0 +1,230 @@
#define MEDAL_PREFIX "Boss"
/mob/living/simple_animal/hostile/megafauna
name = "megafauna"
desc = "Attack the weak point for massive damage."
health = 1000
maxHealth = 1000
a_intent = "harm"
sentience_type = SENTIENCE_BOSS
environment_smash = 3
luminosity = 3
faction = list("mining", "boss")
weather_immunities = list("lava","ash")
flying = 1
robust_searching = 1
ranged_ignores_vision = TRUE
stat_attack = 2
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)
damage_coeff = list(BRUTE = 1, BURN = 0.5, TOX = 1, CLONE = 1, STAMINA = 0, OXY = 1)
minbodytemp = 0
maxbodytemp = INFINITY
aggro_vision_range = 18
idle_vision_range = 5
environment_target_typecache = list(
/obj/machinery/door/window,
/obj/structure/window,
/obj/structure/closet,
/obj/structure/table,
/obj/structure/grille,
/obj/structure/girder,
/obj/structure/rack,
/obj/structure/barricade,
/obj/machinery/field,
/obj/machinery/power/emitter)
var/medal_type = MEDAL_PREFIX
var/score_type = BOSS_SCORE
var/elimination = 0
var/anger_modifier = 0
var/obj/item/device/gps/internal_gps
anchored = TRUE
mob_size = MOB_SIZE_LARGE
layer = MOB_LAYER + 0.5 //Looks weird with them slipping under mineral walls and cameras and shit otherwise
mouse_opacity = 2 // Easier to click on in melee, they're giant targets anyway
/mob/living/simple_animal/hostile/megafauna/Destroy()
qdel(internal_gps)
. = ..()
/mob/living/simple_animal/hostile/megafauna/death(gibbed)
if(health > 0)
return
else
if(!admin_spawned)
feedback_set_details("megafauna_kills","[initial(name)]")
if(!elimination) //used so the achievment only occurs for the last legion to die.
grant_achievement(medal_type,score_type)
..()
/mob/living/simple_animal/hostile/megafauna/gib()
if(health > 0)
return
else
..()
/mob/living/simple_animal/hostile/megafauna/dust()
if(health > 0)
return
else
..()
/mob/living/simple_animal/hostile/megafauna/AttackingTarget()
..()
if(isliving(target))
var/mob/living/L = target
if(L.stat != DEAD)
if(!client && ranged && ranged_cooldown <= world.time)
OpenFire()
else
devour(L)
/mob/living/simple_animal/hostile/megafauna/onShuttleMove()
var/turf/oldloc = loc
. = ..()
if(!.)
return
var/turf/newloc = loc
message_admins("Megafauna [src] \
(<A HREF='?_src_=holder;adminplayerobservefollow=[UID()]'>FLW</A>) \
moved via shuttle from ([oldloc.x], [oldloc.y], [oldloc.z]) to \
([newloc.x], [newloc.y], [newloc.z])")
/mob/living/simple_animal/hostile/megafauna/proc/devour(mob/living/L)
if(!L)
return
visible_message(
"<span class='danger'>[src] devours [L]!</span>",
"<span class='userdanger'>You feast on [L], restoring your health!</span>")
adjustBruteLoss(-L.maxHealth/2)
L.gib()
/mob/living/simple_animal/hostile/megafauna/ex_act(severity, target)
switch(severity)
if(1)
adjustBruteLoss(250)
if(2)
adjustBruteLoss(100)
if(3)
adjustBruteLoss(50)
/mob/living/simple_animal/hostile/megafauna/proc/grant_achievement(medaltype,scoretype)
if(medal_type == "Boss") //Don't award medals if the medal type isn't set
return
if(admin_spawned)
return
if(global.medal_hub && global.medal_pass && global.medals_enabled)
for(var/mob/living/L in view(7,src))
if(L.stat)
continue
if(L.client)
var/client/C = L.client
var/suffixm = BOSS_KILL_MEDAL
UnlockMedal("Boss [suffixm]",C)
UnlockMedal("[medaltype] [suffixm]",C)
SetScore(BOSS_SCORE,C,1)
SetScore(score_type,C,1)
/proc/UnlockMedal(medal,client/player)
if(!player || !medal)
return
if(global.medal_hub && global.medal_pass && global.medals_enabled)
spawn()
var/result = world.SetMedal(medal, player, global.medal_hub, global.medal_pass)
if(isnull(result))
global.medals_enabled = FALSE
log_game("MEDAL ERROR: Could not contact hub to award medal:[medal] player:[player.ckey]")
message_admins("Error! Failed to contact hub to award [medal] medal to [player.ckey]!")
else if(result)
to_chat(player.mob, "<span class='greenannounce'><B>Achievement unlocked: [medal]!</B></span>")
/proc/SetScore(score,client/player,increment,force)
if(!score || !player)
return
if(global.medal_hub && global.medal_pass && global.medals_enabled)
spawn()
var/list/oldscore = GetScore(score,player,1)
if(increment)
if(!oldscore[score])
oldscore[score] = 1
else
oldscore[score] = (text2num(oldscore[score]) + 1)
else
oldscore[score] = force
var/newscoreparam = list2params(oldscore)
var/result = world.SetScores(player.ckey, newscoreparam, global.medal_hub, global.medal_pass)
if(isnull(result))
global.medals_enabled = FALSE
log_game("SCORE ERROR: Could not contact hub to set score. Score:[score] player:[player.ckey]")
message_admins("Error! Failed to contact hub to set [score] score for [player.ckey]!")
/proc/GetScore(score,client/player,returnlist)
if(!score || !player)
return
if(global.medal_hub && global.medal_pass && global.medals_enabled)
var/scoreget = world.GetScores(player.ckey, score, global.medal_hub, global.medal_pass)
if(isnull(scoreget))
global.medals_enabled = FALSE
log_game("SCORE ERROR: Could not contact hub to get score. Score:[score] player:[player.ckey]")
message_admins("Error! Failed to contact hub to get score: [score] for [player.ckey]!")
return
var/list/scoregetlist = params2list(scoreget)
if(returnlist)
return scoregetlist
else
return scoregetlist[score]
/proc/CheckMedal(medal,client/player)
if(!player || !medal)
return
if(global.medal_hub && global.medal_pass && global.medals_enabled)
var/result = world.GetMedal(medal, player, global.medal_hub, global.medal_pass)
if(isnull(result))
global.medals_enabled = FALSE
log_game("MEDAL ERROR: Could not contact hub to get medal:[medal] player:[player.ckey]")
message_admins("Error! Failed to contact hub to get [medal] medal for [player.ckey]!")
else if(result)
to_chat(player.mob, "[medal] is unlocked")
/proc/LockMedal(medal,client/player)
if(!player || !medal)
return
if(global.medal_hub && global.medal_pass && global.medals_enabled)
var/result = world.ClearMedal(medal, player, global.medal_hub, global.medal_pass)
if(isnull(result))
global.medals_enabled = FALSE
log_game("MEDAL ERROR: Could not contact hub to clear medal:[medal] player:[player.ckey]")
message_admins("Error! Failed to contact hub to clear [medal] medal for [player.ckey]!")
else if(result)
message_admins("Medal: [medal] removed for [player.ckey]")
else
message_admins("Medal: [medal] was not found for [player.ckey]. Unable to clear.")
/proc/ClearScore(client/player)
world.SetScores(player.ckey, "", global.medal_hub, global.medal_pass)
#undef MEDAL_PREFIX
@@ -91,10 +91,6 @@
..()
icon_state = initial(icon_state)
/mob/living/simple_animal/hostile/mimic/crate/LostTarget()
..()
icon_state = initial(icon_state)
/mob/living/simple_animal/hostile/mimic/crate/death(gibbed)
var/obj/structure/closet/crate/C = new(get_turf(src))
// Put loot in crate
@@ -0,0 +1,78 @@
/mob/living/simple_animal/hostile/asteroid/goldgrub
name = "goldgrub"
desc = "A worm that grows fat from eating everything in its sight. Seems to enjoy precious metals and other shiny things, hence the name."
icon = 'icons/mob/animal.dmi'
icon_state = "Goldgrub"
icon_living = "Goldgrub"
icon_aggro = "Goldgrub_alert"
icon_dead = "Goldgrub_dead"
icon_gib = "syndicate_gib"
vision_range = 2
aggro_vision_range = 9
idle_vision_range = 2
move_to_delay = 5
friendly = "harmlessly rolls into"
maxHealth = 45
health = 45
harm_intent_damage = 5
melee_damage_lower = 0
melee_damage_upper = 0
attacktext = "barrels into"
attack_sound = 'sound/weapons/punch1.ogg'
a_intent = I_HELP
speak_emote = list("screeches")
throw_message = "sinks in slowly, before being pushed out of "
status_flags = CANPUSH
search_objects = 1
wanted_objects = list(/obj/item/weapon/ore/diamond, /obj/item/weapon/ore/gold, /obj/item/weapon/ore/silver,
/obj/item/weapon/ore/uranium)
var/chase_time = 100
var/will_burrow = TRUE
/mob/living/simple_animal/hostile/asteroid/goldgrub/New()
..()
var/i = rand(1,3)
while(i)
loot += pick(/obj/item/weapon/ore/silver, /obj/item/weapon/ore/gold, /obj/item/weapon/ore/uranium, /obj/item/weapon/ore/diamond)
i--
/mob/living/simple_animal/hostile/asteroid/goldgrub/GiveTarget(new_target)
target = new_target
if(target != null)
if(istype(target, /obj/item/weapon/ore) && loot.len < 10)
visible_message("<span class='notice'>The [src.name] looks at [target.name] with hungry eyes.</span>")
else if(isliving(target))
Aggro()
visible_message("<span class='danger'>The [src.name] tries to flee from [target.name]!</span>")
retreat_distance = 10
minimum_distance = 10
if(will_burrow)
spawn(chase_time)
Burrow()
/mob/living/simple_animal/hostile/asteroid/goldgrub/AttackingTarget()
if(istype(target, /obj/item/weapon/ore))
EatOre(target)
return
..()
/mob/living/simple_animal/hostile/asteroid/goldgrub/proc/EatOre(var/atom/targeted_ore)
for(var/obj/item/weapon/ore/O in targeted_ore.loc)
if(loot.len < 10)
loot += O.type
qdel(O)
visible_message("<span class='notice'>The ore was swallowed whole!</span>")
/mob/living/simple_animal/hostile/asteroid/goldgrub/proc/Burrow()//Begin the chase to kill the goldgrub in time
if(!stat)
visible_message("<span class='danger'>The [src.name] buries into the ground, vanishing from sight!</span>")
qdel(src)
/mob/living/simple_animal/hostile/asteroid/goldgrub/bullet_act(obj/item/projectile/P)
visible_message("<span class='danger'>The [P.name] was repelled by [src.name]'s girth!</span>")
return
/mob/living/simple_animal/hostile/asteroid/goldgrub/adjustHealth(damage)
idle_vision_range = 9
. = ..()
@@ -0,0 +1,319 @@
/mob/living/simple_animal/hostile/asteroid/hivelord
name = "hivelord"
desc = "A truly alien creature, it is a mass of unknown organic material, constantly fluctuating. When attacking, pieces of it split off and attack in tandem with the original."
icon = 'icons/mob/lavaland/lavaland_monsters.dmi'
icon_state = "Hivelord"
icon_living = "Hivelord"
icon_aggro = "Hivelord_alert"
icon_dead = "Hivelord_dead"
icon_gib = "syndicate_gib"
mouse_opacity = 2
move_to_delay = 14
ranged = 1
vision_range = 5
aggro_vision_range = 9
idle_vision_range = 5
speed = 3
maxHealth = 75
health = 75
harm_intent_damage = 5
melee_damage_lower = 0
melee_damage_upper = 0
attacktext = "lashes out at"
speak_emote = list("telepathically cries")
attack_sound = 'sound/weapons/pierce.ogg'
throw_message = "falls right through the strange body of the"
ranged_cooldown = 0
ranged_cooldown_time = 20
environment_smash = 0
retreat_distance = 3
minimum_distance = 3
pass_flags = PASSTABLE
loot = list(/obj/item/organ/internal/hivelord_core)
var/brood_type = /mob/living/simple_animal/hostile/asteroid/hivelordbrood
/mob/living/simple_animal/hostile/asteroid/hivelord/OpenFire(the_target)
if(world.time >= ranged_cooldown)
var/mob/living/simple_animal/hostile/asteroid/hivelordbrood/A = new brood_type(src.loc)
A.admin_spawned = admin_spawned
A.GiveTarget(target)
A.friends = friends
A.faction = faction.Copy()
ranged_cooldown = world.time + ranged_cooldown_time
/mob/living/simple_animal/hostile/asteroid/hivelord/AttackingTarget()
OpenFire()
/mob/living/simple_animal/hostile/asteroid/hivelord/death(gibbed)
mouse_opacity = 1
..(gibbed)
/obj/item/organ/internal/hivelord_core
name = "hivelord remains"
desc = "All that remains of a hivelord, it seems to be what allows it to break pieces of itself off without being hurt... its healing properties will soon become inert if not used quickly."
icon_state = "roro core 2"
flags = NOBLUDGEON
slot = "hivecore"
force = 0
actions_types = list(/datum/action/item_action/organ_action/use)
var/inert = 0
var/preserved = 0
/obj/item/organ/internal/hivelord_core/New()
..()
addtimer(src, "inert_check", 2400)
/obj/item/organ/internal/hivelord_core/proc/inert_check()
if(!owner && !preserved)
go_inert()
else
preserved(implanted = 1)
/obj/item/organ/internal/hivelord_core/proc/preserved(implanted = 0)
inert = FALSE
preserved = TRUE
update_icon()
if(implanted)
feedback_add_details("hivelord_core", "[type]|implanted")
else
feedback_add_details("hivelord_core", "[type]|stabilizer")
/obj/item/organ/internal/hivelord_core/proc/go_inert()
inert = TRUE
desc = "The remains of a hivelord that have become useless, having been left alone too long after being harvested."
feedback_add_details("hivelord_core", "[src.type]|inert")
update_icon()
/obj/item/organ/internal/hivelord_core/ui_action_click()
owner.revive()
qdel(src)
/obj/item/organ/internal/hivelord_core/on_life()
..()
if(owner.health < config.health_threshold_crit)
ui_action_click()
/obj/item/organ/internal/hivelord_core/afterattack(atom/target, mob/user, proximity_flag)
if(proximity_flag && ishuman(target))
var/mob/living/carbon/human/H = target
if(inert)
to_chat(user, "<span class='notice'>[src] has become inert, its healing properties are no more.</span>")
return
else
if(H.stat == DEAD)
to_chat(user, "<span class='notice'>[src] are useless on the dead.</span>")
return
if(H != user)
H.visible_message("[user] forces [H] to apply [src]... They quickly regenerate all injuries!")
feedback_add_details("hivelord_core","[src.type]|used|other")
else
to_chat(user, "<span class='notice'>You start to smear [src] on yourself. It feels and smells disgusting, but you feel amazingly refreshed in mere moments.</span>")
feedback_add_details("hivelord_core","[src.type]|used|self")
playsound(src.loc,'sound/items/eatfood.ogg', rand(10,50), 1)
H.revive()
qdel(src)
..()
/obj/item/organ/internal/hivelord_core/prepare_eat()
return null
/mob/living/simple_animal/hostile/asteroid/hivelordbrood
name = "hivelord brood"
desc = "A fragment of the original Hivelord, rallying behind its original. One isn't much of a threat, but..."
icon = 'icons/mob/lavaland/lavaland_monsters.dmi'
icon_state = "Hivelordbrood"
icon_living = "Hivelordbrood"
icon_aggro = "Hivelordbrood"
icon_dead = "Hivelordbrood"
icon_gib = "syndicate_gib"
mouse_opacity = 2
move_to_delay = 1
friendly = "buzzes near"
vision_range = 10
speed = 3
maxHealth = 1
health = 1
flying = 1
harm_intent_damage = 5
melee_damage_lower = 2
melee_damage_upper = 2
attacktext = "slashes"
speak_emote = list("telepathically cries")
attack_sound = 'sound/weapons/pierce.ogg'
throw_message = "falls right through the strange body of the"
environment_smash = 0
pass_flags = PASSTABLE
del_on_death = 1
/mob/living/simple_animal/hostile/asteroid/hivelordbrood/New()
..()
addtimer(src, "death", 100)
/mob/living/simple_animal/hostile/asteroid/hivelordbrood/blood
name = "blood brood"
desc = "A living string of blood and alien materials."
icon_state = "bloodbrood"
icon_living = "bloodbrood"
icon_aggro = "bloodbrood"
attacktext = "pierces"
color = "#C80000"
/mob/living/simple_animal/hostile/asteroid/hivelordbrood/blood/death()
if(loc) // Splash the turf we are on with blood
reagents.reaction(get_turf(src))
..()
/mob/living/simple_animal/hostile/asteroid/hivelordbrood/blood/New()
create_reagents(30)
..()
/mob/living/simple_animal/hostile/asteroid/hivelordbrood/blood/AttackingTarget()
..()
if(iscarbon(target))
transfer_reagents(target, 1)
/mob/living/simple_animal/hostile/asteroid/hivelordbrood/blood/attack_hand(mob/living/carbon/human/M)
if("\ref[M]" in faction)
reabsorb_host(M)
else
return ..()
/mob/living/simple_animal/hostile/asteroid/hivelordbrood/blood/attack_alien(mob/living/carbon/alien/humanoid/M)
if("\ref[M]" in faction)
reabsorb_host(M)
else
return ..()
/mob/living/simple_animal/hostile/asteroid/hivelordbrood/blood/proc/reabsorb_host(mob/living/carbon/C)
C.visible_message("<span class='notice'>[src] is reabsorbed by [C]'s body.</span>", \
"<span class='notice'>[src] is reabsorbed by your body.</span>")
transfer_reagents(C)
death()
/mob/living/simple_animal/hostile/asteroid/hivelordbrood/blood/proc/transfer_reagents(mob/living/carbon/C, volume = 30)
if(!reagents.total_volume)
return
volume = min(volume, reagents.total_volume)
var/fraction = min(volume/reagents.total_volume, 1)
reagents.reaction(C, INGEST, fraction)
reagents.trans_to(C, volume)
/mob/living/simple_animal/hostile/asteroid/hivelordbrood/blood/proc/link_host(mob/living/carbon/human/H)
faction = list("\ref[src]", "\ref[H]") // Hostile to everyone except the host.
H.vessel.trans_to(src, 30)
color = mix_color_from_reagents(reagents.reagent_list)
// Legion
/mob/living/simple_animal/hostile/asteroid/hivelord/legion
name = "legion"
desc = "You can still see what was once a human under the shifting mass of corruption."
icon = 'icons/mob/lavaland/lavaland_monsters.dmi'
icon_state = "legion"
icon_living = "legion"
icon_aggro = "legion"
icon_dead = "legion"
icon_gib = "syndicate_gib"
melee_damage_lower = 15
melee_damage_upper = 15
attacktext = "lashes out at"
speak_emote = list("echoes")
attack_sound = 'sound/weapons/pierce.ogg'
throw_message = "bounces harmlessly off of"
loot = list(/obj/item/organ/internal/hivelord_core/legion)
brood_type = /mob/living/simple_animal/hostile/asteroid/hivelordbrood/legion
del_on_death = 1
stat_attack = 1
robust_searching = 1
var/mob/living/carbon/human/stored_mob
/mob/living/simple_animal/hostile/asteroid/hivelord/legion/death(gibbed)
visible_message("<span class='warning'>The skulls on [src] wail in anger as they flee from their dying host!</span>")
var/turf/T = get_turf(src)
if(T)
if(stored_mob)
stored_mob.forceMove(get_turf(src))
stored_mob = null
else
new /obj/effect/landmark/corpse/damaged(T)
..(gibbed)
/mob/living/simple_animal/hostile/asteroid/hivelordbrood/legion
name = "legion"
desc = "One of many."
icon = 'icons/mob/lavaland/lavaland_monsters.dmi'
icon_state = "legion_head"
icon_living = "legion_head"
icon_aggro = "legion_head"
icon_dead = "legion_head"
icon_gib = "syndicate_gib"
friendly = "buzzes near"
vision_range = 10
maxHealth = 1
health = 5
harm_intent_damage = 5
melee_damage_lower = 12
melee_damage_upper = 12
attacktext = "bites"
speak_emote = list("echoes")
attack_sound = 'sound/weapons/pierce.ogg'
throw_message = "is shrugged off by"
pass_flags = PASSTABLE
del_on_death = 1
stat_attack = 1
robust_searching = 1
/mob/living/simple_animal/hostile/asteroid/hivelordbrood/legion/Life()
if(isturf(loc))
for(var/mob/living/carbon/human/H in view(src,1)) //Only for corpse right next to/on same tile
if(H.stat == UNCONSCIOUS)
infest(H)
..()
/mob/living/simple_animal/hostile/asteroid/hivelordbrood/legion/proc/infest(mob/living/carbon/human/H)
visible_message("<span class='warning'>[name] burrows into the flesh of [H]!</span>")
var/mob/living/simple_animal/hostile/asteroid/hivelord/legion/L = new(H.loc)
visible_message("<span class='warning'>[L] staggers to their feet!</span>")
H.death()
H.adjustBruteLoss(1000)
L.stored_mob = H
H.forceMove(L)
qdel(src)
/obj/item/organ/internal/hivelord_core/legion
name = "legion's soul"
desc = "A strange rock that still crackles with power... its \
healing properties will soon become inert if not used quickly."
icon_state = "legion_soul"
/obj/item/organ/internal/hivelord_core/legion/New()
..()
update_icon()
/obj/item/organ/internal/hivelord_core/legion/update_icon()
icon_state = inert ? "legion_soul_inert" : "legion_soul"
overlays.Cut()
if(!inert && !preserved)
overlays += image(icon, "legion_soul_crackle")
for(var/X in actions)
var/datum/action/A = X
A.UpdateButtonIcon()
/obj/item/organ/internal/hivelord_core/legion/go_inert()
. = ..()
desc = "[src] has become inert, it crackles no more and is useless for \
healing injuries."
/obj/item/organ/internal/hivelord_core/legion/preserved(implanted = 0)
..()
desc = "[src] has been stabilized. It no longer crackles with power, but it's healing properties are preserved indefinitely."
/obj/item/weapon/legion_skull
name = "legion's head"
desc = "The once living, now empty eyes of the former human's skull cut deep into your soul."
icon = 'icons/obj/mining.dmi'
icon_state = "skull"
@@ -58,7 +58,7 @@
projectilesound = 'sound/weapons/pierce.ogg'
ranged = 1
ranged_message = "stares"
ranged_cooldown_cap = 20
ranged_cooldown_time = 30
throw_message = "does nothing against the hard shell of"
vision_range = 2
speed = 3
@@ -71,7 +71,6 @@
a_intent = I_HARM
speak_emote = list("chitters")
attack_sound = 'sound/weapons/bladeslice.ogg'
ranged_cooldown_cap = 4
aggro_vision_range = 9
idle_vision_range = 2
turns_per_move = 5
@@ -104,232 +103,6 @@
if(3.0)
adjustBruteLoss(110)
/mob/living/simple_animal/hostile/asteroid/goldgrub
name = "goldgrub"
desc = "A worm that grows fat from eating everything in its sight. Seems to enjoy precious metals and other shiny things, hence the name."
icon = 'icons/mob/animal.dmi'
icon_state = "Goldgrub"
icon_living = "Goldgrub"
icon_aggro = "Goldgrub_alert"
icon_dead = "Goldgrub_dead"
icon_gib = "syndicate_gib"
vision_range = 2
aggro_vision_range = 9
idle_vision_range = 2
move_to_delay = 5
friendly = "harmlessly rolls into"
maxHealth = 45
health = 45
harm_intent_damage = 5
melee_damage_lower = 0
melee_damage_upper = 0
attacktext = "barrels into"
attack_sound = 'sound/weapons/punch1.ogg'
a_intent = I_HELP
speak_emote = list("screeches")
throw_message = "sinks in slowly, before being pushed out of "
status_flags = CANPUSH
search_objects = 1
wanted_objects = list(/obj/item/weapon/ore/diamond, /obj/item/weapon/ore/gold, /obj/item/weapon/ore/silver,
/obj/item/weapon/ore/uranium)
var/list/ore_types_eaten = list()
var/alerted = 0
var/ore_eaten = 1
var/chase_time = 100
var/will_burrow = 1
/mob/living/simple_animal/hostile/asteroid/goldgrub/New()
..()
ore_types_eaten += pick(/obj/item/weapon/ore/silver, /obj/item/weapon/ore/gold, /obj/item/weapon/ore/uranium, /obj/item/weapon/ore/diamond)
ore_eaten = rand(1,3)
/mob/living/simple_animal/hostile/asteroid/goldgrub/GiveTarget(var/new_target)
target = new_target
if(target != null)
if(istype(target, /obj/item/weapon/ore))
visible_message("<span class='notice'>The [src.name] looks at [target.name] with hungry eyes.</span>")
else if(isliving(target))
Aggro()
visible_message("<span class='danger'>The [src.name] tries to flee from [target.name]!</span>")
retreat_distance = 10
minimum_distance = 10
Burrow()
/mob/living/simple_animal/hostile/asteroid/goldgrub/AttackingTarget()
if(istype(target, /obj/item/weapon/ore))
EatOre(target)
return
..()
/mob/living/simple_animal/hostile/asteroid/goldgrub/proc/EatOre(var/atom/targeted_ore)
for(var/obj/item/weapon/ore/O in targeted_ore.loc)
ore_eaten++
if(!(O.type in ore_types_eaten))
ore_types_eaten += O.type
qdel(O)
if(ore_eaten > 10)//Limit the scope of the reward you can get, or else things might get silly
ore_eaten = 10
visible_message("<span class='notice'>The ore was swallowed whole!</span>")
/mob/living/simple_animal/hostile/asteroid/goldgrub/proc/Burrow()//Begin the chase to kill the goldgrub in time
if(!alerted && will_burrow)
alerted = 1
spawn(chase_time)
if(alerted)
visible_message("<span class='danger'>The [src.name] buries into the ground, vanishing from sight!</span>")
qdel(src)
/mob/living/simple_animal/hostile/asteroid/goldgrub/proc/Reward()
if(!ore_eaten || ore_types_eaten.len == 0)
return
visible_message("<span class='danger'>[src] spits up the contents of its stomach before dying!</span>")
var/counter
for(var/R in ore_types_eaten)
for(counter=0, counter < ore_eaten, counter++)
new R(src.loc)
ore_types_eaten.Cut()
ore_eaten = 0
/mob/living/simple_animal/hostile/asteroid/goldgrub/bullet_act(var/obj/item/projectile/P)
visible_message("<span class='danger'>The [P.name] was repelled by [src.name]'s girth!</span>")
return
/mob/living/simple_animal/hostile/asteroid/goldgrub/death(gibbed)
alerted = 0
Reward()
..()
/mob/living/simple_animal/hostile/asteroid/goldgrub/adjustHealth(damage)
idle_vision_range = 9
..()
/mob/living/simple_animal/hostile/asteroid/hivelord
name = "hivelord"
desc = "A truly alien creature, it is a mass of unknown organic material, constantly fluctuating. When attacking, pieces of it split off and attack in tandem with the original."
icon = 'icons/mob/animal.dmi'
icon_state = "Hivelord"
icon_living = "Hivelord"
icon_aggro = "Hivelord_alert"
icon_dead = "Hivelord_dead"
icon_gib = "syndicate_gib"
mouse_opacity = 2
move_to_delay = 14
ranged = 1
vision_range = 5
aggro_vision_range = 9
idle_vision_range = 5
speed = 3
maxHealth = 75
health = 75
harm_intent_damage = 5
melee_damage_lower = 0
melee_damage_upper = 0
attacktext = "lashes out at"
speak_emote = list("telepathically cries")
attack_sound = 'sound/weapons/pierce.ogg'
throw_message = "falls right through the strange body of the"
ranged_cooldown = 0
ranged_cooldown_cap = 0
environment_smash = 0
retreat_distance = 3
minimum_distance = 3
pass_flags = PASSTABLE
loot = list(/obj/item/organ/internal/hivelord_core)
/mob/living/simple_animal/hostile/asteroid/hivelord/OpenFire(var/the_target)
var/mob/living/simple_animal/hostile/asteroid/hivelordbrood/A = new /mob/living/simple_animal/hostile/asteroid/hivelordbrood(src.loc)
A.GiveTarget(target)
A.friends = friends
A.faction = faction
return
/mob/living/simple_animal/hostile/asteroid/hivelord/AttackingTarget()
OpenFire()
/obj/item/organ/internal/hivelord_core
name = "hivelord remains"
desc = "All that remains of a hivelord, it seems to be what allows it to break pieces of itself off without being hurt... its healing properties will soon become inert if not used quickly. Try not to think about what you're eating."
icon = 'icons/obj/food/food.dmi'
icon_state = "boiledrorocore"
slot = "hivecore"
var/inert = 0
var/preserved = 0
/obj/item/organ/internal/hivelord_core/New()
spawn(2400)
if(!preserved)
inert = 1
desc = "The remains of a hivelord that have become useless, having been left alone too long after being harvested."
/obj/item/organ/internal/hivelord_core/on_life()
..()
if(owner)
owner.adjustBruteLoss(-1)
owner.adjustFireLoss(-1)
owner.adjustOxyLoss(-2)
if(ishuman(owner))
var/mob/living/carbon/human/H = owner
var/datum/reagent/blood/B = locate() in H.vessel.reagent_list //Grab some blood
var/blood_volume = round(H.vessel.get_reagent_amount("blood"))
if(B && blood_volume < H.max_blood && blood_volume)
B.volume += 2 // Fast blood regen
/obj/item/organ/internal/hivelord_core/attack(mob/living/M as mob, mob/living/user as mob)
if(ishuman(M))
var/mob/living/carbon/human/H = M
if(inert)
to_chat(user, "<span class='notice'>[src] have become inert, its healing properties are no more.</span>")
return
else
if(H.stat == DEAD)
to_chat(user, "<span class='notice'>[src] are useless on the dead.</span>")
return
if(H != user)
H.visible_message("<span class='notice'>[user] forces [H] to eat [src]... they quickly regenerate all injuries!</span>")
else
to_chat(user, "<span class='notice'>You chomp into [src], barely managing to hold it down, but feel amazingly refreshed in mere moments.</span>")
playsound(src.loc,'sound/items/eatfood.ogg', rand(10,50), 1)
H.revive()
qdel(src)
..()
/obj/item/organ/internal/hivelord_core/prepare_eat()
return null
/mob/living/simple_animal/hostile/asteroid/hivelordbrood
name = "hivelord brood"
desc = "A fragment of the original Hivelord, rallying behind its original. One isn't much of a threat, but..."
icon = 'icons/mob/animal.dmi'
icon_state = "Hivelordbrood"
icon_living = "Hivelordbrood"
icon_aggro = "Hivelordbrood"
icon_dead = "Hivelordbrood"
icon_gib = "syndicate_gib"
mouse_opacity = 2
move_to_delay = 1
friendly = "buzzes near"
vision_range = 10
speed = 3
maxHealth = 1
health = 1
harm_intent_damage = 5
melee_damage_lower = 2
melee_damage_upper = 2
attacktext = "slashes"
speak_emote = list("telepathically cries")
attack_sound = 'sound/weapons/pierce.ogg'
throw_message = "falls right through the strange body of the"
environment_smash = 0
pass_flags = PASSTABLE
del_on_death = 1
/mob/living/simple_animal/hostile/asteroid/hivelordbrood/New()
..()
spawn(100)
death()
/mob/living/simple_animal/hostile/asteroid/goliath
name = "goliath"
desc = "A massive beast that uses long tentacles to ensare its prey, threatening them is not advised under any conditions."
@@ -344,7 +117,7 @@
move_to_delay = 40
ranged = 1
ranged_cooldown = 2 //By default, start the Goliath with his cooldown off so that people can run away quickly on first sight
ranged_cooldown_cap = 8
ranged_cooldown_time = 120
friendly = "wails at"
speak_emote = list("bellows")
vision_range = 4
@@ -368,7 +141,7 @@
handle_preattack()
/mob/living/simple_animal/hostile/asteroid/goliath/proc/handle_preattack()
if(ranged_cooldown <= 2 && !pre_attack)
if(ranged_cooldown <= world.time + ranged_cooldown_time * 0.25 && !pre_attack)
pre_attack++
if(!pre_attack || stat || AIStatus == AI_IDLE)
return
@@ -383,7 +156,7 @@
if(get_dist(src, target) <= 7)//Screen range check, so you can't get tentacle'd offscreen
visible_message("<span class='warning'>The [src.name] digs its tentacles under [target.name]!</span>")
new /obj/effect/goliath_tentacle/original(tturf)
ranged_cooldown = ranged_cooldown_cap
ranged_cooldown = world.time + ranged_cooldown_time
icon_state = icon_aggro
pre_attack = 0
return
@@ -163,7 +163,7 @@
clothes_req = 0
range = 14
/obj/effect/proc_holder/spell/aoe_turf/flicker_lights/cast(list/targets)
/obj/effect/proc_holder/spell/aoe_turf/flicker_lights/cast(list/targets, mob/user = usr)
for(var/turf/T in targets)
for(var/obj/machinery/light/L in T)
L.flicker()
@@ -179,9 +179,9 @@
clothes_req = 0
range = 10
/obj/effect/proc_holder/spell/aoe_turf/blindness/cast(list/targets)
/obj/effect/proc_holder/spell/aoe_turf/blindness/cast(list/targets, mob/user = usr)
for(var/mob/living/L in living_mob_list)
if(L == usr)
if(L == user)
continue
var/turf/T = get_turf(L.loc)
if(T && T in targets)
@@ -200,7 +200,7 @@
range = -1
include_user = 1
/obj/effect/proc_holder/spell/targeted/night_vision/cast(list/targets)
/obj/effect/proc_holder/spell/targeted/night_vision/cast(list/targets, mob/user = usr)
for(var/mob/living/target in targets)
if(target.see_invisible == SEE_INVISIBLE_LIVING)
@@ -301,6 +301,9 @@
var/damage = rand(M.melee_damage_lower, M.melee_damage_upper)
attack_threshold_check(damage,M.melee_damage_type)
/mob/living/simple_animal/proc/attacked_by(obj/item/I, mob/living/user) // Handled in _onclick/click.dm
return
/mob/living/simple_animal/bullet_act(var/obj/item/projectile/Proj)
if(!Proj)
return
@@ -579,21 +582,7 @@
density = initial(density)
update_canmove()
/mob/living/simple_animal/show_inv(mob/user as mob)
user.set_machine(src)
var/dat = {"<table>
<tr><td><B>Left Hand:</B></td><td><A href='?src=[UID()];item=[slot_l_hand]'>[(l_hand && !(l_hand.flags&ABSTRACT)) ? l_hand : "<font color=grey>Empty</font>"]</A></td></tr>
<tr><td><B>Right Hand:</B></td><td><A href='?src=[UID()];item=[slot_r_hand]'>[(r_hand && !(r_hand.flags&ABSTRACT)) ? r_hand : "<font color=grey>Empty</font>"]</A></td></tr>
<tr><td>&nbsp;</td></tr>"}
if(can_collar)
dat += "<tr><td><B>Collar:</B></td><td><A href='?src=[UID()];[collar?"remove_inv":"add_inv"]=collar'>[(collar && !(collar.flags&ABSTRACT)) ? collar : "<font color=grey>Empty</font>"]</A></td></tr>"
dat += {"</table>
<A href='?src=[user.UID()];mach_close=mob\ref[src]'>Close</A>
"}
var/datum/browser/popup = new(user, "mob\ref[src]", "[src]", 440, 250)
popup.set_content(dat)
popup.open()
/mob/living/simple_animal/proc/make_babies() // <3 <3 <3
if(gender != FEMALE || stat || !scan_ready || !childtype || !simplespecies)
@@ -652,57 +641,74 @@
if(changed)
animate(src, transform = ntransform, time = 2, easing = EASE_IN|EASE_OUT)
/mob/living/simple_animal/Topic(href, href_list)
if(!usr.stat && usr.canmove && !usr.restrained() && in_range(src, usr))
if(href_list["remove_inv"])
if(!Adjacent(usr) || !(ishuman(usr) || isrobot(usr) || isalienadult(usr)))
return
var/remove_from = href_list["remove_inv"]
switch(remove_from)
if("collar")
if(!can_collar)
return
if(collar)
if(collar.flags & NODROP)
to_chat(usr, "<span class='warning'>\The [collar] is stuck too hard to [src] for you to remove!</span>")
return
collar.dropped(src)
collar.forceMove(src.loc)
collar = null
regenerate_icons()
else
to_chat(usr, "<span class='danger'>There is nothing to remove from its [remove_from].</span>")
return
show_inv(usr)
else if(href_list["add_inv"])
if(!Adjacent(usr) || !(ishuman(usr) || isrobot(usr) || isalienadult(usr)))
return
/* Inventory */
var/add_to = href_list["add_inv"]
switch(add_to)
if("collar")
if(!can_collar || collar)
return
var/obj/item/clothing/accessory/petcollar/C = usr.get_active_hand()
if(!istype(C))
usr.visible_message("[usr] rubs [src]'s neck.","<span class='notice'>You rub [src]'s neck for a moment.</span>")
return
usr.drop_item()
C.forceMove(src)
collar = C
collar.equipped(src)
regenerate_icons()
to_chat(usr, "<span class='notice'>You put \the [C] around \the [src]'s neck.</span>")
if(C.tagname)
name = C.tagname
real_name = C.tagname
show_inv(usr)
/mob/living/simple_animal/show_inv(mob/user as mob)
if(!can_collar)
return
user.set_machine(src)
var/dat = "<table><tr><td><B>Collar:</B></td><td><A href='?src=[UID()];item=[slot_collar]'>[(collar && !(collar.flags&ABSTRACT)) ? collar : "<font color=grey>Empty</font>"]</A></td></tr></table>"
dat += "<A href='?src=[user.UID()];mach_close=mob\ref[src]'>Close</A>"
var/datum/browser/popup = new(user, "mob\ref[src]", "[src]", 440, 250)
popup.set_content(dat)
popup.open()
/mob/living/simple_animal/get_item_by_slot(slot_id)
switch(slot_id)
if(slot_collar)
return collar
. = ..()
/mob/living/simple_animal/can_equip(obj/item/I, slot, disable_warning = 0)
// . = ..() // Do not call parent. We do not want animals using their hand slots.
switch(slot)
if(slot_collar)
if(collar)
return 0
if(!can_collar)
return 0
if(!istype(I, /obj/item/clothing/accessory/petcollar))
return 0
return 1
/mob/living/simple_animal/equip_to_slot(obj/item/W, slot)
if(!istype(W))
return 0
if(!slot)
return 0
W.forceMove(src)
W.equipped(src, slot)
W.layer = 20
W.plane = HUD_PLANE
switch(slot)
if(slot_collar)
collar = W
if(collar.tagname)
name = collar.tagname
real_name = collar.tagname
regenerate_icons()
/mob/living/simple_animal/unEquip(obj/item/I, force)
. = ..()
if(!. || !I)
return
if(I == collar)
collar = null
regenerate_icons()
/mob/living/simple_animal/get_access()
. = ..()
if(collar)
. |= collar.GetAccess()
/* End Inventory */
/mob/living/simple_animal/proc/sentience_act() //Called when a simple animal gains sentience via gold slime potion
return
@@ -40,6 +40,7 @@
return 0
spawn_delay = world.time + spawn_time
var/mob/living/simple_animal/L = new mob_type(src.loc)
L.admin_spawned = admin_spawned //If we were admin spawned, lets have our children count as that as well.
spawned_mobs += L
L.nest = src
L.faction = src.faction
+3 -1
View File
@@ -1222,9 +1222,11 @@ mob/proc/yank_out_object()
if(mind)
return mind.grab_ghost(force = force)
/mob/proc/notify_ghost_cloning(var/message = "Someone is trying to revive you. Re-enter your corpse if you want to be revived!", var/sound = 'sound/effects/genetics.ogg', var/atom/source = null)
/mob/proc/notify_ghost_cloning(message = "Someone is trying to revive you. Re-enter your corpse if you want to be revived!", sound = 'sound/effects/genetics.ogg', atom/source = null, flashwindow = TRUE)
var/mob/dead/observer/ghost = get_ghost()
if(ghost)
if(flashwindow)
window_flash(ghost.client)
ghost.notify_cloning(message, sound, source)
return ghost
+8 -6
View File
@@ -434,20 +434,22 @@ var/list/intents = list(I_HELP,I_DISARM,I_GRAB,I_HARM)
lname = "<span class='name'>[lname]</span> "
to_chat(M, "<span class='deadsay'>[lname][follow][message]</span>")
/proc/notify_ghosts(var/message, var/ghost_sound = null, var/enter_link = null, var/atom/source = null, var/image/alert_overlay = null, var/attack_not_jump = 0) //Easy notification of ghosts.
/proc/notify_ghosts(message, ghost_sound = null, enter_link = null, atom/source = null, image/alert_overlay = null, attack_not_jump = 0, flashwindow = TRUE, var/action = NOTIFY_JUMP) //Easy notification of ghosts.
for(var/mob/dead/observer/O in player_list)
if(O.client)
to_chat(O, "<span class='ghostalert'>[message][(enter_link) ? " [enter_link]" : ""]<span>")
if(ghost_sound)
O << sound(ghost_sound)
if(flashwindow)
window_flash(O.client)
if(source)
var/obj/screen/alert/notify_jump/A = O.throw_alert("\ref[source]_notify_jump", /obj/screen/alert/notify_jump)
var/obj/screen/alert/notify_action/A = O.throw_alert("\ref[source]_notify_action", /obj/screen/alert/notify_action)
if(A)
if(O.client.prefs && O.client.prefs.UI_style)
A.icon = ui_style2icon(O.client.prefs.UI_style)
A.desc = message
A.attack_not_jump = attack_not_jump
A.jump_target = source
A.action = action
A.target = source
if(!alert_overlay)
var/old_layer = source.layer
var/old_plane = source.plane
@@ -586,8 +588,8 @@ var/list/intents = list(I_HELP,I_DISARM,I_GRAB,I_HARM)
if(5)
newletter="glor"
newphrase+="[newletter]";counter-=1
return newphrase
return newphrase
/mob/proc/get_preference(toggleflag)
if(!client)
return FALSE
-125
View File
@@ -1,125 +0,0 @@
/*
/tg/station13 /datum Pool:
---------------------------------
By RemieRichards
Creation/Deletion is laggy, so let's reduce reuse and recycle!
Usage:
To get a object, just call
- PoolOrNew(type, arg) if you only want to pass one argument to New(), usually loc
- PoolOrNew(type, list) if you want to pass multiple arguments to New()
To put a object back in the pool, call PlaceInPool(object)
This will call destroy on the object, set its loc to null,
and reset all of its vars to their default
You can override your object's destroy to return QDEL_HINT_PUTINPOOL
to ensure its always placed in this pool (this will only be acted on if qdel calls destroy, and destroy will not get called twice)
For almost all pooling purposes, it is better to use the QDEL hint than to pool it directly with PlaceInPool
*/
var/global/list/GlobalPool = list()
//You'll be using this proc 90% of the time.
//It grabs a type from the pool if it can
//And if it can't, it creates one
//The pool is flexible and will expand to fit
//The new created atom when it eventually
//Goes into the pool
//Second argument can be a single arg
//Or a list of arguments
//Either way it gets passed to new
/proc/PoolOrNew(get_type,second_arg)
if(!get_type)
return
. = GetFromPool(get_type,second_arg)
if(!.)
if(ispath(get_type))
if(islist(second_arg))
. = new get_type (arglist(second_arg))
else
. = new get_type (second_arg)
/proc/GetFromPool(get_type,second_arg)
if(!get_type)
return
if(isnull(GlobalPool[get_type]))
return
if(length(GlobalPool[get_type]) == 0)
return
var/datum/pooled = pop(GlobalPool[get_type])
if(pooled)
var/atom/movable/AM
if(istype(pooled, /atom/movable))
AM = pooled
if(islist(second_arg))
if(AM)
AM.loc = second_arg[1] //we need to do loc setting explicetly before even calling New() to replicate new()'s behavior
pooled.New(arglist(second_arg))
else
if(AM)
AM.loc = second_arg
pooled.New(second_arg)
return pooled
/proc/PlaceInPool(datum/diver, destroy = 1)
if(!istype(diver))
return
if(diver in GlobalPool[diver.type])
return
if(!GlobalPool[diver.type])
GlobalPool[diver.type] = list()
GlobalPool[diver.type] |= diver
if(destroy)
diver.Destroy()
diver.ResetVars()
var/list/exclude = list("animate_movement", "contents", "loc", "locs", "parent_type", "vars", "verbs", "type")
var/list/pooledvariables = list()
//thanks to clusterfack @ /vg/station for these two procs
/datum/proc/createVariables()
pooledvariables[type] = new/list()
var/list/exclude = global.exclude + args
for(var/key in vars)
if(key in exclude)
continue
pooledvariables[type][key] = initial(vars[key])
/datum/proc/ResetVars()
if(!pooledvariables[type])
createVariables(args)
for(var/key in pooledvariables[type])
vars[key] = pooledvariables[type][key]
/atom/movable/ResetVars()
..()
loc = null
contents = initial(contents) //something is really wrong if this object still has stuff in it by this point
/image/ResetVars()
..()
loc = null
+3 -3
View File
@@ -80,12 +80,12 @@
to_chat(user, "You inject the solution into the power cell.")
if(S.reagents.has_reagent("plasma", 5))
if(S.reagents.has_reagent("plasma", 5) || S.reagents.has_reagent("plasma_dust", 5))
rigged = 1
log_admin("LOG: [user.name] ([user.ckey]) injected a power cell with plasma, rigging it to explode.")
message_admins("LOG: [user.name] ([user.ckey]) injected a power cell with plasma, rigging it to explode.")
log_admin("LOG: [key_name(user)] injected a power cell with plasma, rigging it to explode.")
message_admins("LOG: [key_name_admin(user)] injected a power cell with plasma, rigging it to explode.")
S.reagents.clear_reagents()
+3 -3
View File
@@ -674,10 +674,10 @@
to_chat(user, "You inject the solution into the [src].")
if(S.reagents.has_reagent("plasma", 5))
if(S.reagents.has_reagent("plasma", 5) || S.reagents.has_reagent("plasma_dust", 5))
log_admin("LOG: [user.name] ([user.ckey]) injected a light with plasma, rigging it to explode.")
message_admins("LOG: [user.name] ([user.ckey]) injected a light with plasma, rigging it to explode.")
log_admin("LOG: [key_name(user)] injected a light with plasma, rigging it to explode.")
message_admins("LOG: [key_name_admin(user)] injected a light with plasma, rigging it to explode.")
rigged = 1
+1 -1
View File
@@ -32,7 +32,7 @@
var/area/A = get_area(src)
if(A)
var/image/alert_overlay = image('icons/effects/effects.dmi', "ghostalertsie")
notify_ghosts("Nar-Sie has risen in \the [A.name]. Reach out to the Geometer to be given a new shell for your soul.", source = src, alert_overlay = alert_overlay, attack_not_jump = 1)
notify_ghosts("Nar-Sie has risen in \the [A.name]. Reach out to the Geometer to be given a new shell for your soul.", source = src, alert_overlay = alert_overlay, action=NOTIFY_ATTACK)
narsie_spawn_animation()
@@ -37,6 +37,7 @@
src.energy = starting_energy
..()
processing_objects.Add(src)
poi_list |= src
for(var/obj/machinery/power/singularity_beacon/singubeacon in world)
if(singubeacon.active)
target = singubeacon
@@ -45,6 +46,7 @@
/obj/singularity/Destroy()
processing_objects.Remove(src)
poi_list.Remove(src)
singularities -= src
target = null
return ..()
@@ -64,6 +64,7 @@
/obj/machinery/power/supermatter_shard/New()
. = ..()
poi_list |= src
radio = new(src)
radio.listening = 0
investigate_log("has been created.", "supermatter")
@@ -71,8 +72,10 @@
/obj/machinery/power/supermatter_shard/Destroy()
investigate_log("has been destroyed.", "supermatter")
qdel(radio)
radio = null
if(radio)
qdel(radio)
radio = null
poi_list.Remove(src)
return ..()
/obj/machinery/power/supermatter_shard/proc/explode()
+5
View File
@@ -34,6 +34,8 @@ var/list/blacklisted_tesla_types = typecacheof(list(/obj/machinery/atmospherics,
var/produced_power
var/energy_to_raise = 32
var/energy_to_lower = -20
/obj/singularity/energy_ball/Destroy()
if(orbiting && istype(orbiting, /obj/singularity/energy_ball))
@@ -44,6 +46,8 @@ var/list/blacklisted_tesla_types = typecacheof(list(/obj/machinery/atmospherics,
for(var/ball in orbiting_balls)
var/obj/singularity/energy_ball/EB = ball
qdel(EB)
poi_list.Remove(src)
return ..()
@@ -125,6 +129,7 @@ var/list/blacklisted_tesla_types = typecacheof(list(/obj/machinery/atmospherics,
/obj/singularity/energy_ball/orbit(obj/singularity/energy_ball/target)
if(istype(target))
target.orbiting_balls += src
poi_list.Remove(src)
. = ..()
+6
View File
@@ -188,3 +188,9 @@
//Behavior for magazines
/obj/item/ammo_box/magazine/proc/ammo_count()
return stored_ammo.len
/obj/item/ammo_box/magazine/proc/empty_magazine()
var/turf_mag = get_turf(src)
for(var/obj/item/ammo in stored_ammo)
ammo.forceMove(turf_mag)
stored_ammo -= ammo
@@ -3,6 +3,12 @@
caliber = "357"
projectile_type = /obj/item/projectile/bullet
/obj/item/ammo_casing/rubber9mm
desc = "A 9mm rubber bullet casing."
caliber = "9mm"
icon_state = "r-casing"
projectile_type = /obj/item/projectile/bullet/weakbullet4
/obj/item/ammo_casing/a762
desc = "A 7.62mm bullet casing."
icon_state = "762-casing"
@@ -20,6 +26,7 @@
/obj/item/ammo_casing/c38
desc = "A .38 bullet casing."
caliber = "38"
icon_state = "r-casing"
projectile_type = /obj/item/projectile/bullet/weakbullet2/rubber
/obj/item/ammo_casing/c10mm
@@ -76,6 +83,12 @@
caliber = "4.6x30mm"
projectile_type = /obj/item/projectile/bullet/incendiary/firebullet
/obj/item/ammo_casing/rubber45
desc = "A .45 rubber bullet casing."
caliber = ".45"
icon_state = "r-casing"
projectile_type = /obj/item/projectile/bullet/weakbullet4
/obj/item/ammo_casing/c45
desc = "A .45 bullet casing."
caliber = ".45"
@@ -120,7 +133,7 @@
/obj/item/ammo_casing/shotgun/rubbershot
name = "rubber shot"
desc = "A shotgun casing filled with densely-packed rubber balls, used to incapacitate crowds from a distance."
icon_state = "bshell"
icon_state = "cshell"
projectile_type = /obj/item/projectile/bullet/rpellet
pellets = 6
variance = 25
@@ -233,9 +246,9 @@
/obj/item/ammo_casing/shotgun/dart/New()
..()
flags |= NOREACT
flags |= OPENCONTAINER
create_reagents(30)
reagents.set_reacting(FALSE)
/obj/item/ammo_casing/shotgun/dart/attackby()
return
@@ -254,7 +267,7 @@
/obj/item/ammo_casing/shotgun/tranquilizer
name = "tranquilizer darts"
desc = "A tranquilizer round used to subdue individuals utilizing stimulants."
icon_state = "cshell"
icon_state = "nshell"
projectile_type = /obj/item/projectile/bullet/dart/syringe/tranquilizer
materials = list(MAT_METAL=250)
@@ -362,3 +375,9 @@
desc = "A cap for children toys."
caliber = "caps"
projectile_type = /obj/item/projectile/bullet/cap
/obj/item/ammo_casing/laser
desc = "An experimental laser casing."
caliber = "laser"
projectile_type = /obj/item/projectile/beam/laser
icon_state = "lasercasing"
+13 -3
View File
@@ -35,6 +35,12 @@
ammo_type = /obj/item/ammo_casing/c45
max_ammo = 20
/obj/item/ammo_box/rubber45
name = "ammo box (.45 rubber)"
icon_state = "45box-r"
ammo_type = /obj/item/ammo_casing/rubber45
max_ammo = 16
/obj/item/ammo_box/a40mm
name = "ammo box (40mm grenades)"
icon_state = "40mm"
@@ -52,14 +58,14 @@
/obj/item/ammo_box/n762
name = "ammo box (7.62x38mmR)"
icon_state = "10mmbox"
icon_state = "riflebox"
origin_tech = "combat=2"
ammo_type = /obj/item/ammo_casing/n762
max_ammo = 14
/obj/item/ammo_box/shotgun
name = "Ammunition Box (slug)"
icon_state = "9mmbox"
icon_state = "slugbox"
origin_tech = "combat=2"
ammo_type = /obj/item/ammo_casing/shotgun
max_ammo = 7
@@ -67,26 +73,30 @@
/obj/item/ammo_box/shotgun/buck
name = "Ammunition Box (buckshot)"
icon_state = "buckshotbox"
ammo_type = /obj/item/ammo_casing/shotgun/buckshot
/obj/item/ammo_box/shotgun/stun
name = "Ammunition Box (stun shells)"
icon_state = "stunbox"
ammo_type = /obj/item/ammo_casing/shotgun/stunslug
materials = list(MAT_METAL=1750)
/obj/item/ammo_box/shotgun/beanbag
name = "Ammunition Box (beanbag shells)"
icon_state = "beanbagbox"
ammo_type = /obj/item/ammo_casing/shotgun/beanbag
materials = list(MAT_METAL=1750)
/obj/item/ammo_box/shotgun/rubbershot
name = "Ammunition Box (rubbershot shells)"
icon_state = "rubbershotbox"
ammo_type = /obj/item/ammo_casing/shotgun/rubbershot
materials = list(MAT_METAL=28000)
/obj/item/ammo_box/shotgun/tranquilizer
name = "Ammunition Box (tranquilizer darts)"
icon_state = "45box"
icon_state = "tranqbox"
ammo_type = /obj/item/ammo_casing/shotgun/tranquilizer
materials = list(MAT_METAL=1750)
@@ -209,6 +209,34 @@
caliber = ".45"
max_ammo = 8
multiple_sprites = 1
/obj/item/ammo_box/magazine/m45/enforcer45
name = "handgun magazine (.45)"
icon_state = "enforcer"
ammo_type = /obj/item/ammo_casing/rubber45
/obj/item/ammo_box/magazine/m45/enforcer45/update_icon()
..()
overlays.Cut()
var/ammo = ammo_count()
if(ammo && is_rubber())
overlays += image('icons/obj/ammo.dmi', icon_state = "enforcer-r")
/obj/item/ammo_box/magazine/m45/enforcer45/examine(mob/user, var/distance)
..()
if(distance <= 2)
to_chat(user, "It seems to be loaded with [is_rubber() ? "rubber" : "lethal"] bullets.")//only can see the topmost one.
/obj/item/ammo_box/magazine/m45/enforcer45/proc/is_rubber()//if the topmost bullet is a rubber one
var/ammo = ammo_count()
if(!ammo)
return 0
if(istype(contents[contents.len], /obj/item/ammo_casing/rubber45))
return 1
return 0
/obj/item/ammo_box/magazine/m45/enforcer45/lethal
ammo_type = /obj/item/ammo_casing/c45
/obj/item/ammo_box/magazine/wt550m9
name = "wt550 magazine (4.6x30mm)"
@@ -409,3 +437,12 @@
/obj/item/ammo_box/magazine/toy/m762/update_icon()
..()
icon_state = "a762-[round(ammo_count(),10)]"
/obj/item/ammo_box/magazine/laser
name = "encased laser projector magazine"
desc = "Fits experimental laser ammo casings."
icon_state = "laser"
ammo_type = /obj/item/ammo_casing/laser
origin_tech = "combat=3"
caliber = "laser"
max_ammo = 20
@@ -26,6 +26,9 @@
/obj/item/ammo_casing/magic/chaos
projectile_type = /obj/item/projectile/magic
/obj/item/ammo_casing/magic/spellblade
projectile_type = /obj/item/projectile/magic/spellblade
/obj/item/ammo_casing/magic/chaos/newshot()
projectile_type = pick(typesof(/obj/item/projectile/magic))
+1 -1
View File
@@ -154,7 +154,7 @@
qdel(S)
D.icon_state = "syringeproj"
D.name = "syringe"
D.flags |= NOREACT
D.reagents.set_reacting(FALSE)
playsound(user.loc, 'sound/items/syringeproj.ogg', 50, 1)
for(var/i=0, i<6, i++)
+26 -1
View File
@@ -8,6 +8,7 @@
ammo_type = /obj/item/ammo_casing/magic/change
icon_state = "staffofchange"
item_state = "staffofchange"
fire_sound = "sound/magic/Staff_Change.ogg"
/obj/item/weapon/gun/magic/staff/animate
name = "staff of animation"
@@ -15,6 +16,7 @@
ammo_type = /obj/item/ammo_casing/magic/animate
icon_state = "staffofanimation"
item_state = "staffofanimation"
fire_sound = "sound/magic/Staff_animation.ogg"
/obj/item/weapon/gun/magic/staff/healing
name = "staff of healing"
@@ -22,6 +24,7 @@
ammo_type = /obj/item/ammo_casing/magic/heal
icon_state = "staffofhealing"
item_state = "staffofhealing"
fire_sound = "sound/magic/Staff_Healing.ogg"
/obj/item/weapon/gun/magic/staff/healing/handle_suicide() //Stops people trying to commit suicide to heal themselves
return
@@ -35,6 +38,7 @@
max_charges = 10
recharge_rate = 2
no_den_usage = 1
fire_sound = "sound/magic/Staff_Chaos.ogg"
/obj/item/weapon/gun/magic/staff/door
name = "staff of door creation"
@@ -45,16 +49,17 @@
max_charges = 10
recharge_rate = 2
no_den_usage = 1
fire_sound = "sound/magic/Staff_Door.ogg"
/obj/item/weapon/gun/magic/staff/honk
name = "staff of the honkmother"
desc = "Honk"
fire_sound = "sound/items/airhorn.ogg"
ammo_type = /obj/item/ammo_casing/magic/honk
icon_state = "honker"
item_state = "honker"
max_charges = 4
recharge_rate = 8
fire_sound = "sound/items/airhorn.ogg"
/obj/item/weapon/gun/magic/staff/focus
name = "mental focus"
@@ -63,3 +68,23 @@
icon_state = "focus"
item_state = "focus"
ammo_type = list(/obj/item/ammo_casing/forcebolt)
/obj/item/weapon/gun/magic/staff/spellblade
name = "spellblade"
desc = "A deadly combination of laziness and boodlust, this blade allows the user to dismember their enemies without all the hard work of actually swinging the sword."
fire_sound = "sound/magic/Fireball.ogg"
ammo_type = /obj/item/ammo_casing/magic/spellblade
icon_state = "spellblade"
item_state = "spellblade"
hitsound = 'sound/weapons/rapierhit.ogg'
force = 20
armour_penetration = 75
block_chance = 50
sharp = 1
edge = 1
max_charges = 4
/obj/item/weapon/gun/magic/staff/spellblade/hit_reaction(mob/living/carbon/human/owner, attack_text, final_block_chance, damage, attack_type)
if(attack_type == PROJECTILE_ATTACK)
final_block_chance = 0
return ..()
@@ -59,6 +59,7 @@
/obj/item/weapon/gun/magic/wand/death
name = "wand of death"
desc = "This deadly wand overwhelms the victim's body with pure energy, slaying them without fail."
fire_sound = "sound/magic/WandoDeath.ogg"
ammo_type = /obj/item/ammo_casing/magic/death
icon_state = "deathwand"
max_charges = 3 //3, 2, 2, 1
@@ -79,6 +80,7 @@
name = "wand of resurrection"
desc = "This wand uses healing magics to heal and revive. They are rarely utilized within the Wizard Federation for some reason."
ammo_type = /obj/item/ammo_casing/magic/heal
fire_sound = "sound/magic/Staff_Healing.ogg"
icon_state = "revivewand"
max_charges = 3 //3, 2, 2, 1
@@ -96,6 +98,7 @@
name = "wand of polymorph"
desc = "This wand is attuned to chaos and will radically alter the victim's form."
ammo_type = /obj/item/ammo_casing/magic/change
fire_sound = "sound/magic/Staff_Change.ogg"
icon_state = "polywand"
max_charges = 10 //10, 5, 5, 4
@@ -115,6 +118,7 @@
icon_state = "telewand"
max_charges = 10 //10, 5, 5, 4
no_den_usage = 1
fire_sound = "sound/magic/Wand_Teleport.ogg"
/obj/item/weapon/gun/magic/wand/teleport/zap_self(mob/living/user)
do_teleport(user, user, 10)
@@ -132,6 +136,7 @@
name = "wand of door creation"
desc = "This particular wand can create doors in any wall for the unscrupulous wizard who shuns teleportation magics."
ammo_type = /obj/item/ammo_casing/magic/door
fire_sound = "sound/magic/Staff_Door.ogg"
icon_state = "doorwand"
max_charges = 20 //20, 10, 10, 7
@@ -147,6 +152,7 @@
/obj/item/weapon/gun/magic/wand/fireball
name = "wand of fireball"
desc = "This wand shoots scorching balls of fire that explode into destructive flames."
fire_sound = "sound/magic/Fireball.ogg"
ammo_type = /obj/item/ammo_casing/magic/fireball
icon_state = "firewand"
max_charges = 8 //8, 4, 4, 3
@@ -249,3 +249,15 @@
/obj/item/weapon/gun/projectile/automatic/shotgun/bulldog/afterattack(atom/target as mob|obj|turf|area, mob/living/user as mob|obj, flag)
..()
empty_alarm()
/obj/item/weapon/gun/projectile/automatic/lasercarbine
name = "\improper IK-60 Laser Carbine"
desc = "An experimental carbine. Uses encased laser projectors as ammunition."//we need to uncouple the toroidal resistance dejammers
icon_state = "lasercarbine"
item_state = "laser"
w_class = 3
origin_tech = "combat=5;materials=5"
mag_type = /obj/item/ammo_box/magazine/laser
fire_sound = 'sound/weapons/emitter2.ogg'
can_suppress = 0
burst_size = 2
@@ -0,0 +1,98 @@
/obj/item/weapon/gun/projectile/bow
name = "bow"
desc = "A sturdy bow made out of wood and reinforced with iron."
icon_state = "bow_unloaded"
item_state = "bow"
fire_sound = 'sound/weapons/grenadelaunch.ogg'
mag_type = /obj/item/ammo_box/magazine/internal/bow
flags = HANDSLOW
weapon_weight = WEAPON_HEAVY
var/draw_sound = 'sound/weapons/draw_bow.ogg'
var/ready_to_fire = 0
var/slowdown_when_ready = 2
/obj/item/weapon/gun/projectile/bow/update_icon()
if(magazine.ammo_count() && !ready_to_fire)
icon_state = "bow_loaded"
else if(ready_to_fire)
icon_state = "bow_firing"
slowdown = slowdown_when_ready
else
icon_state = initial(icon_state)
slowdown = initial(slowdown)
/obj/item/weapon/gun/projectile/bow/dropped(mob/user)
if(magazine && magazine.ammo_count())
magazine.empty_magazine()
ready_to_fire = FALSE
update_icon()
/obj/item/weapon/gun/projectile/bow/attack_self(mob/living/user)
if(!ready_to_fire && magazine.ammo_count())
ready_to_fire = TRUE
playsound(user, draw_sound, 100, 1)
update_icon()
else
ready_to_fire = FALSE
update_icon()
/obj/item/weapon/gun/projectile/bow/attackby(obj/item/A, mob/user, params)
var/num_loaded = magazine.attackby(A, user, params, 1)
if(num_loaded)
to_chat(user, "<span class='notice'>You ready \the [A] into \the [src].</span>")
update_icon()
chamber_round()
/obj/item/weapon/gun/projectile/bow/can_shoot()
. = ..()
if(!ready_to_fire)
return FALSE
/obj/item/weapon/gun/projectile/bow/shoot_with_empty_chamber(mob/living/user as mob|obj)
return
/obj/item/weapon/gun/projectile/bow/process_chamber(eject_casing = 0, empty_chamber = 1)
. = ..()
ready_to_fire = FALSE
update_icon()
// ammo
/obj/item/ammo_box/magazine/internal/bow
name = "bow internal magazine"
ammo_type = /obj/item/ammo_casing/caseless/arrow
caliber = "arrow"
max_ammo = 1
/obj/item/projectile/bullet/reusable/arrow
name = "arrow"
icon_state = "arrow"
ammo_type = /obj/item/ammo_casing/caseless/arrow
range = 10
damage = 25
damage_type = BRUTE
/obj/item/ammo_casing/caseless/arrow
name = "arrow"
desc = "Stab, stab, stab."
icon_state = "arrow"
force = 10
sharp = 1
projectile_type = /obj/item/projectile/bullet/reusable/arrow
caliber = "arrow"
//quiver
/obj/item/weapon/storage/backpack/quiver
name = "quiver"
desc = "A quiver for holding arrows."
icon_state = "quiver"
item_state = "quiver"
storage_slots = 20
can_hold = list(
/obj/item/ammo_casing/caseless/arrow
)
/obj/item/weapon/storage/backpack/quiver/full/New()
..()
for(var/i in 1 to storage_slots)
new /obj/item/ammo_casing/caseless/arrow(src)
@@ -40,6 +40,14 @@
mag_type = /obj/item/ammo_box/magazine/m50
can_suppress = 0
/obj/item/weapon/gun/projectile/automatic/pistol/enforcer45
name = "Enforcer .45"
desc = "A pistol of modern design."
icon_state = "enforcer"
force = 10
mag_type = /obj/item/ammo_box/magazine/m45/enforcer45
can_suppress = 0
/obj/item/weapon/gun/projectile/automatic/pistol/deagle/update_icon()
..()
icon_state = "[initial(icon_state)][magazine ? "" : "-e"]"
@@ -87,7 +87,7 @@ obj/item/projectile/bullet/saw/incen/Move()
..()
var/turf/location = get_turf(src)
if(location)
PoolOrNew(/obj/effect/hotspot, location)
new /obj/effect/hotspot(location)
location.hotspot_expose(700, 50, 1)
/obj/item/projectile/bullet/saw/incen/on_hit(atom/target, blocked = 0)
@@ -53,6 +53,7 @@
damage = 70
stun = 5
weaken = 5
dismemberment = 50
armour_penetration = 50
var/breakthings = TRUE
@@ -82,6 +83,7 @@
armour_penetration = 0
nodamage = 1
stun = 0
dismemberment = 0
weaken = 0
breakthings = FALSE
@@ -113,6 +115,7 @@
armour_penetration = 15
damage = 15
stun = 0
dismemberment = 0
weaken = 0
breakthings = FALSE
@@ -142,5 +145,6 @@
damage = 60
forcedodge = 1
stun = 0
dismemberment = 0
weaken = 0
breakthings = FALSE
+1
View File
@@ -50,6 +50,7 @@
var/jitter = 0
var/embed = 0 // whether or not the projectile can embed itself in the mob
var/forcedodge = 0 //to pass through everything
var/dismemberment = 0 //The higher the number, the greater the bonus to dismembering. 0 will not dismember at all.
var/log = 1 //whether print to admin attack logs or just keep it in the diary
+11 -2
View File
@@ -42,6 +42,7 @@
damage = 5
weaken = 3
stamina = 60
icon_state = "bullet-r"
/obj/item/projectile/bullet/weakbullet2/rubber //detective's bullets that don't embed
embed = 0
@@ -50,6 +51,13 @@
/obj/item/projectile/bullet/weakbullet3
damage = 20
/obj/item/projectile/bullet/weakbullet4
name = "rubber bullet"
damage = 5
stamina = 30
icon_state = "bullet-r"
embed = 0
sharp = 0
/obj/item/projectile/bullet/toxinbullet
damage = 15
@@ -135,6 +143,7 @@
name = "rubber pellet"
damage = 3
stamina = 25
icon_state = "bullet-r"
/obj/item/projectile/bullet/stunshot//taser slugs for shotguns, nothing special
name = "stunshot"
@@ -234,8 +243,8 @@
/obj/item/projectile/bullet/dart/New()
..()
flags |= NOREACT
create_reagents(50)
reagents.set_reacting(FALSE)
/obj/item/projectile/bullet/dart/on_hit(var/atom/target, var/blocked = 0, var/hit_zone)
if(iscarbon(target))
@@ -251,7 +260,7 @@
target.visible_message("<span class='danger'>The [name] was deflected!</span>", \
"<span class='userdanger'>You were protected against the [name]!</span>")
..(target, blocked, hit_zone)
flags &= ~NOREACT
reagents.set_reacting(TRUE)
reagents.handle_reactions()
return 1

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