Merge branch 'master' into WanderingFox95-TheUnrollingPin
This commit is contained in:
@@ -428,7 +428,7 @@
|
||||
output += "<option value='[j]'>[j]</option>"
|
||||
for(var/j in GLOB.nonhuman_positions)
|
||||
output += "<option value='[j]'>[j]</option>"
|
||||
for(var/j in list(ROLE_TRAITOR, ROLE_CHANGELING, ROLE_OPERATIVE, ROLE_REV, ROLE_CULTIST, ROLE_WIZARD))
|
||||
for(var/j in list(ROLE_TRAITOR, ROLE_CHANGELING, ROLE_OPERATIVE, ROLE_REV, ROLE_CULTIST, ROLE_WIZARD, ROLE_HERETIC))
|
||||
output += "<option value='[j]'>[j]</option>"
|
||||
output += "</select></td></tr></table>"
|
||||
output += "<b>Reason:<br></b><textarea name='dbbanreason' cols='50'></textarea><br>"
|
||||
|
||||
@@ -93,7 +93,7 @@ GLOBAL_PROTECT(admin_verbs_ban)
|
||||
GLOBAL_LIST_INIT(admin_verbs_sounds, list(/client/proc/play_local_sound, /client/proc/play_sound, /client/proc/manual_play_web_sound, /client/proc/set_round_end_sound))
|
||||
GLOBAL_PROTECT(admin_verbs_sounds)
|
||||
GLOBAL_LIST_INIT(admin_verbs_fun, list(
|
||||
/client/proc/cmd_admin_dress,
|
||||
/client/proc/cmd_select_equipment,
|
||||
/client/proc/cmd_admin_gib_self,
|
||||
/client/proc/drop_bomb,
|
||||
/client/proc/set_dynex_scale,
|
||||
@@ -232,7 +232,7 @@ GLOBAL_LIST_INIT(admin_verbs_hideable, list(
|
||||
/client/proc/play_local_sound,
|
||||
/client/proc/play_sound,
|
||||
/client/proc/set_round_end_sound,
|
||||
/client/proc/cmd_admin_dress,
|
||||
/client/proc/cmd_select_equipment,
|
||||
/client/proc/cmd_admin_gib_self,
|
||||
/client/proc/drop_bomb,
|
||||
/client/proc/drop_dynex_bomb,
|
||||
|
||||
@@ -101,6 +101,10 @@ GLOBAL_VAR(antag_prototypes)
|
||||
out += "Mind currently owned by key: [key] [active?"(synced)":"(not synced)"]<br>"
|
||||
out += "Assigned role: [assigned_role]. <a href='?src=[REF(src)];role_edit=1'>Edit</a><br>"
|
||||
out += "Faction and special role: <b><font color='red'>[special_role]</font></b><br>"
|
||||
var/datum/component/activity/activity = current.GetComponent(/datum/component/activity)
|
||||
if(activity)
|
||||
out += "Activity level: [activity.activity_level]<br>"
|
||||
out += "Hasn't changed areas in approximately [activity.not_moved_counter] seconds"
|
||||
|
||||
var/special_statuses = get_special_statuses()
|
||||
if(length(special_statuses))
|
||||
|
||||
@@ -0,0 +1,196 @@
|
||||
|
||||
/client/proc/open_outfit_editor(datum/outfit/target)
|
||||
var/datum/outfit_editor/ui = new(usr, target)
|
||||
ui.ui_interact(usr)
|
||||
|
||||
#define OUTFIT_EDITOR_NAME "Outfit-O-Tron 9000"
|
||||
/datum/outfit_editor
|
||||
var/client/owner
|
||||
|
||||
var/dummy_key
|
||||
|
||||
var/datum/outfit/drip
|
||||
|
||||
/datum/outfit_editor/New(user, datum/outfit/target)
|
||||
owner = CLIENT_FROM_VAR(user)
|
||||
|
||||
if(ispath(target))
|
||||
drip = new /datum/outfit
|
||||
drip.copy_from(new target)
|
||||
else if(istype(target))
|
||||
drip = target
|
||||
else
|
||||
drip = new /datum/outfit
|
||||
drip.name = "New Outfit"
|
||||
|
||||
/datum/outfit_editor/ui_state(mob/user)
|
||||
return GLOB.admin_state
|
||||
|
||||
/datum/outfit_editor/ui_status(mob/user, datum/ui_state/state)
|
||||
if(QDELETED(drip))
|
||||
return UI_CLOSE
|
||||
return ..()
|
||||
|
||||
/datum/outfit_editor/ui_close(mob/user)
|
||||
clear_human_dummy(dummy_key)
|
||||
qdel(src)
|
||||
|
||||
/datum/outfit_editor/proc/init_dummy()
|
||||
dummy_key = "outfit_editor_[owner]"
|
||||
generate_dummy_lookalike(dummy_key, owner.mob)
|
||||
unset_busy_human_dummy(dummy_key)
|
||||
|
||||
/datum/outfit_editor/ui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, "OutfitEditor", OUTFIT_EDITOR_NAME)
|
||||
ui.open()
|
||||
ui.set_autoupdate(FALSE)
|
||||
|
||||
/datum/outfit_editor/proc/entry(data)
|
||||
if(ispath(data, /obj/item))
|
||||
var/obj/item/item = data
|
||||
return list(
|
||||
"path" = item,
|
||||
"name" = initial(item.name),
|
||||
"desc" = initial(item.desc),
|
||||
// at this point initializing the item is probably faster tbh
|
||||
"sprite" = icon2base64(icon(initial(item.icon), initial(item.icon_state))),
|
||||
)
|
||||
|
||||
return data
|
||||
|
||||
/datum/outfit_editor/proc/serialize_outfit()
|
||||
var/list/outfit_slots = drip.get_json_data()
|
||||
. = list()
|
||||
for(var/key in outfit_slots)
|
||||
var/val = outfit_slots[key]
|
||||
. += list("[key]" = entry(val))
|
||||
|
||||
/datum/outfit_editor/ui_data(mob/user)
|
||||
var/list/data = list()
|
||||
|
||||
data["outfit"] = serialize_outfit()
|
||||
data["saveable"] = !GLOB.custom_outfits.Find(drip)
|
||||
|
||||
if(!dummy_key)
|
||||
init_dummy()
|
||||
var/icon/dummysprite = get_flat_human_icon(null,
|
||||
dummy_key = dummy_key,
|
||||
showDirs = list(SOUTH),
|
||||
outfit_override = drip)
|
||||
data["dummy64"] = icon2base64(dummysprite)
|
||||
|
||||
return data
|
||||
|
||||
|
||||
/datum/outfit_editor/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
|
||||
if(..())
|
||||
return
|
||||
. = TRUE
|
||||
|
||||
var/slot = params["slot"]
|
||||
switch(action)
|
||||
if("click")
|
||||
choose_item(slot)
|
||||
if("ctrlClick")
|
||||
choose_any_item(slot)
|
||||
if("clear")
|
||||
if(drip.vars.Find(slot))
|
||||
drip.vars[slot] = null
|
||||
|
||||
if("rename")
|
||||
var/newname = stripped_input(owner, "What do you want to name this outfit?", OUTFIT_EDITOR_NAME)
|
||||
if(newname)
|
||||
drip.name = newname
|
||||
if("save")
|
||||
GLOB.custom_outfits |= drip
|
||||
SStgui.update_user_uis(owner.mob)
|
||||
if("delete")
|
||||
GLOB.custom_outfits -= drip
|
||||
SStgui.update_user_uis(owner.mob)
|
||||
if("vv")
|
||||
owner.debug_variables(drip)
|
||||
|
||||
|
||||
/datum/outfit_editor/proc/set_item(slot, obj/item/choice)
|
||||
if(!choice)
|
||||
return
|
||||
if(!ispath(choice))
|
||||
alert(owner, "Invalid item", OUTFIT_EDITOR_NAME, "oh no")
|
||||
return
|
||||
if(initial(choice.icon_state) == null) //hacky check copied from experimentor code
|
||||
var/msg = "Warning: This item's icon_state is null, indicating it is very probably not actually a usable item."
|
||||
if(alert(owner, msg, OUTFIT_EDITOR_NAME, "Use it anyway", "Cancel") != "Use it anyway")
|
||||
return
|
||||
|
||||
if(drip.vars.Find(slot))
|
||||
drip.vars[slot] = choice
|
||||
|
||||
/datum/outfit_editor/proc/choose_any_item(slot)
|
||||
var/obj/item/choice = pick_closest_path(FALSE)
|
||||
|
||||
if(!choice)
|
||||
return
|
||||
|
||||
set_item(slot, choice)
|
||||
|
||||
//this proc will try to give a good selection of items that the user can choose from
|
||||
//it does *not* give a selection of all items that can fit in a slot because lag;
|
||||
//most notably the hand and pocket slots because they accept pretty much anything
|
||||
//also stuff that fits in the belt and back slots are scattered pretty much all over the place
|
||||
/datum/outfit_editor/proc/choose_item(slot)
|
||||
var/list/options = list()
|
||||
|
||||
switch(slot)
|
||||
if("head")
|
||||
options = typesof(/obj/item/clothing/head)
|
||||
if("glasses")
|
||||
options = typesof(/obj/item/clothing/glasses)
|
||||
if("ears")
|
||||
options = typesof(/obj/item/radio/headset)
|
||||
|
||||
if("neck")
|
||||
options = typesof(/obj/item/clothing/neck)
|
||||
if("mask")
|
||||
options = typesof(/obj/item/clothing/mask)
|
||||
|
||||
if("uniform")
|
||||
options = typesof(/obj/item/clothing/under)
|
||||
if("suit")
|
||||
options = typesof(/obj/item/clothing/suit)
|
||||
if("gloves")
|
||||
options = typesof(/obj/item/clothing/gloves)
|
||||
|
||||
if("suit_store")
|
||||
var/obj/item/clothing/suit/suit = drip.suit
|
||||
if(suit)
|
||||
suit = new suit //initial() doesn't like lists
|
||||
options = suit.allowed
|
||||
if(!options.len) //nothing will happen, but don't let the user think it's broken
|
||||
to_chat(owner, "<span class='warning'>No options available for the current suit.</span>")
|
||||
|
||||
if("belt")
|
||||
options = typesof(/obj/item/storage/belt)
|
||||
if("id")
|
||||
options = typesof(/obj/item/card/id)
|
||||
|
||||
if("l_hand")
|
||||
choose_any_item(slot)
|
||||
if("back")
|
||||
options = typesof(/obj/item/storage/backpack)
|
||||
if("r_hand")
|
||||
choose_any_item(slot)
|
||||
|
||||
if("l_pocket")
|
||||
choose_any_item(slot)
|
||||
if("shoes")
|
||||
options = typesof(/obj/item/clothing/shoes)
|
||||
if("r_pocket")
|
||||
choose_any_item(slot)
|
||||
|
||||
if(length(options))
|
||||
set_item(slot, tgui_input_list(owner, "Choose an item", OUTFIT_EDITOR_NAME, options))
|
||||
|
||||
|
||||
#undef OUTFIT_EDITOR_NAME
|
||||
@@ -0,0 +1,73 @@
|
||||
/client/proc/outfit_manager()
|
||||
set category = "Debug"
|
||||
set name = "Outfit Manager"
|
||||
|
||||
if(!check_rights(R_DEBUG))
|
||||
return
|
||||
var/datum/outfit_manager/ui = new(usr)
|
||||
ui.ui_interact(usr)
|
||||
|
||||
|
||||
/datum/outfit_manager
|
||||
var/client/owner
|
||||
|
||||
/datum/outfit_manager/New(user)
|
||||
owner = CLIENT_FROM_VAR(user)
|
||||
|
||||
/datum/outfit_manager/ui_state(mob/user)
|
||||
return GLOB.admin_state
|
||||
|
||||
/datum/outfit_manager/ui_close(mob/user)
|
||||
qdel(src)
|
||||
|
||||
/datum/outfit_manager/ui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, "OutfitManager")
|
||||
ui.open()
|
||||
|
||||
/datum/outfit_manager/proc/entry(datum/outfit/outfit)
|
||||
var/vv = FALSE
|
||||
var/datum/outfit/varedit/varoutfit = outfit
|
||||
if(istype(varoutfit))
|
||||
vv = length(varoutfit.vv_values)
|
||||
return list(
|
||||
"name" = "[outfit.name] [vv ? "(VV)" : ""]",
|
||||
"ref" = REF(outfit),
|
||||
)
|
||||
|
||||
/datum/outfit_manager/ui_data(mob/user)
|
||||
var/list/data = list()
|
||||
|
||||
var/list/outfits = list()
|
||||
for(var/datum/outfit/custom_outfit in GLOB.custom_outfits)
|
||||
outfits += list(entry(custom_outfit))
|
||||
data["outfits"] = outfits
|
||||
|
||||
return data
|
||||
|
||||
/datum/outfit_manager/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
|
||||
if(..())
|
||||
return
|
||||
. = TRUE
|
||||
|
||||
switch(action)
|
||||
if("new")
|
||||
owner.open_outfit_editor(new /datum/outfit)
|
||||
if("load")
|
||||
owner.holder.load_outfit(owner.mob)
|
||||
if("copy")
|
||||
var/datum/outfit/outfit = tgui_input_list(owner, "Pick an outfit to copy from", "Outfit Manager", subtypesof(/datum/outfit))
|
||||
if(ispath(outfit))
|
||||
owner.open_outfit_editor(new outfit)
|
||||
|
||||
var/datum/outfit/target_outfit = locate(params["outfit"])
|
||||
if(!istype(target_outfit))
|
||||
return
|
||||
switch(action) //wow we're switching through action again this is horrible optimization smh
|
||||
if("edit")
|
||||
owner.open_outfit_editor(target_outfit)
|
||||
if("save")
|
||||
owner.holder.save_outfit(owner.mob, target_outfit)
|
||||
if("delete")
|
||||
owner.holder.delete_outfit(owner.mob, target_outfit)
|
||||
@@ -0,0 +1,32 @@
|
||||
GLOBAL_LIST_EMPTY(custom_outfits) //Admin created outfits
|
||||
|
||||
/datum/admins/proc/save_outfit(mob/admin, datum/outfit/O)
|
||||
O.save_to_file(admin)
|
||||
SStgui.update_user_uis(admin)
|
||||
|
||||
/datum/admins/proc/delete_outfit(mob/admin, datum/outfit/O)
|
||||
GLOB.custom_outfits -= O
|
||||
qdel(O)
|
||||
to_chat(admin,"<span class='notice'>Outfit deleted.</span>")
|
||||
SStgui.update_user_uis(admin)
|
||||
|
||||
/datum/admins/proc/load_outfit(mob/admin)
|
||||
var/outfit_file = input("Pick outfit json file:", "File") as null|file
|
||||
if(!outfit_file)
|
||||
return
|
||||
var/filedata = file2text(outfit_file)
|
||||
var/json = json_decode(filedata)
|
||||
if(!json)
|
||||
to_chat(admin,"<span class='warning'>JSON decode error.</span>")
|
||||
return
|
||||
var/otype = text2path(json["outfit_type"])
|
||||
if(!ispath(otype,/datum/outfit))
|
||||
to_chat(admin,"<span class='warning'>Malformed/Outdated file.</span>")
|
||||
return
|
||||
var/datum/outfit/O = new otype
|
||||
if(!O.load_from(json))
|
||||
to_chat(admin,"<span class='warning'>Malformed/Outdated file.</span>")
|
||||
return
|
||||
GLOB.custom_outfits += O
|
||||
SStgui.update_user_uis(admin)
|
||||
|
||||
@@ -870,6 +870,12 @@
|
||||
else
|
||||
dat += "<td width='20%'><a href='?src=[REF(src)];[HrefToken()];jobban3=changeling;jobban4=[REF(M)]'>Changeling</a></td>"
|
||||
|
||||
//Heretic
|
||||
if(jobban_isbanned(M, ROLE_HERETIC) || isbanned_dept)
|
||||
dat += "<td width='20%'><a href='?src=[REF(src)];[HrefToken()];jobban3=heretic;jobban4=[REF(M)]'><font color=red>Heretic</font></a></td>"
|
||||
else
|
||||
dat += "<td width='20%'><a href='?src=[REF(src)];[HrefToken()];jobban3=heretic;jobban4=[REF(M)]'>Heretic</a></td>"
|
||||
|
||||
//Nuke Operative
|
||||
if(jobban_isbanned(M, ROLE_OPERATIVE) || isbanned_dept)
|
||||
dat += "<td width='20%'><a href='?src=[REF(src)];[HrefToken()];jobban3=operative;jobban4=[REF(M)]'><font color=red>Nuke Operative</font></a></td>"
|
||||
|
||||
@@ -484,74 +484,52 @@
|
||||
set name = "Test Areas (ALL)"
|
||||
cmd_admin_areatest(FALSE)
|
||||
|
||||
/client/proc/cmd_admin_dress(mob/M in GLOB.mob_list)
|
||||
set category = "Admin.Events"
|
||||
set name = "Select equipment"
|
||||
if(!(ishuman(M) || isobserver(M)))
|
||||
alert("Invalid mob")
|
||||
return
|
||||
|
||||
var/dresscode = robust_dress_shop()
|
||||
|
||||
if(!dresscode)
|
||||
return
|
||||
|
||||
var/delete_pocket
|
||||
var/mob/living/carbon/human/H
|
||||
if(isobserver(M))
|
||||
H = M.change_mob_type(/mob/living/carbon/human, null, null, TRUE)
|
||||
else
|
||||
H = M
|
||||
if(alert("Drop Items in Pockets? No will delete them.", "Robust quick dress shop", "Yes", "No") == "No")
|
||||
delete_pocket = TRUE
|
||||
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Select Equipment") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
for (var/obj/item/I in H.get_equipped_items(delete_pocket))
|
||||
qdel(I)
|
||||
if(dresscode != "Naked")
|
||||
H.equipOutfit(dresscode)
|
||||
|
||||
H.regenerate_icons()
|
||||
|
||||
log_admin("[key_name(usr)] changed the equipment of [key_name(H)] to [dresscode].")
|
||||
message_admins("<span class='adminnotice'>[key_name_admin(usr)] changed the equipment of [ADMIN_LOOKUPFLW(H)] to [dresscode].</span>")
|
||||
|
||||
/client/proc/robust_dress_shop()
|
||||
var/list/outfits = list("Cancel","Naked","Custom","As Job...")
|
||||
var/list/paths = subtypesof(/datum/outfit) - typesof(/datum/outfit/job)
|
||||
|
||||
var/list/baseoutfits = list("Naked","Custom","As Job...", "As Plasmaman...")
|
||||
var/list/outfits = list()
|
||||
var/list/paths = subtypesof(/datum/outfit) - typesof(/datum/outfit/job) - typesof(/datum/outfit/plasmaman)
|
||||
|
||||
for(var/path in paths)
|
||||
var/datum/outfit/O = path //not much to initalize here but whatever
|
||||
if(initial(O.can_be_admin_equipped))
|
||||
outfits[initial(O.name)] = path
|
||||
outfits[initial(O.name)] = path
|
||||
|
||||
var/dresscode = input("Select outfit", "Robust quick dress shop") as null|anything in outfits
|
||||
var/dresscode = input("Select outfit", "Robust quick dress shop") as null|anything in baseoutfits + sortList(outfits)
|
||||
if (isnull(dresscode))
|
||||
return
|
||||
|
||||
if (outfits[dresscode])
|
||||
dresscode = outfits[dresscode]
|
||||
|
||||
if(dresscode == "Cancel")
|
||||
return
|
||||
|
||||
if (dresscode == "As Job...")
|
||||
var/list/job_paths = subtypesof(/datum/outfit/job)
|
||||
var/list/job_outfits = list()
|
||||
for(var/path in job_paths)
|
||||
var/datum/outfit/O = path
|
||||
if(initial(O.can_be_admin_equipped))
|
||||
job_outfits[initial(O.name)] = path
|
||||
job_outfits[initial(O.name)] = path
|
||||
|
||||
dresscode = input("Select job equipment", "Robust quick dress shop") as null|anything in job_outfits
|
||||
dresscode = input("Select job equipment", "Robust quick dress shop") as null|anything in sortList(job_outfits)
|
||||
dresscode = job_outfits[dresscode]
|
||||
if(isnull(dresscode))
|
||||
return
|
||||
|
||||
if (dresscode == "As Plasmaman...")
|
||||
var/list/plasmaman_paths = typesof(/datum/outfit/plasmaman)
|
||||
var/list/plasmaman_outfits = list()
|
||||
for(var/path in plasmaman_paths)
|
||||
var/datum/outfit/O = path
|
||||
plasmaman_outfits[initial(O.name)] = path
|
||||
|
||||
dresscode = input("Select plasmeme equipment", "Robust quick dress shop") as null|anything in sortList(plasmaman_outfits)
|
||||
dresscode = plasmaman_outfits[dresscode]
|
||||
if(isnull(dresscode))
|
||||
return
|
||||
|
||||
if (dresscode == "Custom")
|
||||
var/list/custom_names = list()
|
||||
for(var/datum/outfit/D in GLOB.custom_outfits)
|
||||
custom_names[D.name] = D
|
||||
var/selected_name = input("Select outfit", "Robust quick dress shop") as null|anything in custom_names
|
||||
var/selected_name = input("Select outfit", "Robust quick dress shop") as null|anything in sortList(custom_names)
|
||||
dresscode = custom_names[selected_name]
|
||||
if(isnull(dresscode))
|
||||
return
|
||||
|
||||
@@ -879,8 +879,6 @@ Traitors and the like can also be revived with the previous role mostly intact.
|
||||
message_admins("[ADMIN_LOOKUPFLW(usr)] [N.timing ? "activated" : "deactivated"] a nuke at [ADMIN_VERBOSEJMP(N)].")
|
||||
SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle Nuke", "[N.timing]")) //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
GLOBAL_LIST_EMPTY(custom_outfits) //Admin created outfits
|
||||
|
||||
/client/proc/create_outfits()
|
||||
set category = "Debug"
|
||||
set name = "Create Custom Outfit"
|
||||
@@ -1547,6 +1545,55 @@ GLOBAL_LIST_EMPTY(custom_outfits) //Admin created outfits
|
||||
msg += "</UL></BODY></HTML>"
|
||||
src << browse(msg.Join(), "window=Player_playtime_check")
|
||||
|
||||
/obj/effect/temp_visual/fireball
|
||||
icon = 'icons/obj/wizard.dmi'
|
||||
icon_state = "fireball"
|
||||
name = "fireball"
|
||||
desc = "Get out of the way!"
|
||||
layer = FLY_LAYER
|
||||
randomdir = FALSE
|
||||
duration = 9
|
||||
pixel_z = 270
|
||||
|
||||
/obj/effect/temp_visual/fireball/Initialize()
|
||||
. = ..()
|
||||
animate(src, pixel_z = 0, time = duration)
|
||||
|
||||
/obj/effect/temp_visual/target
|
||||
icon = 'icons/mob/actions/actions_items.dmi'
|
||||
icon_state = "sniper_zoom"
|
||||
layer = BELOW_MOB_LAYER
|
||||
light_range = 2
|
||||
duration = 9
|
||||
|
||||
/obj/effect/temp_visual/target/ex_act()
|
||||
return
|
||||
|
||||
/obj/effect/temp_visual/target/Initialize(mapload, list/flame_hit)
|
||||
. = ..()
|
||||
INVOKE_ASYNC(src, .proc/fall, flame_hit)
|
||||
|
||||
/obj/effect/temp_visual/target/proc/fall(list/flame_hit)
|
||||
var/turf/T = get_turf(src)
|
||||
playsound(T,'sound/magic/fleshtostone.ogg', 80, 1)
|
||||
new /obj/effect/temp_visual/fireball(T)
|
||||
sleep(duration)
|
||||
if(ismineralturf(T))
|
||||
var/turf/closed/mineral/M = T
|
||||
M.gets_drilled()
|
||||
playsound(T, "explosion", 80, 1)
|
||||
new /obj/effect/hotspot(T)
|
||||
T.hotspot_expose(700, 50, 1)
|
||||
for(var/mob/living/L in T.contents)
|
||||
if(istype(L, /mob/living/simple_animal/hostile/megafauna/dragon))
|
||||
continue
|
||||
if(islist(flame_hit) && !flame_hit[L])
|
||||
L.adjustFireLoss(40)
|
||||
to_chat(L, "<span class='userdanger'>You're hit by the drake's fire breath!</span>")
|
||||
flame_hit[L] = TRUE
|
||||
else
|
||||
L.adjustFireLoss(10) //if we've already hit them, do way less damage
|
||||
|
||||
/datum/admins/proc/cmd_show_exp_panel(client/client_to_check)
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
|
||||
@@ -0,0 +1,227 @@
|
||||
/client/proc/cmd_select_equipment(mob/target in GLOB.mob_list)
|
||||
set category = "Admin.Events"
|
||||
set name = "Select equipment"
|
||||
|
||||
|
||||
var/datum/select_equipment/ui = new(usr, target)
|
||||
ui.ui_interact(usr)
|
||||
|
||||
/*
|
||||
* This is the datum housing the select equipment UI.
|
||||
*
|
||||
* You may notice some oddities about the way outfits are passed to the UI and vice versa here.
|
||||
* That's because it handles both outfit typepaths (for normal outfits) *and* outfit objects (for custom outfits).
|
||||
*
|
||||
* Custom outfits need to be objects as they're created in runtime.
|
||||
* "Then just handle the normal outfits as objects too and simplify the handling" - you may say.
|
||||
* There are about 300 outfit types at the time of writing this. Initializing all of these to objects would be a huge waste.
|
||||
*
|
||||
*/
|
||||
|
||||
/datum/select_equipment
|
||||
var/client/user
|
||||
var/mob/target_mob
|
||||
|
||||
var/dummy_key
|
||||
|
||||
//static list to share all the outfit typepaths between all instances of this datum.
|
||||
var/static/list/cached_outfits
|
||||
|
||||
//a typepath if the selected outfit is a normal outfit;
|
||||
//an object if the selected outfit is a custom outfit
|
||||
var/datum/outfit/selected_outfit = /datum/outfit
|
||||
//serializable string for the UI to keep track of which outfit is selected
|
||||
var/selected_identifier = "/datum/outfit"
|
||||
|
||||
/datum/select_equipment/New(_user, mob/target)
|
||||
user = CLIENT_FROM_VAR(_user)
|
||||
|
||||
if(!ishuman(target) && !isobserver(target))
|
||||
alert("Invalid mob")
|
||||
return
|
||||
target_mob = target
|
||||
|
||||
/datum/select_equipment/ui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, "SelectEquipment", "Select Equipment")
|
||||
ui.open()
|
||||
ui.set_autoupdate(FALSE)
|
||||
|
||||
/datum/select_equipment/ui_state(mob/user)
|
||||
return GLOB.admin_state
|
||||
|
||||
/datum/select_equipment/ui_status(mob/user, datum/ui_state/state)
|
||||
if(QDELETED(target_mob))
|
||||
return UI_CLOSE
|
||||
return ..()
|
||||
|
||||
/datum/select_equipment/ui_close(mob/user)
|
||||
clear_human_dummy(dummy_key)
|
||||
qdel(src)
|
||||
|
||||
/datum/select_equipment/proc/init_dummy()
|
||||
dummy_key = "selectequipmentUI_[target_mob]"
|
||||
generate_dummy_lookalike(dummy_key, target_mob)
|
||||
unset_busy_human_dummy(dummy_key)
|
||||
return
|
||||
|
||||
/**
|
||||
* Packs up data about an outfit as an assoc list to send to the UI as an outfit entry.
|
||||
*
|
||||
* Args:
|
||||
* * category (string) - The tab it will be under
|
||||
*
|
||||
* * identifier (typepath or ref) - This will sent this back to ui_act to preview or spawn in an outfit.
|
||||
* * Must be unique between all entries.
|
||||
*
|
||||
* * name (string) - Will be the text on the button
|
||||
*
|
||||
* * priority (bool)(optional) - If True, the UI will sort the entry to the top, right below favorites.
|
||||
*
|
||||
* * custom_entry (bool)(optional) - Send the identifier with a "ref" keyword instead of "path",
|
||||
* * for the UI to tell apart custom outfits from normal ones.
|
||||
*
|
||||
* Returns (list) An outfit entry
|
||||
*/
|
||||
|
||||
/datum/select_equipment/proc/outfit_entry(category, identifier, name, priority=FALSE, custom_entry=FALSE)
|
||||
if(custom_entry)
|
||||
return list("category" = category, "ref" = identifier, "name" = name, "priority" = priority)
|
||||
return list("category" = category, "path" = identifier, "name" = name, "priority" = priority)
|
||||
|
||||
/datum/select_equipment/proc/make_outfit_entries(category="General", list/outfit_list)
|
||||
var/list/entries = list()
|
||||
for(var/path as anything in outfit_list)
|
||||
var/datum/outfit/outfit = path
|
||||
entries += list(outfit_entry(category, path, initial(outfit.name)))
|
||||
return entries
|
||||
|
||||
//GLOB.custom_outfits lists outfit *objects* so we'll need to do some custom handling for it
|
||||
/datum/select_equipment/proc/make_custom_outfit_entries(list/outfit_list)
|
||||
var/list/entries = list()
|
||||
for(var/datum/outfit/outfit as anything in outfit_list)
|
||||
entries += list(outfit_entry("Custom", REF(outfit), outfit.name, custom_entry=TRUE)) //it's either this or special handling on the UI side
|
||||
return entries
|
||||
|
||||
/datum/select_equipment/ui_data(mob/user)
|
||||
var/list/data = list()
|
||||
if(!dummy_key)
|
||||
init_dummy()
|
||||
|
||||
var/icon/dummysprite = get_flat_human_icon(null,
|
||||
dummy_key = dummy_key,
|
||||
outfit_override = selected_outfit,
|
||||
no_anim = TRUE)
|
||||
data["icon64"] = icon2base64(dummysprite)
|
||||
data["name"] = target_mob
|
||||
|
||||
var/datum/preferences/prefs = user?.client?.prefs
|
||||
data["favorites"] = list()
|
||||
if(prefs)
|
||||
data["favorites"] = prefs.favorite_outfits
|
||||
|
||||
var/list/custom
|
||||
custom += make_custom_outfit_entries(GLOB.custom_outfits)
|
||||
data["custom_outfits"] = custom
|
||||
data["current_outfit"] = selected_identifier
|
||||
return data
|
||||
|
||||
|
||||
/datum/select_equipment/ui_static_data(mob/user)
|
||||
var/list/data = list()
|
||||
if(!cached_outfits)
|
||||
cached_outfits = list()
|
||||
cached_outfits += list(outfit_entry("General", /datum/outfit, "Naked", priority=TRUE))
|
||||
cached_outfits += make_outfit_entries("General", subtypesof(/datum/outfit) - typesof(/datum/outfit/job) - typesof(/datum/outfit/plasmaman))
|
||||
cached_outfits += make_outfit_entries("Jobs", typesof(/datum/outfit/job))
|
||||
cached_outfits += make_outfit_entries("Plasmamen Outfits", typesof(/datum/outfit/plasmaman))
|
||||
|
||||
data["outfits"] = cached_outfits
|
||||
return data
|
||||
|
||||
|
||||
/datum/select_equipment/proc/resolve_outfit(text)
|
||||
|
||||
var/path = text2path(text)
|
||||
if(ispath(path, /datum/outfit))
|
||||
return path
|
||||
|
||||
else //don't bail yet - could be a custom outfit
|
||||
var/datum/outfit/custom_outfit = locate(text)
|
||||
if(istype(custom_outfit))
|
||||
return custom_outfit
|
||||
|
||||
|
||||
/datum/select_equipment/ui_act(action, params)
|
||||
if(..())
|
||||
return
|
||||
. = TRUE
|
||||
switch(action)
|
||||
if("preview")
|
||||
var/datum/outfit/new_outfit = resolve_outfit(params["path"])
|
||||
|
||||
if(ispath(new_outfit)) //got a typepath - that means we're dealing with a normal outfit
|
||||
selected_identifier = new_outfit //these are keyed by type
|
||||
//by the way, no, they can't be keyed by name because many of them have duplicate names
|
||||
|
||||
else if(istype(new_outfit)) //got an initialized object - means it's a custom outfit
|
||||
selected_identifier = REF(new_outfit) //and the outfit will be keyed by its ref (cause its type will always be /datum/outfit)
|
||||
|
||||
else //we got nothing and should bail
|
||||
return
|
||||
|
||||
selected_outfit = new_outfit
|
||||
|
||||
if("applyoutfit")
|
||||
var/datum/outfit/new_outfit = resolve_outfit(params["path"])
|
||||
if(new_outfit && ispath(new_outfit)) //initialize it
|
||||
new_outfit = new new_outfit
|
||||
if(!istype(new_outfit))
|
||||
return
|
||||
user.admin_apply_outfit(target_mob, new_outfit)
|
||||
|
||||
if("customoutfit")
|
||||
user.outfit_manager()
|
||||
|
||||
if("togglefavorite")
|
||||
var/datum/outfit/outfit_path = resolve_outfit(params["path"])
|
||||
if(!ispath(outfit_path)) //we do *not* want custom outfits (i.e objects) here, they're not even persistent
|
||||
return
|
||||
|
||||
if(user.prefs.favorite_outfits.Find(outfit_path)) //already there, remove it
|
||||
user.prefs.favorite_outfits -= outfit_path
|
||||
else //not there, add it
|
||||
user.prefs.favorite_outfits += outfit_path
|
||||
user.prefs.save_preferences()
|
||||
|
||||
/client/proc/admin_apply_outfit(mob/target, dresscode)
|
||||
if(!ishuman(target) && !isobserver(target))
|
||||
alert("Invalid mob")
|
||||
return
|
||||
|
||||
if(!dresscode)
|
||||
return
|
||||
|
||||
var/delete_pocket
|
||||
var/mob/living/carbon/human/human_target
|
||||
if(isobserver(target))
|
||||
human_target = target.change_mob_type(/mob/living/carbon/human, delete_old_mob = TRUE)
|
||||
else
|
||||
human_target = target
|
||||
if(human_target.l_store || human_target.r_store || human_target.s_store) //saves a lot of time for admins and coders alike
|
||||
if(alert("Drop Items in Pockets? No will delete them.", "Robust quick dress shop", "Yes", "No") == "No")
|
||||
delete_pocket = TRUE
|
||||
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Select Equipment") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
for(var/obj/item/item in human_target.get_equipped_items(delete_pocket))
|
||||
qdel(item)
|
||||
if(dresscode != "Naked")
|
||||
human_target.equipOutfit(dresscode)
|
||||
|
||||
human_target.regenerate_icons()
|
||||
|
||||
log_admin("[key_name(usr)] changed the equipment of [key_name(human_target)] to [dresscode].")
|
||||
message_admins("<span class='adminnotice'>[key_name_admin(usr)] changed the equipment of [ADMIN_LOOKUPFLW(human_target)] to [dresscode].</span>")
|
||||
|
||||
return dresscode
|
||||
@@ -111,6 +111,7 @@ GLOBAL_LIST_EMPTY(antagonists)
|
||||
var/datum/skill_modifier/job/M = GLOB.skill_modifiers[GET_SKILL_MOD_ID(A, type)]
|
||||
if(istype(M))
|
||||
M.name = "[name] Training"
|
||||
owner.AddComponent(/datum/component/activity)
|
||||
SEND_SIGNAL(owner.current, COMSIG_MOB_ANTAG_ON_GAIN, src)
|
||||
|
||||
/datum/antagonist/proc/is_banned(mob/M)
|
||||
@@ -141,6 +142,7 @@ GLOBAL_LIST_EMPTY(antagonists)
|
||||
var/datum/team/team = get_team()
|
||||
if(team)
|
||||
team.remove_member(owner)
|
||||
// we don't remove the activity component on purpose--no real point to it
|
||||
qdel(src)
|
||||
|
||||
/datum/antagonist/proc/greet()
|
||||
|
||||
@@ -511,8 +511,7 @@
|
||||
|
||||
/obj/item/abductor/baton/proc/StunAttack(mob/living/L,mob/living/user)
|
||||
|
||||
L.lastattacker = user.real_name
|
||||
L.lastattackerckey = user.ckey
|
||||
L.set_last_attacker(user)
|
||||
|
||||
L.adjustStaminaLoss(35) //because previously it took 5-6 hits to actually "incapacitate" someone for the purposes of the sleep inducement
|
||||
L.DefaultCombatKnockdown(140)
|
||||
|
||||
@@ -385,8 +385,7 @@
|
||||
qdel(src)
|
||||
return
|
||||
log_combat(user, M, "used a cult spell on", source.name, "")
|
||||
M.lastattacker = user.real_name
|
||||
M.lastattackerckey = user.ckey
|
||||
M.set_last_attacker(user)
|
||||
|
||||
/obj/item/melee/blood_magic/afterattack(atom/target, mob/living/carbon/user, proximity)
|
||||
. = ..()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//Revenants: based off of wraiths from Goon
|
||||
//"Ghosts" that are invisible and move like ghosts, cannot take damage while invisible
|
||||
//Don't hear deadchat and are NOT normal ghosts
|
||||
//Can hear deadchat, but are NOT normal ghosts and do NOT have x-ray vision
|
||||
//Admin-spawn or random event
|
||||
|
||||
#define INVISIBILITY_REVENANT 50
|
||||
@@ -77,6 +77,7 @@
|
||||
|
||||
/mob/living/simple_animal/revenant/Initialize(mapload)
|
||||
. = ..()
|
||||
ADD_TRAIT(src, TRAIT_SIXTHSENSE, INNATE_TRAIT)
|
||||
AddSpell(new /obj/effect/proc_holder/spell/targeted/night_vision/revenant(null))
|
||||
AddSpell(new /obj/effect/proc_holder/spell/targeted/telepathy/revenant(null))
|
||||
AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/revenant/defile(null))
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
continue
|
||||
if(!SSpersistence.IsValidDebrisLocation(C.loc, allowed_turf_typecache, allowed_z_cache, C.type, FALSE))
|
||||
continue
|
||||
weight += 0.05
|
||||
weight += 0.03
|
||||
return ..()
|
||||
|
||||
/datum/round_event/ghost_role/slaughter
|
||||
|
||||
@@ -1,30 +1,7 @@
|
||||
/datum/traitor_class/human/assassin
|
||||
/datum/traitor_class/human/subterfuge/assassin
|
||||
name = "Donk Co Operative"
|
||||
employer = "Donk Corporation"
|
||||
weight = 0
|
||||
weight = 6
|
||||
chaos = 1
|
||||
threat = 2
|
||||
|
||||
/datum/traitor_class/human/assassin/forge_single_objective(datum/antagonist/traitor/T)
|
||||
.=1
|
||||
var/permakill_prob = 20
|
||||
var/datum/game_mode/dynamic/mode
|
||||
if(istype(SSticker.mode,/datum/game_mode/dynamic))
|
||||
mode = SSticker.mode
|
||||
permakill_prob = max(0,mode.threat_level-50)
|
||||
var/list/active_ais = active_ais()
|
||||
if(active_ais.len && prob(100/GLOB.joined_player_list.len))
|
||||
var/datum/objective/destroy/destroy_objective = new
|
||||
destroy_objective.owner = T.owner
|
||||
destroy_objective.find_target()
|
||||
T.add_objective(destroy_objective)
|
||||
else if(prob(permakill_prob))
|
||||
var/datum/objective/assassinate/kill_objective = new
|
||||
kill_objective.owner = T.owner
|
||||
kill_objective.find_target()
|
||||
T.add_objective(kill_objective)
|
||||
else
|
||||
var/datum/objective/assassinate/once/kill_objective = new
|
||||
kill_objective.owner = T.owner
|
||||
kill_objective.find_target()
|
||||
T.add_objective(kill_objective)
|
||||
assassin_prob = 70
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
/datum/traitor_class/human/freeform
|
||||
name = "Waffle Co Agent"
|
||||
employer = "Waffle Company"
|
||||
weight = 0 // should not spawn in unless admins bus something in the traitor panel with setting traitor classes
|
||||
weight = 5
|
||||
chaos = 0
|
||||
|
||||
/datum/traitor_class/human/freeform/forge_objectives(datum/antagonist/traitor/T)
|
||||
var/datum/objective/escape/O = new
|
||||
O.explanation_text = "You have no explicit goals! While we don't approve of mindless slaughter, you may antagonize nanotrasen any way you wish! Make sure to escape alive and not in custody, though!"
|
||||
var/datum/objective/freedom/O = new
|
||||
O.explanation_text = "You have no explicit goals! While we don't approve of mindless slaughter, you may antagonize nanotrasen any way you wish! Don't get captured or killed, but if you've done nothing, you'll be in trouble!"
|
||||
O.owner = T.owner
|
||||
T.add_objective(O)
|
||||
return
|
||||
|
||||
@@ -13,8 +13,12 @@
|
||||
T.assign_exchange_role(SSticker.mode.exchange_blue)
|
||||
objective_count += 1 //Exchange counts towards number of objectives
|
||||
var/toa = CONFIG_GET(number/traitor_objectives_amount)
|
||||
var/attempts = 0
|
||||
for(var/i = objective_count, i < toa, i++)
|
||||
forge_single_objective(T)
|
||||
var/success = FALSE
|
||||
while(!success && attempts < max(toa*10, 100))
|
||||
success = forge_single_objective(T)
|
||||
attempts += 1
|
||||
if(!(locate(/datum/objective/escape) in T.objectives))
|
||||
var/datum/objective/escape/escape_objective = new
|
||||
escape_objective.owner = T.owner
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
/datum/traitor_class/human/subterfuge
|
||||
name = "MI13 Operative"
|
||||
employer = "MI13"
|
||||
weight = 36
|
||||
weight = 25
|
||||
chaos = -5
|
||||
var/assassin_prob = 25
|
||||
|
||||
/datum/traitor_class/human/subterfuge/forge_single_objective(datum/antagonist/traitor/T)
|
||||
.=1
|
||||
var/assassin_prob = 30
|
||||
var/datum/game_mode/dynamic/mode
|
||||
if(istype(SSticker.mode,/datum/game_mode/dynamic))
|
||||
mode = SSticker.mode
|
||||
@@ -16,24 +15,31 @@
|
||||
kill_objective.owner = T.owner
|
||||
kill_objective.find_target()
|
||||
T.add_objective(kill_objective)
|
||||
return TRUE
|
||||
else
|
||||
var/list/weights = list()
|
||||
weights["sabo"] = length(subtypesof(/datum/sabotage_objective))
|
||||
weights["steal"] = length(subtypesof(/datum/objective_item/steal))
|
||||
var/datum/objective/sabotage/sabotage_objective = new
|
||||
sabotage_objective.owner = T.owner
|
||||
if(sabotage_objective.find_target())
|
||||
weights["sabo"] = length(subtypesof(/datum/objective_item/steal))
|
||||
var/datum/objective/steal/steal_objective = new
|
||||
steal_objective.owner = T.owner
|
||||
if(steal_objective.find_target())
|
||||
weights["steal"] = length(subtypesof(/datum/objective_item/steal))
|
||||
weights["download"] = !(locate(/datum/objective/download) in T.objectives || (T.owner.assigned_role in list("Research Director", "Scientist", "Roboticist")))
|
||||
switch(pickweight(weights))
|
||||
if("sabo")
|
||||
var/datum/objective/sabotage/sabotage_objective = new
|
||||
sabotage_objective.owner = T.owner
|
||||
sabotage_objective.find_target()
|
||||
T.add_objective(sabotage_objective)
|
||||
qdel(steal_objective)
|
||||
return TRUE
|
||||
if("steal")
|
||||
var/datum/objective/steal/steal_objective = new
|
||||
steal_objective.owner = T.owner
|
||||
steal_objective.find_target()
|
||||
T.add_objective(steal_objective)
|
||||
qdel(sabotage_objective)
|
||||
return TRUE
|
||||
if("download")
|
||||
var/datum/objective/download/download_objective = new
|
||||
download_objective.owner = T.owner
|
||||
download_objective.gen_amount_goal()
|
||||
T.add_objective(download_objective)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
@@ -7,7 +7,8 @@ GLOBAL_LIST_EMPTY(traitor_classes)
|
||||
var/chaos = 0
|
||||
var/threat = 0
|
||||
var/TC = 20
|
||||
/// Minimum players for this to randomly roll via get_random_traitor_class().
|
||||
var/processing = FALSE
|
||||
/// Minimum players for this to randomly roll via get_random_traitor_kind().
|
||||
var/min_players = 0
|
||||
var/list/uplink_filters
|
||||
|
||||
@@ -43,4 +44,6 @@ GLOBAL_LIST_EMPTY(traitor_classes)
|
||||
|
||||
/datum/traitor_class/proc/clean_up_traitor(datum/antagonist/traitor/T)
|
||||
// Any effects that need to be cleaned up if traitor class is being swapped.
|
||||
|
||||
|
||||
/datum/traitor_class/proc/on_process(/datum/antagonist/traitor/T)
|
||||
// only for processing traitor classes; runs once an SSprocessing tick
|
||||
|
||||
@@ -26,6 +26,8 @@
|
||||
if(traitor_kind)
|
||||
traitor_kind.remove_innate_effects(owner.current)
|
||||
traitor_kind.clean_up_traitor(src)
|
||||
if(traitor_kind.processing)
|
||||
STOP_PROCESSING(SSprocessing, src)
|
||||
swap_from_old = TRUE
|
||||
traitor_kind = GLOB.traitor_classes[kind]
|
||||
traitor_kind.apply_innate_effects(owner.current)
|
||||
@@ -33,11 +35,16 @@
|
||||
for(var/O in objectives)
|
||||
qdel(O)
|
||||
traitor_kind.forge_objectives(src)
|
||||
if(traitor_kind.processing)
|
||||
START_PROCESSING(SSprocessing, src)
|
||||
if(swap_from_old)
|
||||
traitor_kind.finalize_traitor(src)
|
||||
traitor_kind.greet(src)
|
||||
owner.announce_objectives()
|
||||
|
||||
/datum/antagonist/traitor/process()
|
||||
traitor_kind.on_process(src)
|
||||
|
||||
/proc/get_random_traitor_kind(var/list/blacklist = list())
|
||||
var/chaos_weight = 0
|
||||
if(istype(SSticker.mode,/datum/game_mode/dynamic))
|
||||
|
||||
@@ -345,6 +345,14 @@
|
||||
InsertAll("", each, GLOB.alldirs)
|
||||
..()
|
||||
|
||||
/datum/asset/spritesheet/decals
|
||||
name = "decals"
|
||||
|
||||
/datum/asset/spritesheet/decals/register()
|
||||
for(var/each in list('icons/turf/decals.dmi'))
|
||||
InsertAll("", each, GLOB.alldirs)
|
||||
..()
|
||||
|
||||
/datum/asset/spritesheet/supplypods
|
||||
name = "supplypods"
|
||||
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
GLOBAL_LIST_EMPTY(bluespace_pipe_networks)
|
||||
/obj/machinery/atmospherics/pipe/bluespace
|
||||
name = "bluespace pipe"
|
||||
desc = "Transmits gas across large distances of space. Developed using bluespace technology."
|
||||
icon = 'icons/obj/atmospherics/pipes/bluespace.dmi'
|
||||
icon_state = "map"
|
||||
pipe_state = "bluespace"
|
||||
dir = SOUTH
|
||||
initialize_directions = SOUTH
|
||||
device_type = UNARY
|
||||
can_buckle = FALSE
|
||||
construction_type = /obj/item/pipe/bluespace
|
||||
var/bluespace_network_name
|
||||
|
||||
/obj/machinery/atmospherics/pipe/bluespace/New()
|
||||
icon_state = "pipe"
|
||||
if(bluespace_network_name) // in case someone maps one in for some reason
|
||||
if(!GLOB.bluespace_pipe_networks[bluespace_network_name])
|
||||
GLOB.bluespace_pipe_networks[bluespace_network_name] = list()
|
||||
GLOB.bluespace_pipe_networks[bluespace_network_name] |= src
|
||||
..()
|
||||
|
||||
/obj/machinery/atmospherics/pipe/bluespace/on_construction()
|
||||
. = ..()
|
||||
if(bluespace_network_name)
|
||||
if(!GLOB.bluespace_pipe_networks[bluespace_network_name])
|
||||
GLOB.bluespace_pipe_networks[bluespace_network_name] = list()
|
||||
GLOB.bluespace_pipe_networks[bluespace_network_name] |= src
|
||||
|
||||
/obj/machinery/atmospherics/pipe/bluespace/Destroy()
|
||||
if(GLOB.bluespace_pipe_networks[bluespace_network_name])
|
||||
GLOB.bluespace_pipe_networks[bluespace_network_name] -= src
|
||||
for(var/p in GLOB.bluespace_pipe_networks[bluespace_network_name])
|
||||
var/obj/machinery/atmospherics/pipe/bluespace/P = p
|
||||
QDEL_NULL(P.parent)
|
||||
P.build_network()
|
||||
return ..()
|
||||
|
||||
/obj/machinery/atmospherics/pipe/bluespace/examine(user)
|
||||
. = ..()
|
||||
. += "<span class='notice'>This one is connected to the \"[html_encode(bluespace_network_name)]\" network.</span>"
|
||||
|
||||
/obj/machinery/atmospherics/pipe/bluespace/SetInitDirections()
|
||||
initialize_directions = dir
|
||||
|
||||
/obj/machinery/atmospherics/pipe/bluespace/pipeline_expansion()
|
||||
return ..() + GLOB.bluespace_pipe_networks[bluespace_network_name] - src
|
||||
|
||||
/obj/machinery/atmospherics/pipe/bluespace/hide()
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/atmospherics/pipe/bluespace/update_icon(showpipe)
|
||||
underlays.Cut()
|
||||
|
||||
var/turf/T = loc
|
||||
if(level == 2 || !T.intact)
|
||||
showpipe = TRUE
|
||||
plane = GAME_PLANE
|
||||
else
|
||||
showpipe = FALSE
|
||||
plane = FLOOR_PLANE
|
||||
|
||||
if(!showpipe)
|
||||
return //no need to update the pipes if they aren't showing
|
||||
|
||||
var/connected = 0 //Direction bitset
|
||||
|
||||
for(var/i in 1 to device_type) //adds intact pieces
|
||||
if(nodes[i])
|
||||
var/obj/machinery/atmospherics/node = nodes[i]
|
||||
var/image/img = get_pipe_underlay("pipe_intact", get_dir(src, node), node.pipe_color)
|
||||
underlays += img
|
||||
connected |= img.dir
|
||||
|
||||
for(var/direction in GLOB.cardinals)
|
||||
if((initialize_directions & direction) && !(connected & direction))
|
||||
underlays += get_pipe_underlay("pipe_exposed", direction)
|
||||
|
||||
/obj/machinery/atmospherics/pipe/bluespace/paint()
|
||||
return FALSE
|
||||
|
||||
/obj/machinery/atmospherics/pipe/bluespace/proc/get_pipe_underlay(state, dir, color = null)
|
||||
if(color)
|
||||
. = getpipeimage('icons/obj/atmospherics/components/binary_devices.dmi', state, dir, color)
|
||||
else
|
||||
. = getpipeimage('icons/obj/atmospherics/components/binary_devices.dmi', state, dir)
|
||||
@@ -48,3 +48,12 @@
|
||||
price_max = 300
|
||||
stock_max = 3
|
||||
availability_prob = 40
|
||||
|
||||
/datum/blackmarket_item/weapon/derringer
|
||||
name = ".38 Derringer"
|
||||
desc = "Compact safety! Now at a premium!"
|
||||
item = /obj/item/gun/ballistic/derringer
|
||||
price_min = 500
|
||||
price_max = 1500
|
||||
stock_max = 3
|
||||
availability_prob = 30
|
||||
|
||||
@@ -75,7 +75,7 @@
|
||||
cost = 250
|
||||
unit_name = "heart"
|
||||
export_types = list(/obj/item/organ/heart)
|
||||
exclude_types = list(/obj/item/organ/heart/cursed, /obj/item/organ/heart/cybernetic)
|
||||
exclude_types = list(/obj/item/organ/heart/cursed, /obj/item/organ/heart/cybernetic/tier2, /obj/item/organ/heart/cybernetic/tier3)
|
||||
|
||||
/datum/export/organs/tongue
|
||||
cost = 75
|
||||
@@ -92,29 +92,30 @@
|
||||
cost = 50 //can be replaced
|
||||
unit_name = "stomach"
|
||||
export_types = list(/obj/item/organ/stomach)
|
||||
exclude_types = list(/obj/item/organ/stomach/cybernetic/tier2, /obj/item/organ/stomach/cybernetic/tier3)
|
||||
|
||||
/datum/export/organs/lungs
|
||||
cost = 150
|
||||
unit_name = "lungs"
|
||||
export_types = list(/obj/item/organ/lungs)
|
||||
exclude_types = list(/obj/item/organ/lungs/cybernetic, /obj/item/organ/lungs/cybernetic/upgraded)
|
||||
export_types = list(/obj/item/organ/lungs,)
|
||||
exclude_types = list(/obj/item/organ/lungs/cybernetic/tier2, /obj/item/organ/lungs/cybernetic/tier3)
|
||||
|
||||
/datum/export/organs/liver
|
||||
cost = 175
|
||||
unit_name = "liver"
|
||||
export_types = list(/obj/item/organ/liver)
|
||||
exclude_types = list(/obj/item/organ/liver/cybernetic, /obj/item/organ/liver/cybernetic/upgraded)
|
||||
exclude_types = list(/obj/item/organ/liver/cybernetic/tier2, /obj/item/organ/liver/cybernetic/tier3)
|
||||
|
||||
/datum/export/organs/cybernetic
|
||||
cost = 225
|
||||
unit_name = "cybernetic organ"
|
||||
export_types = list(/obj/item/organ/liver/cybernetic, /obj/item/organ/lungs/cybernetic, /obj/item/organ/eyes/robotic, /obj/item/organ/heart/cybernetic)
|
||||
exclude_types = list(/obj/item/organ/lungs/cybernetic/upgraded, /obj/item/organ/liver/cybernetic/upgraded)
|
||||
export_types = list(/obj/item/organ/liver/cybernetic/tier2, /obj/item/organ/lungs/cybernetic/tier2, /obj/item/organ/eyes/robotic/shield, /obj/item/organ/eyes/robotic/glow, /obj/item/organ/stomach/cybernetic/tier2, /obj/item/organ/heart/cybernetic/tier2)
|
||||
exclude_types = list(/obj/item/organ/liver/cybernetic/tier3, /obj/item/organ/lungs/cybernetic/tier3, /obj/item/organ/eyes/robotic/xray, /obj/item/organ/eyes/robotic/thermals, /obj/item/organ/stomach/cybernetic/tier3, /obj/item/organ/heart/cybernetic/tier3)
|
||||
|
||||
/datum/export/organs/upgraded
|
||||
cost = 275
|
||||
unit_name = "upgraded cybernetic organ"
|
||||
export_types = list(/obj/item/organ/lungs/cybernetic/upgraded, /obj/item/organ/liver/cybernetic/upgraded)
|
||||
export_types = list(/obj/item/organ/liver/cybernetic/tier3, /obj/item/organ/lungs/cybernetic/tier3, /obj/item/organ/eyes/robotic/xray, /obj/item/organ/eyes/robotic/thermals, /obj/item/organ/stomach/cybernetic/tier3, /obj/item/organ/heart/cybernetic/tier3)
|
||||
|
||||
/datum/export/organs/tail // yeah have fun pulling this off someone without catching a bwoink
|
||||
cost = 500
|
||||
|
||||
@@ -15,13 +15,17 @@
|
||||
var/special_enabled = FALSE
|
||||
var/DropPodOnly = FALSE //only usable by the Bluespace Drop Pod via the express cargo console
|
||||
var/admin_spawned = FALSE //Can only an admin spawn this crate?
|
||||
// this might be all in all unnecessary with current code if some changes are made
|
||||
var/goody = PACK_GOODY_NONE //Small items can be grouped into a single crate.They also come in a closet/lockbox instead of a full crate, so the 700 min doesn't apply
|
||||
var/can_private_buy = TRUE //Can it be purchased privately by each crewmember?
|
||||
|
||||
/datum/supply_pack/proc/generate(atom/A, datum/bank_account/paying_account)
|
||||
var/obj/structure/closet/crate/C
|
||||
if(paying_account)
|
||||
C = new /obj/structure/closet/crate/secure/owned(A, paying_account)
|
||||
if(ispath(crate_type, /obj/structure/closet/secure_closet/goodies)) // lets ensure private orders don't come in crates when the original one comes in lockers
|
||||
C = new /obj/structure/closet/secure_closet/goodies/owned(A, paying_account) // that would lead to infinite money exploits
|
||||
else
|
||||
C = new /obj/structure/closet/crate/secure/owned(A, paying_account)
|
||||
C.name = "[crate_name] - Purchased by [paying_account.account_holder]"
|
||||
else
|
||||
C = new crate_type(A)
|
||||
|
||||
@@ -232,3 +232,35 @@
|
||||
desc = "Contains one hellgun, an old pattern of laser gun infamous for its ability to horribly disfigure targets with burns. Technically violates the Space Geneva Convention when used on humanoids."
|
||||
cost = 1500
|
||||
contains = list(/obj/item/gun/energy/laser/hellgun)
|
||||
|
||||
/datum/supply_pack/security/armory/derringerclassic
|
||||
name = "Holdout Crate"
|
||||
crate_name = "dented crate"
|
||||
desc = "Hey kid.. c'mere. Boss says we need to offload these, to any buyer, no questions asked. You pay us, we give you three of these guns, no strings attached. Locks are to ensure they get to PAYING customers."
|
||||
cost = 2000
|
||||
contraband = TRUE
|
||||
can_private_buy = TRUE
|
||||
contains = list(/obj/item/storage/fancy/cigarettes/derringer/smuggled,
|
||||
/obj/item/storage/fancy/cigarettes/derringer/smuggled,
|
||||
/obj/item/storage/fancy/cigarettes/derringer/smuggled,
|
||||
/obj/item/storage/wallet)
|
||||
|
||||
/datum/supply_pack/security/armory/esoteric_arms
|
||||
name = "Esoteric Armory Shipment"
|
||||
desc = "Well.. you're an agent of taste, I can tell that much. For the right price.. we could see our way clear to send you one of our more... unique weapons."
|
||||
hidden = TRUE
|
||||
cost = 10000
|
||||
can_private_buy = TRUE
|
||||
crate_name = "dusty crate"
|
||||
var/num_contained = 1
|
||||
contains = list(/obj/item/gun/ballistic/shotgun/leveraction,
|
||||
/obj/item/storage/fancy/cigarettes/derringer/gold,
|
||||
/obj/item/gun/ballistic/revolver/nagant,
|
||||
/obj/item/gun/ballistic/automatic/pistol/APS,
|
||||
/obj/item/gun/ballistic/revolver/golden)
|
||||
|
||||
/datum/supply_pack/security/armory/esoteric_arms/fill(obj/structure/closet/crate/C)
|
||||
var/list/L = contains.Copy()
|
||||
for(var/i in 1 to num_contained)
|
||||
var/item = pick_n_take(L)
|
||||
new item(C)
|
||||
|
||||
@@ -81,3 +81,4 @@
|
||||
desc = "Contains one standard epinephrine medipen and one standard emergency first-aid kit medipen. For when you want to prepare for the worst."
|
||||
cost = 500
|
||||
contains = list(/obj/item/reagent_containers/hypospray/medipen, /obj/item/reagent_containers/hypospray/medipen/ekit)
|
||||
|
||||
|
||||
@@ -14,56 +14,56 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/datum/supply_pack/materials/cardboard50
|
||||
goody = PACK_GOODY_PUBLIC
|
||||
crate_type = /obj/structure/closet/secure_closet/goodies
|
||||
name = "50 Cardboard Sheets"
|
||||
desc = "Create a bunch of boxes."
|
||||
cost = 300 //thrice their export value
|
||||
contains = list(/obj/item/stack/sheet/cardboard/fifty)
|
||||
|
||||
/datum/supply_pack/materials/glass50
|
||||
goody = PACK_GOODY_PUBLIC
|
||||
crate_type = /obj/structure/closet/secure_closet/goodies
|
||||
name = "50 Glass Sheets"
|
||||
desc = "Let some nice light in with fifty glass sheets!"
|
||||
cost = 300 //double their export value
|
||||
contains = list(/obj/item/stack/sheet/glass/fifty)
|
||||
|
||||
/datum/supply_pack/materials/metal50
|
||||
goody = PACK_GOODY_PUBLIC
|
||||
crate_type = /obj/structure/closet/secure_closet/goodies
|
||||
name = "50 Metal Sheets"
|
||||
desc = "Any construction project begins with a good stack of fifty metal sheets!"
|
||||
cost = 300 //double their export value
|
||||
contains = list(/obj/item/stack/sheet/metal/fifty)
|
||||
|
||||
/datum/supply_pack/materials/plasteel20
|
||||
goody = PACK_GOODY_PUBLIC
|
||||
crate_type = /obj/structure/closet/secure_closet/goodies
|
||||
name = "20 Plasteel Sheets"
|
||||
desc = "Reinforce the station's integrity with twenty plasteel sheets!"
|
||||
cost = 4000
|
||||
contains = list(/obj/item/stack/sheet/plasteel/twenty)
|
||||
|
||||
/datum/supply_pack/materials/plastic50
|
||||
goody = PACK_GOODY_PUBLIC
|
||||
crate_type = /obj/structure/closet/secure_closet/goodies
|
||||
name = "50 Plastic Sheets"
|
||||
desc = "Build a limitless amount of toys with fifty plastic sheets!"
|
||||
cost = 200 // double their export
|
||||
contains = list(/obj/item/stack/sheet/plastic/twenty)
|
||||
|
||||
/datum/supply_pack/materials/sandstone30
|
||||
goody = PACK_GOODY_PUBLIC
|
||||
crate_type = /obj/structure/closet/secure_closet/goodies
|
||||
name = "30 Sandstone Blocks"
|
||||
desc = "Neither sandy nor stoney, these thirty blocks will still get the job done."
|
||||
cost = 150 // five times their export
|
||||
contains = list(/obj/item/stack/sheet/mineral/sandstone/thirty)
|
||||
|
||||
/datum/supply_pack/materials/wood20
|
||||
goody = PACK_GOODY_PUBLIC
|
||||
crate_type = /obj/structure/closet/secure_closet/goodies
|
||||
name = "20 Wood Planks"
|
||||
desc = "Turn cargo's boring metal groundwork into beautiful panelled flooring and much more with twenty wooden planks!"
|
||||
cost = 400 // 6-7 planks shy from having equal import/export prices
|
||||
contains = list(/obj/item/stack/sheet/mineral/wood/twenty)
|
||||
|
||||
/datum/supply_pack/materials/rcdammo
|
||||
goody = PACK_GOODY_PUBLIC
|
||||
crate_type = /obj/structure/closet/secure_closet/goodies
|
||||
name = "Large RCD ammo Single-Pack"
|
||||
desc = "A single large compressed RCD matter pack, to help with any holes or projects people might be working on."
|
||||
cost = 600
|
||||
|
||||
@@ -370,7 +370,7 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/datum/supply_pack/misc/carpet
|
||||
goody = PACK_GOODY_PUBLIC
|
||||
crate_type = /obj/structure/closet/secure_closet/goodies
|
||||
name = "Classic Carpet Single-Pack"
|
||||
desc = "Plasteel floor tiles getting on your nerves? This 50 units stack of extra soft carpet will tie any room together."
|
||||
cost = 200
|
||||
|
||||
@@ -80,15 +80,15 @@
|
||||
|
||||
/datum/supply_pack/security/russianclothing
|
||||
name = "Russian Surplus Clothing"
|
||||
desc = "An old russian crate full of surplus armor that they used to use! Has two sets of bulletproff armor, a few union suits and some warm hats!"
|
||||
desc = "An old russian crate full of surplus armor that they used to use! Has two sets of bulletproof armor, a few union suits and some warm hats!"
|
||||
contraband = TRUE
|
||||
cost = 5750 // Its basicly sec suits, good boots/gloves
|
||||
contains = list(/obj/item/clothing/suit/armor/navyblue/russian,
|
||||
/obj/item/clothing/suit/armor/navyblue/russian,
|
||||
contains = list(/obj/item/clothing/under/syndicate/rus_army,
|
||||
/obj/item/clothing/under/syndicate/rus_army,
|
||||
/obj/item/clothing/shoes/combat,
|
||||
/obj/item/clothing/shoes/combat,
|
||||
/obj/item/clothing/head/ushanka,
|
||||
/obj/item/clothing/head/ushanka,
|
||||
/obj/item/clothing/head/helmet/rus_helmet,
|
||||
/obj/item/clothing/head/helmet/rus_helmet,
|
||||
/obj/item/clothing/suit/armor/bulletproof,
|
||||
/obj/item/clothing/suit/armor/bulletproof,
|
||||
/obj/item/clothing/head/helmet/alt,
|
||||
@@ -98,23 +98,21 @@
|
||||
/obj/item/clothing/mask/gas,
|
||||
/obj/item/clothing/mask/gas)
|
||||
crate_name = "surplus russian clothing"
|
||||
crate_type = /obj/structure/closet/crate/internals
|
||||
|
||||
/datum/supply_pack/security/russian_partisan
|
||||
name = "Russian Partisan Gear"
|
||||
desc = "An old russian partisan equipment crate, comes with a full russian outfit, a loaded surplus rifle and a second magazine."
|
||||
contraband = TRUE
|
||||
access = FALSE
|
||||
cost = 6500
|
||||
contains = list(/obj/item/clothing/suit/armor/navyblue/russian,
|
||||
/obj/item/clothing/shoes/combat,
|
||||
/obj/item/clothing/head/ushanka,
|
||||
/obj/item/clothing/head/helmet/rus_helmet,
|
||||
/obj/item/clothing/suit/armor/bulletproof,
|
||||
/obj/item/clothing/head/helmet/alt,
|
||||
/obj/item/clothing/gloves/tackler/combat/insulated,
|
||||
/obj/item/clothing/under/syndicate/rus_army,
|
||||
/obj/item/clothing/mask/gas)
|
||||
crate_name = "surplus russian gear"
|
||||
crate_type = /obj/structure/closet/crate/internals
|
||||
|
||||
/datum/supply_pack/security/russian_partisan/fill(obj/structure/closet/crate/C)
|
||||
..()
|
||||
@@ -241,7 +239,7 @@
|
||||
access = FALSE
|
||||
access_any = list(ACCESS_SECURITY, ACCESS_FORENSICS_LOCKERS)
|
||||
contains = list(/obj/item/ammo_box/c38/dumdum)
|
||||
crate_name = ".38 match crate"
|
||||
crate_name = ".38 dumdum crate"
|
||||
|
||||
/datum/supply_pack/security/match
|
||||
name = ".38 Match Grade Speedloader"
|
||||
|
||||
@@ -227,6 +227,8 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
var/persistent_scars = TRUE
|
||||
///If we want to broadcast deadchat connect/disconnect messages
|
||||
var/broadcast_login_logout = TRUE
|
||||
///What outfit typepaths we've favorited in the SelectEquipment menu
|
||||
var/list/favorite_outfits = list()
|
||||
/// We have 5 slots for persistent scars, if enabled we pick a random one to load (empty by default) and scars at the end of the shift if we survived as our original person
|
||||
var/list/scars_list = list("1" = "", "2" = "", "3" = "", "4" = "", "5" = "")
|
||||
/// Which of the 5 persistent scar slots we randomly roll to load for this round, if enabled. Actually rolled in [/datum/preferences/proc/load_character(slot)]
|
||||
|
||||
@@ -385,6 +385,15 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
|
||||
S["auto_ooc"] >> auto_ooc
|
||||
S["no_tetris_storage"] >> no_tetris_storage
|
||||
|
||||
//favorite outfits
|
||||
S["favorite_outfits"] >> favorite_outfits
|
||||
|
||||
var/list/parsed_favs = list()
|
||||
for(var/typetext in favorite_outfits)
|
||||
var/datum/outfit/path = text2path(typetext)
|
||||
if(ispath(path)) //whatever typepath fails this check probably doesn't exist anymore
|
||||
parsed_favs += path
|
||||
favorite_outfits = uniqueList(parsed_favs)
|
||||
|
||||
//try to fix any outdated data if necessary
|
||||
if(needs_update >= 0)
|
||||
@@ -434,6 +443,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
|
||||
no_tetris_storage = sanitize_integer(no_tetris_storage, 0, 1, initial(no_tetris_storage))
|
||||
key_bindings = sanitize_islist(key_bindings, list())
|
||||
modless_key_bindings = sanitize_islist(modless_key_bindings, list())
|
||||
favorite_outfits = SANITIZE_LIST(favorite_outfits)
|
||||
|
||||
verify_keybindings_valid() // one of these days this will runtime and you'll be glad that i put it in a different proc so no one gets their saves wiped
|
||||
|
||||
@@ -535,6 +545,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
|
||||
WRITE_FILE(S["pda_skin"], pda_skin)
|
||||
WRITE_FILE(S["key_bindings"], key_bindings)
|
||||
WRITE_FILE(S["modless_key_bindings"], modless_key_bindings)
|
||||
WRITE_FILE(S["favorite_outfits"], favorite_outfits)
|
||||
|
||||
//citadel code
|
||||
WRITE_FILE(S["screenshake"], screenshake)
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
set desc = "Authorizes your account in the panic bunker of any servers connected to this function."
|
||||
set category = "OOC"
|
||||
|
||||
if(prefs.db_flags & DB_FLAG_AGE_CONFIRMATION_INCOMPLETE)
|
||||
to_chat(src, "<span class='danger'>You are not age verified.</span>")
|
||||
return
|
||||
|
||||
if(autobunker_last_try + 5 SECONDS > world.time)
|
||||
to_chat(src, "<span class='danger'>Function on cooldown, try again in 5 seconds.</span>")
|
||||
return
|
||||
|
||||
@@ -83,8 +83,7 @@
|
||||
standard_outfit_options = list()
|
||||
for(var/path in subtypesof(/datum/outfit/job))
|
||||
var/datum/outfit/O = path
|
||||
if(initial(O.can_be_admin_equipped))
|
||||
standard_outfit_options[initial(O.name)] = path
|
||||
standard_outfit_options[initial(O.name)] = path
|
||||
sortTim(standard_outfit_options, /proc/cmp_text_asc)
|
||||
outfit_options = standard_outfit_options
|
||||
|
||||
|
||||
@@ -358,6 +358,12 @@
|
||||
..()
|
||||
user.cure_blind("blindfold_[REF(src)]")
|
||||
|
||||
/obj/item/clothing/glasses/fakeblindfold
|
||||
name = "thin blindfold"
|
||||
desc = "Covers the eyes, but not thick enough to obscure vision. Mostly for aesthetic."
|
||||
icon_state = "blindfoldwhite"
|
||||
item_state = "blindfoldwhite"
|
||||
|
||||
/obj/item/clothing/glasses/sunglasses/blindfold/white
|
||||
name = "blind personnel blindfold"
|
||||
desc = "Indicates that the wearer suffers from blindness."
|
||||
|
||||
@@ -278,6 +278,19 @@
|
||||
visible_message("[src] finishes cooking!")
|
||||
new /obj/item/reagent_containers/food/snacks/meat/steak/goliath(loc)
|
||||
qdel(src)
|
||||
|
||||
/obj/item/reagent_containers/food/snacks/meat/slab/dragon
|
||||
name = "ash drake meat"
|
||||
desc = "Meat from an ash drake. It's probably not a good idea to eat this raw."
|
||||
list_reagents = list(/datum/reagent/consumable/nutriment = 3, /datum/reagent/toxin = 5, /datum/reagent/consumable/cooking_oil = 3)
|
||||
icon_state = "goliathmeat"
|
||||
tastes = list("meat" = 1)
|
||||
foodtype = RAW | MEAT | TOXIC
|
||||
|
||||
/obj/item/reagent_containers/food/snacks/meat/slab/dragon/burn()
|
||||
visible_message("[src] finishes cooking!")
|
||||
new /obj/item/reagent_containers/food/snacks/meat/steak/dragon(loc)
|
||||
qdel(src)
|
||||
|
||||
/obj/item/reagent_containers/food/snacks/meat/slab/meatwheat
|
||||
name = "meatwheat clump"
|
||||
@@ -395,6 +408,16 @@
|
||||
trash = null
|
||||
tastes = list("meat" = 1, "rock" = 1)
|
||||
foodtype = MEAT
|
||||
|
||||
/obj/item/reagent_containers/food/snacks/meat/steak/dragon
|
||||
name = "dragon steak"
|
||||
desc = "Spicy."
|
||||
resistance_flags = LAVA_PROOF | FIRE_PROOF
|
||||
icon_state = "goliathsteak"
|
||||
list_reagents = list(/datum/reagent/consumable/nutriment = 5, /datum/reagent/consumable/capsaicin = 3)
|
||||
trash = null
|
||||
tastes = list("meat" = 1, "fire" = 1)
|
||||
foodtype = MEAT
|
||||
|
||||
/obj/item/reagent_containers/food/snacks/meat/steak/gondola
|
||||
name = "gondola steak"
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
desc = "It's watching you suspiciously."
|
||||
|
||||
/obj/structure/closet/crate/necropolis/tendril/magic/PopulateContents()
|
||||
var/loot = rand(1,9)
|
||||
var/loot = rand(1,10)
|
||||
switch(loot)
|
||||
if(1)
|
||||
new /obj/item/soulstone/anybody(src)
|
||||
@@ -57,6 +57,8 @@
|
||||
new /obj/item/immortality_talisman(src)
|
||||
if(9)
|
||||
new /obj/item/gun/magic/wand/book/healing(src)
|
||||
if(10)
|
||||
new /obj/item/guardiancreator(src)
|
||||
|
||||
/obj/structure/closet/crate/necropolis/tendril/weapon_armor/PopulateContents()
|
||||
var/loot = rand(1,11)
|
||||
@@ -128,7 +130,7 @@
|
||||
new /obj/item/disk/design_disk/modkit_disc/rapid_repeater(src)
|
||||
|
||||
/obj/structure/closet/crate/necropolis/tendril/all/PopulateContents()
|
||||
var/loot = rand(1,28)
|
||||
var/loot = rand(1,29)
|
||||
switch(loot)
|
||||
if(1)
|
||||
new /obj/item/shared_storage/red(src)
|
||||
@@ -192,6 +194,8 @@
|
||||
new /obj/item/immortality_talisman(src)
|
||||
if(28)
|
||||
new /obj/item/gun/magic/wand/book/healing(src)
|
||||
if(29)
|
||||
new /obj/item/guardiancreator(src)
|
||||
|
||||
//KA modkit design discs
|
||||
/obj/item/disk/design_disk/modkit_disc
|
||||
@@ -1105,14 +1109,12 @@
|
||||
/obj/structure/closet/crate/necropolis/bubblegum/PopulateContents()
|
||||
new /obj/item/clothing/suit/space/hostile_environment(src)
|
||||
new /obj/item/clothing/head/helmet/space/hostile_environment(src)
|
||||
var/loot = rand(1,3)
|
||||
var/loot = rand(1,2)
|
||||
switch(loot)
|
||||
if(1)
|
||||
new /obj/item/mayhem(src)
|
||||
if(2)
|
||||
new /obj/item/book/granter/spell/asura(src)
|
||||
if(3)
|
||||
new /obj/item/guardiancreator(src)
|
||||
|
||||
/obj/structure/closet/crate/necropolis/bubblegum/crusher
|
||||
name = "bloody bubblegum chest"
|
||||
|
||||
@@ -297,6 +297,11 @@
|
||||
icon = 'icons/obj/surgery.dmi'
|
||||
icon_state = "posibrain-ipc"
|
||||
|
||||
/obj/item/organ/brain/slime
|
||||
name = "slime nucleus"
|
||||
desc = "A slimey membranous mass from a slimeperson."
|
||||
icon_state = "brain-s"
|
||||
|
||||
|
||||
////////////////////////////////////TRAUMAS////////////////////////////////////////
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
|
||||
/mob/living/carbon/apply_damage(damage, damagetype = BRUTE, def_zone = null, blocked = FALSE, forced = FALSE, spread_damage = FALSE, wound_bonus = 0, bare_wound_bonus = 0, sharpness = SHARP_NONE)
|
||||
SEND_SIGNAL(src, COMSIG_MOB_APPLY_DAMGE, damage, damagetype, def_zone)
|
||||
SEND_SIGNAL(src, COMSIG_MOB_APPLY_DAMAGE, damage, damagetype, def_zone)
|
||||
var/hit_percent = (100-blocked)/100
|
||||
if(!forced && hit_percent <= 0)
|
||||
return 0
|
||||
|
||||
@@ -24,7 +24,12 @@ INITIALIZE_IMMEDIATE(/mob/living/carbon/human/dummy)
|
||||
/mob/living/carbon/human/dummy/proc/wipe_state()
|
||||
delete_equipment()
|
||||
icon_render_key = null
|
||||
cut_overlays()
|
||||
cut_overlays(TRUE)
|
||||
|
||||
/mob/living/carbon/human/dummy/setup_human_dna()
|
||||
create_dna(src)
|
||||
randomize_human(src)
|
||||
dna.initialize_dna(skip_index = TRUE) //Skip stuff that requires full round init.
|
||||
|
||||
//Inefficient pooling/caching way.
|
||||
GLOBAL_LIST_EMPTY(human_dummy_list)
|
||||
@@ -42,13 +47,48 @@ GLOBAL_LIST_EMPTY(dummy_mob_list)
|
||||
D = new
|
||||
GLOB.human_dummy_list[slotkey] = D
|
||||
GLOB.dummy_mob_list += D
|
||||
else
|
||||
D.regenerate_icons() //they were cut in wipe_state()
|
||||
D.in_use = TRUE
|
||||
return D
|
||||
|
||||
/proc/unset_busy_human_dummy(slotnumber)
|
||||
if(!slotnumber)
|
||||
/proc/generate_dummy_lookalike(slotkey, mob/target)
|
||||
if(!istype(target))
|
||||
return generate_or_wait_for_human_dummy(slotkey)
|
||||
|
||||
var/mob/living/carbon/human/dummy/copycat = generate_or_wait_for_human_dummy(slotkey)
|
||||
|
||||
if(iscarbon(target))
|
||||
var/mob/living/carbon/carbon_target = target
|
||||
carbon_target.dna.transfer_identity(copycat, transfer_SE = TRUE)
|
||||
|
||||
if(ishuman(target))
|
||||
var/mob/living/carbon/human/human_target = target
|
||||
human_target.copy_clothing_prefs(copycat)
|
||||
|
||||
copycat.updateappearance(icon_update=TRUE, mutcolor_update=TRUE, mutations_overlay_update=TRUE)
|
||||
else
|
||||
//even if target isn't a carbon, if they have a client we can make the
|
||||
//dummy look like what their human would look like based on their prefs
|
||||
target?.client?.prefs?.copy_to(copycat, icon_updates=TRUE, roundstart_checks=FALSE)
|
||||
|
||||
return copycat
|
||||
|
||||
/proc/unset_busy_human_dummy(slotkey)
|
||||
if(!slotkey)
|
||||
return
|
||||
var/mob/living/carbon/human/dummy/D = GLOB.human_dummy_list[slotnumber]
|
||||
var/mob/living/carbon/human/dummy/D = GLOB.human_dummy_list[slotkey]
|
||||
if(istype(D))
|
||||
D.wipe_state()
|
||||
D.in_use = FALSE
|
||||
|
||||
/proc/clear_human_dummy(slotkey)
|
||||
if(!slotkey)
|
||||
return
|
||||
|
||||
var/mob/living/carbon/human/dummy/dummy = GLOB.human_dummy_list[slotkey]
|
||||
|
||||
GLOB.human_dummy_list -= slotkey
|
||||
if(istype(dummy))
|
||||
GLOB.dummy_mob_list -= dummy
|
||||
qdel(dummy)
|
||||
|
||||
@@ -14,10 +14,7 @@
|
||||
//initialize limbs first
|
||||
create_bodyparts()
|
||||
|
||||
//initialize dna. for spawned humans; overwritten by other code
|
||||
create_dna(src)
|
||||
randomize_human(src)
|
||||
dna.initialize_dna()
|
||||
setup_human_dna()
|
||||
|
||||
if(dna.species)
|
||||
set_species(dna.species.type)
|
||||
@@ -36,6 +33,11 @@
|
||||
RegisterSignal(src, COMSIG_COMPONENT_CLEAN_ACT, /atom.proc/clean_blood)
|
||||
GLOB.human_list += src
|
||||
|
||||
/mob/living/carbon/human/proc/setup_human_dna()
|
||||
//initialize dna. for spawned humans; overwritten by other code
|
||||
create_dna(src)
|
||||
randomize_human(src)
|
||||
dna.initialize_dna()
|
||||
|
||||
/mob/living/carbon/human/ComponentInitialize()
|
||||
. = ..()
|
||||
|
||||
@@ -176,3 +176,9 @@
|
||||
|
||||
/mob/living/carbon/human/get_biological_state()
|
||||
return dna.species.get_biological_state()
|
||||
|
||||
///copies over clothing preferences like underwear to another human
|
||||
/mob/living/carbon/human/proc/copy_clothing_prefs(mob/living/carbon/human/destination)
|
||||
destination.underwear = underwear
|
||||
destination.undershirt = undershirt
|
||||
destination.socks = socks
|
||||
|
||||
@@ -1620,8 +1620,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
"<span class='userdanger'>[user] [atk_verb]ed you!</span>", null, COMBAT_MESSAGE_RANGE, null, \
|
||||
user, "<span class='danger'>You [atk_verb]ed [target]!</span>")
|
||||
|
||||
target.lastattacker = user.real_name
|
||||
target.lastattackerckey = user.ckey
|
||||
target.set_last_attacker(user)
|
||||
user.dna.species.spec_unarmedattacked(user, target)
|
||||
|
||||
if(user.limb_destroyer)
|
||||
@@ -2039,8 +2038,6 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
user, "<span class='danger'>You shove [target.name]!</span>")
|
||||
target.Stagger(SHOVE_STAGGER_DURATION)
|
||||
var/obj/item/target_held_item = target.get_active_held_item()
|
||||
if(!is_type_in_typecache(target_held_item, GLOB.shove_disarming_types))
|
||||
target_held_item = null
|
||||
if(!target.has_status_effect(STATUS_EFFECT_OFF_BALANCE))
|
||||
if(target_held_item)
|
||||
if(!HAS_TRAIT(target_held_item, TRAIT_NODROP))
|
||||
@@ -2058,7 +2055,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
log_combat(user, target, "shoved", append_message)
|
||||
|
||||
/datum/species/proc/apply_damage(damage, damagetype = BRUTE, def_zone = null, blocked, mob/living/carbon/human/H, forced = FALSE, spread_damage = FALSE, wound_bonus = 0, bare_wound_bonus = 0, sharpness = SHARP_NONE)
|
||||
SEND_SIGNAL(H, COMSIG_MOB_APPLY_DAMGE, damage, damagetype, def_zone, wound_bonus, bare_wound_bonus, sharpness) // make sure putting wound_bonus here doesn't screw up other signals or uses for this signal
|
||||
SEND_SIGNAL(H, COMSIG_MOB_APPLY_DAMAGE, damage, damagetype, def_zone, wound_bonus, bare_wound_bonus, sharpness) // make sure putting wound_bonus here doesn't screw up other signals or uses for this signal
|
||||
var/hit_percent = (100-(blocked+armor))/100
|
||||
hit_percent = (hit_percent * (100-H.physiology.damage_resistance))/100
|
||||
if(!forced && hit_percent <= 0)
|
||||
|
||||
@@ -7,6 +7,9 @@
|
||||
species_traits = list(MUTCOLORS,EYECOLOR,HAIR,FACEHAIR,WINGCOLOR,HAS_FLESH)
|
||||
mutantlungs = /obj/item/organ/lungs/slime
|
||||
mutant_heart = /obj/item/organ/heart/slime
|
||||
mutantstomach = /obj/item/organ/stomach/slime
|
||||
mutantliver = /obj/item/organ/liver/slime
|
||||
mutant_brain = /obj/item/organ/brain/slime
|
||||
mutant_bodyparts = list("mcolor" = "FFFFFF", "mam_tail" = "None", "mam_ears" = "None", "mam_snouts" = "None", "taur" = "None", "deco_wings" = "None", "legs" = "Plantigrade")
|
||||
inherent_traits = list(TRAIT_TOXINLOVER)
|
||||
meat = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/slime
|
||||
@@ -22,18 +25,12 @@
|
||||
heatmod = 0.5 // = 1/4x heat damage
|
||||
burnmod = 0.5 // = 1/2x generic burn damage
|
||||
species_language_holder = /datum/language_holder/jelly
|
||||
mutant_brain = /obj/item/organ/brain/jelly
|
||||
|
||||
tail_type = "mam_tail"
|
||||
wagging_type = "mam_waggingtail"
|
||||
species_category = SPECIES_CATEGORY_JELLY
|
||||
ass_image = 'icons/ass/assslime.png'
|
||||
|
||||
/obj/item/organ/brain/jelly
|
||||
name = "slime nucleus"
|
||||
desc = "A slimey membranous mass from a slime person"
|
||||
icon_state = "brain-slime"
|
||||
|
||||
/datum/species/jelly/on_species_loss(mob/living/carbon/C)
|
||||
C.faction -= "slime"
|
||||
if(ishuman(C))
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
/**
|
||||
* Applies damage to this mob
|
||||
*
|
||||
* Sends [COMSIG_MOB_APPLY_DAMGE]
|
||||
* Sends [COMSIG_MOB_APPLY_DAMAGE]
|
||||
*
|
||||
* Arguuments:
|
||||
* * damage - amount of damage
|
||||
|
||||
@@ -55,6 +55,8 @@
|
||||
|
||||
|
||||
/mob/living/death(gibbed)
|
||||
SEND_SIGNAL(src, COMSIG_LIVING_PREDEATH, gibbed)
|
||||
|
||||
stat = DEAD
|
||||
unset_machine()
|
||||
timeofdeath = world.time
|
||||
|
||||
@@ -274,7 +274,7 @@
|
||||
|
||||
/mob/living/on_attack_hand(mob/user, act_intent = user.a_intent, attackchain_flags)
|
||||
..() //Ignoring parent return value here.
|
||||
SEND_SIGNAL(src, COMSIG_MOB_ATTACK_HAND, user)
|
||||
SEND_SIGNAL(src, COMSIG_MOB_ATTACK_HAND, user, act_intent)
|
||||
if((user != src) && act_intent != INTENT_HELP && (mob_run_block(user, 0, user.name, ATTACK_TYPE_UNARMED | ATTACK_TYPE_MELEE | ((attackchain_flags & ATTACK_IS_PARRY_COUNTERATTACK)? ATTACK_TYPE_PARRY_COUNTERATTACK : NONE), null, user, check_zone(user.zone_selected), null) & BLOCK_SUCCESS))
|
||||
log_combat(user, src, "attempted to touch")
|
||||
visible_message("<span class='warning'>[user] attempted to touch [src]!</span>",
|
||||
@@ -561,3 +561,9 @@
|
||||
|
||||
/mob/living/proc/getFireLoss_nonProsthetic()
|
||||
return getFireLoss()
|
||||
|
||||
/mob/living/proc/set_last_attacker(mob/attacker)
|
||||
lastattacker = attacker.real_name
|
||||
lastattackerckey = attacker.ckey
|
||||
SEND_SIGNAL(src, COMSIG_LIVING_ATTACKER_SET, attacker)
|
||||
SEND_SIGNAL(attacker, COMSIG_LIVING_SET_AS_ATTACKER, src)
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
#define MEDAL_PREFIX "Bubblegum"
|
||||
|
||||
/*
|
||||
|
||||
BUBBLEGUM
|
||||
@@ -7,24 +5,25 @@ 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 acts as a melee creature, chasing down and attacking its target while also using different attacks to augment its power
|
||||
|
||||
It often charges, dealing massive damage to anything unfortunate enough to be standing where it's aiming.
|
||||
Whenever it isn't chasing something down, it will sink into nearby blood pools (if possible) and springs out of the closest one to its target.
|
||||
To make this possible, it sprays streams of blood at random.
|
||||
From these blood pools Bubblegum may summon slaughterlings - weak, low-damage minions designed to impede the target's progress.
|
||||
It leaves blood trails behind wherever it goes, its clones do as well.
|
||||
It tries to strike at its target through any bloodpools under them; if it fails to do that.
|
||||
If it does warp it will enter an enraged state, becoming immune to all projectiles, becoming much faster, and dealing damage and knockback to anything that gets in the cloud around it.
|
||||
It may summon clones charging from all sides, one of these charges being bubblegum himself.
|
||||
It can charge at its target, and also heavily damaging anything directly hit in the charge.
|
||||
If at half health it will start to charge from all sides with clones.
|
||||
|
||||
When Bubblegum dies, it leaves behind a H.E.C.K. suit+helmet as well as a chest that can contain three things:
|
||||
1. A spellblade that can slice off limbs at range
|
||||
2. A bottle that, when activated, drives everyone nearby into a frenzy
|
||||
3. A super double-barrel shotgun that shoots both shells at the same time.
|
||||
When Bubblegum dies, it leaves behind a H.E.C.K. mining suit as well as a chest that can contain three things:
|
||||
1. A bottle that, when activated, drives everyone nearby into a frenzy
|
||||
2. A scroll that teaches the reader a martial art that sacrifices health for raw demonic power with their bare hands.
|
||||
|
||||
Difficulty: Hard
|
||||
|
||||
*/
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum
|
||||
name = "bubblegum"
|
||||
name = "Bubblegum"
|
||||
desc = "In what passes for a hierarchy among slaughter demons, this one is king."
|
||||
health = 2500
|
||||
maxHealth = 2500
|
||||
@@ -42,15 +41,20 @@ Difficulty: Hard
|
||||
melee_damage_lower = 40
|
||||
melee_damage_upper = 40
|
||||
speed = 1
|
||||
move_to_delay = 10
|
||||
ranged_cooldown_time = 10
|
||||
move_to_delay = 5
|
||||
retreat_distance = 5
|
||||
minimum_distance = 5
|
||||
rapid_melee = 8 // every 1/4 second
|
||||
melee_queue_distance = 20 // as far as possible really, need this because of blood warp
|
||||
ranged = 1
|
||||
pixel_x = -32
|
||||
gender = MALE
|
||||
del_on_death = 1
|
||||
crusher_loot = list(/obj/structure/closet/crate/necropolis/bubblegum/crusher)
|
||||
loot = list(/obj/structure/closet/crate/necropolis/bubblegum)
|
||||
blood_volume = BLOOD_VOLUME_MAXIMUM //BLEED FOR ME
|
||||
var/charging = 0
|
||||
var/enrage_till = null
|
||||
|
||||
achievement_type = /datum/award/achievement/boss/bubblegum_kill
|
||||
crusher_achievement_type = /datum/award/achievement/boss/bubblegum_crusher
|
||||
@@ -67,36 +71,60 @@ Difficulty: Hard
|
||||
desc = "You're not quite sure how a signal can be bloody."
|
||||
invisibility = 100
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/BiologicalLife(seconds, times_fired)
|
||||
if(!(. = ..()))
|
||||
return
|
||||
move_to_delay = clamp(round((health/maxHealth) * 10), 3, 10)
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/adjustBruteLoss(amount, updating_health = TRUE, forced = FALSE, only_robotic = FALSE, only_organic = TRUE)
|
||||
. = ..()
|
||||
if(. > 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(GLOB.cardinals))
|
||||
else
|
||||
B.setDir(pick(GLOB.cardinals))
|
||||
|
||||
/obj/effect/decal/cleanable/blood/gibs/bubblegum
|
||||
name = "thick blood"
|
||||
desc = "Thick, splattered blood."
|
||||
random_icon_states = list("gib3", "gib5", "gib6")
|
||||
bloodiness = 20
|
||||
|
||||
/obj/effect/decal/cleanable/blood/gibs/bubblegum/can_bloodcrawl_in()
|
||||
return TRUE
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/OpenFire()
|
||||
anger_modifier = clamp(((maxHealth - health)/50),0,20)
|
||||
anger_modifier = clamp(((maxHealth - health)/60),0,20)
|
||||
if(charging)
|
||||
return
|
||||
ranged_cooldown = world.time + ranged_cooldown_time
|
||||
ranged_cooldown = world.time + 50
|
||||
if(!try_bloodattack())
|
||||
blood_warp()
|
||||
|
||||
blood_warp()
|
||||
|
||||
if(prob(25))
|
||||
INVOKE_ASYNC(src, .proc/blood_spray)
|
||||
|
||||
else if(prob(5+anger_modifier/2))
|
||||
slaughterlings()
|
||||
else
|
||||
if(health > maxHealth/2 && !client)
|
||||
INVOKE_ASYNC(src, .proc/charge)
|
||||
if(health > maxHealth * 0.5)
|
||||
if(prob(50 + anger_modifier))
|
||||
charge(delay = 6)
|
||||
charge(delay = 4) // The FitnessGram Pacer Test is a multistage aerobic capacity test that progressively gets more difficult as it continues.
|
||||
charge(delay = 2)
|
||||
SetRecoveryTime(15)
|
||||
else
|
||||
INVOKE_ASYNC(src, .proc/triple_charge)
|
||||
hallucination_charge_around(times = 6, delay = 10 - anger_modifier / 5)
|
||||
SetRecoveryTime(10)
|
||||
else
|
||||
if(prob(50 - anger_modifier))
|
||||
hallucination_charge_around(times = 4, delay = 9)
|
||||
hallucination_charge_around(times = 4, delay = 8)
|
||||
hallucination_charge_around(times = 4, delay = 7)
|
||||
SetRecoveryTime(15)
|
||||
else
|
||||
for(var/i = 1 to 5)
|
||||
INVOKE_ASYNC(src, .proc/hallucination_charge_around, 2, 10, 2, 0)
|
||||
sleep(5)
|
||||
SetRecoveryTime(10)
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/Initialize()
|
||||
. = ..()
|
||||
for(var/mob/living/simple_animal/hostile/megafauna/bubblegum/B in GLOB.mob_list)
|
||||
if(B != src)
|
||||
return INITIALIZE_HINT_QDEL //There can be only one
|
||||
if(istype(src, /mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination))
|
||||
return
|
||||
for(var/mob/living/simple_animal/hostile/megafauna/bubblegum/B in GLOB.mob_living_list) if(B != src)
|
||||
return INITIALIZE_HINT_QDEL //There can be only one
|
||||
var/obj/effect/proc_holder/spell/bloodcrawl/bloodspell = new
|
||||
AddSpell(bloodspell)
|
||||
if(istype(loc, /obj/effect/dummy/phased_mob/slaughter))
|
||||
@@ -109,52 +137,78 @@ Difficulty: Hard
|
||||
SSshuttle.shuttle_purchase_requirements_met |= "bubblegum"
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/do_attack_animation(atom/A, visual_effect_icon, obj/item/used_item, no_effect)
|
||||
if(charging)
|
||||
return
|
||||
..()
|
||||
if(!charging)
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/AttackingTarget()
|
||||
if(charging)
|
||||
if(!charging)
|
||||
. = ..()
|
||||
if(.)
|
||||
recovery_time = world.time + 20 // can only attack melee once every 2 seconds but rapid_melee gives higher priority
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/bullet_act(obj/item/projectile/P)
|
||||
if(is_enraged())
|
||||
visible_message("<span class='danger'>[src] deflects the projectile; [p_they()] can't be hit with ranged weapons while enraged!</span>", "<span class='userdanger'>You deflect the projectile!</span>")
|
||||
playsound(src, pick('sound/weapons/bulletflyby.ogg', 'sound/weapons/bulletflyby2.ogg', 'sound/weapons/bulletflyby3.ogg'), 300, 1)
|
||||
return 0
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/ex_act(severity, target)
|
||||
if(severity >= EXPLODE_LIGHT)
|
||||
return
|
||||
..()
|
||||
severity = EXPLODE_LIGHT // puny mortals
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/CanPass(atom/movable/mover, turf/target)
|
||||
if(istype(mover, /mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination))
|
||||
return 1
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/Goto(target, delay, minimum_distance)
|
||||
if(charging)
|
||||
return
|
||||
..()
|
||||
if(!charging)
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/MoveToTarget(list/possible_targets)
|
||||
if(!charging)
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/Move()
|
||||
if(!stat)
|
||||
playsound(src.loc, 'sound/effects/meteorimpact.ogg', 200, 1, 2, 1)
|
||||
if(charging)
|
||||
new/obj/effect/temp_visual/decoy/fading(loc,src)
|
||||
new /obj/effect/temp_visual/decoy/fading(loc,src)
|
||||
DestroySurroundings()
|
||||
. = ..()
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/Moved()
|
||||
new /obj/effect/decal/cleanable/blood(src.loc)
|
||||
if(charging)
|
||||
DestroySurroundings()
|
||||
playsound(src, 'sound/effects/meteorimpact.ogg', 200, 1, 2, 1)
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/triple_charge()
|
||||
charge()
|
||||
sleep(10)
|
||||
charge()
|
||||
sleep(10)
|
||||
charge()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/charge()
|
||||
var/turf/T = get_turf(target)
|
||||
if(!T || T == loc)
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/charge(atom/chargeat = target, delay = 3, chargepast = 2)
|
||||
if(!chargeat)
|
||||
return
|
||||
new /obj/effect/temp_visual/dragon_swoop(T)
|
||||
var/chargeturf = get_turf(chargeat)
|
||||
if(!chargeturf)
|
||||
return
|
||||
var/dir = get_dir(src, chargeturf)
|
||||
var/turf/T = get_ranged_target_turf(chargeturf, dir, chargepast)
|
||||
if(!T)
|
||||
return
|
||||
new /obj/effect/temp_visual/dragon_swoop/bubblegum(T)
|
||||
charging = 1
|
||||
DestroySurroundings()
|
||||
walk(src, 0)
|
||||
setDir(get_dir(src, T))
|
||||
setDir(dir)
|
||||
var/obj/effect/temp_visual/decoy/D = new /obj/effect/temp_visual/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)
|
||||
animate(D, alpha = 0, color = "#FF0000", transform = matrix()*2, time = 3)
|
||||
sleep(delay)
|
||||
var/movespeed = 0.7
|
||||
walk_towards(src, T, movespeed)
|
||||
sleep(get_dist(src, T) * movespeed)
|
||||
walk(src, 0) // cancel the movement
|
||||
try_bloodattack()
|
||||
charging = 0
|
||||
Goto(target, move_to_delay, minimum_distance)
|
||||
|
||||
/**
|
||||
* Attack by override for bubblegum
|
||||
@@ -176,36 +230,147 @@ Difficulty: Hard
|
||||
if(isturf(A) || isobj(A) && A.density)
|
||||
A.ex_act(EXPLODE_HEAVY)
|
||||
DestroySurroundings()
|
||||
if(isliving(A))
|
||||
var/mob/living/L = A
|
||||
L.visible_message("<span class='danger'>[src] slams into [L]!</span>", "<span class='userdanger'>[src] tramples you into the ground!</span>")
|
||||
src.forceMove(get_turf(L))
|
||||
L.apply_damage(istype(src, /mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination) ? 15 : 30, BRUTE)
|
||||
playsound(get_turf(L), 'sound/effects/meteorimpact.ogg', 100, 1)
|
||||
shake_camera(L, 4, 3)
|
||||
shake_camera(src, 2, 3)
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
|
||||
if(!charging)
|
||||
return ..()
|
||||
/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_mob(L) || L.stat == DEAD))
|
||||
. += L
|
||||
|
||||
else if(isliving(hit_atom))
|
||||
var/mob/living/L = hit_atom
|
||||
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(throwtarget, 3)
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/try_bloodattack()
|
||||
var/list/targets = get_mobs_on_blood()
|
||||
if(targets.len)
|
||||
INVOKE_ASYNC(src, .proc/bloodattack, targets, prob(50))
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
charging = 0
|
||||
/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/temp_visual/bubblegum_hands/rightsmack(T)
|
||||
else
|
||||
new /obj/effect/temp_visual/bubblegum_hands/leftsmack(T)
|
||||
sleep(4)
|
||||
for(var/mob/living/L in T)
|
||||
if(!faction_check_mob(L))
|
||||
to_chat(L, "<span class='userdanger'>[src] rends you!</span>")
|
||||
playsound(T, attack_sound, 100, 1, -1)
|
||||
var/limb_to_hit = L.get_bodypart(pick(BODY_ZONE_HEAD, BODY_ZONE_CHEST, BODY_ZONE_R_ARM, BODY_ZONE_L_ARM, BODY_ZONE_R_LEG, BODY_ZONE_L_LEG))
|
||||
L.apply_damage(10, 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/temp_visual/bubblegum_hands/rightpaw(T)
|
||||
new /obj/effect/temp_visual/bubblegum_hands/rightthumb(T)
|
||||
else
|
||||
new /obj/effect/temp_visual/bubblegum_hands/leftpaw(T)
|
||||
new /obj/effect/temp_visual/bubblegum_hands/leftthumb(T)
|
||||
sleep(6)
|
||||
for(var/mob/living/L in T)
|
||||
if(!faction_check_mob(L))
|
||||
if(L.stat != CONSCIOUS)
|
||||
to_chat(L, "<span class='userdanger'>[src] drags you through the blood!</span>")
|
||||
playsound(T, 'sound/magic/enter_blood.ogg', 100, 1, -1)
|
||||
var/turf/targetturf = get_step(src, dir)
|
||||
L.forceMove(targetturf)
|
||||
playsound(targetturf, 'sound/magic/exit_blood.ogg', 100, 1, -1)
|
||||
addtimer(CALLBACK(src, .proc/devour, L), 2)
|
||||
sleep(1)
|
||||
|
||||
/obj/effect/temp_visual/dragon_swoop/bubblegum
|
||||
duration = 10
|
||||
|
||||
/obj/effect/temp_visual/bubblegum_hands
|
||||
icon = 'icons/effects/bubblegum.dmi'
|
||||
duration = 9
|
||||
|
||||
/obj/effect/temp_visual/bubblegum_hands/rightthumb
|
||||
icon_state = "rightthumbgrab"
|
||||
|
||||
/obj/effect/temp_visual/bubblegum_hands/leftthumb
|
||||
icon_state = "leftthumbgrab"
|
||||
|
||||
/obj/effect/temp_visual/bubblegum_hands/rightpaw
|
||||
icon_state = "rightpawgrab"
|
||||
layer = BELOW_MOB_LAYER
|
||||
|
||||
/obj/effect/temp_visual/bubblegum_hands/leftpaw
|
||||
icon_state = "leftpawgrab"
|
||||
layer = BELOW_MOB_LAYER
|
||||
|
||||
/obj/effect/temp_visual/bubblegum_hands/rightsmack
|
||||
icon_state = "rightsmack"
|
||||
|
||||
/obj/effect/temp_visual/bubblegum_hands/leftsmack
|
||||
icon_state = "leftsmack"
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/blood_warp()
|
||||
if(Adjacent(target) || (enrage_till + 30 > world.time))
|
||||
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/temp_visual/decoy/DA = new /obj/effect/temp_visual/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 = 3)
|
||||
sleep(3)
|
||||
qdel(DA)
|
||||
var/obj/effect/decal/cleanable/blood/found_bloodpool
|
||||
var/list/pools = list()
|
||||
var/can_jaunt = FALSE
|
||||
for(var/obj/effect/decal/cleanable/blood/nearby in view(src,2))
|
||||
can_jaunt = TRUE
|
||||
break
|
||||
if(!can_jaunt)
|
||||
return
|
||||
for(var/obj/effect/decal/cleanable/blood/nearby in view(get_turf(target),2))
|
||||
pools += nearby
|
||||
pools = get_pools(get_turf(target), 2)
|
||||
pools_to_remove = get_pools(get_turf(target), 1)
|
||||
pools -= pools_to_remove
|
||||
if(pools.len)
|
||||
shuffle_inplace(pools)
|
||||
found_bloodpool = pick(pools)
|
||||
@@ -215,48 +380,110 @@ Difficulty: Hard
|
||||
forceMove(get_turf(found_bloodpool))
|
||||
playsound(get_turf(src), 'sound/magic/exit_blood.ogg', 100, 1, -1)
|
||||
visible_message("<span class='danger'>And springs back out!</span>")
|
||||
blood_enrage()
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/blood_enrage(var/boost_time = 30)
|
||||
enrage_till = world.time + boost_time
|
||||
retreat_distance = null
|
||||
minimum_distance = 1
|
||||
change_move_delay(3.75)
|
||||
var/newcolor = rgb(149, 10, 10)
|
||||
add_atom_colour(newcolor, TEMPORARY_COLOUR_PRIORITY)
|
||||
var/datum/callback/cb = CALLBACK(src, .proc/blood_enrage_end)
|
||||
addtimer(cb, boost_time)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/blood_spray()
|
||||
visible_message("<span class='danger'>[src] sprays a stream of gore!</span>")
|
||||
var/turf/E = get_edge_target_turf(src, src.dir)
|
||||
var/range = 10
|
||||
var/turf/previousturf = get_turf(src)
|
||||
for(var/turf/J in getline(src,E))
|
||||
if(!range)
|
||||
break
|
||||
new /obj/effect/temp_visual/dir_setting/bloodsplatter(previousturf, get_dir(previousturf, J))
|
||||
if(!previousturf.CanAtmosPass(J))
|
||||
break
|
||||
playsound(J,'sound/effects/splat.ogg', 100, 1, -1)
|
||||
new /obj/effect/decal/cleanable/blood(J)
|
||||
range--
|
||||
previousturf = J
|
||||
sleep(1)
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/blood_enrage_end(var/newcolor = rgb(149, 10, 10))
|
||||
retreat_distance = initial(retreat_distance)
|
||||
minimum_distance = initial(minimum_distance)
|
||||
change_move_delay()
|
||||
remove_atom_colour(TEMPORARY_COLOUR_PRIORITY, newcolor)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/slaughterlings()
|
||||
visible_message("<span class='danger'>[src] summons a shoal of slaughterlings!</span>")
|
||||
for(var/obj/effect/decal/cleanable/blood/H in range(src, 10))
|
||||
if(prob(25))
|
||||
new /mob/living/simple_animal/hostile/asteroid/hivelordbrood/slaughter(H.loc)
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/is_enraged()
|
||||
return (enrage_till > world.time)
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/hivelordbrood/slaughter
|
||||
name = "slaughterling"
|
||||
desc = "Though not yet strong enough to create a true physical form, it's nonetheless determined to murder you."
|
||||
icon_state = "bloodbrood"
|
||||
icon_living = "bloodbrood"
|
||||
icon_aggro = "bloodbrood"
|
||||
attack_verb_continuous = "pierces"
|
||||
attack_verb_simple = "pierce"
|
||||
color = "#C80000"
|
||||
density = FALSE
|
||||
faction = list("mining", "boss")
|
||||
weather_immunities = list("lava","ash")
|
||||
has_field_of_vision = FALSE
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/change_move_delay(var/newmove = initial(move_to_delay))
|
||||
move_to_delay = newmove
|
||||
handle_automated_action() // need to recheck movement otherwise move_to_delay won't update until the next checking aka will be wrong speed for a bit
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/hivelordbrood/slaughter/CanPass(atom/movable/mover, turf/target)
|
||||
if(istype(mover, /mob/living/simple_animal/hostile/megafauna/bubblegum))
|
||||
/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
|
||||
|
||||
/obj/effect/decal/cleanable/blood/bubblegum
|
||||
bloodiness = 0
|
||||
|
||||
/obj/effect/decal/cleanable/blood/bubblegum/can_bloodcrawl_in()
|
||||
return TRUE
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/hallucination_charge_around(var/times = 4, var/delay = 6, var/chargepast = 0, var/useoriginal = 1)
|
||||
var/startingangle = rand(1, 360)
|
||||
if(!target)
|
||||
return
|
||||
var/turf/chargeat = get_turf(target)
|
||||
var/srcplaced = 0
|
||||
for(var/i = 1 to times)
|
||||
var/ang = (startingangle + 360/times * i)
|
||||
if(!chargeat)
|
||||
return
|
||||
var/turf/place = locate(chargeat.x + cos(ang) * times, chargeat.y + sin(ang) * times, chargeat.z)
|
||||
if(!place)
|
||||
continue
|
||||
if(!srcplaced && useoriginal)
|
||||
forceMove(place)
|
||||
srcplaced = 1
|
||||
continue
|
||||
var/mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination/B = new /mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination(src.loc)
|
||||
B.forceMove(place)
|
||||
INVOKE_ASYNC(B, .proc/charge, chargeat, delay, chargepast)
|
||||
if(useoriginal)
|
||||
charge(chargeat, delay, chargepast)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination
|
||||
name = "Bubblegum's hallucination"
|
||||
desc = "Is that really just a hallucination?"
|
||||
health = 1
|
||||
maxHealth = 1
|
||||
alpha = 127.5
|
||||
crusher_loot = null
|
||||
loot = null
|
||||
deathmessage = "Explodes into a pool of blood!"
|
||||
deathsound = 'sound/effects/splat.ogg'
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination/Initialize()
|
||||
..()
|
||||
toggle_ai(AI_OFF)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination/charge(atom/chargeat = target, delay = 3, chargepast = 2)
|
||||
..()
|
||||
qdel(src)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination/Destroy()
|
||||
new /obj/effect/decal/cleanable/blood(get_turf(src))
|
||||
. = ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination/CanPass(atom/movable/mover, turf/target)
|
||||
if(istype(mover, /mob/living/simple_animal/hostile/megafauna/bubblegum)) // hallucinations should not be stopping bubblegum or eachother
|
||||
return 1
|
||||
return 0
|
||||
return ..()
|
||||
|
||||
#undef MEDAL_PREFIX
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination/Life()
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination/adjustBruteLoss(amount, updating_health = TRUE, forced = FALSE, only_robotic = FALSE, only_organic = TRUE)
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination/OpenFire()
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination/AttackingTarget()
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination/try_bloodattack()
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination/grant_achievement(medaltype,scoretype)
|
||||
return
|
||||
|
||||
@@ -60,10 +60,10 @@ Difficulty: Medium
|
||||
pixel_x = -16
|
||||
crusher_loot = list(/obj/structure/closet/crate/necropolis/dragon/crusher)
|
||||
loot = list(/obj/structure/closet/crate/necropolis/dragon)
|
||||
butcher_results = list(/obj/item/stack/ore/diamond = 5, /obj/item/stack/sheet/sinew = 5, /obj/item/stack/sheet/bone = 30)
|
||||
butcher_results = list(/obj/item/stack/ore/diamond = 5, /obj/item/stack/sheet/sinew = 5, /obj/item/stack/sheet/bone = 30, /obj/item/reagent_containers/food/snacks/meat/slab/dragon = 5)
|
||||
guaranteed_butcher_results = list(/obj/item/stack/sheet/animalhide/ashdrake = 10)
|
||||
var/swooping = NONE
|
||||
var/swoop_cooldown = 0
|
||||
var/player_cooldown = 0
|
||||
achievement_type = /datum/award/achievement/boss/drake_kill
|
||||
crusher_achievement_type = /datum/award/achievement/boss/drake_crusher
|
||||
score_achievement_type = /datum/award/score/drake_score
|
||||
@@ -116,66 +116,167 @@ Difficulty: Medium
|
||||
ranged_cooldown = world.time + ranged_cooldown_time
|
||||
|
||||
if(prob(15 + anger_modifier) && !client)
|
||||
if(health < maxHealth/2)
|
||||
INVOKE_ASYNC(src, .proc/swoop_attack, TRUE, null, 50)
|
||||
if(health < maxHealth*0.5)
|
||||
swoop_attack(lava_arena = TRUE)
|
||||
else
|
||||
fire_rain()
|
||||
lava_swoop()
|
||||
|
||||
else if(prob(10+anger_modifier) && !client)
|
||||
if(health > maxHealth/2)
|
||||
INVOKE_ASYNC(src, .proc/swoop_attack)
|
||||
if(health < maxHealth*0.5)
|
||||
mass_fire()
|
||||
else
|
||||
INVOKE_ASYNC(src, .proc/triple_swoop)
|
||||
fire_cone()
|
||||
else
|
||||
fire_walls()
|
||||
if(prob(50) && !client)
|
||||
INVOKE_ASYNC(src, .proc/lava_pools, 10, 2)
|
||||
fire_cone()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/proc/fire_rain()
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/proc/lava_pools(var/amount, var/delay = 0.8)
|
||||
if(!target)
|
||||
return
|
||||
target.visible_message("<span class='boldwarning'>Fire rains from the sky!</span>")
|
||||
for(var/turf/turf in range(9,get_turf(target)))
|
||||
if(prob(11))
|
||||
new /obj/effect/temp_visual/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 GLOB.cardinals)
|
||||
INVOKE_ASYNC(src, .proc/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 || (J != previousturf && (!previousturf.atmos_adjacent_turfs || !previousturf.atmos_adjacent_turfs[J])))
|
||||
target.visible_message("<span class='boldwarning'>Lava starts to pool up around you!</span>")
|
||||
while(amount > 0)
|
||||
if(!target)
|
||||
break
|
||||
range--
|
||||
new /obj/effect/hotspot(J)
|
||||
J.hotspot_expose(DRAKE_FIRE_TEMP, DRAKE_FIRE_EXPOSURE, 1)
|
||||
for(var/mob/living/L in J.contents - hit_things)
|
||||
if(istype(L, /mob/living/simple_animal/hostile/megafauna/dragon))
|
||||
var/turf/T = pick(RANGE_TURFS(1, target))
|
||||
new /obj/effect/temp_visual/lava_warning(T, 60) // longer reset time for the lava
|
||||
amount--
|
||||
sleep(delay)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/proc/lava_swoop(var/amount = 30)
|
||||
INVOKE_ASYNC(src, .proc/lava_pools, amount)
|
||||
swoop_attack(FALSE, target, 1000) // longer cooldown until it gets reset below
|
||||
fire_cone()
|
||||
if(health < maxHealth*0.5)
|
||||
sleep(10)
|
||||
fire_cone()
|
||||
sleep(10)
|
||||
fire_cone()
|
||||
SetRecoveryTime(40)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/proc/mass_fire(var/spiral_count = 12, var/range = 15, var/times = 3)
|
||||
for(var/i = 1 to times)
|
||||
SetRecoveryTime(50)
|
||||
playsound(get_turf(src),'sound/magic/fireball.ogg', 200, 1)
|
||||
var/increment = 360 / spiral_count
|
||||
for(var/j = 1 to spiral_count)
|
||||
var/list/turfs = line_target(j * increment + i * increment / 2, range, src)
|
||||
INVOKE_ASYNC(src, .proc/fire_line, turfs)
|
||||
sleep(25)
|
||||
SetRecoveryTime(30)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/proc/lava_arena()
|
||||
if(!target)
|
||||
return
|
||||
target.visible_message("<span class='boldwarning'>[src] encases you in an arena of fire!</span>")
|
||||
var/amount = 3
|
||||
var/turf/center = get_turf(target)
|
||||
var/list/walled = RANGE_TURFS(3, center) - RANGE_TURFS(2, center)
|
||||
var/list/drakewalls = list()
|
||||
for(var/turf/T in walled)
|
||||
drakewalls += new /obj/effect/temp_visual/drakewall(T) // no people with lava immunity can just run away from the attack for free
|
||||
var/list/indestructible_turfs = list()
|
||||
for(var/turf/T in RANGE_TURFS(2, center))
|
||||
if(istype(T, /turf/open/indestructible))
|
||||
continue
|
||||
if(!istype(T, /turf/closed/indestructible))
|
||||
T.ChangeTurf(/turf/open/floor/plating/asteroid/basalt/lava_land_surface)
|
||||
else
|
||||
indestructible_turfs += T
|
||||
sleep(10) // give them a bit of time to realize what attack is actually happening
|
||||
|
||||
var/list/turfs = RANGE_TURFS(2, center)
|
||||
while(amount > 0)
|
||||
var/list/empty = indestructible_turfs.Copy() // can't place safe turfs on turfs that weren't changed to be open
|
||||
var/any_attack = 0
|
||||
for(var/turf/T in turfs)
|
||||
for(var/mob/living/L in T.contents)
|
||||
if(L.client)
|
||||
empty += pick(((RANGE_TURFS(2, L) - RANGE_TURFS(1, L)) & turfs) - empty) // picks a turf within 2 of the creature not outside or in the shield
|
||||
any_attack = 1
|
||||
for(var/obj/mecha/M in T.contents)
|
||||
empty += pick(((RANGE_TURFS(2, M) - RANGE_TURFS(1, M)) & turfs) - empty)
|
||||
any_attack = 1
|
||||
if(!any_attack)
|
||||
for(var/obj/effect/temp_visual/drakewall/D in drakewalls)
|
||||
qdel(D)
|
||||
return 0 // nothing to attack in the arena time for enraged attack if we still have a target
|
||||
for(var/turf/T in turfs)
|
||||
if(!(T in empty))
|
||||
new /obj/effect/temp_visual/lava_warning(T)
|
||||
else if(!istype(T, /turf/closed/indestructible))
|
||||
new /obj/effect/temp_visual/lava_safe(T)
|
||||
amount--
|
||||
sleep(24)
|
||||
return 1 // attack finished completely
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/proc/arena_escape_enrage() // you ran somehow / teleported away from my arena attack now i'm mad fucker
|
||||
SetRecoveryTime(80)
|
||||
visible_message("<span class='boldwarning'>[src] starts to glow vibrantly as its wounds close up!</span>")
|
||||
adjustBruteLoss(-250) // yeah you're gonna pay for that, don't run nerd
|
||||
add_atom_colour(rgb(255, 255, 0), TEMPORARY_COLOUR_PRIORITY)
|
||||
move_to_delay = move_to_delay / 2
|
||||
light_range = 10
|
||||
sleep(10) // run.
|
||||
mass_fire(20, 15, 3)
|
||||
remove_atom_colour(TEMPORARY_COLOUR_PRIORITY)
|
||||
move_to_delay = initial(move_to_delay)
|
||||
light_range = initial(light_range)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/proc/fire_cone(var/atom/at = target)
|
||||
playsound(get_turf(src),'sound/magic/fireball.ogg', 200, 1)
|
||||
if(QDELETED(src) || stat == DEAD) // we dead no fire
|
||||
return
|
||||
var/range = 15
|
||||
var/list/turfs = list()
|
||||
turfs = line_target(-40, range, at)
|
||||
INVOKE_ASYNC(src, .proc/fire_line, turfs)
|
||||
turfs = line_target(0, range, at)
|
||||
INVOKE_ASYNC(src, .proc/fire_line, turfs)
|
||||
turfs = line_target(40, range, at)
|
||||
INVOKE_ASYNC(src, .proc/fire_line, turfs)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/proc/line_target(var/offset, var/range, var/atom/at = target)
|
||||
if(!at)
|
||||
return
|
||||
var/angle = ATAN2(at.x - src.x, at.y - src.y) + offset
|
||||
var/turf/T = get_turf(src)
|
||||
for(var/i in 1 to range)
|
||||
var/turf/check = locate(src.x + cos(angle) * i, src.y + sin(angle) * i, src.z)
|
||||
if(!check)
|
||||
break
|
||||
T = check
|
||||
return (getline(src, T) - get_turf(src))
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/proc/fire_line(var/list/turfs)
|
||||
var/list/hit_list = list()
|
||||
for(var/turf/T in turfs)
|
||||
if(istype(T, /turf/closed))
|
||||
break
|
||||
new /obj/effect/hotspot(T)
|
||||
T.hotspot_expose(700,50,1)
|
||||
for(var/mob/living/L in T.contents)
|
||||
if(L in hit_list || L == src)
|
||||
continue
|
||||
hit_list += L
|
||||
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)
|
||||
to_chat(L, "<span class='userdanger'>You're hit by [src]'s fire breath!</span>")
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/proc/triple_swoop()
|
||||
swoop_attack(swoop_duration = 30)
|
||||
swoop_attack(swoop_duration = 30)
|
||||
swoop_attack(swoop_duration = 30)
|
||||
// deals damage to mechs
|
||||
for(var/obj/mecha/M in T.contents)
|
||||
if(M in hit_list)
|
||||
continue
|
||||
hit_list += M
|
||||
M.take_damage(45, BRUTE, "melee", 1)
|
||||
sleep(1.5)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/proc/swoop_attack(fire_rain, atom/movable/manual_target, swoop_duration = 40)
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/proc/swoop_attack(lava_arena = FALSE, atom/movable/manual_target, var/swoop_cooldown = 30)
|
||||
if(stat || swooping)
|
||||
return
|
||||
if(manual_target)
|
||||
target = manual_target
|
||||
if(!target)
|
||||
return
|
||||
swoop_cooldown = world.time + 200
|
||||
stop_automated_movement = TRUE
|
||||
swooping |= SWOOP_DAMAGEABLE
|
||||
density = FALSE
|
||||
@@ -209,32 +310,16 @@ Difficulty: Medium
|
||||
swooping |= SWOOP_INVULNERABLE
|
||||
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
sleep(7)
|
||||
var/list/flame_hit = list()
|
||||
while(swoop_duration > 0)
|
||||
if(!target && !FindTarget())
|
||||
break //we lost our target while chasing it down and couldn't get a new one
|
||||
if(swoop_duration < 7)
|
||||
fire_rain = FALSE //stop raining fire near the end of the swoop
|
||||
if(loc == get_turf(target))
|
||||
if(!fire_rain)
|
||||
break //we're not spewing fire at our target, slam they
|
||||
if(isliving(target))
|
||||
var/mob/living/L = target
|
||||
if(L.stat == DEAD)
|
||||
break //target is dead and we're on em, slam they
|
||||
if(fire_rain)
|
||||
new /obj/effect/temp_visual/target(loc, flame_hit)
|
||||
|
||||
while(target && loc != get_turf(target))
|
||||
forceMove(get_step(src, get_dir(src, target)))
|
||||
if(loc == get_turf(target))
|
||||
if(!fire_rain)
|
||||
break
|
||||
if(isliving(target))
|
||||
var/mob/living/L = target
|
||||
if(L.stat == DEAD)
|
||||
break
|
||||
var/swoop_speed = 1.5
|
||||
swoop_duration -= swoop_speed
|
||||
sleep(swoop_speed)
|
||||
sleep(0.5)
|
||||
|
||||
// Ash drake flies onto its target and rains fire down upon them
|
||||
var/descentTime = 10;
|
||||
var/lava_success = 1
|
||||
if(lava_arena)
|
||||
lava_success = lava_arena()
|
||||
|
||||
//ensure swoop direction continuity.
|
||||
if(negative)
|
||||
@@ -245,8 +330,8 @@ Difficulty: Medium
|
||||
negative = TRUE
|
||||
new /obj/effect/temp_visual/dragon_flight/end(loc, negative)
|
||||
new /obj/effect/temp_visual/dragon_swoop(loc)
|
||||
animate(src, alpha = 255, transform = oldtransform, time = 5)
|
||||
sleep(5)
|
||||
animate(src, alpha = 255, transform = oldtransform, descentTime)
|
||||
sleep(descentTime)
|
||||
swooping &= ~SWOOP_INVULNERABLE
|
||||
mouse_opacity = initial(mouse_opacity)
|
||||
icon_state = "dragon"
|
||||
@@ -264,6 +349,8 @@ Difficulty: Medium
|
||||
var/throwtarget = get_edge_target_turf(src, throw_dir)
|
||||
L.throw_at(throwtarget, 3)
|
||||
visible_message("<span class='warning'>[L] is thrown clear of [src]!</span>")
|
||||
for(var/obj/mecha/M in orange(1, src))
|
||||
M.take_damage(75, BRUTE, "melee", 1)
|
||||
|
||||
for(var/mob/M in range(7, src))
|
||||
shake_camera(M, 15, 1)
|
||||
@@ -271,16 +358,20 @@ Difficulty: Medium
|
||||
density = TRUE
|
||||
sleep(1)
|
||||
swooping &= ~SWOOP_DAMAGEABLE
|
||||
SetRecoveryTime(MEGAFAUNA_DEFAULT_RECOVERY_TIME)
|
||||
SetRecoveryTime(swoop_cooldown)
|
||||
if(!lava_success)
|
||||
arena_escape_enrage()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/AltClickOn(atom/movable/A)
|
||||
if(!istype(A))
|
||||
AltClickNoInteract(src, A)
|
||||
return
|
||||
if(swoop_cooldown >= world.time)
|
||||
to_chat(src, "<span class='warning'>You need to wait 20 seconds between swoop attacks!</span>")
|
||||
if(player_cooldown >= world.time)
|
||||
to_chat(src, "<span class='warning'>You need to wait [(player_cooldown - world.time) / 10] seconds before swooping again!</span>")
|
||||
return
|
||||
swoop_attack(TRUE, A, 25)
|
||||
swoop_attack(FALSE, A)
|
||||
lava_pools(10, 2) // less pools but longer delay before spawns
|
||||
player_cooldown = world.time + 200 // needs seperate cooldown or cant use fire attacks
|
||||
|
||||
/obj/item/gps/internal/dragon
|
||||
icon_state = null
|
||||
@@ -289,54 +380,63 @@ Difficulty: Medium
|
||||
invisibility = 100
|
||||
|
||||
|
||||
/obj/effect/temp_visual/fireball
|
||||
icon = 'icons/obj/wizard.dmi'
|
||||
icon_state = "fireball"
|
||||
name = "fireball"
|
||||
desc = "Get out of the way!"
|
||||
layer = FLY_LAYER
|
||||
randomdir = FALSE
|
||||
duration = 9
|
||||
pixel_z = DRAKE_SWOOP_HEIGHT
|
||||
|
||||
/obj/effect/temp_visual/fireball/Initialize()
|
||||
. = ..()
|
||||
animate(src, pixel_z = 0, time = duration)
|
||||
|
||||
/obj/effect/temp_visual/target
|
||||
icon = 'icons/mob/actions/actions_items.dmi'
|
||||
icon_state = "sniper_zoom"
|
||||
/obj/effect/temp_visual/lava_warning
|
||||
icon_state = "lavastaff_warn"
|
||||
layer = BELOW_MOB_LAYER
|
||||
light_range = 2
|
||||
duration = 9
|
||||
duration = 13
|
||||
|
||||
/obj/effect/temp_visual/target/ex_act()
|
||||
/obj/effect/temp_visual/lava_warning/ex_act()
|
||||
return
|
||||
|
||||
/obj/effect/temp_visual/target/Initialize(mapload, list/flame_hit)
|
||||
/obj/effect/temp_visual/lava_warning/Initialize(mapload, var/reset_time = 10)
|
||||
. = ..()
|
||||
INVOKE_ASYNC(src, .proc/fall, flame_hit)
|
||||
INVOKE_ASYNC(src, .proc/fall, reset_time)
|
||||
src.alpha = 63.75
|
||||
animate(src, alpha = 255, time = duration)
|
||||
|
||||
/obj/effect/temp_visual/target/proc/fall(list/flame_hit)
|
||||
/obj/effect/temp_visual/lava_warning/proc/fall(var/reset_time)
|
||||
var/turf/T = get_turf(src)
|
||||
playsound(T,'sound/magic/fleshtostone.ogg', 80, 1)
|
||||
new /obj/effect/temp_visual/fireball(T)
|
||||
sleep(duration)
|
||||
if(ismineralturf(T))
|
||||
var/turf/closed/mineral/M = T
|
||||
M.gets_drilled()
|
||||
playsound(T, "explosion", 80, 1)
|
||||
new /obj/effect/hotspot(T)
|
||||
T.hotspot_expose(700, 50, 1)
|
||||
playsound(T,'sound/magic/fireball.ogg', 200, 1)
|
||||
|
||||
for(var/mob/living/L in T.contents)
|
||||
if(istype(L, /mob/living/simple_animal/hostile/megafauna/dragon))
|
||||
continue
|
||||
if(islist(flame_hit) && !flame_hit[L])
|
||||
L.adjustFireLoss(40)
|
||||
to_chat(L, "<span class='userdanger'>You're hit by the drake's fire breath!</span>")
|
||||
flame_hit[L] = TRUE
|
||||
else
|
||||
L.adjustFireLoss(10) //if we've already hit them, do way less damage
|
||||
L.adjustFireLoss(10)
|
||||
to_chat(L, "<span class='userdanger'>You fall directly into the pool of lava!</span>")
|
||||
|
||||
// deals damage to mechs
|
||||
for(var/obj/mecha/M in T.contents)
|
||||
M.take_damage(45, BRUTE, "melee", 1)
|
||||
|
||||
// changes turf to lava temporarily
|
||||
if(!istype(T, /turf/closed) && !istype(T, /turf/open/lava))
|
||||
var/lava_turf = /turf/open/lava/smooth
|
||||
var/reset_turf = T.type
|
||||
T.ChangeTurf(lava_turf)
|
||||
sleep(reset_time)
|
||||
T.ChangeTurf(reset_turf)
|
||||
|
||||
/obj/effect/temp_visual/drakewall
|
||||
desc = "An ash drakes true flame."
|
||||
name = "Fire Barrier"
|
||||
icon = 'icons/effects/fire.dmi'
|
||||
icon_state = "1"
|
||||
anchored = TRUE
|
||||
opacity = 0
|
||||
density = TRUE
|
||||
CanAtmosPass = ATMOS_PASS_DENSITY
|
||||
duration = 82
|
||||
color = COLOR_DARK_ORANGE
|
||||
|
||||
/obj/effect/temp_visual/lava_safe
|
||||
icon = 'icons/obj/hand_of_god_structures.dmi'
|
||||
icon_state = "trap-earth"
|
||||
layer = BELOW_MOB_LAYER
|
||||
light_range = 2
|
||||
duration = 13
|
||||
|
||||
/obj/effect/temp_visual/dragon_swoop
|
||||
name = "certain death"
|
||||
@@ -347,7 +447,7 @@ Difficulty: Medium
|
||||
pixel_x = -32
|
||||
pixel_y = -32
|
||||
color = "#FF0000"
|
||||
duration = 5
|
||||
duration = 10
|
||||
|
||||
/obj/effect/temp_visual/dragon_flight
|
||||
icon = 'icons/mob/lavaland/64x64megafauna.dmi'
|
||||
@@ -376,7 +476,7 @@ Difficulty: Medium
|
||||
/obj/effect/temp_visual/dragon_flight/end
|
||||
pixel_x = DRAKE_SWOOP_HEIGHT
|
||||
pixel_z = DRAKE_SWOOP_HEIGHT
|
||||
duration = 5
|
||||
duration = 10
|
||||
|
||||
/obj/effect/temp_visual/dragon_flight/end/flight(negative)
|
||||
if(negative)
|
||||
@@ -399,6 +499,16 @@ Difficulty: Medium
|
||||
crusher_loot = list()
|
||||
butcher_results = list(/obj/item/stack/ore/diamond = 5, /obj/item/stack/sheet/sinew = 5, /obj/item/stack/sheet/bone = 30)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/lesser/AltClickOn(atom/movable/A)
|
||||
if(!istype(A))
|
||||
return
|
||||
if(player_cooldown >= world.time)
|
||||
to_chat(src, "<span class='warning'>You need to wait [(player_cooldown - world.time) / 10] seconds before swooping again!</span>")
|
||||
return
|
||||
swoop_attack(FALSE, A)
|
||||
lava_pools(10, 2) // less pools but longer delay before spawns
|
||||
player_cooldown = world.time + 200 // needs seperate cooldown or cant use fire attacks
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/lesser/transformed //ash drake balanced around player control
|
||||
name = "transformed ash drake"
|
||||
desc = "A sentient being transformed into an ash drake"
|
||||
|
||||
@@ -64,7 +64,6 @@
|
||||
friendly_verb_simple = "groom"
|
||||
mob_size = MOB_SIZE_SMALL
|
||||
movement_type = FLYING
|
||||
gold_core_spawnable = FRIENDLY_SPAWN
|
||||
|
||||
var/parrot_damage_upper = 10
|
||||
var/parrot_state = PARROT_WANDER //Hunt for a perch when created
|
||||
|
||||
@@ -267,8 +267,7 @@ They *could* go in their appropriate files, but this is supposed to be modular
|
||||
apply_effect(EFFECT_STUTTER, G.stunforce)
|
||||
SEND_SIGNAL(src, COMSIG_LIVING_MINOR_SHOCK)
|
||||
|
||||
lastattacker = H.real_name
|
||||
lastattackerckey = H.ckey
|
||||
set_last_attacker(H)
|
||||
log_combat(H, src, "stunned")
|
||||
|
||||
playsound(loc, 'sound/weapons/egloves.ogg', 50, 1, -1)
|
||||
|
||||
@@ -390,7 +390,7 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
|
||||
speaking = "[DisplayTimeText(i, TRUE)] remain before causality stabilization."
|
||||
else
|
||||
speaking = "[i*0.1]..."
|
||||
radio.talk_into(src, speaking, common_channel)
|
||||
radio.talk_into(src, speaking, common_channel, list(SPAN_COMMAND)) // IT GOT WORSE, LOUD TIME
|
||||
sleep(10)
|
||||
|
||||
explode()
|
||||
@@ -715,7 +715,8 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
|
||||
|
||||
//Oh shit it's bad, time to freak out
|
||||
if(damage > emergency_point)
|
||||
radio.talk_into(src, "[emergency_alert] Integrity: [get_integrity()]%", common_channel)
|
||||
// it's bad, LETS YELL
|
||||
radio.talk_into(src, "[emergency_alert] Integrity: [get_integrity()]%", common_channel, list(SPAN_YELL))
|
||||
lastwarning = REALTIMEOFDAY
|
||||
if(!has_reached_emergency)
|
||||
investigate_log("has reached the emergency point for the first time.", INVESTIGATE_SUPERMATTER)
|
||||
|
||||
@@ -73,3 +73,11 @@
|
||||
name = ".38 DumDum bullet casing"
|
||||
desc = "A .38 DumDum bullet casing."
|
||||
projectile_type = /obj/item/projectile/bullet/c38/dumdum
|
||||
|
||||
//.45-70 GOVT (Gunslinger's Derringer)
|
||||
|
||||
/obj/item/ammo_casing/g4570
|
||||
name= ".45-70 Govt bullet casing"
|
||||
desc = "An exceedingly rare .45-70 Govt bullet casing."
|
||||
caliber = "45-70g"
|
||||
projectile_type = /obj/item/projectile/bullet/g4570
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
/obj/item/ammo_casing/chemgun
|
||||
name = "dart synthesiser"
|
||||
desc = "A high-power spring, linked to an energy-based dart synthesiser."
|
||||
projectile_type = /obj/item/projectile/bullet/dart
|
||||
projectile_type = /obj/item/projectile/bullet/dart/piercing
|
||||
firing_effect_type = null
|
||||
|
||||
/obj/item/ammo_casing/chemgun/ready_proj(atom/target, mob/living/user, quiet, zone_override = "")
|
||||
@@ -35,7 +35,7 @@
|
||||
var/obj/item/gun/chem/CG = loc
|
||||
if(CG.syringes_left <= 0)
|
||||
return
|
||||
CG.reagents.trans_to(BB, 15)
|
||||
CG.reagents.trans_to(BB, 10)
|
||||
BB.name = "chemical dart"
|
||||
CG.syringes_left--
|
||||
..()
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
/obj/item/ammo_box/magazine/internal/derringer
|
||||
name = "derringer muzzle"
|
||||
ammo_type = /obj/item/ammo_casing/c38
|
||||
caliber = "38"
|
||||
max_ammo = 2
|
||||
multiload = FALSE
|
||||
|
||||
/obj/item/ammo_box/magazine/internal/derringer/ammo_count(countempties = 1)
|
||||
if (!countempties)
|
||||
var/boolets = 0
|
||||
for(var/obj/item/ammo_casing/bullet in stored_ammo)
|
||||
if(bullet.BB)
|
||||
boolets++
|
||||
return boolets
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/item/ammo_box/magazine/internal/derringer/a357
|
||||
name = "\improper derringer muzzle"
|
||||
ammo_type = /obj/item/ammo_casing/a357
|
||||
caliber = "357"
|
||||
max_ammo = 2
|
||||
multiload = FALSE
|
||||
|
||||
/obj/item/ammo_box/magazine/internal/derringer/g4570
|
||||
name = "\improper derringer muzzle"
|
||||
ammo_type = /obj/item/ammo_casing/g4570
|
||||
caliber = "45-70g"
|
||||
max_ammo = 2
|
||||
multiload = FALSE
|
||||
@@ -407,11 +407,11 @@
|
||||
fire_sound = 'sound/weapons/rifleshot.ogg'
|
||||
weapon_weight = WEAPON_HEAVY
|
||||
mag_type = /obj/item/ammo_box/magazine/m10mm/rifle
|
||||
fire_delay = 30
|
||||
fire_delay = 10
|
||||
burst_size = 1
|
||||
can_unsuppress = TRUE
|
||||
can_suppress = TRUE
|
||||
w_class = WEIGHT_CLASS_HUGE
|
||||
w_class = WEIGHT_CLASS_BULKY
|
||||
slot_flags = ITEM_SLOT_BACK
|
||||
automatic_burst_overlay = FALSE
|
||||
actions_types = list()
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
/obj/item/gun/ballistic/derringer
|
||||
name = "\improper .38 Derringer"
|
||||
desc = "A easily concealable derringer. Uses .38 ammo"
|
||||
icon = 'icons/obj/guns/projectile.dmi'
|
||||
icon_state = "derringer"
|
||||
mag_type = /obj/item/ammo_box/magazine/internal/derringer
|
||||
obj_flags = UNIQUE_RENAME
|
||||
fire_sound = 'sound/weapons/revolvershot.ogg'
|
||||
casing_ejector = FALSE
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
|
||||
/obj/item/gun/ballistic/derringer/Initialize()
|
||||
..()
|
||||
transform *= 0.8 //Spriter too lazy to make icons smaller than default revolvers, local coder hacks in solution.
|
||||
|
||||
/obj/item/gun/ballistic/derringer/get_ammo(countchambered = FALSE, countempties = TRUE)
|
||||
var/boolets = 0 //legacy var name maturity
|
||||
if (chambered && countchambered)
|
||||
boolets++
|
||||
if (magazine)
|
||||
boolets += magazine.ammo_count(countempties)
|
||||
return boolets
|
||||
|
||||
/obj/item/gun/ballistic/derringer/attackby(obj/item/A, mob/user, params)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
var/num_loaded = magazine.attackby(A, user, params, 1)
|
||||
if(num_loaded)
|
||||
to_chat(user, "<span class='notice'>You load [num_loaded] shell\s into \the [src].</span>")
|
||||
playsound(user, 'sound/weapons/bulletinsert.ogg', 60, 1)
|
||||
A.update_icon()
|
||||
update_icon()
|
||||
chamber_round(0)
|
||||
|
||||
|
||||
/obj/item/gun/ballistic/derringer/attack_self(mob/living/user)
|
||||
var/num_unloaded = 0
|
||||
while (get_ammo() > 0)
|
||||
var/obj/item/ammo_casing/CB
|
||||
CB = magazine.get_round(0)
|
||||
chambered = null
|
||||
CB.forceMove(drop_location())
|
||||
CB.update_icon()
|
||||
num_unloaded++
|
||||
if (num_unloaded)
|
||||
to_chat(user, "<span class='notice'>You break open \the [src] and unload [num_unloaded] bullets\s.</span>")
|
||||
else
|
||||
to_chat(user, "<span class='warning'>[src] is empty!</span>")
|
||||
|
||||
/obj/item/gun/ballistic/derringer/examine(mob/user)
|
||||
. = ..()
|
||||
var/live_ammo = get_ammo(FALSE, FALSE)
|
||||
. += "[live_ammo ? live_ammo : "None"] of those are live rounds."
|
||||
|
||||
/obj/item/gun/ballistic/derringer/traitor
|
||||
name = "\improper .357 Syndicate Derringer"
|
||||
desc = "An easily concealable derriger, if not for the bright red and black. Uses .357 ammo"
|
||||
icon_state = "derringer_syndie"
|
||||
mag_type = /obj/item/ammo_box/magazine/internal/derringer/a357
|
||||
|
||||
/obj/item/gun/ballistic/derringer/gold
|
||||
name = "\improper Golden Derringer"
|
||||
desc = "The golden sheen is somewhat counterintuitive as a stealth weapon, but it looks cool. Uses .357 ammo"
|
||||
icon_state = "derringer_gold"
|
||||
mag_type = /obj/item/ammo_box/magazine/internal/derringer/a357
|
||||
fire_sound = 'sound/weapons/resonator_blast.ogg'
|
||||
|
||||
/obj/item/gun/ballistic/derringer/nukeop
|
||||
name = "\improper Gunslinger's Derringer"
|
||||
desc = "Sandalwood grip, wellkempt blue-grey steel barrels, and a crash like thunder itself. Uses the exceedingly rare 45-70 Govt. ammo"
|
||||
icon_state = "derringer"
|
||||
mag_type = /obj/item/ammo_box/magazine/internal/derringer/g4570
|
||||
fire_sound = 'sound/weapons/gunshotshotgunshot.ogg'
|
||||
@@ -13,9 +13,9 @@
|
||||
custom_materials = list(/datum/material/iron=2000)
|
||||
clumsy_check = FALSE
|
||||
fire_sound = 'sound/items/syringeproj.ogg'
|
||||
var/time_per_syringe = 250
|
||||
var/syringes_left = 4
|
||||
var/max_syringes = 4
|
||||
var/time_per_syringe = 300
|
||||
var/syringes_left = 5
|
||||
var/max_syringes = 5
|
||||
var/last_synth = 0
|
||||
|
||||
/obj/item/gun/chem/Initialize()
|
||||
|
||||
@@ -138,3 +138,13 @@
|
||||
embedding = list(embed_chance=90, fall_chance=2, jostle_chance=5, ignore_throwspeed_threshold=TRUE, pain_stam_pct=0.4, pain_mult=5, jostle_pain_mult=6, rip_time=10)
|
||||
wound_falloff_tile = -1
|
||||
embed_falloff_tile = -5
|
||||
|
||||
//.45-70 GOVT (Gunslinger's Derringer)
|
||||
//0bserver here. For all that is holy, do me a flavor, and do NOT allow people easy access to this ammo. This is meant for extremely lucky traitors, and nuclear operatives.
|
||||
|
||||
/obj/item/projectile/bullet/g4570
|
||||
name = ".45-70 Govt bullet"
|
||||
damage = 60
|
||||
armour_penetration = 40
|
||||
wound_bonus = -80
|
||||
|
||||
|
||||
@@ -105,3 +105,13 @@
|
||||
materials = list(/datum/material/iron = 2000, /datum/material/bluespace = 500)
|
||||
category = list("Bluespace Designs")
|
||||
departmental_flags = DEPARTMENTAL_FLAG_SERVICE
|
||||
|
||||
/datum/design/bluespace_pipe
|
||||
name = "Bluespace Pipe"
|
||||
desc = "A pipe that teleports gases."
|
||||
id = "bluespace_pipe"
|
||||
build_type = PROTOLATHE
|
||||
materials = list(/datum/material/gold = 1000, /datum/material/diamond = 750, /datum/material/uranium = 250, /datum/material/bluespace = 2000)
|
||||
build_path = /obj/item/pipe/bluespace
|
||||
category = list("Bluespace Designs")
|
||||
departmental_flags = DEPARTMENTAL_FLAG_SCIENCE | DEPARTMENTAL_FLAG_ENGINEERING
|
||||
|
||||
@@ -644,66 +644,109 @@
|
||||
//Cybernetic organs
|
||||
|
||||
/datum/design/cybernetic_liver
|
||||
name = "Cybernetic Liver"
|
||||
desc = "A cybernetic liver"
|
||||
name = "Basic Cybernetic Liver"
|
||||
desc = "A basic cybernetic liver."
|
||||
id = "cybernetic_liver"
|
||||
build_type = PROTOLATHE | MECHFAB
|
||||
construction_time = 40
|
||||
materials = list(/datum/material/iron = 500, /datum/material/glass = 500)
|
||||
build_path = /obj/item/organ/liver/cybernetic
|
||||
category = list("Misc","Medical Designs")
|
||||
departmental_flags = DEPARTMENTAL_FLAG_MEDICAL
|
||||
|
||||
/datum/design/cybernetic_heart
|
||||
name = "Cybernetic Heart"
|
||||
desc = "A cybernetic heart"
|
||||
id = "cybernetic_heart"
|
||||
build_type = PROTOLATHE | MECHFAB
|
||||
materials = list(/datum/material/iron = 500, /datum/material/glass = 500)
|
||||
build_path = /obj/item/organ/heart/cybernetic
|
||||
category = list("Misc","Medical Designs")
|
||||
departmental_flags = DEPARTMENTAL_FLAG_MEDICAL
|
||||
|
||||
/datum/design/cybernetic_heart_u
|
||||
name = "Upgraded Cybernetic Heart"
|
||||
desc = "An upgraded cybernetic heart"
|
||||
id = "cybernetic_heart_u"
|
||||
build_type = PROTOLATHE | MECHFAB
|
||||
construction_time = 50
|
||||
materials = list(/datum/material/iron = 500, /datum/material/glass = 500, /datum/material/silver = 500)
|
||||
build_path = /obj/item/organ/heart/cybernetic/upgraded
|
||||
category = list("Misc", "Medical Designs")
|
||||
departmental_flags = DEPARTMENTAL_FLAG_MEDICAL
|
||||
|
||||
/datum/design/cybernetic_liver_u
|
||||
name = "Upgraded Cybernetic Liver"
|
||||
desc = "An upgraded cybernetic liver"
|
||||
id = "cybernetic_liver_u"
|
||||
build_type = PROTOLATHE | MECHFAB
|
||||
/datum/design/cybernetic_liver/tier2
|
||||
name = "Cybernetic Liver"
|
||||
desc = "A cybernetic liver."
|
||||
id = "cybernetic_liver_tier2"
|
||||
materials = list(/datum/material/iron = 500, /datum/material/glass = 500)
|
||||
build_path = /obj/item/organ/liver/cybernetic/upgraded
|
||||
category = list("Misc","Medical Designs")
|
||||
build_path = /obj/item/organ/liver/cybernetic/tier2
|
||||
|
||||
/datum/design/cybernetic_liver/tier3
|
||||
name = "Upgraded Cybernetic Liver"
|
||||
desc = "An upgraded cybernetic liver."
|
||||
id = "cybernetic_liver_tier3"
|
||||
construction_time = 50
|
||||
materials = list(/datum/material/iron = 500, /datum/material/glass = 500, /datum/material/silver = 600, /datum/material/gold = 600, /datum/material/plasma = 1000, /datum/material/diamond = 2000)
|
||||
build_path = /obj/item/organ/liver/cybernetic/tier3
|
||||
|
||||
/datum/design/cybernetic_heart
|
||||
name = "Basic Cybernetic Heart"
|
||||
desc = "A basic cybernetic heart."
|
||||
id = "cybernetic_heart"
|
||||
build_type = PROTOLATHE | MECHFAB
|
||||
construction_time = 40
|
||||
materials = list(/datum/material/iron = 500, /datum/material/glass = 500)
|
||||
build_path = /obj/item/organ/heart/cybernetic
|
||||
category = list("Misc", "Medical Designs")
|
||||
departmental_flags = DEPARTMENTAL_FLAG_MEDICAL
|
||||
|
||||
/datum/design/cybernetic_heart/tier2
|
||||
name = "Cybernetic Heart"
|
||||
desc = "A cybernetic heart."
|
||||
id = "cybernetic_heart_tier2"
|
||||
materials = list(/datum/material/iron = 500, /datum/material/glass = 500)
|
||||
build_path = /obj/item/organ/heart/cybernetic/tier2
|
||||
|
||||
/datum/design/cybernetic_heart/tier3
|
||||
name = "Upgraded Cybernetic Heart"
|
||||
desc = "An upgraded cybernetic heart."
|
||||
id = "cybernetic_heart_tier3"
|
||||
construction_time = 50
|
||||
materials = list(/datum/material/iron = 500, /datum/material/glass = 500, /datum/material/silver = 600, /datum/material/gold = 600, /datum/material/plasma = 1000, /datum/material/diamond = 2000)
|
||||
build_path = /obj/item/organ/heart/cybernetic/tier3
|
||||
|
||||
/datum/design/cybernetic_lungs
|
||||
name = "Cybernetic Lungs"
|
||||
desc = "A pair of cybernetic lungs."
|
||||
name = "Basic Cybernetic Lungs"
|
||||
desc = "A basic pair of cybernetic lungs."
|
||||
id = "cybernetic_lungs"
|
||||
build_type = PROTOLATHE | MECHFAB
|
||||
construction_time = 40
|
||||
materials = list(/datum/material/iron = 500, /datum/material/glass = 500)
|
||||
build_path = /obj/item/organ/lungs/cybernetic
|
||||
category = list("Misc","Medical Designs")
|
||||
category = list("Misc", "Medical Designs")
|
||||
departmental_flags = DEPARTMENTAL_FLAG_MEDICAL
|
||||
|
||||
/datum/design/cybernetic_lungs_u
|
||||
/datum/design/cybernetic_lungs/tier2
|
||||
name = "Cybernetic Lungs"
|
||||
desc = "A pair of cybernetic lungs."
|
||||
id = "cybernetic_lungs_tier2"
|
||||
materials = list(/datum/material/iron = 500, /datum/material/glass = 500)
|
||||
build_path = /obj/item/organ/lungs/cybernetic/tier2
|
||||
|
||||
/datum/design/cybernetic_lungs/tier3
|
||||
name = "Upgraded Cybernetic Lungs"
|
||||
desc = "A pair of upgraded cybernetic lungs."
|
||||
id = "cybernetic_lungs_u"
|
||||
id = "cybernetic_lungs_tier3"
|
||||
construction_time = 50
|
||||
materials = list(/datum/material/iron = 500, /datum/material/glass = 500, /datum/material/silver = 600, /datum/material/gold = 600, /datum/material/plasma = 1000, /datum/material/diamond = 2000)
|
||||
build_path = /obj/item/organ/lungs/cybernetic/tier3
|
||||
|
||||
/datum/design/cybernetic_stomach
|
||||
name = "Basic Cybernetic Stomach"
|
||||
desc = "A basic cybernetic stomach."
|
||||
id = "cybernetic_stomach"
|
||||
build_type = PROTOLATHE | MECHFAB
|
||||
materials = list(/datum/material/iron = 500, /datum/material/glass = 500, /datum/material/silver = 500)
|
||||
build_path = /obj/item/organ/lungs/cybernetic/upgraded
|
||||
category = list("Misc","Medical Designs")
|
||||
construction_time = 40
|
||||
materials = list(/datum/material/iron = 500, /datum/material/glass = 500)
|
||||
build_path = /obj/item/organ/stomach/cybernetic
|
||||
category = list("Misc", "Medical Designs")
|
||||
departmental_flags = DEPARTMENTAL_FLAG_MEDICAL
|
||||
|
||||
/datum/design/cybernetic_stomach/tier2
|
||||
name = "Cybernetic Stomach"
|
||||
desc = "A cybernetic stomach."
|
||||
id = "cybernetic_stomach_tier2"
|
||||
materials = list(/datum/material/iron = 500, /datum/material/glass = 500)
|
||||
build_path = /obj/item/organ/stomach/cybernetic/tier2
|
||||
|
||||
/datum/design/cybernetic_stomach/tier3
|
||||
name = "Upgraded Cybernetic Stomach"
|
||||
desc = "An upgraded cybernetic stomach."
|
||||
id = "cybernetic_stomach_tier3"
|
||||
construction_time = 50
|
||||
materials = list(/datum/material/iron = 500, /datum/material/glass = 500, /datum/material/silver = 600, /datum/material/gold = 600, /datum/material/plasma = 1000, /datum/material/diamond = 2000)
|
||||
build_path = /obj/item/organ/stomach/cybernetic/tier3
|
||||
|
||||
/datum/design/cybernetic_tongue
|
||||
name = "Cybernetic tongue"
|
||||
desc = "A fancy cybernetic tongue."
|
||||
@@ -711,7 +754,7 @@
|
||||
build_type = PROTOLATHE | MECHFAB
|
||||
materials = list(/datum/material/iron = 500, /datum/material/glass = 500)
|
||||
build_path = /obj/item/organ/tongue/cybernetic
|
||||
category = list("Misc","Medical Designs")
|
||||
category = list("Misc", "Medical Designs")
|
||||
departmental_flags = DEPARTMENTAL_FLAG_MEDICAL
|
||||
|
||||
/datum/design/cybernetic_ears
|
||||
|
||||
@@ -61,7 +61,7 @@
|
||||
display_name = "Bluespace Travel"
|
||||
description = "Application of Bluespace for static teleportation technology."
|
||||
prereq_ids = list("adv_power", "adv_bluespace")
|
||||
design_ids = list("tele_station", "tele_hub", "quantumpad", "quantum_keycard", "launchpad", "launchpad_console", "teleconsole", "roastingstick")
|
||||
design_ids = list("tele_station", "tele_hub", "quantumpad", "quantum_keycard", "launchpad", "launchpad_console", "teleconsole", "roastingstick", "bluespace_pipe")
|
||||
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
|
||||
|
||||
/datum/techweb_node/unregulated_bluespace
|
||||
|
||||
@@ -67,20 +67,27 @@
|
||||
design_ids = list("implanter", "implantcase", "implant_chem", "implant_tracking", "locator", "c38_trac")
|
||||
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
|
||||
|
||||
/datum/techweb_node/basic_cyber_organs
|
||||
id = "basic_cyber_organs"
|
||||
starting_node = TRUE
|
||||
display_name = "Basic Cybernetic Organs"
|
||||
description = "We have the techinology to force him to live a disgusting halflife."
|
||||
design_ids = list("cybernetic_liver", "cybernetic_heart", "cybernetic_lungs", "cybernetic_stomach")
|
||||
|
||||
/datum/techweb_node/cyber_organs
|
||||
id = "cyber_organs"
|
||||
display_name = "Cybernetic Organs"
|
||||
description = "We have the technology to rebuild him."
|
||||
prereq_ids = list("adv_biotech")
|
||||
design_ids = list("cybernetic_ears", "cybernetic_heart", "cybernetic_liver", "cybernetic_lungs", "cybernetic_tongue")
|
||||
prereq_ids = list("biotech")
|
||||
design_ids = list("cybernetic_ears", "cybernetic_heart_tier2", "cybernetic_liver_tier2", "cybernetic_lungs_tier2", "cybernetic_stomach_tier2")
|
||||
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 1000)
|
||||
|
||||
/datum/techweb_node/cyber_organs_upgraded
|
||||
id = "cyber_organs_upgraded"
|
||||
display_name = "Upgraded Cybernetic Organs"
|
||||
description = "We have the technology to upgrade him."
|
||||
prereq_ids = list("cyber_organs")
|
||||
design_ids = list("cybernetic_ears_u", "cybernetic_heart_u", "cybernetic_liver_u", "cybernetic_lungs_u", "ipc_stomach")
|
||||
prereq_ids = list("adv_biotech", "cyber_organs")
|
||||
design_ids = list("cybernetic_ears_u", "cybernetic_heart_tier3", "cybernetic_liver_tier3", "cybernetic_lungs_tier3", "cybernetic_stomach_tier3")
|
||||
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 1500)
|
||||
|
||||
/datum/techweb_node/cyber_implants
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
id = "advanced_illegal_ballistics"
|
||||
display_name = "Advanced Non-Standard Ballistics"
|
||||
description = "Ballistic ammunition for non-standard firearms. Usually the ones you don't have nor want to be involved with."
|
||||
design_ids = list("10mm","10mmap","10mminc","10mmhp","sl357","sl357ap","pistolm9mm","m45","bolt_clip")
|
||||
design_ids = list("10mm","10mmap","10mminc","10mmhp","sl357","sl357ap","pistolm9mm","m45","bolt_clip","m10apbox","m10firebox","m10hpbox")
|
||||
prereq_ids = list("ballistic_weapons","syndicate_basic","explosive_weapons")
|
||||
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 25000) //This gives sec lethal mags/clips for guns from traitors, space, or anything in between.
|
||||
|
||||
|
||||
@@ -128,7 +128,7 @@ GLOBAL_LIST_INIT(cargo_shuttle_leave_behind_typecache, typecacheof(list(
|
||||
var/value = 0
|
||||
var/purchases = 0
|
||||
var/list/goodies_by_buyer = list() // if someone orders more than GOODY_FREE_SHIPPING_MAX goodies, we upcharge to a normal crate so they can't carry around 20 combat shotties
|
||||
|
||||
// var/list/lockers_by_buyer = list() // TODO, combine orders that come in lockers into a single locker to not crowd the shuttle
|
||||
for(var/datum/supply_order/SO in SSshuttle.shoppinglist)
|
||||
if(!empty_turfs.len)
|
||||
break
|
||||
|
||||
@@ -98,8 +98,8 @@
|
||||
failed = TRUE
|
||||
|
||||
/obj/item/organ/heart/slime
|
||||
name = "slime heart"
|
||||
desc = "It seems we've gotten to the slimy core of the matter."
|
||||
name = "mitochondria"
|
||||
desc = "The powerhouse of the cell. Or in this case, the hearty organelle of a slimeperson."
|
||||
icon_state = "heart-s-on"
|
||||
icon_base = "heart-s"
|
||||
|
||||
@@ -197,45 +197,67 @@
|
||||
colour = "red"
|
||||
|
||||
/obj/item/organ/heart/cybernetic
|
||||
name = "cybernetic heart"
|
||||
desc = "An electronic device designed to mimic the functions of an organic human heart. Offers no benefit over an organic heart other than being easy to make."
|
||||
name = "basic cybernetic heart"
|
||||
desc = "A basic electronic device designed to mimic the functions of an organic human heart."
|
||||
icon_state = "heart-c"
|
||||
organ_flags = ORGAN_SYNTHETIC
|
||||
maxHealth = STANDARD_ORGAN_THRESHOLD*0.75 //This also hits defib timer, so a bit higher than its less important counterparts
|
||||
|
||||
var/dose_available = FALSE
|
||||
var/rid = /datum/reagent/medicine/epinephrine
|
||||
var/ramount = 10
|
||||
var/emp_vulnerability = 1 //The value the severity of emps are divided by to determine the likelihood of permanent damage.
|
||||
|
||||
/obj/item/organ/heart/cybernetic/tier2
|
||||
name = "cybernetic heart"
|
||||
desc = "An electronic device designed to mimic the functions of an organic human heart. Also holds an emergency dose of epinephrine, used automatically after facing severe trauma."
|
||||
icon_state = "heart-c-u"
|
||||
maxHealth = 1.5 * STANDARD_ORGAN_THRESHOLD
|
||||
dose_available = TRUE
|
||||
emp_vulnerability = 2
|
||||
|
||||
/obj/item/organ/heart/cybernetic/tier3
|
||||
name = "upgraded cybernetic heart"
|
||||
desc = "An electronic device designed to mimic the functions of an organic human heart. Also holds an emergency dose of epinephrine, used automatically after facing severe trauma. This upgraded model can regenerate its dose after use."
|
||||
icon_state = "heart-c-u2"
|
||||
maxHealth = 2 * STANDARD_ORGAN_THRESHOLD
|
||||
dose_available = TRUE
|
||||
rid = /datum/reagent/medicine/atropine
|
||||
ramount = 5
|
||||
emp_vulnerability = 3
|
||||
|
||||
/obj/item/organ/heart/cybernetic/emp_act(severity)
|
||||
. = ..()
|
||||
|
||||
// If the owner doesn't need a heart, we don't need to do anything with it.
|
||||
if(!owner.needs_heart())
|
||||
return
|
||||
|
||||
if(. & EMP_PROTECT_SELF)
|
||||
return
|
||||
Stop()
|
||||
addtimer(CALLBACK(src, .proc/Restart), 0.2*severity SECONDS)
|
||||
damage += severity
|
||||
if(!COOLDOWN_FINISHED(src, severe_cooldown)) //So we cant just spam emp to kill people.
|
||||
owner.Dizzy(10)
|
||||
owner.losebreath += 10
|
||||
COOLDOWN_START(src, severe_cooldown, 20 SECONDS)
|
||||
if(prob(severity/emp_vulnerability)) //Chance of permanent effects
|
||||
organ_flags |= ORGAN_SYNTHETIC_EMP //Starts organ faliure - gonna need replacing soon.
|
||||
Stop()
|
||||
owner.visible_message("<span class='danger'>[owner] clutches at [owner.p_their()] chest as if [owner.p_their()] heart is stopping!</span>", \
|
||||
"<span class='userdanger'>You feel a terrible pain in your chest, as if your heart has stopped!</span>")
|
||||
addtimer(CALLBACK(src, .proc/Restart), 10 SECONDS)
|
||||
|
||||
/obj/item/organ/heart/cybernetic/upgraded
|
||||
name = "upgraded cybernetic heart"
|
||||
desc = "An electronic device designed to mimic the functions of an organic human heart. Also holds an emergency dose of epinephrine, used automatically after facing severe trauma. This upgraded model can regenerate its dose after use."
|
||||
icon_state = "heart-c-u"
|
||||
maxHealth = 2 * STANDARD_ORGAN_THRESHOLD
|
||||
|
||||
//I put it on upgraded for now.
|
||||
var/dose_available = TRUE
|
||||
var/rid = /datum/reagent/medicine/epinephrine
|
||||
var/ramount = 10
|
||||
|
||||
/obj/item/organ/heart/cybernetic/upgraded/on_life()
|
||||
/obj/item/organ/heart/cybernetic/on_life(delta_time, times_fired)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
if(dose_available && owner.health <= owner.crit_threshold && !owner.reagents.has_reagent(rid))
|
||||
owner.reagents.add_reagent(rid, ramount)
|
||||
used_dose()
|
||||
if(ramount < 10) //eats your nutrition to regen epinephrine
|
||||
var/regen_amount = owner.nutrition/2000
|
||||
owner.adjust_nutrition(-regen_amount)
|
||||
ramount += regen_amount
|
||||
|
||||
/obj/item/organ/heart/cybernetic/upgraded/proc/used_dose()
|
||||
/obj/item/organ/heart/cybernetic/proc/used_dose()
|
||||
owner.reagents.add_reagent(rid, ramount)
|
||||
dose_available = FALSE
|
||||
|
||||
/obj/item/organ/heart/cybernetic/tier3/used_dose()
|
||||
. = ..()
|
||||
addtimer(VARSET_CALLBACK(src, dose_available, TRUE), 5 MINUTES)
|
||||
ramount = 0
|
||||
|
||||
/obj/item/organ/heart/ipc
|
||||
name = "IPC heart"
|
||||
|
||||
@@ -77,6 +77,11 @@
|
||||
C.action_cooldown_mod *= value
|
||||
cachedmoveCalc = value
|
||||
|
||||
/obj/item/organ/liver/slime
|
||||
name = "viscoplasm" //this is the name that Fermis came up with when working on that organ PR that never got finished - if Fermis ever updates this, this probably will have a lot more functionality.
|
||||
icon_state = "liver-s"
|
||||
desc = "An organelle resembling a liver for slimepeople."
|
||||
|
||||
/obj/item/organ/liver/fly
|
||||
name = "insectoid liver"
|
||||
icon_state = "liver-x" //xenomorph liver? It's just a black liver so it fits.
|
||||
@@ -93,23 +98,41 @@
|
||||
icon_state = "liver-c"
|
||||
|
||||
/obj/item/organ/liver/cybernetic
|
||||
name = "cybernetic liver"
|
||||
name = "basic cybernetic liver"
|
||||
icon_state = "liver-c"
|
||||
desc = "An electronic device designed to mimic the functions of a human liver. It has no benefits over an organic liver, but is easy to produce."
|
||||
desc = "A very basic device designed to mimic the functions of a human liver. Handles toxins slightly worse than an organic liver."
|
||||
organ_flags = ORGAN_SYNTHETIC
|
||||
maxHealth = 1.1 * STANDARD_ORGAN_THRESHOLD
|
||||
toxTolerance = 0.3 * LIVER_DEFAULT_TOX_TOLERANCE //little less than 1u of toxin purging
|
||||
toxLethality = 1.1 * LIVER_DEFAULT_TOX_LETHALITY
|
||||
maxHealth = STANDARD_ORGAN_THRESHOLD*0.5
|
||||
|
||||
/obj/item/organ/liver/cybernetic/upgraded
|
||||
name = "upgraded cybernetic liver"
|
||||
var/emp_vulnerability = 1 //The value the severity of emps are divided by to determine the likelihood of permanent damage.
|
||||
|
||||
/obj/item/organ/liver/cybernetic/tier2
|
||||
name = "cybernetic liver"
|
||||
icon_state = "liver-c-u"
|
||||
desc = "An upgraded version of the cybernetic liver, designed to improve upon organic livers. It is resistant to alcohol poisoning and is very robust at filtering toxins."
|
||||
desc = "An electronic device designed to mimic the functions of a human liver. Handles toxins slightly better than an organic liver."
|
||||
maxHealth = 1.5 * STANDARD_ORGAN_THRESHOLD
|
||||
toxTolerance = 2 * LIVER_DEFAULT_TOX_TOLERANCE //6 units of toxin purging
|
||||
toxLethality = 0.8 * LIVER_DEFAULT_TOX_LETHALITY //20% less damage than a normal liver
|
||||
emp_vulnerability = 2
|
||||
|
||||
/obj/item/organ/liver/cybernetic/tier3
|
||||
name = "upgraded cybernetic liver"
|
||||
icon_state = "liver-c-u2"
|
||||
desc = "An upgraded version of the cybernetic liver, designed to improve further upon organic livers. It is resistant to alcohol poisoning and is very robust at filtering toxins."
|
||||
alcohol_tolerance = 0.001
|
||||
maxHealth = 2 * STANDARD_ORGAN_THRESHOLD
|
||||
toxTolerance = 15 //can shrug off up to 15u of toxins
|
||||
toxLethality = 0.008 //20% less damage than a normal liver
|
||||
toxTolerance = 5 * LIVER_DEFAULT_TOX_TOLERANCE //15 units of toxin purging
|
||||
toxLethality = 0.4 * LIVER_DEFAULT_TOX_LETHALITY //60% less damage than a normal liver
|
||||
emp_vulnerability = 3
|
||||
|
||||
/obj/item/organ/liver/cybernetic/emp_act(severity)
|
||||
. = ..()
|
||||
if(. & EMP_PROTECT_SELF)
|
||||
return
|
||||
damage += severity
|
||||
if(!COOLDOWN_FINISHED(src, severe_cooldown)) //So we cant just spam emp to kill people.
|
||||
owner.adjustToxLoss(10)
|
||||
COOLDOWN_START(src, severe_cooldown, 10 SECONDS)
|
||||
if(prob(severity/emp_vulnerability)) //Chance of permanent effects
|
||||
organ_flags |= ORGAN_SYNTHETIC_EMP //Starts organ faliure - gonna need replacing soon.
|
||||
|
||||
@@ -547,33 +547,52 @@
|
||||
maxHealth = INFINITY//I don't understand how plamamen work, so I'm not going to try t give them special lungs atm
|
||||
|
||||
/obj/item/organ/lungs/cybernetic
|
||||
name = "cybernetic lungs"
|
||||
desc = "A cybernetic version of the lungs found in traditional humanoid entities. It functions the same as an organic lung and is merely meant as a replacement."
|
||||
name = "basic cybernetic lungs"
|
||||
desc = "A basic cybernetic version of the lungs found in traditional humanoid entities."
|
||||
icon_state = "lungs-c"
|
||||
organ_flags = ORGAN_SYNTHETIC
|
||||
maxHealth = 400
|
||||
safe_oxygen_min = 13
|
||||
maxHealth = STANDARD_ORGAN_THRESHOLD * 0.5
|
||||
|
||||
/obj/item/organ/lungs/cybernetic/emp_act()
|
||||
. = ..()
|
||||
if(. & EMP_PROTECT_SELF)
|
||||
return
|
||||
owner.losebreath = 20
|
||||
owner.adjustOrganLoss(ORGAN_SLOT_LUNGS, 25)
|
||||
var/emp_vulnerability = 1 //The value the severity of emps are divided by to determine the likelihood of permanent damage.
|
||||
|
||||
/obj/item/organ/lungs/cybernetic/upgraded
|
||||
name = "upgraded cybernetic lungs"
|
||||
desc = "A more advanced version of the stock cybernetic lungs. They are capable of filtering out lower levels of toxins and carbon dioxide."
|
||||
/obj/item/organ/lungs/cybernetic/tier2
|
||||
name = "cybernetic lungs"
|
||||
desc = "A cybernetic version of the lungs found in traditional humanoid entities. Allows for greater intakes of oxygen than organic lungs, requiring slightly less pressure."
|
||||
icon_state = "lungs-c-u"
|
||||
safe_toxins_max = 20
|
||||
safe_co2_max = 20
|
||||
safe_oxygen_max = 250
|
||||
maxHealth = 1.5 * STANDARD_ORGAN_THRESHOLD
|
||||
safe_oxygen_min = 13
|
||||
safe_oxygen_max = 100
|
||||
emp_vulnerability = 2
|
||||
|
||||
/obj/item/organ/lungs/cybernetic/tier3
|
||||
name = "upgraded cybernetic lungs"
|
||||
desc = "A more advanced version of the stock cybernetic lungs. Features the ability to filter out various airbourne toxins and carbon dioxide even at heavy levels."
|
||||
icon_state = "lungs-c-u2"
|
||||
maxHealth = 2 * STANDARD_ORGAN_THRESHOLD
|
||||
safe_oxygen_min = 4 //You could literally be breathing the thinnest amount of oxygen and be fine
|
||||
safe_oxygen_max = 250 //Or be in an enriched oxygen room for that matter
|
||||
safe_toxins_max = 30
|
||||
safe_co2_max = 30
|
||||
SA_para_min = 30
|
||||
SA_sleep_min = 50
|
||||
BZ_trip_balls_min = 30
|
||||
emp_vulnerability = 3
|
||||
|
||||
cold_level_1_threshold = 200
|
||||
cold_level_2_threshold = 140
|
||||
cold_level_3_threshold = 100
|
||||
maxHealth = 550
|
||||
|
||||
/obj/item/organ/lungs/cybernetic/emp_act(severity)
|
||||
. = ..()
|
||||
if(. & EMP_PROTECT_SELF)
|
||||
return
|
||||
if(!COOLDOWN_FINISHED(src, severe_cooldown)) //So we cant just spam emp to kill people.
|
||||
owner.losebreath += 20
|
||||
COOLDOWN_START(src, severe_cooldown, 30 SECONDS)
|
||||
if(prob(severity/emp_vulnerability)) //Chance of permanent effects
|
||||
organ_flags |= ORGAN_SYNTHETIC_EMP //Starts organ faliure - gonna need replacing soon.
|
||||
|
||||
/obj/item/organ/lungs/ashwalker
|
||||
name = "ash lungs"
|
||||
desc = "blackened lungs identical from specimens recovered from lavaland, unsuited to higher air pressures."
|
||||
@@ -591,6 +610,7 @@
|
||||
|
||||
/obj/item/organ/lungs/slime
|
||||
name = "vacuole"
|
||||
icon_state = "lungs-s"
|
||||
desc = "A large organelle designed to store oxygen and other important gasses."
|
||||
|
||||
safe_toxins_max = 0 //We breathe this to gain POWER.
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
var/decay_factor = 0 //same as above but when without a living owner, set to 0 for generic organs
|
||||
var/high_threshold = STANDARD_ORGAN_THRESHOLD * 0.45 //when severe organ damage occurs
|
||||
var/low_threshold = STANDARD_ORGAN_THRESHOLD * 0.1 //when minor organ damage occurs
|
||||
var/severe_cooldown //cooldown for severe effects, used for synthetic organ emp effects.
|
||||
|
||||
///Organ variables for determining what we alert the owner with when they pass/clear the damage thresholds
|
||||
var/prev_damage = 0
|
||||
@@ -153,6 +154,9 @@
|
||||
/obj/item/organ/proc/on_life() //repair organ damage if the organ is not failing or synthetic
|
||||
if(organ_flags & ORGAN_FAILING || !owner)
|
||||
return FALSE
|
||||
if(organ_flags & ORGAN_SYNTHETIC_EMP) //Synthetic organ has been emped, is now failing.
|
||||
applyOrganDamage(maxHealth * decay_factor)
|
||||
return
|
||||
if(!is_cold() && damage)
|
||||
///Damage decrements by a percent of its maxhealth
|
||||
var/healing_amount = -(maxHealth * healing_factor)
|
||||
|
||||
@@ -78,6 +78,11 @@
|
||||
SEND_SIGNAL(H, COMSIG_CLEAR_MOOD_EVENT, "disgust")
|
||||
..()
|
||||
|
||||
/obj/item/organ/stomach/slime
|
||||
name = "macrolysosome" //an original cell has multiple lysosomes, but in this case a slimeperson only really has one... a big one? probably give it "macro" in the name.
|
||||
icon_state = "stomach-s"
|
||||
desc = "A slimeperson organelle resembling a stomach. It breaks down, or digests macromolecules. Or food and drinks."
|
||||
|
||||
/obj/item/organ/stomach/fly
|
||||
name = "insectoid stomach"
|
||||
icon_state = "stomach-x" //xenomorph liver? It's just a black liver so it fits.
|
||||
@@ -88,6 +93,40 @@
|
||||
icon_state = "stomach-p"
|
||||
desc = "A strange crystal that is responsible for metabolizing the unseen energy force that feeds plasmamen."
|
||||
|
||||
/obj/item/organ/stomach/cybernetic
|
||||
name = "basic cybernetic stomach"
|
||||
icon_state = "stomach-c"
|
||||
desc = "A basic device designed to mimic the functions of a human stomach"
|
||||
organ_flags = ORGAN_SYNTHETIC
|
||||
maxHealth = STANDARD_ORGAN_THRESHOLD * 0.5
|
||||
var/emp_vulnerability = 1 //The value the severity of emps are divided by to determine the likelihood of permanent damage.
|
||||
|
||||
/obj/item/organ/stomach/cybernetic/tier2
|
||||
name = "cybernetic stomach"
|
||||
icon_state = "stomach-c-u"
|
||||
desc = "An electronic device designed to mimic the functions of a human stomach. Handles disgusting food a bit better."
|
||||
maxHealth = 1.5 * STANDARD_ORGAN_THRESHOLD
|
||||
disgust_metabolism = 2
|
||||
emp_vulnerability = 2
|
||||
|
||||
/obj/item/organ/stomach/cybernetic/tier3
|
||||
name = "upgraded cybernetic stomach"
|
||||
icon_state = "stomach-c-u2"
|
||||
desc = "An upgraded version of the cybernetic stomach, designed to improve further upon organic stomachs. Handles disgusting food very well."
|
||||
maxHealth = 2 * STANDARD_ORGAN_THRESHOLD
|
||||
disgust_metabolism = 3
|
||||
emp_vulnerability = 3
|
||||
|
||||
/obj/item/organ/stomach/cybernetic/emp_act(severity)
|
||||
. = ..()
|
||||
if(. & EMP_PROTECT_SELF)
|
||||
return
|
||||
if(!COOLDOWN_FINISHED(src, severe_cooldown)) //So we cant just spam emp to kill people.
|
||||
owner.vomit(stun = FALSE)
|
||||
COOLDOWN_START(src, severe_cooldown, 10 SECONDS)
|
||||
if(prob(severity/emp_vulnerability)) //Chance of permanent effects
|
||||
organ_flags |= ORGAN_SYNTHETIC_EMP //Starts organ faliure - gonna need replacing soon.
|
||||
|
||||
/obj/item/organ/stomach/ipc
|
||||
name = "ipc cell"
|
||||
icon_state = "stomach-ipc"
|
||||
|
||||
@@ -172,17 +172,17 @@
|
||||
|
||||
/datum/uplink_item/bundles_TC/reroll
|
||||
name = "Renegotiate Contract"
|
||||
desc = "Selecting this will inform your employers that you wish for new objectives. Can only be done once; no take-backs."
|
||||
desc = "Selecting this will inform your employers that you wish for new objectives. Can only be done twice."
|
||||
item = /obj/effect/gibspawner/generic
|
||||
cost = 0
|
||||
cant_discount = TRUE
|
||||
restricted = TRUE
|
||||
limited_stock = 1
|
||||
limited_stock = 2
|
||||
|
||||
/datum/uplink_item/bundles_TC/reroll/purchase(mob/user, datum/component/uplink/U)
|
||||
var/datum/antagonist/traitor/T = user?.mind?.has_antag_datum(/datum/antagonist/traitor)
|
||||
if(istype(T))
|
||||
T.set_traitor_kind(/datum/traitor_class/human/subterfuge)
|
||||
T.set_traitor_kind(get_random_traitor_kind(blacklist = list(/datum/traitor_class/human/freeform, /datum/traitor_class/human/hijack, /datum/traitor_class/human/martyr)))
|
||||
else
|
||||
to_chat(user,"Invalid user for contract renegotiation.")
|
||||
|
||||
|
||||
@@ -22,6 +22,17 @@
|
||||
cost = 12
|
||||
include_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops)
|
||||
|
||||
/datum/uplink_item/implants/deathrattle
|
||||
name = "Box of Deathrattle Implants"
|
||||
desc = "A collection of implants (and one reusable implanter) that should be injected into the team. When one of the team \
|
||||
dies, all other implant holders recieve a mental message informing them of their teammates' name \
|
||||
and the location of their death. Unlike most implants, these are designed to be implanted \
|
||||
in any creature, biological or mechanical."
|
||||
item = /obj/item/storage/box/syndie_kit/imp_deathrattle
|
||||
cost = 4
|
||||
surplus = 0
|
||||
include_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops)
|
||||
|
||||
/datum/uplink_item/implants/freedom
|
||||
name = "Freedom Implant"
|
||||
desc = "An implant injected into the body and later activated at the user's will. It will attempt to free the \
|
||||
|
||||
@@ -208,9 +208,10 @@
|
||||
|
||||
/datum/uplink_item/role_restricted/chemical_gun
|
||||
name = "Reagent Dartgun"
|
||||
desc = "A heavily modified syringe gun which is capable of synthesizing its own chemical darts using input reagents. Can hold 100u of reagents."
|
||||
desc = "A heavily modified syringe gun which is capable of synthesizing its own chemical darts using input reagents. \
|
||||
Synthesizes one piercing 10 unit dart every 30 seconds up to a maximum of five. Can hold 100u of reagents."
|
||||
item = /obj/item/gun/chem
|
||||
cost = 12
|
||||
cost = 10
|
||||
restricted_roles = list("Chemist", "Chief Medical Officer")
|
||||
|
||||
/datum/uplink_item/role_restricted/reverse_bear_trap
|
||||
@@ -257,4 +258,4 @@
|
||||
item = /obj/item/storage/toolbox/emergency/turret
|
||||
cost = 11
|
||||
restricted_roles = list("Station Engineer")
|
||||
|
||||
|
||||
|
||||
@@ -45,6 +45,26 @@
|
||||
item = /obj/item/toy/plush/carpplushie/dehy_carp
|
||||
cost = 1
|
||||
|
||||
/datum/uplink_item/stealthy_weapons/derringerpack
|
||||
name = "Compact Derringer"
|
||||
desc = "An easily concealable handgun capable of firing .357 rounds. Comes in an inconspicuious packet of cigarettes with additional munitions."
|
||||
item = /obj/item/storage/fancy/cigarettes/derringer
|
||||
cost = 8
|
||||
surplus = 30
|
||||
|
||||
/datum/uplink_item/stealthy_weapons/derringerpack/purchase(mob/user, datum/component/uplink/U)
|
||||
if(prob(1)) //For the 1%
|
||||
item = /obj/item/storage/fancy/cigarettes/derringer/gold
|
||||
..()
|
||||
|
||||
/datum/uplink_item/stalthy_weapons/derringerpack_nukie
|
||||
name = "Antique Derringer"
|
||||
desc = "An easy to conceal, yet extremely deadly handgun, capable of firing .45-70 Govt rounds. Comes in a unique pack of cigarettes with additional munitions."
|
||||
item = /obj/item/storage/fancy/cigarettes/derringer/midworld
|
||||
include_modes = list(/datum/game_mode/nuclear)
|
||||
cost = 10
|
||||
surplus = 2
|
||||
|
||||
/datum/uplink_item/stealthy_weapons/edagger
|
||||
name = "Energy Dagger"
|
||||
desc = "A dagger made of energy that looks and functions as a pen when off."
|
||||
|
||||
Reference in New Issue
Block a user