Merge branch 'master' of https://github.com/Citadel-Station-13/Citadel-Station-13 into radiationsuitsareugly
# Conflicts: # icons/mob/clothing/hands.dmi # icons/mob/clothing/head.dmi # icons/obj/clothing/gloves.dmi # icons/obj/clothing/hats.dmi
This commit is contained in:
@@ -104,7 +104,7 @@
|
||||
QDEL_IN(src, 300)
|
||||
|
||||
//ATTACK HAND IGNORING PARENT RETURN VALUE
|
||||
/obj/effect/hallucination/simple/bluespace_stream/attack_hand(mob/user)
|
||||
/obj/effect/hallucination/simple/bluespace_stream/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
|
||||
if(user != seer || !linked_to)
|
||||
return
|
||||
var/slip_in_message = pick("slides sideways in an odd way, and disappears", "jumps into an unseen dimension",\
|
||||
|
||||
@@ -0,0 +1,463 @@
|
||||
/datum/component/personal_crafting/Initialize()
|
||||
if(ismob(parent))
|
||||
RegisterSignal(parent, COMSIG_MOB_CLIENT_LOGIN, .proc/create_mob_button)
|
||||
|
||||
/datum/component/personal_crafting/proc/create_mob_button(mob/user, client/CL)
|
||||
var/datum/hud/H = user.hud_used
|
||||
var/obj/screen/craft/C = new()
|
||||
C.icon = H.ui_style
|
||||
H.static_inventory += C
|
||||
CL.screen += C
|
||||
RegisterSignal(C, COMSIG_CLICK, .proc/component_ui_interact)
|
||||
|
||||
/datum/component/personal_crafting
|
||||
var/busy
|
||||
var/viewing_category = 1 //typical powergamer starting on the Weapons tab
|
||||
var/viewing_subcategory = 1
|
||||
var/list/categories = list(
|
||||
CAT_WEAPONRY = list(
|
||||
CAT_WEAPON,
|
||||
CAT_AMMO,
|
||||
),
|
||||
CAT_ROBOT = CAT_NONE,
|
||||
CAT_MISC = list(
|
||||
CAT_MISCELLANEOUS,
|
||||
CAT_TOOL,
|
||||
CAT_FURNITURE,
|
||||
),
|
||||
CAT_PRIMAL = CAT_NONE,
|
||||
CAT_FOOD = list(
|
||||
CAT_BREAD,
|
||||
CAT_BURGER,
|
||||
CAT_CAKE,
|
||||
CAT_DONUT,
|
||||
CAT_EGG,
|
||||
CAT_ICE,
|
||||
CAT_MEAT,
|
||||
CAT_MEXICAN,
|
||||
CAT_MISCFOOD,
|
||||
CAT_PASTRY,
|
||||
CAT_PIE,
|
||||
CAT_PIZZA,
|
||||
CAT_SEAFOOD,
|
||||
CAT_SALAD,
|
||||
CAT_SANDWICH,
|
||||
CAT_SOUP,
|
||||
CAT_SPAGHETTI,
|
||||
),
|
||||
CAT_DRINK = CAT_NONE,
|
||||
CAT_CLOTHING = CAT_NONE,
|
||||
)
|
||||
|
||||
var/cur_category = CAT_NONE
|
||||
var/cur_subcategory = CAT_NONE
|
||||
var/datum/action/innate/crafting/button
|
||||
var/display_craftable_only = FALSE
|
||||
var/display_compact = TRUE
|
||||
|
||||
/* This is what procs do:
|
||||
get_environment - gets a list of things accessable for crafting by user
|
||||
get_surroundings - takes a list of things and makes a list of key-types to values-amounts of said type in the list
|
||||
check_contents - takes a recipe and a key-type list and checks if said recipe can be done with available stuff
|
||||
check_tools - takes recipe, a key-type list, and a user and checks if there are enough tools to do the stuff, checks bugs one level deep
|
||||
construct_item - takes a recipe and a user, call all the checking procs, calls do_after, checks all the things again, calls del_reqs, creates result, calls CheckParts of said result with argument being list returned by deel_reqs
|
||||
del_reqs - takes recipe and a user, loops over the recipes reqs var and tries to find everything in the list make by get_environment and delete it/add to parts list, then returns the said list
|
||||
*/
|
||||
|
||||
/**
|
||||
* Check that the contents of the recipe meet the requirements.
|
||||
*
|
||||
* user: The /mob that initated the crafting.
|
||||
* R: The /datum/crafting_recipe being attempted.
|
||||
* contents: List of items to search for R's reqs.
|
||||
*/
|
||||
/datum/component/personal_crafting/proc/check_contents(atom/a, datum/crafting_recipe/R, list/contents)
|
||||
var/list/item_instances = contents["instances"]
|
||||
contents = contents["other"]
|
||||
|
||||
var/list/requirements_list = list()
|
||||
|
||||
// Process all requirements
|
||||
for(var/requirement_path in R.reqs)
|
||||
// Check we have the appropriate amount available in the contents list
|
||||
var/needed_amount = R.reqs[requirement_path]
|
||||
for(var/content_item_path in contents)
|
||||
// Right path and not blacklisted
|
||||
if(!ispath(content_item_path, requirement_path) || R.blacklist.Find(content_item_path))
|
||||
continue
|
||||
|
||||
needed_amount -= contents[content_item_path]
|
||||
if(needed_amount <= 0)
|
||||
break
|
||||
|
||||
if(needed_amount > 0)
|
||||
return FALSE
|
||||
|
||||
// Store the instances of what we will use for R.check_requirements() for requirement_path
|
||||
var/list/instances_list = list()
|
||||
for(var/instance_path in item_instances)
|
||||
if(ispath(instance_path, requirement_path))
|
||||
instances_list += item_instances[instance_path]
|
||||
|
||||
requirements_list[requirement_path] = instances_list
|
||||
|
||||
for(var/requirement_path in R.chem_catalysts)
|
||||
if(contents[requirement_path] < R.chem_catalysts[requirement_path])
|
||||
return FALSE
|
||||
|
||||
return R.check_requirements(a, requirements_list)
|
||||
|
||||
/datum/component/personal_crafting/proc/get_environment(atom/a, list/blacklist = null, radius_range = 1)
|
||||
. = list()
|
||||
|
||||
if(!isturf(a.loc))
|
||||
return
|
||||
|
||||
for(var/atom/movable/AM in range(radius_range, a))
|
||||
if(AM.flags_1 & HOLOGRAM_1)
|
||||
continue
|
||||
. += AM
|
||||
|
||||
/datum/component/personal_crafting/proc/get_surroundings(atom/a)
|
||||
. = list()
|
||||
.["tool_behaviour"] = list()
|
||||
.["other"] = list()
|
||||
.["instances"] = list()
|
||||
for(var/obj/item/I in get_environment(a))
|
||||
if(I.flags_1 & HOLOGRAM_1)
|
||||
continue
|
||||
if(.["instances"][I.type])
|
||||
.["instances"][I.type] += I
|
||||
else
|
||||
.["instances"][I.type] = list(I)
|
||||
if(istype(I, /obj/item/stack))
|
||||
var/obj/item/stack/S = I
|
||||
.["other"][I.type] += S.amount
|
||||
else if(I.tool_behaviour)
|
||||
.["tool_behaviour"] += I.tool_behaviour
|
||||
.["other"][I.type] += 1
|
||||
else
|
||||
if(istype(I, /obj/item/reagent_containers))
|
||||
var/obj/item/reagent_containers/RC = I
|
||||
if(RC.is_drainable())
|
||||
for(var/datum/reagent/A in RC.reagents.reagent_list)
|
||||
.["other"][A.type] += A.volume
|
||||
.["other"][I.type] += 1
|
||||
|
||||
/datum/component/personal_crafting/proc/check_tools(atom/a, datum/crafting_recipe/R, list/contents)
|
||||
if(!R.tools.len)
|
||||
return TRUE
|
||||
var/list/possible_tools = list()
|
||||
var/list/present_qualities = list()
|
||||
present_qualities |= contents["tool_behaviour"]
|
||||
for(var/obj/item/I in a.contents)
|
||||
if(istype(I, /obj/item/storage))
|
||||
for(var/obj/item/SI in I.contents)
|
||||
possible_tools += SI.type
|
||||
if(SI.tool_behaviour)
|
||||
present_qualities.Add(SI.tool_behaviour)
|
||||
|
||||
possible_tools += I.type
|
||||
|
||||
if(I.tool_behaviour)
|
||||
present_qualities.Add(I.tool_behaviour)
|
||||
|
||||
possible_tools |= contents["other"]
|
||||
|
||||
main_loop:
|
||||
for(var/A in R.tools)
|
||||
if(A in present_qualities)
|
||||
continue
|
||||
else
|
||||
for(var/I in possible_tools)
|
||||
if(ispath(I, A))
|
||||
continue main_loop
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/component/personal_crafting/proc/construct_item(atom/a, datum/crafting_recipe/R)
|
||||
var/list/contents = get_surroundings(a)
|
||||
var/send_feedback = 1
|
||||
if(check_contents(a, R, contents))
|
||||
if(check_tools(a, R, contents))
|
||||
//If we're a mob we'll try a do_after; non mobs will instead instantly construct the item
|
||||
if(ismob(a) && !do_after(a, R.time, target = a))
|
||||
return "."
|
||||
contents = get_surroundings(a)
|
||||
if(!check_contents(a, R, contents))
|
||||
return ", missing component."
|
||||
if(!check_tools(a, R, contents))
|
||||
return ", missing tool."
|
||||
var/list/parts = del_reqs(R, a)
|
||||
var/atom/movable/I = new R.result (get_turf(a.loc))
|
||||
I.CheckParts(parts, R)
|
||||
if(send_feedback)
|
||||
SSblackbox.record_feedback("tally", "object_crafted", 1, I.type)
|
||||
return I //Send the item back to whatever called this proc so it can handle whatever it wants to do with the new item
|
||||
return ", missing tool."
|
||||
return ", missing component."
|
||||
|
||||
/*Del reqs works like this:
|
||||
|
||||
Loop over reqs var of the recipe
|
||||
Set var amt to the value current cycle req is pointing to, its amount of type we need to delete
|
||||
Get var/surroundings list of things accessable to crafting by get_environment()
|
||||
Check the type of the current cycle req
|
||||
If its reagent then do a while loop, inside it try to locate() reagent containers, inside such containers try to locate needed reagent, if there isnt remove thing from surroundings
|
||||
If there is enough reagent in the search result then delete the needed amount, create the same type of reagent with the same data var and put it into deletion list
|
||||
If there isnt enough take all of that reagent from the container, put into deletion list, substract the amt var by the volume of reagent, remove the container from surroundings list and keep searching
|
||||
While doing above stuff check deletion list if it already has such reagnet, if yes merge instead of adding second one
|
||||
If its stack check if it has enough amount
|
||||
If yes create new stack with the needed amount and put in into deletion list, substract taken amount from the stack
|
||||
If no put all of the stack in the deletion list, substract its amount from amt and keep searching
|
||||
While doing above stuff check deletion list if it already has such stack type, if yes try to merge them instead of adding new one
|
||||
If its anything else just locate() in in the list in a while loop, each find --s the amt var and puts the found stuff in deletion loop
|
||||
|
||||
Then do a loop over parts var of the recipe
|
||||
Do similar stuff to what we have done above, but now in deletion list, until the parts conditions are satisfied keep taking from the deletion list and putting it into parts list for return
|
||||
|
||||
After its done loop over deletion list and delete all the shit that wasnt taken by parts loop
|
||||
|
||||
del_reqs return the list of parts resulting object will receive as argument of CheckParts proc, on the atom level it will add them all to the contents, on all other levels it calls ..() and does whatever is needed afterwards but from contents list already
|
||||
*/
|
||||
|
||||
/datum/component/personal_crafting/proc/del_reqs(datum/crafting_recipe/R, atom/a)
|
||||
var/list/surroundings
|
||||
var/list/Deletion = list()
|
||||
. = list()
|
||||
var/data
|
||||
var/amt
|
||||
main_loop:
|
||||
for(var/A in R.reqs)
|
||||
amt = R.reqs[A]
|
||||
surroundings = get_environment(a, R.blacklist)
|
||||
surroundings -= Deletion
|
||||
if(ispath(A, /datum/reagent))
|
||||
var/datum/reagent/RG = new A
|
||||
var/datum/reagent/RGNT
|
||||
while(amt > 0)
|
||||
var/obj/item/reagent_containers/RC = locate() in surroundings
|
||||
RG = RC.reagents.get_reagent(A)
|
||||
if(RG)
|
||||
if(!locate(RG.type) in Deletion)
|
||||
Deletion += new RG.type()
|
||||
if(RG.volume > amt)
|
||||
RG.volume -= amt
|
||||
data = RG.data
|
||||
RC.reagents.conditional_update(RC)
|
||||
RG = locate(RG.type) in Deletion
|
||||
RG.volume = amt
|
||||
RG.data += data
|
||||
continue main_loop
|
||||
else
|
||||
surroundings -= RC
|
||||
amt -= RG.volume
|
||||
RC.reagents.reagent_list -= RG
|
||||
RC.reagents.conditional_update(RC)
|
||||
RGNT = locate(RG.type) in Deletion
|
||||
RGNT.volume += RG.volume
|
||||
RGNT.data += RG.data
|
||||
qdel(RG)
|
||||
RC.on_reagent_change()
|
||||
else
|
||||
surroundings -= RC
|
||||
else if(ispath(A, /obj/item/stack))
|
||||
var/obj/item/stack/S
|
||||
var/obj/item/stack/SD
|
||||
while(amt > 0)
|
||||
S = locate(A) in surroundings
|
||||
if(S.amount >= amt)
|
||||
if(!locate(S.type) in Deletion)
|
||||
SD = new S.type()
|
||||
Deletion += SD
|
||||
S.use(amt)
|
||||
SD = locate(S.type) in Deletion
|
||||
SD.amount += amt
|
||||
continue main_loop
|
||||
else
|
||||
amt -= S.amount
|
||||
if(!locate(S.type) in Deletion)
|
||||
Deletion += S
|
||||
else
|
||||
data = S.amount
|
||||
S = locate(S.type) in Deletion
|
||||
S.add(data)
|
||||
surroundings -= S
|
||||
else
|
||||
var/atom/movable/I
|
||||
while(amt > 0)
|
||||
I = locate(A) in surroundings
|
||||
Deletion += I
|
||||
surroundings -= I
|
||||
amt--
|
||||
var/list/partlist = list(R.parts.len)
|
||||
for(var/M in R.parts)
|
||||
partlist[M] = R.parts[M]
|
||||
for(var/A in R.parts)
|
||||
if(istype(A, /datum/reagent))
|
||||
var/datum/reagent/RG = locate(A) in Deletion
|
||||
if(RG.volume > partlist[A])
|
||||
RG.volume = partlist[A]
|
||||
. += RG
|
||||
Deletion -= RG
|
||||
continue
|
||||
else if(istype(A, /obj/item/stack))
|
||||
var/obj/item/stack/ST = locate(A) in Deletion
|
||||
if(ST.amount > partlist[A])
|
||||
ST.amount = partlist[A]
|
||||
. += ST
|
||||
Deletion -= ST
|
||||
continue
|
||||
else
|
||||
while(partlist[A] > 0)
|
||||
var/atom/movable/AM = locate(A) in Deletion
|
||||
. += AM
|
||||
Deletion -= AM
|
||||
partlist[A] -= 1
|
||||
while(Deletion.len)
|
||||
var/DL = Deletion[Deletion.len]
|
||||
Deletion.Cut(Deletion.len)
|
||||
qdel(DL)
|
||||
|
||||
/datum/component/personal_crafting/proc/component_ui_interact(obj/screen/craft/image, location, control, params, user)
|
||||
if(user == parent)
|
||||
ui_interact(user)
|
||||
|
||||
//For the UI related things we're going to assume the user is a mob rather than typesetting it to an atom as the UI isn't generated if the parent is an atom
|
||||
/datum/component/personal_crafting/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.not_incapacitated_turf_state)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
cur_category = categories[1]
|
||||
if(islist(categories[cur_category]))
|
||||
var/list/subcats = categories[cur_category]
|
||||
cur_subcategory = subcats[1]
|
||||
else
|
||||
cur_subcategory = CAT_NONE
|
||||
ui = new(user, src, ui_key, "PersonalCrafting", "Crafting Menu", 700, 800, master_ui, state)
|
||||
ui.open()
|
||||
|
||||
/datum/component/personal_crafting/ui_data(mob/user)
|
||||
var/list/data = list()
|
||||
data["busy"] = busy
|
||||
data["category"] = cur_category
|
||||
data["subcategory"] = cur_subcategory
|
||||
data["display_craftable_only"] = display_craftable_only
|
||||
data["display_compact"] = display_compact
|
||||
|
||||
var/list/surroundings = get_surroundings(user)
|
||||
var/list/craftability = list()
|
||||
for(var/rec in GLOB.crafting_recipes)
|
||||
var/datum/crafting_recipe/R = rec
|
||||
|
||||
if(!R.always_availible && !(R.type in user?.mind?.learned_recipes)) //User doesn't actually know how to make this.
|
||||
continue
|
||||
|
||||
if((R.category != cur_category) || (R.subcategory != cur_subcategory))
|
||||
continue
|
||||
|
||||
craftability["[REF(R)]"] = check_contents(user, R, surroundings)
|
||||
|
||||
data["craftability"] = craftability
|
||||
return data
|
||||
|
||||
/datum/component/personal_crafting/ui_static_data(mob/user)
|
||||
var/list/data = list()
|
||||
|
||||
var/list/crafting_recipes = list()
|
||||
for(var/rec in GLOB.crafting_recipes)
|
||||
var/datum/crafting_recipe/R = rec
|
||||
|
||||
if(R.name == "") //This is one of the invalid parents that sneaks in
|
||||
continue
|
||||
|
||||
if(!R.always_availible && !(R.type in user?.mind?.learned_recipes)) //User doesn't actually know how to make this.
|
||||
continue
|
||||
|
||||
if(isnull(crafting_recipes[R.category]))
|
||||
crafting_recipes[R.category] = list()
|
||||
|
||||
if(R.subcategory == CAT_NONE)
|
||||
crafting_recipes[R.category] += list(build_recipe_data(R))
|
||||
else
|
||||
if(isnull(crafting_recipes[R.category][R.subcategory]))
|
||||
crafting_recipes[R.category][R.subcategory] = list()
|
||||
crafting_recipes[R.category]["has_subcats"] = TRUE
|
||||
crafting_recipes[R.category][R.subcategory] += list(build_recipe_data(R))
|
||||
|
||||
data["crafting_recipes"] = crafting_recipes
|
||||
return data
|
||||
|
||||
/datum/component/personal_crafting/ui_act(action, params)
|
||||
if(..())
|
||||
return
|
||||
switch(action)
|
||||
if("make")
|
||||
var/mob/user = usr
|
||||
var/datum/crafting_recipe/TR = locate(params["recipe"]) in GLOB.crafting_recipes
|
||||
busy = TRUE
|
||||
ui_interact(user)
|
||||
var/atom/movable/result = construct_item(user, TR)
|
||||
if(!istext(result)) //We made an item and didn't get a fail message
|
||||
if(ismob(user) && isitem(result)) //In case the user is actually possessing a non mob like a machine
|
||||
user.put_in_hands(result)
|
||||
else
|
||||
result.forceMove(user.drop_location())
|
||||
to_chat(user, "<span class='notice'>[TR.name] constructed.</span>")
|
||||
else
|
||||
to_chat(user, "<span class='warning'>Construction failed[result]</span>")
|
||||
busy = FALSE
|
||||
if("toggle_recipes")
|
||||
display_craftable_only = !display_craftable_only
|
||||
. = TRUE
|
||||
if("toggle_compact")
|
||||
display_compact = !display_compact
|
||||
. = TRUE
|
||||
if("set_category")
|
||||
if(!isnull(params["category"]))
|
||||
cur_category = params["category"]
|
||||
if(!isnull(params["subcategory"]))
|
||||
if(params["subcategory"] == "0")
|
||||
cur_subcategory = ""
|
||||
else
|
||||
cur_subcategory = params["subcategory"]
|
||||
. = TRUE
|
||||
|
||||
/datum/component/personal_crafting/proc/build_recipe_data(datum/crafting_recipe/R)
|
||||
var/list/data = list()
|
||||
data["name"] = R.name
|
||||
data["ref"] = "[REF(R)]"
|
||||
var/req_text = ""
|
||||
var/tool_text = ""
|
||||
var/catalyst_text = ""
|
||||
|
||||
for(var/a in R.reqs)
|
||||
//We just need the name, so cheat-typecast to /atom for speed (even tho Reagents are /datum they DO have a "name" var)
|
||||
//Also these are typepaths so sadly we can't just do "[a]"
|
||||
var/atom/A = a
|
||||
req_text += " [R.reqs[A]] [initial(A.name)],"
|
||||
req_text = replacetext(req_text,",","",-1)
|
||||
data["req_text"] = req_text
|
||||
|
||||
for(var/a in R.chem_catalysts)
|
||||
var/atom/A = a //cheat-typecast
|
||||
catalyst_text += " [R.chem_catalysts[A]] [initial(A.name)],"
|
||||
catalyst_text = replacetext(catalyst_text,",","",-1)
|
||||
data["catalyst_text"] = catalyst_text
|
||||
|
||||
for(var/a in R.tools)
|
||||
if(ispath(a, /obj/item))
|
||||
var/obj/item/b = a
|
||||
tool_text += " [initial(b.name)],"
|
||||
else
|
||||
tool_text += " [a],"
|
||||
tool_text = replacetext(tool_text,",","",-1)
|
||||
data["tool_text"] = tool_text
|
||||
|
||||
return data
|
||||
|
||||
//Mind helpers
|
||||
|
||||
/datum/mind/proc/teach_crafting_recipe(R)
|
||||
if(!learned_recipes)
|
||||
learned_recipes = list()
|
||||
learned_recipes |= R
|
||||
@@ -1,4 +1,4 @@
|
||||
k// PARTS //
|
||||
// PARTS //
|
||||
/obj/item/weaponcrafting
|
||||
icon = 'icons/obj/improvised.dmi'
|
||||
|
||||
@@ -8,61 +8,33 @@ k// PARTS //
|
||||
custom_materials = list(/datum/material/wood = MINERAL_MATERIAL_AMOUNT * 6)
|
||||
icon_state = "riflestock"
|
||||
|
||||
/obj/item/weaponcrafting/durathread_string
|
||||
name = "durathread string"
|
||||
desc = "A long piece of durathread with some resemblance to cable coil."
|
||||
/obj/item/weaponcrafting/string
|
||||
name = "wound thread"
|
||||
desc = "A long piece of thread with some resemblance to cable coil."
|
||||
icon_state = "durastring"
|
||||
|
||||
////////////////////////////////
|
||||
// KAT IMPROVISED WEAPON PARTS//
|
||||
// IMPROVISED WEAPON PARTS//
|
||||
////////////////////////////////
|
||||
|
||||
/obj/item/weaponcrafting/improvised_parts
|
||||
name = "Eerie bunch of coloured dots."
|
||||
desc = "You feel the urge to report to Central that the parent type of guncrafting, which should never appear in this reality, has appeared. Whatever that means."
|
||||
name = "Debug Improvised Gun Part"
|
||||
desc = "A badly coded gun part. You should report coders if you see this."
|
||||
icon = 'icons/obj/guns/gun_parts.dmi'
|
||||
icon_state = "palette"
|
||||
|
||||
// BARRELS
|
||||
|
||||
/obj/item/weaponcrafting/improvised_parts/barrel_rifle
|
||||
name = "rifle barrel"
|
||||
desc = "A pipe with a diameter just the right size to fire 7.62 rounds out of."
|
||||
icon_state = "barrel_rifle"
|
||||
|
||||
/obj/item/weaponcrafting/improvised_parts/barrel_shotgun
|
||||
name = "shotgun barrel"
|
||||
desc = "A twenty bore shotgun barrel."
|
||||
icon_state = "barrel_shotgun"
|
||||
|
||||
/obj/item/weaponcrafting/improvised_parts/barrel_pistol
|
||||
name = "pistol barrel"
|
||||
desc = "A pipe with a small diameter and some holes finely cut into it. It fits .32 ACP bullets. Probably."
|
||||
icon_state = "barrel_pistol"
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
|
||||
// RECEIVERS
|
||||
|
||||
/obj/item/weaponcrafting/improvised_parts/rifle_receiver
|
||||
name = "bolt action receiver"
|
||||
desc = "A crudely constructed receiver to create an improvised bolt-action breechloaded rifle. It's generic enough to modify to create other rifles, potentially."
|
||||
name = "rifle receiver"
|
||||
desc = "A crudely constructed receiver to create an improvised bolt-action breechloaded rifle." // removed some text implying that the item had more uses than it does
|
||||
icon_state = "receiver_rifle"
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
|
||||
/obj/item/weaponcrafting/improvised_parts/pistol_receiver
|
||||
name = "pistol receiver"
|
||||
desc = "A receiver to connect house and connects all the parts to make an improvised pistol."
|
||||
icon_state = "receiver_pistol"
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
|
||||
/obj/item/weaponcrafting/improvised_parts/laser_receiver
|
||||
name = "energy emitter assembly"
|
||||
desc = "A mixture of components haphazardly wired together to form an energy emitter."
|
||||
icon_state = "laser_assembly"
|
||||
|
||||
/obj/item/weaponcrafting/improvised_parts/shotgun_receiver
|
||||
name = "break-action assembly"
|
||||
desc = "An improvised receiver to create a break-action breechloaded shotgun. Parts of this are still useful if you want to make another type of shotgun, however."
|
||||
name = "shotgun reciever"
|
||||
desc = "An improvised receiver to create a break-action breechloaded shotgun." // removed some text implying that the item had more uses than it does
|
||||
icon_state = "receiver_shotgun"
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
|
||||
@@ -78,15 +50,3 @@ k// PARTS //
|
||||
name = "wooden firearm body"
|
||||
desc = "A crudely fashioned wooden body to help keep higher calibre improvised weapons from blowing themselves apart."
|
||||
icon_state = "wooden_body"
|
||||
|
||||
/obj/item/weaponcrafting/improvised_parts/wooden_grip
|
||||
name = "wooden pistol grip"
|
||||
desc = "A nice wooden grip hollowed out for pistol magazines."
|
||||
icon_state = "wooden_pistolgrip"
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
|
||||
/obj/item/weaponcrafting/improvised_parts/makeshift_lens
|
||||
name = "makeshift focusing lens"
|
||||
desc = "A properly made lens made with actual glassworking tools would perform much better, but this will have to do."
|
||||
icon_state = "focusing_lens"
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
|
||||
@@ -244,7 +244,7 @@
|
||||
|
||||
/datum/crafting_recipe/rcl
|
||||
name = "Makeshift Rapid Cable Layer"
|
||||
result = /obj/item/twohanded/rcl/ghetto
|
||||
result = /obj/item/rcl/ghetto
|
||||
time = 40
|
||||
tools = list(TOOL_WELDER, TOOL_SCREWDRIVER, TOOL_WRENCH)
|
||||
reqs = list(/obj/item/stack/sheet/metal = 15)
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
|
||||
/datum/crafting_recipe/bonespear
|
||||
name = "Bone Spear"
|
||||
result = /obj/item/twohanded/bonespear
|
||||
result = /obj/item/spear/bonespear
|
||||
time = 30
|
||||
reqs = list(/obj/item/stack/sheet/bone = 4,
|
||||
/obj/item/stack/sheet/sinew = 1)
|
||||
@@ -58,7 +58,7 @@
|
||||
|
||||
/datum/crafting_recipe/boneaxe
|
||||
name = "Bone Axe"
|
||||
result = /obj/item/twohanded/fireaxe/boneaxe
|
||||
result = /obj/item/fireaxe/boneaxe
|
||||
time = 50
|
||||
reqs = list(/obj/item/stack/sheet/bone = 6,
|
||||
/obj/item/stack/sheet/sinew = 3)
|
||||
@@ -74,20 +74,20 @@
|
||||
/datum/crafting_recipe/headpike
|
||||
name = "Spike Head (Glass Spear)"
|
||||
time = 65
|
||||
reqs = list(/obj/item/twohanded/spear = 1,
|
||||
reqs = list(/obj/item/spear = 1,
|
||||
/obj/item/bodypart/head = 1)
|
||||
parts = list(/obj/item/bodypart/head = 1,
|
||||
/obj/item/twohanded/spear = 1)
|
||||
/obj/item/spear = 1)
|
||||
result = /obj/structure/headpike
|
||||
category = CAT_PRIMAL
|
||||
|
||||
/datum/crafting_recipe/headpikebone
|
||||
name = "Spike Head (Bone Spear)"
|
||||
time = 65
|
||||
reqs = list(/obj/item/twohanded/bonespear = 1,
|
||||
reqs = list(/obj/item/spear/bonespear = 1,
|
||||
/obj/item/bodypart/head = 1)
|
||||
parts = list(/obj/item/bodypart/head = 1,
|
||||
/obj/item/twohanded/bonespear = 1)
|
||||
/obj/item/spear/bonespear = 1)
|
||||
result = /obj/structure/headpike/bone
|
||||
category = CAT_PRIMAL
|
||||
|
||||
@@ -103,7 +103,7 @@
|
||||
/datum/crafting_recipe/bone_bow
|
||||
name = "Bone Bow"
|
||||
result = /obj/item/gun/ballistic/bow/ashen
|
||||
time = 200
|
||||
time = 120 // 80+120 = 200
|
||||
always_availible = FALSE
|
||||
reqs = list(/obj/item/stack/sheet/bone = 8,
|
||||
/obj/item/stack/sheet/sinew = 4)
|
||||
@@ -112,7 +112,7 @@
|
||||
/datum/crafting_recipe/bow_tablet
|
||||
name = "Sandstone Bow Making Manual"
|
||||
result = /obj/item/book/granter/crafting_recipe/bone_bow
|
||||
time = 600 //Scribing
|
||||
time = 200 //Scribing // don't care
|
||||
always_availible = FALSE
|
||||
reqs = list(/obj/item/stack/rods = 1,
|
||||
/obj/item/stack/sheet/mineral/sandstone = 4)
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
|
||||
/datum/crafting_recipe/spear
|
||||
name = "Spear"
|
||||
result = /obj/item/twohanded/spear
|
||||
result = /obj/item/spear
|
||||
reqs = list(/obj/item/restraints/handcuffs/cable = 1,
|
||||
/obj/item/shard = 1,
|
||||
/obj/item/stack/rods = 1)
|
||||
@@ -110,7 +110,7 @@
|
||||
|
||||
/datum/crafting_recipe/chainsaw
|
||||
name = "Chainsaw"
|
||||
result = /obj/item/twohanded/required/chainsaw
|
||||
result = /obj/item/chainsaw
|
||||
reqs = list(/obj/item/circular_saw = 1,
|
||||
/obj/item/stack/cable_coil = 3,
|
||||
/obj/item/stack/sheet/plasteel = 5)
|
||||
@@ -141,7 +141,7 @@
|
||||
result = /obj/item/bombcore/chemical
|
||||
reqs = list(
|
||||
/obj/item/stock_parts/matter_bin = 1,
|
||||
/obj/item/twohanded/required/gibtonite = 1,
|
||||
/obj/item/gibtonite = 1,
|
||||
/obj/item/grenade/chem_grenade = 2
|
||||
)
|
||||
parts = list(/obj/item/stock_parts/matter_bin = 1, /obj/item/grenade/chem_grenade = 2)
|
||||
@@ -173,10 +173,10 @@
|
||||
|
||||
/datum/crafting_recipe/lance
|
||||
name = "Explosive Lance (Grenade)"
|
||||
result = /obj/item/twohanded/spear
|
||||
reqs = list(/obj/item/twohanded/spear = 1,
|
||||
result = /obj/item/spear
|
||||
reqs = list(/obj/item/spear = 1,
|
||||
/obj/item/grenade = 1)
|
||||
parts = list(/obj/item/twohanded/spear = 1,
|
||||
parts = list(/obj/item/spear = 1,
|
||||
/obj/item/grenade = 1)
|
||||
time = 15
|
||||
category = CAT_WEAPONRY
|
||||
@@ -192,8 +192,8 @@
|
||||
result = /obj/item/gun/ballistic/bow/pipe
|
||||
reqs = list(/obj/item/pipe = 5,
|
||||
/obj/item/stack/sheet/plastic = 15,
|
||||
/obj/item/weaponcrafting/durathread_string = 5)
|
||||
time = 450
|
||||
/obj/item/weaponcrafting/string = 5)
|
||||
time = 150
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_WEAPON
|
||||
|
||||
@@ -248,10 +248,10 @@
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_WEAPON
|
||||
|
||||
/datum/crafting_recipe/ishotgun
|
||||
/datum/crafting_recipe/ishotgun // smaller and more versatile gun requires some better materials
|
||||
name = "Improvised Shotgun"
|
||||
result = /obj/item/gun/ballistic/revolver/doublebarrel/improvised
|
||||
reqs = list(/obj/item/weaponcrafting/improvised_parts/barrel_shotgun = 1,
|
||||
reqs = list(/obj/item/pipe = 2, // putting a large amount of meaningless timegates by forcing people to turn base resources into upgraded resources kinda sucks
|
||||
/obj/item/weaponcrafting/improvised_parts/shotgun_receiver = 1,
|
||||
/obj/item/weaponcrafting/improvised_parts/trigger_assembly = 1,
|
||||
/obj/item/weaponcrafting/improvised_parts/wooden_body = 1,
|
||||
@@ -262,10 +262,10 @@
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_WEAPON
|
||||
|
||||
/datum/crafting_recipe/irifle
|
||||
/datum/crafting_recipe/irifle // larger and less versatile gun, but a bit easier to make
|
||||
name = "Improvised Rifle (7.62mm)"
|
||||
result = /obj/item/gun/ballistic/shotgun/boltaction/improvised
|
||||
reqs = list(/obj/item/weaponcrafting/improvised_parts/barrel_rifle = 1,
|
||||
reqs = list(/obj/item/pipe = 2, // above
|
||||
/obj/item/weaponcrafting/improvised_parts/rifle_receiver = 1,
|
||||
/obj/item/weaponcrafting/improvised_parts/trigger_assembly = 1,
|
||||
/obj/item/weaponcrafting/improvised_parts/wooden_body = 1,
|
||||
@@ -276,49 +276,6 @@
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_WEAPON
|
||||
|
||||
/datum/crafting_recipe/ipistol
|
||||
name = "Improvised Pistol (.32)"
|
||||
result = /obj/item/gun/ballistic/automatic/pistol/improvised/nomag
|
||||
reqs = list(/obj/item/weaponcrafting/improvised_parts/barrel_pistol = 1,
|
||||
/obj/item/weaponcrafting/improvised_parts/pistol_receiver = 1,
|
||||
/obj/item/weaponcrafting/improvised_parts/trigger_assembly = 1,
|
||||
/obj/item/weaponcrafting/improvised_parts/wooden_grip = 1,
|
||||
/obj/item/stack/sheet/plastic = 15,
|
||||
/obj/item/stack/sheet/plasteel = 1)
|
||||
tools = list(TOOL_SCREWDRIVER, TOOL_WELDER, TOOL_WIRECUTTER)
|
||||
time = 100
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_WEAPON
|
||||
|
||||
/datum/crafting_recipe/ilaser
|
||||
name = "Improvised Energy Gun"
|
||||
result = /obj/item/gun/energy/e_gun/old/improvised
|
||||
reqs = list(/obj/item/weaponcrafting/improvised_parts/laser_receiver = 1,
|
||||
/obj/item/weaponcrafting/improvised_parts/trigger_assembly = 1,
|
||||
/obj/item/weaponcrafting/improvised_parts/makeshift_lens = 1,
|
||||
/obj/item/stock_parts/cell = 1,
|
||||
/obj/item/stack/sheet/metal = 10,
|
||||
/obj/item/stack/sheet/plasteel = 5,
|
||||
/obj/item/stack/cable_coil = 10)
|
||||
tools = list(TOOL_SCREWDRIVER)
|
||||
time = 100
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_WEAPON
|
||||
|
||||
/datum/crafting_recipe/ilaser/upgraded
|
||||
name = "Improvised Energy Gun Upgrade"
|
||||
result = /obj/item/gun/energy/e_gun/old/improvised/upgraded
|
||||
reqs = list(/obj/item/gun/energy/e_gun/old/improvised = 1,
|
||||
/obj/item/glasswork/glass_base/lens = 1,
|
||||
/obj/item/stock_parts/capacitor/quadratic = 2,
|
||||
/obj/item/stock_parts/micro_laser/ultra = 1,
|
||||
/obj/item/stock_parts/cell/bluespace = 1,
|
||||
/obj/item/stack/cable_coil = 5)
|
||||
tools = list(TOOL_SCREWDRIVER, TOOL_MULTITOOL)
|
||||
time = 100
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_WEAPON
|
||||
|
||||
//////////////////
|
||||
///AMMO CRAFTING//
|
||||
//////////////////
|
||||
@@ -326,9 +283,9 @@
|
||||
/datum/crafting_recipe/arrow
|
||||
name = "Arrow"
|
||||
result = /obj/item/ammo_casing/caseless/arrow/wood
|
||||
time = 30
|
||||
time = 5 // these only do 15 damage
|
||||
reqs = list(/obj/item/stack/sheet/mineral/wood = 1,
|
||||
/obj/item/stack/sheet/durathread = 1,
|
||||
/obj/item/stack/sheet/cloth = 1,
|
||||
/obj/item/stack/rods = 1) // 1 metal sheet = 2 rods = 2 arrows
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_AMMO
|
||||
@@ -336,7 +293,7 @@
|
||||
/datum/crafting_recipe/bone_arrow
|
||||
name = "Bone Arrow"
|
||||
result = /obj/item/ammo_casing/caseless/arrow/bone
|
||||
time = 30
|
||||
time = 5
|
||||
always_availible = FALSE
|
||||
reqs = list(/obj/item/stack/sheet/bone = 1,
|
||||
/obj/item/stack/sheet/sinew = 1,
|
||||
@@ -348,7 +305,7 @@
|
||||
name = "Ashen Arrow"
|
||||
result = /obj/item/ammo_casing/caseless/arrow/ash
|
||||
tools = list(TOOL_WELDER)
|
||||
time = 30
|
||||
time = 10 // 1.5 seconds minimum per actually worthwhile arrow excluding interface lag
|
||||
always_availible = FALSE
|
||||
reqs = list(/obj/item/ammo_casing/caseless/arrow/wood = 1)
|
||||
category = CAT_WEAPONRY
|
||||
@@ -442,92 +399,28 @@
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_AMMO
|
||||
|
||||
/datum/crafting_recipe/m32acp
|
||||
name = ".32ACP Empty Magazine"
|
||||
result = /obj/item/ammo_box/magazine/m32acp/empty
|
||||
reqs = list(/obj/item/stack/sheet/metal = 3,
|
||||
/obj/item/stack/sheet/plasteel = 1,
|
||||
/obj/item/stack/packageWrap = 1)
|
||||
tools = list(TOOL_WELDER,TOOL_SCREWDRIVER)
|
||||
time = 5
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_AMMO
|
||||
|
||||
////////////////////
|
||||
// PARTS CRAFTING //
|
||||
////////////////////
|
||||
|
||||
// BARRELS
|
||||
|
||||
/datum/crafting_recipe/rifle_barrel
|
||||
name = "Improvised Rifle Barrel"
|
||||
result = /obj/item/weaponcrafting/improvised_parts/barrel_rifle
|
||||
reqs = list(/obj/item/pipe = 2)
|
||||
tools = list(TOOL_WELDER,TOOL_SAW)
|
||||
time = 150
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_PARTS
|
||||
|
||||
/datum/crafting_recipe/shotgun_barrel
|
||||
name = "Improvised Shotgun Barrel"
|
||||
result = /obj/item/weaponcrafting/improvised_parts/barrel_shotgun
|
||||
reqs = list(/obj/item/pipe = 2)
|
||||
tools = list(TOOL_WELDER,TOOL_SAW)
|
||||
time = 150
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_PARTS
|
||||
|
||||
/datum/crafting_recipe/pistol_barrel
|
||||
name = "Improvised Pistol Barrel"
|
||||
result = /obj/item/weaponcrafting/improvised_parts/barrel_pistol
|
||||
reqs = list(/obj/item/pipe = 1,
|
||||
/obj/item/stack/sheet/plasteel = 1)
|
||||
tools = list(TOOL_WELDER,TOOL_SAW)
|
||||
time = 150
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_PARTS
|
||||
|
||||
// RECEIVERS
|
||||
|
||||
/datum/crafting_recipe/rifle_receiver
|
||||
name = "Improvised Rifle Receiver"
|
||||
result = /obj/item/weaponcrafting/improvised_parts/rifle_receiver
|
||||
reqs = list(/obj/item/stack/sheet/metal = 10,
|
||||
/obj/item/stack/sheet/plasteel = 1)
|
||||
reqs = list(/obj/item/stack/sheet/metal = 15) // you can carry multiple shotguns
|
||||
tools = list(TOOL_SCREWDRIVER, TOOL_WELDER)
|
||||
time = 50
|
||||
time = 25
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_PARTS
|
||||
|
||||
/datum/crafting_recipe/shotgun_receiver
|
||||
name = "Improvised Shotgun Receiver"
|
||||
result = /obj/item/weaponcrafting/improvised_parts/shotgun_receiver
|
||||
reqs = list(/obj/item/stack/sheet/metal = 10,
|
||||
/obj/item/stack/sheet/plasteel = 1)
|
||||
tools = list(TOOL_SCREWDRIVER, TOOL_WELDER) // Dual wielding has been removed, plasteel is a soft timesink to obtain for most to make mass production harder.
|
||||
time = 50
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_PARTS
|
||||
|
||||
/datum/crafting_recipe/pistol_receiver
|
||||
name = "Improvised Pistol Receiver"
|
||||
result = /obj/item/weaponcrafting/improvised_parts/pistol_receiver
|
||||
reqs = list(/obj/item/stack/sheet/metal = 5,
|
||||
/obj/item/stack/sheet/plasteel = 1)
|
||||
tools = list(TOOL_SCREWDRIVER, TOOL_WELDER, TOOL_SAW)
|
||||
time = 50
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_PARTS
|
||||
|
||||
/datum/crafting_recipe/laser_receiver
|
||||
name = "Energy Weapon Assembly"
|
||||
result = /obj/item/weaponcrafting/improvised_parts/laser_receiver
|
||||
reqs = list(/obj/item/stack/sheet/metal = 10,
|
||||
/obj/item/stock_parts/capacitor = 2,
|
||||
/obj/item/stock_parts/micro_laser = 1,
|
||||
/obj/item/assembly/prox_sensor = 1)
|
||||
tools = list(TOOL_SCREWDRIVER, TOOL_MULTITOOL, TOOL_WELDER) // Prox sensor and multitool for the circuit board, welder for extremely ghetto soldering.
|
||||
time = 150
|
||||
reqs = list(/obj/item/stack/sheet/metal = 15,
|
||||
/obj/item/stack/sheet/plasteel = 1) // requires access or hacking since shotgun is better
|
||||
tools = list(TOOL_SCREWDRIVER, TOOL_WELDER)
|
||||
time = 25
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_PARTS
|
||||
|
||||
@@ -539,16 +432,6 @@
|
||||
reqs = list(/obj/item/stack/sheet/metal = 3,
|
||||
/obj/item/assembly/igniter = 1)
|
||||
tools = list(TOOL_SCREWDRIVER, TOOL_WELDER)
|
||||
time = 150
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_PARTS
|
||||
|
||||
/datum/crafting_recipe/makeshift_lens
|
||||
name = "Makeshift Lens"
|
||||
result = /obj/item/weaponcrafting/improvised_parts/makeshift_lens
|
||||
reqs = list(/obj/item/stack/sheet/metal = 1,
|
||||
/obj/item/stack/sheet/glass = 2)
|
||||
tools = list(TOOL_WELDER) // Glassmaking lets you make non-makeshift lenses.
|
||||
time = 50
|
||||
time = 25
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_PARTS
|
||||
|
||||
@@ -51,7 +51,8 @@ Behavior that's still missing from this component that original food items had t
|
||||
|
||||
var/atom/owner = parent
|
||||
|
||||
owner.create_reagents(volume, INJECTABLE)
|
||||
if(!owner.reagents) //we don't want to override what's in the item if it possibly contains reagents already
|
||||
owner.create_reagents(volume, INJECTABLE)
|
||||
|
||||
if(initial_reagents)
|
||||
for(var/rid in initial_reagents)
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
/*!
|
||||
This component essentially encapsulates frying and utilizes the edible component
|
||||
This means fried items can work like regular ones, and generally the code is far less messy
|
||||
*/
|
||||
/datum/component/fried
|
||||
var/fry_power //how powerfully was this item fried
|
||||
var/atom/owner //the atom it is owned by
|
||||
var/stored_name //name of the owner when the component was first added
|
||||
var/frying_examine_text = "the coders messed frying code up, report this!"
|
||||
|
||||
/datum/component/fried/Initialize(frying_power)
|
||||
if(!isatom(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
|
||||
RegisterSignal(parent, COMSIG_PARENT_EXAMINE, .proc/examine)
|
||||
RegisterSignal(parent, COMSIG_COMPONENT_CLEAN_ACT, .proc/restore) //basically, unfry people who are being cleaned (badmemes fried someone)
|
||||
|
||||
fry_power = frying_power
|
||||
owner = parent
|
||||
stored_name = owner.name
|
||||
|
||||
setup_fried_item()
|
||||
|
||||
//some stuff to do with the contents of fried junk
|
||||
GLOBAL_VAR_INIT(frying_hardmode, TRUE)
|
||||
GLOBAL_VAR_INIT(frying_bad_chem_add_volume, TRUE)
|
||||
GLOBAL_LIST_INIT(frying_bad_chems, list(
|
||||
/datum/reagent/toxin/bad_food = 1,
|
||||
/datum/reagent/toxin = 1,
|
||||
/datum/reagent/lithium = 1,
|
||||
/datum/reagent/mercury = 1,
|
||||
))
|
||||
|
||||
/datum/component/fried/proc/examine(datum/source, mob/user, list/examine_list)
|
||||
examine_list += "[parent] has been [frying_examine_text]"
|
||||
|
||||
/datum/component/fried/proc/setup_fried_item() //sets the name, colour and examine text and edibility up
|
||||
//first we do some checks depending on the type of item being fried
|
||||
var/list/fried_tastes = list("crispy")
|
||||
var/fried_foodtypes = FRIED
|
||||
var/fried_junk = FALSE
|
||||
|
||||
if(!isfood(owner) && GLOB.frying_hardmode && GLOB.frying_bad_chems.len && !owner.reagents) //you fried some junk, it's not gonna taste great
|
||||
fried_junk = TRUE
|
||||
fried_foodtypes |= TOXIC // junk tastes toxic too
|
||||
else
|
||||
if(isfood(owner))
|
||||
var/obj/item/reagent_containers/food/snacks/food_item = owner
|
||||
fried_tastes += food_item.tastes
|
||||
fried_foodtypes |= food_item.foodtype
|
||||
|
||||
var/fried_eat_time = 0
|
||||
if(isturf(owner))
|
||||
fried_eat_time = 30 //we want turfs to be eaten slowly
|
||||
|
||||
var/colour_priority = FIXED_COLOUR_PRIORITY
|
||||
if(ismob(owner))
|
||||
colour_priority = WASHABLE_COLOUR_PRIORITY //badmins fried someone and we want to let them wash the fry colour off
|
||||
//lets heavily hint at how to undo their frying
|
||||
to_chat(owner, "<span class='warning'>You've been coated in hot cooking oil! You should probably go wash it off at the showers.</span>")
|
||||
else
|
||||
owner.AddComponent(/datum/component/edible, foodtypes = fried_tastes, tastes = fried_tastes, eat_time = fried_eat_time) //we don't want mobs to get the edible component
|
||||
|
||||
switch(fry_power)
|
||||
if(0 to 15)
|
||||
owner.name = "lightly fried [owner.name]"
|
||||
owner.add_atom_colour(rgb(166,103,54), colour_priority)
|
||||
frying_examine_text = "lightly fried"
|
||||
if(16 to 49)
|
||||
owner.name = "fried [owner.name]"
|
||||
owner.add_atom_colour(rgb(103,63,24), colour_priority)
|
||||
frying_examine_text = "moderately fried"
|
||||
if(50 to 59)
|
||||
owner.name = "deep fried [owner.name]"
|
||||
owner.add_atom_colour(rgb(63,23,4), colour_priority)
|
||||
frying_examine_text = "deeply fried"
|
||||
else
|
||||
owner.name = "the physical manifestation of fried foods"
|
||||
owner.add_atom_colour(rgb(33,19,9), colour_priority)
|
||||
frying_examine_text = "incomprehensibly fried to a crisp"
|
||||
|
||||
//adding the edible component gives it reagents meaning we can now add the bad frying reagents if it's junk
|
||||
if(fried_junk && owner.reagents) //check again just incase
|
||||
var/R = rand(1, GLOB.frying_bad_chems.len)
|
||||
var/bad_chem = GLOB.frying_bad_chems[R]
|
||||
var/bad_chem_amount = max(4,GLOB.frying_bad_chems[bad_chem] * (fry_power/12.5)) //4u of bad chem reached when deeply fried
|
||||
owner.reagents.add_reagent(bad_chem, bad_chem_amount)
|
||||
|
||||
/datum/component/fried/proc/restore_name() //restore somethings name
|
||||
//we do string manipulation and not restoring their name to real_name because some things hide your real_name and we want to maintain that
|
||||
if(copytext(owner.name,1,14) == "lightly fried ")
|
||||
owner.name = copytext(owner.name,15)
|
||||
else
|
||||
if(copytext(owner.name,1,6) == "fried ")
|
||||
owner.name = copytext(owner.name,7)
|
||||
else
|
||||
if(copytext(owner.name,1,11) == "deep fried ")
|
||||
owner.name = copytext(owner.name, 12)
|
||||
else
|
||||
if(owner.name == "the physical manifestation of fried foods") //if the name is still this, their name hasn't changed, so we can safely restore their stored name
|
||||
owner.name = stored_name
|
||||
|
||||
/datum/component/fried/proc/restore() //restore a fried mob to being not-fried
|
||||
if(ismob(owner))
|
||||
//restore the name, the colour should wash off itself, and then remove the component
|
||||
restore_name()
|
||||
RemoveComponent()
|
||||
@@ -0,0 +1,153 @@
|
||||
///Global GPS_list. All GPS components get saved in here for easy reference.
|
||||
GLOBAL_LIST_EMPTY(GPS_list)
|
||||
///GPS component. Atoms that have this show up on gps. Pretty simple stuff.
|
||||
/datum/component/gps
|
||||
var/gpstag = "COM0"
|
||||
var/tracking = TRUE
|
||||
var/emped = FALSE
|
||||
|
||||
/datum/component/gps/Initialize(_gpstag = "COM0")
|
||||
if(!isatom(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
gpstag = _gpstag
|
||||
GLOB.GPS_list += src
|
||||
|
||||
/datum/component/gps/Destroy()
|
||||
GLOB.GPS_list -= src
|
||||
return ..()
|
||||
|
||||
///GPS component subtype. Only gps/item's can be used to open the UI.
|
||||
/datum/component/gps/item
|
||||
var/updating = TRUE //Automatic updating of GPS list. Can be set to manual by user.
|
||||
var/global_mode = TRUE //If disabled, only GPS signals of the same Z level are shown
|
||||
|
||||
/datum/component/gps/item/Initialize(_gpstag = "COM0", emp_proof = FALSE)
|
||||
. = ..()
|
||||
if(. == COMPONENT_INCOMPATIBLE || !isitem(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
var/atom/A = parent
|
||||
A.add_overlay("working")
|
||||
A.name = "[initial(A.name)] ([gpstag])"
|
||||
RegisterSignal(parent, COMSIG_ITEM_ATTACK_SELF, .proc/interact)
|
||||
if(!emp_proof)
|
||||
RegisterSignal(parent, COMSIG_ATOM_EMP_ACT, .proc/on_emp_act)
|
||||
RegisterSignal(parent, COMSIG_PARENT_EXAMINE, .proc/on_examine)
|
||||
RegisterSignal(parent, COMSIG_CLICK_ALT, .proc/on_AltClick)
|
||||
|
||||
///Called on COMSIG_ITEM_ATTACK_SELF
|
||||
/datum/component/gps/item/proc/interact(datum/source, mob/user)
|
||||
if(user)
|
||||
ui_interact(user)
|
||||
|
||||
///Called on COMSIG_PARENT_EXAMINE
|
||||
/datum/component/gps/item/proc/on_examine(datum/source, mob/user, list/examine_list)
|
||||
examine_list += "<span class='notice'>Alt-click to switch it [tracking ? "off":"on"].</span>"
|
||||
|
||||
///Called on COMSIG_ATOM_EMP_ACT
|
||||
/datum/component/gps/item/proc/on_emp_act(datum/source, severity)
|
||||
emped = TRUE
|
||||
var/atom/A = parent
|
||||
A.cut_overlay("working")
|
||||
A.add_overlay("emp")
|
||||
addtimer(CALLBACK(src, .proc/reboot), 300, TIMER_UNIQUE|TIMER_OVERRIDE) //if a new EMP happens, remove the old timer so it doesn't reactivate early
|
||||
SStgui.close_uis(src) //Close the UI control if it is open.
|
||||
|
||||
///Restarts the GPS after getting turned off by an EMP.
|
||||
/datum/component/gps/item/proc/reboot()
|
||||
emped = FALSE
|
||||
var/atom/A = parent
|
||||
A.cut_overlay("emp")
|
||||
A.add_overlay("working")
|
||||
|
||||
///Calls toggletracking
|
||||
/datum/component/gps/item/proc/on_AltClick(datum/source, mob/user)
|
||||
toggletracking(user)
|
||||
|
||||
///Toggles the tracking for the gps
|
||||
/datum/component/gps/item/proc/toggletracking(mob/user)
|
||||
if(!user.canUseTopic(parent, BE_CLOSE))
|
||||
return //user not valid to use gps
|
||||
if(emped)
|
||||
to_chat(user, "<span class='warning'>It's busted!</span>")
|
||||
return
|
||||
var/atom/A = parent
|
||||
if(tracking)
|
||||
A.cut_overlay("working")
|
||||
to_chat(user, "<span class='notice'>[parent] is no longer tracking, or visible to other GPS devices.</span>")
|
||||
tracking = FALSE
|
||||
else
|
||||
A.add_overlay("working")
|
||||
to_chat(user, "<span class='notice'>[parent] is now tracking, and visible to other GPS devices.</span>")
|
||||
tracking = TRUE
|
||||
|
||||
/datum/component/gps/item/ui_interact(mob/user, ui_key = "gps", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) // Remember to use the appropriate state.
|
||||
if(emped)
|
||||
to_chat(user, "<span class='hear'>[parent] fizzles weakly.</span>")
|
||||
return
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
// Variable window height, depending on how many GPS units there are
|
||||
// to show, clamped to relatively safe range.
|
||||
var/gps_window_height = clamp(325 + GLOB.GPS_list.len * 14, 325, 700)
|
||||
ui = new(user, src, ui_key, "Gps", "Global Positioning System", 470, gps_window_height, master_ui, state) //width, height
|
||||
ui.open()
|
||||
|
||||
ui.set_autoupdate(state = updating)
|
||||
|
||||
/datum/component/gps/item/ui_data(mob/user)
|
||||
var/list/data = list()
|
||||
data["power"] = tracking
|
||||
data["tag"] = gpstag
|
||||
data["updating"] = updating
|
||||
data["globalmode"] = global_mode
|
||||
if(!tracking || emped) //Do not bother scanning if the GPS is off or EMPed
|
||||
return data
|
||||
|
||||
var/turf/curr = get_turf(parent)
|
||||
data["currentArea"] = "[get_area_name(curr, TRUE)]"
|
||||
data["currentCoords"] = "[curr.x], [curr.y], [curr.z]"
|
||||
|
||||
var/list/signals = list()
|
||||
data["signals"] = list()
|
||||
|
||||
for(var/gps in GLOB.GPS_list)
|
||||
var/datum/component/gps/G = gps
|
||||
if(G.emped || !G.tracking || G == src)
|
||||
continue
|
||||
var/turf/pos = get_turf(G.parent)
|
||||
if(!pos || !global_mode && pos.z != curr.z)
|
||||
continue
|
||||
var/list/signal = list()
|
||||
signal["entrytag"] = G.gpstag //Name or 'tag' of the GPS
|
||||
signal["coords"] = "[pos.x], [pos.y], [pos.z]"
|
||||
if(pos.z == curr.z) //Distance/Direction calculations for same z-level only
|
||||
signal["dist"] = max(get_dist(curr, pos), 0) //Distance between the src and remote GPS turfs
|
||||
signal["degrees"] = round(Get_Angle(curr, pos)) //0-360 degree directional bearing, for more precision.
|
||||
signals += list(signal) //Add this signal to the list of signals
|
||||
data["signals"] = signals
|
||||
return data
|
||||
|
||||
/datum/component/gps/item/ui_act(action, params)
|
||||
if(..())
|
||||
return
|
||||
switch(action)
|
||||
if("rename")
|
||||
var/atom/parentasatom = parent
|
||||
var/a = stripped_input(usr, "Please enter desired tag.", parentasatom.name, gpstag, 20)
|
||||
|
||||
if (!a)
|
||||
return
|
||||
|
||||
gpstag = a
|
||||
. = TRUE
|
||||
parentasatom.name = "global positioning system ([gpstag])"
|
||||
|
||||
if("power")
|
||||
toggletracking(usr)
|
||||
. = TRUE
|
||||
if("updating")
|
||||
updating = !updating
|
||||
. = TRUE
|
||||
if("globalmode")
|
||||
global_mode = !global_mode
|
||||
. = TRUE
|
||||
@@ -105,7 +105,7 @@
|
||||
|
||||
/// Proc specifically for inserting items, returns the amount of materials entered.
|
||||
/datum/component/material_container/proc/insert_item(obj/item/I, var/multiplier = 1, stack_amt)
|
||||
if(!I)
|
||||
if(QDELETED(I))
|
||||
return FALSE
|
||||
|
||||
multiplier = CEILING(multiplier, 0.01)
|
||||
|
||||
@@ -34,3 +34,8 @@
|
||||
qdel(A)
|
||||
return
|
||||
. = ..()
|
||||
|
||||
/datum/component/storage/concrete/bluespace/bag_of_holding/can_be_inserted(obj/item/I, stop_messages = FALSE, mob/M)
|
||||
if(I.GetComponent(/datum/component/storage/concrete/bluespace/bag_of_holding))
|
||||
return TRUE
|
||||
return ..()
|
||||
|
||||
@@ -0,0 +1,311 @@
|
||||
/**
|
||||
* Two Handed Component
|
||||
*
|
||||
* When applied to an item it will make it two handed
|
||||
*
|
||||
*/
|
||||
/datum/component/two_handed
|
||||
dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS // Only one of the component can exist on an item
|
||||
var/wielded = FALSE /// Are we holding the two handed item properly
|
||||
var/force_multiplier = 0 /// The multiplier applied to force when wielded, does not work with force_wielded, and force_unwielded
|
||||
var/force_wielded = 0 /// The force of the item when weilded
|
||||
var/force_unwielded = 0 /// The force of the item when unweilded
|
||||
var/wieldsound = FALSE /// Play sound when wielded
|
||||
var/unwieldsound = FALSE /// Play sound when unwielded
|
||||
var/attacksound = FALSE /// Play sound on attack when wielded
|
||||
var/require_twohands = FALSE /// Does it have to be held in both hands
|
||||
var/icon_wielded = FALSE /// The icon that will be used when wielded
|
||||
var/obj/item/offhand/offhand_item = null /// Reference to the offhand created for the item
|
||||
var/sharpened_increase = 0 /// The amount of increase recived from sharpening the item
|
||||
|
||||
/**
|
||||
* Two Handed component
|
||||
*
|
||||
* vars:
|
||||
* * require_twohands (optional) Does the item need both hands to be carried
|
||||
* * wieldsound (optional) The sound to play when wielded
|
||||
* * unwieldsound (optional) The sound to play when unwielded
|
||||
* * attacksound (optional) The sound to play when wielded and attacking
|
||||
* * force_multiplier (optional) The force multiplier when wielded, do not use with force_wielded, and force_unwielded
|
||||
* * force_wielded (optional) The force setting when the item is wielded, do not use with force_multiplier
|
||||
* * force_unwielded (optional) The force setting when the item is unwielded, do not use with force_multiplier
|
||||
* * icon_wielded (optional) The icon to be used when wielded
|
||||
*/
|
||||
/datum/component/two_handed/Initialize(require_twohands=FALSE, wieldsound=FALSE, unwieldsound=FALSE, attacksound=FALSE, \
|
||||
force_multiplier=0, force_wielded=0, force_unwielded=0, icon_wielded=FALSE)
|
||||
if(!isitem(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
|
||||
src.require_twohands = require_twohands
|
||||
src.wieldsound = wieldsound
|
||||
src.unwieldsound = unwieldsound
|
||||
src.attacksound = attacksound
|
||||
src.force_multiplier = force_multiplier
|
||||
src.force_wielded = force_wielded
|
||||
src.force_unwielded = force_unwielded
|
||||
src.icon_wielded = icon_wielded
|
||||
|
||||
// Inherit the new values passed to the component
|
||||
/datum/component/two_handed/InheritComponent(datum/component/two_handed/new_comp, original, require_twohands, wieldsound, unwieldsound, \
|
||||
force_multiplier, force_wielded, force_unwielded, icon_wielded)
|
||||
if(!original)
|
||||
return
|
||||
if(require_twohands)
|
||||
src.require_twohands = require_twohands
|
||||
if(wieldsound)
|
||||
src.wieldsound = wieldsound
|
||||
if(unwieldsound)
|
||||
src.unwieldsound = unwieldsound
|
||||
if(attacksound)
|
||||
src.attacksound = attacksound
|
||||
if(force_multiplier)
|
||||
src.force_multiplier = force_multiplier
|
||||
if(force_wielded)
|
||||
src.force_wielded = force_wielded
|
||||
if(force_unwielded)
|
||||
src.force_unwielded = force_unwielded
|
||||
if(icon_wielded)
|
||||
src.icon_wielded = icon_wielded
|
||||
|
||||
// register signals withthe parent item
|
||||
/datum/component/two_handed/RegisterWithParent()
|
||||
RegisterSignal(parent, COMSIG_ITEM_EQUIPPED, .proc/on_equip)
|
||||
RegisterSignal(parent, COMSIG_ITEM_DROPPED, .proc/on_drop)
|
||||
RegisterSignal(parent, COMSIG_ITEM_ATTACK_SELF, .proc/on_attack_self)
|
||||
RegisterSignal(parent, COMSIG_ITEM_ATTACK, .proc/on_attack)
|
||||
RegisterSignal(parent, COMSIG_ATOM_UPDATE_ICON, .proc/on_update_icon)
|
||||
RegisterSignal(parent, COMSIG_MOVABLE_MOVED, .proc/on_moved)
|
||||
RegisterSignal(parent, COMSIG_ITEM_SHARPEN_ACT, .proc/on_sharpen)
|
||||
|
||||
// Remove all siginals registered to the parent item
|
||||
/datum/component/two_handed/UnregisterFromParent()
|
||||
UnregisterSignal(parent, list(COMSIG_ITEM_EQUIPPED,
|
||||
COMSIG_ITEM_DROPPED,
|
||||
COMSIG_ITEM_ATTACK_SELF,
|
||||
COMSIG_ITEM_ATTACK,
|
||||
COMSIG_ATOM_UPDATE_ICON,
|
||||
COMSIG_MOVABLE_MOVED,
|
||||
COMSIG_ITEM_SHARPEN_ACT))
|
||||
|
||||
/// Triggered on equip of the item containing the component
|
||||
/datum/component/two_handed/proc/on_equip(datum/source, mob/user, slot)
|
||||
if(require_twohands && slot == SLOT_HANDS) // force equip the item
|
||||
wield(user)
|
||||
if(!user.is_holding(parent) && wielded && !require_twohands)
|
||||
unwield(user)
|
||||
|
||||
/// Triggered on drop of item containing the component
|
||||
/datum/component/two_handed/proc/on_drop(datum/source, mob/user)
|
||||
if(require_twohands)
|
||||
unwield(user, show_message=TRUE)
|
||||
if(wielded)
|
||||
unwield(user)
|
||||
if(source == offhand_item && !QDELETED(src))
|
||||
qdel(src)
|
||||
|
||||
/// Triggered on attack self of the item containing the component
|
||||
/datum/component/two_handed/proc/on_attack_self(datum/source, mob/user)
|
||||
if(wielded)
|
||||
unwield(user)
|
||||
else
|
||||
wield(user)
|
||||
|
||||
/**
|
||||
* Wield the two handed item in both hands
|
||||
*
|
||||
* vars:
|
||||
* * user The mob/living/carbon that is wielding the item
|
||||
*/
|
||||
/datum/component/two_handed/proc/wield(mob/living/carbon/user)
|
||||
if(wielded)
|
||||
return
|
||||
if(ismonkey(user))
|
||||
to_chat(user, "<span class='warning'>It's too heavy for you to wield fully.</span>")
|
||||
return
|
||||
if(user.get_inactive_held_item())
|
||||
if(require_twohands)
|
||||
to_chat(user, "<span class='notice'>[parent] is too cumbersome to carry in one hand!</span>")
|
||||
user.dropItemToGround(parent, force=TRUE)
|
||||
else
|
||||
to_chat(user, "<span class='warning'>You need your other hand to be empty!</span>")
|
||||
return
|
||||
if(user.get_num_arms() < 2)
|
||||
if(require_twohands)
|
||||
user.dropItemToGround(parent, force=TRUE)
|
||||
to_chat(user, "<span class='warning'>You don't have enough intact hands.</span>")
|
||||
return
|
||||
|
||||
// wield update status
|
||||
if(SEND_SIGNAL(parent, COMSIG_TWOHANDED_WIELD, user) & COMPONENT_TWOHANDED_BLOCK_WIELD)
|
||||
return // blocked wield from item
|
||||
wielded = TRUE
|
||||
RegisterSignal(user, COMSIG_MOB_SWAP_HANDS, .proc/on_swap_hands)
|
||||
|
||||
// update item stats and name
|
||||
var/obj/item/parent_item = parent
|
||||
if(force_multiplier)
|
||||
parent_item.force *= force_multiplier
|
||||
else if(force_wielded)
|
||||
parent_item.force = force_wielded
|
||||
if(sharpened_increase)
|
||||
parent_item.force += sharpened_increase
|
||||
parent_item.name = "[parent_item.name] (Wielded)"
|
||||
parent_item.update_icon()
|
||||
|
||||
if(iscyborg(user))
|
||||
to_chat(user, "<span class='notice'>You dedicate your module to [parent].</span>")
|
||||
else
|
||||
to_chat(user, "<span class='notice'>You grab [parent] with both hands.</span>")
|
||||
|
||||
// Play sound if one is set
|
||||
if(wieldsound)
|
||||
playsound(parent_item.loc, wieldsound, 50, TRUE)
|
||||
|
||||
// Let's reserve the other hand
|
||||
offhand_item = new(user)
|
||||
offhand_item.name = "[parent_item.name] - offhand"
|
||||
offhand_item.desc = "Your second grip on [parent_item]."
|
||||
offhand_item.wielded = TRUE
|
||||
RegisterSignal(offhand_item, COMSIG_ITEM_DROPPED, .proc/on_drop)
|
||||
user.put_in_inactive_hand(offhand_item)
|
||||
|
||||
/**
|
||||
* Unwield the two handed item
|
||||
*
|
||||
* vars:
|
||||
* * user The mob/living/carbon that is unwielding the item
|
||||
* * show_message (option) show a message to chat on unwield
|
||||
*/
|
||||
/datum/component/two_handed/proc/unwield(mob/living/carbon/user, show_message=TRUE)
|
||||
if(!wielded || !user)
|
||||
return
|
||||
|
||||
// wield update status
|
||||
wielded = FALSE
|
||||
UnregisterSignal(user, COMSIG_MOB_SWAP_HANDS)
|
||||
SEND_SIGNAL(parent, COMSIG_TWOHANDED_UNWIELD, user)
|
||||
|
||||
// update item stats
|
||||
var/obj/item/parent_item = parent
|
||||
if(sharpened_increase)
|
||||
parent_item.force -= sharpened_increase
|
||||
if(force_multiplier)
|
||||
parent_item.force /= force_multiplier
|
||||
else if(force_unwielded)
|
||||
parent_item.force = force_unwielded
|
||||
|
||||
// update the items name to remove the wielded status
|
||||
var/sf = findtext(parent_item.name, " (Wielded)", -10) // 10 == length(" (Wielded)")
|
||||
if(sf)
|
||||
parent_item.name = copytext(parent_item.name, 1, sf)
|
||||
else
|
||||
parent_item.name = "[initial(parent_item.name)]"
|
||||
|
||||
// Update icons
|
||||
parent_item.update_icon()
|
||||
if(user.get_item_by_slot(ITEM_SLOT_BACK) == parent)
|
||||
user.update_inv_back()
|
||||
else
|
||||
user.update_inv_hands()
|
||||
|
||||
// if the item requires two handed drop the item on unwield
|
||||
if(require_twohands)
|
||||
user.dropItemToGround(parent, force=TRUE)
|
||||
|
||||
// Show message if requested
|
||||
if(show_message)
|
||||
if(iscyborg(user))
|
||||
to_chat(user, "<span class='notice'>You free up your module.</span>")
|
||||
else if(require_twohands)
|
||||
to_chat(user, "<span class='notice'>You drop [parent].</span>")
|
||||
else
|
||||
to_chat(user, "<span class='notice'>You are now carrying [parent] with one hand.</span>")
|
||||
|
||||
// Play sound if set
|
||||
if(unwieldsound)
|
||||
playsound(parent_item.loc, unwieldsound, 50, TRUE)
|
||||
|
||||
// Remove the object in the offhand
|
||||
if(offhand_item)
|
||||
UnregisterSignal(offhand_item, COMSIG_ITEM_DROPPED)
|
||||
qdel(offhand_item)
|
||||
// Clear any old refrence to an item that should be gone now
|
||||
offhand_item = null
|
||||
|
||||
/**
|
||||
* on_attack triggers on attack with the parent item
|
||||
*/
|
||||
/datum/component/two_handed/proc/on_attack(obj/item/source, mob/living/target, mob/living/user)
|
||||
if(wielded && attacksound)
|
||||
var/obj/item/parent_item = parent
|
||||
playsound(parent_item.loc, attacksound, 50, TRUE)
|
||||
|
||||
/**
|
||||
* on_update_icon triggers on call to update parent items icon
|
||||
*
|
||||
* Updates the icon using icon_wielded if set
|
||||
*/
|
||||
/datum/component/two_handed/proc/on_update_icon(datum/source)
|
||||
if(icon_wielded && wielded)
|
||||
var/obj/item/parent_item = parent
|
||||
if(parent_item)
|
||||
parent_item.icon_state = icon_wielded
|
||||
return COMSIG_ATOM_NO_UPDATE_ICON_STATE
|
||||
|
||||
/**
|
||||
* on_moved Triggers on item moved
|
||||
*/
|
||||
/datum/component/two_handed/proc/on_moved(datum/source, mob/user, dir)
|
||||
unwield(user)
|
||||
|
||||
/**
|
||||
* on_swap_hands Triggers on swapping hands, blocks swap if the other hand is busy
|
||||
*/
|
||||
/datum/component/two_handed/proc/on_swap_hands(mob/user, obj/item/held_item)
|
||||
if(!held_item)
|
||||
return
|
||||
if(held_item == parent)
|
||||
return COMPONENT_BLOCK_SWAP
|
||||
|
||||
/**
|
||||
* on_sharpen Triggers on usage of a sharpening stone on the item
|
||||
*/
|
||||
/datum/component/two_handed/proc/on_sharpen(obj/item/item, amount, max_amount)
|
||||
if(!item)
|
||||
return COMPONENT_BLOCK_SHARPEN_BLOCKED
|
||||
if(sharpened_increase)
|
||||
return COMPONENT_BLOCK_SHARPEN_ALREADY
|
||||
var/wielded_val = 0
|
||||
if(force_multiplier)
|
||||
var/obj/item/parent_item = parent
|
||||
if(wielded)
|
||||
wielded_val = parent_item.force
|
||||
else
|
||||
wielded_val = parent_item.force * force_multiplier
|
||||
else
|
||||
wielded_val = force_wielded
|
||||
if(wielded_val > max_amount)
|
||||
return COMPONENT_BLOCK_SHARPEN_MAXED
|
||||
sharpened_increase = min(amount, (max_amount - wielded_val))
|
||||
return COMPONENT_BLOCK_SHARPEN_APPLIED
|
||||
|
||||
/**
|
||||
* The offhand dummy item for two handed items
|
||||
*
|
||||
*/
|
||||
/obj/item/offhand
|
||||
name = "offhand"
|
||||
icon_state = "offhand"
|
||||
w_class = WEIGHT_CLASS_HUGE
|
||||
item_flags = ABSTRACT
|
||||
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
|
||||
var/wielded = FALSE // Off Hand tracking of wielded status
|
||||
|
||||
/obj/item/offhand/Destroy()
|
||||
wielded = FALSE
|
||||
return ..()
|
||||
|
||||
/obj/item/offhand/equipped(mob/user, slot)
|
||||
. = ..()
|
||||
if(wielded && !user.is_holding(src) && !QDELETED(src))
|
||||
qdel(src)
|
||||
@@ -24,16 +24,17 @@ GLOBAL_LIST_EMPTY(uplinks)
|
||||
var/unlock_note
|
||||
var/unlock_code
|
||||
var/failsafe_code
|
||||
var/datum/ui_state/checkstate
|
||||
var/compact_mode = FALSE
|
||||
var/debug = FALSE
|
||||
var/saved_player_population = 0
|
||||
var/list/filters = list()
|
||||
|
||||
|
||||
/datum/component/uplink/Initialize(_owner, _lockable = TRUE, _enabled = FALSE, datum/game_mode/_gamemode, starting_tc = 20, datum/ui_state/_checkstate, datum/traitor_class/traitor_class)
|
||||
if(!isitem(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
|
||||
|
||||
RegisterSignal(parent, COMSIG_PARENT_ATTACKBY, .proc/OnAttackBy)
|
||||
RegisterSignal(parent, COMSIG_ITEM_ATTACK_SELF, .proc/interact)
|
||||
if(istype(parent, /obj/item/implant))
|
||||
@@ -65,7 +66,6 @@ GLOBAL_LIST_EMPTY(uplinks)
|
||||
active = _enabled
|
||||
gamemode = _gamemode
|
||||
telecrystals = starting_tc
|
||||
checkstate = _checkstate
|
||||
if(!lockable)
|
||||
active = TRUE
|
||||
locked = FALSE
|
||||
@@ -136,13 +136,13 @@ GLOBAL_LIST_EMPTY(uplinks)
|
||||
|
||||
/datum/component/uplink/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
|
||||
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.inventory_state)
|
||||
state = checkstate ? checkstate : state
|
||||
active = TRUE
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "uplink", name, 620, 580, master_ui, state)
|
||||
ui.set_autoupdate(FALSE) // This UI is only ever opened by one person, and never is updated outside of user input.
|
||||
ui.set_style("syndicate")
|
||||
ui = new(user, src, ui_key, "Uplink", name, 620, 580, master_ui, state)
|
||||
// This UI is only ever opened by one person,
|
||||
// and never is updated outside of user input.
|
||||
ui.set_autoupdate(FALSE)
|
||||
ui.open()
|
||||
|
||||
/datum/component/uplink/ui_host(mob/user)
|
||||
@@ -157,8 +157,7 @@ GLOBAL_LIST_EMPTY(uplinks)
|
||||
var/list/data = list()
|
||||
data["telecrystals"] = telecrystals
|
||||
data["lockable"] = lockable
|
||||
data["compact_mode"] = compact_mode
|
||||
|
||||
data["compactMode"] = compact_mode
|
||||
return data
|
||||
|
||||
/datum/component/uplink/ui_static_data(mob/user)
|
||||
@@ -192,21 +191,16 @@ GLOBAL_LIST_EMPTY(uplinks)
|
||||
/datum/component/uplink/ui_act(action, params)
|
||||
if(!active)
|
||||
return
|
||||
|
||||
switch(action)
|
||||
if("buy")
|
||||
var/item = params["item"]
|
||||
|
||||
var/item_name = params["name"]
|
||||
var/list/buyable_items = list()
|
||||
for(var/category in uplink_items)
|
||||
buyable_items += uplink_items[category]
|
||||
|
||||
if(item in buyable_items)
|
||||
var/datum/uplink_item/I = buyable_items[item]
|
||||
//check to make sure people cannot buy items when the player pop is below the requirement
|
||||
if(GLOB.joined_player_list.len >= I.player_minimum)
|
||||
MakePurchase(usr, I)
|
||||
. = TRUE
|
||||
if(item_name in buyable_items)
|
||||
var/datum/uplink_item/I = buyable_items[item_name]
|
||||
MakePurchase(usr, I)
|
||||
return TRUE
|
||||
if("lock")
|
||||
active = FALSE
|
||||
locked = TRUE
|
||||
@@ -215,9 +209,10 @@ GLOBAL_LIST_EMPTY(uplinks)
|
||||
SStgui.close_uis(src)
|
||||
if("select")
|
||||
selected_cat = params["category"]
|
||||
return TRUE
|
||||
if("compact_toggle")
|
||||
compact_mode = !compact_mode
|
||||
return TRUE
|
||||
return TRUE
|
||||
|
||||
/datum/component/uplink/proc/MakePurchase(mob/user, datum/uplink_item/U)
|
||||
if(!istype(U))
|
||||
@@ -262,12 +257,12 @@ GLOBAL_LIST_EMPTY(uplinks)
|
||||
var/obj/item/pda/master = parent
|
||||
if(trim(lowertext(new_ring_text)) != trim(lowertext(unlock_code)))
|
||||
if(trim(lowertext(new_ring_text)) == trim(lowertext(failsafe_code)))
|
||||
failsafe()
|
||||
failsafe(user)
|
||||
return COMPONENT_STOP_RINGTONE_CHANGE
|
||||
return
|
||||
locked = FALSE
|
||||
interact(null, user)
|
||||
to_chat(user, "The PDA softly beeps.")
|
||||
to_chat(user, "<span class='hear'>The PDA softly beeps.</span>")
|
||||
user << browse(null, "window=pda")
|
||||
master.mode = 0
|
||||
return COMPONENT_STOP_RINGTONE_CHANGE
|
||||
@@ -279,7 +274,7 @@ GLOBAL_LIST_EMPTY(uplinks)
|
||||
var/frequency = arguments[1]
|
||||
if(frequency != unlock_code)
|
||||
if(frequency == failsafe_code)
|
||||
failsafe()
|
||||
failsafe(master.loc)
|
||||
return
|
||||
locked = FALSE
|
||||
if(ismob(master.loc))
|
||||
@@ -316,11 +311,13 @@ GLOBAL_LIST_EMPTY(uplinks)
|
||||
else if(istype(parent,/obj/item/pen))
|
||||
return rand(1, 360)
|
||||
|
||||
/datum/component/uplink/proc/failsafe()
|
||||
/datum/component/uplink/proc/failsafe(mob/living/carbon/user)
|
||||
if(!parent)
|
||||
return
|
||||
var/turf/T = get_turf(parent)
|
||||
if(!T)
|
||||
return
|
||||
message_admins("[ADMIN_LOOKUPFLW(user)] has triggered an uplink failsafe explosion at [AREACOORD(T)] The owner of the uplink was [ADMIN_LOOKUPFLW(owner)].")
|
||||
log_game("[key_name(user)] triggered an uplink failsafe explosion. The owner of the uplink was [key_name(owner)].")
|
||||
explosion(T,1,2,3)
|
||||
qdel(parent) //Alternatively could brick the uplink.
|
||||
|
||||
@@ -121,7 +121,7 @@
|
||||
if(-INFINITY to T0C)
|
||||
add_wet(TURF_WET_ICE, max_time_left()) //Water freezes into ice!
|
||||
if(T0C to T0C + 100)
|
||||
decrease = ((T.air.temperature - T0C) / SSwet_floors.temperature_coeff) * (diff / SSwet_floors.time_ratio)
|
||||
decrease = ((T.air.return_temperature() - T0C) / SSwet_floors.temperature_coeff) * (diff / SSwet_floors.time_ratio)
|
||||
if(T0C + 100 to INFINITY)
|
||||
decrease = INFINITY
|
||||
decrease = max(0, decrease)
|
||||
|
||||
@@ -81,7 +81,7 @@
|
||||
if(N.new_character)
|
||||
log_manifest(N.ckey,N.new_character.mind,N.new_character)
|
||||
if(ishuman(N.new_character))
|
||||
manifest_inject(N.new_character, N.client)
|
||||
manifest_inject(N.new_character, N.client, N.client.prefs)
|
||||
CHECK_TICK
|
||||
|
||||
/datum/datacore/proc/manifest_modify(name, assignment)
|
||||
@@ -197,7 +197,7 @@
|
||||
return dat
|
||||
|
||||
|
||||
/datum/datacore/proc/manifest_inject(mob/living/carbon/human/H, client/C)
|
||||
/datum/datacore/proc/manifest_inject(mob/living/carbon/human/H, client/C, datum/preferences/prefs)
|
||||
set waitfor = FALSE
|
||||
var/static/list/show_directions = list(SOUTH, WEST)
|
||||
if(H.mind && (H.mind.assigned_role != H.mind.special_role))
|
||||
@@ -260,7 +260,7 @@
|
||||
M.fields["alg_d"] = "No allergies have been detected in this patient."
|
||||
M.fields["cdi"] = "None"
|
||||
M.fields["cdi_d"] = "No diseases have been diagnosed at the moment."
|
||||
M.fields["notes"] = H.get_trait_string(medical)
|
||||
M.fields["notes"] = "Trait information as of shift start: [H.get_trait_string(medical)]<br>[prefs.medical_records]"
|
||||
medical += M
|
||||
|
||||
//Security Record
|
||||
@@ -270,7 +270,7 @@
|
||||
S.fields["criminal"] = "None"
|
||||
S.fields["mi_crim"] = list()
|
||||
S.fields["ma_crim"] = list()
|
||||
S.fields["notes"] = "No notes."
|
||||
S.fields["notes"] = prefs.security_records || "No notes."
|
||||
security += S
|
||||
|
||||
//Locked Record
|
||||
|
||||
@@ -39,6 +39,9 @@
|
||||
/// A weak reference to another datum
|
||||
var/datum/weakref/weak_reference
|
||||
|
||||
///Lazy associative list of currently active cooldowns.
|
||||
var/list/cooldowns
|
||||
|
||||
#ifdef TESTING
|
||||
var/running_find_references
|
||||
var/last_find_references = 0
|
||||
@@ -201,3 +204,34 @@
|
||||
qdel(D)
|
||||
else
|
||||
return returned
|
||||
|
||||
/**
|
||||
* Callback called by a timer to end an associative-list-indexed cooldown.
|
||||
*
|
||||
* Arguments:
|
||||
* * source - datum storing the cooldown
|
||||
* * index - string index storing the cooldown on the cooldowns associative list
|
||||
*
|
||||
* This sends a signal reporting the cooldown end.
|
||||
*/
|
||||
/proc/end_cooldown(datum/source, index)
|
||||
if(QDELETED(source))
|
||||
return
|
||||
SEND_SIGNAL(source, COMSIG_CD_STOP(index))
|
||||
TIMER_COOLDOWN_END(source, index)
|
||||
|
||||
|
||||
/**
|
||||
* Proc used by stoppable timers to end a cooldown before the time has ran out.
|
||||
*
|
||||
* Arguments:
|
||||
* * source - datum storing the cooldown
|
||||
* * index - string index storing the cooldown on the cooldowns associative list
|
||||
*
|
||||
* This sends a signal reporting the cooldown end, passing the time left as an argument.
|
||||
*/
|
||||
/proc/reset_cooldown(datum/source, index)
|
||||
if(QDELETED(source))
|
||||
return
|
||||
SEND_SIGNAL(source, COMSIG_CD_RESET(index), S_TIMER_COOLDOWN_TIMELEFT(source, index))
|
||||
TIMER_COOLDOWN_END(source, index)
|
||||
|
||||
@@ -404,7 +404,7 @@
|
||||
if(M.loc)
|
||||
environment = M.loc.return_air()
|
||||
if(environment)
|
||||
plasmamount = environment.gases[/datum/gas/plasma]
|
||||
plasmamount = environment.get_moles(/datum/gas/plasma)
|
||||
if(plasmamount && plasmamount > GLOB.meta_gas_visibility[/datum/gas/plasma]) //if there's enough plasma in the air to see
|
||||
. += power * 0.5
|
||||
if(M.reagents.has_reagent(/datum/reagent/toxin/plasma))
|
||||
|
||||
+16
-3
@@ -15,6 +15,7 @@
|
||||
var/mob/living/holder
|
||||
var/delete_species = TRUE //Set to FALSE when a body is scanned by a cloner to fix #38875
|
||||
var/mutation_index[DNA_MUTATION_BLOCKS] //List of which mutations this carbon has and its assigned block
|
||||
var/default_mutation_genes[DNA_MUTATION_BLOCKS] //List of the default genes from this mutation to allow DNA Scanner highlighting
|
||||
var/stability = 100
|
||||
var/scrambled = FALSE //Did we take something like mutagen? In that case we cant get our genes scanned to instantly cheese all the powers.
|
||||
var/skin_tone_override //because custom skin tones are not found in the skin_tones global list.
|
||||
@@ -58,6 +59,7 @@
|
||||
H.give_genitals(TRUE)//This gives the body the genitals of this DNA. Used for any transformations based on DNA
|
||||
if(transfer_SE)
|
||||
destination.dna.mutation_index = mutation_index
|
||||
destination.dna.default_mutation_genes = default_mutation_genes
|
||||
|
||||
destination.dna.update_body_size(old_size)
|
||||
|
||||
@@ -66,6 +68,7 @@
|
||||
/datum/dna/proc/copy_dna(datum/dna/new_dna)
|
||||
new_dna.unique_enzymes = unique_enzymes
|
||||
new_dna.mutation_index = mutation_index
|
||||
new_dna.default_mutation_genes = default_mutation_genes
|
||||
new_dna.uni_identity = uni_identity
|
||||
new_dna.blood_type = blood_type
|
||||
new_dna.skin_tone_override = skin_tone_override
|
||||
@@ -160,15 +163,18 @@
|
||||
if(!LAZYLEN(mutations_temp))
|
||||
return
|
||||
mutation_index.Cut()
|
||||
default_mutation_genes.Cut()
|
||||
shuffle_inplace(mutations_temp)
|
||||
if(ismonkey(holder))
|
||||
mutations |= new RACEMUT(MUT_NORMAL)
|
||||
mutation_index[RACEMUT] = GET_SEQUENCE(RACEMUT)
|
||||
else
|
||||
mutation_index[RACEMUT] = create_sequence(RACEMUT, FALSE)
|
||||
default_mutation_genes[RACEMUT] = mutation_index[RACEMUT]
|
||||
for(var/i in 2 to DNA_MUTATION_BLOCKS)
|
||||
var/datum/mutation/human/M = mutations_temp[i]
|
||||
mutation_index[M.type] = create_sequence(M.type, FALSE,M.difficulty)
|
||||
mutation_index[M.type] = create_sequence(M.type, FALSE, M.difficulty)
|
||||
default_mutation_genes[M.type] = mutation_index[M.type]
|
||||
shuffle_inplace(mutation_index)
|
||||
|
||||
//Used to generate original gene sequences for every mutation
|
||||
@@ -389,7 +395,7 @@
|
||||
return dna
|
||||
|
||||
|
||||
/mob/living/carbon/human/proc/hardset_dna(ui, list/mutation_index, newreal_name, newblood_type, datum/species/mrace, newfeatures)
|
||||
/mob/living/carbon/human/proc/hardset_dna(ui, list/mutation_index, newreal_name, newblood_type, datum/species/mrace, newfeatures, list/default_mutation_genes)
|
||||
|
||||
if(newreal_name)
|
||||
real_name = newreal_name
|
||||
@@ -414,6 +420,10 @@
|
||||
|
||||
if(LAZYLEN(mutation_index))
|
||||
dna.mutation_index = mutation_index.Copy()
|
||||
if(LAZYLEN(default_mutation_genes))
|
||||
dna.default_mutation_genes = default_mutation_genes.Copy()
|
||||
else
|
||||
dna.default_mutation_genes = mutation_index.Copy()
|
||||
domutcheck()
|
||||
|
||||
SEND_SIGNAL(src, COMSIG_HUMAN_HARDSET_DNA, ui, mutation_index, newreal_name, newblood_type, mrace, newfeatures)
|
||||
@@ -505,8 +515,11 @@
|
||||
. = TRUE
|
||||
if(on)
|
||||
mutation_index[HM.type] = GET_SEQUENCE(HM.type)
|
||||
default_mutation_genes[HM.type] = mutation_index[HM.type]
|
||||
else if(GET_SEQUENCE(HM.type) == mutation_index[HM.type])
|
||||
mutation_index[HM.type] = create_sequence(HM.type, FALSE, HM.difficulty)
|
||||
default_mutation_genes[HM.type] = mutation_index[HM.type]
|
||||
|
||||
|
||||
/datum/dna/proc/activate_mutation(mutation) //note that this returns a boolean and not a new mob
|
||||
if(!mutation)
|
||||
@@ -678,7 +691,7 @@
|
||||
holder.update_transform()
|
||||
var/danger = CONFIG_GET(number/threshold_body_size_slowdown)
|
||||
if(features["body_size"] < danger)
|
||||
var/slowdown = 1 + round(danger/features["body_size"], 0.1) * CONFIG_GET(number/body_size_slowdown_multiplier)
|
||||
var/slowdown = (1 - round(features["body_size"] / danger, 0.1)) * CONFIG_GET(number/body_size_slowdown_multiplier)
|
||||
holder.add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/small_stride, TRUE, slowdown)
|
||||
else if(old_size < danger)
|
||||
holder.remove_movespeed_modifier(/datum/movespeed_modifier/small_stride)
|
||||
|
||||
@@ -82,9 +82,10 @@ GLOBAL_LIST_EMPTY(mobs_with_editable_flavor_text) //et tu, hacky code
|
||||
return
|
||||
if(href_list["show_flavor"])
|
||||
var/atom/target = locate(href_list["show_flavor"])
|
||||
var/mob/living/L = target
|
||||
var/text = texts_by_atom[target]
|
||||
if(text)
|
||||
usr << browse("<HTML><HEAD><meta http-equiv='Content-Type' content='text/html; charset=UTF-8'><TITLE>[target.name]</TITLE></HEAD><BODY><TT>[replacetext(texts_by_atom[target], "\n", "<BR>")]</TT></BODY></HTML>", "window=[target.name];size=500x200")
|
||||
usr << browse("<HTML><HEAD><meta http-equiv='Content-Type' content='text/html; charset=UTF-8'><TITLE>[isliving(target) ? L.get_visible_name() : target.name]</TITLE></HEAD><BODY><TT>[replacetext(texts_by_atom[target], "\n", "<BR>")]</TT></BODY></HTML>", "window=[isliving(target) ? L.get_visible_name() : target.name];size=500x200")
|
||||
onclose(usr, "[target.name]")
|
||||
return TRUE
|
||||
|
||||
|
||||
@@ -117,9 +117,8 @@
|
||||
continue
|
||||
|
||||
var/datum/gas_mixture/A = F.air
|
||||
var/list/A_gases = A.gases
|
||||
var/trace_gases
|
||||
for(var/id in A_gases)
|
||||
for(var/id in A.get_gases())
|
||||
if(id in GLOB.hardcoded_gases)
|
||||
continue
|
||||
trace_gases = TRUE
|
||||
@@ -128,15 +127,15 @@
|
||||
// Can most things breathe?
|
||||
if(trace_gases)
|
||||
continue
|
||||
if(A_gases[/datum/gas/oxygen] <= 16)
|
||||
if(A.get_moles(/datum/gas/oxygen) < 16)
|
||||
continue
|
||||
if(A_gases[/datum/gas/plasma])
|
||||
if(A.get_moles(/datum/gas/plasma))
|
||||
continue
|
||||
if(A_gases[/datum/gas/carbon_dioxide] >= 10)
|
||||
if(A.get_moles(/datum/gas/carbon_dioxide) >= 10)
|
||||
continue
|
||||
|
||||
// Aim for goldilocks temperatures and pressure
|
||||
if((A.temperature <= 270) || (A.temperature >= 360))
|
||||
if((A.return_temperature() <= 270) || (A.return_temperature() >= 360))
|
||||
continue
|
||||
var/pressure = A.return_pressure()
|
||||
if((pressure <= 20) || (pressure >= 550))
|
||||
|
||||
@@ -58,12 +58,10 @@
|
||||
var/datum/martial_art/boxing/style = new
|
||||
|
||||
/obj/item/clothing/gloves/boxing/equipped(mob/user, slot)
|
||||
if(!ishuman(user))
|
||||
return
|
||||
if(slot == SLOT_GLOVES)
|
||||
. = ..()
|
||||
if(ishuman(user) && slot == SLOT_GLOVES)
|
||||
var/mob/living/carbon/human/H = user
|
||||
style.teach(H,TRUE)
|
||||
return
|
||||
|
||||
/obj/item/clothing/gloves/boxing/dropped(mob/user)
|
||||
. = ..()
|
||||
|
||||
@@ -196,9 +196,8 @@
|
||||
var/datum/martial_art/krav_maga/style = new
|
||||
|
||||
/obj/item/clothing/gloves/krav_maga/equipped(mob/user, slot)
|
||||
if(!ishuman(user))
|
||||
return
|
||||
if(slot == SLOT_GLOVES)
|
||||
. = ..()
|
||||
if(ishuman(user) && slot == SLOT_GLOVES)
|
||||
var/mob/living/carbon/human/H = user
|
||||
style.teach(H,1)
|
||||
|
||||
|
||||
@@ -180,14 +180,12 @@
|
||||
to_chat(usr, "<span class='notice'>Keelhaul</span>: Harm Grab. Kick opponents to the floor. Against prone targets, deal additional stamina damage and disarm them.")
|
||||
to_chat(usr, "<span class='notice'>In addition, your body has become incredibly resilient to most forms of attack. Weapons cannot readily pierce your hardened skin, and you are highly resistant to stuns and knockdowns, and can block all projectiles in Throw Mode. However, you are not invincible, and sustained damage will take it's toll. Avoid heat at all costs!</span>")
|
||||
|
||||
/obj/item/twohanded/bostaff
|
||||
/obj/item/staff/bostaff
|
||||
name = "bo staff"
|
||||
desc = "A long, tall staff made of polished wood. Traditionally used in ancient old-Earth martial arts. Can be wielded to both kill and incapacitate."
|
||||
force = 10
|
||||
w_class = WEIGHT_CLASS_BULKY
|
||||
slot_flags = ITEM_SLOT_BACK
|
||||
force_unwielded = 10
|
||||
force_wielded = 24
|
||||
throwforce = 20
|
||||
throw_speed = 2
|
||||
attack_verb = list("smashed", "slammed", "whacked", "thwacked")
|
||||
@@ -196,11 +194,29 @@
|
||||
lefthand_file = 'icons/mob/inhands/weapons/staves_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/weapons/staves_righthand.dmi'
|
||||
block_chance = 50
|
||||
var/wielded = FALSE // track wielded status on item
|
||||
|
||||
/obj/item/twohanded/bostaff/update_icon_state()
|
||||
icon_state = "bostaff[wielded]"
|
||||
/obj/item/staff/bostaff/Initialize()
|
||||
. = ..()
|
||||
RegisterSignal(src, COMSIG_TWOHANDED_WIELD, .proc/on_wield)
|
||||
RegisterSignal(src, COMSIG_TWOHANDED_UNWIELD, .proc/on_unwield)
|
||||
|
||||
/obj/item/twohanded/bostaff/attack(mob/target, mob/living/user)
|
||||
/obj/item/staff/bostaff/ComponentInitialize()
|
||||
. = ..()
|
||||
AddComponent(/datum/component/two_handed, force_unwielded=10, force_wielded=24, icon_wielded="bostaff1")
|
||||
|
||||
/// triggered on wield of two handed item
|
||||
/obj/item/staff/bostaff/proc/on_wield(obj/item/source, mob/user)
|
||||
wielded = TRUE
|
||||
|
||||
/// triggered on unwield of two handed item
|
||||
/obj/item/staff/bostaff/proc/on_unwield(obj/item/source, mob/user)
|
||||
wielded = FALSE
|
||||
|
||||
/obj/item/staff/bostaff/update_icon_state()
|
||||
icon_state = "bostaff0"
|
||||
|
||||
/obj/item/staff/bostaff/attack(mob/target, mob/living/user)
|
||||
add_fingerprint(user)
|
||||
if((HAS_TRAIT(user, TRAIT_CLUMSY)) && prob(50))
|
||||
to_chat(user, "<span class ='warning'>You club yourself over the head with [src].</span>")
|
||||
@@ -249,7 +265,7 @@
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/item/twohanded/bostaff/run_block(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
|
||||
/obj/item/staff/bostaff/run_block(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
|
||||
if(!wielded)
|
||||
return BLOCK_NONE
|
||||
return ..()
|
||||
|
||||
@@ -215,11 +215,17 @@
|
||||
|
||||
/datum/martial_art/wrestling/proc/FlipAnimation(mob/living/carbon/human/D)
|
||||
set waitfor = FALSE
|
||||
var/transform_before
|
||||
var/laying_before
|
||||
if (D)
|
||||
transform_before = D.transform
|
||||
laying_before = D.lying
|
||||
animate(D, transform = matrix(180, MATRIX_ROTATE), time = 1, loop = 0)
|
||||
sleep(15)
|
||||
if (D)
|
||||
animate(D, transform = null, time = 1, loop = 0)
|
||||
if(transform_before && laying_before == D.lying) //animate calls sleep so this should be fine and stop a bug with transforms
|
||||
D.transform = transform_before
|
||||
animate(D, transform = null, time = 1, loop = 0)
|
||||
|
||||
/datum/martial_art/wrestling/proc/slam(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
if(!D)
|
||||
@@ -377,7 +383,7 @@
|
||||
var/turf/ST = null
|
||||
var/falling = 0
|
||||
var/damage = damage_roll(A,D)
|
||||
|
||||
|
||||
for (var/obj/O in oview(1, A))
|
||||
if (O.density == 1)
|
||||
if (O == A)
|
||||
@@ -415,11 +421,17 @@
|
||||
to_chat(A, "You can't drop onto [D] from here!")
|
||||
return FALSE
|
||||
|
||||
var/transform_before
|
||||
var/laying_before
|
||||
if(A)
|
||||
transform_before = A.transform
|
||||
laying_before = A.lying
|
||||
animate(A, transform = matrix(90, MATRIX_ROTATE), time = 1, loop = 0)
|
||||
sleep(10)
|
||||
if(A)
|
||||
animate(A, transform = null, time = 1, loop = 0)
|
||||
if(transform_before && laying_before == A.lying) //if they suddenly dropped to the floor between this period, don't revert their animation
|
||||
animate(A, transform = null, time = 1, loop = 0)
|
||||
A.transform = transform_before
|
||||
|
||||
A.forceMove(D.loc)
|
||||
|
||||
@@ -472,12 +484,10 @@
|
||||
var/datum/martial_art/wrestling/style = new
|
||||
|
||||
/obj/item/storage/belt/champion/wrestling/equipped(mob/user, slot)
|
||||
if(!ishuman(user))
|
||||
return
|
||||
if(slot == SLOT_BELT)
|
||||
. = ..()
|
||||
if(ishuman(user) && slot == SLOT_BELT)
|
||||
var/mob/living/carbon/human/H = user
|
||||
style.teach(H,1)
|
||||
return
|
||||
|
||||
/obj/item/storage/belt/champion/wrestling/dropped(mob/user)
|
||||
. = ..()
|
||||
|
||||
@@ -124,6 +124,8 @@
|
||||
transfer_martial_arts(new_character)
|
||||
if(active || force_key_move)
|
||||
new_character.key = key //now transfer the key to link the client to our new body
|
||||
if(new_character.client)
|
||||
LAZYCLEARLIST(new_character.client.recent_examines)
|
||||
current.update_atom_languages()
|
||||
|
||||
//CIT CHANGE - makes arousal update when transfering bodies
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
var/synchronizer_coeff = -1 //makes the mutation hurt the user less
|
||||
var/power_coeff = -1 //boosts mutation strength
|
||||
var/energy_coeff = -1 //lowers mutation cooldown
|
||||
var/list/valid_chrom_list = list() //List of strings of valid chromosomes this mutation can accept.
|
||||
|
||||
/datum/mutation/human/New(class_ = MUT_OTHER, timer, datum/mutation/human/copymut)
|
||||
. = ..()
|
||||
@@ -90,7 +91,7 @@
|
||||
/datum/mutation/human/proc/get_visual_indicator()
|
||||
return
|
||||
|
||||
/datum/mutation/human/proc/on_attack_hand(atom/target, proximity)
|
||||
/datum/mutation/human/proc/on_attack_hand(atom/target, proximity, act_intent, unarmed_attack_flags)
|
||||
return
|
||||
|
||||
/datum/mutation/human/proc/on_ranged_attack(atom/target, mouseparams)
|
||||
@@ -167,6 +168,7 @@
|
||||
energy_coeff = HM.energy_coeff
|
||||
mutadone_proof = HM.mutadone_proof
|
||||
can_chromosome = HM.can_chromosome
|
||||
valid_chrom_list = HM.valid_chrom_list
|
||||
|
||||
/datum/mutation/human/proc/remove_chromosome()
|
||||
stabilizer_coeff = initial(stabilizer_coeff)
|
||||
@@ -192,3 +194,23 @@
|
||||
power.panel = "Genetic"
|
||||
owner.AddSpell(power)
|
||||
return TRUE
|
||||
|
||||
// Runs through all the coefficients and uses this to determine which chromosomes the
|
||||
// mutation can take. Stores these as text strings in a list.
|
||||
/datum/mutation/human/proc/update_valid_chromosome_list()
|
||||
valid_chrom_list.Cut()
|
||||
|
||||
if(can_chromosome == CHROMOSOME_NEVER)
|
||||
valid_chrom_list += "none"
|
||||
return
|
||||
|
||||
valid_chrom_list += "Reinforcement"
|
||||
|
||||
if(stabilizer_coeff != -1)
|
||||
valid_chrom_list += "Stabilizer"
|
||||
if(synchronizer_coeff != -1)
|
||||
valid_chrom_list += "Synchronizer"
|
||||
if(power_coeff != -1)
|
||||
valid_chrom_list += "Power"
|
||||
if(energy_coeff != -1)
|
||||
valid_chrom_list += "Energetic"
|
||||
|
||||
@@ -226,9 +226,8 @@
|
||||
/obj/effect/proc_holder/spell/targeted/olfaction/cast(list/targets, mob/living/user = usr)
|
||||
//can we sniff? is there miasma in the air?
|
||||
var/datum/gas_mixture/air = user.loc.return_air()
|
||||
var/list/cached_gases = air.gases
|
||||
|
||||
if(cached_gases[/datum/gas/miasma])
|
||||
if(air.get_moles(/datum/gas/miasma))
|
||||
user.adjust_disgust(sensitivity * 45)
|
||||
to_chat(user, "<span class='warning'>With your overly sensitive nose, you get a whiff of stench and feel sick! Try moving to a cleaner area!</span>")
|
||||
return
|
||||
|
||||
@@ -19,8 +19,8 @@
|
||||
SEND_SIGNAL(owner, COMSIG_ADD_MOOD_EVENT, "hulk", /datum/mood_event/hulk)
|
||||
RegisterSignal(owner, COMSIG_MOB_SAY, .proc/handle_speech)
|
||||
|
||||
/datum/mutation/human/hulk/on_attack_hand(atom/target, proximity)
|
||||
if(proximity) //no telekinetic hulk attack
|
||||
/datum/mutation/human/hulk/on_attack_hand(atom/target, proximity, act_intent, unarmed_attack_flags)
|
||||
if(proximity && (act_intent == INTENT_HARM)) //no telekinetic hulk attack
|
||||
return target.attack_hulk(owner)
|
||||
|
||||
/datum/mutation/human/hulk/on_life()
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
/datum/mutation/human/wacky
|
||||
name = "Wacky"
|
||||
desc = "<span class='sans'>Unknown.</span>"
|
||||
desc = "Unknown."
|
||||
quality = MINOR_NEGATIVE
|
||||
text_gain_indication = "<span class='sans'>You feel an off sensation in your voicebox.</span>"
|
||||
text_lose_indication = "<span class='notice'>The off sensation passes.</span>"
|
||||
|
||||
@@ -104,6 +104,9 @@
|
||||
rack.AddComponent(/datum/component/magnetic_catch)
|
||||
|
||||
//Whatever special stuff you want
|
||||
/datum/map_template/shuttle/proc/post_load(obj/docking_port/mobile/M)
|
||||
return
|
||||
|
||||
/datum/map_template/shuttle/proc/on_bought()
|
||||
return
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
/datum/skill_holder/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.always_state)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "skillpanel", "[owner.name]'s Skills", 620, 580, master_ui, state)
|
||||
ui = new(user, src, ui_key, "SkillPanel", "[owner.name]'s Skills", 620, 580, master_ui, state)
|
||||
ui.set_autoupdate(FALSE) // This UI is only ever opened by one person, and never is updated outside of user input.
|
||||
ui.open()
|
||||
else if(need_static_data_update)
|
||||
@@ -40,7 +40,7 @@
|
||||
. = list()
|
||||
.["playername"] = owner.name
|
||||
.["see_skill_mods"] = see_skill_mods
|
||||
.["admin"] = check_rights(R_DEBUG)
|
||||
.["admin"] = check_rights(R_DEBUG, FALSE)
|
||||
|
||||
/datum/skill_holder/ui_act(action, params)
|
||||
. = ..()
|
||||
|
||||
@@ -33,6 +33,10 @@ GLOBAL_LIST_INIT_TYPED(skill_datums, /datum/skill, init_skill_datums())
|
||||
var/base_multiplier = 1
|
||||
/// Value added to the base multiplier depending on overall competency compared to maximum value/level.
|
||||
var/competency_multiplier = 1
|
||||
/// Experience gain multiplier gained from using items.
|
||||
var/item_skill_gain_multi = 1
|
||||
/// Skill gain quantisation
|
||||
var/skill_gain_quantisation = 0.1
|
||||
/// A list of ways this skill can affect or be affected through actions and skill modifiers.
|
||||
var/list/skill_traits = list(SKILL_SANITY, SKILL_INTELLIGENCE)
|
||||
/// Index of this skill in the UI
|
||||
@@ -108,6 +112,10 @@ GLOBAL_LIST_INIT_TYPED(skill_datums, /datum/skill, init_skill_datums())
|
||||
/// Min value of this skill
|
||||
var/min_value = 0
|
||||
|
||||
/datum/skill/numerical/New()
|
||||
..()
|
||||
skill_gain_quantisation = item_skill_gain_multi = item_skill_gain_multi * (max_value - min_value) * STD_NUM_SKILL_ITEM_GAIN_MULTI
|
||||
|
||||
/datum/skill/numerical/sanitize_value(new_value)
|
||||
return clamp(new_value, min_value, max_value)
|
||||
|
||||
|
||||
@@ -91,10 +91,10 @@
|
||||
CRASH("Invalid set_skill_value call. Use skill typepaths.") //until a time when we somehow need text ids for dynamic skills, I'm enforcing this.
|
||||
var/datum/skill/S = GLOB.skill_datums[skill]
|
||||
value = S.sanitize_value(value)
|
||||
skill_holder.need_static_data_update = TRUE
|
||||
if(!isnull(value))
|
||||
LAZYINITLIST(skill_holder.skills)
|
||||
S.set_skill_value(skill_holder, value, src, silent)
|
||||
skill_holder.need_static_data_update = TRUE
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
@@ -120,11 +120,9 @@
|
||||
CRASH("You cannot auto increment a non numerical(experience skill!")
|
||||
var/current = get_skill_value(skill, FALSE)
|
||||
var/affinity = get_skill_affinity(skill)
|
||||
var/target_value = current + (value * affinity)
|
||||
if(maximum)
|
||||
target_value = min(target_value, maximum)
|
||||
if(target_value == maximum) //no more experience to gain, early return.
|
||||
return
|
||||
var/target_value = round(current + (value * affinity), S.skill_gain_quantisation)
|
||||
if(maximum && target_value >= maximum) //no more experience to gain, early return.
|
||||
return
|
||||
boost_skill_value_to(skill, target_value, silent, current)
|
||||
|
||||
/**
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
/datum/spawners_menu/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.observer_state)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "spawners_menu", "Spawners Menu", 700, 600, master_ui, state)
|
||||
ui = new(user, src, ui_key, "SpawnersMenu", "Spawners Menu", 700, 600, master_ui, state)
|
||||
ui.open()
|
||||
|
||||
/datum/spawners_menu/ui_data(mob/user)
|
||||
|
||||
@@ -365,9 +365,9 @@
|
||||
status_type = STATUS_EFFECT_REPLACE
|
||||
alert_type = null
|
||||
var/mutable_appearance/marked_underlay
|
||||
var/obj/item/twohanded/kinetic_crusher/hammer_synced
|
||||
var/obj/item/kinetic_crusher/hammer_synced
|
||||
|
||||
/datum/status_effect/crusher_mark/on_creation(mob/living/new_owner, obj/item/twohanded/kinetic_crusher/new_hammer_synced)
|
||||
/datum/status_effect/crusher_mark/on_creation(mob/living/new_owner, obj/item/kinetic_crusher/new_hammer_synced)
|
||||
. = ..()
|
||||
if(.)
|
||||
hammer_synced = new_hammer_synced
|
||||
|
||||
@@ -314,6 +314,13 @@ GLOBAL_LIST_EMPTY(family_heirlooms)
|
||||
medical_record_text = "Patient is usually anxious in social encounters and prefers to avoid them."
|
||||
var/dumb_thing = TRUE
|
||||
|
||||
/datum/quirk/social_anxiety/add()
|
||||
RegisterSignal(quirk_holder, COMSIG_MOB_EYECONTACT, .proc/eye_contact)
|
||||
RegisterSignal(quirk_holder, COMSIG_MOB_EXAMINATE, .proc/looks_at_floor)
|
||||
|
||||
/datum/quirk/social_anxiety/remove()
|
||||
UnregisterSignal(quirk_holder, list(COMSIG_MOB_EYECONTACT, COMSIG_MOB_EXAMINATE))
|
||||
|
||||
/datum/quirk/social_anxiety/on_process()
|
||||
var/nearby_people = 0
|
||||
for(var/mob/living/carbon/human/H in oview(3, quirk_holder))
|
||||
@@ -330,6 +337,45 @@ GLOBAL_LIST_EMPTY(family_heirlooms)
|
||||
dumb_thing = FALSE //only once per life
|
||||
if(prob(1))
|
||||
new/obj/item/reagent_containers/food/snacks/pastatomato(get_turf(H)) //now that's what I call spaghetti code
|
||||
// small chance to make eye contact with inanimate objects/mindless mobs because of nerves
|
||||
|
||||
|
||||
|
||||
/datum/quirk/social_anxiety/proc/looks_at_floor(datum/source, atom/A)
|
||||
var/mob/living/mind_check = A
|
||||
if(prob(85) || (istype(mind_check) && mind_check.mind))
|
||||
return
|
||||
|
||||
addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, quirk_holder, "<span class='smallnotice'>You make eye contact with [A].</span>"), 3)
|
||||
|
||||
/datum/quirk/social_anxiety/proc/eye_contact(datum/source, mob/living/other_mob, triggering_examiner)
|
||||
if(prob(75))
|
||||
return
|
||||
var/msg
|
||||
if(triggering_examiner)
|
||||
msg = "You make eye contact with [other_mob], "
|
||||
else
|
||||
msg = "[other_mob] makes eye contact with you, "
|
||||
|
||||
switch(rand(1,3))
|
||||
if(1)
|
||||
quirk_holder.Jitter(10)
|
||||
msg += "causing you to start fidgeting!"
|
||||
if(2)
|
||||
quirk_holder.stuttering = max(3, quirk_holder.stuttering)
|
||||
msg += "causing you to start stuttering!"
|
||||
if(3)
|
||||
quirk_holder.Stun(2 SECONDS)
|
||||
msg += "causing you to freeze up!"
|
||||
|
||||
SEND_SIGNAL(quirk_holder, COMSIG_ADD_MOOD_EVENT, "anxiety_eyecontact", /datum/mood_event/anxiety_eyecontact)
|
||||
addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, quirk_holder, "<span class='userdanger'>[msg]</span>"), 3) // so the examine signal has time to fire and this will print after
|
||||
return COMSIG_BLOCK_EYECONTACT
|
||||
|
||||
/datum/mood_event/anxiety_eyecontact
|
||||
description = "<span class='warning'>Sometimes eye contact makes me so nervous...</span>\n"
|
||||
mood_change = -5
|
||||
timeout = 3 MINUTES
|
||||
|
||||
/datum/quirk/phobia
|
||||
name = "Phobia"
|
||||
@@ -406,3 +452,21 @@ GLOBAL_LIST_EMPTY(family_heirlooms)
|
||||
mob_trait = TRAIT_COLDBLOODED
|
||||
gain_text = "<span class='notice'>You feel cold-blooded.</span>"
|
||||
lose_text = "<span class='notice'>You feel more warm-blooded.</span>"
|
||||
|
||||
/datum/quirk/monophobia
|
||||
name = "Monophobia"
|
||||
desc = "You will become increasingly stressed when not in company of others, triggering panic reactions ranging from sickness to heart attacks."
|
||||
value = -3 // Might change it to 4.
|
||||
gain_text = "<span class='danger'>You feel really lonely...</span>"
|
||||
lose_text = "<span class='notice'>You feel like you could be safe on your own.</span>"
|
||||
medical_record_text = "Patient feels sick and distressed when not around other people, leading to potentially lethal levels of stress."
|
||||
|
||||
/datum/quirk/monophobia/post_add()
|
||||
. = ..()
|
||||
var/mob/living/carbon/human/H = quirk_holder
|
||||
H.gain_trauma(/datum/brain_trauma/severe/monophobia, TRAUMA_RESILIENCE_ABSOLUTE)
|
||||
|
||||
/datum/quirk/monophobia/remove()
|
||||
. = ..()
|
||||
var/mob/living/carbon/human/H = quirk_holder
|
||||
H?.cure_trauma_type(/datum/brain_trauma/severe/monophobia, TRAUMA_RESILIENCE_ABSOLUTE)
|
||||
|
||||
@@ -242,8 +242,8 @@
|
||||
/datum/wires/ui_interact(mob/user, ui_key = "wires", datum/tgui/ui = null, force_open = FALSE, \
|
||||
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.physical_state)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "wires", "[holder.name] Wires", 350, 150 + wires.len * 30, master_ui, state)
|
||||
if (!ui)
|
||||
ui = new(user, src, ui_key, "Wires", "[holder.name] Wires", 350, 150 + wires.len * 30, master_ui, state)
|
||||
ui.open()
|
||||
|
||||
/datum/wires/ui_data(mob/user)
|
||||
|
||||
@@ -75,8 +75,8 @@
|
||||
|
||||
|
||||
/datum/wires/explosive/gibtonite
|
||||
holder_type = /obj/item/twohanded/required/gibtonite
|
||||
holder_type = /obj/item/gibtonite
|
||||
|
||||
/datum/wires/explosive/gibtonite/explode()
|
||||
var/obj/item/twohanded/required/gibtonite/P = holder
|
||||
var/obj/item/gibtonite/P = holder
|
||||
P.GibtoniteReaction(null, 2)
|
||||
@@ -74,6 +74,25 @@
|
||||
for(var/client/C in GLOB.clients)
|
||||
C.AnnouncePR(final_composed)
|
||||
|
||||
/datum/world_topic/auto_bunker_passthrough
|
||||
keyword = "auto_bunker_override"
|
||||
require_comms_key = TRUE
|
||||
|
||||
/datum/world_topic/auto_bunker_passthrough/Run(list/input)
|
||||
if(!CONFIG_GET(flag/allow_cross_server_bunker_override))
|
||||
return "Function Disabled"
|
||||
var/ckeytobypass = input["ckey"]
|
||||
var/is_new_ckey = !(ckey(ckeytobypass) in GLOB.bunker_passthrough)
|
||||
var/sender = input["source"] || "UNKNOWN"
|
||||
GLOB.bunker_passthrough |= ckey(ckeytobypass)
|
||||
GLOB.bunker_passthrough[ckey(ckeytobypass)] = world.realtime
|
||||
SSpersistence.SavePanicBunker() //we can do this every time, it's okay
|
||||
if(!is_new_ckey)
|
||||
log_admin("AUTO BUNKER: [ckeytobypass] given access (incoming comms from [sender]).")
|
||||
message_admins("AUTO BUNKER: [ckeytobypass] given access (incoming comms from [sender]).")
|
||||
send2irc("Panic Bunker", "AUTO BUNKER: [ckeytobypass] given access (incoming comms from [sender]).")
|
||||
return "Success"
|
||||
|
||||
/datum/world_topic/ahelp_relay
|
||||
keyword = "Ahelp"
|
||||
require_comms_key = TRUE
|
||||
|
||||
Reference in New Issue
Block a user